summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/can/dev/rx-offload.c126
-rw-r--r--drivers/net/can/flexcan.c724
-rw-r--r--drivers/net/dsa/Kconfig2
-rw-r--r--drivers/net/dsa/Makefile1
-rw-r--r--drivers/net/dsa/ocelot/Kconfig22
-rw-r--r--drivers/net/dsa/ocelot/Makefile8
-rw-r--r--drivers/net/dsa/ocelot/felix.c812
-rw-r--r--drivers/net/dsa/ocelot/felix.h51
-rw-r--r--drivers/net/dsa/ocelot/felix_tsn.c432
-rw-r--r--drivers/net/dsa/ocelot/felix_tsn.h61
-rw-r--r--drivers/net/dsa/ocelot/felix_vsc9959.c1100
-rw-r--r--drivers/net/ethernet/freescale/Kconfig13
-rw-r--r--drivers/net/ethernet/freescale/Makefile3
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c340
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/Kconfig26
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/Makefile1
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c1219
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h207
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c83
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c693
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h144
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c122
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h135
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni.c374
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni.h196
-rw-r--r--drivers/net/ethernet/freescale/enetc/Kconfig21
-rw-r--r--drivers/net/ethernet/freescale/enetc/Makefile5
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c119
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h55
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_cbdr.c5
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c79
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_hw.h601
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_mdio.c120
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_mdio.h12
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c43
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c226
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.h8
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_qos.c300
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_tsn.c2049
-rw-r--r--drivers/net/ethernet/freescale/fec.h55
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c538
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c35
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.h4
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_port.c14
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_port.h2
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/Kconfig184
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/Makefile46
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c580
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h138
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c180
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h43
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c1203
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h673
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c205
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h49
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c2085
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h241
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c1746
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h227
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c381
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c1268
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c278
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h144
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c561
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c930
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/mac.c489
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/mac.h134
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c848
-rw-r--r--drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h59
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Kconfig162
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Makefile11
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile15
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c1236
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile28
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c1504
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h228
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c97
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h42
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c674
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h226
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c119
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h43
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c847
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c165
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c532
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c215
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c367
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c1159
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h111
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c78
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h73
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c1017
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h151
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c139
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h80
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile15
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c237
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h203
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c59
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c1031
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h479
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c883
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h144
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile24
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile26
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h360
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c7583
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h399
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c3246
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h206
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c5572
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h555
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c2095
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h543
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h280
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c1847
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h165
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c423
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h316
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c984
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h101
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c890
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c129
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile15
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c6442
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h999
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h494
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c753
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c1570
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile15
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c692
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h96
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c334
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile15
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c757
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h85
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c197
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c5223
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h648
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h465
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c174
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c1400
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h1214
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h93
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h117
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/Makefile12
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/error.c95
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/list.c71
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c620
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/mm.c1155
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/mm.h105
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c81
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h57
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h56
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h364
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h210
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h1731
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h887
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h1271
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h170
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h3974
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h2608
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h619
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h411
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h76
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h90
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h55
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h476
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h141
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h77
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h233
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h447
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h205
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h529
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h358
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h318
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h208
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h310
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h118
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h37
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h52
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h78
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h273
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h825
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h1096
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h107
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h514
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h434
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h78
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h593
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h102
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h449
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h138
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h479
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h291
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h71
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h304
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h293
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h59
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h304
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h294
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h64
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h185
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h213
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h82
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h635
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h276
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h83
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h336
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h100
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h435
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h430
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h48
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h49
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h162
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h56
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h62
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h56
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h791
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h56
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk53
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h65
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h62
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/Makefile11
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h118
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h46
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h208
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h84
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h130
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h163
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h953
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h50
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile10
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c171
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile19
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c1665
-rwxr-xr-xdrivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c2939
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h294
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c1512
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c4854
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c1299
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h755
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h121
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c191
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h144
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make28
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c60
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h60
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c1858
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h136
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c1268
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h56
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile18
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c46
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c906
-rw-r--r--drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c919
-rw-r--r--drivers/net/ethernet/mscc/Makefile1
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c1217
-rw-r--r--drivers/net/ethernet/mscc/ocelot.h491
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ace.c14
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ace.h8
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ana.h625
-rw-r--r--drivers/net/ethernet/mscc/ocelot_board.c150
-rw-r--r--drivers/net/ethernet/mscc/ocelot_dev.h275
-rw-r--r--drivers/net/ethernet/mscc/ocelot_dev_gmii.h153
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c32
-rw-r--r--drivers/net/ethernet/mscc/ocelot_io.c14
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.c36
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.h4
-rw-r--r--drivers/net/ethernet/mscc/ocelot_qsys.h270
-rw-r--r--drivers/net/ethernet/mscc/ocelot_regs.c3
-rw-r--r--drivers/net/ethernet/mscc/ocelot_sys.h144
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tc.c56
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tsn.c1586
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tsn.h51
-rw-r--r--drivers/net/ethernet/mscc/ocelot_vcap.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c399
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c24
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4.h40
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c111
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c42
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c49
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c120
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.h24
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c76
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c42
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc_core.c16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c438
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c73
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c139
-rw-r--r--drivers/net/ivshmem-net.c1077
-rw-r--r--drivers/net/phy/Kconfig15
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/aquantia_main.c128
-rw-r--r--drivers/net/phy/at803x.c86
-rw-r--r--drivers/net/phy/inphi.c594
-rw-r--r--drivers/net/phy/mdio_bus.c8
-rw-r--r--drivers/net/phy/mscc.c10
-rw-r--r--drivers/net/phy/nxp-tja11xx.c173
-rw-r--r--drivers/net/phy/phy-core.c4
-rw-r--r--drivers/net/phy/phy_device.c25
-rw-r--r--drivers/net/phy/phylink.c14
-rw-r--r--drivers/net/phy/realtek.c80
-rw-r--r--drivers/net/phy/swphy.c1
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c45
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c244
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h41
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c60
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c57
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c179
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c20
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c27
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c45
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c247
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h60
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c15
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h4
-rw-r--r--drivers/net/wireless/nxp/Kconfig17
-rw-r--r--drivers/net/wireless/nxp/Makefile5
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/Kconfig12
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/Makefile2
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/Makefile503
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan.h37
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.c1309
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.h52
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.c904
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.h58
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11d.c1590
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.c4274
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.h201
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.c3092
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.h408
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.c603
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.h38
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.c1497
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.h104
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cfp.c3608
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cmdevt.c8377
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_decl.h1988
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_fw.h7410
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ieee.h1888
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.c1959
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.h125
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ioctl.h5159
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.c2621
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.h42
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_main.h4137
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.c465
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.h55
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_misc.c5866
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_module.c65
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.c4205
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.h650
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_scan.c6468
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.c3013
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.h550
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c1700
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmd.c2950
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmdresp.c2749
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_event.c1026
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_ioctl.c5615
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_rx.c488
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_tx.c326
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_txrx.c424
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap.h57
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_cmdevent.c5587
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_ioctl.c2240
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_txrx.c820
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_usb.c1264
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_util.h492
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.c3282
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.h242
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan.h37
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_decl.h1988
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ieee.h1888
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ioctl.h5159
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.c4679
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.h478
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.c4207
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.h781
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_debug.c1468
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.c16895
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.h675
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_init.c2355
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_ioctl.c6979
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.c9625
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.h3150
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.c2447
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.h148
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.c6863
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.h485
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_proc.c1099
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio.h174
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c2106
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.c3284
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.h122
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.c7893
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.h41
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.c4526
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.h581
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.c3259
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.h30
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.c179
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.h128
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_wext.c1865
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c2028
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.h234
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.c3175
-rw-r--r--drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.h58
433 files changed, 344709 insertions, 3389 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index df3cd2589bcf..9a446ee8fe3b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -528,4 +528,8 @@ config NET_FAILOVER
a VM with direct attached VF by failing over to the paravirtual
datapath when the VF is unplugged.
+config IVSHMEM_NET
+ tristate "IVSHMEM virtual network device"
+ depends on PCI
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0d3ba056cda3..5041c293d4d0 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -79,3 +79,5 @@ thunderbolt-net-y += thunderbolt.o
obj-$(CONFIG_THUNDERBOLT_NET) += thunderbolt-net.o
obj-$(CONFIG_NETDEVSIM) += netdevsim/
obj-$(CONFIG_NET_FAILOVER) += net_failover.o
+
+obj-$(CONFIG_IVSHMEM_NET) += ivshmem-net.o
diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c
index 7e75a87a8a6a..999315b4a8e1 100644
--- a/drivers/net/can/dev/rx-offload.c
+++ b/drivers/net/can/dev/rx-offload.c
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2014 David Jander, Protonic Holland
- * Copyright (C) 2014-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
+/* Copyright (c) 2014 Protonic Holland,
+ * David Jander
+ * Copyright (C) 2014-2017 Pengutronix,
+ * Marc Kleine-Budde <kernel@pengutronix.de>
*/
#include <linux/can/dev.h>
@@ -11,14 +12,17 @@ struct can_rx_offload_cb {
u32 timestamp;
};
-static inline struct can_rx_offload_cb *can_rx_offload_get_cb(struct sk_buff *skb)
+static inline struct can_rx_offload_cb *
+can_rx_offload_get_cb(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
return (struct can_rx_offload_cb *)skb->cb;
}
-static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned int a, unsigned int b)
+static inline bool
+can_rx_offload_le(struct can_rx_offload *offload,
+ unsigned int a, unsigned int b)
{
if (offload->inc)
return a <= b;
@@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned in
return a >= b;
}
-static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
+static inline unsigned int
+can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
{
if (offload->inc)
return (*val)++;
@@ -36,7 +41,9 @@ static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, un
static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
{
- struct can_rx_offload *offload = container_of(napi, struct can_rx_offload, napi);
+ struct can_rx_offload *offload = container_of(napi,
+ struct can_rx_offload,
+ napi);
struct net_device *dev = offload->dev;
struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb;
@@ -44,11 +51,11 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
while ((work_done < quota) &&
(skb = skb_dequeue(&offload->skb_queue))) {
- struct can_frame *cf = (struct can_frame *)skb->data;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
work_done++;
stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
+ stats->rx_bytes += cfd->len;
netif_receive_skb(skb);
}
@@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
return work_done;
}
-static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
- int (*compare)(struct sk_buff *a, struct sk_buff *b))
+static inline void
+__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
+ int (*compare)(struct sk_buff *a, struct sk_buff *b))
{
struct sk_buff *pos, *insert = NULL;
@@ -101,7 +109,7 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
cb_a = can_rx_offload_get_cb(a);
cb_b = can_rx_offload_get_cb(b);
- /* Substract two u32 and return result as int, to keep
+ /* Subtract two u32 and return result as int, to keep
* difference steady around the u32 overflow.
*/
return cb_b->timestamp - cb_a->timestamp;
@@ -131,75 +139,40 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
static struct sk_buff *
can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
{
- struct sk_buff *skb = NULL, *skb_error = NULL;
+ struct sk_buff *skb;
struct can_rx_offload_cb *cb;
- struct can_frame *cf;
- int ret;
-
- if (likely(skb_queue_len(&offload->skb_queue) <
- offload->skb_queue_len_max)) {
- skb = alloc_can_skb(offload->dev, &cf);
- if (unlikely(!skb))
- skb_error = ERR_PTR(-ENOMEM); /* skb alloc failed */
- } else {
- skb_error = ERR_PTR(-ENOBUFS); /* skb_queue is full */
- }
-
- /* If queue is full or skb not available, drop by reading into
- * overflow buffer.
- */
- if (unlikely(skb_error)) {
- struct can_frame cf_overflow;
- u32 timestamp;
-
- ret = offload->mailbox_read(offload, &cf_overflow,
- &timestamp, n);
-
- /* Mailbox was empty. */
- if (unlikely(!ret))
- return NULL;
-
- /* Mailbox has been read and we're dropping it or
- * there was a problem reading the mailbox.
- *
- * Increment error counters in any case.
- */
- offload->dev->stats.rx_dropped++;
- offload->dev->stats.rx_fifo_errors++;
+ bool drop = false;
+ u32 timestamp;
- /* There was a problem reading the mailbox, propagate
- * error value.
- */
- if (unlikely(ret < 0))
- return ERR_PTR(ret);
-
- return skb_error;
- }
-
- cb = can_rx_offload_get_cb(skb);
- ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
+ /* If queue is full drop frame */
+ if (unlikely(skb_queue_len(&offload->skb_queue) >
+ offload->skb_queue_len_max))
+ drop = true;
+ skb = offload->mailbox_read(offload, n, &timestamp, drop);
/* Mailbox was empty. */
- if (unlikely(!ret)) {
- kfree_skb(skb);
+ if (unlikely(!skb))
return NULL;
- }
-
- /* There was a problem reading the mailbox, propagate error value. */
- if (unlikely(ret < 0)) {
- kfree_skb(skb);
+ /* There was a problem reading the mailbox, propagate
+ * error value.
+ */
+ if (unlikely(IS_ERR(skb))) {
offload->dev->stats.rx_dropped++;
offload->dev->stats.rx_fifo_errors++;
- return ERR_PTR(ret);
+ return skb;
}
/* Mailbox was read. */
+ cb = can_rx_offload_get_cb(skb);
+ cb->timestamp = timestamp;
+
return skb;
}
-int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pending)
+int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
+ u64 pending)
{
struct sk_buff_head skb_queue;
unsigned int i;
@@ -229,8 +202,8 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pen
skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
- if ((queue_len = skb_queue_len(&offload->skb_queue)) >
- (offload->skb_queue_len_max / 8))
+ queue_len = skb_queue_len(&offload->skb_queue);
+ if (queue_len > offload->skb_queue_len_max / 8)
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
__func__, queue_len);
@@ -328,7 +301,9 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
}
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
-static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
+static int can_rx_offload_init_queue(struct net_device *dev,
+ struct can_rx_offload *offload,
+ unsigned int weight)
{
offload->dev = dev;
@@ -337,7 +312,6 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
offload->skb_queue_len_max *= 4;
skb_queue_head_init(&offload->skb_queue);
- can_rx_offload_reset(offload);
netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
@@ -346,7 +320,8 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
return 0;
}
-int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *offload)
+int can_rx_offload_add_timestamp(struct net_device *dev,
+ struct can_rx_offload *offload)
{
unsigned int weight;
@@ -366,7 +341,8 @@ int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *
}
EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
-int can_rx_offload_add_fifo(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
+int can_rx_offload_add_fifo(struct net_device *dev,
+ struct can_rx_offload *offload, unsigned int weight)
{
if (!offload->mailbox_read)
return -EINVAL;
@@ -377,7 +353,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
void can_rx_offload_enable(struct can_rx_offload *offload)
{
- can_rx_offload_reset(offload);
napi_enable(&offload->napi);
}
EXPORT_SYMBOL_GPL(can_rx_offload_enable);
@@ -388,8 +363,3 @@ void can_rx_offload_del(struct can_rx_offload *offload)
skb_queue_purge(&offload->skb_queue);
}
EXPORT_SYMBOL_GPL(can_rx_offload_del);
-
-void can_rx_offload_reset(struct can_rx_offload *offload)
-{
-}
-EXPORT_SYMBOL_GPL(can_rx_offload_reset);
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 7ec15cb356c0..8a1c7cc7b206 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -6,6 +6,7 @@
// Copyright (c) 2009 Sascha Hauer, Pengutronix
// Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (c) 2014 David Jander, Protonic Holland
+// Copyright 2015, 2018 NXP
//
// Based on code originally by Andrey Volkov <avolkov@varma-el.com>
@@ -26,8 +27,14 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
+#ifdef CONFIG_IMX_SCU_SOC
+#include <linux/firmware/imx/sci.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+#endif
+
#define DRV_NAME "flexcan"
/* 8 for RX fifo and 2 error handling */
@@ -52,6 +59,7 @@
#define FLEXCAN_MCR_IRMQ BIT(16)
#define FLEXCAN_MCR_LPRIO_EN BIT(13)
#define FLEXCAN_MCR_AEN BIT(12)
+#define FLEXCAN_MCR_FDEN BIT(11)
/* MCR_MAXMB: maximum used MBs is MAXMB + 1 */
#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f)
#define FLEXCAN_MCR_IDAM_A (0x0 << 8)
@@ -91,6 +99,7 @@
#define FLEXCAN_CTRL2_MRP BIT(18)
#define FLEXCAN_CTRL2_RRS BIT(17)
#define FLEXCAN_CTRL2_EACEN BIT(16)
+#define FLEXCAN_CTRL2_ISOCANFDEN BIT(12)
/* FLEXCAN memory error control register (MECR) bits */
#define FLEXCAN_MECR_ECRWRDIS BIT(31)
@@ -134,15 +143,37 @@
(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
#define FLEXCAN_ESR_ALL_INT \
(FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
- FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
- FLEXCAN_ESR_WAK_INT)
+ FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
+
+/* FLEXCAN Bit Timing register (CBT) bits */
+#define FLEXCAN_CBT_BTF BIT(31)
+#define FLEXCAN_CBT_EPRESDIV(x) (((x) & 0x3ff) << 21)
+#define FLEXCAN_CBT_ERJW(x) (((x) & 0x0f) << 16)
+#define FLEXCAN_CBT_EPROPSEG(x) (((x) & 0x3f) << 10)
+#define FLEXCAN_CBT_EPSEG1(x) (((x) & 0x1f) << 5)
+#define FLEXCAN_CBT_EPSEG2(x) ((x) & 0x1f)
+
+/* FLEXCAN FD control register (FDCTRL) bits */
+#define FLEXCAN_FDCTRL_FDRATE BIT(31)
+#define FLEXCAN_FDCTRL_TDCEN BIT(15)
+#define FLEXCAN_FDCTRL_TDCFAIL BIT(14)
+#define FLEXCAN_FDCTRL_MBDSR1(x) (((x) & 0x3) << 19)
+#define FLEXCAN_FDCTRL_MBDSR0(x) (((x) & 0x3) << 16)
+#define FLEXCAN_FDCTRL_TDCOFF(x) (((x) & 0x1f) << 8)
+
+/* FLEXCAN FD Bit Timing register (FDCBT) bits */
+#define FLEXCAN_FDCBT_FPRESDIV(x) (((x) & 0x3ff) << 20)
+#define FLEXCAN_FDCBT_FRJW(x) (((x) & 0x07) << 16)
+#define FLEXCAN_FDCBT_FPROPSEG(x) (((x) & 0x1f) << 10)
+#define FLEXCAN_FDCBT_FPSEG1(x) (((x) & 0x07) << 5)
+#define FLEXCAN_FDCBT_FPSEG2(x) ((x) & 0x07)
/* FLEXCAN interrupt flag register (IFLAG) bits */
/* Errata ERR005829 step7: Reserve first valid MB */
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
-#define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f)
+#define FLEXCAN_IFLAG_MB(x) BIT_ULL(x)
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
@@ -161,6 +192,9 @@
#define FLEXCAN_MB_CODE_TX_DATA (0xc << 24)
#define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24)
+#define FLEXCAN_MB_CNT_EDL BIT(31)
+#define FLEXCAN_MB_CNT_BRS BIT(30)
+#define FLEXCAN_MB_CNT_ESI BIT(29)
#define FLEXCAN_MB_CNT_SRR BIT(22)
#define FLEXCAN_MB_CNT_IDE BIT(21)
#define FLEXCAN_MB_CNT_RTR BIT(20)
@@ -172,26 +206,30 @@
/* FLEXCAN hardware feature flags
*
* Below is some version info we got:
- * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR re-
- * Filter? connected? Passive detection ception in MB
- * MX25 FlexCAN2 03.00.00.00 no no no no no
- * MX28 FlexCAN2 03.00.04.00 yes yes no no no
- * MX35 FlexCAN2 03.00.00.00 no no no no no
- * MX53 FlexCAN2 03.00.00.00 yes no no no no
- * MX6s FlexCAN3 10.00.12.00 yes yes no no yes
- * VF610 FlexCAN3 ? no yes no yes yes?
- * LS1021A FlexCAN2 03.00.04.00 no yes no no yes
+ * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode
+ * Filter? connected? Passive detection ption in MB Supported?
+ * MX25 FlexCAN2 03.00.00.00 no no no no no no
+ * MX28 FlexCAN2 03.00.04.00 yes yes no no no no
+ * MX35 FlexCAN2 03.00.00.00 no no no no no no
+ * MX53 FlexCAN2 03.00.00.00 yes no no no no no
+ * MX6s FlexCAN3 10.00.12.00 yes yes no no yes no
+ * MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes
+ * VF610 FlexCAN3 ? no yes no yes yes? no
+ * LS1021A FlexCAN2 03.00.04.00 no yes no no yes no
+ * LX2160A FlexCAN3 03.00.23.00 no yes no no yes yes
*
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
*/
#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) /* [TR]WRN_INT not connected */
#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */
-#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */
+#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable non-correctable errors interrupt and freeze mode */
#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */
#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */
#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) /* default to BE register access */
#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) /* Setup stop mode to support wakeup */
+#define FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD BIT(9) /* Use timestamp then support can fd mode */
+#define FLEXCAN_QUIRK_USE_SCFW BIT(10) /* Use System Controller Firmware */
/* Structure of the message buffer */
struct flexcan_mb {
@@ -225,7 +263,8 @@ struct flexcan_regs {
u32 crcr; /* 0x44 */
u32 rxfgmask; /* 0x48 */
u32 rxfir; /* 0x4c */
- u32 _reserved3[12]; /* 0x50 */
+ u32 cbt; /* 0x50 */
+ u32 _reserved3[11]; /* 0x54 */
u8 mb[2][512]; /* 0x80 */
/* FIFO-mode:
* MB
@@ -241,7 +280,16 @@ struct flexcan_regs {
u32 rximr[64]; /* 0x880 */
u32 _reserved5[24]; /* 0x980 */
u32 gfwr_mx6; /* 0x9e0 - MX6 */
- u32 _reserved6[63]; /* 0x9e4 */
+ u32 _reserved6[39]; /* 0x9e4 */
+ u32 _rxfir[6]; /* 0xa80 */
+ u32 _reserved8[2]; /* 0xa98 */
+ u32 _rxmgmask; /* 0xaa0 */
+ u32 _rxfgmask; /* 0xaa4 */
+ u32 _rx14mask; /* 0xaa8 */
+ u32 _rx15mask; /* 0xaac */
+ u32 tx_smb[4]; /* 0xab0 */
+ u32 rx_smb0[4]; /* 0xac0 */
+ u32 rx_smb1[4]; /* 0xad0 */
u32 mecr; /* 0xae0 */
u32 erriar; /* 0xae4 */
u32 erridpr; /* 0xae8 */
@@ -250,6 +298,14 @@ struct flexcan_regs {
u32 rerrdr; /* 0xaf4 */
u32 rerrsynr; /* 0xaf8 */
u32 errsr; /* 0xafc */
+ u32 _reserved7[64]; /* 0xb00 */
+ u32 fdctrl; /* 0xc00 */
+ u32 fdcbt; /* 0xc04 */
+ u32 fdcrc; /* 0xc08 */
+ u32 _reserved9[199]; /* 0xc0c */
+ u32 tx_smb_fd[18]; /* 0xf28 */
+ u32 rx_smb0_fd[18]; /* 0xf70 */
+ u32 rx_smb1_fd[18]; /* 0xfb8 */
};
struct flexcan_devtype_data {
@@ -277,9 +333,9 @@ struct flexcan_priv {
u8 mb_size;
u8 clk_src; /* clock source of CAN Protocol Engine */
+ u64 rx_mask;
+ u64 tx_mask;
u32 reg_ctrl_default;
- u32 reg_imask1_default;
- u32 reg_imask2_default;
struct clk *clk_ipg;
struct clk *clk_per;
@@ -287,6 +343,11 @@ struct flexcan_priv {
struct regulator *reg_xceiver;
struct flexcan_stop_mode stm;
+#ifdef CONFIG_IMX_SCU_SOC
+ /* IPC handle when enable stop mode by System Controller firmware(scfw) */
+ struct imx_sc_ipc *sc_ipc_handle;
+#endif
+
/* Read and Write APIs */
u32 (*read)(void __iomem *addr);
void (*write)(u32 val, void __iomem *addr);
@@ -313,17 +374,41 @@ static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
FLEXCAN_QUIRK_SETUP_STOP_MODE,
};
+static struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+ FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+ FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE |
+ FLEXCAN_QUIRK_USE_SCFW,
+};
+
+static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+ FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+ FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE |
+ FLEXCAN_QUIRK_DISABLE_MECR,
+};
+
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
FLEXCAN_QUIRK_BROKEN_PERR_STATE,
};
+static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+ FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
+ FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD,
+};
+
static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
};
+static struct flexcan_devtype_data fsl_s32v234_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR,
+};
+
static const struct can_bittiming_const flexcan_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 4,
@@ -336,6 +421,30 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
.brp_inc = 1,
};
+static const struct can_bittiming_const flexcan_fd_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 96,
+ .tseg2_min = 2,
+ .tseg2_max = 32,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static const struct can_bittiming_const flexcan_fd_data_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 39,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
/* FlexCAN module is essentially modelled as a little-endian IP in most
* SoCs, i.e the registers as well as the message buffer areas are
* implemented in a little-endian fashion.
@@ -431,6 +540,32 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
priv->write(reg_mcr, &regs->mcr);
}
+#ifdef CONFIG_IMX_SCU_SOC
+static void flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
+{
+ struct device_node *np = priv->dev->of_node;
+ u32 rsrc_id, val;
+ int idx;
+
+ idx = of_alias_get_id(np, "can");
+ if (idx == 0)
+ rsrc_id = IMX_SC_R_CAN_0;
+ else if (idx == 1)
+ rsrc_id = IMX_SC_R_CAN_1;
+ else
+ rsrc_id = IMX_SC_R_CAN_2;
+
+ val = enabled ? 1 : 0;
+ /* stop mode request */
+ imx_sc_misc_set_control(priv->sc_ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val);
+}
+#else
+static int flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
+{
+ return 0;
+}
+#endif
+
static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->regs;
@@ -440,9 +575,12 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
reg_mcr |= FLEXCAN_MCR_SLF_WAK;
priv->write(reg_mcr, &regs->mcr);
- /* enable stop request */
- regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
- 1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
+ /* enable stop request */
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
+ flexcan_stop_mode_enable_scfw(priv, true);
+ else
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
return flexcan_low_power_enter_ack(priv);
}
@@ -453,9 +591,11 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
u32 reg_mcr;
/* remove stop request */
- regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
- 1 << priv->stm.req_bit, 0);
-
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
+ flexcan_stop_mode_enable_scfw(priv, false);
+ else
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 0);
reg_mcr = priv->read(&regs->mcr);
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
@@ -635,10 +775,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct can_frame *cf = (struct can_frame *)skb->data;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
u32 can_id;
u32 data;
- u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
+ u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16);
int i;
if (can_dropped_invalid_skb(dev, skb))
@@ -646,18 +786,25 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
netif_stop_queue(dev);
- if (cf->can_id & CAN_EFF_FLAG) {
- can_id = cf->can_id & CAN_EFF_MASK;
+ if (cfd->can_id & CAN_EFF_FLAG) {
+ can_id = cfd->can_id & CAN_EFF_MASK;
ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
} else {
- can_id = (cf->can_id & CAN_SFF_MASK) << 18;
+ can_id = (cfd->can_id & CAN_SFF_MASK) << 18;
}
- if (cf->can_id & CAN_RTR_FLAG)
+ if (cfd->can_id & CAN_RTR_FLAG)
ctrl |= FLEXCAN_MB_CNT_RTR;
- for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
- data = be32_to_cpup((__be32 *)&cf->data[i]);
+ if (can_is_canfd_skb(skb)) {
+ ctrl |= FLEXCAN_MB_CNT_EDL;
+
+ if (cfd->flags & CANFD_BRS)
+ ctrl |= FLEXCAN_MB_CNT_BRS;
+ }
+
+ for (i = 0; i < cfd->len; i += sizeof(u32)) {
+ data = be32_to_cpup((__be32 *)&cfd->data[i]);
priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
}
@@ -751,8 +898,6 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
u32 timestamp;
int err;
- timestamp = priv->read(&regs->timer) << 16;
-
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
@@ -772,6 +917,8 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
if (likely(new_state == priv->can.state))
return;
+ timestamp = priv->read(&regs->timer) << 16;
+
skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb))
return;
@@ -786,21 +933,58 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
dev->stats.rx_fifo_errors++;
}
+static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask)
+{
+ u64 reg = 0;
+
+ if (upper_32_bits(mask))
+ reg = (u64)priv->read(addr - 4) << 32;
+ if (lower_32_bits(mask))
+ reg |= priv->read(addr);
+
+ return reg & mask;
+}
+
+static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr)
+{
+ if (upper_32_bits(val))
+ priv->write(upper_32_bits(val), addr - 4);
+ if (lower_32_bits(val))
+ priv->write(lower_32_bits(val), addr);
+}
+
+static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+{
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
+}
+
+static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
+{
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
+}
+
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
{
return container_of(offload, struct flexcan_priv, offload);
}
-static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
- struct can_frame *cf,
- u32 *timestamp, unsigned int n)
+static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
+ unsigned int n, u32 *timestamp,
+ bool drop)
{
struct flexcan_priv *priv = rx_offload_to_priv(offload);
struct flexcan_regs __iomem *regs = priv->regs;
struct flexcan_mb __iomem *mb;
+ struct sk_buff *skb;
+ struct canfd_frame *cfd;
u32 reg_ctrl, reg_id, reg_iflag1;
int i;
+ if (unlikely(drop)) {
+ skb = ERR_PTR(-ENOBUFS);
+ goto mark_as_read;
+ }
+
mb = flexcan_get_mb(priv, n);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
@@ -814,7 +998,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
(code != FLEXCAN_MB_CODE_RX_OVERRUN))
- return 0;
+ return NULL;
if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
/* This MB was overrun, we lost data */
@@ -824,39 +1008,54 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
} else {
reg_iflag1 = priv->read(&regs->iflag1);
if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE))
- return 0;
+ return NULL;
reg_ctrl = priv->read(&mb->can_ctrl);
}
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
+ skb = alloc_canfd_skb(offload->dev, &cfd);
+ else
+ skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd);
+ if (unlikely(!skb)) {
+ skb = ERR_PTR(-ENOMEM);
+ goto mark_as_read;
+ }
+
/* increase timstamp to full 32 bit */
*timestamp = reg_ctrl << 16;
reg_id = priv->read(&mb->can_id);
if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
- cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
- cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+ cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
+ cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+ cfd->flags |= CANFD_BRS;
+ } else {
+ cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+ cfd->can_id |= CAN_RTR_FLAG;
+ }
- if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
- cf->can_id |= CAN_RTR_FLAG;
- cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+ if (reg_ctrl & FLEXCAN_MB_CNT_ESI)
+ cfd->flags |= CANFD_ESI;
- for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
+ for (i = 0; i < cfd->len; i += sizeof(u32)) {
__be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
- *(__be32 *)(cf->data + i) = data;
+ *(__be32 *)(cfd->data + i) = data;
}
- /* mark as read */
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
- /* Clear IRQ */
- if (n < 32)
- priv->write(BIT(n), &regs->iflag1);
- else
- priv->write(BIT(n - 32), &regs->iflag2);
- } else {
+ mark_as_read:
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
+ flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), &regs->iflag1);
+ else
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
- }
/* Read the Free Running Timer. It is optional but recommended
* to unlock Mailbox as soon as possible and make it available
@@ -864,20 +1063,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
*/
priv->read(&regs->timer);
- return 1;
-}
-
-
-static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
-{
- struct flexcan_regs __iomem *regs = priv->regs;
- u32 iflag1, iflag2;
-
- iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
- ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
- iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
-
- return (u64)iflag2 << 32 | iflag1;
+ return skb;
}
static irqreturn_t flexcan_irq(int irq, void *dev_id)
@@ -887,18 +1073,19 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
irqreturn_t handled = IRQ_NONE;
- u32 reg_iflag2, reg_esr;
+ u64 reg_iflag_tx;
+ u32 reg_esr;
enum can_state last_state = priv->can.state;
/* reception interrupt */
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
- u64 reg_iflag;
+ u64 reg_iflag_rx;
int ret;
- while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) {
+ while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
handled = IRQ_HANDLED;
ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
- reg_iflag);
+ reg_iflag_rx);
if (!ret)
break;
}
@@ -921,10 +1108,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
}
}
- reg_iflag2 = priv->read(&regs->iflag2);
+ reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
/* transmission complete interrupt */
- if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
+ if (reg_iflag_tx & priv->tx_mask) {
u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
handled = IRQ_HANDLED;
@@ -936,12 +1123,18 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
/* after sending a RTR frame MB is in RX mode */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&priv->tx_mb->can_ctrl);
- priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2);
+ flexcan_write64(priv, priv->tx_mask, &regs->iflag1);
netif_wake_queue(dev);
}
reg_esr = priv->read(&regs->esr);
+ /* ACK wakeup interrupt */
+ if (reg_esr & FLEXCAN_ESR_WAK_INT) {
+ handled = IRQ_HANDLED;
+ priv->write(reg_esr & FLEXCAN_ESR_WAK_INT, &regs->esr);
+ }
+
/* ACK all bus error and state change IRQ sources */
if (reg_esr & FLEXCAN_ESR_ALL_INT) {
handled = IRQ_HANDLED;
@@ -1002,27 +1195,14 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
static void flexcan_set_bittiming(struct net_device *dev)
{
- const struct flexcan_priv *priv = netdev_priv(dev);
- const struct can_bittiming *bt = &priv->can.bittiming;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct can_bittiming *dbt = &priv->can.data_bittiming;
struct flexcan_regs __iomem *regs = priv->regs;
- u32 reg;
+ u32 reg, reg_cbt, reg_fdcbt, reg_fdctrl;
reg = priv->read(&regs->ctrl);
- reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
- FLEXCAN_CTRL_RJW(0x3) |
- FLEXCAN_CTRL_PSEG1(0x7) |
- FLEXCAN_CTRL_PSEG2(0x7) |
- FLEXCAN_CTRL_PROPSEG(0x7) |
- FLEXCAN_CTRL_LPB |
- FLEXCAN_CTRL_SMP |
- FLEXCAN_CTRL_LOM);
-
- reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
- FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
- FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
- FLEXCAN_CTRL_RJW(bt->sjw - 1) |
- FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
-
+ reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
reg |= FLEXCAN_CTRL_LPB;
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
@@ -1033,9 +1213,189 @@ static void flexcan_set_bittiming(struct net_device *dev)
netdev_dbg(dev, "writing ctrl=0x%08x\n", reg);
priv->write(reg, &regs->ctrl);
- /* print chip status */
- netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
- priv->read(&regs->mcr), priv->read(&regs->ctrl));
+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+ reg_cbt = priv->read(&regs->cbt);
+ reg_cbt &= ~(FLEXCAN_CBT_EPRESDIV(0x3ff) |
+ FLEXCAN_CBT_EPSEG1(0x1f) |
+ FLEXCAN_CBT_EPSEG2(0x1f) |
+ FLEXCAN_CBT_ERJW(0x1f) |
+ FLEXCAN_CBT_EPROPSEG(0x3f) |
+ FLEXCAN_CBT_BTF);
+
+ /* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit long.
+ * The can_calc_bittiming tries to divide the tseg1 equally
+ * between phase_seg1 and prop_seg, which may not fit in CBT
+ * register. Therefore, if phase_seg1 is more than possible
+ * value, increase prop_seg and decrease phase_seg1
+ */
+ if (bt->phase_seg1 > 0x20) {
+ bt->prop_seg += (bt->phase_seg1 - 0x20);
+ bt->phase_seg1 = 0x20;
+ }
+
+ reg_cbt = FLEXCAN_CBT_EPRESDIV(bt->brp - 1) |
+ FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) |
+ FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1) |
+ FLEXCAN_CBT_ERJW(bt->sjw - 1) |
+ FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) |
+ FLEXCAN_CBT_BTF;
+ priv->write(reg_cbt, &regs->cbt);
+
+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+ bt->sjw - 1, bt->prop_seg - 1);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ reg_fdcbt = priv->read(&regs->fdcbt);
+ reg_fdcbt &= ~(FLEXCAN_FDCBT_FPRESDIV(0x3ff) |
+ FLEXCAN_FDCBT_FPSEG1(0x07) |
+ FLEXCAN_FDCBT_FPSEG2(0x07) |
+ FLEXCAN_FDCBT_FRJW(0x07) |
+ FLEXCAN_FDCBT_FPROPSEG(0x1f));
+
+ /* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is 5 bit long.
+ * The can_calc_bittiming tries to divide the tseg1 equally
+ * between phase_seg1 and prop_seg, which may not fit in FDCBT
+ * register. Therefore, if phase_seg1 is more than possible
+ * value, increase prop_seg and decrease phase_seg1
+ */
+ if (dbt->phase_seg1 > 0x8) {
+ dbt->prop_seg += (dbt->phase_seg1 - 0x8);
+ dbt->phase_seg1 = 0x8;
+ }
+
+ reg_fdcbt = FLEXCAN_FDCBT_FPRESDIV(dbt->brp - 1) |
+ FLEXCAN_FDCBT_FPSEG1(dbt->phase_seg1 - 1) |
+ FLEXCAN_FDCBT_FPSEG2(dbt->phase_seg2 - 1) |
+ FLEXCAN_FDCBT_FRJW(dbt->sjw - 1) |
+ FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg);
+ priv->write(reg_fdcbt, &regs->fdcbt);
+
+ /* enable transceiver delay compensation(TDC) for fd frame.
+ * TDC must be disabled when Loop Back mode is enabled.
+ */
+ reg_fdctrl = priv->read(&regs->fdctrl);
+ if (!(reg & FLEXCAN_CTRL_LPB)) {
+ reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN;
+ reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCOFF(0x1f);
+ /* for the TDC to work reliably, the offset has to use optimal settings */
+ reg_fdctrl |= FLEXCAN_FDCTRL_TDCOFF(((dbt->phase_seg1 - 1) + dbt->prop_seg + 2) *
+ ((dbt->brp -1) + 1));
+ } else {
+ reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN;
+ }
+ priv->write(reg_fdctrl, &regs->fdctrl);
+
+ if (bt->brp != dbt->brp)
+ netdev_warn(dev, "Warning!! data brp = %d and brp = %d don't match.\n"
+ "flexcan may not work. consider using different bitrate or data bitrate\n",
+ dbt->brp, bt->brp);
+
+ netdev_dbg(dev, "fdbt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ dbt->brp - 1, dbt->phase_seg1 - 1, dbt->phase_seg2 - 1,
+ dbt->sjw - 1, dbt->prop_seg);
+
+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n",
+ __func__, priv->read(&regs->mcr),
+ priv->read(&regs->ctrl),
+ priv->read(&regs->cbt),
+ priv->read(&regs->fdcbt));
+ }
+ } else {
+ reg = priv->read(&regs->ctrl);
+ reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+ FLEXCAN_CTRL_RJW(0x3) |
+ FLEXCAN_CTRL_PSEG1(0x7) |
+ FLEXCAN_CTRL_PSEG2(0x7) |
+ FLEXCAN_CTRL_PROPSEG(0x7));
+
+ reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+ FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+ FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+ FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+ FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+ priv->write(reg, &regs->ctrl);
+
+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+ bt->sjw - 1, bt->prop_seg - 1);
+
+ /* print chip status */
+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+ priv->read(&regs->mcr), priv->read(&regs->ctrl));
+ }
+}
+
+static void flexcan_init_ram(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ u32 reg_ctrl2;
+ int i, size;
+
+ /* CTRL2[WRMFRZ] grants write access to all memory positions that
+ * require initialization. MCR[RFEN] must not be set during FlexCAN
+ * memory initialization.
+ */
+ reg_ctrl2 = priv->read(&regs->ctrl2);
+ reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ;
+ priv->write(reg_ctrl2, &regs->ctrl2);
+
+ /* initialize MBs RAM */
+ size = sizeof(regs->mb) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->mb[0][0] + sizeof(u32) * i);
+
+ /* initialize RXIMRs RAM */
+ size = sizeof(regs->rximr) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->rximr[i]);
+
+ /* initialize RXFIRs RAM */
+ size = sizeof(regs->_rxfir) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->_rxfir[i]);
+
+ /* initialize RXMGMASK, RXFGMASK, RX14MASK, RX15MASK RAM */
+ priv->write(0, &regs->_rxmgmask);
+ priv->write(0, &regs->_rxfgmask);
+ priv->write(0, &regs->_rx14mask);
+ priv->write(0, &regs->_rx15mask);
+
+ /* initialize TX_SMB RAM */
+ size = sizeof(regs->tx_smb) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->tx_smb[i]);
+
+ /* initialize RX_SMB0 RAM */
+ size = sizeof(regs->rx_smb0) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->rx_smb0[i]);
+
+ /* initialize RX_SMB1 RAM */
+ size = sizeof(regs->rx_smb1) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->rx_smb1[i]);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ /* initialize TX_SMB_FD RAM */
+ size = sizeof(regs->tx_smb_fd) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->tx_smb_fd[i]);
+
+ /* initialize RX_SMB0_FD RAM */
+ size = sizeof(regs->rx_smb0_fd) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->rx_smb0_fd[i]);
+
+ /* initialize RX_SMB1_FD RAM */
+ size = sizeof(regs->rx_smb1_fd) / sizeof(u32);
+ for (i = 0; i < size; i++)
+ priv->write(0, &regs->rx_smb0_fd[i]);
+ }
+
+ reg_ctrl2 &= ~FLEXCAN_CTRL2_WRMFRZ;
+ priv->write(reg_ctrl2, &regs->ctrl2);
}
/* flexcan_chip_start
@@ -1047,7 +1407,8 @@ static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
- u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
+ u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr, reg_fdctrl;
+ u64 reg_imask;
int err, i;
struct flexcan_mb __iomem *mb;
@@ -1063,6 +1424,9 @@ static int flexcan_chip_start(struct net_device *dev)
flexcan_set_bittiming(dev);
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR)
+ flexcan_init_ram(dev);
+
/* set freeze, halt */
err = flexcan_chip_freeze(priv);
if (err)
@@ -1145,6 +1509,31 @@ static int flexcan_chip_start(struct net_device *dev)
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
priv->write(reg_ctrl, &regs->ctrl);
+ /* FDCTRL */
+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+ reg_fdctrl = priv->read(&regs->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE;
+ reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3));
+ reg_mcr = priv->read(&regs->mcr) & ~FLEXCAN_MCR_FDEN;
+ reg_ctrl2 = priv->read(&regs->ctrl2) & ~FLEXCAN_CTRL2_ISOCANFDEN;
+
+ /* support BRS when set CAN FD mode
+ * 64 bytes payload per MB and 7 MBs per RAM block by default
+ * enable CAN FD mode
+ */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
+ reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3);
+ reg_mcr |= FLEXCAN_MCR_FDEN;
+
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
+ reg_ctrl2 |= FLEXCAN_CTRL2_ISOCANFDEN;
+ }
+
+ priv->write(reg_fdctrl, &regs->fdctrl);
+ priv->write(reg_mcr, &regs->mcr);
+ priv->write(reg_ctrl2, &regs->ctrl2);
+ }
+
if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
reg_ctrl2 = priv->read(&regs->ctrl2);
reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS;
@@ -1186,8 +1575,8 @@ static int flexcan_chip_start(struct net_device *dev)
for (i = 0; i < priv->mb_count; i++)
priv->write(0, &regs->rximr[i]);
- /* On Vybrid, disable memory error detection interrupts
- * and freeze mode.
+ /* On Vybrid, disable non-correctable errors interrupt and freeze
+ * mode. It still can correct the correctable errors when HW supports ECC.
* This also works around errata e5295 which generates
* false positive memory errors and put the device in
* freeze mode.
@@ -1195,19 +1584,32 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) {
/* Follow the protocol as described in "Detection
* and Correction of Memory Errors" to write to
- * MECR register
+ * MECR register (step 1 - 5)
+ * 1. By default, CTRL2[ECRWRE] = 0, MECR[ECRWRDIS] = 1
+ * 2. set CTRL2[ECRWRE]
*/
reg_ctrl2 = priv->read(&regs->ctrl2);
reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE;
priv->write(reg_ctrl2, &regs->ctrl2);
+ /* 3. clear MECR[ECRWRDIS] */
reg_mecr = priv->read(&regs->mecr);
reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
priv->write(reg_mecr, &regs->mecr);
- reg_mecr |= FLEXCAN_MECR_ECCDIS;
+
+ /* 4. all writes to MECR must keep MECR[ECRWRDIS] cleared */
reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
FLEXCAN_MECR_FANCEI_MSK);
priv->write(reg_mecr, &regs->mecr);
+
+ /* 5. after configuration done, lock MECR by either setting
+ * MECR[ECRWRDIS] or clearing CTRL2[ECRWRE]
+ */
+ reg_mecr |= FLEXCAN_MECR_ECRWRDIS;
+ priv->write(reg_mecr, &regs->mecr);
+ reg_ctrl2 &= ~FLEXCAN_CTRL2_ECRWRE;
+ priv->write(reg_ctrl2, &regs->ctrl2);
+
}
/* synchronize with the can bus */
@@ -1220,8 +1622,9 @@ static int flexcan_chip_start(struct net_device *dev)
/* enable interrupts atomically */
disable_irq(dev->irq);
priv->write(priv->reg_ctrl_default, &regs->ctrl);
- priv->write(priv->reg_imask1_default, &regs->imask1);
- priv->write(priv->reg_imask2_default, &regs->imask2);
+ reg_imask = priv->rx_mask | priv->tx_mask;
+ priv->write(upper_32_bits(reg_imask), &regs->imask2);
+ priv->write(lower_32_bits(reg_imask), &regs->imask1);
enable_irq(dev->irq);
/* print chip status */
@@ -1284,6 +1687,12 @@ static int flexcan_open(struct net_device *dev)
struct flexcan_priv *priv = netdev_priv(dev);
int err;
+ if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) &&
+ (priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
+ netdev_err(dev, "three samples mode and fd mode can't be used together\n");
+ return -EINVAL;
+ }
+
err = pm_runtime_get_sync(priv->dev);
if (err < 0) {
pm_runtime_put_noidle(priv->dev);
@@ -1302,7 +1711,11 @@ static int flexcan_open(struct net_device *dev)
if (err)
goto out_transceiver_disable;
- priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
+ else
+ priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
+
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
(sizeof(priv->regs->mb[1]) / priv->mb_size);
@@ -1314,26 +1727,19 @@ static int flexcan_open(struct net_device *dev)
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
priv->tx_mb_idx = priv->mb_count - 1;
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
-
- priv->reg_imask1_default = 0;
- priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+ priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
priv->offload.mailbox_read = flexcan_mailbox_read;
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
- u64 imask;
-
priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
priv->offload.mb_last = priv->mb_count - 2;
- imask = GENMASK_ULL(priv->offload.mb_last,
- priv->offload.mb_first);
- priv->reg_imask1_default |= imask;
- priv->reg_imask2_default |= imask >> 32;
-
+ priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
+ priv->offload.mb_first);
err = can_rx_offload_add_timestamp(dev, &priv->offload);
} else {
- priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+ priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
err = can_rx_offload_add_fifo(dev, &priv->offload,
FLEXCAN_NAPI_WEIGHT);
@@ -1534,11 +1940,6 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit,
priv->stm.ack_gpr, priv->stm.ack_bit);
- device_set_wakeup_capable(&pdev->dev, true);
-
- if (of_property_read_bool(np, "wakeup-source"))
- device_set_wakeup_enable(&pdev->dev, true);
-
return 0;
out_put_node:
@@ -1546,7 +1947,33 @@ out_put_node:
return ret;
}
+#ifdef CONFIG_IMX_SCU_SOC
+static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct flexcan_priv *priv;
+ int ret;
+
+ priv = netdev_priv(dev);
+
+ ret = imx_scu_get_handle(&(priv->sc_ipc_handle));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "get ipc handle used by SCU failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
static const struct of_device_id flexcan_of_match[] = {
+ { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
+ { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
{ .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
@@ -1555,6 +1982,9 @@ static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
{ .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
{ .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
+ { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
+ { .compatible = "fsl,s32v234-flexcan",
+ .data = &fsl_s32v234_devtype_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, flexcan_of_match);
@@ -1572,7 +2002,6 @@ static int flexcan_probe(struct platform_device *pdev)
struct net_device *dev;
struct flexcan_priv *priv;
struct regulator *reg_xceiver;
- struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
struct flexcan_regs __iomem *regs;
int err, irq;
@@ -1607,12 +2036,11 @@ static int flexcan_probe(struct platform_device *pdev)
clock_freq = clk_get_rate(clk_per);
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return -ENODEV;
- regs = devm_ioremap_resource(&pdev->dev, mem);
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
@@ -1663,6 +2091,18 @@ static int flexcan_probe(struct platform_device *pdev)
priv->devtype_data = devtype_data;
priv->reg_xceiver = reg_xceiver;
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO;
+ priv->can.bittiming_const = &flexcan_fd_bittiming_const;
+ priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
+ } else {
+ dev_err(&pdev->dev, "can fd mode can't work on fifo mode\n");
+ err = -EINVAL;
+ goto failed_register;
+ }
+ }
+
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -1676,9 +2116,19 @@ static int flexcan_probe(struct platform_device *pdev)
devm_can_led_init(dev);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
- err = flexcan_setup_stop_mode(pdev);
- if (err)
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
+ err = flexcan_setup_stop_mode_scfw(pdev);
+ else
+ err = flexcan_setup_stop_mode(pdev);
+
+ if (err) {
dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
+ } else {
+ device_set_wakeup_capable(&pdev->dev, true);
+
+ if (of_property_read_bool(pdev->dev.of_node, "wakeup-source"))
+ device_set_wakeup_enable(&pdev->dev, true);
+ }
}
return 0;
@@ -1705,7 +2155,7 @@ static int __maybe_unused flexcan_suspend(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
- int err = 0;
+ int err;
if (netif_running(dev)) {
/* if wakeup is enabled, enter stop mode
@@ -1717,23 +2167,27 @@ static int __maybe_unused flexcan_suspend(struct device *device)
if (err)
return err;
} else {
- err = flexcan_chip_disable(priv);
+ flexcan_chip_stop(dev);
+
+ err = pm_runtime_force_suspend(device);
if (err)
return err;
+
+ pinctrl_pm_select_sleep_state(device);
}
netif_stop_queue(dev);
netif_device_detach(dev);
}
priv->can.state = CAN_STATE_SLEEPING;
- return err;
+ return 0;
}
static int __maybe_unused flexcan_resume(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
- int err = 0;
+ int err;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(dev)) {
@@ -1745,11 +2199,19 @@ static int __maybe_unused flexcan_resume(struct device *device)
if (err)
return err;
} else {
- err = flexcan_chip_enable(priv);
+ pinctrl_pm_select_default_state(device);
+
+ err = pm_runtime_force_resume(device);
+ if (err)
+ return err;
+
+ err = flexcan_chip_start(dev);
+ if (err)
+ return err;
}
}
- return err;
+ return 0;
}
static int __maybe_unused flexcan_runtime_suspend(struct device *device)
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 685e12b05a7c..c7667645f04a 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfig"
source "drivers/net/dsa/mv88e6xxx/Kconfig"
+source "drivers/net/dsa/ocelot/Kconfig"
+
source "drivers/net/dsa/sja1105/Kconfig"
config NET_DSA_QCA8K
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index ae70b79628d6..9d384a32b3a2 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -20,4 +20,5 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
obj-y += b53/
obj-y += microchip/
obj-y += mv88e6xxx/
+obj-y += ocelot/
obj-y += sja1105/
diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig
new file mode 100644
index 000000000000..7c9ad0d6d7db
--- /dev/null
+++ b/drivers/net/dsa/ocelot/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config NET_DSA_MSCC_FELIX
+ tristate "Ocelot / Felix Ethernet switch support"
+ depends on NET_DSA && PCI
+ depends on NET_VENDOR_MICROSEMI
+ depends on NET_VENDOR_FREESCALE
+ select MSCC_OCELOT_SWITCH
+ select NET_DSA_TAG_OCELOT
+ select FSL_ENETC_MDIO
+ help
+ This driver supports the VSC9959 network switch, which is a member of
+ the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
+ It is embedded as a PCIe function of the NXP LS1028A ENETC integrated
+ endpoint.
+
+config MSCC_FELIX_SWITCH_TSN
+ tristate "TSN on FELIX switch driver"
+ depends on NET_DSA_MSCC_FELIX
+ depends on TSN
+ help
+ This driver supports TSN on felix switch.
+
diff --git a/drivers/net/dsa/ocelot/Makefile b/drivers/net/dsa/ocelot/Makefile
new file mode 100644
index 000000000000..c8db4cd0b0f7
--- /dev/null
+++ b/drivers/net/dsa/ocelot/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
+
+mscc_felix-objs := \
+ felix.o \
+ felix_vsc9959.o
+
+obj-$(CONFIG_MSCC_FELIX_SWITCH_TSN) += felix_tsn.o
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
new file mode 100644
index 000000000000..e4c17074a0d2
--- /dev/null
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -0,0 +1,812 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2019 NXP Semiconductors
+ */
+#include <uapi/linux/if_bridge.h>
+#include <soc/mscc/ocelot_qsys.h>
+#include <soc/mscc/ocelot_sys.h>
+#include <soc/mscc/ocelot_dev.h>
+#include <soc/mscc/ocelot_ana.h>
+#include <soc/mscc/ocelot.h>
+#include <linux/packing.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/pci.h>
+#include <linux/of.h>
+#include <net/dsa.h>
+#include "felix.h"
+#include "felix_tsn.h"
+
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
+const struct tsn_ops switch_tsn_ops = {
+ .device_init = felix_tsn_init,
+ .get_capability = felix_tsn_get_cap,
+ .qbv_set = felix_qbv_set,
+ .qbv_get = felix_qbv_get,
+ .qbv_get_status = felix_qbv_get_status,
+ .qbu_set = felix_qbu_set,
+ .qbu_get = felix_qbu_get,
+ .cb_streamid_set = felix_cb_streamid_set,
+ .cb_streamid_get = felix_cb_streamid_get,
+ .cb_streamid_counters_get = felix_cb_streamid_counters_get,
+ .qci_sfi_set = felix_qci_sfi_set,
+ .qci_sfi_get = felix_qci_sfi_get,
+ .qci_sfi_counters_get = felix_qci_sfi_counters_get,
+ .qci_get_maxcap = felix_qci_max_cap_get,
+ .qci_sgi_set = felix_qci_sgi_set,
+ .qci_sgi_get = felix_qci_sgi_get,
+ .qci_sgi_status_get = felix_qci_sgi_status_get,
+ .qci_fmi_set = felix_qci_fmi_set,
+ .qci_fmi_get = felix_qci_fmi_get,
+ .cbs_set = felix_cbs_set,
+ .cbs_get = felix_cbs_get,
+ .ct_set = felix_cut_thru_set,
+ .cbgen_set = felix_seq_gen_set,
+ .cbrec_set = felix_seq_rec_set,
+ .cb_get = felix_cb_get,
+ .dscp_set = felix_dscp_set,
+};
+#endif
+
+static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
+ int port)
+{
+ return DSA_TAG_PROTO_OCELOT;
+}
+
+static int felix_set_ageing_time(struct dsa_switch *ds,
+ unsigned int ageing_time)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_set_ageing_time(ocelot, ageing_time);
+
+ return 0;
+}
+
+static int felix_fdb_dump(struct dsa_switch *ds, int port,
+ dsa_fdb_dump_cb_t *cb, void *data)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_fdb_dump(ocelot, port, cb, data);
+}
+
+static int felix_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct ocelot *ocelot = ds->priv;
+ bool vlan_aware;
+
+ vlan_aware = dsa_port_is_vlan_filtering(dsa_to_port(ds, port));
+
+ return ocelot_fdb_add(ocelot, port, addr, vid, vlan_aware);
+}
+
+static int felix_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_fdb_del(ocelot, port, addr, vid);
+}
+
+static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port,
+ u8 state)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_bridge_stp_state_set(ocelot, port, state);
+}
+
+static int felix_bridge_join(struct dsa_switch *ds, int port,
+ struct net_device *br)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_port_bridge_join(ocelot, port, br);
+}
+
+static void felix_bridge_leave(struct dsa_switch *ds, int port,
+ struct net_device *br)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_bridge_leave(ocelot, port, br);
+}
+
+/* This callback needs to be present */
+static int felix_vlan_prepare(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ return 0;
+}
+
+static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_vlan_filtering(ocelot, port, enabled);
+
+ return 0;
+}
+
+static void felix_vlan_add(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ struct ocelot *ocelot = ds->priv;
+ u16 vid;
+ int err;
+
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ err = ocelot_vlan_add(ocelot, port, vid,
+ vlan->flags & BRIDGE_VLAN_INFO_PVID,
+ vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+ if (err) {
+ dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n",
+ vid, port, err);
+ return;
+ }
+ }
+}
+
+static int felix_vlan_del(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ struct ocelot *ocelot = ds->priv;
+ u16 vid;
+ int err;
+
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ err = ocelot_vlan_del(ocelot, port, vid);
+ if (err) {
+ dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n",
+ vid, port, err);
+ return err;
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
+static int felix_tsn_enable(struct dsa_port *dp)
+{
+ struct net_device *dev;
+
+ if (dp->type == DSA_PORT_TYPE_USER) {
+ dev = dp->slave;
+ tsn_port_register(dev,
+ (struct tsn_ops *)&switch_tsn_ops,
+ GROUP_OFFSET_SWITCH);
+ }
+ return 0;
+}
+#endif
+
+static int felix_port_enable(struct dsa_switch *ds, int port,
+ struct phy_device *phy)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_port_enable(ocelot, port, phy);
+
+ return 0;
+}
+
+static void felix_port_disable(struct dsa_switch *ds, int port)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_port_disable(ocelot, port);
+}
+
+static void felix_phylink_validate(struct dsa_switch *ds, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ if (state->interface != PHY_INTERFACE_MODE_NA &&
+ state->interface != ocelot_port->phy_mode) {
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ return;
+ }
+
+ /* No half-duplex. */
+ phylink_set_port_modes(mask);
+ phylink_set(mask, Autoneg);
+ phylink_set(mask, Pause);
+ phylink_set(mask, Asym_Pause);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Full);
+ phylink_set(mask, 1000baseT_Full);
+
+ /* The internal ports that run at 2.5G are overclocked GMII */
+ if (state->interface == PHY_INTERFACE_MODE_GMII ||
+ state->interface == PHY_INTERFACE_MODE_2500BASEX ||
+ state->interface == PHY_INTERFACE_MODE_USXGMII) {
+ phylink_set(mask, 2500baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ }
+
+ bitmap_and(supported, supported, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
+ struct phylink_link_state *state)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ if (felix->info->pcs_link_state)
+ felix->info->pcs_link_state(ocelot, port, state);
+
+ return 0;
+}
+
+static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct felix *felix = ocelot_to_felix(ocelot);
+ u32 mac_fc_cfg;
+
+ /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and
+ * PORT_RST bits in CLOCK_CFG
+ */
+ ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed),
+ DEV_CLOCK_CFG);
+
+ /* Flow control. Link speed is only used here to evaluate the time
+ * specification in incoming pause frames.
+ */
+ mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed);
+
+ /* handle Rx pause in all cases, with 2500base-X this is used for rate
+ * adaptation.
+ */
+ mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
+
+ if (state->pause & MLO_PAUSE_TX)
+ mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
+ SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
+ SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+ SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
+ ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
+
+ ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+
+ if (felix->info->pcs_init)
+ felix->info->pcs_init(ocelot, port, link_an_mode, state);
+}
+
+static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ if (felix->info->pcs_an_restart)
+ felix->info->pcs_an_restart(ocelot, port);
+}
+
+static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int link_an_mode,
+ phy_interface_t interface)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
+ ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+ QSYS_SWITCH_PORT_MODE, port);
+}
+
+static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int link_an_mode,
+ phy_interface_t interface,
+ struct phy_device *phydev)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ /* Enable MAC module */
+ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
+ DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
+
+ /* Enable receiving frames on the port, and activate auto-learning of
+ * MAC addresses.
+ */
+ ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
+ ANA_PORT_PORT_CFG_RECV_ENA |
+ ANA_PORT_PORT_CFG_PORTID_VAL(port),
+ ANA_PORT_PORT_CFG, port);
+
+ /* Core: Enable port for frame transfer */
+ ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
+ QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
+ QSYS_SWITCH_PORT_MODE_PORT_ENA,
+ QSYS_SWITCH_PORT_MODE, port);
+}
+
+static void felix_get_strings(struct dsa_switch *ds, int port,
+ u32 stringset, u8 *data)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_get_strings(ocelot, port, stringset, data);
+}
+
+static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ ocelot_get_ethtool_stats(ocelot, port, data);
+}
+
+static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_get_sset_count(ocelot, port, sset);
+}
+
+static int felix_get_ts_info(struct dsa_switch *ds, int port,
+ struct ethtool_ts_info *info)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_get_ts_info(ocelot, port, info);
+}
+
+static int felix_parse_ports_node(struct felix *felix,
+ struct device_node *ports_node,
+ phy_interface_t *port_phy_modes)
+{
+ struct ocelot *ocelot = &felix->ocelot;
+ struct device *dev = felix->ocelot.dev;
+ struct device_node *child;
+
+ for_each_available_child_of_node(ports_node, child) {
+ phy_interface_t phy_mode;
+ u32 port;
+ int err;
+
+ /* Get switch port number from DT */
+ if (of_property_read_u32(child, "reg", &port) < 0) {
+ dev_err(dev, "Port number not defined in device tree "
+ "(property \"reg\")\n");
+ of_node_put(child);
+ return -ENODEV;
+ }
+
+ /* Get PHY mode from DT */
+ err = of_get_phy_mode(child);
+ if (err < 0) {
+ dev_err(dev, "Failed to read phy-mode or "
+ "phy-interface-type property for port %d\n",
+ port);
+ of_node_put(child);
+ return -ENODEV;
+ }
+
+ phy_mode = err;
+
+ err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode);
+ if (err < 0) {
+ dev_err(dev, "Unsupported PHY mode %s on port %d\n",
+ phy_modes(phy_mode), port);
+ return err;
+ }
+
+ port_phy_modes[port] = phy_mode;
+ }
+
+ return 0;
+}
+
+static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
+{
+ struct device *dev = felix->ocelot.dev;
+ struct device_node *switch_node;
+ struct device_node *ports_node;
+ int err;
+
+ switch_node = dev->of_node;
+
+ ports_node = of_get_child_by_name(switch_node, "ports");
+ if (!ports_node) {
+ dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
+ return -ENODEV;
+ }
+
+ err = felix_parse_ports_node(felix, ports_node, port_phy_modes);
+ of_node_put(ports_node);
+
+ return err;
+}
+
+static int felix_init_structs(struct felix *felix, int num_phys_ports)
+{
+ struct ocelot *ocelot = &felix->ocelot;
+ phy_interface_t *port_phy_modes;
+ resource_size_t switch_base;
+ int port, i, err;
+
+ ocelot->num_phys_ports = num_phys_ports;
+ ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports,
+ sizeof(struct ocelot_port *), GFP_KERNEL);
+ if (!ocelot->ports)
+ return -ENOMEM;
+
+ ocelot->map = felix->info->map;
+ ocelot->stats_layout = felix->info->stats_layout;
+ ocelot->num_stats = felix->info->num_stats;
+ ocelot->shared_queue_sz = felix->info->shared_queue_sz;
+ ocelot->ops = felix->info->ops;
+
+ port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
+ GFP_KERNEL);
+ if (!port_phy_modes)
+ return -ENOMEM;
+
+ err = felix_parse_dt(felix, port_phy_modes);
+ if (err) {
+ kfree(port_phy_modes);
+ return err;
+ }
+
+ switch_base = pci_resource_start(felix->pdev,
+ felix->info->switch_pci_bar);
+
+ for (i = 0; i < TARGET_MAX; i++) {
+ struct regmap *target;
+ struct resource *res;
+
+ if (!felix->info->target_io_res[i].name)
+ continue;
+
+ res = &felix->info->target_io_res[i];
+ res->flags = IORESOURCE_MEM;
+ res->start += switch_base;
+ res->end += switch_base;
+
+ target = ocelot_regmap_init(ocelot, res);
+ if (IS_ERR(target)) {
+ dev_err(ocelot->dev,
+ "Failed to map device memory space\n");
+ kfree(port_phy_modes);
+ return PTR_ERR(target);
+ }
+
+ ocelot->targets[i] = target;
+ }
+
+ err = ocelot_regfields_init(ocelot, felix->info->regfields);
+ if (err) {
+ dev_err(ocelot->dev, "failed to init reg fields map\n");
+ kfree(port_phy_modes);
+ return err;
+ }
+
+ for (port = 0; port < num_phys_ports; port++) {
+ struct ocelot_port *ocelot_port;
+ void __iomem *port_regs;
+ struct resource *res;
+
+ ocelot_port = devm_kzalloc(ocelot->dev,
+ sizeof(struct ocelot_port),
+ GFP_KERNEL);
+ if (!ocelot_port) {
+ dev_err(ocelot->dev,
+ "failed to allocate port memory\n");
+ kfree(port_phy_modes);
+ return -ENOMEM;
+ }
+
+ res = &felix->info->port_io_res[port];
+ res->flags = IORESOURCE_MEM;
+ res->start += switch_base;
+ res->end += switch_base;
+
+ port_regs = devm_ioremap_resource(ocelot->dev, res);
+ if (IS_ERR(port_regs)) {
+ dev_err(ocelot->dev,
+ "failed to map registers for port %d\n", port);
+ kfree(port_phy_modes);
+ return PTR_ERR(port_regs);
+ }
+
+ ocelot_port->phy_mode = port_phy_modes[port];
+ ocelot_port->ocelot = ocelot;
+ ocelot_port->regs = port_regs;
+ ocelot->ports[port] = ocelot_port;
+ }
+
+ kfree(port_phy_modes);
+
+ if (felix->info->mdio_bus_alloc) {
+ err = felix->info->mdio_bus_alloc(ocelot);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Hardware initialization done here so that we can allocate structures with
+ * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
+ * us to allocate structures twice (leak memory) and map PCI memory twice
+ * (which will not work).
+ */
+static int felix_setup(struct dsa_switch *ds)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+ int port, err;
+
+ err = felix_init_structs(felix, ds->num_ports);
+ if (err)
+ return err;
+
+ ocelot_init(ocelot);
+
+ for (port = 0; port < ds->num_ports; port++) {
+ ocelot_init_port(ocelot, port);
+
+ if (dsa_is_cpu_port(ds, port))
+ ocelot_set_cpu_port(ocelot, port,
+ OCELOT_TAG_PREFIX_NONE,
+ OCELOT_TAG_PREFIX_LONG);
+ }
+
+ /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040)
+ * isn't instantiated for the Felix PF.
+ * In-band AN may take a few ms to complete, so we need to poll.
+ */
+ ds->pcs_poll = true;
+
+ return 0;
+}
+
+static void felix_teardown(struct dsa_switch *ds)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ if (felix->info->mdio_bus_free)
+ felix->info->mdio_bus_free(ocelot);
+
+ /* stop workqueue thread */
+ ocelot_deinit(ocelot);
+}
+
+static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_hwstamp_get(ocelot, port, ifr);
+}
+
+static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct ocelot *ocelot = ds->priv;
+
+ return ocelot_hwstamp_set(ocelot, port, ifr);
+}
+
+static bool felix_rxtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct ocelot *ocelot = ds->priv;
+ u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
+ u32 tstamp_lo, tstamp_hi;
+ struct timespec64 ts;
+ u64 tstamp, val;
+
+ ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
+ tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+
+ packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0);
+ tstamp_lo = (u32)val;
+
+ tstamp_hi = tstamp >> 32;
+ if ((tstamp & 0xffffffff) < tstamp_lo)
+ tstamp_hi--;
+
+ tstamp = ((u64)tstamp_hi << 32) | tstamp_lo;
+
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = tstamp;
+ return false;
+}
+
+bool felix_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *clone, unsigned int type)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone))
+ return true;
+
+ return false;
+}
+
+static const struct dsa_switch_ops felix_switch_ops = {
+ .get_tag_protocol = felix_get_tag_protocol,
+ .setup = felix_setup,
+ .teardown = felix_teardown,
+ .set_ageing_time = felix_set_ageing_time,
+ .get_strings = felix_get_strings,
+ .get_ethtool_stats = felix_get_ethtool_stats,
+ .get_sset_count = felix_get_sset_count,
+ .get_ts_info = felix_get_ts_info,
+ .phylink_validate = felix_phylink_validate,
+ .phylink_mac_link_state = felix_phylink_mac_pcs_get_state,
+ .phylink_mac_config = felix_phylink_mac_config,
+ .phylink_mac_an_restart = felix_phylink_mac_an_restart,
+ .phylink_mac_link_down = felix_phylink_mac_link_down,
+ .phylink_mac_link_up = felix_phylink_mac_link_up,
+ .port_enable = felix_port_enable,
+ .port_disable = felix_port_disable,
+ .port_fdb_dump = felix_fdb_dump,
+ .port_fdb_add = felix_fdb_add,
+ .port_fdb_del = felix_fdb_del,
+ .port_bridge_join = felix_bridge_join,
+ .port_bridge_leave = felix_bridge_leave,
+ .port_stp_state_set = felix_bridge_stp_state_set,
+ .port_vlan_prepare = felix_vlan_prepare,
+ .port_vlan_filtering = felix_vlan_filtering,
+ .port_vlan_add = felix_vlan_add,
+ .port_vlan_del = felix_vlan_del,
+ .port_hwtstamp_get = felix_hwtstamp_get,
+ .port_hwtstamp_set = felix_hwtstamp_set,
+ .port_rxtstamp = felix_rxtstamp,
+ .port_txtstamp = felix_txtstamp,
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
+ .port_tsn_enable = felix_tsn_enable,
+#endif
+};
+
+static struct felix_info *felix_instance_tbl[] = {
+ [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959,
+};
+
+static irqreturn_t felix_irq_handler(int irq, void *data)
+{
+ struct ocelot *ocelot = (struct ocelot *)data;
+
+ /* The INTB interrupt is used for both PTP TX timestamp interrupt
+ * and preemption status change interrupt on each port.
+ */
+
+ ocelot_preempt_irq_clean(ocelot);
+ ocelot_get_txtstamp(ocelot);
+
+ return IRQ_HANDLED;
+}
+
+static int felix_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ enum felix_instance instance = id->driver_data;
+ struct dsa_switch *ds;
+ struct ocelot *ocelot;
+ struct felix *felix;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "device enable failed\n");
+ goto err_pci_enable;
+ }
+
+ /* set up for high or low dma */
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev,
+ "DMA configuration failed: 0x%x\n", err);
+ goto err_dma;
+ }
+ }
+
+ felix = devm_kzalloc(&pdev->dev, sizeof(*felix), GFP_KERNEL);
+ if (!felix) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to allocate driver memory\n");
+ goto err_alloc_felix;
+ }
+
+ pci_set_drvdata(pdev, felix);
+ ocelot = &felix->ocelot;
+ ocelot->dev = &pdev->dev;
+ felix->pdev = pdev;
+ felix->info = felix_instance_tbl[instance];
+
+ pci_set_master(pdev);
+
+ err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL,
+ &felix_irq_handler, IRQF_ONESHOT,
+ "felix-intb", ocelot);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to request irq\n");
+ goto err_alloc_irq;
+ }
+
+ ocelot->ptp = 1;
+
+ ds = dsa_switch_alloc(&pdev->dev, felix->info->num_ports);
+ if (!ds) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to allocate DSA switch\n");
+ goto err_alloc_ds;
+ }
+
+ ds->dev = &pdev->dev;
+ ds->num_ports = felix->info->num_ports;
+ ds->ops = &felix_switch_ops;
+ ds->priv = ocelot;
+ felix->ds = ds;
+
+ err = dsa_register_switch(ds);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err);
+ goto err_register_ds;
+ }
+
+ return 0;
+
+err_register_ds:
+err_alloc_ds:
+err_alloc_irq:
+err_alloc_felix:
+err_dma:
+ pci_disable_device(pdev);
+err_pci_enable:
+ return err;
+}
+
+static void felix_pci_remove(struct pci_dev *pdev)
+{
+ struct felix *felix;
+
+ felix = pci_get_drvdata(pdev);
+
+ dsa_unregister_switch(felix->ds);
+
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id felix_ids[] = {
+ {
+ /* NXP LS1028A */
+ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0),
+ .driver_data = FELIX_INSTANCE_VSC9959,
+ },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, felix_ids);
+
+static struct pci_driver felix_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = felix_ids,
+ .probe = felix_pci_probe,
+ .remove = felix_pci_remove,
+};
+
+module_pci_driver(felix_pci_driver);
+
+MODULE_DESCRIPTION("Felix Switch driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
new file mode 100644
index 000000000000..3a7580015b62
--- /dev/null
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2019 NXP Semiconductors
+ */
+#ifndef _MSCC_FELIX_H
+#define _MSCC_FELIX_H
+
+#define ocelot_to_felix(o) container_of((o), struct felix, ocelot)
+
+/* Platform-specific information */
+struct felix_info {
+ struct resource *target_io_res;
+ struct resource *port_io_res;
+ struct resource *imdio_res;
+ const struct reg_field *regfields;
+ const u32 *const *map;
+ const struct ocelot_ops *ops;
+ int shared_queue_sz;
+ const struct ocelot_stat_layout *stats_layout;
+ unsigned int num_stats;
+ int num_ports;
+ int switch_pci_bar;
+ int imdio_pci_bar;
+ int (*mdio_bus_alloc)(struct ocelot *ocelot);
+ void (*mdio_bus_free)(struct ocelot *ocelot);
+ void (*pcs_init)(struct ocelot *ocelot, int port,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state);
+ void (*pcs_an_restart)(struct ocelot *ocelot, int port);
+ void (*pcs_link_state)(struct ocelot *ocelot, int port,
+ struct phylink_link_state *state);
+ int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port,
+ phy_interface_t phy_mode);
+};
+
+extern struct felix_info felix_info_vsc9959;
+
+enum felix_instance {
+ FELIX_INSTANCE_VSC9959 = 0,
+};
+
+/* DSA glue / front-end for struct ocelot */
+struct felix {
+ struct dsa_switch *ds;
+ struct pci_dev *pdev;
+ struct felix_info *info;
+ struct ocelot ocelot;
+ struct mii_bus *imdio;
+ struct phy_device **pcs;
+};
+
+#endif
diff --git a/drivers/net/dsa/ocelot/felix_tsn.c b/drivers/net/dsa/ocelot/felix_tsn.c
new file mode 100644
index 000000000000..2e446a165f13
--- /dev/null
+++ b/drivers/net/dsa/ocelot/felix_tsn.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Felix Switch TSN driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <soc/mscc/ocelot.h>
+#include <net/tsn.h>
+#include "felix.h"
+
+static struct ocelot *felix_dev_to_ocelot(struct net_device *ndev)
+{
+ struct pci_dev *pdev;
+ struct felix *felix;
+
+ pdev = list_entry(ndev->dev.parent, struct pci_dev, dev);
+ felix = pci_get_drvdata(pdev);
+ if (!felix)
+ return NULL;
+
+ return &felix->ocelot;
+}
+
+static int felix_dev_to_port(struct net_device *ndev, struct ocelot *ocelot)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct dsa_switch *ds = felix->ds;
+ struct dsa_port *dp;
+ int i;
+
+ for (i = 0; i < ds->num_ports; i++) {
+ dp = &ds->ports[i];
+ if (dp->dn == ndev->dev.of_node)
+ return dp->index;
+ }
+
+ return -ENODEV;
+}
+
+u32 felix_tsn_get_cap(struct net_device *ndev)
+{
+ u32 cap = 0;
+
+ cap = (TSN_CAP_QBV | TSN_CAP_QCI | TSN_CAP_QBU | TSN_CAP_CBS |
+ TSN_CAP_CB | TSN_CAP_TBS | TSN_CAP_CTH);
+
+ return cap;
+}
+
+int felix_qbv_set(struct net_device *ndev,
+ struct tsn_qbv_conf *shaper_config)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qbv_set(ocelot, port, shaper_config);
+}
+
+int felix_qbv_get(struct net_device *ndev,
+ struct tsn_qbv_conf *shaper_config)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qbv_get(ocelot, port, shaper_config);
+}
+
+int felix_qbv_get_status(struct net_device *ndev,
+ struct tsn_qbv_status *qbvstatus)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qbv_get_status(ocelot, port, qbvstatus);
+}
+
+int felix_qbu_set(struct net_device *ndev, u8 preemptible)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qbu_set(ocelot, port, preemptible);
+}
+
+int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qbu_get(ocelot, port, c);
+}
+
+int felix_cb_streamid_set(struct net_device *ndev, u32 index, bool enable,
+ struct tsn_cb_streamid *streamid)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cb_streamid_set(ocelot, port, index, enable, streamid);
+}
+
+int felix_cb_streamid_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid *streamid)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cb_streamid_get(ocelot, port, index, streamid);
+}
+
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid_counters *sc)
+{
+ return 0;
+}
+
+int felix_qci_sfi_set(struct net_device *ndev, u32 index, bool enable,
+ struct tsn_qci_psfp_sfi_conf *sfi)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sfi_set(ocelot, port, index, enable, sfi);
+}
+
+int felix_qci_sfi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_conf *sfi)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sfi_get(ocelot, port, index, sfi);
+}
+
+int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_counters *sfi_cnt)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sfi_counters_get(ocelot, port, index, sfi_cnt);
+}
+
+int felix_qci_max_cap_get(struct net_device *ndev,
+ struct tsn_qci_psfp_stream_param *stream_para)
+{
+ struct ocelot *ocelot;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+
+ return ocelot_qci_max_cap_get(ocelot, stream_para);
+}
+
+int felix_qci_sgi_set(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sgi_set(ocelot, port, index, sgi_conf);
+}
+
+int felix_qci_sgi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sgi_get(ocelot, port, index, sgi_conf);
+}
+
+int felix_qci_sgi_status_get(struct net_device *ndev, u32 index,
+ struct tsn_psfp_sgi_status *sgi_status)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_sgi_status_get(ocelot, port, index, sgi_status);
+}
+
+int felix_qci_fmi_set(struct net_device *ndev, u32 index,
+ bool enable, struct tsn_qci_psfp_fmi *fmi)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_fmi_set(ocelot, port, index, enable, fmi);
+}
+
+int felix_qci_fmi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_fmi *fmi,
+ struct tsn_qci_psfp_fmi_counters *counters)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_qci_fmi_get(ocelot, port, index, fmi, counters);
+}
+
+int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cbs_set(ocelot, port, tc, bw);
+}
+
+int felix_cbs_get(struct net_device *ndev, u8 tc)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cbs_get(ocelot, port, tc);
+}
+
+int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cut_thru_set(ocelot, port, cut_thru);
+}
+
+int felix_seq_gen_set(struct net_device *ndev, u32 index,
+ struct tsn_seq_gen_conf *sg_conf)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_seq_gen_set(ocelot, port, index, sg_conf);
+}
+
+int felix_seq_rec_set(struct net_device *ndev, u32 index,
+ struct tsn_seq_rec_conf *sr_conf)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_seq_rec_set(ocelot, port, index, sr_conf);
+}
+
+int felix_cb_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_status *c)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_cb_get(ocelot, port, index, c);
+}
+
+int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
+ struct tsn_qos_switch_dscp_conf *c)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return -ENODEV;
+ port = felix_dev_to_port(ndev, ocelot);
+ if (port < 0)
+ return -ENODEV;
+
+ return ocelot_dscp_set(ocelot, port, enable, dscp_ix, c);
+}
+
+void felix_tsn_init(struct net_device *ndev)
+{
+ struct ocelot *ocelot;
+ int port;
+
+ ocelot = felix_dev_to_ocelot(ndev);
+ if (!ocelot)
+ return;
+ port = felix_dev_to_port(ndev, ocelot);
+
+ ocelot_pcp_map_enable(ocelot, port);
+ ocelot_rtag_parse_enable(ocelot, port);
+}
diff --git a/drivers/net/dsa/ocelot/felix_tsn.h b/drivers/net/dsa/ocelot/felix_tsn.h
new file mode 100644
index 000000000000..f5d8a0defea7
--- /dev/null
+++ b/drivers/net/dsa/ocelot/felix_tsn.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * TSN_SWITCH driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#ifndef _MSCC_FELIX_SWITCH_TSN_H_
+#define _MSCC_FELIX_SWITCH_TSN_H_
+#include <net/tsn.h>
+
+u32 felix_tsn_get_cap(struct net_device *ndev);
+int felix_qbv_set(struct net_device *ndev,
+ struct tsn_qbv_conf *shaper_config);
+int felix_qbv_get(struct net_device *ndev,
+ struct tsn_qbv_conf *shaper_config);
+int felix_qbv_get_status(struct net_device *ndev,
+ struct tsn_qbv_status *qbvstatus);
+int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru);
+int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw);
+int felix_cbs_get(struct net_device *ndev, u8 tc);
+int felix_qbu_set(struct net_device *ndev, u8 preemptible);
+int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c);
+int felix_cb_streamid_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid *streamid);
+int felix_cb_streamid_set(struct net_device *ndev, u32 index,
+ bool enable, struct tsn_cb_streamid *streamid);
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid_counters *sc);
+int felix_qci_sfi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_conf *sfi);
+int felix_qci_sfi_set(struct net_device *ndev, u32 index,
+ bool enable, struct tsn_qci_psfp_sfi_conf *sfi);
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid_counters *s_counters);
+int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_counters *sfi_counters);
+int felix_qci_max_cap_get(struct net_device *ndev,
+ struct tsn_qci_psfp_stream_param *stream_para);
+int felix_qci_sgi_set(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf);
+int felix_qci_sgi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf);
+int felix_qci_sgi_status_get(struct net_device *ndev, u16 index,
+ struct tsn_psfp_sgi_status *sgi_status);
+int felix_qci_fmi_set(struct net_device *ndev, u32 index,
+ bool enable, struct tsn_qci_psfp_fmi *fmi);
+int felix_qci_fmi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_fmi *fmi,
+ struct tsn_qci_psfp_fmi_counters *counters);
+int felix_seq_gen_set(struct net_device *ndev, u32 index,
+ struct tsn_seq_gen_conf *sg_conf);
+int felix_seq_rec_set(struct net_device *ndev, u32 index,
+ struct tsn_seq_rec_conf *sr_conf);
+int felix_cb_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_status *c);
+int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
+ struct tsn_qos_switch_dscp_conf *c);
+
+void felix_tsn_init(struct net_device *ndev);
+#endif
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
new file mode 100644
index 000000000000..7ab976f75430
--- /dev/null
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -0,0 +1,1100 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright 2017 Microsemi Corporation
+ * Copyright 2018-2019 NXP Semiconductors
+ */
+#include <linux/fsl/enetc_mdio.h>
+#include <soc/mscc/ocelot_sys.h>
+#include <soc/mscc/ocelot.h>
+#include <linux/iopoll.h>
+#include <linux/pci.h>
+#include "felix.h"
+
+/* TODO: should find a better place for these */
+#define USXGMII_BMCR_RESET BIT(15)
+#define USXGMII_BMCR_AN_EN BIT(12)
+#define USXGMII_BMCR_RST_AN BIT(9)
+#define USXGMII_BMSR_LNKS(status) (((status) & GENMASK(2, 2)) >> 2)
+#define USXGMII_BMSR_AN_CMPL(status) (((status) & GENMASK(5, 5)) >> 5)
+#define USXGMII_ADVERTISE_LNKS(x) (((x) << 15) & BIT(15))
+#define USXGMII_ADVERTISE_FDX BIT(12)
+#define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9))
+#define USXGMII_LPA_LNKS(lpa) ((lpa) >> 15)
+#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12)
+#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9)
+
+enum usxgmii_speed {
+ USXGMII_SPEED_10 = 0,
+ USXGMII_SPEED_100 = 1,
+ USXGMII_SPEED_1000 = 2,
+ USXGMII_SPEED_2500 = 4,
+};
+
+static const u32 vsc9959_ana_regmap[] = {
+ REG(ANA_ADVLEARN, 0x0089a0),
+ REG(ANA_VLANMASK, 0x0089a4),
+ REG_RESERVED(ANA_PORT_B_DOMAIN),
+ REG(ANA_ANAGEFIL, 0x0089ac),
+ REG(ANA_ANEVENTS, 0x0089b0),
+ REG(ANA_STORMLIMIT_BURST, 0x0089b4),
+ REG(ANA_STORMLIMIT_CFG, 0x0089b8),
+ REG(ANA_ISOLATED_PORTS, 0x0089c8),
+ REG(ANA_COMMUNITY_PORTS, 0x0089cc),
+ REG(ANA_AUTOAGE, 0x0089d0),
+ REG(ANA_MACTOPTIONS, 0x0089d4),
+ REG(ANA_LEARNDISC, 0x0089d8),
+ REG(ANA_AGENCTRL, 0x0089dc),
+ REG(ANA_MIRRORPORTS, 0x0089e0),
+ REG(ANA_EMIRRORPORTS, 0x0089e4),
+ REG(ANA_FLOODING, 0x0089e8),
+ REG(ANA_FLOODING_IPMC, 0x008a08),
+ REG(ANA_SFLOW_CFG, 0x008a0c),
+ REG(ANA_PORT_MODE, 0x008a28),
+ REG(ANA_CUT_THRU_CFG, 0x008a48),
+ REG(ANA_PGID_PGID, 0x008400),
+ REG(ANA_TABLES_ANMOVED, 0x007f1c),
+ REG(ANA_TABLES_MACHDATA, 0x007f20),
+ REG(ANA_TABLES_MACLDATA, 0x007f24),
+ REG(ANA_TABLES_STREAMDATA, 0x007f28),
+ REG(ANA_TABLES_MACACCESS, 0x007f2c),
+ REG(ANA_TABLES_MACTINDX, 0x007f30),
+ REG(ANA_TABLES_VLANACCESS, 0x007f34),
+ REG(ANA_TABLES_VLANTIDX, 0x007f38),
+ REG(ANA_TABLES_ISDXACCESS, 0x007f3c),
+ REG(ANA_TABLES_ISDXTIDX, 0x007f40),
+ REG(ANA_TABLES_ENTRYLIM, 0x007f00),
+ REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44),
+ REG(ANA_TABLES_PTP_ID_LOW, 0x007f48),
+ REG(ANA_TABLES_STREAMACCESS, 0x007f4c),
+ REG(ANA_TABLES_STREAMTIDX, 0x007f50),
+ REG(ANA_TABLES_SEQ_HISTORY, 0x007f54),
+ REG(ANA_TABLES_SEQ_MASK, 0x007f58),
+ REG(ANA_TABLES_SFID_MASK, 0x007f5c),
+ REG(ANA_TABLES_SFIDACCESS, 0x007f60),
+ REG(ANA_TABLES_SFIDTIDX, 0x007f64),
+ REG(ANA_MSTI_STATE, 0x008600),
+ REG(ANA_OAM_UPM_LM_CNT, 0x008000),
+ REG(ANA_SG_ACCESS_CTRL, 0x008a64),
+ REG(ANA_SG_CONFIG_REG_1, 0x007fb0),
+ REG(ANA_SG_CONFIG_REG_2, 0x007fb4),
+ REG(ANA_SG_CONFIG_REG_3, 0x007fb8),
+ REG(ANA_SG_CONFIG_REG_4, 0x007fbc),
+ REG(ANA_SG_CONFIG_REG_5, 0x007fc0),
+ REG(ANA_SG_GCL_GS_CONFIG, 0x007f80),
+ REG(ANA_SG_GCL_TI_CONFIG, 0x007f90),
+ REG(ANA_SG_STATUS_REG_1, 0x008980),
+ REG(ANA_SG_STATUS_REG_2, 0x008984),
+ REG(ANA_SG_STATUS_REG_3, 0x008988),
+ REG(ANA_PORT_VLAN_CFG, 0x007800),
+ REG(ANA_PORT_DROP_CFG, 0x007804),
+ REG(ANA_PORT_QOS_CFG, 0x007808),
+ REG(ANA_PORT_VCAP_CFG, 0x00780c),
+ REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810),
+ REG(ANA_PORT_VCAP_S2_CFG, 0x00781c),
+ REG(ANA_PORT_PCP_DEI_MAP, 0x007820),
+ REG(ANA_PORT_CPU_FWD_CFG, 0x007860),
+ REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864),
+ REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868),
+ REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c),
+ REG(ANA_PORT_PORT_CFG, 0x007870),
+ REG(ANA_PORT_POL_CFG, 0x007874),
+ REG(ANA_PORT_PTP_CFG, 0x007878),
+ REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c),
+ REG(ANA_PORT_PTP_DLY2_CFG, 0x007880),
+ REG(ANA_PORT_SFID_CFG, 0x007884),
+ REG(ANA_PFC_PFC_CFG, 0x008800),
+ REG_RESERVED(ANA_PFC_PFC_TIMER),
+ REG_RESERVED(ANA_IPT_OAM_MEP_CFG),
+ REG_RESERVED(ANA_IPT_IPT),
+ REG_RESERVED(ANA_PPT_PPT),
+ REG_RESERVED(ANA_FID_MAP_FID_MAP),
+ REG(ANA_AGGR_CFG, 0x008a68),
+ REG(ANA_CPUQ_CFG, 0x008a6c),
+ REG_RESERVED(ANA_CPUQ_CFG2),
+ REG(ANA_CPUQ_8021_CFG, 0x008a74),
+ REG(ANA_DSCP_CFG, 0x008ab4),
+ REG(ANA_DSCP_REWR_CFG, 0x008bb4),
+ REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4),
+ REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14),
+ REG_RESERVED(ANA_VRAP_CFG),
+ REG_RESERVED(ANA_VRAP_HDR_DATA),
+ REG_RESERVED(ANA_VRAP_HDR_MASK),
+ REG(ANA_DISCARD_CFG, 0x008c40),
+ REG(ANA_FID_CFG, 0x008c44),
+ REG(ANA_POL_PIR_CFG, 0x004000),
+ REG(ANA_POL_CIR_CFG, 0x004004),
+ REG(ANA_POL_MODE_CFG, 0x004008),
+ REG(ANA_POL_PIR_STATE, 0x00400c),
+ REG(ANA_POL_CIR_STATE, 0x004010),
+ REG_RESERVED(ANA_POL_STATE),
+ REG(ANA_POL_FLOWC, 0x008c48),
+ REG(ANA_POL_HYST, 0x008cb4),
+ REG_RESERVED(ANA_POL_MISC_CFG),
+};
+
+static const u32 vsc9959_qs_regmap[] = {
+ REG(QS_XTR_GRP_CFG, 0x000000),
+ REG(QS_XTR_RD, 0x000008),
+ REG(QS_XTR_FRM_PRUNING, 0x000010),
+ REG(QS_XTR_FLUSH, 0x000018),
+ REG(QS_XTR_DATA_PRESENT, 0x00001c),
+ REG(QS_XTR_CFG, 0x000020),
+ REG(QS_INJ_GRP_CFG, 0x000024),
+ REG(QS_INJ_WR, 0x00002c),
+ REG(QS_INJ_CTRL, 0x000034),
+ REG(QS_INJ_STATUS, 0x00003c),
+ REG(QS_INJ_ERR, 0x000040),
+ REG_RESERVED(QS_INH_DBG),
+};
+
+static const u32 vsc9959_s2_regmap[] = {
+ REG(S2_CORE_UPDATE_CTRL, 0x000000),
+ REG(S2_CORE_MV_CFG, 0x000004),
+ REG(S2_CACHE_ENTRY_DAT, 0x000008),
+ REG(S2_CACHE_MASK_DAT, 0x000108),
+ REG(S2_CACHE_ACTION_DAT, 0x000208),
+ REG(S2_CACHE_CNT_DAT, 0x000308),
+ REG(S2_CACHE_TG_DAT, 0x000388),
+};
+
+static const u32 vsc9959_qsys_regmap[] = {
+ REG(QSYS_PORT_MODE, 0x00f460),
+ REG(QSYS_SWITCH_PORT_MODE, 0x00f480),
+ REG(QSYS_STAT_CNT_CFG, 0x00f49c),
+ REG(QSYS_EEE_CFG, 0x00f4a0),
+ REG(QSYS_EEE_THRES, 0x00f4b8),
+ REG(QSYS_IGR_NO_SHARING, 0x00f4bc),
+ REG(QSYS_EGR_NO_SHARING, 0x00f4c0),
+ REG(QSYS_SW_STATUS, 0x00f4c4),
+ REG(QSYS_EXT_CPU_CFG, 0x00f4e0),
+ REG_RESERVED(QSYS_PAD_CFG),
+ REG(QSYS_CPU_GROUP_MAP, 0x00f4e8),
+ REG_RESERVED(QSYS_QMAP),
+ REG_RESERVED(QSYS_ISDX_SGRP),
+ REG_RESERVED(QSYS_TIMED_FRAME_ENTRY),
+ REG(QSYS_TFRM_MISC, 0x00f50c),
+ REG(QSYS_TFRM_PORT_DLY, 0x00f510),
+ REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514),
+ REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518),
+ REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c),
+ REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520),
+ REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524),
+ REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528),
+ REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c),
+ REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530),
+ REG(QSYS_RED_PROFILE, 0x00f534),
+ REG(QSYS_RES_QOS_MODE, 0x00f574),
+ REG(QSYS_RES_CFG, 0x00c000),
+ REG(QSYS_RES_STAT, 0x00c004),
+ REG(QSYS_EGR_DROP_MODE, 0x00f578),
+ REG(QSYS_EQ_CTRL, 0x00f57c),
+ REG_RESERVED(QSYS_EVENTS_CORE),
+ REG(QSYS_QMAXSDU_CFG_0, 0x00f584),
+ REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0),
+ REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc),
+ REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8),
+ REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4),
+ REG(QSYS_QMAXSDU_CFG_5, 0x00f610),
+ REG(QSYS_QMAXSDU_CFG_6, 0x00f62c),
+ REG(QSYS_QMAXSDU_CFG_7, 0x00f648),
+ REG(QSYS_PREEMPTION_CFG, 0x00f664),
+ REG(QSYS_CIR_CFG, 0x000000),
+ REG(QSYS_EIR_CFG, 0x000004),
+ REG(QSYS_SE_CFG, 0x000008),
+ REG(QSYS_SE_DWRR_CFG, 0x00000c),
+ REG_RESERVED(QSYS_SE_CONNECT),
+ REG(QSYS_SE_DLB_SENSE, 0x000040),
+ REG(QSYS_CIR_STATE, 0x000044),
+ REG(QSYS_EIR_STATE, 0x000048),
+ REG_RESERVED(QSYS_SE_STATE),
+ REG(QSYS_HSCH_MISC_CFG, 0x00f67c),
+ REG(QSYS_TAG_CONFIG, 0x00f680),
+ REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698),
+ REG(QSYS_PORT_MAX_SDU, 0x00f69c),
+ REG(QSYS_PARAM_CFG_REG_1, 0x00f440),
+ REG(QSYS_PARAM_CFG_REG_2, 0x00f444),
+ REG(QSYS_PARAM_CFG_REG_3, 0x00f448),
+ REG(QSYS_PARAM_CFG_REG_4, 0x00f44c),
+ REG(QSYS_PARAM_CFG_REG_5, 0x00f450),
+ REG(QSYS_GCL_CFG_REG_1, 0x00f454),
+ REG(QSYS_GCL_CFG_REG_2, 0x00f458),
+ REG(QSYS_PARAM_STATUS_REG_1, 0x00f400),
+ REG(QSYS_PARAM_STATUS_REG_2, 0x00f404),
+ REG(QSYS_PARAM_STATUS_REG_3, 0x00f408),
+ REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c),
+ REG(QSYS_PARAM_STATUS_REG_5, 0x00f410),
+ REG(QSYS_PARAM_STATUS_REG_6, 0x00f414),
+ REG(QSYS_PARAM_STATUS_REG_7, 0x00f418),
+ REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c),
+ REG(QSYS_PARAM_STATUS_REG_9, 0x00f420),
+ REG(QSYS_GCL_STATUS_REG_1, 0x00f424),
+ REG(QSYS_GCL_STATUS_REG_2, 0x00f428),
+};
+
+static const u32 vsc9959_rew_regmap[] = {
+ REG(REW_PORT_VLAN_CFG, 0x000000),
+ REG(REW_TAG_CFG, 0x000004),
+ REG(REW_PORT_CFG, 0x000008),
+ REG(REW_DSCP_CFG, 0x00000c),
+ REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010),
+ REG(REW_PTP_CFG, 0x000050),
+ REG(REW_PTP_DLY1_CFG, 0x000054),
+ REG(REW_RED_TAG_CFG, 0x000058),
+ REG(REW_DSCP_REMAP_DP1_CFG, 0x000410),
+ REG(REW_DSCP_REMAP_CFG, 0x000510),
+ REG_RESERVED(REW_STAT_CFG),
+ REG_RESERVED(REW_REW_STICKY),
+ REG_RESERVED(REW_PPT),
+};
+
+static const u32 vsc9959_sys_regmap[] = {
+ REG(SYS_COUNT_RX_OCTETS, 0x000000),
+ REG(SYS_COUNT_RX_MULTICAST, 0x000008),
+ REG(SYS_COUNT_RX_SHORTS, 0x000010),
+ REG(SYS_COUNT_RX_FRAGMENTS, 0x000014),
+ REG(SYS_COUNT_RX_JABBERS, 0x000018),
+ REG(SYS_COUNT_RX_64, 0x000024),
+ REG(SYS_COUNT_RX_65_127, 0x000028),
+ REG(SYS_COUNT_RX_128_255, 0x00002c),
+ REG(SYS_COUNT_RX_256_1023, 0x000030),
+ REG(SYS_COUNT_RX_1024_1526, 0x000034),
+ REG(SYS_COUNT_RX_1527_MAX, 0x000038),
+ REG(SYS_COUNT_RX_LONGS, 0x000044),
+ REG(SYS_COUNT_TX_OCTETS, 0x000200),
+ REG(SYS_COUNT_TX_COLLISION, 0x000210),
+ REG(SYS_COUNT_TX_DROPS, 0x000214),
+ REG(SYS_COUNT_TX_64, 0x00021c),
+ REG(SYS_COUNT_TX_65_127, 0x000220),
+ REG(SYS_COUNT_TX_128_511, 0x000224),
+ REG(SYS_COUNT_TX_512_1023, 0x000228),
+ REG(SYS_COUNT_TX_1024_1526, 0x00022c),
+ REG(SYS_COUNT_TX_1527_MAX, 0x000230),
+ REG(SYS_COUNT_TX_AGING, 0x000278),
+ REG(SYS_RESET_CFG, 0x000e00),
+ REG(SYS_SR_ETYPE_CFG, 0x000e04),
+ REG(SYS_VLAN_ETYPE_CFG, 0x000e08),
+ REG(SYS_PORT_MODE, 0x000e0c),
+ REG(SYS_FRONT_PORT_MODE, 0x000e2c),
+ REG(SYS_FRM_AGING, 0x000e44),
+ REG(SYS_STAT_CFG, 0x000e48),
+ REG(SYS_SW_STATUS, 0x000e4c),
+ REG_RESERVED(SYS_MISC_CFG),
+ REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c),
+ REG(SYS_REW_MAC_LOW_CFG, 0x000e84),
+ REG(SYS_TIMESTAMP_OFFSET, 0x000e9c),
+ REG(SYS_PAUSE_CFG, 0x000ea0),
+ REG(SYS_PAUSE_TOT_CFG, 0x000ebc),
+ REG(SYS_ATOP, 0x000ec0),
+ REG(SYS_ATOP_TOT_CFG, 0x000edc),
+ REG(SYS_MAC_FC_CFG, 0x000ee0),
+ REG(SYS_MMGT, 0x000ef8),
+ REG_RESERVED(SYS_MMGT_FAST),
+ REG_RESERVED(SYS_EVENTS_DIF),
+ REG_RESERVED(SYS_EVENTS_CORE),
+ REG(SYS_CNT, 0x000000),
+ REG(SYS_PTP_STATUS, 0x000f14),
+ REG(SYS_PTP_TXSTAMP, 0x000f18),
+ REG(SYS_PTP_NXT, 0x000f1c),
+ REG(SYS_PTP_CFG, 0x000f20),
+ REG(SYS_RAM_INIT, 0x000f24),
+ REG_RESERVED(SYS_CM_ADDR),
+ REG_RESERVED(SYS_CM_DATA_WR),
+ REG_RESERVED(SYS_CM_DATA_RD),
+ REG_RESERVED(SYS_CM_OP),
+ REG_RESERVED(SYS_CM_DATA),
+};
+
+static const u32 vsc9959_ptp_regmap[] = {
+ REG(PTP_PIN_CFG, 0x000000),
+ REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
+ REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
+ REG(PTP_PIN_TOD_NSEC, 0x00000c),
+ REG(PTP_CFG_MISC, 0x0000a0),
+ REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
+ REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
+ REG(PTP_CUR_NSF, 0x0000bc),
+ REG(PTP_CUR_NSEC, 0x0000c0),
+ REG(PTP_CUR_SEC_LSB, 0x0000c4),
+ REG(PTP_CUR_SEC_MSB, 0x0000c8),
+};
+
+static const u32 vsc9959_gcb_regmap[] = {
+ REG(GCB_SOFT_RST, 0x000004),
+};
+
+static const u32 *vsc9959_regmap[] = {
+ [ANA] = vsc9959_ana_regmap,
+ [QS] = vsc9959_qs_regmap,
+ [QSYS] = vsc9959_qsys_regmap,
+ [REW] = vsc9959_rew_regmap,
+ [SYS] = vsc9959_sys_regmap,
+ [S2] = vsc9959_s2_regmap,
+ [PTP] = vsc9959_ptp_regmap,
+ [GCB] = vsc9959_gcb_regmap,
+};
+
+/* Addresses are relative to the PCI device's base address and
+ * will be fixed up at ioremap time.
+ */
+static struct resource vsc9959_target_io_res[] = {
+ [ANA] = {
+ .start = 0x0280000,
+ .end = 0x028ffff,
+ .name = "ana",
+ },
+ [QS] = {
+ .start = 0x0080000,
+ .end = 0x00800ff,
+ .name = "qs",
+ },
+ [QSYS] = {
+ .start = 0x0200000,
+ .end = 0x021ffff,
+ .name = "qsys",
+ },
+ [REW] = {
+ .start = 0x0030000,
+ .end = 0x003ffff,
+ .name = "rew",
+ },
+ [SYS] = {
+ .start = 0x0010000,
+ .end = 0x001ffff,
+ .name = "sys",
+ },
+ [S2] = {
+ .start = 0x0060000,
+ .end = 0x00603ff,
+ .name = "s2",
+ },
+ [PTP] = {
+ .start = 0x0090000,
+ .end = 0x00900cb,
+ .name = "ptp",
+ },
+ [GCB] = {
+ .start = 0x0070000,
+ .end = 0x00701ff,
+ .name = "devcpu_gcb",
+ },
+};
+
+static struct resource vsc9959_port_io_res[] = {
+ {
+ .start = 0x0100000,
+ .end = 0x010ffff,
+ .name = "port0",
+ },
+ {
+ .start = 0x0110000,
+ .end = 0x011ffff,
+ .name = "port1",
+ },
+ {
+ .start = 0x0120000,
+ .end = 0x012ffff,
+ .name = "port2",
+ },
+ {
+ .start = 0x0130000,
+ .end = 0x013ffff,
+ .name = "port3",
+ },
+ {
+ .start = 0x0140000,
+ .end = 0x014ffff,
+ .name = "port4",
+ },
+ {
+ .start = 0x0150000,
+ .end = 0x015ffff,
+ .name = "port5",
+ },
+};
+
+/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
+ * SGMII/QSGMII MAC PCS can be found.
+ */
+static struct resource vsc9959_imdio_res = {
+ .start = 0x8030,
+ .end = 0x8040,
+ .name = "imdio",
+};
+
+static const struct reg_field vsc9959_regfields[] = {
+ [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
+ [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
+ [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30),
+ [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26),
+ [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24),
+ [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23),
+ [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22),
+ [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21),
+ [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20),
+ [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19),
+ [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18),
+ [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17),
+ [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15),
+ [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14),
+ [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13),
+ [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12),
+ [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11),
+ [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10),
+ [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9),
+ [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8),
+ [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7),
+ [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6),
+ [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5),
+ [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4),
+ [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3),
+ [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2),
+ [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1),
+ [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0),
+ [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16),
+ [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12),
+ [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10),
+ [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0),
+ [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0),
+};
+
+static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
+ { .offset = 0x00, .name = "rx_octets", },
+ { .offset = 0x01, .name = "rx_unicast", },
+ { .offset = 0x02, .name = "rx_multicast", },
+ { .offset = 0x03, .name = "rx_broadcast", },
+ { .offset = 0x04, .name = "rx_shorts", },
+ { .offset = 0x05, .name = "rx_fragments", },
+ { .offset = 0x06, .name = "rx_jabbers", },
+ { .offset = 0x07, .name = "rx_crc_align_errs", },
+ { .offset = 0x08, .name = "rx_sym_errs", },
+ { .offset = 0x09, .name = "rx_frames_below_65_octets", },
+ { .offset = 0x0A, .name = "rx_frames_65_to_127_octets", },
+ { .offset = 0x0B, .name = "rx_frames_128_to_255_octets", },
+ { .offset = 0x0C, .name = "rx_frames_256_to_511_octets", },
+ { .offset = 0x0D, .name = "rx_frames_512_to_1023_octets", },
+ { .offset = 0x0E, .name = "rx_frames_1024_to_1526_octets", },
+ { .offset = 0x0F, .name = "rx_frames_over_1526_octets", },
+ { .offset = 0x10, .name = "rx_pause", },
+ { .offset = 0x11, .name = "rx_control", },
+ { .offset = 0x12, .name = "rx_longs", },
+ { .offset = 0x13, .name = "rx_classified_drops", },
+ { .offset = 0x14, .name = "rx_red_prio_0", },
+ { .offset = 0x15, .name = "rx_red_prio_1", },
+ { .offset = 0x16, .name = "rx_red_prio_2", },
+ { .offset = 0x17, .name = "rx_red_prio_3", },
+ { .offset = 0x18, .name = "rx_red_prio_4", },
+ { .offset = 0x19, .name = "rx_red_prio_5", },
+ { .offset = 0x1A, .name = "rx_red_prio_6", },
+ { .offset = 0x1B, .name = "rx_red_prio_7", },
+ { .offset = 0x1C, .name = "rx_yellow_prio_0", },
+ { .offset = 0x1D, .name = "rx_yellow_prio_1", },
+ { .offset = 0x1E, .name = "rx_yellow_prio_2", },
+ { .offset = 0x1F, .name = "rx_yellow_prio_3", },
+ { .offset = 0x20, .name = "rx_yellow_prio_4", },
+ { .offset = 0x21, .name = "rx_yellow_prio_5", },
+ { .offset = 0x22, .name = "rx_yellow_prio_6", },
+ { .offset = 0x23, .name = "rx_yellow_prio_7", },
+ { .offset = 0x24, .name = "rx_green_prio_0", },
+ { .offset = 0x25, .name = "rx_green_prio_1", },
+ { .offset = 0x26, .name = "rx_green_prio_2", },
+ { .offset = 0x27, .name = "rx_green_prio_3", },
+ { .offset = 0x28, .name = "rx_green_prio_4", },
+ { .offset = 0x29, .name = "rx_green_prio_5", },
+ { .offset = 0x2A, .name = "rx_green_prio_6", },
+ { .offset = 0x2B, .name = "rx_green_prio_7", },
+ { .offset = 0x80, .name = "tx_octets", },
+ { .offset = 0x81, .name = "tx_unicast", },
+ { .offset = 0x82, .name = "tx_multicast", },
+ { .offset = 0x83, .name = "tx_broadcast", },
+ { .offset = 0x84, .name = "tx_collision", },
+ { .offset = 0x85, .name = "tx_drops", },
+ { .offset = 0x86, .name = "tx_pause", },
+ { .offset = 0x87, .name = "tx_frames_below_65_octets", },
+ { .offset = 0x88, .name = "tx_frames_65_to_127_octets", },
+ { .offset = 0x89, .name = "tx_frames_128_255_octets", },
+ { .offset = 0x8B, .name = "tx_frames_256_511_octets", },
+ { .offset = 0x8C, .name = "tx_frames_1024_1526_octets", },
+ { .offset = 0x8D, .name = "tx_frames_over_1526_octets", },
+ { .offset = 0x8E, .name = "tx_yellow_prio_0", },
+ { .offset = 0x8F, .name = "tx_yellow_prio_1", },
+ { .offset = 0x90, .name = "tx_yellow_prio_2", },
+ { .offset = 0x91, .name = "tx_yellow_prio_3", },
+ { .offset = 0x92, .name = "tx_yellow_prio_4", },
+ { .offset = 0x93, .name = "tx_yellow_prio_5", },
+ { .offset = 0x94, .name = "tx_yellow_prio_6", },
+ { .offset = 0x95, .name = "tx_yellow_prio_7", },
+ { .offset = 0x96, .name = "tx_green_prio_0", },
+ { .offset = 0x97, .name = "tx_green_prio_1", },
+ { .offset = 0x98, .name = "tx_green_prio_2", },
+ { .offset = 0x99, .name = "tx_green_prio_3", },
+ { .offset = 0x9A, .name = "tx_green_prio_4", },
+ { .offset = 0x9B, .name = "tx_green_prio_5", },
+ { .offset = 0x9C, .name = "tx_green_prio_6", },
+ { .offset = 0x9D, .name = "tx_green_prio_7", },
+ { .offset = 0x9E, .name = "tx_aged", },
+ { .offset = 0x100, .name = "drop_local", },
+ { .offset = 0x101, .name = "drop_tail", },
+ { .offset = 0x102, .name = "drop_yellow_prio_0", },
+ { .offset = 0x103, .name = "drop_yellow_prio_1", },
+ { .offset = 0x104, .name = "drop_yellow_prio_2", },
+ { .offset = 0x105, .name = "drop_yellow_prio_3", },
+ { .offset = 0x106, .name = "drop_yellow_prio_4", },
+ { .offset = 0x107, .name = "drop_yellow_prio_5", },
+ { .offset = 0x108, .name = "drop_yellow_prio_6", },
+ { .offset = 0x109, .name = "drop_yellow_prio_7", },
+ { .offset = 0x10A, .name = "drop_green_prio_0", },
+ { .offset = 0x10B, .name = "drop_green_prio_1", },
+ { .offset = 0x10C, .name = "drop_green_prio_2", },
+ { .offset = 0x10D, .name = "drop_green_prio_3", },
+ { .offset = 0x10E, .name = "drop_green_prio_4", },
+ { .offset = 0x10F, .name = "drop_green_prio_5", },
+ { .offset = 0x110, .name = "drop_green_prio_6", },
+ { .offset = 0x111, .name = "drop_green_prio_7", },
+};
+
+#define VSC9959_INIT_TIMEOUT 50000
+#define VSC9959_GCB_RST_SLEEP 100
+#define VSC9959_SYS_RAMINIT_SLEEP 80
+
+static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot)
+{
+ int val;
+
+ regmap_field_read(ocelot->regfields[GCB_SOFT_RST_SWC_RST], &val);
+
+ return val;
+}
+
+static int vsc9959_sys_ram_init_status(struct ocelot *ocelot)
+{
+ return ocelot_read(ocelot, SYS_RAM_INIT);
+}
+
+static int vsc9959_reset(struct ocelot *ocelot)
+{
+ int val, err;
+
+ /* soft-reset the switch core */
+ regmap_field_write(ocelot->regfields[GCB_SOFT_RST_SWC_RST], 1);
+
+ err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val,
+ VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT);
+ if (err) {
+ dev_err(ocelot->dev, "timeout: switch core reset\n");
+ return err;
+ }
+
+ /* initialize switch mem ~40us */
+ ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT);
+ err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val,
+ VSC9959_SYS_RAMINIT_SLEEP,
+ VSC9959_INIT_TIMEOUT);
+ if (err) {
+ dev_err(ocelot->dev, "timeout: switch sram init\n");
+ return err;
+ }
+
+ /* enable switch core */
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
+
+ return 0;
+}
+
+static void vsc9959_pcs_an_restart_sgmii(struct phy_device *pcs)
+{
+ phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
+}
+
+static void vsc9959_pcs_an_restart_usxgmii(struct phy_device *pcs)
+{
+ phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR,
+ USXGMII_BMCR_RESET |
+ USXGMII_BMCR_AN_EN |
+ USXGMII_BMCR_RST_AN);
+}
+
+static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct phy_device *pcs = felix->pcs[port];
+
+ if (!pcs)
+ return;
+
+ switch (pcs->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ vsc9959_pcs_an_restart_sgmii(pcs);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ vsc9959_pcs_an_restart_usxgmii(pcs);
+ break;
+ default:
+ dev_err(ocelot->dev, "Invalid PCS interface type %s\n",
+ phy_modes(pcs->interface));
+ break;
+ }
+}
+
+/* We enable SGMII AN only when the PHY has managed = "in-band-status" in the
+ * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed
+ * into the PCS, which is retrieved out-of-band over MDIO. This also has the
+ * benefit of working with SGMII fixed-links, like downstream switches, where
+ * both link partners attempt to operate as AN slaves and therefore AN never
+ * completes. But it also has the disadvantage that some PHY chips don't pass
+ * traffic if SGMII AN is enabled but not completed (acknowledged by us), so
+ * setting MLO_AN_INBAND is actually required for those.
+ */
+static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ int bmsr, bmcr;
+
+ if (link_an_mode == MLO_AN_INBAND) {
+ /* Some PHYs like VSC8234 don't like it when AN restarts on
+ * their system side and they restart line side AN too, going
+ * into an endless link up/down loop. Don't restart PCS AN if
+ * link is up already.
+ * We do check that AN is enabled just in case this is the 1st
+ * call, PCS detects a carrier but AN is disabled from power on
+ * or by boot loader.
+ */
+ bmcr = phy_read(pcs, MII_BMCR);
+ bmsr = phy_read(pcs, MII_BMSR);
+ if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_LSTATUS))
+ return;
+
+ /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
+ * for the MAC PCS in order to acknowledge the AN.
+ */
+ phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII |
+ ADVERTISE_LPACK);
+
+ phy_write(pcs, ENETC_PCS_IF_MODE,
+ ENETC_PCS_IF_MODE_SGMII_EN |
+ ENETC_PCS_IF_MODE_USE_SGMII_AN);
+
+ /* Adjust link timer for SGMII */
+ phy_write(pcs, ENETC_PCS_LINK_TIMER1,
+ ENETC_PCS_LINK_TIMER1_VAL);
+ phy_write(pcs, ENETC_PCS_LINK_TIMER2,
+ ENETC_PCS_LINK_TIMER2_VAL);
+
+ phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE);
+ } else {
+ int speed;
+
+ if (state->duplex == DUPLEX_HALF) {
+ phydev_err(pcs, "Half duplex not supported\n");
+ return;
+ }
+ switch (state->speed) {
+ case SPEED_1000:
+ speed = ENETC_PCS_SPEED_1000;
+ break;
+ case SPEED_100:
+ speed = ENETC_PCS_SPEED_100;
+ break;
+ case SPEED_10:
+ speed = ENETC_PCS_SPEED_10;
+ break;
+ case SPEED_UNKNOWN:
+ /* Silently don't do anything */
+ return;
+ default:
+ phydev_err(pcs, "Invalid PCS speed %d\n", state->speed);
+ return;
+ }
+
+ phy_write(pcs, ENETC_PCS_IF_MODE,
+ ENETC_PCS_IF_MODE_SGMII_EN |
+ ENETC_PCS_IF_MODE_SGMII_SPEED(speed));
+
+ /* Yes, not a mistake: speed is given by IF_MODE. */
+ phy_write(pcs, MII_BMCR, BMCR_RESET |
+ BMCR_SPEED1000 |
+ BMCR_FULLDPLX);
+ }
+}
+
+/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
+ * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
+ * auto-negotiation of any link parameters. Electrically it is compatible with
+ * a single lane of XAUI.
+ * The hardware reference manual wants to call this mode SGMII, but it isn't
+ * really, since the fundamental features of SGMII:
+ * - Downgrading the link speed by duplicating symbols
+ * - Auto-negotiation
+ * are not there.
+ * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers
+ * because the clock frequency is actually given by a PLL configured in the
+ * Reset Configuration Word (RCW).
+ * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
+ * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
+ * lower link speed on line side, the system-side interface remains fixed at
+ * 2500 Mbps and we do rate adaptation through pause frames.
+ */
+static void vsc9959_pcs_init_2500basex(struct phy_device *pcs,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ if (link_an_mode == MLO_AN_INBAND) {
+ phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n");
+ return;
+ }
+
+ phy_write(pcs, ENETC_PCS_IF_MODE,
+ ENETC_PCS_IF_MODE_SGMII_EN |
+ ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500));
+
+ phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
+ BMCR_FULLDPLX |
+ BMCR_RESET);
+}
+
+static void vsc9959_pcs_init_usxgmii(struct phy_device *pcs,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ if (link_an_mode != MLO_AN_INBAND) {
+ phydev_err(pcs, "USXGMII only supports in-band AN for now\n");
+ return;
+ }
+
+ /* Configure device ability for the USXGMII Replicator */
+ phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
+ USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) |
+ USXGMII_ADVERTISE_LNKS(1) |
+ ADVERTISE_SGMII |
+ ADVERTISE_LPACK |
+ USXGMII_ADVERTISE_FDX);
+}
+
+static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct phy_device *pcs = felix->pcs[port];
+
+ if (!pcs)
+ return;
+
+ /* The PCS does not implement the BMSR register fully, so capability
+ * detection via genphy_read_abilities does not work. Since we can get
+ * the PHY config word from the LPA register though, there is still
+ * value in using the generic phy_resolve_aneg_linkmode function. So
+ * populate the supported and advertising link modes manually here.
+ */
+ linkmode_set_bit_array(phy_basic_ports_array,
+ ARRAY_SIZE(phy_basic_ports_array),
+ pcs->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
+ if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX ||
+ pcs->interface == PHY_INTERFACE_MODE_USXGMII)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ pcs->supported);
+ if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ pcs->supported);
+ phy_advertise_supported(pcs);
+
+ switch (pcs->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ vsc9959_pcs_init_2500basex(pcs, link_an_mode, state);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ vsc9959_pcs_init_usxgmii(pcs, link_an_mode, state);
+ break;
+ default:
+ dev_err(ocelot->dev, "Unsupported link mode %s\n",
+ phy_modes(pcs->interface));
+ }
+}
+
+static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs,
+ struct phylink_link_state *state)
+{
+ state->an_complete = pcs->autoneg_complete;
+ state->an_enabled = pcs->autoneg;
+ state->link = pcs->link;
+ state->duplex = pcs->duplex;
+ state->speed = pcs->speed;
+ /* SGMII AN does not negotiate flow control, but that's ok,
+ * since phylink already knows that, and does:
+ * link_state.pause |= pl->phy_state.pause;
+ */
+ state->pause = MLO_PAUSE_NONE;
+
+ phydev_dbg(pcs,
+ "mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
+ phy_modes(pcs->interface),
+ phy_speed_to_str(pcs->speed),
+ phy_duplex_to_str(pcs->duplex),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->advertising,
+ __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->lp_advertising,
+ pcs->link, pcs->autoneg, pcs->autoneg_complete);
+}
+
+static void vsc9959_pcs_link_state_sgmii(struct phy_device *pcs,
+ struct phylink_link_state *state)
+{
+ int err;
+
+ err = genphy_update_link(pcs);
+ if (err < 0)
+ return;
+
+ if (pcs->autoneg_complete) {
+ u16 lpa = phy_read(pcs, MII_LPA);
+
+ mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
+
+ phy_resolve_aneg_linkmode(pcs);
+ }
+}
+
+static void vsc9959_pcs_link_state_2500basex(struct phy_device *pcs,
+ struct phylink_link_state *state)
+{
+ int err;
+
+ err = genphy_update_link(pcs);
+ if (err < 0)
+ return;
+
+ pcs->speed = SPEED_2500;
+ pcs->asym_pause = true;
+ pcs->pause = true;
+}
+
+static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs,
+ struct phylink_link_state *state)
+{
+ int status, lpa;
+
+ status = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_BMSR);
+ if (status < 0)
+ return;
+
+ pcs->autoneg = true;
+ pcs->autoneg_complete = USXGMII_BMSR_AN_CMPL(status);
+ pcs->link = USXGMII_BMSR_LNKS(status);
+
+ if (!pcs->link || !pcs->autoneg_complete)
+ return;
+
+ lpa = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_LPA);
+ if (lpa < 0)
+ return;
+
+ switch (USXGMII_LPA_SPEED(lpa)) {
+ case USXGMII_SPEED_10:
+ pcs->speed = SPEED_10;
+ break;
+ case USXGMII_SPEED_100:
+ pcs->speed = SPEED_100;
+ break;
+ case USXGMII_SPEED_1000:
+ pcs->speed = SPEED_1000;
+ break;
+ case USXGMII_SPEED_2500:
+ pcs->speed = SPEED_2500;
+ break;
+ default:
+ break;
+ }
+
+ if (USXGMII_LPA_DUPLEX(lpa))
+ pcs->duplex = DUPLEX_FULL;
+ else
+ pcs->duplex = DUPLEX_HALF;
+}
+
+static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
+ struct phylink_link_state *state)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct phy_device *pcs = felix->pcs[port];
+
+ if (!pcs)
+ return;
+
+ pcs->speed = SPEED_UNKNOWN;
+ pcs->duplex = DUPLEX_UNKNOWN;
+ pcs->pause = 0;
+ pcs->asym_pause = 0;
+
+ switch (pcs->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ vsc9959_pcs_link_state_sgmii(pcs, state);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ vsc9959_pcs_link_state_2500basex(pcs, state);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ vsc9959_pcs_link_state_usxgmii(pcs, state);
+ break;
+ default:
+ return;
+ }
+
+ vsc9959_pcs_link_state_resolve(pcs, state);
+}
+
+static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
+ phy_interface_t phy_mode)
+{
+ switch (phy_mode) {
+ case PHY_INTERFACE_MODE_GMII:
+ /* Only supported on internal to-CPU ports */
+ if (port != 4 && port != 5)
+ return -ENOTSUPP;
+ return 0;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ /* Not supported on internal to-CPU ports */
+ if (port == 4 || port == 5)
+ return -ENOTSUPP;
+ return 0;
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static const struct ocelot_ops vsc9959_ops = {
+ .reset = vsc9959_reset,
+};
+
+static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct enetc_mdio_priv *mdio_priv;
+ struct device *dev = ocelot->dev;
+ resource_size_t imdio_base;
+ void __iomem *imdio_regs;
+ struct resource *res;
+ struct enetc_hw *hw;
+ struct mii_bus *bus;
+ int port;
+ int rc;
+
+ felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
+ sizeof(struct phy_device *),
+ GFP_KERNEL);
+ if (!felix->pcs) {
+ dev_err(dev, "failed to allocate array for PCS PHYs\n");
+ return -ENOMEM;
+ }
+
+ imdio_base = pci_resource_start(felix->pdev,
+ felix->info->imdio_pci_bar);
+
+ res = felix->info->imdio_res;
+ res->flags = IORESOURCE_MEM;
+ res->start += imdio_base;
+ res->end += imdio_base;
+
+ imdio_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(imdio_regs)) {
+ dev_err(dev, "failed to map internal MDIO registers\n");
+ return PTR_ERR(imdio_regs);
+ }
+
+ hw = enetc_hw_alloc(dev, imdio_regs);
+ if (IS_ERR(hw)) {
+ dev_err(dev, "failed to allocate ENETC HW structure\n");
+ return PTR_ERR(hw);
+ }
+
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "VSC9959 internal MDIO bus";
+ bus->read = enetc_mdio_read;
+ bus->write = enetc_mdio_write;
+ bus->parent = dev;
+ mdio_priv = bus->priv;
+ mdio_priv->hw = hw;
+ /* This gets added to imdio_regs, which already maps addresses
+ * starting with the proper offset.
+ */
+ mdio_priv->mdio_base = 0;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
+
+ /* Needed in order to initialize the bus mutex lock */
+ rc = mdiobus_register(bus);
+ if (rc < 0) {
+ dev_err(dev, "failed to register MDIO bus\n");
+ return rc;
+ }
+
+ felix->imdio = bus;
+
+ for (port = 0; port < felix->info->num_ports; port++) {
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct phy_device *pcs;
+ bool is_c45 = false;
+
+ if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_USXGMII)
+ is_c45 = true;
+
+ pcs = get_phy_device(felix->imdio, port, is_c45);
+ if (IS_ERR(pcs))
+ continue;
+
+ pcs->interface = ocelot_port->phy_mode;
+ felix->pcs[port] = pcs;
+
+ dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
+ }
+
+ return 0;
+}
+
+static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ int port;
+
+ for (port = 0; port < ocelot->num_phys_ports; port++) {
+ struct phy_device *pcs = felix->pcs[port];
+
+ if (!pcs)
+ continue;
+
+ put_device(&pcs->mdio.dev);
+ }
+ mdiobus_unregister(felix->imdio);
+}
+
+struct felix_info felix_info_vsc9959 = {
+ .target_io_res = vsc9959_target_io_res,
+ .port_io_res = vsc9959_port_io_res,
+ .imdio_res = &vsc9959_imdio_res,
+ .regfields = vsc9959_regfields,
+ .map = vsc9959_regmap,
+ .ops = &vsc9959_ops,
+ .stats_layout = vsc9959_stats_layout,
+ .num_stats = ARRAY_SIZE(vsc9959_stats_layout),
+ .shared_queue_sz = 128 * 1024,
+ .num_ports = 6,
+ .switch_pci_bar = 4,
+ .imdio_pci_bar = 0,
+ .mdio_bus_alloc = vsc9959_mdio_bus_alloc,
+ .mdio_bus_free = vsc9959_mdio_bus_free,
+ .pcs_init = vsc9959_pcs_init,
+ .pcs_an_restart = vsc9959_pcs_an_restart,
+ .pcs_link_state = vsc9959_pcs_link_state,
+ .prevalidate_phy_mode = vsc9959_prevalidate_phy_mode,
+};
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 941c7e667afc..b35b35b378c5 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -6,10 +6,10 @@
config NET_VENDOR_FREESCALE
bool "Freescale devices"
default y
- depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
+ depends on FSL_SOC || (QUICC_ENGINE && PPC32) || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
- ARCH_LAYERSCAPE || COMPILE_TEST
+ ARCH_LAYERSCAPE || ARCH_S32 || COMPILE_TEST
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -23,13 +23,13 @@ if NET_VENDOR_FREESCALE
config FEC
tristate "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
- ARCH_MXC || SOC_IMX28 || COMPILE_TEST)
+ ARCH_MXC || ARCH_S32 || SOC_IMX28 || COMPILE_TEST)
default ARCH_MXC || SOC_IMX28 if ARM
select PHYLIB
imply PTP_1588_CLOCK
---help---
Say Y here if you want to use the built-in 10/100 Fast ethernet
- controller on some Motorola ColdFire and Freescale i.MX processors.
+ controller on some Motorola ColdFire and Freescale i.MX/S32 processors.
config FEC_MPC52xx
tristate "FEC MPC52xx driver"
@@ -74,7 +74,7 @@ config FSL_XGMAC_MDIO
config UCC_GETH
tristate "Freescale QE Gigabit Ethernet"
- depends on QUICC_ENGINE
+ depends on QUICC_ENGINE && FSL_SOC && PPC32
select FSL_PQ_MDIO
select PHYLIB
select FIXED_PHY
@@ -97,7 +97,8 @@ config GIANFAR
This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
and MPC86xx family of chips, the eTSEC on LS1021A and the FEC
on the 8540.
-
+source "drivers/net/ethernet/freescale/sdk_fman/Kconfig"
+source "drivers/net/ethernet/freescale/sdk_dpaa/Kconfig"
source "drivers/net/ethernet/freescale/dpaa/Kconfig"
source "drivers/net/ethernet/freescale/dpaa2/Kconfig"
source "drivers/net/ethernet/freescale/enetc/Kconfig"
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 6a93293d31e0..ec956b93c83d 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -19,6 +19,9 @@ gianfar_driver-objs := gianfar.o \
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
+obj-$(if $(CONFIG_FSL_SDK_FMAN),y) += sdk_fman/
+obj-$(if $(CONFIG_FSL_SDK_DPAA_ETH),y) += sdk_dpaa/
+
obj-$(CONFIG_FSL_FMAN) += fman/
obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 00c4beb760c3..a0b556cc4e06 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -50,10 +50,15 @@
#include <linux/highmem.h>
#include <linux/percpu.h>
#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
#include <linux/sort.h>
#include <linux/phy_fixed.h>
#include <soc/fsl/bman.h>
#include <soc/fsl/qman.h>
+#if !defined(CONFIG_PPC) && defined(CONFIG_SOC_BUS)
+#include <linux/sys_soc.h> /* soc_device_match */
+#endif
+
#include "fman.h"
#include "fman_port.h"
#include "mac.h"
@@ -73,6 +78,10 @@ static u16 tx_timeout = 1000;
module_param(tx_timeout, ushort, 0444);
MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
+#ifndef CONFIG_PPC
+bool dpaa_errata_a010022;
+#endif
+
#define FM_FD_STAT_RX_ERRORS \
(FM_FD_ERR_DMA | FM_FD_ERR_PHYSICAL | \
FM_FD_ERR_SIZE | FM_FD_ERR_CLS_DISCARD | \
@@ -1495,7 +1504,19 @@ static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp)
u8 i;
for (i = 0; i < 8; i++) {
+#ifndef CONFIG_PPC
+ if (dpaa_errata_a010022) {
+ struct page *page = alloc_page(GFP_KERNEL);
+
+ if (unlikely(!page))
+ goto release_previous_buffs;
+ new_buf = page_address(page);
+ } else {
+ new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
+ }
+#else
new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
+#endif
if (unlikely(!new_buf)) {
dev_err(dev, "netdev_alloc_frag() failed, size %zu\n",
dpaa_bp->raw_size);
@@ -1595,6 +1616,17 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv)
return 0;
}
+static phys_addr_t dpaa_iova_to_phys(struct device *dev, dma_addr_t addr)
+{
+ struct iommu_domain *domain;
+
+ domain = iommu_get_domain_for_dev(dev);
+ if (domain)
+ return iommu_iova_to_phys(domain, addr);
+ else
+ return addr;
+}
+
/* Cleanup function for outgoing frame descriptors that were built on Tx path,
* either contiguous frames or scatter/gather ones.
* Skb freeing is not handled here.
@@ -1619,19 +1651,22 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
int nr_frags, i;
u64 ns;
- skbh = (struct sk_buff **)phys_to_virt(addr);
+ skbh = (struct sk_buff **)phys_to_virt(dpaa_iova_to_phys(dev, addr));
skb = *skbh;
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
- dma_unmap_single(dev, addr,
- qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
- dma_dir);
/* The sgt buffer has been allocated with netdev_alloc_frag(),
* it's from lowmem.
*/
- sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
+ sgt = phys_to_virt(dpaa_iova_to_phys(dev,
+ addr +
+ qm_fd_get_offset(fd)));
+
+ dma_unmap_single(dev, addr,
+ qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+ dma_dir);
/* sgt[0] is from lowmem, was dma_map_single()-ed */
dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
@@ -1644,6 +1679,13 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
qm_sg_entry_get_len(&sgt[i]), dma_dir);
}
+#ifndef CONFIG_PPC
+ if (dpaa_errata_a010022)
+ put_page(virt_to_page(sgt));
+ else
+#endif
+ /* Free the page frag that we allocated on Tx */
+ skb_free_frag(skbh);
} else {
dma_unmap_single(dev, addr,
skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
@@ -1692,25 +1734,21 @@ static u8 rx_csum_offload(const struct dpaa_priv *priv, const struct qm_fd *fd)
* accommodate the shared info area of the skb.
*/
static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
- const struct qm_fd *fd)
+ const struct qm_fd *fd,
+ struct dpaa_bp *dpaa_bp,
+ void *vaddr)
{
ssize_t fd_off = qm_fd_get_offset(fd);
- dma_addr_t addr = qm_fd_addr(fd);
- struct dpaa_bp *dpaa_bp;
struct sk_buff *skb;
- void *vaddr;
- vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
- dpaa_bp = dpaa_bpid2pool(fd->bpid);
- if (!dpaa_bp)
- goto free_buffer;
-
skb = build_skb(vaddr, dpaa_bp->size +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
- if (WARN_ONCE(!skb, "Build skb failure on Rx\n"))
- goto free_buffer;
+ if (WARN_ONCE(!skb, "Build skb failure on Rx\n")) {
+ skb_free_frag(vaddr);
+ return NULL;
+ }
WARN_ON(fd_off != priv->rx_headroom);
skb_reserve(skb, fd_off);
skb_put(skb, qm_fd_get_length(fd));
@@ -1718,10 +1756,6 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
skb->ip_summed = rx_csum_offload(priv, fd);
return skb;
-
-free_buffer:
- skb_free_frag(vaddr);
- return NULL;
}
/* Build an skb with the data of the first S/G entry in the linear portion and
@@ -1730,14 +1764,14 @@ free_buffer:
* The page fragment holding the S/G Table is recycled here.
*/
static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
- const struct qm_fd *fd)
+ const struct qm_fd *fd,
+ struct dpaa_bp *dpaa_bp,
+ void *vaddr)
{
ssize_t fd_off = qm_fd_get_offset(fd);
- dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct page *page, *head_page;
- struct dpaa_bp *dpaa_bp;
- void *vaddr, *sg_vaddr;
+ void *sg_vaddr;
int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
@@ -1746,7 +1780,6 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
int *count_ptr;
int i;
- vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
/* Iterate through the SGT entries and add data buffers to the skb */
@@ -1757,14 +1790,18 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
sg_addr = qm_sg_addr(&sgt[i]);
- sg_vaddr = phys_to_virt(sg_addr);
- WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
- SMP_CACHE_BYTES));
/* We may use multiple Rx pools */
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
- if (!dpaa_bp)
+ if (!dpaa_bp) {
+ pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
+ __func__, sgt[i].bpid);
goto free_buffers;
+ }
+ sg_vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev,
+ sg_addr));
+ WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+ SMP_CACHE_BYTES));
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
@@ -1836,10 +1873,11 @@ free_buffers:
/* free all the SG entries */
for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
sg_addr = qm_sg_addr(&sgt[i]);
- sg_vaddr = phys_to_virt(sg_addr);
- skb_free_frag(sg_vaddr);
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
if (dpaa_bp) {
+ sg_addr = dpaa_iova_to_phys(dpaa_bp->dev, sg_addr);
+ sg_vaddr = phys_to_virt(sg_addr);
+ skb_free_frag(sg_vaddr);
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
(*count_ptr)--;
}
@@ -1922,14 +1960,26 @@ static int skb_to_sg_fd(struct dpaa_priv *priv,
size_t frag_len;
void *sgt_buf;
- /* get a page frag to store the SGTable */
- sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
- sgt_buf = netdev_alloc_frag(sz);
- if (unlikely(!sgt_buf)) {
- netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n",
- sz);
- return -ENOMEM;
+#ifndef CONFIG_PPC
+ if (unlikely(dpaa_errata_a010022)) {
+ struct page *page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!page))
+ return -ENOMEM;
+ sgt_buf = page_address(page);
+ } else {
+#endif
+ /* get a page frag to store the SGTable */
+ sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
+ sgt_buf = netdev_alloc_frag(sz);
+ if (unlikely(!sgt_buf)) {
+ netdev_err(net_dev,
+ "netdev_alloc_frag() failed for size %d\n",
+ sz);
+ return -ENOMEM;
+ }
+#ifndef CONFIG_PPC
}
+#endif
/* Enable L3/L4 hardware checksum computation.
*
@@ -2049,6 +2099,131 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
return 0;
}
+#ifndef CONFIG_PPC
+/* On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
+ * transfers in the FMan under certain conditions. This, combined with a fixed
+ * size FIFO of ongoing DMA transfers that may overflow when a split occurs,
+ * results in the FMan stalling DMA transfers under high traffic. To avoid the
+ * problem, one needs to prevent the DMA transfer splits to occur by preparing
+ * the buffers
+ */
+
+#define DPAA_A010022_HEADROOM 256
+#define CROSS_4K_BOUND(start, size) \
+ (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
+
+static bool dpaa_errata_a010022_has_dma_issue(struct sk_buff *skb,
+ struct dpaa_priv *priv)
+{
+ int nr_frags, i = 0;
+ skb_frag_t *frag;
+
+ /* Transfers that do not start at 16B aligned addresses will be split;
+ * Transfers that cross a 4K page boundary will also be split
+ */
+
+ /* Check if the frame data is aligned to 16 bytes */
+ if ((uintptr_t)skb->data % DPAA_FD_DATA_ALIGNMENT)
+ return true;
+
+ /* Check if the headroom crosses a boundary */
+ if (CROSS_4K_BOUND((uintptr_t)skb->head, skb_headroom(skb)))
+ return true;
+
+ /* Check if the non-paged data crosses a boundary */
+ if (CROSS_4K_BOUND((uintptr_t)skb->data, skb_headlen(skb)))
+ return true;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ while (i < nr_frags) {
+ frag = &skb_shinfo(skb)->frags[i];
+
+ /* Check if a paged fragment crosses a boundary from its
+ * offset to its end.
+ */
+ if (CROSS_4K_BOUND(skb_frag_off(frag), skb_frag_size(frag)))
+ return true;
+
+ i++;
+ }
+
+ return false;
+}
+
+static struct sk_buff *dpaa_errata_a010022_prevent(struct sk_buff *skb,
+ struct dpaa_priv *priv)
+{
+ int trans_offset = skb_transport_offset(skb);
+ int net_offset = skb_network_offset(skb);
+ int nsize, npage_order, headroom;
+ struct sk_buff *nskb = NULL;
+ struct page *npage;
+ void *npage_addr;
+
+ if (!dpaa_errata_a010022_has_dma_issue(skb, priv))
+ return skb;
+
+ /* For the new skb we only need the old one's data (both non-paged and
+ * paged). We can skip the old tailroom.
+ *
+ * The headroom also needs to fit our private info (64 bytes) but we
+ * reserve 256 bytes instead in order to guarantee that the data is
+ * aligned to 256.
+ */
+ headroom = DPAA_A010022_HEADROOM;
+ nsize = ALIGN(headroom + skb->len, SMP_CACHE_BYTES) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ /* Reserve enough memory to accommodate Jumbo frames */
+ npage_order = (nsize - 1) / PAGE_SIZE;
+ npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
+ if (unlikely(!npage)) {
+ WARN_ONCE(1, "Memory allocation failure\n");
+ return NULL;
+ }
+ npage_addr = page_address(npage);
+
+ nskb = build_skb(npage_addr, nsize);
+ if (unlikely(!nskb))
+ goto err;
+
+ /* Code borrowed and adapted from skb_copy() */
+ skb_reserve(nskb, headroom);
+ skb_put(nskb, skb->len);
+ if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
+ WARN_ONCE(1, "skb parsing failure\n");
+ goto err;
+ }
+ skb_copy_header(nskb, skb);
+
+ /* Copy relevant timestamp info from the old skb to the new */
+ if (priv->tx_tstamp) {
+ skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags;
+ skb_shinfo(nskb)->hwtstamps = skb_shinfo(skb)->hwtstamps;
+ skb_shinfo(nskb)->tskey = skb_shinfo(skb)->tskey;
+ if (skb->sk)
+ skb_set_owner_w(nskb, skb->sk);
+ }
+
+ /* We move the headroom when we align it so we have to reset the
+ * network and transport header offsets relative to the new data
+ * pointer. The checksum offload relies on these offsets.
+ */
+ skb_set_network_header(nskb, net_offset);
+ skb_set_transport_header(nskb, trans_offset);
+
+ dev_kfree_skb(skb);
+ return nskb;
+
+err:
+ if (nskb)
+ dev_kfree_skb(nskb);
+ put_page(npage);
+ return NULL;
+}
+#endif
+
static netdev_tx_t
dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
{
@@ -2095,6 +2270,15 @@ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
nonlinear = skb_is_nonlinear(skb);
}
+#ifndef CONFIG_PPC
+ if (unlikely(dpaa_errata_a010022)) {
+ skb = dpaa_errata_a010022_prevent(skb, priv);
+ if (!skb)
+ goto enomem;
+ nonlinear = skb_is_nonlinear(skb);
+ }
+#endif
+
if (nonlinear) {
/* Just create a S/G fd based on the skb */
err = skb_to_sg_fd(priv, skb, &fd);
@@ -2313,12 +2497,12 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
if (!dpaa_bp)
return qman_cb_dqrr_consume;
- dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
-
/* prefetch the first 64 bytes of the frame or the SGT start */
- vaddr = phys_to_virt(addr);
+ vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev, addr));
prefetch(vaddr + qm_fd_get_offset(fd));
+ dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
+
/* The only FD types that we may receive are contig and S/G */
WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
@@ -2329,9 +2513,9 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
(*count_ptr)--;
if (likely(fd_format == qm_fd_contig))
- skb = contig_fd_to_skb(priv, fd);
+ skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
else
- skb = sg_fd_to_skb(priv, fd);
+ skb = sg_fd_to_skb(priv, fd, dpaa_bp, vaddr);
if (!skb)
return qman_cb_dqrr_consume;
@@ -2784,8 +2968,46 @@ static int dpaa_eth_probe(struct platform_device *pdev)
int err = 0, i, channel;
struct device *dev;
+ err = bman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to bman probe error\n");
+ return -ENODEV;
+ }
+ err = qman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to qman probe error\n");
+ return -ENODEV;
+ }
+ err = bman_portals_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failing probe due to bman portals probe error\n");
+ return -ENODEV;
+ }
+ err = qman_portals_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failing probe due to qman portals probe error\n");
+ return -ENODEV;
+ }
+
+ mac_dev = dpaa_mac_dev_get(pdev);
+ if (IS_ERR(mac_dev)) {
+ dev_err(&pdev->dev, "dpaa_mac_dev_get() failed\n");
+ err = PTR_ERR(mac_dev);
+ goto probe_err;
+ }
+
/* device used for DMA mapping */
- dev = pdev->dev.parent;
+ dev = fman_port_get_device(mac_dev->port[RX]);
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
if (err) {
dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
@@ -2810,13 +3032,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)
priv->msg_enable = netif_msg_init(debug, DPAA_MSG_DEFAULT);
- mac_dev = dpaa_mac_dev_get(pdev);
- if (IS_ERR(mac_dev)) {
- dev_err(dev, "dpaa_mac_dev_get() failed\n");
- err = PTR_ERR(mac_dev);
- goto free_netdev;
- }
-
/* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
* we choose conservatively and let the user explicitly set a higher
* MTU via ifconfig. Otherwise, the user may end up with different MTUs
@@ -2952,9 +3167,9 @@ delete_egress_cgr:
qman_release_cgrid(priv->cgr_data.cgr.cgrid);
free_dpaa_bps:
dpaa_bps_free(priv);
-free_netdev:
dev_set_drvdata(dev, NULL);
free_netdev(net_dev);
+probe_err:
return err;
}
@@ -2992,6 +3207,23 @@ static int dpaa_remove(struct platform_device *pdev)
return err;
}
+#ifndef CONFIG_PPC
+static bool __init soc_has_errata_a010022(void)
+{
+#ifdef CONFIG_SOC_BUS
+ const struct soc_device_attribute soc_msi_matches[] = {
+ { .family = "QorIQ LS1043A",
+ .data = NULL },
+ { },
+ };
+
+ if (!soc_device_match(soc_msi_matches))
+ return false;
+#endif
+ return true; /* cannot identify SoC or errata applies */
+}
+#endif
+
static const struct platform_device_id dpaa_devtype[] = {
{
.name = "dpaa-ethernet",
@@ -3016,6 +3248,10 @@ static int __init dpaa_load(void)
pr_debug("FSL DPAA Ethernet driver\n");
+#ifndef CONFIG_PPC
+ /* Detect if the current SoC requires the DMA transfer alignment workaround */
+ dpaa_errata_a010022 = soc_has_errata_a010022();
+#endif
/* initialize dpaa_eth mirror values */
dpaa_rx_extra_headroom = fman_get_rx_extra_headroom();
dpaa_max_frm = fman_get_max_frm();
diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig
index fbef2829f3de..78b80e3b15e5 100644
--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
+++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
@@ -8,6 +8,32 @@ config FSL_DPAA2_ETH
The driver manages network objects discovered on the Freescale
MC bus.
+if FSL_DPAA2_ETH
+config FSL_DPAA2_ETH_DCB
+ bool "Data Center Bridging (DCB) Support"
+ default n
+ depends on DCB
+ help
+ Enable Priority-Based Flow Control (PFC) support in the driver
+
+config FSL_DPAA2_ETH_USE_ERR_QUEUE
+ bool "Enable Rx error queue"
+ default n
+ help
+ Allow Rx error frames to be enqueued on an error queue
+ and processed by the driver (by default they are dropped
+ in hardware).
+ This may impact performance, recommended for debugging
+ purposes only.
+
+config FSL_DPAA2_ETH_CEETM
+ depends on NET_SCHED
+ bool "DPAA2 Ethernet CEETM QoS"
+ default n
+ help
+ Enable QoS offloading support through the CEETM hardware block.
+endif
+
config FSL_DPAA2_PTP_CLOCK
tristate "Freescale DPAA2 PTP Clock"
depends on FSL_DPAA2_ETH && PTP_1588_CLOCK_QORIQ
diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile
index d1e78cdd512f..bfa51e3b686e 100644
--- a/drivers/net/ethernet/freescale/dpaa2/Makefile
+++ b/drivers/net/ethernet/freescale/dpaa2/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o
fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o
fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
+fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_CEETM} += dpaa2-eth-ceetm.o
fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o
# Needed by the tracing framework
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
new file mode 100644
index 000000000000..bffcebb58bef
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
@@ -0,0 +1,1219 @@
+/* Copyright 2017 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/init.h>
+#include <linux/module.h>
+
+#include "dpaa2-eth-ceetm.h"
+#include "dpaa2-eth.h"
+
+#define DPAA2_CEETM_DESCRIPTION "FSL DPAA2 CEETM qdisc"
+/* Conversion formula from userspace passed Bps to expected Mbit */
+#define dpaa2_eth_bps_to_mbit(rate) (rate >> 17)
+
+static const struct nla_policy dpaa2_ceetm_policy[DPAA2_CEETM_TCA_MAX] = {
+ [DPAA2_CEETM_TCA_COPT] = { .len = sizeof(struct dpaa2_ceetm_tc_copt) },
+ [DPAA2_CEETM_TCA_QOPS] = { .len = sizeof(struct dpaa2_ceetm_tc_qopt) },
+};
+
+struct Qdisc_ops dpaa2_ceetm_qdisc_ops;
+
+static inline int dpaa2_eth_set_ch_shaping(struct dpaa2_eth_priv *priv,
+ struct dpni_tx_shaping_cfg *scfg,
+ struct dpni_tx_shaping_cfg *ecfg,
+ int coupled, int ch_id)
+{
+ int err = 0;
+
+ netdev_dbg(priv->net_dev, "%s: ch_id %d rate %d mbps\n", __func__,
+ ch_id, scfg->rate_limit);
+ err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, scfg,
+ ecfg, coupled);
+ if (err)
+ netdev_err(priv->net_dev, "dpni_set_tx_shaping err\n");
+
+ return err;
+}
+
+static inline int dpaa2_eth_reset_ch_shaping(struct dpaa2_eth_priv *priv,
+ int ch_id)
+{
+ struct dpni_tx_shaping_cfg cfg = { 0 };
+
+ return dpaa2_eth_set_ch_shaping(priv, &cfg, &cfg, 0, ch_id);
+}
+
+static inline int
+dpaa2_eth_update_shaping_cfg(struct net_device *dev,
+ struct dpaa2_ceetm_shaping_cfg cfg,
+ struct dpni_tx_shaping_cfg *scfg,
+ struct dpni_tx_shaping_cfg *ecfg)
+{
+ scfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.cir);
+ ecfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.eir);
+
+ if (cfg.cbs > DPAA2_ETH_MAX_BURST_SIZE) {
+ netdev_err(dev, "Committed burst size must be under %d\n",
+ DPAA2_ETH_MAX_BURST_SIZE);
+ return -EINVAL;
+ }
+
+ scfg->max_burst_size = cfg.cbs;
+
+ if (cfg.ebs > DPAA2_ETH_MAX_BURST_SIZE) {
+ netdev_err(dev, "Excess burst size must be under %d\n",
+ DPAA2_ETH_MAX_BURST_SIZE);
+ return -EINVAL;
+ }
+
+ ecfg->max_burst_size = cfg.ebs;
+
+ if ((!cfg.cir || !cfg.eir) && cfg.coupled) {
+ netdev_err(dev, "Coupling can be set when both CIR and EIR are finite\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+enum update_tx_prio {
+ DPAA2_ETH_ADD_CQ,
+ DPAA2_ETH_DEL_CQ,
+};
+
+/* Normalize weights based on max passed value */
+static inline int dpaa2_eth_normalize_tx_prio(struct dpaa2_ceetm_qdisc *priv)
+{
+ struct dpni_tx_schedule_cfg *sched_cfg;
+ struct dpaa2_ceetm_class *cl;
+ u32 qpri;
+ u16 weight_max = 0, increment;
+ int i;
+
+ /* Check the boundaries of the provided values */
+ for (i = 0; i < priv->clhash.hashsize; i++)
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
+ weight_max = (weight_max == 0 ? cl->prio.weight :
+ (weight_max < cl->prio.weight ?
+ cl->prio.weight : weight_max));
+
+ /* If there are no elements, there's nothing to do */
+ if (weight_max == 0)
+ return 0;
+
+ increment = (DPAA2_CEETM_MAX_WEIGHT - DPAA2_CEETM_MIN_WEIGHT) /
+ weight_max;
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
+ if (cl->prio.mode == STRICT_PRIORITY)
+ continue;
+
+ qpri = cl->prio.qpri;
+ sched_cfg = &priv->prio.tx_prio_cfg.tc_sched[qpri];
+
+ sched_cfg->delta_bandwidth =
+ DPAA2_CEETM_MIN_WEIGHT +
+ (cl->prio.weight * increment);
+
+ pr_debug("%s: Normalized CQ qpri %d weight to %d\n",
+ __func__, qpri, sched_cfg->delta_bandwidth);
+ }
+ }
+
+ return 0;
+}
+
+static inline int dpaa2_eth_update_tx_prio(struct dpaa2_eth_priv *priv,
+ struct dpaa2_ceetm_class *cl,
+ enum update_tx_prio type)
+{
+ struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
+ struct dpni_tx_schedule_cfg *sched_cfg;
+ struct dpni_taildrop td = {0};
+ u8 ch_id = 0, tc_id = 0;
+ u32 qpri = 0;
+ int err = 0;
+
+ qpri = cl->prio.qpri;
+ tc_id = DPNI_BUILD_CH_TC(ch_id, qpri);
+
+ switch (type) {
+ case DPAA2_ETH_ADD_CQ:
+ /* Enable taildrop */
+ td.enable = 1;
+ td.units = DPNI_CONGESTION_UNIT_FRAMES;
+ td.threshold = DPAA2_CEETM_TD_THRESHOLD;
+ err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
+ DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
+ 0, &td);
+ if (err) {
+ netdev_err(priv->net_dev, "Error enabling Tx taildrop %d\n",
+ err);
+ return err;
+ }
+ break;
+ case DPAA2_ETH_DEL_CQ:
+ /* Disable taildrop */
+ td.enable = 0;
+ err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
+ DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
+ 0, &td);
+ if (err) {
+ netdev_err(priv->net_dev, "Error disabling Tx taildrop %d\n",
+ err);
+ return err;
+ }
+ break;
+ }
+
+ /* We can zero out the structure in the tx_prio_conf array */
+ if (type == DPAA2_ETH_DEL_CQ) {
+ sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[qpri];
+ memset(sched_cfg, 0, sizeof(*sched_cfg));
+ }
+
+ /* Normalize priorities */
+ err = dpaa2_eth_normalize_tx_prio(sch);
+
+ /* Debug print goes here */
+ print_hex_dump_debug("tx_prio: ", DUMP_PREFIX_OFFSET, 16, 1,
+ &sch->prio.tx_prio_cfg,
+ sizeof(sch->prio.tx_prio_cfg), 0);
+
+ /* Call dpni_set_tx_priorities for the entire prio qdisc */
+ err = dpni_set_tx_priorities(priv->mc_io, 0, priv->mc_token,
+ &sch->prio.tx_prio_cfg);
+ if (err)
+ netdev_err(priv->net_dev, "dpni_set_tx_priorities err %d\n",
+ err);
+
+ return err;
+}
+
+static void dpaa2_eth_ceetm_enable(struct dpaa2_eth_priv *priv)
+{
+ priv->ceetm_en = true;
+}
+
+static void dpaa2_eth_ceetm_disable(struct dpaa2_eth_priv *priv)
+{
+ priv->ceetm_en = false;
+}
+
+/* Find class in qdisc hash table using given handle */
+static inline struct dpaa2_ceetm_class *dpaa2_ceetm_find(u32 handle,
+ struct Qdisc *sch)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct Qdisc_class_common *clc;
+
+ pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n",
+ __func__, handle, sch->handle);
+
+ clc = qdisc_class_find(&priv->clhash, handle);
+ return clc ? container_of(clc, struct dpaa2_ceetm_class, common) : NULL;
+}
+
+/* Insert a class in the qdisc's class hash */
+static void dpaa2_ceetm_link_class(struct Qdisc *sch,
+ struct Qdisc_class_hash *clhash,
+ struct Qdisc_class_common *common)
+{
+ sch_tree_lock(sch);
+ qdisc_class_hash_insert(clhash, common);
+ sch_tree_unlock(sch);
+ qdisc_class_hash_grow(sch, clhash);
+}
+
+/* Destroy a ceetm class */
+static void dpaa2_ceetm_cls_destroy(struct Qdisc *sch,
+ struct dpaa2_ceetm_class *cl)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_eth_priv *priv = netdev_priv(dev);
+
+ if (!cl)
+ return;
+
+ pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ /* Recurse into child first */
+ if (cl->child) {
+ qdisc_put(cl->child);
+ cl->child = NULL;
+ }
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ if (dpaa2_eth_reset_ch_shaping(priv, cl->root.ch_id))
+ netdev_err(dev, "Error resetting channel shaping\n");
+
+ break;
+
+ case CEETM_PRIO:
+ if (dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_DEL_CQ))
+ netdev_err(dev, "Error resetting tx_priorities\n");
+
+ if (cl->prio.cstats)
+ free_percpu(cl->prio.cstats);
+
+ break;
+ }
+
+ tcf_block_put(cl->block);
+ kfree(cl);
+}
+
+/* Destroy a ceetm qdisc */
+static void dpaa2_ceetm_destroy(struct Qdisc *sch)
+{
+ unsigned int i;
+ struct hlist_node *next;
+ struct dpaa2_ceetm_class *cl;
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
+
+ pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
+ __func__, sch->handle);
+
+ /* All filters need to be removed before destroying the classes */
+ tcf_block_put(priv->block);
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
+ tcf_block_put(cl->block);
+ }
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i],
+ common.hnode)
+ dpaa2_ceetm_cls_destroy(sch, cl);
+ }
+
+ qdisc_class_hash_destroy(&priv->clhash);
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ dpaa2_eth_ceetm_disable(priv_eth);
+
+ if (priv->root.qstats)
+ free_percpu(priv->root.qstats);
+
+ if (!priv->root.qdiscs)
+ break;
+
+ /* Destroy the pfifo qdiscs in case they haven't been attached
+ * to the netdev queues yet.
+ */
+ for (i = 0; i < dev->num_tx_queues; i++)
+ if (priv->root.qdiscs[i])
+ qdisc_put(priv->root.qdiscs[i]);
+
+ kfree(priv->root.qdiscs);
+ break;
+
+ case CEETM_PRIO:
+ if (priv->prio.parent)
+ priv->prio.parent->child = NULL;
+ break;
+ }
+}
+
+static int dpaa2_ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct Qdisc *qdisc;
+ unsigned int ntx, i;
+ struct nlattr *nest;
+ struct dpaa2_ceetm_tc_qopt qopt;
+ struct dpaa2_ceetm_qdisc_stats *qstats;
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ sch_tree_lock(sch);
+ memset(&qopt, 0, sizeof(qopt));
+ qopt.type = priv->type;
+ qopt.shaped = priv->shaped;
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ /* Gather statistics from the underlying pfifo qdiscs */
+ sch->q.qlen = 0;
+ memset(&sch->bstats, 0, sizeof(sch->bstats));
+ memset(&sch->qstats, 0, sizeof(sch->qstats));
+
+ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
+ sch->q.qlen += qdisc->q.qlen;
+ sch->bstats.bytes += qdisc->bstats.bytes;
+ sch->bstats.packets += qdisc->bstats.packets;
+ sch->qstats.qlen += qdisc->qstats.qlen;
+ sch->qstats.backlog += qdisc->qstats.backlog;
+ sch->qstats.drops += qdisc->qstats.drops;
+ sch->qstats.requeues += qdisc->qstats.requeues;
+ sch->qstats.overlimits += qdisc->qstats.overlimits;
+ }
+
+ for_each_online_cpu(i) {
+ qstats = per_cpu_ptr(priv->root.qstats, i);
+ sch->qstats.drops += qstats->drops;
+ }
+
+ break;
+
+ case CEETM_PRIO:
+ qopt.prio_group_A = priv->prio.tx_prio_cfg.prio_group_A;
+ qopt.prio_group_B = priv->prio.tx_prio_cfg.prio_group_B;
+ qopt.separate_groups = priv->prio.tx_prio_cfg.separate_groups;
+ break;
+
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ sch_tree_unlock(sch);
+ return -EINVAL;
+ }
+
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+ if (!nest)
+ goto nla_put_failure;
+ if (nla_put(skb, DPAA2_CEETM_TCA_QOPS, sizeof(qopt), &qopt))
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+
+ sch_tree_unlock(sch);
+ return skb->len;
+
+nla_put_failure:
+ sch_tree_unlock(sch);
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+static int dpaa2_ceetm_change_prio(struct Qdisc *sch,
+ struct dpaa2_ceetm_qdisc *priv,
+ struct dpaa2_ceetm_tc_qopt *qopt)
+{
+ /* TODO: Once LX2 support is added */
+ /* priv->shaped = parent_cl->shaped; */
+ priv->prio.tx_prio_cfg.prio_group_A = qopt->prio_group_A;
+ priv->prio.tx_prio_cfg.prio_group_B = qopt->prio_group_B;
+ priv->prio.tx_prio_cfg.separate_groups = qopt->separate_groups;
+
+ return 0;
+}
+
+/* Edit a ceetm qdisc */
+static int dpaa2_ceetm_change(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
+ struct dpaa2_ceetm_tc_qopt *qopt;
+ int err;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
+ dpaa2_ceetm_policy, extack);
+ if (err < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "nla_parse_nested_deprecated");
+ return err;
+ }
+
+ if (!tb[DPAA2_CEETM_TCA_QOPS]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "tb");
+ return -EINVAL;
+ }
+
+ if (TC_H_MIN(sch->handle)) {
+ pr_err("CEETM: a qdisc should not have a minor\n");
+ return -EINVAL;
+ }
+
+ qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
+
+ if (priv->type != qopt->type) {
+ pr_err("CEETM: qdisc %X is not of the provided type\n",
+ sch->handle);
+ return -EINVAL;
+ }
+
+ switch (priv->type) {
+ case CEETM_PRIO:
+ err = dpaa2_ceetm_change_prio(sch, priv, qopt);
+ break;
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/* Configure a root ceetm qdisc */
+static int dpaa2_ceetm_init_root(struct Qdisc *sch,
+ struct dpaa2_ceetm_qdisc *priv,
+ struct dpaa2_ceetm_tc_qopt *qopt,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
+ struct netdev_queue *dev_queue;
+ unsigned int i, parent_id;
+ struct Qdisc *qdisc;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ /* Validate inputs */
+ if (sch->parent != TC_H_ROOT) {
+ pr_err("CEETM: a root ceetm qdisc must be root\n");
+ return -EINVAL;
+ }
+
+ /* Pre-allocate underlying pfifo qdiscs.
+ *
+ * We want to offload shaping and scheduling decisions to the hardware.
+ * The pfifo qdiscs will be attached to the netdev queues and will
+ * guide the traffic from the IP stack down to the driver with minimum
+ * interference.
+ *
+ * The CEETM qdiscs and classes will be crossed when the traffic
+ * reaches the driver.
+ */
+ priv->root.qdiscs = kcalloc(dev->num_tx_queues,
+ sizeof(priv->root.qdiscs[0]),
+ GFP_KERNEL);
+ if (!priv->root.qdiscs)
+ return -ENOMEM;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ dev_queue = netdev_get_tx_queue(dev, i);
+ parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle),
+ TC_H_MIN(i + PFIFO_MIN_OFFSET));
+
+ qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
+ parent_id, extack);
+ if (!qdisc)
+ return -ENOMEM;
+
+ priv->root.qdiscs[i] = qdisc;
+ qdisc->flags |= TCQ_F_ONETXQUEUE;
+ }
+
+ sch->flags |= TCQ_F_MQROOT;
+
+ priv->root.qstats = alloc_percpu(struct dpaa2_ceetm_qdisc_stats);
+ if (!priv->root.qstats) {
+ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ dpaa2_eth_ceetm_enable(priv_eth);
+ return 0;
+}
+
+/* Configure a prio ceetm qdisc */
+static int dpaa2_ceetm_init_prio(struct Qdisc *sch,
+ struct dpaa2_ceetm_qdisc *priv,
+ struct dpaa2_ceetm_tc_qopt *qopt)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_ceetm_class *parent_cl;
+ struct Qdisc *parent_qdisc;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (sch->parent == TC_H_ROOT) {
+ pr_err("CEETM: a prio ceetm qdisc can not be root\n");
+ return -EINVAL;
+ }
+
+ parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
+ if (strcmp(parent_qdisc->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+ return -EINVAL;
+ }
+
+ /* Obtain the parent root ceetm_class */
+ parent_cl = dpaa2_ceetm_find(sch->parent, parent_qdisc);
+
+ if (!parent_cl || parent_cl->type != CEETM_ROOT) {
+ pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
+ return -EINVAL;
+ }
+
+ priv->prio.parent = parent_cl;
+ parent_cl->child = sch;
+
+ return dpaa2_ceetm_change_prio(sch, priv, qopt);
+}
+
+/* Configure a generic ceetm qdisc */
+static int dpaa2_ceetm_init(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
+ struct dpaa2_ceetm_tc_qopt *qopt;
+ int err;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (!netif_is_multiqueue(dev))
+ return -EOPNOTSUPP;
+
+ err = tcf_block_get(&priv->block, &priv->filter_list, sch, extack);
+ if (err) {
+ pr_err("CEETM: unable to get tcf_block\n");
+ return err;
+ }
+
+ if (!opt) {
+ pr_err(KBUILD_BASENAME " : %s : tc error - opt = NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
+ dpaa2_ceetm_policy, extack);
+ if (err < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "nla_parse_nested_deprecated");
+ return err;
+ }
+
+ if (!tb[DPAA2_CEETM_TCA_QOPS]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "tb");
+ return -EINVAL;
+ }
+
+ if (TC_H_MIN(sch->handle)) {
+ pr_err("CEETM: a qdisc should not have a minor\n");
+ return -EINVAL;
+ }
+
+ qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
+
+ /* Initialize the class hash list. Each qdisc has its own class hash */
+ err = qdisc_class_hash_init(&priv->clhash);
+ if (err < 0) {
+ pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n",
+ __func__);
+ return err;
+ }
+
+ priv->type = qopt->type;
+ priv->shaped = qopt->shaped;
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ err = dpaa2_ceetm_init_root(sch, priv, qopt, extack);
+ break;
+ case CEETM_PRIO:
+ err = dpaa2_ceetm_init_prio(sch, priv, qopt);
+ break;
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ /* Note: dpaa2_ceetm_destroy() will be called by our caller */
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/* Attach the underlying pfifo qdiscs */
+static void dpaa2_ceetm_attach(struct Qdisc *sch)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct Qdisc *qdisc, *old_qdisc;
+ unsigned int i;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ qdisc = priv->root.qdiscs[i];
+ old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
+ if (old_qdisc)
+ qdisc_put(old_qdisc);
+ }
+
+ /* Remove the references to the pfifo qdiscs since the kernel will
+ * destroy them when needed. No cleanup from our part is required from
+ * this point on.
+ */
+ kfree(priv->root.qdiscs);
+ priv->root.qdiscs = NULL;
+}
+
+static unsigned long dpaa2_ceetm_cls_find(struct Qdisc *sch, u32 classid)
+{
+ struct dpaa2_ceetm_class *cl;
+
+ pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
+ __func__, classid, sch->handle);
+ cl = dpaa2_ceetm_find(classid, sch);
+
+ return (unsigned long)cl;
+}
+
+static int dpaa2_ceetm_cls_change_root(struct dpaa2_ceetm_class *cl,
+ struct dpaa2_ceetm_tc_copt *copt,
+ struct net_device *dev)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(dev);
+ struct dpni_tx_shaping_cfg scfg = { 0 }, ecfg = { 0 };
+ int err = 0;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X\n", __func__,
+ cl->common.classid);
+
+ if (!cl->shaped)
+ return 0;
+
+ if (dpaa2_eth_update_shaping_cfg(dev, copt->shaping_cfg,
+ &scfg, &ecfg))
+ return -EINVAL;
+
+ err = dpaa2_eth_set_ch_shaping(priv, &scfg, &ecfg,
+ copt->shaping_cfg.coupled,
+ cl->root.ch_id);
+ if (err)
+ return err;
+
+ memcpy(&cl->root.shaping_cfg, &copt->shaping_cfg,
+ sizeof(struct dpaa2_ceetm_shaping_cfg));
+
+ return err;
+}
+
+static int dpaa2_ceetm_cls_change_prio(struct dpaa2_ceetm_class *cl,
+ struct dpaa2_ceetm_tc_copt *copt,
+ struct net_device *dev)
+{
+ struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
+ struct dpni_tx_schedule_cfg *sched_cfg;
+ struct dpaa2_eth_priv *priv = netdev_priv(dev);
+ int err;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X mode %d weight %d\n",
+ __func__, cl->common.classid, copt->mode, copt->weight);
+
+ if (!cl->prio.cstats) {
+ cl->prio.cstats = alloc_percpu(struct dpaa2_ceetm_class_stats);
+ if (!cl->prio.cstats) {
+ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+
+ cl->prio.mode = copt->mode;
+ cl->prio.weight = copt->weight;
+
+ sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[cl->prio.qpri];
+
+ switch (copt->mode) {
+ case STRICT_PRIORITY:
+ sched_cfg->mode = DPNI_TX_SCHED_STRICT_PRIORITY;
+ break;
+ case WEIGHTED_A:
+ sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_A;
+ break;
+ case WEIGHTED_B:
+ sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_B;
+ break;
+ }
+
+ err = dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_ADD_CQ);
+
+ return err;
+}
+
+/* Add a new ceetm class */
+static int dpaa2_ceetm_cls_add(struct Qdisc *sch, u32 classid,
+ struct dpaa2_ceetm_tc_copt *copt,
+ unsigned long *arg,
+ struct netlink_ext_ack *extack)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
+ struct dpaa2_ceetm_class *cl;
+ int err;
+
+ if (copt->type == CEETM_ROOT &&
+ priv->clhash.hashelems == dpaa2_eth_ch_count(priv_eth)) {
+ pr_err("CEETM: only %d channel%s per DPNI allowed, sorry\n",
+ dpaa2_eth_ch_count(priv_eth),
+ dpaa2_eth_ch_count(priv_eth) == 1 ? "" : "s");
+ return -EINVAL;
+ }
+
+ if (copt->type == CEETM_PRIO &&
+ priv->clhash.hashelems == dpaa2_eth_tc_count(priv_eth)) {
+ pr_err("CEETM: only %d queue%s per channel allowed, sorry\n",
+ dpaa2_eth_tc_count(priv_eth),
+ dpaa2_eth_tc_count(priv_eth) == 1 ? "" : "s");
+ return -EINVAL;
+ }
+
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
+ if (err) {
+ pr_err("%s: Unable to set new root class\n", __func__);
+ goto out_free;
+ }
+
+ cl->common.classid = classid;
+ cl->parent = sch;
+ cl->child = NULL;
+
+ /* Add class handle in Qdisc */
+ dpaa2_ceetm_link_class(sch, &priv->clhash, &cl->common);
+
+ cl->shaped = copt->shaped;
+ cl->type = copt->type;
+
+ /* Claim a CEETM channel / tc - DPAA2. will assume transition from
+ * classid to qdid/qpri, starting from qdid / qpri 0
+ */
+ switch (copt->type) {
+ case CEETM_ROOT:
+ cl->root.ch_id = classid - sch->handle - 1;
+ err = dpaa2_ceetm_cls_change_root(cl, copt, dev);
+ break;
+ case CEETM_PRIO:
+ cl->prio.qpri = classid - sch->handle - 1;
+ err = dpaa2_ceetm_cls_change_prio(cl, copt, dev);
+ break;
+ }
+
+ if (err) {
+ pr_err("%s: Unable to set new %s class\n", __func__,
+ (copt->type == CEETM_ROOT ? "root" : "prio"));
+ goto out_free;
+ }
+
+ switch (copt->type) {
+ case CEETM_ROOT:
+ pr_debug(KBUILD_BASENAME " : %s : configured root class %X associated with channel qdid %d\n",
+ __func__, classid, cl->root.ch_id);
+ break;
+ case CEETM_PRIO:
+ pr_debug(KBUILD_BASENAME " : %s : configured prio class %X associated with queue qpri %d\n",
+ __func__, classid, cl->prio.qpri);
+ break;
+ }
+
+ *arg = (unsigned long)cl;
+ return 0;
+
+out_free:
+ kfree(cl);
+ return err;
+}
+
+/* Add or configure a ceetm class */
+static int dpaa2_ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
+ struct nlattr **tca, unsigned long *arg,
+ struct netlink_ext_ack *extack)
+{
+ struct dpaa2_ceetm_qdisc *priv;
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)*arg;
+ struct nlattr *opt = tca[TCA_OPTIONS];
+ struct nlattr *tb[DPAA2_CEETM_TCA_MAX];
+ struct dpaa2_ceetm_tc_copt *copt;
+ struct net_device *dev = qdisc_dev(sch);
+ int err;
+
+ pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
+ __func__, classid, sch->handle);
+
+ if (strcmp(sch->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n");
+ return -EINVAL;
+ }
+
+ priv = qdisc_priv(sch);
+
+ if (!opt) {
+ pr_err(KBUILD_BASENAME " : %s : tc error NULL opt\n", __func__);
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_COPT, opt,
+ dpaa2_ceetm_policy, extack);
+ if (err < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "nla_parse_nested_deprecated");
+ return -EINVAL;
+ }
+
+ if (!tb[DPAA2_CEETM_TCA_COPT]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
+ "tb");
+ return -EINVAL;
+ }
+
+ copt = nla_data(tb[DPAA2_CEETM_TCA_COPT]);
+
+ /* Configure an existing ceetm class */
+ if (cl) {
+ if (copt->type != cl->type) {
+ pr_err("CEETM: class %X is not of the provided type\n",
+ cl->common.classid);
+ return -EINVAL;
+ }
+
+ switch (copt->type) {
+ case CEETM_ROOT:
+ return dpaa2_ceetm_cls_change_root(cl, copt, dev);
+ case CEETM_PRIO:
+ return dpaa2_ceetm_cls_change_prio(cl, copt, dev);
+
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid class\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ return dpaa2_ceetm_cls_add(sch, classid, copt, arg, extack);
+}
+
+static void dpaa2_ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct dpaa2_ceetm_class *cl;
+ unsigned int i;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (arg->stop)
+ return;
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+ arg->stop = 1;
+ return;
+ }
+ arg->count++;
+ }
+ }
+}
+
+static int dpaa2_ceetm_cls_dump(struct Qdisc *sch, unsigned long arg,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+ struct nlattr *nest;
+ struct dpaa2_ceetm_tc_copt copt;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ sch_tree_lock(sch);
+
+ tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle;
+ tcm->tcm_handle = cl->common.classid;
+
+ memset(&copt, 0, sizeof(copt));
+
+ copt.shaped = cl->shaped;
+ copt.type = cl->type;
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ if (cl->child)
+ tcm->tcm_info = cl->child->handle;
+
+ memcpy(&copt.shaping_cfg, &cl->root.shaping_cfg,
+ sizeof(struct dpaa2_ceetm_shaping_cfg));
+
+ break;
+
+ case CEETM_PRIO:
+ if (cl->child)
+ tcm->tcm_info = cl->child->handle;
+
+ copt.mode = cl->prio.mode;
+ copt.weight = cl->prio.weight;
+
+ break;
+ }
+
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+ if (!nest)
+ goto nla_put_failure;
+ if (nla_put(skb, DPAA2_CEETM_TCA_COPT, sizeof(copt), &copt))
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+ sch_tree_unlock(sch);
+ return skb->len;
+
+nla_put_failure:
+ sch_tree_unlock(sch);
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+static int dpaa2_ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ sch_tree_lock(sch);
+ qdisc_class_hash_remove(&priv->clhash, &cl->common);
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+/* Get the class' child qdisc, if any */
+static struct Qdisc *dpaa2_ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ case CEETM_PRIO:
+ return cl->child;
+ }
+
+ return NULL;
+}
+
+static int dpaa2_ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old,
+ struct netlink_ext_ack *extack)
+{
+ if (new && strcmp(new->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int dpaa2_ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
+ struct gnet_dump *d)
+{
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+ struct gnet_stats_basic_packed tmp_bstats;
+ struct dpaa2_ceetm_tc_xstats xstats;
+ union dpni_statistics dpni_stats;
+ struct net_device *dev = qdisc_dev(sch);
+ struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
+ u8 ch_id = 0;
+ int err;
+
+ memset(&xstats, 0, sizeof(xstats));
+ memset(&tmp_bstats, 0, sizeof(tmp_bstats));
+
+ if (cl->type == CEETM_ROOT)
+ return 0;
+
+ err = dpni_get_statistics(priv_eth->mc_io, 0, priv_eth->mc_token, 3,
+ DPNI_BUILD_CH_TC(ch_id, cl->prio.qpri),
+ &dpni_stats);
+ if (err)
+ netdev_warn(dev, "dpni_get_stats(%d) failed - %d\n", 3, err);
+
+ xstats.ceetm_dequeue_bytes = dpni_stats.page_3.egress_dequeue_bytes;
+ xstats.ceetm_dequeue_frames = dpni_stats.page_3.egress_dequeue_frames;
+ xstats.ceetm_reject_bytes = dpni_stats.page_3.egress_reject_bytes;
+ xstats.ceetm_reject_frames = dpni_stats.page_3.egress_reject_frames;
+
+ return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static struct tcf_block *dpaa2_ceetm_tcf_block(struct Qdisc *sch,
+ unsigned long arg,
+ struct netlink_ext_ack *extack)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+ return cl ? cl->block : priv->block;
+}
+
+static unsigned long dpaa2_ceetm_tcf_bind(struct Qdisc *sch,
+ unsigned long parent,
+ u32 classid)
+{
+ struct dpaa2_ceetm_class *cl = dpaa2_ceetm_find(classid, sch);
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+ return (unsigned long)cl;
+}
+
+static void dpaa2_ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg)
+{
+ struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+}
+
+const struct Qdisc_class_ops dpaa2_ceetm_cls_ops = {
+ .graft = dpaa2_ceetm_cls_graft,
+ .leaf = dpaa2_ceetm_cls_leaf,
+ .find = dpaa2_ceetm_cls_find,
+ .change = dpaa2_ceetm_cls_change,
+ .delete = dpaa2_ceetm_cls_delete,
+ .walk = dpaa2_ceetm_cls_walk,
+ .tcf_block = dpaa2_ceetm_tcf_block,
+ .bind_tcf = dpaa2_ceetm_tcf_bind,
+ .unbind_tcf = dpaa2_ceetm_tcf_unbind,
+ .dump = dpaa2_ceetm_cls_dump,
+ .dump_stats = dpaa2_ceetm_cls_dump_stats,
+};
+
+struct Qdisc_ops dpaa2_ceetm_qdisc_ops __read_mostly = {
+ .id = "ceetm",
+ .priv_size = sizeof(struct dpaa2_ceetm_qdisc),
+ .cl_ops = &dpaa2_ceetm_cls_ops,
+ .init = dpaa2_ceetm_init,
+ .destroy = dpaa2_ceetm_destroy,
+ .change = dpaa2_ceetm_change,
+ .dump = dpaa2_ceetm_dump,
+ .attach = dpaa2_ceetm_attach,
+ .owner = THIS_MODULE,
+};
+
+/* Run the filters and classifiers attached to the qdisc on the provided skb */
+int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qdid, u8 *qpri)
+{
+ struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
+ struct dpaa2_ceetm_class *cl = NULL;
+ struct tcf_result res;
+ struct tcf_proto *tcf;
+ int result;
+
+ tcf = rcu_dereference_bh(priv->filter_list);
+ while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ case TC_ACT_SHOT:
+ /* No valid class found due to action */
+ return -1;
+ }
+#endif
+ cl = (void *)res.class;
+ if (!cl) {
+ /* The filter leads to the qdisc */
+ if (res.classid == sch->handle)
+ return 0;
+
+ cl = dpaa2_ceetm_find(res.classid, sch);
+ /* The filter leads to an invalid class */
+ if (!cl)
+ break;
+ }
+
+ /* The class might have its own filters attached */
+ tcf = rcu_dereference_bh(cl->filter_list);
+ }
+
+ /* No valid class found */
+ if (!cl)
+ return 0;
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ *qdid = cl->root.ch_id;
+
+ /* The root class does not have a child prio qdisc */
+ if (!cl->child)
+ return 0;
+
+ /* Run the prio qdisc classifiers */
+ return dpaa2_ceetm_classify(skb, cl->child, qdid, qpri);
+
+ case CEETM_PRIO:
+ *qpri = cl->prio.qpri;
+ break;
+ }
+
+ return 0;
+}
+
+int __init dpaa2_ceetm_register(void)
+{
+ int err = 0;
+
+ pr_debug(KBUILD_MODNAME ": " DPAA2_CEETM_DESCRIPTION "\n");
+
+ err = register_qdisc(&dpaa2_ceetm_qdisc_ops);
+ if (unlikely(err))
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): register_qdisc() = %d\n",
+ KBUILD_BASENAME ".c", __LINE__, __func__, err);
+
+ return err;
+}
+
+void __exit dpaa2_ceetm_unregister(void)
+{
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME ".c", __func__);
+
+ unregister_qdisc(&dpaa2_ceetm_qdisc_ops);
+}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
new file mode 100644
index 000000000000..0f914ef44d01
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
@@ -0,0 +1,207 @@
+/* Copyright 2017 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DPAA2_ETH_CEETM_H
+#define __DPAA2_ETH_CEETM_H
+
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+#include <net/netlink.h>
+
+#include "dpaa2-eth.h"
+
+/* For functional purposes, there are num_tx_queues pfifo qdiscs through which
+ * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20
+ * are reserved for the maximum 32 CEETM channels (majors and minors are in
+ * hex).
+ */
+#define PFIFO_MIN_OFFSET 0x21
+
+#define DPAA2_CEETM_MIN_WEIGHT 100
+#define DPAA2_CEETM_MAX_WEIGHT 24800
+
+#define DPAA2_CEETM_TD_THRESHOLD 1000
+
+enum wbfs_group_type {
+ WBFS_GRP_A,
+ WBFS_GRP_B,
+ WBFS_GRP_LARGE
+};
+
+enum {
+ DPAA2_CEETM_TCA_UNSPEC,
+ DPAA2_CEETM_TCA_COPT,
+ DPAA2_CEETM_TCA_QOPS,
+ DPAA2_CEETM_TCA_MAX,
+};
+
+/* CEETM configuration types */
+enum dpaa2_ceetm_type {
+ CEETM_ROOT = 1,
+ CEETM_PRIO,
+};
+
+enum {
+ STRICT_PRIORITY = 0,
+ WEIGHTED_A,
+ WEIGHTED_B,
+};
+
+struct dpaa2_ceetm_shaping_cfg {
+ __u64 cir; /* committed information rate */
+ __u64 eir; /* excess information rate */
+ __u16 cbs; /* committed burst size */
+ __u16 ebs; /* excess burst size */
+ __u8 coupled; /* shaper coupling */
+};
+
+extern const struct nla_policy ceetm_policy[DPAA2_CEETM_TCA_MAX];
+
+struct dpaa2_ceetm_class;
+struct dpaa2_ceetm_qdisc_stats;
+struct dpaa2_ceetm_class_stats;
+
+/* corresponds to CEETM shaping at LNI level */
+struct dpaa2_root_q {
+ struct Qdisc **qdiscs;
+ struct dpaa2_ceetm_qdisc_stats __percpu *qstats;
+};
+
+/* corresponds to the number of priorities a channel serves */
+struct dpaa2_prio_q {
+ struct dpaa2_ceetm_class *parent;
+ struct dpni_tx_priorities_cfg tx_prio_cfg;
+};
+
+struct dpaa2_ceetm_qdisc {
+ struct Qdisc_class_hash clhash;
+ struct tcf_proto *filter_list; /* qdisc attached filters */
+ struct tcf_block *block;
+
+ enum dpaa2_ceetm_type type; /* ROOT/PRIO */
+ bool shaped;
+ union {
+ struct dpaa2_root_q root;
+ struct dpaa2_prio_q prio;
+ };
+};
+
+/* CEETM Qdisc configuration parameters */
+struct dpaa2_ceetm_tc_qopt {
+ enum dpaa2_ceetm_type type;
+ __u16 shaped;
+ __u8 prio_group_A;
+ __u8 prio_group_B;
+ __u8 separate_groups;
+};
+
+/* root class - corresponds to a channel */
+struct dpaa2_root_c {
+ struct dpaa2_ceetm_shaping_cfg shaping_cfg;
+ u32 ch_id;
+};
+
+/* prio class - corresponds to a strict priority queue (group) */
+struct dpaa2_prio_c {
+ struct dpaa2_ceetm_class_stats __percpu *cstats;
+ u32 qpri;
+ u8 mode;
+ u16 weight;
+};
+
+struct dpaa2_ceetm_class {
+ struct Qdisc_class_common common;
+ struct tcf_proto *filter_list; /* class attached filters */
+ struct tcf_block *block;
+ struct Qdisc *parent;
+ struct Qdisc *child;
+
+ enum dpaa2_ceetm_type type; /* ROOT/PRIO */
+ bool shaped;
+ union {
+ struct dpaa2_root_c root;
+ struct dpaa2_prio_c prio;
+ };
+};
+
+/* CEETM Class configuration parameters */
+struct dpaa2_ceetm_tc_copt {
+ enum dpaa2_ceetm_type type;
+ struct dpaa2_ceetm_shaping_cfg shaping_cfg;
+ __u16 shaped;
+ __u8 mode;
+ __u16 weight;
+};
+
+/* CEETM stats */
+struct dpaa2_ceetm_qdisc_stats {
+ __u32 drops;
+};
+
+struct dpaa2_ceetm_class_stats {
+ /* Software counters */
+ struct gnet_stats_basic_packed bstats;
+ __u32 ern_drop_count;
+};
+
+struct dpaa2_ceetm_tc_xstats {
+ __u64 ceetm_dequeue_bytes;
+ __u64 ceetm_dequeue_frames;
+ __u64 ceetm_reject_bytes;
+ __u64 ceetm_reject_frames;
+};
+
+#ifdef CONFIG_FSL_DPAA2_ETH_CEETM
+int __init dpaa2_ceetm_register(void);
+void __exit dpaa2_ceetm_unregister(void);
+int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qdid, u8 *qpri);
+#else
+static inline int dpaa2_ceetm_register(void)
+{
+ return 0;
+}
+
+static inline void dpaa2_ceetm_unregister(void) {}
+
+static inline int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qdid, u8 *qpri)
+{
+ return 0;
+}
+#endif
+
+static inline bool dpaa2_eth_ceetm_is_enabled(struct dpaa2_eth_priv *priv)
+{
+ return priv->ceetm_en;
+}
+
+#endif
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
index a9afe46b837f..86d64f5b40f5 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
@@ -81,8 +81,8 @@ static int dpaa2_dbg_fqs_show(struct seq_file *file, void *offset)
int i, err;
seq_printf(file, "FQ stats for %s:\n", priv->net_dev->name);
- seq_printf(file, "%s%16s%16s%16s%16s\n",
- "VFQID", "CPU", "Type", "Frames", "Pending frames");
+ seq_printf(file, "%s%16s%16s%16s%16s%16s\n",
+ "VFQID", "CPU", "TC", "Type", "Frames", "Pending frames");
for (i = 0; i < priv->num_fqs; i++) {
fq = &priv->fq[i];
@@ -90,9 +90,14 @@ static int dpaa2_dbg_fqs_show(struct seq_file *file, void *offset)
if (err)
fcnt = 0;
- seq_printf(file, "%5d%16d%16s%16llu%16u\n",
+ /* Skip FQs with no traffic */
+ if (!fq->stats.frames && !fcnt)
+ continue;
+
+ seq_printf(file, "%5d%16d%16d%16s%16llu%16u\n",
fq->fqid,
fq->target_cpu,
+ fq->tc,
fq_type_to_str(fq),
fq->stats.frames,
fcnt);
@@ -127,16 +132,18 @@ static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset)
int i;
seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name);
- seq_printf(file, "%s%16s%16s%16s%16s\n",
- "CHID", "CPU", "Deq busy", "CDANs", "Buf count");
+ seq_printf(file, "%s%16s%16s%16s%16s%16s%16s\n",
+ "CHID", "CPU", "Deq busy", "Frames", "CDANs", "Avg Frm/CDAN", "Buf count");
for (i = 0; i < priv->num_channels; i++) {
ch = priv->channel[i];
- seq_printf(file, "%4d%16d%16llu%16llu%16d\n",
+ seq_printf(file, "%4d%16d%16llu%16llu%16llu%16llu%16d\n",
ch->ch_id,
ch->nctx.desired_cpu,
ch->stats.dequeue_portal_busy,
+ ch->stats.frames,
ch->stats.cdan,
+ ch->stats.frames / ch->stats.cdan,
ch->buf_count);
}
@@ -162,6 +169,62 @@ static const struct file_operations dpaa2_dbg_ch_ops = {
.release = single_release,
};
+static ssize_t dpaa2_dbg_reset_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct dpaa2_eth_priv *priv = file->private_data;
+ struct rtnl_link_stats64 *percpu_stats;
+ struct dpaa2_eth_drv_stats *percpu_extras;
+ struct dpaa2_eth_fq *fq;
+ struct dpaa2_eth_channel *ch;
+ int i;
+
+ for_each_online_cpu(i) {
+ percpu_stats = per_cpu_ptr(priv->percpu_stats, i);
+ memset(percpu_stats, 0, sizeof(*percpu_stats));
+
+ percpu_extras = per_cpu_ptr(priv->percpu_extras, i);
+ memset(percpu_extras, 0, sizeof(*percpu_extras));
+ }
+
+ for (i = 0; i < priv->num_fqs; i++) {
+ fq = &priv->fq[i];
+ memset(&fq->stats, 0, sizeof(fq->stats));
+ }
+
+ for (i = 0; i < priv->num_channels; i++) {
+ ch = priv->channel[i];
+ memset(&ch->stats, 0, sizeof(ch->stats));
+ }
+
+ return count;
+}
+
+static const struct file_operations dpaa2_dbg_reset_ops = {
+ .open = simple_open,
+ .write = dpaa2_dbg_reset_write,
+};
+
+static ssize_t dpaa2_dbg_reset_mc_write(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct dpaa2_eth_priv *priv = file->private_data;
+ int err;
+
+ err = dpni_reset_statistics(priv->mc_io, 0, priv->mc_token);
+ if (err)
+ netdev_err(priv->net_dev,
+ "dpni_reset_statistics() failed %d\n", err);
+
+ return count;
+}
+
+static const struct file_operations dpaa2_dbg_reset_mc_ops = {
+ .open = simple_open,
+ .write = dpaa2_dbg_reset_mc_write,
+};
+
void dpaa2_dbg_add(struct dpaa2_eth_priv *priv)
{
struct dentry *dir;
@@ -178,6 +241,14 @@ void dpaa2_dbg_add(struct dpaa2_eth_priv *priv)
/* per-fq stats file */
debugfs_create_file("ch_stats", 0444, dir, priv, &dpaa2_dbg_ch_ops);
+
+ /* reset stats */
+ debugfs_create_file("reset_stats", 0200, dir, priv,
+ &dpaa2_dbg_reset_ops);
+
+ /* reset MC stats */
+ debugfs_create_file("reset_mc_stats", 0222, dir, priv,
+ &dpaa2_dbg_reset_mc_ops);
}
void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 7af7cc7c8669..e19340b0e4a0 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -18,6 +18,7 @@
#include <net/sock.h>
#include "dpaa2-eth.h"
+#include "dpaa2-eth-ceetm.h"
/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
* using trace events only need to #include <trace/events/sched.h>
@@ -221,6 +222,7 @@ static void xdp_release_buf(struct dpaa2_eth_priv *priv,
struct dpaa2_eth_channel *ch,
dma_addr_t addr)
{
+ int retries = 0;
int err;
ch->xdp.drop_bufs[ch->xdp.drop_cnt++] = addr;
@@ -229,8 +231,11 @@ static void xdp_release_buf(struct dpaa2_eth_priv *priv,
while ((err = dpaa2_io_service_release(ch->dpio, priv->bpid,
ch->xdp.drop_bufs,
- ch->xdp.drop_cnt)) == -EBUSY)
+ ch->xdp.drop_cnt)) == -EBUSY) {
+ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
+ break;
cpu_relax();
+ }
if (err) {
free_bufs(priv, ch->xdp.drop_bufs, ch->xdp.drop_cnt);
@@ -348,6 +353,16 @@ out:
return xdp_act;
}
+static bool frame_is_tcp(const struct dpaa2_fd *fd, struct dpaa2_fas *fas)
+{
+ struct dpaa2_fapr *fapr = dpaa2_get_fapr(fas, false);
+
+ if (!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FAPRV))
+ return false;
+
+ return !!(fapr->faf_hi & DPAA2_FAF_HI_TCP_PRESENT);
+}
+
/* Main Rx frame processing routine */
static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
struct dpaa2_eth_channel *ch,
@@ -435,7 +450,10 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
percpu_stats->rx_packets++;
percpu_stats->rx_bytes += dpaa2_fd_get_len(fd);
- list_add_tail(&skb->list, ch->rx_list);
+ if (frame_is_tcp(fd, fas))
+ napi_gro_receive(&ch->napi, skb);
+ else
+ list_add_tail(&skb->list, ch->rx_list);
return;
@@ -445,6 +463,53 @@ err_frame_format:
percpu_stats->rx_dropped++;
}
+#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
+/* Processing of Rx frames received on the error FQ
+ * We check and print the error bits and then free the frame
+ */
+static void dpaa2_eth_rx_err(struct dpaa2_eth_priv *priv,
+ struct dpaa2_eth_channel *ch,
+ const struct dpaa2_fd *fd,
+ struct dpaa2_eth_fq *fq __always_unused)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ dma_addr_t addr = dpaa2_fd_get_addr(fd);
+ void *vaddr;
+ struct rtnl_link_stats64 *percpu_stats;
+ struct dpaa2_fas *fas;
+ u32 status = 0;
+ u32 fd_errors;
+ bool has_fas_errors = false;
+
+ vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
+ dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, DMA_BIDIRECTIONAL);
+
+ /* check frame errors in the FD field */
+ fd_errors = dpaa2_fd_get_ctrl(fd) & DPAA2_FD_RX_ERR_MASK;
+ if (likely(fd_errors)) {
+ has_fas_errors = (fd_errors & FD_CTRL_FAERR) &&
+ !!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV);
+ if (net_ratelimit())
+ netdev_dbg(priv->net_dev, "RX frame FD err: %08x\n",
+ fd_errors);
+ }
+
+ /* check frame errors in the FAS field */
+ if (has_fas_errors) {
+ fas = dpaa2_get_fas(vaddr, false);
+ status = le32_to_cpu(fas->status);
+ if (net_ratelimit())
+ netdev_dbg(priv->net_dev, "Rx frame FAS err: 0x%08x\n",
+ status & DPAA2_FAS_RX_ERR_MASK);
+ }
+ free_rx_fd(priv, fd, vaddr);
+
+ percpu_stats = this_cpu_ptr(priv->percpu_stats);
+ percpu_stats->rx_errors++;
+ ch->buf_count--;
+}
+#endif
+
/* Consume all frames pull-dequeued into the store. This is the simplest way to
* make sure we don't accidentally issue another volatile dequeue which would
* overwrite (leak) frames already in the store.
@@ -458,7 +523,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch,
struct dpaa2_eth_fq *fq = NULL;
struct dpaa2_dq *dq;
const struct dpaa2_fd *fd;
- int cleaned = 0;
+ int cleaned = 0, retries = 0;
int is_last;
do {
@@ -469,6 +534,11 @@ static int consume_frames(struct dpaa2_eth_channel *ch,
* the store until we get some sort of valid response
* token (either a valid frame or an "empty dequeue")
*/
+ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) {
+ netdev_err_once(priv->net_dev,
+ "Unable to read a valid dequeue response\n");
+ return 0;
+ }
continue;
}
@@ -477,12 +547,14 @@ static int consume_frames(struct dpaa2_eth_channel *ch,
fq->consume(priv, ch, fd, fq);
cleaned++;
+ retries = 0;
} while (!is_last);
if (!cleaned)
return 0;
fq->stats.frames += cleaned;
+ ch->stats.frames += cleaned;
/* A dequeue operation only pulls frames from a single queue
* into the store. Return the frame queue as an out param.
@@ -758,7 +830,7 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
unsigned int needed_headroom;
u32 fd_len;
u8 prio = 0;
- int err, i;
+ int err, i, ch_id = 0;
percpu_stats = this_cpu_ptr(priv->percpu_stats);
percpu_extras = this_cpu_ptr(priv->percpu_extras);
@@ -829,6 +901,15 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
}
fq = &priv->fq[queue_mapping];
+ if (dpaa2_eth_ceetm_is_enabled(priv)) {
+ err = dpaa2_ceetm_classify(skb, net_dev->qdisc, &ch_id, &prio);
+ if (err) {
+ free_tx_fd(priv, fq, &fd, false);
+ percpu_stats->tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+ }
+
fd_len = dpaa2_fd_get_len(&fd);
nq = netdev_get_tx_queue(net_dev, queue_mapping);
netdev_tx_sent_queue(nq, fd_len);
@@ -949,6 +1030,7 @@ static int add_bufs(struct dpaa2_eth_priv *priv,
u64 buf_array[DPAA2_ETH_BUFS_PER_CMD];
struct page *page;
dma_addr_t addr;
+ int retries = 0;
int i, err;
for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) {
@@ -980,8 +1062,11 @@ static int add_bufs(struct dpaa2_eth_priv *priv,
release_bufs:
/* In case the portal is busy, retry until successful */
while ((err = dpaa2_io_service_release(ch->dpio, bpid,
- buf_array, i)) == -EBUSY)
+ buf_array, i)) == -EBUSY) {
+ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
+ break;
cpu_relax();
+ }
/* If release command failed, clean up and bail out;
* not much else we can do about it
@@ -1032,16 +1117,21 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid)
static void drain_bufs(struct dpaa2_eth_priv *priv, int count)
{
u64 buf_array[DPAA2_ETH_BUFS_PER_CMD];
+ int retries = 0;
int ret;
do {
ret = dpaa2_io_service_acquire(NULL, priv->bpid,
buf_array, count);
if (ret < 0) {
+ if (ret == -EBUSY &&
+ retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES)
+ continue;
netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n");
return;
}
free_bufs(priv, buf_array, ret);
+ retries = 0;
} while (ret);
}
@@ -1094,7 +1184,7 @@ static int pull_channel(struct dpaa2_eth_channel *ch)
ch->store);
dequeues++;
cpu_relax();
- } while (err == -EBUSY);
+ } while (err == -EBUSY && dequeues < DPAA2_ETH_SWP_BUSY_RETRIES);
ch->stats.dequeue_portal_busy += dequeues;
if (unlikely(err))
@@ -1118,6 +1208,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
struct netdev_queue *nq;
int store_cleaned, work_done;
struct list_head rx_list;
+ int retries = 0;
int err;
ch = container_of(napi, struct dpaa2_eth_channel, napi);
@@ -1163,7 +1254,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
do {
err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx);
cpu_relax();
- } while (err == -EBUSY);
+ } while (err == -EBUSY && retries++ < DPAA2_ETH_SWP_BUSY_RETRIES);
WARN_ONCE(err, "CDAN notifications rearm failed on core %d",
ch->nctx.desired_cpu);
@@ -1208,31 +1299,67 @@ static void disable_ch_napi(struct dpaa2_eth_priv *priv)
}
}
-static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, bool enable)
+static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv,
+ bool tx_pause, bool pfc)
{
struct dpni_taildrop td = {0};
+ struct dpaa2_eth_fq *fq;
int i, err;
- if (priv->rx_td_enabled == enable)
- return;
+ /* FQ taildrop: threshold is in bytes, per frame queue. Enabled if
+ * flow control is disabled (as it might interfere with either the
+ * buffer pool depletion trigger for pause frames or with the group
+ * congestion trigger for PFC frames)
+ */
+ td.enable = !tx_pause;
+ if (priv->rx_fqtd_enabled == td.enable)
+ goto set_cgtd;
- td.enable = enable;
- td.threshold = DPAA2_ETH_TAILDROP_THRESH;
+ td.threshold = DPAA2_ETH_FQ_TAILDROP_THRESH;
+ td.units = DPNI_CONGESTION_UNIT_BYTES;
for (i = 0; i < priv->num_fqs; i++) {
- if (priv->fq[i].type != DPAA2_RX_FQ)
+ fq = &priv->fq[i];
+ if (fq->type != DPAA2_RX_FQ)
continue;
err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
- DPNI_CP_QUEUE, DPNI_QUEUE_RX, 0,
- priv->fq[i].flowid, &td);
+ DPNI_CP_QUEUE, DPNI_QUEUE_RX,
+ fq->tc, fq->flowid, &td);
if (err) {
netdev_err(priv->net_dev,
- "dpni_set_taildrop() failed\n");
- break;
+ "dpni_set_taildrop(FQ) failed\n");
+ return;
+ }
+ }
+
+ priv->rx_fqtd_enabled = td.enable;
+
+set_cgtd:
+ /* Congestion group taildrop: threshold is in frames, per group
+ * of FQs belonging to the same traffic class
+ * Enabled if general Tx pause disabled or if PFCs are enabled
+ * (congestion group threhsold for PFC generation is lower than the
+ * CG taildrop threshold, so it won't interfere with it; we also
+ * want frames in non-PFC enabled traffic classes to be kept in check)
+ */
+ td.enable = !tx_pause || (tx_pause && pfc);
+ if (priv->rx_cgtd_enabled == td.enable)
+ return;
+
+ td.threshold = DPAA2_ETH_CG_TAILDROP_THRESH(priv);
+ td.units = DPNI_CONGESTION_UNIT_FRAMES;
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
+ DPNI_CP_GROUP, DPNI_QUEUE_RX,
+ i, 0, &td);
+ if (err) {
+ netdev_err(priv->net_dev,
+ "dpni_set_taildrop(CG) failed\n");
+ return;
}
}
- priv->rx_td_enabled = enable;
+ priv->rx_cgtd_enabled = td.enable;
}
static void update_tx_fqids(struct dpaa2_eth_priv *priv);
@@ -1243,7 +1370,13 @@ static int link_state_update(struct dpaa2_eth_priv *priv)
bool tx_pause;
int err;
- err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
+ DPNI_LINK_AUTONEG_VER_MINOR) < 0)
+ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token,
+ &state);
+ else
+ err = dpni_get_link_state_v2(priv->mc_io, 0, priv->mc_token,
+ &state);
if (unlikely(err)) {
netdev_err(priv->net_dev,
"dpni_get_link_state() failed\n");
@@ -1254,9 +1387,8 @@ static int link_state_update(struct dpaa2_eth_priv *priv)
* Rx FQ taildrop configuration as well. We configure taildrop
* only when pause frame generation is disabled.
*/
- tx_pause = !!(state.options & DPNI_LINK_OPT_PAUSE) ^
- !!(state.options & DPNI_LINK_OPT_ASYM_PAUSE);
- dpaa2_eth_set_rx_taildrop(priv, !tx_pause);
+ tx_pause = dpaa2_eth_tx_pause_enabled(state.options);
+ dpaa2_eth_set_rx_taildrop(priv, tx_pause, priv->pfc_enabled);
/* Chech link state; speed / duplex changes are not treated yet */
if (priv->link_state.up == state.up)
@@ -1376,7 +1508,7 @@ static void wait_for_egress_fq_empty(struct dpaa2_eth_priv *priv)
goto out;
do {
- err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, 6,
+ err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, 6, 0,
&stats);
if (err)
goto out;
@@ -1972,17 +2104,13 @@ static int update_xps(struct dpaa2_eth_priv *priv)
return err;
}
-static int dpaa2_eth_setup_tc(struct net_device *net_dev,
- enum tc_setup_type type, void *type_data)
+static int dpaa2_eth_setup_mqprio(struct net_device *net_dev,
+ struct tc_mqprio_qopt *mqprio)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- struct tc_mqprio_qopt *mqprio = type_data;
u8 num_tc, num_queues;
int i;
- if (type != TC_SETUP_QDISC_MQPRIO)
- return -EOPNOTSUPP;
-
mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
num_queues = dpaa2_eth_queue_count(priv);
num_tc = mqprio->num_tc;
@@ -2014,6 +2142,20 @@ out:
return 0;
}
+static int dpaa2_eth_setup_tc(struct net_device *net_dev,
+ enum tc_setup_type type,
+ void *type_data)
+{
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ return 0;
+ case TC_SETUP_QDISC_MQPRIO:
+ return dpaa2_eth_setup_mqprio(net_dev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct net_device_ops dpaa2_eth_ops = {
.ndo_open = dpaa2_eth_open,
.ndo_start_xmit = dpaa2_eth_tx,
@@ -2046,7 +2188,6 @@ static struct fsl_mc_device *setup_dpcon(struct dpaa2_eth_priv *priv)
{
struct fsl_mc_device *dpcon;
struct device *dev = priv->net_dev->dev.parent;
- struct dpcon_attr attrs;
int err;
err = fsl_mc_object_allocate(to_fsl_mc_device(dev),
@@ -2071,12 +2212,6 @@ static struct fsl_mc_device *setup_dpcon(struct dpaa2_eth_priv *priv)
goto close;
}
- err = dpcon_get_attributes(priv->mc_io, 0, dpcon->mc_handle, &attrs);
- if (err) {
- dev_err(dev, "dpcon_get_attributes() failed\n");
- goto close;
- }
-
err = dpcon_enable(priv->mc_io, 0, dpcon->mc_handle);
if (err) {
dev_err(dev, "dpcon_enable() failed\n");
@@ -2303,6 +2438,7 @@ static void set_fq_affinity(struct dpaa2_eth_priv *priv)
fq = &priv->fq[i];
switch (fq->type) {
case DPAA2_RX_FQ:
+ case DPAA2_RX_ERR_FQ:
fq->target_cpu = rx_cpu;
rx_cpu = cpumask_next(rx_cpu, &priv->dpio_cpumask);
if (rx_cpu >= nr_cpu_ids)
@@ -2325,7 +2461,7 @@ static void set_fq_affinity(struct dpaa2_eth_priv *priv)
static void setup_fqs(struct dpaa2_eth_priv *priv)
{
- int i;
+ int i, j;
/* We have one TxConf FQ per Tx flow.
* The number of Tx and Rx queues is the same.
@@ -2337,12 +2473,21 @@ static void setup_fqs(struct dpaa2_eth_priv *priv)
priv->fq[priv->num_fqs++].flowid = (u16)i;
}
- for (i = 0; i < dpaa2_eth_queue_count(priv); i++) {
- priv->fq[priv->num_fqs].type = DPAA2_RX_FQ;
- priv->fq[priv->num_fqs].consume = dpaa2_eth_rx;
- priv->fq[priv->num_fqs++].flowid = (u16)i;
+ for (j = 0; j < dpaa2_eth_tc_count(priv); j++) {
+ for (i = 0; i < dpaa2_eth_queue_count(priv); i++) {
+ priv->fq[priv->num_fqs].type = DPAA2_RX_FQ;
+ priv->fq[priv->num_fqs].consume = dpaa2_eth_rx;
+ priv->fq[priv->num_fqs].tc = (u8)j;
+ priv->fq[priv->num_fqs++].flowid = (u16)i;
+ }
}
+#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
+ /* We have exactly one Rx error queue per DPNI */
+ priv->fq[priv->num_fqs].type = DPAA2_RX_ERR_FQ;
+ priv->fq[priv->num_fqs++].consume = dpaa2_eth_rx_err;
+#endif
+
/* For each FQ, decide on which core to process incoming frames */
set_fq_affinity(priv);
}
@@ -2590,6 +2735,118 @@ out_err:
priv->enqueue = dpaa2_eth_enqueue_qd;
}
+/* Configure ingress classification based on VLAN PCP */
+static int set_vlan_qos(struct dpaa2_eth_priv *priv)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ struct dpkg_profile_cfg kg_cfg = {0};
+ struct dpni_qos_tbl_cfg qos_cfg = {0};
+ struct dpni_rule_cfg key_params;
+ void *dma_mem, *key, *mask;
+ u8 key_size = 2; /* VLAN TCI field */
+ int i, pcp, err;
+
+ /* VLAN-based classification only makes sense if we have multiple
+ * traffic classes.
+ * Also, we need to extract just the 3-bit PCP field from the VLAN
+ * header and we can only do that by using a mask
+ */
+ if (dpaa2_eth_tc_count(priv) == 1 || !dpaa2_eth_fs_mask_enabled(priv)) {
+ dev_dbg(dev, "VLAN-based QoS classification not supported\n");
+ return -ENOTSUPP;
+ }
+
+ dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL);
+ if (!dma_mem)
+ return -ENOMEM;
+
+ kg_cfg.num_extracts = 1;
+ kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_HDR;
+ kg_cfg.extracts[0].extract.from_hdr.prot = NET_PROT_VLAN;
+ kg_cfg.extracts[0].extract.from_hdr.type = DPKG_FULL_FIELD;
+ kg_cfg.extracts[0].extract.from_hdr.field = NH_FLD_VLAN_TCI;
+
+ err = dpni_prepare_key_cfg(&kg_cfg, dma_mem);
+ if (err) {
+ dev_err(dev, "dpni_prepare_key_cfg failed\n");
+ goto out_free_tbl;
+ }
+
+ /* set QoS table */
+ qos_cfg.default_tc = 0;
+ qos_cfg.discard_on_miss = 0;
+ qos_cfg.key_cfg_iova = dma_map_single(dev, dma_mem,
+ DPAA2_CLASSIFIER_DMA_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, qos_cfg.key_cfg_iova)) {
+ dev_err(dev, "QoS table DMA mapping failed\n");
+ err = -ENOMEM;
+ goto out_free_tbl;
+ }
+
+ err = dpni_set_qos_table(priv->mc_io, 0, priv->mc_token, &qos_cfg);
+ if (err) {
+ dev_err(dev, "dpni_set_qos_table failed\n");
+ goto out_unmap_tbl;
+ }
+
+ /* Add QoS table entries */
+ key = kzalloc(key_size * 2, GFP_KERNEL);
+ if (!key) {
+ err = -ENOMEM;
+ goto out_unmap_tbl;
+ }
+ mask = key + key_size;
+ *(u16 *)mask = cpu_to_be16(VLAN_PRIO_MASK);
+
+ key_params.key_iova = dma_map_single(dev, key, key_size * 2,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, key_params.key_iova)) {
+ dev_err(dev, "Qos table entry DMA mapping failed\n");
+ err = -ENOMEM;
+ goto out_free_key;
+ }
+
+ key_params.mask_iova = key_params.key_iova + key_size;
+ key_params.key_size = key_size;
+
+ /* We add rules for PCP-based distribution starting with highest
+ * priority (VLAN PCP = 7). If this DPNI doesn't have enough traffic
+ * classes to accommodate all priority levels, the lowest ones end up
+ * on TC 0 which was configured as default
+ */
+ for (i = dpaa2_eth_tc_count(priv) - 1, pcp = 7; i >= 0; i--, pcp--) {
+ *(u16 *)key = cpu_to_be16(pcp << VLAN_PRIO_SHIFT);
+ dma_sync_single_for_device(dev, key_params.key_iova,
+ key_size * 2, DMA_TO_DEVICE);
+
+ err = dpni_add_qos_entry(priv->mc_io, 0, priv->mc_token,
+ &key_params, i, i);
+ if (err) {
+ dev_err(dev, "dpni_add_qos_entry failed\n");
+ dpni_clear_qos_table(priv->mc_io, 0, priv->mc_token);
+ goto out_unmap_key;
+ }
+ }
+
+ priv->vlan_cls_enabled = true;
+
+ /* Table and key memory is not persistent, clean everything up after
+ * configuration is finished
+ */
+out_unmap_key:
+ dma_unmap_single(dev, key_params.key_iova, key_size * 2, DMA_TO_DEVICE);
+out_free_key:
+ kfree(key);
+out_unmap_tbl:
+ dma_unmap_single(dev, qos_cfg.key_cfg_iova, DPAA2_CLASSIFIER_DMA_SIZE,
+ DMA_TO_DEVICE);
+out_free_tbl:
+ kfree(dma_mem);
+
+ return err;
+}
+
/* Configure the DPNI object this interface is associated with */
static int setup_dpni(struct fsl_mc_device *ls_dev)
{
@@ -2652,6 +2909,10 @@ static int setup_dpni(struct fsl_mc_device *ls_dev)
goto close;
}
+ err = set_vlan_qos(priv);
+ if (err && err != -ENOTSUPP)
+ goto close;
+
priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) *
dpaa2_eth_fs_count(priv), GFP_KERNEL);
if (!priv->cls_rules) {
@@ -2688,7 +2949,7 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv,
int err;
err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
- DPNI_QUEUE_RX, 0, fq->flowid, &queue, &qid);
+ DPNI_QUEUE_RX, fq->tc, fq->flowid, &queue, &qid);
if (err) {
dev_err(dev, "dpni_get_queue(RX) failed\n");
return err;
@@ -2701,7 +2962,7 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv,
queue.destination.priority = 1;
queue.user_context = (u64)(uintptr_t)fq;
err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
- DPNI_QUEUE_RX, 0, fq->flowid,
+ DPNI_QUEUE_RX, fq->tc, fq->flowid,
DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST,
&queue);
if (err) {
@@ -2710,6 +2971,10 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv,
}
/* xdp_rxq setup */
+ /* only once for each channel */
+ if (fq->tc > 0)
+ return 0;
+
err = xdp_rxq_info_reg(&fq->channel->xdp_rxq, priv->net_dev,
fq->flowid);
if (err) {
@@ -2775,6 +3040,40 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv,
return 0;
}
+#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
+static int setup_rx_err_flow(struct dpaa2_eth_priv *priv,
+ struct dpaa2_eth_fq *fq)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ struct dpni_queue q = { { 0 } };
+ struct dpni_queue_id qid;
+ u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST;
+ int err;
+
+ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
+ DPNI_QUEUE_RX_ERR, 0, 0, &q, &qid);
+ if (err) {
+ dev_err(dev, "dpni_get_queue() failed (%d)\n", err);
+ return err;
+ }
+
+ fq->fqid = qid.fqid;
+
+ q.destination.id = fq->channel->dpcon_id;
+ q.destination.type = DPNI_DEST_DPCON;
+ q.destination.priority = 1;
+ q.user_context = (u64)fq;
+ err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
+ DPNI_QUEUE_RX_ERR, 0, 0, q_opt, &q);
+ if (err) {
+ dev_err(dev, "dpni_set_queue() failed (%d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+#endif
+
/* Supported header fields for Rx hash distribution key */
static const struct dpaa2_eth_dist_fields dist_fields[] = {
{
@@ -2847,7 +3146,7 @@ static int config_legacy_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
{
struct device *dev = priv->net_dev->dev.parent;
struct dpni_rx_tc_dist_cfg dist_cfg;
- int err;
+ int i, err = 0;
memset(&dist_cfg, 0, sizeof(dist_cfg));
@@ -2855,9 +3154,14 @@ static int config_legacy_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
dist_cfg.dist_mode = DPNI_DIST_MODE_HASH;
- err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg);
- if (err)
- dev_err(dev, "dpni_set_rx_tc_dist failed\n");
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token,
+ i, &dist_cfg);
+ if (err) {
+ dev_err(dev, "dpni_set_rx_tc_dist failed\n");
+ break;
+ }
+ }
return err;
}
@@ -2867,7 +3171,7 @@ static int config_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
{
struct device *dev = priv->net_dev->dev.parent;
struct dpni_rx_dist_cfg dist_cfg;
- int err;
+ int i, err = 0;
memset(&dist_cfg, 0, sizeof(dist_cfg));
@@ -2875,9 +3179,15 @@ static int config_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
dist_cfg.enable = 1;
- err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
- if (err)
- dev_err(dev, "dpni_set_rx_hash_dist failed\n");
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ dist_cfg.tc = i;
+ err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token,
+ &dist_cfg);
+ if (err) {
+ dev_err(dev, "dpni_set_rx_hash_dist failed\n");
+ break;
+ }
+ }
return err;
}
@@ -2887,7 +3197,7 @@ static int config_cls_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
{
struct device *dev = priv->net_dev->dev.parent;
struct dpni_rx_dist_cfg dist_cfg;
- int err;
+ int i, err = 0;
memset(&dist_cfg, 0, sizeof(dist_cfg));
@@ -2895,9 +3205,15 @@ static int config_cls_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
dist_cfg.enable = 1;
- err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
- if (err)
- dev_err(dev, "dpni_set_rx_fs_dist failed\n");
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ dist_cfg.tc = i;
+ err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token,
+ &dist_cfg);
+ if (err) {
+ dev_err(dev, "dpni_set_rx_fs_dist failed\n");
+ break;
+ }
+ }
return err;
}
@@ -3127,7 +3443,11 @@ static int bind_dpni(struct dpaa2_eth_priv *priv)
/* Configure handling of error frames */
err_cfg.errors = DPAA2_FAS_RX_ERR_MASK;
err_cfg.set_frame_annotation = 1;
+#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
+ err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE;
+#else
err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD;
+#endif
err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token,
&err_cfg);
if (err) {
@@ -3144,6 +3464,11 @@ static int bind_dpni(struct dpaa2_eth_priv *priv)
case DPAA2_TX_CONF_FQ:
err = setup_tx_flow(priv, &priv->fq[i]);
break;
+#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE
+ case DPAA2_RX_ERR_FQ:
+ err = setup_rx_err_flow(priv, &priv->fq[i]);
+ break;
+#endif
default:
dev_err(dev, "Invalid FQ type %d\n", priv->fq[i].type);
return -EINVAL;
@@ -3441,6 +3766,233 @@ static void del_ch_napi(struct dpaa2_eth_priv *priv)
}
}
+#ifdef CONFIG_FSL_DPAA2_ETH_DCB
+static int dpaa2_eth_dcbnl_ieee_getpfc(struct net_device *net_dev,
+ struct ieee_pfc *pfc)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ if (!(priv->link_state.options & DPNI_LINK_OPT_PFC_PAUSE))
+ return 0;
+
+ memcpy(pfc, &priv->pfc, sizeof(priv->pfc));
+ pfc->pfc_cap = dpaa2_eth_tc_count(priv);
+
+ return 0;
+}
+
+static inline bool is_prio_enabled(u8 pfc_en, u8 tc)
+{
+ return !!(pfc_en & (1 << tc));
+}
+
+static int set_pfc_cn(struct dpaa2_eth_priv *priv, u8 pfc_en)
+{
+ struct dpni_congestion_notification_cfg cfg = {0};
+ int i, err;
+
+ cfg.notification_mode = DPNI_CONG_OPT_FLOW_CONTROL;
+ cfg.units = DPNI_CONGESTION_UNIT_FRAMES;
+ cfg.message_iova = 0ULL;
+ cfg.message_ctx = 0ULL;
+
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ if (is_prio_enabled(pfc_en, i)) {
+ cfg.threshold_entry = DPAA2_ETH_CN_THRESH_ENTRY(priv);
+ cfg.threshold_exit = DPAA2_ETH_CN_THRESH_EXIT(priv);
+ } else {
+ /* For priorities not set in the pfc_en mask, we leave
+ * the congestion thresholds at zero, which effectively
+ * disables generation of PFC frames for them
+ */
+ cfg.threshold_entry = 0;
+ cfg.threshold_exit = 0;
+ }
+
+ err = dpni_set_congestion_notification(priv->mc_io, 0,
+ priv->mc_token,
+ DPNI_QUEUE_RX, i, &cfg);
+ if (err) {
+ netdev_err(priv->net_dev,
+ "dpni_set_congestion_notification failed\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int dpaa2_eth_dcbnl_ieee_setpfc(struct net_device *net_dev,
+ struct ieee_pfc *pfc)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ struct dpni_link_cfg link_cfg = {0};
+ bool tx_pause;
+ int err;
+
+ if (pfc->mbc || pfc->delay)
+ return -EOPNOTSUPP;
+
+ /* If same PFC enabled mask, nothing to do */
+ if (priv->pfc.pfc_en == pfc->pfc_en)
+ return 0;
+
+ /* We allow PFC configuration even if it won't have any effect until
+ * general pause frames are enabled
+ */
+ tx_pause = dpaa2_eth_tx_pause_enabled(priv->link_state.options);
+ if (!dpaa2_eth_rx_pause_enabled(priv->link_state.options) || !tx_pause)
+ netdev_warn(net_dev, "Pause support must be enabled in order for PFC to work!\n");
+
+ link_cfg.rate = priv->link_state.rate;
+ link_cfg.options = priv->link_state.options;
+ if (pfc->pfc_en)
+ link_cfg.options |= DPNI_LINK_OPT_PFC_PAUSE;
+ else
+ link_cfg.options &= ~DPNI_LINK_OPT_PFC_PAUSE;
+ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &link_cfg);
+ if (err) {
+ netdev_err(net_dev, "dpni_set_link_cfg failed\n");
+ return err;
+ }
+
+ /* Configure congestion notifications for the enabled priorities */
+ err = set_pfc_cn(priv, pfc->pfc_en);
+ if (err)
+ return err;
+
+ memcpy(&priv->pfc, pfc, sizeof(priv->pfc));
+ priv->pfc_enabled = !!pfc->pfc_en;
+
+ dpaa2_eth_set_rx_taildrop(priv, tx_pause, priv->pfc_enabled);
+
+ return 0;
+}
+
+static u8 dpaa2_eth_dcbnl_getdcbx(struct net_device *net_dev)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ return priv->dcbx_mode;
+}
+
+static u8 dpaa2_eth_dcbnl_setdcbx(struct net_device *net_dev, u8 mode)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ priv->dcbx_mode = mode;
+ return 0;
+}
+
+static u8 dpaa2_eth_dcbnl_getcap(struct net_device *net_dev, int capid, u8 *cap)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ switch (capid) {
+ case DCB_CAP_ATTR_PFC:
+ *cap = true;
+ break;
+ case DCB_CAP_ATTR_PFC_TCS:
+ *cap = 1 << (dpaa2_eth_tc_count(priv) - 1);
+ break;
+ case DCB_CAP_ATTR_DCBX:
+ *cap = priv->dcbx_mode;
+ break;
+ default:
+ *cap = false;
+ break;
+ }
+
+ return 0;
+}
+
+const struct dcbnl_rtnl_ops dpaa2_eth_dcbnl_ops = {
+ .ieee_getpfc = dpaa2_eth_dcbnl_ieee_getpfc,
+ .ieee_setpfc = dpaa2_eth_dcbnl_ieee_setpfc,
+ .getdcbx = dpaa2_eth_dcbnl_getdcbx,
+ .setdcbx = dpaa2_eth_dcbnl_setdcbx,
+ .getcap = dpaa2_eth_dcbnl_getcap,
+};
+#endif
+
+/* SysFS support */
+static ssize_t dpaa2_eth_show_tx_shaping(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev));
+ /* No MC API for getting the shaping config. We're stateful. */
+ struct dpni_tx_shaping_cfg *scfg = &priv->shaping_cfg;
+
+ return sprintf(buf, "%u %hu\n", scfg->rate_limit, scfg->max_burst_size);
+}
+
+static ssize_t dpaa2_eth_write_tx_shaping(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int err, items;
+ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev));
+ struct dpni_tx_shaping_cfg scfg, ercfg = {0};
+
+ items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size);
+ if (items != 2) {
+ pr_err("Expected format: \"rate_limit(Mbps) max_burst_size(bytes)\"\n");
+ return -EINVAL;
+ }
+ /* Size restriction as per MC API documentation */
+ if (scfg.max_burst_size > DPAA2_ETH_MAX_BURST_SIZE) {
+ pr_err("max_burst_size must be <= %d\n",
+ DPAA2_ETH_MAX_BURST_SIZE);
+ return -EINVAL;
+ }
+
+ err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg,
+ &ercfg, 0);
+ if (err) {
+ dev_err(dev, "dpni_set_tx_shaping() failed\n");
+ return -EPERM;
+ }
+ /* If successful, save the current configuration for future inquiries */
+ priv->shaping_cfg = scfg;
+
+ return count;
+}
+
+static struct device_attribute dpaa2_eth_attrs[] = {
+ __ATTR(tx_shaping,
+ 0600,
+ dpaa2_eth_show_tx_shaping,
+ dpaa2_eth_write_tx_shaping),
+};
+
+static void dpaa2_eth_sysfs_init(struct device *dev)
+{
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) {
+ err = device_create_file(dev, &dpaa2_eth_attrs[i]);
+ if (err) {
+ dev_err(dev, "ERROR creating sysfs file\n");
+ goto undo;
+ }
+ }
+ return;
+
+undo:
+ while (i > 0)
+ device_remove_file(dev, &dpaa2_eth_attrs[--i]);
+}
+
+static void dpaa2_eth_sysfs_remove(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++)
+ device_remove_file(dev, &dpaa2_eth_attrs[i]);
+}
+
static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
{
struct device *dev;
@@ -3530,6 +4082,15 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
if (err)
goto err_alloc_rings;
+#ifdef CONFIG_FSL_DPAA2_ETH_DCB
+ if (dpaa2_eth_has_pause_support(priv) && priv->vlan_cls_enabled) {
+ priv->dcbx_mode = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
+ net_dev->dcbnl_ops = &dpaa2_eth_dcbnl_ops;
+ } else {
+ dev_dbg(dev, "PFC not supported\n");
+ }
+#endif
+
err = setup_irqs(dpni_dev);
if (err) {
netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n");
@@ -3551,6 +4112,7 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
#ifdef CONFIG_DEBUG_FS
dpaa2_dbg_add(priv);
#endif
+ dpaa2_eth_sysfs_init(&net_dev->dev);
dev_info(dev, "Probed interface %s\n", net_dev->name);
return 0;
@@ -3598,6 +4160,8 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
#ifdef CONFIG_DEBUG_FS
dpaa2_dbg_remove(priv);
#endif
+ dpaa2_eth_sysfs_remove(&net_dev->dev);
+
unregister_netdev(net_dev);
if (priv->do_link_poll)
@@ -3648,18 +4212,27 @@ static int __init dpaa2_eth_driver_init(void)
dpaa2_eth_dbg_init();
err = fsl_mc_driver_register(&dpaa2_eth_driver);
- if (err) {
- dpaa2_eth_dbg_exit();
- return err;
- }
+ if (err)
+ goto out_debugfs_err;
+
+ err = dpaa2_ceetm_register();
+ if (err)
+ goto out_ceetm_err;
return 0;
+
+out_ceetm_err:
+ fsl_mc_driver_unregister(&dpaa2_eth_driver);
+out_debugfs_err:
+ dpaa2_eth_dbg_exit();
+ return err;
}
static void __exit dpaa2_eth_driver_exit(void)
{
- dpaa2_eth_dbg_exit();
+ dpaa2_ceetm_unregister();
fsl_mc_driver_unregister(&dpaa2_eth_driver);
+ dpaa2_eth_dbg_exit();
}
module_init(dpaa2_eth_driver_init);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
index 4570ed53c6c7..8f0a04979d6c 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -6,6 +6,7 @@
#ifndef __DPAA2_ETH_H
#define __DPAA2_ETH_H
+#include <linux/dcbnl.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/fsl/mc.h>
@@ -35,27 +36,49 @@
/* Convert L3 MTU to L2 MFL */
#define DPAA2_ETH_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN)
-/* Set the taildrop threshold (in bytes) to allow the enqueue of several jumbo
- * frames in the Rx queues (length of the current frame is not
- * taken into account when making the taildrop decision)
+/* Set the taildrop threshold (in bytes) to allow the enqueue of a large
+ * enuough number of jumbo frames in the Rx queues (length of the current
+ * frame is not taken into account when making the taildrop decision)
*/
-#define DPAA2_ETH_TAILDROP_THRESH (64 * 1024)
+#define DPAA2_ETH_FQ_TAILDROP_THRESH (1024 * 1024)
+
+/* Maximum burst size value for Tx shaping */
+#define DPAA2_ETH_MAX_BURST_SIZE 0xF7FF
/* Maximum number of Tx confirmation frames to be processed
* in a single NAPI call
*/
#define DPAA2_ETH_TXCONF_PER_NAPI 256
-/* Buffer quota per queue. Must be large enough such that for minimum sized
- * frames taildrop kicks in before the bpool gets depleted, so we compute
- * how many 64B frames fit inside the taildrop threshold and add a margin
- * to accommodate the buffer refill delay.
+/* Buffer qouta per channel. We want to keep in check number of ingress frames
+ * in flight: for small sized frames, congestion group taildrop may kick in
+ * first; for large sizes, Rx FQ taildrop threshold will ensure only a
+ * reasonable number of frames will be pending at any given time.
+ * Ingress frame drop due to buffer pool depletion should be a corner case only
*/
-#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE (DPAA2_ETH_TAILDROP_THRESH / 64)
-#define DPAA2_ETH_NUM_BUFS (DPAA2_ETH_MAX_FRAMES_PER_QUEUE + 256)
+#define DPAA2_ETH_NUM_BUFS 1280
#define DPAA2_ETH_REFILL_THRESH \
(DPAA2_ETH_NUM_BUFS - DPAA2_ETH_BUFS_PER_CMD)
+/* Congestion group taildrop threshold: number of frames allowed to accumulate
+ * at any moment in a group of Rx queues belonging to the same traffic class.
+ * Choose value such that we don't risk depleting the buffer pool before the
+ * taildrop kicks in
+ */
+#define DPAA2_ETH_CG_TAILDROP_THRESH(priv) \
+ (1024 * dpaa2_eth_queue_count(priv) / dpaa2_eth_tc_count(priv))
+
+/* Congestion group notification threshold: when this many frames accumulate
+ * on the Rx queues belonging to the same TC, the MAC is instructed to send
+ * PFC frames for that TC.
+ * When number of pending frames drops below exit threshold transmission of
+ * PFC frames is stopped.
+ */
+#define DPAA2_ETH_CN_THRESH_ENTRY(priv) \
+ (DPAA2_ETH_CG_TAILDROP_THRESH(priv) / 2)
+#define DPAA2_ETH_CN_THRESH_EXIT(priv) \
+ (DPAA2_ETH_CN_THRESH_ENTRY(priv) * 3 / 4)
+
/* Maximum number of buffers that can be acquired/released through a single
* QBMan command
*/
@@ -155,6 +178,49 @@ struct dpaa2_fas {
*/
#define DPAA2_TS_OFFSET 0x8
+/* Frame annotation parse results */
+struct dpaa2_fapr {
+ /* 64-bit word 1 */
+ __le32 faf_lo;
+ __le16 faf_ext;
+ __le16 nxt_hdr;
+ /* 64-bit word 2 */
+ __le64 faf_hi;
+ /* 64-bit word 3 */
+ u8 last_ethertype_offset;
+ u8 vlan_tci_offset_n;
+ u8 vlan_tci_offset_1;
+ u8 llc_snap_offset;
+ u8 eth_offset;
+ u8 ip1_pid_offset;
+ u8 shim_offset_2;
+ u8 shim_offset_1;
+ /* 64-bit word 4 */
+ u8 l5_offset;
+ u8 l4_offset;
+ u8 gre_offset;
+ u8 l3_offset_n;
+ u8 l3_offset_1;
+ u8 mpls_offset_n;
+ u8 mpls_offset_1;
+ u8 pppoe_offset;
+ /* 64-bit word 5 */
+ __le16 running_sum;
+ __le16 gross_running_sum;
+ u8 ipv6_frag_offset;
+ u8 nxt_hdr_offset;
+ u8 routing_hdr_offset_2;
+ u8 routing_hdr_offset_1;
+ /* 64-bit word 6 */
+ u8 reserved[5]; /* Soft-parsing context */
+ u8 ip_proto_offset_n;
+ u8 nxt_hdr_frag_offset;
+ u8 parse_error_code;
+};
+
+#define DPAA2_FAPR_OFFSET 0x10
+#define DPAA2_FAPR_SIZE sizeof((struct dpaa2_fapr))
+
/* Frame annotation egress action descriptor */
#define DPAA2_FAEAD_OFFSET 0x58
@@ -185,6 +251,11 @@ static inline __le64 *dpaa2_get_ts(void *buf_addr, bool swa)
return dpaa2_get_hwa(buf_addr, swa) + DPAA2_TS_OFFSET;
}
+static inline struct dpaa2_fapr *dpaa2_get_fapr(void *buf_addr, bool swa)
+{
+ return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAPR_OFFSET;
+}
+
static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa)
{
return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAEAD_OFFSET;
@@ -236,6 +307,9 @@ static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa)
DPAA2_FAS_L3CE | \
DPAA2_FAS_L4CE)
+/* TCP indication in Frame Annotation Parse Results */
+#define DPAA2_FAF_HI_TCP_PRESENT BIT(23)
+
/* Time in milliseconds between link state updates */
#define DPAA2_ETH_LINK_STATE_REFRESH 1000
@@ -245,6 +319,14 @@ static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa)
*/
#define DPAA2_ETH_ENQUEUE_RETRIES 10
+/* Number of times to retry DPIO portal operations while waiting
+ * for portal to finish executing current command and become
+ * available. We want to avoid being stuck in a while loop in case
+ * hardware becomes unresponsive, but not give up too easily if
+ * the portal really is busy for valid reasons
+ */
+#define DPAA2_ETH_SWP_BUSY_RETRIES 1000
+
/* Driver statistics, other than those in struct rtnl_link_stats64.
* These are usually collected per-CPU and aggregated by ethtool.
*/
@@ -279,14 +361,20 @@ struct dpaa2_eth_ch_stats {
__u64 xdp_tx;
__u64 xdp_tx_err;
__u64 xdp_redirect;
+ /* Must be last, does not show up in ethtool stats */
+ __u64 frames;
};
/* Maximum number of queues associated with a DPNI */
#define DPAA2_ETH_MAX_TCS 8
-#define DPAA2_ETH_MAX_RX_QUEUES 16
+#define DPAA2_ETH_MAX_RX_QUEUES_PER_TC 16
+#define DPAA2_ETH_MAX_RX_QUEUES \
+ (DPAA2_ETH_MAX_RX_QUEUES_PER_TC * DPAA2_ETH_MAX_TCS)
#define DPAA2_ETH_MAX_TX_QUEUES 16
+#define DPAA2_ETH_MAX_RX_ERR_QUEUES 1
#define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \
- DPAA2_ETH_MAX_TX_QUEUES)
+ DPAA2_ETH_MAX_TX_QUEUES + \
+ DPAA2_ETH_MAX_RX_ERR_QUEUES)
#define DPAA2_ETH_MAX_NETDEV_QUEUES \
(DPAA2_ETH_MAX_TX_QUEUES * DPAA2_ETH_MAX_TCS)
@@ -295,6 +383,7 @@ struct dpaa2_eth_ch_stats {
enum dpaa2_eth_fq_type {
DPAA2_RX_FQ = 0,
DPAA2_TX_CONF_FQ,
+ DPAA2_RX_ERR_FQ
};
struct dpaa2_eth_priv;
@@ -393,7 +482,8 @@ struct dpaa2_eth_priv {
struct dpaa2_eth_drv_stats __percpu *percpu_extras;
u16 mc_token;
- u8 rx_td_enabled;
+ u8 rx_fqtd_enabled;
+ u8 rx_cgtd_enabled;
struct dpni_link_state link_state;
bool do_link_poll;
@@ -404,10 +494,19 @@ struct dpaa2_eth_priv {
u64 rx_cls_fields;
struct dpaa2_eth_cls_rule *cls_rules;
u8 rx_cls_enabled;
+ u8 vlan_cls_enabled;
+ u8 pfc_enabled;
+#ifdef CONFIG_FSL_DPAA2_ETH_DCB
+ u8 dcbx_mode;
+ struct ieee_pfc pfc;
+#endif
struct bpf_prog *xdp_prog;
#ifdef CONFIG_DEBUG_FS
struct dpaa2_debugfs dbg;
#endif
+ struct dpni_tx_shaping_cfg shaping_cfg;
+
+ bool ceetm_en;
};
#define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
@@ -484,6 +583,20 @@ enum dpaa2_eth_rx_dist {
(dpaa2_eth_cmp_dpni_ver((priv), DPNI_PAUSE_VER_MAJOR, \
DPNI_PAUSE_VER_MINOR) >= 0)
+static inline bool dpaa2_eth_tx_pause_enabled(u64 link_options)
+{
+ return !!(link_options & DPNI_LINK_OPT_PAUSE) ^
+ !!(link_options & DPNI_LINK_OPT_ASYM_PAUSE);
+}
+
+static inline bool dpaa2_eth_rx_pause_enabled(u64 link_options)
+{
+ return !!(link_options & DPNI_LINK_OPT_PAUSE);
+}
+
+#define DPNI_LINK_AUTONEG_VER_MAJOR 7
+#define DPNI_LINK_AUTONEG_VER_MINOR 8
+
static inline
unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv,
struct sk_buff *skb)
@@ -517,6 +630,11 @@ static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv)
return priv->tx_data_offset - DPAA2_ETH_RX_HWA_SIZE;
}
+static inline int dpaa2_eth_ch_count(struct dpaa2_eth_priv *priv)
+{
+ return 1;
+}
+
int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags);
int dpaa2_eth_set_cls(struct net_device *net_dev, u64 key);
int dpaa2_eth_cls_key_size(u64 key);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
index e4d9fb0e72bf..afb52d75c327 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
@@ -79,29 +79,119 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
sizeof(drvinfo->bus_info));
}
+struct dpaa2_eth_link_mode_map {
+ u64 dpni_lm;
+ u64 ethtool_lm;
+};
+
+static const struct dpaa2_eth_link_mode_map dpaa2_eth_lm_map[] = {
+ {DPNI_ADVERTISED_10BASET_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT},
+ {DPNI_ADVERTISED_100BASET_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT},
+ {DPNI_ADVERTISED_1000BASET_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
+ {DPNI_ADVERTISED_10000BASET_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT},
+ {DPNI_ADVERTISED_2500BASEX_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT},
+ {DPNI_ADVERTISED_AUTONEG, ETHTOOL_LINK_MODE_Autoneg_BIT},
+};
+
+static void link_mode_dpni2ethtool(u64 dpni_lm, unsigned long *ethtool_lm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) {
+ if (dpni_lm & dpaa2_eth_lm_map[i].dpni_lm)
+ __set_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm);
+ }
+}
+
+static void link_mode_ethtool2dpni(const unsigned long *ethtool_lm,
+ u64 *dpni_lm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_lm_map); i++) {
+ if (test_bit(dpaa2_eth_lm_map[i].ethtool_lm, ethtool_lm))
+ *dpni_lm |= dpaa2_eth_lm_map[i].dpni_lm;
+ }
+}
+
static int
dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
struct ethtool_link_ksettings *link_settings)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- link_settings->base.autoneg = AUTONEG_DISABLE;
+ if (priv->link_state.options & DPNI_LINK_OPT_AUTONEG)
+ link_settings->base.autoneg = AUTONEG_ENABLE;
if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
link_settings->base.duplex = DUPLEX_FULL;
link_settings->base.speed = priv->link_state.rate;
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
+ DPNI_LINK_AUTONEG_VER_MINOR) >= 0) {
+ link_mode_dpni2ethtool(priv->link_state.supported,
+ link_settings->link_modes.supported);
+ link_mode_dpni2ethtool(priv->link_state.advertising,
+ link_settings->link_modes.advertising);
+ }
+
return 0;
}
+#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7
+#define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1
+static int
+dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
+ const struct ethtool_link_ksettings *link_settings)
+{
+ struct dpni_link_cfg cfg = {0};
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ int err = 0;
+
+ /* If using an older MC version, the DPNI must be down
+ * in order to be able to change link settings. Taking steps to let
+ * the user know that.
+ */
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR,
+ DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) {
+ if (netif_running(net_dev)) {
+ netdev_info(net_dev, "Interface must be brought down first.\n");
+ return -EACCES;
+ }
+ }
+
+ cfg.rate = link_settings->base.speed;
+ cfg.options = priv->link_state.options;
+ if (link_settings->base.autoneg == AUTONEG_ENABLE)
+ cfg.options |= DPNI_LINK_OPT_AUTONEG;
+ else
+ cfg.options &= ~DPNI_LINK_OPT_AUTONEG;
+ if (link_settings->base.duplex == DUPLEX_HALF)
+ cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX;
+ else
+ cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
+
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_LINK_AUTONEG_VER_MAJOR,
+ DPNI_LINK_AUTONEG_VER_MINOR) < 0) {
+ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
+ } else {
+ link_mode_ethtool2dpni(link_settings->link_modes.advertising,
+ &cfg.advertising);
+ dpni_set_link_cfg_v2(priv->mc_io, 0, priv->mc_token, &cfg);
+ }
+ if (err)
+ netdev_err(net_dev, "dpni_set_link_cfg failed");
+
+ return err;
+}
+
static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
u64 link_options = priv->link_state.options;
- pause->rx_pause = !!(link_options & DPNI_LINK_OPT_PAUSE);
- pause->tx_pause = pause->rx_pause ^
- !!(link_options & DPNI_LINK_OPT_ASYM_PAUSE);
+ pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
+ pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
pause->autoneg = AUTONEG_DISABLE;
}
@@ -212,7 +302,7 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
if (j == 4 || j == 5)
continue;
err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
- j, &dpni_stats);
+ j, 0, &dpni_stats);
if (err == -EINVAL)
/* Older firmware versions don't support all pages */
memset(&dpni_stats, 0, sizeof(dpni_stats));
@@ -235,7 +325,7 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
/* Per-channel stats */
for (k = 0; k < priv->num_channels; k++) {
ch_stats = &priv->channel[k]->stats;
- for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64); j++)
+ for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64) - 1; j++)
*((__u64 *)data + i + j) += *((__u64 *)ch_stats + j);
}
i += j;
@@ -502,7 +592,7 @@ static int do_cls_rule(struct net_device *net_dev,
dma_addr_t key_iova;
u64 fields = 0;
void *key_buf;
- int err;
+ int i, err;
if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
fs->ring_cookie >= dpaa2_eth_queue_count(priv))
@@ -562,11 +652,18 @@ static int do_cls_rule(struct net_device *net_dev,
fs_act.options |= DPNI_FS_OPT_DISCARD;
else
fs_act.flow_id = fs->ring_cookie;
- err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
- fs->location, &rule_cfg, &fs_act);
- } else {
- err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
- &rule_cfg);
+ }
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ if (add)
+ err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token,
+ i, fs->location, &rule_cfg,
+ &fs_act);
+ else
+ err = dpni_remove_fs_entry(priv->mc_io, 0,
+ priv->mc_token, i,
+ &rule_cfg);
+ if (err)
+ break;
}
dma_unmap_single(dev, key_iova, rule_cfg.key_size * 2, DMA_TO_DEVICE);
@@ -728,6 +825,7 @@ const struct ethtool_ops dpaa2_ethtool_ops = {
.get_drvinfo = dpaa2_eth_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_link_ksettings = dpaa2_eth_get_link_ksettings,
+ .set_link_ksettings = dpaa2_eth_set_link_ksettings,
.get_pauseparam = dpaa2_eth_get_pauseparam,
.set_pauseparam = dpaa2_eth_set_pauseparam,
.get_sset_count = dpaa2_eth_get_sset_count,
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
index d9b6918807af..8010ed997257 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
@@ -11,9 +11,11 @@
#define DPNI_VER_MAJOR 7
#define DPNI_VER_MINOR 0
#define DPNI_CMD_BASE_VERSION 1
+#define DPNI_CMD_2ND_VERSION 2
#define DPNI_CMD_ID_OFFSET 4
#define DPNI_CMD(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION)
+#define DPNI_CMD_V2(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_2ND_VERSION)
#define DPNI_CMDID_OPEN DPNI_CMD(0x801)
#define DPNI_CMDID_CLOSE DPNI_CMD(0x800)
@@ -42,10 +44,12 @@
#define DPNI_CMDID_GET_QDID DPNI_CMD(0x210)
#define DPNI_CMDID_GET_TX_DATA_OFFSET DPNI_CMD(0x212)
#define DPNI_CMDID_GET_LINK_STATE DPNI_CMD(0x215)
+#define DPNI_CMDID_GET_LINK_STATE_V2 DPNI_CMD_V2(0x215)
#define DPNI_CMDID_SET_MAX_FRAME_LENGTH DPNI_CMD(0x216)
#define DPNI_CMDID_GET_MAX_FRAME_LENGTH DPNI_CMD(0x217)
#define DPNI_CMDID_SET_LINK_CFG DPNI_CMD(0x21A)
-#define DPNI_CMDID_SET_TX_SHAPING DPNI_CMD(0x21B)
+#define DPNI_CMDID_SET_LINK_CFG_V2 DPNI_CMD_V2(0x21A)
+#define DPNI_CMDID_SET_TX_SHAPING DPNI_CMD_V2(0x21B)
#define DPNI_CMDID_SET_MCAST_PROMISC DPNI_CMD(0x220)
#define DPNI_CMDID_GET_MCAST_PROMISC DPNI_CMD(0x221)
@@ -59,11 +63,17 @@
#define DPNI_CMDID_SET_RX_TC_DIST DPNI_CMD(0x235)
+#define DPNI_CMDID_SET_QOS_TBL DPNI_CMD(0x240)
+#define DPNI_CMDID_ADD_QOS_ENT DPNI_CMD(0x241)
+#define DPNI_CMDID_REMOVE_QOS_ENT DPNI_CMD(0x242)
+#define DPNI_CMDID_CLR_QOS_TBL DPNI_CMD(0x243)
#define DPNI_CMDID_ADD_FS_ENT DPNI_CMD(0x244)
#define DPNI_CMDID_REMOVE_FS_ENT DPNI_CMD(0x245)
#define DPNI_CMDID_CLR_FS_ENT DPNI_CMD(0x246)
-#define DPNI_CMDID_GET_STATISTICS DPNI_CMD(0x25D)
+#define DPNI_CMDID_SET_TX_PRIORITIES DPNI_CMD_V2(0x250)
+#define DPNI_CMDID_GET_STATISTICS DPNI_CMD_V2(0x25D)
+#define DPNI_CMDID_RESET_STATISTICS DPNI_CMD(0x25E)
#define DPNI_CMDID_GET_QUEUE DPNI_CMD(0x25F)
#define DPNI_CMDID_SET_QUEUE DPNI_CMD(0x260)
#define DPNI_CMDID_GET_TAILDROP DPNI_CMD(0x261)
@@ -279,6 +289,7 @@ struct dpni_rsp_get_tx_data_offset {
struct dpni_cmd_get_statistics {
u8 page_number;
+ u8 param;
};
struct dpni_rsp_get_statistics {
@@ -295,8 +306,22 @@ struct dpni_cmd_link_cfg {
__le64 options;
};
+struct dpni_cmd_set_link_cfg_v2 {
+ /* cmd word 0 */
+ __le64 pad0;
+ /* cmd word 1 */
+ __le32 rate;
+ __le32 pad1;
+ /* cmd word 2 */
+ __le64 options;
+ /* cmd word 3 */
+ __le64 advertising;
+};
+
#define DPNI_LINK_STATE_SHIFT 0
#define DPNI_LINK_STATE_SIZE 1
+#define DPNI_STATE_VALID_SHIFT 1
+#define DPNI_STATE_VALID_SIZE 1
struct dpni_rsp_get_link_state {
/* response word 0 */
@@ -311,6 +336,39 @@ struct dpni_rsp_get_link_state {
__le64 options;
};
+struct dpni_rsp_get_link_state_v2 {
+ /* response word 0 */
+ __le32 pad0;
+ /* from LSB: up:1, valid:1 */
+ u8 flags;
+ u8 pad1[3];
+ /* response word 1 */
+ __le32 rate;
+ __le32 pad2;
+ /* response word 2 */
+ __le64 options;
+ /* cmd word 3 */
+ __le64 supported;
+ /* cmd word 4 */
+ __le64 advertising;
+};
+
+#define DPNI_COUPLED_SHIFT 0
+#define DPNI_COUPLED_SIZE 1
+
+struct dpni_cmd_set_tx_shaping {
+ /* cmd word 0 */
+ __le16 tx_cr_max_burst_size;
+ __le16 tx_er_max_burst_size;
+ __le32 pad;
+ /* cmd word 1 */
+ __le32 tx_cr_rate_limit;
+ __le32 tx_er_rate_limit;
+ /* cmd word 2 */
+ /* from LSB: coupled:1 */
+ u8 coupled;
+};
+
struct dpni_cmd_set_max_frame_length {
__le16 max_frame_length;
};
@@ -370,6 +428,24 @@ struct dpni_cmd_clear_mac_filters {
u8 flags;
};
+#define DPNI_SEPARATE_GRP_SHIFT 0
+#define DPNI_SEPARATE_GRP_SIZE 1
+#define DPNI_MODE_1_SHIFT 0
+#define DPNI_MODE_1_SIZE 4
+#define DPNI_MODE_2_SHIFT 4
+#define DPNI_MODE_2_SIZE 4
+
+struct dpni_cmd_set_tx_priorities {
+ __le16 flags;
+ u8 prio_group_A;
+ u8 prio_group_B;
+ __le32 pad0;
+ u8 modes[4];
+ __le32 pad1;
+ __le64 pad2;
+ __le16 delta_bandwidth[8];
+};
+
#define DPNI_DIST_MODE_SHIFT 0
#define DPNI_DIST_MODE_SIZE 4
#define DPNI_MISS_ACTION_SHIFT 4
@@ -567,4 +643,59 @@ struct dpni_cmd_remove_fs_entry {
__le64 mask_iova;
};
+#define DPNI_DISCARD_ON_MISS_SHIFT 0
+#define DPNI_DISCARD_ON_MISS_SIZE 1
+
+struct dpni_cmd_set_qos_table {
+ __le32 pad;
+ u8 default_tc;
+ /* only the LSB */
+ u8 discard_on_miss;
+ __le16 pad1[21];
+ __le64 key_cfg_iova;
+};
+
+struct dpni_cmd_add_qos_entry {
+ __le16 pad;
+ u8 tc_id;
+ u8 key_size;
+ __le16 index;
+ __le16 pad1;
+ __le64 key_iova;
+ __le64 mask_iova;
+};
+
+struct dpni_cmd_remove_qos_entry {
+ u8 pad[3];
+ u8 key_size;
+ __le32 pad1;
+ __le64 key_iova;
+ __le64 mask_iova;
+};
+
+#define DPNI_DEST_TYPE_SHIFT 0
+#define DPNI_DEST_TYPE_SIZE 4
+#define DPNI_CONG_UNITS_SHIFT 4
+#define DPNI_CONG_UNITS_SIZE 2
+
+struct dpni_cmd_set_congestion_notification {
+ /* cmd word 0 */
+ u8 qtype;
+ u8 tc;
+ u8 pad[6];
+ /* cmd word 1 */
+ __le32 dest_id;
+ __le16 notification_mode;
+ u8 dest_priority;
+ /* from LSB: dest_type: 4 units:2 */
+ u8 type_units;
+ /* cmd word 2 */
+ __le64 message_iova;
+ /* cmd word 3 */
+ __le64 message_ctx;
+ /* cmd word 4 */
+ __le32 threshold_entry;
+ __le32 threshold_exit;
+};
+
#endif /* _FSL_DPNI_CMD_H */
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c
index dd54e6953aeb..ac043122525b 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
@@ -853,6 +853,36 @@ int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
}
/**
+ * dpni_set_link_cfg_v2() - set the link configuration.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: Link configuration
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_set_link_cfg_v2(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_link_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpni_cmd_set_link_cfg_v2 *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG_V2,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_link_cfg_v2 *)cmd.params;
+ cmd_params->rate = cpu_to_le32(cfg->rate);
+ cmd_params->options = cpu_to_le64(cfg->options);
+ cmd_params->advertising = cpu_to_le64(cfg->advertising);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
* dpni_get_link_cfg() - return the link configuration
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -926,6 +956,84 @@ int dpni_get_link_state(struct fsl_mc_io *mc_io,
}
/**
+ * dpni_get_link_state_v2() - Return the link state (either up or down)
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @state: Returned link state;
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_get_link_state_v2(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpni_link_state *state)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpni_rsp_get_link_state_v2 *rsp_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE_V2,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ rsp_params = (struct dpni_rsp_get_link_state_v2 *)cmd.params;
+ state->up = dpni_get_field(rsp_params->flags, LINK_STATE);
+ state->state_valid = dpni_get_field(rsp_params->flags, STATE_VALID);
+ state->rate = le32_to_cpu(rsp_params->rate);
+ state->options = le64_to_cpu(rsp_params->options);
+ state->supported = le64_to_cpu(rsp_params->supported);
+ state->advertising = le64_to_cpu(rsp_params->advertising);
+
+ return 0;
+}
+
+/**
+ * dpni_set_tx_shaping() - Set the transmit shaping
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @tx_cr_shaper: TX committed rate shaping configuration
+ * @tx_er_shaper: TX excess rate shaping configuration
+ * @coupled: Committed and excess rate shapers are coupled
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_tx_shaping_cfg *tx_cr_shaper,
+ const struct dpni_tx_shaping_cfg *tx_er_shaper,
+ int coupled)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpni_cmd_set_tx_shaping *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_SHAPING,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_tx_shaping *)cmd.params;
+ cmd_params->tx_cr_max_burst_size =
+ cpu_to_le16(tx_cr_shaper->max_burst_size);
+ cmd_params->tx_er_max_burst_size =
+ cpu_to_le16(tx_er_shaper->max_burst_size);
+ cmd_params->tx_cr_rate_limit = cpu_to_le32(tx_cr_shaper->rate_limit);
+ cmd_params->tx_er_rate_limit = cpu_to_le32(tx_er_shaper->rate_limit);
+ dpni_set_field(cmd_params->coupled, COUPLED, coupled);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
* dpni_set_max_frame_length() - Set the maximum received frame length.
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -1317,6 +1425,55 @@ int dpni_clear_mac_filters(struct fsl_mc_io *mc_io,
}
/**
+ * dpni_set_tx_priorities() - Set transmission TC priority configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: Transmission selection configuration
+ *
+ * warning: Allowed only when DPNI is disabled
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_set_tx_priorities(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_tx_priorities_cfg *cfg)
+{
+ struct dpni_cmd_set_tx_priorities *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+ int i;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_PRIORITIES,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_tx_priorities *)cmd.params;
+ dpni_set_field(cmd_params->flags,
+ SEPARATE_GRP,
+ cfg->separate_groups);
+ cmd_params->prio_group_A = cfg->prio_group_A;
+ cmd_params->prio_group_B = cfg->prio_group_B;
+
+ for (i = 0; i + 1 < DPNI_MAX_TC; i += 2) {
+ dpni_set_field(cmd_params->modes[i / 2],
+ MODE_1,
+ cfg->tc_sched[i].mode);
+ dpni_set_field(cmd_params->modes[i / 2],
+ MODE_2,
+ cfg->tc_sched[i + 1].mode);
+ }
+
+ for (i = 0; i < DPNI_MAX_TC; i++) {
+ cmd_params->delta_bandwidth[i] =
+ cpu_to_le16(cfg->tc_sched[i].delta_bandwidth);
+ }
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
* dpni_set_rx_tc_dist() - Set Rx traffic class distribution configuration
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -1355,6 +1512,55 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io,
}
/**
+ * dpni_set_congestion_notification() - Set traffic class congestion
+ * notification configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported
+ * @tc_id: bits 7-4 contain ceetm channel index (valid only for TX);
+ * bits 3-0 contain traffic class.
+ * Use macro DPNI_BUILD_CH_TC() to build correct value for
+ * tc_id parameter
+ * @cfg: Congestion notification configuration
+ *
+ * Return: '0' on Success; error code otherwise.
+ */
+int dpni_set_congestion_notification(
+ struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ enum dpni_queue_type qtype,
+ u8 tc_id,
+ const struct dpni_congestion_notification_cfg *cfg)
+{
+ struct dpni_cmd_set_congestion_notification *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header =
+ mc_encode_cmd_header(DPNI_CMDID_SET_CONGESTION_NOTIFICATION,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params;
+ cmd_params->qtype = qtype;
+ cmd_params->tc = tc_id;
+ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
+ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
+ cmd_params->dest_priority = cfg->dest_cfg.priority;
+ dpni_set_field(cmd_params->type_units, DEST_TYPE,
+ cfg->dest_cfg.dest_type);
+ dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units);
+ cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
+ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
+ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
+ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
* dpni_set_queue() - Set queue parameters
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -1471,6 +1677,8 @@ int dpni_get_queue(struct fsl_mc_io *mc_io,
* @token: Token of DPNI object
* @page: Selects the statistics page to retrieve, see
* DPNI_GET_STATISTICS output. Pages are numbered 0 to 6.
+ * @param: Custom parameter for some pages used to select a certain
+ * statistic source, for example the TC.
* @stat: Structure containing the statistics
*
* Return: '0' on Success; Error code otherwise.
@@ -1479,6 +1687,7 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
u8 page,
+ u8 param,
union dpni_statistics *stat)
{
struct fsl_mc_command cmd = { 0 };
@@ -1492,6 +1701,7 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
token);
cmd_params = (struct dpni_cmd_get_statistics *)cmd.params;
cmd_params->page_number = page;
+ cmd_params->param = param;
/* send command to mc */
err = mc_send_command(mc_io, &cmd);
@@ -1507,6 +1717,29 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
}
/**
+ * dpni_reset_statistics() - Clears DPNI statistics
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_reset_statistics(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET_STATISTICS,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
* dpni_set_taildrop() - Set taildrop per queue or TC
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -1514,7 +1747,10 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
* @cg_point: Congestion point
* @q_type: Queue type on which the taildrop is configured.
* Only Rx queues are supported for now
- * @tc: Traffic class to apply this taildrop to
+ * @tc: bits 7-4 contain ceetm channel index (valid only for TX);
+ * bits 3-0 contain traffic class.
+ * Use macro DPNI_BUILD_CH_TC() to build correct value for
+ * tc parameter.
* @q_index: Index of the queue if the DPNI supports multiple queues for
* traffic distribution. Ignored if CONGESTION_POINT is not 0.
* @taildrop: Taildrop structure
@@ -1558,7 +1794,10 @@ int dpni_set_taildrop(struct fsl_mc_io *mc_io,
* @cg_point: Congestion point
* @q_type: Queue type on which the taildrop is configured.
* Only Rx queues are supported for now
- * @tc: Traffic class to apply this taildrop to
+ * @tc: bits 7-4 contain ceetm channel index (valid only for TX);
+ * bits 3-0 contain traffic class.
+ * Use macro DPNI_BUILD_CH_TC() to build correct value for
+ * tc parameter.
* @q_index: Index of the queue if the DPNI supports multiple queues for
* traffic distribution. Ignored if CONGESTION_POINT is not 0.
* @taildrop: Taildrop structure
@@ -1786,3 +2025,134 @@ int dpni_remove_fs_entry(struct fsl_mc_io *mc_io,
/* send command to mc*/
return mc_send_command(mc_io, &cmd);
}
+
+/**
+ * dpni_set_qos_table() - Set QoS mapping table
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: QoS table configuration
+ *
+ * This function and all QoS-related functions require that
+ *'max_tcs > 1' was set at DPNI creation.
+ *
+ * warning: Before calling this function, call dpkg_prepare_key_cfg() to
+ * prepare the key_cfg_iova parameter
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_set_qos_table(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_qos_tbl_cfg *cfg)
+{
+ struct dpni_cmd_set_qos_table *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QOS_TBL,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_qos_table *)cmd.params;
+ cmd_params->default_tc = cfg->default_tc;
+ cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova);
+ dpni_set_field(cmd_params->discard_on_miss, DISCARD_ON_MISS,
+ cfg->discard_on_miss);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_add_qos_entry() - Add QoS mapping entry (to select a traffic class)
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: QoS rule to add
+ * @tc_id: Traffic class selection (0-7)
+ * @index: Location in the QoS table where to insert the entry.
+ * Only relevant if MASKING is enabled for QoS classification on
+ * this DPNI, it is ignored for exact match.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_add_qos_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rule_cfg *cfg,
+ u8 tc_id,
+ u16 index)
+{
+ struct dpni_cmd_add_qos_entry *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_QOS_ENT,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_add_qos_entry *)cmd.params;
+ cmd_params->tc_id = tc_id;
+ cmd_params->key_size = cfg->key_size;
+ cmd_params->index = cpu_to_le16(index);
+ cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_remove_qos_entry() - Remove QoS mapping entry
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: QoS rule to remove
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_remove_qos_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rule_cfg *cfg)
+{
+ struct dpni_cmd_remove_qos_entry *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_QOS_ENT,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_remove_qos_entry *)cmd.params;
+ cmd_params->key_size = cfg->key_size;
+ cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_clear_qos_table() - Clear all QoS mapping entries
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ *
+ * Following this function call, all frames are directed to
+ * the default traffic class (0)
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_clear_qos_table(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_QOS_TBL,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h
index ee0711d06b3a..11b823a60f4a 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
@@ -494,8 +494,13 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
u8 page,
+ u8 param,
union dpni_statistics *stat);
+int dpni_reset_statistics(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
/**
* Enable auto-negotiation
*/
@@ -514,6 +519,24 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
#define DPNI_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
/**
+ * Enable priority flow control pause frames
+ */
+#define DPNI_LINK_OPT_PFC_PAUSE 0x0000000000000010ULL
+/**
+ * Advertised link speeds
+ */
+#define DPNI_ADVERTISED_10BASET_FULL 0x0000000000000001ULL
+#define DPNI_ADVERTISED_100BASET_FULL 0x0000000000000002ULL
+#define DPNI_ADVERTISED_1000BASET_FULL 0x0000000000000004ULL
+#define DPNI_ADVERTISED_10000BASET_FULL 0x0000000000000010ULL
+#define DPNI_ADVERTISED_2500BASEX_FULL 0x0000000000000020ULL
+
+/**
+ * Advertise auto-negotiation enabled
+ */
+#define DPNI_ADVERTISED_AUTONEG 0x0000000000000008ULL
+
+/**
* struct - Structure representing DPNI link configuration
* @rate: Rate
* @options: Mask of available options; use 'DPNI_LINK_OPT_<X>' values
@@ -521,6 +544,7 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
struct dpni_link_cfg {
u32 rate;
u64 options;
+ u64 advertising;
};
int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
@@ -528,6 +552,11 @@ int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
u16 token,
const struct dpni_link_cfg *cfg);
+int dpni_set_link_cfg_v2(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_link_cfg *cfg);
+
int dpni_get_link_cfg(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
@@ -542,7 +571,10 @@ int dpni_get_link_cfg(struct fsl_mc_io *mc_io,
struct dpni_link_state {
u32 rate;
u64 options;
+ u64 supported;
+ u64 advertising;
int up;
+ int state_valid;
};
int dpni_get_link_state(struct fsl_mc_io *mc_io,
@@ -550,6 +582,28 @@ int dpni_get_link_state(struct fsl_mc_io *mc_io,
u16 token,
struct dpni_link_state *state);
+int dpni_get_link_state_v2(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpni_link_state *state);
+
+/**
+ * struct dpni_tx_shaping - Structure representing DPNI tx shaping configuration
+ * @rate_limit: rate in Mbps
+ * @max_burst_size: burst size in bytes (up to 64KB)
+ */
+struct dpni_tx_shaping_cfg {
+ u32 rate_limit;
+ u16 max_burst_size;
+};
+
+int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_tx_shaping_cfg *tx_cr_shaper,
+ const struct dpni_tx_shaping_cfg *tx_er_shaper,
+ int coupled);
+
int dpni_set_max_frame_length(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
@@ -651,6 +705,50 @@ int dpni_prepare_key_cfg(const struct dpkg_profile_cfg *cfg,
u8 *key_cfg_buf);
/**
+ * enum dpni_tx_schedule_mode - DPNI Tx scheduling mode
+ * @DPNI_TX_SCHED_STRICT_PRIORITY: strict priority
+ * @DPNI_TX_SCHED_WEIGHTED_A: weighted based scheduling in group A
+ * @DPNI_TX_SCHED_WEIGHTED_B: weighted based scheduling in group B
+ */
+enum dpni_tx_schedule_mode {
+ DPNI_TX_SCHED_STRICT_PRIORITY = 0,
+ DPNI_TX_SCHED_WEIGHTED_A,
+ DPNI_TX_SCHED_WEIGHTED_B,
+};
+
+/**
+ * struct dpni_tx_schedule_cfg - Structure representing Tx scheduling conf
+ * @mode: Scheduling mode
+ * @delta_bandwidth: Bandwidth represented in weights from 100 to 10000;
+ * not applicable for 'strict-priority' mode;
+ */
+struct dpni_tx_schedule_cfg {
+ enum dpni_tx_schedule_mode mode;
+ u16 delta_bandwidth;
+};
+
+/**
+ * struct dpni_tx_priorities_cfg - Structure representing transmission
+ * priorities for DPNI TCs
+ * @tc_sched: An array of traffic-classes
+ * @prio_group_A: Priority of group A
+ * @prio_group_B: Priority of group B
+ * @separate_groups: Treat A and B groups as separate
+ * @ceetm_ch_idx: ceetm channel index to apply the changes
+ */
+struct dpni_tx_priorities_cfg {
+ struct dpni_tx_schedule_cfg tc_sched[DPNI_MAX_TC];
+ u8 prio_group_A;
+ u8 prio_group_B;
+ u8 separate_groups;
+};
+
+int dpni_set_tx_priorities(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_tx_priorities_cfg *cfg);
+
+/**
* struct dpni_rx_tc_dist_cfg - Rx traffic class distribution configuration
* @dist_size: Set the distribution size;
* supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96,
@@ -716,6 +814,26 @@ int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io,
const struct dpni_rx_dist_cfg *cfg);
/**
+ * struct dpni_qos_tbl_cfg - Structure representing QOS table configuration
+ * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with
+ * key extractions to be used as the QoS criteria by calling
+ * dpkg_prepare_key_cfg()
+ * @discard_on_miss: Set to '1' to discard frames in case of no match (miss);
+ * '0' to use the 'default_tc' in such cases
+ * @default_tc: Used in case of no-match and 'discard_on_miss'= 0
+ */
+struct dpni_qos_tbl_cfg {
+ u64 key_cfg_iova;
+ int discard_on_miss;
+ u8 default_tc;
+};
+
+int dpni_set_qos_table(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_qos_tbl_cfg *cfg);
+
+/**
* enum dpni_dest - DPNI destination types
* @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and
* does not generate FQDAN notifications; user is expected to
@@ -858,6 +976,68 @@ enum dpni_congestion_point {
};
/**
+ * struct dpni_dest_cfg - Structure representing DPNI destination parameters
+ * @dest_type: Destination type
+ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
+ * @priority: Priority selection within the DPIO or DPCON channel; valid
+ * values are 0-1 or 0-7, depending on the number of priorities
+ * in that channel; not relevant for 'DPNI_DEST_NONE' option
+ */
+struct dpni_dest_cfg {
+ enum dpni_dest dest_type;
+ int dest_id;
+ u8 priority;
+};
+
+/* DPNI congestion options */
+
+/**
+ * This congestion will trigger flow control or priority flow control.
+ * This will have effect only if flow control is enabled with
+ * dpni_set_link_cfg().
+ */
+#define DPNI_CONG_OPT_FLOW_CONTROL 0x00000040
+
+/**
+ * struct dpni_congestion_notification_cfg - congestion notification
+ * configuration
+ * @units: Units type
+ * @threshold_entry: Above this threshold we enter a congestion state.
+ * set it to '0' to disable it
+ * @threshold_exit: Below this threshold we exit the congestion state.
+ * @message_ctx: The context that will be part of the CSCN message
+ * @message_iova: I/O virtual address (must be in DMA-able memory),
+ * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>'
+ * is contained in 'options'
+ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
+ * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values
+ */
+
+struct dpni_congestion_notification_cfg {
+ enum dpni_congestion_unit units;
+ u32 threshold_entry;
+ u32 threshold_exit;
+ u64 message_ctx;
+ u64 message_iova;
+ struct dpni_dest_cfg dest_cfg;
+ u16 notification_mode;
+};
+
+/** Compose TC parameter for function dpni_set_congestion_notification()
+ * and dpni_get_congestion_notification().
+ */
+#define DPNI_BUILD_CH_TC(ceetm_ch_idx, tc) \
+ ((((ceetm_ch_idx) & 0x0F) << 4) | ((tc) & 0x0F))
+
+int dpni_set_congestion_notification(
+ struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ enum dpni_queue_type qtype,
+ u8 tc_id,
+ const struct dpni_congestion_notification_cfg *cfg);
+
+/**
* struct dpni_taildrop - Structure representing the taildrop
* @enable: Indicates whether the taildrop is active or not.
* @units: Indicates the unit of THRESHOLD. Queue taildrop only supports
@@ -961,6 +1141,22 @@ int dpni_remove_fs_entry(struct fsl_mc_io *mc_io,
u8 tc_id,
const struct dpni_rule_cfg *cfg);
+int dpni_add_qos_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rule_cfg *cfg,
+ u8 tc_id,
+ u16 index);
+
+int dpni_remove_qos_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rule_cfg *cfg);
+
+int dpni_clear_qos_table(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
int dpni_get_api_version(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 *major_ver,
diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index c219587bd334..7167de4e887b 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -2,6 +2,7 @@
config FSL_ENETC
tristate "ENETC PF driver"
depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST)
+ select FSL_ENETC_MDIO
select PHYLIB
help
This driver supports NXP ENETC gigabit ethernet controller PCIe
@@ -50,3 +51,23 @@ config FSL_ENETC_HW_TIMESTAMPING
allocation has not been supported and it is too expensive to use
extended RX BDs if timestamping is not used, this option enables
extended RX BDs in order to support hardware timestamping.
+
+config FSL_ENETC_QOS
+ bool "ENETC hardware Time-sensitive Network support"
+ depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
+ help
+ There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
+ /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
+ enable/disable from user space via Qos commands(tc). In the kernel
+ side, it can be loaded by Qos driver. Currently, it is only support
+ taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
+
+config ENETC_TSN
+ bool "TSN Support for NXP ENETC driver"
+ default n
+ depends on TSN && FSL_ENETC
+ help
+ This driver supports TSN on Freescale ENETC driver. Provide
+ interface to config the tsn capabilities of ENETC. The interface link
+ to the /net/tsn/* and include/net/tsn.h. User space refer the
+ include/uapi/linux/tsn.h.
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index d200c27c3bf6..202620368e11 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -3,11 +3,14 @@
common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
-fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
+fsl-enetc-y := enetc_pf.o $(common-objs)
fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
+fsl-enetc-$(CONFIG_ENETC_TSN) += enetc_tsn.o
obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
fsl-enetc-vf-y := enetc_vf.o $(common-objs)
+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index b77eaf31bd4e..38830b2cab6f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -34,7 +34,10 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
+ read_lock(&enetc_mdio_lock);
count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
+ read_unlock(&enetc_mdio_lock);
+
if (unlikely(!count))
goto drop_packet_err;
@@ -142,7 +145,8 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
tx_swbd->do_tstamp = do_tstamp;
- tx_swbd->check_wb = tx_swbd->do_tstamp;
+ tx_swbd->qbv_en = !!(active_offloads & ENETC_F_QBV);
+ tx_swbd->check_wb = tx_swbd->do_tstamp || tx_swbd->qbv_en;
if (do_vlan || do_tstamp)
flags |= ENETC_TXBD_FLAGS_EX;
@@ -228,7 +232,7 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
tx_ring->next_to_use = i;
/* let H/W know BD ring has been updated */
- enetc_wr_reg(tx_ring->tpir, i); /* includes wmb() */
+ enetc_wr_reg_hot(tx_ring->tpir, i); /* includes wmb() */
return count;
@@ -251,11 +255,15 @@ static irqreturn_t enetc_msix(int irq, void *data)
struct enetc_int_vector *v = data;
int i;
+ read_lock(&enetc_mdio_lock);
+
/* disable interrupts */
- enetc_wr_reg(v->rbier, 0);
+ enetc_wr_reg_hot(v->rbier, 0);
+
+ for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+ enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0);
- for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
- enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i), 0);
+ read_unlock(&enetc_mdio_lock);
napi_schedule_irqoff(&v->napi);
@@ -287,19 +295,23 @@ static int enetc_poll(struct napi_struct *napi, int budget)
napi_complete_done(napi, work_done);
+ read_lock(&enetc_mdio_lock);
+
/* enable interrupts */
- enetc_wr_reg(v->rbier, ENETC_RBIER_RXTIE);
+ enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE);
+
+ for_each_set_bit(i, &v->tx_rings_map, v->count_tx_rings)
+ enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i),
+ ENETC_TBIER_TXTIE);
- for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
- enetc_wr_reg(v->tbier_base + ENETC_BDR_OFF(i),
- ENETC_TBIER_TXTIE);
+ read_unlock(&enetc_mdio_lock);
return work_done;
}
static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
{
- int pi = enetc_rd_reg(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK;
+ int pi = enetc_rd_reg_hot(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK;
return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi;
}
@@ -331,7 +343,7 @@ static void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
{
struct net_device *ndev = tx_ring->ndev;
- int tx_frm_cnt = 0, tx_byte_cnt = 0;
+ int tx_frm_cnt = 0, tx_byte_cnt = 0, tx_win_drop = 0;
struct enetc_tx_swbd *tx_swbd;
int i, bds_to_clean;
bool do_tstamp;
@@ -339,7 +351,10 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
i = tx_ring->next_to_clean;
tx_swbd = &tx_ring->tx_swbd[i];
+
+ read_lock(&enetc_mdio_lock);
bds_to_clean = enetc_bd_ready_count(tx_ring, i);
+ read_unlock(&enetc_mdio_lock);
do_tstamp = false;
@@ -358,6 +373,10 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
&tstamp);
do_tstamp = true;
}
+
+ if (tx_swbd->qbv_en &&
+ txbd->wb.status & ENETC_TXBD_STATS_WIN)
+ tx_win_drop++;
}
if (likely(tx_swbd->dma))
@@ -382,21 +401,26 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
tx_swbd = tx_ring->tx_swbd;
}
+ read_lock(&enetc_mdio_lock);
+
/* BD iteration loop end */
if (is_eof) {
tx_frm_cnt++;
/* re-arm interrupt source */
- enetc_wr_reg(tx_ring->idr, BIT(tx_ring->index) |
- BIT(16 + tx_ring->index));
+ enetc_wr_reg_hot(tx_ring->idr, BIT(tx_ring->index) |
+ BIT(16 + tx_ring->index));
}
if (unlikely(!bds_to_clean))
bds_to_clean = enetc_bd_ready_count(tx_ring, i);
+
+ read_unlock(&enetc_mdio_lock);
}
tx_ring->next_to_clean = i;
tx_ring->stats.packets += tx_frm_cnt;
tx_ring->stats.bytes += tx_byte_cnt;
+ tx_ring->stats.win_drop += tx_win_drop;
if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) &&
__netif_subqueue_stopped(ndev, tx_ring->index) &&
@@ -470,13 +494,14 @@ static int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
rx_ring->next_to_alloc = i; /* keep track from page reuse */
rx_ring->next_to_use = i;
/* update ENETC's consumer index */
- enetc_wr_reg(rx_ring->rcir, i);
+ enetc_wr_reg_hot(rx_ring->rcir, i);
}
return j;
}
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+/* Must be called with the read-side enetc_mdio_lock held */
static void enetc_get_rx_tstamp(struct net_device *ndev,
union enetc_rx_bd *rxbd,
struct sk_buff *skb)
@@ -488,8 +513,8 @@ static void enetc_get_rx_tstamp(struct net_device *ndev,
u64 tstamp;
if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) {
- lo = enetc_rd(hw, ENETC_SICTR0);
- hi = enetc_rd(hw, ENETC_SICTR1);
+ lo = enetc_rd_reg_hot(hw->reg + ENETC_SICTR0);
+ hi = enetc_rd_reg_hot(hw->reg + ENETC_SICTR1);
tstamp_lo = le32_to_cpu(rxbd->r.tstamp);
if (lo <= tstamp_lo)
hi -= 1;
@@ -637,6 +662,8 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
u32 bd_status;
u16 size;
+ read_lock(&enetc_mdio_lock);
+
if (cleaned_cnt >= ENETC_RXBD_BUNDLE) {
int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt);
@@ -645,15 +672,19 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
rxbd = ENETC_RXBD(*rx_ring, i);
bd_status = le32_to_cpu(rxbd->r.lstatus);
- if (!bd_status)
+ if (!bd_status) {
+ read_unlock(&enetc_mdio_lock);
break;
+ }
- enetc_wr_reg(rx_ring->idr, BIT(rx_ring->index));
+ enetc_wr_reg_hot(rx_ring->idr, BIT(rx_ring->index));
dma_rmb(); /* for reading other rxbd fields */
size = le16_to_cpu(rxbd->r.buf_len);
skb = enetc_map_rx_buff_to_skb(rx_ring, i, size);
- if (!skb)
+ if (!skb) {
+ read_unlock(&enetc_mdio_lock);
break;
+ }
enetc_get_offloads(rx_ring, rxbd, skb);
@@ -667,6 +698,7 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
if (unlikely(bd_status &
ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) {
+ read_unlock(&enetc_mdio_lock);
dev_kfree_skb(skb);
while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
dma_rmb();
@@ -710,6 +742,8 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
enetc_process_skb(rx_ring, skb);
+ read_unlock(&enetc_mdio_lock);
+
napi_gro_receive(napi, skb);
rx_frm_cnt++;
@@ -742,9 +776,17 @@ void enetc_get_si_caps(struct enetc_si *si)
si->num_rss = 0;
val = enetc_rd(hw, ENETC_SIPCAPR0);
if (val & ENETC_SIPCAPR0_RSS) {
- val = enetc_rd(hw, ENETC_SIRSSCAPR);
- si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
+ u32 rss;
+
+ rss = enetc_rd(hw, ENETC_SIRSSCAPR);
+ si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
}
+
+ if (val & ENETC_SIPCAPR0_QBV)
+ si->hw_features |= ENETC_SI_F_QBV;
+
+ if (val & ENETC_SIPCAPR0_QBU)
+ si->hw_features |= ENETC_SI_F_QBU;
}
static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
@@ -1309,8 +1351,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
static void adjust_link(struct net_device *ndev)
{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
+ if (priv->active_offloads & ENETC_F_QBV)
+ enetc_sched_speed_set(ndev);
+
phy_print_status(phydev);
}
@@ -1318,6 +1364,7 @@ static int enetc_phy_connect(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct phy_device *phydev;
+ struct ethtool_eee edata;
if (!priv->phy_node)
return 0; /* phy-less mode */
@@ -1331,6 +1378,10 @@ static int enetc_phy_connect(struct net_device *ndev)
phy_attached_info(phydev);
+ /* disable EEE autoneg, until ENETC driver supports it */
+ memset(&edata, 0, sizeof(struct ethtool_eee));
+ phy_ethtool_set_eee(phydev, &edata);
+
return 0;
}
@@ -1422,8 +1473,7 @@ int enetc_close(struct net_device *ndev)
return 0;
}
-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
- void *type_data)
+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct tc_mqprio_qopt *mqprio = type_data;
@@ -1431,9 +1481,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
u8 num_tc;
int i;
- if (type != TC_SETUP_QDISC_MQPRIO)
- return -EOPNOTSUPP;
-
mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
num_tc = mqprio->num_tc;
@@ -1478,6 +1525,21 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
return 0;
}
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data)
+{
+ switch (type) {
+ case TC_SETUP_QDISC_MQPRIO:
+ return enetc_setup_tc_mqprio(ndev, type_data);
+ case TC_SETUP_QDISC_TAPRIO:
+ return enetc_setup_tc_taprio(ndev, type_data);
+ case TC_SETUP_QDISC_CBS:
+ return enetc_setup_tc_cbs(ndev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
struct net_device_stats *enetc_get_stats(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -1594,7 +1656,10 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
if (cmd == SIOCGHWTSTAMP)
return enetc_hwtstamp_get(ndev, rq);
#endif
- return -EINVAL;
+
+ if (!ndev->phydev)
+ return -EINVAL;
+ return phy_mii_ioctl(ndev->phydev, rq, cmd);
}
int enetc_alloc_msix(struct enetc_ndev_priv *priv)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index b8801a2b6a02..0187c49abab2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -10,6 +10,7 @@
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/phy.h>
+#include <net/tsn.h>
#include "enetc_hw.h"
@@ -24,6 +25,7 @@ struct enetc_tx_swbd {
u8 is_dma_page:1;
u8 check_wb:1;
u8 do_tstamp:1;
+ u8 qbv_en:1;
};
#define ENETC_RX_MAXFRM_SIZE ENETC_MAC_MAXFRM_SIZE
@@ -42,6 +44,7 @@ struct enetc_ring_stats {
unsigned int packets;
unsigned int bytes;
unsigned int rx_alloc_errs;
+ unsigned int win_drop;
};
#define ENETC_BDR_DEFAULT_SIZE 1024
@@ -111,6 +114,28 @@ struct enetc_msg_swbd {
int size;
};
+#ifdef CONFIG_ENETC_TSN
+/* Credit-Based Shaper parameters */
+struct cbs {
+ u8 tc;
+ bool enable;
+ u8 bw;
+ u32 hi_credit;
+ u32 lo_credit;
+ u32 idle_slope;
+ u32 send_slope;
+ u32 tc_max_sized_frame;
+ u32 max_interfrence_size;
+};
+
+struct enetc_cbs {
+ u32 port_transmit_rate;
+ u32 port_max_size_frame;
+ u8 tc_nums;
+ struct cbs cbs[0];
+};
+#endif
+
#define ENETC_REV1 0x1
enum enetc_errata {
ENETC_ERR_TXCSUM = BIT(0),
@@ -118,6 +143,9 @@ enum enetc_errata {
ENETC_ERR_UCMCSWP = BIT(2),
};
+#define ENETC_SI_F_QBV BIT(0)
+#define ENETC_SI_F_QBU BIT(1)
+
/* PCI IEP device data */
struct enetc_si {
struct pci_dev *pdev;
@@ -133,6 +161,11 @@ struct enetc_si {
int num_fs_entries;
int num_rss; /* number of RSS buckets */
unsigned short pad;
+ int hw_features;
+#ifdef CONFIG_ENETC_TSN
+ struct enetc_cbs *ecbs;
+#endif
+
};
#define ENETC_SI_ALIGN 32
@@ -173,6 +206,8 @@ struct enetc_cls_rule {
enum enetc_active_offloads {
ENETC_F_RX_TSTAMP = BIT(0),
ENETC_F_TX_TSTAMP = BIT(1),
+ ENETC_F_QBV = BIT(2),
+ ENETC_F_QBU = BIT(3),
};
struct enetc_ndev_priv {
@@ -188,6 +223,8 @@ struct enetc_ndev_priv {
u16 msg_enable;
int active_offloads;
+ u32 speed; /* store speed for compare update pspeed */
+
struct enetc_bdr *tx_ring[16];
struct enetc_bdr *rx_ring[16];
@@ -249,3 +286,21 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+
+#ifdef CONFIG_FSL_ENETC_QOS
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+void enetc_sched_speed_set(struct net_device *ndev);
+int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
+#else
+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#define enetc_sched_speed_set(ndev) (void)0
+#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
+#endif
+#ifdef CONFIG_ENETC_TSN
+void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev);
+void enetc_tsn_pf_deinit(struct net_device *netdev);
+#else
+#define enetc_tsn_pf_init(netdev, pdev) (void)0
+#define enetc_tsn_pf_deinit(netdev) (void)0
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index de466b71bf8f..201cbc362e33 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
r->bd_count;
}
-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
{
struct enetc_cbdr *ring = &si->cbd_ring;
int timeout = ENETC_CBDR_TIMEOUT;
@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
if (!timeout)
return -EBUSY;
+ /* CBD may writeback data, feedback up level */
+ *cbd = *dest_cbd;
+
enetc_clean_cbdr(si);
return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 89121d7ce3e6..9136b31feae0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -187,6 +187,21 @@ static const struct {
{ ENETC_PICDR(3), "ICM DR3 discarded frames" },
};
+static const struct {
+ int reg;
+ char name[ETH_GSTRING_LEN];
+} enetc_pmac_counters[] = {
+ { ENETC_PM1_RFRM, "PMAC rx frames" },
+ { ENETC_PM1_RPKT, "PMAC rx packets" },
+ { ENETC_PM1_RDRP, "PMAC rx dropped packets" },
+ { ENETC_PM1_RFRG, "PMAC rx fragment packets" },
+ { ENETC_PM1_TFRM, "PMAC tx frames" },
+ { ENETC_PM1_TERR, "PMAC tx error frames" },
+ { ENETC_PM1_TPKT, "PMAC tx packets" },
+ { ENETC_MAC_MERGE_MMFCRXR, "MAC merge fragment rx counter" },
+ { ENETC_MAC_MERGE_MMFCTXR, "MAC merge fragment tx counter"},
+};
+
static const char rx_ring_stats[][ETH_GSTRING_LEN] = {
"Rx ring %2d frames",
"Rx ring %2d alloc errors",
@@ -196,18 +211,34 @@ static const char tx_ring_stats[][ETH_GSTRING_LEN] = {
"Tx ring %2d frames",
};
+static const char tx_windrop_stats[][ETH_GSTRING_LEN] = {
+ "Tx window drop %2d frames",
+};
+
static int enetc_get_sset_count(struct net_device *ndev, int sset)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int len;
+
+ if (sset != ETH_SS_STATS)
+ return -EOPNOTSUPP;
- if (sset == ETH_SS_STATS)
- return ARRAY_SIZE(enetc_si_counters) +
- ARRAY_SIZE(tx_ring_stats) * priv->num_tx_rings +
- ARRAY_SIZE(rx_ring_stats) * priv->num_rx_rings +
- (enetc_si_is_pf(priv->si) ?
- ARRAY_SIZE(enetc_port_counters) : 0);
+ len = ARRAY_SIZE(enetc_si_counters) +
+ ARRAY_SIZE(tx_ring_stats) * priv->num_tx_rings +
+ ARRAY_SIZE(rx_ring_stats) * priv->num_rx_rings;
- return -EOPNOTSUPP;
+ if (!enetc_si_is_pf(priv->si))
+ return len;
+
+ len += ARRAY_SIZE(enetc_port_counters);
+
+ if (priv->active_offloads & ENETC_F_QBU)
+ len += ARRAY_SIZE(enetc_pmac_counters);
+
+ if (priv->active_offloads & ENETC_F_QBV)
+ len += ARRAY_SIZE(tx_windrop_stats) * priv->num_tx_rings;
+
+ return len;
}
static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
@@ -245,6 +276,28 @@ static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
+
+ if (!(priv->active_offloads & ENETC_F_QBU))
+ break;
+
+ for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++) {
+ strlcpy(p, enetc_pmac_counters[i].name,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+
+ if (!((priv->active_offloads & ENETC_F_QBV)))
+ break;
+
+ for (i = 0; i < priv->num_tx_rings; i++) {
+ for (j = 0; j < ARRAY_SIZE(tx_windrop_stats); j++) {
+ snprintf(p, ETH_GSTRING_LEN,
+ tx_windrop_stats[j],
+ i);
+ p += ETH_GSTRING_LEN;
+ }
+ }
+
break;
}
}
@@ -272,6 +325,18 @@ static void enetc_get_ethtool_stats(struct net_device *ndev,
for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++)
data[o++] = enetc_port_rd(hw, enetc_port_counters[i].reg);
+
+ if (!(priv->active_offloads & ENETC_F_QBU))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(enetc_pmac_counters); i++)
+ data[o++] = enetc_port_rd(hw, enetc_pmac_counters[i].reg);
+
+ if (!((priv->active_offloads & ENETC_F_QBV)))
+ return;
+
+ for (i = 0; i < priv->num_tx_rings; i++)
+ data[o++] = priv->tx_ring[i]->stats.win_drop;
}
#define ENETC_RSSHASH_L3 (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO | RXH_IP_SRC | \
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index fac80831d532..ee8622b3a975 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -18,6 +18,8 @@
#define ENETC_SICTR0 0x18
#define ENETC_SICTR1 0x1c
#define ENETC_SIPCAPR0 0x20
+#define ENETC_SIPCAPR0_QBV BIT(4)
+#define ENETC_SIPCAPR0_QBU BIT(3)
#define ENETC_SIPCAPR0_RSS BIT(8)
#define ENETC_SIPCAPR1 0x24
#define ENETC_SITGTGR 0x30
@@ -148,6 +150,11 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PORT_BASE 0x10000
#define ENETC_PMR 0x0000
#define ENETC_PMR_EN GENMASK(18, 16)
+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
+#define ENETC_PMR_PSPEED_10M 0
+#define ENETC_PMR_PSPEED_100M BIT(8)
+#define ENETC_PMR_PSPEED_1000M BIT(9)
+#define ENETC_PMR_PSPEED_2500M BIT(10)
#define ENETC_PSR 0x0004 /* RO */
#define ENETC_PSIPMR 0x0018
#define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */
@@ -179,6 +186,8 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PSICFGR0_SIVC(bmp) (((bmp) & 0xff) << 24) /* VLAN_TYPE */
#define ENETC_PTCCBSR0(n) (0x1110 + (n) * 8) /* n = 0 to 7*/
+#define ENETC_CBSE BIT(31)
+#define ENETC_CBS_BW_MASK GENMASK(6, 0)
#define ENETC_PTCCBSR1(n) (0x1114 + (n) * 8) /* n = 0 to 7*/
#define ENETC_RSSHASH_KEY_SIZE 40
#define ENETC_PRSSCAPR 0x1404
@@ -194,6 +203,7 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PFPMR 0x1900
#define ENETC_PFPMR_PMACE BIT(1)
#define ENETC_PFPMR_MWLM BIT(0)
+#define ENETC_EMDIO_BASE 0x1c00
#define ENETC_PSIUMHFR0(n, err) (((err) ? 0x1d08 : 0x1d00) + (n) * 0x10)
#define ENETC_PSIUMHFR1(n) (0x1d04 + (n) * 0x10)
#define ENETC_PSIMMHFR0(n, err) (((err) ? 0x1d00 : 0x1d08) + (n) * 0x10)
@@ -216,11 +226,40 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM0_MAXFRM 0x8014
#define ENETC_SET_TX_MTU(val) ((val) << 16)
#define ENETC_SET_MAXFRM(val) ((val) & 0xffff)
+#define ENETC_PM0_RX_FIFO 0x801c
+#define ENETC_PM0_RX_FIFO_VAL 1
+
+#define ENETC_PM_IMDIO_BASE 0x8030
+/* PCS registers */
+#define ENETC_PCS_CR 0x0
+#define ENETC_PCS_CR_RESET_AN 0x1200
+#define ENETC_PCS_CR_DEF_VAL 0x0140
+#define ENETC_PCS_CR_LANE_RESET 0x8000
+#define ENETC_PCS_DEV_ABILITY 0x04
+#define ENETC_PCS_DEV_ABILITY_SGMII 0x4001
+#define ENETC_PCS_DEV_ABILITY_SXGMII 0x5001
+#define ENETC_PCS_LINK_TIMER1 0x12
+#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0
+#define ENETC_PCS_LINK_TIMER2 0x13
+#define ENETC_PCS_LINK_TIMER2_VAL 0x0003
+#define ENETC_PCS_IF_MODE 0x14
+#define ENETC_PCS_IF_MODE_SGMII_AN 0x0003
+
#define ENETC_PM0_IF_MODE 0x8300
+#define ENETC_PM1_IF_MODE 0x9300
#define ENETC_PMO_IFM_RG BIT(2)
#define ENETC_PM0_IFM_RLP (BIT(5) | BIT(11))
#define ENETC_PM0_IFM_RGAUTO (BIT(15) | ENETC_PMO_IFM_RG | BIT(1))
#define ENETC_PM0_IFM_XGMII BIT(12)
+#define ENETC_PSIDCAPR 0x1b08
+#define ENETC_PSIDCAPR_MSK GENMASK(15, 0)
+#define ENETC_PSFCAPR 0x1b18
+#define ENETC_PSFCAPR_MSK GENMASK(15, 0)
+#define ENETC_PSGCAPR 0x1b28
+#define ENETC_PSGCAPR_GCL_MSK GENMASK(18, 16)
+#define ENETC_PSGCAPR_SGIT_MSK GENMASK(15, 0)
+#define ENETC_PFMCAPR 0x1b38
+#define ENETC_PFMCAPR_MSK GENMASK(15, 0)
/* MAC counters */
#define ENETC_PM0_REOCT 0x8100
@@ -274,6 +313,15 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM0_TSCOL 0x82E0
#define ENETC_PM0_TLCOL 0x82E8
#define ENETC_PM0_TECOL 0x82F0
+#define ENETC_PM1_RFRM 0x9120
+#define ENETC_PM1_RDRP 0x9158
+#define ENETC_PM1_RPKT 0x9160
+#define ENETC_PM1_RFRG 0x91B8
+#define ENETC_PM1_TFRM 0x9220
+#define ENETC_PM1_TERR 0x9238
+#define ENETC_PM1_TPKT 0x9260
+#define ENETC_MAC_MERGE_MMFCRXR 0x1f14
+#define ENETC_MAC_MERGE_MMFCTXR 0x1f18
/* Port counters */
#define ENETC_PICDR(n) (0x0700 + (n) * 8) /* n = [0..3] */
@@ -303,8 +351,15 @@ struct enetc_hw {
};
/* general register accessors */
-#define enetc_rd_reg(reg) ioread32((reg))
-#define enetc_wr_reg(reg, val) iowrite32((val), (reg))
+#define enetc_rd_reg(reg) enetc_rd_reg_wa((reg))
+#define enetc_wr_reg(reg, val) enetc_wr_reg_wa((reg), (val))
+
+/* accessors for data-path, due to MDIO issue on LS1028 these should be called
+ * only under the rwlock_t enetc_mdio_lock
+ */
+#define enetc_rd_reg_hot(reg) ioread32((reg))
+#define enetc_wr_reg_hot(reg, val) iowrite32((val), (reg))
+
#ifdef ioread64
#define enetc_rd_reg64(reg) ioread64((reg))
#else
@@ -323,12 +378,57 @@ static inline u64 enetc_rd_reg64(void __iomem *reg)
}
#endif
+extern rwlock_t enetc_mdio_lock;
+
+static inline u32 enetc_rd_reg_wa(void *reg)
+{
+ u32 val;
+
+ read_lock(&enetc_mdio_lock);
+ val = ioread32(reg);
+ read_unlock(&enetc_mdio_lock);
+
+ return val;
+}
+
+static inline void enetc_wr_reg_wa(void *reg, u32 val)
+{
+ read_lock(&enetc_mdio_lock);
+ iowrite32(val, reg);
+ read_unlock(&enetc_mdio_lock);
+}
+
+static inline u32 enetc_rd_reg_wa_single(void *reg)
+{
+ unsigned long flags;
+ u32 val;
+
+ write_lock_irqsave(&enetc_mdio_lock, flags);
+ val = ioread32(reg);
+ write_unlock_irqrestore(&enetc_mdio_lock, flags);
+
+ return val;
+}
+
+static inline void enetc_wr_reg_wa_single(void *reg, u32 val)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&enetc_mdio_lock, flags);
+ iowrite32(val, reg);
+ write_unlock_irqrestore(&enetc_mdio_lock, flags);
+}
+
#define enetc_rd(hw, off) enetc_rd_reg((hw)->reg + (off))
#define enetc_wr(hw, off, val) enetc_wr_reg((hw)->reg + (off), val)
#define enetc_rd64(hw, off) enetc_rd_reg64((hw)->reg + (off))
/* port register accessors - PF only */
-#define enetc_port_rd(hw, off) enetc_rd_reg((hw)->port + (off))
-#define enetc_port_wr(hw, off, val) enetc_wr_reg((hw)->port + (off), val)
+#define enetc_port_rd(hw, off) enetc_rd_reg_wa((hw)->port + (off))
+#define enetc_port_wr(hw, off, val) enetc_wr_reg_wa((hw)->port + (off), val)
+#define enetc_port_rd_single(hw, off) enetc_rd_reg_wa_single(\
+ (hw)->port + (off))
+#define enetc_port_wr_single(hw, off, val) enetc_wr_reg_wa_single(\
+ (hw)->port + (off), val)
/* global register accessors - PF only */
#define enetc_global_rd(hw, off) enetc_rd_reg((hw)->global + (off))
#define enetc_global_wr(hw, off, val) enetc_wr_reg((hw)->global + (off), val)
@@ -380,6 +480,7 @@ union enetc_tx_bd {
#define ENETC_TXBD_FLAGS_CSUM BIT(3)
#define ENETC_TXBD_FLAGS_EX BIT(6)
#define ENETC_TXBD_FLAGS_F BIT(7)
+#define ENETC_TXBD_STATS_WIN BIT(7)
static inline void enetc_clear_tx_bd(union enetc_tx_bd *txbd)
{
@@ -407,6 +508,8 @@ static inline __le16 enetc_txbd_l3_csoff(int start, int hdr_sz, u16 l3_flags)
#define ENETC_TXBD_L4_UDP BIT(5)
#define ENETC_TXBD_L4_TCP BIT(6)
+#define enetc_tsn_is_enabled() IS_ENABLED(CONFIG_ENETC_TSN)
+
union enetc_rx_bd {
struct {
__le64 addr;
@@ -446,22 +549,6 @@ union enetc_rx_bd {
#define EMETC_MAC_ADDR_FILT_RES 3 /* # of reserved entries at the beginning */
#define ENETC_MAX_NUM_VFS 2
-struct enetc_cbd {
- union {
- struct {
- __le32 addr[2];
- __le32 opt[4];
- };
- __le32 data[6];
- };
- __le16 index;
- __le16 length;
- u8 cmd;
- u8 cls;
- u8 _res;
- u8 status_flags;
-};
-
#define ENETC_CBD_FLAGS_SF BIT(7) /* short format */
#define ENETC_CBD_STATUS_MASK 0xf
@@ -560,3 +647,477 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
val |= ENETC_TBMR_SET_PRIO(prio);
enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
}
+
+enum bdcr_cmd_class {
+ BDCR_CMD_UNSPEC = 0,
+ BDCR_CMD_MAC_FILTER,
+ BDCR_CMD_VLAN_FILTER,
+ BDCR_CMD_RSS,
+ BDCR_CMD_RFS,
+ BDCR_CMD_PORT_GCL,
+ BDCR_CMD_RECV_CLASSIFIER,
+ BDCR_CMD_STREAM_IDENTIFY,
+ BDCR_CMD_STREAM_FILTER,
+ BDCR_CMD_STREAM_GCL,
+ BDCR_CMD_FLOW_METER,
+ __BDCR_CMD_MAX_LEN,
+ BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+};
+
+/* class 7, command 0, Stream Identity Entry Configuration */
+struct streamid_conf {
+ __le32 stream_handle; /* init gate value */
+ __le32 iports;
+ u8 id_type;
+ u8 oui[3];
+ u8 res[3];
+ u8 en;
+};
+
+#define ENETC_CBDR_SID_VID_MASK 0xfff
+#define ENETC_CBDR_SID_VIDM BIT(12)
+#define ENETC_CBDR_SID_TG_MASK 0xc000
+/* streamid_conf address point to this data space */
+struct null_streamid_data {
+ u8 dmac[6];
+ u16 vid_vidm_tg;
+};
+
+struct smac_streamid_data {
+ u8 smac[6];
+ u16 vid_vidm_tg;
+};
+
+/* class 7, command 1, query config , long format */
+/* No need structure define */
+
+#define ENETC_CDBR_SID_ENABLE BIT(7)
+/* Stream ID Query Response Data Buffer */
+struct streamid_query_resp {
+ u32 stream_handle;
+ u32 input_ports;
+ u8 id_type;
+ u8 oui[3];
+ u8 mac[6];
+ u16 vid_vidm_tg;
+ u8 res[3];
+ u8 en;
+};
+
+/* class 7, command 2, qeury status count, Stream ID query long format */
+struct streamid_stat_query {
+ u8 res[12];
+ __le32 input_ports;
+};
+
+/* Stream Identity Statistics Query */
+struct streamid_stat_query_resp {
+ u32 psinl;
+ u32 psinh;
+ u64 pspi[32];
+};
+
+#define ENETC_CBDR_SFI_PRI_MASK 0x7
+#define ENETC_CBDR_SFI_PRIM BIT(3)
+#define ENETC_CBDR_SFI_BLOV BIT(4)
+#define ENETC_CBDR_SFI_BLEN BIT(5)
+#define ENETC_CBDR_SFI_MSDUEN BIT(6)
+#define ENETC_CBDR_SFI_FMITEN BIT(7)
+#define ENETC_CBDR_SFI_ENABLE BIT(7)
+/* class 8, command 0, Stream Filter Instance, Short Format */
+struct sfi_conf {
+ __le32 stream_handle;
+ u8 multi;
+ u8 res[2];
+ u8 sthm;
+ /* Max Service Data Unit or Flow Meter Instance Table index.
+ * Depending on the value of FLT this represents either Max
+ * Service Data Unit (max frame size) allowed by the filter
+ * entry or is an index into the Flow Meter Instance table
+ * index identifying the policer which will be used to police
+ * it.
+ */
+ __le16 fm_inst_table_index;
+ __le16 msdu;
+ __le16 sg_inst_table_index;
+ u8 res1[2];
+ __le32 input_ports;
+ u8 res2[3];
+ u8 en;
+};
+
+/* class 8, command 1, Stream Filter Instance, write back, short Format */
+struct sfi_query {
+ u32 stream_handle;
+ u8 multi;
+ u8 res[2];
+ u8 sthm;
+ u16 fm_inst_table_index;
+ u16 msdu;
+ u16 sg_inst_table_index;
+ u8 res1[2];
+ u32 input_ports;
+ u8 res2[3];
+ u8 en;
+};
+
+/* class 8, command 2 stream Filter Instance status query short format
+ * command no need structure define
+ * Stream Filter Instance Query Statistics Response data
+ */
+struct sfi_counter_data {
+ u32 matchl;
+ u32 matchh;
+ u32 msdu_dropl;
+ u32 msdu_droph;
+ u32 stream_gate_dropl;
+ u32 stream_gate_droph;
+ u32 flow_meter_dropl;
+ u32 flow_meter_droph;
+};
+
+#define ENETC_CBDR_SGI_OIPV_MASK 0x7
+#define ENETC_CBDR_SGI_OIPV_EN BIT(3)
+#define ENETC_CBDR_SGI_CGTST BIT(6)
+#define ENETC_CBDR_SGI_OGTST BIT(7)
+#define ENETC_CBDR_SGI_CFG_CHG BIT(1)
+#define ENETC_CBDR_SGI_CFG_PND BIT(2)
+#define ENETC_CBDR_SGI_OEX BIT(4)
+#define ENETC_CBDR_SGI_OEXEN BIT(5)
+#define ENETC_CBDR_SGI_IRX BIT(6)
+#define ENETC_CBDR_SGI_IRXEN BIT(7)
+#define ENETC_CBDR_SGI_ACLLEN_MASK 0x3
+#define ENETC_CBDR_SGI_OCLLEN_MASK 0xc
+#define ENETC_CBDR_SGI_EN BIT(7)
+/* class 9, command 0, Stream Gate Instance Table, Short Format
+ * class 9, command 2, Stream Gate Instance Table entry query write back
+ * Short Format
+ */
+struct sgi_table {
+ u8 res[8];
+ u8 oipv;
+ u8 res0[2];
+ u8 ocgtst;
+ u8 res1[7];
+ u8 gset;
+ u8 oacl_len;
+ u8 res2[2];
+ u8 en;
+};
+
+#define ENETC_CBDR_SGI_AIPV_MASK 0x7
+#define ENETC_CBDR_SGI_AIPV_EN BIT(3)
+#define ENETC_CBDR_SGI_AGTST BIT(7)
+
+/* class 9, command 1, Stream Gate Control List, Long Format */
+struct sgcl_conf {
+ u8 aipv;
+ u8 res[2];
+ u8 agtst;
+ u8 res1[4];
+ union {
+ struct {
+ u8 res2[4];
+ u8 acl_len;
+ u8 res3[3];
+ };
+ u8 cct[8]; /* Config change time */
+ };
+};
+
+/* stream control list class 9 , cmd 1 data buffer */
+struct sgcl_data {
+ u32 btl;
+ u32 bth;
+ u32 ct;
+ u32 cte;
+ /*struct sgce *sgcl;*/
+};
+
+/* class 9, command 2, stream gate instant table enery query, short format
+ * write back see struct sgi_table. Do not need define.
+ * class 9, command 3 Stream Gate Control List Query Descriptor - Long Format
+ * ocl_len or acl_len to be 0, oper or admin would not show in the data space
+ * true len will be write back in the space.
+ */
+struct sgcl_query {
+ u8 res[12];
+ u8 oacl_len;
+ u8 res1[3];
+};
+
+/* define for 'stat' */
+#define ENETC_CBDR_SGIQ_AIPV_MASK 0x7
+#define ENETC_CBDR_SGIQ_AIPV_EN BIT(3)
+#define ENETC_CBDR_SGIQ_AGTST BIT(4)
+#define ENETC_CBDR_SGIQ_ACL_LEN_MASK 0x60
+#define ENETC_CBDR_SGIQ_OIPV_MASK 0x380
+#define ENETC_CBDR_SGIQ_OIPV_EN BIT(10)
+#define ENETC_CBDR_SGIQ_OGTST BIT(11)
+#define ENETC_CBDR_SGIQ_OCL_LEN_MASK 0x3000
+/* class 9, command 3 data space */
+struct sgcl_query_resp {
+ u16 stat;
+ u16 res;
+ u32 abtl;
+ u32 abth;
+ u32 act;
+ u32 acte;
+ u32 cctl;
+ u32 ccth;
+ u32 obtl;
+ u32 obth;
+ u32 oct;
+ u32 octe;
+};
+
+/* class 9, command 4 Stream Gate Instance Table Query Statistics Response
+ * short command, write back, no command define
+ */
+struct sgi_query_stat_resp {
+ u32 pgcl;
+ u32 pgch;
+ u32 dgcl;
+ u32 dgch;
+ u16 msdu_avail;
+ u8 res[6];
+};
+
+#define ENETC_CBDR_FMI_MR BIT(0)
+#define ENETC_CBDR_FMI_MREN BIT(1)
+#define ENETC_CBDR_FMI_DOY BIT(2)
+#define ENETC_CBDR_FMI_CM BIT(3)
+#define ENETC_CBDR_FMI_CF BIT(4)
+#define ENETC_CBDR_FMI_NDOR BIT(5)
+#define ENETC_CBDR_FMI_OALEN BIT(6)
+#define ENETC_CBDR_FMI_IRFPP_MASK 0x1f
+/* class 10: command 0/1, Flow Meter Instance Set, short Format */
+struct fmi_conf {
+ __le32 cir;
+ __le32 cbs;
+ __le32 eir;
+ __le32 ebs;
+ u8 conf;
+ u8 res1;
+ u8 ir_fpp;
+ u8 res2[4];
+ u8 en;
+};
+
+/* class:10, command:2, Flow Meter Instance Statistics Query Response */
+struct fmi_query_stat_resp {
+ u32 bcl;
+ u32 bch;
+ u32 dfl;
+ u32 dfh;
+ u32 d0gfl;
+ u32 d0gfh;
+ u32 d1gfl;
+ u32 d1gfh;
+ u32 dyfl;
+ u32 dyfh;
+ u32 ryfl;
+ u32 ryfh;
+ u32 drfl;
+ u32 drfh;
+ u32 rrfl;
+ u32 rrfh;
+ u32 lts;
+ u32 bci;
+ u32 bcf;
+ u32 bei;
+ u32 bef;
+};
+
+/* class 5, command 0 */
+struct tgs_gcl_conf {
+ u8 atc; /* init gate value */
+ u8 res[7];
+ union {
+ struct {
+ u8 res1[4];
+ __le16 acl_len;
+ u8 res2[2];
+ };
+ struct {
+ u32 cctl;
+ u32 ccth;
+ };
+ };
+};
+
+#define ENETC_CBDR_SGL_IOMEN BIT(0)
+#define ENETC_CBDR_SGL_IPVEN BIT(3)
+#define ENETC_CBDR_SGL_GTST BIT(4)
+#define ENETC_CBDR_SGL_IPV_MASK 0xe
+/* Stream Gate Control List Entry */
+struct sgce {
+ u32 interval;
+ u8 msdu[3];
+ u8 multi;
+};
+
+/* gate control list entry */
+struct gce {
+ __le32 period;
+ u8 gate;
+ u8 res[3];
+};
+
+/* tgs_gcl_conf address point to this data space */
+struct tgs_gcl_data {
+ __le32 btl;
+ __le32 bth;
+ __le32 ct;
+ __le32 cte;
+ struct gce entry[0];
+};
+
+/* class 5, command 1 */
+struct tgs_gcl_query {
+ u8 res[12];
+ union {
+ struct {
+ __le16 acl_len; /* admin list length */
+ __le16 ocl_len; /* operation list length */
+ };
+ struct {
+ u16 admin_list_len;
+ u16 oper_list_len;
+ };
+ };
+
+};
+
+/* tgs_gcl_query command response data format */
+struct tgs_gcl_resp {
+ u32 abtl; /* base time */
+ u32 abth;
+ u32 act; /* cycle time */
+ u32 acte; /* cycle time extend */
+ u32 cctl; /* config change time */
+ u32 ccth;
+ u32 obtl; /* operation base time */
+ u32 obth;
+ u32 oct; /* operation cycle time */
+ u32 octe; /* operation cycle time extend */
+ u32 ccel; /* config change error */
+ u32 cceh;
+ /*struct gce *gcl;*/
+};
+
+struct enetc_cbd {
+ union{
+ struct sfi_conf sfi_conf;
+ struct sgi_table sgi_table;
+ struct sgi_query_stat_resp sgi_query_stat_resp;
+ struct fmi_conf fmi_conf;
+ struct {
+ __le32 addr[2];
+ union {
+ __le32 opt[4];
+ struct tgs_gcl_conf gcl_conf;
+ struct tgs_gcl_query gcl_query;
+ struct streamid_conf sid_set;
+ struct streamid_stat_query sid_stat;
+ struct sgcl_conf sgcl_conf;
+ struct sgcl_query sgcl_query;
+ };
+ }; /* Long format */
+ __le32 data[6];
+ };
+ __le16 index;
+ __le16 length;
+ u8 cmd;
+ u8 cls;
+ u8 _res;
+ u8 status_flags;
+};
+
+#define ENETC_CLK 400000000ULL
+
+#define ENETC_PTCFPR(n) (0x1910 + (n) * 4) /* n = [0 ..7] */
+#define ENETC_FPE BIT(31)
+
+/* Port capability register 0 */
+#define ENETC_PCAPR0_PSFPM BIT(10)
+#define ENETC_PCAPR0_PSFP BIT(9)
+#define ENETC_PCAPR0_TSN BIT(4)
+#define ENETC_PCAPR0_QBU BIT(3)
+
+/* port time gating control register */
+#define ENETC_QBV_PTGCR_OFFSET 0x11a00
+#define ENETC_QBV_TGE BIT(31)
+#define ENETC_QBV_TGPE BIT(30)
+#define ENETC_QBV_TGDROP_DISABLE BIT(29)
+
+/* Port time gating capability register */
+#define ENETC_QBV_PTGCAPR_OFFSET 0x11a08
+#define ENETC_QBV_MAX_GCL_LEN_MASK GENMASK(15, 0)
+
+/* Port time gating tick granularity register */
+#define ENETC_QBV_PTGTGR_OFFSET 0x11a0c
+#define ENETC_QBV_TICK_GRAN_MASK 0xffffffff
+
+/* Port time gating admin gate list status register */
+#define ENETC_QBV_PTGAGLSR_OFFSET 0x11a10
+
+#define ENETC_QBV_CFG_PEND_MASK 0x00000002
+
+/* Port time gating admin gate list length register */
+#define ENETC_QBV_PTGAGLLR_OFFSET 0x11a14
+#define ENETC_QBV_ADMIN_GATE_LIST_LENGTH_MASK 0xffff
+
+/* Port time gating operational gate list status register */
+#define ENETC_QBV_PTGOGLSR_OFFSET 0x11a18
+#define ENETC_QBV_HTA_POS_MASK 0xffff0000
+
+#define ENETC_QBV_CURR_POS_MASK 0x0000ffff
+
+/* Port time gating operational gate list length register */
+#define ENETC_QBV_PTGOGLLR_OFFSET 0x11a1c
+#define ENETC_QBV_OPER_GATE_LIST_LENGTH_MASK 0xffff
+
+/* Port time gating current time register */
+#define ENETC_QBV_PTGCTR_OFFSET 0x11a20
+#define ENETC_QBV_CURR_TIME_MASK 0xffffffffffffffff
+
+/* Port traffic class a time gating control register */
+#define ENETC_QBV_PTC0TGCR_OFFSET 0x11a40
+#define ENETC_QBV_PTC1TGCR_OFFSET 0x11a50
+#define ENETC_QBV_PTC2TGCR_OFFSET 0x11a60
+#define ENETC_QBV_PTC3TGCR_OFFSET 0x11a70
+#define ENETC_QBV_PTC4TGCR_OFFSET 0x11a80
+#define ENETC_QBV_PTC5TGCR_OFFSET 0x11a90
+#define ENETC_QBV_PTC6TGCR_OFFSET 0x11aa0
+#define ENETC_QBV_PTC7TGCR_OFFSET 0x11ab0
+
+/* Maximum Service Data Unit. */
+#define ENETC_PTC0MSDUR 0x12020
+#define ENETC_PTC1MSDUR 0x12024
+#define ENETC_PTC2MSDUR 0x12028
+#define ENETC_PTC3MSDUR 0x1202c
+#define ENETC_PTC4MSDUR 0x12030
+#define ENETC_PTC5MSDUR 0x12034
+#define ENETC_PTC6MSDUR 0x12038
+#define ENETC_PTC7MSDUR 0x1203c
+
+#define ENETC_QBV_MAXSDU_MASK 0xffff
+
+/* Port traffic class a time gating status register */
+#define ENETC_QBV_PTC0TGSR_OFFSET 0x11a44
+#define ENETC_QBV_HTA_STATE_MASK 0x10000
+#define ENETC_QBV_CURR_STATE_MASK 0x1
+
+/* Port traffic class a time gating transmission overrun counter register*/
+#define ENETC_QBV_PTC0TGTOCR_OFFSET 0x11a48
+#define ENETC_QBV_TX_OVERRUN_MASK 0xffffffffffffffff
+#define ENETC_TGLSTR 0xa200
+#define ENETC_TGS_MIN_DIS_MASK 0x80000000
+#define ENETC_MIN_LOOKAHEAD_MASK 0xffff
+
+#define ENETC_PPSFPMR 0x11b00
+#define ENETC_PPSFPMR_PSFPEN BIT(0)
+#define ENETC_PPSFPMR_VS BIT(1)
+#define ENETC_PPSFPMR_PVC BIT(2)
+#define ENETC_PPSFPMR_PVZC BIT(3)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
index 149883c8f0b8..ac119b7e59d5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c
@@ -1,41 +1,56 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
+#include <linux/fsl/enetc_mdio.h>
#include <linux/mdio.h>
#include <linux/of_mdio.h>
#include <linux/iopoll.h>
#include <linux/of.h>
-#include "enetc_mdio.h"
+#include "enetc_pf.h"
-#define ENETC_MDIO_REG_OFFSET 0x1c00
#define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */
#define ENETC_MDIO_CTL 0x4 /* MDIO control */
#define ENETC_MDIO_DATA 0x8 /* MDIO data */
#define ENETC_MDIO_ADDR 0xc /* MDIO address */
-#define enetc_mdio_rd(hw, off) \
- enetc_port_rd(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET)
-#define enetc_mdio_wr(hw, off, val) \
- enetc_port_wr(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET, val)
-#define enetc_mdio_rd_reg(off) enetc_mdio_rd(hw, off)
+static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
+{
+ return enetc_port_rd_single(mdio_priv->hw, mdio_priv->mdio_base + off);
+}
+
+static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
+ u32 val)
+{
+ enetc_port_wr_single(mdio_priv->hw, mdio_priv->mdio_base + off, val);
+}
-#define ENETC_MDC_DIV 258
+#define enetc_mdio_rd(mdio_priv, off) \
+ _enetc_mdio_rd(mdio_priv, ENETC_##off)
+#define enetc_mdio_wr(mdio_priv, off, val) \
+ _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
+#define enetc_mdio_rd_reg(off) enetc_mdio_rd(mdio_priv, off)
#define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8)
#define MDIO_CFG_BSY BIT(0)
#define MDIO_CFG_RD_ER BIT(1)
+#define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2))
#define MDIO_CFG_ENC45 BIT(6)
/* external MDIO only - driven on neg MDC edge */
#define MDIO_CFG_NEG BIT(23)
+#define ENETC_EMDIO_CFG \
+ (MDIO_CFG_HOLD(2) | \
+ MDIO_CFG_CLKDIV(258) | \
+ MDIO_CFG_NEG)
+
#define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f)
#define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
#define MDIO_CTL_READ BIT(15)
#define MDIO_DATA(x) ((x) & 0xffff)
#define TIMEOUT 1000
-static int enetc_mdio_wait_complete(struct enetc_hw *hw)
+static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
{
u32 val;
@@ -46,12 +61,11 @@ static int enetc_mdio_wait_complete(struct enetc_hw *hw)
int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
{
struct enetc_mdio_priv *mdio_priv = bus->priv;
- struct enetc_hw *hw = mdio_priv->hw;
u32 mdio_ctl, mdio_cfg;
u16 dev_addr;
int ret;
- mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
+ mdio_cfg = ENETC_EMDIO_CFG;
if (regnum & MII_ADDR_C45) {
dev_addr = (regnum >> 16) & 0x1f;
mdio_cfg |= MDIO_CFG_ENC45;
@@ -61,44 +75,44 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
mdio_cfg &= ~MDIO_CFG_ENC45;
}
- enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
+ enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
/* set port and dev addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
- enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
+ enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
/* set the register address */
if (regnum & MII_ADDR_C45) {
- enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
+ enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
}
/* write the value */
- enetc_mdio_wr(hw, MDIO_DATA, MDIO_DATA(value));
+ enetc_mdio_wr(mdio_priv, MDIO_DATA, MDIO_DATA(value));
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
return 0;
}
+EXPORT_SYMBOL_GPL(enetc_mdio_write);
int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{
struct enetc_mdio_priv *mdio_priv = bus->priv;
- struct enetc_hw *hw = mdio_priv->hw;
u32 mdio_ctl, mdio_cfg;
u16 dev_addr, value;
int ret;
- mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
+ mdio_cfg = ENETC_EMDIO_CFG;
if (regnum & MII_ADDR_C45) {
dev_addr = (regnum >> 16) & 0x1f;
mdio_cfg |= MDIO_CFG_ENC45;
@@ -107,86 +121,56 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
mdio_cfg &= ~MDIO_CFG_ENC45;
}
- enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
+ enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
/* set port and device addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
- enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
+ enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
/* set the register address */
if (regnum & MII_ADDR_C45) {
- enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
+ enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
}
/* initiate the read */
- enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
+ enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
- ret = enetc_mdio_wait_complete(hw);
+ ret = enetc_mdio_wait_complete(mdio_priv);
if (ret)
return ret;
/* return all Fs if nothing was there */
- if (enetc_mdio_rd(hw, MDIO_CFG) & MDIO_CFG_RD_ER) {
+ if (enetc_mdio_rd(mdio_priv, MDIO_CFG) & MDIO_CFG_RD_ER) {
dev_dbg(&bus->dev,
"Error while reading PHY%d reg at %d.%hhu\n",
phy_id, dev_addr, regnum);
return 0xffff;
}
- value = enetc_mdio_rd(hw, MDIO_DATA) & 0xffff;
+ value = enetc_mdio_rd(mdio_priv, MDIO_DATA) & 0xffff;
return value;
}
+EXPORT_SYMBOL_GPL(enetc_mdio_read);
-int enetc_mdio_probe(struct enetc_pf *pf)
+struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
{
- struct device *dev = &pf->si->pdev->dev;
- struct enetc_mdio_priv *mdio_priv;
- struct device_node *np;
- struct mii_bus *bus;
- int err;
-
- bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
- if (!bus)
- return -ENOMEM;
-
- bus->name = "Freescale ENETC MDIO Bus";
- bus->read = enetc_mdio_read;
- bus->write = enetc_mdio_write;
- bus->parent = dev;
- mdio_priv = bus->priv;
- mdio_priv->hw = &pf->si->hw;
- snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
-
- np = of_get_child_by_name(dev->of_node, "mdio");
- if (!np) {
- dev_err(dev, "MDIO node missing\n");
- return -EINVAL;
- }
-
- err = of_mdiobus_register(bus, np);
- if (err) {
- of_node_put(np);
- dev_err(dev, "cannot register MDIO bus\n");
- return err;
- }
+ struct enetc_hw *hw;
- of_node_put(np);
- pf->mdio = bus;
+ hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return ERR_PTR(-ENOMEM);
- return 0;
-}
+ hw->port = port_regs;
-void enetc_mdio_remove(struct enetc_pf *pf)
-{
- if (pf->mdio)
- mdiobus_unregister(pf->mdio);
+ return hw;
}
+EXPORT_SYMBOL_GPL(enetc_hw_alloc);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h b/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
deleted file mode 100644
index 60c9a3889824..000000000000
--- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/* Copyright 2019 NXP */
-
-#include <linux/phy.h>
-#include "enetc_pf.h"
-
-struct enetc_mdio_priv {
- struct enetc_hw *hw;
-};
-
-int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value);
-int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
index fbd41ce01f06..87c0e969da40 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
+#include <linux/fsl/enetc_mdio.h>
#include <linux/of_mdio.h>
-#include "enetc_mdio.h"
+#include "enetc_pf.h"
#define ENETC_MDIO_DEV_ID 0xee01
#define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO"
@@ -13,17 +14,29 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
{
struct enetc_mdio_priv *mdio_priv;
struct device *dev = &pdev->dev;
+ void __iomem *port_regs;
struct enetc_hw *hw;
struct mii_bus *bus;
int err;
- hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
- if (!hw)
- return -ENOMEM;
+ port_regs = pci_iomap(pdev, 0, 0);
+ if (!port_regs) {
+ dev_err(dev, "iomap failed\n");
+ err = -ENXIO;
+ goto err_ioremap;
+ }
+
+ hw = enetc_hw_alloc(dev, port_regs);
+ if (IS_ERR(enetc_hw_alloc)) {
+ err = PTR_ERR(hw);
+ goto err_hw_alloc;
+ }
bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
- if (!bus)
- return -ENOMEM;
+ if (!bus) {
+ err = -ENOMEM;
+ goto err_mdiobus_alloc;
+ }
bus->name = ENETC_MDIO_BUS_NAME;
bus->read = enetc_mdio_read;
@@ -31,13 +44,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
bus->parent = dev;
mdio_priv = bus->priv;
mdio_priv->hw = hw;
+ mdio_priv->mdio_base = ENETC_EMDIO_BASE;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
pcie_flr(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(dev, "device enable failed\n");
- return err;
+ goto err_pci_enable;
}
err = pci_request_region(pdev, 0, KBUILD_MODNAME);
@@ -46,13 +60,6 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
goto err_pci_mem_reg;
}
- hw->port = pci_iomap(pdev, 0, 0);
- if (!hw->port) {
- err = -ENXIO;
- dev_err(dev, "iomap failed\n");
- goto err_ioremap;
- }
-
err = of_mdiobus_register(bus, dev->of_node);
if (err)
goto err_mdiobus_reg;
@@ -62,12 +69,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
return 0;
err_mdiobus_reg:
- iounmap(mdio_priv->hw->port);
-err_ioremap:
pci_release_mem_regions(pdev);
err_pci_mem_reg:
pci_disable_device(pdev);
-
+err_pci_enable:
+err_mdiobus_alloc:
+ iounmap(port_regs);
+err_hw_alloc:
+err_ioremap:
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index ac62464e0416..99ad75800160 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -2,6 +2,7 @@
/* Copyright 2017-2019 NXP */
#include <linux/module.h>
+#include <linux/fsl/enetc_mdio.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "enetc_pf.h"
@@ -507,7 +508,8 @@ static void enetc_port_si_configure(struct enetc_si *si)
enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
}
-static void enetc_configure_port_mac(struct enetc_hw *hw)
+static void enetc_configure_port_mac(struct enetc_hw *hw,
+ phy_interface_t phy_mode)
{
enetc_port_wr(hw, ENETC_PM0_MAXFRM,
ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
@@ -523,10 +525,23 @@ static void enetc_configure_port_mac(struct enetc_hw *hw)
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC |
ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
/* set auto-speed for RGMII */
- if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG)
+ if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG ||
+ phy_mode == PHY_INTERFACE_MODE_RGMII) {
enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO);
- if (enetc_global_rd(hw, ENETC_G_EPFBLPR(1)) == ENETC_G_EPFBLPR1_XGMII)
+ enetc_port_wr(hw, ENETC_PM1_IF_MODE, ENETC_PM0_IFM_RGAUTO);
+ }
+
+ if (phy_mode == PHY_INTERFACE_MODE_XGMII ||
+ phy_mode == PHY_INTERFACE_MODE_USXGMII) {
enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
+ enetc_port_wr(hw, ENETC_PM1_IF_MODE, ENETC_PM0_IFM_XGMII);
+ }
+
+ /* on LS1028A the MAC Rx FIFO defaults to value 2, which is too high and
+ * may lead to Rx lock-up under traffic. Set it to 1 instead, as
+ * recommended by the hardware team.
+ */
+ enetc_port_wr(hw, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
}
static void enetc_configure_port_pmac(struct enetc_hw *hw)
@@ -549,7 +564,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
enetc_configure_port_pmac(hw);
- enetc_configure_port_mac(hw);
+ enetc_configure_port_mac(hw, pf->if_mode);
enetc_port_si_configure(pf->si);
@@ -740,38 +755,86 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
ndev->features &= ~NETIF_F_HW_CSUM;
}
- ndev->priv_flags |= IFF_UNICAST_FLT;
+ ndev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
+
+ if (si->hw_features & ENETC_SI_F_QBV)
+ priv->active_offloads |= ENETC_F_QBV;
+
+ if (enetc_tsn_is_enabled() && (si->hw_features & ENETC_SI_F_QBU))
+ priv->active_offloads |= ENETC_F_QBU;
/* pick up primary MAC address from SI */
enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
}
-static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
+static int enetc_mdio_probe(struct enetc_pf *pf)
{
- struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct device_node *np = priv->dev->of_node;
- struct device_node *mdio_np;
+ struct device *dev = &pf->si->pdev->dev;
+ struct enetc_mdio_priv *mdio_priv;
+ struct device_node *np;
+ struct mii_bus *bus;
int err;
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "Freescale ENETC MDIO Bus";
+ bus->read = enetc_mdio_read;
+ bus->write = enetc_mdio_write;
+ bus->parent = dev;
+ mdio_priv = bus->priv;
+ mdio_priv->hw = &pf->si->hw;
+ mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+ np = of_get_child_by_name(dev->of_node, "mdio");
if (!np) {
- dev_err(priv->dev, "missing ENETC port node\n");
- return -ENODEV;
+ dev_err(dev, "MDIO node missing\n");
+ return -EINVAL;
}
- priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
- if (!priv->phy_node) {
+ err = of_mdiobus_register(bus, np);
+ if (err) {
+ of_node_put(np);
+ dev_err(dev, "cannot register MDIO bus\n");
+ return err;
+ }
+
+ of_node_put(np);
+ pf->mdio = bus;
+
+ return 0;
+}
+
+static void enetc_mdio_remove(struct enetc_pf *pf)
+{
+ if (pf->mdio)
+ mdiobus_unregister(pf->mdio);
+}
+
+static int enetc_of_get_phy(struct enetc_pf *pf)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *mdio_np;
+ int phy_mode;
+ int err;
+
+ pf->phy_node = of_parse_phandle(np, "phy-handle", 0);
+ if (!pf->phy_node) {
if (!of_phy_is_fixed_link(np)) {
- dev_err(priv->dev, "PHY not specified\n");
+ dev_err(dev, "PHY not specified\n");
return -ENODEV;
}
err = of_phy_register_fixed_link(np);
if (err < 0) {
- dev_err(priv->dev, "fixed link registration failed\n");
+ dev_err(dev, "fixed link registration failed\n");
return err;
}
- priv->phy_node = of_node_get(np);
+ pf->phy_node = of_node_get(np);
}
mdio_np = of_get_child_by_name(np, "mdio");
@@ -779,34 +842,109 @@ static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
of_node_put(mdio_np);
err = enetc_mdio_probe(pf);
if (err) {
- of_node_put(priv->phy_node);
+ of_node_put(pf->phy_node);
return err;
}
}
- priv->if_mode = of_get_phy_mode(np);
- if ((int)priv->if_mode < 0) {
- dev_err(priv->dev, "missing phy type\n");
- of_node_put(priv->phy_node);
- if (of_phy_is_fixed_link(np))
- of_phy_deregister_fixed_link(np);
- else
- enetc_mdio_remove(pf);
-
- return -EINVAL;
- }
+ phy_mode = of_get_phy_mode(np);
+ if (phy_mode < 0)
+ pf->if_mode = PHY_INTERFACE_MODE_NA; /* fixed link */
+ else
+ pf->if_mode = phy_mode;
return 0;
}
-static void enetc_of_put_phy(struct enetc_ndev_priv *priv)
+static void enetc_of_put_phy(struct enetc_pf *pf)
{
- struct device_node *np = priv->dev->of_node;
+ struct device_node *np = pf->si->pdev->dev.of_node;
if (np && of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
- if (priv->phy_node)
- of_node_put(priv->phy_node);
+ if (pf->phy_node)
+ of_node_put(pf->phy_node);
+}
+
+static void enetc_configure_sgmii(struct mii_bus *imdio)
+{
+ /* Set to SGMII mode, use AN */
+ imdio->write(imdio, 0, ENETC_PCS_IF_MODE,
+ ENETC_PCS_IF_MODE_SGMII_AN);
+
+ /* Dev ability - SGMII */
+ imdio->write(imdio, 0, ENETC_PCS_DEV_ABILITY,
+ ENETC_PCS_DEV_ABILITY_SGMII);
+
+ /* Adjust link timer for SGMII */
+ imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER1,
+ ENETC_PCS_LINK_TIMER1_VAL);
+ imdio->write(imdio, 0, ENETC_PCS_LINK_TIMER2,
+ ENETC_PCS_LINK_TIMER2_VAL);
+
+ /* restart PCS AN */
+ imdio->write(imdio, 0, ENETC_PCS_CR,
+ ENETC_PCS_CR_RESET_AN | ENETC_PCS_CR_DEF_VAL);
+}
+
+static void enetc_configure_sxgmii(struct mii_bus *imdio)
+{
+ /* Dev ability - SXGMII */
+ imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
+
+ /* Restart PCS AN */
+ imdio->write(imdio, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) |
+ ENETC_PCS_CR,
+ ENETC_PCS_CR_LANE_RESET | ENETC_PCS_CR_RESET_AN);
+}
+
+static int enetc_imdio_init(struct enetc_pf *pf)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ struct enetc_mdio_priv *mdio_priv;
+ struct mii_bus *bus;
+
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "FSL ENETC internal MDIO Bus";
+ bus->read = enetc_mdio_read;
+ bus->write = enetc_mdio_write;
+ bus->parent = dev;
+ mdio_priv = bus->priv;
+ mdio_priv->hw = &pf->si->hw;
+ mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+ pf->imdio = bus;
+
+ return 0;
+}
+
+static int enetc_configure_serdes(struct enetc_ndev_priv *priv)
+{
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ int err;
+
+ if (priv->if_mode != PHY_INTERFACE_MODE_SGMII &&
+ priv->if_mode != PHY_INTERFACE_MODE_XGMII &&
+ priv->if_mode != PHY_INTERFACE_MODE_USXGMII)
+ return 0;
+
+ err = enetc_imdio_init(pf);
+ if (err)
+ return err;
+
+ if (priv->if_mode == PHY_INTERFACE_MODE_SGMII)
+ enetc_configure_sgmii(pf->imdio);
+
+ if (priv->if_mode == PHY_INTERFACE_MODE_XGMII ||
+ priv->if_mode == PHY_INTERFACE_MODE_USXGMII)
+ enetc_configure_sxgmii(pf->imdio);
+
+ return 0;
}
/* Initialize the entire shared memory for the flow steering entries
@@ -907,6 +1045,10 @@ static int enetc_pf_probe(struct pci_dev *pdev,
pf->si = si;
pf->total_vfs = pci_sriov_get_totalvfs(pdev);
+ err = enetc_of_get_phy(pf);
+ if (err)
+ dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
+
enetc_configure_port(pf);
enetc_get_si_caps(si);
@@ -921,6 +1063,8 @@ static int enetc_pf_probe(struct pci_dev *pdev,
enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops);
priv = netdev_priv(ndev);
+ priv->phy_node = pf->phy_node;
+ priv->if_mode = pf->if_mode;
enetc_init_si_rings_params(priv);
@@ -954,9 +1098,9 @@ static int enetc_pf_probe(struct pci_dev *pdev,
goto err_alloc_msix;
}
- err = enetc_of_get_phy(priv);
+ err = enetc_configure_serdes(priv);
if (err)
- dev_warn(&pdev->dev, "Fallback to PHY-less operation\n");
+ dev_warn(&pdev->dev, "Attempted serdes config but failed\n");
err = register_netdev(ndev);
if (err)
@@ -967,11 +1111,11 @@ static int enetc_pf_probe(struct pci_dev *pdev,
netif_info(priv, probe, ndev, "%s v%s\n",
enetc_drv_name, enetc_drv_ver);
+ enetc_tsn_pf_init(ndev, pdev);
+
return 0;
err_reg_netdev:
- enetc_mdio_remove(pf);
- enetc_of_put_phy(priv);
enetc_free_msix(priv);
err_config_si:
err_init_port_rss:
@@ -982,6 +1126,8 @@ err_alloc_si_res:
si->ndev = NULL;
free_netdev(ndev);
err_alloc_netdev:
+ enetc_mdio_remove(pf);
+ enetc_of_put_phy(pf);
err_device_disabled:
err_map_pf_space:
enetc_pci_remove(pdev);
@@ -1002,10 +1148,12 @@ static void enetc_pf_remove(struct pci_dev *pdev)
netif_info(priv, drv, si->ndev, "%s v%s remove\n",
enetc_drv_name, enetc_drv_ver);
+ enetc_tsn_pf_deinit(si->ndev);
+
unregister_netdev(si->ndev);
enetc_mdio_remove(pf);
- enetc_of_put_phy(priv);
+ enetc_of_put_phy(pf);
enetc_free_msix(priv);
@@ -1016,6 +1164,10 @@ static void enetc_pf_remove(struct pci_dev *pdev)
enetc_pci_remove(pdev);
}
+/* Lock for MDIO access errata on LS1028A */
+DEFINE_RWLOCK(enetc_mdio_lock);
+EXPORT_SYMBOL_GPL(enetc_mdio_lock);
+
static const struct pci_device_id enetc_pf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
{ 0, } /* End of table. */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 10dd1b53bb08..e4f041eb2c9b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -44,12 +44,12 @@ struct enetc_pf {
DECLARE_BITMAP(active_vlans, VLAN_N_VID);
struct mii_bus *mdio; /* saved for cleanup */
+ struct mii_bus *imdio;
+
+ struct device_node *phy_node;
+ phy_interface_t if_mode;
};
int enetc_msg_psi_init(struct enetc_pf *pf);
void enetc_msg_psi_free(struct enetc_pf *pf);
void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
-
-/* MDIO */
-int enetc_mdio_probe(struct enetc_pf *pf);
-void enetc_mdio_remove(struct enetc_pf *pf);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
new file mode 100644
index 000000000000..2e99438cb1bf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include "enetc.h"
+
+#include <net/pkt_sched.h>
+#include <linux/math64.h>
+
+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+ return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+ & ENETC_QBV_MAX_GCL_LEN_MASK;
+}
+
+void enetc_sched_speed_set(struct net_device *ndev)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+ u32 old_speed = priv->speed;
+ u32 speed, pspeed;
+
+ if (phydev->speed == old_speed)
+ return;
+
+ speed = phydev->speed;
+ switch (speed) {
+ case SPEED_1000:
+ pspeed = ENETC_PMR_PSPEED_1000M;
+ break;
+ case SPEED_2500:
+ pspeed = ENETC_PMR_PSPEED_2500M;
+ break;
+ case SPEED_100:
+ pspeed = ENETC_PMR_PSPEED_100M;
+ break;
+ case SPEED_10:
+ default:
+ pspeed = ENETC_PMR_PSPEED_10M;
+ netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
+ }
+
+ priv->speed = speed;
+ enetc_port_wr(&priv->si->hw, ENETC_PMR,
+ (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+ & (~ENETC_PMR_PSPEED_MASK))
+ | pspeed);
+}
+
+static int enetc_setup_taprio(struct net_device *ndev,
+ struct tc_taprio_qopt_offload *admin_conf)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_cbd cbd = {.cmd = 0};
+ struct tgs_gcl_conf *gcl_config;
+ struct tgs_gcl_data *gcl_data;
+ struct gce *gce;
+ dma_addr_t dma;
+ u16 data_size;
+ u16 gcl_len;
+ u32 tge;
+ int err;
+ int i;
+
+ if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
+ return -EINVAL;
+ gcl_len = admin_conf->num_entries;
+
+ tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
+ if (!admin_conf->enable) {
+ enetc_wr(&priv->si->hw,
+ ENETC_QBV_PTGCR_OFFSET,
+ tge & (~ENETC_QBV_TGE));
+ return 0;
+ }
+
+ if (admin_conf->cycle_time > U32_MAX ||
+ admin_conf->cycle_time_extension > U32_MAX)
+ return -EINVAL;
+
+ /* Configure the (administrative) gate control list using the
+ * control BD descriptor.
+ */
+ gcl_config = &cbd.gcl_conf;
+
+ data_size = struct_size(gcl_data, entry, gcl_len);
+ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!gcl_data)
+ return -ENOMEM;
+
+ gce = (struct gce *)(gcl_data + 1);
+
+ /* Set all gates open as default */
+ gcl_config->atc = 0xff;
+ gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+ if (!admin_conf->base_time) {
+ gcl_data->btl =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+ gcl_data->bth =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+ } else {
+ gcl_data->btl =
+ cpu_to_le32(lower_32_bits(admin_conf->base_time));
+ gcl_data->bth =
+ cpu_to_le32(upper_32_bits(admin_conf->base_time));
+ }
+
+ gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
+ gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
+
+ for (i = 0; i < gcl_len; i++) {
+ struct tc_taprio_sched_entry *temp_entry;
+ struct gce *temp_gce = gce + i;
+
+ temp_entry = &admin_conf->entries[i];
+
+ temp_gce->gate = (u8)temp_entry->gate_mask;
+ temp_gce->period = cpu_to_le32(temp_entry->interval);
+ }
+
+ cbd.length = cpu_to_le16(data_size);
+ cbd.status_flags = 0;
+
+ dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+ data_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ cbd.addr[0] = lower_32_bits(dma);
+ cbd.addr[1] = upper_32_bits(dma);
+ cbd.cls = BDCR_CMD_PORT_GCL;
+ cbd.status_flags = 0;
+
+ enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+ tge | ENETC_QBV_TGE);
+
+ err = enetc_send_cmd(priv->si, &cbd);
+ if (err)
+ enetc_wr(&priv->si->hw,
+ ENETC_QBV_PTGCR_OFFSET,
+ tge & (~ENETC_QBV_TGE));
+
+ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+ kfree(gcl_data);
+
+ return err;
+}
+
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
+{
+ struct tc_taprio_qopt_offload *taprio = type_data;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int err;
+ int i;
+
+ for (i = 0; i < priv->num_tx_rings; i++)
+ enetc_set_bdr_prio(&priv->si->hw,
+ priv->tx_ring[i]->index,
+ taprio->enable ? i : 0);
+
+ err = enetc_setup_taprio(ndev, taprio);
+
+ if (err)
+ for (i = 0; i < priv->num_tx_rings; i++)
+ enetc_set_bdr_prio(&priv->si->hw,
+ priv->tx_ring[i]->index,
+ taprio->enable ? 0 : i);
+
+ return err;
+}
+
+static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc)
+{
+ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE;
+}
+
+static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc)
+{
+ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK;
+}
+
+int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct tc_cbs_qopt_offload *cbs = type_data;
+ u32 port_transmit_rate = priv->speed;
+ u8 tc_nums = netdev_get_num_tc(ndev);
+ struct enetc_si *si = priv->si;
+ u32 hi_credit_bit, hi_credit_reg;
+ u32 max_interference_size;
+ u32 port_frame_max_size;
+ u32 tc_max_sized_frame;
+ u8 tc = cbs->queue;
+ u8 prio_top, prio_next;
+ int bw_sum = 0;
+ u8 bw;
+
+ prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
+ prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
+
+ /* Support highest prio and second prio tc in cbs mode */
+ if (tc != prio_top && tc != prio_next)
+ return -EOPNOTSUPP;
+
+ if (!cbs->enable) {
+ /* Make sure the other TC that are numerically
+ * lower than this TC have been disabled.
+ */
+ if (tc == prio_top &&
+ enetc_get_cbs_enable(&si->hw, prio_next)) {
+ dev_err(&ndev->dev,
+ "Disable TC%d before disable TC%d\n",
+ prio_next, tc);
+ return -EINVAL;
+ }
+
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
+
+ return 0;
+ }
+
+ if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L ||
+ cbs->idleslope < 0 || cbs->sendslope > 0)
+ return -EOPNOTSUPP;
+
+ port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+
+ bw = cbs->idleslope / (port_transmit_rate * 10UL);
+
+ /* Make sure the other TC that are numerically
+ * higher than this TC have been enabled.
+ */
+ if (tc == prio_next) {
+ if (!enetc_get_cbs_enable(&si->hw, prio_top)) {
+ dev_err(&ndev->dev,
+ "Enable TC%d first before enable TC%d\n",
+ prio_top, prio_next);
+ return -EINVAL;
+ }
+ bw_sum += enetc_get_cbs_bw(&si->hw, prio_top);
+ }
+
+ if (bw_sum + bw >= 100) {
+ dev_err(&ndev->dev,
+ "The sum of all CBS Bandwidth can't exceed 100\n");
+ return -EINVAL;
+ }
+
+ tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
+
+ /* For top prio TC, the max_interfrence_size is maxSizedFrame.
+ *
+ * For next prio TC, the max_interfrence_size is calculated as below:
+ *
+ * max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra)
+ *
+ * - RA: idleSlope for AVB Class A
+ * - R0: port transmit rate
+ * - M0: maximum sized frame for the port
+ * - MA: maximum sized frame for AVB Class A
+ */
+
+ if (tc == prio_top) {
+ max_interference_size = port_frame_max_size * 8;
+ } else {
+ u32 m0, ma, r0, ra;
+
+ m0 = port_frame_max_size * 8;
+ ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8;
+ ra = enetc_get_cbs_bw(&si->hw, prio_top) *
+ port_transmit_rate * 10000ULL;
+ r0 = port_transmit_rate * 1000000ULL;
+ max_interference_size = m0 + ma +
+ (u32)div_u64((u64)ra * m0, r0 - ra);
+ }
+
+ /* hiCredit bits calculate by:
+ *
+ * maxSizedFrame * (idleSlope/portTxRate)
+ */
+ hi_credit_bit = max_interference_size * bw / 100;
+
+ /* hiCredit bits to hiCredit register need to calculated as:
+ *
+ * (enetClockFrequency / portTransmitRate) * 100
+ */
+ hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
+ port_transmit_rate * 1000000ULL);
+
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
+
+ /* Set bw register and enable this traffic class */
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_tsn.c b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
new file mode 100644
index 000000000000..b07738fb21ce
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
@@ -0,0 +1,2049 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2017-2019 NXP */
+
+#ifdef CONFIG_ENETC_TSN
+#include "enetc.h"
+
+#include <net/tsn.h>
+#include <linux/module.h>
+#include <linux/irqflags.h>
+#include <linux/preempt.h>
+
+static u32 get_ndev_speed(struct net_device *netdev);
+
+static int alloc_cbdr(struct enetc_si *si, struct enetc_cbd **curr_cbd)
+{
+ struct enetc_cbdr *ring = &si->cbd_ring;
+ int i;
+
+ i = ring->next_to_use;
+ *curr_cbd = ENETC_CBD(*ring, i);
+
+ memset(*curr_cbd, 0, sizeof(struct enetc_cbd));
+ return i;
+}
+
+/* Transmit the BD control ring by writing the pir register.
+ * Update the counters maintained by software.
+ */
+static int xmit_cbdr(struct enetc_si *si, int i)
+{
+ struct enetc_cbdr *ring = &si->cbd_ring;
+ struct enetc_cbd *dest_cbd;
+ int nc, timeout;
+
+ i = (i + 1) % ring->bd_count;
+
+ ring->next_to_use = i;
+ /* let H/W know BD ring has been updated */
+ enetc_wr_reg(ring->pir, i);
+
+ timeout = ENETC_CBDR_TIMEOUT;
+
+ do {
+ if (enetc_rd_reg(ring->cir) == i)
+ break;
+ usleep_range(10, 20);
+ timeout -= 10;
+ } while (timeout);
+
+ if (!timeout)
+ return -EBUSY;
+
+ nc = ring->next_to_clean;
+
+ while (enetc_rd_reg(ring->cir) != nc) {
+ dest_cbd = ENETC_CBD(*ring, nc);
+ if (dest_cbd->status_flags & ENETC_CBD_STATUS_MASK)
+ WARN_ON(1);
+
+ nc = (nc + 1) % ring->bd_count;
+ }
+
+ ring->next_to_clean = nc;
+
+ return 0;
+}
+
+static inline u64 get_current_time(struct enetc_si *si)
+{
+ u64 tmp = 0;
+
+ tmp = (u64)enetc_rd(&si->hw, ENETC_SICTR0);
+ return ((u64)enetc_rd(&si->hw, ENETC_SICTR1) << 32) + tmp;
+}
+
+/* Class 10: Flow Meter Instance Statistics Query Descriptor - Long Format */
+int enetc_qci_fmi_counters_get(struct net_device *ndev, u32 index,
+ struct fmi_query_stat_resp *counters)
+{
+ struct enetc_cbd *cbdr;
+ struct fmi_query_stat_resp *fmi_data;
+ dma_addr_t dma;
+ u16 data_size, dma_size;
+ int curr_cbd;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 2;
+ cbdr->cls = BDCR_CMD_FLOW_METER;
+ cbdr->status_flags = 0;
+
+ data_size = sizeof(struct fmi_query_stat_resp);
+
+ fmi_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!fmi_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+
+ dma = dma_map_single(&priv->si->pdev->dev, fmi_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(fmi_data);
+ return -ENOMEM;
+ }
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memcpy(counters, fmi_data, sizeof(struct fmi_query_stat_resp));
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(fmi_data);
+ return 0;
+}
+
+u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+ return (enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+ & ENETC_QBV_MAX_GCL_LEN_MASK);
+}
+
+void enetc_pspeed_set(struct net_device *ndev)
+{
+ u32 speed, pspeed;
+ u32 difflag = 0;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ speed = get_ndev_speed(ndev);
+ pspeed = enetc_port_rd(&priv->si->hw, ENETC_PMR)
+ & ENETC_PMR_PSPEED_MASK;
+ switch (speed) {
+ case SPEED_1000:
+ if (pspeed != ENETC_PMR_PSPEED_1000M) {
+ difflag = 1;
+ pspeed = ENETC_PMR_PSPEED_1000M;
+ }
+ break;
+ case SPEED_2500:
+ if (pspeed != ENETC_PMR_PSPEED_2500M) {
+ difflag = 1;
+ pspeed = ENETC_PMR_PSPEED_2500M;
+ }
+
+ break;
+ case SPEED_100:
+ if (pspeed != ENETC_PMR_PSPEED_100M) {
+ difflag = 1;
+ pspeed = ENETC_PMR_PSPEED_100M;
+ }
+ break;
+ case SPEED_10:
+ if (pspeed != ENETC_PMR_PSPEED_10M) {
+ difflag = 1;
+ pspeed = ENETC_PMR_PSPEED_10M;
+ }
+ break;
+ default:
+ netdev_err(ndev, "not support speed\n");
+ }
+
+ if (difflag) {
+ enetc_port_wr(&priv->si->hw, ENETC_PMR,
+ (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+ & (~ENETC_PMR_PSPEED_MASK))
+ | pspeed);
+ }
+}
+
+/* CBD Class 5: Time Gated Scheduling Gate Control List configuration
+ * Descriptor - Long Format
+ */
+int enetc_qbv_set(struct net_device *ndev, struct tsn_qbv_conf *admin_conf)
+{
+ struct enetc_cbd *cbdr;
+ struct tgs_gcl_data *gcl_data;
+ struct tgs_gcl_conf *gcl_config;
+ struct gce *gce;
+ u16 gcl_len;
+ u16 data_size;
+ int i;
+ dma_addr_t dma;
+ int curr_cbd;
+ struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ u32 temp;
+ u64 tempclock;
+ struct tsn_port *port;
+
+ port = tsn_get_port(ndev);
+ if (!port) {
+ netdev_err(priv->si->ndev, "TSN device not registered!\n");
+ return -ENODEV;
+ }
+
+ enetc_pspeed_set(ndev);
+
+ gcl_len = admin_basic->control_list_length;
+ if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
+ return -EINVAL;
+
+ temp = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
+ if (admin_conf->gate_enabled && !(temp & ENETC_QBV_TGE)) {
+ enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+ temp & (~ENETC_QBV_TGE));
+ usleep_range(10, 20);
+ enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+ temp | ENETC_QBV_TGE);
+ } else if (!admin_conf->gate_enabled) {
+ enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+ temp & (~ENETC_QBV_TGE));
+ memcpy(&port->nd.ntdata, admin_conf, sizeof(*admin_conf));
+ call_tsn_notifiers(TSN_QBV_CONFIGCHANGETIME_ARRIVE,
+ ndev, &port->nd);
+ return 0;
+ }
+
+ /* Set the maximum frame size for each traffic class index
+ * PTCaMSDUR[MAXSDU]. The maximum frame size cannot exceed
+ * 9,600 bytes (0x2580). Frames that exceed the limit are
+ * discarded.
+ */
+ if (admin_conf->maxsdu) {
+ enetc_wr(&priv->si->hw, ENETC_PTC0MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC1MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC2MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC3MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC4MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC5MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC6MSDUR, admin_conf->maxsdu);
+ enetc_wr(&priv->si->hw, ENETC_PTC7MSDUR, admin_conf->maxsdu);
+ }
+
+ /* Configure the (administrative) gate control list using the
+ * control BD descriptor.
+ */
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ gcl_config = &cbdr->gcl_conf;
+
+ data_size = struct_size(gcl_data, entry, gcl_len);
+
+ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!gcl_data)
+ return -ENOMEM;
+
+ gce = &gcl_data->entry[0];
+
+ gcl_config->atc = admin_basic->gate_states;
+ gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+ if (!admin_basic->base_time) {
+ gcl_data->btl =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+ gcl_data->bth =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+ } else {
+ gcl_data->btl =
+ cpu_to_le32(lower_32_bits(admin_basic->base_time));
+ gcl_data->bth =
+ cpu_to_le32(upper_32_bits(admin_basic->base_time));
+ }
+
+ gcl_data->ct = cpu_to_le32(admin_basic->cycle_time);
+ gcl_data->cte = cpu_to_le32(admin_basic->cycle_time_extension);
+
+ for (i = 0; i < gcl_len; i++) {
+ struct gce *temp_gce = gce + i;
+ struct tsn_qbv_entry *temp_entry;
+
+ temp_entry = admin_basic->control_list + i;
+
+ temp_gce->gate = temp_entry->gate_state;
+ temp_gce->period = cpu_to_le32(temp_entry->time_interval);
+ }
+
+ cbdr->length = cpu_to_le16(data_size);
+ cbdr->status_flags = 0;
+
+ dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+ data_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_PORT_GCL;
+
+ /* Updated by ENETC on completion of the configuration
+ * command. A zero value indicates success.
+ */
+ cbdr->status_flags = 0;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memcpy(&port->nd.ntdata, admin_conf, sizeof(*admin_conf));
+
+ tempclock = ((u64)le32_to_cpu(gcl_config->ccth)) << 32;
+ port->nd.ntdata.qbv_notify.admin.base_time =
+ le32_to_cpu(gcl_config->cctl) + tempclock;
+
+ memset(cbdr, 0, sizeof(struct enetc_cbd));
+ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+ kfree(gcl_data);
+
+ call_tsn_notifiers(TSN_QBV_CONFIGCHANGETIME_ARRIVE,
+ ndev, &port->nd);
+
+ return 0;
+}
+
+/* CBD Class 5: Time Gated Scheduling Gate Control List query
+ * Descriptor - Long Format
+ */
+int enetc_qbv_get(struct net_device *ndev, struct tsn_qbv_conf *admin_conf)
+{
+ struct enetc_cbd *cbdr;
+ struct tgs_gcl_resp *gcl_data;
+ struct tgs_gcl_query *gcl_query;
+ struct gce *gce;
+ struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ dma_addr_t dma;
+ int curr_cbd;
+ u16 maxlen;
+ u16 data_size, dma_size;
+ u16 admin_len;
+ u16 oper_len;
+ u64 temp;
+ int i;
+
+ if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE) {
+ admin_conf->gate_enabled = true;
+ } else {
+ admin_conf->gate_enabled = false;
+ return 0;
+ }
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ gcl_query = &cbdr->gcl_query;
+
+ maxlen = enetc_get_max_gcl_len(&priv->si->hw);
+
+ data_size = sizeof(struct tgs_gcl_resp)
+ + sizeof(struct gce) * 2 * maxlen;
+
+ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!gcl_data)
+ return -ENOMEM;
+
+ gce = (struct gce *)(gcl_data + 1);
+
+ gcl_query->acl_len = cpu_to_le16(maxlen);
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+ cbdr->status_flags = 0;
+
+ dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+ cbdr->cmd = 1;
+ cbdr->cls = BDCR_CMD_PORT_GCL;
+ xmit_cbdr(priv->si, curr_cbd);
+ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE);
+
+ /* since cbdr already passed to free, below could be get wrong */
+ admin_len = le16_to_cpu(gcl_query->admin_list_len);
+ oper_len = le16_to_cpu(gcl_query->oper_list_len);
+
+ admin_basic->control_list_length = admin_len;
+
+ temp = ((u64)le32_to_cpu(gcl_data->abth)) << 32;
+ admin_basic->base_time = le32_to_cpu(gcl_data->abtl) + temp;
+
+ admin_basic->cycle_time = le32_to_cpu(gcl_data->act);
+ admin_basic->cycle_time_extension = le32_to_cpu(gcl_data->acte);
+
+ admin_basic->control_list = kcalloc(admin_len,
+ sizeof(admin_basic->control_list),
+ GFP_KERNEL);
+ if (!admin_basic->control_list) {
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < admin_len; i++) {
+ struct gce *temp_gce = gce + i;
+ struct tsn_qbv_entry *temp_entry;
+
+ temp_entry = admin_basic->control_list + i;
+
+ temp_entry->gate_state = temp_gce->gate;
+ temp_entry->time_interval = le32_to_cpu(temp_gce->period);
+ }
+
+ /* Updated by ENETC on completion of the configuration
+ * command. A zero value indicates success.
+ */
+ admin_conf->config_change = true;
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(gcl_data);
+
+ return 0;
+}
+
+int enetc_qbv_get_status(struct net_device *ndev,
+ struct tsn_qbv_status *status)
+{
+ struct enetc_cbd *cbdr;
+ struct tgs_gcl_resp *gcl_data;
+ struct tgs_gcl_query *gcl_query;
+ struct gce *gce;
+ struct tsn_qbv_basic *oper_basic;
+ struct enetc_ndev_priv *priv;
+ dma_addr_t dma;
+ int curr_cbd;
+ u16 maxlen;
+ u16 data_size, dma_size;
+ u16 admin_len;
+ u16 oper_len;
+ u64 temp;
+ int i;
+
+ if (!ndev)
+ return -EINVAL;
+
+ if (!status)
+ return -EINVAL;
+
+ oper_basic = &status->oper;
+ priv = netdev_priv(ndev);
+
+ if (!(enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE))
+ return -EINVAL;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ gcl_query = &cbdr->gcl_query;
+
+ maxlen = enetc_get_max_gcl_len(&priv->si->hw);
+
+ data_size = sizeof(struct tgs_gcl_resp) +
+ sizeof(struct gce) * 2 * maxlen;
+
+ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!gcl_data)
+ return -ENOMEM;
+
+ gce = (struct gce *)(gcl_data + 1);
+
+ gcl_query->acl_len = cpu_to_le16(maxlen);
+ gcl_query->ocl_len = cpu_to_le16(maxlen);
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+ cbdr->status_flags = 0; /* long format command no ie */
+
+ dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+ cbdr->cmd = 1;
+ cbdr->cls = BDCR_CMD_PORT_GCL;
+ xmit_cbdr(priv->si, curr_cbd);
+ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_FROM_DEVICE);
+
+ /* since cbdr already passed to free, below could be get wrong */
+ admin_len = le16_to_cpu(gcl_query->admin_list_len);
+ oper_len = le16_to_cpu(gcl_query->oper_list_len);
+
+ if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGAGLSR_OFFSET) &
+ ENETC_QBV_CFG_PEND_MASK) {
+ status->config_pending = true;
+ goto exit;
+ }
+
+ /* The Oper and Admin timing fields exist in the response buffer even
+ * if no valid corresponding lists exists. These fields are considered
+ * invalid if the corresponding list does not exist.
+ */
+ status->config_pending = false;
+ temp = ((u64)le32_to_cpu(gcl_data->ccth)) << 32;
+ status->config_change_time = le32_to_cpu(gcl_data->cctl) + temp;
+
+ temp = ((u64)le32_to_cpu(gcl_data->cceh)) << 32;
+ status->config_change_error = le32_to_cpu(gcl_data->ccel) + temp;
+
+ /* changed to SITGTGR */
+ status->tick_granularity = enetc_rd(&priv->si->hw, ENETC_SITGTGR);
+
+ /* current time */
+ status->current_time = get_current_time(priv->si);
+
+ status->supported_list_max = maxlen;
+
+ /* status->oper.gate_states , no init oper/admin gate state */
+ status->oper.control_list_length = oper_len;
+ temp = ((u64)le32_to_cpu(gcl_data->obth)) << 32;
+ status->oper.base_time = le32_to_cpu(gcl_data->obtl) + temp;
+ status->oper.cycle_time = le32_to_cpu(gcl_data->oct);
+ status->oper.cycle_time_extension = le32_to_cpu(gcl_data->octe);
+
+ oper_basic->control_list =
+ kcalloc(oper_len, sizeof(oper_basic->control_list), GFP_KERNEL);
+ if (!oper_basic->control_list) {
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(gcl_data);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < oper_len; i++) {
+ struct gce *temp_gce = gce + maxlen + i;
+ struct tsn_qbv_entry *temp_entry = oper_basic->control_list + i;
+
+ temp_entry->gate_state = temp_gce->gate;
+ temp_entry->time_interval = le32_to_cpu(temp_gce->period);
+ }
+
+exit:
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(gcl_data);
+ return 0;
+}
+
+/* CBD Class 7: Stream Identity Entry Set Descriptor - Long Format */
+int enetc_cb_streamid_set(struct net_device *ndev, u32 index,
+ bool en, struct tsn_cb_streamid *streamid)
+{
+ struct enetc_cbd *cbdr;
+ void *si_data;
+ struct null_streamid_data *si_data1;
+ struct smac_streamid_data *si_data2;
+ struct streamid_conf *si_conf;
+ struct enetc_ndev_priv *priv;
+ dma_addr_t dma;
+ u16 data_size, dma_size;
+ int curr_cbd;
+
+ if (!ndev)
+ return -EINVAL;
+
+ priv = netdev_priv(ndev);
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
+ cbdr->status_flags = 0;
+
+ data_size = sizeof(struct null_streamid_data);
+ si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ cbdr->length = cpu_to_le16(data_size);
+
+ dma = dma_map_single(&priv->si->pdev->dev, si_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(si_data);
+ return -ENOMEM;
+ }
+
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+ si_data1 = (struct null_streamid_data *)si_data;
+ si_data1->dmac[0] = 0xFF;
+ si_data1->dmac[1] = 0xFF;
+ si_data1->dmac[2] = 0xFF;
+ si_data1->dmac[3] = 0xFF;
+ si_data1->dmac[4] = 0xFF;
+ si_data1->dmac[5] = 0xFF;
+ si_data1->vid_vidm_tg =
+ cpu_to_le16(ENETC_CBDR_SID_VID_MASK
+ + ((0x3 << 14) | ENETC_CBDR_SID_VIDM));
+
+ si_conf = &cbdr->sid_set;
+ /* Only one port supported for one entry, set itself */
+ si_conf->iports = 1 << (priv->si->pdev->devfn & 0x7);
+ si_conf->id_type = 1;
+ si_conf->oui[2] = 0x0;
+ si_conf->oui[1] = 0x80;
+ si_conf->oui[0] = 0xC2;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(si_data);
+
+ if (!en)
+ return 0;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
+ cbdr->status_flags = 0;
+
+ si_conf = &cbdr->sid_set;
+ si_conf->en = 0x80;
+ si_conf->stream_handle = cpu_to_le32(streamid->handle);
+ si_conf->iports = 1 << (priv->si->pdev->devfn & 0x7);
+ si_conf->id_type = streamid->type;
+ si_conf->oui[2] = 0x0;
+ si_conf->oui[1] = 0x80;
+ si_conf->oui[0] = 0xC2;
+
+ if (si_conf->id_type == 1) {
+ data_size = sizeof(struct null_streamid_data);
+ si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ } else if (si_conf->id_type == 2) {
+ data_size = sizeof(struct smac_streamid_data);
+ si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ } else {
+ return -EINVAL;
+ }
+
+ if (!si_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+ cbdr->status_flags = 0;
+
+ dma = dma_map_single(&priv->si->pdev->dev, si_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(si_data);
+ return -ENOMEM;
+ }
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+
+ /* VIDM default to be 1.
+ * VID Match. If set (b1) then the VID must match, otherwise
+ * any VID is considered a match. VIDM setting is only used
+ * when TG is set to b01.
+ */
+ if (si_conf->id_type == 1) {
+ si_data1 = (struct null_streamid_data *)si_data;
+ si_data1->dmac[0] = streamid->para.nid.dmac & 0xFF;
+ si_data1->dmac[1] = (streamid->para.nid.dmac >> 8) & 0xFF;
+ si_data1->dmac[2] = (streamid->para.nid.dmac >> 16) & 0xFF;
+ si_data1->dmac[3] = (streamid->para.nid.dmac >> 24) & 0xFF;
+ si_data1->dmac[4] = (streamid->para.nid.dmac >> 32) & 0xFF;
+ si_data1->dmac[5] = (streamid->para.nid.dmac >> 40) & 0xFF;
+ si_data1->vid_vidm_tg =
+ cpu_to_le16((streamid->para.nid.vid & ENETC_CBDR_SID_VID_MASK) +
+ ((((u16)(streamid->para.nid.tagged) & 0x3) << 14)
+ | ENETC_CBDR_SID_VIDM));
+ } else if (si_conf->id_type == 2) {
+ si_data2 = (struct smac_streamid_data *)si_data;
+ si_data2->smac[0] = streamid->para.sid.smac & 0xFF;
+ si_data2->smac[1] = (streamid->para.sid.smac >> 8) & 0xFF;
+ si_data2->smac[2] = (streamid->para.sid.smac >> 16) & 0xFF;
+ si_data2->smac[3] = (streamid->para.sid.smac >> 24) & 0xFF;
+ si_data2->smac[4] = (streamid->para.sid.smac >> 32) & 0xFF;
+ si_data2->smac[5] = (streamid->para.sid.smac >> 40) & 0xFF;
+ si_data2->vid_vidm_tg =
+ cpu_to_le16((streamid->para.sid.vid & ENETC_CBDR_SID_VID_MASK) +
+ ((((u16)(streamid->para.sid.tagged) & 0x3) << 14)
+ | ENETC_CBDR_SID_VIDM));
+ }
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(si_data);
+
+ return 0;
+}
+
+/* CBD Class 7: Stream Identity Entry Query Descriptor - Long Format */
+int enetc_cb_streamid_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid *streamid)
+{
+ struct enetc_cbd *cbdr;
+ struct streamid_query_resp *si_data;
+ struct enetc_ndev_priv *priv;
+ dma_addr_t dma;
+ u16 data_size, dma_size;
+ int curr_cbd;
+ int valid;
+
+ if (!ndev)
+ return -EINVAL;
+
+ priv = netdev_priv(ndev);
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le32(index);
+ cbdr->cmd = 1;
+ cbdr->cls = BDCR_CMD_STREAM_IDENTIFY;
+ cbdr->status_flags = 0;
+
+ data_size = sizeof(struct streamid_query_resp);
+ si_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!si_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+ cbdr->status_flags = 0; /* long format command no ie */
+
+ dma = dma_map_single(&priv->si->pdev->dev, si_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(si_data);
+ return -ENOMEM;
+ }
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ streamid->type = si_data->id_type;
+
+ if (streamid->type == 1) {
+ streamid->para.nid.dmac = si_data->mac[0]
+ + ((u64)si_data->mac[1] << 8)
+ + ((u64)si_data->mac[2] << 16)
+ + ((u64)si_data->mac[3] << 24)
+ + ((u64)si_data->mac[4] << 32)
+ + ((u64)si_data->mac[5] << 40);
+ /* VID Match. If set (b1) then the VID must match, otherwise
+ * any VID is considered a match.
+ */
+ streamid->para.nid.vid =
+ le16_to_cpu(si_data->vid_vidm_tg
+ & ENETC_CBDR_SID_VID_MASK);
+ streamid->para.nid.tagged =
+ le16_to_cpu(si_data->vid_vidm_tg >> 14 & 0x3);
+ } else if (streamid->type == 2) {
+ streamid->para.sid.smac = si_data->mac[0]
+ + ((u64)si_data->mac[1] << 8)
+ + ((u64)si_data->mac[2] << 16)
+ + ((u64)si_data->mac[3] << 24)
+ + ((u64)si_data->mac[4] << 32)
+ + ((u64)si_data->mac[5] << 40);
+ /* VID Match. If set (b1) then the VID must match, otherwise
+ * any VID is considered a match.
+ */
+ streamid->para.sid.vid =
+ le16_to_cpu(si_data->vid_vidm_tg
+ & ENETC_CBDR_SID_VID_MASK);
+ streamid->para.sid.tagged =
+ le16_to_cpu(si_data->vid_vidm_tg >> 14 & 0x3);
+ }
+
+ streamid->handle = le32_to_cpu(si_data->stream_handle);
+ streamid->ifac_iport = le32_to_cpu(si_data->input_ports);
+ valid = si_data->en ? 1 : 0;
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ kfree(si_data);
+
+ return valid;
+}
+
+/* CBD Class 7: Stream Identity Statistics Query Descriptor - Long Format */
+int enetc_cb_streamid_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_cb_streamid_counters *counters)
+{
+ return 0;
+}
+
+void enetc_qci_enable(struct enetc_hw *hw)
+{
+ enetc_wr(hw, ENETC_PPSFPMR, enetc_rd(hw, ENETC_PPSFPMR)
+ | ENETC_PPSFPMR_PSFPEN | ENETC_PPSFPMR_VS
+ | ENETC_PPSFPMR_PVC | ENETC_PPSFPMR_PVZC);
+}
+
+void enetc_qci_disable(struct enetc_hw *hw)
+{
+ enetc_wr(hw, ENETC_PPSFPMR, enetc_rd(hw, ENETC_PPSFPMR)
+ & ~ENETC_PPSFPMR_PSFPEN & ~ENETC_PPSFPMR_VS
+ & ~ENETC_PPSFPMR_PVC & ~ENETC_PPSFPMR_PVZC);
+}
+
+/* CBD Class 8: Stream Filter Instance Set Descriptor - Short Format */
+int enetc_qci_sfi_set(struct net_device *ndev, u32 index, bool en,
+ struct tsn_qci_psfp_sfi_conf *tsn_qci_sfi)
+{
+ struct enetc_cbd *cbdr;
+ struct sfi_conf *sfi_config;
+
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int curr_cbd;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_STREAM_FILTER;
+ cbdr->status_flags = 0x80;
+ cbdr->length = cpu_to_le16(1);
+
+ sfi_config = &cbdr->sfi_conf;
+ if (en)
+ sfi_config->en = 0x80;
+
+ if (tsn_qci_sfi->stream_handle_spec >= 0) {
+ sfi_config->stream_handle =
+ cpu_to_le32(tsn_qci_sfi->stream_handle_spec);
+ sfi_config->sthm |= 0x80;
+ }
+
+ sfi_config->sg_inst_table_index =
+ cpu_to_le16(tsn_qci_sfi->stream_gate_instance_id);
+ sfi_config->input_ports = 1 << (priv->si->pdev->devfn & 0x7);
+
+ /* The priority value which may be matched against the
+ * frame’s priority value to determine a match for this entry.
+ */
+ if (tsn_qci_sfi->priority_spec >= 0)
+ sfi_config->multi |= (tsn_qci_sfi->priority_spec & 0x7) | 0x8;
+
+ /* Filter Type. Identifies the contents of the MSDU/FM_INST_INDEX
+ * field as being either an MSDU value or an index into the Flow
+ * Meter Instance table.
+ */
+ if (tsn_qci_sfi->stream_filter.maximum_sdu_size != 0) {
+ sfi_config->msdu =
+ cpu_to_le16(tsn_qci_sfi->stream_filter.maximum_sdu_size);
+ sfi_config->multi |= 0x40;
+ }
+
+ if (tsn_qci_sfi->stream_filter.flow_meter_instance_id >= 0) {
+ sfi_config->fm_inst_table_index =
+ cpu_to_le16(tsn_qci_sfi->stream_filter.flow_meter_instance_id);
+ sfi_config->multi |= 0x80;
+ }
+
+ /* Stream blocked due to oversized frame enable. TRUE or FALSE */
+ if (tsn_qci_sfi->block_oversize_enable)
+ sfi_config->multi |= 0x20;
+
+ /* Stream blocked due to oversized frame. TRUE or FALSE */
+ if (tsn_qci_sfi->block_oversize)
+ sfi_config->multi |= 0x10;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 8: Stream Filter Instance Query Descriptor - Short Format */
+int enetc_qci_sfi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_conf *tsn_qci_sfi)
+{
+ struct enetc_cbd *cbdr;
+ struct sfi_conf *sfi_config;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int curr_cbd;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 1;
+ cbdr->cls = BDCR_CMD_STREAM_FILTER;
+ cbdr->status_flags = 0x80;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ sfi_config = &cbdr->sfi_conf;
+ if (sfi_config->sthm & 0x80)
+ tsn_qci_sfi->stream_handle_spec =
+ le32_to_cpu(sfi_config->stream_handle);
+ else
+ tsn_qci_sfi->stream_handle_spec = -1;
+
+ tsn_qci_sfi->stream_gate_instance_id =
+ le16_to_cpu(sfi_config->sg_inst_table_index);
+
+ if (sfi_config->multi & 0x8)
+ tsn_qci_sfi->priority_spec =
+ le16_to_cpu(sfi_config->multi & 0x7);
+ else
+ tsn_qci_sfi->priority_spec = -1;
+
+ /* Filter Type. Identifies the contents of the MSDU/FM_INST_INDEX
+ * field as being either an MSDU value or an index into the Flow
+ * Meter Instance table.
+ */
+ if (sfi_config->multi & 0x80)
+ tsn_qci_sfi->stream_filter.flow_meter_instance_id =
+ le16_to_cpu(sfi_config->fm_inst_table_index);
+ else
+ tsn_qci_sfi->stream_filter.flow_meter_instance_id = -1;
+
+ if (sfi_config->multi & 0x40)
+ tsn_qci_sfi->stream_filter.maximum_sdu_size =
+ le16_to_cpu(sfi_config->msdu);
+
+ /* Stream blocked due to oversized frame enable. TRUE or FALSE */
+ if (sfi_config->multi & 0x20)
+ tsn_qci_sfi->block_oversize_enable = true;
+ /* Stream blocked due to oversized frame. TRUE or FALSE */
+ if (sfi_config->multi & 0x10)
+ tsn_qci_sfi->block_oversize = true;
+
+ if (sfi_config->en & 0x80) {
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 1;
+ }
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 8: Stream Filter Instance Query Statistics
+ * Descriptor - Long Format
+ */
+int enetc_qci_sfi_counters_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sfi_counters *counters)
+{
+ struct enetc_cbd *cbdr;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int curr_cbd;
+ struct sfi_counter_data *sfi_counter_data;
+ dma_addr_t dma;
+ u16 data_size, dma_size;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 2;
+ cbdr->cls = BDCR_CMD_STREAM_FILTER;
+ cbdr->status_flags = 0;
+
+ data_size = sizeof(struct sfi_counter_data);
+ sfi_counter_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!sfi_counter_data)
+ return -ENOMEM;
+
+ dma = dma_map_single(&priv->si->pdev->dev, sfi_counter_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(sfi_counter_data);
+ return -ENOMEM;
+ }
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ counters->matching_frames_count =
+ ((u64)le32_to_cpu(sfi_counter_data->matchh) << 32)
+ + sfi_counter_data->matchl;
+
+ counters->not_passing_sdu_count =
+ ((u64)le32_to_cpu(sfi_counter_data->msdu_droph) << 32)
+ + sfi_counter_data->msdu_dropl;
+
+ counters->passing_sdu_count = counters->matching_frames_count
+ - counters->not_passing_sdu_count;
+
+ counters->not_passing_frames_count =
+ ((u64)le32_to_cpu(sfi_counter_data->stream_gate_droph) << 32)
+ + le32_to_cpu(sfi_counter_data->stream_gate_dropl);
+
+ counters->passing_frames_count = counters->matching_frames_count
+ - counters->not_passing_sdu_count
+ - counters->not_passing_frames_count;
+
+ counters->red_frames_count =
+ ((u64)le32_to_cpu(sfi_counter_data->flow_meter_droph) << 32)
+ + le32_to_cpu(sfi_counter_data->flow_meter_dropl);
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 9: Stream Gate Instance Table Entry Set
+ * Descriptor - Short Format
+ */
+int enetc_qci_sgi_set(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *tsn_qci_sgi)
+{
+ struct enetc_cbd *cbdr, *cbdr_sgcl;
+ struct sgi_table *sgi_config;
+ struct sgcl_conf *sgcl_config;
+ struct sgcl_data *sgcl_data;
+ struct sgce *sgce;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ dma_addr_t dma;
+ u16 data_size, dma_size;
+ int curr_cbd, i;
+
+ /* disable first */
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+ memset(cbdr, 0, sizeof(*cbdr));
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_STREAM_GCL;
+ cbdr->status_flags = 0x80;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ if (!tsn_qci_sgi->gate_enabled) {
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+ }
+
+ /* Re-enable */
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+ memset(cbdr, 0, sizeof(*cbdr));
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_STREAM_GCL;
+ cbdr->status_flags = 0x80;
+
+ sgi_config = &cbdr->sgi_table;
+
+ sgi_config->ocgtst = tsn_qci_sgi->admin.control_list_length ?
+ 0x80 : (tsn_qci_sgi->admin.gate_states ? 0x80 : 0x0);
+
+ sgi_config->oipv =
+ tsn_qci_sgi->admin.control_list_length ?
+ 0x0 : ((tsn_qci_sgi->admin.init_ipv < 0) ?
+ 0x0 : ((tsn_qci_sgi->admin.init_ipv & 0x7) | 0x8));
+
+ sgi_config->en = 0x80;
+
+ if (tsn_qci_sgi->block_invalid_rx_enable)
+ sgi_config->gset |= 0x80;
+ if (tsn_qci_sgi->block_invalid_rx)
+ sgi_config->gset |= 0x40;
+ if (tsn_qci_sgi->block_octets_exceeded)
+ sgi_config->gset |= 0x10;
+ if (tsn_qci_sgi->block_octets_exceeded_enable)
+ sgi_config->gset |= 0x20;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ if (tsn_qci_sgi->admin.control_list_length == 0)
+ goto exit;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
+ memset(cbdr, 0, sizeof(*cbdr));
+
+ cbdr_sgcl->index = cpu_to_le16(index);
+ cbdr_sgcl->cmd = 1;
+ cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
+ cbdr_sgcl->status_flags = 0;
+
+ sgcl_config = &cbdr_sgcl->sgcl_conf;
+
+ /* tsn_qci_sgi->admin.control_list_length is not zero now */
+ if (tsn_qci_sgi->admin.control_list_length > 4)
+ return -EINVAL;
+
+ sgcl_config->acl_len =
+ (tsn_qci_sgi->admin.control_list_length - 1) & 0x3;
+
+ data_size = sizeof(struct sgcl_data) +
+ (sgcl_config->acl_len + 1) * sizeof(struct sgce);
+
+ sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!sgcl_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr_sgcl->length = dma_size;
+
+ dma = dma_map_single(&priv->si->pdev->dev,
+ sgcl_data, data_size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ memset(cbdr, 0, sizeof(*cbdr));
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+ return -ENOMEM;
+ }
+ cbdr_sgcl->addr[0] = lower_32_bits(dma);
+ cbdr_sgcl->addr[1] = upper_32_bits(dma);
+
+ sgce = (struct sgce *)(sgcl_data + 1);
+
+ if (tsn_qci_sgi->admin.gate_states)
+ sgcl_config->agtst = 0x80;
+
+ sgcl_data->ct = cpu_to_le32(tsn_qci_sgi->admin.cycle_time);
+ sgcl_data->cte = cpu_to_le32(tsn_qci_sgi->admin.cycle_time_extension);
+
+ if (tsn_qci_sgi->admin.init_ipv >= 0)
+ sgcl_config->aipv = (tsn_qci_sgi->admin.init_ipv & 0x7) | 0x8;
+
+ for (i = 0; i < tsn_qci_sgi->admin.control_list_length; i++) {
+ struct tsn_qci_psfp_gcl *temp_sgcl = tsn_qci_sgi->admin.gcl + i;
+ struct sgce *temp_entry = (struct sgce *)(sgce + i);
+
+ if (temp_sgcl->gate_state)
+ temp_entry->multi |= 0x10;
+
+ if (temp_sgcl->ipv >= 0)
+ temp_entry->multi |= ((temp_sgcl->ipv & 0x7) << 5)
+ | 0x08;
+
+ if (temp_sgcl->octet_max)
+ temp_entry->multi |= 0x01;
+
+ temp_entry->interval = cpu_to_le32(temp_sgcl->time_interval);
+ temp_entry->msdu[0] = temp_sgcl->octet_max & 0xFF;
+ temp_entry->msdu[1] = (temp_sgcl->octet_max >> 8) & 0xFF;
+ temp_entry->msdu[2] = (temp_sgcl->octet_max >> 16) & 0xFF;
+ }
+
+ if (!tsn_qci_sgi->admin.base_time) {
+ sgcl_data->btl =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+ sgcl_data->bth =
+ cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+ } else {
+ u32 tempu, templ;
+
+ tempu = upper_32_bits(tsn_qci_sgi->admin.base_time);
+ templ = lower_32_bits(tsn_qci_sgi->admin.base_time);
+ sgcl_data->bth = cpu_to_le32(tempu);
+ sgcl_data->btl = cpu_to_le32(templ);
+ }
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+
+exit:
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 9: Stream Gate Instance Table Entry Query
+ * Descriptor - Short Format
+ */
+int enetc_qci_sgi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_sgi_conf *tsn_qci_sgi)
+{
+ struct enetc_cbd *cbdr, *cbdr_sgcl;
+ struct sgi_table *sgi_config;
+ struct sgcl_query *sgcl_query;
+ struct sgcl_query_resp *sgcl_data;
+ struct sgce *sgce;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ dma_addr_t dma;
+ u16 data_size, dma_size, gcl_data_stat = 0;
+ u8 admin_len = 0;
+ int curr_cbd, i;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 2;
+ cbdr->cls = BDCR_CMD_STREAM_GCL;
+ cbdr->status_flags = 0x80;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ sgi_config = &cbdr->sgi_table;
+
+ tsn_qci_sgi->admin.gate_states = (sgi_config->ocgtst & 0x80) ?
+ true : false;
+ if (sgi_config->oipv & 0x08)
+ tsn_qci_sgi->admin.init_ipv = sgi_config->oipv & 0x7;
+ else
+ tsn_qci_sgi->admin.init_ipv = -1;
+
+ if (sgi_config->en & 0x80)
+ tsn_qci_sgi->gate_enabled = true;
+ if (sgi_config->gset & 0x80)
+ tsn_qci_sgi->block_invalid_rx_enable = true;
+ if (sgi_config->gset & 0x40)
+ tsn_qci_sgi->block_invalid_rx = true;
+ if (sgi_config->gset & 0x20)
+ tsn_qci_sgi->block_octets_exceeded_enable = true;
+ if (sgi_config->gset & 0x10)
+ tsn_qci_sgi->block_octets_exceeded = true;
+
+ /* Check gate list length is zero? */
+ if (!(sgi_config->oacl_len & 0x30)) {
+ tsn_qci_sgi->admin.control_list_length = 0;
+ goto exit;
+ }
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
+
+ cbdr_sgcl->index = cpu_to_le16(index);
+ cbdr_sgcl->cmd = 3;
+ cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
+ cbdr_sgcl->status_flags = 0;
+
+ data_size = sizeof(struct sgcl_query_resp) + 4 * sizeof(struct sgce);
+
+ sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!sgcl_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr_sgcl->length = dma_size;
+ cbdr_sgcl->status_flags = 0;
+
+ sgcl_query = &cbdr_sgcl->sgcl_query;
+
+ sgcl_query->oacl_len = 0x10;
+
+ dma = dma_map_single(&priv->si->pdev->dev, sgcl_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ memset(cbdr, 0, sizeof(*cbdr));
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+ return -ENOMEM;
+ }
+ cbdr_sgcl->addr[0] = lower_32_bits(dma);
+ cbdr_sgcl->addr[1] = upper_32_bits(dma);
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ sgce = (struct sgce *)(sgcl_data + 1);
+
+ gcl_data_stat = le16_to_cpu(sgcl_data->stat);
+ if (gcl_data_stat & 0x10)
+ tsn_qci_sgi->admin.gate_states = true;
+
+ if (gcl_data_stat & 0x80)
+ tsn_qci_sgi->admin.init_ipv = gcl_data_stat & 0x7;
+ else
+ tsn_qci_sgi->admin.init_ipv = -1;
+
+ /* admin_len can also get from gcl_data_stat bit 5,6
+ * OR sgi_config->oacl_len
+ */
+ admin_len = (sgcl_query->oacl_len & 0x3) + 1;
+ tsn_qci_sgi->admin.control_list_length = admin_len;
+ tsn_qci_sgi->admin.cycle_time = le32_to_cpu(sgcl_data->act);
+ tsn_qci_sgi->admin.cycle_time_extension = le32_to_cpu(sgcl_data->acte);
+ tsn_qci_sgi->admin.base_time = ((u64)(le32_to_cpu(sgcl_data->abth))
+ << 32)
+ + le32_to_cpu(sgcl_data->abtl);
+
+ tsn_qci_sgi->admin.gcl = kcalloc(admin_len,
+ sizeof(struct tsn_qci_psfp_gcl),
+ GFP_KERNEL);
+ if (!tsn_qci_sgi->admin.gcl) {
+ kfree(sgcl_data);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < admin_len; i++) {
+ struct tsn_qci_psfp_gcl *temp_sgcl = tsn_qci_sgi->admin.gcl + i;
+ struct sgce *temp_entry = (struct sgce *)(sgce + i);
+
+ if (temp_entry->multi & 0x10)
+ temp_sgcl->gate_state = true;
+
+ if (temp_entry->multi & 0x08)
+ temp_sgcl->ipv = temp_entry->multi >> 5;
+ else
+ temp_sgcl->ipv = -1;
+
+ temp_sgcl->time_interval = le32_to_cpu(temp_entry->interval);
+
+ if (temp_entry->multi & 0x01)
+ temp_sgcl->octet_max = (temp_entry->msdu[0] & 0xff)
+ | (((u32)temp_entry->msdu[1] << 8) & 0xff00)
+ | (((u32)temp_entry->msdu[1] << 16) & 0xff0000);
+ else
+ temp_sgcl->octet_max = 0;
+ }
+
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+
+exit:
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 9: Stream Gate Instance Table Entry Query Descriptor
+ * CBD Class 9: Stream Gate Control List Query Descriptor
+ */
+int enetc_qci_sgi_status_get(struct net_device *ndev, u16 index,
+ struct tsn_psfp_sgi_status *status)
+{
+ struct enetc_cbd *cbdr_sgi, *cbdr_sgcl;
+ struct sgi_table *sgi_config;
+ struct sgcl_query *sgcl_query;
+ struct sgcl_query_resp *sgcl_data;
+ struct sgce *sgce;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ dma_addr_t dma;
+ u16 data_size, dma_size, gcl_data_stat = 0;
+ u8 oper_len = 0;
+ int curr_cbd, i;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr_sgi);
+
+ cbdr_sgi->index = cpu_to_le16(index);
+ cbdr_sgi->cmd = 2;
+ cbdr_sgi->cls = BDCR_CMD_STREAM_GCL;
+ cbdr_sgi->status_flags = 0x80;
+
+ sgi_config = &cbdr_sgi->sgi_table;
+
+ if (sgi_config->gset & 0x4)
+ status->config_pending = true;
+
+ status->oper.gate_states = ((sgi_config->ocgtst & 0x80) ? true : false);
+
+ /* Check gate list length is zero */
+ if (!(sgi_config->oacl_len & 0x30)) {
+ status->oper.control_list_length = 0;
+ goto cmd2quit;
+ }
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr_sgcl);
+
+ cbdr_sgcl->index = cpu_to_le16(index);
+ cbdr_sgcl->cmd = 3;
+ cbdr_sgcl->cls = BDCR_CMD_STREAM_GCL;
+ cbdr_sgcl->status_flags = 0;
+
+ /* Max size */
+ data_size = sizeof(struct sgcl_query_resp) + 4 * sizeof(struct sgce);
+
+ sgcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!sgcl_data)
+ return -ENOMEM;
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr_sgcl->length = dma_size;
+ cbdr_sgcl->status_flags = 0;
+
+ sgcl_query = &cbdr_sgcl->sgcl_query;
+
+ sgcl_query->oacl_len = 0x20;
+
+ dma = dma_map_single(&priv->si->pdev->dev, sgcl_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+ return -ENOMEM;
+ }
+ cbdr_sgcl->addr[0] = lower_32_bits(dma);
+ cbdr_sgcl->addr[1] = upper_32_bits(dma);
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ sgce = (struct sgce *)(sgcl_data + 1);
+
+ /* oper_len can also get from gcl_data_stat bit 5,6
+ * OR sgi_config->oacl_len
+ */
+ oper_len = ((sgcl_query->oacl_len & 0x0c) >> 2) + 1;
+
+ /* Get Stream Gate Control List */
+ status->oper.cycle_time = le32_to_cpu(sgcl_data->oct);
+ status->oper.cycle_time_extension = le32_to_cpu(sgcl_data->octe);
+ status->oper.base_time = le32_to_cpu(sgcl_data->obtl)
+ + ((u64)le32_to_cpu(sgcl_data->obth) << 32);
+ status->oper.control_list_length = oper_len;
+
+ gcl_data_stat = le16_to_cpu(sgcl_data->stat);
+ if (gcl_data_stat & 0x400)
+ status->oper.init_ipv = gcl_data_stat & 0x38 >> 7;
+ else
+ status->oper.init_ipv = -1;
+
+ if (gcl_data_stat & 0x800)
+ status->oper.gate_states = true;
+
+ status->oper.gcl = kcalloc(oper_len,
+ sizeof(struct tsn_qci_psfp_gcl),
+ GFP_KERNEL);
+ if (!status->oper.gcl) {
+ memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < oper_len; i++) {
+ struct tsn_qci_psfp_gcl *temp_sgcl = status->oper.gcl + i;
+ struct sgce *temp_entry = (struct sgce *)(sgce + i);
+
+ if (temp_entry->multi & 0x10)
+ temp_sgcl->gate_state = true;
+
+ if (temp_entry->multi & 0x08)
+ temp_sgcl->ipv = temp_entry->multi >> 5;
+ else
+ temp_sgcl->ipv = -1;
+
+ temp_sgcl->time_interval = le32_to_cpu(temp_entry->interval);
+
+ if (temp_entry->multi & 0x01)
+ temp_sgcl->octet_max = temp_entry->msdu[0]
+ | ((((u32)temp_entry->msdu[1]) << 8)
+ & 0xff00)
+ | ((((u32)temp_entry->msdu[2]) << 16)
+ & 0xff0000);
+ else
+ temp_sgcl->octet_max = 0;
+ }
+
+ status->config_change_time = le32_to_cpu(sgcl_data->cctl)
+ + ((u64)le32_to_cpu(sgcl_data->ccth) << 32);
+
+ memset(cbdr_sgcl, 0, sizeof(*cbdr_sgcl));
+ kfree(sgcl_data);
+
+cmd2quit:
+ /* changed to SITGTGR */
+ status->tick_granularity = enetc_rd(&priv->si->hw, ENETC_SITGTGR);
+
+ /* current time */
+ status->current_time = get_current_time(priv->si);
+
+ memset(cbdr_sgi, 0, sizeof(*cbdr_sgi));
+
+ return 0;
+}
+
+/* CBD Class 10: Flow Meter Instance Set Descriptor - Short Format */
+int enetc_qci_fmi_set(struct net_device *ndev, u32 index, bool enable,
+ struct tsn_qci_psfp_fmi *tsn_qci_fmi)
+{
+ struct enetc_cbd *cbdr;
+ struct fmi_conf *fmi_config;
+
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int curr_cbd;
+ u64 temp = 0;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_FLOW_METER;
+ cbdr->status_flags = 0x80;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ if (!enable) {
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+ }
+
+ /* Re-enable */
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+ memset(cbdr, 0, sizeof(*cbdr));
+ cbdr->index = cpu_to_le16((u16)index);
+ cbdr->cmd = 0;
+ cbdr->cls = BDCR_CMD_FLOW_METER;
+ cbdr->status_flags = 0x80;
+
+ fmi_config = &cbdr->fmi_conf;
+ fmi_config->en = 0x80;
+ if (tsn_qci_fmi->cir) {
+ temp = (u64)1000 * tsn_qci_fmi->cir;
+ temp = temp / 3725;
+ }
+ fmi_config->cir = cpu_to_le32((u32)temp);
+ fmi_config->cbs = cpu_to_le32(tsn_qci_fmi->cbs);
+ temp = 0;
+ if (tsn_qci_fmi->eir) {
+ temp = (u64)1000 * tsn_qci_fmi->eir;
+ temp = temp / 3725;
+ }
+ fmi_config->eir = cpu_to_le32((u32)temp);
+ fmi_config->ebs = cpu_to_le32(tsn_qci_fmi->ebs);
+
+ if (tsn_qci_fmi->mark_red)
+ fmi_config->conf |= 0x1;
+
+ if (tsn_qci_fmi->mark_red_enable)
+ fmi_config->conf |= 0x2;
+
+ if (tsn_qci_fmi->drop_on_yellow)
+ fmi_config->conf |= 0x4;
+
+ if (tsn_qci_fmi->cm)
+ fmi_config->conf |= 0x8;
+
+ if (tsn_qci_fmi->cf)
+ fmi_config->conf |= 0x10;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memset(cbdr, 0, sizeof(*cbdr));
+ return 0;
+}
+
+/* CBD Class 10: Flow Meter Instance Query Descriptor - Short Format */
+int enetc_qci_fmi_get(struct net_device *ndev, u32 index,
+ struct tsn_qci_psfp_fmi *tsn_qci_fmi,
+ struct tsn_qci_psfp_fmi_counters *counters)
+{
+ struct enetc_cbd *cbdr;
+ struct fmi_conf *fmi_config;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ int curr_cbd;
+ u16 data_size, dma_size;
+ dma_addr_t dma;
+ struct fmi_query_stat_resp *fmi_counter_data;
+ u64 temp = 0;
+
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 1;
+ cbdr->cls = BDCR_CMD_FLOW_METER;
+ cbdr->status_flags = 0x80;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ fmi_config = &cbdr->fmi_conf;
+ if (fmi_config->cir) {
+ temp = (u64)3725 * fmi_config->cir;
+ temp = temp / 1000;
+ }
+ tsn_qci_fmi->cir = le32_to_cpu((u32)temp);
+ tsn_qci_fmi->cbs = le32_to_cpu(fmi_config->cbs);
+ temp = 0;
+ if (fmi_config->eir) {
+ temp = (u64)3725 * fmi_config->eir;
+ temp = temp / 1000;
+ }
+ tsn_qci_fmi->eir = le32_to_cpu((u32)temp);
+ tsn_qci_fmi->ebs = le32_to_cpu(fmi_config->ebs);
+
+ if (fmi_config->conf & 0x1)
+ tsn_qci_fmi->mark_red = true;
+
+ if (fmi_config->conf & 0x2)
+ tsn_qci_fmi->mark_red_enable = true;
+
+ if (fmi_config->conf & 0x4)
+ tsn_qci_fmi->drop_on_yellow = true;
+
+ if (fmi_config->conf & 0x8)
+ tsn_qci_fmi->cm = true;
+
+ if (fmi_config->conf & 0x10)
+ tsn_qci_fmi->cf = true;
+
+ memset(cbdr, 0, sizeof(*cbdr));
+
+ /* Get counters */
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
+
+ cbdr->index = cpu_to_le16(index);
+ cbdr->cmd = 2;
+ cbdr->cls = BDCR_CMD_FLOW_METER;
+ cbdr->status_flags = 0x0;
+
+ data_size = sizeof(struct fmi_query_stat_resp);
+ fmi_counter_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+ if (!fmi_counter_data)
+ return -ENOMEM;
+
+ dma = dma_map_single(&priv->si->pdev->dev, fmi_counter_data,
+ data_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+ kfree(fmi_counter_data);
+ return -ENOMEM;
+ }
+ cbdr->addr[0] = lower_32_bits(dma);
+ cbdr->addr[1] = upper_32_bits(dma);
+
+ dma_size = cpu_to_le16(data_size);
+ cbdr->length = dma_size;
+
+ xmit_cbdr(priv->si, curr_cbd);
+
+ memcpy(counters, fmi_counter_data, sizeof(*counters));
+
+ return 0;
+}
+
+int enetc_qbu_set(struct net_device *ndev, u8 ptvector)
+{
+ u32 temp;
+ int i;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ temp = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
+ if (temp & ENETC_QBV_TGE)
+ enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+ temp & (~ENETC_QBV_TGPE));
+
+ for (i = 0; i < 8; i++) {
+ /* 1 Enabled. Traffic is transmitted on the preemptive MAC. */
+ temp = enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i));
+
+ if ((ptvector >> i) & 0x1)
+ enetc_port_wr(&priv->si->hw,
+ ENETC_PTCFPR(i),
+ temp | ENETC_FPE);
+ else
+ enetc_port_wr(&priv->si->hw,
+ ENETC_PTCFPR(i),
+ temp & ~ENETC_FPE);
+ }
+
+ return 0;
+}
+
+int enetc_qbu_get(struct net_device *ndev,
+ struct tsn_preempt_status *preemptstat)
+{
+ int i;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ if (enetc_port_rd(&priv->si->hw, ENETC_PFPMR) & ENETC_PFPMR_PMACE) {
+ preemptstat->preemption_active = true;
+ if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET)
+ & ENETC_QBV_TGE)
+ preemptstat->hold_request = 1;
+ else
+ preemptstat->hold_request = 2;
+ } else {
+ preemptstat->preemption_active = false;
+ return 0;
+ }
+
+ for (i = 0; i < 8; i++)
+ if (enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i)) & 0x80000000)
+ preemptstat->admin_state |= 1 << i;
+
+ preemptstat->hold_advance =
+ enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & 0xFFFF;
+ preemptstat->release_advance =
+ enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & 0xFFFF;
+
+ return 0;
+}
+
+u32 __enetc_tsn_get_cap(struct enetc_si *si)
+{
+ u32 reg = 0;
+ u32 cap = 0;
+
+ reg = enetc_port_rd(&si->hw, ENETC_PCAPR0);
+
+ if (reg & ENETC_PCAPR0_PSFP)
+ cap |= TSN_CAP_QCI;
+
+ if (reg & ENETC_PCAPR0_TSN)
+ cap |= TSN_CAP_QBV;
+
+ if (reg & ENETC_PCAPR0_QBU)
+ cap |= TSN_CAP_QBU;
+
+ cap |= TSN_CAP_CBS;
+ cap |= TSN_CAP_TBS;
+
+ return cap;
+}
+
+u32 enetc_tsn_get_capability(struct net_device *ndev)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ return __enetc_tsn_get_cap(priv->si);
+}
+
+static int __enetc_get_max_cap(struct enetc_si *si,
+ struct tsn_qci_psfp_stream_param *stream_para)
+{
+ u32 reg = 0;
+
+ /* Port stream filter capability */
+ reg = enetc_port_rd(&si->hw, ENETC_PSFCAPR);
+ stream_para->max_sf_instance = reg & ENETC_PSFCAPR_MSK;
+ /* Port stream filter capability */
+ reg = enetc_port_rd(&si->hw, ENETC_PSGCAPR);
+ stream_para->max_sg_instance = (reg & ENETC_PSGCAPR_SGIT_MSK);
+ stream_para->supported_list_max = (reg & ENETC_PSGCAPR_GCL_MSK) >> 16;
+ /* Port flow meter capability */
+ reg = enetc_port_rd(&si->hw, ENETC_PFMCAPR);
+ stream_para->max_fm_instance = reg & ENETC_PFMCAPR_MSK;
+
+ return 0;
+}
+
+int enetc_get_max_cap(struct net_device *ndev,
+ struct tsn_qci_psfp_stream_param *stream_para)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+ return __enetc_get_max_cap(priv->si, stream_para);
+}
+
+static int enetc_set_cbs(struct net_device *ndev, u8 tc, u8 bw)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
+ struct enetc_cbs *ecbs = si->ecbs;
+ struct cbs *cbs;
+
+ int bw_sum = 0;
+ u32 port_transmit_rate;
+ u32 port_frame_max_size;
+ u8 tc_nums;
+ int i;
+
+ u32 max_interfrence_size;
+ u32 send_slope;
+ u32 hi_credit;
+
+ if (!ecbs)
+ return -ENOMEM;
+
+ port_transmit_rate = get_ndev_speed(si->ndev);
+ if (port_transmit_rate != ecbs->port_transmit_rate)
+ ecbs->port_transmit_rate = port_transmit_rate;
+ port_frame_max_size = ecbs->port_max_size_frame;
+ tc_nums = ecbs->tc_nums;
+ cbs = ecbs->cbs;
+
+ if (tc >= tc_nums) {
+ dev_err(&ndev->dev, "Make sure the TC less than %d\n", tc_nums);
+ return -EINVAL;
+ }
+
+ if (!bw) {
+ if (cbs[tc].enable) {
+ /* Make sure the other TC that are numerically
+ * lower than this TC have been disabled.
+ */
+ for (i = 0; i < tc; i++) {
+ if (cbs[i].enable)
+ break;
+ }
+ if (i < tc) {
+ dev_err(&ndev->dev,
+ "TC%d has been disabled first\n", i);
+ return -EINVAL;
+ }
+ memset(&cbs[tc], 0, sizeof(*cbs));
+ cbs[tc].enable = false;
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
+ }
+ return 0;
+ }
+
+ /* Make sure the other TC that are numerically
+ * higher than this TC have been enabled.
+ */
+ for (i = tc_nums - 1; i > tc; i--) {
+ if (!cbs[i].enable) {
+ dev_err(&ndev->dev,
+ "TC%d has been enabled first\n", i);
+ return -EINVAL;
+ }
+ bw_sum += cbs[i].bw;
+ }
+
+ if (bw_sum + bw >= 100) {
+ dev_err(&ndev->dev,
+ "The sum of all CBS Bandwidth cann't exceed 100\n");
+ return -EINVAL;
+ }
+
+ cbs[tc].bw = bw;
+ cbs[tc].tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
+ cbs[tc].idle_slope = port_transmit_rate / 100 * bw;
+ cbs[tc].send_slope = port_transmit_rate - cbs[tc].idle_slope;
+
+ /* For TC7, the max_interfrence_size is ENETC_MAC_MAXFRM_SIZE.
+ * For TC6, the max_interfrence_size is calculated as below:
+ *
+ * max_interfrence_size = (M0 + Ma + Ra * M0 / (R0 - Ra))
+ *
+ * For other traffic class, for example SR class Q:
+ *
+ * R0 * (M0 + Ma + ... + Mp)
+ * max_interfrence_size = ------------------------------
+ * (R0 - Ra) + ... + (R0 - Rp)
+ *
+ */
+
+ if (tc == tc_nums - 1) {
+ cbs[tc].max_interfrence_size = port_frame_max_size * 8;
+
+ } else if (tc == tc_nums - 2) {
+ cbs[tc].max_interfrence_size = (port_frame_max_size
+ + cbs[tc + 1].tc_max_sized_frame
+ + port_frame_max_size * (cbs[tc + 1].idle_slope
+ / cbs[tc + 1].send_slope)) * 8;
+ } else {
+ max_interfrence_size = port_frame_max_size;
+ send_slope = 0;
+ for (i = tc + 1; i < tc_nums; i++) {
+ send_slope += cbs[i].send_slope;
+ max_interfrence_size += cbs[i].tc_max_sized_frame;
+ }
+ max_interfrence_size = ((u64)port_transmit_rate
+ * max_interfrence_size) / send_slope;
+ cbs[tc].max_interfrence_size = max_interfrence_size * 8;
+ }
+
+ cbs[tc].hi_credit = cbs[tc].max_interfrence_size * cbs[tc].bw / 100;
+ cbs[tc].lo_credit = cbs[tc].tc_max_sized_frame * (cbs[tc].send_slope
+ / port_transmit_rate);
+ cbs[tc].tc = tc;
+
+ hi_credit = (ENETC_CLK * 100L) * (u64)cbs[tc].hi_credit
+ / port_transmit_rate;
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit);
+
+ /* Set bw register and enable this traffic class*/
+ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc),
+ (cbs[tc].bw & 0x7F) | (1 << 31));
+ cbs[tc].enable = true;
+
+ return 0;
+}
+
+static int enetc_get_cbs(struct net_device *ndev, u8 tc)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
+ struct enetc_cbs *ecbs = si->ecbs;
+ struct cbs *cbs;
+
+ if (!ecbs)
+ return -ENOMEM;
+ cbs = ecbs->cbs;
+ if (tc >= ecbs->tc_nums) {
+ dev_err(&ndev->dev, "The maximum of TC is %d\n", ecbs->tc_nums);
+ return -EINVAL;
+ }
+
+ return cbs[tc].bw;
+}
+
+static int enetc_set_tsd(struct net_device *ndev, struct tsn_tsd *ttsd)
+{
+ return 0;
+}
+
+static int enetc_get_tsd(struct net_device *ndev, struct tsn_tsd_status *tts)
+{
+ return 0;
+}
+
+static u32 get_ndev_speed(struct net_device *netdev)
+{
+ struct ethtool_link_ksettings ksettings;
+ int rc = -1;
+
+ if (netdev->ethtool_ops->get_link_ksettings) {
+ if (netdev->ethtool_ops->begin) {
+ rc = netdev->ethtool_ops->begin(netdev);
+ if (rc < 0)
+ return 0;
+ }
+
+ memset(&ksettings, 0, sizeof(ksettings));
+
+ if (!netdev->ethtool_ops->get_link_ksettings)
+ return 0;
+
+ rc = netdev->ethtool_ops->get_link_ksettings(netdev,
+ &ksettings);
+
+ if (netdev->ethtool_ops->complete)
+ netdev->ethtool_ops->complete(netdev);
+ }
+
+ return (rc < 0) ? 0 : ksettings.base.speed;
+}
+
+static void enetc_cbs_init(struct enetc_si *si)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
+ u8 tc_nums;
+
+ tc_nums = priv->num_tx_rings;
+ si->ecbs = kzalloc(sizeof(*si->ecbs) +
+ sizeof(struct cbs) * tc_nums, GFP_KERNEL);
+ if (!si->ecbs)
+ return;
+
+ si->ecbs->port_max_size_frame = si->ndev->mtu + ETH_HLEN
+ + VLAN_HLEN + ETH_FCS_LEN;
+ si->ecbs->tc_nums = tc_nums;
+ si->ecbs->port_transmit_rate = get_ndev_speed(si->ndev);
+
+ /*This trick is used only for CFP*/
+ if (!si->ecbs->port_transmit_rate)
+ si->ecbs->port_transmit_rate = 1000000000;
+
+ if (!si->ecbs->port_transmit_rate) {
+ dev_err(&si->pdev->dev, "Failure to get port speed for CBS\n");
+ kfree(si->ecbs);
+ si->ecbs = NULL;
+ }
+}
+
+static void enetc_qbv_init(struct enetc_hw *hw)
+{
+ /* Set PSPEED to be 1Gbps */
+ enetc_port_wr(hw, ENETC_PMR,
+ (enetc_port_rd(hw, ENETC_PMR)
+ & (~ENETC_PMR_PSPEED_MASK))
+ | ENETC_PMR_PSPEED_1000M);
+}
+
+void enetc_tsn_init(struct net_device *ndev)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
+ u32 capability = 0;
+
+ capability = __enetc_tsn_get_cap(si);
+
+ if (capability & TSN_CAP_CBS)
+ enetc_cbs_init(si);
+
+ if (capability & TSN_CAP_QBV)
+ enetc_qbv_init(&si->hw);
+
+ if (capability & TSN_CAP_QCI)
+ enetc_qci_enable(&si->hw);
+
+ dev_info(&si->pdev->dev, "%s: setup done\n", __func__);
+}
+
+void enetc_tsn_deinit(struct net_device *ndev)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_si *si = priv->si;
+
+ dev_info(&si->pdev->dev, "%s: release\n", __func__);
+}
+
+static struct tsn_ops enetc_tsn_ops_full = {
+ .device_init = enetc_tsn_init,
+ .device_deinit = enetc_tsn_deinit,
+ .get_capability = enetc_tsn_get_capability,
+ .qbv_set = enetc_qbv_set,
+ .qbv_get = enetc_qbv_get,
+ .qbv_get_status = enetc_qbv_get_status,
+ .cb_streamid_set = enetc_cb_streamid_set,
+ .cb_streamid_get = enetc_cb_streamid_get,
+ .cb_streamid_counters_get = enetc_cb_streamid_counters_get,
+ .qci_get_maxcap = enetc_get_max_cap,
+ .qci_sfi_set = enetc_qci_sfi_set,
+ .qci_sfi_get = enetc_qci_sfi_get,
+ .qci_sfi_counters_get = enetc_qci_sfi_counters_get,
+ .qci_sgi_set = enetc_qci_sgi_set,
+ .qci_sgi_get = enetc_qci_sgi_get,
+ .qci_sgi_status_get = enetc_qci_sgi_status_get,
+ .qci_fmi_set = enetc_qci_fmi_set,
+ .qci_fmi_get = enetc_qci_fmi_get,
+ .qbu_set = enetc_qbu_set,
+ .qbu_get = enetc_qbu_get,
+ .cbs_set = enetc_set_cbs,
+ .cbs_get = enetc_get_cbs,
+ .tsd_set = enetc_set_tsd,
+ .tsd_get = enetc_get_tsd,
+};
+
+static struct tsn_ops enetc_tsn_ops_part = {
+ .device_init = enetc_tsn_init,
+ .device_deinit = enetc_tsn_deinit,
+ .get_capability = enetc_tsn_get_capability,
+ .cb_streamid_set = enetc_cb_streamid_set,
+ .cb_streamid_get = enetc_cb_streamid_get,
+ .cb_streamid_counters_get = enetc_cb_streamid_counters_get,
+ .qci_get_maxcap = enetc_get_max_cap,
+ .qci_sfi_set = enetc_qci_sfi_set,
+ .qci_sfi_get = enetc_qci_sfi_get,
+ .qci_sfi_counters_get = enetc_qci_sfi_counters_get,
+ .qci_sgi_set = enetc_qci_sgi_set,
+ .qci_sgi_get = enetc_qci_sgi_get,
+ .qci_sgi_status_get = enetc_qci_sgi_status_get,
+ .qci_fmi_set = enetc_qci_fmi_set,
+ .qci_fmi_get = enetc_qci_fmi_get,
+};
+
+void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev)
+{
+ int port = pdev->devfn & 0x7;
+
+ if (port == 1 || port == 3)
+ tsn_port_register(netdev, &enetc_tsn_ops_part,
+ (u16)pdev->bus->number);
+ else
+ tsn_port_register(netdev, &enetc_tsn_ops_full,
+ (u16)pdev->bus->number);
+}
+
+void enetc_tsn_pf_deinit(struct net_device *netdev)
+{
+ tsn_port_unregister(netdev);
+}
+#endif /* #if IS_ENABLED(CONFIG_ENETC_TSN) */
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index d89568f810bc..dba05f2cfecb 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -16,9 +16,15 @@
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
+#include <linux/pm_qos.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
+#ifdef CONFIG_IMX_SCU_SOC
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/sci.h>
+#endif
+
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST)
@@ -77,6 +83,8 @@
#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
+#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
+#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -380,6 +388,10 @@ struct bufdesc_ex {
#define FEC_NAPI_IMASK FEC_ENET_MII
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+#define FEC_ENET_ETHEREN ((uint)0x00000002)
+#define FEC_ENET_TXC_DLY ((uint)0x00010000)
+#define FEC_ENET_RXC_DLY ((uint)0x00020000)
+
/* ENET interrupt coalescing macro define */
#define FEC_ITR_CLK_SEL (0x1 << 30)
#define FEC_ITR_EN (0x1 << 31)
@@ -456,6 +468,25 @@ struct bufdesc_ex {
* those FIFO receive registers are resolved in other platforms.
*/
#define FEC_QUIRK_HAS_FRREG (1 << 16)
+/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE
+ * standard. For the transmission, MAC supply two user registers to set
+ * Sleep (TS) and Wake (TW) time.
+ */
+#define FEC_QUIRK_HAS_EEE (1 << 17)
+/* i.MX8QM ENET IP version add new feture to generate delayed TXC/RXC
+ * as an alternative option to make sure it works well with various PHYs.
+ * For the implementation of delayed clock, ENET takes synchronized 250MHz
+ * clocks to generate 2ns delay.
+ */
+#define FEC_QUIRK_DELAYED_CLKS_SUPPORT (1 << 18)
+/* request pmqos during low power */
+#define FEC_QUIRK_HAS_PMQOS (1 << 19)
+
+struct fec_enet_stop_mode {
+ struct regmap *gpr;
+ u8 req_gpr;
+ u8 req_bit;
+};
struct bufdesc_prop {
int qid;
@@ -488,12 +519,6 @@ struct fec_enet_priv_rx_q {
struct sk_buff *rx_skbuff[RX_RING_SIZE];
};
-struct fec_stop_mode_gpr {
- struct regmap *gpr;
- u8 reg;
- u8 bit;
-};
-
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
* tx_bd_base always point to the base of the buffer descriptors. The
* cur_rx and cur_tx point to the currently available buffer.
@@ -513,6 +538,7 @@ struct fec_enet_private {
struct clk *clk_ref;
struct clk *clk_enet_out;
struct clk *clk_ptp;
+ struct clk *clk_2x_txclk;
bool ptp_clk_on;
struct mutex ptp_clk_mutex;
@@ -540,6 +566,10 @@ struct fec_enet_private {
uint phy_speed;
phy_interface_t phy_interface;
struct device_node *phy_node;
+ bool rgmii_txc_dly;
+ bool rgmii_rxc_dly;
+ bool mii_bus_share;
+ bool rpm_active;
int link;
int full_duplex;
int speed;
@@ -548,6 +578,7 @@ struct fec_enet_private {
bool bufdesc_ex;
int pause_flag;
int wol_flag;
+ int wake_irq;
u32 quirks;
struct napi_struct napi;
@@ -568,7 +599,7 @@ struct fec_enet_private {
int hwts_tx_en;
struct delayed_work time_keep;
struct regulator *reg_phy;
- struct fec_stop_mode_gpr stop_gpr;
+ struct pm_qos_request pm_qos_req;
unsigned int tx_align;
unsigned int rx_align;
@@ -580,6 +611,10 @@ struct fec_enet_private {
unsigned int tx_time_itr;
unsigned int itr_clk_rate;
+ /* tx lpi eee mode */
+ struct ethtool_eee eee;
+ unsigned int clk_ref_rate;
+
u32 rx_copybreak;
/* ptp clock period in ns*/
@@ -591,6 +626,12 @@ struct fec_enet_private {
int pps_enable;
unsigned int next_counter;
+ /* stop mode */
+ struct fec_enet_stop_mode lpm;
+#ifdef CONFIG_IMX_SCU_SOC
+ struct imx_sc_ipc *ipc_handle;
+#endif
+
u64 ethtool_stats[0];
};
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b1856552ab81..022549fc193c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -61,10 +61,12 @@
#include <linux/regulator/consumer.h>
#include <linux/if_vlan.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
#include <linux/prefetch.h>
+#include <soc/imx/cpuidle.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
-#include <soc/imx/cpuidle.h>
#include <asm/cacheflush.h>
@@ -76,6 +78,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
#define DRIVER_NAME "fec"
#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+static const u16 fec_enet_vlan_pri_to_queue[8] = {1, 1, 1, 1, 2, 2, 2, 2};
/* Pause frame feild and FIFO threshold */
#define FEC_ENET_FCE (1 << 5)
@@ -86,56 +89,6 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
#define FEC_ENET_OPD_V 0xFFF0
#define FEC_MDIO_PM_TIMEOUT 100 /* ms */
-struct fec_devinfo {
- u32 quirks;
- u8 stop_gpr_reg;
- u8 stop_gpr_bit;
-};
-
-static const struct fec_devinfo fec_imx25_info = {
- .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
- FEC_QUIRK_HAS_FRREG,
-};
-
-static const struct fec_devinfo fec_imx27_info = {
- .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
-};
-
-static const struct fec_devinfo fec_imx28_info = {
- .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
- FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
- FEC_QUIRK_HAS_FRREG,
-};
-
-static const struct fec_devinfo fec_imx6q_info = {
- .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
- FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
- FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
- FEC_QUIRK_HAS_RACC,
- .stop_gpr_reg = 0x34,
- .stop_gpr_bit = 27,
-};
-
-static const struct fec_devinfo fec_mvf600_info = {
- .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
-};
-
-static const struct fec_devinfo fec_imx6x_info = {
- .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
- FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
- FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
- FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
- FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
-};
-
-static const struct fec_devinfo fec_imx6ul_info = {
- .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
- FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
- FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
- FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
- FEC_QUIRK_HAS_COALESCE,
-};
-
static struct platform_device_id fec_devtype[] = {
{
/* keep it for coldfire */
@@ -143,25 +96,61 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = 0,
}, {
.name = "imx25-fec",
- .driver_data = (kernel_ulong_t)&fec_imx25_info,
+ .driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
+ FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx27-fec",
- .driver_data = (kernel_ulong_t)&fec_imx27_info,
+ .driver_data = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx28-fec",
- .driver_data = (kernel_ulong_t)&fec_imx28_info,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
+ FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
+ FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx6q-fec",
- .driver_data = (kernel_ulong_t)&fec_imx6q_info,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_PMQOS,
}, {
.name = "mvf600-fec",
- .driver_data = (kernel_ulong_t)&fec_mvf600_info,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
}, {
.name = "imx6sx-fec",
- .driver_data = (kernel_ulong_t)&fec_imx6x_info,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
}, {
.name = "imx6ul-fec",
- .driver_data = (kernel_ulong_t)&fec_imx6ul_info,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
+ FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
+ FEC_QUIRK_HAS_COALESCE,
+ }, {
+ .name = "imx8mq-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+ FEC_QUIRK_HAS_EEE,
+ }, {
+ .name = "imx8qm-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+ FEC_QUIRK_DELAYED_CLKS_SUPPORT,
+ }, {
+ .name = "s32v234-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE,
}, {
/* sentinel */
}
@@ -176,6 +165,9 @@ enum imx_fec_type {
MVF600_FEC,
IMX6SX_FEC,
IMX6UL_FEC,
+ IMX8MQ_FEC,
+ IMX8QM_FEC,
+ S32V234_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
@@ -186,6 +178,9 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
{ .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
+ { .compatible = "fsl,imx8mq-fec", .data = &fec_devtype[IMX8MQ_FEC], },
+ { .compatible = "fsl,imx8qm-fec", .data = &fec_devtype[IMX8QM_FEC], },
+ { .compatible = "fsl,s32v234-fec", .data = &fec_devtype[S32V234_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -270,7 +265,15 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
-#define COPYBREAK_DEFAULT 256
+/* By default, set the copybreak to 1518,
+ * then the RX path always keep DMA memory unchanged, and
+ * allocate one new skb and copy DMA memory data to the new skb
+ * buffer, which can improve the performance when SMMU is enabled.
+ *
+ * The driver support .set_tunable() interface for ethtool, user
+ * can dynamicly change the copybreak value.
+ */
+#define COPYBREAK_DEFAULT 1518
/* Max number of allowed TCP segments for software TSO */
#define FEC_MAX_TSO_SEGS 100
@@ -953,7 +956,7 @@ fec_restart(struct net_device *ndev)
u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
- u32 ecntl = 0x2; /* ETHEREN */
+ u32 ecntl = FEC_ENET_ETHEREN; /* ETHEREN */
/* Whack a reset. We should wait for this.
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1107,6 +1110,13 @@ fec_restart(struct net_device *ndev)
if (fep->bufdesc_ex)
ecntl |= (1 << 4);
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+ fep->rgmii_txc_dly)
+ ecntl |= FEC_ENET_TXC_DLY;
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+ fep->rgmii_rxc_dly)
+ ecntl |= FEC_ENET_RXC_DLY;
+
#ifndef CONFIG_M5272
/* Enable the MIB statistic event counters */
writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
@@ -1130,22 +1140,75 @@ fec_restart(struct net_device *ndev)
}
-static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
+#ifdef CONFIG_IMX_SCU_SOC
+static int fec_enet_ipc_handle_init(struct fec_enet_private *fep)
+{
+ if (!(of_machine_is_compatible("fsl,imx8qm") ||
+ of_machine_is_compatible("fsl,imx8qxp") ||
+ of_machine_is_compatible("fsl,imx8dxl")))
+ return 0;
+
+ return imx_scu_get_handle(&fep->ipc_handle);
+}
+
+static void fec_enet_ipg_stop_set(struct fec_enet_private *fep, bool enabled)
+{
+ struct device_node *np = fep->pdev->dev.of_node;
+ u32 rsrc_id, val;
+ int idx;
+
+ if (!np || !fep->ipc_handle)
+ return;
+
+ idx = of_alias_get_id(np, "ethernet");
+ if (idx < 0)
+ idx = 0;
+ rsrc_id = idx ? IMX_SC_R_ENET_1 : IMX_SC_R_ENET_0;
+
+ val = enabled ? 1 : 0;
+ imx_sc_misc_set_control(fep->ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val);
+}
+#else
+static int fec_enet_ipc_handle_init(struct fec_enet_private *fep)
+{
+ return 0;
+}
+
+static void fec_enet_ipg_stop_set(struct fec_enet_private *fep, bool enabled) {}
+#endif
+
+static void fec_enet_enter_stop_mode(struct fec_enet_private *fep)
{
struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
- struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr;
- if (stop_gpr->gpr) {
- if (enabled)
- regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
- BIT(stop_gpr->bit),
- BIT(stop_gpr->bit));
- else
- regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
- BIT(stop_gpr->bit), 0);
- } else if (pdata && pdata->sleep_mode_enable) {
- pdata->sleep_mode_enable(enabled);
- }
+ if (!IS_ERR_OR_NULL(fep->lpm.gpr))
+ regmap_update_bits(fep->lpm.gpr, fep->lpm.req_gpr,
+ 1 << fep->lpm.req_bit,
+ 1 << fep->lpm.req_bit);
+ else if (pdata && pdata->sleep_mode_enable)
+ pdata->sleep_mode_enable(true);
+ else
+ fec_enet_ipg_stop_set(fep, true);
+}
+
+static void fec_enet_exit_stop_mode(struct fec_enet_private *fep)
+{
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
+
+ if (!IS_ERR_OR_NULL(fep->lpm.gpr))
+ regmap_update_bits(fep->lpm.gpr, fep->lpm.req_gpr,
+ 1 << fep->lpm.req_bit, 0);
+ else if (pdata && pdata->sleep_mode_enable)
+ pdata->sleep_mode_enable(false);
+ else
+ fec_enet_ipg_stop_set(fep, false);
+}
+
+static inline void fec_irqs_disable(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ writel(0, fep->hwp + FEC_IMASK);
}
static void
@@ -1180,7 +1243,6 @@ fec_stop(struct net_device *ndev)
val = readl(fep->hwp + FEC_ECNTRL);
val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);
- fec_enet_stop_mode(fep, true);
}
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -1690,7 +1752,7 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
}
/* ------------------------------------------------------------------------- */
-static void fec_get_mac(struct net_device *ndev)
+static int fec_get_mac(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
@@ -1713,6 +1775,8 @@ static void fec_get_mac(struct net_device *ndev)
const char *mac = of_get_mac_address(np);
if (!IS_ERR(mac))
iap = (unsigned char *) mac;
+ else if (PTR_ERR(mac) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
}
}
@@ -1749,7 +1813,7 @@ static void fec_get_mac(struct net_device *ndev)
eth_hw_addr_random(ndev);
dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
ndev->dev_addr);
- return;
+ return 0;
}
memcpy(ndev->dev_addr, iap, ETH_ALEN);
@@ -1757,6 +1821,8 @@ static void fec_get_mac(struct net_device *ndev)
/* Adjust MAC if using macaddr */
if (iap == macaddr)
ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id;
+
+ return 0;
}
/* ------------------------------------------------------------------------- */
@@ -1823,6 +1889,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
struct fec_enet_private *fep = bus->priv;
struct device *dev = &fep->pdev->dev;
unsigned long time_left;
+ uint int_events;
int ret = 0, frame_start, frame_addr, frame_op;
bool is_c45 = !!(regnum & MII_ADDR_C45);
@@ -1869,9 +1936,12 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
time_left = wait_for_completion_timeout(&fep->mdio_done,
usecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
- netdev_err(fep->netdev, "MDIO read timeout\n");
- ret = -ETIMEDOUT;
- goto out;
+ int_events = readl(fep->hwp + FEC_IEVENT);
+ if (!(int_events & FEC_ENET_MII)) {
+ netdev_err(fep->netdev, "MDIO read timeout\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
@@ -1992,6 +2062,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
if (ret)
goto failed_clk_ref;
+ ret = clk_prepare_enable(fep->clk_2x_txclk);
+ if (ret)
+ goto failed_clk_2x_txclk;
+
fec_enet_phy_reset_after_clk_enable(ndev);
} else {
clk_disable_unprepare(fep->clk_enet_out);
@@ -2002,13 +2076,17 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
mutex_unlock(&fep->ptp_clk_mutex);
}
clk_disable_unprepare(fep->clk_ref);
+ clk_disable_unprepare(fep->clk_2x_txclk);
}
return 0;
-failed_clk_ref:
+failed_clk_2x_txclk:
if (fep->clk_ref)
clk_disable_unprepare(fep->clk_ref);
+failed_clk_ref:
+ if (fep->clk_ptp)
+ clk_disable_unprepare(fep->clk_ptp);
failed_clk_ptp:
if (fep->clk_enet_out)
clk_disable_unprepare(fep->clk_enet_out);
@@ -2016,6 +2094,25 @@ failed_clk_ptp:
return ret;
}
+static int fec_restore_mii_bus(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int ret;
+
+ ret = pm_runtime_get_sync(&fep->pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ writel(0xffc00000, fep->hwp + FEC_IEVENT);
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+ writel(FEC_ENET_ETHEREN, fep->hwp + FEC_ECNTRL);
+
+ pm_runtime_mark_last_busy(&fep->pdev->dev);
+ pm_runtime_put_autosuspend(&fep->pdev->dev);
+ return 0;
+}
+
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
@@ -2084,6 +2181,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
static int fec_enet_mii_init(struct platform_device *pdev)
{
static struct mii_bus *fec0_mii_bus;
+ static bool *fec_mii_bus_share;
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
struct device_node *node;
@@ -2110,6 +2208,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
/* fec1 uses fec0 mii_bus */
if (mii_cnt && fec0_mii_bus) {
fep->mii_bus = fec0_mii_bus;
+ *fec_mii_bus_share = true;
mii_cnt++;
return 0;
}
@@ -2176,8 +2275,10 @@ static int fec_enet_mii_init(struct platform_device *pdev)
mii_cnt++;
/* save fec0 mii_bus */
- if (fep->quirks & FEC_QUIRK_SINGLE_MDIO)
+ if (fep->quirks & FEC_QUIRK_SINGLE_MDIO) {
fec0_mii_bus = fep->mii_bus;
+ fec_mii_bus_share = &fep->mii_bus_share;
+ }
return 0;
@@ -2677,6 +2778,92 @@ static int fec_enet_set_tunable(struct net_device *netdev,
return ret;
}
+/* LPI Sleep Ts count base on tx clk (clk_ref).
+ * The lpi sleep cnt value = X us / (cycle_ns)
+ */
+static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ return us * (fep->clk_ref_rate / 1000) / 1000;
+}
+
+static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+ unsigned int sleep_cycle, wake_cycle;
+ int ret = 0;
+
+ if (enable) {
+ ret = phy_init_eee(ndev->phydev, 0);
+ if (ret)
+ return ret;
+
+ sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
+ wake_cycle = sleep_cycle;
+ } else {
+ sleep_cycle = 0;
+ wake_cycle = 0;
+ }
+
+ p->tx_lpi_enabled = enable;
+ p->eee_enabled = enable;
+ p->eee_active = enable;
+
+ writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
+ writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
+
+ return 0;
+}
+
+static int
+fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ if (!netif_running(ndev))
+ return -ENETDOWN;
+
+ edata->eee_enabled = p->eee_enabled;
+ edata->eee_active = p->eee_active;
+ edata->tx_lpi_timer = p->tx_lpi_timer;
+ edata->tx_lpi_enabled = p->tx_lpi_enabled;
+
+ return phy_ethtool_get_eee(ndev->phydev, edata);
+}
+
+static int
+fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+ int ret = 0;
+
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ if (!netif_running(ndev))
+ return -ENETDOWN;
+
+ p->tx_lpi_timer = edata->tx_lpi_timer;
+
+ if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
+ !edata->tx_lpi_timer)
+ ret = fec_enet_eee_mode_set(ndev, false);
+ else
+ ret = fec_enet_eee_mode_set(ndev, true);
+
+ if (ret)
+ return ret;
+
+ return phy_ethtool_set_eee(ndev->phydev, edata);
+}
+
static void
fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
@@ -2702,15 +2889,10 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
return -EINVAL;
device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
- if (device_may_wakeup(&ndev->dev)) {
+ if (device_may_wakeup(&ndev->dev))
fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
- if (fep->irq[0] > 0)
- enable_irq_wake(fep->irq[0]);
- } else {
+ else
fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
- if (fep->irq[0] > 0)
- disable_irq_wake(fep->irq[0]);
- }
return 0;
}
@@ -2735,6 +2917,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.set_tunable = fec_enet_set_tunable,
.get_wol = fec_enet_get_wol,
.set_wol = fec_enet_set_wol,
+ .get_eee = fec_enet_get_eee,
+ .set_eee = fec_enet_set_eee,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
@@ -3016,6 +3200,10 @@ fec_enet_open(struct net_device *ndev)
if (fep->quirks & FEC_QUIRK_ERR006687)
imx6q_cpuidle_fec_irqs_used();
+ if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
+ pm_qos_add_request(&fep->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ 0);
napi_enable(&fep->napi);
phy_start(ndev->phydev);
@@ -3033,7 +3221,8 @@ err_enet_alloc:
clk_enable:
pm_runtime_mark_last_busy(&fep->pdev->dev);
pm_runtime_put_autosuspend(&fep->pdev->dev);
- pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ if (!fep->mii_bus_share)
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
return ret;
}
@@ -3051,6 +3240,7 @@ fec_enet_close(struct net_device *ndev)
}
phy_disconnect(ndev->phydev);
+ ndev->phydev = NULL;
if (fep->quirks & FEC_QUIRK_ERR006687)
imx6q_cpuidle_fec_irqs_unused();
@@ -3058,7 +3248,10 @@ fec_enet_close(struct net_device *ndev)
fec_enet_update_ethtool_stats(ndev);
fec_enet_clk_enable(ndev, false);
- pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
+ pm_qos_remove_request(&fep->pm_qos_req);
+ if (!fep->mii_bus_share)
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
pm_runtime_mark_last_busy(&fep->pdev->dev);
pm_runtime_put_autosuspend(&fep->pdev->dev);
@@ -3219,10 +3412,42 @@ static int fec_set_features(struct net_device *netdev,
return 0;
}
+u16 fec_enet_get_raw_vlan_tci(struct sk_buff *skb)
+{
+ struct vlan_ethhdr *vhdr;
+ unsigned short vlan_TCI = 0;
+
+ if (skb->protocol == ntohs(ETH_P_ALL)) {
+ vhdr = (struct vlan_ethhdr *)(skb->data);
+ vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+ }
+
+ return vlan_TCI;
+}
+
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+ struct net_device *sb_dev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
+ u16 vlan_tag;
+
+ if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ return netdev_pick_tx(ndev, skb, NULL);
+
+ vlan_tag = fec_enet_get_raw_vlan_tci(skb);
+ if (!vlan_tag)
+ return vlan_tag;
+
+ return fec_enet_vlan_pri_to_queue[vlan_tag >> 13];
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
.ndo_start_xmit = fec_enet_start_xmit,
+ .ndo_select_queue = fec_enet_select_queue,
.ndo_set_rx_mode = set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = fec_timeout,
@@ -3289,7 +3514,10 @@ static int fec_enet_init(struct net_device *ndev)
}
/* Get the Ethernet address */
- fec_get_mac(ndev);
+ ret = fec_get_mac(ndev);
+ if (ret)
+ goto free_queue_mem;
+
/* make sure MAC we just acquired is programmed into the hw */
fec_set_mac_address(ndev, NULL);
@@ -3479,35 +3707,39 @@ static int fec_enet_get_irq_cnt(struct platform_device *pdev)
return irq_cnt;
}
-static int fec_enet_init_stop_mode(struct fec_enet_private *fep,
- struct fec_devinfo *dev_info,
- struct device_node *np)
+static void fec_enet_of_parse_stop_mode(struct platform_device *pdev)
{
- struct device_node *gpr_np;
- int ret = 0;
-
- if (!dev_info)
- return 0;
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int ret;
- gpr_np = of_parse_phandle(np, "gpr", 0);
- if (!gpr_np)
- return 0;
+ ret = of_property_read_u32_array(np, "stop-mode", out_val, 3);
+ if (ret) {
+ dev_dbg(&pdev->dev, "no stop-mode property\n");
+ return;
+ }
- fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np);
- if (IS_ERR(fep->stop_gpr.gpr)) {
- dev_err(&fep->pdev->dev, "could not find gpr regmap\n");
- ret = PTR_ERR(fep->stop_gpr.gpr);
- fep->stop_gpr.gpr = NULL;
- goto out;
+ phandle = *out_val;
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(&pdev->dev, "could not find gpr node by phandle\n");
+ return;
}
- fep->stop_gpr.reg = dev_info->stop_gpr_reg;
- fep->stop_gpr.bit = dev_info->stop_gpr_bit;
+ fep->lpm.gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(fep->lpm.gpr)) {
+ dev_dbg(&pdev->dev, "could not find gpr regmap\n");
+ return;
+ }
-out:
- of_node_put(gpr_np);
+ of_node_put(node);
- return ret;
+ fep->lpm.req_gpr = out_val[1];
+ fep->lpm.req_bit = out_val[2];
}
static int
@@ -3524,7 +3756,6 @@ fec_probe(struct platform_device *pdev)
int num_rx_qs;
char irq_name[8];
int irq_cnt;
- struct fec_devinfo *dev_info;
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
@@ -3542,9 +3773,7 @@ fec_probe(struct platform_device *pdev)
of_id = of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
pdev->id_entry = of_id->data;
- dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data;
- if (dev_info)
- fep->quirks = dev_info->quirks;
+ fep->quirks = pdev->id_entry->driver_data;
fep->netdev = ndev;
fep->num_rx_queues = num_rx_qs;
@@ -3575,12 +3804,19 @@ fec_probe(struct platform_device *pdev)
!of_property_read_bool(np, "fsl,err006687-workaround-present"))
fep->quirks |= FEC_QUIRK_ERR006687;
+ fec_enet_of_parse_stop_mode(pdev);
+ ret = fec_enet_ipc_handle_init(fep);
+ if (ret)
+ goto failed_ipc_init;
+
if (of_get_property(np, "fsl,magic-packet", NULL))
fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
- ret = fec_enet_init_stop_mode(fep, dev_info, np);
- if (ret)
- goto failed_stop_mode;
+ if (of_get_property(np, "fsl,rgmii_txc_dly", NULL))
+ fep->rgmii_txc_dly = true;
+
+ if (of_get_property(np, "fsl,rgmii_rxc_dly", NULL))
+ fep->rgmii_rxc_dly = true;
phy_node = of_parse_phandle(np, "phy-handle", 0);
if (!phy_node && of_phy_is_fixed_link(np)) {
@@ -3605,6 +3841,8 @@ fec_probe(struct platform_device *pdev)
fep->phy_interface = ret;
}
+ request_bus_freq(BUS_FREQ_HIGH);
+
fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fep->clk_ipg)) {
ret = PTR_ERR(fep->clk_ipg);
@@ -3631,6 +3869,12 @@ fec_probe(struct platform_device *pdev)
fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL;
+ fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
+
+ /* clk_2x_txclk is optional, depends on board */
+ fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk");
+ if (IS_ERR(fep->clk_2x_txclk))
+ fep->clk_2x_txclk = NULL;
fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
@@ -3701,7 +3945,17 @@ fec_probe(struct platform_device *pdev)
fep->irq[i] = irq;
}
+ /* get wake up irq */
+ ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);
+ if (!ret && irq < irq_cnt)
+ fep->wake_irq = fep->irq[irq];
+ else
+ fep->wake_irq = fep->irq[0];
+
init_completion(&fep->mdio_done);
+ /* board only enable one mii bus in default */
+ if (!of_get_property(np, "fsl,mii-exclusive", NULL))
+ fep->quirks |= FEC_QUIRK_SINGLE_MDIO;
ret = fec_enet_mii_init(pdev);
if (ret)
goto failed_mii_init;
@@ -3747,10 +4001,11 @@ failed_clk_ahb:
failed_clk_ipg:
fec_enet_clk_enable(ndev, false);
failed_clk:
+ release_bus_freq(BUS_FREQ_HIGH);
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(phy_node);
-failed_stop_mode:
+failed_ipc_init:
failed_phy:
dev_id--;
failed_ioremap:
@@ -3798,6 +4053,8 @@ static int __maybe_unused fec_suspend(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
+ int ret;
+
if (fep->wol_flag & FEC_WOL_FLAG_ENABLE)
fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON;
phy_stop(ndev->phydev);
@@ -3806,9 +4063,24 @@ static int __maybe_unused fec_suspend(struct device *dev)
netif_device_detach(ndev);
netif_tx_unlock_bh(ndev);
fec_stop(ndev);
- fec_enet_clk_enable(ndev, false);
- if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
+ if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
+ fec_irqs_disable(ndev);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ } else {
+ fec_enet_enter_stop_mode(fep);
+ disable_irq(fep->wake_irq);
+ enable_irq_wake(fep->wake_irq);
+ }
+ fec_enet_clk_enable(ndev, false);
+
+ fep->rpm_active = !pm_runtime_status_suspended(dev);
+ if (fep->rpm_active) {
+ ret = pm_runtime_force_suspend(dev);
+ if (ret < 0)
+ return ret;
+ }
+ } else if (fep->mii_bus_share && !ndev->phydev) {
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
}
rtnl_unlock();
@@ -3828,7 +4100,7 @@ static int __maybe_unused fec_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
- int ret;
+ int ret = 0;
int val;
if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
@@ -3839,14 +4111,18 @@ static int __maybe_unused fec_resume(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
+ if (fep->rpm_active)
+ pm_runtime_force_resume(dev);
+
ret = fec_enet_clk_enable(ndev, true);
if (ret) {
rtnl_unlock();
goto failed_clk;
}
if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
- fec_enet_stop_mode(fep, false);
-
+ disable_irq_wake(fep->wake_irq);
+ fec_enet_exit_stop_mode(fep);
+ enable_irq(fep->wake_irq);
val = readl(fep->hwp + FEC_ECNTRL);
val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);
@@ -3860,10 +4136,14 @@ static int __maybe_unused fec_resume(struct device *dev)
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
phy_start(ndev->phydev);
+ } else if (fep->mii_bus_share && !ndev->phydev) {
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
+ /* And then recovery mii bus */
+ ret = fec_restore_mii_bus(ndev);
}
rtnl_unlock();
- return 0;
+ return ret;
failed_clk:
if (fep->reg_phy)
@@ -3878,6 +4158,7 @@ static int __maybe_unused fec_runtime_suspend(struct device *dev)
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
+ release_bus_freq(BUS_FREQ_HIGH);
return 0;
}
@@ -3888,6 +4169,8 @@ static int __maybe_unused fec_runtime_resume(struct device *dev)
struct fec_enet_private *fep = netdev_priv(ndev);
int ret;
+ request_bus_freq(BUS_FREQ_HIGH);
+
ret = clk_prepare_enable(fep->clk_ahb);
if (ret)
return ret;
@@ -3899,6 +4182,7 @@ static int __maybe_unused fec_runtime_resume(struct device *dev)
failed_clk_ipg:
clk_disable_unprepare(fep->clk_ahb);
+ release_bus_freq(BUS_FREQ_HIGH);
return ret;
}
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index c8e434c8ab98..a255610e320a 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -634,6 +634,7 @@ static void set_port_order_restoration(struct fman_fpm_regs __iomem *fpm_rg,
iowrite32be(tmp, &fpm_rg->fmfp_prc);
}
+#ifdef CONFIG_PPC
static void set_port_liodn(struct fman *fman, u8 port_id,
u32 liodn_base, u32 liodn_ofst)
{
@@ -651,6 +652,27 @@ static void set_port_liodn(struct fman *fman, u8 port_id,
iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]);
iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
}
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+static void save_restore_port_icids(struct fman *fman, bool save)
+{
+ int port_idxes[] = {
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc,
+ 0xd, 0xe, 0xf, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x10, 0x11, 0x30, 0x31
+ };
+ int idx, i;
+
+ for (i = 0; i < ARRAY_SIZE(port_idxes); i++) {
+ idx = port_idxes[i];
+ if (save)
+ fman->sp_icids[idx] =
+ ioread32be(&fman->bmi_regs->fmbm_spliodn[idx]);
+ else
+ iowrite32be(fman->sp_icids[idx],
+ &fman->bmi_regs->fmbm_spliodn[idx]);
+ }
+}
+#endif
static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
{
@@ -1918,7 +1940,10 @@ _return:
static int fman_init(struct fman *fman)
{
struct fman_cfg *cfg = NULL;
- int err = 0, i, count;
+ int err = 0, count;
+#ifdef CONFIG_PPC
+ int i;
+#endif
if (is_init_done(fman->cfg))
return -EINVAL;
@@ -1938,6 +1963,7 @@ static int fman_init(struct fman *fman)
memset_io((void __iomem *)(fman->base_addr + CGP_OFFSET), 0,
fman->state->fm_port_num_of_cg);
+#ifdef CONFIG_PPC
/* Save LIODN info before FMan reset
* Skipping non-existent port 0 (i = 1)
*/
@@ -1957,6 +1983,9 @@ static int fman_init(struct fman *fman)
}
fman->liodn_base[i] = liodn_base;
}
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+ save_restore_port_icids(fman, true);
+#endif
err = fman_reset(fman);
if (err)
@@ -2185,8 +2214,12 @@ int fman_set_port_params(struct fman *fman,
if (err)
goto return_err;
+#ifdef CONFIG_PPC
set_port_liodn(fman, port_id, fman->liodn_base[port_id],
fman->liodn_offset[port_id]);
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+ save_restore_port_icids(fman, false);
+#endif
if (fman->state->rev_info.major < 6)
set_port_order_restoration(fman->fpm_regs, port_id);
diff --git a/drivers/net/ethernet/freescale/fman/fman.h b/drivers/net/ethernet/freescale/fman/fman.h
index f2ede1360f03..7dd153e1d585 100644
--- a/drivers/net/ethernet/freescale/fman/fman.h
+++ b/drivers/net/ethernet/freescale/fman/fman.h
@@ -347,8 +347,12 @@ struct fman {
unsigned long fifo_offset;
size_t fifo_size;
+#ifdef CONFIG_PPC
u32 liodn_base[64];
u32 liodn_offset[64];
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+ u32 sp_icids[64];
+#endif
struct fman_dts_params dts_params;
};
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c
index 47f6fee1f396..5ef39a36842f 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1728,6 +1728,20 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port)
}
EXPORT_SYMBOL(fman_port_get_qman_channel_id);
+/**
+ * fman_port_get_device
+ * port: Pointer to the FMan port device
+ *
+ * Get the 'struct device' associated to the specified FMan port device
+ *
+ * Return: pointer to associated 'struct device'
+ */
+struct device *fman_port_get_device(struct fman_port *port)
+{
+ return port->dev;
+}
+EXPORT_SYMBOL(fman_port_get_device);
+
int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
{
if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE)
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h b/drivers/net/ethernet/freescale/fman/fman_port.h
index 9dbb69f40121..82f12661a46d 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.h
+++ b/drivers/net/ethernet/freescale/fman/fman_port.h
@@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp);
struct fman_port *fman_port_bind(struct device *dev);
+struct device *fman_port_get_device(struct fman_port *port);
+
#endif /* __FMAN_PORT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
new file mode 100644
index 000000000000..d7bbc1dce928
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
@@ -0,0 +1,184 @@
+menuconfig FSL_SDK_DPAA_ETH
+ tristate "DPAA Ethernet"
+ depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && FSL_SDK_FMAN && !FSL_DPAA_ETH
+ select PHYLIB
+ help
+ Data Path Acceleration Architecture Ethernet driver,
+ supporting the Freescale QorIQ chips.
+ Depends on Freescale Buffer Manager and Queue Manager
+ driver and Frame Manager Driver.
+
+if FSL_SDK_DPAA_ETH
+
+config FSL_DPAA_HOOKS
+ bool "DPAA Ethernet driver hooks"
+
+config FSL_DPAA_CEETM
+ bool "DPAA CEETM QoS"
+ depends on NET_SCHED
+ default n
+ help
+ Enable QoS offloading support through the CEETM hardware block.
+
+config FSL_DPAA_CEETM_CCS_THRESHOLD_1G
+ hex "CEETM egress congestion threshold on 1G ports"
+ depends on FSL_DPAA_CEETM
+ range 0x1000 0x10000000
+ default "0x00005000"
+ help
+ The size in bytes of the CEETM egress Class Congestion State threshold on 1G ports.
+ The threshold needs to be configured keeping in mind the following factors:
+ - A threshold too large will buffer frames for a long time in the TX queues,
+ when a small shaping rate is configured. This will cause buffer pool depletion
+ or out of memory errors. This in turn will cause frame loss on RX;
+ - A threshold too small will cause unnecessary frame loss by entering
+ congestion too often.
+
+config FSL_DPAA_CEETM_CCS_THRESHOLD_10G
+ hex "CEETM egress congestion threshold on 10G ports"
+ depends on FSL_DPAA_CEETM
+ range 0x1000 0x20000000
+ default "0x00032000"
+ help
+ The size in bytes of the CEETM egress Class Congestion State threshold on 10G ports.
+ See FSL_DPAA_CEETM_CCS_THRESHOLD_1G for details.
+
+config FSL_DPAA_OFFLINE_PORTS
+ bool "Offline Ports support"
+ depends on FSL_SDK_DPAA_ETH
+ default y
+ help
+ The Offline Parsing / Host Command ports (short: OH ports, of Offline ports) provide
+ most of the functionality of the regular, online ports, except they receive their
+ frames from a core or an accelerator on the SoC, via QMan frame queues,
+ rather than directly from the network.
+ Offline ports are configured via PCD (Parse-Classify-Distribute) schemes, just like
+ any online FMan port. They deliver the processed frames to frame queues, according
+ to the applied PCD configurations.
+
+ Choosing this feature will not impact the functionality and/or performance of the system,
+ so it is safe to have it.
+
+config FSL_DPAA_ADVANCED_DRIVERS
+ bool "Advanced DPAA Ethernet drivers"
+ depends on FSL_SDK_DPAA_ETH
+ default y
+ help
+ Besides the standard DPAA Ethernet driver the DPAA Proxy initialization driver
+ is needed to support advanced scenarios. Select this to also build the advanced
+ drivers.
+
+config FSL_DPAA_ETH_JUMBO_FRAME
+ bool "Optimize for jumbo frames"
+ default n
+ help
+ Optimize the DPAA Ethernet driver throughput for large frames
+ termination traffic (e.g. 4K and above).
+ NOTE: This option can only be used if FSL_FM_MAX_FRAME_SIZE
+ is set to 9600 bytes.
+ Using this option in combination with small frames increases
+ significantly the driver's memory footprint and may even deplete
+ the system memory. Also, the skb truesize is altered and messages
+ from the stack that warn against this are bypassed.
+
+config FSL_DPAA_TS
+ bool "Linux compliant timestamping"
+ depends on FSL_SDK_DPAA_ETH
+ default n
+ help
+ Enable Linux API compliant timestamping support.
+
+config FSL_DPAA_1588
+ bool "IEEE 1588-compliant timestamping"
+ depends on FSL_SDK_DPAA_ETH
+ select FSL_DPAA_TS
+ default n
+ help
+ Enable IEEE1588 support code.
+
+config FSL_DPAA_ETH_MAX_BUF_COUNT
+ int "Maximum nuber of buffers in private bpool"
+ depends on FSL_SDK_DPAA_ETH
+ range 64 2048
+ default "128"
+ help
+ The maximum number of buffers to be by default allocated in the DPAA-Ethernet private port's
+ buffer pool. One needn't normally modify this, as it has probably been tuned for performance
+ already. This cannot be lower than DPAA_ETH_REFILL_THRESHOLD.
+
+config FSL_DPAA_ETH_REFILL_THRESHOLD
+ int "Private bpool refill threshold"
+ depends on FSL_SDK_DPAA_ETH
+ range 32 FSL_DPAA_ETH_MAX_BUF_COUNT
+ default "80"
+ help
+ The DPAA-Ethernet driver will start replenishing buffer pools whose count
+ falls below this threshold. This must be related to DPAA_ETH_MAX_BUF_COUNT. One needn't normally
+ modify this value unless one has very specific performance reasons.
+
+config FSL_DPAA_CS_THRESHOLD_1G
+ hex "Egress congestion threshold on 1G ports"
+ depends on FSL_SDK_DPAA_ETH
+ range 0x1000 0x10000000
+ default "0x06000000"
+ help
+ The size in bytes of the egress Congestion State notification threshold on 1G ports.
+ The 1G dTSECs can quite easily be flooded by cores doing Tx in a tight loop
+ (e.g. by sending UDP datagrams at "while(1) speed"),
+ and the larger the frame size, the more acute the problem.
+ So we have to find a balance between these factors:
+ - avoiding the device staying congested for a prolonged time (risking
+ the netdev watchdog to fire - see also the tx_timeout module param);
+ - affecting performance of protocols such as TCP, which otherwise
+ behave well under the congestion notification mechanism;
+ - preventing the Tx cores from tightly-looping (as if the congestion
+ threshold was too low to be effective);
+ - running out of memory if the CS threshold is set too high.
+
+config FSL_DPAA_CS_THRESHOLD_10G
+ hex "Egress congestion threshold on 10G ports"
+ depends on FSL_SDK_DPAA_ETH
+ range 0x1000 0x20000000
+ default "0x10000000"
+ help
+ The size in bytes of the egress Congestion State notification threshold on 10G ports.
+
+config FSL_DPAA_INGRESS_CS_THRESHOLD
+ hex "Ingress congestion threshold on FMan ports"
+ depends on FSL_SDK_DPAA_ETH
+ default "0x10000000"
+ help
+ The size in bytes of the ingress tail-drop threshold on FMan ports.
+ Traffic piling up above this value will be rejected by QMan and discarded by FMan.
+
+config FSL_DPAA_ETH_DEBUGFS
+ bool "DPAA Ethernet debugfs interface"
+ depends on DEBUG_FS && FSL_SDK_DPAA_ETH
+ default y
+ help
+ This option compiles debugfs code for the DPAA Ethernet driver.
+
+config FSL_DPAA_ETH_DEBUG
+ bool "DPAA Ethernet Debug Support"
+ depends on FSL_SDK_DPAA_ETH
+ default n
+ help
+ This option compiles debug code for the DPAA Ethernet driver.
+
+config FSL_DPAA_DBG_LOOP
+ bool "DPAA Ethernet Debug loopback"
+ depends on FSL_DPAA_ETH_DEBUGFS
+ default n
+ help
+ This option allows to divert all received traffic on a certain interface A towards a
+ selected interface B. This option is used to benchmark the HW + Ethernet driver in
+ isolation from the Linux networking stack. The loops are controlled by debugfs entries,
+ one for each interface. By default all loops are disabled (target value is -1). I.e. to
+ change the loop setting for interface 4 and divert all received traffic to interface 5
+ write Tx interface number in the receive interface debugfs file:
+ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ 4->-1
+ # echo 5 > /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ 4->5
+endif # FSL_SDK_DPAA_ETH
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
new file mode 100644
index 000000000000..a0623b24fa1c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
@@ -0,0 +1,46 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+# Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+ccflags-y += -I$(NET_DPA)
+
+obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o
+
+fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o
+ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y)
+fsl_dpa-objs += dpaa_debugfs.o
+endif
+ifeq ($(CONFIG_FSL_DPAA_1588),y)
+fsl_dpa-objs += dpaa_1588.o
+endif
+
+ifeq ($(CONFIG_FSL_DPAA_CEETM),y)
+ccflags-y += -I$(srctree)/drivers/net/ethernet/freescale/sdk_fman/src/wrapper
+fsl_dpa-objs += dpaa_eth_ceetm.o
+endif
+
+fsl_mac-objs += mac.o mac-api.o
+
+# Advanced drivers
+ifeq ($(CONFIG_FSL_DPAA_ADVANCED_DRIVERS),y)
+obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_advanced.o
+obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_proxy.o
+
+fsl_advanced-objs += dpaa_eth_base.o
+# suport for multiple drivers per kernel module comes in kernel 3.14
+# so we are forced to generate several modules for the advanced drivers
+fsl_proxy-objs += dpaa_eth_proxy.o
+
+ifeq ($(CONFIG_FSL_DPAA_OFFLINE_PORTS),y)
+obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_oh.o
+
+fsl_oh-objs += offline_port.o
+endif
+endif
+
+# Needed by the tracing framework
+CFLAGS_dpaa_eth.o := -I$(src)
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c
new file mode 100644
index 000000000000..3bf8cbca7e36
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c
@@ -0,0 +1,580 @@
+/* Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2009 IXXAT Automation, GmbH
+ *
+ * DPAA Ethernet Driver -- IEEE 1588 interface functionality
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <asm/div64.h>
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#include "dpaa_1588.h"
+#include "mac.h"
+
+static int dpa_ptp_init_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size)
+{
+ struct circ_buf *circ_buf = &ptp_buf->circ_buf;
+
+ circ_buf->buf = vmalloc(sizeof(struct dpa_ptp_data) * size);
+ if (!circ_buf->buf)
+ return 1;
+
+ circ_buf->head = 0;
+ circ_buf->tail = 0;
+ ptp_buf->size = size;
+ spin_lock_init(&ptp_buf->ptp_lock);
+
+ return 0;
+}
+
+static void dpa_ptp_reset_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size)
+{
+ struct circ_buf *circ_buf = &ptp_buf->circ_buf;
+
+ circ_buf->head = 0;
+ circ_buf->tail = 0;
+ ptp_buf->size = size;
+}
+
+static int dpa_ptp_insert(struct dpa_ptp_circ_buf *ptp_buf,
+ struct dpa_ptp_data *data)
+{
+ struct circ_buf *circ_buf = &ptp_buf->circ_buf;
+ int size = ptp_buf->size;
+ struct dpa_ptp_data *tmp;
+ unsigned long flags;
+ int head, tail;
+
+ spin_lock_irqsave(&ptp_buf->ptp_lock, flags);
+
+ head = circ_buf->head;
+ tail = circ_buf->tail;
+
+ if (CIRC_SPACE(head, tail, size) <= 0)
+ circ_buf->tail = (tail + 1) & (size - 1);
+
+ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + head;
+ memcpy(tmp, data, sizeof(struct dpa_ptp_data));
+
+ circ_buf->head = (head + 1) & (size - 1);
+
+ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
+
+ return 0;
+}
+
+static int dpa_ptp_is_ident_match(struct dpa_ptp_ident *dst,
+ struct dpa_ptp_ident *src)
+{
+ int ret;
+
+ if ((dst->version != src->version) || (dst->msg_type != src->msg_type))
+ return 0;
+
+ if ((dst->netw_prot == src->netw_prot)
+ || src->netw_prot == DPA_PTP_PROT_DONTCARE) {
+ if (dst->seq_id != src->seq_id)
+ return 0;
+
+ ret = memcmp(dst->snd_port_id, src->snd_port_id,
+ DPA_PTP_SOURCE_PORT_LENGTH);
+ if (ret)
+ return 0;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+static int dpa_ptp_find_and_remove(struct dpa_ptp_circ_buf *ptp_buf,
+ struct dpa_ptp_ident *ident,
+ struct dpa_ptp_time *ts)
+{
+ struct circ_buf *circ_buf = &ptp_buf->circ_buf;
+ int size = ptp_buf->size;
+ int head, tail, idx;
+ unsigned long flags;
+ struct dpa_ptp_data *tmp, *tmp2;
+ struct dpa_ptp_ident *tmp_ident;
+
+ spin_lock_irqsave(&ptp_buf->ptp_lock, flags);
+
+ head = circ_buf->head;
+ tail = idx = circ_buf->tail;
+
+ if (CIRC_CNT(head, tail, size) == 0) {
+ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
+ return 1;
+ }
+
+ while (idx != head) {
+ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
+ tmp_ident = &tmp->ident;
+ if (dpa_ptp_is_ident_match(tmp_ident, ident))
+ break;
+ idx = (idx + 1) & (size - 1);
+ }
+
+ if (idx == head) {
+ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
+ return 1;
+ }
+
+ ts->sec = tmp->ts.sec;
+ ts->nsec = tmp->ts.nsec;
+
+ if (idx != tail) {
+ if (CIRC_CNT(idx, tail, size) > TS_ACCUMULATION_THRESHOLD) {
+ tail = circ_buf->tail =
+ (idx - TS_ACCUMULATION_THRESHOLD) & (size - 1);
+ }
+
+ while (CIRC_CNT(idx, tail, size) > 0) {
+ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
+ idx = (idx - 1) & (size - 1);
+ tmp2 = (struct dpa_ptp_data *)(circ_buf->buf) + idx;
+ *tmp = *tmp2;
+ }
+ }
+ circ_buf->tail = (tail + 1) & (size - 1);
+
+ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags);
+
+ return 0;
+}
+
+/* Parse the PTP packets
+ *
+ * The PTP header can be found in an IPv4 packet, IPv6 patcket or in
+ * an IEEE802.3 ethernet frame. This function returns the position of
+ * the PTP packet or NULL if no PTP found
+ */
+static u8 *dpa_ptp_parse_packet(struct sk_buff *skb, u16 *eth_type)
+{
+ u8 *pos = skb->data + ETH_ALEN + ETH_ALEN;
+ u8 *ptp_loc = NULL;
+ u8 msg_type;
+ u32 access_len = ETH_ALEN + ETH_ALEN + DPA_ETYPE_LEN;
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct ipv6hdr *ipv6h;
+
+ /* when we can receive S/G frames we need to check the data we want to
+ * access is in the linear skb buffer
+ */
+ if (!pskb_may_pull(skb, access_len))
+ return NULL;
+
+ *eth_type = *((u16 *)pos);
+
+ /* Check if inner tag is here */
+ if (*eth_type == ETH_P_8021Q) {
+ access_len += DPA_VLAN_TAG_LEN;
+
+ if (!pskb_may_pull(skb, access_len))
+ return NULL;
+
+ pos += DPA_VLAN_TAG_LEN;
+ *eth_type = *((u16 *)pos);
+ }
+
+ pos += DPA_ETYPE_LEN;
+
+ switch (*eth_type) {
+ /* Transport of PTP over Ethernet */
+ case ETH_P_1588:
+ ptp_loc = pos;
+
+ if (!pskb_may_pull(skb, access_len + PTP_OFFS_MSG_TYPE + 1))
+ return NULL;
+
+ msg_type = *((u8 *)(ptp_loc + PTP_OFFS_MSG_TYPE)) & 0xf;
+ if ((msg_type == PTP_MSGTYPE_SYNC)
+ || (msg_type == PTP_MSGTYPE_DELREQ)
+ || (msg_type == PTP_MSGTYPE_PDELREQ)
+ || (msg_type == PTP_MSGTYPE_PDELRESP))
+ return ptp_loc;
+ break;
+ /* Transport of PTP over IPv4 */
+ case ETH_P_IP:
+ iph = (struct iphdr *)pos;
+ access_len += sizeof(struct iphdr);
+
+ if (!pskb_may_pull(skb, access_len))
+ return NULL;
+
+ if (ntohs(iph->protocol) != IPPROTO_UDP)
+ return NULL;
+
+ access_len += iph->ihl * 4 - sizeof(struct iphdr) +
+ sizeof(struct udphdr);
+
+ if (!pskb_may_pull(skb, access_len))
+ return NULL;
+
+ pos += iph->ihl * 4;
+ udph = (struct udphdr *)pos;
+ if (ntohs(udph->dest) != 319)
+ return NULL;
+ ptp_loc = pos + sizeof(struct udphdr);
+ break;
+ /* Transport of PTP over IPv6 */
+ case ETH_P_IPV6:
+ ipv6h = (struct ipv6hdr *)pos;
+
+ access_len += sizeof(struct ipv6hdr) + sizeof(struct udphdr);
+
+ if (ntohs(ipv6h->nexthdr) != IPPROTO_UDP)
+ return NULL;
+
+ pos += sizeof(struct ipv6hdr);
+ udph = (struct udphdr *)pos;
+ if (ntohs(udph->dest) != 319)
+ return NULL;
+ ptp_loc = pos + sizeof(struct udphdr);
+ break;
+ default:
+ break;
+ }
+
+ return ptp_loc;
+}
+
+static int dpa_ptp_store_stamp(const struct dpa_priv_s *priv,
+ struct sk_buff *skb, void *data, enum port_type rx_tx,
+ struct dpa_ptp_data *ptp_data)
+{
+ u64 nsec;
+ u32 mod;
+ u8 *ptp_loc;
+ u16 eth_type;
+
+ ptp_loc = dpa_ptp_parse_packet(skb, &eth_type);
+ if (!ptp_loc)
+ return -EINVAL;
+
+ switch (eth_type) {
+ case ETH_P_IP:
+ ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV4;
+ break;
+ case ETH_P_IPV6:
+ ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV6;
+ break;
+ case ETH_P_1588:
+ ptp_data->ident.netw_prot = DPA_PTP_PROT_802_3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!pskb_may_pull(skb, ptp_loc - skb->data + PTP_OFFS_SEQ_ID + 2))
+ return -EINVAL;
+
+ ptp_data->ident.version = *(ptp_loc + PTP_OFFS_VER_PTP) & 0xf;
+ ptp_data->ident.msg_type = *(ptp_loc + PTP_OFFS_MSG_TYPE) & 0xf;
+ ptp_data->ident.seq_id = *((u16 *)(ptp_loc + PTP_OFFS_SEQ_ID));
+ memcpy(ptp_data->ident.snd_port_id, ptp_loc + PTP_OFFS_SRCPRTID,
+ DPA_PTP_SOURCE_PORT_LENGTH);
+
+ nsec = dpa_get_timestamp_ns(priv, rx_tx, data);
+ mod = do_div(nsec, NANOSEC_PER_SECOND);
+ ptp_data->ts.sec = nsec;
+ ptp_data->ts.nsec = mod;
+
+ return 0;
+}
+
+void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv,
+ struct sk_buff *skb, void *data)
+{
+ struct dpa_ptp_tsu *tsu = priv->tsu;
+ struct dpa_ptp_data ptp_tx_data;
+
+ if (dpa_ptp_store_stamp(priv, skb, data, TX, &ptp_tx_data))
+ return;
+
+ dpa_ptp_insert(&tsu->tx_timestamps, &ptp_tx_data);
+}
+
+void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv,
+ struct sk_buff *skb, void *data)
+{
+ struct dpa_ptp_tsu *tsu = priv->tsu;
+ struct dpa_ptp_data ptp_rx_data;
+
+ if (dpa_ptp_store_stamp(priv, skb, data, RX, &ptp_rx_data))
+ return;
+
+ dpa_ptp_insert(&tsu->rx_timestamps, &ptp_rx_data);
+}
+
+static uint8_t dpa_get_tx_timestamp(struct dpa_ptp_tsu *ptp_tsu,
+ struct dpa_ptp_ident *ident,
+ struct dpa_ptp_time *ts)
+{
+ struct dpa_ptp_tsu *tsu = ptp_tsu;
+ struct dpa_ptp_time tmp;
+ int flag;
+
+ flag = dpa_ptp_find_and_remove(&tsu->tx_timestamps, ident, &tmp);
+ if (!flag) {
+ ts->sec = tmp.sec;
+ ts->nsec = tmp.nsec;
+ return 0;
+ }
+
+ return -1;
+}
+
+static uint8_t dpa_get_rx_timestamp(struct dpa_ptp_tsu *ptp_tsu,
+ struct dpa_ptp_ident *ident,
+ struct dpa_ptp_time *ts)
+{
+ struct dpa_ptp_tsu *tsu = ptp_tsu;
+ struct dpa_ptp_time tmp;
+ int flag;
+
+ flag = dpa_ptp_find_and_remove(&tsu->rx_timestamps, ident, &tmp);
+ if (!flag) {
+ ts->sec = tmp.sec;
+ ts->nsec = tmp.nsec;
+ return 0;
+ }
+
+ return -1;
+}
+
+static void dpa_set_fiper_alarm(struct dpa_ptp_tsu *tsu,
+ struct dpa_ptp_time *cnt_time)
+{
+ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
+ u64 tmp, fiper;
+
+ if (mac_dev->fm_rtc_disable)
+ mac_dev->fm_rtc_disable(get_fm_handle(tsu->dpa_priv->net_dev));
+
+ /* TMR_FIPER1 will pulse every second after ALARM1 expired */
+ tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec;
+ fiper = NANOSEC_PER_SECOND - DPA_PTP_NOMINAL_FREQ_PERIOD_NS;
+ if (mac_dev->fm_rtc_set_alarm)
+ mac_dev->fm_rtc_set_alarm(get_fm_handle(tsu->dpa_priv->net_dev),
+ 0, tmp);
+ if (mac_dev->fm_rtc_set_fiper)
+ mac_dev->fm_rtc_set_fiper(get_fm_handle(tsu->dpa_priv->net_dev),
+ 0, fiper);
+
+ if (mac_dev->fm_rtc_enable)
+ mac_dev->fm_rtc_enable(get_fm_handle(tsu->dpa_priv->net_dev));
+}
+
+static void dpa_get_curr_cnt(struct dpa_ptp_tsu *tsu,
+ struct dpa_ptp_time *curr_time)
+{
+ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
+ u64 tmp;
+ u32 mod;
+
+ if (mac_dev->fm_rtc_get_cnt)
+ mac_dev->fm_rtc_get_cnt(get_fm_handle(tsu->dpa_priv->net_dev),
+ &tmp);
+
+ mod = do_div(tmp, NANOSEC_PER_SECOND);
+ curr_time->sec = (u32)tmp;
+ curr_time->nsec = mod;
+}
+
+static void dpa_set_1588cnt(struct dpa_ptp_tsu *tsu,
+ struct dpa_ptp_time *cnt_time)
+{
+ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
+ u64 tmp;
+
+ tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec;
+
+ if (mac_dev->fm_rtc_set_cnt)
+ mac_dev->fm_rtc_set_cnt(get_fm_handle(tsu->dpa_priv->net_dev),
+ tmp);
+
+ /* Restart fiper two seconds later */
+ cnt_time->sec += 2;
+ cnt_time->nsec = 0;
+ dpa_set_fiper_alarm(tsu, cnt_time);
+}
+
+static void dpa_get_drift(struct dpa_ptp_tsu *tsu, u32 *addend)
+{
+ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
+ u32 drift;
+
+ if (mac_dev->fm_rtc_get_drift)
+ mac_dev->fm_rtc_get_drift(get_fm_handle(tsu->dpa_priv->net_dev),
+ &drift);
+
+ *addend = drift;
+}
+
+static void dpa_set_drift(struct dpa_ptp_tsu *tsu, u32 addend)
+{
+ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev;
+
+ if (mac_dev->fm_rtc_set_drift)
+ mac_dev->fm_rtc_set_drift(get_fm_handle(tsu->dpa_priv->net_dev),
+ addend);
+}
+
+static void dpa_flush_timestamp(struct dpa_ptp_tsu *tsu)
+{
+ dpa_ptp_reset_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ);
+ dpa_ptp_reset_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ);
+}
+
+int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+ struct dpa_ptp_tsu *tsu = priv->tsu;
+ struct mac_device *mac_dev = priv->mac_dev;
+ struct dpa_ptp_data ptp_data;
+ struct dpa_ptp_data *ptp_data_user;
+ struct dpa_ptp_time act_time;
+ u32 addend;
+ int retval = 0;
+
+ if (!tsu || !tsu->valid)
+ return -ENODEV;
+
+ switch (cmd) {
+ case PTP_ENBL_TXTS_IOCTL:
+ tsu->hwts_tx_en_ioctl = 1;
+ if (mac_dev->fm_rtc_enable)
+ mac_dev->fm_rtc_enable(get_fm_handle(dev));
+ if (mac_dev->ptp_enable)
+ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
+ break;
+ case PTP_DSBL_TXTS_IOCTL:
+ tsu->hwts_tx_en_ioctl = 0;
+ if (mac_dev->fm_rtc_disable)
+ mac_dev->fm_rtc_disable(get_fm_handle(dev));
+ if (mac_dev->ptp_disable)
+ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
+ break;
+ case PTP_ENBL_RXTS_IOCTL:
+ tsu->hwts_rx_en_ioctl = 1;
+ break;
+ case PTP_DSBL_RXTS_IOCTL:
+ tsu->hwts_rx_en_ioctl = 0;
+ break;
+ case PTP_GET_RX_TIMESTAMP:
+ ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data;
+ if (copy_from_user(&ptp_data.ident,
+ &ptp_data_user->ident, sizeof(ptp_data.ident)))
+ return -EINVAL;
+
+ if (dpa_get_rx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts))
+ return -EAGAIN;
+
+ if (copy_to_user((void __user *)&ptp_data_user->ts,
+ &ptp_data.ts, sizeof(ptp_data.ts)))
+ return -EFAULT;
+ break;
+ case PTP_GET_TX_TIMESTAMP:
+ ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data;
+ if (copy_from_user(&ptp_data.ident,
+ &ptp_data_user->ident, sizeof(ptp_data.ident)))
+ return -EINVAL;
+
+ if (dpa_get_tx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts))
+ return -EAGAIN;
+
+ if (copy_to_user((void __user *)&ptp_data_user->ts,
+ &ptp_data.ts, sizeof(ptp_data.ts)))
+ return -EFAULT;
+ break;
+ case PTP_GET_TIME:
+ dpa_get_curr_cnt(tsu, &act_time);
+ if (copy_to_user(ifr->ifr_data, &act_time, sizeof(act_time)))
+ return -EFAULT;
+ break;
+ case PTP_SET_TIME:
+ if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time)))
+ return -EINVAL;
+ dpa_set_1588cnt(tsu, &act_time);
+ break;
+ case PTP_GET_ADJ:
+ dpa_get_drift(tsu, &addend);
+ if (copy_to_user(ifr->ifr_data, &addend, sizeof(addend)))
+ return -EFAULT;
+ break;
+ case PTP_SET_ADJ:
+ if (copy_from_user(&addend, ifr->ifr_data, sizeof(addend)))
+ return -EINVAL;
+ dpa_set_drift(tsu, addend);
+ break;
+ case PTP_SET_FIPER_ALARM:
+ if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time)))
+ return -EINVAL;
+ dpa_set_fiper_alarm(tsu, &act_time);
+ break;
+ case PTP_CLEANUP_TS:
+ dpa_flush_timestamp(tsu);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+int dpa_ptp_init(struct dpa_priv_s *priv)
+{
+ struct dpa_ptp_tsu *tsu;
+
+ /* Allocate memory for PTP structure */
+ tsu = kzalloc(sizeof(struct dpa_ptp_tsu), GFP_KERNEL);
+ if (!tsu)
+ return -ENOMEM;
+
+ tsu->valid = TRUE;
+ tsu->dpa_priv = priv;
+
+ dpa_ptp_init_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ);
+ dpa_ptp_init_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ);
+
+ priv->tsu = tsu;
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_ptp_init);
+
+void dpa_ptp_cleanup(struct dpa_priv_s *priv)
+{
+ struct dpa_ptp_tsu *tsu = priv->tsu;
+
+ tsu->valid = FALSE;
+ vfree(tsu->rx_timestamps.circ_buf.buf);
+ vfree(tsu->tx_timestamps.circ_buf.buf);
+
+ kfree(tsu);
+}
+EXPORT_SYMBOL(dpa_ptp_cleanup);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h
new file mode 100644
index 000000000000..733901689a58
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h
@@ -0,0 +1,138 @@
+/* Copyright (C) 2011 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef __DPAA_1588_H__
+#define __DPAA_1588_H__
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/circ_buf.h>
+#include <linux/fsl_qman.h>
+
+#define DEFAULT_PTP_RX_BUF_SZ 256
+#define DEFAULT_PTP_TX_BUF_SZ 256
+
+/* 1588 private ioctl calls */
+#define PTP_ENBL_TXTS_IOCTL SIOCDEVPRIVATE
+#define PTP_DSBL_TXTS_IOCTL (SIOCDEVPRIVATE + 1)
+#define PTP_ENBL_RXTS_IOCTL (SIOCDEVPRIVATE + 2)
+#define PTP_DSBL_RXTS_IOCTL (SIOCDEVPRIVATE + 3)
+#define PTP_GET_TX_TIMESTAMP (SIOCDEVPRIVATE + 4)
+#define PTP_GET_RX_TIMESTAMP (SIOCDEVPRIVATE + 5)
+#define PTP_SET_TIME (SIOCDEVPRIVATE + 6)
+#define PTP_GET_TIME (SIOCDEVPRIVATE + 7)
+#define PTP_SET_FIPER_ALARM (SIOCDEVPRIVATE + 8)
+#define PTP_SET_ADJ (SIOCDEVPRIVATE + 9)
+#define PTP_GET_ADJ (SIOCDEVPRIVATE + 10)
+#define PTP_CLEANUP_TS (SIOCDEVPRIVATE + 11)
+
+/* PTP V2 message type */
+enum {
+ PTP_MSGTYPE_SYNC = 0x0,
+ PTP_MSGTYPE_DELREQ = 0x1,
+ PTP_MSGTYPE_PDELREQ = 0x2,
+ PTP_MSGTYPE_PDELRESP = 0x3,
+ PTP_MSGTYPE_FLWUP = 0x8,
+ PTP_MSGTYPE_DELRESP = 0x9,
+ PTP_MSGTYPE_PDELRES_FLWUP = 0xA,
+ PTP_MSGTYPE_ANNOUNCE = 0xB,
+ PTP_MSGTYPE_SGNLNG = 0xC,
+ PTP_MSGTYPE_MNGMNT = 0xD,
+};
+
+/* Byte offset of data in the PTP V2 headers */
+#define PTP_OFFS_MSG_TYPE 0
+#define PTP_OFFS_VER_PTP 1
+#define PTP_OFFS_MSG_LEN 2
+#define PTP_OFFS_DOM_NMB 4
+#define PTP_OFFS_FLAGS 6
+#define PTP_OFFS_CORFIELD 8
+#define PTP_OFFS_SRCPRTID 20
+#define PTP_OFFS_SEQ_ID 30
+#define PTP_OFFS_CTRL 32
+#define PTP_OFFS_LOGMEAN 33
+
+#define PTP_IP_OFFS 14
+#define PTP_UDP_OFFS 34
+#define PTP_HEADER_OFFS 42
+#define PTP_MSG_TYPE_OFFS (PTP_HEADER_OFFS + PTP_OFFS_MSG_TYPE)
+#define PTP_SPORT_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SRCPRTID)
+#define PTP_SEQ_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SEQ_ID)
+#define PTP_CTRL_OFFS (PTP_HEADER_OFFS + PTP_OFFS_CTRL)
+
+/* 1588-2008 network protocol enumeration values */
+#define DPA_PTP_PROT_IPV4 1
+#define DPA_PTP_PROT_IPV6 2
+#define DPA_PTP_PROT_802_3 3
+#define DPA_PTP_PROT_DONTCARE 0xFFFF
+
+#define DPA_PTP_SOURCE_PORT_LENGTH 10
+#define DPA_PTP_HEADER_SZE 34
+#define DPA_ETYPE_LEN 2
+#define DPA_VLAN_TAG_LEN 4
+#define NANOSEC_PER_SECOND 1000000000
+
+/* The threshold between the current found one and the oldest one */
+#define TS_ACCUMULATION_THRESHOLD 50
+
+/* Struct needed to identify a timestamp */
+struct dpa_ptp_ident {
+ u8 version;
+ u8 msg_type;
+ u16 netw_prot;
+ u16 seq_id;
+ u8 snd_port_id[DPA_PTP_SOURCE_PORT_LENGTH];
+};
+
+/* Timestamp format in 1588-2008 */
+struct dpa_ptp_time {
+ u64 sec; /* just 48 bit used */
+ u32 nsec;
+};
+
+/* needed for timestamp data over ioctl */
+struct dpa_ptp_data {
+ struct dpa_ptp_ident ident;
+ struct dpa_ptp_time ts;
+};
+
+struct dpa_ptp_circ_buf {
+ struct circ_buf circ_buf;
+ u32 size;
+ spinlock_t ptp_lock;
+};
+
+/* PTP TSU control structure */
+struct dpa_ptp_tsu {
+ struct dpa_priv_s *dpa_priv;
+ bool valid;
+ struct dpa_ptp_circ_buf rx_timestamps;
+ struct dpa_ptp_circ_buf tx_timestamps;
+
+ /* HW timestamping over ioctl enabled flag */
+ int hwts_tx_en_ioctl;
+ int hwts_rx_en_ioctl;
+};
+
+extern int dpa_ptp_init(struct dpa_priv_s *priv);
+extern void dpa_ptp_cleanup(struct dpa_priv_s *priv);
+extern void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv,
+ struct sk_buff *skb, void *data);
+extern void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv,
+ struct sk_buff *skb, void *data);
+extern int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd);
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c
new file mode 100644
index 000000000000..25d9f5f188f1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c
@@ -0,0 +1,180 @@
+/* Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/module.h>
+#include <linux/fsl_qman.h> /* struct qm_mcr_querycgr */
+#include <linux/debugfs.h>
+#include "dpaa_debugfs.h"
+#include "dpaa_eth.h" /* struct dpa_priv_s, dpa_percpu_priv_s, dpa_bp */
+
+#define DPA_DEBUGFS_DESCRIPTION "FSL DPAA Ethernet debugfs entries"
+#define DPA_ETH_DEBUGFS_ROOT "fsl_dpa"
+
+static struct dentry *dpa_debugfs_root;
+
+static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file);
+static ssize_t dpa_loop_write(struct file *f,
+ const char __user *buf, size_t count, loff_t *off);
+
+static const struct file_operations dpa_debugfs_lp_fops = {
+ .open = dpa_debugfs_loop_open,
+ .write = dpa_loop_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dpa_debugfs_loop_show(struct seq_file *file, void *offset)
+{
+ struct dpa_priv_s *priv;
+
+ BUG_ON(offset == NULL);
+
+ priv = netdev_priv((struct net_device *)file->private);
+ seq_printf(file, "%d->%d\n", priv->loop_id, priv->loop_to);
+
+ return 0;
+}
+
+static int user_input_convert(const char __user *user_buf, size_t count,
+ long *val)
+{
+ char buf[12];
+
+ if (count > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ if (kstrtol(buf, 0, val))
+ return -EINVAL;
+ return 0;
+}
+
+static ssize_t dpa_loop_write(struct file *f,
+ const char __user *buf, size_t count, loff_t *off)
+{
+ struct dpa_priv_s *priv;
+ struct net_device *netdev;
+ struct seq_file *sf;
+ int ret;
+ long val;
+
+ ret = user_input_convert(buf, count, &val);
+ if (ret)
+ return ret;
+
+ sf = (struct seq_file *)f->private_data;
+ netdev = (struct net_device *)sf->private;
+ priv = netdev_priv(netdev);
+
+ priv->loop_to = ((val < 0) || (val > 20)) ? -1 : val;
+
+ return count;
+}
+
+static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file)
+{
+ int _errno;
+ const struct net_device *net_dev;
+
+ _errno = single_open(file, dpa_debugfs_loop_show, inode->i_private);
+ if (unlikely(_errno < 0)) {
+ net_dev = (struct net_device *)inode->i_private;
+
+ if (netif_msg_drv((struct dpa_priv_s *)netdev_priv(net_dev)))
+ netdev_err(net_dev, "single_open() = %d\n",
+ _errno);
+ }
+
+ return _errno;
+}
+
+
+int dpa_netdev_debugfs_create(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ static int cnt;
+ char loop_file_name[100];
+
+ if (unlikely(dpa_debugfs_root == NULL)) {
+ pr_err(KBUILD_MODNAME ": %s:%hu:%s(): \t%s\n",
+ KBUILD_BASENAME".c", __LINE__, __func__,
+ "root debugfs missing, possible module ordering issue");
+ return -ENOMEM;
+ }
+
+ sprintf(loop_file_name, "eth%d_loop", ++cnt);
+ priv->debugfs_loop_file = debugfs_create_file(loop_file_name,
+ S_IRUGO,
+ dpa_debugfs_root,
+ net_dev,
+ &dpa_debugfs_lp_fops);
+ if (unlikely(priv->debugfs_loop_file == NULL)) {
+ netdev_err(net_dev, "debugfs_create_file(%s/%s)",
+ dpa_debugfs_root->d_iname,
+ loop_file_name);
+
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void dpa_netdev_debugfs_remove(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+
+ debugfs_remove(priv->debugfs_loop_file);
+}
+
+int __init dpa_debugfs_module_init(void)
+{
+ int _errno = 0;
+
+ pr_info(KBUILD_MODNAME ": " DPA_DEBUGFS_DESCRIPTION "\n");
+
+ dpa_debugfs_root = debugfs_create_dir(DPA_ETH_DEBUGFS_ROOT, NULL);
+
+ if (unlikely(dpa_debugfs_root == NULL)) {
+ _errno = -ENOMEM;
+ pr_err(KBUILD_MODNAME ": %s:%hu:%s():\n",
+ KBUILD_BASENAME".c", __LINE__, __func__);
+ pr_err("\tdebugfs_create_dir(%s/"KBUILD_MODNAME") = %d\n",
+ DPA_ETH_DEBUGFS_ROOT, _errno);
+ }
+
+ return _errno;
+}
+
+void __exit dpa_debugfs_module_exit(void)
+{
+ debugfs_remove(dpa_debugfs_root);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h
new file mode 100644
index 000000000000..63d35427a286
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h
@@ -0,0 +1,43 @@
+/* Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef DPAA_DEBUGFS_H_
+#define DPAA_DEBUGFS_H_
+
+#include <linux/netdevice.h>
+#include <linux/dcache.h> /* struct dentry needed in dpaa_eth.h */
+
+int dpa_netdev_debugfs_create(struct net_device *net_dev);
+void dpa_netdev_debugfs_remove(struct net_device *net_dev);
+int __init dpa_debugfs_module_init(void);
+void __exit dpa_debugfs_module_exit(void);
+
+#endif /* DPAA_DEBUGFS_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
new file mode 100644
index 000000000000..0abef58bfbc3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c
@@ -0,0 +1,1203 @@
+/* Copyright 2008-2013 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/if_arp.h> /* arp_hdr_len() */
+#include <linux/if_vlan.h> /* VLAN_HLEN */
+#include <linux/icmp.h> /* struct icmphdr */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/ipv6.h> /* struct ipv6hdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/net.h> /* net_ratelimit() */
+#include <linux/if_ether.h> /* ETH_P_IP and ETH_P_IPV6 */
+#include <linux/highmem.h>
+#include <linux/percpu.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_bman.h>
+#ifdef CONFIG_SOC_BUS
+#include <linux/sys_soc.h> /* soc_device_match */
+#endif
+
+#include "fsl_fman.h"
+#include "fm_ext.h"
+#include "fm_port_ext.h"
+
+#include "mac.h"
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+#include "dpaa_debugfs.h"
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+#ifdef CONFIG_FSL_DPAA_CEETM
+#include "dpaa_eth_ceetm.h"
+#endif
+
+/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
+ * using trace events only need to #include <trace/events/sched.h>
+ */
+#define CREATE_TRACE_POINTS
+#include "dpaa_eth_trace.h"
+
+#define DPA_NAPI_WEIGHT 64
+
+/* Valid checksum indication */
+#define DPA_CSUM_VALID 0xFFFF
+
+#define DPA_DESCRIPTION "FSL DPAA Ethernet driver"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_AUTHOR("Andy Fleming <afleming@freescale.com>");
+
+MODULE_DESCRIPTION(DPA_DESCRIPTION);
+
+static uint8_t debug = -1;
+module_param(debug, byte, S_IRUGO);
+MODULE_PARM_DESC(debug, "Module/Driver verbosity level");
+
+/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */
+static uint16_t tx_timeout = 1000;
+module_param(tx_timeout, ushort, S_IRUGO);
+MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
+
+static const char rtx[][3] = {
+ [RX] = "RX",
+ [TX] = "TX"
+};
+
+/* BM */
+
+#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8)
+
+static uint8_t dpa_priv_common_bpid;
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+struct net_device *dpa_loop_netdevs[20];
+#endif
+
+#ifdef CONFIG_FSL_DPAA_CEETM
+extern struct Qdisc_ops ceetm_qdisc_ops;
+#endif
+
+#ifdef CONFIG_PM
+
+static int dpaa_suspend(struct device *dev)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+ int err = 0;
+
+ net_dev = dev_get_drvdata(dev);
+
+ if (net_dev->flags & IFF_UP) {
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ if (priv->wol & DPAA_WOL_MAGIC) {
+ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
+ priv->mac_dev->get_mac_handle(mac_dev), true);
+ if (err) {
+ netdev_err(net_dev, "set_wol() = %d\n", err);
+ goto set_wol_failed;
+ }
+ }
+
+ err = fm_port_suspend(mac_dev->port_dev[RX]);
+ if (err) {
+ netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err);
+ goto rx_port_suspend_failed;
+ }
+
+ err = fm_port_suspend(mac_dev->port_dev[TX]);
+ if (err) {
+ netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err);
+ goto tx_port_suspend_failed;
+ }
+ }
+
+ return 0;
+
+tx_port_suspend_failed:
+ fm_port_resume(mac_dev->port_dev[RX]);
+rx_port_suspend_failed:
+ if (priv->wol & DPAA_WOL_MAGIC) {
+ priv->mac_dev->set_wol(mac_dev->port_dev[RX],
+ priv->mac_dev->get_mac_handle(mac_dev), false);
+ }
+set_wol_failed:
+ return err;
+}
+
+static int dpaa_resume(struct device *dev)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+ int err = 0;
+
+ net_dev = dev_get_drvdata(dev);
+
+ if (net_dev->flags & IFF_UP) {
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ err = fm_mac_resume(mac_dev->get_mac_handle(mac_dev));
+ if (err) {
+ netdev_err(net_dev, "fm_mac_resume = %d\n", err);
+ goto resume_failed;
+ }
+
+ err = fm_port_resume(mac_dev->port_dev[TX]);
+ if (err) {
+ netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err);
+ goto resume_failed;
+ }
+
+ err = fm_port_resume(mac_dev->port_dev[RX]);
+ if (err) {
+ netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err);
+ goto resume_failed;
+ }
+
+ if (priv->wol & DPAA_WOL_MAGIC) {
+ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
+ priv->mac_dev->get_mac_handle(mac_dev), false);
+ if (err) {
+ netdev_err(net_dev, "set_wol() = %d\n", err);
+ goto resume_failed;
+ }
+ }
+ }
+
+ return 0;
+
+resume_failed:
+ return err;
+}
+
+static const struct dev_pm_ops dpaa_pm_ops = {
+ .suspend = dpaa_suspend,
+ .resume = dpaa_resume,
+};
+
+#define DPAA_PM_OPS (&dpaa_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define DPAA_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
+/* Checks whether the checksum field in Parse Results array is valid
+ * (equals 0xFFFF) and increments the .cse counter otherwise
+ */
+static inline void
+dpa_csum_validation(const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd)
+{
+ dma_addr_t addr = qm_fd_addr(fd);
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
+ void *frm = phys_to_virt(addr);
+ fm_prs_result_t *parse_result;
+
+ if (unlikely(!frm))
+ return;
+
+ dma_sync_single_for_cpu(dpa_bp->dev, addr, DPA_RX_PRIV_DATA_SIZE +
+ DPA_PARSE_RESULTS_SIZE, DMA_BIDIRECTIONAL);
+
+ parse_result = (fm_prs_result_t *)(frm + DPA_RX_PRIV_DATA_SIZE);
+
+ if (parse_result->cksum != DPA_CSUM_VALID)
+ percpu_priv->rx_errors.cse++;
+}
+
+static void _dpa_rx_error(struct net_device *net_dev,
+ const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ /* limit common, possibly innocuous Rx FIFO Overflow errors'
+ * interference with zero-loss convergence benchmark results.
+ */
+ if (likely(fd->status & FM_FD_STAT_ERR_PHYSICAL))
+ pr_warn_once("fsl-dpa: non-zero error counters in fman statistics (sysfs)\n");
+ else
+ if (netif_msg_hw(priv) && net_ratelimit())
+ netdev_dbg(net_dev, "Err FD status = 0x%08x\n",
+ fd->status & FM_FD_STAT_RX_ERRORS);
+#ifdef CONFIG_FSL_DPAA_HOOKS
+ if (dpaa_eth_hooks.rx_error &&
+ dpaa_eth_hooks.rx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
+ /* it's up to the hook to perform resource cleanup */
+ return;
+#endif
+ percpu_priv->stats.rx_errors++;
+
+ if (fd->status & FM_PORT_FRM_ERR_DMA)
+ percpu_priv->rx_errors.dme++;
+ if (fd->status & FM_PORT_FRM_ERR_PHYSICAL)
+ percpu_priv->rx_errors.fpe++;
+ if (fd->status & FM_PORT_FRM_ERR_SIZE)
+ percpu_priv->rx_errors.fse++;
+ if (fd->status & FM_PORT_FRM_ERR_PRS_HDR_ERR)
+ percpu_priv->rx_errors.phe++;
+ if (fd->status & FM_FD_STAT_L4CV)
+ dpa_csum_validation(priv, percpu_priv, fd);
+
+ dpa_fd_release(net_dev, fd);
+}
+
+static void _dpa_tx_error(struct net_device *net_dev,
+ const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ struct sk_buff *skb;
+
+ if (netif_msg_hw(priv) && net_ratelimit())
+ netdev_warn(net_dev, "FD status = 0x%08x\n",
+ fd->status & FM_FD_STAT_TX_ERRORS);
+#ifdef CONFIG_FSL_DPAA_HOOKS
+ if (dpaa_eth_hooks.tx_error &&
+ dpaa_eth_hooks.tx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
+ /* now the hook must ensure proper cleanup */
+ return;
+#endif
+ percpu_priv->stats.tx_errors++;
+
+ /* If we intended the buffers from this frame to go into the bpools
+ * when the FMan transmit was done, we need to put it in manually.
+ */
+ if (fd->bpid != 0xff) {
+ dpa_fd_release(net_dev, fd);
+ return;
+ }
+
+ skb = _dpa_cleanup_tx_fd(priv, fd);
+ dev_kfree_skb(skb);
+}
+
+/* Helper function to factor out frame validation logic on all Rx paths. Its
+ * purpose is to extract from the Parse Results structure information about
+ * the integrity of the frame, its checksum, the length of the parsed headers
+ * and whether the frame is suitable for GRO.
+ *
+ * Assumes no parser errors, since any error frame is dropped before this
+ * function is called.
+ *
+ * @skb will have its ip_summed field overwritten;
+ * @use_gro will only be written with 0, if the frame is definitely not
+ * GRO-able; otherwise, it will be left unchanged;
+ * @hdr_size will be written with a safe value, at least the size of the
+ * headers' length.
+ */
+void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results,
+ const struct qm_fd *fd,
+ struct sk_buff *skb, int *use_gro)
+{
+ if (fd->status & FM_FD_STAT_L4CV) {
+ /* The parser has run and performed L4 checksum validation.
+ * We know there were no parser errors (and implicitly no
+ * L4 csum error), otherwise we wouldn't be here.
+ */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ /* Don't go through GRO for certain types of traffic that
+ * we know are not GRO-able, such as dgram-based protocols.
+ * In the worst-case scenarios, such as small-pkt terminating
+ * UDP, the extra GRO processing would be overkill.
+ *
+ * The only protocol the Parser supports that is also GRO-able
+ * is currently TCP.
+ */
+ if (!fm_l4_frame_is_tcp(parse_results))
+ *use_gro = 0;
+
+ return;
+ }
+
+ /* We're here because either the parser didn't run or the L4 checksum
+ * was not verified. This may include the case of a UDP frame with
+ * checksum zero or an L4 proto other than TCP/UDP
+ */
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Bypass GRO for unknown traffic or if no PCDs are applied */
+ *use_gro = 0;
+}
+
+int dpaa_eth_poll(struct napi_struct *napi, int budget)
+{
+ struct dpa_napi_portal *np =
+ container_of(napi, struct dpa_napi_portal, napi);
+
+ int cleaned = qman_p_poll_dqrr(np->p, budget);
+
+ if (cleaned < budget) {
+ int tmp;
+ napi_complete(napi);
+ tmp = qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
+ DPA_BUG_ON(tmp);
+ }
+
+ return cleaned;
+}
+EXPORT_SYMBOL(dpaa_eth_poll);
+
+static void __hot _dpa_tx_conf(struct net_device *net_dev,
+ const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ struct sk_buff *skb;
+
+ /* do we need the timestamp for the error frames? */
+
+ if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) {
+ if (netif_msg_hw(priv) && net_ratelimit())
+ netdev_warn(net_dev, "FD status = 0x%08x\n",
+ fd->status & FM_FD_STAT_TX_ERRORS);
+
+ percpu_priv->stats.tx_errors++;
+ }
+
+ /* hopefully we need not get the timestamp before the hook */
+#ifdef CONFIG_FSL_DPAA_HOOKS
+ if (dpaa_eth_hooks.tx_confirm && dpaa_eth_hooks.tx_confirm(net_dev,
+ fd, fqid) == DPAA_ETH_STOLEN)
+ /* it's the hook that must now perform cleanup */
+ return;
+#endif
+ /* This might not perfectly reflect the reality, if the core dequeuing
+ * the Tx confirmation is different from the one that did the enqueue,
+ * but at least it'll show up in the total count.
+ */
+ percpu_priv->tx_confirm++;
+
+ skb = _dpa_cleanup_tx_fd(priv, fd);
+
+ dev_kfree_skb(skb);
+}
+
+enum qman_cb_dqrr_result
+priv_rx_error_dqrr(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct dpa_percpu_priv_s *percpu_priv;
+ int *count_ptr;
+
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
+ priv = netdev_priv(net_dev);
+
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+ count_ptr = raw_cpu_ptr(priv->dpa_bp->percpu_count);
+
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
+ return qman_cb_dqrr_stop;
+
+ if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp, count_ptr)))
+ /* Unable to refill the buffer pool due to insufficient
+ * system memory. Just release the frame back into the pool,
+ * otherwise we'll soon end up with an empty buffer pool.
+ */
+ dpa_fd_release(net_dev, &dq->fd);
+ else
+ _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
+
+ return qman_cb_dqrr_consume;
+}
+
+
+enum qman_cb_dqrr_result __hot
+priv_rx_default_dqrr(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct dpa_percpu_priv_s *percpu_priv;
+ int *count_ptr;
+ struct dpa_bp *dpa_bp;
+
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
+ priv = netdev_priv(net_dev);
+ dpa_bp = priv->dpa_bp;
+
+ /* Trace the Rx fd */
+ trace_dpa_rx_fd(net_dev, fq, &dq->fd);
+
+ /* IRQ handler, non-migratable; safe to use raw_cpu_ptr here */
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+ count_ptr = raw_cpu_ptr(dpa_bp->percpu_count);
+
+ if (unlikely(dpaa_eth_napi_schedule(percpu_priv, portal)))
+ return qman_cb_dqrr_stop;
+
+ /* Vale of plenty: make sure we didn't run out of buffers */
+
+ if (unlikely(dpaa_eth_refill_bpools(dpa_bp, count_ptr)))
+ /* Unable to refill the buffer pool due to insufficient
+ * system memory. Just release the frame back into the pool,
+ * otherwise we'll soon end up with an empty buffer pool.
+ */
+ dpa_fd_release(net_dev, &dq->fd);
+ else
+ _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid,
+ count_ptr);
+
+ return qman_cb_dqrr_consume;
+}
+
+enum qman_cb_dqrr_result
+priv_tx_conf_error_dqrr(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct dpa_percpu_priv_s *percpu_priv;
+
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
+ priv = netdev_priv(net_dev);
+
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
+ return qman_cb_dqrr_stop;
+
+ _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
+
+ return qman_cb_dqrr_consume;
+}
+
+enum qman_cb_dqrr_result __hot
+priv_tx_conf_default_dqrr(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+ struct dpa_percpu_priv_s *percpu_priv;
+
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
+ priv = netdev_priv(net_dev);
+
+ /* Trace the fd */
+ trace_dpa_tx_conf_fd(net_dev, fq, &dq->fd);
+
+ /* Non-migratable context, safe to use raw_cpu_ptr */
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+
+ if (dpaa_eth_napi_schedule(percpu_priv, portal))
+ return qman_cb_dqrr_stop;
+
+ _dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
+
+ return qman_cb_dqrr_consume;
+}
+
+void priv_ern(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_mr_entry *msg)
+{
+ struct net_device *net_dev;
+ const struct dpa_priv_s *priv;
+ struct sk_buff *skb;
+ struct dpa_percpu_priv_s *percpu_priv;
+ struct qm_fd fd = msg->ern.fd;
+
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
+ priv = netdev_priv(net_dev);
+ /* Non-migratable context, safe to use raw_cpu_ptr */
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+
+ percpu_priv->stats.tx_dropped++;
+ percpu_priv->stats.tx_fifo_errors++;
+ count_ern(percpu_priv, msg);
+
+ /* If we intended this buffer to go into the pool
+ * when the FM was done, we need to put it in
+ * manually.
+ */
+ if (msg->ern.fd.bpid != 0xff) {
+ dpa_fd_release(net_dev, &fd);
+ return;
+ }
+
+ skb = _dpa_cleanup_tx_fd(priv, &fd);
+ dev_kfree_skb_any(skb);
+}
+
+const struct dpa_fq_cbs_t private_fq_cbs = {
+ .rx_defq = { .cb = { .dqrr = priv_rx_default_dqrr } },
+ .tx_defq = { .cb = { .dqrr = priv_tx_conf_default_dqrr } },
+ .rx_errq = { .cb = { .dqrr = priv_rx_error_dqrr } },
+ .tx_errq = { .cb = { .dqrr = priv_tx_conf_error_dqrr } },
+ .egress_ern = { .cb = { .ern = priv_ern } }
+};
+EXPORT_SYMBOL(private_fq_cbs);
+
+static void dpaa_eth_napi_enable(struct dpa_priv_s *priv)
+{
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, j;
+
+ for_each_possible_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+
+ for (j = 0; j < qman_portal_max; j++)
+ napi_enable(&percpu_priv->np[j].napi);
+ }
+}
+
+static void dpaa_eth_napi_disable(struct dpa_priv_s *priv)
+{
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, j;
+
+ for_each_possible_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+
+ for (j = 0; j < qman_portal_max; j++)
+ napi_disable(&percpu_priv->np[j].napi);
+ }
+}
+
+static int __cold dpa_eth_priv_start(struct net_device *net_dev)
+{
+ int err;
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+
+ dpaa_eth_napi_enable(priv);
+
+ err = dpa_start(net_dev);
+ if (err < 0)
+ dpaa_eth_napi_disable(priv);
+
+ return err;
+}
+
+
+
+static int __cold dpa_eth_priv_stop(struct net_device *net_dev)
+{
+ int _errno;
+ struct dpa_priv_s *priv;
+
+ _errno = dpa_stop(net_dev);
+ /* Allow NAPI to consume any frame still in the Rx/TxConfirm
+ * ingress queues. This is to avoid a race between the current
+ * context and ksoftirqd which could leave NAPI disabled while
+ * in fact there's still Rx traffic to be processed.
+ */
+ usleep_range(5000, 10000);
+
+ priv = netdev_priv(net_dev);
+ dpaa_eth_napi_disable(priv);
+
+ return _errno;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void dpaa_eth_poll_controller(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv =
+ raw_cpu_ptr(priv->percpu_priv);
+ struct qman_portal *p;
+ const struct qman_portal_config *pc;
+ struct dpa_napi_portal *np;
+
+ p = (struct qman_portal *)qman_get_affine_portal(smp_processor_id());
+ pc = qman_p_get_portal_config(p);
+ np = &percpu_priv->np[pc->index];
+
+ qman_p_irqsource_remove(np->p, QM_PIRQ_DQRI);
+ qman_p_poll_dqrr(np->p, np->napi.weight);
+ qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
+}
+#endif
+
+static const struct net_device_ops dpa_private_ops = {
+ .ndo_open = dpa_eth_priv_start,
+ .ndo_start_xmit = dpa_tx,
+ .ndo_stop = dpa_eth_priv_stop,
+ .ndo_tx_timeout = dpa_timeout,
+ .ndo_get_stats64 = dpa_get_stats64,
+ .ndo_set_mac_address = dpa_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_FMAN_PFC
+ .ndo_select_queue = dpa_select_queue,
+#endif
+ .ndo_set_rx_mode = dpa_set_rx_mode,
+ .ndo_init = dpa_ndo_init,
+ .ndo_set_features = dpa_set_features,
+ .ndo_fix_features = dpa_fix_features,
+ .ndo_do_ioctl = dpa_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = dpaa_eth_poll_controller,
+#endif
+};
+
+static int dpa_private_napi_add(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, cpu;
+
+ for_each_possible_cpu(cpu) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
+
+ percpu_priv->np = devm_kzalloc(net_dev->dev.parent,
+ qman_portal_max * sizeof(struct dpa_napi_portal),
+ GFP_KERNEL);
+
+ if (unlikely(percpu_priv->np == NULL)) {
+ dev_err(net_dev->dev.parent, "devm_kzalloc() failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < qman_portal_max; i++)
+ netif_napi_add(net_dev, &percpu_priv->np[i].napi,
+ dpaa_eth_poll, DPA_NAPI_WEIGHT);
+ }
+
+ return 0;
+}
+
+void dpa_private_napi_del(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv;
+ int i, cpu;
+
+ for_each_possible_cpu(cpu) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu);
+
+ if (percpu_priv->np) {
+ for (i = 0; i < qman_portal_max; i++)
+ netif_napi_del(&percpu_priv->np[i].napi);
+
+ devm_kfree(net_dev->dev.parent, percpu_priv->np);
+ }
+ }
+}
+EXPORT_SYMBOL(dpa_private_napi_del);
+
+static int dpa_private_netdev_init(struct net_device *net_dev)
+{
+ int i;
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct dpa_percpu_priv_s *percpu_priv;
+ const uint8_t *mac_addr;
+
+ /* Although we access another CPU's private data here
+ * we do it at initialization so it is safe
+ */
+ for_each_possible_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+ percpu_priv->net_dev = net_dev;
+ }
+
+ net_dev->netdev_ops = &dpa_private_ops;
+ mac_addr = priv->mac_dev->addr;
+
+ net_dev->mem_start = priv->mac_dev->res->start;
+ net_dev->mem_end = priv->mac_dev->res->end;
+
+ /* Configure the maximum MTU according to the FMan's MAXFRM */
+ net_dev->min_mtu = ETH_MIN_MTU;
+ net_dev->max_mtu = dpa_get_max_mtu();
+
+ net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_LLTX);
+
+ /* Advertise S/G and HIGHDMA support for private interfaces */
+ net_dev->hw_features |= NETIF_F_SG | NETIF_F_HIGHDMA;
+ /* Recent kernels enable GSO automatically, if
+ * we declare NETIF_F_SG. For conformity, we'll
+ * still declare GSO explicitly.
+ */
+ net_dev->features |= NETIF_F_GSO;
+
+ /* Advertise GRO support */
+ net_dev->features |= NETIF_F_GRO;
+
+ /* Advertise NETIF_F_HW_ACCEL_MQ to avoid Tx timeout warnings */
+ net_dev->features |= NETIF_F_HW_ACCEL_MQ;
+
+ return dpa_netdev_init(net_dev, mac_addr, tx_timeout);
+}
+
+static struct dpa_bp * __cold
+dpa_priv_bp_probe(struct device *dev)
+{
+ struct dpa_bp *dpa_bp;
+
+ dpa_bp = devm_kzalloc(dev, sizeof(*dpa_bp), GFP_KERNEL);
+ if (unlikely(dpa_bp == NULL)) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dpa_bp->percpu_count = devm_alloc_percpu(dev, *dpa_bp->percpu_count);
+ dpa_bp->target_count = CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT;
+
+ dpa_bp->seed_cb = dpa_bp_priv_seed;
+ dpa_bp->free_buf_cb = _dpa_bp_free_pf;
+
+ return dpa_bp;
+}
+
+/* Place all ingress FQs (Rx Default, Rx Error, PCD FQs) in a dedicated CGR.
+ * We won't be sending congestion notifications to FMan; for now, we just use
+ * this CGR to generate enqueue rejections to FMan in order to drop the frames
+ * before they reach our ingress queues and eat up memory.
+ */
+static int dpaa_eth_priv_ingress_cgr_init(struct dpa_priv_s *priv)
+{
+ struct qm_mcc_initcgr initcgr;
+ u32 cs_th;
+ int err;
+
+ err = qman_alloc_cgrid(&priv->ingress_cgr.cgrid);
+ if (err < 0) {
+ pr_err("Error %d allocating CGR ID\n", err);
+ goto out_error;
+ }
+
+ /* Enable CS TD, but disable Congestion State Change Notifications. */
+ initcgr.we_mask = QM_CGR_WE_CS_THRES;
+ initcgr.cgr.cscn_en = QM_CGR_EN;
+ cs_th = CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD;
+ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
+
+ initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+ initcgr.cgr.cstd_en = QM_CGR_EN;
+
+ /* This is actually a hack, because this CGR will be associated with
+ * our affine SWP. However, we'll place our ingress FQs in it.
+ */
+ err = qman_create_cgr(&priv->ingress_cgr, QMAN_CGR_FLAG_USE_INIT,
+ &initcgr);
+ if (err < 0) {
+ pr_err("Error %d creating ingress CGR with ID %d\n", err,
+ priv->ingress_cgr.cgrid);
+ qman_release_cgrid(priv->ingress_cgr.cgrid);
+ goto out_error;
+ }
+ pr_debug("Created ingress CGR %d for netdev with hwaddr %pM\n",
+ priv->ingress_cgr.cgrid, priv->mac_dev->addr);
+
+ /* struct qman_cgr allows special cgrid values (i.e. outside the 0..255
+ * range), but we have no common initialization path between the
+ * different variants of the DPAA Eth driver, so we do it here rather
+ * than modifying every other variant than "private Eth".
+ */
+ priv->use_ingress_cgr = true;
+
+out_error:
+ return err;
+}
+
+static int dpa_priv_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
+ size_t count)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ int i;
+
+ if (netif_msg_probe(priv))
+ dev_dbg(net_dev->dev.parent,
+ "Using private BM buffer pools\n");
+
+ priv->bp_count = count;
+
+ for (i = 0; i < count; i++) {
+ int err;
+ err = dpa_bp_alloc(&dpa_bp[i], net_dev->dev.parent);
+ if (err < 0) {
+ dpa_bp_free(priv);
+ priv->dpa_bp = NULL;
+ return err;
+ }
+
+ priv->dpa_bp = &dpa_bp[i];
+ }
+
+ dpa_priv_common_bpid = priv->dpa_bp->bpid;
+ return 0;
+}
+
+static const struct of_device_id dpa_match[];
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static int dpa_new_loop_id(void)
+{
+ static int if_id;
+
+ return if_id++;
+}
+#endif
+
+static int
+dpaa_eth_priv_probe(struct platform_device *_of_dev)
+{
+ int err = 0, i, channel;
+ struct device *dev;
+ struct device_node *dpa_node;
+ struct dpa_bp *dpa_bp;
+ size_t count = 1;
+ struct net_device *net_dev = NULL;
+ struct dpa_priv_s *priv = NULL;
+ struct dpa_percpu_priv_s *percpu_priv;
+ struct fm_port_fqs port_fqs;
+ struct dpa_buffer_layout_s *buf_layout = NULL;
+ struct mac_device *mac_dev;
+
+ dev = &_of_dev->dev;
+
+ dpa_node = dev->of_node;
+
+ if (!of_device_is_available(dpa_node))
+ return -ENODEV;
+
+ /* Get the buffer pools assigned to this interface;
+ * run only once the default pool probing code
+ */
+ dpa_bp = (dpa_bpid2pool(dpa_priv_common_bpid)) ? :
+ dpa_priv_bp_probe(dev);
+ if (IS_ERR(dpa_bp))
+ return PTR_ERR(dpa_bp);
+
+ /* Allocate this early, so we can store relevant information in
+ * the private area (needed by 1588 code in dpa_mac_probe)
+ */
+ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES);
+ if (!net_dev) {
+ dev_err(dev, "alloc_etherdev_mq() failed\n");
+ goto alloc_etherdev_mq_failed;
+ }
+
+ /* Do this here, so we can be verbose early */
+ SET_NETDEV_DEV(net_dev, dev);
+ dev_set_drvdata(dev, net_dev);
+
+ priv = netdev_priv(net_dev);
+ priv->net_dev = net_dev;
+ strcpy(priv->if_type, "private");
+
+ priv->msg_enable = netif_msg_init(debug, -1);
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ priv->loop_id = dpa_new_loop_id();
+ priv->loop_to = -1; /* disabled by default */
+ dpa_loop_netdevs[priv->loop_id] = net_dev;
+#endif
+
+ mac_dev = dpa_mac_probe(_of_dev);
+ if (IS_ERR(mac_dev) || !mac_dev) {
+ err = PTR_ERR(mac_dev);
+ goto mac_probe_failed;
+ }
+
+ /* We have physical ports, so we need to establish
+ * the buffer layout.
+ */
+ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout),
+ GFP_KERNEL);
+ if (!buf_layout) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ goto alloc_failed;
+ }
+ dpa_set_buffers_layout(mac_dev, buf_layout);
+
+ /* For private ports, need to compute the size of the default
+ * buffer pool, based on FMan port buffer layout;also update
+ * the maximum buffer size for private ports if necessary
+ */
+ dpa_bp->size = dpa_bp_size(&buf_layout[RX]);
+
+#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
+ /* We only want to use jumbo frame optimization if we actually have
+ * L2 MAX FRM set for jumbo frames as well.
+ */
+ if(fm_get_max_frm() < 9600)
+ dev_warn(dev,
+ "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n");
+#endif
+
+ INIT_LIST_HEAD(&priv->dpa_fq_list);
+
+ memset(&port_fqs, 0, sizeof(port_fqs));
+
+ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, &port_fqs, true, RX);
+ if (!err)
+ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list,
+ &port_fqs, true, TX);
+
+ if (err < 0)
+ goto fq_probe_failed;
+
+ /* bp init */
+
+ err = dpa_priv_bp_create(net_dev, dpa_bp, count);
+
+ if (err < 0)
+ goto bp_create_failed;
+
+ priv->mac_dev = mac_dev;
+
+ channel = dpa_get_channel();
+
+ if (channel < 0) {
+ err = channel;
+ goto get_channel_failed;
+ }
+
+ priv->channel = (uint16_t)channel;
+ dpaa_eth_add_channel(priv->channel);
+
+ dpa_fq_setup(priv, &private_fq_cbs, priv->mac_dev->port_dev[TX]);
+
+ /* Create a congestion group for this netdev, with
+ * dynamically-allocated CGR ID.
+ * Must be executed after probing the MAC, but before
+ * assigning the egress FQs to the CGRs.
+ */
+ err = dpaa_eth_cgr_init(priv);
+ if (err < 0) {
+ dev_err(dev, "Error initializing CGR\n");
+ goto tx_cgr_init_failed;
+ }
+ err = dpaa_eth_priv_ingress_cgr_init(priv);
+ if (err < 0) {
+ dev_err(dev, "Error initializing ingress CGR\n");
+ goto rx_cgr_init_failed;
+ }
+
+ /* Add the FQs to the interface, and make them active */
+ err = dpa_fqs_init(dev, &priv->dpa_fq_list, false);
+ if (err < 0)
+ goto fq_alloc_failed;
+
+ priv->buf_layout = buf_layout;
+ priv->tx_headroom = dpa_get_headroom(&priv->buf_layout[TX]);
+ priv->rx_headroom = dpa_get_headroom(&priv->buf_layout[RX]);
+
+ /* All real interfaces need their ports initialized */
+ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs,
+ buf_layout, dev);
+
+#ifdef CONFIG_FMAN_PFC
+ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
+ err = fm_port_set_pfc_priorities_mapping_to_qman_wq(
+ mac_dev->port_dev[TX], i, i);
+ if (unlikely(err != 0)) {
+ dev_err(dev, "Error maping PFC %u to WQ %u\n", i, i);
+ goto pfc_mapping_failed;
+ }
+ }
+#endif
+
+ priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv);
+
+ if (priv->percpu_priv == NULL) {
+ dev_err(dev, "devm_alloc_percpu() failed\n");
+ err = -ENOMEM;
+ goto alloc_percpu_failed;
+ }
+ for_each_possible_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+ memset(percpu_priv, 0, sizeof(*percpu_priv));
+ }
+
+ /* Initialize NAPI */
+ err = dpa_private_napi_add(net_dev);
+
+ if (err < 0)
+ goto napi_add_failed;
+
+ err = dpa_private_netdev_init(net_dev);
+
+ if (err < 0)
+ goto netdev_init_failed;
+
+ dpaa_eth_sysfs_init(&net_dev->dev);
+
+#ifdef CONFIG_PM
+ device_set_wakeup_capable(dev, true);
+#endif
+
+ pr_info("fsl_dpa: Probed interface %s\n", net_dev->name);
+
+ return 0;
+
+netdev_init_failed:
+napi_add_failed:
+ dpa_private_napi_del(net_dev);
+alloc_percpu_failed:
+#ifdef CONFIG_FMAN_PFC
+pfc_mapping_failed:
+#endif
+ dpa_fq_free(dev, &priv->dpa_fq_list);
+fq_alloc_failed:
+ qman_delete_cgr_safe(&priv->ingress_cgr);
+ qman_release_cgrid(priv->ingress_cgr.cgrid);
+rx_cgr_init_failed:
+ qman_delete_cgr_safe(&priv->cgr_data.cgr);
+ qman_release_cgrid(priv->cgr_data.cgr.cgrid);
+tx_cgr_init_failed:
+get_channel_failed:
+ dpa_bp_free(priv);
+bp_create_failed:
+fq_probe_failed:
+alloc_failed:
+mac_probe_failed:
+ dev_set_drvdata(dev, NULL);
+ free_netdev(net_dev);
+alloc_etherdev_mq_failed:
+ if (atomic_read(&dpa_bp->refs) == 0)
+ devm_kfree(dev, dpa_bp);
+
+ return err;
+}
+
+static const struct of_device_id dpa_match[] = {
+ {
+ .compatible = "fsl,dpa-ethernet"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dpa_match);
+
+static struct platform_driver dpa_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = dpa_match,
+ .owner = THIS_MODULE,
+ .pm = DPAA_PM_OPS,
+ },
+ .probe = dpaa_eth_priv_probe,
+ .remove = dpa_remove
+};
+
+static int __init __cold dpa_load(void)
+{
+ int _errno;
+
+ pr_info(DPA_DESCRIPTION "\n");
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ dpa_debugfs_module_init();
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+
+ /* initialise dpaa_eth mirror values */
+ dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
+ dpa_max_frm = fm_get_max_frm();
+ dpa_num_cpus = num_possible_cpus();
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs));
+#endif
+
+ _errno = platform_driver_register(&dpa_driver);
+ if (unlikely(_errno < 0)) {
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__, _errno);
+ }
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+
+#ifdef CONFIG_FSL_DPAA_CEETM
+ _errno = register_qdisc(&ceetm_qdisc_ops);
+ if (unlikely(_errno))
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): register_qdisc() = %d\n",
+ KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
+#endif
+
+ return _errno;
+}
+module_init(dpa_load);
+
+static void __exit __cold dpa_unload(void)
+{
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME".c", __func__);
+
+#ifdef CONFIG_FSL_DPAA_CEETM
+ unregister_qdisc(&ceetm_qdisc_ops);
+#endif
+
+ platform_driver_unregister(&dpa_driver);
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ dpa_debugfs_module_exit();
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+
+ /* Only one channel is used and needs to be relased after all
+ * interfaces are removed
+ */
+ dpa_release_channel();
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+}
+module_exit(dpa_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
new file mode 100644
index 000000000000..b06cb57b89a7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
@@ -0,0 +1,673 @@
+/* Copyright 2008-2012 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DPA_H
+#define __DPA_H
+
+#include <linux/netdevice.h>
+#include <linux/fsl_qman.h> /* struct qman_fq */
+
+#include "fm_ext.h"
+#include "dpaa_eth_trace.h"
+
+extern int dpa_rx_extra_headroom;
+extern int dpa_max_frm;
+extern int dpa_num_cpus;
+
+#define dpa_get_rx_extra_headroom() dpa_rx_extra_headroom
+#define dpa_get_max_frm() dpa_max_frm
+
+#define dpa_get_max_mtu() \
+ (dpa_get_max_frm() - (VLAN_ETH_HLEN + ETH_FCS_LEN))
+
+#define __hot
+
+/* Simple enum of FQ types - used for array indexing */
+enum port_type {RX, TX};
+
+/* TODO: This structure should be renamed & moved to the FMD wrapper */
+struct dpa_buffer_layout_s {
+ uint16_t priv_data_size;
+ bool parse_results;
+ bool time_stamp;
+ bool hash_results;
+ uint8_t manip_extra_space;
+ uint16_t data_align;
+};
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define DPA_BUG_ON(cond) BUG_ON(cond)
+#else
+#define DPA_BUG_ON(cond)
+#endif
+
+#define DPA_TX_PRIV_DATA_SIZE 16
+#define DPA_PARSE_RESULTS_SIZE sizeof(fm_prs_result_t)
+#define DPA_TIME_STAMP_SIZE 8
+#define DPA_HASH_RESULTS_SIZE 8
+#define DPA_RX_PRIV_DATA_SIZE (DPA_TX_PRIV_DATA_SIZE + \
+ dpa_get_rx_extra_headroom())
+
+#define FM_FD_STAT_RX_ERRORS \
+ (FM_PORT_FRM_ERR_DMA | FM_PORT_FRM_ERR_PHYSICAL | \
+ FM_PORT_FRM_ERR_SIZE | FM_PORT_FRM_ERR_CLS_DISCARD | \
+ FM_PORT_FRM_ERR_EXTRACTION | FM_PORT_FRM_ERR_NO_SCHEME | \
+ FM_PORT_FRM_ERR_ILL_PLCR | FM_PORT_FRM_ERR_PRS_TIMEOUT | \
+ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | FM_PORT_FRM_ERR_PRS_HDR_ERR)
+
+#define FM_FD_STAT_TX_ERRORS \
+ (FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT | \
+ FM_PORT_FRM_ERR_LENGTH | FM_PORT_FRM_ERR_DMA)
+
+#ifndef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
+/* The raw buffer size must be cacheline aligned.
+ * Normally we use 2K buffers.
+ */
+#define DPA_BP_RAW_SIZE 2048
+#else
+/* For jumbo frame optimizations, use buffers large enough to accommodate
+ * 9.6K frames, FD maximum offset, skb sh_info overhead and some extra
+ * space to account for further alignments.
+ */
+#define DPA_MAX_FRM_SIZE 9600
+#ifndef FM_ERRATUM_A050385
+#define DPA_BP_RAW_SIZE \
+ ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+ sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1))
+#else /* FM_ERRATUM_A050385 */
+#define DPA_BP_RAW_SIZE ((unlikely(fm_has_errata_a050385())) ? 2048 : \
+ ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \
+ sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1)))
+#endif /* FM_ERRATUM_A050385 */
+#endif /* CONFIG_FSL_DPAA_ETH_JUMBO_FRAME */
+
+/* This is what FMan is ever allowed to use.
+ * FMan-DMA requires 16-byte alignment for Rx buffers, but SKB_DATA_ALIGN is
+ * even stronger (SMP_CACHE_BYTES-aligned), so we just get away with that,
+ * via SKB_WITH_OVERHEAD(). We can't rely on netdev_alloc_frag() giving us
+ * half-page-aligned buffers (can we?), so we reserve some more space
+ * for start-of-buffer alignment.
+ */
+#define dpa_bp_size(buffer_layout) (SKB_WITH_OVERHEAD(DPA_BP_RAW_SIZE) - \
+ SMP_CACHE_BYTES)
+/* We must ensure that skb_shinfo is always cacheline-aligned. */
+#define DPA_SKB_SIZE(size) ((size) & ~(SMP_CACHE_BYTES - 1))
+
+/* Maximum size of a buffer for which recycling is allowed.
+ * We need an upper limit such that forwarded skbs that get reallocated on Tx
+ * aren't allowed to grow unboundedly. On the other hand, we need to make sure
+ * that skbs allocated by us will not fail to be recycled due to their size.
+ *
+ * For a requested size, the kernel allocator provides the next power of two
+ * sized block, which the stack will use as is, regardless of the actual size
+ * it required; since we must accommodate at most 9.6K buffers (L2 maximum
+ * supported frame size), set the recycling upper limit to 16K.
+ */
+#define DPA_RECYCLE_MAX_SIZE 16384
+
+#if defined(CONFIG_FSL_SDK_FMAN_TEST)
+/*TODO: temporary for fman pcd testing */
+#define FMAN_PCD_TESTS_MAX_NUM_RANGES 20
+#endif
+
+#define DPAA_ETH_FQ_DELTA 0x10000
+
+#define DPAA_ETH_PCD_FQ_BASE(device_addr) \
+ (((device_addr) & 0x1fffff) >> 6)
+
+#define DPAA_ETH_PCD_FQ_HI_PRIO_BASE(device_addr) \
+ (DPAA_ETH_FQ_DELTA + DPAA_ETH_PCD_FQ_BASE(device_addr))
+
+/* Largest value that the FQD's OAL field can hold.
+ * This is DPAA-1.x specific.
+ * TODO: This rather belongs in fsl_qman.h
+ */
+#define FSL_QMAN_MAX_OAL 127
+
+/* Maximum offset value for a contig or sg FD (represented on 9 bits) */
+#define DPA_MAX_FD_OFFSET ((1 << 9) - 1)
+
+/* Default alignment for start of data in an Rx FD */
+#define DPA_FD_DATA_ALIGNMENT 16
+
+/* Values for the L3R field of the FM Parse Results
+ */
+/* L3 Type field: First IP Present IPv4 */
+#define FM_L3_PARSE_RESULT_IPV4 0x8000
+/* L3 Type field: First IP Present IPv6 */
+#define FM_L3_PARSE_RESULT_IPV6 0x4000
+
+/* Values for the L4R field of the FM Parse Results
+ * See $8.8.4.7.20 - L4 HXS - L4 Results from DPAA-Rev2 Reference Manual.
+ */
+/* L4 Type field: UDP */
+#define FM_L4_PARSE_RESULT_UDP 0x40
+/* L4 Type field: TCP */
+#define FM_L4_PARSE_RESULT_TCP 0x20
+/* FD status field indicating whether the FM Parser has attempted to validate
+ * the L4 csum of the frame.
+ * Note that having this bit set doesn't necessarily imply that the checksum
+ * is valid. One would have to check the parse results to find that out.
+ */
+#define FM_FD_STAT_L4CV 0x00000004
+
+
+#define FM_FD_STAT_ERR_PHYSICAL FM_PORT_FRM_ERR_PHYSICAL
+
+/* Check if the parsed frame was found to be a TCP segment.
+ *
+ * @parse_result_ptr must be of type (fm_prs_result_t *).
+ */
+#define fm_l4_frame_is_tcp(parse_result_ptr) \
+ ((parse_result_ptr)->l4r & FM_L4_PARSE_RESULT_TCP)
+
+/* number of Tx queues to FMan */
+#ifdef CONFIG_FMAN_PFC
+#define DPAA_ETH_TX_QUEUES (NR_CPUS * CONFIG_FMAN_PFC_COS_COUNT)
+#else
+#define DPAA_ETH_TX_QUEUES NR_CPUS
+#endif
+
+#define DPAA_ETH_RX_QUEUES 128
+
+/* Convenience macros for storing/retrieving the skb back-pointers. They must
+ * accommodate both recycling and confirmation paths - i.e. cases when the buf
+ * was allocated by ourselves, respectively by the stack. In the former case,
+ * we could store the skb at negative offset; in the latter case, we can't,
+ * so we'll use 0 as offset.
+ *
+ * NB: @off is an offset from a (struct sk_buff **) pointer!
+ */
+#define DPA_WRITE_SKB_PTR(skb, skbh, addr, off) \
+{ \
+ skbh = (struct sk_buff **)addr; \
+ *(skbh + (off)) = skb; \
+}
+#define DPA_READ_SKB_PTR(skb, skbh, addr, off) \
+{ \
+ skbh = (struct sk_buff **)addr; \
+ skb = *(skbh + (off)); \
+}
+
+#ifdef CONFIG_PM
+/* Magic Packet wakeup */
+#define DPAA_WOL_MAGIC 0x00000001
+#endif
+
+#if defined(CONFIG_FSL_SDK_FMAN_TEST)
+struct pcd_range {
+ uint32_t base;
+ uint32_t count;
+};
+#endif
+
+/* More detailed FQ types - used for fine-grained WQ assignments */
+enum dpa_fq_type {
+ FQ_TYPE_RX_DEFAULT = 1, /* Rx Default FQs */
+ FQ_TYPE_RX_ERROR, /* Rx Error FQs */
+ FQ_TYPE_RX_PCD, /* User-defined PCDs */
+ FQ_TYPE_TX, /* "Real" Tx FQs */
+ FQ_TYPE_TX_CONFIRM, /* Tx default Conf FQ (actually an Rx FQ) */
+ FQ_TYPE_TX_CONF_MQ, /* Tx conf FQs (one for each Tx FQ) */
+ FQ_TYPE_TX_ERROR, /* Tx Error FQs (these are actually Rx FQs) */
+ FQ_TYPE_RX_PCD_HI_PRIO, /* User-defined high-priority PCDs */
+};
+
+struct dpa_fq {
+ struct qman_fq fq_base;
+ struct list_head list;
+ struct net_device *net_dev;
+ bool init;
+ uint32_t fqid;
+ uint32_t flags;
+ uint16_t channel;
+ uint8_t wq;
+ enum dpa_fq_type fq_type;
+};
+
+struct dpa_fq_cbs_t {
+ struct qman_fq rx_defq;
+ struct qman_fq tx_defq;
+ struct qman_fq rx_errq;
+ struct qman_fq tx_errq;
+ struct qman_fq egress_ern;
+};
+
+struct fqid_cell {
+ uint32_t start;
+ uint32_t count;
+};
+
+struct dpa_bp {
+ struct bman_pool *pool;
+ uint8_t bpid;
+ struct device *dev;
+ union {
+ /* The buffer pools used for the private ports are initialized
+ * with target_count buffers for each CPU; at runtime the
+ * number of buffers per CPU is constantly brought back to this
+ * level
+ */
+ int target_count;
+ /* The configured value for the number of buffers in the pool,
+ * used for shared port buffer pools
+ */
+ int config_count;
+ };
+ size_t size;
+ bool seed_pool;
+ /* physical address of the contiguous memory used by the pool to store
+ * the buffers
+ */
+ dma_addr_t paddr;
+ /* virtual address of the contiguous memory used by the pool to store
+ * the buffers
+ */
+ void __iomem *vaddr;
+ /* current number of buffers in the bpool alloted to this CPU */
+ int __percpu *percpu_count;
+ atomic_t refs;
+ /* some bpools need to be seeded before use by this cb */
+ int (*seed_cb)(struct dpa_bp *);
+ /* some bpools need to be emptied before freeing; this cb is used
+ * for freeing of individual buffers taken from the pool
+ */
+ void (*free_buf_cb)(void *addr);
+};
+
+struct dpa_rx_errors {
+ u64 dme; /* DMA Error */
+ u64 fpe; /* Frame Physical Error */
+ u64 fse; /* Frame Size Error */
+ u64 phe; /* Header Error */
+ u64 cse; /* Checksum Validation Error */
+};
+
+/* Counters for QMan ERN frames - one counter per rejection code */
+struct dpa_ern_cnt {
+ u64 cg_tdrop; /* Congestion group taildrop */
+ u64 wred; /* WRED congestion */
+ u64 err_cond; /* Error condition */
+ u64 early_window; /* Order restoration, frame too early */
+ u64 late_window; /* Order restoration, frame too late */
+ u64 fq_tdrop; /* FQ taildrop */
+ u64 fq_retired; /* FQ is retired */
+ u64 orp_zero; /* ORP disabled */
+};
+
+struct dpa_napi_portal {
+ struct napi_struct napi;
+ struct qman_portal *p;
+};
+
+struct dpa_percpu_priv_s {
+ struct net_device *net_dev;
+ struct dpa_napi_portal *np;
+ u64 in_interrupt;
+ u64 tx_returned;
+ u64 tx_confirm;
+ /* fragmented (non-linear) skbuffs received from the stack */
+ u64 tx_frag_skbuffs;
+ /* number of S/G frames received */
+ u64 rx_sg;
+
+ struct rtnl_link_stats64 stats;
+ struct dpa_rx_errors rx_errors;
+ struct dpa_ern_cnt ern_cnt;
+};
+
+struct dpa_priv_s {
+ struct dpa_percpu_priv_s __percpu *percpu_priv;
+ struct dpa_bp *dpa_bp;
+ /* Store here the needed Tx headroom for convenience and speed
+ * (even though it can be computed based on the fields of buf_layout)
+ */
+ uint16_t tx_headroom;
+ struct net_device *net_dev;
+ struct mac_device *mac_dev;
+ struct qman_fq *egress_fqs[DPAA_ETH_TX_QUEUES];
+ struct qman_fq *conf_fqs[DPAA_ETH_TX_QUEUES];
+
+ size_t bp_count;
+
+ uint16_t channel; /* "fsl,qman-channel-id" */
+ struct list_head dpa_fq_list;
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ struct dentry *debugfs_loop_file;
+#endif
+
+ uint32_t msg_enable; /* net_device message level */
+#ifdef CONFIG_FSL_DPAA_1588
+ struct dpa_ptp_tsu *tsu;
+#endif
+
+#if defined(CONFIG_FSL_SDK_FMAN_TEST)
+/* TODO: this is temporary until pcd support is implemented in dpaa */
+ int priv_pcd_num_ranges;
+ struct pcd_range priv_pcd_ranges[FMAN_PCD_TESTS_MAX_NUM_RANGES];
+#endif
+
+ struct {
+ /**
+ * All egress queues to a given net device belong to one
+ * (and the same) congestion group.
+ */
+ struct qman_cgr cgr;
+ /* If congested, when it began. Used for performance stats. */
+ u32 congestion_start_jiffies;
+ /* Number of jiffies the Tx port was congested. */
+ u32 congested_jiffies;
+ /**
+ * Counter for the number of times the CGR
+ * entered congestion state
+ */
+ u32 cgr_congested_count;
+ } cgr_data;
+ /* Use a per-port CGR for ingress traffic. */
+ bool use_ingress_cgr;
+ struct qman_cgr ingress_cgr;
+
+#ifdef CONFIG_FSL_DPAA_TS
+ bool ts_tx_en; /* Tx timestamping enabled */
+ bool ts_rx_en; /* Rx timestamping enabled */
+#endif /* CONFIG_FSL_DPAA_TS */
+
+ struct dpa_buffer_layout_s *buf_layout;
+ uint16_t rx_headroom;
+ char if_type[30];
+
+ void *peer;
+#ifdef CONFIG_PM
+ u32 wol;
+#endif
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ int loop_id;
+ int loop_to;
+#endif
+#ifdef CONFIG_FSL_DPAA_CEETM
+ bool ceetm_en; /* CEETM QoS enabled */
+#endif
+};
+
+struct fm_port_fqs {
+ struct dpa_fq *tx_defq;
+ struct dpa_fq *tx_errq;
+ struct dpa_fq *rx_defq;
+ struct dpa_fq *rx_errq;
+};
+
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+extern struct net_device *dpa_loop_netdevs[20];
+#endif
+
+/* functions with different implementation for SG and non-SG: */
+int dpa_bp_priv_seed(struct dpa_bp *dpa_bp);
+int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *count_ptr);
+void __hot _dpa_rx(struct net_device *net_dev,
+ struct qman_portal *portal,
+ const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd,
+ u32 fqid,
+ int *count_ptr);
+int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev);
+int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev,
+ struct qman_fq *egress_fq, struct qman_fq *conf_fq);
+struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv,
+ const struct qm_fd *fd);
+void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results,
+ const struct qm_fd *fd,
+ struct sk_buff *skb,
+ int *use_gro);
+#ifndef CONFIG_FSL_DPAA_TS
+bool dpa_skb_is_recyclable(struct sk_buff *skb);
+bool dpa_buf_is_recyclable(struct sk_buff *skb,
+ uint32_t min_size,
+ uint16_t min_offset,
+ unsigned char **new_buf_start);
+#endif
+int __hot skb_to_contig_fd(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd,
+ int *count_ptr, int *offset);
+int __hot skb_to_sg_fd(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd);
+int __cold __attribute__((nonnull))
+ _dpa_fq_free(struct device *dev, struct qman_fq *fq);
+
+/* Turn on HW checksum computation for this outgoing frame.
+ * If the current protocol is not something we support in this regard
+ * (or if the stack has already computed the SW checksum), we do nothing.
+ *
+ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value
+ * otherwise.
+ *
+ * Note that this function may modify the fd->cmd field and the skb data buffer
+ * (the Parse Results area).
+ */
+int dpa_enable_tx_csum(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
+
+static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv,
+ struct qman_portal *portal)
+{
+ /* In case of threaded ISR for RT enable kernel,
+ * in_irq() does not return appropriate value, so use
+ * in_serving_softirq to distinguish softirq or irq context.
+ */
+ if (unlikely(in_irq() || !in_serving_softirq())) {
+ /* Disable QMan IRQ and invoke NAPI */
+ int ret = qman_p_irqsource_remove(portal, QM_PIRQ_DQRI);
+ if (likely(!ret)) {
+ const struct qman_portal_config *pc =
+ qman_p_get_portal_config(portal);
+ struct dpa_napi_portal *np =
+ &percpu_priv->np[pc->index];
+
+ np->p = portal;
+ napi_schedule(&np->napi);
+ percpu_priv->in_interrupt++;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static inline ssize_t __const __must_check __attribute__((nonnull))
+dpa_fd_length(const struct qm_fd *fd)
+{
+ return fd->length20;
+}
+
+static inline ssize_t __const __must_check __attribute__((nonnull))
+dpa_fd_offset(const struct qm_fd *fd)
+{
+ return fd->offset;
+}
+
+static inline uint16_t dpa_get_headroom(struct dpa_buffer_layout_s *bl)
+{
+ uint16_t headroom;
+ /* The frame headroom must accommodate:
+ * - the driver private data area
+ * - parse results, hash results, timestamp if selected
+ * - manip extra space
+ * If either hash results or time stamp are selected, both will
+ * be copied to/from the frame headroom, as TS is located between PR and
+ * HR in the IC and IC copy size has a granularity of 16bytes
+ * (see description of FMBM_RICP and FMBM_TICP registers in DPAARM)
+ *
+ * Also make sure the headroom is a multiple of data_align bytes
+ */
+ headroom = (uint16_t)(bl->priv_data_size +
+ (bl->parse_results ? DPA_PARSE_RESULTS_SIZE : 0) +
+ (bl->hash_results || bl->time_stamp ?
+ DPA_TIME_STAMP_SIZE + DPA_HASH_RESULTS_SIZE : 0) +
+ bl->manip_extra_space);
+
+ return bl->data_align ? ALIGN(headroom, bl->data_align) : headroom;
+}
+
+int fm_mac_dump_regs(struct mac_device *h_dev, char *buf, int n);
+int fm_mac_dump_rx_stats(struct mac_device *h_dev, char *buf, int n);
+int fm_mac_dump_tx_stats(struct mac_device *h_dev, char *buf, int n);
+
+void dpaa_eth_sysfs_remove(struct device *dev);
+void dpaa_eth_sysfs_init(struct device *dev);
+int dpaa_eth_poll(struct napi_struct *napi, int budget);
+
+void dpa_private_napi_del(struct net_device *net_dev);
+
+/* Equivalent to a memset(0), but works faster */
+static inline void clear_fd(struct qm_fd *fd)
+{
+ fd->opaque_addr = 0;
+ fd->opaque = 0;
+ fd->cmd = 0;
+}
+
+static inline int _dpa_tx_fq_to_id(const struct dpa_priv_s *priv,
+ struct qman_fq *tx_fq)
+{
+ int i;
+
+ for (i = 0; i < DPAA_ETH_TX_QUEUES; i++)
+ if (priv->egress_fqs[i] == tx_fq)
+ return i;
+
+ return -EINVAL;
+}
+
+static inline int __hot dpa_xmit(struct dpa_priv_s *priv,
+ struct rtnl_link_stats64 *percpu_stats,
+ struct qm_fd *fd, struct qman_fq *egress_fq,
+ struct qman_fq *conf_fq)
+{
+ int err, i;
+
+ if (fd->bpid == 0xff)
+ fd->cmd |= qman_fq_fqid(conf_fq);
+
+ /* Trace this Tx fd */
+ trace_dpa_tx_fd(priv->net_dev, egress_fq, fd);
+
+ for (i = 0; i < 100000; i++) {
+ err = qman_enqueue(egress_fq, fd, 0);
+ if (err != -EBUSY)
+ break;
+ }
+
+ if (unlikely(err < 0)) {
+ /* TODO differentiate b/w -EBUSY (EQCR full) and other codes? */
+ percpu_stats->tx_errors++;
+ percpu_stats->tx_fifo_errors++;
+ return err;
+ }
+
+ percpu_stats->tx_packets++;
+ percpu_stats->tx_bytes += dpa_fd_length(fd);
+
+ return 0;
+}
+
+/* Use multiple WQs for FQ assignment:
+ * - Tx Confirmation queues go to WQ1.
+ * - Rx Default, Tx and PCD queues go to WQ3 (no differentiation between
+ * Rx and Tx traffic, or between Rx Default and Rx PCD frames).
+ * - Rx Error and Tx Error queues go to WQ2 (giving them a better chance
+ * to be scheduled, in case there are many more FQs in WQ3).
+ * This ensures that Tx-confirmed buffers are timely released. In particular,
+ * it avoids congestion on the Tx Confirm FQs, which can pile up PFDRs if they
+ * are greatly outnumbered by other FQs in the system (usually PCDs), while
+ * dequeue scheduling is round-robin.
+ */
+static inline void _dpa_assign_wq(struct dpa_fq *fq)
+{
+ switch (fq->fq_type) {
+ case FQ_TYPE_TX_CONFIRM:
+ case FQ_TYPE_TX_CONF_MQ:
+ fq->wq = 1;
+ break;
+ case FQ_TYPE_RX_DEFAULT:
+ case FQ_TYPE_TX:
+ fq->wq = 3;
+ break;
+ case FQ_TYPE_RX_ERROR:
+ case FQ_TYPE_TX_ERROR:
+ case FQ_TYPE_RX_PCD_HI_PRIO:
+ fq->wq = 2;
+ break;
+ case FQ_TYPE_RX_PCD:
+ fq->wq = 5;
+ break;
+ default:
+ WARN(1, "Invalid FQ type %d for FQID %d!\n",
+ fq->fq_type, fq->fqid);
+ }
+}
+
+#ifdef CONFIG_FMAN_PFC
+/* Use in lieu of skb_get_queue_mapping() */
+#define dpa_get_queue_mapping(skb) \
+ (((skb)->priority < CONFIG_FMAN_PFC_COS_COUNT) ? \
+ ((skb)->priority * dpa_num_cpus + smp_processor_id()) : \
+ ((CONFIG_FMAN_PFC_COS_COUNT - 1) * \
+ dpa_num_cpus + smp_processor_id()));
+#else
+#define dpa_get_queue_mapping(skb) skb_get_queue_mapping(skb)
+#endif
+
+static inline void _dpa_bp_free_pf(void *addr)
+{
+ put_page(virt_to_head_page(addr));
+}
+
+/* LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue
+ * manifests itself at high traffic rates when frames cross 4K memory
+ * boundaries, when they are not aligned to 16 bytes or when they have
+ * Scatter/Gather fragments; For the moment, we use a SW workaround that
+ * realigns frames to 256 bytes. Scatter/Gather frames aren't supported
+ * on egress.
+ */
+
+#ifdef FM_ERRATUM_A050385
+#define CROSS_4K(start, size) \
+ (((uintptr_t)(start) + (size)) > \
+ (((uintptr_t)(start) + 0x1000) & ~0xFFF))
+/* The headroom needs to accommodate our private data (64 bytes) but
+ * we reserve 256 bytes instead to guarantee 256 data alignment.
+ */
+#define DPAA_A050385_HEADROOM 256
+#endif /* FM_ERRATUM_A050385 */
+
+#endif /* __DPA_H */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
new file mode 100644
index 000000000000..be6e4f88150c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c
@@ -0,0 +1,205 @@
+/* Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/etherdevice.h>
+#include <linux/kthread.h>
+#include <linux/percpu.h>
+#include <linux/highmem.h>
+#include <linux/sort.h>
+#include <linux/fsl_qman.h>
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#include "dpaa_eth_base.h"
+
+#define DPA_DESCRIPTION "FSL DPAA Advanced drivers:"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+uint8_t advanced_debug = -1;
+module_param(advanced_debug, byte, S_IRUGO);
+MODULE_PARM_DESC(advanced_debug, "Module/Driver verbosity level");
+EXPORT_SYMBOL(advanced_debug);
+
+static int dpa_bp_cmp(const void *dpa_bp0, const void *dpa_bp1)
+{
+ return ((struct dpa_bp *)dpa_bp0)->size -
+ ((struct dpa_bp *)dpa_bp1)->size;
+}
+
+struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
+dpa_bp_probe(struct platform_device *_of_dev, size_t *count)
+{
+ int i, lenp, na, ns, err;
+ struct device *dev;
+ struct device_node *dev_node;
+ const __be32 *bpool_cfg;
+ struct dpa_bp *dpa_bp;
+ u32 bpid;
+
+ dev = &_of_dev->dev;
+
+ *count = of_count_phandle_with_args(dev->of_node,
+ "fsl,bman-buffer-pools", NULL);
+ if (*count < 1) {
+ dev_err(dev, "missing fsl,bman-buffer-pools device tree entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL);
+ if (dpa_bp == NULL) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dev_node = of_find_node_by_path("/");
+ if (unlikely(dev_node == NULL)) {
+ dev_err(dev, "of_find_node_by_path(/) failed\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ na = of_n_addr_cells(dev_node);
+ ns = of_n_size_cells(dev_node);
+
+ for (i = 0; i < *count; i++) {
+ of_node_put(dev_node);
+
+ dev_node = of_parse_phandle(dev->of_node,
+ "fsl,bman-buffer-pools", i);
+ if (dev_node == NULL) {
+ dev_err(dev, "of_find_node_by_phandle() failed\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) {
+ dev_err(dev,
+ "!of_device_is_compatible(%s, fsl,bpool)\n",
+ dev_node->full_name);
+ dpa_bp = ERR_PTR(-EINVAL);
+ goto _return_of_node_put;
+ }
+
+ err = of_property_read_u32(dev_node, "fsl,bpid", &bpid);
+ if (err) {
+ dev_err(dev, "Cannot find buffer pool ID in the device tree\n");
+ dpa_bp = ERR_PTR(-EINVAL);
+ goto _return_of_node_put;
+ }
+ dpa_bp[i].bpid = (uint8_t)bpid;
+
+ bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg",
+ &lenp);
+ if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) {
+ const uint32_t *seed_pool;
+
+ dpa_bp[i].config_count =
+ (int)of_read_number(bpool_cfg, ns);
+ dpa_bp[i].size =
+ (size_t)of_read_number(bpool_cfg + ns, ns);
+ dpa_bp[i].paddr =
+ of_read_number(bpool_cfg + 2 * ns, na);
+
+ seed_pool = of_get_property(dev_node,
+ "fsl,bpool-ethernet-seeds", &lenp);
+ dpa_bp[i].seed_pool = !!seed_pool;
+
+ } else {
+ dev_err(dev,
+ "Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n",
+ dev_node->full_name);
+ dpa_bp = ERR_PTR(-EINVAL);
+ goto _return_of_node_put;
+ }
+ }
+
+ sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL);
+
+ return dpa_bp;
+
+_return_of_node_put:
+ if (dev_node)
+ of_node_put(dev_node);
+
+ return dpa_bp;
+}
+EXPORT_SYMBOL(dpa_bp_probe);
+
+int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
+ size_t count)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ int i;
+
+ priv->dpa_bp = dpa_bp;
+ priv->bp_count = count;
+
+ for (i = 0; i < count; i++) {
+ int err;
+ err = dpa_bp_alloc(&dpa_bp[i], net_dev->dev.parent);
+ if (err < 0) {
+ dpa_bp_free(priv);
+ priv->dpa_bp = NULL;
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_bp_create);
+
+static int __init __cold dpa_advanced_load(void)
+{
+ pr_info(DPA_DESCRIPTION "\n");
+
+ return 0;
+}
+module_init(dpa_advanced_load);
+
+static void __exit __cold dpa_advanced_unload(void)
+{
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME".c", __func__);
+
+}
+module_exit(dpa_advanced_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
new file mode 100644
index 000000000000..6ec68c3cca30
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h
@@ -0,0 +1,49 @@
+/* Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DPAA_ETH_BASE_H
+#define __DPAA_ETH_BASE_H
+
+#include <linux/etherdevice.h> /* struct net_device */
+#include <linux/fsl_bman.h> /* struct bm_buffer */
+#include <linux/of_platform.h> /* struct platform_device */
+#include <linux/net_tstamp.h> /* struct hwtstamp_config */
+
+extern uint8_t advanced_debug;
+extern const struct dpa_fq_cbs_t shared_fq_cbs;
+extern int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev);
+
+struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */
+dpa_bp_probe(struct platform_device *_of_dev, size_t *count);
+int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
+ size_t count);
+
+#endif /* __DPAA_ETH_BASE_H */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
new file mode 100644
index 000000000000..637192f87ecb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
@@ -0,0 +1,2085 @@
+/* Copyright 2008-2016 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/init.h>
+#include "dpaa_eth_ceetm.h"
+
+const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1] = {
+ [TCA_CEETM_COPT] = { .len = sizeof(struct tc_ceetm_copt) },
+ [TCA_CEETM_QOPS] = { .len = sizeof(struct tc_ceetm_qopt) },
+};
+
+struct Qdisc_ops ceetm_qdisc_ops;
+EXPORT_SYMBOL(ceetm_qdisc_ops);
+
+/* Obtain the DCP and the SP ids from the FMan port */
+static void get_dcp_and_sp(struct net_device *dev, enum qm_dc_portal *dcp_id,
+ unsigned int *sp_id)
+{
+ struct dpa_priv_s *dpa_priv = netdev_priv(dev);
+ struct mac_device *mac_dev = dpa_priv->mac_dev;
+ t_LnxWrpFmPortDev *port_dev;
+ uint32_t channel;
+
+ port_dev = (t_LnxWrpFmPortDev *)mac_dev->port_dev[TX];
+ channel = port_dev->txCh;
+
+ *sp_id = channel & CHANNEL_SP_MASK;
+ pr_debug(KBUILD_BASENAME " : FM sub-portal ID %d\n", *sp_id);
+
+ if (channel < DCP0_MAX_CHANNEL) {
+ *dcp_id = qm_dc_portal_fman0;
+ pr_debug(KBUILD_BASENAME " : DCP ID 0\n");
+ } else {
+ *dcp_id = qm_dc_portal_fman1;
+ pr_debug(KBUILD_BASENAME " : DCP ID 1\n");
+ }
+}
+
+/* Wait for the DPAA Eth driver WQ TX FQs to empty */
+static void dpaa_drain_fqs(struct net_device *dev)
+{
+ const struct dpa_priv_s *priv = netdev_priv(dev);
+ struct qm_mcr_queryfq_np np;
+ struct qman_fq *fq;
+ int ret, i;
+
+ for (i = 0; i < DPAA_ETH_TX_QUEUES; i++) {
+ fq = priv->egress_fqs[i];
+ while (true) {
+ ret = qman_query_fq_np(fq, &np);
+ if (unlikely(ret)) {
+ pr_err(KBUILD_BASENAME
+ " : %s : unable to query FQ %x: %d\n",
+ __func__, fq->fqid, ret);
+ break;
+ }
+
+ if (np.frm_cnt == 0)
+ break;
+ }
+ }
+}
+
+/* Wait for the DPAA CEETM TX CQs to empty */
+static void ceetm_drain_class(struct ceetm_class *cl)
+{
+ struct qm_mcr_ceetm_cq_query cq_query;
+ struct qm_ceetm_cq *cq = NULL;
+ unsigned int idx;
+ int ret;
+
+ if (!cl)
+ return;
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ /* The ROOT classes aren't directly linked to CEETM CQs */
+ return;
+ case CEETM_PRIO:
+ cq = (struct qm_ceetm_cq *)cl->prio.cq;
+ break;
+ case CEETM_WBFS:
+ cq = (struct qm_ceetm_cq *)cl->wbfs.cq;
+ break;
+ }
+
+ if (!cq || !cl->ch)
+ return;
+
+ /* Build the query CQID by merging the channel and the CQ IDs */
+ idx = (cq->parent->idx << 4) | cq->idx;
+
+ while (true) {
+ ret = qman_ceetm_query_cq(idx,
+ cl->ch->dcp_idx,
+ &cq_query);
+ if (unlikely(ret)) {
+ pr_err(KBUILD_BASENAME
+ " : %s : unable to query CQ %x: %d\n",
+ __func__, idx, ret);
+ break;
+ }
+
+ if (cq_query.frm_cnt == 0)
+ break;
+ }
+}
+
+/* Enqueue Rejection Notification callback */
+static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq,
+ const struct qm_mr_entry *msg)
+{
+ struct dpa_percpu_priv_s *dpa_percpu_priv;
+ struct ceetm_class_stats *cstats = NULL;
+ const struct dpa_priv_s *dpa_priv;
+ struct qm_fd fd = msg->ern.fd;
+ struct net_device *net_dev;
+ struct ceetm_fq *ceetm_fq;
+ struct ceetm_class *cls;
+ struct sk_buff *skb;
+
+ ceetm_fq = container_of(fq, struct ceetm_fq, fq);
+ net_dev = ceetm_fq->net_dev;
+ dpa_priv = netdev_priv(net_dev);
+ dpa_percpu_priv = raw_cpu_ptr(dpa_priv->percpu_priv);
+
+ /* Increment DPA counters */
+ dpa_percpu_priv->stats.tx_dropped++;
+ dpa_percpu_priv->stats.tx_fifo_errors++;
+ count_ern(dpa_percpu_priv, msg);
+
+ /* Increment CEETM counters */
+ cls = ceetm_fq->ceetm_cls;
+ switch (cls->type) {
+ case CEETM_PRIO:
+ cstats = this_cpu_ptr(cls->prio.cstats);
+ break;
+ case CEETM_WBFS:
+ cstats = this_cpu_ptr(cls->wbfs.cstats);
+ break;
+ }
+
+ if (cstats)
+ cstats->ern_drop_count++;
+
+ /* Release the buffers that were supposed to be recycled. */
+ if (fd.bpid != 0xff) {
+ dpa_fd_release(net_dev, &fd);
+ return;
+ }
+
+ /* Release the frames that were supposed to return on the
+ * confirmation path.
+ */
+ skb = _dpa_cleanup_tx_fd(dpa_priv, &fd);
+ dev_kfree_skb_any(skb);
+}
+
+/* Congestion State Change Notification callback */
+static void ceetm_cscn(struct qm_ceetm_ccg *ccg, void *cb_ctx, int congested)
+{
+ struct ceetm_class_stats *cstats = NULL;
+ struct dpa_priv_s *dpa_priv;
+ struct ceetm_fq *ceetm_fq;
+ struct ceetm_class *cls;
+
+ ceetm_fq = (struct ceetm_fq *)cb_ctx;
+ dpa_priv = netdev_priv(ceetm_fq->net_dev);
+ cls = ceetm_fq->ceetm_cls;
+
+ switch (cls->type) {
+ case CEETM_PRIO:
+ cstats = this_cpu_ptr(cls->prio.cstats);
+ break;
+ case CEETM_WBFS:
+ cstats = this_cpu_ptr(cls->wbfs.cstats);
+ break;
+ }
+
+ ceetm_fq->congested = congested;
+
+ if (congested) {
+ dpa_priv->cgr_data.congestion_start_jiffies = jiffies;
+ dpa_priv->cgr_data.cgr_congested_count++;
+ if (cstats)
+ cstats->congested_count++;
+ } else {
+ dpa_priv->cgr_data.congested_jiffies +=
+ (jiffies - dpa_priv->cgr_data.congestion_start_jiffies);
+ }
+}
+
+/* Allocate a ceetm fq */
+static int ceetm_alloc_fq(struct ceetm_fq **fq, struct net_device *dev,
+ struct ceetm_class *cls)
+{
+ *fq = kzalloc(sizeof(**fq), GFP_KERNEL);
+ if (!*fq)
+ return -ENOMEM;
+
+ (*fq)->net_dev = dev;
+ (*fq)->ceetm_cls = cls;
+ (*fq)->congested = 0;
+ return 0;
+}
+
+/* Configure a ceetm Class Congestion Group */
+static int ceetm_config_ccg(struct qm_ceetm_ccg **ccg,
+ struct qm_ceetm_channel *channel, unsigned int id,
+ struct ceetm_fq *fq, struct dpa_priv_s *dpa_priv)
+{
+ struct qm_ceetm_ccg_params ccg_params;
+ u16 ccg_mask;
+ u32 cs_th;
+ int err;
+
+ err = qman_ceetm_ccg_claim(ccg, channel, id, ceetm_cscn, fq);
+ if (err)
+ return err;
+
+ /* Configure the count mode (frames/bytes), enable congestion state
+ * notifications, configure the congestion entry and exit thresholds,
+ * enable tail-drop, configure the tail-drop mode, and set the
+ * overhead accounting limit
+ */
+ ccg_mask = QM_CCGR_WE_MODE |
+ QM_CCGR_WE_CSCN_EN |
+ QM_CCGR_WE_CS_THRES_IN | QM_CCGR_WE_CS_THRES_OUT |
+ QM_CCGR_WE_TD_EN | QM_CCGR_WE_TD_MODE |
+ QM_CCGR_WE_OAL;
+
+ ccg_params.mode = 0; /* count bytes */
+ ccg_params.cscn_en = 1; /* generate notifications */
+ ccg_params.td_en = 1; /* enable tail-drop */
+ ccg_params.td_mode = 0; /* tail-drop on congestion state */
+ ccg_params.oal = (signed char)(min(sizeof(struct sk_buff) +
+ dpa_priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
+
+ /* Set the congestion state thresholds according to the link speed */
+ if (dpa_priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
+ cs_th = CONFIG_FSL_DPAA_CEETM_CCS_THRESHOLD_10G;
+ else
+ cs_th = CONFIG_FSL_DPAA_CEETM_CCS_THRESHOLD_1G;
+
+ qm_cgr_cs_thres_set64(&ccg_params.cs_thres_in, cs_th, 1);
+ qm_cgr_cs_thres_set64(&ccg_params.cs_thres_out,
+ cs_th * CEETM_CCGR_RATIO, 1);
+
+ err = qman_ceetm_ccg_set(*ccg, ccg_mask, &ccg_params);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Configure a ceetm Logical Frame Queue */
+static int ceetm_config_lfq(struct qm_ceetm_cq *cq, struct ceetm_fq *fq,
+ struct qm_ceetm_lfq **lfq)
+{
+ u64 context_a;
+ u32 context_b;
+ int err;
+
+ err = qman_ceetm_lfq_claim(lfq, cq);
+ if (err)
+ return err;
+
+ /* Get the former contexts in order to preserve context B */
+ err = qman_ceetm_lfq_get_context(*lfq, &context_a, &context_b);
+ if (err)
+ return err;
+
+ context_a = CEETM_CONTEXT_A;
+ err = qman_ceetm_lfq_set_context(*lfq, context_a, context_b);
+ if (err)
+ return err;
+
+ (*lfq)->ern = ceetm_ern;
+
+ err = qman_ceetm_create_fq(*lfq, &fq->fq);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Configure a prio ceetm class */
+static int ceetm_config_prio_cls(struct ceetm_class *cls,
+ struct net_device *dev,
+ unsigned int id)
+{
+ struct dpa_priv_s *dpa_priv = netdev_priv(dev);
+ int err;
+
+ err = ceetm_alloc_fq(&cls->prio.fq, dev, cls);
+ if (err)
+ return err;
+
+ /* Claim and configure the CCG */
+ err = ceetm_config_ccg(&cls->prio.ccg, cls->ch, id, cls->prio.fq,
+ dpa_priv);
+ if (err)
+ return err;
+
+ /* Claim and configure the CQ */
+ err = qman_ceetm_cq_claim(&cls->prio.cq, cls->ch, id, cls->prio.ccg);
+ if (err)
+ return err;
+
+ if (cls->shaped) {
+ err = qman_ceetm_channel_set_cq_cr_eligibility(cls->ch, id, 1);
+ if (err)
+ return err;
+
+ err = qman_ceetm_channel_set_cq_er_eligibility(cls->ch, id, 1);
+ if (err)
+ return err;
+ }
+
+ /* Claim and configure a LFQ */
+ err = ceetm_config_lfq(cls->prio.cq, cls->prio.fq, &cls->prio.lfq);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Configure a wbfs ceetm class */
+static int ceetm_config_wbfs_cls(struct ceetm_class *cls,
+ struct net_device *dev,
+ unsigned int id, int type)
+{
+ struct dpa_priv_s *dpa_priv = netdev_priv(dev);
+ int err;
+
+ err = ceetm_alloc_fq(&cls->wbfs.fq, dev, cls);
+ if (err)
+ return err;
+
+ /* Claim and configure the CCG */
+ err = ceetm_config_ccg(&cls->wbfs.ccg, cls->ch, id, cls->wbfs.fq,
+ dpa_priv);
+ if (err)
+ return err;
+
+ /* Claim and configure the CQ */
+ if (type == WBFS_GRP_B)
+ err = qman_ceetm_cq_claim_B(&cls->wbfs.cq, cls->ch, id,
+ cls->wbfs.ccg);
+ else
+ err = qman_ceetm_cq_claim_A(&cls->wbfs.cq, cls->ch, id,
+ cls->wbfs.ccg);
+ if (err)
+ return err;
+
+ /* Configure the CQ weight: real number multiplied by 100 to get rid
+ * of the fraction
+ */
+ err = qman_ceetm_set_queue_weight_in_ratio(cls->wbfs.cq,
+ cls->wbfs.weight * 100);
+ if (err)
+ return err;
+
+ /* Claim and configure a LFQ */
+ err = ceetm_config_lfq(cls->wbfs.cq, cls->wbfs.fq, &cls->wbfs.lfq);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Find class in qdisc hash table using given handle */
+static inline struct ceetm_class *ceetm_find(u32 handle, struct Qdisc *sch)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct Qdisc_class_common *clc;
+
+ pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n",
+ __func__, handle, sch->handle);
+
+ clc = qdisc_class_find(&priv->clhash, handle);
+ return clc ? container_of(clc, struct ceetm_class, common) : NULL;
+}
+
+/* Insert a class in the qdisc's class hash */
+static void ceetm_link_class(struct Qdisc *sch,
+ struct Qdisc_class_hash *clhash,
+ struct Qdisc_class_common *common)
+{
+ sch_tree_lock(sch);
+ qdisc_class_hash_insert(clhash, common);
+ sch_tree_unlock(sch);
+ qdisc_class_hash_grow(sch, clhash);
+}
+
+/* Destroy a ceetm class */
+static void ceetm_cls_destroy(struct Qdisc *sch, struct ceetm_class *cl)
+{
+ struct net_device *dev = qdisc_dev(sch);
+
+ if (!cl)
+ return;
+
+ pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ if (cl->root.child) {
+ qdisc_put(cl->root.child);
+ cl->root.child = NULL;
+ }
+
+ if (cl->ch && qman_ceetm_channel_release(cl->ch))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the channel %d\n",
+ __func__, cl->ch->idx);
+
+ break;
+
+ case CEETM_PRIO:
+ if (cl->prio.child) {
+ qdisc_put(cl->prio.child);
+ cl->prio.child = NULL;
+ }
+
+ /* We must make sure the CQ is empty before releasing it.
+ * Pause all transmissions while we wait for it to drain.
+ */
+ netif_tx_stop_all_queues(dev);
+ ceetm_drain_class(cl);
+
+ if (cl->prio.lfq && qman_ceetm_lfq_release(cl->prio.lfq))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the LFQ %d\n",
+ __func__, cl->prio.lfq->idx);
+
+ if (cl->prio.cq && qman_ceetm_cq_release(cl->prio.cq))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the CQ %d\n",
+ __func__, cl->prio.cq->idx);
+
+ if (cl->prio.ccg && qman_ceetm_ccg_release(cl->prio.ccg))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the CCG %d\n",
+ __func__, cl->prio.ccg->idx);
+
+ kfree(cl->prio.fq);
+
+ if (cl->prio.cstats)
+ free_percpu(cl->prio.cstats);
+
+ netif_tx_wake_all_queues(dev);
+ break;
+
+ case CEETM_WBFS:
+ /* We must make sure the CQ is empty before releasing it.
+ * Pause all transmissions while we wait for it to drain.
+ */
+ netif_tx_stop_all_queues(dev);
+ ceetm_drain_class(cl);
+
+ if (cl->wbfs.lfq && qman_ceetm_lfq_release(cl->wbfs.lfq))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the LFQ %d\n",
+ __func__, cl->wbfs.lfq->idx);
+
+ if (cl->wbfs.cq && qman_ceetm_cq_release(cl->wbfs.cq))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the CQ %d\n",
+ __func__, cl->wbfs.cq->idx);
+
+ if (cl->wbfs.ccg && qman_ceetm_ccg_release(cl->wbfs.ccg))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the CCG %d\n",
+ __func__, cl->wbfs.ccg->idx);
+
+ kfree(cl->wbfs.fq);
+
+ if (cl->wbfs.cstats)
+ free_percpu(cl->wbfs.cstats);
+
+ netif_tx_wake_all_queues(dev);
+ }
+
+ tcf_block_put(cl->block);
+ kfree(cl);
+}
+
+/* Destroy a ceetm qdisc */
+static void ceetm_destroy(struct Qdisc *sch)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct hlist_node *next;
+ struct ceetm_class *cl;
+ unsigned int ntx, i;
+
+ pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
+ __func__, sch->handle);
+
+ /* All filters need to be removed before destroying the classes */
+ tcf_block_put(priv->block);
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
+ tcf_block_put(cl->block);
+ cl->block = NULL;
+ }
+ }
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i],
+ common.hnode)
+ ceetm_cls_destroy(sch, cl);
+ }
+
+ qdisc_class_hash_destroy(&priv->clhash);
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ dpa_disable_ceetm(dev);
+
+ if (priv->root.lni && qman_ceetm_lni_release(priv->root.lni))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the LNI %d\n",
+ __func__, priv->root.lni->idx);
+
+ if (priv->root.sp && qman_ceetm_sp_release(priv->root.sp))
+ pr_err(KBUILD_BASENAME
+ " : %s : error releasing the SP %d\n",
+ __func__, priv->root.sp->idx);
+
+ if (priv->root.qstats)
+ free_percpu(priv->root.qstats);
+
+ if (!priv->root.qdiscs)
+ break;
+
+ /* Destroy the pfifo qdiscs in case they haven't been attached
+ * to the netdev queues yet.
+ */
+ for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
+ if (priv->root.qdiscs[ntx])
+ qdisc_put(priv->root.qdiscs[ntx]);
+
+ kfree(priv->root.qdiscs);
+ break;
+
+ case CEETM_PRIO:
+ if (priv->prio.parent)
+ priv->prio.parent->root.child = NULL;
+ break;
+
+ case CEETM_WBFS:
+ /* Reset the WBFS groups and priorities */
+ if (priv->wbfs.ch)
+ qman_ceetm_channel_set_group(priv->wbfs.ch, 1, 0, 0);
+
+ if (priv->wbfs.parent)
+ priv->wbfs.parent->prio.child = NULL;
+ break;
+ }
+}
+
+static int ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct ceetm_qdisc_stats *qstats;
+ struct tc_ceetm_qopt qopt;
+ struct Qdisc *qdisc;
+ unsigned int ntx, i;
+ struct nlattr *nest;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ sch_tree_lock(sch);
+ memset(&qopt, 0, sizeof(qopt));
+ qopt.type = priv->type;
+ qopt.shaped = priv->shaped;
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ /* Gather statistics from the underlying pfifo qdiscs */
+ sch->q.qlen = 0;
+ memset(&sch->bstats, 0, sizeof(sch->bstats));
+ memset(&sch->qstats, 0, sizeof(sch->qstats));
+
+ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
+ sch->q.qlen += qdisc->q.qlen;
+ sch->bstats.bytes += qdisc->bstats.bytes;
+ sch->bstats.packets += qdisc->bstats.packets;
+ sch->qstats.qlen += qdisc->qstats.qlen;
+ sch->qstats.backlog += qdisc->qstats.backlog;
+ sch->qstats.drops += qdisc->qstats.drops;
+ sch->qstats.requeues += qdisc->qstats.requeues;
+ sch->qstats.overlimits += qdisc->qstats.overlimits;
+ }
+
+ for_each_online_cpu(i) {
+ qstats = per_cpu_ptr(priv->root.qstats, i);
+ sch->qstats.drops += qstats->drops;
+ }
+
+ qopt.rate = priv->root.rate;
+ qopt.ceil = priv->root.ceil;
+ qopt.overhead = priv->root.overhead;
+ break;
+
+ case CEETM_PRIO:
+ qopt.qcount = priv->prio.qcount;
+ break;
+
+ case CEETM_WBFS:
+ qopt.qcount = priv->wbfs.qcount;
+ qopt.cr = priv->wbfs.cr;
+ qopt.er = priv->wbfs.er;
+ break;
+
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ sch_tree_unlock(sch);
+ return -EINVAL;
+ }
+
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+ if (!nest)
+ goto nla_put_failure;
+ if (nla_put(skb, TCA_CEETM_QOPS, sizeof(qopt), &qopt))
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+
+ sch_tree_unlock(sch);
+ return skb->len;
+
+nla_put_failure:
+ sch_tree_unlock(sch);
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+/* Configure a root ceetm qdisc */
+static int ceetm_init_root(struct Qdisc *sch, struct ceetm_qdisc *priv,
+ struct tc_ceetm_qopt *qopt,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ unsigned int i, sp_id, parent_id;
+ struct netdev_queue *dev_queue;
+ struct dpa_priv_s *dpa_priv;
+ struct mac_device *mac_dev;
+ enum qm_dc_portal dcp_id;
+ struct qm_ceetm_lni *lni;
+ struct qm_ceetm_sp *sp;
+ struct Qdisc *qdisc;
+ int err;
+ u64 bps;
+
+ dpa_priv = netdev_priv(dev);
+ mac_dev = dpa_priv->mac_dev;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ /* Validate inputs */
+ if (sch->parent != TC_H_ROOT) {
+ pr_err("CEETM: a root ceetm qdisc must be root\n");
+ return -EINVAL;
+ }
+
+ if (!mac_dev) {
+ pr_err("CEETM: the interface is lacking a mac\n");
+ return -EINVAL;
+ }
+
+ /* Pre-allocate underlying pfifo qdiscs.
+ *
+ * We want to offload shaping and scheduling decisions to the hardware.
+ * The pfifo qdiscs will be attached to the netdev queues and will
+ * guide the traffic from the IP stack down to the driver with minimum
+ * interference.
+ *
+ * The CEETM qdiscs and classes will be crossed when the traffic
+ * reaches the driver.
+ */
+ priv->root.qdiscs = kcalloc(dev->num_tx_queues,
+ sizeof(priv->root.qdiscs[0]),
+ GFP_KERNEL);
+ if (!priv->root.qdiscs)
+ return -ENOMEM;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ dev_queue = netdev_get_tx_queue(dev, i);
+ parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle),
+ TC_H_MIN(i + PFIFO_MIN_OFFSET));
+
+ qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
+ parent_id, extack);
+ if (!qdisc)
+ return -ENOMEM;
+
+ priv->root.qdiscs[i] = qdisc;
+ qdisc->flags |= TCQ_F_ONETXQUEUE;
+ }
+
+ sch->flags |= TCQ_F_MQROOT;
+
+ priv->root.qstats = alloc_percpu(struct ceetm_qdisc_stats);
+ if (!priv->root.qstats) {
+ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ priv->shaped = qopt->shaped;
+ priv->root.rate = qopt->rate;
+ priv->root.ceil = qopt->ceil;
+ priv->root.overhead = qopt->overhead;
+
+ /* Claim the SP */
+ get_dcp_and_sp(dev, &dcp_id, &sp_id);
+ err = qman_ceetm_sp_claim(&sp, dcp_id, sp_id);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to claim the SP\n",
+ __func__);
+ return err;
+ }
+
+ priv->root.sp = sp;
+
+ /* Claim the LNI - will use the same id as the SP id since SPs 0-7
+ * are connected to the TX FMan ports
+ */
+ err = qman_ceetm_lni_claim(&lni, dcp_id, sp_id);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to claim the LNI\n",
+ __func__);
+ return err;
+ }
+
+ priv->root.lni = lni;
+
+ err = qman_ceetm_sp_set_lni(sp, lni);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to link the SP and LNI\n",
+ __func__);
+ return err;
+ }
+
+ lni->sp = sp;
+
+ /* Configure the LNI shaper */
+ if (priv->shaped) {
+ err = qman_ceetm_lni_enable_shaper(lni, 1, priv->root.overhead);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+ __func__);
+ return err;
+ }
+
+ bps = priv->root.rate << 3; /* Bps -> bps */
+ err = qman_ceetm_lni_set_commit_rate_bps(lni, bps, dev->mtu);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+ __func__);
+ return err;
+ }
+
+ bps = priv->root.ceil << 3; /* Bps -> bps */
+ err = qman_ceetm_lni_set_excess_rate_bps(lni, bps, dev->mtu);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n",
+ __func__);
+ return err;
+ }
+ }
+
+ /* TODO default configuration */
+
+ dpa_enable_ceetm(dev);
+ return 0;
+}
+
+/* Configure a prio ceetm qdisc */
+static int ceetm_init_prio(struct Qdisc *sch, struct ceetm_qdisc *priv,
+ struct tc_ceetm_qopt *qopt)
+{
+ struct ceetm_class *parent_cl, *child_cl;
+ struct net_device *dev = qdisc_dev(sch);
+ struct Qdisc *root_qdisc = dev->qdisc;
+ unsigned int i;
+ int err;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (sch->parent == TC_H_ROOT) {
+ pr_err("CEETM: a prio ceetm qdisc can not be root\n");
+ return -EINVAL;
+ }
+
+ if (TC_H_MAJ(sch->parent) != TC_H_MAJ(root_qdisc->handle)) {
+ pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
+ return -EINVAL;
+ }
+
+ if (strcmp(root_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+ return -EINVAL;
+ }
+
+ /* Obtain the parent root ceetm_class */
+ parent_cl = ceetm_find(sch->parent, root_qdisc);
+
+ if (!parent_cl || parent_cl->type != CEETM_ROOT) {
+ pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
+ return -EINVAL;
+ }
+
+ priv->prio.parent = parent_cl;
+ parent_cl->root.child = sch;
+
+ priv->shaped = parent_cl->shaped;
+ priv->prio.qcount = qopt->qcount;
+ priv->prio.ch = parent_cl->ch;
+
+ /* Create and configure qcount child classes */
+ for (i = 0; i < priv->prio.qcount; i++) {
+ child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
+ if (!child_cl)
+ return -ENOMEM;
+
+ child_cl->prio.cstats = alloc_percpu(struct ceetm_class_stats);
+ if (!child_cl->prio.cstats) {
+ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+ __func__);
+ err = -ENOMEM;
+ goto err_init_prio_cls;
+ }
+
+ child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
+ child_cl->parent = sch;
+ child_cl->type = CEETM_PRIO;
+ child_cl->shaped = priv->shaped;
+ child_cl->prio.child = NULL;
+ child_cl->ch = priv->prio.ch;
+
+ /* All shaped CQs have CR and ER enabled by default */
+ child_cl->prio.cr = child_cl->shaped;
+ child_cl->prio.er = child_cl->shaped;
+ child_cl->prio.fq = NULL;
+ child_cl->prio.cq = NULL;
+
+ /* Configure the corresponding hardware CQ */
+ err = ceetm_config_prio_cls(child_cl, dev, i);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n",
+ __func__, child_cl->common.classid);
+ goto err_init_prio_cls;
+ }
+
+ /* Add class handle in Qdisc */
+ ceetm_link_class(sch, &priv->clhash, &child_cl->common);
+ pr_debug(KBUILD_BASENAME " : %s : added ceetm prio class %X associated with CQ %d and CCG %d\n",
+ __func__, child_cl->common.classid,
+ child_cl->prio.cq->idx, child_cl->prio.ccg->idx);
+ }
+
+ return 0;
+
+err_init_prio_cls:
+ ceetm_cls_destroy(sch, child_cl);
+ /* Note: ceetm_destroy() will be called by our caller */
+ return err;
+}
+
+/* Configure a wbfs ceetm qdisc */
+static int ceetm_init_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
+ struct tc_ceetm_qopt *qopt)
+{
+ struct ceetm_class *parent_cl, *child_cl, *tmp_cl, *root_cl = NULL;
+ struct Qdisc *root_qdisc, *parent_qdisc = NULL;
+ struct net_device *dev = qdisc_dev(sch);
+ unsigned int i, id, prio_a, prio_b;
+ int err, group_b, small_group;
+ struct ceetm_qdisc *root_priv;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ /* Validate inputs */
+ if (sch->parent == TC_H_ROOT) {
+ pr_err("CEETM: a wbfs ceetm qdiscs can not be root\n");
+ return -EINVAL;
+ }
+
+ root_qdisc = dev->qdisc;
+
+ if (strcmp(root_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
+ return -EINVAL;
+ }
+
+ root_priv = qdisc_priv(root_qdisc);
+
+ /* Obtain the root ceetm class and the parent prio ceetm qdisc */
+ for (i = 0; i < root_priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(tmp_cl, &root_priv->clhash.hash[i],
+ common.hnode) {
+ if (tmp_cl->root.child &&
+ (TC_H_MAJ(tmp_cl->root.child->handle) ==
+ TC_H_MAJ(sch->parent))) {
+ parent_qdisc = tmp_cl->root.child;
+ root_cl = tmp_cl;
+ break;
+ }
+ }
+ }
+
+ if (!parent_qdisc ||
+ strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
+ return -EINVAL;
+ }
+
+ /* Obtain the parent prio ceetm class */
+ parent_cl = ceetm_find(sch->parent, parent_qdisc);
+
+ if (!parent_cl || parent_cl->type != CEETM_PRIO) {
+ pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n");
+ return -EINVAL;
+ }
+
+ if (!qopt->qcount || !qopt->qweight[0]) {
+ pr_err("CEETM: qcount and qweight are mandatory for a wbfs ceetm qdisc\n");
+ return -EINVAL;
+ }
+
+ priv->shaped = parent_cl->shaped;
+
+ if (!priv->shaped && (qopt->cr || qopt->er)) {
+ pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
+ return -EINVAL;
+ }
+
+ if (priv->shaped && !(qopt->cr || qopt->er)) {
+ pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
+ return -EINVAL;
+ }
+
+ if ((root_cl->root.wbfs_grp_a && root_cl->root.wbfs_grp_b) ||
+ root_cl->root.wbfs_grp_large) {
+ pr_err("CEETM: no more wbfs classes are available\n");
+ return -EINVAL;
+ }
+
+ if ((root_cl->root.wbfs_grp_a || root_cl->root.wbfs_grp_b) &&
+ qopt->qcount == CEETM_MAX_WBFS_QCOUNT) {
+ pr_err("CEETM: only %d wbfs classes are available\n",
+ CEETM_MIN_WBFS_QCOUNT);
+ return -EINVAL;
+ }
+
+ priv->wbfs.parent = parent_cl;
+ parent_cl->prio.child = sch;
+
+ priv->wbfs.qcount = qopt->qcount;
+ priv->wbfs.cr = qopt->cr;
+ priv->wbfs.er = qopt->er;
+ priv->wbfs.ch = parent_cl->ch;
+
+ /* Configure the hardware wbfs channel groups */
+ if (priv->wbfs.qcount == CEETM_MAX_WBFS_QCOUNT) {
+ /* Configure the large group A */
+ priv->wbfs.group_type = WBFS_GRP_LARGE;
+ small_group = false;
+ group_b = false;
+ prio_a = TC_H_MIN(parent_cl->common.classid) - 1;
+ prio_b = prio_a;
+
+ } else if (root_cl->root.wbfs_grp_a) {
+ /* Configure the group B */
+ priv->wbfs.group_type = WBFS_GRP_B;
+
+ err = qman_ceetm_channel_get_group(priv->wbfs.ch, &small_group,
+ &prio_a, &prio_b);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+ __func__);
+ return err;
+ }
+
+ small_group = true;
+ group_b = true;
+ prio_b = TC_H_MIN(parent_cl->common.classid) - 1;
+ /* If group A isn't configured, configure it as group B */
+ prio_a = prio_a ? : prio_b;
+
+ } else {
+ /* Configure the small group A */
+ priv->wbfs.group_type = WBFS_GRP_A;
+
+ err = qman_ceetm_channel_get_group(priv->wbfs.ch, &small_group,
+ &prio_a, &prio_b);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to get group details\n",
+ __func__);
+ return err;
+ }
+
+ small_group = true;
+ group_b = false;
+ prio_a = TC_H_MIN(parent_cl->common.classid) - 1;
+ /* If group B isn't configured, configure it as group A */
+ prio_b = prio_b ? : prio_a;
+ }
+
+ err = qman_ceetm_channel_set_group(priv->wbfs.ch, small_group, prio_a,
+ prio_b);
+ if (err)
+ return err;
+
+ if (priv->shaped) {
+ err = qman_ceetm_channel_set_group_cr_eligibility(priv->wbfs.ch,
+ group_b,
+ priv->wbfs.cr);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to set group CR eligibility\n",
+ __func__);
+ return err;
+ }
+
+ err = qman_ceetm_channel_set_group_er_eligibility(priv->wbfs.ch,
+ group_b,
+ priv->wbfs.er);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to set group ER eligibility\n",
+ __func__);
+ return err;
+ }
+ }
+
+ /* Create qcount child classes */
+ for (i = 0; i < priv->wbfs.qcount; i++) {
+ child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL);
+ if (!child_cl)
+ return -ENOMEM;
+
+ child_cl->wbfs.cstats = alloc_percpu(struct ceetm_class_stats);
+ if (!child_cl->wbfs.cstats) {
+ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
+ __func__);
+ err = -ENOMEM;
+ goto err_init_wbfs_cls;
+ }
+
+ child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1));
+ child_cl->parent = sch;
+ child_cl->type = CEETM_WBFS;
+ child_cl->shaped = priv->shaped;
+ child_cl->wbfs.fq = NULL;
+ child_cl->wbfs.cq = NULL;
+ child_cl->wbfs.weight = qopt->qweight[i];
+ child_cl->ch = priv->wbfs.ch;
+
+ if (priv->wbfs.group_type == WBFS_GRP_B)
+ id = WBFS_GRP_B_OFFSET + i;
+ else
+ id = WBFS_GRP_A_OFFSET + i;
+
+ err = ceetm_config_wbfs_cls(child_cl, dev, id,
+ priv->wbfs.group_type);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n",
+ __func__, child_cl->common.classid);
+ goto err_init_wbfs_cls;
+ }
+
+ /* Add class handle in Qdisc */
+ ceetm_link_class(sch, &priv->clhash, &child_cl->common);
+ pr_debug(KBUILD_BASENAME " : %s : added ceetm wbfs class %X associated with CQ %d and CCG %d\n",
+ __func__, child_cl->common.classid,
+ child_cl->wbfs.cq->idx, child_cl->wbfs.ccg->idx);
+ }
+
+ /* Signal the root class that a group has been configured */
+ switch (priv->wbfs.group_type) {
+ case WBFS_GRP_LARGE:
+ root_cl->root.wbfs_grp_large = true;
+ break;
+ case WBFS_GRP_A:
+ root_cl->root.wbfs_grp_a = true;
+ break;
+ case WBFS_GRP_B:
+ root_cl->root.wbfs_grp_b = true;
+ break;
+ }
+
+ return 0;
+
+err_init_wbfs_cls:
+ ceetm_cls_destroy(sch, child_cl);
+ /* Note: ceetm_destroy() will be called by our caller */
+ return err;
+}
+
+/* Configure a generic ceetm qdisc */
+static int ceetm_init(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct nlattr *tb[TCA_CEETM_QOPS + 1];
+ struct tc_ceetm_qopt *qopt;
+ int ret;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (!netif_is_multiqueue(dev))
+ return -EOPNOTSUPP;
+
+ if (!opt) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = tcf_block_get(&priv->block, &priv->filter_list, sch, extack);
+ if (ret)
+ return ret;
+
+ ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt,
+ ceetm_policy, NULL);
+ if (ret < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return ret;
+ }
+
+ if (!tb[TCA_CEETM_QOPS]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ if (TC_H_MIN(sch->handle)) {
+ pr_err("CEETM: a qdisc should not have a minor\n");
+ return -EINVAL;
+ }
+
+ qopt = nla_data(tb[TCA_CEETM_QOPS]);
+
+ /* Initialize the class hash list. Each qdisc has its own class hash */
+ ret = qdisc_class_hash_init(&priv->clhash);
+ if (ret < 0) {
+ pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n",
+ __func__);
+ return ret;
+ }
+
+ priv->type = qopt->type;
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ netif_tx_stop_all_queues(dev);
+ dpaa_drain_fqs(dev);
+ ret = ceetm_init_root(sch, priv, qopt, extack);
+ netif_tx_wake_all_queues(dev);
+ break;
+ case CEETM_PRIO:
+ ret = ceetm_init_prio(sch, priv, qopt);
+ break;
+ case CEETM_WBFS:
+ ret = ceetm_init_wbfs(sch, priv, qopt);
+ break;
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ /* Note: ceetm_destroy() will be called by our caller */
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/* Edit a root ceetm qdisc */
+static int ceetm_change_root(struct Qdisc *sch, struct ceetm_qdisc *priv,
+ struct net_device *dev,
+ struct tc_ceetm_qopt *qopt)
+{
+ int err = 0;
+ u64 bps;
+
+ if (priv->shaped != (bool)qopt->shaped) {
+ pr_err("CEETM: qdisc %X is %s\n", sch->handle,
+ priv->shaped ? "shaped" : "unshaped");
+ return -EINVAL;
+ }
+
+ /* Nothing to modify for unshaped qdiscs */
+ if (!priv->shaped)
+ return 0;
+
+ /* Configure the LNI shaper */
+ if (priv->root.overhead != qopt->overhead) {
+ err = qman_ceetm_lni_enable_shaper(priv->root.lni, 1,
+ qopt->overhead);
+ if (err)
+ goto change_err;
+ priv->root.overhead = qopt->overhead;
+ }
+
+ if (priv->root.rate != qopt->rate) {
+ bps = qopt->rate << 3; /* Bps -> bps */
+ err = qman_ceetm_lni_set_commit_rate_bps(priv->root.lni, bps,
+ dev->mtu);
+ if (err)
+ goto change_err;
+ priv->root.rate = qopt->rate;
+ }
+
+ if (priv->root.ceil != qopt->ceil) {
+ bps = qopt->ceil << 3; /* Bps -> bps */
+ err = qman_ceetm_lni_set_excess_rate_bps(priv->root.lni, bps,
+ dev->mtu);
+ if (err)
+ goto change_err;
+ priv->root.ceil = qopt->ceil;
+ }
+
+ return 0;
+
+change_err:
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the root ceetm qdisc %X\n",
+ __func__, sch->handle);
+ return err;
+}
+
+/* Edit a wbfs ceetm qdisc */
+static int ceetm_change_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv,
+ struct tc_ceetm_qopt *qopt)
+{
+ bool group_b;
+ int err;
+
+ if (qopt->qcount) {
+ pr_err("CEETM: the qcount can not be modified\n");
+ return -EINVAL;
+ }
+
+ if (qopt->qweight[0]) {
+ pr_err("CEETM: the qweight can be modified through the wbfs classes\n");
+ return -EINVAL;
+ }
+
+ if (!priv->shaped && (qopt->cr || qopt->er)) {
+ pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n");
+ return -EINVAL;
+ }
+
+ if (priv->shaped && !(qopt->cr || qopt->er)) {
+ pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n");
+ return -EINVAL;
+ }
+
+ /* Nothing to modify for unshaped qdiscs */
+ if (!priv->shaped)
+ return 0;
+
+ group_b = priv->wbfs.group_type == WBFS_GRP_B;
+
+ if (qopt->cr != priv->wbfs.cr) {
+ err = qman_ceetm_channel_set_group_cr_eligibility(priv->wbfs.ch,
+ group_b,
+ qopt->cr);
+ if (err)
+ goto change_err;
+ priv->wbfs.cr = qopt->cr;
+ }
+
+ if (qopt->er != priv->wbfs.er) {
+ err = qman_ceetm_channel_set_group_er_eligibility(priv->wbfs.ch,
+ group_b,
+ qopt->er);
+ if (err)
+ goto change_err;
+ priv->wbfs.er = qopt->er;
+ }
+
+ return 0;
+
+change_err:
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the wbfs ceetm qdisc %X\n",
+ __func__, sch->handle);
+ return err;
+}
+
+/* Edit a ceetm qdisc */
+static int ceetm_change(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct nlattr *tb[TCA_CEETM_QOPS + 1];
+ struct tc_ceetm_qopt *qopt;
+ int ret;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ ret = nla_parse_nested_deprecated(tb, TCA_CEETM_QOPS, opt,
+ ceetm_policy, NULL);
+ if (ret < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return ret;
+ }
+
+ if (!tb[TCA_CEETM_QOPS]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ if (TC_H_MIN(sch->handle)) {
+ pr_err("CEETM: a qdisc should not have a minor\n");
+ return -EINVAL;
+ }
+
+ qopt = nla_data(tb[TCA_CEETM_QOPS]);
+
+ if (priv->type != qopt->type) {
+ pr_err("CEETM: qdisc %X is not of the provided type\n",
+ sch->handle);
+ return -EINVAL;
+ }
+
+ switch (priv->type) {
+ case CEETM_ROOT:
+ ret = ceetm_change_root(sch, priv, dev, qopt);
+ break;
+ case CEETM_PRIO:
+ pr_err("CEETM: prio qdiscs can not be modified\n");
+ ret = -EINVAL;
+ break;
+ case CEETM_WBFS:
+ ret = ceetm_change_wbfs(sch, priv, qopt);
+ break;
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/* Graft the underlying pfifo qdiscs to the netdev queues.
+ * It's safe to remove our references at this point, since the kernel will
+ * destroy the qdiscs on its own and no cleanup from our part is required.
+ */
+static void ceetm_attach(struct Qdisc *sch)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct Qdisc *qdisc, *old_qdisc;
+ unsigned int i;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ qdisc = priv->root.qdiscs[i];
+ old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
+ if (old_qdisc)
+ qdisc_put(old_qdisc);
+ }
+
+ kfree(priv->root.qdiscs);
+ priv->root.qdiscs = NULL;
+}
+
+static unsigned long ceetm_cls_search(struct Qdisc *sch, u32 handle)
+{
+ return (unsigned long)ceetm_find(handle, sch);
+}
+
+static int ceetm_cls_change_root(struct ceetm_class *cl,
+ struct tc_ceetm_copt *copt,
+ struct net_device *dev)
+{
+ int err;
+ u64 bps;
+
+ if ((bool)copt->shaped != cl->shaped) {
+ pr_err("CEETM: class %X is %s\n", cl->common.classid,
+ cl->shaped ? "shaped" : "unshaped");
+ return -EINVAL;
+ }
+
+ if (cl->shaped && cl->root.rate != copt->rate) {
+ bps = copt->rate << 3; /* Bps -> bps */
+ err = qman_ceetm_channel_set_commit_rate_bps(cl->ch, bps,
+ dev->mtu);
+ if (err)
+ goto change_cls_err;
+ cl->root.rate = copt->rate;
+ }
+
+ if (cl->shaped && cl->root.ceil != copt->ceil) {
+ bps = copt->ceil << 3; /* Bps -> bps */
+ err = qman_ceetm_channel_set_excess_rate_bps(cl->ch, bps,
+ dev->mtu);
+ if (err)
+ goto change_cls_err;
+ cl->root.ceil = copt->ceil;
+ }
+
+ if (!cl->shaped && cl->root.tbl != copt->tbl) {
+ err = qman_ceetm_channel_set_weight(cl->ch, copt->tbl);
+ if (err)
+ goto change_cls_err;
+ cl->root.tbl = copt->tbl;
+ }
+
+ return 0;
+
+change_cls_err:
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm root class %X\n",
+ __func__, cl->common.classid);
+ return err;
+}
+
+static int ceetm_cls_change_prio(struct ceetm_class *cl,
+ struct tc_ceetm_copt *copt)
+{
+ int err;
+
+ if (!cl->shaped && (copt->cr || copt->er)) {
+ pr_err("CEETM: only shaped classes can have CR and ER enabled\n");
+ return -EINVAL;
+ }
+
+ if (cl->prio.cr != (bool)copt->cr) {
+ err = qman_ceetm_channel_set_cq_cr_eligibility
+ (cl->prio.cq->parent,
+ cl->prio.cq->idx,
+ copt->cr);
+ if (err)
+ goto change_cls_err;
+ cl->prio.cr = copt->cr;
+ }
+
+ if (cl->prio.er != (bool)copt->er) {
+ err = qman_ceetm_channel_set_cq_er_eligibility
+ (cl->prio.cq->parent,
+ cl->prio.cq->idx,
+ copt->er);
+ if (err)
+ goto change_cls_err;
+ cl->prio.er = copt->er;
+ }
+
+ return 0;
+
+change_cls_err:
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n",
+ __func__, cl->common.classid);
+ return err;
+}
+
+static int ceetm_cls_change_wbfs(struct ceetm_class *cl,
+ struct tc_ceetm_copt *copt)
+{
+ int err;
+
+ if (copt->weight != cl->wbfs.weight) {
+ /* Configure the CQ weight: real number multiplied by 100 to
+ * get rid of the fraction
+ */
+ err = qman_ceetm_set_queue_weight_in_ratio(cl->wbfs.cq,
+ copt->weight * 100);
+
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n",
+ __func__, cl->common.classid);
+ return err;
+ }
+
+ cl->wbfs.weight = copt->weight;
+ }
+
+ return 0;
+}
+
+/* Add a ceetm root class or configure a ceetm root/prio/wbfs class */
+static int ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
+ struct nlattr **tca, unsigned long *arg,
+ struct netlink_ext_ack *extack)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)*arg;
+ struct net_device *dev = qdisc_dev(sch);
+ struct nlattr *opt = tca[TCA_OPTIONS];
+ struct nlattr *tb[__TCA_CEETM_MAX];
+ struct qm_ceetm_channel *channel;
+ struct tc_ceetm_copt *copt;
+ struct ceetm_qdisc *priv;
+ int err;
+ u64 bps;
+
+ pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
+ __func__, classid, sch->handle);
+
+ if (strcmp(sch->ops->id, ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n");
+ return -EINVAL;
+ }
+
+ priv = qdisc_priv(sch);
+
+ if (!opt) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!cl && sch->handle != parentid) {
+ pr_err("CEETM: classes can be attached to the root ceetm qdisc only\n");
+ return -EINVAL;
+ }
+
+ if (!cl && priv->type != CEETM_ROOT) {
+ pr_err("CEETM: root ceetm classes can be attached to the root ceetm qdisc only\n");
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_CEETM_COPT, opt,
+ ceetm_policy, NULL);
+ if (err < 0) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!tb[TCA_CEETM_COPT]) {
+ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__);
+ return -EINVAL;
+ }
+
+ if (TC_H_MIN(classid) >= PFIFO_MIN_OFFSET) {
+ pr_err("CEETM: only minors 0x01 to 0x20 can be used for ceetm root classes\n");
+ return -EINVAL;
+ }
+
+ copt = nla_data(tb[TCA_CEETM_COPT]);
+
+ /* Configure an existing ceetm class */
+ if (cl) {
+ if (copt->type != cl->type) {
+ pr_err("CEETM: class %X is not of the provided type\n",
+ cl->common.classid);
+ return -EINVAL;
+ }
+
+ switch (copt->type) {
+ case CEETM_ROOT:
+ return ceetm_cls_change_root(cl, copt, dev);
+
+ case CEETM_PRIO:
+ return ceetm_cls_change_prio(cl, copt);
+
+ case CEETM_WBFS:
+ return ceetm_cls_change_wbfs(cl, copt);
+
+ default:
+ pr_err(KBUILD_BASENAME " : %s : invalid class\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ /* Add a new root ceetm class */
+ if (copt->type != CEETM_ROOT) {
+ pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n");
+ return -EINVAL;
+ }
+
+ if (copt->shaped && !priv->shaped) {
+ pr_err("CEETM: can not add a shaped ceetm root class under an unshaped ceetm root qdisc\n");
+ return -EINVAL;
+ }
+
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
+ if (err) {
+ kfree(cl);
+ return err;
+ }
+
+ cl->type = copt->type;
+ cl->shaped = copt->shaped;
+ cl->root.rate = copt->rate;
+ cl->root.ceil = copt->ceil;
+ cl->root.tbl = copt->tbl;
+
+ cl->common.classid = classid;
+ cl->parent = sch;
+ cl->root.child = NULL;
+ cl->root.wbfs_grp_a = false;
+ cl->root.wbfs_grp_b = false;
+ cl->root.wbfs_grp_large = false;
+
+ /* Claim a CEETM channel */
+ err = qman_ceetm_channel_claim(&channel, priv->root.lni);
+ if (err) {
+ pr_err(KBUILD_BASENAME " : %s : failed to claim a channel\n",
+ __func__);
+ goto claim_err;
+ }
+
+ cl->ch = channel;
+
+ if (cl->shaped) {
+ /* Configure the channel shaper */
+ err = qman_ceetm_channel_enable_shaper(channel, 1);
+ if (err)
+ goto channel_err;
+
+ bps = cl->root.rate << 3; /* Bps -> bps */
+ err = qman_ceetm_channel_set_commit_rate_bps(channel, bps,
+ dev->mtu);
+ if (err)
+ goto channel_err;
+
+ bps = cl->root.ceil << 3; /* Bps -> bps */
+ err = qman_ceetm_channel_set_excess_rate_bps(channel, bps,
+ dev->mtu);
+ if (err)
+ goto channel_err;
+
+ } else {
+ /* Configure the uFQ algorithm */
+ err = qman_ceetm_channel_set_weight(channel, cl->root.tbl);
+ if (err)
+ goto channel_err;
+ }
+
+ /* Add class handle in Qdisc */
+ ceetm_link_class(sch, &priv->clhash, &cl->common);
+
+ pr_debug(KBUILD_BASENAME " : %s : configured class %X associated with channel %d\n",
+ __func__, classid, channel->idx);
+ *arg = (unsigned long)cl;
+ return 0;
+
+channel_err:
+ pr_err(KBUILD_BASENAME " : %s : failed to configure the channel %d\n",
+ __func__, channel->idx);
+ if (qman_ceetm_channel_release(channel))
+ pr_err(KBUILD_BASENAME " : %s : failed to release the channel %d\n",
+ __func__, channel->idx);
+claim_err:
+ tcf_block_put(cl->block);
+ kfree(cl);
+ return err;
+}
+
+static void ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct ceetm_class *cl;
+ unsigned int i;
+
+ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
+
+ if (arg->stop)
+ return;
+
+ for (i = 0; i < priv->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+ arg->stop = 1;
+ return;
+ }
+ arg->count++;
+ }
+ }
+}
+
+static int ceetm_cls_dump(struct Qdisc *sch, unsigned long arg,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+ struct tc_ceetm_copt copt;
+ struct nlattr *nest;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ sch_tree_lock(sch);
+
+ tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle;
+ tcm->tcm_handle = cl->common.classid;
+
+ memset(&copt, 0, sizeof(copt));
+
+ copt.shaped = cl->shaped;
+ copt.type = cl->type;
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ if (cl->root.child)
+ tcm->tcm_info = cl->root.child->handle;
+
+ copt.rate = cl->root.rate;
+ copt.ceil = cl->root.ceil;
+ copt.tbl = cl->root.tbl;
+ break;
+
+ case CEETM_PRIO:
+ if (cl->prio.child)
+ tcm->tcm_info = cl->prio.child->handle;
+
+ copt.cr = cl->prio.cr;
+ copt.er = cl->prio.er;
+ break;
+
+ case CEETM_WBFS:
+ copt.weight = cl->wbfs.weight;
+ break;
+ }
+
+ nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
+ if (!nest)
+ goto nla_put_failure;
+ if (nla_put(skb, TCA_CEETM_COPT, sizeof(copt), &copt))
+ goto nla_put_failure;
+ nla_nest_end(skb, nest);
+ sch_tree_unlock(sch);
+ return skb->len;
+
+nla_put_failure:
+ sch_tree_unlock(sch);
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+static int ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ sch_tree_lock(sch);
+ qdisc_class_hash_remove(&priv->clhash, &cl->common);
+
+ sch_tree_unlock(sch);
+ ceetm_cls_destroy(sch, cl);
+ return 0;
+}
+
+/* Get the class' child qdisc, if any */
+static struct Qdisc *ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
+ __func__, cl->common.classid, sch->handle);
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ return cl->root.child;
+
+ case CEETM_PRIO:
+ return cl->prio.child;
+ }
+
+ return NULL;
+}
+
+static int ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old,
+ struct netlink_ext_ack *extack)
+{
+ if (new && strcmp(new->ops->id, ceetm_qdisc_ops.id)) {
+ pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
+ struct gnet_dump *d)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+ struct gnet_stats_basic_packed tmp_bstats;
+ struct ceetm_class_stats *cstats = NULL;
+ struct qm_ceetm_cq *cq = NULL;
+ struct tc_ceetm_xstats xstats;
+ unsigned int i;
+
+ memset(&xstats, 0, sizeof(xstats));
+ memset(&tmp_bstats, 0, sizeof(tmp_bstats));
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ return 0;
+ case CEETM_PRIO:
+ cq = cl->prio.cq;
+ break;
+ case CEETM_WBFS:
+ cq = cl->wbfs.cq;
+ break;
+ }
+
+ for_each_online_cpu(i) {
+ switch (cl->type) {
+ case CEETM_PRIO:
+ cstats = per_cpu_ptr(cl->prio.cstats, i);
+ break;
+ case CEETM_WBFS:
+ cstats = per_cpu_ptr(cl->wbfs.cstats, i);
+ break;
+ }
+
+ if (cstats) {
+ xstats.ern_drop_count += cstats->ern_drop_count;
+ xstats.congested_count += cstats->congested_count;
+ tmp_bstats.bytes += cstats->bstats.bytes;
+ tmp_bstats.packets += cstats->bstats.packets;
+ }
+ }
+
+ if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
+ d, NULL, &tmp_bstats) < 0)
+ return -1;
+
+ if (cq && qman_ceetm_cq_get_dequeue_statistics(cq, 0,
+ &xstats.frame_count,
+ &xstats.byte_count))
+ return -1;
+
+ return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static struct tcf_block *ceetm_tcf_block(struct Qdisc *sch, unsigned long arg,
+ struct netlink_ext_ack *extack)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct tcf_block *block;
+
+ block = cl ? cl->block : priv->block;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+ return block;
+}
+
+static unsigned long ceetm_tcf_bind(struct Qdisc *sch, unsigned long parent,
+ u32 classid)
+{
+ struct ceetm_class *cl = ceetm_find(classid, sch);
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+ return (unsigned long)cl;
+}
+
+static void ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg)
+{
+ struct ceetm_class *cl = (struct ceetm_class *)arg;
+
+ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
+ cl ? cl->common.classid : 0, sch->handle);
+}
+
+const struct Qdisc_class_ops ceetm_cls_ops = {
+ .graft = ceetm_cls_graft,
+ .leaf = ceetm_cls_leaf,
+ .find = ceetm_cls_search,
+ .change = ceetm_cls_change,
+ .delete = ceetm_cls_delete,
+ .walk = ceetm_cls_walk,
+ .tcf_block = ceetm_tcf_block,
+ .bind_tcf = ceetm_tcf_bind,
+ .unbind_tcf = ceetm_tcf_unbind,
+ .dump = ceetm_cls_dump,
+ .dump_stats = ceetm_cls_dump_stats,
+};
+
+struct Qdisc_ops ceetm_qdisc_ops __read_mostly = {
+ .id = "ceetm",
+ .priv_size = sizeof(struct ceetm_qdisc),
+ .cl_ops = &ceetm_cls_ops,
+ .init = ceetm_init,
+ .destroy = ceetm_destroy,
+ .change = ceetm_change,
+ .dump = ceetm_dump,
+ .attach = ceetm_attach,
+ .owner = THIS_MODULE,
+};
+
+/* Run the filters and classifiers attached to the qdisc on the provided skb */
+static struct ceetm_class *ceetm_classify(struct sk_buff *skb,
+ struct Qdisc *sch, int *qerr,
+ bool *act_drop)
+{
+ struct ceetm_qdisc *priv = qdisc_priv(sch);
+ struct ceetm_class *cl = NULL, *wbfs_cl;
+ struct tcf_result res;
+ struct tcf_proto *tcf;
+ int result;
+
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+ tcf = priv->filter_list;
+ while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ case TC_ACT_TRAP:
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+ /* fall through */
+ case TC_ACT_SHOT:
+ /* No valid class found due to action */
+ *act_drop = true;
+ return NULL;
+ }
+#endif
+ cl = (void *)res.class;
+ if (!cl) {
+ if (res.classid == sch->handle) {
+ /* The filter leads to the qdisc */
+ /* TODO default qdisc */
+ return NULL;
+ }
+
+ cl = ceetm_find(res.classid, sch);
+ if (!cl)
+ /* The filter leads to an invalid class */
+ break;
+ }
+
+ /* The class might have its own filters attached */
+ tcf = cl->filter_list;
+ }
+
+ if (!cl) {
+ /* No valid class found */
+ /* TODO default qdisc */
+ return NULL;
+ }
+
+ switch (cl->type) {
+ case CEETM_ROOT:
+ if (cl->root.child) {
+ /* Run the prio qdisc classifiers */
+ return ceetm_classify(skb, cl->root.child, qerr,
+ act_drop);
+ } else {
+ /* The root class does not have a child prio qdisc */
+ /* TODO default qdisc */
+ return NULL;
+ }
+ case CEETM_PRIO:
+ if (cl->prio.child) {
+ /* If filters lead to a wbfs class, return it.
+ * Otherwise, return the prio class
+ */
+ wbfs_cl = ceetm_classify(skb, cl->prio.child, qerr,
+ act_drop);
+ /* A NULL result might indicate either an erroneous
+ * filter, or no filters at all. We will assume the
+ * latter
+ */
+ return wbfs_cl ? : cl;
+ }
+ }
+
+ /* For wbfs and childless prio classes, return the class directly */
+ return cl;
+}
+
+int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev)
+{
+ int queue_mapping = dpa_get_queue_mapping(skb);
+ struct Qdisc *sch = net_dev->qdisc;
+ struct ceetm_class_stats *cstats;
+ struct ceetm_qdisc_stats *qstats;
+ struct dpa_priv_s *priv_dpa;
+ struct ceetm_fq *ceetm_fq;
+ struct ceetm_qdisc *priv;
+ struct qman_fq *conf_fq;
+ struct ceetm_class *cl;
+ spinlock_t *root_lock;
+ bool act_drop = false;
+ int ret;
+
+ root_lock = qdisc_lock(sch);
+ priv = qdisc_priv(sch);
+ qstats = this_cpu_ptr(priv->root.qstats);
+
+ spin_lock(root_lock);
+ cl = ceetm_classify(skb, sch, &ret, &act_drop);
+ spin_unlock(root_lock);
+
+#ifdef CONFIG_NET_CLS_ACT
+ if (act_drop) {
+ if (ret & __NET_XMIT_BYPASS)
+ qstats->drops++;
+ goto drop;
+ }
+#endif
+ /* TODO default class */
+ if (unlikely(!cl)) {
+ qstats->drops++;
+ goto drop;
+ }
+
+ if (unlikely(queue_mapping >= DPAA_ETH_TX_QUEUES))
+ queue_mapping = queue_mapping % DPAA_ETH_TX_QUEUES;
+
+ priv_dpa = netdev_priv(net_dev);
+ conf_fq = priv_dpa->conf_fqs[queue_mapping];
+
+ /* Choose the proper tx fq and update the basic stats (bytes and
+ * packets sent by the class)
+ */
+ switch (cl->type) {
+ case CEETM_PRIO:
+ ceetm_fq = cl->prio.fq;
+ cstats = this_cpu_ptr(cl->prio.cstats);
+ break;
+ case CEETM_WBFS:
+ ceetm_fq = cl->wbfs.fq;
+ cstats = this_cpu_ptr(cl->wbfs.cstats);
+ break;
+ default:
+ qstats->drops++;
+ goto drop;
+ }
+
+ /* If the FQ is congested, avoid enqueuing the frame and dropping it
+ * when it returns on the ERN path. Drop it here directly instead.
+ */
+ if (unlikely(ceetm_fq->congested)) {
+ qstats->drops++;
+ goto drop;
+ }
+
+ bstats_update(&cstats->bstats, skb);
+ return dpa_tx_extended(skb, net_dev, &ceetm_fq->fq, conf_fq);
+
+drop:
+ dev_kfree_skb_any(skb);
+ return NET_XMIT_SUCCESS;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
new file mode 100644
index 000000000000..66edc82da8c2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h
@@ -0,0 +1,241 @@
+/* Copyright 2008-2016 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DPAA_ETH_CEETM_H
+#define __DPAA_ETH_CEETM_H
+
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+#include <net/netlink.h>
+#include <lnxwrp_fm.h>
+
+#include "mac.h"
+#include "dpaa_eth_common.h"
+
+/* Mask to determine the sub-portal id from a channel number */
+#define CHANNEL_SP_MASK 0x1f
+/* The number of the last channel that services DCP0, connected to FMan 0.
+ * Value validated for B4 and T series platforms.
+ */
+#define DCP0_MAX_CHANNEL 0x80f
+/* A2V=1 - field A2 is valid
+ * A0V=1 - field A0 is valid - enables frame confirmation
+ * OVOM=1 - override operation mode bits with values from A2
+ * EBD=1 - external buffers are deallocated at the end of the FMan flow
+ * NL=0 - the BMI releases all the internal buffers
+ */
+#define CEETM_CONTEXT_A 0x1a00000080000000
+/* The ratio between the superior and inferior congestion state thresholds. The
+ * lower threshold is set to 7/8 of the superior one (as the default for WQ
+ * scheduling).
+ */
+#define CEETM_CCGR_RATIO 0.875
+/* For functional purposes, there are num_tx_queues pfifo qdiscs through which
+ * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20
+ * are reserved for the maximum 32 CEETM channels (majors and minors are in
+ * hex).
+ */
+#define PFIFO_MIN_OFFSET 0x21
+
+/* A maximum of 8 CQs can be linked to a CQ channel or to a WBFS scheduler. */
+#define CEETM_MAX_PRIO_QCOUNT 8
+#define CEETM_MAX_WBFS_QCOUNT 8
+#define CEETM_MIN_WBFS_QCOUNT 4
+
+/* The id offsets of the CQs belonging to WBFS groups (ids 8-11/15 for group A
+ * and/or 12-15 for group B).
+ */
+#define WBFS_GRP_A_OFFSET 8
+#define WBFS_GRP_B_OFFSET 12
+
+#define WBFS_GRP_A 1
+#define WBFS_GRP_B 2
+#define WBFS_GRP_LARGE 3
+
+enum {
+ TCA_CEETM_UNSPEC,
+ TCA_CEETM_COPT,
+ TCA_CEETM_QOPS,
+ __TCA_CEETM_MAX,
+};
+
+/* CEETM configuration types */
+enum {
+ CEETM_ROOT = 1,
+ CEETM_PRIO,
+ CEETM_WBFS
+};
+
+#define TCA_CEETM_MAX (__TCA_CEETM_MAX - 1)
+extern const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1];
+
+struct ceetm_class;
+struct ceetm_qdisc_stats;
+struct ceetm_class_stats;
+
+struct ceetm_fq {
+ struct qman_fq fq;
+ struct net_device *net_dev;
+ struct ceetm_class *ceetm_cls;
+ int congested; /* Congestion status */
+};
+
+struct root_q {
+ struct Qdisc **qdiscs;
+ __u16 overhead;
+ __u32 rate;
+ __u32 ceil;
+ struct qm_ceetm_sp *sp;
+ struct qm_ceetm_lni *lni;
+ struct ceetm_qdisc_stats __percpu *qstats;
+};
+
+struct prio_q {
+ __u16 qcount;
+ struct ceetm_class *parent;
+ struct qm_ceetm_channel *ch;
+};
+
+struct wbfs_q {
+ __u16 qcount;
+ int group_type;
+ struct ceetm_class *parent;
+ struct qm_ceetm_channel *ch;
+ __u16 cr;
+ __u16 er;
+};
+
+struct ceetm_qdisc {
+ int type; /* LNI/CHNL/WBFS */
+ bool shaped;
+ union {
+ struct root_q root;
+ struct prio_q prio;
+ struct wbfs_q wbfs;
+ };
+ struct Qdisc_class_hash clhash;
+ struct tcf_proto *filter_list; /* qdisc attached filters */
+ struct tcf_block *block;
+};
+
+/* CEETM Qdisc configuration parameters */
+struct tc_ceetm_qopt {
+ __u32 type;
+ __u16 shaped;
+ __u16 qcount;
+ __u16 overhead;
+ __u32 rate;
+ __u32 ceil;
+ __u16 cr;
+ __u16 er;
+ __u8 qweight[CEETM_MAX_WBFS_QCOUNT];
+};
+
+struct root_c {
+ unsigned int rate;
+ unsigned int ceil;
+ unsigned int tbl;
+ bool wbfs_grp_a;
+ bool wbfs_grp_b;
+ bool wbfs_grp_large;
+ struct Qdisc *child;
+};
+
+struct prio_c {
+ bool cr;
+ bool er;
+ struct ceetm_fq *fq; /* Hardware FQ instance Handle */
+ struct qm_ceetm_lfq *lfq;
+ struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */
+ struct qm_ceetm_ccg *ccg;
+ /* only one wbfs can be linked to one priority CQ */
+ struct Qdisc *child;
+ struct ceetm_class_stats __percpu *cstats;
+};
+
+struct wbfs_c {
+ __u8 weight; /* The weight of the class between 1 and 248 */
+ struct ceetm_fq *fq; /* Hardware FQ instance Handle */
+ struct qm_ceetm_lfq *lfq;
+ struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */
+ struct qm_ceetm_ccg *ccg;
+ struct ceetm_class_stats __percpu *cstats;
+};
+
+struct ceetm_class {
+ struct Qdisc_class_common common;
+ struct tcf_proto *filter_list; /* class attached filters */
+ struct tcf_block *block;
+ struct Qdisc *parent;
+ struct qm_ceetm_channel *ch;
+ bool shaped;
+ int type; /* ROOT/PRIO/WBFS */
+ union {
+ struct root_c root;
+ struct prio_c prio;
+ struct wbfs_c wbfs;
+ };
+};
+
+/* CEETM Class configuration parameters */
+struct tc_ceetm_copt {
+ __u32 type;
+ __u16 shaped;
+ __u32 rate;
+ __u32 ceil;
+ __u16 tbl;
+ __u16 cr;
+ __u16 er;
+ __u8 weight;
+};
+
+/* CEETM stats */
+struct ceetm_qdisc_stats {
+ __u32 drops;
+};
+
+struct ceetm_class_stats {
+ /* Software counters */
+ struct gnet_stats_basic_packed bstats;
+ __u32 ern_drop_count;
+ __u32 congested_count;
+};
+
+struct tc_ceetm_xstats {
+ __u32 ern_drop_count;
+ __u32 congested_count;
+ /* Hardware counters */
+ __u64 frame_count;
+ __u64 byte_count;
+};
+
+int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev);
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
new file mode 100644
index 000000000000..548e6bd24683
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
@@ -0,0 +1,1746 @@
+/* Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/etherdevice.h>
+#include <linux/kthread.h>
+#include <linux/percpu.h>
+#include <linux/highmem.h>
+#include <linux/sort.h>
+#include <linux/fsl_qman.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h> /* vlan_eth_hdr */
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#ifdef CONFIG_FSL_DPAA_1588
+#include "dpaa_1588.h"
+#endif
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+#include "dpaa_debugfs.h"
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+#include "mac.h"
+
+/* Size in bytes of the FQ taildrop threshold */
+#define DPA_FQ_TD 0x200000
+
+static struct dpa_bp *dpa_bp_array[64];
+
+int dpa_max_frm;
+EXPORT_SYMBOL(dpa_max_frm);
+
+int dpa_rx_extra_headroom;
+EXPORT_SYMBOL(dpa_rx_extra_headroom);
+
+int dpa_num_cpus = NR_CPUS;
+
+static const struct fqid_cell tx_confirm_fqids[] = {
+ {0, DPAA_ETH_TX_QUEUES}
+};
+
+static struct fqid_cell default_fqids[][3] = {
+ [RX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_RX_QUEUES} },
+ [TX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_TX_QUEUES} }
+};
+
+static const char fsl_qman_frame_queues[][25] = {
+ [RX] = "fsl,qman-frame-queues-rx",
+ [TX] = "fsl,qman-frame-queues-tx"
+};
+#ifdef CONFIG_FSL_DPAA_HOOKS
+/* A set of callbacks for hooking into the fastpath at different points. */
+struct dpaa_eth_hooks_s dpaa_eth_hooks;
+EXPORT_SYMBOL(dpaa_eth_hooks);
+/* This function should only be called on the probe paths, since it makes no
+ * effort to guarantee consistency of the destination hooks structure.
+ */
+void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks)
+{
+ if (hooks)
+ dpaa_eth_hooks = *hooks;
+ else
+ pr_err("NULL pointer to hooks!\n");
+}
+EXPORT_SYMBOL(fsl_dpaa_eth_set_hooks);
+#endif
+
+int dpa_netdev_init(struct net_device *net_dev,
+ const uint8_t *mac_addr,
+ uint16_t tx_timeout)
+{
+ int err;
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct device *dev = net_dev->dev.parent;
+
+ net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
+ net_dev->features |= net_dev->hw_features;
+ net_dev->vlan_features = net_dev->features;
+
+ memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len);
+ memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len);
+
+ net_dev->ethtool_ops = &dpa_ethtool_ops;
+
+ net_dev->needed_headroom = priv->tx_headroom;
+ net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout);
+
+ err = register_netdev(net_dev);
+ if (err < 0) {
+ dev_err(dev, "register_netdev() = %d\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ /* create debugfs entry for this net_device */
+ err = dpa_netdev_debugfs_create(net_dev);
+ if (err) {
+ unregister_netdev(net_dev);
+ return err;
+ }
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_netdev_init);
+
+int __cold dpa_start(struct net_device *net_dev)
+{
+ int err, i;
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ err = mac_dev->init_phy(net_dev, priv->mac_dev);
+ if (err < 0) {
+ if (netif_msg_ifup(priv))
+ netdev_err(net_dev, "init_phy() = %d\n", err);
+ return err;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ err = fm_port_enable(mac_dev->port_dev[i]);
+ if (err)
+ goto mac_start_failed;
+ }
+
+ err = priv->mac_dev->start(mac_dev);
+ if (err < 0) {
+ if (netif_msg_ifup(priv))
+ netdev_err(net_dev, "mac_dev->start() = %d\n", err);
+ goto mac_start_failed;
+ }
+
+ netif_tx_start_all_queues(net_dev);
+
+ return 0;
+
+mac_start_failed:
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_disable(mac_dev->port_dev[i]);
+
+ return err;
+}
+EXPORT_SYMBOL(dpa_start);
+
+int __cold dpa_stop(struct net_device *net_dev)
+{
+ int _errno, i, err;
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ netif_tx_stop_all_queues(net_dev);
+ /* Allow the Fman (Tx) port to process in-flight frames before we
+ * try switching it off.
+ */
+ usleep_range(5000, 10000);
+
+ _errno = mac_dev->stop(mac_dev);
+ if (unlikely(_errno < 0))
+ if (netif_msg_ifdown(priv))
+ netdev_err(net_dev, "mac_dev->stop() = %d\n",
+ _errno);
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ err = fm_port_disable(mac_dev->port_dev[i]);
+ _errno = err ? err : _errno;
+ }
+
+ if (mac_dev->phy_dev)
+ phy_disconnect(mac_dev->phy_dev);
+ mac_dev->phy_dev = NULL;
+
+ return _errno;
+}
+EXPORT_SYMBOL(dpa_stop);
+
+void __cold dpa_timeout(struct net_device *net_dev)
+{
+ const struct dpa_priv_s *priv;
+ struct dpa_percpu_priv_s *percpu_priv;
+
+ priv = netdev_priv(net_dev);
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+
+ if (netif_msg_timer(priv))
+ netdev_crit(net_dev, "Transmit timeout!\n");
+
+ percpu_priv->stats.tx_errors++;
+}
+EXPORT_SYMBOL(dpa_timeout);
+
+/* net_device */
+
+/**
+ * @param net_dev the device for which statistics are calculated
+ * @param stats the function fills this structure with the device's statistics
+ * @return the address of the structure containing the statistics
+ *
+ * Calculates the statistics for the given device by adding the statistics
+ * collected by each CPU.
+ */
+void __cold
+dpa_get_stats64(struct net_device *net_dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ u64 *cpustats;
+ u64 *netstats = (u64 *)stats;
+ int i, j;
+ struct dpa_percpu_priv_s *percpu_priv;
+ int numstats = sizeof(struct rtnl_link_stats64) / sizeof(u64);
+
+ for_each_possible_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+
+ cpustats = (u64 *)&percpu_priv->stats;
+
+ for (j = 0; j < numstats; j++)
+ netstats[j] += cpustats[j];
+ }
+}
+EXPORT_SYMBOL(dpa_get_stats64);
+
+/* .ndo_init callback */
+int dpa_ndo_init(struct net_device *net_dev)
+{
+ /* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
+ * we choose conservatively and let the user explicitly set a higher
+ * MTU via ifconfig. Otherwise, the user may end up with different MTUs
+ * in the same LAN.
+ * If on the other hand fsl_fm_max_frm has been chosen below 1500,
+ * start with the maximum allowed.
+ */
+ int init_mtu = min(dpa_get_max_mtu(), ETH_DATA_LEN);
+
+ pr_debug("Setting initial MTU on net device: %d\n", init_mtu);
+ net_dev->mtu = init_mtu;
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_ndo_init);
+
+int dpa_set_features(struct net_device *dev, netdev_features_t features)
+{
+ /* Not much to do here for now */
+ dev->features = features;
+ return 0;
+}
+EXPORT_SYMBOL(dpa_set_features);
+
+netdev_features_t dpa_fix_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ netdev_features_t unsupported_features = 0;
+
+ /* In theory we should never be requested to enable features that
+ * we didn't set in netdev->features and netdev->hw_features at probe
+ * time, but double check just to be on the safe side.
+ * We don't support enabling Rx csum through ethtool yet
+ */
+ unsupported_features |= NETIF_F_RXCSUM;
+
+ features &= ~unsupported_features;
+
+ return features;
+}
+EXPORT_SYMBOL(dpa_fix_features);
+
+#ifdef CONFIG_FSL_DPAA_TS
+u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv, enum port_type rx_tx,
+ const void *data)
+{
+ u64 *ts;
+
+ ts = fm_port_get_buffer_time_stamp(priv->mac_dev->port_dev[rx_tx],
+ data);
+
+ if (!ts || *ts == 0)
+ return 0;
+
+ be64_to_cpus(ts);
+
+ return *ts;
+}
+
+int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
+ struct skb_shared_hwtstamps *shhwtstamps, const void *data)
+{
+ u64 ns;
+
+ ns = dpa_get_timestamp_ns(priv, rx_tx, data);
+
+ if (ns == 0)
+ return -EINVAL;
+
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+
+ return 0;
+}
+
+static void dpa_ts_tx_enable(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+ struct mac_device *mac_dev = priv->mac_dev;
+
+ if (mac_dev->ptp_enable)
+ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
+
+ priv->ts_tx_en = true;
+}
+
+static void dpa_ts_tx_disable(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+
+#if 0
+/* the RTC might be needed by the Rx Ts, cannot disable here
+ * no separate ptp_disable API for Rx/Tx, cannot disable here
+ */
+ struct mac_device *mac_dev = priv->mac_dev;
+
+ if (mac_dev->fm_rtc_disable)
+ mac_dev->fm_rtc_disable(get_fm_handle(dev));
+
+ if (mac_dev->ptp_disable)
+ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
+#endif
+
+ priv->ts_tx_en = false;
+}
+
+static void dpa_ts_rx_enable(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+ struct mac_device *mac_dev = priv->mac_dev;
+
+ if (mac_dev->ptp_enable)
+ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev));
+
+ priv->ts_rx_en = true;
+}
+
+static void dpa_ts_rx_disable(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+
+#if 0
+/* the RTC might be needed by the Tx Ts, cannot disable here
+ * no separate ptp_disable API for Rx/Tx, cannot disable here
+ */
+ struct mac_device *mac_dev = priv->mac_dev;
+
+ if (mac_dev->fm_rtc_disable)
+ mac_dev->fm_rtc_disable(get_fm_handle(dev));
+
+ if (mac_dev->ptp_disable)
+ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev));
+#endif
+
+ priv->ts_rx_en = false;
+}
+
+static int dpa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct hwtstamp_config config;
+
+ if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ dpa_ts_tx_disable(dev);
+ break;
+ case HWTSTAMP_TX_ON:
+ dpa_ts_tx_enable(dev);
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (config.rx_filter == HWTSTAMP_FILTER_NONE)
+ dpa_ts_rx_disable(dev);
+ else {
+ dpa_ts_rx_enable(dev);
+ /* TS is set for all frame types, not only those requested */
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ }
+
+ return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+#endif /* CONFIG_FSL_DPAA_TS */
+
+int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+#ifdef CONFIG_FSL_DPAA_1588
+ struct dpa_priv_s *priv = netdev_priv(dev);
+#endif
+ int ret = -EINVAL;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (cmd == SIOCGMIIREG) {
+ if (!dev->phydev)
+ ret = -EINVAL;
+ else
+ ret = phy_mii_ioctl(dev->phydev, rq, cmd);
+ }
+
+#ifdef CONFIG_FSL_DPAA_TS
+ if (cmd == SIOCSHWTSTAMP)
+ return dpa_ts_ioctl(dev, rq, cmd);
+#endif /* CONFIG_FSL_DPAA_TS */
+
+#ifdef CONFIG_FSL_DPAA_1588
+ if ((cmd >= PTP_ENBL_TXTS_IOCTL) && (cmd <= PTP_CLEANUP_TS)) {
+ if (priv->tsu && priv->tsu->valid)
+ ret = dpa_ioctl_1588(dev, rq, cmd);
+ else
+ ret = -ENODEV;
+ }
+#endif
+
+ return ret;
+}
+EXPORT_SYMBOL(dpa_ioctl);
+
+int __cold dpa_remove(struct platform_device *of_dev)
+{
+ int err;
+ struct device *dev;
+ struct net_device *net_dev;
+ struct dpa_priv_s *priv;
+
+ dev = &of_dev->dev;
+ net_dev = dev_get_drvdata(dev);
+
+ priv = netdev_priv(net_dev);
+
+ dpaa_eth_sysfs_remove(dev);
+
+ dev_set_drvdata(dev, NULL);
+ unregister_netdev(net_dev);
+
+ err = dpa_fq_free(dev, &priv->dpa_fq_list);
+
+ qman_delete_cgr_safe(&priv->ingress_cgr);
+ qman_release_cgrid(priv->ingress_cgr.cgrid);
+ qman_delete_cgr_safe(&priv->cgr_data.cgr);
+ qman_release_cgrid(priv->cgr_data.cgr.cgrid);
+
+ dpa_private_napi_del(net_dev);
+
+ dpa_bp_free(priv);
+
+ if (priv->buf_layout)
+ devm_kfree(dev, priv->buf_layout);
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ /* remove debugfs entry for this net_device */
+ dpa_netdev_debugfs_remove(net_dev);
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid)
+ dpa_ptp_cleanup(priv);
+#endif
+
+ free_netdev(net_dev);
+
+ return err;
+}
+EXPORT_SYMBOL(dpa_remove);
+
+struct mac_device * __cold __must_check
+__attribute__((nonnull))
+dpa_mac_probe(struct platform_device *_of_dev)
+{
+ struct device *dpa_dev, *dev;
+ struct device_node *mac_node;
+ struct platform_device *of_dev;
+ struct mac_device *mac_dev;
+#ifdef CONFIG_FSL_DPAA_1588
+ int lenp;
+ const phandle *phandle_prop;
+ struct net_device *net_dev = NULL;
+ struct dpa_priv_s *priv = NULL;
+ struct device_node *timer_node;
+#endif
+ dpa_dev = &_of_dev->dev;
+
+ mac_node = of_parse_phandle(_of_dev->dev.of_node, "fsl,fman-mac", 0);
+ if (unlikely(mac_node == NULL)) {
+ dev_err(dpa_dev, "Cannot find MAC device device tree node\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ of_dev = of_find_device_by_node(mac_node);
+ if (unlikely(of_dev == NULL)) {
+ dev_err(dpa_dev, "of_find_device_by_node(%s) failed\n",
+ mac_node->full_name);
+ of_node_put(mac_node);
+ return ERR_PTR(-EINVAL);
+ }
+ of_node_put(mac_node);
+
+ dev = &of_dev->dev;
+
+ mac_dev = dev_get_drvdata(dev);
+ if (unlikely(mac_dev == NULL)) {
+ dev_err(dpa_dev, "dev_get_drvdata(%s) failed\n",
+ dev_name(dev));
+ return ERR_PTR(-EINVAL);
+ }
+
+#ifdef CONFIG_FSL_DPAA_1588
+ phandle_prop = of_get_property(mac_node, "ptp-timer", &lenp);
+ if (phandle_prop && ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) ||
+ ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) &&
+ (mac_dev->speed == SPEED_1000)))) {
+ timer_node = of_find_node_by_phandle(*phandle_prop);
+ if (timer_node)
+ net_dev = dev_get_drvdata(dpa_dev);
+ if (timer_node && net_dev) {
+ priv = netdev_priv(net_dev);
+ if (!dpa_ptp_init(priv))
+ dev_info(dev, "%s: ptp 1588 is initialized.\n",
+ mac_node->full_name);
+ }
+ }
+#endif
+
+ return mac_dev;
+}
+EXPORT_SYMBOL(dpa_mac_probe);
+
+int dpa_set_mac_address(struct net_device *net_dev, void *addr)
+{
+ const struct dpa_priv_s *priv;
+ int _errno;
+ struct mac_device *mac_dev;
+
+ priv = netdev_priv(net_dev);
+
+ _errno = eth_mac_addr(net_dev, addr);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev,
+ "eth_mac_addr() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ mac_dev = priv->mac_dev;
+
+ _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev),
+ net_dev->dev_addr);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev,
+ "mac_dev->change_addr() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_set_mac_address);
+
+void dpa_set_rx_mode(struct net_device *net_dev)
+{
+ int _errno;
+ const struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+
+ if (!!(net_dev->flags & IFF_PROMISC) != priv->mac_dev->promisc) {
+ priv->mac_dev->promisc = !priv->mac_dev->promisc;
+ _errno = priv->mac_dev->set_promisc(
+ priv->mac_dev->get_mac_handle(priv->mac_dev),
+ priv->mac_dev->promisc);
+ if (unlikely(_errno < 0) && netif_msg_drv(priv))
+ netdev_err(net_dev,
+ "mac_dev->set_promisc() = %d\n",
+ _errno);
+ }
+
+ _errno = priv->mac_dev->set_multi(net_dev, priv->mac_dev);
+ if (unlikely(_errno < 0) && netif_msg_drv(priv))
+ netdev_err(net_dev, "mac_dev->set_multi() = %d\n", _errno);
+}
+EXPORT_SYMBOL(dpa_set_rx_mode);
+
+void dpa_set_buffers_layout(struct mac_device *mac_dev,
+ struct dpa_buffer_layout_s *layout)
+{
+ struct fm_port_params params;
+
+ /* Rx */
+ layout[RX].priv_data_size = (uint16_t)DPA_RX_PRIV_DATA_SIZE;
+ layout[RX].parse_results = true;
+ layout[RX].hash_results = true;
+#ifdef CONFIG_FSL_DPAA_TS
+ layout[RX].time_stamp = true;
+#endif
+ fm_port_get_buff_layout_ext_params(mac_dev->port_dev[RX], &params);
+ layout[RX].manip_extra_space = params.manip_extra_space;
+ /* a value of zero for data alignment means "don't care", so align to
+ * a non-zero value to prevent FMD from using its own default
+ */
+ layout[RX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT;
+
+ /* Tx */
+ layout[TX].priv_data_size = DPA_TX_PRIV_DATA_SIZE;
+ layout[TX].parse_results = true;
+ layout[TX].hash_results = true;
+#ifdef CONFIG_FSL_DPAA_TS
+ layout[TX].time_stamp = true;
+#endif
+ fm_port_get_buff_layout_ext_params(mac_dev->port_dev[TX], &params);
+ layout[TX].manip_extra_space = params.manip_extra_space;
+ layout[TX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT;
+}
+EXPORT_SYMBOL(dpa_set_buffers_layout);
+
+int __attribute__((nonnull))
+dpa_bp_alloc(struct dpa_bp *dpa_bp, struct device *dev)
+{
+ int err;
+ struct bman_pool_params bp_params;
+
+ if (dpa_bp->size == 0 || dpa_bp->config_count == 0) {
+ pr_err("Buffer pool is not properly initialized! Missing size or initial number of buffers");
+ return -EINVAL;
+ }
+
+ memset(&bp_params, 0, sizeof(struct bman_pool_params));
+#ifdef CONFIG_FMAN_PFC
+ bp_params.flags = BMAN_POOL_FLAG_THRESH;
+ bp_params.thresholds[0] = bp_params.thresholds[2] =
+ CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD;
+ bp_params.thresholds[1] = bp_params.thresholds[3] =
+ CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT;
+#endif
+
+ /* If the pool is already specified, we only create one per bpid */
+ if (dpa_bpid2pool_use(dpa_bp->bpid))
+ return 0;
+
+ if (dpa_bp->bpid == 0)
+ bp_params.flags |= BMAN_POOL_FLAG_DYNAMIC_BPID;
+ else
+ bp_params.bpid = dpa_bp->bpid;
+
+ dpa_bp->pool = bman_new_pool(&bp_params);
+ if (unlikely(dpa_bp->pool == NULL)) {
+ pr_err("bman_new_pool() failed\n");
+ return -ENODEV;
+ }
+
+ dpa_bp->bpid = (uint8_t)bman_get_params(dpa_bp->pool)->bpid;
+
+ err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
+ if (err) {
+ pr_err("dma_coerce_mask_and_coherent() failed\n");
+ goto bman_free_pool;
+ }
+
+ dpa_bp->dev = dev;
+
+ if (dpa_bp->seed_cb) {
+ err = dpa_bp->seed_cb(dpa_bp);
+ if (err)
+ goto bman_free_pool;
+ }
+
+ dpa_bpid2pool_map(dpa_bp->bpid, dpa_bp);
+
+ return 0;
+
+bman_free_pool:
+ bman_free_pool(dpa_bp->pool);
+
+ return err;
+}
+EXPORT_SYMBOL(dpa_bp_alloc);
+
+void dpa_bp_drain(struct dpa_bp *bp)
+{
+ int ret, num = 8;
+
+ do {
+ struct bm_buffer bmb[8];
+ int i;
+
+ ret = bman_acquire(bp->pool, bmb, num, 0);
+ if (ret < 0) {
+ if (num == 8) {
+ /* we have less than 8 buffers left;
+ * drain them one by one
+ */
+ num = 1;
+ ret = 1;
+ continue;
+ } else {
+ /* Pool is fully drained */
+ break;
+ }
+ }
+
+ for (i = 0; i < num; i++) {
+ dma_addr_t addr = bm_buf_addr(&bmb[i]);
+
+ dma_unmap_single(bp->dev, addr, bp->size,
+ DMA_BIDIRECTIONAL);
+
+ bp->free_buf_cb(phys_to_virt(addr));
+ }
+ } while (ret > 0);
+}
+EXPORT_SYMBOL(dpa_bp_drain);
+
+static void __cold __attribute__((nonnull))
+_dpa_bp_free(struct dpa_bp *dpa_bp)
+{
+ struct dpa_bp *bp = dpa_bpid2pool(dpa_bp->bpid);
+
+ /* the mapping between bpid and dpa_bp is done very late in the
+ * allocation procedure; if something failed before the mapping, the bp
+ * was not configured, therefore we don't need the below instructions
+ */
+ if (!bp)
+ return;
+
+ if (!atomic_dec_and_test(&bp->refs))
+ return;
+
+ if (bp->free_buf_cb)
+ dpa_bp_drain(bp);
+
+ dpa_bp_array[bp->bpid] = NULL;
+ bman_free_pool(bp->pool);
+}
+
+void __cold __attribute__((nonnull))
+dpa_bp_free(struct dpa_priv_s *priv)
+{
+ int i;
+
+ if (priv->dpa_bp)
+ for (i = 0; i < priv->bp_count; i++)
+ _dpa_bp_free(&priv->dpa_bp[i]);
+}
+EXPORT_SYMBOL(dpa_bp_free);
+
+struct dpa_bp *dpa_bpid2pool(int bpid)
+{
+ return dpa_bp_array[bpid];
+}
+EXPORT_SYMBOL(dpa_bpid2pool);
+
+void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp)
+{
+ dpa_bp_array[bpid] = dpa_bp;
+ atomic_set(&dpa_bp->refs, 1);
+}
+
+bool dpa_bpid2pool_use(int bpid)
+{
+ if (dpa_bpid2pool(bpid)) {
+ atomic_inc(&dpa_bp_array[bpid]->refs);
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef CONFIG_FMAN_PFC
+u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback)
+{
+ return dpa_get_queue_mapping(skb);
+}
+#endif
+
+struct dpa_fq *dpa_fq_alloc(struct device *dev,
+ u32 fq_start,
+ u32 fq_count,
+ struct list_head *list,
+ enum dpa_fq_type fq_type)
+{
+ int i;
+ struct dpa_fq *dpa_fq;
+
+ dpa_fq = devm_kzalloc(dev, sizeof(*dpa_fq) * fq_count, GFP_KERNEL);
+ if (dpa_fq == NULL)
+ return NULL;
+
+ for (i = 0; i < fq_count; i++) {
+ dpa_fq[i].fq_type = fq_type;
+ if (fq_type == FQ_TYPE_RX_PCD_HI_PRIO)
+ dpa_fq[i].fqid = fq_start ?
+ DPAA_ETH_FQ_DELTA + fq_start + i : 0;
+ else
+ dpa_fq[i].fqid = fq_start ? fq_start + i : 0;
+
+ list_add_tail(&dpa_fq[i].list, list);
+ }
+
+#ifdef CONFIG_FMAN_PFC
+ if (fq_type == FQ_TYPE_TX)
+ for (i = 0; i < fq_count; i++)
+ dpa_fq[i].wq = i / dpa_num_cpus;
+ else
+#endif
+ for (i = 0; i < fq_count; i++)
+ _dpa_assign_wq(dpa_fq + i);
+
+ return dpa_fq;
+}
+EXPORT_SYMBOL(dpa_fq_alloc);
+
+/* Probing of FQs for MACful ports */
+int dpa_fq_probe_mac(struct device *dev, struct list_head *list,
+ struct fm_port_fqs *port_fqs,
+ bool alloc_tx_conf_fqs,
+ enum port_type ptype)
+{
+ struct fqid_cell *fqids = NULL;
+ const void *fqids_off = NULL;
+ struct dpa_fq *dpa_fq = NULL;
+ struct device_node *np = dev->of_node;
+ int num_ranges;
+ int i, lenp;
+
+ if (ptype == TX && alloc_tx_conf_fqs) {
+ if (!dpa_fq_alloc(dev, tx_confirm_fqids->start,
+ tx_confirm_fqids->count, list,
+ FQ_TYPE_TX_CONF_MQ))
+ goto fq_alloc_failed;
+ }
+
+ fqids_off = of_get_property(np, fsl_qman_frame_queues[ptype], &lenp);
+ if (fqids_off == NULL) {
+ /* No dts definition, so use the defaults. */
+ fqids = default_fqids[ptype];
+ num_ranges = 3;
+ } else {
+ num_ranges = lenp / sizeof(*fqids);
+
+ fqids = devm_kzalloc(dev, sizeof(*fqids) * num_ranges,
+ GFP_KERNEL);
+ if (fqids == NULL)
+ goto fqids_alloc_failed;
+
+ /* convert to CPU endianess */
+ for (i = 0; i < num_ranges; i++) {
+ fqids[i].start = be32_to_cpup(fqids_off +
+ i * sizeof(*fqids));
+ fqids[i].count = be32_to_cpup(fqids_off +
+ i * sizeof(*fqids) + sizeof(__be32));
+ }
+ }
+
+ for (i = 0; i < num_ranges; i++) {
+ switch (i) {
+ case 0:
+ /* The first queue is the error queue */
+ if (fqids[i].count != 1)
+ goto invalid_error_queue;
+
+ dpa_fq = dpa_fq_alloc(dev, fqids[i].start,
+ fqids[i].count, list,
+ ptype == RX ?
+ FQ_TYPE_RX_ERROR :
+ FQ_TYPE_TX_ERROR);
+ if (dpa_fq == NULL)
+ goto fq_alloc_failed;
+
+ if (ptype == RX)
+ port_fqs->rx_errq = &dpa_fq[0];
+ else
+ port_fqs->tx_errq = &dpa_fq[0];
+ break;
+ case 1:
+ /* the second queue is the default queue */
+ if (fqids[i].count != 1)
+ goto invalid_default_queue;
+
+ dpa_fq = dpa_fq_alloc(dev, fqids[i].start,
+ fqids[i].count, list,
+ ptype == RX ?
+ FQ_TYPE_RX_DEFAULT :
+ FQ_TYPE_TX_CONFIRM);
+ if (dpa_fq == NULL)
+ goto fq_alloc_failed;
+
+ if (ptype == RX)
+ port_fqs->rx_defq = &dpa_fq[0];
+ else
+ port_fqs->tx_defq = &dpa_fq[0];
+ break;
+ default:
+ /* all subsequent queues are either RX* PCD or Tx */
+ if (ptype == RX) {
+ if (!dpa_fq_alloc(dev, fqids[i].start,
+ fqids[i].count, list,
+ FQ_TYPE_RX_PCD) ||
+ !dpa_fq_alloc(dev, fqids[i].start,
+ fqids[i].count, list,
+ FQ_TYPE_RX_PCD_HI_PRIO))
+ goto fq_alloc_failed;
+ } else {
+ if (!dpa_fq_alloc(dev, fqids[i].start,
+ fqids[i].count, list,
+ FQ_TYPE_TX))
+ goto fq_alloc_failed;
+ }
+ break;
+ }
+ }
+
+ return 0;
+
+fq_alloc_failed:
+fqids_alloc_failed:
+ dev_err(dev, "Cannot allocate memory for frame queues\n");
+ return -ENOMEM;
+
+invalid_default_queue:
+invalid_error_queue:
+ dev_err(dev, "Too many default or error queues\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL(dpa_fq_probe_mac);
+
+static u32 rx_pool_channel;
+static DEFINE_SPINLOCK(rx_pool_channel_init);
+
+int dpa_get_channel(void)
+{
+ spin_lock(&rx_pool_channel_init);
+ if (!rx_pool_channel) {
+ u32 pool;
+ int ret = qman_alloc_pool(&pool);
+ if (!ret)
+ rx_pool_channel = pool;
+ }
+ spin_unlock(&rx_pool_channel_init);
+ if (!rx_pool_channel)
+ return -ENOMEM;
+ return rx_pool_channel;
+}
+EXPORT_SYMBOL(dpa_get_channel);
+
+void dpa_release_channel(void)
+{
+ qman_release_pool(rx_pool_channel);
+}
+EXPORT_SYMBOL(dpa_release_channel);
+
+void dpaa_eth_add_channel(u16 channel)
+{
+ const cpumask_t *cpus = qman_affine_cpus();
+ u32 pool = QM_SDQCR_CHANNELS_POOL_CONV(channel);
+ int cpu;
+ struct qman_portal *portal;
+
+ for_each_cpu(cpu, cpus) {
+ portal = (struct qman_portal *)qman_get_affine_portal(cpu);
+ qman_p_static_dequeue_add(portal, pool);
+ }
+}
+EXPORT_SYMBOL(dpaa_eth_add_channel);
+
+/**
+ * Congestion group state change notification callback.
+ * Stops the device's egress queues while they are congested and
+ * wakes them upon exiting congested state.
+ * Also updates some CGR-related stats.
+ */
+static void dpaa_eth_cgscn(struct qman_portal *qm, struct qman_cgr *cgr,
+
+ int congested)
+{
+ struct dpa_priv_s *priv = (struct dpa_priv_s *)container_of(cgr,
+ struct dpa_priv_s, cgr_data.cgr);
+
+ if (congested) {
+ priv->cgr_data.congestion_start_jiffies = jiffies;
+ netif_tx_stop_all_queues(priv->net_dev);
+ priv->cgr_data.cgr_congested_count++;
+ } else {
+ priv->cgr_data.congested_jiffies +=
+ (jiffies - priv->cgr_data.congestion_start_jiffies);
+ netif_tx_wake_all_queues(priv->net_dev);
+ }
+}
+
+int dpaa_eth_cgr_init(struct dpa_priv_s *priv)
+{
+ struct qm_mcc_initcgr initcgr;
+ u32 cs_th;
+ int err;
+
+ err = qman_alloc_cgrid(&priv->cgr_data.cgr.cgrid);
+ if (err < 0) {
+ pr_err("Error %d allocating CGR ID\n", err);
+ goto out_error;
+ }
+ priv->cgr_data.cgr.cb = dpaa_eth_cgscn;
+
+ /* Enable Congestion State Change Notifications and CS taildrop */
+ initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES;
+ initcgr.cgr.cscn_en = QM_CGR_EN;
+
+ /* Set different thresholds based on the MAC speed.
+ * TODO: this may turn suboptimal if the MAC is reconfigured at a speed
+ * lower than its max, e.g. if a dTSEC later negotiates a 100Mbps link.
+ * In such cases, we ought to reconfigure the threshold, too.
+ */
+ if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
+ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G;
+ else
+ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G;
+ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
+
+ initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
+ initcgr.cgr.cstd_en = QM_CGR_EN;
+
+ err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT,
+ &initcgr);
+ if (err < 0) {
+ pr_err("Error %d creating CGR with ID %d\n", err,
+ priv->cgr_data.cgr.cgrid);
+ qman_release_cgrid(priv->cgr_data.cgr.cgrid);
+ goto out_error;
+ }
+ pr_debug("Created CGR %d for netdev with hwaddr %pM on QMan channel %d\n",
+ priv->cgr_data.cgr.cgrid, priv->mac_dev->addr,
+ priv->cgr_data.cgr.chan);
+
+out_error:
+ return err;
+}
+EXPORT_SYMBOL(dpaa_eth_cgr_init);
+
+static inline void dpa_setup_ingress(const struct dpa_priv_s *priv,
+ struct dpa_fq *fq,
+ const struct qman_fq *template)
+{
+ fq->fq_base = *template;
+ fq->net_dev = priv->net_dev;
+
+ fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE;
+ fq->channel = priv->channel;
+}
+
+static inline void dpa_setup_egress(const struct dpa_priv_s *priv,
+ struct dpa_fq *fq,
+ struct fm_port *port,
+ const struct qman_fq *template)
+{
+ fq->fq_base = *template;
+ fq->net_dev = priv->net_dev;
+
+ if (port) {
+ fq->flags = QMAN_FQ_FLAG_TO_DCPORTAL;
+ fq->channel = (uint16_t)fm_get_tx_port_channel(port);
+ } else {
+ fq->flags = QMAN_FQ_FLAG_NO_MODIFY;
+ }
+}
+
+void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
+ struct fm_port *tx_port)
+{
+ struct dpa_fq *fq;
+ uint16_t portals[NR_CPUS];
+ int cpu, portal_cnt = 0, num_portals = 0;
+ uint32_t pcd_fqid, pcd_fqid_hi_prio;
+ const cpumask_t *affine_cpus = qman_affine_cpus();
+ int egress_cnt = 0, conf_cnt = 0;
+
+ /* Prepare for PCD FQs init */
+ for_each_cpu(cpu, affine_cpus)
+ portals[num_portals++] = qman_affine_channel(cpu);
+ if (num_portals == 0)
+ dev_err(priv->net_dev->dev.parent,
+ "No Qman software (affine) channels found");
+
+ pcd_fqid = (priv->mac_dev) ?
+ DPAA_ETH_PCD_FQ_BASE(priv->mac_dev->res->start) : 0;
+ pcd_fqid_hi_prio = (priv->mac_dev) ?
+ DPAA_ETH_PCD_FQ_HI_PRIO_BASE(priv->mac_dev->res->start) : 0;
+
+ /* Initialize each FQ in the list */
+ list_for_each_entry(fq, &priv->dpa_fq_list, list) {
+ switch (fq->fq_type) {
+ case FQ_TYPE_RX_DEFAULT:
+ BUG_ON(!priv->mac_dev);
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
+ break;
+ case FQ_TYPE_RX_ERROR:
+ BUG_ON(!priv->mac_dev);
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_errq);
+ break;
+ case FQ_TYPE_RX_PCD:
+ /* For MACless we can't have dynamic Rx queues */
+ BUG_ON(!priv->mac_dev && !fq->fqid);
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
+ if (!fq->fqid)
+ fq->fqid = pcd_fqid++;
+ fq->channel = portals[portal_cnt];
+ portal_cnt = (portal_cnt + 1) % num_portals;
+ break;
+ case FQ_TYPE_RX_PCD_HI_PRIO:
+ /* For MACless we can't have dynamic Hi Pri Rx queues */
+ BUG_ON(!priv->mac_dev && !fq->fqid);
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
+ if (!fq->fqid)
+ fq->fqid = pcd_fqid_hi_prio++;
+ fq->channel = portals[portal_cnt];
+ portal_cnt = (portal_cnt + 1) % num_portals;
+ break;
+ case FQ_TYPE_TX:
+ dpa_setup_egress(priv, fq, tx_port,
+ &fq_cbs->egress_ern);
+ /* If we have more Tx queues than the number of cores,
+ * just ignore the extra ones.
+ */
+ if (egress_cnt < DPAA_ETH_TX_QUEUES)
+ priv->egress_fqs[egress_cnt++] = &fq->fq_base;
+ break;
+ case FQ_TYPE_TX_CONFIRM:
+ BUG_ON(!priv->mac_dev);
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
+ break;
+ case FQ_TYPE_TX_CONF_MQ:
+ BUG_ON(!priv->mac_dev);
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
+ priv->conf_fqs[conf_cnt++] = &fq->fq_base;
+ break;
+ case FQ_TYPE_TX_ERROR:
+ BUG_ON(!priv->mac_dev);
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_errq);
+ break;
+ default:
+ dev_warn(priv->net_dev->dev.parent,
+ "Unknown FQ type detected!\n");
+ break;
+ }
+ }
+
+ /* The number of Tx queues may be smaller than the number of cores, if
+ * the Tx queue range is specified in the device tree instead of being
+ * dynamically allocated.
+ * Make sure all CPUs receive a corresponding Tx queue.
+ */
+ while (egress_cnt < DPAA_ETH_TX_QUEUES) {
+ list_for_each_entry(fq, &priv->dpa_fq_list, list) {
+ if (fq->fq_type != FQ_TYPE_TX)
+ continue;
+ priv->egress_fqs[egress_cnt++] = &fq->fq_base;
+ if (egress_cnt == DPAA_ETH_TX_QUEUES)
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(dpa_fq_setup);
+
+int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable)
+{
+ int _errno;
+ const struct dpa_priv_s *priv;
+ struct device *dev;
+ struct qman_fq *fq;
+ struct qm_mcc_initfq initfq;
+ struct qman_fq *confq;
+ int queue_id;
+
+ priv = netdev_priv(dpa_fq->net_dev);
+ dev = dpa_fq->net_dev->dev.parent;
+
+ if (dpa_fq->fqid == 0)
+ dpa_fq->flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
+
+ dpa_fq->init = !(dpa_fq->flags & QMAN_FQ_FLAG_NO_MODIFY);
+
+ _errno = qman_create_fq(dpa_fq->fqid, dpa_fq->flags, &dpa_fq->fq_base);
+ if (_errno) {
+ dev_err(dev, "qman_create_fq() failed\n");
+ return _errno;
+ }
+ fq = &dpa_fq->fq_base;
+
+ if (dpa_fq->init) {
+ memset(&initfq, 0, sizeof(initfq));
+
+ initfq.we_mask = QM_INITFQ_WE_FQCTRL;
+
+ /* Try to reduce the number of portal interrupts for
+ * Tx Confirmation FQs.
+ */
+ if (dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM)
+ initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE;
+
+ /* FQ placement */
+ initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
+
+ initfq.fqd.dest.channel = dpa_fq->channel;
+ initfq.fqd.dest.wq = dpa_fq->wq;
+
+ /* Put all egress queues in a congestion group of their own.
+ * Sensu stricto, the Tx confirmation queues are Rx FQs,
+ * rather than Tx - but they nonetheless account for the
+ * memory footprint on behalf of egress traffic. We therefore
+ * place them in the netdev's CGR, along with the Tx FQs.
+ */
+ if (dpa_fq->fq_type == FQ_TYPE_TX ||
+ dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM ||
+ dpa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) {
+ initfq.we_mask |= QM_INITFQ_WE_CGID;
+ initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+ initfq.fqd.cgid = (uint8_t)priv->cgr_data.cgr.cgrid;
+ /* Set a fixed overhead accounting, in an attempt to
+ * reduce the impact of fixed-size skb shells and the
+ * driver's needed headroom on system memory. This is
+ * especially the case when the egress traffic is
+ * composed of small datagrams.
+ * Unfortunately, QMan's OAL value is capped to an
+ * insufficient value, but even that is better than
+ * no overhead accounting at all.
+ */
+ initfq.we_mask |= QM_INITFQ_WE_OAC;
+ initfq.fqd.oac_init.oac = QM_OAC_CG;
+ initfq.fqd.oac_init.oal =
+ (signed char)(min(sizeof(struct sk_buff) +
+ priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
+ }
+
+ if (td_enable) {
+ initfq.we_mask |= QM_INITFQ_WE_TDTHRESH;
+ qm_fqd_taildrop_set(&initfq.fqd.td,
+ DPA_FQ_TD, 1);
+ initfq.fqd.fq_ctrl = QM_FQCTRL_TDE;
+ }
+
+ /* Configure the Tx confirmation queue, now that we know
+ * which Tx queue it pairs with.
+ */
+ if (dpa_fq->fq_type == FQ_TYPE_TX) {
+ queue_id = _dpa_tx_fq_to_id(priv, &dpa_fq->fq_base);
+ if (queue_id >= 0) {
+ confq = priv->conf_fqs[queue_id];
+ if (confq) {
+ initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
+ /* ContextA: OVOM=1 (use contextA2 bits instead of ICAD)
+ * A2V=1 (contextA A2 field is valid)
+ * A0V=1 (contextA A0 field is valid)
+ * B0V=1 (contextB field is valid)
+ * ContextA A2: EBD=1 (deallocate buffers inside FMan)
+ * ContextB B0(ASPID): 0 (absolute Virtual Storage ID)
+ */
+ initfq.fqd.context_a.hi = 0x1e000000;
+ initfq.fqd.context_a.lo = 0x80000000;
+ }
+ }
+ }
+
+ /* Put all *private* ingress queues in our "ingress CGR". */
+ if (priv->use_ingress_cgr &&
+ (dpa_fq->fq_type == FQ_TYPE_RX_DEFAULT ||
+ dpa_fq->fq_type == FQ_TYPE_RX_ERROR ||
+ dpa_fq->fq_type == FQ_TYPE_RX_PCD ||
+ dpa_fq->fq_type == FQ_TYPE_RX_PCD_HI_PRIO)) {
+ initfq.we_mask |= QM_INITFQ_WE_CGID;
+ initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE;
+ initfq.fqd.cgid = (uint8_t)priv->ingress_cgr.cgrid;
+ /* Set a fixed overhead accounting, just like for the
+ * egress CGR.
+ */
+ initfq.we_mask |= QM_INITFQ_WE_OAC;
+ initfq.fqd.oac_init.oac = QM_OAC_CG;
+ initfq.fqd.oac_init.oal =
+ (signed char)(min(sizeof(struct sk_buff) +
+ priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL));
+ }
+
+ /* Initialization common to all ingress queues */
+ if (dpa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) {
+ initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
+ initfq.fqd.fq_ctrl |=
+ QM_FQCTRL_CTXASTASHING | QM_FQCTRL_AVOIDBLOCK;
+ initfq.fqd.context_a.stashing.exclusive =
+ QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX |
+ QM_STASHING_EXCL_ANNOTATION;
+ initfq.fqd.context_a.stashing.data_cl = 2;
+ initfq.fqd.context_a.stashing.annotation_cl = 1;
+ initfq.fqd.context_a.stashing.context_cl =
+ DIV_ROUND_UP(sizeof(struct qman_fq), 64);
+ }
+
+ _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq);
+ if (_errno < 0) {
+ if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno)) {
+ dpa_fq->init = 0;
+ } else {
+ dev_err(dev, "qman_init_fq(%u) = %d\n",
+ qman_fq_fqid(fq), _errno);
+ qman_destroy_fq(fq, 0);
+ }
+ return _errno;
+ }
+ }
+
+ dpa_fq->fqid = qman_fq_fqid(fq);
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_fq_init);
+
+int __cold __attribute__((nonnull))
+_dpa_fq_free(struct device *dev, struct qman_fq *fq)
+{
+ int _errno, __errno;
+ struct dpa_fq *dpa_fq;
+ const struct dpa_priv_s *priv;
+
+ _errno = 0;
+
+ dpa_fq = container_of(fq, struct dpa_fq, fq_base);
+ priv = netdev_priv(dpa_fq->net_dev);
+
+ if (dpa_fq->init) {
+ _errno = qman_retire_fq(fq, NULL);
+ if (unlikely(_errno < 0) && netif_msg_drv(priv))
+ dev_err(dev, "qman_retire_fq(%u) = %d\n",
+ qman_fq_fqid(fq), _errno);
+
+ __errno = qman_oos_fq(fq);
+ if (unlikely(__errno < 0) && netif_msg_drv(priv)) {
+ dev_err(dev, "qman_oos_fq(%u) = %d\n",
+ qman_fq_fqid(fq), __errno);
+ if (_errno >= 0)
+ _errno = __errno;
+ }
+ }
+
+ qman_destroy_fq(fq, 0);
+ list_del(&dpa_fq->list);
+
+ return _errno;
+}
+EXPORT_SYMBOL(_dpa_fq_free);
+
+int __cold __attribute__((nonnull))
+dpa_fq_free(struct device *dev, struct list_head *list)
+{
+ int _errno, __errno;
+ struct dpa_fq *dpa_fq, *tmp;
+
+ _errno = 0;
+ list_for_each_entry_safe(dpa_fq, tmp, list, list) {
+ __errno = _dpa_fq_free(dev, (struct qman_fq *)dpa_fq);
+ if (unlikely(__errno < 0) && _errno >= 0)
+ _errno = __errno;
+ }
+
+ return _errno;
+}
+EXPORT_SYMBOL(dpa_fq_free);
+
+int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable)
+{
+ int _errno, __errno;
+ struct dpa_fq *dpa_fq, *tmp;
+ static bool print_msg __read_mostly;
+
+ _errno = 0;
+ print_msg = true;
+ list_for_each_entry_safe(dpa_fq, tmp, list, list) {
+ __errno = dpa_fq_init(dpa_fq, td_enable);
+ if (unlikely(__errno < 0) && _errno >= 0) {
+ if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, __errno)) {
+ if (print_msg) {
+ dev_warn(dev,
+ "Skip RX PCD High Priority FQs initialization\n");
+ print_msg = false;
+ }
+ if (_dpa_fq_free(dev, (struct qman_fq *)dpa_fq))
+ dev_warn(dev,
+ "Error freeing frame queues\n");
+ } else {
+ _errno = __errno;
+ break;
+ }
+ }
+ }
+
+ return _errno;
+}
+EXPORT_SYMBOL(dpa_fqs_init);
+static void
+dpaa_eth_init_tx_port(struct fm_port *port, struct dpa_fq *errq,
+ struct dpa_fq *defq, struct dpa_buffer_layout_s *buf_layout)
+{
+ struct fm_port_params tx_port_param;
+ bool frag_enabled = false;
+
+ memset(&tx_port_param, 0, sizeof(tx_port_param));
+ dpaa_eth_init_port(tx, port, tx_port_param, errq->fqid, defq->fqid,
+ buf_layout, frag_enabled);
+}
+
+static void
+dpaa_eth_init_rx_port(struct fm_port *port, struct dpa_bp *bp, size_t count,
+ struct dpa_fq *errq, struct dpa_fq *defq,
+ struct dpa_buffer_layout_s *buf_layout)
+{
+ struct fm_port_params rx_port_param;
+ int i;
+ bool frag_enabled = false;
+
+ memset(&rx_port_param, 0, sizeof(rx_port_param));
+ count = min(ARRAY_SIZE(rx_port_param.pool_param), count);
+ rx_port_param.num_pools = (uint8_t)count;
+ for (i = 0; i < count; i++) {
+ if (i >= rx_port_param.num_pools)
+ break;
+ rx_port_param.pool_param[i].id = bp[i].bpid;
+ rx_port_param.pool_param[i].size = (uint16_t)bp[i].size;
+ }
+
+ dpaa_eth_init_port(rx, port, rx_port_param, errq->fqid, defq->fqid,
+ buf_layout, frag_enabled);
+}
+
+#if defined(CONFIG_FSL_SDK_FMAN_TEST)
+/* Defined as weak, to be implemented by fman pcd tester. */
+int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *)
+__attribute__((weak));
+
+int dpa_free_pcd_fqids(struct device *, uint32_t) __attribute__((weak));
+#else
+int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *);
+
+int dpa_free_pcd_fqids(struct device *, uint32_t);
+
+#endif /* CONFIG_FSL_SDK_FMAN_TEST */
+
+
+int dpa_alloc_pcd_fqids(struct device *dev, uint32_t num,
+ uint8_t alignment, uint32_t *base_fqid)
+{
+ dev_crit(dev, "callback not implemented!\n");
+
+ return 0;
+}
+
+int dpa_free_pcd_fqids(struct device *dev, uint32_t base_fqid)
+{
+
+ dev_crit(dev, "callback not implemented!\n");
+
+ return 0;
+}
+
+void dpaa_eth_init_ports(struct mac_device *mac_dev,
+ struct dpa_bp *bp, size_t count,
+ struct fm_port_fqs *port_fqs,
+ struct dpa_buffer_layout_s *buf_layout,
+ struct device *dev)
+{
+ struct fm_port_pcd_param rx_port_pcd_param;
+ struct fm_port *rxport = mac_dev->port_dev[RX];
+ struct fm_port *txport = mac_dev->port_dev[TX];
+
+ dpaa_eth_init_tx_port(txport, port_fqs->tx_errq,
+ port_fqs->tx_defq, &buf_layout[TX]);
+ dpaa_eth_init_rx_port(rxport, bp, count, port_fqs->rx_errq,
+ port_fqs->rx_defq, &buf_layout[RX]);
+
+ rx_port_pcd_param.cba = dpa_alloc_pcd_fqids;
+ rx_port_pcd_param.cbf = dpa_free_pcd_fqids;
+ rx_port_pcd_param.dev = dev;
+ fm_port_pcd_bind(rxport, &rx_port_pcd_param);
+}
+EXPORT_SYMBOL(dpaa_eth_init_ports);
+
+void dpa_release_sgt(struct qm_sg_entry *sgt)
+{
+ struct dpa_bp *dpa_bp;
+ struct bm_buffer bmb[DPA_BUFF_RELEASE_MAX];
+ uint8_t i = 0, j;
+
+ memset(bmb, 0, DPA_BUFF_RELEASE_MAX * sizeof(struct bm_buffer));
+
+ do {
+ dpa_bp = dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i]));
+ DPA_BUG_ON(!dpa_bp);
+
+ j = 0;
+ do {
+ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
+ bm_buffer_set64(&bmb[j], qm_sg_addr(&sgt[i]));
+
+ j++; i++;
+ } while (j < ARRAY_SIZE(bmb) &&
+ !qm_sg_entry_get_final(&sgt[i-1]) &&
+ qm_sg_entry_get_bpid(&sgt[i-1]) ==
+ qm_sg_entry_get_bpid(&sgt[i]));
+
+ while (bman_release(dpa_bp->pool, bmb, j, 0))
+ cpu_relax();
+ } while (!qm_sg_entry_get_final(&sgt[i-1]));
+}
+EXPORT_SYMBOL(dpa_release_sgt);
+
+void __attribute__((nonnull))
+dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd)
+{
+ struct qm_sg_entry *sgt;
+ struct dpa_bp *dpa_bp;
+ struct bm_buffer bmb;
+ dma_addr_t addr;
+ void *vaddr;
+
+ bmb.opaque = 0;
+ bm_buffer_set64(&bmb, qm_fd_addr(fd));
+
+ dpa_bp = dpa_bpid2pool(fd->bpid);
+ DPA_BUG_ON(!dpa_bp);
+
+ if (fd->format == qm_fd_sg) {
+ vaddr = phys_to_virt(qm_fd_addr(fd));
+ sgt = vaddr + dpa_fd_offset(fd);
+
+ dma_unmap_single(dpa_bp->dev, qm_fd_addr(fd), dpa_bp->size,
+ DMA_BIDIRECTIONAL);
+
+ dpa_release_sgt(sgt);
+ addr = dma_map_single(dpa_bp->dev, vaddr, dpa_bp->size,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ dev_err(dpa_bp->dev, "DMA mapping failed");
+ return;
+ }
+ bm_buffer_set64(&bmb, addr);
+ }
+
+ while (bman_release(dpa_bp->pool, &bmb, 1, 0))
+ cpu_relax();
+}
+EXPORT_SYMBOL(dpa_fd_release);
+
+void count_ern(struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_mr_entry *msg)
+{
+ switch (msg->ern.rc & QM_MR_RC_MASK) {
+ case QM_MR_RC_CGR_TAILDROP:
+ percpu_priv->ern_cnt.cg_tdrop++;
+ break;
+ case QM_MR_RC_WRED:
+ percpu_priv->ern_cnt.wred++;
+ break;
+ case QM_MR_RC_ERROR:
+ percpu_priv->ern_cnt.err_cond++;
+ break;
+ case QM_MR_RC_ORPWINDOW_EARLY:
+ percpu_priv->ern_cnt.early_window++;
+ break;
+ case QM_MR_RC_ORPWINDOW_LATE:
+ percpu_priv->ern_cnt.late_window++;
+ break;
+ case QM_MR_RC_FQ_TAILDROP:
+ percpu_priv->ern_cnt.fq_tdrop++;
+ break;
+ case QM_MR_RC_ORPWINDOW_RETIRED:
+ percpu_priv->ern_cnt.fq_retired++;
+ break;
+ case QM_MR_RC_ORP_ZERO:
+ percpu_priv->ern_cnt.orp_zero++;
+ break;
+ }
+}
+EXPORT_SYMBOL(count_ern);
+
+/**
+ * Turn on HW checksum computation for this outgoing frame.
+ * If the current protocol is not something we support in this regard
+ * (or if the stack has already computed the SW checksum), we do nothing.
+ *
+ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value
+ * otherwise.
+ *
+ * Note that this function may modify the fd->cmd field and the skb data buffer
+ * (the Parse Results area).
+ */
+int dpa_enable_tx_csum(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd, char *parse_results)
+{
+ fm_prs_result_t *parse_result;
+ struct iphdr *iph;
+ struct ipv6hdr *ipv6h = NULL;
+ u8 l4_proto;
+ u16 ethertype = ntohs(skb->protocol);
+ int retval = 0;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
+ /* Note: L3 csum seems to be already computed in sw, but we can't choose
+ * L4 alone from the FM configuration anyway.
+ */
+
+ /* Fill in some fields of the Parse Results array, so the FMan
+ * can find them as if they came from the FMan Parser.
+ */
+ parse_result = (fm_prs_result_t *)parse_results;
+
+ /* If we're dealing with VLAN, get the real Ethernet type */
+ if (ethertype == ETH_P_8021Q) {
+ /* We can't always assume the MAC header is set correctly
+ * by the stack, so reset to beginning of skb->data
+ */
+ skb_reset_mac_header(skb);
+ ethertype = ntohs(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto);
+ }
+
+ /* Fill in the relevant L3 parse result fields
+ * and read the L4 protocol type
+ */
+ switch (ethertype) {
+ case ETH_P_IP:
+ parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV4);
+ iph = ip_hdr(skb);
+ DPA_BUG_ON(iph == NULL);
+ l4_proto = iph->protocol;
+ break;
+ case ETH_P_IPV6:
+ parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV6);
+ ipv6h = ipv6_hdr(skb);
+ DPA_BUG_ON(ipv6h == NULL);
+ l4_proto = ipv6h->nexthdr;
+ break;
+ default:
+ /* We shouldn't even be here */
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ netdev_alert(priv->net_dev,
+ "Can't compute HW csum for L3 proto 0x%x\n",
+ ntohs(skb->protocol));
+ retval = -EIO;
+ goto return_error;
+ }
+
+ /* Fill in the relevant L4 parse result fields */
+ switch (l4_proto) {
+ case IPPROTO_UDP:
+ parse_result->l4r = FM_L4_PARSE_RESULT_UDP;
+ break;
+ case IPPROTO_TCP:
+ parse_result->l4r = FM_L4_PARSE_RESULT_TCP;
+ break;
+ default:
+ /* This can as well be a BUG() */
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ netdev_alert(priv->net_dev,
+ "Can't compute HW csum for L4 proto 0x%x\n",
+ l4_proto);
+ retval = -EIO;
+ goto return_error;
+ }
+
+ /* At index 0 is IPOffset_1 as defined in the Parse Results */
+ parse_result->ip_off[0] = (uint8_t)skb_network_offset(skb);
+ parse_result->l4_off = (uint8_t)skb_transport_offset(skb);
+
+ /* Enable L3 (and L4, if TCP or UDP) HW checksum. */
+ fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
+
+ /* On P1023 and similar platforms fd->cmd interpretation could
+ * be disabled by setting CONTEXT_A bit ICMD; currently this bit
+ * is not set so we do not need to check; in the future, if/when
+ * using context_a we need to check this bit
+ */
+
+return_error:
+ return retval;
+}
+EXPORT_SYMBOL(dpa_enable_tx_csum);
+
+#ifdef CONFIG_FSL_DPAA_CEETM
+void dpa_enable_ceetm(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+ priv->ceetm_en = true;
+}
+EXPORT_SYMBOL(dpa_enable_ceetm);
+
+void dpa_disable_ceetm(struct net_device *dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(dev);
+ priv->ceetm_en = false;
+}
+EXPORT_SYMBOL(dpa_disable_ceetm);
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
new file mode 100644
index 000000000000..efea855a417d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h
@@ -0,0 +1,227 @@
+/* Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DPAA_ETH_COMMON_H
+#define __DPAA_ETH_COMMON_H
+
+#include <linux/etherdevice.h> /* struct net_device */
+#include <linux/fsl_bman.h> /* struct bm_buffer */
+#include <linux/of_platform.h> /* struct platform_device */
+#include <linux/net_tstamp.h> /* struct hwtstamp_config */
+
+#include "dpaa_eth.h"
+#include "lnxwrp_fsl_fman.h"
+
+#define dpaa_eth_init_port(type, port, param, errq_id, defq_id, buf_layout,\
+ frag_enabled) \
+{ \
+ param.errq = errq_id; \
+ param.defq = defq_id; \
+ param.priv_data_size = buf_layout->priv_data_size; \
+ param.parse_results = buf_layout->parse_results; \
+ param.hash_results = buf_layout->hash_results; \
+ param.frag_enable = frag_enabled; \
+ param.time_stamp = buf_layout->time_stamp; \
+ param.manip_extra_space = buf_layout->manip_extra_space; \
+ param.data_align = buf_layout->data_align; \
+ fm_set_##type##_port_params(port, &param); \
+}
+
+/* The SGT needs to be 256 bytes long. Even if the table has only one entry,
+ * the FMan will read 256 bytes from its start.
+ */
+#define DPA_SGT_SIZE 256
+#define DPA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */
+
+#define DPA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */
+
+#define DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno) \
+ (((dpa_fq)->fq_type == FQ_TYPE_RX_PCD_HI_PRIO) && \
+ (_errno == -EIO))
+/* return codes for the dpaa-eth hooks */
+enum dpaa_eth_hook_result {
+ /* fd/skb was retained by the hook.
+ *
+ * On the Rx path, this means the Ethernet driver will _not_
+ * deliver the skb to the stack. Instead, the hook implementation
+ * is expected to properly dispose of the skb.
+ *
+ * On the Tx path, the Ethernet driver's dpa_tx() function will
+ * immediately return NETDEV_TX_OK. The hook implementation is expected
+ * to free the skb. *DO*NOT* release it to BMan, or enqueue it to FMan,
+ * unless you know exactly what you're doing!
+ *
+ * On the confirmation/error paths, the Ethernet driver will _not_
+ * perform any fd cleanup, nor update the interface statistics.
+ */
+ DPAA_ETH_STOLEN,
+ /* fd/skb was returned to the Ethernet driver for regular processing.
+ * The hook is not allowed to, for instance, reallocate the skb (as if
+ * by linearizing, copying, cloning or reallocating the headroom).
+ */
+ DPAA_ETH_CONTINUE
+};
+
+typedef enum dpaa_eth_hook_result (*dpaa_eth_ingress_hook_t)(
+ struct sk_buff *skb, struct net_device *net_dev, u32 fqid);
+typedef enum dpaa_eth_hook_result (*dpaa_eth_egress_hook_t)(
+ struct sk_buff *skb, struct net_device *net_dev);
+typedef enum dpaa_eth_hook_result (*dpaa_eth_confirm_hook_t)(
+ struct net_device *net_dev, const struct qm_fd *fd, u32 fqid);
+
+/* used in napi related functions */
+extern u16 qman_portal_max;
+
+/* from dpa_ethtool.c */
+extern const struct ethtool_ops dpa_ethtool_ops;
+
+#ifdef CONFIG_FSL_DPAA_HOOKS
+/* Various hooks used for unit-testing and/or fastpath optimizations.
+ * Currently only one set of such hooks is supported.
+ */
+struct dpaa_eth_hooks_s {
+ /* Invoked on the Tx private path, immediately after receiving the skb
+ * from the stack.
+ */
+ dpaa_eth_egress_hook_t tx;
+
+ /* Invoked on the Rx private path, right before passing the skb
+ * up the stack. At that point, the packet's protocol id has already
+ * been set. The skb's data pointer is now at the L3 header, and
+ * skb->mac_header points to the L2 header. skb->len has been adjusted
+ * to be the length of L3+payload (i.e., the length of the
+ * original frame minus the L2 header len).
+ * For more details on what the skb looks like, see eth_type_trans().
+ */
+ dpaa_eth_ingress_hook_t rx_default;
+
+ /* Driver hook for the Rx error private path. */
+ dpaa_eth_confirm_hook_t rx_error;
+ /* Driver hook for the Tx confirmation private path. */
+ dpaa_eth_confirm_hook_t tx_confirm;
+ /* Driver hook for the Tx error private path. */
+ dpaa_eth_confirm_hook_t tx_error;
+};
+
+void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks);
+
+extern struct dpaa_eth_hooks_s dpaa_eth_hooks;
+#endif
+
+int dpa_netdev_init(struct net_device *net_dev,
+ const uint8_t *mac_addr,
+ uint16_t tx_timeout);
+int __cold dpa_start(struct net_device *net_dev);
+int __cold dpa_stop(struct net_device *net_dev);
+void __cold dpa_timeout(struct net_device *net_dev);
+void __cold
+dpa_get_stats64(struct net_device *net_dev,
+ struct rtnl_link_stats64 *stats);
+int dpa_ndo_init(struct net_device *net_dev);
+int dpa_set_features(struct net_device *dev, netdev_features_t features);
+netdev_features_t dpa_fix_features(struct net_device *dev,
+ netdev_features_t features);
+#ifdef CONFIG_FSL_DPAA_TS
+u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv,
+ enum port_type rx_tx, const void *data);
+/* Updates the skb shared hw timestamp from the hardware timestamp */
+int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx,
+ struct skb_shared_hwtstamps *shhwtstamps, const void *data);
+#endif /* CONFIG_FSL_DPAA_TS */
+int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+int __cold dpa_remove(struct platform_device *of_dev);
+struct mac_device * __cold __must_check
+__attribute__((nonnull)) dpa_mac_probe(struct platform_device *_of_dev);
+int dpa_set_mac_address(struct net_device *net_dev, void *addr);
+void dpa_set_rx_mode(struct net_device *net_dev);
+void dpa_set_buffers_layout(struct mac_device *mac_dev,
+ struct dpa_buffer_layout_s *layout);
+int __attribute__((nonnull))
+dpa_bp_alloc(struct dpa_bp *dpa_bp, struct device *dev);
+void __cold __attribute__((nonnull))
+dpa_bp_free(struct dpa_priv_s *priv);
+struct dpa_bp *dpa_bpid2pool(int bpid);
+void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp);
+bool dpa_bpid2pool_use(int bpid);
+void dpa_bp_drain(struct dpa_bp *bp);
+#ifdef CONFIG_FMAN_PFC
+u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback);
+#endif
+struct dpa_fq *dpa_fq_alloc(struct device *dev,
+ u32 fq_start,
+ u32 fq_count,
+ struct list_head *list,
+ enum dpa_fq_type fq_type);
+int dpa_fq_probe_mac(struct device *dev, struct list_head *list,
+ struct fm_port_fqs *port_fqs,
+ bool tx_conf_fqs_per_core,
+ enum port_type ptype);
+int dpa_get_channel(void);
+void dpa_release_channel(void);
+void dpaa_eth_add_channel(u16 channel);
+int dpaa_eth_cgr_init(struct dpa_priv_s *priv);
+void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
+ struct fm_port *tx_port);
+int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable);
+int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable);
+int __cold __attribute__((nonnull))
+dpa_fq_free(struct device *dev, struct list_head *list);
+void dpaa_eth_init_ports(struct mac_device *mac_dev,
+ struct dpa_bp *bp, size_t count,
+ struct fm_port_fqs *port_fqs,
+ struct dpa_buffer_layout_s *buf_layout,
+ struct device *dev);
+void dpa_release_sgt(struct qm_sg_entry *sgt);
+void __attribute__((nonnull))
+dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd);
+void count_ern(struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_mr_entry *msg);
+int dpa_enable_tx_csum(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd, char *parse_results);
+#ifdef CONFIG_FSL_DPAA_CEETM
+void dpa_enable_ceetm(struct net_device *dev);
+void dpa_disable_ceetm(struct net_device *dev);
+#endif
+struct proxy_device {
+ struct mac_device *mac_dev;
+};
+
+/* mac device control functions exposed by proxy interface*/
+int dpa_proxy_start(struct net_device *net_dev);
+int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev);
+int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
+ struct net_device *net_dev);
+int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
+ struct net_device *net_dev);
+
+#endif /* __DPAA_ETH_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c
new file mode 100644
index 000000000000..994d38cd80ef
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c
@@ -0,0 +1,381 @@
+/* Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#include "dpaa_eth_base.h"
+#include "lnxwrp_fsl_fman.h" /* fm_get_rx_extra_headroom(), fm_get_max_frm() */
+#include "mac.h"
+
+#define DPA_DESCRIPTION "FSL DPAA Proxy initialization driver"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_DESCRIPTION(DPA_DESCRIPTION);
+
+static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev);
+#ifdef CONFIG_PM
+
+static int proxy_suspend(struct device *dev)
+{
+ struct proxy_device *proxy_dev = dev_get_drvdata(dev);
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ int err = 0;
+
+ err = fm_port_suspend(mac_dev->port_dev[RX]);
+ if (err)
+ goto port_suspend_failed;
+
+ err = fm_port_suspend(mac_dev->port_dev[TX]);
+ if (err)
+ err = fm_port_resume(mac_dev->port_dev[RX]);
+
+port_suspend_failed:
+ return err;
+}
+
+static int proxy_resume(struct device *dev)
+{
+ struct proxy_device *proxy_dev = dev_get_drvdata(dev);
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ int err = 0;
+
+ err = fm_port_resume(mac_dev->port_dev[TX]);
+ if (err)
+ goto port_resume_failed;
+
+ err = fm_port_resume(mac_dev->port_dev[RX]);
+ if (err)
+ err = fm_port_suspend(mac_dev->port_dev[TX]);
+
+port_resume_failed:
+ return err;
+}
+
+static const struct dev_pm_ops proxy_pm_ops = {
+ .suspend = proxy_suspend,
+ .resume = proxy_resume,
+};
+
+#define PROXY_PM_OPS (&proxy_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define PROXY_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
+static int dpaa_eth_proxy_probe(struct platform_device *_of_dev)
+{
+ int err = 0, i;
+ struct device *dev;
+ struct device_node *dpa_node;
+ struct dpa_bp *dpa_bp;
+ struct list_head proxy_fq_list;
+ size_t count;
+ struct fm_port_fqs port_fqs;
+ struct dpa_buffer_layout_s *buf_layout = NULL;
+ struct mac_device *mac_dev;
+ struct proxy_device *proxy_dev;
+
+ dev = &_of_dev->dev;
+
+ dpa_node = dev->of_node;
+
+ if (!of_device_is_available(dpa_node))
+ return -ENODEV;
+
+ /* Get the buffer pools assigned to this interface */
+ dpa_bp = dpa_bp_probe(_of_dev, &count);
+ if (IS_ERR(dpa_bp))
+ return PTR_ERR(dpa_bp);
+
+ mac_dev = dpa_mac_probe(_of_dev);
+ if (IS_ERR(mac_dev))
+ return PTR_ERR(mac_dev);
+
+ proxy_dev = devm_kzalloc(dev, sizeof(*proxy_dev), GFP_KERNEL);
+ if (!proxy_dev) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ return -ENOMEM;
+ }
+
+ proxy_dev->mac_dev = mac_dev;
+ dev_set_drvdata(dev, proxy_dev);
+
+ /* We have physical ports, so we need to establish
+ * the buffer layout.
+ */
+ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout),
+ GFP_KERNEL);
+ if (!buf_layout) {
+ dev_err(dev, "devm_kzalloc() failed\n");
+ return -ENOMEM;
+ }
+ dpa_set_buffers_layout(mac_dev, buf_layout);
+
+ INIT_LIST_HEAD(&proxy_fq_list);
+
+ memset(&port_fqs, 0, sizeof(port_fqs));
+
+ err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, RX);
+ if (!err)
+ err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true,
+ TX);
+ if (err < 0) {
+ devm_kfree(dev, buf_layout);
+ return err;
+ }
+
+ /* Proxy initializer - Just configures the MAC on behalf of
+ * another partition.
+ */
+ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs,
+ buf_layout, dev);
+
+ /* Proxy interfaces need to be started, and the allocated
+ * memory freed
+ */
+ devm_kfree(dev, buf_layout);
+ devm_kfree(dev, dpa_bp);
+
+ /* Free FQ structures */
+ devm_kfree(dev, port_fqs.rx_defq);
+ devm_kfree(dev, port_fqs.rx_errq);
+ devm_kfree(dev, port_fqs.tx_defq);
+ devm_kfree(dev, port_fqs.tx_errq);
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ err = fm_port_enable(mac_dev->port_dev[i]);
+ if (err)
+ goto port_enable_fail;
+ }
+
+ dev_info(dev, "probed MAC device with MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
+ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
+ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]);
+
+ return 0; /* Proxy interface initialization ended */
+
+port_enable_fail:
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_disable(mac_dev->port_dev[i]);
+ dpa_eth_proxy_remove(_of_dev);
+
+ return err;
+}
+
+int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev,
+ struct net_device *net_dev)
+{
+ struct mac_device *mac_dev;
+ int _errno;
+
+ mac_dev = proxy_dev->mac_dev;
+
+ _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev),
+ net_dev->dev_addr);
+ if (_errno < 0)
+ return _errno;
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_proxy_set_mac_address);
+
+int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev,
+ struct net_device *net_dev)
+{
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ int _errno;
+
+ if (!!(net_dev->flags & IFF_PROMISC) != mac_dev->promisc) {
+ mac_dev->promisc = !mac_dev->promisc;
+ _errno = mac_dev->set_promisc(mac_dev->get_mac_handle(mac_dev),
+ mac_dev->promisc);
+ if (unlikely(_errno < 0))
+ netdev_err(net_dev, "mac_dev->set_promisc() = %d\n",
+ _errno);
+ }
+
+ _errno = mac_dev->set_multi(net_dev, mac_dev);
+ if (unlikely(_errno < 0))
+ return _errno;
+
+ return 0;
+}
+EXPORT_SYMBOL(dpa_proxy_set_rx_mode);
+
+int dpa_proxy_start(struct net_device *net_dev)
+{
+ struct mac_device *mac_dev;
+ const struct dpa_priv_s *priv;
+ struct proxy_device *proxy_dev;
+ int _errno;
+ int i;
+
+ priv = netdev_priv(net_dev);
+ proxy_dev = (struct proxy_device *)priv->peer;
+ mac_dev = proxy_dev->mac_dev;
+
+ _errno = mac_dev->init_phy(net_dev, mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "init_phy() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ _errno = fm_port_enable(mac_dev->port_dev[i]);
+ if (_errno)
+ goto port_enable_fail;
+ }
+
+ _errno = mac_dev->start(mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "mac_dev->start() = %d\n",
+ _errno);
+ goto port_enable_fail;
+ }
+
+ return _errno;
+
+port_enable_fail:
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_disable(mac_dev->port_dev[i]);
+
+ return _errno;
+}
+EXPORT_SYMBOL(dpa_proxy_start);
+
+int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev)
+{
+ struct mac_device *mac_dev = proxy_dev->mac_dev;
+ const struct dpa_priv_s *priv = netdev_priv(net_dev);
+ int _errno, i, err;
+
+ _errno = mac_dev->stop(mac_dev);
+ if (_errno < 0) {
+ if (netif_msg_drv(priv))
+ netdev_err(net_dev, "mac_dev->stop() = %d\n",
+ _errno);
+ return _errno;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ err = fm_port_disable(mac_dev->port_dev[i]);
+ _errno = err ? err : _errno;
+ }
+
+ if (mac_dev->phy_dev)
+ phy_disconnect(mac_dev->phy_dev);
+ mac_dev->phy_dev = NULL;
+
+ return _errno;
+}
+EXPORT_SYMBOL(dpa_proxy_stop);
+
+static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev)
+{
+ struct device *dev = &of_dev->dev;
+ struct proxy_device *proxy_dev = dev_get_drvdata(dev);
+
+ kfree(proxy_dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id dpa_proxy_match[] = {
+ {
+ .compatible = "fsl,dpa-ethernet-init"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dpa_proxy_match);
+
+static struct platform_driver dpa_proxy_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME "-proxy",
+ .of_match_table = dpa_proxy_match,
+ .owner = THIS_MODULE,
+ .pm = PROXY_PM_OPS,
+ },
+ .probe = dpaa_eth_proxy_probe,
+ .remove = dpa_eth_proxy_remove
+};
+
+static int __init __cold dpa_proxy_load(void)
+{
+ int _errno;
+
+ pr_info(DPA_DESCRIPTION "\n");
+
+ /* Initialize dpaa_eth mirror values */
+ dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
+ dpa_max_frm = fm_get_max_frm();
+
+ _errno = platform_driver_register(&dpa_proxy_driver);
+ if (unlikely(_errno < 0)) {
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__, _errno);
+ }
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+
+ return _errno;
+}
+module_init(dpa_proxy_load);
+
+static void __exit __cold dpa_proxy_unload(void)
+{
+ platform_driver_unregister(&dpa_proxy_driver);
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+}
+module_exit(dpa_proxy_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
new file mode 100644
index 000000000000..c05cbe8d0687
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
@@ -0,0 +1,1268 @@
+/* Copyright 2012 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/highmem.h>
+#include <linux/fsl_bman.h>
+#include <net/sock.h>
+
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+#ifdef CONFIG_FSL_DPAA_1588
+#include "dpaa_1588.h"
+#endif
+#ifdef CONFIG_FSL_DPAA_CEETM
+#include "dpaa_eth_ceetm.h"
+#endif
+
+/* DMA map and add a page frag back into the bpool.
+ * @vaddr fragment must have been allocated with netdev_alloc_frag(),
+ * specifically for fitting into @dpa_bp.
+ */
+static void dpa_bp_recycle_frag(struct dpa_bp *dpa_bp, unsigned long vaddr,
+ int *count_ptr)
+{
+ struct bm_buffer bmb;
+ dma_addr_t addr;
+
+ bmb.opaque = 0;
+
+ addr = dma_map_single(dpa_bp->dev, (void *)vaddr, dpa_bp->size,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ dev_err(dpa_bp->dev, "DMA mapping failed");
+ return;
+ }
+
+ bm_buffer_set64(&bmb, addr);
+
+ while (bman_release(dpa_bp->pool, &bmb, 1, 0))
+ cpu_relax();
+
+ (*count_ptr)++;
+}
+
+static int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp)
+{
+ void *new_buf, *fman_buf;
+ struct bm_buffer bmb[8];
+ dma_addr_t addr;
+ uint8_t i;
+ struct device *dev = dpa_bp->dev;
+ struct sk_buff *skb, **skbh;
+
+ memset(bmb, 0, sizeof(struct bm_buffer) * 8);
+
+ for (i = 0; i < 8; i++) {
+ /* We'll prepend the skb back-pointer; can't use the DPA
+ * priv space, because FMan will overwrite it (from offset 0)
+ * if it ends up being the second, third, etc. fragment
+ * in a S/G frame.
+ *
+ * We only need enough space to store a pointer, but allocate
+ * an entire cacheline for performance reasons.
+ */
+#ifdef FM_ERRATUM_A050385
+ if (unlikely(fm_has_errata_a050385())) {
+ struct page *new_page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!new_page))
+ goto netdev_alloc_failed;
+ new_buf = page_address(new_page);
+ }
+ else
+#endif
+ new_buf = netdev_alloc_frag(SMP_CACHE_BYTES + DPA_BP_RAW_SIZE);
+
+ if (unlikely(!new_buf))
+ goto netdev_alloc_failed;
+ new_buf = PTR_ALIGN(new_buf, SMP_CACHE_BYTES);
+
+ /* Apart from the buffer that will be used by the FMan, the
+ * skb also guarantees enough space to hold the backpointer
+ * in the headroom and the shared info at the end.
+ */
+ skb = build_skb(new_buf,
+ SMP_CACHE_BYTES + DPA_SKB_SIZE(dpa_bp->size) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+ if (unlikely(!skb)) {
+ put_page(virt_to_head_page(new_buf));
+ goto build_skb_failed;
+ }
+
+ /* Reserve SMP_CACHE_BYTES in the skb's headroom to store the
+ * backpointer. This area will not be synced to, or
+ * overwritten by, the FMan.
+ */
+ skb_reserve(skb, SMP_CACHE_BYTES);
+
+ /* We don't sync the first SMP_CACHE_BYTES of the buffer to
+ * the FMan. The skb backpointer is stored at the end of the
+ * reserved headroom. Otherwise it will be overwritten by the
+ * FMan.
+ * The buffer synced with the FMan starts right after the
+ * reserved headroom.
+ */
+ fman_buf = new_buf + SMP_CACHE_BYTES;
+ DPA_WRITE_SKB_PTR(skb, skbh, fman_buf, -1);
+
+ addr = dma_map_single(dev, fman_buf,
+ dpa_bp->size, DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dev, addr)))
+ goto dma_map_failed;
+
+ bm_buffer_set64(&bmb[i], addr);
+ }
+
+release_bufs:
+ /* Release the buffers. In case bman is busy, keep trying
+ * until successful. bman_release() is guaranteed to succeed
+ * in a reasonable amount of time
+ */
+ while (unlikely(bman_release(dpa_bp->pool, bmb, i, 0)))
+ cpu_relax();
+ return i;
+
+dma_map_failed:
+ kfree_skb(skb);
+
+build_skb_failed:
+netdev_alloc_failed:
+ net_err_ratelimited("dpa_bp_add_8_bufs() failed\n");
+ WARN_ONCE(1, "Memory allocation failure on Rx\n");
+
+ bm_buffer_set64(&bmb[i], 0);
+ /* Avoid releasing a completely null buffer; bman_release() requires
+ * at least one buffer.
+ */
+ if (likely(i))
+ goto release_bufs;
+
+ return 0;
+}
+
+/* Cold path wrapper over _dpa_bp_add_8_bufs(). */
+static void dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp, int cpu)
+{
+ int *count_ptr = per_cpu_ptr(dpa_bp->percpu_count, cpu);
+ *count_ptr += _dpa_bp_add_8_bufs(dpa_bp);
+}
+
+int dpa_bp_priv_seed(struct dpa_bp *dpa_bp)
+{
+ int i;
+
+ /* Give each CPU an allotment of "config_count" buffers */
+ for_each_possible_cpu(i) {
+ int j;
+
+ /* Although we access another CPU's counters here
+ * we do it at boot time so it is safe
+ */
+ for (j = 0; j < dpa_bp->config_count; j += 8)
+ dpa_bp_add_8_bufs(dpa_bp, i);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dpa_bp_priv_seed);
+
+/* Add buffers/(pages) for Rx processing whenever bpool count falls below
+ * REFILL_THRESHOLD.
+ */
+int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *countptr)
+{
+ int count = *countptr;
+ int new_bufs;
+
+ if (unlikely(count < CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD)) {
+ do {
+ new_bufs = _dpa_bp_add_8_bufs(dpa_bp);
+ if (unlikely(!new_bufs)) {
+ /* Avoid looping forever if we've temporarily
+ * run out of memory. We'll try again at the
+ * next NAPI cycle.
+ */
+ break;
+ }
+ count += new_bufs;
+ } while (count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT);
+
+ *countptr = count;
+ if (unlikely(count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT))
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dpaa_eth_refill_bpools);
+
+/* Cleanup function for outgoing frame descriptors that were built on Tx path,
+ * either contiguous frames or scatter/gather ones.
+ * Skb freeing is not handled here.
+ *
+ * This function may be called on error paths in the Tx function, so guard
+ * against cases when not all fd relevant fields were filled in.
+ *
+ * Return the skb backpointer, since for S/G frames the buffer containing it
+ * gets freed here.
+ */
+struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv,
+ const struct qm_fd *fd)
+{
+ const struct qm_sg_entry *sgt;
+ int i;
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
+ dma_addr_t addr = qm_fd_addr(fd);
+ dma_addr_t sg_addr;
+ struct sk_buff **skbh;
+ struct sk_buff *skb = NULL;
+ const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
+ int nr_frags;
+ int sg_len;
+
+ /* retrieve skb back pointer */
+ DPA_READ_SKB_PTR(skb, skbh, phys_to_virt(addr), 0);
+
+ if (unlikely(fd->format == qm_fd_sg)) {
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ dma_unmap_single(dpa_bp->dev, addr,
+ dpa_fd_offset(fd) + DPA_SGT_SIZE,
+ dma_dir);
+
+ /* The sgt buffer has been allocated with netdev_alloc_frag(),
+ * it's from lowmem.
+ */
+ sgt = phys_to_virt(addr + dpa_fd_offset(fd));
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid &&
+ priv->tsu->hwts_tx_en_ioctl)
+ dpa_ptp_store_txstamp(priv, skb, (void *)skbh);
+#endif
+#ifdef CONFIG_FSL_DPAA_TS
+ if (unlikely(priv->ts_tx_en &&
+ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ struct skb_shared_hwtstamps shhwtstamps;
+
+ dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh);
+ skb_tstamp_tx(skb, &shhwtstamps);
+ }
+#endif /* CONFIG_FSL_DPAA_TS */
+
+ /* sgt[0] is from lowmem, was dma_map_single()-ed */
+ sg_addr = qm_sg_addr(&sgt[0]);
+ sg_len = qm_sg_entry_get_len(&sgt[0]);
+ dma_unmap_single(dpa_bp->dev, sg_addr, sg_len, dma_dir);
+
+ /* remaining pages were mapped with dma_map_page() */
+ for (i = 1; i <= nr_frags; i++) {
+ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
+ sg_addr = qm_sg_addr(&sgt[i]);
+ sg_len = qm_sg_entry_get_len(&sgt[i]);
+ dma_unmap_page(dpa_bp->dev, sg_addr, sg_len, dma_dir);
+ }
+
+ /* Free the page frag that we allocated on Tx */
+ put_page(virt_to_head_page(sgt));
+ } else {
+ dma_unmap_single(dpa_bp->dev, addr,
+ skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
+#ifdef CONFIG_FSL_DPAA_TS
+ /* get the timestamp for non-SG frames */
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid &&
+ priv->tsu->hwts_tx_en_ioctl)
+ dpa_ptp_store_txstamp(priv, skb, (void *)skbh);
+#endif
+ if (unlikely(priv->ts_tx_en &&
+ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ struct skb_shared_hwtstamps shhwtstamps;
+
+ dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh);
+ skb_tstamp_tx(skb, &shhwtstamps);
+ }
+#endif
+ }
+
+ return skb;
+}
+EXPORT_SYMBOL(_dpa_cleanup_tx_fd);
+
+#ifndef CONFIG_FSL_DPAA_TS
+bool dpa_skb_is_recyclable(struct sk_buff *skb)
+{
+ /* No recycling possible if skb buffer is kmalloc'ed */
+ if (skb->head_frag == 0)
+ return false;
+
+ /* or if it's an userspace buffer */
+ if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
+ return false;
+
+ /* or if it's cloned or shared */
+ if (skb_shared(skb) || skb_cloned(skb) ||
+ skb->fclone != SKB_FCLONE_UNAVAILABLE)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL(dpa_skb_is_recyclable);
+
+bool dpa_buf_is_recyclable(struct sk_buff *skb,
+ uint32_t min_size,
+ uint16_t min_offset,
+ unsigned char **new_buf_start)
+{
+ unsigned char *new;
+
+ /* In order to recycle a buffer, the following conditions must be met:
+ * - buffer size no less than the buffer pool size
+ * - buffer size no higher than an upper limit (to avoid moving too much
+ * system memory to the buffer pools)
+ * - buffer address aligned to cacheline bytes
+ * - offset of data from start of buffer no lower than a minimum value
+ * - offset of data from start of buffer no higher than a maximum value
+ * - the skb back-pointer is stored safely
+ */
+
+ /* guarantee both the minimum size and the minimum data offset */
+ new = min(skb_end_pointer(skb) - min_size, skb->data - min_offset);
+
+ /* left align to the nearest cacheline */
+ new = (unsigned char *)((unsigned long)new & ~(SMP_CACHE_BYTES - 1));
+
+ /* Make sure there is enough space to store the skb back-pointer in
+ * the headroom, right before the start of the buffer.
+ *
+ * Guarantee that both maximum size and maximum data offsets aren't
+ * crossed.
+ */
+ if (likely(new >= (skb->head + sizeof(void *)) &&
+ new >= (skb->data - DPA_MAX_FD_OFFSET) &&
+ skb_end_pointer(skb) - new <= DPA_RECYCLE_MAX_SIZE)) {
+ *new_buf_start = new;
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(dpa_buf_is_recyclable);
+#endif
+
+/* Build a linear skb around the received buffer.
+ * We are guaranteed there is enough room at the end of the data buffer to
+ * accommodate the shared info area of the skb.
+ */
+static struct sk_buff *__hot contig_fd_to_skb(const struct dpa_priv_s *priv,
+ const struct qm_fd *fd, int *use_gro)
+{
+ dma_addr_t addr = qm_fd_addr(fd);
+ ssize_t fd_off = dpa_fd_offset(fd);
+ void *vaddr;
+ const fm_prs_result_t *parse_results;
+ struct sk_buff *skb = NULL, **skbh;
+
+ vaddr = phys_to_virt(addr);
+ DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
+
+ /* Retrieve the skb and adjust data and tail pointers, to make sure
+ * forwarded skbs will have enough space on Tx if extra headers
+ * are added.
+ */
+ DPA_READ_SKB_PTR(skb, skbh, vaddr, -1);
+
+#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
+ /* When using jumbo Rx buffers, we risk having frames dropped due to
+ * the socket backlog reaching its maximum allowed size.
+ * Use the frame length for the skb truesize instead of the buffer
+ * size, as this is the size of the data that actually gets copied to
+ * userspace.
+ * The stack may increase the payload. In this case, it will want to
+ * warn us that the frame length is larger than the truesize. We
+ * bypass the warning.
+ */
+ skb->truesize = SKB_TRUESIZE(dpa_fd_length(fd));
+#endif
+
+ DPA_BUG_ON(fd_off != priv->rx_headroom);
+ skb_reserve(skb, fd_off);
+ skb_put(skb, dpa_fd_length(fd));
+
+ /* Peek at the parse results for csum validation */
+ parse_results = (const fm_prs_result_t *)(vaddr +
+ DPA_RX_PRIV_DATA_SIZE);
+ _dpa_process_parse_results(parse_results, fd, skb, use_gro);
+
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_rx_en_ioctl)
+ dpa_ptp_store_rxstamp(priv, skb, vaddr);
+#endif
+#ifdef CONFIG_FSL_DPAA_TS
+ if (priv->ts_rx_en)
+ dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr);
+#endif /* CONFIG_FSL_DPAA_TS */
+
+ return skb;
+}
+
+
+/* Build an skb with the data of the first S/G entry in the linear portion and
+ * the rest of the frame as skb fragments.
+ *
+ * The page fragment holding the S/G Table is recycled here.
+ */
+static struct sk_buff *__hot sg_fd_to_skb(const struct dpa_priv_s *priv,
+ const struct qm_fd *fd, int *use_gro,
+ int *count_ptr)
+{
+ const struct qm_sg_entry *sgt;
+ dma_addr_t addr = qm_fd_addr(fd);
+ ssize_t fd_off = dpa_fd_offset(fd);
+ dma_addr_t sg_addr;
+ void *vaddr, *sg_vaddr;
+ struct dpa_bp *dpa_bp;
+ struct page *page, *head_page;
+ int frag_offset, frag_len;
+ int page_offset;
+ int i;
+ const fm_prs_result_t *parse_results;
+ struct sk_buff *skb = NULL, *skb_tmp, **skbh;
+
+ vaddr = phys_to_virt(addr);
+ DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
+
+ dpa_bp = priv->dpa_bp;
+ /* Iterate through the SGT entries and add data buffers to the skb */
+ sgt = vaddr + fd_off;
+ for (i = 0; i < DPA_SGT_MAX_ENTRIES; i++) {
+ /* Extension bit is not supported */
+ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i]));
+
+ /* We use a single global Rx pool */
+ DPA_BUG_ON(dpa_bp !=
+ dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i])));
+
+ sg_addr = qm_sg_addr(&sgt[i]);
+ sg_vaddr = phys_to_virt(sg_addr);
+ DPA_BUG_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+ SMP_CACHE_BYTES));
+
+ dma_unmap_single(dpa_bp->dev, sg_addr, dpa_bp->size,
+ DMA_BIDIRECTIONAL);
+ if (i == 0) {
+ DPA_READ_SKB_PTR(skb, skbh, sg_vaddr, -1);
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid &&
+ priv->tsu->hwts_rx_en_ioctl)
+ dpa_ptp_store_rxstamp(priv, skb, vaddr);
+#endif
+#ifdef CONFIG_FSL_DPAA_TS
+ if (priv->ts_rx_en)
+ dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr);
+#endif /* CONFIG_FSL_DPAA_TS */
+
+ /* In the case of a SG frame, FMan stores the Internal
+ * Context in the buffer containing the sgt.
+ * Inspect the parse results before anything else.
+ */
+ parse_results = (const fm_prs_result_t *)(vaddr +
+ DPA_RX_PRIV_DATA_SIZE);
+ _dpa_process_parse_results(parse_results, fd, skb,
+ use_gro);
+
+ /* Make sure forwarded skbs will have enough space
+ * on Tx, if extra headers are added.
+ */
+ DPA_BUG_ON(fd_off != priv->rx_headroom);
+ skb_reserve(skb, fd_off);
+ skb_put(skb, qm_sg_entry_get_len(&sgt[i]));
+ } else {
+ /* Not the first S/G entry; all data from buffer will
+ * be added in an skb fragment; fragment index is offset
+ * by one since first S/G entry was incorporated in the
+ * linear part of the skb.
+ *
+ * Caution: 'page' may be a tail page.
+ */
+ DPA_READ_SKB_PTR(skb_tmp, skbh, sg_vaddr, -1);
+ page = virt_to_page(sg_vaddr);
+ head_page = virt_to_head_page(sg_vaddr);
+
+ /* Free (only) the skbuff shell because its data buffer
+ * is already a frag in the main skb.
+ */
+ get_page(head_page);
+ dev_kfree_skb(skb_tmp);
+
+ /* Compute offset in (possibly tail) page */
+ page_offset = ((unsigned long)sg_vaddr &
+ (PAGE_SIZE - 1)) +
+ (page_address(page) - page_address(head_page));
+ /* page_offset only refers to the beginning of sgt[i];
+ * but the buffer itself may have an internal offset.
+ */
+ frag_offset = qm_sg_entry_get_offset(&sgt[i]) +
+ page_offset;
+ frag_len = qm_sg_entry_get_len(&sgt[i]);
+ /* skb_add_rx_frag() does no checking on the page; if
+ * we pass it a tail page, we'll end up with
+ * bad page accounting and eventually with segafults.
+ */
+ skb_add_rx_frag(skb, i - 1, head_page, frag_offset,
+ frag_len, dpa_bp->size);
+ }
+ /* Update the pool count for the current {cpu x bpool} */
+ (*count_ptr)--;
+
+ if (qm_sg_entry_get_final(&sgt[i]))
+ break;
+ }
+ WARN_ONCE(i == DPA_SGT_MAX_ENTRIES, "No final bit on SGT\n");
+
+ /* recycle the SGT fragment */
+ DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid));
+ dpa_bp_recycle_frag(dpa_bp, (unsigned long)vaddr, count_ptr);
+ return skb;
+}
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static inline int dpa_skb_loop(const struct dpa_priv_s *priv,
+ struct sk_buff *skb)
+{
+ if (unlikely(priv->loop_to < 0))
+ return 0; /* loop disabled by default */
+
+ skb_push(skb, ETH_HLEN); /* compensate for eth_type_trans */
+ /* Save the current CPU ID in order to maintain core affinity */
+ skb_set_queue_mapping(skb, raw_smp_processor_id());
+ dpa_tx(skb, dpa_loop_netdevs[priv->loop_to]);
+
+ return 1; /* Frame Tx on the selected interface */
+}
+#endif
+
+void __hot _dpa_rx(struct net_device *net_dev,
+ struct qman_portal *portal,
+ const struct dpa_priv_s *priv,
+ struct dpa_percpu_priv_s *percpu_priv,
+ const struct qm_fd *fd,
+ u32 fqid,
+ int *count_ptr)
+{
+ struct dpa_bp *dpa_bp;
+ struct sk_buff *skb;
+ dma_addr_t addr = qm_fd_addr(fd);
+ u32 fd_status = fd->status;
+ unsigned int skb_len;
+ struct rtnl_link_stats64 *percpu_stats = &percpu_priv->stats;
+ int use_gro = net_dev->features & NETIF_F_GRO;
+
+ if (unlikely(fd_status & FM_FD_STAT_RX_ERRORS) != 0) {
+ if (netif_msg_hw(priv) && net_ratelimit())
+ netdev_warn(net_dev, "FD status = 0x%08x\n",
+ fd_status & FM_FD_STAT_RX_ERRORS);
+
+ percpu_stats->rx_errors++;
+ goto _release_frame;
+ }
+
+ dpa_bp = priv->dpa_bp;
+ DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid));
+
+ /* prefetch the first 64 bytes of the frame or the SGT start */
+ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
+ prefetch(phys_to_virt(addr) + dpa_fd_offset(fd));
+
+ /* The only FD types that we may receive are contig and S/G */
+ DPA_BUG_ON((fd->format != qm_fd_contig) && (fd->format != qm_fd_sg));
+
+ if (likely(fd->format == qm_fd_contig)) {
+#ifdef CONFIG_FSL_DPAA_HOOKS
+ /* Execute the Rx processing hook, if it exists. */
+ if (dpaa_eth_hooks.rx_default &&
+ dpaa_eth_hooks.rx_default((void *)fd, net_dev,
+ fqid) == DPAA_ETH_STOLEN) {
+ /* won't count the rx bytes in */
+ return;
+ }
+#endif
+ skb = contig_fd_to_skb(priv, fd, &use_gro);
+ } else {
+ skb = sg_fd_to_skb(priv, fd, &use_gro, count_ptr);
+ percpu_priv->rx_sg++;
+ }
+
+ /* Account for either the contig buffer or the SGT buffer (depending on
+ * which case we were in) having been removed from the pool.
+ */
+ (*count_ptr)--;
+ skb->protocol = eth_type_trans(skb, net_dev);
+
+ skb_len = skb->len;
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ if (dpa_skb_loop(priv, skb)) {
+ percpu_stats->rx_packets++;
+ percpu_stats->rx_bytes += skb_len;
+ return;
+ }
+#endif
+
+ skb_record_rx_queue(skb, raw_smp_processor_id());
+
+ if (use_gro) {
+ gro_result_t gro_result;
+ const struct qman_portal_config *pc =
+ qman_p_get_portal_config(portal);
+ struct dpa_napi_portal *np = &percpu_priv->np[pc->index];
+
+ np->p = portal;
+ gro_result = napi_gro_receive(&np->napi, skb);
+ /* If frame is dropped by the stack, rx_dropped counter is
+ * incremented automatically, so no need for us to update it
+ */
+ if (unlikely(gro_result == GRO_DROP))
+ goto packet_dropped;
+ } else if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
+ goto packet_dropped;
+
+ percpu_stats->rx_packets++;
+ percpu_stats->rx_bytes += skb_len;
+
+packet_dropped:
+ return;
+
+_release_frame:
+ dpa_fd_release(net_dev, fd);
+}
+
+int __hot skb_to_contig_fd(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd,
+ int *count_ptr, int *offset)
+{
+ struct sk_buff **skbh;
+ dma_addr_t addr;
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
+ struct net_device *net_dev = priv->net_dev;
+ int err;
+ enum dma_data_direction dma_dir;
+ unsigned char *buffer_start;
+ int dma_map_size;
+
+#ifndef CONFIG_FSL_DPAA_TS
+ /* Check recycling conditions; only if timestamp support is not
+ * enabled, otherwise we need the fd back on tx confirmation
+ */
+
+ /* We can recycle the buffer if:
+ * - the pool is not full
+ * - the buffer meets the skb recycling conditions
+ * - the buffer meets our own (size, offset, align) conditions
+ */
+ if (likely((*count_ptr < dpa_bp->target_count) &&
+ dpa_skb_is_recyclable(skb) &&
+ dpa_buf_is_recyclable(skb, dpa_bp->size,
+ priv->tx_headroom, &buffer_start))) {
+ /* Buffer is recyclable; use the new start address
+ * and set fd parameters and DMA mapping direction
+ */
+ fd->bpid = dpa_bp->bpid;
+ DPA_BUG_ON(skb->data - buffer_start > DPA_MAX_FD_OFFSET);
+ fd->offset = (uint16_t)(skb->data - buffer_start);
+ dma_dir = DMA_BIDIRECTIONAL;
+ dma_map_size = dpa_bp->size;
+
+ /* Store the skb back-pointer before the start of the buffer.
+ * Otherwise it will be overwritten by the FMan.
+ */
+ DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, -1);
+ *offset = skb_headroom(skb) - fd->offset;
+ } else
+#endif
+ {
+ /* Not recyclable.
+ * We are guaranteed to have at least tx_headroom bytes
+ * available, so just use that for offset.
+ */
+ fd->bpid = 0xff;
+ buffer_start = skb->data - priv->tx_headroom;
+ fd->offset = priv->tx_headroom;
+ dma_dir = DMA_TO_DEVICE;
+ dma_map_size = skb_tail_pointer(skb) - buffer_start;
+
+ /* The buffer will be Tx-confirmed, but the TxConf cb must
+ * necessarily look at our Tx private data to retrieve the
+ * skbuff. Store the back-pointer inside the buffer.
+ */
+ DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0);
+ }
+
+ /* Enable L3/L4 hardware checksum computation.
+ *
+ * We must do this before dma_map_single(DMA_TO_DEVICE), because we may
+ * need to write into the skb.
+ */
+ err = dpa_enable_tx_csum(priv, skb, fd,
+ ((char *)skbh) + DPA_TX_PRIV_DATA_SIZE);
+ if (unlikely(err < 0)) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ netdev_err(net_dev, "HW csum error: %d\n", err);
+ return err;
+ }
+
+ /* Fill in the rest of the FD fields */
+ fd->format = qm_fd_contig;
+ fd->length20 = skb->len;
+ fd->cmd |= FM_FD_CMD_FCO;
+
+ /* Map the entire buffer size that may be seen by FMan, but no more */
+ addr = dma_map_single(dpa_bp->dev, skbh, dma_map_size, dma_dir);
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ netdev_err(net_dev, "dma_map_single() failed\n");
+ return -EINVAL;
+ }
+ qm_fd_addr_set64(fd, addr);
+
+ return 0;
+}
+EXPORT_SYMBOL(skb_to_contig_fd);
+
+#ifdef FM_ERRATUM_A050385
+/* Verify the conditions that trigger the A050385 errata:
+ * - 4K memory address boundary crossings when the data/SG fragments aren't
+ * aligned to 256 bytes
+ * - data and SG fragments that aren't aligned to 16 bytes
+ * - SG fragments that aren't mod 16 bytes in size (except for the last
+ * fragment)
+ */
+static bool a050385_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv)
+{
+ skb_frag_t *frag;
+ int i, nr_frags;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ /* Check if the linear data is 16 byte aligned */
+ if ((uintptr_t)skb->data % 16)
+ return true;
+
+ /* Check if the needed headroom crosses a 4K address boundary without
+ * being 256 byte aligned
+ */
+ if (CROSS_4K(skb->data - priv->tx_headroom, priv->tx_headroom) &&
+ (((uintptr_t)skb->data - priv->tx_headroom) % 256))
+ return true;
+
+ /* Check if the linear data crosses a 4K address boundary without
+ * being 256 byte aligned
+ */
+ if (CROSS_4K(skb->data, skb_headlen(skb)) &&
+ ((uintptr_t)skb->data % 256))
+ return true;
+
+ /* When using Scatter/Gather, the linear data becomes the first
+ * fragment in the list and must follow the same restrictions as the
+ * other fragments.
+ *
+ * Check if the linear data is mod 16 bytes in size.
+ */
+ if (nr_frags && (skb_headlen(skb) % 16))
+ return true;
+
+ /* Check the SG fragments. They must follow the same rules as the
+ * linear data with and additional restriction: they must be multiple
+ * of 16 bytes in size to account for the hardware carryover effect.
+ */
+ for (i = 0; i < nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+
+ /* Check if the fragment is a multiple of 16 bytes in size.
+ * The last fragment is exempt from this restriction.
+ */
+ if ((i != (nr_frags - 1)) && (skb_frag_size(frag) % 16))
+ return true;
+
+ /* Check if the fragment is 16 byte aligned */
+ if (skb_frag_off(frag) % 16)
+ return true;
+
+ /* Check if the fragment crosses a 4K address boundary. Since
+ * the alignment of previous fragments can influence the
+ * current fragment, checking for the 256 byte alignment
+ * isn't relevant.
+ */
+ if (CROSS_4K(skb_frag_off(frag), skb_frag_size(frag)))
+ return true;
+ }
+
+ return false;
+}
+
+/* Realign the skb by copying its contents at the start of a newly allocated
+ * page. Build a new skb around the new buffer and release the old one.
+ * A performance drop should be expected.
+ */
+static struct sk_buff *a050385_realign_skb(struct sk_buff *skb,
+ struct dpa_priv_s *priv)
+{
+ int trans_offset = skb_transport_offset(skb);
+ int net_offset = skb_network_offset(skb);
+ struct sk_buff *nskb = NULL;
+ int nsize, headroom;
+ struct page *npage;
+ void *npage_addr;
+
+ headroom = DPAA_A050385_HEADROOM;
+
+ /* For the new skb we only need the old one's data (both non-paged and
+ * paged). We can skip the old tailroom.
+ *
+ * Make sure the skb_shinfo is cache-line aligned.
+ */
+ nsize = SMP_CACHE_BYTES + DPA_SKB_SIZE(headroom + skb->len) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ /* Reserve enough memory to accommodate Jumbo frames */
+ npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, get_order(nsize));
+ if (unlikely(!npage)) {
+ WARN_ONCE(1, "Memory allocation failure\n");
+ return NULL;
+ }
+ npage_addr = page_address(npage);
+
+ nskb = build_skb(npage_addr, nsize);
+ if (unlikely(!nskb))
+ goto err;
+
+ /* Reserve only the needed headroom in order to guarantee the data's
+ * alignment.
+ * Code borrowed and adapted from skb_copy().
+ */
+ skb_reserve(nskb, headroom);
+ skb_put(nskb, skb->len);
+ if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
+ WARN_ONCE(1, "skb parsing failure\n");
+ goto err;
+ }
+ skb_copy_header(nskb, skb);
+
+#ifdef CONFIG_FSL_DPAA_TS
+ /* Copy relevant timestamp info from the old skb to the new */
+ if (priv->ts_tx_en) {
+ skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags;
+ skb_shinfo(nskb)->hwtstamps = skb_shinfo(skb)->hwtstamps;
+ skb_shinfo(nskb)->tskey = skb_shinfo(skb)->tskey;
+ if (skb->sk)
+ skb_set_owner_w(nskb, skb->sk);
+ }
+#endif
+ /* We move the headroom when we align it so we have to reset the
+ * network and transport header offsets relative to the new data
+ * pointer. The checksum offload relies on these offsets.
+ */
+ skb_set_network_header(nskb, net_offset);
+ skb_set_transport_header(nskb, trans_offset);
+
+ return nskb;
+
+err:
+ if (nskb)
+ dev_kfree_skb(nskb);
+ put_page(npage);
+ return NULL;
+}
+#endif
+
+int __hot skb_to_sg_fd(struct dpa_priv_s *priv,
+ struct sk_buff *skb, struct qm_fd *fd)
+{
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
+ dma_addr_t addr;
+ dma_addr_t sg_addr;
+ struct sk_buff **skbh;
+ struct net_device *net_dev = priv->net_dev;
+ int sg_len, sgt_size;
+ int err;
+
+ struct qm_sg_entry *sgt;
+ void *sgt_buf;
+ skb_frag_t *frag;
+ int i = 0, j = 0;
+ int nr_frags;
+ const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ fd->format = qm_fd_sg;
+
+ /* The FMan reads 256 bytes from the start of the SGT regardless of
+ * its size. In accordance, we reserve the same amount of memory as
+ * well.
+ */
+ sgt_size = DPA_SGT_SIZE;
+
+ /* Get a page frag to store the SGTable, or a full page if the errata
+ * is in place and we need to avoid crossing a 4k boundary.
+ */
+#ifdef FM_ERRATUM_A050385
+ if (unlikely(fm_has_errata_a050385())) {
+ struct page *new_page = alloc_page(GFP_ATOMIC);
+
+ if (unlikely(!new_page))
+ return -ENOMEM;
+ sgt_buf = page_address(new_page);
+ }
+ else
+#endif
+ sgt_buf = netdev_alloc_frag(priv->tx_headroom + sgt_size);
+ if (unlikely(!sgt_buf)) {
+ dev_err(dpa_bp->dev, "netdev_alloc_frag() failed\n");
+ return -ENOMEM;
+ }
+
+ /* it seems that the memory allocator does not zero the allocated mem */
+ memset(sgt_buf, 0, priv->tx_headroom + sgt_size);
+
+ /* Enable L3/L4 hardware checksum computation.
+ *
+ * We must do this before dma_map_single(DMA_TO_DEVICE), because we may
+ * need to write into the skb.
+ */
+ err = dpa_enable_tx_csum(priv, skb, fd,
+ sgt_buf + DPA_TX_PRIV_DATA_SIZE);
+ if (unlikely(err < 0)) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ netdev_err(net_dev, "HW csum error: %d\n", err);
+ goto csum_failed;
+ }
+
+ /* Assign the data from skb->data to the first SG list entry */
+ sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom);
+ sg_len = skb_headlen(skb);
+ qm_sg_entry_set_bpid(&sgt[0], 0xff);
+ qm_sg_entry_set_offset(&sgt[0], 0);
+ qm_sg_entry_set_len(&sgt[0], sg_len);
+ qm_sg_entry_set_ext(&sgt[0], 0);
+ qm_sg_entry_set_final(&sgt[0], 0);
+
+ addr = dma_map_single(dpa_bp->dev, skb->data, sg_len, dma_dir);
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ dev_err(dpa_bp->dev, "DMA mapping failed");
+ err = -EINVAL;
+ goto sg0_map_failed;
+ }
+
+ qm_sg_entry_set64(&sgt[0], addr);
+
+ /* populate the rest of SGT entries */
+ for (i = 1; i <= nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i - 1];
+ qm_sg_entry_set_bpid(&sgt[i], 0xff);
+ qm_sg_entry_set_offset(&sgt[i], 0);
+ qm_sg_entry_set_len(&sgt[i], frag->bv_len);
+ qm_sg_entry_set_ext(&sgt[i], 0);
+
+ if (i == nr_frags)
+ qm_sg_entry_set_final(&sgt[i], 1);
+ else
+ qm_sg_entry_set_final(&sgt[i], 0);
+
+ DPA_BUG_ON(!skb_frag_page(frag));
+ addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, frag->bv_len,
+ dma_dir);
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ dev_err(dpa_bp->dev, "DMA mapping failed");
+ err = -EINVAL;
+ goto sg_map_failed;
+ }
+
+ /* keep the offset in the address */
+ qm_sg_entry_set64(&sgt[i], addr);
+ }
+
+ fd->length20 = skb->len;
+ fd->offset = priv->tx_headroom;
+
+ /* DMA map the SGT page
+ *
+ * It's safe to store the skb back-pointer inside the buffer since
+ * S/G frames are non-recyclable.
+ */
+ DPA_WRITE_SKB_PTR(skb, skbh, sgt_buf, 0);
+ addr = dma_map_single(dpa_bp->dev, sgt_buf,
+ priv->tx_headroom + sgt_size,
+ dma_dir);
+
+ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) {
+ dev_err(dpa_bp->dev, "DMA mapping failed");
+ err = -EINVAL;
+ goto sgt_map_failed;
+ }
+
+ qm_fd_addr_set64(fd, addr);
+ fd->bpid = 0xff;
+ fd->cmd |= FM_FD_CMD_FCO;
+
+ return 0;
+
+sgt_map_failed:
+sg_map_failed:
+ for (j = 0; j < i; j++) {
+ sg_addr = qm_sg_addr(&sgt[j]);
+ dma_unmap_page(dpa_bp->dev, sg_addr,
+ qm_sg_entry_get_len(&sgt[j]), dma_dir);
+ }
+sg0_map_failed:
+csum_failed:
+ put_page(virt_to_head_page(sgt_buf));
+
+ return err;
+}
+EXPORT_SYMBOL(skb_to_sg_fd);
+
+int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv;
+ int queue_mapping = dpa_get_queue_mapping(skb);
+ struct qman_fq *egress_fq, *conf_fq;
+
+#ifdef CONFIG_FSL_DPAA_HOOKS
+ /* If there is a Tx hook, run it. */
+ if (dpaa_eth_hooks.tx &&
+ dpaa_eth_hooks.tx(skb, net_dev) == DPAA_ETH_STOLEN)
+ /* won't update any Tx stats */
+ return NETDEV_TX_OK;
+#endif
+
+ priv = netdev_priv(net_dev);
+
+#ifdef CONFIG_FSL_DPAA_CEETM
+ if (priv->ceetm_en)
+ return ceetm_tx(skb, net_dev);
+#endif
+
+ if (unlikely(queue_mapping >= DPAA_ETH_TX_QUEUES))
+ queue_mapping = queue_mapping % DPAA_ETH_TX_QUEUES;
+
+ egress_fq = priv->egress_fqs[queue_mapping];
+ conf_fq = priv->conf_fqs[queue_mapping];
+
+ return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq);
+}
+
+int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev,
+ struct qman_fq *egress_fq, struct qman_fq *conf_fq)
+{
+ struct dpa_priv_s *priv;
+ struct qm_fd fd;
+ struct dpa_percpu_priv_s *percpu_priv;
+ struct rtnl_link_stats64 *percpu_stats;
+ int err = 0;
+ bool nonlinear, skb_changed, skb_need_wa;
+ int *countptr, offset = 0;
+ struct sk_buff *nskb;
+
+ /* Flags to help optimize the A050385 errata restriction checks.
+ *
+ * First flag marks if the skb changed between the first A050385 check
+ * and the moment it's converted to an FD.
+ *
+ * The second flag marks if the skb needs to be realigned in order to
+ * avoid the errata.
+ *
+ * The flags should have minimal impact on platforms not impacted by
+ * the errata.
+ */
+ skb_changed = false;
+ skb_need_wa = false;
+
+ priv = netdev_priv(net_dev);
+ /* Non-migratable context, safe to use raw_cpu_ptr */
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
+ percpu_stats = &percpu_priv->stats;
+ countptr = raw_cpu_ptr(priv->dpa_bp->percpu_count);
+
+ clear_fd(&fd);
+
+#ifdef FM_ERRATUM_A050385
+ if (unlikely(fm_has_errata_a050385()) && a050385_check_skb(skb, priv))
+ skb_need_wa = true;
+#endif
+
+ nonlinear = skb_is_nonlinear(skb);
+
+#ifdef CONFIG_FSL_DPAA_1588
+ if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_tx_en_ioctl)
+ fd.cmd |= FM_FD_CMD_UPD;
+#endif
+#ifdef CONFIG_FSL_DPAA_TS
+ if (unlikely(priv->ts_tx_en &&
+ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ fd.cmd |= FM_FD_CMD_UPD;
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+#endif /* CONFIG_FSL_DPAA_TS */
+
+ /* MAX_SKB_FRAGS is larger than our DPA_SGT_MAX_ENTRIES; make sure
+ * we don't feed FMan with more fragments than it supports.
+ * Btw, we're using the first sgt entry to store the linear part of
+ * the skb, so we're one extra frag short.
+ */
+ if (nonlinear && !skb_need_wa &&
+ likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) {
+ /* Just create a S/G fd based on the skb */
+ err = skb_to_sg_fd(priv, skb, &fd);
+ percpu_priv->tx_frag_skbuffs++;
+ } else {
+ /* Make sure we have enough headroom to accommodate private
+ * data, parse results, etc. Normally this shouldn't happen if
+ * we're here via the standard kernel stack.
+ */
+ if (unlikely(skb_headroom(skb) < priv->tx_headroom)) {
+ struct sk_buff *skb_new;
+
+ skb_new = skb_realloc_headroom(skb, priv->tx_headroom);
+ if (unlikely(!skb_new)) {
+ dev_kfree_skb(skb);
+ percpu_stats->tx_errors++;
+ return NETDEV_TX_OK;
+ }
+
+ /* propagate the skb ownership information */
+ if (skb->sk)
+ skb_set_owner_w(skb_new, skb->sk);
+
+ dev_kfree_skb(skb);
+ skb = skb_new;
+ skb_changed = true;
+ }
+
+ /* We're going to store the skb backpointer at the beginning
+ * of the data buffer, so we need a privately owned skb
+ *
+ * Under the A050385 errata, we are going to have a privately
+ * owned skb after realigning the current one, so no point in
+ * copying it here in that case.
+ */
+
+ /* Code borrowed from skb_unshare(). */
+ if (skb_cloned(skb) && !skb_need_wa) {
+ nskb = skb_copy(skb, GFP_ATOMIC);
+ kfree_skb(skb);
+ skb = nskb;
+ skb_changed = true;
+
+ /* skb_copy() has now linearized the skbuff. */
+ } else if (unlikely(nonlinear) && !skb_need_wa) {
+ /* We are here because the egress skb contains
+ * more fragments than we support. In this case,
+ * we have no choice but to linearize it ourselves.
+ */
+#ifdef FM_ERRATUM_A050385
+ /* No point in linearizing the skb now if we are going
+ * to realign and linearize it again further down due
+ * to the A050385 errata
+ */
+ if (unlikely(fm_has_errata_a050385()))
+ skb_need_wa = true;
+ else
+#endif
+ err = __skb_linearize(skb);
+ }
+ if (unlikely(!skb || err < 0))
+ /* Common out-of-memory error path */
+ goto enomem;
+
+#ifdef FM_ERRATUM_A050385
+ /* Verify the skb a second time if it has been updated since
+ * the previous check
+ */
+ if (unlikely(fm_has_errata_a050385()) && skb_changed &&
+ a050385_check_skb(skb, priv))
+ skb_need_wa = true;
+
+ if (unlikely(fm_has_errata_a050385()) && skb_need_wa) {
+ nskb = a050385_realign_skb(skb, priv);
+ if (!nskb)
+ goto skb_to_fd_failed;
+ dev_kfree_skb(skb);
+ skb = nskb;
+ }
+#endif
+
+ err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset);
+ }
+ if (unlikely(err < 0))
+ goto skb_to_fd_failed;
+
+ if (fd.bpid != 0xff) {
+ skb_recycle(skb);
+ /* skb_recycle() reserves NET_SKB_PAD as skb headroom,
+ * but we need the skb to look as if returned by build_skb().
+ * We need to manually adjust the tailptr as well.
+ */
+ skb->data = skb->head + offset;
+ skb_reset_tail_pointer(skb);
+
+ (*countptr)++;
+ percpu_priv->tx_returned++;
+ }
+
+ if (unlikely(dpa_xmit(priv, percpu_stats, &fd, egress_fq, conf_fq) < 0))
+ goto xmit_failed;
+
+ netif_trans_update(net_dev);
+ return NETDEV_TX_OK;
+
+xmit_failed:
+ if (fd.bpid != 0xff) {
+ (*countptr)--;
+ percpu_priv->tx_returned--;
+ dpa_fd_release(net_dev, &fd);
+ percpu_stats->tx_errors++;
+ return NETDEV_TX_OK;
+ }
+ _dpa_cleanup_tx_fd(priv, &fd);
+skb_to_fd_failed:
+enomem:
+ percpu_stats->tx_errors++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+EXPORT_SYMBOL(dpa_tx_extended);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c
new file mode 100644
index 000000000000..3542d0b2c090
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c
@@ -0,0 +1,278 @@
+/* Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/of_net.h>
+#include "dpaa_eth.h"
+#include "mac.h" /* struct mac_device */
+#ifdef CONFIG_FSL_DPAA_1588
+#include "dpaa_1588.h"
+#endif
+
+static ssize_t dpaa_eth_show_addr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ struct mac_device *mac_dev = priv->mac_dev;
+
+ if (mac_dev)
+ return sprintf(buf, "%llx",
+ (unsigned long long)mac_dev->res->start);
+ else
+ return sprintf(buf, "none");
+}
+
+static ssize_t dpaa_eth_show_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ ssize_t res = 0;
+
+ if (priv)
+ res = sprintf(buf, "%s", priv->if_type);
+
+ return res;
+}
+
+static ssize_t dpaa_eth_show_fqids(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ ssize_t bytes = 0;
+ int i = 0;
+ char *str;
+ struct dpa_fq *fq;
+ struct dpa_fq *tmp;
+ struct dpa_fq *prev = NULL;
+ u32 first_fqid = 0;
+ u32 last_fqid = 0;
+ char *prevstr = NULL;
+
+ list_for_each_entry_safe(fq, tmp, &priv->dpa_fq_list, list) {
+ switch (fq->fq_type) {
+ case FQ_TYPE_RX_DEFAULT:
+ str = "Rx default";
+ break;
+ case FQ_TYPE_RX_ERROR:
+ str = "Rx error";
+ break;
+ case FQ_TYPE_RX_PCD:
+ str = "Rx PCD";
+ break;
+ case FQ_TYPE_TX_CONFIRM:
+ str = "Tx default confirmation";
+ break;
+ case FQ_TYPE_TX_CONF_MQ:
+ str = "Tx confirmation (mq)";
+ break;
+ case FQ_TYPE_TX_ERROR:
+ str = "Tx error";
+ break;
+ case FQ_TYPE_TX:
+ str = "Tx";
+ break;
+ case FQ_TYPE_RX_PCD_HI_PRIO:
+ str ="Rx PCD High Priority";
+ break;
+ default:
+ str = "Unknown";
+ }
+
+ if (prev && (abs(fq->fqid - prev->fqid) != 1 ||
+ str != prevstr)) {
+ if (last_fqid == first_fqid)
+ bytes += sprintf(buf + bytes,
+ "%s: %d\n", prevstr, prev->fqid);
+ else
+ bytes += sprintf(buf + bytes,
+ "%s: %d - %d\n", prevstr,
+ first_fqid, last_fqid);
+ }
+
+ if (prev && abs(fq->fqid - prev->fqid) == 1 && str == prevstr)
+ last_fqid = fq->fqid;
+ else
+ first_fqid = last_fqid = fq->fqid;
+
+ prev = fq;
+ prevstr = str;
+ i++;
+ }
+
+ if (prev) {
+ if (last_fqid == first_fqid)
+ bytes += sprintf(buf + bytes, "%s: %d\n", prevstr,
+ prev->fqid);
+ else
+ bytes += sprintf(buf + bytes, "%s: %d - %d\n", prevstr,
+ first_fqid, last_fqid);
+ }
+
+ return bytes;
+}
+
+static ssize_t dpaa_eth_show_bpids(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t bytes = 0;
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
+ int i = 0;
+
+ for (i = 0; i < priv->bp_count; i++)
+ bytes += snprintf(buf + bytes, PAGE_SIZE, "%u\n",
+ dpa_bp[i].bpid);
+
+ return bytes;
+}
+
+static ssize_t dpaa_eth_show_mac_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ struct mac_device *mac_dev = priv->mac_dev;
+ int n = 0;
+
+ if (mac_dev)
+ n = fm_mac_dump_regs(mac_dev, buf, n);
+ else
+ return sprintf(buf, "no mac registers\n");
+
+ return n;
+}
+
+static ssize_t dpaa_eth_show_mac_rx_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ struct mac_device *mac_dev = priv->mac_dev;
+ int n = 0;
+
+ if (mac_dev)
+ n = fm_mac_dump_rx_stats(mac_dev, buf, n);
+ else
+ return sprintf(buf, "no mac rx stats\n");
+
+ return n;
+}
+
+static ssize_t dpaa_eth_show_mac_tx_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ struct mac_device *mac_dev = priv->mac_dev;
+ int n = 0;
+
+ if (mac_dev)
+ n = fm_mac_dump_tx_stats(mac_dev, buf, n);
+ else
+ return sprintf(buf, "no mac tx stats\n");
+
+ return n;
+}
+
+#ifdef CONFIG_FSL_DPAA_1588
+static ssize_t dpaa_eth_show_ptp_1588(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+
+ if (priv->tsu && priv->tsu->valid)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t dpaa_eth_set_ptp_1588(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev));
+ unsigned int num;
+ unsigned long flags;
+
+ if (kstrtouint(buf, 0, &num) < 0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (num) {
+ if (priv->tsu)
+ priv->tsu->valid = TRUE;
+ } else {
+ if (priv->tsu)
+ priv->tsu->valid = FALSE;
+ }
+
+ local_irq_restore(flags);
+
+ return count;
+}
+#endif
+
+static struct device_attribute dpaa_eth_attrs[] = {
+ __ATTR(device_addr, S_IRUGO, dpaa_eth_show_addr, NULL),
+ __ATTR(device_type, S_IRUGO, dpaa_eth_show_type, NULL),
+ __ATTR(fqids, S_IRUGO, dpaa_eth_show_fqids, NULL),
+ __ATTR(bpids, S_IRUGO, dpaa_eth_show_bpids, NULL),
+ __ATTR(mac_regs, S_IRUGO, dpaa_eth_show_mac_regs, NULL),
+ __ATTR(mac_rx_stats, S_IRUGO, dpaa_eth_show_mac_rx_stats, NULL),
+ __ATTR(mac_tx_stats, S_IRUGO, dpaa_eth_show_mac_tx_stats, NULL),
+#ifdef CONFIG_FSL_DPAA_1588
+ __ATTR(ptp_1588, S_IRUGO | S_IWUSR, dpaa_eth_show_ptp_1588,
+ dpaa_eth_set_ptp_1588),
+#endif
+};
+
+void dpaa_eth_sysfs_init(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++)
+ if (device_create_file(dev, &dpaa_eth_attrs[i])) {
+ dev_err(dev, "Error creating sysfs file\n");
+ while (i > 0)
+ device_remove_file(dev, &dpaa_eth_attrs[--i]);
+ return;
+ }
+}
+EXPORT_SYMBOL(dpaa_eth_sysfs_init);
+
+void dpaa_eth_sysfs_remove(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++)
+ device_remove_file(dev, &dpaa_eth_attrs[i]);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h
new file mode 100644
index 000000000000..30069ef9a624
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h
@@ -0,0 +1,144 @@
+/* Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dpaa_eth
+
+#if !defined(_DPAA_ETH_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _DPAA_ETH_TRACE_H
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include "dpaa_eth.h"
+#include <linux/tracepoint.h>
+
+#define fd_format_name(format) { qm_fd_##format, #format }
+#define fd_format_list \
+ fd_format_name(contig), \
+ fd_format_name(sg)
+#define TR_FMT "[%s] fqid=%d, fd: addr=0x%llx, format=%s, off=%u, len=%u," \
+ " status=0x%08x"
+
+/* This is used to declare a class of events.
+ * individual events of this type will be defined below.
+ */
+
+/* Store details about a frame descriptor and the FQ on which it was
+ * transmitted/received.
+ */
+DECLARE_EVENT_CLASS(dpaa_eth_fd,
+ /* Trace function prototype */
+ TP_PROTO(struct net_device *netdev,
+ struct qman_fq *fq,
+ const struct qm_fd *fd),
+
+ /* Repeat argument list here */
+ TP_ARGS(netdev, fq, fd),
+
+ /* A structure containing the relevant information we want to record.
+ * Declare name and type for each normal element, name, type and size
+ * for arrays. Use __string for variable length strings.
+ */
+ TP_STRUCT__entry(
+ __field(u32, fqid)
+ __field(u64, fd_addr)
+ __field(u8, fd_format)
+ __field(u16, fd_offset)
+ __field(u32, fd_length)
+ __field(u32, fd_status)
+ __string(name, netdev->name)
+ ),
+
+ /* The function that assigns values to the above declared fields */
+ TP_fast_assign(
+ __entry->fqid = fq->fqid;
+ __entry->fd_addr = qm_fd_addr_get64(fd);
+ __entry->fd_format = fd->format;
+ __entry->fd_offset = dpa_fd_offset(fd);
+ __entry->fd_length = dpa_fd_length(fd);
+ __entry->fd_status = fd->status;
+ __assign_str(name, netdev->name);
+ ),
+
+ /* This is what gets printed when the trace event is triggered */
+ /* TODO: print the status using __print_flags() */
+ TP_printk(TR_FMT,
+ __get_str(name), __entry->fqid, __entry->fd_addr,
+ __print_symbolic(__entry->fd_format, fd_format_list),
+ __entry->fd_offset, __entry->fd_length, __entry->fd_status)
+);
+
+/* Now declare events of the above type. Format is:
+ * DEFINE_EVENT(class, name, proto, args), with proto and args same as for class
+ */
+
+/* Tx (egress) fd */
+DEFINE_EVENT(dpaa_eth_fd, dpa_tx_fd,
+
+ TP_PROTO(struct net_device *netdev,
+ struct qman_fq *fq,
+ const struct qm_fd *fd),
+
+ TP_ARGS(netdev, fq, fd)
+);
+
+/* Rx fd */
+DEFINE_EVENT(dpaa_eth_fd, dpa_rx_fd,
+
+ TP_PROTO(struct net_device *netdev,
+ struct qman_fq *fq,
+ const struct qm_fd *fd),
+
+ TP_ARGS(netdev, fq, fd)
+);
+
+/* Tx confirmation fd */
+DEFINE_EVENT(dpaa_eth_fd, dpa_tx_conf_fd,
+
+ TP_PROTO(struct net_device *netdev,
+ struct qman_fq *fq,
+ const struct qm_fd *fd),
+
+ TP_ARGS(netdev, fq, fd)
+);
+
+/* If only one event of a certain type needs to be declared, use TRACE_EVENT().
+ * The syntax is the same as for DECLARE_EVENT_CLASS().
+ */
+
+#endif /* _DPAA_ETH_TRACE_H */
+
+/* This must be outside ifdef _DPAA_ETH_TRACE_H */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE dpaa_eth_trace
+#include <trace/define_trace.h>
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
new file mode 100644
index 000000000000..57553bb672c0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c
@@ -0,0 +1,561 @@
+/* Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/string.h>
+#include <linux/of_platform.h>
+#include <linux/net_tstamp.h>
+#include <linux/fsl/ptp_qoriq.h>
+
+#include "dpaa_eth.h"
+#include "mac.h" /* struct mac_device */
+#include "dpaa_eth_common.h"
+
+static const char dpa_stats_percpu[][ETH_GSTRING_LEN] = {
+ "interrupts",
+ "rx packets",
+ "tx packets",
+ "tx recycled",
+ "tx confirm",
+ "tx S/G",
+ "rx S/G",
+ "tx error",
+ "rx error",
+ "bp count"
+};
+
+static char dpa_stats_global[][ETH_GSTRING_LEN] = {
+ /* dpa rx errors */
+ "rx dma error",
+ "rx frame physical error",
+ "rx frame size error",
+ "rx header error",
+ "rx csum error",
+
+ /* demultiplexing errors */
+ "qman cg_tdrop",
+ "qman wred",
+ "qman error cond",
+ "qman early window",
+ "qman late window",
+ "qman fq tdrop",
+ "qman fq retired",
+ "qman orp disabled",
+
+ /* congestion related stats */
+ "congestion time (ms)",
+ "entered congestion",
+ "congested (0/1)"
+};
+
+#define DPA_STATS_PERCPU_LEN ARRAY_SIZE(dpa_stats_percpu)
+#define DPA_STATS_GLOBAL_LEN ARRAY_SIZE(dpa_stats_global)
+
+static int __cold dpa_get_ksettings(struct net_device *net_dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_dbg(net_dev, "phy device not initialized\n");
+ return 0;
+ }
+
+ phy_ethtool_ksettings_get(priv->mac_dev->phy_dev, cmd);
+
+ return 0;
+}
+
+static int __cold dpa_set_ksettings(struct net_device *net_dev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ int _errno;
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ _errno = phy_ethtool_ksettings_set(priv->mac_dev->phy_dev, cmd);
+ if (unlikely(_errno < 0))
+ netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", _errno);
+
+ return _errno;
+}
+
+static void __cold dpa_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ int _errno;
+
+ strncpy(drvinfo->driver, KBUILD_MODNAME,
+ sizeof(drvinfo->driver) - 1)[sizeof(drvinfo->driver)-1] = 0;
+ _errno = snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%X", 0);
+
+ if (unlikely(_errno >= sizeof(drvinfo->fw_version))) {
+ /* Truncated output */
+ netdev_notice(net_dev, "snprintf() = %d\n", _errno);
+ } else if (unlikely(_errno < 0)) {
+ netdev_warn(net_dev, "snprintf() = %d\n", _errno);
+ memset(drvinfo->fw_version, 0, sizeof(drvinfo->fw_version));
+ }
+ strncpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
+ sizeof(drvinfo->bus_info)-1)[sizeof(drvinfo->bus_info)-1] = 0;
+}
+
+static uint32_t __cold dpa_get_msglevel(struct net_device *net_dev)
+{
+ return ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable;
+}
+
+static void __cold dpa_set_msglevel(struct net_device *net_dev,
+ uint32_t msg_enable)
+{
+ ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable = msg_enable;
+}
+
+static int __cold dpa_nway_reset(struct net_device *net_dev)
+{
+ int _errno;
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ _errno = 0;
+ if (priv->mac_dev->phy_dev->autoneg) {
+ _errno = phy_start_aneg(priv->mac_dev->phy_dev);
+ if (unlikely(_errno < 0))
+ netdev_err(net_dev, "phy_start_aneg() = %d\n",
+ _errno);
+ }
+
+ return _errno;
+}
+
+static void __cold dpa_get_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+ struct phy_device *phy_dev;
+
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ if (mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return;
+ }
+
+ phy_dev = mac_dev->phy_dev;
+ if (unlikely(phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return;
+ }
+
+ epause->autoneg = mac_dev->autoneg_pause;
+ epause->rx_pause = mac_dev->rx_pause_active;
+ epause->tx_pause = mac_dev->tx_pause_active;
+}
+
+static int __cold dpa_set_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct dpa_priv_s *priv;
+ struct mac_device *mac_dev;
+ struct phy_device *phy_dev;
+ int _errno;
+ bool rx_pause, tx_pause;
+
+ priv = netdev_priv(net_dev);
+ mac_dev = priv->mac_dev;
+
+ if (mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+
+ phy_dev = mac_dev->phy_dev;
+ if (unlikely(phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ if (!phy_validate_pause(phy_dev, epause))
+ return -EINVAL;
+
+ /* The MAC should know how to handle PAUSE frame autonegotiation before
+ * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
+ * settings.
+ */
+ mac_dev->autoneg_pause = !!epause->autoneg;
+ mac_dev->rx_pause_req = !!epause->rx_pause;
+ mac_dev->tx_pause_req = !!epause->tx_pause;
+
+ /* Determine the sym/asym advertised PAUSE capabilities from the desired
+ * rx/tx pause settings.
+ */
+ phy_set_asym_pause(phy_dev, epause->rx_pause, epause->tx_pause);
+
+ get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
+ _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
+ if (unlikely(_errno < 0))
+ netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno);
+
+ return _errno;
+}
+
+#ifdef CONFIG_PM
+static void dpa_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (!priv->wol || !device_can_wakeup(net_dev->dev.parent))
+ return;
+
+ if (priv->wol & DPAA_WOL_MAGIC) {
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = WAKE_MAGIC;
+ }
+}
+
+static int dpa_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_dbg(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ if (!device_can_wakeup(net_dev->dev.parent) ||
+ (wol->wolopts & ~WAKE_MAGIC))
+ return -EOPNOTSUPP;
+
+ priv->wol = 0;
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ priv->wol = DPAA_WOL_MAGIC;
+ device_set_wakeup_enable(net_dev->dev.parent, 1);
+ } else {
+ device_set_wakeup_enable(net_dev->dev.parent, 0);
+ }
+
+ return 0;
+}
+#endif
+
+static int dpa_get_eee(struct net_device *net_dev, struct ethtool_eee *et_eee)
+{
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ return phy_ethtool_get_eee(priv->mac_dev->phy_dev, et_eee);
+}
+
+static int dpa_set_eee(struct net_device *net_dev, struct ethtool_eee *et_eee)
+{
+ struct dpa_priv_s *priv;
+
+ priv = netdev_priv(net_dev);
+ if (priv->mac_dev == NULL) {
+ netdev_info(net_dev, "This is a MAC-less interface\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(priv->mac_dev->phy_dev == NULL)) {
+ netdev_err(net_dev, "phy device not initialized\n");
+ return -ENODEV;
+ }
+
+ return phy_ethtool_set_eee(priv->mac_dev->phy_dev, et_eee);
+}
+
+static int dpa_get_sset_count(struct net_device *net_dev, int type)
+{
+ unsigned int total_stats, num_stats;
+
+ num_stats = num_online_cpus() + 1;
+ total_stats = num_stats * DPA_STATS_PERCPU_LEN + DPA_STATS_GLOBAL_LEN;
+
+ switch (type) {
+ case ETH_SS_STATS:
+ return total_stats;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void copy_stats(struct dpa_percpu_priv_s *percpu_priv, int num_cpus,
+ int crr_cpu, u64 bp_count, u64 *data)
+{
+ int num_stat_values = num_cpus + 1;
+ int crr_stat = 0;
+
+ /* update current CPU's stats and also add them to the total values */
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->in_interrupt;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->in_interrupt;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_packets;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_packets;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_packets;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_packets;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_returned;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_returned;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_confirm;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_confirm;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_frag_skbuffs;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_frag_skbuffs;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->rx_sg;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->rx_sg;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_errors;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_errors;
+
+ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_errors;
+ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_errors;
+
+ data[crr_stat * num_stat_values + crr_cpu] = bp_count;
+ data[crr_stat++ * num_stat_values + num_cpus] += bp_count;
+}
+
+static void dpa_get_ethtool_stats(struct net_device *net_dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ u64 bp_count, cg_time, cg_num, cg_status;
+ struct dpa_percpu_priv_s *percpu_priv;
+ struct qm_mcr_querycgr query_cgr;
+ struct dpa_rx_errors rx_errors;
+ struct dpa_ern_cnt ern_cnt;
+ struct dpa_priv_s *priv;
+ unsigned int num_cpus, offset;
+ struct dpa_bp *dpa_bp;
+ int total_stats, i;
+
+ total_stats = dpa_get_sset_count(net_dev, ETH_SS_STATS);
+ priv = netdev_priv(net_dev);
+ dpa_bp = priv->dpa_bp;
+ num_cpus = num_online_cpus();
+ bp_count = 0;
+
+ memset(&rx_errors, 0, sizeof(struct dpa_rx_errors));
+ memset(&ern_cnt, 0, sizeof(struct dpa_ern_cnt));
+ memset(data, 0, total_stats * sizeof(u64));
+
+ for_each_online_cpu(i) {
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
+
+ if (dpa_bp->percpu_count)
+ bp_count = *(per_cpu_ptr(dpa_bp->percpu_count, i));
+
+ rx_errors.dme += percpu_priv->rx_errors.dme;
+ rx_errors.fpe += percpu_priv->rx_errors.fpe;
+ rx_errors.fse += percpu_priv->rx_errors.fse;
+ rx_errors.phe += percpu_priv->rx_errors.phe;
+ rx_errors.cse += percpu_priv->rx_errors.cse;
+
+ ern_cnt.cg_tdrop += percpu_priv->ern_cnt.cg_tdrop;
+ ern_cnt.wred += percpu_priv->ern_cnt.wred;
+ ern_cnt.err_cond += percpu_priv->ern_cnt.err_cond;
+ ern_cnt.early_window += percpu_priv->ern_cnt.early_window;
+ ern_cnt.late_window += percpu_priv->ern_cnt.late_window;
+ ern_cnt.fq_tdrop += percpu_priv->ern_cnt.fq_tdrop;
+ ern_cnt.fq_retired += percpu_priv->ern_cnt.fq_retired;
+ ern_cnt.orp_zero += percpu_priv->ern_cnt.orp_zero;
+
+ copy_stats(percpu_priv, num_cpus, i, bp_count, data);
+ }
+
+ offset = (num_cpus + 1) * DPA_STATS_PERCPU_LEN;
+ memcpy(data + offset, &rx_errors, sizeof(struct dpa_rx_errors));
+
+ offset += sizeof(struct dpa_rx_errors) / sizeof(u64);
+ memcpy(data + offset, &ern_cnt, sizeof(struct dpa_ern_cnt));
+
+ /* gather congestion related counters */
+ cg_num = 0;
+ cg_status = 0;
+ cg_time = jiffies_to_msecs(priv->cgr_data.congested_jiffies);
+ if (qman_query_cgr(&priv->cgr_data.cgr, &query_cgr) == 0) {
+ cg_num = priv->cgr_data.cgr_congested_count;
+ cg_status = query_cgr.cgr.cs;
+
+ /* reset congestion stats (like QMan API does */
+ priv->cgr_data.congested_jiffies = 0;
+ priv->cgr_data.cgr_congested_count = 0;
+ }
+
+ offset += sizeof(struct dpa_ern_cnt) / sizeof(u64);
+ data[offset++] = cg_time;
+ data[offset++] = cg_num;
+ data[offset++] = cg_status;
+}
+
+static void dpa_get_strings(struct net_device *net_dev, u32 stringset, u8 *data)
+{
+ unsigned int i, j, num_cpus, size;
+ char stat_string_cpu[ETH_GSTRING_LEN];
+ u8 *strings;
+
+ strings = data;
+ num_cpus = num_online_cpus();
+ size = DPA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
+
+ for (i = 0; i < DPA_STATS_PERCPU_LEN; i++) {
+ for (j = 0; j < num_cpus; j++) {
+ snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]", dpa_stats_percpu[i], j);
+ memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN);
+ strings += ETH_GSTRING_LEN;
+ }
+ snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]", dpa_stats_percpu[i]);
+ memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN);
+ strings += ETH_GSTRING_LEN;
+ }
+ memcpy(strings, dpa_stats_global, size);
+}
+
+static int dpaa_get_ts_info(struct net_device *net_dev,
+ struct ethtool_ts_info *info)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct device *dev = priv->mac_dev->dev;
+ struct device_node *mac_node = dev->of_node;
+ struct device_node *fman_node = NULL, *ptp_node = NULL;
+ struct platform_device *ptp_dev = NULL;
+ struct ptp_qoriq *ptp = NULL;
+
+ info->phc_index = -1;
+
+ fman_node = of_get_parent(mac_node);
+ if (fman_node)
+ ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
+
+ if (ptp_node)
+ ptp_dev = of_find_device_by_node(ptp_node);
+
+ if (ptp_dev)
+ ptp = platform_get_drvdata(ptp_dev);
+
+ if (ptp)
+ info->phc_index = ptp->phc_index;
+
+#ifdef CONFIG_FSL_DPAA_TS
+ info->so_timestamping = 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_ALL);
+#else
+ info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+#endif
+
+ return 0;
+}
+
+const struct ethtool_ops dpa_ethtool_ops = {
+ .get_link_ksettings = dpa_get_ksettings,
+ .set_link_ksettings = dpa_set_ksettings,
+ .get_drvinfo = dpa_get_drvinfo,
+ .get_msglevel = dpa_get_msglevel,
+ .set_msglevel = dpa_set_msglevel,
+ .nway_reset = dpa_nway_reset,
+ .get_pauseparam = dpa_get_pauseparam,
+ .set_pauseparam = dpa_set_pauseparam,
+ .self_test = NULL, /* TODO invoke the cold-boot unit-test? */
+ .get_link = ethtool_op_get_link,
+ .get_eee = dpa_get_eee,
+ .set_eee = dpa_set_eee,
+ .get_sset_count = dpa_get_sset_count,
+ .get_ethtool_stats = dpa_get_ethtool_stats,
+ .get_strings = dpa_get_strings,
+#ifdef CONFIG_PM
+ .get_wol = dpa_get_wol,
+ .set_wol = dpa_set_wol,
+#endif
+ .get_ts_info = dpaa_get_ts_info,
+};
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
new file mode 100644
index 000000000000..d0dda69d3ffe
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c
@@ -0,0 +1,930 @@
+/* Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+
+#include "dpaa_eth.h"
+#include "mac.h"
+#include "lnxwrp_fsl_fman.h"
+
+#include "error_ext.h" /* GET_ERROR_TYPE, E_OK */
+
+#include "fsl_fman_dtsec.h"
+#include "fsl_fman_tgec.h"
+#include "fsl_fman_memac.h"
+#include "../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h"
+
+#define MAC_DESCRIPTION "FSL FMan MAC API based driver"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_AUTHOR("Emil Medve <Emilian.Medve@Freescale.com>");
+
+MODULE_DESCRIPTION(MAC_DESCRIPTION);
+
+struct mac_priv_s {
+ struct fm_mac_dev *fm_mac;
+};
+
+const char *mac_driver_description __initconst = MAC_DESCRIPTION;
+const size_t mac_sizeof_priv[] = {
+ [DTSEC] = sizeof(struct mac_priv_s),
+ [XGMAC] = sizeof(struct mac_priv_s),
+ [MEMAC] = sizeof(struct mac_priv_s)
+};
+
+static const enet_mode_t _100[] = {
+ [PHY_INTERFACE_MODE_MII] = e_ENET_MODE_MII_100,
+ [PHY_INTERFACE_MODE_RMII] = e_ENET_MODE_RMII_100
+};
+
+static const enet_mode_t _1000[] = {
+ [PHY_INTERFACE_MODE_GMII] = e_ENET_MODE_GMII_1000,
+ [PHY_INTERFACE_MODE_SGMII] = e_ENET_MODE_SGMII_1000,
+ [PHY_INTERFACE_MODE_QSGMII] = e_ENET_MODE_QSGMII_1000,
+ [PHY_INTERFACE_MODE_TBI] = e_ENET_MODE_TBI_1000,
+ [PHY_INTERFACE_MODE_RGMII] = e_ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_ID] = e_ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_RXID] = e_ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RGMII_TXID] = e_ENET_MODE_RGMII_1000,
+ [PHY_INTERFACE_MODE_RTBI] = e_ENET_MODE_RTBI_1000
+};
+
+static enet_mode_t __cold __attribute__((nonnull))
+macdev2enetinterface(const struct mac_device *mac_dev)
+{
+ switch (mac_dev->max_speed) {
+ case SPEED_100:
+ return _100[mac_dev->phy_if];
+ case SPEED_1000:
+ return _1000[mac_dev->phy_if];
+ case SPEED_2500:
+ return e_ENET_MODE_SGMII_2500;
+ case SPEED_10000:
+ return e_ENET_MODE_XGMII_10000;
+ default:
+ return e_ENET_MODE_MII_100;
+ }
+}
+
+static void mac_exception(handle_t _mac_dev, e_FmMacExceptions exception)
+{
+ struct mac_device *mac_dev;
+
+ mac_dev = (struct mac_device *)_mac_dev;
+
+ if (e_FM_MAC_EX_10G_RX_FIFO_OVFL == exception) {
+ /* don't flag RX FIFO after the first */
+ fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
+ e_FM_MAC_EX_10G_RX_FIFO_OVFL, false);
+ dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n",
+ exception);
+ }
+
+ dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME".c", __func__,
+ exception);
+}
+
+static int __cold init(struct mac_device *mac_dev)
+{
+ int _errno;
+ struct mac_priv_s *priv;
+ t_FmMacParams param;
+ uint32_t version;
+
+ priv = macdev_priv(mac_dev);
+
+ param.baseAddr = (typeof(param.baseAddr))(uintptr_t)devm_ioremap(
+ mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enetMode = macdev2enetinterface(mac_dev);
+ memcpy(&param.addr, mac_dev->addr, min(sizeof(param.addr),
+ sizeof(mac_dev->addr)));
+ param.macId = mac_dev->cell_index;
+ param.h_Fm = (handle_t)mac_dev->fm;
+ param.mdioIrq = NO_IRQ;
+ param.f_Exception = mac_exception;
+ param.f_Event = mac_exception;
+ param.h_App = mac_dev;
+
+ priv->fm_mac = fm_mac_config(&param);
+ if (unlikely(priv->fm_mac == NULL)) {
+ _errno = -EINVAL;
+ goto _return;
+ }
+
+ fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac,
+ (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
+ param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS);
+
+ _errno = fm_mac_config_max_frame_length(priv->fm_mac,
+ fm_get_max_frm());
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) {
+ /* 10G always works with pad and CRC */
+ _errno = fm_mac_config_pad_and_crc(priv->fm_mac, true);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ _errno = fm_mac_config_half_duplex(priv->fm_mac,
+ mac_dev->half_duplex);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+ } else {
+ _errno = fm_mac_config_reset_on_init(priv->fm_mac, true);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+ }
+
+ _errno = fm_mac_init(priv->fm_mac);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+#ifndef CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN
+ /* For 1G MAC, disable by default the MIB counters overflow interrupt */
+ if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) {
+ _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
+ e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, FALSE);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+ }
+#endif /* !CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN */
+
+ /* For 10G MAC, disable Tx ECC exception */
+ if (macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) {
+ _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev),
+ e_FM_MAC_EX_10G_1TX_ECC_ER, FALSE);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+ }
+
+ _errno = fm_mac_get_version(priv->fm_mac, &version);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n",
+ ((macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
+ "dTSEC" : "XGEC"), version);
+
+ goto _return;
+
+
+_return_fm_mac_free:
+ fm_mac_free(mac_dev->get_mac_handle(mac_dev));
+
+_return:
+ return _errno;
+}
+
+static int __cold memac_init(struct mac_device *mac_dev)
+{
+ int _errno;
+ struct mac_priv_s *priv;
+ t_FmMacParams param;
+
+ priv = macdev_priv(mac_dev);
+
+ param.baseAddr = (typeof(param.baseAddr))(uintptr_t)devm_ioremap(
+ mac_dev->dev, mac_dev->res->start, 0x2000);
+ param.enetMode = macdev2enetinterface(mac_dev);
+ memcpy(&param.addr, mac_dev->addr, sizeof(mac_dev->addr));
+ param.macId = mac_dev->cell_index;
+ param.h_Fm = (handle_t)mac_dev->fm;
+ param.mdioIrq = NO_IRQ;
+ param.f_Exception = mac_exception;
+ param.f_Event = mac_exception;
+ param.h_App = mac_dev;
+
+ priv->fm_mac = fm_mac_config(&param);
+ if (unlikely(priv->fm_mac == NULL)) {
+ _errno = -EINVAL;
+ goto _return;
+ }
+
+ fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac,
+ (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ?
+ param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS);
+
+ _errno = fm_mac_config_max_frame_length(priv->fm_mac, fm_get_max_frm());
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ _errno = fm_mac_config_reset_on_init(priv->fm_mac, true);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ _errno = fm_mac_init(priv->fm_mac);
+ if (unlikely(_errno < 0))
+ goto _return_fm_mac_free;
+
+ dev_info(mac_dev->dev, "FMan MEMAC\n");
+
+ goto _return;
+
+_return_fm_mac_free:
+ fm_mac_free(priv->fm_mac);
+
+_return:
+ return _errno;
+}
+
+static int __cold start(struct mac_device *mac_dev)
+{
+ int _errno;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+
+ _errno = fm_mac_enable(mac_dev->get_mac_handle(mac_dev));
+
+ if (!_errno && phy_dev)
+ phy_start(phy_dev);
+
+ return _errno;
+}
+
+static int __cold stop(struct mac_device *mac_dev)
+{
+ if (mac_dev->phy_dev)
+ phy_stop(mac_dev->phy_dev);
+
+ return fm_mac_disable(mac_dev->get_mac_handle(mac_dev));
+}
+
+static int __cold set_multi(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct mac_priv_s *mac_priv;
+ struct mac_address *old_addr, *tmp;
+ struct netdev_hw_addr *ha;
+ int _errno;
+
+ mac_priv = macdev_priv(mac_dev);
+
+ /* Clear previous address list */
+ list_for_each_entry_safe(old_addr, tmp, &mac_dev->mc_addr_list, list) {
+ _errno = fm_mac_remove_hash_mac_addr(mac_priv->fm_mac,
+ (t_EnetAddr *)old_addr->addr);
+ if (_errno < 0)
+ return _errno;
+
+ list_del(&old_addr->list);
+ kfree(old_addr);
+ }
+
+ /* Add all the addresses from the new list */
+ netdev_for_each_mc_addr(ha, net_dev) {
+ _errno = fm_mac_add_hash_mac_addr(mac_priv->fm_mac,
+ (t_EnetAddr *)ha->addr);
+ if (_errno < 0)
+ return _errno;
+
+ tmp = kmalloc(sizeof(struct mac_address), GFP_ATOMIC);
+ if (!tmp) {
+ dev_err(mac_dev->dev, "Out of memory\n");
+ return -ENOMEM;
+ }
+ memcpy(tmp->addr, ha->addr, ETH_ALEN);
+ list_add(&tmp->list, &mac_dev->mc_addr_list);
+ }
+ return 0;
+}
+
+/* Avoid redundant calls to FMD, if the MAC driver already contains the desired
+ * active PAUSE settings. Otherwise, the new active settings should be reflected
+ * in FMan.
+ */
+int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
+{
+ struct fm_mac_dev *fm_mac_dev = mac_dev->get_mac_handle(mac_dev);
+ int _errno = 0;
+
+ if (unlikely(rx != mac_dev->rx_pause_active)) {
+ _errno = fm_mac_set_rx_pause_frames(fm_mac_dev, rx);
+ if (likely(_errno == 0))
+ mac_dev->rx_pause_active = rx;
+ }
+
+ if (unlikely(tx != mac_dev->tx_pause_active)) {
+ _errno = fm_mac_set_tx_pause_frames(fm_mac_dev, tx);
+ if (likely(_errno == 0))
+ mac_dev->tx_pause_active = tx;
+ }
+
+ return _errno;
+}
+EXPORT_SYMBOL(set_mac_active_pause);
+
+/* Determine the MAC RX/TX PAUSE frames settings based on PHY
+ * autonegotiation or values set by eththool.
+ */
+void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause)
+{
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+ u16 lcl_adv, rmt_adv;
+ u8 flowctrl;
+
+ *rx_pause = *tx_pause = false;
+
+ if (!phy_dev->duplex)
+ return;
+
+ /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings
+ * are those set by ethtool.
+ */
+ if (!mac_dev->autoneg_pause) {
+ *rx_pause = mac_dev->rx_pause_req;
+ *tx_pause = mac_dev->tx_pause_req;
+ return;
+ }
+
+ /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE
+ * settings depend on the result of the link negotiation.
+ */
+
+ /* get local capabilities */
+ lcl_adv = linkmode_adv_to_lcl_adv_t(phy_dev->advertising);
+
+ /* get link partner capabilities */
+ rmt_adv = 0;
+ if (phy_dev->pause)
+ rmt_adv |= LPA_PAUSE_CAP;
+ if (phy_dev->asym_pause)
+ rmt_adv |= LPA_PAUSE_ASYM;
+
+ /* Calculate TX/RX settings based on local and peer advertised
+ * symmetric/asymmetric PAUSE capabilities.
+ */
+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+ if (flowctrl & FLOW_CTRL_RX)
+ *rx_pause = true;
+ if (flowctrl & FLOW_CTRL_TX)
+ *tx_pause = true;
+}
+EXPORT_SYMBOL(get_pause_cfg);
+
+static void adjust_link_void(struct net_device *net_dev)
+{
+}
+
+static void adjust_link(struct net_device *net_dev)
+{
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
+ struct mac_device *mac_dev = priv->mac_dev;
+ struct phy_device *phy_dev = mac_dev->phy_dev;
+ struct fm_mac_dev *fm_mac_dev;
+ bool rx_pause, tx_pause;
+ int _errno;
+
+ fm_mac_dev = mac_dev->get_mac_handle(mac_dev);
+ fm_mac_adjust_link(fm_mac_dev, phy_dev->link, phy_dev->speed,
+ phy_dev->duplex);
+
+ get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
+ _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause);
+ if (unlikely(_errno < 0))
+ netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno);
+}
+
+/* Initializes driver's PHY state, and attaches to the PHY.
+ * Returns 0 on success.
+ */
+static int dtsec_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ if (of_phy_is_fixed_link(mac_dev->phy_node))
+ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
+ 0, mac_dev->phy_if);
+ else
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link, 0, mac_dev->phy_if);
+ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ /* Remove any features not supported by the controller */
+ ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
+ linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_support_asym_pause(phy_dev);
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int xgmac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ if (of_phy_is_fixed_link(mac_dev->phy_node))
+ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node,
+ 0, mac_dev->phy_if);
+ else
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ &adjust_link_void, 0, mac_dev->phy_if);
+ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not attach to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
+ linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_support_asym_pause(phy_dev);
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int memac_init_phy(struct net_device *net_dev,
+ struct mac_device *mac_dev)
+{
+ struct phy_device *phy_dev;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+ void (*adjust_link_handler)(struct net_device *);
+
+ if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) ||
+ (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500)) {
+ /* Pass a void link state handler to the PHY state machine
+ * for XGMII (10G) and SGMII 2.5G, as the hardware does not
+ * permit dynamic link speed adjustments. */
+ adjust_link_handler = adjust_link_void;
+ } else if (macdev2enetinterface(mac_dev) & e_ENET_IF_RGMII) {
+ /* Regular RGMII ports connected to a PHY, as well as
+ * ports that are marked as "fixed-link" in the DTS,
+ * will have the adjust_link callback. This calls
+ * fman_memac_adjust_link in order to configure the
+ * IF_MODE register, which is needed in both cases.
+ */
+ adjust_link_handler = adjust_link;
+ } else if (of_phy_is_fixed_link(mac_dev->phy_node)) {
+ /* Pass a void link state handler for fixed-link
+ * interfaces that are not RGMII. Only RGMII has been
+ * tested and confirmed to work with fixed-link. Other
+ * MII interfaces may need further work.
+ * TODO: Change this as needed.
+ */
+ adjust_link_handler = adjust_link_void;
+ } else {
+ /* MII, RMII, SMII, GMII, SGMII, BASEX ports,
+ * that are NOT fixed-link.
+ * TODO: May not be needed for interfaces that
+ * pass through the SerDes block (*SGMII, XFI).
+ */
+ adjust_link_handler = adjust_link;
+ }
+ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
+ adjust_link_handler, 0,
+ mac_dev->phy_if);
+
+ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) {
+ netdev_err(net_dev, "Could not connect to PHY %s\n",
+ mac_dev->phy_node ?
+ mac_dev->phy_node->full_name :
+ mac_dev->fixed_bus_id);
+ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev);
+ }
+
+ /* Remove any features not supported by the controller */
+ ethtool_convert_legacy_u32_to_link_mode(mask, mac_dev->if_support);
+ linkmode_and(phy_dev->supported, phy_dev->supported, mask);
+ /* Enable the symmetric and asymmetric PAUSE frame advertisements,
+ * as most of the PHY drivers do not enable them by default.
+ */
+ phy_support_asym_pause(phy_dev);
+
+ mac_dev->phy_dev = phy_dev;
+
+ return 0;
+}
+
+static int __cold uninit(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno, __errno;
+
+ _errno = fm_mac_disable(fm_mac_dev);
+ __errno = fm_mac_free(fm_mac_dev);
+
+ if (unlikely(__errno < 0))
+ _errno = __errno;
+
+ return _errno;
+}
+
+static struct fm_mac_dev *get_mac_handle(struct mac_device *mac_dev)
+{
+ const struct mac_priv_s *priv;
+ priv = macdev_priv(mac_dev);
+ return priv->fm_mac;
+}
+
+static int dtsec_dump_regs(struct mac_device *h_mac, char *buf, int nn)
+{
+ struct dtsec_regs *p_mm = (struct dtsec_regs *) h_mac->vaddr;
+ int i = 0, n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - DTSEC-%d", h_mac->cell_index);
+
+ FM_DMP_V32(buf, n, p_mm, tsec_id);
+ FM_DMP_V32(buf, n, p_mm, tsec_id2);
+ FM_DMP_V32(buf, n, p_mm, ievent);
+ FM_DMP_V32(buf, n, p_mm, imask);
+ FM_DMP_V32(buf, n, p_mm, ecntrl);
+ FM_DMP_V32(buf, n, p_mm, ptv);
+ FM_DMP_V32(buf, n, p_mm, tmr_ctrl);
+ FM_DMP_V32(buf, n, p_mm, tmr_pevent);
+ FM_DMP_V32(buf, n, p_mm, tmr_pemask);
+ FM_DMP_V32(buf, n, p_mm, tctrl);
+ FM_DMP_V32(buf, n, p_mm, rctrl);
+ FM_DMP_V32(buf, n, p_mm, maccfg1);
+ FM_DMP_V32(buf, n, p_mm, maccfg2);
+ FM_DMP_V32(buf, n, p_mm, ipgifg);
+ FM_DMP_V32(buf, n, p_mm, hafdup);
+ FM_DMP_V32(buf, n, p_mm, maxfrm);
+
+ FM_DMP_V32(buf, n, p_mm, macstnaddr1);
+ FM_DMP_V32(buf, n, p_mm, macstnaddr2);
+
+ for (i = 0; i < 7; ++i) {
+ FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match1);
+ FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match2);
+ }
+
+ FM_DMP_V32(buf, n, p_mm, car1);
+ FM_DMP_V32(buf, n, p_mm, car2);
+
+ return n;
+}
+
+static int xgmac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
+{
+ struct tgec_regs *p_mm = (struct tgec_regs *) h_mac->vaddr;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - TGEC -%d", h_mac->cell_index);
+
+ FM_DMP_V32(buf, n, p_mm, tgec_id);
+ FM_DMP_V32(buf, n, p_mm, command_config);
+ FM_DMP_V32(buf, n, p_mm, mac_addr_0);
+ FM_DMP_V32(buf, n, p_mm, mac_addr_1);
+ FM_DMP_V32(buf, n, p_mm, maxfrm);
+ FM_DMP_V32(buf, n, p_mm, pause_quant);
+ FM_DMP_V32(buf, n, p_mm, rx_fifo_sections);
+ FM_DMP_V32(buf, n, p_mm, tx_fifo_sections);
+ FM_DMP_V32(buf, n, p_mm, rx_fifo_almost_f_e);
+ FM_DMP_V32(buf, n, p_mm, tx_fifo_almost_f_e);
+ FM_DMP_V32(buf, n, p_mm, hashtable_ctrl);
+ FM_DMP_V32(buf, n, p_mm, mdio_cfg_status);
+ FM_DMP_V32(buf, n, p_mm, mdio_command);
+ FM_DMP_V32(buf, n, p_mm, mdio_data);
+ FM_DMP_V32(buf, n, p_mm, mdio_regaddr);
+ FM_DMP_V32(buf, n, p_mm, status);
+ FM_DMP_V32(buf, n, p_mm, tx_ipg_len);
+ FM_DMP_V32(buf, n, p_mm, mac_addr_2);
+ FM_DMP_V32(buf, n, p_mm, mac_addr_3);
+ FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_rd);
+ FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_wr);
+ FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_rd);
+ FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_wr);
+ FM_DMP_V32(buf, n, p_mm, imask);
+ FM_DMP_V32(buf, n, p_mm, ievent);
+
+ return n;
+}
+
+static int memac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
+{
+ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr;
+ int i = 0, n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d", h_mac->cell_index);
+
+ FM_DMP_V32(buf, n, p_mm, command_config);
+ FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_l);
+ FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_u);
+ FM_DMP_V32(buf, n, p_mm, maxfrm);
+ FM_DMP_V32(buf, n, p_mm, hashtable_ctrl);
+ FM_DMP_V32(buf, n, p_mm, ievent);
+ FM_DMP_V32(buf, n, p_mm, tx_ipg_length);
+ FM_DMP_V32(buf, n, p_mm, imask);
+
+ for (i = 0; i < 4; ++i)
+ FM_DMP_V32(buf, n, p_mm, pause_quanta[i]);
+
+ for (i = 0; i < 4; ++i)
+ FM_DMP_V32(buf, n, p_mm, pause_thresh[i]);
+
+ FM_DMP_V32(buf, n, p_mm, rx_pause_status);
+
+ for (i = 0; i < MEMAC_NUM_OF_PADDRS; ++i) {
+ FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_l);
+ FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_u);
+ }
+
+ FM_DMP_V32(buf, n, p_mm, lpwake_timer);
+ FM_DMP_V32(buf, n, p_mm, sleep_timer);
+ FM_DMP_V32(buf, n, p_mm, statn_config);
+ FM_DMP_V32(buf, n, p_mm, if_mode);
+ FM_DMP_V32(buf, n, p_mm, if_status);
+ FM_DMP_V32(buf, n, p_mm, hg_config);
+ FM_DMP_V32(buf, n, p_mm, hg_pause_quanta);
+ FM_DMP_V32(buf, n, p_mm, hg_pause_thresh);
+ FM_DMP_V32(buf, n, p_mm, hgrx_pause_status);
+ FM_DMP_V32(buf, n, p_mm, hg_fifos_status);
+ FM_DMP_V32(buf, n, p_mm, rhm);
+ FM_DMP_V32(buf, n, p_mm, thm);
+
+ return n;
+}
+
+static int memac_dump_regs_rx(struct mac_device *h_mac, char *buf, int nn)
+{
+ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Rx stats", h_mac->cell_index);
+
+ /* Rx Statistics Counter */
+ FM_DMP_V32(buf, n, p_mm, reoct_l);
+ FM_DMP_V32(buf, n, p_mm, reoct_u);
+ FM_DMP_V32(buf, n, p_mm, roct_l);
+ FM_DMP_V32(buf, n, p_mm, roct_u);
+ FM_DMP_V32(buf, n, p_mm, raln_l);
+ FM_DMP_V32(buf, n, p_mm, raln_u);
+ FM_DMP_V32(buf, n, p_mm, rxpf_l);
+ FM_DMP_V32(buf, n, p_mm, rxpf_u);
+ FM_DMP_V32(buf, n, p_mm, rfrm_l);
+ FM_DMP_V32(buf, n, p_mm, rfrm_u);
+ FM_DMP_V32(buf, n, p_mm, rfcs_l);
+ FM_DMP_V32(buf, n, p_mm, rfcs_u);
+ FM_DMP_V32(buf, n, p_mm, rvlan_l);
+ FM_DMP_V32(buf, n, p_mm, rvlan_u);
+ FM_DMP_V32(buf, n, p_mm, rerr_l);
+ FM_DMP_V32(buf, n, p_mm, rerr_u);
+ FM_DMP_V32(buf, n, p_mm, ruca_l);
+ FM_DMP_V32(buf, n, p_mm, ruca_u);
+ FM_DMP_V32(buf, n, p_mm, rmca_l);
+ FM_DMP_V32(buf, n, p_mm, rmca_u);
+ FM_DMP_V32(buf, n, p_mm, rbca_l);
+ FM_DMP_V32(buf, n, p_mm, rbca_u);
+ FM_DMP_V32(buf, n, p_mm, rdrp_l);
+ FM_DMP_V32(buf, n, p_mm, rdrp_u);
+ FM_DMP_V32(buf, n, p_mm, rpkt_l);
+ FM_DMP_V32(buf, n, p_mm, rpkt_u);
+ FM_DMP_V32(buf, n, p_mm, rund_l);
+ FM_DMP_V32(buf, n, p_mm, rund_u);
+ FM_DMP_V32(buf, n, p_mm, r64_l);
+ FM_DMP_V32(buf, n, p_mm, r64_u);
+ FM_DMP_V32(buf, n, p_mm, r127_l);
+ FM_DMP_V32(buf, n, p_mm, r127_u);
+ FM_DMP_V32(buf, n, p_mm, r255_l);
+ FM_DMP_V32(buf, n, p_mm, r255_u);
+ FM_DMP_V32(buf, n, p_mm, r511_l);
+ FM_DMP_V32(buf, n, p_mm, r511_u);
+ FM_DMP_V32(buf, n, p_mm, r1023_l);
+ FM_DMP_V32(buf, n, p_mm, r1023_u);
+ FM_DMP_V32(buf, n, p_mm, r1518_l);
+ FM_DMP_V32(buf, n, p_mm, r1518_u);
+ FM_DMP_V32(buf, n, p_mm, r1519x_l);
+ FM_DMP_V32(buf, n, p_mm, r1519x_u);
+ FM_DMP_V32(buf, n, p_mm, rovr_l);
+ FM_DMP_V32(buf, n, p_mm, rovr_u);
+ FM_DMP_V32(buf, n, p_mm, rjbr_l);
+ FM_DMP_V32(buf, n, p_mm, rjbr_u);
+ FM_DMP_V32(buf, n, p_mm, rfrg_l);
+ FM_DMP_V32(buf, n, p_mm, rfrg_u);
+ FM_DMP_V32(buf, n, p_mm, rcnp_l);
+ FM_DMP_V32(buf, n, p_mm, rcnp_u);
+ FM_DMP_V32(buf, n, p_mm, rdrntp_l);
+ FM_DMP_V32(buf, n, p_mm, rdrntp_u);
+
+ return n;
+}
+
+static int memac_dump_regs_tx(struct mac_device *h_mac, char *buf, int nn)
+{
+ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Tx stats", h_mac->cell_index);
+
+
+ /* Tx Statistics Counter */
+ FM_DMP_V32(buf, n, p_mm, teoct_l);
+ FM_DMP_V32(buf, n, p_mm, teoct_u);
+ FM_DMP_V32(buf, n, p_mm, toct_l);
+ FM_DMP_V32(buf, n, p_mm, toct_u);
+ FM_DMP_V32(buf, n, p_mm, txpf_l);
+ FM_DMP_V32(buf, n, p_mm, txpf_u);
+ FM_DMP_V32(buf, n, p_mm, tfrm_l);
+ FM_DMP_V32(buf, n, p_mm, tfrm_u);
+ FM_DMP_V32(buf, n, p_mm, tfcs_l);
+ FM_DMP_V32(buf, n, p_mm, tfcs_u);
+ FM_DMP_V32(buf, n, p_mm, tvlan_l);
+ FM_DMP_V32(buf, n, p_mm, tvlan_u);
+ FM_DMP_V32(buf, n, p_mm, terr_l);
+ FM_DMP_V32(buf, n, p_mm, terr_u);
+ FM_DMP_V32(buf, n, p_mm, tuca_l);
+ FM_DMP_V32(buf, n, p_mm, tuca_u);
+ FM_DMP_V32(buf, n, p_mm, tmca_l);
+ FM_DMP_V32(buf, n, p_mm, tmca_u);
+ FM_DMP_V32(buf, n, p_mm, tbca_l);
+ FM_DMP_V32(buf, n, p_mm, tbca_u);
+ FM_DMP_V32(buf, n, p_mm, tpkt_l);
+ FM_DMP_V32(buf, n, p_mm, tpkt_u);
+ FM_DMP_V32(buf, n, p_mm, tund_l);
+ FM_DMP_V32(buf, n, p_mm, tund_u);
+ FM_DMP_V32(buf, n, p_mm, t64_l);
+ FM_DMP_V32(buf, n, p_mm, t64_u);
+ FM_DMP_V32(buf, n, p_mm, t127_l);
+ FM_DMP_V32(buf, n, p_mm, t127_u);
+ FM_DMP_V32(buf, n, p_mm, t255_l);
+ FM_DMP_V32(buf, n, p_mm, t255_u);
+ FM_DMP_V32(buf, n, p_mm, t511_l);
+ FM_DMP_V32(buf, n, p_mm, t511_u);
+ FM_DMP_V32(buf, n, p_mm, t1023_l);
+ FM_DMP_V32(buf, n, p_mm, t1023_u);
+ FM_DMP_V32(buf, n, p_mm, t1518_l);
+ FM_DMP_V32(buf, n, p_mm, t1518_u);
+ FM_DMP_V32(buf, n, p_mm, t1519x_l);
+ FM_DMP_V32(buf, n, p_mm, t1519x_u);
+ FM_DMP_V32(buf, n, p_mm, tcnp_l);
+ FM_DMP_V32(buf, n, p_mm, tcnp_u);
+
+ return n;
+}
+
+int fm_mac_dump_regs(struct mac_device *h_mac, char *buf, int nn)
+{
+ int n = nn;
+
+ n = h_mac->dump_mac_regs(h_mac, buf, n);
+
+ return n;
+}
+EXPORT_SYMBOL(fm_mac_dump_regs);
+
+int fm_mac_dump_rx_stats(struct mac_device *h_mac, char *buf, int nn)
+{
+ int n = nn;
+
+ if(h_mac->dump_mac_rx_stats)
+ n = h_mac->dump_mac_rx_stats(h_mac, buf, n);
+
+ return n;
+}
+EXPORT_SYMBOL(fm_mac_dump_rx_stats);
+
+int fm_mac_dump_tx_stats(struct mac_device *h_mac, char *buf, int nn)
+{
+ int n = nn;
+
+ if(h_mac->dump_mac_tx_stats)
+ n = h_mac->dump_mac_tx_stats(h_mac, buf, n);
+
+ return n;
+}
+EXPORT_SYMBOL(fm_mac_dump_tx_stats);
+
+static void __cold setup_dtsec(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = dtsec_init_phy;
+ mac_dev->init = init;
+ mac_dev->start = start;
+ mac_dev->stop = stop;
+ mac_dev->set_promisc = fm_mac_set_promiscuous;
+ mac_dev->change_addr = fm_mac_modify_mac_addr;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = uninit;
+ mac_dev->ptp_enable = fm_mac_enable_1588_time_stamp;
+ mac_dev->ptp_disable = fm_mac_disable_1588_time_stamp;
+ mac_dev->get_mac_handle = get_mac_handle;
+ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames;
+ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames;
+ mac_dev->fm_rtc_enable = fm_rtc_enable;
+ mac_dev->fm_rtc_disable = fm_rtc_disable;
+ mac_dev->fm_rtc_get_cnt = fm_rtc_get_cnt;
+ mac_dev->fm_rtc_set_cnt = fm_rtc_set_cnt;
+ mac_dev->fm_rtc_get_drift = fm_rtc_get_drift;
+ mac_dev->fm_rtc_set_drift = fm_rtc_set_drift;
+ mac_dev->fm_rtc_set_alarm = fm_rtc_set_alarm;
+ mac_dev->fm_rtc_set_fiper = fm_rtc_set_fiper;
+ mac_dev->set_wol = fm_mac_set_wol;
+ mac_dev->dump_mac_regs = dtsec_dump_regs;
+}
+
+static void __cold setup_xgmac(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = xgmac_init_phy;
+ mac_dev->init = init;
+ mac_dev->start = start;
+ mac_dev->stop = stop;
+ mac_dev->set_promisc = fm_mac_set_promiscuous;
+ mac_dev->change_addr = fm_mac_modify_mac_addr;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = uninit;
+ mac_dev->get_mac_handle = get_mac_handle;
+ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames;
+ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames;
+ mac_dev->set_wol = fm_mac_set_wol;
+ mac_dev->dump_mac_regs = xgmac_dump_regs;
+}
+
+static void __cold setup_memac(struct mac_device *mac_dev)
+{
+ mac_dev->init_phy = memac_init_phy;
+ mac_dev->init = memac_init;
+ mac_dev->start = start;
+ mac_dev->stop = stop;
+ mac_dev->set_promisc = fm_mac_set_promiscuous;
+ mac_dev->change_addr = fm_mac_modify_mac_addr;
+ mac_dev->set_multi = set_multi;
+ mac_dev->uninit = uninit;
+ mac_dev->get_mac_handle = get_mac_handle;
+ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames;
+ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames;
+ mac_dev->fm_rtc_enable = fm_rtc_enable;
+ mac_dev->fm_rtc_disable = fm_rtc_disable;
+ mac_dev->fm_rtc_get_cnt = fm_rtc_get_cnt;
+ mac_dev->fm_rtc_set_cnt = fm_rtc_set_cnt;
+ mac_dev->fm_rtc_get_drift = fm_rtc_get_drift;
+ mac_dev->fm_rtc_set_drift = fm_rtc_set_drift;
+ mac_dev->fm_rtc_set_alarm = fm_rtc_set_alarm;
+ mac_dev->fm_rtc_set_fiper = fm_rtc_set_fiper;
+ mac_dev->set_wol = fm_mac_set_wol;
+ mac_dev->dump_mac_regs = memac_dump_regs;
+ mac_dev->dump_mac_rx_stats = memac_dump_regs_rx;
+ mac_dev->dump_mac_tx_stats = memac_dump_regs_tx;
+}
+
+void (*const mac_setup[])(struct mac_device *mac_dev) = {
+ [DTSEC] = setup_dtsec,
+ [XGMAC] = setup_xgmac,
+ [MEMAC] = setup_memac
+};
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac.c b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
new file mode 100644
index 000000000000..3092c49e9e1c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c
@@ -0,0 +1,489 @@
+/* Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/phy_fixed.h>
+#include <linux/device.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+
+#include "lnxwrp_fm_ext.h"
+
+#include "mac.h"
+
+#define DTSEC_SUPPORTED \
+ (SUPPORTED_10baseT_Half \
+ | SUPPORTED_10baseT_Full \
+ | SUPPORTED_100baseT_Half \
+ | SUPPORTED_100baseT_Full \
+ | SUPPORTED_Autoneg \
+ | SUPPORTED_Pause \
+ | SUPPORTED_Asym_Pause \
+ | SUPPORTED_MII)
+
+static const char phy_str[][11] = {
+ [PHY_INTERFACE_MODE_MII] = "mii",
+ [PHY_INTERFACE_MODE_GMII] = "gmii",
+ [PHY_INTERFACE_MODE_SGMII] = "sgmii",
+ [PHY_INTERFACE_MODE_QSGMII] = "qsgmii",
+ [PHY_INTERFACE_MODE_TBI] = "tbi",
+ [PHY_INTERFACE_MODE_RMII] = "rmii",
+ [PHY_INTERFACE_MODE_RGMII] = "rgmii",
+ [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
+ [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+ [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+ [PHY_INTERFACE_MODE_RTBI] = "rtbi",
+ [PHY_INTERFACE_MODE_XGMII] = "xgmii",
+ [PHY_INTERFACE_MODE_2500BASEX] = "sgmii-2500",
+};
+
+static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(phy_str); i++)
+ if (strcmp(str, phy_str[i]) == 0)
+ return (phy_interface_t)i;
+
+ return PHY_INTERFACE_MODE_MII;
+}
+
+static const uint16_t phy2speed[] = {
+ [PHY_INTERFACE_MODE_MII] = SPEED_100,
+ [PHY_INTERFACE_MODE_GMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_SGMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_TBI] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RMII] = SPEED_100,
+ [PHY_INTERFACE_MODE_RGMII] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
+ [PHY_INTERFACE_MODE_RTBI] = SPEED_1000,
+ [PHY_INTERFACE_MODE_XGMII] = SPEED_10000,
+ [PHY_INTERFACE_MODE_2500BASEX] = SPEED_2500,
+};
+
+static struct mac_device * __cold
+alloc_macdev(struct device *dev, size_t sizeof_priv,
+ void (*setup)(struct mac_device *mac_dev))
+{
+ struct mac_device *mac_dev;
+
+ mac_dev = devm_kzalloc(dev, sizeof(*mac_dev) + sizeof_priv, GFP_KERNEL);
+ if (unlikely(mac_dev == NULL))
+ mac_dev = ERR_PTR(-ENOMEM);
+ else {
+ mac_dev->dev = dev;
+ dev_set_drvdata(dev, mac_dev);
+ setup(mac_dev);
+ }
+
+ return mac_dev;
+}
+
+static int __cold free_macdev(struct mac_device *mac_dev)
+{
+ dev_set_drvdata(mac_dev->dev, NULL);
+
+ return mac_dev->uninit(mac_dev->get_mac_handle(mac_dev));
+}
+
+static const struct of_device_id mac_match[] = {
+ [DTSEC] = {
+ .compatible = "fsl,fman-dtsec"
+ },
+ [XGMAC] = {
+ .compatible = "fsl,fman-xgec"
+ },
+ [MEMAC] = {
+ .compatible = "fsl,fman-memac"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mac_match);
+
+static int __cold mac_probe(struct platform_device *_of_dev)
+{
+ int _errno, i;
+ struct device *dev;
+ struct device_node *mac_node, *dev_node;
+ struct mac_device *mac_dev;
+ struct platform_device *of_dev;
+ struct resource res;
+ const uint8_t *mac_addr;
+ const char *char_prop;
+ int nph;
+ u32 cell_index;
+ const struct of_device_id *match;
+
+ dev = &_of_dev->dev;
+ mac_node = dev->of_node;
+
+ match = of_match_device(mac_match, dev);
+ if (!match)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(mac_match) - 1 && match != mac_match + i;
+ i++)
+ ;
+ BUG_ON(i >= ARRAY_SIZE(mac_match) - 1);
+
+ mac_dev = alloc_macdev(dev, mac_sizeof_priv[i], mac_setup[i]);
+ if (IS_ERR(mac_dev)) {
+ _errno = PTR_ERR(mac_dev);
+ dev_err(dev, "alloc_macdev() = %d\n", _errno);
+ goto _return;
+ }
+
+ INIT_LIST_HEAD(&mac_dev->mc_addr_list);
+
+ /* Get the FM node */
+ dev_node = of_get_parent(mac_node);
+ if (unlikely(dev_node == NULL)) {
+ dev_err(dev, "of_get_parent(%s) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (unlikely(of_dev == NULL)) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->fm_dev = fm_bind(&of_dev->dev);
+ if (unlikely(mac_dev->fm_dev == NULL)) {
+ dev_err(dev, "fm_bind(%s) failed\n", dev_node->full_name);
+ _errno = -ENODEV;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->fm = (void *)fm_get_handle(mac_dev->fm_dev);
+ of_node_put(dev_node);
+
+ /* Get the address of the memory mapped registers */
+ _errno = of_address_to_resource(mac_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ dev_err(dev, "of_address_to_resource(%s) = %d\n",
+ mac_node->full_name, _errno);
+ goto _return_dev_set_drvdata;
+ }
+
+ mac_dev->res = __devm_request_region(
+ dev,
+ fm_get_mem_region(mac_dev->fm_dev),
+ res.start, res.end + 1 - res.start, "mac");
+ if (unlikely(mac_dev->res == NULL)) {
+ dev_err(dev, "__devm_request_mem_region(mac) failed\n");
+ _errno = -EBUSY;
+ goto _return_dev_set_drvdata;
+ }
+
+ mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
+ mac_dev->res->end + 1
+ - mac_dev->res->start);
+ if (unlikely(mac_dev->vaddr == NULL)) {
+ dev_err(dev, "devm_ioremap() failed\n");
+ _errno = -EIO;
+ goto _return_dev_set_drvdata;
+ }
+
+#define TBIPA_OFFSET 0x1c
+#define TBIPA_DEFAULT_ADDR 5 /* override if used as external PHY addr. */
+ mac_dev->tbi_node = of_parse_phandle(mac_node, "tbi-handle", 0);
+ if (mac_dev->tbi_node) {
+ u32 tbiaddr = TBIPA_DEFAULT_ADDR;
+ const __be32 *tbi_reg;
+ void __iomem *addr;
+
+ tbi_reg = of_get_property(mac_dev->tbi_node, "reg", NULL);
+ if (tbi_reg)
+ tbiaddr = be32_to_cpup(tbi_reg);
+ addr = mac_dev->vaddr + TBIPA_OFFSET;
+ /* TODO: out_be32 does not exist on ARM */
+ out_be32(addr, tbiaddr);
+ }
+
+ if (!of_device_is_available(mac_node)) {
+ devm_iounmap(dev, mac_dev->vaddr);
+ __devm_release_region(dev, fm_get_mem_region(mac_dev->fm_dev),
+ res.start, res.end + 1 - res.start);
+ fm_unbind(mac_dev->fm_dev);
+ devm_kfree(dev, mac_dev);
+ dev_set_drvdata(dev, NULL);
+ return -ENODEV;
+ }
+
+ /* Get the cell-index */
+ _errno = of_property_read_u32(mac_node, "cell-index", &cell_index);
+ if (unlikely(_errno)) {
+ dev_err(dev, "Cannot read cell-index of mac node %s from device tree\n",
+ mac_node->full_name);
+ goto _return_dev_set_drvdata;
+ }
+ mac_dev->cell_index = (uint8_t)cell_index;
+ if (mac_dev->cell_index >= 8)
+ mac_dev->cell_index -= 8;
+
+ /* Get the MAC address */
+ mac_addr = of_get_mac_address(mac_node);
+ if (unlikely(mac_addr == NULL)) {
+ dev_err(dev, "of_get_mac_address(%s) failed\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+ memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr));
+
+ /* Verify the number of port handles */
+ nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
+ if (unlikely(nph < 0)) {
+ dev_err(dev, "Cannot read port handles of mac node %s from device tree\n",
+ mac_node->full_name);
+ _errno = nph;
+ goto _return_dev_set_drvdata;
+ }
+
+ if (nph != ARRAY_SIZE(mac_dev->port_dev)) {
+ dev_err(dev, "Not supported number of port handles of mac node %s from device tree\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_dev_set_drvdata;
+ }
+
+ for_each_port_device(i, mac_dev->port_dev) {
+ dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
+ if (unlikely(dev_node == NULL)) {
+ dev_err(dev, "Cannot find port node referenced by mac node %s from device tree\n",
+ mac_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ of_dev = of_find_device_by_node(dev_node);
+ if (unlikely(of_dev == NULL)) {
+ dev_err(dev, "of_find_device_by_node(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+
+ mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev);
+ if (unlikely(mac_dev->port_dev[i] == NULL)) {
+ dev_err(dev, "dev_get_drvdata(%s) failed\n",
+ dev_node->full_name);
+ _errno = -EINVAL;
+ goto _return_of_node_put;
+ }
+ of_node_put(dev_node);
+ }
+
+ /* Get the PHY connection type */
+ _errno = of_property_read_string(mac_node, "phy-connection-type",
+ &char_prop);
+ if (unlikely(_errno)) {
+ dev_warn(dev,
+ "Cannot read PHY connection type of mac node %s from device tree. Defaulting to MII\n",
+ mac_node->full_name);
+ mac_dev->phy_if = PHY_INTERFACE_MODE_MII;
+ } else
+ mac_dev->phy_if = str2phy(char_prop);
+
+ mac_dev->link = false;
+ mac_dev->half_duplex = false;
+ mac_dev->speed = phy2speed[mac_dev->phy_if];
+ mac_dev->max_speed = mac_dev->speed;
+ mac_dev->if_support = DTSEC_SUPPORTED;
+ /* We don't support half-duplex in SGMII mode */
+ if (strstr(char_prop, "sgmii") || strstr(char_prop, "qsgmii") ||
+ strstr(char_prop, "sgmii-2500"))
+ mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
+ SUPPORTED_100baseT_Half);
+
+ /* Gigabit support (no half-duplex) */
+ if (mac_dev->max_speed == SPEED_1000 ||
+ mac_dev->max_speed == SPEED_2500)
+ mac_dev->if_support |= SUPPORTED_1000baseT_Full;
+
+ /* The 10G interface only supports one mode */
+ if (strstr(char_prop, "xgmii"))
+ mac_dev->if_support = SUPPORTED_10000baseT_Full;
+
+ /* Get the rest of the PHY information */
+ mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
+ if (!mac_dev->phy_node) {
+ struct phy_device *phy;
+
+ if (!of_phy_is_fixed_link(mac_node)) {
+ dev_err(dev, "Wrong PHY information of mac node %s\n",
+ mac_node->full_name);
+ goto _return_dev_set_drvdata;
+ }
+
+ _errno = of_phy_register_fixed_link(mac_node);
+ if (_errno)
+ goto _return_dev_set_drvdata;
+
+ mac_dev->fixed_link = devm_kzalloc(mac_dev->dev,
+ sizeof(*mac_dev->fixed_link),
+ GFP_KERNEL);
+ if (!mac_dev->fixed_link)
+ goto _return_dev_set_drvdata;
+
+ mac_dev->phy_node = of_node_get(mac_node);
+ phy = of_phy_find_device(mac_dev->phy_node);
+ if (!phy)
+ goto _return_dev_set_drvdata;
+
+ mac_dev->fixed_link->link = phy->link;
+ mac_dev->fixed_link->speed = phy->speed;
+ mac_dev->fixed_link->duplex = phy->duplex;
+ mac_dev->fixed_link->pause = phy->pause;
+ mac_dev->fixed_link->asym_pause = phy->asym_pause;
+ }
+
+ _errno = mac_dev->init(mac_dev);
+ if (unlikely(_errno < 0)) {
+ dev_err(dev, "mac_dev->init() = %d\n", _errno);
+ goto _return_dev_set_drvdata;
+ }
+
+ /* pause frame autonegotiation enabled*/
+ mac_dev->autoneg_pause = true;
+
+ /* by intializing the values to false, force FMD to enable PAUSE frames
+ * on RX and TX
+ */
+ mac_dev->rx_pause_req = mac_dev->tx_pause_req = true;
+ mac_dev->rx_pause_active = mac_dev->tx_pause_active = false;
+ _errno = set_mac_active_pause(mac_dev, true, true);
+ if (unlikely(_errno < 0))
+ dev_err(dev, "set_mac_active_pause() = %d\n", _errno);
+
+ dev_info(dev,
+ "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
+ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
+ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]);
+
+ goto _return;
+
+_return_of_node_put:
+ of_node_put(dev_node);
+_return_dev_set_drvdata:
+ dev_set_drvdata(dev, NULL);
+_return:
+ return _errno;
+}
+
+static int __cold mac_remove(struct platform_device *of_dev)
+{
+ int i, _errno;
+ struct device *dev;
+ struct mac_device *mac_dev;
+
+ dev = &of_dev->dev;
+ mac_dev = (struct mac_device *)dev_get_drvdata(dev);
+
+ for_each_port_device(i, mac_dev->port_dev)
+ fm_port_unbind(mac_dev->port_dev[i]);
+
+ fm_unbind(mac_dev->fm_dev);
+
+ _errno = free_macdev(mac_dev);
+
+ return _errno;
+}
+
+static struct platform_driver mac_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = mac_match,
+ .owner = THIS_MODULE,
+ },
+ .probe = mac_probe,
+ .remove = mac_remove
+};
+
+static int __init __cold mac_load(void)
+{
+ int _errno;
+
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME".c", __func__);
+
+ pr_info(KBUILD_MODNAME ": %s\n", mac_driver_description);
+
+ _errno = platform_driver_register(&mac_driver);
+ if (unlikely(_errno < 0)) {
+ pr_err(KBUILD_MODNAME ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__, _errno);
+ goto _return;
+ }
+
+ goto _return;
+
+_return:
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+
+ return _errno;
+}
+module_init(mac_load);
+
+static void __exit __cold mac_unload(void)
+{
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME".c", __func__);
+
+ platform_driver_unregister(&mac_driver);
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+}
+module_exit(mac_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac.h b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h
new file mode 100644
index 000000000000..c42373454833
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h
@@ -0,0 +1,134 @@
+/* Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __MAC_H
+#define __MAC_H
+
+#include <linux/device.h> /* struct device, BUS_ID_SIZE */
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/phy.h> /* phy_interface_t, struct phy_device */
+#include <linux/list.h>
+
+#include "lnxwrp_fsl_fman.h" /* struct port_device */
+
+enum {DTSEC, XGMAC, MEMAC};
+
+struct mac_device {
+ struct device *dev;
+ void *priv;
+ uint8_t cell_index;
+ struct resource *res;
+ void __iomem *vaddr;
+ uint8_t addr[ETH_ALEN];
+ bool promisc;
+
+ struct fm *fm_dev;
+ struct fm_port *port_dev[2];
+
+ phy_interface_t phy_if;
+ u32 if_support;
+ bool link;
+ bool half_duplex;
+ uint16_t speed;
+ uint16_t max_speed;
+ struct device_node *phy_node;
+ char fixed_bus_id[MII_BUS_ID_SIZE + 3];
+ struct device_node *tbi_node;
+ struct phy_device *phy_dev;
+ void *fm;
+ /* List of multicast addresses */
+ struct list_head mc_addr_list;
+ struct fixed_phy_status *fixed_link;
+
+ bool autoneg_pause;
+ bool rx_pause_req;
+ bool tx_pause_req;
+ bool rx_pause_active;
+ bool tx_pause_active;
+
+ struct fm_mac_dev *(*get_mac_handle)(struct mac_device *mac_dev);
+ int (*init_phy)(struct net_device *net_dev, struct mac_device *mac_dev);
+ int (*init)(struct mac_device *mac_dev);
+ int (*start)(struct mac_device *mac_dev);
+ int (*stop)(struct mac_device *mac_dev);
+ int (*set_promisc)(struct fm_mac_dev *fm_mac_dev, bool enable);
+ int (*change_addr)(struct fm_mac_dev *fm_mac_dev, uint8_t *addr);
+ int (*set_multi)(struct net_device *net_dev,
+ struct mac_device *mac_dev);
+ int (*uninit)(struct fm_mac_dev *fm_mac_dev);
+ int (*ptp_enable)(struct fm_mac_dev *fm_mac_dev);
+ int (*ptp_disable)(struct fm_mac_dev *fm_mac_dev);
+ int (*set_rx_pause)(struct fm_mac_dev *fm_mac_dev, bool en);
+ int (*set_tx_pause)(struct fm_mac_dev *fm_mac_dev, bool en);
+ int (*fm_rtc_enable)(struct fm *fm_dev);
+ int (*fm_rtc_disable)(struct fm *fm_dev);
+ int (*fm_rtc_get_cnt)(struct fm *fm_dev, uint64_t *ts);
+ int (*fm_rtc_set_cnt)(struct fm *fm_dev, uint64_t ts);
+ int (*fm_rtc_get_drift)(struct fm *fm_dev, uint32_t *drift);
+ int (*fm_rtc_set_drift)(struct fm *fm_dev, uint32_t drift);
+ int (*fm_rtc_set_alarm)(struct fm *fm_dev, uint32_t id, uint64_t time);
+ int (*fm_rtc_set_fiper)(struct fm *fm_dev, uint32_t id,
+ uint64_t fiper);
+ int (*fm_rtc_enable_interrupt)(struct fm *fm_dev, uint32_t events);
+ int (*fm_rtc_disable_interrupt)(struct fm *fm_dev, uint32_t events);
+
+ int (*set_wol)(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
+ bool en);
+ int (*dump_mac_regs)(struct mac_device *h_mac, char *buf, int nn);
+ int (*dump_mac_rx_stats)(struct mac_device *h_mac, char *buf, int nn);
+ int (*dump_mac_tx_stats)(struct mac_device *h_mac, char *buf, int nn);
+};
+
+struct mac_address {
+ uint8_t addr[ETH_ALEN];
+ struct list_head list;
+};
+
+#define get_fm_handle(net_dev) \
+ (((struct dpa_priv_s *)netdev_priv(net_dev))->mac_dev->fm_dev)
+
+#define for_each_port_device(i, port_dev) \
+ for (i = 0; i < ARRAY_SIZE(port_dev); i++)
+
+static inline __attribute((nonnull)) void *macdev_priv(
+ const struct mac_device *mac_dev)
+{
+ return (void *)mac_dev + sizeof(*mac_dev);
+}
+
+extern const char *mac_driver_description;
+extern const size_t mac_sizeof_priv[];
+extern void (*const mac_setup[])(struct mac_device *mac_dev);
+
+int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx);
+void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause);
+
+#endif /* __MAC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c
new file mode 100644
index 000000000000..fb084af5cc24
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c
@@ -0,0 +1,848 @@
+/* Copyright 2011-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/* Offline Parsing / Host Command port driver for FSL QorIQ FMan.
+ * Validates device-tree configuration and sets up the offline ports.
+ */
+
+#ifdef CONFIG_FSL_DPAA_ETH_DEBUG
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \
+ KBUILD_BASENAME".c", __LINE__, __func__
+#else
+#define pr_fmt(fmt) \
+ KBUILD_MODNAME ": " fmt
+#endif
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/fsl_qman.h>
+
+#include "offline_port.h"
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+
+#define OH_MOD_DESCRIPTION "FSL FMan Offline Parsing port driver"
+/* Manip extra space and data alignment for fragmentation */
+#define FRAG_MANIP_SPACE 128
+#define FRAG_DATA_ALIGN 64
+
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Bogdan Hamciuc <bogdan.hamciuc@freescale.com>");
+MODULE_DESCRIPTION(OH_MOD_DESCRIPTION);
+
+
+static const struct of_device_id oh_port_match_table[] = {
+ {
+ .compatible = "fsl,dpa-oh"
+ },
+ {
+ .compatible = "fsl,dpa-oh-shared"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, oh_port_match_table);
+
+#ifdef CONFIG_PM
+
+static int oh_suspend(struct device *dev)
+{
+ struct dpa_oh_config_s *oh_config;
+
+ oh_config = dev_get_drvdata(dev);
+ return fm_port_suspend(oh_config->oh_port);
+}
+
+static int oh_resume(struct device *dev)
+{
+ struct dpa_oh_config_s *oh_config;
+
+ oh_config = dev_get_drvdata(dev);
+ return fm_port_resume(oh_config->oh_port);
+}
+
+static const struct dev_pm_ops oh_pm_ops = {
+ .suspend = oh_suspend,
+ .resume = oh_resume,
+};
+
+#define OH_PM_OPS (&oh_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define OH_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
+/* Creates Frame Queues */
+static uint32_t oh_fq_create(struct qman_fq *fq,
+ uint32_t fq_id, uint16_t channel,
+ uint16_t wq_id)
+{
+ struct qm_mcc_initfq fq_opts;
+ uint32_t create_flags, init_flags;
+ uint32_t ret = 0;
+
+ if (fq == NULL)
+ return 1;
+
+ /* Set flags for FQ create */
+ create_flags = QMAN_FQ_FLAG_LOCKED | QMAN_FQ_FLAG_TO_DCPORTAL;
+
+ /* Create frame queue */
+ ret = qman_create_fq(fq_id, create_flags, fq);
+ if (ret != 0)
+ return 1;
+
+ /* Set flags for FQ init */
+ init_flags = QMAN_INITFQ_FLAG_SCHED;
+
+ /* Set FQ init options. Specify destination WQ ID and channel */
+ fq_opts.we_mask = QM_INITFQ_WE_DESTWQ;
+ fq_opts.fqd.dest.wq = wq_id;
+ fq_opts.fqd.dest.channel = channel;
+
+ /* Initialize frame queue */
+ ret = qman_init_fq(fq, init_flags, &fq_opts);
+ if (ret != 0) {
+ qman_destroy_fq(fq, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void dump_fq(struct device *dev, int fqid, uint16_t channel)
+{
+ if (channel) {
+ /* display fqs with a valid (!= 0) destination channel */
+ dev_info(dev, "FQ ID:%d Channel ID:%d\n", fqid, channel);
+ }
+}
+
+static void dump_fq_duple(struct device *dev, struct qman_fq *fqs,
+ int fqs_count, uint16_t channel_id)
+{
+ int i;
+ for (i = 0; i < fqs_count; i++)
+ dump_fq(dev, (fqs + i)->fqid, channel_id);
+}
+
+static void dump_oh_config(struct device *dev, struct dpa_oh_config_s *conf)
+{
+ struct list_head *fq_list;
+ struct fq_duple *fqd;
+ int i;
+
+ dev_info(dev, "Default egress frame queue: %d\n", conf->default_fqid);
+ dev_info(dev, "Default error frame queue: %d\n", conf->error_fqid);
+
+ /* TX queues (old initialization) */
+ dev_info(dev, "Initialized queues:");
+ for (i = 0; i < conf->egress_cnt; i++)
+ dump_fq_duple(dev, conf->egress_fqs, conf->egress_cnt,
+ conf->channel);
+
+ /* initialized ingress queues */
+ list_for_each(fq_list, &conf->fqs_ingress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+ dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id);
+ }
+
+ /* initialized egress queues */
+ list_for_each(fq_list, &conf->fqs_egress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+ dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id);
+ }
+}
+
+/* Destroys Frame Queues */
+static void oh_fq_destroy(struct qman_fq *fq)
+{
+ int _errno = 0;
+
+ _errno = qman_retire_fq(fq, NULL);
+ if (unlikely(_errno < 0))
+ pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_retire_fq(%u)=%d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__,
+ qman_fq_fqid(fq), _errno);
+
+ _errno = qman_oos_fq(fq);
+ if (unlikely(_errno < 0)) {
+ pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_oos_fq(%u)=%d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__,
+ qman_fq_fqid(fq), _errno);
+ }
+
+ qman_destroy_fq(fq, 0);
+}
+
+/* Allocation code for the OH port's PCD frame queues */
+static int __cold oh_alloc_pcd_fqids(struct device *dev,
+ uint32_t num,
+ uint8_t alignment,
+ uint32_t *base_fqid)
+{
+ dev_crit(dev, "callback not implemented!\n");
+ BUG();
+
+ return 0;
+}
+
+static int __cold oh_free_pcd_fqids(struct device *dev, uint32_t base_fqid)
+{
+ dev_crit(dev, "callback not implemented!\n");
+ BUG();
+
+ return 0;
+}
+
+static void oh_set_buffer_layout(struct fm_port *port,
+ struct dpa_buffer_layout_s *layout)
+{
+ struct fm_port_params params;
+
+ layout->priv_data_size = DPA_TX_PRIV_DATA_SIZE;
+ layout->parse_results = true;
+ layout->hash_results = true;
+ layout->time_stamp = false;
+
+ fm_port_get_buff_layout_ext_params(port, &params);
+ layout->manip_extra_space = params.manip_extra_space;
+ layout->data_align = params.data_align;
+}
+
+static int
+oh_port_probe(struct platform_device *_of_dev)
+{
+ struct device *dpa_oh_dev;
+ struct device_node *dpa_oh_node;
+ int lenp, _errno = 0, fq_idx, duple_idx;
+ int n_size, i, j, ret, duples_count;
+ struct platform_device *oh_of_dev;
+ struct device_node *oh_node, *bpool_node = NULL, *root_node;
+ struct device *oh_dev;
+ struct dpa_oh_config_s *oh_config = NULL;
+ const __be32 *oh_all_queues;
+ const __be32 *channel_ids;
+ const __be32 *oh_tx_queues;
+ uint32_t queues_count;
+ uint32_t crt_fqid_base;
+ uint32_t crt_fq_count;
+ bool frag_enabled = false;
+ struct fm_port_params oh_port_tx_params;
+ struct fm_port_pcd_param oh_port_pcd_params;
+ struct dpa_buffer_layout_s buf_layout;
+
+ /* True if the current partition owns the OH port. */
+ bool init_oh_port;
+
+ const struct of_device_id *match;
+ int crt_ext_pools_count;
+ u32 ext_pool_size;
+ u32 port_id;
+ u32 channel_id;
+
+ int channel_ids_count;
+ int channel_idx;
+ struct fq_duple *fqd;
+ struct list_head *fq_list, *fq_list_tmp;
+
+ const __be32 *bpool_cfg;
+ uint32_t bpid;
+
+ memset(&oh_port_tx_params, 0, sizeof(oh_port_tx_params));
+ dpa_oh_dev = &_of_dev->dev;
+ dpa_oh_node = dpa_oh_dev->of_node;
+ BUG_ON(dpa_oh_node == NULL);
+
+ match = of_match_device(oh_port_match_table, dpa_oh_dev);
+ if (!match)
+ return -EINVAL;
+
+ dev_dbg(dpa_oh_dev, "Probing OH port...\n");
+
+ /* Find the referenced OH node */
+ oh_node = of_parse_phandle(dpa_oh_node, "fsl,fman-oh-port", 0);
+ if (oh_node == NULL) {
+ dev_err(dpa_oh_dev,
+ "Can't find OH node referenced from node %s\n",
+ dpa_oh_node->full_name);
+ return -EINVAL;
+ }
+ dev_info(dpa_oh_dev, "Found OH node handle compatible with %s\n",
+ match->compatible);
+
+ _errno = of_property_read_u32(oh_node, "cell-index", &port_id);
+ if (_errno) {
+ dev_err(dpa_oh_dev, "No port id found in node %s\n",
+ dpa_oh_node->full_name);
+ goto return_kfree;
+ }
+
+ _errno = of_property_read_u32(oh_node, "fsl,qman-channel-id",
+ &channel_id);
+ if (_errno) {
+ dev_err(dpa_oh_dev, "No channel id found in node %s\n",
+ dpa_oh_node->full_name);
+ goto return_kfree;
+ }
+
+ oh_of_dev = of_find_device_by_node(oh_node);
+ BUG_ON(oh_of_dev == NULL);
+ oh_dev = &oh_of_dev->dev;
+
+ /* The OH port must be initialized exactly once.
+ * The following scenarios are of interest:
+ * - the node is Linux-private (will always initialize it);
+ * - the node is shared between two Linux partitions
+ * (only one of them will initialize it);
+ * - the node is shared between a Linux and a LWE partition
+ * (Linux will initialize it) - "fsl,dpa-oh-shared"
+ */
+
+ /* Check if the current partition owns the OH port
+ * and ought to initialize it. It may be the case that we leave this
+ * to another (also Linux) partition.
+ */
+ init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared");
+
+ /* If we aren't the "owner" of the OH node, we're done here. */
+ if (!init_oh_port) {
+ dev_dbg(dpa_oh_dev,
+ "Not owning the shared OH port %s, will not initialize it.\n",
+ oh_node->full_name);
+ of_node_put(oh_node);
+ return 0;
+ }
+
+ /* Allocate OH dev private data */
+ oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL);
+ if (oh_config == NULL) {
+ dev_err(dpa_oh_dev,
+ "Can't allocate private data for OH node %s referenced from node %s!\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ INIT_LIST_HEAD(&oh_config->fqs_ingress_list);
+ INIT_LIST_HEAD(&oh_config->fqs_egress_list);
+
+ /* FQs that enter OH port */
+ lenp = 0;
+ oh_all_queues = of_get_property(dpa_oh_node,
+ "fsl,qman-frame-queues-ingress", &lenp);
+ if (lenp % (2 * sizeof(*oh_all_queues))) {
+ dev_warn(dpa_oh_dev,
+ "Wrong ingress queues format for OH node %s referenced from node %s!\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ /* just ignore the last unpaired value */
+ }
+
+ duples_count = lenp / (2 * sizeof(*oh_all_queues));
+ dev_err(dpa_oh_dev, "Allocating %d ingress frame queues duples\n",
+ duples_count);
+ for (duple_idx = 0; duple_idx < duples_count; duple_idx++) {
+ crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]);
+ crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]);
+
+ fqd = devm_kzalloc(dpa_oh_dev,
+ sizeof(struct fq_duple), GFP_KERNEL);
+ if (!fqd) {
+ dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n",
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ fqd->fqs = devm_kzalloc(dpa_oh_dev,
+ crt_fq_count * sizeof(struct qman_fq),
+ GFP_KERNEL);
+ if (!fqd->fqs) {
+ dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n",
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ for (j = 0; j < crt_fq_count; j++)
+ (fqd->fqs + j)->fqid = crt_fqid_base + j;
+ fqd->fqs_count = crt_fq_count;
+ fqd->channel_id = (uint16_t)channel_id;
+ list_add(&fqd->fq_list, &oh_config->fqs_ingress_list);
+ }
+
+ /* create the ingress queues */
+ list_for_each(fq_list, &oh_config->fqs_ingress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+
+ for (j = 0; j < fqd->fqs_count; j++) {
+ ret = oh_fq_create(fqd->fqs + j,
+ (fqd->fqs + j)->fqid,
+ fqd->channel_id, 3);
+ if (ret != 0) {
+ dev_err(dpa_oh_dev, "Unable to create ingress frame queue %d for OH node %s referenced from node %s!\n",
+ (fqd->fqs + j)->fqid,
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+ }
+ }
+
+ /* FQs that exit OH port */
+ lenp = 0;
+ oh_all_queues = of_get_property(dpa_oh_node,
+ "fsl,qman-frame-queues-egress", &lenp);
+ if (lenp % (2 * sizeof(*oh_all_queues))) {
+ dev_warn(dpa_oh_dev,
+ "Wrong egress queues format for OH node %s referenced from node %s!\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ /* just ignore the last unpaired value */
+ }
+
+ duples_count = lenp / (2 * sizeof(*oh_all_queues));
+ dev_dbg(dpa_oh_dev, "Allocating %d egress frame queues duples\n",
+ duples_count);
+ for (duple_idx = 0; duple_idx < duples_count; duple_idx++) {
+ crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]);
+ crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]);
+
+ fqd = devm_kzalloc(dpa_oh_dev,
+ sizeof(struct fq_duple), GFP_KERNEL);
+ if (!fqd) {
+ dev_err(dpa_oh_dev, "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n",
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ fqd->fqs = devm_kzalloc(dpa_oh_dev,
+ crt_fq_count * sizeof(struct qman_fq),
+ GFP_KERNEL);
+ if (!fqd->fqs) {
+ dev_err(dpa_oh_dev,
+ "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n",
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ for (j = 0; j < crt_fq_count; j++)
+ (fqd->fqs + j)->fqid = crt_fqid_base + j;
+ fqd->fqs_count = crt_fq_count;
+ /* channel ID is specified in another attribute */
+ fqd->channel_id = 0;
+ list_add_tail(&fqd->fq_list, &oh_config->fqs_egress_list);
+
+ /* allocate the queue */
+
+ }
+
+ /* channel_ids for FQs that exit OH port */
+ lenp = 0;
+ channel_ids = of_get_property(dpa_oh_node,
+ "fsl,qman-channel-ids-egress", &lenp);
+
+ channel_ids_count = lenp / (sizeof(*channel_ids));
+ if (channel_ids_count != duples_count) {
+ dev_warn(dpa_oh_dev,
+ "Not all egress queues have a channel id for OH node %s referenced from node %s!\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ /* just ignore the queues that do not have a Channel ID */
+ }
+
+ channel_idx = 0;
+ list_for_each(fq_list, &oh_config->fqs_egress_list) {
+ if (channel_idx + 1 > channel_ids_count)
+ break;
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+ fqd->channel_id =
+ (uint16_t)be32_to_cpu(channel_ids[channel_idx++]);
+ }
+
+ /* create egress queues */
+ list_for_each(fq_list, &oh_config->fqs_egress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+
+ if (fqd->channel_id == 0) {
+ /* missing channel id in dts */
+ continue;
+ }
+
+ for (j = 0; j < fqd->fqs_count; j++) {
+ ret = oh_fq_create(fqd->fqs + j,
+ (fqd->fqs + j)->fqid,
+ fqd->channel_id, 3);
+ if (ret != 0) {
+ dev_err(dpa_oh_dev, "Unable to create egress frame queue %d for OH node %s referenced from node %s!\n",
+ (fqd->fqs + j)->fqid,
+ oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+ }
+ }
+
+ /* Read FQ ids/nums for the DPA OH node */
+ oh_all_queues = of_get_property(dpa_oh_node,
+ "fsl,qman-frame-queues-oh", &lenp);
+ if (oh_all_queues == NULL) {
+ dev_err(dpa_oh_dev,
+ "No frame queues have been defined for OH node %s referenced from node %s\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ /* Check that the OH error and default FQs are there */
+ BUG_ON(lenp % (2 * sizeof(*oh_all_queues)));
+ queues_count = lenp / (2 * sizeof(*oh_all_queues));
+ if (queues_count != 2) {
+ dev_err(dpa_oh_dev,
+ "Error and Default queues must be defined for OH node %s referenced from node %s\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ /* Read the FQIDs defined for this OH port */
+ dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count);
+ fq_idx = 0;
+
+ /* Error FQID - must be present */
+ crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]);
+ crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]);
+ if (crt_fq_count != 1) {
+ dev_err(dpa_oh_dev,
+ "Only 1 Error FQ allowed in OH node %s referenced from node %s (read: %d FQIDs).\n",
+ oh_node->full_name, dpa_oh_node->full_name,
+ crt_fq_count);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+ oh_config->error_fqid = crt_fqid_base;
+ dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n",
+ oh_config->error_fqid, oh_node->full_name);
+
+ /* Default FQID - must be present */
+ crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]);
+ crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]);
+ if (crt_fq_count != 1) {
+ dev_err(dpa_oh_dev,
+ "Only 1 Default FQ allowed in OH node %s referenced from %s (read: %d FQIDs).\n",
+ oh_node->full_name, dpa_oh_node->full_name,
+ crt_fq_count);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+ oh_config->default_fqid = crt_fqid_base;
+ dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n",
+ oh_config->default_fqid, oh_node->full_name);
+
+ /* TX FQID - presence is optional */
+ oh_tx_queues = of_get_property(dpa_oh_node, "fsl,qman-frame-queues-tx",
+ &lenp);
+ if (oh_tx_queues == NULL) {
+ dev_dbg(dpa_oh_dev,
+ "No tx queues have been defined for OH node %s referenced from node %s\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ goto config_port;
+ }
+
+ /* Check that queues-tx has only a base and a count defined */
+ BUG_ON(lenp % (2 * sizeof(*oh_tx_queues)));
+ queues_count = lenp / (2 * sizeof(*oh_tx_queues));
+ if (queues_count != 1) {
+ dev_err(dpa_oh_dev,
+ "TX queues must be defined in only one <base count> tuple for OH node %s referenced from node %s\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ fq_idx = 0;
+ crt_fqid_base = be32_to_cpu(oh_tx_queues[fq_idx++]);
+ crt_fq_count = be32_to_cpu(oh_tx_queues[fq_idx++]);
+ oh_config->egress_cnt = crt_fq_count;
+
+ /* Allocate TX queues */
+ dev_dbg(dpa_oh_dev, "Allocating %d queues for TX...\n", crt_fq_count);
+ oh_config->egress_fqs = devm_kzalloc(dpa_oh_dev,
+ crt_fq_count * sizeof(struct qman_fq), GFP_KERNEL);
+ if (oh_config->egress_fqs == NULL) {
+ dev_err(dpa_oh_dev,
+ "Can't allocate private data for TX queues for OH node %s referenced from node %s!\n",
+ oh_node->full_name, dpa_oh_node->full_name);
+ _errno = -ENOMEM;
+ goto return_kfree;
+ }
+
+ /* Create TX queues */
+ for (i = 0; i < crt_fq_count; i++) {
+ ret = oh_fq_create(oh_config->egress_fqs + i,
+ crt_fqid_base + i, (uint16_t)channel_id, 3);
+ if (ret != 0) {
+ dev_err(dpa_oh_dev,
+ "Unable to create TX frame queue %d for OH node %s referenced from node %s!\n",
+ crt_fqid_base + i, oh_node->full_name,
+ dpa_oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+ }
+
+config_port:
+ /* Get a handle to the fm_port so we can set
+ * its configuration params
+ */
+ oh_config->oh_port = fm_port_bind(oh_dev);
+ if (oh_config->oh_port == NULL) {
+ dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n",
+ oh_node->full_name);
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ oh_set_buffer_layout(oh_config->oh_port, &buf_layout);
+
+ /* read the pool handlers */
+ crt_ext_pools_count = of_count_phandle_with_args(dpa_oh_node,
+ "fsl,bman-buffer-pools", NULL);
+ if (crt_ext_pools_count <= 0) {
+ dev_info(dpa_oh_dev,
+ "OH port %s has no buffer pool. Fragmentation will not be enabled\n",
+ oh_node->full_name);
+ goto init_port;
+ }
+
+ /* used for reading ext_pool_size*/
+ root_node = of_find_node_by_path("/");
+ if (root_node == NULL) {
+ dev_err(dpa_oh_dev, "of_find_node_by_path(/) failed\n");
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ n_size = of_n_size_cells(root_node);
+ of_node_put(root_node);
+
+ dev_dbg(dpa_oh_dev, "OH port number of pools = %d\n",
+ crt_ext_pools_count);
+
+ oh_port_tx_params.num_pools = (uint8_t)crt_ext_pools_count;
+
+ for (i = 0; i < crt_ext_pools_count; i++) {
+ bpool_node = of_parse_phandle(dpa_oh_node,
+ "fsl,bman-buffer-pools", i);
+ if (bpool_node == NULL) {
+ dev_err(dpa_oh_dev, "Invalid Buffer pool node\n");
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ _errno = of_property_read_u32(bpool_node, "fsl,bpid", &bpid);
+ if (_errno) {
+ dev_err(dpa_oh_dev, "Invalid Buffer Pool ID\n");
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ oh_port_tx_params.pool_param[i].id = (uint8_t)bpid;
+ dev_dbg(dpa_oh_dev, "OH port bpool id = %u\n", bpid);
+
+ bpool_cfg = of_get_property(bpool_node,
+ "fsl,bpool-ethernet-cfg", &lenp);
+ if (bpool_cfg == NULL) {
+ dev_err(dpa_oh_dev, "Invalid Buffer pool config params\n");
+ _errno = -EINVAL;
+ goto return_kfree;
+ }
+
+ ext_pool_size = of_read_number(bpool_cfg + n_size, n_size);
+ oh_port_tx_params.pool_param[i].size = (uint16_t)ext_pool_size;
+ dev_dbg(dpa_oh_dev, "OH port bpool size = %u\n",
+ ext_pool_size);
+ of_node_put(bpool_node);
+
+ }
+
+ if (buf_layout.data_align != FRAG_DATA_ALIGN ||
+ buf_layout.manip_extra_space != FRAG_MANIP_SPACE)
+ goto init_port;
+
+ frag_enabled = true;
+ dev_info(dpa_oh_dev, "IP Fragmentation enabled for OH port %d",
+ port_id);
+
+init_port:
+ of_node_put(oh_node);
+ /* Set Tx params */
+ dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params,
+ oh_config->error_fqid, oh_config->default_fqid, (&buf_layout),
+ frag_enabled);
+ /* Set PCD params */
+ oh_port_pcd_params.cba = oh_alloc_pcd_fqids;
+ oh_port_pcd_params.cbf = oh_free_pcd_fqids;
+ oh_port_pcd_params.dev = dpa_oh_dev;
+ fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params);
+
+ dev_set_drvdata(dpa_oh_dev, oh_config);
+
+ /* Enable the OH port */
+ _errno = fm_port_enable(oh_config->oh_port);
+ if (_errno)
+ goto return_kfree;
+
+ dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name);
+
+ /* print of all referenced & created queues */
+ dump_oh_config(dpa_oh_dev, oh_config);
+
+ return 0;
+
+return_kfree:
+ if (bpool_node)
+ of_node_put(bpool_node);
+ if (oh_node)
+ of_node_put(oh_node);
+ if (oh_config && oh_config->egress_fqs)
+ devm_kfree(dpa_oh_dev, oh_config->egress_fqs);
+
+ list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_ingress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+ list_del(fq_list);
+ devm_kfree(dpa_oh_dev, fqd->fqs);
+ devm_kfree(dpa_oh_dev, fqd);
+ }
+
+ list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_egress_list) {
+ fqd = list_entry(fq_list, struct fq_duple, fq_list);
+ list_del(fq_list);
+ devm_kfree(dpa_oh_dev, fqd->fqs);
+ devm_kfree(dpa_oh_dev, fqd);
+ }
+
+ devm_kfree(dpa_oh_dev, oh_config);
+ return _errno;
+}
+
+static int __cold oh_port_remove(struct platform_device *_of_dev)
+{
+ int _errno = 0, i;
+ struct dpa_oh_config_s *oh_config;
+
+ pr_info("Removing OH port...\n");
+
+ oh_config = dev_get_drvdata(&_of_dev->dev);
+ if (oh_config == NULL) {
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): No OH config in device private data!\n",
+ KBUILD_BASENAME".c", __LINE__, __func__);
+ _errno = -ENODEV;
+ goto return_error;
+ }
+
+ if (oh_config->egress_fqs)
+ for (i = 0; i < oh_config->egress_cnt; i++)
+ oh_fq_destroy(oh_config->egress_fqs + i);
+
+ if (oh_config->oh_port == NULL) {
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): No fm port in device private data!\n",
+ KBUILD_BASENAME".c", __LINE__, __func__);
+ _errno = -EINVAL;
+ goto free_egress_fqs;
+ }
+
+ _errno = fm_port_disable(oh_config->oh_port);
+
+free_egress_fqs:
+ if (oh_config->egress_fqs)
+ devm_kfree(&_of_dev->dev, oh_config->egress_fqs);
+ devm_kfree(&_of_dev->dev, oh_config);
+ dev_set_drvdata(&_of_dev->dev, NULL);
+
+return_error:
+ return _errno;
+}
+
+static struct platform_driver oh_port_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = oh_port_match_table,
+ .owner = THIS_MODULE,
+ .pm = OH_PM_OPS,
+ },
+ .probe = oh_port_probe,
+ .remove = oh_port_remove
+};
+
+static int __init __cold oh_port_load(void)
+{
+ int _errno;
+
+ pr_info(OH_MOD_DESCRIPTION "\n");
+
+ _errno = platform_driver_register(&oh_port_driver);
+ if (_errno < 0) {
+ pr_err(KBUILD_MODNAME
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
+ KBUILD_BASENAME".c", __LINE__, __func__, _errno);
+ }
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+ return _errno;
+}
+module_init(oh_port_load);
+
+static void __exit __cold oh_port_unload(void)
+{
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
+ KBUILD_BASENAME".c", __func__);
+
+ platform_driver_unregister(&oh_port_driver);
+
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
+ KBUILD_BASENAME".c", __func__);
+}
+module_exit(oh_port_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h
new file mode 100644
index 000000000000..432ee88d79ca
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h
@@ -0,0 +1,59 @@
+/* Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __OFFLINE_PORT_H
+#define __OFFLINE_PORT_H
+
+struct fm_port;
+struct qman_fq;
+
+/* fqs are defined in duples (base_fq, fq_count) */
+struct fq_duple {
+ struct qman_fq *fqs;
+ int fqs_count;
+ uint16_t channel_id;
+ struct list_head fq_list;
+};
+
+/* OH port configuration */
+struct dpa_oh_config_s {
+ uint32_t error_fqid;
+ uint32_t default_fqid;
+ struct fm_port *oh_port;
+ uint32_t egress_cnt;
+ struct qman_fq *egress_fqs;
+ uint16_t channel;
+
+ struct list_head fqs_ingress_list;
+ struct list_head fqs_egress_list;
+};
+
+#endif /* __OFFLINE_PORT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Kconfig b/drivers/net/ethernet/freescale/sdk_fman/Kconfig
new file mode 100644
index 000000000000..3a61c84251f9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Kconfig
@@ -0,0 +1,162 @@
+menu "Frame Manager support"
+
+menuconfig FSL_SDK_FMAN
+ bool "Freescale Frame Manager (datapath) support - SDK driver"
+ depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && !FSL_FMAN
+ default y
+ ---help---
+ If unsure, say Y.
+
+if FSL_SDK_FMAN
+
+config FSL_SDK_FMAN_TEST
+ bool "FMan test module"
+ default n
+ select FSL_DPAA_HOOKS
+ ---help---
+ This option compiles test code for FMan.
+
+menu "FMAN Processor support"
+choice
+ depends on FSL_SDK_FMAN
+ prompt "Processor Type"
+
+config FMAN_ARM
+ bool "LS1043"
+ depends on ARM64 || ARM
+ ---help---
+ Choose "LS1043" for the ARM platforms:
+ LS1043
+
+config FMAN_P3040_P4080_P5020
+ bool "P3040 P4080 5020"
+
+config FMAN_P1023
+ bool "P1023"
+
+config FMAN_V3H
+ bool "FmanV3H"
+ ---help---
+ Choose "FmanV3H" for Fman rev3H:
+ B4860, T4240, T4160, etc
+
+config FMAN_V3L
+ bool "FmanV3L"
+ ---help---
+ Choose "FmanV3L" for Fman rev3L:
+ T1040, T1042, T1020, T1022, T1023, T1024, etc
+
+endchoice
+endmenu
+
+config FSL_SDK_FMAN_RTC_API
+ bool "FMan RTC (1588 timer) APIs"
+ default n
+ help
+ This option enables RTC (1588 timer) initialization and
+ APIs support. The ptp_qoriq driver is not available if
+ it is selected for RTC (1588 timer). Neither of them
+ were not able to be used together.
+
+config FMAN_MIB_CNT_OVF_IRQ_EN
+ bool "Enable the dTSEC MIB counters overflow interrupt"
+ default n
+ ---help---
+ Enable the dTSEC MIB counters overflow interrupt to get
+ accurate MIB counters values. Enabled it compensates
+ for the counters overflow but reduces performance and
+ triggers error messages in HV setups.
+
+config FSL_FM_MAX_FRAME_SIZE
+ int "Maximum L2 frame size"
+ depends on FSL_SDK_FMAN
+ range 64 9600
+ default "1522"
+ help
+ Configure this in relation to the maximum possible MTU of your
+ network configuration. In particular, one would need to
+ increase this value in order to use jumbo frames.
+ FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS (4 bytes)
+ and one ETH+VLAN header (18 bytes), to a total of 22 bytes in
+ excess of the desired L3 MTU.
+
+ Note that having too large a FSL_FM_MAX_FRAME_SIZE (much larger
+ than the actual MTU) may lead to buffer exhaustion, especially
+ in the case of badly fragmented datagrams on the Rx path.
+ Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the actual
+ MTU will lead to frames being dropped.
+
+ This can be overridden by specifying "fsl_fm_max_frm" in
+ the kernel bootargs:
+ * in Hypervisor-based scenarios, by adding a "chosen" node
+ with the "bootargs" property specifying
+ "fsl_fm_max_frm=<YourValue>";
+ * in non-Hypervisor-based scenarios, via u-boot's env, by
+ modifying the "bootargs" env variable.
+
+config FSL_FM_RX_EXTRA_HEADROOM
+ int "Add extra headroom at beginning of data buffers"
+ depends on FSL_SDK_FMAN
+ range 16 384
+ default "64"
+ help
+ Configure this to tell the Frame Manager to reserve some extra
+ space at the beginning of a data buffer on the receive path,
+ before Internal Context fields are copied. This is in addition
+ to the private data area already reserved for driver internal
+ use. The provided value must be a multiple of 16.
+
+ This setting can be overridden by specifying
+ "fsl_fm_rx_extra_headroom" in the kernel bootargs:
+ * in Hypervisor-based scenarios, by adding a "chosen" node
+ with the "bootargs" property specifying
+ "fsl_fm_rx_extra_headroom=<YourValue>";
+ * in non-Hypervisor-based scenarios, via u-boot's env, by
+ modifying the "bootargs" env variable.
+
+config FMAN_PFC
+ bool "FMan PFC support (EXPERIMENTAL)"
+ depends on ( FMAN_V3H || FMAN_V3L || FMAN_ARM) && FSL_SDK_FMAN
+ default n
+ help
+ This option enables PFC support on FMan v3 ports.
+ Data Center Bridging defines Classes of Service that are
+ flow-controlled using PFC pause frames.
+
+if FMAN_PFC
+config FMAN_PFC_COS_COUNT
+ int "Number of PFC Classes of Service"
+ depends on FMAN_PFC && FSL_SDK_FMAN
+ range 1 4
+ default "3"
+ help
+ The number of Classes of Service controlled by PFC.
+
+config FMAN_PFC_QUANTA_0
+ int "The pause quanta for PFC CoS 0"
+ depends on FMAN_PFC && FSL_SDK_FMAN
+ range 0 65535
+ default "65535"
+
+config FMAN_PFC_QUANTA_1
+ int "The pause quanta for PFC CoS 1"
+ depends on FMAN_PFC && FSL_SDK_FMAN
+ range 0 65535
+ default "65535"
+
+config FMAN_PFC_QUANTA_2
+ int "The pause quanta for PFC CoS 2"
+ depends on FMAN_PFC && FSL_SDK_FMAN
+ range 0 65535
+ default "65535"
+
+config FMAN_PFC_QUANTA_3
+ int "The pause quanta for PFC CoS 3"
+ depends on FMAN_PFC && FSL_SDK_FMAN
+ range 0 65535
+ default "65535"
+endif
+
+endif # FSL_SDK_FMAN
+
+endmenu
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Makefile
new file mode 100644
index 000000000000..25ce7e6a13a0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+#
+obj-y += etc/
+obj-y += Peripherals/FM/
+obj-y += src/
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile
new file mode 100644
index 000000000000..d0e76727b98b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-Hc.o
+
+fsl-ncsw-Hc-objs := hc.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
new file mode 100644
index 000000000000..7f8139ee9a81
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c
@@ -0,0 +1,1236 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "sprint_ext.h"
+#include "string_ext.h"
+
+#include "fm_common.h"
+#include "fm_hc.h"
+
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+#define DEFAULT_dataMemId 0
+
+#define HC_HCOR_OPCODE_PLCR_PRFL 0x0
+#define HC_HCOR_OPCODE_KG_SCM 0x1
+#define HC_HCOR_OPCODE_SYNC 0x2
+#define HC_HCOR_OPCODE_CC 0x3
+#define HC_HCOR_OPCODE_CC_AGE_MASK 0x4
+#define HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT 0x5
+#define HC_HCOR_OPCODE_CC_REASSM_TIMEOUT 0x10
+#define HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION 0x11
+#define HC_HCOR_OPCODE_CC_UPDATE_WITH_AGING 0x13
+#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT 24
+#define HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT 24
+#define HC_HCOR_EXTRA_REG_CC_AGING_ADD 0x80000000
+#define HC_HCOR_EXTRA_REG_CC_AGING_REMOVE 0x40000000
+#define HC_HCOR_EXTRA_REG_CC_AGING_CHANGE_MASK 0xC0000000
+#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_SHIFT 24
+#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_MASK 0x1F000000
+#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT 16
+#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK 0xF
+#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT 24
+#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID 16
+
+#define HC_HCOR_GBL 0x20000000
+
+#define HC_HCOR_KG_SCHEME_COUNTER 0x00000400
+
+#if (DPAA_VERSION == 10)
+#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFF800
+#else
+#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFFE00
+#endif /* (DPAA_VERSION == 10) */
+
+#define SIZE_OF_HC_FRAME_PORT_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdKgPortRegs))
+#define SIZE_OF_HC_FRAME_SCHEME_REGS sizeof(t_HcFrame)
+#define SIZE_OF_HC_FRAME_PROFILES_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdPlcrProfileRegs))
+#define SIZE_OF_HC_FRAME_PROFILE_CNT (sizeof(t_HcFrame)-sizeof(t_FmPcdPlcrProfileRegs)+sizeof(uint32_t))
+#define SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC 16
+
+#define HC_CMD_POOL_SIZE (INTG_MAX_NUM_OF_CORES)
+
+#define BUILD_FD(len) \
+do { \
+ memset(&fmFd, 0, sizeof(t_DpaaFD)); \
+ DPAA_FD_SET_ADDR(&fmFd, p_HcFrame); \
+ DPAA_FD_SET_OFFSET(&fmFd, 0); \
+ DPAA_FD_SET_LENGTH(&fmFd, len); \
+} while (0)
+
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+typedef struct t_FmPcdKgPortRegs {
+ volatile uint32_t spReg;
+ volatile uint32_t cppReg;
+} t_FmPcdKgPortRegs;
+
+typedef struct t_HcFrame {
+ volatile uint32_t opcode;
+ volatile uint32_t actionReg;
+ volatile uint32_t extraReg;
+ volatile uint32_t commandSequence;
+ union {
+ struct fman_kg_scheme_regs schemeRegs;
+ struct fman_kg_scheme_regs schemeRegsWithoutCounter;
+ t_FmPcdPlcrProfileRegs profileRegs;
+ volatile uint32_t singleRegForWrite; /* for writing SP, CPP, profile counter */
+ t_FmPcdKgPortRegs portRegsForRead;
+ volatile uint32_t clsPlanEntries[CLS_PLAN_NUM_PER_GRP];
+ t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeout;
+ t_FmPcdCcReassmTimeoutParams ccReassmTimeout;
+ } hcSpecificData;
+} t_HcFrame;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+typedef struct t_FmHc {
+ t_Handle h_FmPcd;
+ t_Handle h_HcPortDev;
+ t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< A callback for enqueuing frames to the QM */
+ t_Handle h_QmArg; /**< A handle to the QM module */
+ uint8_t dataMemId; /**< Memory partition ID for data buffers */
+
+ uint32_t seqNum[HC_CMD_POOL_SIZE]; /* FIFO of seqNum to use when
+ taking buffer */
+ uint32_t nextSeqNumLocation; /* seqNum location in seqNum[] for next buffer */
+ volatile bool enqueued[HC_CMD_POOL_SIZE]; /* HC is active - frame is enqueued
+ and not confirmed yet */
+ t_HcFrame *p_Frm[HC_CMD_POOL_SIZE];
+} t_FmHc;
+
+
+static t_Error FillBufPool(t_FmHc *p_FmHc)
+{
+ uint32_t i;
+
+ ASSERT_COND(p_FmHc);
+
+ for (i = 0; i < HC_CMD_POOL_SIZE; i++)
+ {
+#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
+ p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + (16 - (sizeof(t_FmHc) % 16))),
+ p_FmHc->dataMemId,
+ 16);
+#else
+ p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart(sizeof(t_HcFrame),
+ p_FmHc->dataMemId,
+ 16);
+#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
+ if (!p_FmHc->p_Frm[i])
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM HC frames!"));
+ }
+
+ /* Initialize FIFO of seqNum to use during GetBuf */
+ for (i = 0; i < HC_CMD_POOL_SIZE; i++)
+ {
+ p_FmHc->seqNum[i] = i;
+ }
+ p_FmHc->nextSeqNumLocation = 0;
+
+ return E_OK;
+}
+
+static __inline__ t_HcFrame * GetBuf(t_FmHc *p_FmHc, uint32_t *p_SeqNum)
+{
+ uint32_t intFlags;
+
+ ASSERT_COND(p_FmHc);
+
+ intFlags = FmPcdLock(p_FmHc->h_FmPcd);
+
+ if (p_FmHc->nextSeqNumLocation == HC_CMD_POOL_SIZE)
+ {
+ /* No more buffers */
+ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
+ return NULL;
+ }
+
+ *p_SeqNum = p_FmHc->seqNum[p_FmHc->nextSeqNumLocation];
+ p_FmHc->nextSeqNumLocation++;
+
+ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
+ return p_FmHc->p_Frm[*p_SeqNum];
+}
+
+static __inline__ void PutBuf(t_FmHc *p_FmHc, t_HcFrame *p_Buf, uint32_t seqNum)
+{
+ uint32_t intFlags;
+
+ UNUSED(p_Buf);
+
+ intFlags = FmPcdLock(p_FmHc->h_FmPcd);
+ ASSERT_COND(p_FmHc->nextSeqNumLocation);
+ p_FmHc->nextSeqNumLocation--;
+ p_FmHc->seqNum[p_FmHc->nextSeqNumLocation] = seqNum;
+ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
+}
+
+static __inline__ t_Error EnQFrm(t_FmHc *p_FmHc, t_DpaaFD *p_FmFd, uint32_t seqNum)
+{
+ t_Error err = E_OK;
+ uint32_t intFlags;
+ uint32_t timeout=100;
+
+ intFlags = FmPcdLock(p_FmHc->h_FmPcd);
+ ASSERT_COND(!p_FmHc->enqueued[seqNum]);
+ p_FmHc->enqueued[seqNum] = TRUE;
+ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
+ DBG(TRACE, ("Send Hc, SeqNum %d, buff@0x%x, fd offset 0x%x",
+ seqNum,
+ DPAA_FD_GET_ADDR(p_FmFd),
+ DPAA_FD_GET_OFFSET(p_FmFd)));
+ err = p_FmHc->f_QmEnqueue(p_FmHc->h_QmArg, (void *)p_FmFd);
+ if (err)
+ RETURN_ERROR(MINOR, err, ("HC enqueue failed"));
+
+ while (p_FmHc->enqueued[seqNum] && --timeout)
+ XX_UDelay(100);
+
+ if (!timeout)
+ RETURN_ERROR(MINOR, E_TIMEOUT, ("HC Callback, timeout exceeded"));
+
+ return err;
+}
+
+
+t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams)
+{
+ t_FmHc *p_FmHc;
+ t_FmPortParams fmPortParam;
+ t_Error err;
+
+ p_FmHc = (t_FmHc *)XX_Malloc(sizeof(t_FmHc));
+ if (!p_FmHc)
+ {
+ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC obj"));
+ return NULL;
+ }
+ memset(p_FmHc,0,sizeof(t_FmHc));
+
+ p_FmHc->h_FmPcd = p_FmHcParams->h_FmPcd;
+ p_FmHc->f_QmEnqueue = p_FmHcParams->params.f_QmEnqueue;
+ p_FmHc->h_QmArg = p_FmHcParams->params.h_QmArg;
+ p_FmHc->dataMemId = DEFAULT_dataMemId;
+
+ err = FillBufPool(p_FmHc);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ FmHcFree(p_FmHc);
+ return NULL;
+ }
+
+ if (!FmIsMaster(p_FmHcParams->h_Fm))
+ return (t_Handle)p_FmHc;
+
+ memset(&fmPortParam, 0, sizeof(fmPortParam));
+ fmPortParam.baseAddr = p_FmHcParams->params.portBaseAddr;
+ fmPortParam.portType = e_FM_PORT_TYPE_OH_HOST_COMMAND;
+ fmPortParam.portId = p_FmHcParams->params.portId;
+ fmPortParam.liodnBase = p_FmHcParams->params.liodnBase;
+ fmPortParam.h_Fm = p_FmHcParams->h_Fm;
+
+ fmPortParam.specificParams.nonRxParams.errFqid = p_FmHcParams->params.errFqid;
+ fmPortParam.specificParams.nonRxParams.dfltFqid = p_FmHcParams->params.confFqid;
+ fmPortParam.specificParams.nonRxParams.qmChannel = p_FmHcParams->params.qmChannel;
+
+ p_FmHc->h_HcPortDev = FM_PORT_Config(&fmPortParam);
+ if (!p_FmHc->h_HcPortDev)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM HC port!"));
+ XX_Free(p_FmHc);
+ return NULL;
+ }
+
+ err = FM_PORT_ConfigMaxFrameLength(p_FmHc->h_HcPortDev,
+ (uint16_t)sizeof(t_HcFrame));
+
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, ("FM HC port init!"));
+ FmHcFree(p_FmHc);
+ return NULL;
+ }
+
+ /* final init */
+ err = FM_PORT_Init(p_FmHc->h_HcPortDev);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, ("FM HC port init!"));
+ FmHcFree(p_FmHc);
+ return NULL;
+ }
+
+ err = FM_PORT_Enable(p_FmHc->h_HcPortDev);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, ("FM HC port enable!"));
+ FmHcFree(p_FmHc);
+ return NULL;
+ }
+
+ return (t_Handle)p_FmHc;
+}
+
+void FmHcFree(t_Handle h_FmHc)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ int i;
+
+ if (!p_FmHc)
+ return;
+
+ for (i=0; i<HC_CMD_POOL_SIZE; i++)
+ if (p_FmHc->p_Frm[i])
+ XX_FreeSmart(p_FmHc->p_Frm[i]);
+ else
+ break;
+
+ if (p_FmHc->h_HcPortDev)
+ FM_PORT_Free(p_FmHc->h_HcPortDev);
+
+ XX_Free(p_FmHc);
+}
+
+/*****************************************************************************/
+t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc,
+ uint8_t memId)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ int i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE);
+
+ p_FmHc->dataMemId = memId;
+
+ for (i=0; i<HC_CMD_POOL_SIZE; i++)
+ if (p_FmHc->p_Frm[i])
+ XX_FreeSmart(p_FmHc->p_Frm[i]);
+
+ return FillBufPool(p_FmHc);
+}
+
+void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_FmHc);
+
+ intFlags = FmPcdLock(p_FmHc->h_FmPcd);
+ p_HcFrame = (t_HcFrame *)PTR_MOVE(DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd));
+
+ DBG(TRACE, ("Hc Conf, SeqNum %d, FD@0x%x, fd offset 0x%x",
+ p_HcFrame->commandSequence, DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd)));
+
+ if (!(p_FmHc->enqueued[p_HcFrame->commandSequence]))
+ REPORT_ERROR(MINOR, E_INVALID_FRAME, ("Not an Host-Command frame received!"));
+ else
+ p_FmHc->enqueued[p_HcFrame->commandSequence] = FALSE;
+ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags);
+}
+
+t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc,
+ t_Handle h_Scheme,
+ struct fman_kg_scheme_regs *p_SchemeRegs,
+ bool updateCounter)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint8_t physicalSchemeId;
+ uint32_t seqNum;
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, updateCounter);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ memcpy(&p_HcFrame->hcSpecificData.schemeRegs, p_SchemeRegs, sizeof(struct fman_kg_scheme_regs));
+ if (!updateCounter)
+ {
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_dv0 = p_SchemeRegs->kgse_dv0;
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_dv1 = p_SchemeRegs->kgse_dv1;
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_ccbs = p_SchemeRegs->kgse_ccbs;
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_mv = p_SchemeRegs->kgse_mv;
+ }
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
+ uint32_t seqNum;
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ memset(&p_HcFrame->hcSpecificData.schemeRegs, 0, sizeof(struct fman_kg_scheme_regs));
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint8_t relativeSchemeId;
+ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
+ uint32_t tmpReg32 = 0;
+ uint32_t seqNum;
+
+ /* Scheme is locked by calling routine */
+ /* WARNING - this lock will not be efficient if other HC routine will attempt to change
+ * "kgse_mode" or "kgse_om" without locking scheme !
+ */
+
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
+ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ if (!FmPcdKgGetRequiredActionFlag(p_FmHc->h_FmPcd, relativeSchemeId) ||
+ !(FmPcdKgGetRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId) & requiredAction))
+ {
+ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) &&
+ (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_PLCR))
+ {
+ if ((FmPcdKgIsDirectPlcr(p_FmHc->h_FmPcd, relativeSchemeId) == FALSE) ||
+ (FmPcdKgIsDistrOnPlcrProfile(p_FmHc->h_FmPcd, relativeSchemeId) == TRUE))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared"));
+ err = FmPcdPlcrCcGetSetParams(p_FmHc->h_FmPcd, FmPcdKgGetRelativeProfileId(p_FmHc->h_FmPcd, relativeSchemeId), requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ else /* From here we deal with KG-Schemes only */
+ {
+ /* Pre change general code */
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ p_HcFrame->commandSequence = seqNum;
+ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ /* specific change */
+ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) &&
+ ((FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_DONE) &&
+ (FmPcdKgGetDoneAction(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_ENQ_FRAME)))
+ {
+ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
+ ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+ }
+
+ if ((requiredAction & UPDATE_KG_NIA_CC_WA) &&
+ (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_CC))
+ {
+ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
+ ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
+ tmpReg32 &= ~NIA_FM_CTL_AC_CC;
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_FM_CTL_AC_PRE_CC;
+ }
+
+ if (requiredAction & UPDATE_KG_OPT_MODE)
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_om = value;
+
+ if (requiredAction & UPDATE_KG_NIA)
+ {
+ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode;
+ tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK);
+ tmpReg32 |= value;
+ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32;
+ }
+
+ /* Post change general code */
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+
+ BUILD_FD(sizeof(t_HcFrame));
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+ }
+
+ return E_OK;
+}
+
+uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint32_t retVal;
+ uint8_t relativeSchemeId;
+ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
+ uint32_t seqNum;
+
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
+ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+ return 0;
+ }
+
+ /* first read scheme and check that it is valid */
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ {
+ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ return 0;
+ }
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+ if (err != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return 0;
+ }
+
+ if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode))
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid"));
+ return 0;
+ }
+
+ retVal = p_HcFrame->hcSpecificData.schemeRegs.kgse_spc;
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ return retVal;
+}
+
+t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint8_t relativeSchemeId, physicalSchemeId;
+ uint32_t seqNum;
+
+ physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme);
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId);
+ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ /* first read scheme and check that it is valid */
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_COUNTER;
+ /* write counter */
+ p_HcFrame->hcSpecificData.singleRegForWrite = value;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return err;
+}
+
+t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint8_t i, idx;
+ uint32_t seqNum;
+ const void *src;
+ void *dest;
+ t_Error err = E_OK;
+
+ ASSERT_COND(p_FmHc);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ for (i = p_Set->baseEntry; i < (p_Set->baseEntry+p_Set->numOfClsPlanEntries); i+=8)
+ {
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP));
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+
+ idx = (uint8_t)(i - p_Set->baseEntry);
+ ASSERT_COND(idx < FM_PCD_MAX_NUM_OF_CLS_PLANS);
+ dest = (void *)&p_HcFrame->hcSpecificData.clsPlanEntries;
+ src = &p_Set->vectors[idx];
+ memcpy(dest, src, CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t));
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+ }
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return err;
+}
+
+t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t grpId)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet;
+
+ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
+ if (!p_ClsPlanSet)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
+
+ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
+
+ p_ClsPlanSet->baseEntry = FmPcdKgGetClsPlanGrpBase(p_FmHc->h_FmPcd, grpId);
+ p_ClsPlanSet->numOfClsPlanEntries = FmPcdKgGetClsPlanGrpSize(p_FmHc->h_FmPcd, grpId);
+ ASSERT_COND(p_ClsPlanSet->numOfClsPlanEntries <= FM_PCD_MAX_NUM_OF_CLS_PLANS);
+
+ if (FmHcPcdKgSetClsPlan(p_FmHc, p_ClsPlanSet) != E_OK)
+ {
+ XX_Free(p_ClsPlanSet);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ }
+
+ XX_Free(p_ClsPlanSet);
+ FmPcdKgDestroyClsPlanGrp(p_FmHc->h_FmPcd, grpId);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams )
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT);
+ memcpy(&p_HcFrame->hcSpecificData.ccCapwapReassmTimeout, p_CcCapwapReassmTimeoutParams, sizeof(t_FmPcdCcCapwapReassmTimeoutParams));
+ p_HcFrame->commandSequence = seqNum;
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return err;
+}
+
+t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION);
+ p_HcFrame->actionReg = (uint32_t)(((fill == TRUE) ? 0 : 1) << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT);
+ p_HcFrame->actionReg |= p_FmPcdCcFragScratchPoolCmdParams->bufferPoolId << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID;
+ if (fill == TRUE)
+ {
+ p_HcFrame->extraReg = p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers;
+ }
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers = p_HcFrame->extraReg;
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return E_OK;
+}
+
+t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_REASSM_TIMEOUT);
+ p_HcFrame->actionReg = (uint32_t)((p_CcReassmTimeoutParams->activate ? 0 : 1) << HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT);
+ p_HcFrame->extraReg = (p_CcReassmTimeoutParams->tsbs << HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT) | p_CcReassmTimeoutParams->iprcpt;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ *p_Result = (uint8_t)
+ ((p_HcFrame->actionReg >> HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT) & HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return E_OK;
+}
+
+t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err;
+ uint32_t tmpReg32 = 0;
+ uint32_t requiredActionTmp, requiredActionFlag;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
+
+ /* Profile is locked by calling routine */
+ /* WARNING - this lock will not be efficient if other HC routine will attempt to change
+ * "fmpl_pegnia" "fmpl_peynia" or "fmpl_pernia" without locking Profile !
+ */
+
+ requiredActionTmp = FmPcdPlcrGetRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId);
+ requiredActionFlag = FmPcdPlcrGetRequiredActionFlag(p_FmHc->h_FmPcd, absoluteProfileId);
+
+ if (!requiredActionFlag || !(requiredActionTmp & requiredAction))
+ {
+ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ {
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ /* first read scheme and check that it is valid */
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegnia;
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
+ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(TRUE, FALSE, FALSE);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_peynia;
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
+ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, TRUE, FALSE);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pernia;
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
+ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, FALSE, TRUE);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ }
+ }
+
+ return E_OK;
+}
+
+t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_Error err = E_OK;
+ uint16_t profileIndx;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint32_t seqNum;
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+
+ profileIndx = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
+
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx);
+ p_HcFrame->extraReg = 0x00008000;
+ memcpy(&p_HcFrame->hcSpecificData.profileRegs, p_PlcrRegs, sizeof(t_FmPcdPlcrProfileRegs));
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint32_t seqNum;
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
+ p_HcFrame->actionReg |= 0x00008000;
+ p_HcFrame->extraReg = 0x00008000;
+ memset(&p_HcFrame->hcSpecificData.profileRegs, 0, sizeof(t_FmPcdPlcrProfileRegs));
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value)
+{
+
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
+ t_Error err = E_OK;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint32_t seqNum;
+
+ /* first read scheme and check that it is valid */
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId);
+ p_HcFrame->actionReg |= FmPcdPlcrBuildCounterProfileReg(counter);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->hcSpecificData.singleRegForWrite = value;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT);
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
+ t_Error err;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ uint32_t retVal = 0;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0);
+
+ /* first read scheme and check that it is valid */
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ {
+ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ return 0;
+ }
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL);
+ p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId);
+ p_HcFrame->extraReg = 0x00008000;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+ if (err != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return 0;
+ }
+
+ switch (counter)
+ {
+ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
+ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegpc;
+ break;
+ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
+ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_peypc;
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
+ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perpc;
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
+ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perypc;
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
+ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perrpc;
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ return retVal;
+}
+
+t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err = E_OK;
+ uint32_t seqNum;
+
+ ASSERT_COND(p_FmHc);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ /* first read SP register */
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_PORT_REGS);
+
+ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK)
+ {
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ /* spReg is the first reg, so we can use it both for read and for write */
+ if (add)
+ p_HcFrame->hcSpecificData.portRegsForRead.spReg |= spReg;
+ else
+ p_HcFrame->hcSpecificData.portRegsForRead.spReg &= ~spReg;
+
+ p_HcFrame->actionReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId);
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err = E_OK;
+ uint32_t seqNum;
+
+ ASSERT_COND(p_FmHc);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ /* first read SP register */
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM);
+ p_HcFrame->actionReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId);
+ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK;
+ p_HcFrame->hcSpecificData.singleRegForWrite = cppReg;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err = E_OK;
+ uint32_t seqNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC);
+ p_HcFrame->actionReg = newAdAddrOffset;
+ p_HcFrame->actionReg |= 0xc0000000;
+ p_HcFrame->extraReg = oldAdAddrOffset;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC);
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmHcPcdSync(t_Handle h_FmHc)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ t_HcFrame *p_HcFrame;
+ t_DpaaFD fmFd;
+ t_Error err = E_OK;
+ uint32_t seqNum;
+
+ ASSERT_COND(p_FmHc);
+
+ p_HcFrame = GetBuf(p_FmHc, &seqNum);
+ if (!p_HcFrame)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object"));
+ memset(p_HcFrame, 0, sizeof(t_HcFrame));
+ /* first read SP register */
+ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_SYNC);
+ p_HcFrame->actionReg = 0;
+ p_HcFrame->extraReg = 0;
+ p_HcFrame->commandSequence = seqNum;
+
+ BUILD_FD(sizeof(t_HcFrame));
+
+ err = EnQFrm(p_FmHc, &fmFd, seqNum);
+
+ PutBuf(p_FmHc, p_HcFrame, seqNum);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Handle FmHcGetPort(t_Handle h_FmHc)
+{
+ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc;
+ return p_FmHc->h_HcPortDev;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile
new file mode 100644
index 000000000000..f6b090daa268
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile
@@ -0,0 +1,28 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-MAC.o
+
+fsl-ncsw-MAC-objs := dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o \
+ fman_dtsec.o fman_dtsec_mii_acc.o fman_memac.o \
+ fman_tgec.o fman_crc32.o
+
+ifeq ($(CONFIG_FMAN_V3H),y)
+fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o
+endif
+ifeq ($(CONFIG_FMAN_V3L),y)
+fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o
+endif
+ifeq ($(CONFIG_FMAN_ARM),y)
+fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o
+endif
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
new file mode 100644
index 000000000000..071fa4627f17
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c
@@ -0,0 +1,1504 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File dtsec.c
+
+ @Description FMan dTSEC driver
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "xx_ext.h"
+#include "endian_ext.h"
+#include "debug_ext.h"
+#include "crc_mac_addr_ext.h"
+
+#include "fm_common.h"
+#include "dtsec.h"
+#include "fsl_fman_dtsec.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+/*****************************************************************************/
+/* Internal routines */
+/*****************************************************************************/
+
+static t_Error CheckInitParameters(t_Dtsec *p_Dtsec)
+{
+ if (ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds"));
+ if (p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs"));
+ if (p_Dtsec->addr == 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address"));
+ if ((ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_1000) &&
+ p_Dtsec->p_DtsecDriverParam->halfdup_on)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex"));
+ if (p_Dtsec->p_DtsecDriverParam->halfdup_on && (p_Dtsec->p_DtsecDriverParam)->loopback)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode"));
+#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001
+ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev <= 6) /* fixed for rev3 */
+ if (p_Dtsec->p_DtsecDriverParam->rx_preamble)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn"));
+#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */
+ if (((p_Dtsec->p_DtsecDriverParam)->tx_preamble || (p_Dtsec->p_DtsecDriverParam)->rx_preamble) &&( (p_Dtsec->p_DtsecDriverParam)->preamble_len != 0x7))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes"));
+ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_on &&
+ (p_Dtsec->p_DtsecDriverParam->tx_time_stamp_en || p_Dtsec->p_DtsecDriverParam->rx_time_stamp_en))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable"));
+ if ((p_Dtsec->p_DtsecDriverParam)->rx_flow && (p_Dtsec->p_DtsecDriverParam)->rx_ctrl_acc )
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept "));
+ if ((p_Dtsec->p_DtsecDriverParam)->rx_prepend > MAX_PACKET_ALIGNMENT)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT ));
+ if (((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg1 > MAX_INTER_PACKET_GAP) ||
+ ((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg2 > MAX_INTER_PACKET_GAP) ||
+ ((p_Dtsec->p_DtsecDriverParam)->back_to_back_ipg > MAX_INTER_PACKET_GAP))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP ));
+ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_alt_backoff_val > MAX_INTER_PALTERNATE_BEB)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB ));
+ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_retransmit > MAX_RETRANSMISSION)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION ));
+ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_coll_window > MAX_COLLISION_WINDOW)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW ));
+
+ /* If Auto negotiation process is disabled, need to */
+ /* Set up the PHY using the MII Management Interface */
+ if (p_Dtsec->p_DtsecDriverParam->tbipa > MAX_PHYS)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS));
+ if (!p_Dtsec->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception"));
+ if (!p_Dtsec->f_Event)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event"));
+
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (p_Dtsec->p_DtsecDriverParam->rx_len_check)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
+{
+ uint32_t crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(ethAddr, crc);
+
+ crc = GetMirror32(crc);
+
+ return crc;
+}
+
+/* ......................................................................... */
+
+static void UpdateStatistics(t_Dtsec *p_Dtsec)
+{
+ uint32_t car1, car2;
+
+ fman_dtsec_get_clear_carry_regs(p_Dtsec->p_MemMap, &car1, &car2);
+
+ if (car1)
+ {
+ if (car1 & CAR1_TR64)
+ p_Dtsec->internalStatistics.tr64 += VAL22BIT;
+ if (car1 & CAR1_TR127)
+ p_Dtsec->internalStatistics.tr127 += VAL22BIT;
+ if (car1 & CAR1_TR255)
+ p_Dtsec->internalStatistics.tr255 += VAL22BIT;
+ if (car1 & CAR1_TR511)
+ p_Dtsec->internalStatistics.tr511 += VAL22BIT;
+ if (car1 & CAR1_TRK1)
+ p_Dtsec->internalStatistics.tr1k += VAL22BIT;
+ if (car1 & CAR1_TRMAX)
+ p_Dtsec->internalStatistics.trmax += VAL22BIT;
+ if (car1 & CAR1_TRMGV)
+ p_Dtsec->internalStatistics.trmgv += VAL22BIT;
+ if (car1 & CAR1_RBYT)
+ p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT;
+ if (car1 & CAR1_RPKT)
+ p_Dtsec->internalStatistics.rpkt += VAL22BIT;
+ if (car1 & CAR1_RMCA)
+ p_Dtsec->internalStatistics.rmca += VAL22BIT;
+ if (car1 & CAR1_RBCA)
+ p_Dtsec->internalStatistics.rbca += VAL22BIT;
+ if (car1 & CAR1_RXPF)
+ p_Dtsec->internalStatistics.rxpf += VAL16BIT;
+ if (car1 & CAR1_RALN)
+ p_Dtsec->internalStatistics.raln += VAL16BIT;
+ if (car1 & CAR1_RFLR)
+ p_Dtsec->internalStatistics.rflr += VAL16BIT;
+ if (car1 & CAR1_RCDE)
+ p_Dtsec->internalStatistics.rcde += VAL16BIT;
+ if (car1 & CAR1_RCSE)
+ p_Dtsec->internalStatistics.rcse += VAL16BIT;
+ if (car1 & CAR1_RUND)
+ p_Dtsec->internalStatistics.rund += VAL16BIT;
+ if (car1 & CAR1_ROVR)
+ p_Dtsec->internalStatistics.rovr += VAL16BIT;
+ if (car1 & CAR1_RFRG)
+ p_Dtsec->internalStatistics.rfrg += VAL16BIT;
+ if (car1 & CAR1_RJBR)
+ p_Dtsec->internalStatistics.rjbr += VAL16BIT;
+ if (car1 & CAR1_RDRP)
+ p_Dtsec->internalStatistics.rdrp += VAL16BIT;
+ }
+ if (car2)
+ {
+ if (car2 & CAR2_TFCS)
+ p_Dtsec->internalStatistics.tfcs += VAL12BIT;
+ if (car2 & CAR2_TBYT)
+ p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT;
+ if (car2 & CAR2_TPKT)
+ p_Dtsec->internalStatistics.tpkt += VAL22BIT;
+ if (car2 & CAR2_TMCA)
+ p_Dtsec->internalStatistics.tmca += VAL22BIT;
+ if (car2 & CAR2_TBCA)
+ p_Dtsec->internalStatistics.tbca += VAL22BIT;
+ if (car2 & CAR2_TXPF)
+ p_Dtsec->internalStatistics.txpf += VAL16BIT;
+ if (car2 & CAR2_TDRP)
+ p_Dtsec->internalStatistics.tdrp += VAL16BIT;
+ }
+}
+
+/* .............................................................................. */
+
+static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE, 0);
+
+ return fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap);
+}
+
+/* .............................................................................. */
+
+static void DtsecIsr(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint32_t event;
+ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap;
+
+ /* do not handle MDIO events */
+ event = fman_dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN)));
+
+ event &= fman_dtsec_get_interrupt_mask(p_DtsecMemMap);
+
+ fman_dtsec_ack_event(p_DtsecMemMap, event);
+
+ if (event & DTSEC_IMASK_BREN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX);
+ if (event & DTSEC_IMASK_RXCEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL);
+ if (event & DTSEC_IMASK_MSROEN)
+ UpdateStatistics(p_Dtsec);
+ if (event & DTSEC_IMASK_GTSCEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET);
+ if (event & DTSEC_IMASK_BTEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX);
+ if (event & DTSEC_IMASK_TXCEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL);
+ if (event & DTSEC_IMASK_TXEEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR);
+ if (event & DTSEC_IMASK_LCEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL);
+ if (event & DTSEC_IMASK_CRLEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT);
+ if (event & DTSEC_IMASK_XFUNEN)
+ {
+#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6
+ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+ {
+ uint32_t tpkt1, tmpReg1, tpkt2, tmpReg2, i;
+ /* a. Write 0x00E0_0C00 to DTSEC_ID */
+ /* This is a read only regidter */
+
+ /* b. Read and save the value of TPKT */
+ tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt);
+
+ /* c. Read the register at dTSEC address offset 0x32C */
+ tmpReg1 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c));
+
+ /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */
+ if ((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F))
+ {
+ /* If they are not equal, save the value of this register and wait for at least
+ * MAXFRM*16 ns */
+ XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1)));
+ }
+
+ /* e. Read and save TPKT again and read the register at dTSEC address offset
+ 0x32C again*/
+ tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt);
+ tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c));
+
+ /* f. Compare the value of TPKT saved in step b to value read in step e. Also
+ compare bits [9:15] of the register at offset 0x32C saved in step d to the value
+ of bits [9:15] saved in step e. If the two registers values are unchanged, then
+ the transmit portion of the dTSEC controller is locked up and the user should
+ proceed to the recover sequence. */
+ if ((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000)))
+ {
+ /* recover sequence */
+
+ /* a.Write a 1 to RCTRL[GRS]*/
+
+ WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS);
+
+ /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */
+ for (i = 0 ; i < 100 ; i++ )
+ {
+ if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN)
+ break;
+ XX_UDelay(1);
+ }
+ if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN)
+ WRITE_UINT32(p_DtsecMemMap->ievent, DTSEC_IMASK_GRSCEN);
+ else
+ DBG(INFO,("Rx lockup due to dTSEC Tx lockup"));
+
+ /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/
+ FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId);
+
+ /* d.Wait 4 Tx clocks (32 ns) */
+ XX_UDelay(1);
+
+ /* e.Write a 0 to bit n of FM_RSTC. */
+ /* cleared by FMAN */
+ }
+ }
+#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */
+
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN);
+ }
+ if (event & DTSEC_IMASK_MAGEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT);
+ if (event & DTSEC_IMASK_GRSCEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET);
+ if (event & DTSEC_IMASK_TDPEEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR);
+ if (event & DTSEC_IMASK_RDPEEN)
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR);
+
+ /* - masked interrupts */
+ ASSERT_COND(!(event & DTSEC_IMASK_ABRTEN));
+ ASSERT_COND(!(event & DTSEC_IMASK_IFERREN));
+}
+
+static void DtsecMdioIsr(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint32_t event;
+ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap;
+
+ event = GET_UINT32(p_DtsecMemMap->ievent);
+ /* handle only MDIO events */
+ event &= (DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN);
+ if (event)
+ {
+ event &= GET_UINT32(p_DtsecMemMap->imask);
+
+ WRITE_UINT32(p_DtsecMemMap->ievent, event);
+
+ if (event & DTSEC_IMASK_MMRDEN)
+ p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET);
+ if (event & DTSEC_IMASK_MMWREN)
+ p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET);
+ }
+}
+
+static void Dtsec1588Isr(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint32_t event;
+ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap;
+
+ if (p_Dtsec->ptpTsuEnabled)
+ {
+ event = fman_dtsec_check_and_clear_tmr_event(p_DtsecMemMap);
+
+ if (event)
+ {
+ ASSERT_COND(event & TMR_PEVENT_TSRE);
+ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR);
+ }
+ }
+}
+
+/* ........................................................................... */
+
+static void FreeInitResources(t_Dtsec *p_Dtsec)
+{
+ if (p_Dtsec->mdioIrq != NO_IRQ)
+ {
+ XX_DisableIntr(p_Dtsec->mdioIrq);
+ XX_FreeIntr(p_Dtsec->mdioIrq);
+ }
+ FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR);
+ FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL);
+
+ /* release the driver's group hash table */
+ FreeHashTable(p_Dtsec->p_MulticastAddrHash);
+ p_Dtsec->p_MulticastAddrHash = NULL;
+
+ /* release the driver's individual hash table */
+ FreeHashTable(p_Dtsec->p_UnicastAddrHash);
+ p_Dtsec->p_UnicastAddrHash = NULL;
+}
+
+/* ........................................................................... */
+
+static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode)
+{
+ struct dtsec_regs *p_MemMap;
+ int pollTimeout = 0;
+
+ ASSERT_COND(p_Dtsec);
+
+ p_MemMap = p_Dtsec->p_MemMap;
+ ASSERT_COND(p_MemMap);
+
+ /* Assert the graceful transmit stop bit */
+ if (mode & e_COMM_MODE_RX)
+ {
+ fman_dtsec_stop_rx(p_MemMap);
+
+#ifdef FM_GRS_ERRATA_DTSEC_A002
+ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+ XX_UDelay(100);
+#else /* FM_GRS_ERRATA_DTSEC_A002 */
+#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
+ XX_UDelay(10);
+#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */
+#endif /* FM_GRS_ERRATA_DTSEC_A002 */
+ }
+
+ if (mode & e_COMM_MODE_TX)
+ {
+#if defined(FM_GTS_ERRATA_DTSEC_A004)
+ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+ DBG(INFO, ("GTS not supported due to DTSEC_A004 errata."));
+#else /* not defined(FM_GTS_ERRATA_DTSEC_A004) */
+
+ fman_dtsec_stop_tx(p_MemMap);
+
+#if defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012)
+ XX_UDelay(10);
+#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 || FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 */
+#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) */
+ }
+
+ /* Poll GRSC/GTSC bits in IEVENT register until both are set */
+#if defined(FM_GRS_ERRATA_DTSEC_A002) || defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) || defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839)
+ XX_UDelay(10);
+#else
+ while (fman_dtsec_get_event(p_MemMap, DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN) != (DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN))
+ {
+ if (pollTimeout == 100)
+ break;
+ XX_UDelay(1);
+ pollTimeout++;
+ }
+#endif
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode)
+{
+ struct dtsec_regs *p_MemMap;
+
+ ASSERT_COND(p_Dtsec);
+ p_MemMap = p_Dtsec->p_MemMap;
+ ASSERT_COND(p_MemMap);
+
+ /* clear the graceful receive stop bit */
+ if (mode & e_COMM_MODE_TX)
+ fman_dtsec_start_tx(p_MemMap);
+
+ if (mode & e_COMM_MODE_RX)
+ fman_dtsec_start_rx(p_MemMap);
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* dTSEC Configs modification functions */
+/*****************************************************************************/
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal)
+{
+
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->loopback = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->maximum_frame = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->tx_pad_crc = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->halfdup_on = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigTbiPhyAddr(t_Handle h_Dtsec, uint8_t newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->tbi_phy_addr = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->p_DtsecDriverParam->rx_len_check = newVal;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR)
+ {
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Dtsec->exceptions |= bitMask;
+ else
+ p_Dtsec->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+ }
+ else
+ {
+ if (!p_Dtsec->ptpTsuEnabled)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only"));
+
+ if (enable)
+ p_Dtsec->enTsuErrExeption = TRUE;
+ else
+ p_Dtsec->enTsuErrExeption = FALSE;
+ }
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* dTSEC Run Time API functions */
+/*****************************************************************************/
+
+/* .............................................................................. */
+
+static t_Error DtsecEnable(t_Handle h_Dtsec, e_CommMode mode)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ fman_dtsec_enable(p_Dtsec->p_MemMap,
+ (bool)!!(mode & e_COMM_MODE_RX),
+ (bool)!!(mode & e_COMM_MODE_TX));
+
+ GracefulRestart(p_Dtsec, mode);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ GracefulStop(p_Dtsec, mode);
+
+ fman_dtsec_disable(p_Dtsec->p_MemMap,
+ (bool)!!(mode & e_COMM_MODE_RX),
+ (bool)!!(mode & e_COMM_MODE_TX));
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecSetTxPauseFrames(t_Handle h_Dtsec,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ UNUSED(priority);UNUSED(threshTime);
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003
+ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+ if (0 < pauseTime && pauseTime <= 320)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE,
+ ("This pause-time value of %d is illegal due to errata dTSEC-A003!"
+ " value should be greater than 320."));
+#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */
+
+ GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ fman_dtsec_set_tx_pause_frames(p_Dtsec->p_MemMap, pauseTime);
+
+ GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+/* backward compatibility. will be removed in the future. */
+static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime)
+{
+ return DtsecSetTxPauseFrames(h_Dtsec, 0, pauseTime, 0);
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ bool accept_pause = !en;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ fman_dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause);
+
+ GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->ptpTsuEnabled = TRUE;
+ fman_dtsec_set_ts(p_Dtsec->p_MemMap, TRUE);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->ptpTsuEnabled = FALSE;
+ fman_dtsec_set_ts(p_Dtsec->p_MemMap, FALSE);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ struct dtsec_regs *p_DtsecMemMap;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
+
+ p_DtsecMemMap = p_Dtsec->p_MemMap;
+
+ if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled"));
+
+ memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics));
+
+ if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS)
+ {
+ p_Statistics->eStatPkts64 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64)
+ + p_Dtsec->internalStatistics.tr64;
+ p_Statistics->eStatPkts65to127 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127)
+ + p_Dtsec->internalStatistics.tr127;
+ p_Statistics->eStatPkts128to255 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255)
+ + p_Dtsec->internalStatistics.tr255;
+ p_Statistics->eStatPkts256to511 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511)
+ + p_Dtsec->internalStatistics.tr511;
+ p_Statistics->eStatPkts512to1023 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K)
+ + p_Dtsec->internalStatistics.tr1k;
+ p_Statistics->eStatPkts1024to1518 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX)
+ + p_Dtsec->internalStatistics.trmax;
+ p_Statistics->eStatPkts1519to1522 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV)
+ + p_Dtsec->internalStatistics.trmgv;
+
+ /* MIB II */
+ p_Statistics->ifInOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT)
+ + p_Dtsec->internalStatistics.rbyt;
+ p_Statistics->ifInPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT)
+ + p_Dtsec->internalStatistics.rpkt;
+ p_Statistics->ifInUcastPkts = 0;
+ p_Statistics->ifInMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA)
+ + p_Dtsec->internalStatistics.rmca;
+ p_Statistics->ifInBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA)
+ + p_Dtsec->internalStatistics.rbca;
+ p_Statistics->ifOutOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT)
+ + p_Dtsec->internalStatistics.tbyt;
+ p_Statistics->ifOutPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT)
+ + p_Dtsec->internalStatistics.tpkt;
+ p_Statistics->ifOutUcastPkts = 0;
+ p_Statistics->ifOutMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA)
+ + p_Dtsec->internalStatistics.tmca;
+ p_Statistics->ifOutBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA)
+ + p_Dtsec->internalStatistics.tbca;
+ }
+
+ p_Statistics->eStatFragments = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG)
+ + p_Dtsec->internalStatistics.rfrg;
+ p_Statistics->eStatJabbers = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR)
+ + p_Dtsec->internalStatistics.rjbr;
+ p_Statistics->eStatsDropEvents = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP)
+ + p_Dtsec->internalStatistics.rdrp;
+ p_Statistics->eStatCRCAlignErrors = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN)
+ + p_Dtsec->internalStatistics.raln;
+ p_Statistics->eStatUndersizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND)
+ + p_Dtsec->internalStatistics.rund;
+ p_Statistics->eStatOversizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR)
+ + p_Dtsec->internalStatistics.rovr;
+ p_Statistics->reStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF)
+ + p_Dtsec->internalStatistics.rxpf;
+ p_Statistics->teStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TXPF)
+ + p_Dtsec->internalStatistics.txpf;
+ p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents;
+ p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + p_Statistics->eStatCRCAlignErrors
+ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr
+ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde
+ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse;
+
+ p_Statistics->ifOutDiscards = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TDRP)
+ + p_Dtsec->internalStatistics.tdrp;
+ p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards /**< Number of frames transmitted with error: */
+ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_TFCS)
+ + p_Dtsec->internalStatistics.tfcs;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ /* Initialize MAC Station Address registers (1 & 2) */
+ /* Station address have to be swapped (big endian to little endian */
+ p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr);
+
+ GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ fman_dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr));
+
+ GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecResetCounters (t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ /* clear HW counters */
+ fman_dtsec_reset_stat(p_Dtsec->p_MemMap);
+
+ /* clear SW counters holding carries */
+ memset(&p_Dtsec->internalStatistics, 0, sizeof(t_InternalStatistics));
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ if (ethAddr & GROUP_ADDRESS)
+ /* Multicast address has no effect in PADDR */
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
+
+ /* Make sure no PADDR contains this address */
+ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
+ if (p_Dtsec->indAddrRegUsed[paddrNum])
+ if (p_Dtsec->paddr[paddrNum] == ethAddr)
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
+
+ /* Find first unused PADDR */
+ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
+ if (!(p_Dtsec->indAddrRegUsed[paddrNum]))
+ {
+ /* mark this PADDR as used */
+ p_Dtsec->indAddrRegUsed[paddrNum] = TRUE;
+ /* store address */
+ p_Dtsec->paddr[paddrNum] = ethAddr;
+
+ /* put in hardware */
+ fman_dtsec_add_addr_in_paddr(p_Dtsec->p_MemMap, (uint64_t)PTR_TO_UINT(&ethAddr), paddrNum);
+ p_Dtsec->numOfIndAddrInRegs++;
+
+ return E_OK;
+ }
+
+ /* No free PADDR */
+ RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ /* Find used PADDR containing this address */
+ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++)
+ {
+ if ((p_Dtsec->indAddrRegUsed[paddrNum]) &&
+ (p_Dtsec->paddr[paddrNum] == ethAddr))
+ {
+ /* mark this PADDR as not used */
+ p_Dtsec->indAddrRegUsed[paddrNum] = FALSE;
+ /* clear in hardware */
+ fman_dtsec_clear_addr_in_paddr(p_Dtsec->p_MemMap, paddrNum);
+ p_Dtsec->numOfIndAddrInRegs--;
+
+ return E_OK;
+ }
+ }
+
+ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ t_EthHashEntry *p_HashEntry;
+ uint64_t ethAddr;
+ int32_t bucket;
+ uint32_t crc;
+ bool mcast, ghtx;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE);
+ mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE);
+
+ if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket"));
+
+ crc = GetMacAddrHashCode(ethAddr);
+
+ /* considering the 9 highest order bits in crc H[8:0]:
+ * if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register
+ * and H[5:1] (next 5 bits) identify the hash bit
+ * if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register
+ * and H[4:0] (next 5 bits) identify the hash bit.
+ *
+ * In bucket index output the low 5 bits identify the hash register bit,
+ * while the higher 4 bits identify the hash register
+ */
+
+ if (ghtx)
+ bucket = (int32_t)((crc >> 23) & 0x1ff);
+ else {
+ bucket = (int32_t)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
+ if (mcast)
+ bucket += 0x100;
+ }
+
+ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, TRUE);
+
+ /* Create element to be added to the driver hash table */
+ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
+ p_HashEntry->addr = ethAddr;
+ INIT_LIST(&p_HashEntry->node);
+
+ if (ethAddr & MAC_GROUP_ADDRESS)
+ /* Group Address */
+ LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]));
+ else
+ LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]));
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ t_List *p_Pos;
+ t_EthHashEntry *p_HashEntry = NULL;
+ uint64_t ethAddr;
+ int32_t bucket;
+ uint32_t crc;
+ bool mcast, ghtx;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE);
+ mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE);
+
+ if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket"));
+
+ crc = GetMacAddrHashCode(ethAddr);
+
+ if (ghtx)
+ bucket = (int32_t)((crc >> 23) & 0x1ff);
+ else {
+ bucket = (int32_t)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
+ if (mcast)
+ bucket += 0x100;
+ }
+
+ if (ethAddr & MAC_GROUP_ADDRESS)
+ {
+ /* Group Address */
+ LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]))
+ {
+ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
+ if (p_HashEntry->addr == ethAddr)
+ {
+ LIST_DelAndInit(&p_HashEntry->node);
+ XX_Free(p_HashEntry);
+ break;
+ }
+ }
+ if (LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket]))
+ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE);
+ }
+ else
+ {
+ /* Individual Address */
+ LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]))
+ {
+ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
+ if (p_HashEntry->addr == ethAddr)
+ {
+ LIST_DelAndInit(&p_HashEntry->node);
+ XX_Free(p_HashEntry);
+ break;
+ }
+ }
+ if (LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket]))
+ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE);
+ }
+
+ /* address does not exist */
+ ASSERT_COND(p_HashEntry != NULL);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ fman_dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal);
+ fman_dtsec_set_mc_promisc(p_Dtsec->p_MemMap, newVal);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->statisticsLevel = statisticsLevel;
+
+ err = (t_Error)fman_dtsec_set_stat_level(p_Dtsec->p_MemMap,
+ (enum dtsec_stat_level)statisticsLevel);
+ if (err != E_OK)
+ return err;
+
+ switch (statisticsLevel)
+ {
+ case (e_FM_MAC_NONE_STATISTICS):
+ p_Dtsec->exceptions &= ~DTSEC_IMASK_MSROEN;
+ break;
+ case (e_FM_MAC_PARTIAL_STATISTICS):
+ p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN;
+ break;
+ case (e_FM_MAC_FULL_STATISTICS):
+ p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecSetWakeOnLan(t_Handle h_Dtsec, bool en)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ fman_dtsec_set_wol(p_Dtsec->p_MemMap, en);
+
+ GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ int err;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed);
+ enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode);
+ enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode);
+ p_Dtsec->halfDuplex = !fullDuplex;
+
+ GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ err = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex);
+
+ if (err == -EINVAL)
+ RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode"));
+
+ GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX);
+
+ return (t_Error)err;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecRestartAutoneg(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint16_t tmpReg16;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ DTSEC_MII_ReadPhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, &tmpReg16);
+
+ tmpReg16 &= ~( PHY_CR_SPEED0 | PHY_CR_SPEED1 );
+ tmpReg16 |= (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
+
+ DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, tmpReg16);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ *macId = p_Dtsec->macId;
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ *macVersion = fman_dtsec_get_revision(p_Dtsec->p_MemMap);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+
+ if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR)
+ {
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Dtsec->exceptions |= bitMask;
+ else
+ p_Dtsec->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ if (enable)
+ fman_dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask);
+ else
+ fman_dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask);
+ }
+ else
+ {
+ if (!p_Dtsec->ptpTsuEnabled)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only"));
+
+ if (enable)
+ {
+ p_Dtsec->enTsuErrExeption = TRUE;
+ fman_dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap);
+ }
+ else
+ {
+ p_Dtsec->enTsuErrExeption = FALSE;
+ fman_dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap);
+ }
+ }
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* dTSEC Init & Free API */
+/*****************************************************************************/
+
+/* .............................................................................. */
+
+static t_Error DtsecInit(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ struct dtsec_cfg *p_DtsecDriverParam;
+ t_Error err;
+ uint16_t maxFrmLn;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ t_EnetAddr ethAddr;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
+
+ FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &p_Dtsec->fmMacControllerDriver.fmRevInfo);
+ CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters);
+
+ p_DtsecDriverParam = p_Dtsec->p_DtsecDriverParam;
+ p_Dtsec->halfDuplex = p_DtsecDriverParam->halfdup_on;
+
+ enet_interface = (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode);
+ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_Dtsec->enetMode);
+ MAKE_ENET_ADDR_FROM_UINT64(p_Dtsec->addr, ethAddr);
+
+ err = (t_Error)fman_dtsec_init(p_Dtsec->p_MemMap,
+ p_DtsecDriverParam,
+ enet_interface,
+ enet_speed,
+ (uint8_t*)ethAddr,
+ p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev,
+ p_Dtsec->fmMacControllerDriver.fmRevInfo.minorRev,
+ p_Dtsec->exceptions);
+ if (err)
+ {
+ FreeInitResources(p_Dtsec);
+ RETURN_ERROR(MAJOR, err, ("This DTSEC version does not support the required i/f mode"));
+ }
+
+ if (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII)
+ {
+ uint16_t tmpReg16;
+
+ /* Configure the TBI PHY Control Register */
+ tmpReg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET;
+ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16);
+
+ tmpReg16 = PHY_TBICON_CLK_SEL;
+ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16);
+
+ tmpReg16 = (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
+ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16);
+
+ if (p_Dtsec->enetMode & ENET_IF_SGMII_BASEX)
+ tmpReg16 = PHY_TBIANA_1000X;
+ else
+ tmpReg16 = PHY_TBIANA_SGMII;
+ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 4, tmpReg16);
+
+ tmpReg16 = (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1);
+
+ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16);
+ }
+
+ /* Max Frame Length */
+ maxFrmLn = fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap);
+ err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G,
+ p_Dtsec->fmMacControllerDriver.macId, maxFrmLn);
+ if (err)
+ RETURN_ERROR(MINOR,err, NO_MSG);
+
+ p_Dtsec->p_MulticastAddrHash = AllocHashTable(EXTENDED_HASH_TABLE_SIZE);
+ if (!p_Dtsec->p_MulticastAddrHash) {
+ FreeInitResources(p_Dtsec);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED"));
+ }
+
+ p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
+ if (!p_Dtsec->p_UnicastAddrHash)
+ {
+ FreeInitResources(p_Dtsec);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED"));
+ }
+
+ /* register err intr handler for dtsec to FPM (err)*/
+ FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm,
+ e_FM_MOD_1G_MAC,
+ p_Dtsec->macId,
+ e_FM_INTR_TYPE_ERR,
+ DtsecIsr,
+ p_Dtsec);
+ /* register 1588 intr handler for TMR to FPM (normal)*/
+ FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm,
+ e_FM_MOD_1G_MAC,
+ p_Dtsec->macId,
+ e_FM_INTR_TYPE_NORMAL,
+ Dtsec1588Isr,
+ p_Dtsec);
+ /* register normal intr handler for dtsec to main interrupt controller. */
+ if (p_Dtsec->mdioIrq != NO_IRQ)
+ {
+ XX_SetIntr(p_Dtsec->mdioIrq, DtsecMdioIsr, p_Dtsec);
+ XX_EnableIntr(p_Dtsec->mdioIrq);
+ }
+
+ XX_Free(p_DtsecDriverParam);
+ p_Dtsec->p_DtsecDriverParam = NULL;
+
+ err = DtsecSetStatistics(h_Dtsec, e_FM_MAC_FULL_STATISTICS);
+ if (err)
+ {
+ FreeInitResources(p_Dtsec);
+ RETURN_ERROR(MAJOR, err, ("Undefined statistics level"));
+ }
+
+ return E_OK;
+}
+
+/* ........................................................................... */
+
+static t_Error DtsecFree(t_Handle h_Dtsec)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+
+ if (p_Dtsec->p_DtsecDriverParam)
+ {
+ /* Called after config */
+ XX_Free(p_Dtsec->p_DtsecDriverParam);
+ p_Dtsec->p_DtsecDriverParam = NULL;
+ }
+ else
+ /* Called after init */
+ FreeInitResources(p_Dtsec);
+
+ XX_Free(p_Dtsec);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
+{
+ p_FmMacControllerDriver->f_FM_MAC_Init = DtsecInit;
+ p_FmMacControllerDriver->f_FM_MAC_Free = DtsecFree;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = DtsecSetStatistics;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = DtsecConfigLoopback;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = DtsecConfigMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = NULL; /* Not supported on dTSEC */
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = DtsecConfigPadAndCrc;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = DtsecConfigHalfDuplex;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = DtsecConfigLengthCheck;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr = DtsecConfigTbiPhyAddr;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigException = DtsecConfigException;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable = DtsecEnable;
+ p_FmMacControllerDriver->f_FM_MAC_Disable = DtsecDisable;
+ p_FmMacControllerDriver->f_FM_MAC_Resume = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetException = DtsecSetException;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = DtsecSetPromiscuous;
+ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = DtsecAdjustLink;
+ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = DtsecSetWakeOnLan;
+ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = DtsecRestartAutoneg;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = DtsecEnable1588TimeStamp;
+ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = DtsecDisable1588TimeStamp;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = DtsecTxMacPause;
+ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = DtsecSetTxPauseFrames;
+ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = DtsecRxIgnoreMacPause;
+
+ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = DtsecResetCounters;
+ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = DtsecGetStatistics;
+ p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = DtsecModifyMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = DtsecAddHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = DtsecDelHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = DtsecAddExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = DtsecDelExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_GetId = DtsecGetId;
+ p_FmMacControllerDriver->f_FM_MAC_GetVersion = DtsecGetVersion;
+ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = DtsecGetMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = DTSEC_MII_WritePhyReg;
+ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = DTSEC_MII_ReadPhyReg;
+
+}
+
+
+/*****************************************************************************/
+/* dTSEC Config Main Entry */
+/*****************************************************************************/
+
+/* .............................................................................. */
+
+t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam)
+{
+ t_Dtsec *p_Dtsec;
+ struct dtsec_cfg *p_DtsecDriverParam;
+ uintptr_t baseAddr;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
+
+ baseAddr = p_FmMacParam->baseAddr;
+
+ /* allocate memory for the UCC GETH data structure. */
+ p_Dtsec = (t_Dtsec *)XX_Malloc(sizeof(t_Dtsec));
+ if (!p_Dtsec)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure"));
+ return NULL;
+ }
+ memset(p_Dtsec, 0, sizeof(t_Dtsec));
+ InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver);
+
+ /* allocate memory for the dTSEC driver parameters data structure. */
+ p_DtsecDriverParam = (struct dtsec_cfg *) XX_Malloc(sizeof(struct dtsec_cfg));
+ if (!p_DtsecDriverParam)
+ {
+ XX_Free(p_Dtsec);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters"));
+ return NULL;
+ }
+ memset(p_DtsecDriverParam, 0, sizeof(struct dtsec_cfg));
+
+ /* Plant parameter structure pointer */
+ p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam;
+
+ fman_dtsec_defconfig(p_DtsecDriverParam);
+
+ p_Dtsec->p_MemMap = (struct dtsec_regs *)UINT_TO_PTR(baseAddr);
+ p_Dtsec->p_MiiMemMap = (struct dtsec_mii_reg *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET);
+ p_Dtsec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
+ p_Dtsec->enetMode = p_FmMacParam->enetMode;
+ p_Dtsec->macId = p_FmMacParam->macId;
+ p_Dtsec->exceptions = DEFAULT_exceptions;
+ p_Dtsec->mdioIrq = p_FmMacParam->mdioIrq;
+ p_Dtsec->f_Exception = p_FmMacParam->f_Exception;
+ p_Dtsec->f_Event = p_FmMacParam->f_Event;
+ p_Dtsec->h_App = p_FmMacParam->h_App;
+ p_Dtsec->ptpTsuEnabled = p_Dtsec->p_DtsecDriverParam->ptp_tsu_en;
+ p_Dtsec->enTsuErrExeption = p_Dtsec->p_DtsecDriverParam->ptp_exception_en;
+ p_Dtsec->tbi_phy_addr = p_Dtsec->p_DtsecDriverParam->tbi_phy_addr;
+
+ return p_Dtsec;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h
new file mode 100644
index 000000000000..c26f40cc9664
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File dtsec.h
+
+ @Description FM dTSEC ...
+*//***************************************************************************/
+#ifndef __DTSEC_H
+#define __DTSEC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+#include "enet_ext.h"
+
+#include "dtsec_mii_acc.h"
+#include "fm_mac.h"
+
+
+#define DEFAULT_exceptions \
+ ((uint32_t)(DTSEC_IMASK_BREN | \
+ DTSEC_IMASK_RXCEN | \
+ DTSEC_IMASK_BTEN | \
+ DTSEC_IMASK_TXCEN | \
+ DTSEC_IMASK_TXEEN | \
+ DTSEC_IMASK_ABRTEN | \
+ DTSEC_IMASK_LCEN | \
+ DTSEC_IMASK_CRLEN | \
+ DTSEC_IMASK_XFUNEN | \
+ DTSEC_IMASK_IFERREN | \
+ DTSEC_IMASK_MAGEN | \
+ DTSEC_IMASK_TDPEEN | \
+ DTSEC_IMASK_RDPEEN))
+
+#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \
+ case e_FM_MAC_EX_1G_BAB_RX: \
+ bitMask = DTSEC_IMASK_BREN; break; \
+ case e_FM_MAC_EX_1G_RX_CTL: \
+ bitMask = DTSEC_IMASK_RXCEN; break; \
+ case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET: \
+ bitMask = DTSEC_IMASK_GTSCEN ; break; \
+ case e_FM_MAC_EX_1G_BAB_TX: \
+ bitMask = DTSEC_IMASK_BTEN ; break; \
+ case e_FM_MAC_EX_1G_TX_CTL: \
+ bitMask = DTSEC_IMASK_TXCEN ; break; \
+ case e_FM_MAC_EX_1G_TX_ERR: \
+ bitMask = DTSEC_IMASK_TXEEN ; break; \
+ case e_FM_MAC_EX_1G_LATE_COL: \
+ bitMask = DTSEC_IMASK_LCEN ; break; \
+ case e_FM_MAC_EX_1G_COL_RET_LMT: \
+ bitMask = DTSEC_IMASK_CRLEN ; break; \
+ case e_FM_MAC_EX_1G_TX_FIFO_UNDRN: \
+ bitMask = DTSEC_IMASK_XFUNEN ; break; \
+ case e_FM_MAC_EX_1G_MAG_PCKT: \
+ bitMask = DTSEC_IMASK_MAGEN ; break; \
+ case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET: \
+ bitMask = DTSEC_IMASK_MMRDEN; break; \
+ case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET: \
+ bitMask = DTSEC_IMASK_MMWREN ; break; \
+ case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET: \
+ bitMask = DTSEC_IMASK_GRSCEN; break; \
+ case e_FM_MAC_EX_1G_TX_DATA_ERR: \
+ bitMask = DTSEC_IMASK_TDPEEN; break; \
+ case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL: \
+ bitMask = DTSEC_IMASK_MSROEN ; break; \
+ default: bitMask = 0;break;}
+
+
+#define MAX_PACKET_ALIGNMENT 31
+#define MAX_INTER_PACKET_GAP 0x7f
+#define MAX_INTER_PALTERNATE_BEB 0x0f
+#define MAX_RETRANSMISSION 0x0f
+#define MAX_COLLISION_WINDOW 0x03ff
+
+
+/********************* From mac ext ******************************************/
+typedef uint32_t t_ErrorDisable;
+
+#define ERROR_DISABLE_TRANSMIT 0x00400000
+#define ERROR_DISABLE_LATE_COLLISION 0x00040000
+#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000
+#define ERROR_DISABLE_TxFIFO_UNDERRUN 0x00010000
+#define ERROR_DISABLE_TxABORT 0x00008000
+#define ERROR_DISABLE_INTERFACE 0x00004000
+#define ERROR_DISABLE_TxDATA_PARITY 0x00000002
+#define ERROR_DISABLE_RxDATA_PARITY 0x00000001
+
+/*****************************************************************************/
+#define DTSEC_NUM_OF_PADDRS 15 /* number of pattern match registers (entries) */
+
+#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */
+
+#define HASH_TABLE_SIZE 256 /* Hash table size (= 32 bits * 8 regs) */
+
+#define HASH_TABLE_SIZE 256 /* Hash table size (32 bits * 8 regs) */
+#define EXTENDED_HASH_TABLE_SIZE 512 /* Extended Hash table size (32 bits * 16 regs) */
+
+#define DTSEC_TO_MII_OFFSET 0x1000 /* number of pattern match registers (entries) */
+
+#define MAX_PHYS 32 /* maximum number of phys */
+
+#define VAL32BIT 0x100000000LL
+#define VAL22BIT 0x00400000
+#define VAL16BIT 0x00010000
+#define VAL12BIT 0x00001000
+
+/* CAR1/2 bits */
+#define CAR1_TR64 0x80000000
+#define CAR1_TR127 0x40000000
+#define CAR1_TR255 0x20000000
+#define CAR1_TR511 0x10000000
+#define CAR1_TRK1 0x08000000
+#define CAR1_TRMAX 0x04000000
+#define CAR1_TRMGV 0x02000000
+
+#define CAR1_RBYT 0x00010000
+#define CAR1_RPKT 0x00008000
+#define CAR1_RMCA 0x00002000
+#define CAR1_RBCA 0x00001000
+#define CAR1_RXPF 0x00000400
+#define CAR1_RALN 0x00000100
+#define CAR1_RFLR 0x00000080
+#define CAR1_RCDE 0x00000040
+#define CAR1_RCSE 0x00000020
+#define CAR1_RUND 0x00000010
+#define CAR1_ROVR 0x00000008
+#define CAR1_RFRG 0x00000004
+#define CAR1_RJBR 0x00000002
+#define CAR1_RDRP 0x00000001
+
+#define CAR2_TFCS 0x00040000
+#define CAR2_TBYT 0x00002000
+#define CAR2_TPKT 0x00001000
+#define CAR2_TMCA 0x00000800
+#define CAR2_TBCA 0x00000400
+#define CAR2_TXPF 0x00000200
+#define CAR2_TDRP 0x00000001
+
+typedef struct t_InternalStatistics
+{
+ uint64_t tr64;
+ uint64_t tr127;
+ uint64_t tr255;
+ uint64_t tr511;
+ uint64_t tr1k;
+ uint64_t trmax;
+ uint64_t trmgv;
+ uint64_t rfrg;
+ uint64_t rjbr;
+ uint64_t rdrp;
+ uint64_t raln;
+ uint64_t rund;
+ uint64_t rovr;
+ uint64_t rxpf;
+ uint64_t txpf;
+ uint64_t rbyt;
+ uint64_t rpkt;
+ uint64_t rmca;
+ uint64_t rbca;
+ uint64_t rflr;
+ uint64_t rcde;
+ uint64_t rcse;
+ uint64_t tbyt;
+ uint64_t tpkt;
+ uint64_t tmca;
+ uint64_t tbca;
+ uint64_t tdrp;
+ uint64_t tfcs;
+} t_InternalStatistics;
+
+typedef struct {
+ t_FmMacControllerDriver fmMacControllerDriver;
+ t_Handle h_App; /**< Handle to the upper layer application */
+ struct dtsec_regs *p_MemMap; /**< pointer to dTSEC memory mapped registers. */
+ struct dtsec_mii_reg *p_MiiMemMap; /**< pointer to dTSEC MII memory mapped registers. */
+ uint64_t addr; /**< MAC address of device; */
+ e_EnetMode enetMode; /**< Ethernet physical interface */
+ t_FmMacExceptionCallback *f_Exception;
+ int mdioIrq;
+ t_FmMacExceptionCallback *f_Event;
+ bool indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
+ uint64_t paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */
+ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */
+ bool halfDuplex;
+ t_InternalStatistics internalStatistics;
+ t_EthHash *p_MulticastAddrHash; /* pointer to driver's global address hash table */
+ t_EthHash *p_UnicastAddrHash; /* pointer to driver's individual address hash table */
+ uint8_t macId;
+ uint8_t tbi_phy_addr;
+ uint32_t exceptions;
+ bool ptpTsuEnabled;
+ bool enTsuErrExeption;
+ e_FmMacStatisticsLevel statisticsLevel;
+ struct dtsec_cfg *p_DtsecDriverParam;
+} t_Dtsec;
+
+
+#endif /* __DTSEC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c
new file mode 100644
index 000000000000..87da25ff9e35
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File dtsec_mii_acc.c
+
+ @Description FM dtsec MII register access MAC ...
+*//***************************************************************************/
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_mac.h"
+#include "dtsec.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+
+/*****************************************************************************/
+t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t data)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ struct dtsec_mii_reg *miiregs;
+ uint16_t dtsec_freq;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE);
+
+ dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1);
+ miiregs = p_Dtsec->p_MiiMemMap;
+
+ err = (t_Error)fman_dtsec_mii_write_reg(miiregs, phyAddr, reg, data, dtsec_freq);
+
+ return err;
+}
+
+/*****************************************************************************/
+t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t *p_Data)
+{
+ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec;
+ struct dtsec_mii_reg *miiregs;
+ uint16_t dtsec_freq;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE);
+
+ dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1);
+ miiregs = p_Dtsec->p_MiiMemMap;
+
+ err = fman_dtsec_mii_read_reg(miiregs, phyAddr, reg, p_Data, dtsec_freq);
+
+ if (*p_Data == 0xffff)
+ RETURN_ERROR(MINOR, E_NO_DEVICE,
+ ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x",
+ phyAddr, reg));
+ if (err)
+ RETURN_ERROR(MINOR, (t_Error)err, NO_MSG);
+
+ return E_OK;
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h
new file mode 100644
index 000000000000..75cc658a5c50
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DTSEC_MII_ACC_H
+#define __DTSEC_MII_ACC_H
+
+#include "std_ext.h"
+
+
+t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data);
+t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
+
+#endif /* __DTSEC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
new file mode 100644
index 000000000000..caf3940ad9df
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_mac.c
+
+ @Description FM MAC ...
+*//***************************************************************************/
+#include "std_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "error_ext.h"
+#include "fm_ext.h"
+
+#include "fm_common.h"
+#include "fm_mac.h"
+
+
+/* ......................................................................... */
+
+t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver;
+ uint16_t fmClkFreq;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL);
+
+ fmClkFreq = FmGetClockFreq(p_FmMacParam->h_Fm);
+ if (fmClkFreq == 0)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!"));
+ return NULL;
+ }
+
+#if (DPAA_VERSION == 10)
+ if (ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000)
+ p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam);
+ else
+#if FM_MAX_NUM_OF_10G_MACS > 0
+ p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam);
+#else
+ p_FmMacControllerDriver = NULL;
+#endif /* FM_MAX_NUM_OF_10G_MACS > 0 */
+#else
+ p_FmMacControllerDriver = (t_FmMacControllerDriver *)MEMAC_Config(p_FmMacParam);
+#endif /* (DPAA_VERSION == 10) */
+
+ if (!p_FmMacControllerDriver)
+ return NULL;
+
+ p_FmMacControllerDriver->h_Fm = p_FmMacParam->h_Fm;
+ p_FmMacControllerDriver->enetMode = p_FmMacParam->enetMode;
+ p_FmMacControllerDriver->macId = p_FmMacParam->macId;
+ p_FmMacControllerDriver->resetOnInit = DEFAULT_resetOnInit;
+
+ p_FmMacControllerDriver->clkFreq = fmClkFreq;
+
+ return (t_Handle)p_FmMacControllerDriver;
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Init (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->resetOnInit &&
+ !p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit &&
+ (FmResetMac(p_FmMacControllerDriver->h_Fm,
+ ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ?
+ e_FM_MAC_10G : e_FM_MAC_1G),
+ p_FmMacControllerDriver->macId) != E_OK))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!"));
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Init)
+ return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Free (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Free)
+ return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit(h_FmMac, enable);
+
+ p_FmMacControllerDriver->resetOnInit = enable;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigTbiPhyAddr (t_Handle h_FmMac, uint8_t newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr(h_FmMac,newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigException)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+/* ......................................................................... */
+
+t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround)
+ return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+
+/*****************************************************************************/
+/* Run Time Control */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Enable)
+ return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Disable)
+ return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MAC_Resume (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Resume)
+ return p_FmMacControllerDriver->f_FM_MAC_Resume(h_FmMac);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp)
+ return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp)
+ return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac,
+ uint16_t pauseTime)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames)
+ return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac,
+ pauseTime);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames)
+ return p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames(h_FmMac,
+ priority,
+ pauseTime,
+ threshTime);
+
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames)
+ return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetWakeOnLan (t_Handle h_FmMac, bool en)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan)
+ return p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan(h_FmMac, en);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ResetCounters (t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters)
+ return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetException)
+ return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics)
+ return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics)
+ return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_GetFrameSizeCounters(t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ memset(p_FrameSizeCounters, 0, sizeof(t_FmMacFrameSizeCounters));
+
+ if (p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters)
+ return p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters(h_FmMac, p_FrameSizeCounters, type);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr)
+ return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_GetVersion)
+ return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_GetId)
+ return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous)
+ return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink)
+ return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg)
+ return p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg(h_FmMac);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg)
+ return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg)
+ return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+/* ......................................................................... */
+
+uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength)
+ return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac);
+
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+ return 0;
+}
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/*****************************************************************************/
+t_Error FM_MAC_DumpRegs(t_Handle h_FmMac)
+{
+ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs)
+ return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+#endif /* (defined(DEBUG_ERRORS) && ... */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
new file mode 100644
index 000000000000..ba3b9133a88f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_mac.h
+
+ @Description FM MAC ...
+*//***************************************************************************/
+#ifndef __FM_MAC_H
+#define __FM_MAC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+#include "fm_mac_ext.h"
+#include "fm_common.h"
+
+
+#define __ERR_MODULE__ MODULE_FM_MAC
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+
+
+#define DEFAULT_halfDuplex FALSE
+#define DEFAULT_padAndCrcEnable TRUE
+#define DEFAULT_resetOnInit FALSE
+
+
+typedef struct {
+ uint64_t addr; /* Ethernet Address */
+ t_List node;
+} t_EthHashEntry;
+#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node)
+
+typedef struct {
+ uint16_t size;
+ t_List *p_Lsts;
+} t_EthHash;
+
+typedef struct {
+ t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac);
+ t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac);
+
+ t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel);
+ t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal);
+ t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal);
+ t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag);
+ t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal);
+ t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal);
+ t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal);
+ t_Error (*f_FM_MAC_ConfigTbiPhyAddr) (t_Handle h_FmMac, uint8_t newVal);
+ t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable);
+ t_Error (*f_FM_MAC_ConfigResetOnInit) (t_Handle h_FmMac, bool enable);
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac);
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+ t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
+
+ t_Error (*f_FM_MAC_Enable) (t_Handle h_FmMac, e_CommMode mode);
+ t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode);
+ t_Error (*f_FM_MAC_Resume) (t_Handle h_FmMac);
+ t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac);
+ t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac);
+ t_Error (*f_FM_MAC_Reset) (t_Handle h_FmMac, bool wait);
+
+ t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac,
+ uint16_t pauseTime);
+ t_Error (*f_FM_MAC_SetTxPauseFrames) (t_Handle h_FmMac,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime);
+ t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en);
+
+ t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac);
+ t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
+ t_Error (*f_FM_MAC_GetFrameSizeCounters) (t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type);
+
+ t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+ t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+ t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+ t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+ t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+ t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal);
+ t_Error (*f_FM_MAC_AdjustLink) (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex);
+ t_Error (*f_FM_MAC_RestartAutoneg) (t_Handle h_FmMac);
+
+ t_Error (*f_FM_MAC_SetWakeOnLan) (t_Handle h_FmMac, bool en);
+
+ t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId);
+
+ t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion);
+
+ uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac);
+
+ t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data);
+ t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ t_Handle h_Fm;
+ t_FmRevisionInfo fmRevInfo;
+ e_EnetMode enetMode;
+ uint8_t macId;
+ bool resetOnInit;
+ uint16_t clkFreq;
+} t_FmMacControllerDriver;
+
+
+#if (DPAA_VERSION == 10)
+t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam);
+t_Handle TGEC_Config(t_FmMacParams *p_FmMacParams);
+#else
+t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam);
+#endif /* (DPAA_VERSION == 10) */
+uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac);
+
+
+/* ........................................................................... */
+
+static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst)
+{
+ t_EthHashEntry *p_HashEntry = NULL;
+ if (!LIST_IsEmpty(p_AddrLst))
+ {
+ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next);
+ LIST_DelAndInit(&p_HashEntry->node);
+ }
+ return p_HashEntry;
+}
+
+/* ........................................................................... */
+
+static __inline__ void FreeHashTable(t_EthHash *p_Hash)
+{
+ t_EthHashEntry *p_HashEntry;
+ int i = 0;
+
+ if (p_Hash)
+ {
+ if (p_Hash->p_Lsts)
+ {
+ for (i=0; i<p_Hash->size; i++)
+ {
+ p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]);
+ while (p_HashEntry)
+ {
+ XX_Free(p_HashEntry);
+ p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]);
+ }
+ }
+
+ XX_Free(p_Hash->p_Lsts);
+ }
+
+ XX_Free(p_Hash);
+ }
+}
+
+/* ........................................................................... */
+
+static __inline__ t_EthHash * AllocHashTable(uint16_t size)
+{
+ uint32_t i;
+ t_EthHash *p_Hash;
+
+ /* Allocate address hash table */
+ p_Hash = (t_EthHash *)XX_Malloc(sizeof(t_EthHash));
+ if (!p_Hash)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table"));
+ return NULL;
+ }
+ p_Hash->size = size;
+
+ p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List));
+ if (!p_Hash->p_Lsts)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table"));
+ XX_Free(p_Hash);
+ return NULL;
+ }
+
+ for (i=0 ; i<p_Hash->size; i++)
+ INIT_LIST(&p_Hash->p_Lsts[i]);
+
+ return p_Hash;
+}
+
+
+#endif /* __FM_MAC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c
new file mode 100644
index 000000000000..b6a4ca25f80c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fman_crc32.h"
+#include "common/general.h"
+
+
+/* precomputed CRC values for address hashing */
+static const uint32_t crc_tbl[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/* Get the mirrored value of a byte size number. (0x11010011 --> 0x11001011) */
+static inline uint8_t get_mirror8(uint8_t n)
+{
+ uint8_t mirror[16] = {
+ 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
+ 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
+ };
+ return (uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4])));
+}
+
+static inline uint32_t get_mirror32(uint32_t n)
+{
+ return ((uint32_t)get_mirror8((uint8_t)(n))<<24) |
+ ((uint32_t)get_mirror8((uint8_t)(n>>8))<<16) |
+ ((uint32_t)get_mirror8((uint8_t)(n>>16))<<8) |
+ ((uint32_t)get_mirror8((uint8_t)(n>>24)));
+}
+
+uint32_t get_mac_addr_crc(uint64_t _addr)
+{
+ uint32_t i;
+ uint8_t data;
+ uint32_t crc;
+
+ /* CRC calculation */
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ data = (uint8_t)(_addr >> ((5-i)*8));
+ crc = crc ^ data;
+ crc = crc_tbl[crc&0xff] ^ (crc>>8);
+ }
+
+ crc = get_mirror32(crc);
+ return crc;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h
new file mode 100644
index 000000000000..6e32fdc6c5f6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __FMAN_CRC32_H
+#define __FMAN_CRC32_H
+
+#include "common/general.h"
+
+
+uint32_t get_mac_addr_crc(uint64_t _addr);
+
+
+#endif /* __FMAN_CRC32_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
new file mode 100644
index 000000000000..60dc2df0bc62
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "fsl_fman_dtsec.h"
+
+
+void fman_dtsec_stop_rx(struct dtsec_regs *regs)
+{
+ /* Assert the graceful stop bit */
+ iowrite32be(ioread32be(&regs->rctrl) | RCTRL_GRS, &regs->rctrl);
+}
+
+void fman_dtsec_stop_tx(struct dtsec_regs *regs)
+{
+ /* Assert the graceful stop bit */
+ iowrite32be(ioread32be(&regs->tctrl) | DTSEC_TCTRL_GTS, &regs->tctrl);
+}
+
+void fman_dtsec_start_tx(struct dtsec_regs *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS, &regs->tctrl);
+}
+
+void fman_dtsec_start_rx(struct dtsec_regs *regs)
+{
+ /* clear the graceful stop bit */
+ iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS, &regs->rctrl);
+}
+
+void fman_dtsec_defconfig(struct dtsec_cfg *cfg)
+{
+ cfg->halfdup_on = DEFAULT_HALFDUP_ON;
+ cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT;
+ cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW;
+ cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER;
+ cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF;
+ cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF;
+ cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL;
+ cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN;
+ cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST;
+ cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM;
+ cfg->rx_len_check = DEFAULT_RX_LEN_CHECK;
+ cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC;
+ cfg->tx_crc = DEFAULT_TX_CRC;
+ cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC;
+ cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME;
+ cfg->tbipa = DEFAULT_TBIPA; /* PHY address 0 is reserved (DPAA RM)*/
+ cfg->rx_prepend = DEFAULT_RX_PREPEND;
+ cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN;
+ cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN;
+ cfg->preamble_len = DEFAULT_PREAMBLE_LEN;
+ cfg->rx_preamble = DEFAULT_RX_PREAMBLE;
+ cfg->tx_preamble = DEFAULT_TX_PREAMBLE;
+ cfg->loopback = DEFAULT_LOOPBACK;
+ cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN;
+ cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN;
+ cfg->rx_flow = DEFAULT_RX_FLOW;
+ cfg->tx_flow = DEFAULT_TX_FLOW;
+ cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD;
+ cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD;
+ cfg->rx_promisc = DEFAULT_RX_PROMISC;
+ cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1;
+ cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2;
+ cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT;
+ cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG;
+ cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME;
+ cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR;
+ cfg->wake_on_lan = DEFAULT_WAKE_ON_LAN;
+}
+
+int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg,
+ enum enet_interface iface_mode,
+ enum enet_speed iface_speed,
+ uint8_t *macaddr,
+ uint8_t fm_rev_maj,
+ uint8_t fm_rev_min,
+ uint32_t exception_mask)
+{
+ bool is_rgmii = FALSE;
+ bool is_sgmii = FALSE;
+ bool is_qsgmii = FALSE;
+ int i;
+ uint32_t tmp;
+
+UNUSED(fm_rev_maj);UNUSED(fm_rev_min);
+
+ /* let's start with a soft reset */
+ iowrite32be(MACCFG1_SOFT_RESET, &regs->maccfg1);
+ iowrite32be(0, &regs->maccfg1);
+
+ /*************dtsec_id2******************/
+ tmp = ioread32be(&regs->tsec_id2);
+
+ /* check RGMII support */
+ if (iface_mode == E_ENET_IF_RGMII ||
+ iface_mode == E_ENET_IF_RMII)
+ if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
+ return -EINVAL;
+
+ if (iface_mode == E_ENET_IF_SGMII ||
+ iface_mode == E_ENET_IF_MII)
+ if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
+ return -EINVAL;
+
+ /***************ECNTRL************************/
+
+ is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? TRUE : FALSE);
+ is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? TRUE : FALSE);
+ is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? TRUE : FALSE);
+
+ tmp = 0;
+ if (is_rgmii || iface_mode == E_ENET_IF_GMII)
+ tmp |= DTSEC_ECNTRL_GMIIM;
+ if (is_sgmii)
+ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM);
+ if (is_qsgmii)
+ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM |
+ DTSEC_ECNTRL_QSGMIIM);
+ if (is_rgmii)
+ tmp |= DTSEC_ECNTRL_RPM;
+ if (iface_speed == E_ENET_SPEED_100)
+ tmp |= DTSEC_ECNTRL_R100M;
+
+ iowrite32be(tmp, &regs->ecntrl);
+ /***************ECNTRL************************/
+
+ /***************TCTRL************************/
+ tmp = 0;
+ if (cfg->halfdup_on)
+ tmp |= DTSEC_TCTRL_THDF;
+ if (cfg->tx_time_stamp_en)
+ tmp |= DTSEC_TCTRL_TTSE;
+
+ iowrite32be(tmp, &regs->tctrl);
+
+ /***************TCTRL************************/
+
+ /***************PTV************************/
+ tmp = 0;
+
+#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1
+ if ((fm_rev_maj == 1) && (fm_rev_min == 0))
+ cfg->tx_pause_time += 2;
+#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */
+
+ if (cfg->tx_pause_time)
+ tmp |= cfg->tx_pause_time;
+ if (cfg->tx_pause_time_extd)
+ tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST;
+ iowrite32be(tmp, &regs->ptv);
+
+ /***************RCTRL************************/
+ tmp = 0;
+ tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16;
+ if (cfg->rx_ctrl_acc)
+ tmp |= RCTRL_CFA;
+ if (cfg->rx_group_hash_exd)
+ tmp |= RCTRL_GHTX;
+ if (cfg->rx_time_stamp_en)
+ tmp |= RCTRL_RTSE;
+ if (cfg->rx_drop_bcast)
+ tmp |= RCTRL_BC_REJ;
+ if (cfg->rx_short_frm)
+ tmp |= RCTRL_RSF;
+ if (cfg->rx_promisc)
+ tmp |= RCTRL_PROM;
+
+ iowrite32be(tmp, &regs->rctrl);
+ /***************RCTRL************************/
+
+ /*
+ * Assign a Phy Address to the TBI (TBIPA).
+ * Done also in cases where TBI is not selected to avoid conflict with
+ * the external PHY's Physical address
+ */
+ iowrite32be(cfg->tbipa, &regs->tbipa);
+
+ /***************TMR_CTL************************/
+ iowrite32be(0, &regs->tmr_ctrl);
+
+ if (cfg->ptp_tsu_en) {
+ tmp = 0;
+ tmp |= TMR_PEVENT_TSRE;
+ iowrite32be(tmp, &regs->tmr_pevent);
+
+ if (cfg->ptp_exception_en) {
+ tmp = 0;
+ tmp |= TMR_PEMASK_TSREEN;
+ iowrite32be(tmp, &regs->tmr_pemask);
+ }
+ }
+
+ /***************MACCFG1***********************/
+ tmp = 0;
+ if (cfg->loopback)
+ tmp |= MACCFG1_LOOPBACK;
+ if (cfg->rx_flow)
+ tmp |= MACCFG1_RX_FLOW;
+ if (cfg->tx_flow)
+ tmp |= MACCFG1_TX_FLOW;
+ iowrite32be(tmp, &regs->maccfg1);
+
+ /***************MACCFG1***********************/
+
+ /***************MACCFG2***********************/
+ tmp = 0;
+
+ if (iface_speed < E_ENET_SPEED_1000)
+ tmp |= MACCFG2_NIBBLE_MODE;
+ else if (iface_speed == E_ENET_SPEED_1000)
+ tmp |= MACCFG2_BYTE_MODE;
+
+ tmp |= ((uint32_t) cfg->preamble_len & 0x0000000f)
+ << PREAMBLE_LENGTH_SHIFT;
+
+ if (cfg->rx_preamble)
+ tmp |= MACCFG2_PRE_AM_Rx_EN;
+ if (cfg->tx_preamble)
+ tmp |= MACCFG2_PRE_AM_Tx_EN;
+ if (cfg->rx_len_check)
+ tmp |= MACCFG2_LENGTH_CHECK;
+ if (cfg->tx_pad_crc)
+ tmp |= MACCFG2_PAD_CRC_EN;
+ if (cfg->tx_crc)
+ tmp |= MACCFG2_CRC_EN;
+ if (!cfg->halfdup_on)
+ tmp |= MACCFG2_FULL_DUPLEX;
+ iowrite32be(tmp, &regs->maccfg2);
+
+ /***************MACCFG2***********************/
+
+ /***************IPGIFG************************/
+ tmp = (((cfg->non_back_to_back_ipg1 <<
+ IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT)
+ & IPGIFG_NON_BACK_TO_BACK_IPG_1)
+ | ((cfg->non_back_to_back_ipg2 <<
+ IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT)
+ & IPGIFG_NON_BACK_TO_BACK_IPG_2)
+ | ((cfg->min_ifg_enforcement <<
+ IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT)
+ & IPGIFG_MIN_IFG_ENFORCEMENT)
+ | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG));
+ iowrite32be(tmp, &regs->ipgifg);
+
+ /***************IPGIFG************************/
+
+ /***************HAFDUP************************/
+ tmp = 0;
+
+ if (cfg->halfdup_alt_backoff_en)
+ tmp = (uint32_t)(HAFDUP_ALT_BEB |
+ ((cfg->halfdup_alt_backoff_val & 0x0000000f)
+ << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT));
+ if (cfg->halfdup_bp_no_backoff)
+ tmp |= HAFDUP_BP_NO_BACKOFF;
+ if (cfg->halfdup_no_backoff)
+ tmp |= HAFDUP_NO_BACKOFF;
+ if (cfg->halfdup_excess_defer)
+ tmp |= HAFDUP_EXCESS_DEFER;
+ tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT)
+ & HAFDUP_RETRANSMISSION_MAX);
+ tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW);
+
+ iowrite32be(tmp, &regs->hafdup);
+ /***************HAFDUP************************/
+
+ /***************MAXFRM************************/
+ /* Initialize MAXFRM */
+ iowrite32be(cfg->maximum_frame, &regs->maxfrm);
+
+ /***************MAXFRM************************/
+
+ /***************CAM1************************/
+ iowrite32be(0xffffffff, &regs->cam1);
+ iowrite32be(0xffffffff, &regs->cam2);
+
+ /***************IMASK************************/
+ iowrite32be(exception_mask, &regs->imask);
+ /***************IMASK************************/
+
+ /***************IEVENT************************/
+ iowrite32be(0xffffffff, &regs->ievent);
+
+ /***************MACSTNADDR1/2*****************/
+
+ tmp = (uint32_t)((macaddr[5] << 24) |
+ (macaddr[4] << 16) |
+ (macaddr[3] << 8) |
+ macaddr[2]);
+ iowrite32be(tmp, &regs->macstnaddr1);
+
+ tmp = (uint32_t)((macaddr[1] << 24) |
+ (macaddr[0] << 16));
+ iowrite32be(tmp, &regs->macstnaddr2);
+
+ /***************MACSTNADDR1/2*****************/
+
+ /*****************HASH************************/
+ for (i = 0; i < NUM_OF_HASH_REGS ; i++) {
+ /* Initialize IADDRx */
+ iowrite32be(0, &regs->igaddr[i]);
+ /* Initialize GADDRx */
+ iowrite32be(0, &regs->gaddr[i]);
+ }
+
+ fman_dtsec_reset_stat(regs);
+
+ return 0;
+}
+
+uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs)
+{
+ return (uint16_t)ioread32be(&regs->maxfrm);
+}
+
+void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length)
+{
+ iowrite32be(length, &regs->maxfrm);
+}
+
+void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *adr)
+{
+ uint32_t tmp;
+
+ tmp = (uint32_t)((adr[5] << 24) |
+ (adr[4] << 16) |
+ (adr[3] << 8) |
+ adr[2]);
+ iowrite32be(tmp, &regs->macstnaddr1);
+
+ tmp = (uint32_t)((adr[1] << 24) |
+ (adr[0] << 16));
+ iowrite32be(tmp, &regs->macstnaddr2);
+}
+
+void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr)
+{
+ uint32_t tmp1, tmp2;
+
+ tmp1 = ioread32be(&regs->macstnaddr1);
+ tmp2 = ioread32be(&regs->macstnaddr2);
+
+ macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16);
+ macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24);
+ macaddr[2] = (uint8_t)(tmp1 & 0x000000ff);
+ macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8);
+ macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16);
+ macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24);
+}
+
+void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc, bool mcast, bool ghtx)
+{
+ int32_t bucket;
+ if (ghtx)
+ bucket = (int32_t)((crc >> 23) & 0x1ff);
+ else {
+ bucket = (int32_t)((crc >> 24) & 0xff);
+ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */
+ if (mcast)
+ bucket += 0x100;
+ }
+ fman_dtsec_set_bucket(regs, bucket, TRUE);
+}
+
+void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable)
+{
+ int reg_idx = (bucket >> 5) & 0xf;
+ int bit_idx = bucket & 0x1f;
+ uint32_t bit_mask = 0x80000000 >> bit_idx;
+ uint32_t *reg;
+
+ if (reg_idx > 7)
+ reg = &regs->gaddr[reg_idx-8];
+ else
+ reg = &regs->igaddr[reg_idx];
+
+ if (enable)
+ iowrite32be(ioread32be(reg) | bit_mask, reg);
+ else
+ iowrite32be(ioread32be(reg) & (~bit_mask), reg);
+}
+
+void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, bool ucast)
+{
+ int i;
+ bool ghtx;
+
+ ghtx = (bool)((ioread32be(&regs->rctrl) & RCTRL_GHTX) ? TRUE : FALSE);
+
+ if (ucast || (ghtx && mcast)) {
+ for (i = 0; i < NUM_OF_HASH_REGS; i++)
+ iowrite32be(0, &regs->igaddr[i]);
+ }
+ if (mcast) {
+ for (i = 0; i < NUM_OF_HASH_REGS; i++)
+ iowrite32be(0, &regs->gaddr[i]);
+ }
+}
+
+int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs,
+ uint8_t addr)
+{
+ if (addr > 0 && addr < 32)
+ iowrite32be(addr, &regs->tbipa);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->maccfg2);
+ if (en)
+ tmp |= MACCFG2_MAGIC_PACKET_EN;
+ else
+ tmp &= ~MACCFG2_MAGIC_PACKET_EN;
+ iowrite32be(tmp, &regs->maccfg2);
+}
+
+int fman_dtsec_adjust_link(struct dtsec_regs *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx)
+{
+ uint32_t tmp;
+
+ UNUSED(iface_mode);
+
+ if ((speed == E_ENET_SPEED_1000) && !full_dx)
+ return -EINVAL;
+
+ tmp = ioread32be(&regs->maccfg2);
+ if (!full_dx)
+ tmp &= ~MACCFG2_FULL_DUPLEX;
+ else
+ tmp |= MACCFG2_FULL_DUPLEX;
+
+ tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
+ if (speed < E_ENET_SPEED_1000)
+ tmp |= MACCFG2_NIBBLE_MODE;
+ else if (speed == E_ENET_SPEED_1000)
+ tmp |= MACCFG2_BYTE_MODE;
+ iowrite32be(tmp, &regs->maccfg2);
+
+ tmp = ioread32be(&regs->ecntrl);
+ if (speed == E_ENET_SPEED_100)
+ tmp |= DTSEC_ECNTRL_R100M;
+ else
+ tmp &= ~DTSEC_ECNTRL_R100M;
+ iowrite32be(tmp, &regs->ecntrl);
+
+ return 0;
+}
+
+void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_UPROM;
+ else
+ tmp &= ~RCTRL_UPROM;
+
+ iowrite32be(tmp, &regs->rctrl);
+}
+
+void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->rctrl);
+
+ if (enable)
+ tmp |= RCTRL_MPROM;
+ else
+ tmp &= ~RCTRL_MPROM;
+
+ iowrite32be(tmp, &regs->rctrl);
+}
+
+bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs,
+ uint32_t *car1, uint32_t *car2)
+{
+ /* read carry registers */
+ *car1 = ioread32be(&regs->car1);
+ *car2 = ioread32be(&regs->car2);
+ /* clear carry registers */
+ if (*car1)
+ iowrite32be(*car1, &regs->car1);
+ if (*car2)
+ iowrite32be(*car2, &regs->car2);
+
+ return (bool)((*car1 | *car2) ? TRUE : FALSE);
+}
+
+void fman_dtsec_reset_stat(struct dtsec_regs *regs)
+{
+ /* clear HW counters */
+ iowrite32be(ioread32be(&regs->ecntrl) |
+ DTSEC_ECNTRL_CLRCNT, &regs->ecntrl);
+}
+
+int fman_dtsec_set_stat_level(struct dtsec_regs *regs, enum dtsec_stat_level level)
+{
+ switch (level) {
+ case E_MAC_STAT_NONE:
+ iowrite32be(0xffffffff, &regs->cam1);
+ iowrite32be(0xffffffff, &regs->cam2);
+ iowrite32be(ioread32be(&regs->ecntrl) & ~DTSEC_ECNTRL_STEN,
+ &regs->ecntrl);
+ iowrite32be(ioread32be(&regs->imask) & ~DTSEC_IMASK_MSROEN,
+ &regs->imask);
+ break;
+ case E_MAC_STAT_PARTIAL:
+ iowrite32be(CAM1_ERRORS_ONLY, &regs->cam1);
+ iowrite32be(CAM2_ERRORS_ONLY, &regs->cam2);
+ iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
+ &regs->ecntrl);
+ iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
+ &regs->imask);
+ break;
+ case E_MAC_STAT_MIB_GRP1:
+ iowrite32be((uint32_t)~CAM1_MIB_GRP_1, &regs->cam1);
+ iowrite32be((uint32_t)~CAM2_MIB_GRP_1, &regs->cam2);
+ iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
+ &regs->ecntrl);
+ iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
+ &regs->imask);
+ break;
+ case E_MAC_STAT_FULL:
+ iowrite32be(0, &regs->cam1);
+ iowrite32be(0, &regs->cam2);
+ iowrite32be(ioread32be(&regs->ecntrl) | DTSEC_ECNTRL_STEN,
+ &regs->ecntrl);
+ iowrite32be(ioread32be(&regs->imask) | DTSEC_IMASK_MSROEN,
+ &regs->imask);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en)
+{
+ if (en) {
+ iowrite32be(ioread32be(&regs->rctrl) | RCTRL_RTSE,
+ &regs->rctrl);
+ iowrite32be(ioread32be(&regs->tctrl) | DTSEC_TCTRL_TTSE,
+ &regs->tctrl);
+ } else {
+ iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_RTSE,
+ &regs->rctrl);
+ iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_TTSE,
+ &regs->tctrl);
+ }
+}
+
+void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->maccfg1);
+
+ if (apply_rx)
+ tmp |= MACCFG1_RX_EN ;
+
+ if (apply_tx)
+ tmp |= MACCFG1_TX_EN ;
+
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, uint8_t paddr_num)
+{
+ iowrite32be(0, &regs->macaddr[paddr_num].exact_match1);
+ iowrite32be(0, &regs->macaddr[paddr_num].exact_match2);
+}
+
+void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs,
+ uint64_t addr,
+ uint8_t paddr_num)
+{
+ uint32_t tmp;
+
+ tmp = (uint32_t)(addr);
+ /* swap */
+ tmp = (((tmp & 0x000000FF) << 24) |
+ ((tmp & 0x0000FF00) << 8) |
+ ((tmp & 0x00FF0000) >> 8) |
+ ((tmp & 0xFF000000) >> 24));
+ iowrite32be(tmp, &regs->macaddr[paddr_num].exact_match1);
+
+ tmp = (uint32_t)(addr>>32);
+ /* swap */
+ tmp = (((tmp & 0x000000FF) << 24) |
+ ((tmp & 0x0000FF00) << 8) |
+ ((tmp & 0x00FF0000) >> 8) |
+ ((tmp & 0xFF000000) >> 24));
+ iowrite32be(tmp, &regs->macaddr[paddr_num].exact_match2);
+}
+
+void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->maccfg1);
+
+ if (apply_rx)
+ tmp &= ~MACCFG1_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~MACCFG1_TX_EN;
+
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time)
+{
+ uint32_t ptv = 0;
+
+ /* fixme: don't enable tx pause for half-duplex */
+
+ if (time) {
+ ptv = ioread32be(&regs->ptv);
+ ptv &= 0xffff0000;
+ ptv |= time & 0x0000ffff;
+ iowrite32be(ptv, &regs->ptv);
+
+ /* trigger the transmission of a flow-control pause frame */
+ iowrite32be(ioread32be(&regs->maccfg1) | MACCFG1_TX_FLOW,
+ &regs->maccfg1);
+ } else
+ iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
+ &regs->maccfg1);
+}
+
+void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en)
+{
+ uint32_t tmp;
+
+ /* todo: check if mac is set to full-duplex */
+
+ tmp = ioread32be(&regs->maccfg1);
+ if (en)
+ tmp |= MACCFG1_RX_FLOW;
+ else
+ tmp &= ~MACCFG1_RX_FLOW;
+ iowrite32be(tmp, &regs->maccfg1);
+}
+
+uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs)
+{
+ return ioread32be(&regs->rctrl);
+}
+
+uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs)
+{
+ return ioread32be(&regs->tsec_id);
+}
+
+uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs)
+{
+ uint32_t event;
+
+ event = ioread32be(&regs->tmr_pevent);
+ event &= ioread32be(&regs->tmr_pemask);
+
+ if (event)
+ iowrite32be(event, &regs->tmr_pevent);
+ return event;
+}
+
+void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs *regs)
+{
+ iowrite32be(ioread32be(&regs->tmr_pemask) | TMR_PEMASK_TSREEN,
+ &regs->tmr_pemask);
+}
+
+void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs)
+{
+ iowrite32be(ioread32be(&regs->tmr_pemask) & ~TMR_PEMASK_TSREEN,
+ &regs->tmr_pemask);
+}
+
+void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
+}
+
+void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->imask);
+}
+
+uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs,
+ enum dtsec_stat_counters reg_name)
+{
+ uint32_t ret_val;
+
+ switch (reg_name) {
+ case E_DTSEC_STAT_TR64:
+ ret_val = ioread32be(&regs->tr64);
+ break;
+ case E_DTSEC_STAT_TR127:
+ ret_val = ioread32be(&regs->tr127);
+ break;
+ case E_DTSEC_STAT_TR255:
+ ret_val = ioread32be(&regs->tr255);
+ break;
+ case E_DTSEC_STAT_TR511:
+ ret_val = ioread32be(&regs->tr511);
+ break;
+ case E_DTSEC_STAT_TR1K:
+ ret_val = ioread32be(&regs->tr1k);
+ break;
+ case E_DTSEC_STAT_TRMAX:
+ ret_val = ioread32be(&regs->trmax);
+ break;
+ case E_DTSEC_STAT_TRMGV:
+ ret_val = ioread32be(&regs->trmgv);
+ break;
+ case E_DTSEC_STAT_RBYT:
+ ret_val = ioread32be(&regs->rbyt);
+ break;
+ case E_DTSEC_STAT_RPKT:
+ ret_val = ioread32be(&regs->rpkt);
+ break;
+ case E_DTSEC_STAT_RMCA:
+ ret_val = ioread32be(&regs->rmca);
+ break;
+ case E_DTSEC_STAT_RBCA:
+ ret_val = ioread32be(&regs->rbca);
+ break;
+ case E_DTSEC_STAT_RXPF:
+ ret_val = ioread32be(&regs->rxpf);
+ break;
+ case E_DTSEC_STAT_RALN:
+ ret_val = ioread32be(&regs->raln);
+ break;
+ case E_DTSEC_STAT_RFLR:
+ ret_val = ioread32be(&regs->rflr);
+ break;
+ case E_DTSEC_STAT_RCDE:
+ ret_val = ioread32be(&regs->rcde);
+ break;
+ case E_DTSEC_STAT_RCSE:
+ ret_val = ioread32be(&regs->rcse);
+ break;
+ case E_DTSEC_STAT_RUND:
+ ret_val = ioread32be(&regs->rund);
+ break;
+ case E_DTSEC_STAT_ROVR:
+ ret_val = ioread32be(&regs->rovr);
+ break;
+ case E_DTSEC_STAT_RFRG:
+ ret_val = ioread32be(&regs->rfrg);
+ break;
+ case E_DTSEC_STAT_RJBR:
+ ret_val = ioread32be(&regs->rjbr);
+ break;
+ case E_DTSEC_STAT_RDRP:
+ ret_val = ioread32be(&regs->rdrp);
+ break;
+ case E_DTSEC_STAT_TFCS:
+ ret_val = ioread32be(&regs->tfcs);
+ break;
+ case E_DTSEC_STAT_TBYT:
+ ret_val = ioread32be(&regs->tbyt);
+ break;
+ case E_DTSEC_STAT_TPKT:
+ ret_val = ioread32be(&regs->tpkt);
+ break;
+ case E_DTSEC_STAT_TMCA:
+ ret_val = ioread32be(&regs->tmca);
+ break;
+ case E_DTSEC_STAT_TBCA:
+ ret_val = ioread32be(&regs->tbca);
+ break;
+ case E_DTSEC_STAT_TXPF:
+ ret_val = ioread32be(&regs->txpf);
+ break;
+ case E_DTSEC_STAT_TNCL:
+ ret_val = ioread32be(&regs->tncl);
+ break;
+ case E_DTSEC_STAT_TDRP:
+ ret_val = ioread32be(&regs->tdrp);
+ break;
+ default:
+ ret_val = 0;
+ }
+
+ return ret_val;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
new file mode 100644
index 000000000000..54e7b4a60669
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "common/general.h"
+#include "fsl_fman_dtsec_mii_acc.h"
+
+
+/**
+ * dtsec_mii_get_div() - calculates the value of the dtsec mii divider
+ * @dtsec_freq: dtsec clock frequency (in Mhz)
+ *
+ * This function calculates the dtsec mii clock divider that determines
+ * the MII MDC clock. MII MDC clock will be set to work in the range
+ * of 1.5 to 2.5Mhz
+ * The output of this function is the value of MIIMCFG[MgmtClk] which
+ * implicitly determines the divider value.
+ * Note: the dTSEC system clock is equal to 1/2 of the FMan clock.
+ *
+ * The table below which reflects dtsec_mii_get_div() functionality
+ * shows the relations among dtsec_freq, MgmtClk, actual divider
+ * and the MII frequency:
+ *
+ * dtsec freq MgmtClk div MII freq Mhz
+ * [0.....80] 1 (1/4)(1/8) [0 to 2.5]
+ * [81...120] 2 (1/6)(1/8) [1.6 to 2.5]
+ * [121..160] 3 (1/8)(1/8) [1.8 to 2.5]
+ * [161..200] 4 (1/10)(1/8) [2.0 to 2.5]
+ * [201..280] 5 (1/14)(1/8) [1.8 to 2.5]
+ * [281..400] 6 (1/20)(1/8) [1.1 to 2.5]
+ * [401..560] 7 (1/28)(1/8) [1.8 to 2.5]
+ * [560..frq] 7 (1/28)(1/8) [frq/224]
+ *
+ * Returns: the MIIMCFG[MgmtClk] appropriate value
+ */
+
+static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq)
+{
+ uint16_t mgmt_clk;
+
+ if (dtsec_freq < 80) mgmt_clk = 1;
+ else if (dtsec_freq < 120) mgmt_clk = 2;
+ else if (dtsec_freq < 160) mgmt_clk = 3;
+ else if (dtsec_freq < 200) mgmt_clk = 4;
+ else if (dtsec_freq < 280) mgmt_clk = 5;
+ else if (dtsec_freq < 400) mgmt_clk = 6;
+ else mgmt_clk = 7;
+
+ return (uint8_t)mgmt_clk;
+}
+
+void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs)
+{
+ /* Reset the management interface */
+ iowrite32be(ioread32be(&regs->miimcfg) | MIIMCFG_RESET_MGMT,
+ &regs->miimcfg);
+ iowrite32be(ioread32be(&regs->miimcfg) & ~MIIMCFG_RESET_MGMT,
+ &regs->miimcfg);
+}
+
+
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr,
+ uint8_t reg, uint16_t data, uint16_t dtsec_freq)
+{
+ uint32_t tmp;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
+ wmb();
+
+ /* Stop the MII management read cycle */
+ iowrite32be(0, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->miimcom);
+ wmb();
+
+ /* Setting up MII Management Address Register */
+ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, &regs->miimadd);
+ wmb();
+
+ /* Setting up MII Management Control Register with data */
+ iowrite32be((uint32_t)data, &regs->miimcon);
+ /* Dummy read to make sure MIIMCON is written */
+ tmp = ioread32be(&regs->miimcon);
+ wmb();
+
+ /* Wait until MII management write is complete */
+ /* todo: a timeout could be useful here */
+ while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
+ /* busy wait */;
+
+ return 0;
+}
+
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t addr,
+ uint8_t reg, uint16_t *data, uint16_t dtsec_freq)
+{
+ uint32_t tmp;
+
+ /* Setup the MII Mgmt clock speed */
+ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
+ wmb();
+
+ /* Setting up the MII Management Address Register */
+ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
+ iowrite32be(tmp, &regs->miimadd);
+ wmb();
+
+ /* Perform an MII management read cycle */
+ iowrite32be(MIIMCOM_READ_CYCLE, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->miimcom);
+ wmb();
+
+ /* Wait until MII management read is complete */
+ /* todo: a timeout could be useful here */
+ while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
+ /* busy wait */;
+
+ /* Read MII management status */
+ *data = (uint16_t)ioread32be(&regs->miimstat);
+ wmb();
+
+ iowrite32be(0, &regs->miimcom);
+ /* Dummy read to make sure MIIMCOM is written */
+ tmp = ioread32be(&regs->miimcom);
+
+ if (*data == 0xffff)
+ return -ENXIO;
+
+ return 0;
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
new file mode 100644
index 000000000000..f31a92a2bc0b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_memac.h"
+
+
+uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+void fman_memac_set_promiscuous(struct memac_regs *regs, bool val)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs *regs,
+ uint8_t paddr_num)
+{
+ if (paddr_num == 0) {
+ iowrite32be(0, &regs->mac_addr0.mac_addr_l);
+ iowrite32be(0, &regs->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_l);
+ iowrite32be(0x0, &regs->mac_addr[paddr_num - 1].mac_addr_u);
+ }
+}
+
+void fman_memac_add_addr_in_paddr(struct memac_regs *regs,
+ uint8_t *adr,
+ uint8_t paddr_num)
+{
+ uint32_t tmp0, tmp1;
+
+ tmp0 = (uint32_t)(adr[0] |
+ adr[1] << 8 |
+ adr[2] << 16 |
+ adr[3] << 24);
+ tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
+
+ if (paddr_num == 0) {
+ iowrite32be(tmp0, &regs->mac_addr0.mac_addr_l);
+ iowrite32be(tmp1, &regs->mac_addr0.mac_addr_u);
+ } else {
+ iowrite32be(tmp0, &regs->mac_addr[paddr_num-1].mac_addr_l);
+ iowrite32be(tmp1, &regs->mac_addr[paddr_num-1].mac_addr_u);
+ }
+}
+
+void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (apply_rx)
+ tmp &= ~CMD_CFG_RX_EN;
+
+ if (apply_tx)
+ tmp &= ~CMD_CFG_TX_EN;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_reset_stat(struct memac_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->statn_config);
+
+ tmp |= STATS_CFG_CLR;
+
+ iowrite32be(tmp, &regs->statn_config);
+
+ while (ioread32be(&regs->statn_config) & STATS_CFG_CLR);
+}
+
+void fman_memac_reset(struct memac_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ tmp |= CMD_CFG_SW_RESET;
+
+ iowrite32be(tmp, &regs->command_config);
+
+ while (ioread32be(&regs->command_config) & CMD_CFG_SW_RESET);
+}
+
+int fman_memac_init(struct memac_regs *regs,
+ struct memac_cfg *cfg,
+ enum enet_interface enet_interface,
+ enum enet_speed enet_speed,
+ bool slow_10g_if,
+ uint32_t exceptions)
+{
+ uint32_t tmp;
+
+ /* Config */
+ tmp = 0;
+ if (cfg->wan_mode_enable)
+ tmp |= CMD_CFG_WAN_MODE;
+ if (cfg->promiscuous_mode_enable)
+ tmp |= CMD_CFG_PROMIS_EN;
+ if (cfg->pause_forward_enable)
+ tmp |= CMD_CFG_PAUSE_FWD;
+ if (cfg->pause_ignore)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ if (cfg->tx_addr_ins_enable)
+ tmp |= CMD_CFG_TX_ADDR_INS;
+ if (cfg->loopback_enable)
+ tmp |= CMD_CFG_LOOPBACK_EN;
+ if (cfg->cmd_frame_enable)
+ tmp |= CMD_CFG_CNT_FRM_EN;
+ if (cfg->send_idle_enable)
+ tmp |= CMD_CFG_SEND_IDLE;
+ if (cfg->no_length_check_enable)
+ tmp |= CMD_CFG_NO_LEN_CHK;
+ if (cfg->rx_sfd_any)
+ tmp |= CMD_CFG_SFD_ANY;
+ if (cfg->pad_enable)
+ tmp |= CMD_CFG_TX_PAD_EN;
+ if (cfg->wake_on_lan)
+ tmp |= CMD_CFG_MG;
+
+ tmp |= CMD_CFG_CRC_FWD;
+
+ iowrite32be(tmp, &regs->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((uint32_t)cfg->max_frame_length, &regs->maxfrm);
+
+ /* Pause Time */
+ iowrite32be((uint32_t)cfg->pause_quanta, &regs->pause_quanta[0]);
+ iowrite32be((uint32_t)0, &regs->pause_thresh[0]);
+
+ /* IF_MODE */
+ tmp = 0;
+ switch (enet_interface) {
+ case E_ENET_IF_XGMII:
+ case E_ENET_IF_XFI:
+ tmp |= IF_MODE_XGMII;
+ break;
+ default:
+ tmp |= IF_MODE_GMII;
+ if (enet_interface == E_ENET_IF_RGMII && !cfg->loopback_enable)
+ tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO;
+ }
+ iowrite32be(tmp, &regs->if_mode);
+
+ /* TX_FIFO_SECTIONS */
+ tmp = 0;
+ if (enet_interface == E_ENET_IF_XGMII ||
+ enet_interface == E_ENET_IF_XFI) {
+ if(slow_10g_if) {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
+ } else {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
+ }
+ } else {
+ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G |
+ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G);
+ }
+ iowrite32be(tmp, &regs->tx_fifo_sections);
+
+ /* clear all pending events and set-up interrupts */
+ fman_memac_ack_event(regs, 0xffffffff);
+ fman_memac_set_exception(regs, exceptions, TRUE);
+
+ return 0;
+}
+
+void fman_memac_set_exception(struct memac_regs *regs, uint32_t val, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->imask);
+ if (enable)
+ tmp |= val;
+ else
+ tmp &= ~val;
+
+ iowrite32be(tmp, &regs->imask);
+}
+
+void fman_memac_reset_filter_table(struct memac_regs *regs)
+{
+ uint32_t i;
+ for (i = 0; i < 64; i++)
+ iowrite32be(i & ~HASH_CTRL_MCAST_EN, &regs->hashtable_ctrl);
+}
+
+void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc)
+{
+ iowrite32be(crc | HASH_CTRL_MCAST_EN, &regs->hashtable_ctrl);
+}
+
+void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val)
+{
+ iowrite32be(val, &regs->hashtable_ctrl);
+}
+
+uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->maxfrm);
+
+ return(uint16_t)tmp;
+}
+
+
+void fman_memac_set_tx_pause_frames(struct memac_regs *regs,
+ uint8_t priority,
+ uint16_t pause_time,
+ uint16_t thresh_time)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->tx_fifo_sections);
+
+ if (priority == 0xff) {
+ GET_TX_EMPTY_DEFAULT_VALUE(tmp);
+ iowrite32be(tmp, &regs->tx_fifo_sections);
+
+ tmp = ioread32be(&regs->command_config);
+ tmp &= ~CMD_CFG_PFC_MODE;
+ priority = 0;
+ } else {
+ GET_TX_EMPTY_PFC_VALUE(tmp);
+ iowrite32be(tmp, &regs->tx_fifo_sections);
+
+ tmp = ioread32be(&regs->command_config);
+ tmp |= CMD_CFG_PFC_MODE;
+ }
+
+ iowrite32be(tmp, &regs->command_config);
+
+ tmp = ioread32be(&regs->pause_quanta[priority / 2]);
+ if (priority % 2)
+ tmp &= 0x0000FFFF;
+ else
+ tmp &= 0xFFFF0000;
+ tmp |= ((uint32_t)pause_time << (16 * (priority % 2)));
+ iowrite32be(tmp, &regs->pause_quanta[priority / 2]);
+
+ tmp = ioread32be(&regs->pause_thresh[priority / 2]);
+ if (priority % 2)
+ tmp &= 0x0000FFFF;
+ else
+ tmp &= 0xFFFF0000;
+ tmp |= ((uint32_t)thresh_time<<(16 * (priority % 2)));
+ iowrite32be(tmp, &regs->pause_thresh[priority / 2]);
+}
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs,bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (enable)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_memac_set_wol(struct memac_regs *regs, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ if (enable)
+ tmp |= CMD_CFG_MG;
+ else
+ tmp &= ~CMD_CFG_MG;
+
+ iowrite32be(tmp, &regs->command_config);
+}
+
+#define GET_MEMAC_CNTR_64(bn) \
+ (ioread32be(&regs->bn ## _l) | \
+ ((uint64_t)ioread32be(&regs->bn ## _u) << 32))
+
+uint64_t fman_memac_get_counter(struct memac_regs *regs,
+ enum memac_counters reg_name)
+{
+ uint64_t ret_val;
+
+ switch (reg_name) {
+ case E_MEMAC_COUNTER_R64:
+ ret_val = GET_MEMAC_CNTR_64(r64);
+ break;
+ case E_MEMAC_COUNTER_T64:
+ ret_val = GET_MEMAC_CNTR_64(t64);
+ break;
+ case E_MEMAC_COUNTER_R127:
+ ret_val = GET_MEMAC_CNTR_64(r127);
+ break;
+ case E_MEMAC_COUNTER_T127:
+ ret_val = GET_MEMAC_CNTR_64(t127);
+ break;
+ case E_MEMAC_COUNTER_R255:
+ ret_val = GET_MEMAC_CNTR_64(r255);
+ break;
+ case E_MEMAC_COUNTER_T255:
+ ret_val = GET_MEMAC_CNTR_64(t255);
+ break;
+ case E_MEMAC_COUNTER_R511:
+ ret_val = GET_MEMAC_CNTR_64(r511);
+ break;
+ case E_MEMAC_COUNTER_T511:
+ ret_val = GET_MEMAC_CNTR_64(t511);
+ break;
+ case E_MEMAC_COUNTER_R1023:
+ ret_val = GET_MEMAC_CNTR_64(r1023);
+ break;
+ case E_MEMAC_COUNTER_T1023:
+ ret_val = GET_MEMAC_CNTR_64(t1023);
+ break;
+ case E_MEMAC_COUNTER_R1518:
+ ret_val = GET_MEMAC_CNTR_64(r1518);
+ break;
+ case E_MEMAC_COUNTER_T1518:
+ ret_val = GET_MEMAC_CNTR_64(t1518);
+ break;
+ case E_MEMAC_COUNTER_R1519X:
+ ret_val = GET_MEMAC_CNTR_64(r1519x);
+ break;
+ case E_MEMAC_COUNTER_T1519X:
+ ret_val = GET_MEMAC_CNTR_64(t1519x);
+ break;
+ case E_MEMAC_COUNTER_RFRG:
+ ret_val = GET_MEMAC_CNTR_64(rfrg);
+ break;
+ case E_MEMAC_COUNTER_RJBR:
+ ret_val = GET_MEMAC_CNTR_64(rjbr);
+ break;
+ case E_MEMAC_COUNTER_RDRP:
+ ret_val = GET_MEMAC_CNTR_64(rdrp);
+ break;
+ case E_MEMAC_COUNTER_RALN:
+ ret_val = GET_MEMAC_CNTR_64(raln);
+ break;
+ case E_MEMAC_COUNTER_TUND:
+ ret_val = GET_MEMAC_CNTR_64(tund);
+ break;
+ case E_MEMAC_COUNTER_ROVR:
+ ret_val = GET_MEMAC_CNTR_64(rovr);
+ break;
+ case E_MEMAC_COUNTER_RXPF:
+ ret_val = GET_MEMAC_CNTR_64(rxpf);
+ break;
+ case E_MEMAC_COUNTER_TXPF:
+ ret_val = GET_MEMAC_CNTR_64(txpf);
+ break;
+ case E_MEMAC_COUNTER_ROCT:
+ ret_val = GET_MEMAC_CNTR_64(roct);
+ break;
+ case E_MEMAC_COUNTER_RMCA:
+ ret_val = GET_MEMAC_CNTR_64(rmca);
+ break;
+ case E_MEMAC_COUNTER_RBCA:
+ ret_val = GET_MEMAC_CNTR_64(rbca);
+ break;
+ case E_MEMAC_COUNTER_RPKT:
+ ret_val = GET_MEMAC_CNTR_64(rpkt);
+ break;
+ case E_MEMAC_COUNTER_RUCA:
+ ret_val = GET_MEMAC_CNTR_64(ruca);
+ break;
+ case E_MEMAC_COUNTER_RERR:
+ ret_val = GET_MEMAC_CNTR_64(rerr);
+ break;
+ case E_MEMAC_COUNTER_TOCT:
+ ret_val = GET_MEMAC_CNTR_64(toct);
+ break;
+ case E_MEMAC_COUNTER_TMCA:
+ ret_val = GET_MEMAC_CNTR_64(tmca);
+ break;
+ case E_MEMAC_COUNTER_TBCA:
+ ret_val = GET_MEMAC_CNTR_64(tbca);
+ break;
+ case E_MEMAC_COUNTER_TUCA:
+ ret_val = GET_MEMAC_CNTR_64(tuca);
+ break;
+ case E_MEMAC_COUNTER_TERR:
+ ret_val = GET_MEMAC_CNTR_64(terr);
+ break;
+ default:
+ ret_val = 0;
+ }
+
+ return ret_val;
+}
+
+void fman_memac_adjust_link(struct memac_regs *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->if_mode);
+
+ if (full_dx)
+ tmp &= ~IF_MODE_HD;
+ else
+ tmp |= IF_MODE_HD;
+
+ if (iface_mode == E_ENET_IF_RGMII) {
+ /* Configure RGMII in manual mode */
+ tmp &= ~IF_MODE_RGMII_AUTO;
+ tmp &= ~IF_MODE_RGMII_SP_MASK;
+
+ if (full_dx)
+ tmp |= IF_MODE_RGMII_FD;
+ else
+ tmp &= ~IF_MODE_RGMII_FD;
+
+ switch (speed) {
+ case E_ENET_SPEED_1000:
+ tmp |= IF_MODE_RGMII_1000;
+ break;
+ case E_ENET_SPEED_100:
+ tmp |= IF_MODE_RGMII_100;
+ break;
+ case E_ENET_SPEED_10:
+ tmp |= IF_MODE_RGMII_10;
+ break;
+ default:
+ break;
+ }
+ }
+
+ iowrite32be(tmp, &regs->if_mode);
+}
+
+void fman_memac_defconfig(struct memac_cfg *cfg)
+{
+ cfg->reset_on_init = FALSE;
+ cfg->wan_mode_enable = FALSE;
+ cfg->promiscuous_mode_enable = FALSE;
+ cfg->pause_forward_enable = FALSE;
+ cfg->pause_ignore = FALSE;
+ cfg->tx_addr_ins_enable = FALSE;
+ cfg->loopback_enable = FALSE;
+ cfg->cmd_frame_enable = FALSE;
+ cfg->rx_error_discard = FALSE;
+ cfg->send_idle_enable = FALSE;
+ cfg->no_length_check_enable = TRUE;
+ cfg->lgth_check_nostdr = FALSE;
+ cfg->time_stamp_enable = FALSE;
+ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
+ cfg->max_frame_length = DEFAULT_FRAME_LENGTH;
+ cfg->pause_quanta = DEFAULT_PAUSE_QUANTA;
+ cfg->pad_enable = TRUE;
+ cfg->phy_tx_ena_on = FALSE;
+ cfg->rx_sfd_any = FALSE;
+ cfg->rx_pbl_fwd = FALSE;
+ cfg->tx_pbl_fwd = FALSE;
+ cfg->debug_mode = FALSE;
+ cfg->wake_on_lan = FALSE;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
new file mode 100755
index 000000000000..e785e4c111af
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "fsl_fman_memac_mii_acc.h"
+
+static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ /* Leave only MDIO_CLK_DIV bits set on */
+ tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
+ /* Set maximum MDIO_HOLD value to allow phy to see
+ change of data signal */
+ tmp_reg |= MDIO_CFG_HOLD_MASK;
+ /* Add 10G interface mode */
+ tmp_reg |= MDIO_CFG_ENC45;
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Specify phy and register to be accessed */
+ iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
+ iowrite32be(reg, &mii_regs->mdio_addr);
+ wmb();
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Write data */
+ iowrite32be(data, &mii_regs->mdio_data);
+ wmb();
+
+ /* Wait for write transaction end */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+}
+
+static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t *data)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ /* Leave only MDIO_CLK_DIV bits set on */
+ tmp_reg &= MDIO_CFG_CLK_DIV_MASK;
+ /* Set maximum MDIO_HOLD value to allow phy to see
+ change of data signal */
+ tmp_reg |= MDIO_CFG_HOLD_MASK;
+ /* Add 10G interface mode */
+ tmp_reg |= MDIO_CFG_ENC45;
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Specify phy and register to be accessed */
+ iowrite32be(phy_addr, &mii_regs->mdio_ctrl);
+ iowrite32be(reg, &mii_regs->mdio_addr);
+ wmb();
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Read cycle */
+ tmp_reg = phy_addr;
+ tmp_reg |= MDIO_CTL_READ;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+ wmb();
+
+ /* Wait for data to be available */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+
+ *data = (uint16_t)ioread32be(&mii_regs->mdio_data);
+
+ /* Check if there was an error */
+ return ioread32be(&mii_regs->mdio_cfg);
+}
+
+static void write_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data)
+{
+ uint32_t tmp_reg;
+
+ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Write transaction */
+ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
+ tmp_reg |= reg;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ iowrite32be(data, &mii_regs->mdio_data);
+
+ wmb();
+
+ /* Wait for write transaction to end */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+}
+
+static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t *data)
+{
+ uint32_t tmp_reg;
+
+ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */
+ tmp_reg = ioread32be(&mii_regs->mdio_cfg);
+ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK);
+ iowrite32be(tmp_reg, &mii_regs->mdio_cfg);
+
+ /* Wait for command completion */
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Read transaction */
+ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT);
+ tmp_reg |= reg;
+ tmp_reg |= MDIO_CTL_READ;
+ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl);
+
+ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY)
+ udelay(1);
+
+ /* Wait for data to be available */
+ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY)
+ udelay(1);
+
+ *data = (uint16_t)ioread32be(&mii_regs->mdio_data);
+
+ /* Check error */
+ return ioread32be(&mii_regs->mdio_cfg);
+}
+
+/*****************************************************************************/
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data,
+ enum enet_speed enet_speed)
+{
+ /* Figure out interface type - 10G vs 1G.
+ In 10G interface both phy_addr and devAddr present. */
+ if (enet_speed == E_ENET_SPEED_10000)
+ write_phy_reg_10g(mii_regs, phy_addr, reg, data);
+ else
+ write_phy_reg_1g(mii_regs, phy_addr, reg, data);
+
+ return 0;
+}
+
+/*****************************************************************************/
+int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t *data,
+ enum enet_speed enet_speed)
+{
+ uint32_t ans;
+ /* Figure out interface type - 10G vs 1G.
+ In 10G interface both phy_addr and devAddr present. */
+ if (enet_speed == E_ENET_SPEED_10000)
+ ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data);
+ else
+ ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data);
+
+ if (ans & MDIO_CFG_READ_ERR)
+ return -EINVAL;
+ return 0;
+}
+
+/* ......................................................................... */
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c
new file mode 100644
index 000000000000..fff9d5de80e3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_tgec.h"
+
+
+void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *adr)
+{
+ uint32_t tmp0, tmp1;
+
+ tmp0 = (uint32_t)(adr[0] |
+ adr[1] << 8 |
+ adr[2] << 16 |
+ adr[3] << 24);
+ tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
+ iowrite32be(tmp0, &regs->mac_addr_0);
+ iowrite32be(tmp1, &regs->mac_addr_1);
+}
+
+void fman_tgec_reset_stat(struct tgec_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+
+ tmp |= CMD_CFG_STAT_CLR;
+
+ iowrite32be(tmp, &regs->command_config);
+
+ while (ioread32be(&regs->command_config) & CMD_CFG_STAT_CLR) ;
+}
+
+#define GET_TGEC_CNTR_64(bn) \
+ (((uint64_t)ioread32be(&regs->bn ## _u) << 32) | \
+ ioread32be(&regs->bn ## _l))
+
+uint64_t fman_tgec_get_counter(struct tgec_regs *regs, enum tgec_counters reg_name)
+{
+ uint64_t ret_val;
+
+ switch (reg_name) {
+ case E_TGEC_COUNTER_R64:
+ ret_val = GET_TGEC_CNTR_64(r64);
+ break;
+ case E_TGEC_COUNTER_R127:
+ ret_val = GET_TGEC_CNTR_64(r127);
+ break;
+ case E_TGEC_COUNTER_R255:
+ ret_val = GET_TGEC_CNTR_64(r255);
+ break;
+ case E_TGEC_COUNTER_R511:
+ ret_val = GET_TGEC_CNTR_64(r511);
+ break;
+ case E_TGEC_COUNTER_R1023:
+ ret_val = GET_TGEC_CNTR_64(r1023);
+ break;
+ case E_TGEC_COUNTER_R1518:
+ ret_val = GET_TGEC_CNTR_64(r1518);
+ break;
+ case E_TGEC_COUNTER_R1519X:
+ ret_val = GET_TGEC_CNTR_64(r1519x);
+ break;
+ case E_TGEC_COUNTER_TRFRG:
+ ret_val = GET_TGEC_CNTR_64(trfrg);
+ break;
+ case E_TGEC_COUNTER_TRJBR:
+ ret_val = GET_TGEC_CNTR_64(trjbr);
+ break;
+ case E_TGEC_COUNTER_RDRP:
+ ret_val = GET_TGEC_CNTR_64(rdrp);
+ break;
+ case E_TGEC_COUNTER_RALN:
+ ret_val = GET_TGEC_CNTR_64(raln);
+ break;
+ case E_TGEC_COUNTER_TRUND:
+ ret_val = GET_TGEC_CNTR_64(trund);
+ break;
+ case E_TGEC_COUNTER_TROVR:
+ ret_val = GET_TGEC_CNTR_64(trovr);
+ break;
+ case E_TGEC_COUNTER_RXPF:
+ ret_val = GET_TGEC_CNTR_64(rxpf);
+ break;
+ case E_TGEC_COUNTER_TXPF:
+ ret_val = GET_TGEC_CNTR_64(txpf);
+ break;
+ case E_TGEC_COUNTER_ROCT:
+ ret_val = GET_TGEC_CNTR_64(roct);
+ break;
+ case E_TGEC_COUNTER_RMCA:
+ ret_val = GET_TGEC_CNTR_64(rmca);
+ break;
+ case E_TGEC_COUNTER_RBCA:
+ ret_val = GET_TGEC_CNTR_64(rbca);
+ break;
+ case E_TGEC_COUNTER_RPKT:
+ ret_val = GET_TGEC_CNTR_64(rpkt);
+ break;
+ case E_TGEC_COUNTER_RUCA:
+ ret_val = GET_TGEC_CNTR_64(ruca);
+ break;
+ case E_TGEC_COUNTER_RERR:
+ ret_val = GET_TGEC_CNTR_64(rerr);
+ break;
+ case E_TGEC_COUNTER_TOCT:
+ ret_val = GET_TGEC_CNTR_64(toct);
+ break;
+ case E_TGEC_COUNTER_TMCA:
+ ret_val = GET_TGEC_CNTR_64(tmca);
+ break;
+ case E_TGEC_COUNTER_TBCA:
+ ret_val = GET_TGEC_CNTR_64(tbca);
+ break;
+ case E_TGEC_COUNTER_TUCA:
+ ret_val = GET_TGEC_CNTR_64(tuca);
+ break;
+ case E_TGEC_COUNTER_TERR:
+ ret_val = GET_TGEC_CNTR_64(terr);
+ break;
+ default:
+ ret_val = 0;
+ }
+
+ return ret_val;
+}
+
+void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (apply_rx)
+ tmp |= CMD_CFG_RX_EN;
+ if (apply_tx)
+ tmp |= CMD_CFG_TX_EN;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx)
+{
+ uint32_t tmp_reg_32;
+
+ tmp_reg_32 = ioread32be(&regs->command_config);
+ if (apply_rx)
+ tmp_reg_32 &= ~CMD_CFG_RX_EN;
+ if (apply_tx)
+ tmp_reg_32 &= ~CMD_CFG_TX_EN;
+ iowrite32be(tmp_reg_32, &regs->command_config);
+}
+
+void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (val)
+ tmp |= CMD_CFG_PROMIS_EN;
+ else
+ tmp &= ~CMD_CFG_PROMIS_EN;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_tgec_reset_filter_table(struct tgec_regs *regs)
+{
+ uint32_t i;
+ for (i = 0; i < 512; i++)
+ iowrite32be(i & ~TGEC_HASH_MCAST_EN, &regs->hashtable_ctrl);
+}
+
+void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc)
+{
+ uint32_t hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */
+ iowrite32be(hash | TGEC_HASH_MCAST_EN, &regs->hashtable_ctrl);
+}
+
+void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value)
+{
+ iowrite32be(value, &regs->hashtable_ctrl);
+}
+
+void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time)
+{
+ iowrite32be((uint32_t)pause_time, &regs->pause_quant);
+}
+
+void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (en)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ else
+ tmp &= ~CMD_CFG_PAUSE_IGNORE;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->command_config);
+ if (en)
+ tmp |= CMD_CFG_EN_TIMESTAMP;
+ else
+ tmp &= ~CMD_CFG_EN_TIMESTAMP;
+ iowrite32be(tmp, &regs->command_config);
+}
+
+uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->ievent) & ev_mask;
+}
+
+void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ev_mask, &regs->ievent);
+}
+
+uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs)
+{
+ return ioread32be(&regs->imask);
+}
+
+void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *adr)
+{
+ uint32_t tmp0, tmp1;
+
+ tmp0 = (uint32_t)(adr[0] |
+ adr[1] << 8 |
+ adr[2] << 16 |
+ adr[3] << 24);
+ tmp1 = (uint32_t)(adr[4] | adr[5] << 8);
+ iowrite32be(tmp0, &regs->mac_addr_2);
+ iowrite32be(tmp1, &regs->mac_addr_3);
+}
+
+void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs)
+{
+ iowrite32be(0, &regs->mac_addr_2);
+ iowrite32be(0, &regs->mac_addr_3);
+}
+
+uint32_t fman_tgec_get_revision(struct tgec_regs *regs)
+{
+ return ioread32be(&regs->tgec_id);
+}
+
+void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) | ev_mask, &regs->imask);
+}
+
+void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask)
+{
+ iowrite32be(ioread32be(&regs->imask) & ~ev_mask, &regs->imask);
+}
+
+uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs)
+{
+ return (uint16_t) ioread32be(&regs->maxfrm);
+}
+
+void fman_tgec_defconfig(struct tgec_cfg *cfg)
+{
+ cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE;
+ cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE;
+ cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE;
+ cfg->pause_ignore = DEFAULT_PAUSE_IGNORE;
+ cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE;
+ cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE;
+ cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE;
+ cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD;
+ cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE;
+ cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE;
+ cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR;
+ cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE;
+ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH;
+ cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH;
+ cfg->pause_quant = DEFAULT_PAUSE_QUANT;
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ cfg->skip_fman11_workaround = FALSE;
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+}
+
+int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg,
+ uint32_t exception_mask)
+{
+ uint32_t tmp;
+
+ /* Config */
+ tmp = 0x40; /* CRC forward */
+ if (cfg->wan_mode_enable)
+ tmp |= CMD_CFG_WAN_MODE;
+ if (cfg->promiscuous_mode_enable)
+ tmp |= CMD_CFG_PROMIS_EN;
+ if (cfg->pause_forward_enable)
+ tmp |= CMD_CFG_PAUSE_FWD;
+ if (cfg->pause_ignore)
+ tmp |= CMD_CFG_PAUSE_IGNORE;
+ if (cfg->tx_addr_ins_enable)
+ tmp |= CMD_CFG_TX_ADDR_INS;
+ if (cfg->loopback_enable)
+ tmp |= CMD_CFG_LOOPBACK_EN;
+ if (cfg->cmd_frame_enable)
+ tmp |= CMD_CFG_CMD_FRM_EN;
+ if (cfg->rx_error_discard)
+ tmp |= CMD_CFG_RX_ER_DISC;
+ if (cfg->send_idle_enable)
+ tmp |= CMD_CFG_SEND_IDLE;
+ if (cfg->no_length_check_enable)
+ tmp |= CMD_CFG_NO_LEN_CHK;
+ if (cfg->time_stamp_enable)
+ tmp |= CMD_CFG_EN_TIMESTAMP;
+ iowrite32be(tmp, &regs->command_config);
+
+ /* Max Frame Length */
+ iowrite32be((uint32_t)cfg->max_frame_length, &regs->maxfrm);
+ /* Pause Time */
+ iowrite32be(cfg->pause_quant, &regs->pause_quant);
+
+ /* clear all pending events and set-up interrupts */
+ fman_tgec_ack_event(regs, 0xffffffff);
+ fman_tgec_enable_interrupt(regs, exception_mask);
+
+ return 0;
+}
+
+void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs *regs)
+{
+ uint32_t tmp;
+
+ /* restore the default tx ipg Length */
+ tmp = (ioread32be(&regs->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12;
+
+ iowrite32be(tmp, &regs->tx_ipg_len);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
new file mode 100644
index 000000000000..0d86f5b05a35
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c
@@ -0,0 +1,1159 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File memac.c
+
+ @Description FM mEMAC driver
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "string_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "endian_ext.h"
+#include "debug_ext.h"
+
+#include "fm_common.h"
+#include "memac.h"
+
+
+/*****************************************************************************/
+/* Internal routines */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
+{
+ uint64_t mask1, mask2;
+ uint32_t xorVal = 0;
+ uint8_t i, j;
+
+ for (i=0; i<6; i++)
+ {
+ mask1 = ethAddr & (uint64_t)0x01;
+ ethAddr >>= 1;
+
+ for (j=0; j<7; j++)
+ {
+ mask2 = ethAddr & (uint64_t)0x01;
+ mask1 ^= mask2;
+ ethAddr >>= 1;
+ }
+
+ xorVal |= (mask1 << (5-i));
+ }
+
+ return xorVal;
+}
+
+/* ......................................................................... */
+
+static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr)
+{
+ uint16_t tmpReg16;
+ e_EnetMode enetMode;
+ bool autoneg_disabled = p_Memac->enetMode == e_ENET_MODE_SGMII_2500;
+
+ /* In case the higher MACs are used (i.e. the MACs that should support 10G),
+ speed=10000 is provided for SGMII ports. Temporary modify enet mode
+ to 1G one, so MII functions can work correctly. */
+ enetMode = p_Memac->enetMode;
+
+ /* SGMII mode + AN enable */
+ tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
+ /* unless SGMII 2500 where AN needs to be disabled */
+ if (autoneg_disabled)
+ tmpReg16 = PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII;
+
+ p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000);
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16);
+
+ /* Device ability according to SGMII specification */
+ tmpReg16 = PHY_SGMII_DEV_ABILITY_SGMII;
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16);
+
+ /* Adjust link timer for SGMII -
+ According to Cisco SGMII specification the timer should be 1.6 ms.
+ The link_timer register is configured in units of the clock.
+ - When running as 1G SGMII, Serdes clock is 125 MHz, so
+ unit = 1 / (125*10^6 Hz) = 8 ns.
+ 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2 * 10^5 = 0x30d40
+ - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
+ unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
+ 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5 * 10^5 = 0x7a120.
+ Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
+ we always set up here a value of 2.5 SGMII. */
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007);
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120);
+
+ if (!autoneg_disabled)
+ /* Restart AN */
+ tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ else
+ /* Disable AN */
+ tmpReg16 = PHY_SGMII_CR_DEF_VAL & ~PHY_SGMII_CR_AN_EN;
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16);
+
+ /* Restore original enet mode */
+ p_Memac->enetMode = enetMode;
+}
+
+/* ......................................................................... */
+
+static void SetupSgmiiInternalPhyBaseX(t_Memac *p_Memac, uint8_t phyAddr)
+{
+ uint16_t tmpReg16;
+ e_EnetMode enetMode;
+
+ /* In case the higher MACs are used (i.e. the MACs that should support 10G),
+ speed=10000 is provided for SGMII ports. Temporary modify enet mode
+ to 1G one, so MII functions can work correctly. */
+ enetMode = p_Memac->enetMode;
+ p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000);
+
+ /* 1000BaseX mode */
+ tmpReg16 = PHY_SGMII_IF_MODE_1000X;
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16);
+
+ /* AN Device capability */
+ tmpReg16 = PHY_SGMII_DEV_ABILITY_1000X;
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16);
+
+ /* Adjust link timer for SGMII -
+ For Serdes 1000BaseX auto-negotiation the timer should be 10 ms.
+ The link_timer register is configured in units of the clock.
+ - When running as 1G SGMII, Serdes clock is 125 MHz, so
+ unit = 1 / (125*10^6 Hz) = 8 ns.
+ 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0
+ - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
+ unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
+ 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08.
+ Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
+ we always set up here a value of 2.5 SGMII. */
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x002f);
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xaf08);
+
+ /* Restart AN */
+ tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16);
+
+ /* Restore original enet mode */
+ p_Memac->enetMode = enetMode;
+}
+
+/* ......................................................................... */
+
+static t_Error CheckInitParameters(t_Memac *p_Memac)
+{
+ e_FmMacType portType;
+
+ portType = ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
+
+#if (FM_MAX_NUM_OF_10G_MACS > 0)
+ if ((portType == e_FM_MAC_10G) && (p_Memac->macId >= FM_MAX_NUM_OF_10G_MACS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("10G MAC ID must be less than %d", FM_MAX_NUM_OF_10G_MACS));
+#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */
+
+ if ((portType == e_FM_MAC_1G) && (p_Memac->macId >= FM_MAX_NUM_OF_1G_MACS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("1G MAC ID must be less than %d", FM_MAX_NUM_OF_1G_MACS));
+ if (p_Memac->addr == 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC must have a valid MAC address"));
+ if (!p_Memac->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Exception"));
+ if (!p_Memac->f_Event)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Event"));
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (!p_Memac->p_MemacDriverParam->no_length_check_enable)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+
+ return E_OK;
+}
+
+/* ........................................................................... */
+
+static void MemacErrException(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ uint32_t event, imask;
+
+ event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap);
+
+ /* Imask include both error and notification/event bits.
+ Leaving only error bits enabled by imask.
+ The imask error bits are shifted by 16 bits offset from
+ their corresponding location in the ievent - hence the >> 16 */
+ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
+
+ fman_memac_ack_event(p_Memac->p_MemMap, event);
+
+ if (event & MEMAC_IEVNT_TS_ECC_ER)
+ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_TS_FIFO_ECC_ERR);
+ if (event & MEMAC_IEVNT_TX_ECC_ER)
+ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER);
+ if (event & MEMAC_IEVNT_RX_ECC_ER)
+ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_ECC_ER);
+}
+
+static void MemacException(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ uint32_t event, imask;
+
+ event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff);
+ imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap);
+
+ /* Imask include both error and notification/event bits.
+ Leaving only error bits enabled by imask.
+ The imask error bits are shifted by 16 bits offset from
+ their corresponding location in the ievent - hence the >> 16 */
+ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16);
+
+ fman_memac_ack_event(p_Memac->p_MemMap, event);
+
+ if (event & MEMAC_IEVNT_MGI)
+ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_MAGIC_PACKET_INDICATION);
+}
+
+/* ......................................................................... */
+
+static void FreeInitResources(t_Memac *p_Memac)
+{
+ e_FmMacType portType;
+
+ portType =
+ ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
+
+ if (portType == e_FM_MAC_10G)
+ FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR);
+ else
+ FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ FreeHashTable(p_Memac->p_MulticastAddrHash);
+ p_Memac->p_MulticastAddrHash = NULL;
+
+ /* release the driver's individual hash table */
+ FreeHashTable(p_Memac->p_UnicastAddrHash);
+ p_Memac->p_UnicastAddrHash = NULL;
+}
+
+
+/*****************************************************************************/
+/* mEMAC API routines */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error MemacEnable(t_Handle h_Memac, e_CommMode mode)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_enable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacDisable (t_Handle h_Memac, e_CommMode mode)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_disable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacSetPromiscuous(t_Handle h_Memac, bool newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_set_promiscuous(p_Memac->p_MemMap, newVal);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error MemacAdjustLink(t_Handle h_Memac, e_EnetSpeed speed, bool fullDuplex)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ if ((speed >= e_ENET_SPEED_1000) && (!fullDuplex))
+ RETURN_ERROR(MAJOR, E_CONFLICT,
+ ("Ethernet MAC 1G or 10G does not support half-duplex"));
+
+ fman_memac_adjust_link(p_Memac->p_MemMap,
+ (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Memac->enetMode),
+ (enum enet_speed)speed,
+ fullDuplex);
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Memac Configs modification functions */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error MemacConfigLoopback(t_Handle h_Memac, bool newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->loopback_enable = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigWan(t_Handle h_Memac, bool newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->wan_mode_enable = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigMaxFrameLength(t_Handle h_Memac, uint16_t newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->max_frame_length = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigPad(t_Handle h_Memac, bool newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->pad_enable = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigLengthCheck(t_Handle h_Memac, bool newVal)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->no_length_check_enable = !newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Memac->exceptions |= bitMask;
+ else
+ p_Memac->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacConfigResetOnInit(t_Handle h_Memac, bool enable)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ p_Memac->p_MemacDriverParam->reset_on_init = enable;
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Memac Run Time API functions */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error MemacSetTxPauseFrames(t_Handle h_Memac,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ if (priority != 0xFF)
+ {
+ bool PortConfigured, PreFetchEnabled;
+
+ if (FmGetTnumAgingPeriod(p_Memac->fmMacControllerDriver.h_Fm) == 0)
+ RETURN_ERROR(MAJOR, E_CONFLICT, ("For PFC operation, TNUM aging must be enabled"));
+
+ FmGetPortPreFetchConfiguration(p_Memac->fmMacControllerDriver.h_Fm,
+ p_Memac->fmMacControllerDriver.macId,
+ &PortConfigured,
+ &PreFetchEnabled);
+
+ if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && !PortConfigured)
+ DBG(INFO, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT"));
+
+ if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && PortConfigured && !PreFetchEnabled)
+ DBG(WARNING, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT"));
+ }
+
+ fman_memac_set_tx_pause_frames(p_Memac->p_MemMap, priority, pauseTime, threshTime);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacSetTxAutoPauseFrames(t_Handle h_Memac,
+ uint16_t pauseTime)
+{
+ return MemacSetTxPauseFrames(h_Memac, FM_MAC_NO_PFC, pauseTime, 0);
+}
+
+/* ......................................................................... */
+
+static t_Error MemacSetRxIgnorePauseFrames(t_Handle h_Memac, bool en)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_set_rx_ignore_pause_frames(p_Memac->p_MemMap, en);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacSetWakeOnLan(t_Handle h_Memac, bool en)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_set_wol(p_Memac->p_MemMap, en);
+
+ return E_OK;
+}
+
+/* .............................................................................. */
+
+static t_Error MemacEnable1588TimeStamp(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+UNUSED(p_Memac);
+DBG(WARNING, ("mEMAC has 1588 always enabled!"));
+
+ return E_OK;
+}
+
+/* Counters handling */
+/* ......................................................................... */
+
+static t_Error MemacGetStatistics(t_Handle h_Memac, t_FmMacStatistics *p_Statistics)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
+
+ p_Statistics->eStatPkts64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64);
+ p_Statistics->eStatPkts65to127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127);
+ p_Statistics->eStatPkts128to255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255);
+ p_Statistics->eStatPkts256to511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511);
+ p_Statistics->eStatPkts512to1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023);
+ p_Statistics->eStatPkts1024to1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518);
+ p_Statistics->eStatPkts1519to1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X);
+/* */
+ p_Statistics->eStatFragments = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RFRG);
+ p_Statistics->eStatJabbers = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RJBR);
+
+ p_Statistics->eStatsDropEvents = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RDRP);
+ p_Statistics->eStatCRCAlignErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RALN);
+
+ p_Statistics->eStatUndersizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUND);
+ p_Statistics->eStatOversizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROVR);
+/* Pause */
+ p_Statistics->reStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RXPF);
+ p_Statistics->teStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TXPF);
+
+/* MIB II */
+ p_Statistics->ifInOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROCT);
+ p_Statistics->ifInUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RUCA);
+ p_Statistics->ifInMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RMCA);
+ p_Statistics->ifInBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RBCA);
+ p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts
+ + p_Statistics->ifInMcastPkts
+ + p_Statistics->ifInBcastPkts;
+ p_Statistics->ifInDiscards = 0;
+ p_Statistics->ifInErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RERR);
+
+ p_Statistics->ifOutOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TOCT);
+ p_Statistics->ifOutUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUCA);
+ p_Statistics->ifOutMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TMCA);
+ p_Statistics->ifOutBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TBCA);
+ p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts
+ + p_Statistics->ifOutMcastPkts
+ + p_Statistics->ifOutBcastPkts;
+ p_Statistics->ifOutDiscards = 0;
+ p_Statistics->ifOutErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TERR);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacGetFrameSizeCounters(t_Handle h_Memac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER);
+
+ switch (type)
+ {
+ case e_COMM_MODE_NONE:
+ break;
+
+ case e_COMM_MODE_RX:
+ p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64);
+ p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127);
+ p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255);
+ p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511);
+ p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023);
+ p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518);
+ p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X);
+ break;
+
+ case e_COMM_MODE_TX:
+ p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64);
+ p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127);
+ p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255);
+ p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511);
+ p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023);
+ p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518);
+ p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X);
+ break;
+
+ case e_COMM_MODE_RX_AND_TX:
+ p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64);
+ p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127);
+ p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255);
+ p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511);
+ p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023);
+ p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518);
+ p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X)
+ + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X);
+ break;
+ }
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t *)(*p_EnetAddr), 0);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacResetCounters (t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ fman_memac_reset_stat(p_Memac->p_MemMap);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacAddExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
+{
+ t_Memac *p_Memac = (t_Memac *) h_Memac;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ if (ethAddr & GROUP_ADDRESS)
+ /* Multicast address has no effect in PADDR */
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
+
+ /* Make sure no PADDR contains this address */
+ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
+ if (p_Memac->indAddrRegUsed[paddrNum])
+ if (p_Memac->paddr[paddrNum] == ethAddr)
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
+
+ /* Find first unused PADDR */
+ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
+ if (!(p_Memac->indAddrRegUsed[paddrNum]))
+ {
+ /* mark this PADDR as used */
+ p_Memac->indAddrRegUsed[paddrNum] = TRUE;
+ /* store address */
+ p_Memac->paddr[paddrNum] = ethAddr;
+
+ /* put in hardware */
+ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)(*p_EthAddr), paddrNum);
+ p_Memac->numOfIndAddrInRegs++;
+
+ return E_OK;
+ }
+
+ /* No free PADDR */
+ RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
+}
+
+/* ......................................................................... */
+
+static t_Error MemacDelExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
+{
+ t_Memac *p_Memac = (t_Memac *) h_Memac;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ /* Find used PADDR containing this address */
+ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++)
+ {
+ if ((p_Memac->indAddrRegUsed[paddrNum]) &&
+ (p_Memac->paddr[paddrNum] == ethAddr))
+ {
+ /* mark this PADDR as not used */
+ p_Memac->indAddrRegUsed[paddrNum] = FALSE;
+ /* clear in hardware */
+ fman_memac_clear_addr_in_paddr(p_Memac->p_MemMap, paddrNum);
+ p_Memac->numOfIndAddrInRegs--;
+
+ return E_OK;
+ }
+ }
+
+ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
+}
+
+/* ......................................................................... */
+
+static t_Error MemacGetId(t_Handle h_Memac, uint32_t *macId)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ *macId = p_Memac->macId;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+
+static t_Error MemacAddHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ t_EthHashEntry *p_HashEntry;
+ uint32_t hash;
+ uint64_t ethAddr;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ if (!(ethAddr & GROUP_ADDRESS))
+ /* Unicast addresses not supported in hash */
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address"));
+
+ hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK;
+
+ /* Create element to be added to the driver hash table */
+ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
+ p_HashEntry->addr = ethAddr;
+ INIT_LIST(&p_HashEntry->node);
+
+ LIST_AddToTail(&(p_HashEntry->node), &(p_Memac->p_MulticastAddrHash->p_Lsts[hash]));
+ fman_memac_set_hash_table(p_Memac->p_MemMap, (hash | HASH_CTRL_MCAST_EN));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacDelHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ t_EthHashEntry *p_HashEntry = NULL;
+ t_List *p_Pos;
+ uint32_t hash;
+ uint64_t ethAddr;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK;
+
+ LIST_FOR_EACH(p_Pos, &(p_Memac->p_MulticastAddrHash->p_Lsts[hash]))
+ {
+ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
+ if (p_HashEntry->addr == ethAddr)
+ {
+ LIST_DelAndInit(&p_HashEntry->node);
+ XX_Free(p_HashEntry);
+ break;
+ }
+ }
+ if (LIST_IsEmpty(&p_Memac->p_MulticastAddrHash->p_Lsts[hash]))
+ fman_memac_set_hash_table(p_Memac->p_MemMap, (hash & ~HASH_CTRL_MCAST_EN));
+
+ return E_OK;
+}
+
+
+/* ......................................................................... */
+
+static t_Error MemacSetException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Memac->exceptions |= bitMask;
+ else
+ p_Memac->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ fman_memac_set_exception(p_Memac->p_MemMap, bitMask, enable);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static uint16_t MemacGetMaxFrameLength(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_VALUE(p_Memac, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_Memac->p_MemacDriverParam, E_INVALID_STATE, 0);
+
+ return fman_memac_get_max_frame_len(p_Memac->p_MemMap);
+}
+
+static t_Error MemacInitInternalPhy(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ uint8_t i, phyAddr;
+
+ if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_SGMII)
+ {
+ /* Configure internal SGMII PHY */
+ if (p_Memac->enetMode & ENET_IF_SGMII_BASEX)
+ SetupSgmiiInternalPhyBaseX(p_Memac, PHY_MDIO_ADDR);
+ else
+ SetupSgmiiInternalPhy(p_Memac, PHY_MDIO_ADDR);
+ }
+ else if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_QSGMII)
+ {
+ /* Configure 4 internal SGMII PHYs */
+ for (i = 0; i < 4; i++)
+ {
+ /* QSGMII PHY address occupies 3 upper bits of 5-bit
+ phyAddress; the lower 2 bits are used to extend
+ register address space and access each one of 4
+ ports inside QSGMII. */
+ phyAddr = (uint8_t)((PHY_MDIO_ADDR << 2) | i);
+ if (p_Memac->enetMode & ENET_IF_SGMII_BASEX)
+ SetupSgmiiInternalPhyBaseX(p_Memac, phyAddr);
+ else
+ SetupSgmiiInternalPhy(p_Memac, phyAddr);
+ }
+ }
+ return E_OK;
+}
+
+/*****************************************************************************/
+/* mEMAC Init & Free API */
+/*****************************************************************************/
+
+/* ......................................................................... */
+void *g_MemacRegs;
+static t_Error MemacInit(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+ struct memac_cfg *p_MemacDriverParam;
+ enum enet_interface enet_interface;
+ enum enet_speed enet_speed;
+ t_EnetAddr ethAddr;
+ e_FmMacType portType;
+ t_Error err;
+ bool slow_10g_if = FALSE;
+ if (p_Memac->macId == 3) /* This is a quick WA */
+ g_MemacRegs = p_Memac->p_MemMap;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
+
+ FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo);
+ if (p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6 &&
+ p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 4)
+ slow_10g_if = TRUE;
+
+ CHECK_INIT_PARAMETERS(p_Memac, CheckInitParameters);
+
+ p_MemacDriverParam = p_Memac->p_MemacDriverParam;
+
+ portType =
+ ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G);
+
+ /* First, reset the MAC if desired. */
+ if (p_MemacDriverParam->reset_on_init)
+ fman_memac_reset(p_Memac->p_MemMap);
+
+ /* MAC Address */
+ MAKE_ENET_ADDR_FROM_UINT64(p_Memac->addr, ethAddr);
+ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)ethAddr, 0);
+
+ enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Memac->enetMode);
+ enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Memac->enetMode);
+
+ fman_memac_init(p_Memac->p_MemMap,
+ p_Memac->p_MemacDriverParam,
+ enet_interface,
+ enet_speed,
+ slow_10g_if,
+ p_Memac->exceptions);
+
+#ifdef FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
+ {
+ uint32_t tmpReg = 0;
+
+ FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo);
+ /* check the FMAN version - the bug exists only in rev1 */
+ if ((p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6) &&
+ (p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 0))
+ {
+ /* MAC strips CRC from received frames - this workaround should
+ decrease the likelihood of bug appearance
+ */
+ tmpReg = GET_UINT32(p_Memac->p_MemMap->command_config);
+ tmpReg &= ~CMD_CFG_CRC_FWD;
+ WRITE_UINT32(p_Memac->p_MemMap->command_config, tmpReg);
+ /* DBG(WARNING, ("mEMAC strips CRC from received frames as part of A006320 errata workaround"));*/
+ }
+ }
+#endif /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 */
+
+ MemacInitInternalPhy(h_Memac);
+
+ /* Max Frame Length */
+ err = FmSetMacMaxFrame(p_Memac->fmMacControllerDriver.h_Fm,
+ portType,
+ p_Memac->fmMacControllerDriver.macId,
+ p_MemacDriverParam->max_frame_length);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("settings Mac max frame length is FAILED"));
+
+ p_Memac->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
+ if (!p_Memac->p_MulticastAddrHash)
+ {
+ FreeInitResources(p_Memac);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
+ }
+
+ p_Memac->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
+ if (!p_Memac->p_UnicastAddrHash)
+ {
+ FreeInitResources(p_Memac);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
+ }
+
+ FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm,
+ (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC,
+ p_Memac->macId,
+ e_FM_INTR_TYPE_ERR,
+ MemacErrException,
+ p_Memac);
+
+ FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm,
+ (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC,
+ p_Memac->macId,
+ e_FM_INTR_TYPE_NORMAL,
+ MemacException,
+ p_Memac);
+
+ XX_Free(p_MemacDriverParam);
+ p_Memac->p_MemacDriverParam = NULL;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error MemacFree(t_Handle h_Memac)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+
+ if (p_Memac->p_MemacDriverParam)
+ {
+ /* Called after config */
+ XX_Free(p_Memac->p_MemacDriverParam);
+ p_Memac->p_MemacDriverParam = NULL;
+ }
+ else
+ /* Called after init */
+ FreeInitResources(p_Memac);
+
+ XX_Free(p_Memac);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
+{
+ p_FmMacControllerDriver->f_FM_MAC_Init = MemacInit;
+ p_FmMacControllerDriver->f_FM_MAC_Free = MemacFree;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = MemacConfigLoopback;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = MemacConfigMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = MemacConfigWan;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = MemacConfigPad;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is detected automatically */
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = MemacConfigLengthCheck;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigException = MemacConfigException;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = MemacConfigResetOnInit;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetException = MemacSetException;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = MemacEnable1588TimeStamp; /* always enabled */
+ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = MemacSetPromiscuous;
+ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = MemacAdjustLink;
+ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable = MemacEnable;
+ p_FmMacControllerDriver->f_FM_MAC_Disable = MemacDisable;
+ p_FmMacControllerDriver->f_FM_MAC_Resume = MemacInitInternalPhy;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = MemacSetTxAutoPauseFrames;
+ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = MemacSetTxPauseFrames;
+ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = MemacSetRxIgnorePauseFrames;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = MemacSetWakeOnLan;
+
+ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = MemacResetCounters;
+ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = MemacGetStatistics;
+ p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = MemacGetFrameSizeCounters;
+
+ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = MemacModifyMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = MemacAddHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = MemacDelHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = MemacAddExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = MemacDelExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_GetId = MemacGetId;
+ p_FmMacControllerDriver->f_FM_MAC_GetVersion = NULL;
+ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = MemacGetMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = MEMAC_MII_WritePhyReg;
+ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = MEMAC_MII_ReadPhyReg;
+}
+
+
+/*****************************************************************************/
+/* mEMAC Config Main Entry */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam)
+{
+ t_Memac *p_Memac;
+ struct memac_cfg *p_MemacDriverParam;
+ uintptr_t baseAddr;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
+
+ baseAddr = p_FmMacParam->baseAddr;
+ /* Allocate memory for the mEMAC data structure */
+ p_Memac = (t_Memac *)XX_Malloc(sizeof(t_Memac));
+ if (!p_Memac)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver structure"));
+ return NULL;
+ }
+ memset(p_Memac, 0, sizeof(t_Memac));
+ InitFmMacControllerDriver(&p_Memac->fmMacControllerDriver);
+
+ /* Allocate memory for the mEMAC driver parameters data structure */
+ p_MemacDriverParam = (struct memac_cfg *)XX_Malloc(sizeof(struct memac_cfg));
+ if (!p_MemacDriverParam)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver parameters"));
+ XX_Free(p_Memac);
+ return NULL;
+ }
+ memset(p_MemacDriverParam, 0, sizeof(struct memac_cfg));
+
+ /* Plant parameter structure pointer */
+ p_Memac->p_MemacDriverParam = p_MemacDriverParam;
+
+ fman_memac_defconfig(p_MemacDriverParam);
+
+ p_Memac->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
+
+ p_Memac->p_MemMap = (struct memac_regs *)UINT_TO_PTR(baseAddr);
+ p_Memac->p_MiiMemMap = (struct memac_mii_access_mem_map*)UINT_TO_PTR(baseAddr + MEMAC_TO_MII_OFFSET);
+
+ p_Memac->enetMode = p_FmMacParam->enetMode;
+ p_Memac->macId = p_FmMacParam->macId;
+ p_Memac->exceptions = MEMAC_default_exceptions;
+ p_Memac->f_Exception = p_FmMacParam->f_Exception;
+ p_Memac->f_Event = p_FmMacParam->f_Event;
+ p_Memac->h_App = p_FmMacParam->h_App;
+
+ return p_Memac;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
new file mode 100644
index 000000000000..d361af42b0c2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File memac.h
+
+ @Description FM Multirate Ethernet MAC (mEMAC)
+*//***************************************************************************/
+#ifndef __MEMAC_H
+#define __MEMAC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "fsl_fman_memac_mii_acc.h"
+#include "fm_mac.h"
+#include "fsl_fman_memac.h"
+
+
+#define MEMAC_default_exceptions \
+ ((uint32_t)(MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI))
+
+#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \
+ case e_FM_MAC_EX_10G_1TX_ECC_ER: \
+ bitMask = MEMAC_IMASK_TECC_ER; break; \
+ case e_FM_MAC_EX_10G_RX_ECC_ER: \
+ bitMask = MEMAC_IMASK_RECC_ER; break; \
+ case e_FM_MAC_EX_TS_FIFO_ECC_ERR: \
+ bitMask = MEMAC_IMASK_TSECC_ER; break; \
+ case e_FM_MAC_EX_MAGIC_PACKET_INDICATION: \
+ bitMask = MEMAC_IMASK_MGI; break; \
+ default: bitMask = 0;break;}
+
+
+typedef struct
+{
+ t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */
+ t_Handle h_App; /**< Handle to the upper layer application */
+ struct memac_regs *p_MemMap; /**< Pointer to MAC memory mapped registers */
+ struct memac_mii_access_mem_map *p_MiiMemMap; /**< Pointer to MII memory mapped registers */
+ uint64_t addr; /**< MAC address of device */
+ e_EnetMode enetMode; /**< Ethernet physical interface */
+ t_FmMacExceptionCallback *f_Exception;
+ int mdioIrq;
+ t_FmMacExceptionCallback *f_Event;
+ bool indAddrRegUsed[MEMAC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
+ uint64_t paddr[MEMAC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */
+ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */
+ t_EthHash *p_MulticastAddrHash; /**< Pointer to driver's global address hash table */
+ t_EthHash *p_UnicastAddrHash; /**< Pointer to driver's individual address hash table */
+ bool debugMode;
+ uint8_t macId;
+ uint32_t exceptions;
+ struct memac_cfg *p_MemacDriverParam;
+} t_Memac;
+
+
+/* Internal PHY access */
+#define PHY_MDIO_ADDR 0
+
+/* Internal PHY Registers - SGMII */
+#define PHY_SGMII_CR_PHY_RESET 0x8000
+#define PHY_SGMII_CR_RESET_AN 0x0200
+#define PHY_SGMII_CR_DEF_VAL 0x1140
+#define PHY_SGMII_CR_AN_EN 0x1000
+#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001
+#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0
+#define PHY_SGMII_IF_SPEED_GIGABIT 0x0008
+#define PHY_SGMII_IF_MODE_AN 0x0002
+#define PHY_SGMII_IF_MODE_SGMII 0x0001
+#define PHY_SGMII_IF_MODE_1000X 0x0000
+
+
+#define MEMAC_TO_MII_OFFSET 0x030 /* Offset from the MEM map to the MDIO mem map */
+
+t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t data);
+t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
+
+
+#endif /* __MEMAC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c
new file mode 100644
index 000000000000..56eaffbcf66d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "error_ext.h"
+#include "std_ext.h"
+#include "fm_mac.h"
+#include "memac.h"
+#include "xx_ext.h"
+
+#include "fm_common.h"
+#include "memac_mii_acc.h"
+
+
+/*****************************************************************************/
+t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t data)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE);
+
+ return (t_Error)fman_memac_mii_write_phy_reg(p_Memac->p_MiiMemMap,
+ phyAddr,
+ reg,
+ data,
+ (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode));
+}
+
+/*****************************************************************************/
+t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t *p_Data)
+{
+ t_Memac *p_Memac = (t_Memac *)h_Memac;
+
+ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE);
+
+ return fman_memac_mii_read_phy_reg(p_Memac->p_MiiMemMap,
+ phyAddr,
+ reg,
+ p_Data,
+ (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode));
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h
new file mode 100644
index 000000000000..325ec082ffde
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __MEMAC_MII_ACC_H
+#define __MEMAC_MII_ACC_H
+
+#include "std_ext.h"
+
+
+/* MII Management Registers */
+#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80
+#define MDIO_CFG_CLK_DIV_SHIFT 7
+#define MDIO_CFG_HOLD_MASK 0x0000001c
+#define MDIO_CFG_ENC45 0x00000040
+#define MDIO_CFG_READ_ERR 0x00000002
+#define MDIO_CFG_BSY 0x00000001
+
+#define MDIO_CTL_PHY_ADDR_SHIFT 5
+#define MDIO_CTL_READ 0x00008000
+
+#define MDIO_DATA_BSY 0x80000000
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/*----------------------------------------------------*/
+/* MII Configuration Control Memory Map Registers */
+/*----------------------------------------------------*/
+typedef struct t_MemacMiiAccessMemMap
+{
+ volatile uint32_t mdio_cfg; /* 0x030 */
+ volatile uint32_t mdio_ctrl; /* 0x034 */
+ volatile uint32_t mdio_data; /* 0x038 */
+ volatile uint32_t mdio_addr; /* 0x03c */
+} t_MemacMiiAccessMemMap ;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+#endif /* __MEMAC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
new file mode 100644
index 000000000000..eb00759f9f46
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File tgec.c
+
+ @Description FM 10G MAC ...
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "string_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "endian_ext.h"
+#include "debug_ext.h"
+#include "crc_mac_addr_ext.h"
+
+#include "fm_common.h"
+#include "fsl_fman_tgec.h"
+#include "tgec.h"
+
+
+/*****************************************************************************/
+/* Internal routines */
+/*****************************************************************************/
+
+static t_Error CheckInitParameters(t_Tgec *p_Tgec)
+{
+ if (ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed"));
+#if (FM_MAX_NUM_OF_10G_MACS > 0)
+ if (p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0"));
+#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */
+
+ if (p_Tgec->addr == 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address"));
+ if (!p_Tgec->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception"));
+ if (!p_Tgec->f_Event)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event"));
+#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002
+ if (!p_Tgec->p_TgecDriverParam->no_length_check_enable)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!"));
+#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static uint32_t GetMacAddrHashCode(uint64_t ethAddr)
+{
+ uint32_t crc;
+
+ /* CRC calculation */
+ GET_MAC_ADDR_CRC(ethAddr, crc);
+
+ crc = GetMirror32(crc);
+
+ return crc;
+}
+
+/* ......................................................................... */
+
+static void TgecErrException(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ uint32_t event;
+ struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap;
+
+ /* do not handle MDIO events */
+ event = fman_tgec_get_event(p_TgecMemMap, ~(TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL));
+ event &= fman_tgec_get_interrupt_mask(p_TgecMemMap);
+
+ fman_tgec_ack_event(p_TgecMemMap, event);
+
+ if (event & TGEC_IMASK_REM_FAULT)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT);
+ if (event & TGEC_IMASK_LOC_FAULT)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT);
+ if (event & TGEC_IMASK_TX_ECC_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER);
+ if (event & TGEC_IMASK_TX_FIFO_UNFL)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL);
+ if (event & TGEC_IMASK_TX_FIFO_OVFL)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL);
+ if (event & TGEC_IMASK_TX_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER);
+ if (event & TGEC_IMASK_RX_FIFO_OVFL)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL);
+ if (event & TGEC_IMASK_RX_ECC_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER);
+ if (event & TGEC_IMASK_RX_JAB_FRM)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM);
+ if (event & TGEC_IMASK_RX_OVRSZ_FRM)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM);
+ if (event & TGEC_IMASK_RX_RUNT_FRM)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM);
+ if (event & TGEC_IMASK_RX_FRAG_FRM)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM);
+ if (event & TGEC_IMASK_RX_LEN_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER);
+ if (event & TGEC_IMASK_RX_CRC_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER);
+ if (event & TGEC_IMASK_RX_ALIGN_ER)
+ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER);
+}
+
+/* ......................................................................... */
+
+static void TgecException(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ uint32_t event;
+ struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap;
+
+ /* handle only MDIO events */
+ event = fman_tgec_get_event(p_TgecMemMap, (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL));
+ event &= fman_tgec_get_interrupt_mask(p_TgecMemMap);
+
+ fman_tgec_ack_event(p_TgecMemMap, event);
+
+ if (event & TGEC_IMASK_MDIO_SCAN_EVENT)
+ p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO);
+ if (event & TGEC_IMASK_MDIO_CMD_CMPL)
+ p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL);
+}
+
+/* ......................................................................... */
+
+static void FreeInitResources(t_Tgec *p_Tgec)
+{
+ if (p_Tgec->mdioIrq != NO_IRQ)
+ {
+ XX_DisableIntr(p_Tgec->mdioIrq);
+ XX_FreeIntr(p_Tgec->mdioIrq);
+ }
+
+ FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR);
+
+ /* release the driver's group hash table */
+ FreeHashTable(p_Tgec->p_MulticastAddrHash);
+ p_Tgec->p_MulticastAddrHash = NULL;
+
+ /* release the driver's individual hash table */
+ FreeHashTable(p_Tgec->p_UnicastAddrHash);
+ p_Tgec->p_UnicastAddrHash = NULL;
+}
+
+
+/*****************************************************************************/
+/* 10G MAC API routines */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error TgecEnable(t_Handle h_Tgec, e_CommMode mode)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_enable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_disable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, newVal);
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Tgec Configs modification functions */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->p_TgecDriverParam->loopback_enable = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->p_TgecDriverParam->wan_mode_enable = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->p_TgecDriverParam->max_frame_length = newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ UNUSED(newVal);
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->p_TgecDriverParam->no_length_check_enable = !newVal;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Tgec->exceptions |= bitMask;
+ else
+ p_Tgec->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+/* ......................................................................... */
+
+static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->p_TgecDriverParam->skip_fman11_workaround = TRUE;
+
+ return E_OK;
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+
+/*****************************************************************************/
+/* Tgec Run Time API functions */
+/*****************************************************************************/
+
+/* ......................................................................... */
+/* backward compatibility. will be removed in the future. */
+static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+ fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime);
+
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecSetTxPauseFrames(t_Handle h_Tgec,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ UNUSED(priority); UNUSED(threshTime);
+
+ fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_set_rx_ignore_pause_frames(p_Tgec->p_MemMap, en);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ struct tgec_regs *p_TgecMemMap;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER);
+
+ p_TgecMemMap = p_Tgec->p_MemMap;
+
+ p_Statistics->eStatPkts64 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64);
+ p_Statistics->eStatPkts65to127 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127);
+ p_Statistics->eStatPkts128to255 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255);
+ p_Statistics->eStatPkts256to511 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511);
+ p_Statistics->eStatPkts512to1023 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023);
+ p_Statistics->eStatPkts1024to1518 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518);
+ p_Statistics->eStatPkts1519to1522 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X);
+/* */
+ p_Statistics->eStatFragments = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRFRG);
+ p_Statistics->eStatJabbers = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRJBR);
+
+ p_Statistics->eStatsDropEvents = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RDRP);
+ p_Statistics->eStatCRCAlignErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RALN);
+
+ p_Statistics->eStatUndersizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRUND);
+ p_Statistics->eStatOversizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TROVR);
+/* Pause */
+ p_Statistics->reStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RXPF);
+ p_Statistics->teStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TXPF);
+
+/* MIB II */
+ p_Statistics->ifInOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_ROCT);
+ p_Statistics->ifInUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RUCA);
+ p_Statistics->ifInMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RMCA);
+ p_Statistics->ifInBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RBCA);
+ p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts
+ + p_Statistics->ifInMcastPkts
+ + p_Statistics->ifInBcastPkts;
+ p_Statistics->ifInDiscards = 0;
+ p_Statistics->ifInErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RERR);
+
+ p_Statistics->ifOutOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TOCT);
+ p_Statistics->ifOutUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TUCA);
+ p_Statistics->ifOutMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TMCA);
+ p_Statistics->ifOutBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TBCA);
+ p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts
+ + p_Statistics->ifOutMcastPkts
+ + p_Statistics->ifOutBcastPkts;
+ p_Statistics->ifOutDiscards = 0;
+ p_Statistics->ifOutErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TERR);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecGetFrameSizeCounters(t_Handle h_Tgec, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ struct tgec_regs *p_TgecMemMap;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER);
+
+ p_TgecMemMap = p_Tgec->p_MemMap;
+
+ switch (type)
+ {
+ case e_COMM_MODE_NONE:
+ break;
+
+ case e_COMM_MODE_RX:
+ p_FrameSizeCounters->count_pkts_64 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64);
+ p_FrameSizeCounters->count_pkts_65_to_127 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127);
+ p_FrameSizeCounters->count_pkts_128_to_255 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255);
+ p_FrameSizeCounters->count_pkts_256_to_511 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511);
+ p_FrameSizeCounters->count_pkts_512_to_1023 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023);
+ p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518);
+ p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X);
+ break;
+
+ case e_COMM_MODE_TX:
+ //Tx counters not supported
+ break;
+
+ case e_COMM_MODE_RX_AND_TX:
+ //Tx counters not supported
+ break;
+ }
+
+ return E_OK;
+}
+
+
+/* ......................................................................... */
+
+static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 1);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 0);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ p_Tgec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr);
+ fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)(*p_EnetAddr));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecResetCounters (t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ fman_tgec_reset_stat(p_Tgec->p_MemMap);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
+{
+ t_Tgec *p_Tgec = (t_Tgec *) h_Tgec;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ if (ethAddr & GROUP_ADDRESS)
+ /* Multicast address has no effect in PADDR */
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address"));
+
+ /* Make sure no PADDR contains this address */
+ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
+ if (p_Tgec->indAddrRegUsed[paddrNum])
+ if (p_Tgec->paddr[paddrNum] == ethAddr)
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
+
+ /* Find first unused PADDR */
+ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
+ {
+ if (!(p_Tgec->indAddrRegUsed[paddrNum]))
+ {
+ /* mark this PADDR as used */
+ p_Tgec->indAddrRegUsed[paddrNum] = TRUE;
+ /* store address */
+ p_Tgec->paddr[paddrNum] = ethAddr;
+
+ /* put in hardware */
+ fman_tgec_add_addr_in_paddr(p_Tgec->p_MemMap, (uint8_t*)(*p_EthAddr)/* , paddrNum */);
+ p_Tgec->numOfIndAddrInRegs++;
+
+ return E_OK;
+ }
+ }
+
+ /* No free PADDR */
+ RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
+}
+
+/* ......................................................................... */
+
+static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
+{
+ t_Tgec *p_Tgec = (t_Tgec *) h_Tgec;
+ uint64_t ethAddr;
+ uint8_t paddrNum;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ /* Find used PADDR containing this address */
+ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++)
+ {
+ if ((p_Tgec->indAddrRegUsed[paddrNum]) &&
+ (p_Tgec->paddr[paddrNum] == ethAddr))
+ {
+ /* mark this PADDR as not used */
+ p_Tgec->indAddrRegUsed[paddrNum] = FALSE;
+ /* clear in hardware */
+ fman_tgec_clear_addr_in_paddr(p_Tgec->p_MemMap /*, paddrNum */);
+ p_Tgec->numOfIndAddrInRegs--;
+
+ return E_OK;
+ }
+ }
+
+ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG);
+}
+
+/* ......................................................................... */
+
+static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ t_EthHashEntry *p_HashEntry;
+ uint32_t crc;
+ uint32_t hash;
+ uint64_t ethAddr;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr);
+
+ if (!(ethAddr & GROUP_ADDRESS))
+ /* Unicast addresses not supported in hash */
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address"));
+
+ /* CRC calculation */
+ crc = GetMacAddrHashCode(ethAddr);
+
+ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */
+
+ /* Create element to be added to the driver hash table */
+ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry));
+ p_HashEntry->addr = ethAddr;
+ INIT_LIST(&p_HashEntry->node);
+
+ LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash]));
+ fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash | TGEC_HASH_MCAST_EN));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ t_EthHashEntry *p_HashEntry = NULL;
+ t_List *p_Pos;
+ uint32_t crc;
+ uint32_t hash;
+ uint64_t ethAddr;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ ethAddr = ((*(uint64_t *)p_EthAddr) >> 16);
+
+ /* CRC calculation */
+ crc = GetMacAddrHashCode(ethAddr);
+
+ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */
+
+ LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash]))
+ {
+ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos);
+ if (p_HashEntry->addr == ethAddr)
+ {
+ LIST_DelAndInit(&p_HashEntry->node);
+ XX_Free(p_HashEntry);
+ break;
+ }
+ }
+ if (LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash]))
+ fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash & ~TGEC_HASH_MCAST_EN));
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ UNUSED(p_Tgec);
+ UNUSED(macId);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported"));
+}
+
+/* ......................................................................... */
+
+static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ *macVersion = fman_tgec_get_revision(p_Tgec->p_MemMap);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Tgec->exceptions |= bitMask;
+ else
+ p_Tgec->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ if (enable)
+ fman_tgec_enable_interrupt(p_Tgec->p_MemMap, bitMask);
+ else
+ fman_tgec_disable_interrupt(p_Tgec->p_MemMap, bitMask);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE, 0);
+
+ return fman_tgec_get_max_frame_len(p_Tgec->p_MemMap);
+}
+
+/* ......................................................................... */
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec)
+{
+ t_Error err;
+
+#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)
+ XX_Print("Applying 10G TX ECC workaround (10GMAC-A004) ... ");
+#endif /* (DEBUG_ERRORS > 0) */
+ /* enable and set promiscuous */
+ fman_tgec_enable(p_Tgec->p_MemMap, TRUE, TRUE);
+ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, TRUE);
+ err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId);
+ /* disable */
+ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, FALSE);
+ fman_tgec_enable(p_Tgec->p_MemMap, FALSE, FALSE);
+ fman_tgec_reset_stat(p_Tgec->p_MemMap);
+ fman_tgec_ack_event(p_Tgec->p_MemMap, 0xffffffff);
+#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)
+ if (err)
+ XX_Print("FAILED!\n");
+ else
+ XX_Print("done.\n");
+#endif /* (DEBUG_ERRORS > 0) */
+
+ return err;
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+/*****************************************************************************/
+/* FM Init & Free API */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+static t_Error TgecInit(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ struct tgec_cfg *p_TgecDriverParam;
+ t_EnetAddr ethAddr;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE);
+
+ FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &p_Tgec->fmMacControllerDriver.fmRevInfo);
+ CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters);
+
+ p_TgecDriverParam = p_Tgec->p_TgecDriverParam;
+
+ MAKE_ENET_ADDR_FROM_UINT64(p_Tgec->addr, ethAddr);
+ fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)ethAddr);
+
+ /* interrupts */
+#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005
+ {
+ if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <=2)
+ p_Tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT);
+ }
+#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ if (!p_Tgec->p_TgecDriverParam->skip_fman11_workaround &&
+ ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK))
+ {
+ FreeInitResources(p_Tgec);
+ REPORT_ERROR(MINOR, err, ("TgecTxEccWorkaround FAILED"));
+ }
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+ err = fman_tgec_init(p_Tgec->p_MemMap, p_TgecDriverParam, p_Tgec->exceptions);
+ if (err)
+ {
+ FreeInitResources(p_Tgec);
+ RETURN_ERROR(MAJOR, err, ("This TGEC version does not support the required i/f mode"));
+ }
+
+ /* Max Frame Length */
+ err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm,
+ e_FM_MAC_10G,
+ p_Tgec->fmMacControllerDriver.macId,
+ p_TgecDriverParam->max_frame_length);
+ if (err != E_OK)
+ {
+ FreeInitResources(p_Tgec);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+/* we consider having no IPC a non crasher... */
+
+#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007
+ if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev == 2)
+ fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(p_Tgec->p_MemMap);
+#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */
+
+ p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
+ if (!p_Tgec->p_MulticastAddrHash)
+ {
+ FreeInitResources(p_Tgec);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
+ }
+
+ p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE);
+ if (!p_Tgec->p_UnicastAddrHash)
+ {
+ FreeInitResources(p_Tgec);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED"));
+ }
+
+ FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm,
+ e_FM_MOD_10G_MAC,
+ p_Tgec->macId,
+ e_FM_INTR_TYPE_ERR,
+ TgecErrException,
+ p_Tgec);
+ if (p_Tgec->mdioIrq != NO_IRQ)
+ {
+ XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec);
+ XX_EnableIntr(p_Tgec->mdioIrq);
+ }
+
+ XX_Free(p_TgecDriverParam);
+ p_Tgec->p_TgecDriverParam = NULL;
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static t_Error TgecFree(t_Handle h_Tgec)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+
+ if (p_Tgec->p_TgecDriverParam)
+ {
+ /* Called after config */
+ XX_Free(p_Tgec->p_TgecDriverParam);
+ p_Tgec->p_TgecDriverParam = NULL;
+ }
+ else
+ /* Called after init */
+ FreeInitResources(p_Tgec);
+
+ XX_Free(p_Tgec);
+
+ return E_OK;
+}
+
+/* ......................................................................... */
+
+static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver)
+{
+ p_FmMacControllerDriver->f_FM_MAC_Init = TgecInit;
+ p_FmMacControllerDriver->f_FM_MAC_Free = TgecFree;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = TgecConfigLoopback;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = TgecConfigMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = TgecConfigWan;
+
+ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = NULL; /* TGEC always works with pad+crc */
+ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is not supported in xgec */
+ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = TgecConfigLengthCheck;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigException = TgecConfigException;
+ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL;
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround;
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+ p_FmMacControllerDriver->f_FM_MAC_SetException = TgecSetExcpetion;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = TgecEnable1588TimeStamp;
+ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = TgecDisable1588TimeStamp;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = TgecSetPromiscuous;
+ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = NULL;
+ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = NULL;
+ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_Enable = TgecEnable;
+ p_FmMacControllerDriver->f_FM_MAC_Disable = TgecDisable;
+ p_FmMacControllerDriver->f_FM_MAC_Resume = NULL;
+
+ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = TgecTxMacPause;
+ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = TgecSetTxPauseFrames;
+ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = TgecRxIgnoreMacPause;
+
+ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = TgecResetCounters;
+ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = TgecGetStatistics;
+ p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = TgecGetFrameSizeCounters;
+
+ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = TgecModifyMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = TgecAddHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = TgecDelHashMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = TgecAddExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = TgecDelExactMatchMacAddress;
+ p_FmMacControllerDriver->f_FM_MAC_GetId = TgecGetId;
+ p_FmMacControllerDriver->f_FM_MAC_GetVersion = TgecGetVersion;
+ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = TgecGetMaxFrameLength;
+
+ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = TGEC_MII_WritePhyReg;
+ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = TGEC_MII_ReadPhyReg;
+}
+
+
+/*****************************************************************************/
+/* Tgec Config Main Entry */
+/*****************************************************************************/
+
+/* ......................................................................... */
+
+t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam)
+{
+ t_Tgec *p_Tgec;
+ struct tgec_cfg *p_TgecDriverParam;
+ uintptr_t baseAddr;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL);
+
+ baseAddr = p_FmMacParam->baseAddr;
+ /* allocate memory for the UCC GETH data structure. */
+ p_Tgec = (t_Tgec *)XX_Malloc(sizeof(t_Tgec));
+ if (!p_Tgec)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure"));
+ return NULL;
+ }
+ memset(p_Tgec, 0, sizeof(t_Tgec));
+ InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver);
+
+ /* allocate memory for the 10G MAC driver parameters data structure. */
+ p_TgecDriverParam = (struct tgec_cfg *) XX_Malloc(sizeof(struct tgec_cfg));
+ if (!p_TgecDriverParam)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters"));
+ XX_Free(p_Tgec);
+ return NULL;
+ }
+ memset(p_TgecDriverParam, 0, sizeof(struct tgec_cfg));
+
+ /* Plant parameter structure pointer */
+ p_Tgec->p_TgecDriverParam = p_TgecDriverParam;
+
+ fman_tgec_defconfig(p_TgecDriverParam);
+
+ p_Tgec->p_MemMap = (struct tgec_regs *)UINT_TO_PTR(baseAddr);
+ p_Tgec->p_MiiMemMap = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET);
+ p_Tgec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr);
+ p_Tgec->enetMode = p_FmMacParam->enetMode;
+ p_Tgec->macId = p_FmMacParam->macId;
+ p_Tgec->exceptions = DEFAULT_exceptions;
+ p_Tgec->mdioIrq = p_FmMacParam->mdioIrq;
+ p_Tgec->f_Exception = p_FmMacParam->f_Exception;
+ p_Tgec->f_Event = p_FmMacParam->f_Event;
+ p_Tgec->h_App = p_FmMacParam->h_App;
+
+ return p_Tgec;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h
new file mode 100644
index 000000000000..2aa392385588
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File tgec.h
+
+ @Description FM 10G MAC ...
+*//***************************************************************************/
+#ifndef __TGEC_H
+#define __TGEC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+#include "enet_ext.h"
+
+#include "tgec_mii_acc.h"
+#include "fm_mac.h"
+
+
+#define DEFAULT_exceptions \
+ ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \
+ TGEC_IMASK_REM_FAULT | \
+ TGEC_IMASK_LOC_FAULT | \
+ TGEC_IMASK_TX_ECC_ER | \
+ TGEC_IMASK_TX_FIFO_UNFL | \
+ TGEC_IMASK_TX_FIFO_OVFL | \
+ TGEC_IMASK_TX_ER | \
+ TGEC_IMASK_RX_FIFO_OVFL | \
+ TGEC_IMASK_RX_ECC_ER | \
+ TGEC_IMASK_RX_JAB_FRM | \
+ TGEC_IMASK_RX_OVRSZ_FRM | \
+ TGEC_IMASK_RX_RUNT_FRM | \
+ TGEC_IMASK_RX_FRAG_FRM | \
+ TGEC_IMASK_RX_CRC_ER | \
+ TGEC_IMASK_RX_ALIGN_ER))
+
+#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \
+ case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO: \
+ bitMask = TGEC_IMASK_MDIO_SCAN_EVENT ; break; \
+ case e_FM_MAC_EX_10G_MDIO_CMD_CMPL: \
+ bitMask = TGEC_IMASK_MDIO_CMD_CMPL ; break; \
+ case e_FM_MAC_EX_10G_REM_FAULT: \
+ bitMask = TGEC_IMASK_REM_FAULT ; break; \
+ case e_FM_MAC_EX_10G_LOC_FAULT: \
+ bitMask = TGEC_IMASK_LOC_FAULT ; break; \
+ case e_FM_MAC_EX_10G_1TX_ECC_ER: \
+ bitMask = TGEC_IMASK_TX_ECC_ER ; break; \
+ case e_FM_MAC_EX_10G_TX_FIFO_UNFL: \
+ bitMask = TGEC_IMASK_TX_FIFO_UNFL ; break; \
+ case e_FM_MAC_EX_10G_TX_FIFO_OVFL: \
+ bitMask = TGEC_IMASK_TX_FIFO_OVFL ; break; \
+ case e_FM_MAC_EX_10G_TX_ER: \
+ bitMask = TGEC_IMASK_TX_ER ; break; \
+ case e_FM_MAC_EX_10G_RX_FIFO_OVFL: \
+ bitMask = TGEC_IMASK_RX_FIFO_OVFL ; break; \
+ case e_FM_MAC_EX_10G_RX_ECC_ER: \
+ bitMask = TGEC_IMASK_RX_ECC_ER ; break; \
+ case e_FM_MAC_EX_10G_RX_JAB_FRM: \
+ bitMask = TGEC_IMASK_RX_JAB_FRM ; break; \
+ case e_FM_MAC_EX_10G_RX_OVRSZ_FRM: \
+ bitMask = TGEC_IMASK_RX_OVRSZ_FRM ; break; \
+ case e_FM_MAC_EX_10G_RX_RUNT_FRM: \
+ bitMask = TGEC_IMASK_RX_RUNT_FRM ; break; \
+ case e_FM_MAC_EX_10G_RX_FRAG_FRM: \
+ bitMask = TGEC_IMASK_RX_FRAG_FRM ; break; \
+ case e_FM_MAC_EX_10G_RX_LEN_ER: \
+ bitMask = TGEC_IMASK_RX_LEN_ER ; break; \
+ case e_FM_MAC_EX_10G_RX_CRC_ER: \
+ bitMask = TGEC_IMASK_RX_CRC_ER ; break; \
+ case e_FM_MAC_EX_10G_RX_ALIGN_ER: \
+ bitMask = TGEC_IMASK_RX_ALIGN_ER ; break; \
+ default: bitMask = 0;break;}
+
+#define MAX_PACKET_ALIGNMENT 31
+#define MAX_INTER_PACKET_GAP 0x7f
+#define MAX_INTER_PALTERNATE_BEB 0x0f
+#define MAX_RETRANSMISSION 0x0f
+#define MAX_COLLISION_WINDOW 0x03ff
+
+#define TGEC_NUM_OF_PADDRS 1 /* number of pattern match registers (entries) */
+
+#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */
+
+#define HASH_TABLE_SIZE 512 /* Hash table size (= 32 bits * 8 regs) */
+
+#define TGEC_TO_MII_OFFSET 0x1030 /* Offset from the MEM map to the MDIO mem map */
+
+/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */
+#define TGEC_ID_ID 0xffff0000
+#define TGEC_ID_MAC_VERSION 0x0000FF00
+#define TGEC_ID_MAC_REV 0x000000ff
+
+
+typedef struct {
+ t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */
+ t_Handle h_App; /**< Handle to the upper layer application */
+ struct tgec_regs *p_MemMap; /**< pointer to 10G memory mapped registers. */
+ t_TgecMiiAccessMemMap *p_MiiMemMap; /**< pointer to MII memory mapped registers. */
+ uint64_t addr; /**< MAC address of device; */
+ e_EnetMode enetMode; /**< Ethernet physical interface */
+ t_FmMacExceptionCallback *f_Exception;
+ int mdioIrq;
+ t_FmMacExceptionCallback *f_Event;
+ bool indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */
+ uint64_t paddr[TGEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */
+ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */
+ t_EthHash *p_MulticastAddrHash; /**< pointer to driver's global address hash table */
+ t_EthHash *p_UnicastAddrHash; /**< pointer to driver's individual address hash table */
+ bool debugMode;
+ uint8_t macId;
+ uint32_t exceptions;
+ struct tgec_cfg *p_TgecDriverParam;
+} t_Tgec;
+
+
+t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data);
+t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
+
+
+#endif /* __TGEC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c
new file mode 100644
index 000000000000..e0fafd1d174d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "error_ext.h"
+#include "std_ext.h"
+#include "fm_mac.h"
+#include "tgec.h"
+#include "xx_ext.h"
+
+#include "fm_common.h"
+
+
+/*****************************************************************************/
+t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t data)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ t_TgecMiiAccessMemMap *p_MiiAccess;
+ uint32_t cfgStatusReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE);
+
+ p_MiiAccess = p_Tgec->p_MiiMemMap;
+
+ /* Configure MII */
+ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status);
+ cfgStatusReg &= ~MIIMCOM_DIV_MASK;
+ /* (one half of fm clock => 2.5Mhz) */
+ cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT);
+ WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg);
+
+ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
+ XX_UDelay (1);
+
+ WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr);
+
+ WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg);
+
+ CORE_MemoryBarrier();
+
+ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
+ XX_UDelay (1);
+
+ WRITE_UINT32(p_MiiAccess->mdio_data, data);
+
+ CORE_MemoryBarrier();
+
+ while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY)
+ XX_UDelay (1);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t *p_Data)
+{
+ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec;
+ t_TgecMiiAccessMemMap *p_MiiAccess;
+ uint32_t cfgStatusReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE);
+
+ p_MiiAccess = p_Tgec->p_MiiMemMap;
+
+ /* Configure MII */
+ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status);
+ cfgStatusReg &= ~MIIMCOM_DIV_MASK;
+ /* (one half of fm clock => 2.5Mhz) */
+ cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT);
+ WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg);
+
+ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
+ XX_UDelay (1);
+
+ WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr);
+
+ WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg);
+
+ CORE_MemoryBarrier();
+
+ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY)
+ XX_UDelay (1);
+
+ WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE));
+
+ CORE_MemoryBarrier();
+
+ while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY)
+ XX_UDelay (1);
+
+ *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data);
+
+ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status);
+
+ if (cfgStatusReg & MIIMIND_READ_ERROR)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE,
+ ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgStatusReg 0x%x",
+ ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfgStatusReg));
+
+ return E_OK;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h
new file mode 100644
index 000000000000..645cdde57973
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __TGEC_MII_ACC_H
+#define __TGEC_MII_ACC_H
+
+#include "std_ext.h"
+
+
+/* MII Management Command Register */
+#define MIIMCOM_READ_POST_INCREMENT 0x00004000
+#define MIIMCOM_READ_CYCLE 0x00008000
+#define MIIMCOM_SCAN_CYCLE 0x00000800
+#define MIIMCOM_PREAMBLE_DISABLE 0x00000400
+
+#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0
+#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1
+#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2
+#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3
+
+#define MIIMCOM_DIV_MASK 0x0000ff00
+#define MIIMCOM_DIV_SHIFT 8
+
+/* MII Management Indicator Register */
+#define MIIMIND_BUSY 0x00000001
+#define MIIMIND_READ_ERROR 0x00000002
+
+#define MIIDATA_BUSY 0x80000000
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/*----------------------------------------------------*/
+/* MII Configuration Control Memory Map Registers */
+/*----------------------------------------------------*/
+typedef _Packed struct t_TgecMiiAccessMemMap
+{
+ volatile uint32_t mdio_cfg_status; /* 0x030 */
+ volatile uint32_t mdio_command; /* 0x034 */
+ volatile uint32_t mdio_data; /* 0x038 */
+ volatile uint32_t mdio_regaddr; /* 0x03c */
+} _PackedType t_TgecMiiAccessMemMap ;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+#endif /* __TGEC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile
new file mode 100644
index 000000000000..bfa02f5ee92d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-macsec.o
+
+fsl-ncsw-macsec-objs := fm_macsec.o fm_macsec_guest.o fm_macsec_master.o fm_macsec_secy.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c
new file mode 100644
index 000000000000..0a1b31f11d5f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+/******************************************************************************
+
+ @File fm_macsec.c
+
+ @Description FM MACSEC driver routines implementation.
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+
+#include "fm_macsec.h"
+
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacsecParam, E_INVALID_HANDLE, NULL);
+
+ if (p_FmMacsecParam->guestMode)
+ p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_GUEST_Config(p_FmMacsecParam);
+ else
+ p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_MASTER_Config(p_FmMacsecParam);
+
+ if (!p_FmMacsecControllerDriver)
+ return NULL;
+
+ return (t_Handle)p_FmMacsecControllerDriver;
+}
+
+t_Error FM_MACSEC_Init(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Init)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_Init(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_Free(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Free)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_Free(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment(h_FmMacsec, treatMode);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment(h_FmMacsec, deliverUncontrolled);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(h_FmMacsec, discardUncontrolled);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment(h_FmMacsec, treatMode);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold(h_FmMacsec, pnExhThr);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException(h_FmMacsec, exception, enable);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision(h_FmMacsec, p_MacsecRevision);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+
+t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Enable)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_Enable(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Disable)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_Disable(h_FmMacsec);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
+{
+ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE);
+
+ if (p_FmMacsecControllerDriver->f_FM_MACSEC_SetException)
+ return p_FmMacsecControllerDriver->f_FM_MACSEC_SetException(h_FmMacsec, exception, enable);
+
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h
new file mode 100644
index 000000000000..fbe51875f92f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec.h
+
+ @Description FM MACSEC internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_MACSEC_H
+#define __FM_MACSEC_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_macsec_ext.h"
+
+#include "fm_common.h"
+
+
+#define __ERR_MODULE__ MODULE_FM_MACSEC
+
+
+typedef struct
+{
+ t_Error (*f_FM_MACSEC_Init) (t_Handle h_FmMacsec);
+ t_Error (*f_FM_MACSEC_Free) (t_Handle h_FmMacsec);
+
+ t_Error (*f_FM_MACSEC_ConfigUnknownSciFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode);
+ t_Error (*f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
+ t_Error (*f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) (t_Handle h_FmMacsec, bool discardUncontrolled);
+ t_Error (*f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
+ t_Error (*f_FM_MACSEC_ConfigUntagFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode);
+ t_Error (*f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled);
+ t_Error (*f_FM_MACSEC_ConfigPnExhaustionThreshold) (t_Handle h_FmMacsec, uint32_t pnExhThr);
+ t_Error (*f_FM_MACSEC_ConfigKeysUnreadable) (t_Handle h_FmMacsec);
+ t_Error (*f_FM_MACSEC_ConfigSectagWithoutSCI) (t_Handle h_FmMacsec);
+ t_Error (*f_FM_MACSEC_ConfigException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
+
+ t_Error (*f_FM_MACSEC_GetRevision) (t_Handle h_FmMacsec, uint32_t *p_MacsecRevision);
+ t_Error (*f_FM_MACSEC_Enable) (t_Handle h_FmMacsec);
+ t_Error (*f_FM_MACSEC_Disable) (t_Handle h_FmMacsec);
+ t_Error (*f_FM_MACSEC_SetException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
+
+} t_FmMacsecControllerDriver;
+
+t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam);
+t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParams);
+
+/***********************************************************************/
+/* MACSEC internal routines */
+/***********************************************************************/
+
+/**************************************************************************//**
+
+ @Group FM_MACSEC_InterModule_grp FM MACSEC Inter-Module Unit
+
+ @Description FM MACSEC Inter Module functions -
+ These are not User API routines but routines that may be called
+ from other modules. This will be the case in a single core environment,
+ where instead of using the XX messaging mechanism, the routines may be
+ called from other modules. In a multicore environment, the other modules may
+ be run by other cores and therefore these routines may not be called directly.
+
+ @{
+*//***************************************************************************/
+
+#define MAX_NUM_OF_SA_PER_SC 4
+
+typedef enum
+{
+ e_SC_RX = 0,
+ e_SC_TX
+} e_ScType;
+
+typedef enum
+{
+ e_SC_SA_A = 0,
+ e_SC_SA_B ,
+ e_SC_SA_C ,
+ e_SC_SA_D
+} e_ScSaId;
+
+typedef struct
+{
+ uint32_t scId;
+ macsecSCI_t sci;
+ bool replayProtect;
+ uint32_t replayWindow;
+ e_FmMacsecValidFrameBehavior validateFrames;
+ uint16_t confidentialityOffset;
+ e_FmMacsecSecYCipherSuite cipherSuite;
+} t_RxScParams;
+
+typedef struct
+{
+ uint32_t scId;
+ macsecSCI_t sci;
+ bool protectFrames;
+ e_FmMacsecSciInsertionMode sciInsertionMode;
+ bool confidentialityEnable;
+ uint16_t confidentialityOffset;
+ e_FmMacsecSecYCipherSuite cipherSuite;
+} t_TxScParams;
+
+typedef enum e_FmMacsecGlobalExceptions {
+ e_FM_MACSEC_EX_TX_SC, /**< Tx Sc 0 frame discarded error. */
+ e_FM_MACSEC_EX_ECC /**< MACSEC memory ECC multiple-bit error. */
+} e_FmMacsecGlobalExceptions;
+
+typedef enum e_FmMacsecGlobalEvents {
+ e_FM_MACSEC_EV_TX_SC_NEXT_PN /**< Tx Sc 0 Next Pn exhaustion threshold reached. */
+} e_FmMacsecGlobalEvents;
+
+/**************************************************************************//**
+ @Description Enum for inter-module interrupts registration
+*//***************************************************************************/
+typedef enum e_FmMacsecEventModules{
+ e_FM_MACSEC_MOD_SC_TX,
+ e_FM_MACSEC_MOD_DUMMY_LAST
+} e_FmMacsecEventModules;
+
+typedef enum e_FmMacsecInterModuleEvent {
+ e_FM_MACSEC_EV_SC_TX,
+ e_FM_MACSEC_EV_ERR_SC_TX,
+ e_FM_MACSEC_EV_DUMMY_LAST
+} e_FmMacsecInterModuleEvent;
+
+#define NUM_OF_INTER_MODULE_EVENTS (NUM_OF_TX_SC * 2)
+
+#define GET_MACSEC_MODULE_EVENT(mod, id, intrType, event) \
+ switch(mod){ \
+ case e_FM_MACSEC_MOD_SC_TX: \
+ event = (intrType == e_FM_INTR_TYPE_ERR) ? \
+ e_FM_MACSEC_EV_ERR_SC_TX: \
+ e_FM_MACSEC_EV_SC_TX; \
+ event += (uint8_t)(2 * id);break; \
+ break; \
+ default:event = e_FM_MACSEC_EV_DUMMY_LAST; \
+ break;}
+
+void FmMacsecRegisterIntr(t_Handle h_FmMacsec,
+ e_FmMacsecEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType,
+ void (*f_Isr) (t_Handle h_Arg, uint32_t id),
+ t_Handle h_Arg);
+
+void FmMacsecUnregisterIntr(t_Handle h_FmMacsec,
+ e_FmMacsecEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType);
+
+t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds);
+t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds);
+t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams);
+t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId);
+t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_RxScParams);
+t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId);
+t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key);
+t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key);
+t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId);
+t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId);
+t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive);
+t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN);
+t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN);
+t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an);
+t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An);
+t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable);
+
+t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable);
+t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable);
+
+
+
+#endif /* __FM_MACSEC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c
new file mode 100644
index 000000000000..31d789d042a7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec.c
+
+ @Description FM MACSEC driver routines implementation.
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+#include "fm_macsec.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam)
+{
+ UNUSED(p_FmMacsecParam);
+ return NULL;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c
new file mode 100644
index 000000000000..623612aca2d0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec.c
+
+ @Description FM MACSEC driver routines implementation.
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "fm_mac_ext.h"
+
+#include "fm_macsec_master.h"
+
+
+extern uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac);
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+static t_Error CheckFmMacsecParameters(t_FmMacsec *p_FmMacsec)
+{
+ if (!p_FmMacsec->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
+
+ return E_OK;
+}
+
+static void UnimplementedIsr(t_Handle h_Arg, uint32_t id)
+{
+ UNUSED(h_Arg); UNUSED(id);
+
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented Isr!"));
+}
+
+static void MacsecEventIsr(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t events,event,i;
+
+ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
+
+ events = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->evr);
+ events |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ever);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->evr,events);
+
+ for (i=0; i<NUM_OF_TX_SC; i++)
+ if (events & FM_MACSEC_EV_TX_SC_NEXT_PN(i))
+ {
+ GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_NORMAL, event);
+ p_FmMacsec->intrMng[event].f_Isr(p_FmMacsec->intrMng[event].h_SrcHandle, i);
+ }
+}
+
+static void MacsecErrorIsr(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t errors,error,i;
+
+ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
+
+ errors = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->err);
+ errors |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->erer);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->err,errors);
+
+ for (i=0; i<NUM_OF_TX_SC; i++)
+ if (errors & FM_MACSEC_EX_TX_SC(i))
+ {
+ GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_ERR, error);
+ p_FmMacsec->intrMng[error].f_Isr(p_FmMacsec->intrMng[error].h_SrcHandle, i);
+ }
+
+ if (errors & FM_MACSEC_EX_ECC)
+ {
+ uint8_t eccType;
+ uint32_t tmpReg;
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->meec);
+ ASSERT_COND(tmpReg & MECC_CAP);
+ eccType = (uint8_t)((tmpReg & MECC_CET) >> MECC_CET_SHIFT);
+
+ if (!eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_SINGLE_BIT_ECC))
+ p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_SINGLE_BIT_ECC);
+ else if (eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_MULTI_BIT_ECC))
+ p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_MULTI_BIT_ECC);
+ else
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->meec,tmpReg);
+ }
+}
+
+static t_Error MacsecInit(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_FmMacsecDriverParam *p_FmMacsecDriverParam = NULL;
+ uint32_t tmpReg,i,macId;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ CHECK_INIT_PARAMETERS(p_FmMacsec, CheckFmMacsecParameters);
+
+ p_FmMacsecDriverParam = p_FmMacsec->p_FmMacsecDriverParam;
+
+ for (i=0;i<e_FM_MACSEC_EV_DUMMY_LAST;i++)
+ p_FmMacsec->intrMng[i].f_Isr = UnimplementedIsr;
+
+ tmpReg = 0;
+ tmpReg |= (p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled << CFG_UECT_SHIFT)|
+ (p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled << CFG_ESCBT_SHIFT) |
+ (p_FmMacsecDriverParam->unknownSciTreatMode << CFG_USFT_SHIFT) |
+ (p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled << CFG_ITT_SHIFT) |
+ (p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled << CFG_KFT_SHIFT) |
+ (p_FmMacsecDriverParam->untagTreatMode << CFG_UFT_SHIFT) |
+ (p_FmMacsecDriverParam->keysUnreadable << CFG_KSS_SHIFT) |
+ (p_FmMacsecDriverParam->reservedSc0 << CFG_S0I_SHIFT) |
+ (p_FmMacsecDriverParam->byPassMode << CFG_BYPN_SHIFT);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg);
+
+ tmpReg = FM_MAC_GetMaxFrameLength(p_FmMacsec->h_FmMac);
+ /* At least Ethernet FCS (4 bytes) overhead must be subtracted from MFL.
+ * In addition, the SCI (8 bytes) overhead might be subtracted as well. */
+ tmpReg -= p_FmMacsecDriverParam->mflSubtract;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->mfl, tmpReg);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->tpnet, p_FmMacsecDriverParam->pnExhThr);
+
+ if (!p_FmMacsec->userExceptions)
+ p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
+
+ p_FmMacsec->numRxScAvailable = NUM_OF_RX_SC;
+ if (p_FmMacsecDriverParam->reservedSc0)
+ p_FmMacsec->numRxScAvailable --;
+ p_FmMacsec->numTxScAvailable = NUM_OF_TX_SC;
+
+ XX_Free(p_FmMacsecDriverParam);
+ p_FmMacsec->p_FmMacsecDriverParam = NULL;
+
+ FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId);
+ FmRegisterIntr(p_FmMacsec->h_Fm,
+ e_FM_MOD_MACSEC,
+ (uint8_t)macId,
+ e_FM_INTR_TYPE_NORMAL,
+ MacsecEventIsr,
+ p_FmMacsec);
+
+ FmRegisterIntr(p_FmMacsec->h_Fm,
+ e_FM_MOD_MACSEC,
+ 0,
+ e_FM_INTR_TYPE_ERR,
+ MacsecErrorIsr,
+ p_FmMacsec);
+
+ return E_OK;
+}
+
+static t_Error MacsecFree(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t macId;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId);
+ FmUnregisterIntr(p_FmMacsec->h_Fm,
+ e_FM_MOD_MACSEC,
+ (uint8_t)macId,
+ e_FM_INTR_TYPE_NORMAL);
+
+ FmUnregisterIntr(p_FmMacsec->h_Fm,
+ e_FM_MOD_MACSEC,
+ 0,
+ e_FM_INTR_TYPE_ERR);
+
+ if (p_FmMacsec->rxScSpinLock)
+ XX_FreeSpinlock(p_FmMacsec->rxScSpinLock);
+ if (p_FmMacsec->txScSpinLock)
+ XX_FreeSpinlock(p_FmMacsec->txScSpinLock);
+
+ XX_Free(p_FmMacsec);
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = treatMode;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = deliverUncontrolled;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled = deliverUncontrolled;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled = deliverUncontrolled;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = discardUncontrolled;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = treatMode;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = pnExhThr;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigKeysUnreadable(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = TRUE;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigSectagWithoutSCI(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead -= MACSEC_SCI_SIZE;
+ p_FmMacsec->p_FmMacsecDriverParam->mflSubtract += MACSEC_SCI_SIZE;
+
+ return E_OK;
+}
+
+static t_Error MacsecConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ GET_USER_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsec->userExceptions |= bitMask;
+ else
+ p_FmMacsec->userExceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+static t_Error MacsecGetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ *p_MacsecRevision = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ip_rev1);
+
+ return E_OK;
+}
+
+static t_Error MacsecEnable(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t tmpReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
+ tmpReg |= CFG_BYPN;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg);
+
+ return E_OK;
+}
+
+static t_Error MacsecDisable(t_Handle h_FmMacsec)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t tmpReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
+ tmpReg &= ~CFG_BYPN;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg);
+
+ return E_OK;
+}
+
+static t_Error MacsecSetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t bitMask;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ GET_USER_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsec->userExceptions |= bitMask;
+ else
+ p_FmMacsec->userExceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ if (!p_FmMacsec->userExceptions)
+ p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC;
+ else
+ p_FmMacsec->exceptions |= FM_MACSEC_EX_ECC;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
+
+ return E_OK;
+}
+
+static void InitFmMacsecControllerDriver(t_FmMacsecControllerDriver *p_FmMacsecControllerDriver)
+{
+ p_FmMacsecControllerDriver->f_FM_MACSEC_Init = MacsecInit;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_Free = MacsecFree;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment = MacsecConfigUnknownSciFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment = MacsecConfigInvalidTagsFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment = MacsecConfigEncryptWithNoChangedTextFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment = MacsecConfigUntagFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment = MacsecConfigChangedTextWithNoEncryptFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment = MacsecConfigOnlyScbIsSetFrameTreatment;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold = MacsecConfigPnExhaustionThreshold;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable = MacsecConfigKeysUnreadable;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI = MacsecConfigSectagWithoutSCI;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException = MacsecConfigException;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision = MacsecGetRevision;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_Enable = MacsecEnable;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_Disable = MacsecDisable;
+ p_FmMacsecControllerDriver->f_FM_MACSEC_SetException = MacsecSetException;
+}
+
+/****************************************/
+/* Inter-Module functions */
+/****************************************/
+
+void FmMacsecRegisterIntr(t_Handle h_FmMacsec,
+ e_FmMacsecEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType,
+ void (*f_Isr) (t_Handle h_Arg, uint32_t id),
+ t_Handle h_Arg)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint8_t event= 0;
+
+ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
+
+ GET_MACSEC_MODULE_EVENT(module, modId, intrType, event);
+
+ ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST);
+ p_FmMacsec->intrMng[event].f_Isr = f_Isr;
+ p_FmMacsec->intrMng[event].h_SrcHandle = h_Arg;
+}
+
+void FmMacsecUnregisterIntr(t_Handle h_FmMacsec,
+ e_FmMacsecEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint8_t event= 0;
+
+ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE);
+
+ GET_MACSEC_MODULE_EVENT(module, modId,intrType, event);
+
+ ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST);
+ p_FmMacsec->intrMng[event].f_Isr = NULL;
+ p_FmMacsec->intrMng[event].h_SrcHandle = NULL;
+}
+
+t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ bool *p_ScTable;
+ uint32_t *p_ScAvailable,i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE);
+
+ if (type == e_SC_RX)
+ {
+ p_ScTable = (bool *)p_FmMacsec->rxScTable;
+ p_ScAvailable = &p_FmMacsec->numRxScAvailable;
+ i = (NUM_OF_RX_SC - 1);
+ }
+ else
+ {
+ p_ScTable = (bool *)p_FmMacsec->txScTable;
+ p_ScAvailable = &p_FmMacsec->numTxScAvailable;
+ i = (NUM_OF_TX_SC - 1);
+
+ }
+ if (*p_ScAvailable < numOfScs)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not enough SCs available"));
+
+ if (isPtp)
+ {
+ i = 0;
+ if (p_ScTable[i])
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Sc 0 Not available"));
+ }
+
+ for (;numOfScs;i--)
+ {
+ if (p_ScTable[i])
+ continue;
+ numOfScs --;
+ (*p_ScAvailable)--;
+ p_ScIds[numOfScs] = i;
+ p_ScTable[i] = TRUE;
+ }
+
+ return err;
+}
+
+t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ bool *p_ScTable;
+ uint32_t *p_ScAvailable,maxNumOfSc,i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE);
+
+ if (type == e_SC_RX)
+ {
+ p_ScTable = (bool *)p_FmMacsec->rxScTable;
+ p_ScAvailable = &p_FmMacsec->numRxScAvailable;
+ maxNumOfSc = NUM_OF_RX_SC;
+ }
+ else
+ {
+ p_ScTable = (bool *)p_FmMacsec->txScTable;
+ p_ScAvailable = &p_FmMacsec->numTxScAvailable;
+ maxNumOfSc = NUM_OF_TX_SC;
+ }
+
+ if ((*p_ScAvailable + numOfScs) > maxNumOfSc)
+ RETURN_ERROR(MINOR, E_FULL, ("Too much SCs"));
+
+ for (i=0;i<numOfScs;i++)
+ {
+ p_ScTable[p_ScIds[i]] = FALSE;
+ (*p_ScAvailable)++;
+ }
+
+ return err;
+
+}
+
+t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t tmpReg = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg);
+ if (enable && (tmpReg & CFG_S0I))
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("MACSEC already in point-to-point mode"));
+
+ if (enable)
+ tmpReg |= CFG_S0I;
+ else
+ tmpReg &= ~CFG_S0I;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg);
+
+ return E_OK;
+}
+
+t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_RxScParams, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_RxScParams->scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, p_RxScParams->scId);
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg);
+ if (tmpReg & RX_SCCFG_SCI_EN_MASK)
+ {
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Rx Sc %d must be disable",p_RxScParams->scId));
+ }
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci1h, GET_SCI_FIRST_HALF(p_RxScParams->sci));
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci2h, GET_SCI_SECOND_HALF(p_RxScParams->sci));
+ tmpReg |= ((p_RxScParams->replayProtect << RX_SCCFG_RP_SHIFT) & RX_SCCFG_RP_MASK);
+ tmpReg |= ((p_RxScParams->validateFrames << RX_SCCFG_VF_SHIFT) & RX_SCCFG_VF_MASK);
+ tmpReg |= ((p_RxScParams->confidentialityOffset << RX_SCCFG_CO_SHIFT) & RX_SCCFG_CO_MASK);
+ tmpReg |= RX_SCCFG_SCI_EN_MASK;
+ tmpReg |= (p_RxScParams->cipherSuite << RX_SCCFG_CS_SHIFT);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rpw, p_RxScParams->replayWindow);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ tmpReg &= ~RX_SCCFG_SCI_EN_MASK;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_TxScParams)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+ bool alwaysIncludeSCI = FALSE, useES = FALSE, useSCB = FALSE;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_TxScParams, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_TxScParams->scId < NUM_OF_TX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, p_TxScParams->scId);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
+ if (tmpReg & TX_SCCFG_SCE_MASK)
+ {
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tx Sc %d must be disable",p_TxScParams->scId));
+ }
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci1h, GET_SCI_FIRST_HALF(p_TxScParams->sci));
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci2h, GET_SCI_SECOND_HALF(p_TxScParams->sci));
+ alwaysIncludeSCI = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG);
+ useES = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA);
+
+ tmpReg |= ((p_TxScParams->protectFrames << TX_SCCFG_PF_SHIFT) & TX_SCCFG_PF_MASK);
+ tmpReg |= ((alwaysIncludeSCI << TX_SCCFG_AIS_SHIFT) & TX_SCCFG_AIS_MASK);
+ tmpReg |= ((useES << TX_SCCFG_UES_SHIFT) & TX_SCCFG_UES_MASK);
+ tmpReg |= ((useSCB << TX_SCCFG_USCB_SHIFT) & TX_SCCFG_USCB_MASK);
+ tmpReg |= ((p_TxScParams->confidentialityEnable << TX_SCCFG_CE_SHIFT) & TX_SCCFG_CE_MASK);
+ tmpReg |= ((p_TxScParams->confidentialityOffset << TX_SCCFG_CO_SHIFT) & TX_SCCFG_CO_MASK);
+ tmpReg |= TX_SCCFG_SCE_MASK;
+ tmpReg |= (p_TxScParams->cipherSuite << TX_SCCFG_CS_SHIFT);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_TX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ tmpReg &= ~TX_SCCFG_SCE_MASK;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, DEFAULT_initNextPn);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, lowestPn);
+ MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak, key, sizeof(macsecSAKey_t));
+
+ tmpReg |= RX_SACFG_ACTIVE;
+ tmpReg |= ((an << RX_SACFG_AN_SHIFT) & RX_SACFG_AN_MASK);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, DEFAULT_initNextPn);
+ MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak, key, sizeof(macsecSAKey_t));
+
+ tmpReg |= TX_SACFG_ACTIVE;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, i, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, 0x0);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, 0x0);
+ for (i=0; i<4; i++)
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak[i], 0x0);
+
+ tmpReg |= RX_SACFG_ACTIVE;
+ tmpReg &= ~RX_SACFG_EN_MASK;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, i, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, 0x0);
+ for (i=0; i<4; i++)
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak[i], 0x0);
+
+ tmpReg |= TX_SACFG_ACTIVE;
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs);
+ if (enableReceive)
+ tmpReg |= RX_SACFG_EN_MASK;
+ else
+ tmpReg &= ~RX_SACFG_EN_MASK;
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, updtNextPN);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId);
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, updtLowestPN);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
+
+ tmpReg |= ((an << TX_SCCFG_AN_SHIFT) & TX_SCCFG_AN_MASK);
+ tmpReg |= ((saId << TX_SCCFG_ASA_SHIFT) & TX_SCCFG_ASA_MASK);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ return err;
+}
+
+t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ t_Error err = E_OK;
+ uint32_t tmpReg = 0, intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE);
+
+ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock);
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId);
+
+ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg);
+
+ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags);
+
+ *p_An = (macsecAN_t)((tmpReg & TX_SCCFG_AN_MASK) >> TX_SCCFG_AN_SHIFT);
+
+ return err;
+}
+
+t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t bitMask;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception, scId);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsec->exceptions |= bitMask;
+ else
+ p_FmMacsec->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions);
+
+ return E_OK;
+}
+
+t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable)
+{
+ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec;
+ uint32_t bitMask;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE);
+
+ GET_EVENT_FLAG(bitMask, event, scId);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsec->events |= bitMask;
+ else
+ p_FmMacsec->events &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event"));
+
+ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->ever, p_FmMacsec->events);
+
+ return E_OK;
+}
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParam)
+{
+ t_FmMacsec *p_FmMacsec;
+ uint32_t macId;
+
+ /* Allocate FM MACSEC structure */
+ p_FmMacsec = (t_FmMacsec *) XX_Malloc(sizeof(t_FmMacsec));
+ if (!p_FmMacsec)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver structure"));
+ return NULL;
+ }
+ memset(p_FmMacsec, 0, sizeof(t_FmMacsec));
+ InitFmMacsecControllerDriver(&p_FmMacsec->fmMacsecControllerDriver);
+
+ /* Allocate the FM MACSEC driver's parameters structure */
+ p_FmMacsec->p_FmMacsecDriverParam = (t_FmMacsecDriverParam *)XX_Malloc(sizeof(t_FmMacsecDriverParam));
+ if (!p_FmMacsec->p_FmMacsecDriverParam)
+ {
+ XX_Free(p_FmMacsec);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver parameters"));
+ return NULL;
+ }
+ memset(p_FmMacsec->p_FmMacsecDriverParam, 0, sizeof(t_FmMacsecDriverParam));
+
+ /* Initialize FM MACSEC parameters which will be kept by the driver */
+ p_FmMacsec->h_Fm = p_FmMacsecParam->h_Fm;
+ p_FmMacsec->h_FmMac = p_FmMacsecParam->nonGuestParams.h_FmMac;
+ p_FmMacsec->p_FmMacsecRegs = (t_FmMacsecRegs *)UINT_TO_PTR(p_FmMacsecParam->nonGuestParams.baseAddr);
+ p_FmMacsec->f_Exception = p_FmMacsecParam->nonGuestParams.f_Exception;
+ p_FmMacsec->h_App = p_FmMacsecParam->nonGuestParams.h_App;
+ p_FmMacsec->userExceptions = DEFAULT_userExceptions;
+ p_FmMacsec->exceptions = DEFAULT_exceptions;
+ p_FmMacsec->events = DEFAULT_events;
+ p_FmMacsec->rxScSpinLock = XX_InitSpinlock();
+ p_FmMacsec->txScSpinLock = XX_InitSpinlock();
+
+ /* Initialize FM MACSEC driver parameters parameters (for initialization phase only) */
+ p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = DEFAULT_unknownSciFrameTreatment;
+ p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = DEFAULT_invalidTagsFrameTreatment;
+ p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = DEFAULT_encryptWithNoChangedTextFrameTreatment;
+ p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = DEFAULT_untagFrameTreatment;
+ p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = DEFAULT_keysUnreadable;
+ p_FmMacsec->p_FmMacsecDriverParam->reservedSc0 = DEFAULT_sc0ReservedForPTP;
+ p_FmMacsec->p_FmMacsecDriverParam->byPassMode = !DEFAULT_normalMode;
+ p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = DEFAULT_pnExhThr;
+ p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead = DEFAULT_sectagOverhead;
+ p_FmMacsec->p_FmMacsecDriverParam->mflSubtract = DEFAULT_mflSubtract;
+ /* build the FM MACSEC master IPC address */
+ memset(p_FmMacsec->fmMacsecModuleName, 0, (sizeof(char))*MODULE_NAME_SIZE);
+ FM_MAC_GetId(p_FmMacsec->h_FmMac,&macId);
+ if (Sprint (p_FmMacsec->fmMacsecModuleName, "FM-%d-MAC-%d-MACSEC-Master",
+ FmGetId(p_FmMacsec->h_Fm),macId) != 24)
+ {
+ XX_Free(p_FmMacsec->p_FmMacsecDriverParam);
+ XX_Free(p_FmMacsec);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ return NULL;
+ }
+ return p_FmMacsec;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h
new file mode 100644
index 000000000000..2296a0f10d54
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec_master.h
+
+ @Description FM MACSEC internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_MACSEC_MASTER_H
+#define __FM_MACSEC_MASTER_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+
+#include "fm_macsec.h"
+
+
+#define MACSEC_ICV_SIZE 16
+#define MACSEC_SECTAG_SIZE 16
+#define MACSEC_SCI_SIZE 8
+#define MACSEC_FCS_SIZE 4
+
+/**************************************************************************//**
+ @Description Exceptions
+*//***************************************************************************/
+
+#define FM_MACSEC_EX_TX_SC_0 0x80000000
+#define FM_MACSEC_EX_TX_SC(sc) (FM_MACSEC_EX_TX_SC_0 >> (sc))
+#define FM_MACSEC_EX_ECC 0x00000001
+
+#define GET_EXCEPTION_FLAG(bitMask, exception, id) switch (exception){ \
+ case e_FM_MACSEC_EX_TX_SC: \
+ bitMask = FM_MACSEC_EX_TX_SC(id); break; \
+ case e_FM_MACSEC_EX_ECC: \
+ bitMask = FM_MACSEC_EX_ECC; break; \
+ default: bitMask = 0;break;}
+
+#define FM_MACSEC_USER_EX_SINGLE_BIT_ECC 0x80000000
+#define FM_MACSEC_USER_EX_MULTI_BIT_ECC 0x40000000
+
+#define GET_USER_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \
+ case e_FM_MACSEC_EX_SINGLE_BIT_ECC: \
+ bitMask = FM_MACSEC_USER_EX_SINGLE_BIT_ECC; break; \
+ case e_FM_MACSEC_EX_MULTI_BIT_ECC: \
+ bitMask = FM_MACSEC_USER_EX_MULTI_BIT_ECC; break; \
+ default: bitMask = 0;break;}
+
+/**************************************************************************//**
+ @Description Events
+*//***************************************************************************/
+
+#define FM_MACSEC_EV_TX_SC_0_NEXT_PN 0x80000000
+#define FM_MACSEC_EV_TX_SC_NEXT_PN(sc) (FM_MACSEC_EV_TX_SC_0_NEXT_PN >> (sc))
+
+#define GET_EVENT_FLAG(bitMask, event, id) switch (event){ \
+ case e_FM_MACSEC_EV_TX_SC_NEXT_PN: \
+ bitMask = FM_MACSEC_EV_TX_SC_NEXT_PN(id); break; \
+ default: bitMask = 0;break;}
+
+/**************************************************************************//**
+ @Description Defaults
+*//***************************************************************************/
+#define DEFAULT_userExceptions (FM_MACSEC_USER_EX_SINGLE_BIT_ECC |\
+ FM_MACSEC_USER_EX_MULTI_BIT_ECC)
+
+#define DEFAULT_exceptions (FM_MACSEC_EX_TX_SC(0) |\
+ FM_MACSEC_EX_TX_SC(1) |\
+ FM_MACSEC_EX_TX_SC(2) |\
+ FM_MACSEC_EX_TX_SC(3) |\
+ FM_MACSEC_EX_TX_SC(4) |\
+ FM_MACSEC_EX_TX_SC(5) |\
+ FM_MACSEC_EX_TX_SC(6) |\
+ FM_MACSEC_EX_TX_SC(7) |\
+ FM_MACSEC_EX_TX_SC(8) |\
+ FM_MACSEC_EX_TX_SC(9) |\
+ FM_MACSEC_EX_TX_SC(10) |\
+ FM_MACSEC_EX_TX_SC(11) |\
+ FM_MACSEC_EX_TX_SC(12) |\
+ FM_MACSEC_EX_TX_SC(13) |\
+ FM_MACSEC_EX_TX_SC(14) |\
+ FM_MACSEC_EX_TX_SC(15) |\
+ FM_MACSEC_EX_ECC )
+
+#define DEFAULT_events (FM_MACSEC_EV_TX_SC_NEXT_PN(0) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(1) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(2) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(3) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(4) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(5) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(6) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(7) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(8) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(9) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(10) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(11) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(12) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(13) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(14) |\
+ FM_MACSEC_EV_TX_SC_NEXT_PN(15) )
+
+#define DEFAULT_unknownSciFrameTreatment e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH
+#define DEFAULT_invalidTagsFrameTreatment FALSE
+#define DEFAULT_encryptWithNoChangedTextFrameTreatment FALSE
+#define DEFAULT_untagFrameTreatment e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED
+#define DEFAULT_changedTextWithNoEncryptFrameTreatment FALSE
+#define DEFAULT_onlyScbIsSetFrameTreatment FALSE
+#define DEFAULT_keysUnreadable FALSE
+#define DEFAULT_normalMode TRUE
+#define DEFAULT_sc0ReservedForPTP FALSE
+#define DEFAULT_initNextPn 1
+#define DEFAULT_pnExhThr 0xffffffff
+#define DEFAULT_sectagOverhead (MACSEC_ICV_SIZE + MACSEC_SECTAG_SIZE)
+#define DEFAULT_mflSubtract MACSEC_FCS_SIZE
+
+
+/**************************************************************************//**
+ @Description Memory Mapped Registers
+*//***************************************************************************/
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+typedef _Packed struct
+{
+ /* MACsec configuration */
+ volatile uint32_t cfg; /**< MACsec configuration */
+ volatile uint32_t et; /**< MACsec EtherType */
+ volatile uint8_t res1[56]; /**< reserved */
+ volatile uint32_t mfl; /**< Maximum Frame Length */
+ volatile uint32_t tpnet; /**< TX Packet Number exhaustion threshold */
+ volatile uint8_t res2[56]; /**< reserved */
+ volatile uint32_t rxsca; /**< RX SC access select */
+ volatile uint8_t res3[60]; /**< reserved */
+ volatile uint32_t txsca; /**< TX SC access select */
+ volatile uint8_t res4[60]; /**< reserved */
+
+ /* RX configuration, status and statistic */
+ volatile uint32_t rxsci1h; /**< RX Secure Channel Identifier first half */
+ volatile uint32_t rxsci2h; /**< RX Secure Channel Identifier second half */
+ volatile uint8_t res5[8]; /**< reserved */
+ volatile uint32_t ifio1hs; /**< ifInOctets first half Statistic */
+ volatile uint32_t ifio2hs; /**< ifInOctets second half Statistic */
+ volatile uint32_t ifiups; /**< ifInUcastPkts Statistic */
+ volatile uint8_t res6[4]; /**< reserved */
+ volatile uint32_t ifimps; /**< ifInMulticastPkts Statistic */
+ volatile uint32_t ifibps; /**< ifInBroadcastPkts Statistic */
+ volatile uint32_t rxsccfg; /**< RX Secure Channel configuration */
+ volatile uint32_t rpw; /**< replayWindow */
+ volatile uint8_t res7[16]; /**< reserved */
+ volatile uint32_t inov1hs; /**< InOctetsValidated first half Statistic */
+ volatile uint32_t inov2hs; /**< InOctetsValidated second half Statistic */
+ volatile uint32_t inod1hs; /**< InOctetsDecrypted first half Statistic */
+ volatile uint32_t inod2hs; /**< InOctetsDecrypted second half Statistic */
+ volatile uint32_t rxscipus; /**< RX Secure Channel InPktsUnchecked Statistic */
+ volatile uint32_t rxscipds; /**< RX Secure Channel InPktsDelayed Statistic */
+ volatile uint32_t rxscipls; /**< RX Secure Channel InPktsLate Statistic */
+ volatile uint8_t res8[4]; /**< reserved */
+ volatile uint32_t rxaninuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InNotUsingSA Statistic */
+ volatile uint32_t rxanipuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InPktsUnusedSA Statistic */
+ _Packed struct
+ {
+ volatile uint32_t rxsacs; /**< RX Security Association configuration and status */
+ volatile uint32_t rxsanpn; /**< RX Security Association nextPN */
+ volatile uint32_t rxsalpn; /**< RX Security Association lowestPN */
+ volatile uint32_t rxsaipos; /**< RX Security Association InPktsOK Statistic */
+ volatile uint32_t rxsak[4]; /**< RX Security Association key (128 bit) */
+ volatile uint32_t rxsah[4]; /**< RX Security Association hash (128 bit) */
+ volatile uint32_t rxsaipis; /**< RX Security Association InPktsInvalid Statistic */
+ volatile uint32_t rxsaipnvs; /**< RX Security Association InPktsNotValid Statistic */
+ volatile uint8_t res9[8]; /**< reserved */
+ } _PackedType fmMacsecRxScSa[NUM_OF_SA_PER_RX_SC];
+
+ /* TX configuration, status and statistic */
+ volatile uint32_t txsci1h; /**< TX Secure Channel Identifier first half */
+ volatile uint32_t txsci2h; /**< TX Secure Channel Identifier second half */
+ volatile uint8_t res10[8]; /**< reserved */
+ volatile uint32_t ifoo1hs; /**< ifOutOctets first half Statistic */
+ volatile uint32_t ifoo2hs; /**< ifOutOctets second half Statistic */
+ volatile uint32_t ifoups; /**< ifOutUcastPkts Statistic */
+ volatile uint32_t opus; /**< OutPktsUntagged Statistic */
+ volatile uint32_t ifomps; /**< ifOutMulticastPkts Statistic */
+ volatile uint32_t ifobps; /**< ifOutBroadcastPkts Statistic */
+ volatile uint32_t txsccfg; /**< TX Secure Channel configuration */
+ volatile uint32_t optls; /**< OutPktsTooLong Statistic */
+ volatile uint8_t res11[16]; /**< reserved */
+ volatile uint32_t oop1hs; /**< OutOctetsProtected first half Statistic */
+ volatile uint32_t oop2hs; /**< OutOctetsProtected second half Statistic */
+ volatile uint32_t ooe1hs; /**< OutOctetsEncrypted first half Statistic */
+ volatile uint32_t ooe2hs; /**< OutOctetsEncrypted second half Statistic */
+ volatile uint8_t res12[48]; /**< reserved */
+ _Packed struct
+ {
+ volatile uint32_t txsacs; /**< TX Security Association configuration and status */
+ volatile uint32_t txsanpn; /**< TX Security Association nextPN */
+ volatile uint32_t txsaopps; /**< TX Security Association OutPktsProtected Statistic */
+ volatile uint32_t txsaopes; /**< TX Security Association OutPktsEncrypted Statistic */
+ volatile uint32_t txsak[4]; /**< TX Security Association key (128 bit) */
+ volatile uint32_t txsah[4]; /**< TX Security Association hash (128 bit) */
+ volatile uint8_t res13[16]; /**< reserved */
+ } _PackedType fmMacsecTxScSa[NUM_OF_SA_PER_TX_SC];
+ volatile uint8_t res14[248]; /**< reserved */
+
+ /* Global configuration and status */
+ volatile uint32_t ip_rev1; /**< MACsec IP Block Revision 1 register */
+ volatile uint32_t ip_rev2; /**< MACsec IP Block Revision 2 register */
+ volatile uint32_t evr; /**< MACsec Event Register */
+ volatile uint32_t ever; /**< MACsec Event Enable Register */
+ volatile uint32_t evfr; /**< MACsec Event Force Register */
+ volatile uint32_t err; /**< MACsec Error Register */
+ volatile uint32_t erer; /**< MACsec Error Enable Register */
+ volatile uint32_t erfr; /**< MACsec Error Force Register */
+ volatile uint8_t res15[40]; /**< reserved */
+ volatile uint32_t meec; /**< MACsec Memory ECC Error Capture Register */
+ volatile uint32_t idle; /**< MACsec Idle status Register */
+ volatile uint8_t res16[184]; /**< reserved */
+ /* DEBUG */
+ volatile uint32_t rxec; /**< MACsec RX error capture Register */
+ volatile uint8_t res17[28]; /**< reserved */
+ volatile uint32_t txec; /**< MACsec TX error capture Register */
+ volatile uint8_t res18[220]; /**< reserved */
+
+ /* Macsec Rx global statistic */
+ volatile uint32_t ifiocp1hs; /**< ifInOctetsCp first half Statistic */
+ volatile uint32_t ifiocp2hs; /**< ifInOctetsCp second half Statistic */
+ volatile uint32_t ifiupcps; /**< ifInUcastPktsCp Statistic */
+ volatile uint8_t res19[4]; /**< reserved */
+ volatile uint32_t ifioup1hs; /**< ifInOctetsUp first half Statistic */
+ volatile uint32_t ifioup2hs; /**< ifInOctetsUp second half Statistic */
+ volatile uint32_t ifiupups; /**< ifInUcastPktsUp Statistic */
+ volatile uint8_t res20[4]; /**< reserved */
+ volatile uint32_t ifimpcps; /**< ifInMulticastPktsCp Statistic */
+ volatile uint32_t ifibpcps; /**< ifInBroadcastPktsCp Statistic */
+ volatile uint32_t ifimpups; /**< ifInMulticastPktsUp Statistic */
+ volatile uint32_t ifibpups; /**< ifInBroadcastPktsUp Statistic */
+ volatile uint32_t ipwts; /**< InPktsWithoutTag Statistic */
+ volatile uint32_t ipkays; /**< InPktsKaY Statistic */
+ volatile uint32_t ipbts; /**< InPktsBadTag Statistic */
+ volatile uint32_t ipsnfs; /**< InPktsSCINotFound Statistic */
+ volatile uint32_t ipuecs; /**< InPktsUnsupportedEC Statistic */
+ volatile uint32_t ipescbs; /**< InPktsEponSingleCopyBroadcast Statistic */
+ volatile uint32_t iptls; /**< InPktsTooLong Statistic */
+ volatile uint8_t res21[52]; /**< reserved */
+
+ /* Macsec Tx global statistic */
+ volatile uint32_t opds; /**< OutPktsDiscarded Statistic */
+#if (DPAA_VERSION >= 11)
+ volatile uint8_t res22[124]; /**< reserved */
+ _Packed struct
+ {
+ volatile uint32_t rxsak[8]; /**< RX Security Association key (128/256 bit) */
+ volatile uint8_t res23[32]; /**< reserved */
+ } _PackedType rxScSaKey[NUM_OF_SA_PER_RX_SC];
+ _Packed struct
+ {
+ volatile uint32_t txsak[8]; /**< TX Security Association key (128/256 bit) */
+ volatile uint8_t res24[32]; /**< reserved */
+ } _PackedType txScSaKey[NUM_OF_SA_PER_TX_SC];
+#endif /* (DPAA_VERSION >= 11) */
+} _PackedType t_FmMacsecRegs;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/**************************************************************************//**
+ @Description General defines
+*//***************************************************************************/
+
+#define SCI_HIGH_MASK 0xffffffff00000000LL
+#define SCI_LOW_MASK 0x00000000ffffffffLL
+
+#define LONG_SHIFT 32
+
+#define GET_SCI_FIRST_HALF(sci) (uint32_t)((macsecSCI_t)((macsecSCI_t)(sci) & SCI_HIGH_MASK) >> LONG_SHIFT)
+#define GET_SCI_SECOND_HALF(sci) (uint32_t)((macsecSCI_t)(sci) & SCI_LOW_MASK)
+
+/**************************************************************************//**
+ @Description Configuration defines
+*//***************************************************************************/
+
+/* masks */
+#define CFG_UECT 0x00000800
+#define CFG_ESCBT 0x00000400
+#define CFG_USFT 0x00000300
+#define CFG_ITT 0x00000080
+#define CFG_KFT 0x00000040
+#define CFG_UFT 0x00000030
+#define CFG_KSS 0x00000004
+#define CFG_BYPN 0x00000002
+#define CFG_S0I 0x00000001
+
+#define ET_TYPE 0x0000ffff
+
+#define MFL_MAX_LEN 0x0000ffff
+
+#define RXSCA_SC_SEL 0x0000000f
+
+#define TXSCA_SC_SEL 0x0000000f
+
+#define IP_REV_1_IP_ID 0xffff0000
+#define IP_REV_1_IP_MJ 0x0000ff00
+#define IP_REV_1_IP_MM 0x000000ff
+
+#define IP_REV_2_IP_INT 0x00ff0000
+#define IP_REV_2_IP_ERR 0x0000ff00
+#define IP_REV_2_IP_CFG 0x000000ff
+
+#define MECC_CAP 0x80000000
+#define MECC_CET 0x40000000
+#define MECC_SERCNT 0x00ff0000
+#define MECC_MEMADDR 0x000001ff
+
+/* shifts */
+#define CFG_UECT_SHIFT (31-20)
+#define CFG_ESCBT_SHIFT (31-21)
+#define CFG_USFT_SHIFT (31-23)
+#define CFG_ITT_SHIFT (31-24)
+#define CFG_KFT_SHIFT (31-25)
+#define CFG_UFT_SHIFT (31-27)
+#define CFG_KSS_SHIFT (31-29)
+#define CFG_BYPN_SHIFT (31-30)
+#define CFG_S0I_SHIFT (31-31)
+
+#define IP_REV_1_IP_ID_SHIFT (31-15)
+#define IP_REV_1_IP_MJ_SHIFT (31-23)
+#define IP_REV_1_IP_MM_SHIFT (31-31)
+
+#define IP_REV_2_IP_INT_SHIFT (31-15)
+#define IP_REV_2_IP_ERR_SHIFT (31-23)
+#define IP_REV_2_IP_CFG_SHIFT (31-31)
+
+#define MECC_CAP_SHIFT (31-0)
+#define MECC_CET_SHIFT (31-1)
+#define MECC_SERCNT_SHIFT (31-15)
+#define MECC_MEMADDR_SHIFT (31-31)
+
+/**************************************************************************//**
+ @Description RX SC defines
+*//***************************************************************************/
+
+/* masks */
+#define RX_SCCFG_SCI_EN_MASK 0x00000800
+#define RX_SCCFG_RP_MASK 0x00000400
+#define RX_SCCFG_VF_MASK 0x00000300
+#define RX_SCCFG_CO_MASK 0x0000003f
+
+/* shifts */
+#define RX_SCCFG_SCI_EN_SHIFT (31-20)
+#define RX_SCCFG_RP_SHIFT (31-21)
+#define RX_SCCFG_VF_SHIFT (31-23)
+#define RX_SCCFG_CO_SHIFT (31-31)
+#define RX_SCCFG_CS_SHIFT (31-7)
+
+/**************************************************************************//**
+ @Description RX SA defines
+*//***************************************************************************/
+
+/* masks */
+#define RX_SACFG_ACTIVE 0x80000000
+#define RX_SACFG_AN_MASK 0x00000006
+#define RX_SACFG_EN_MASK 0x00000001
+
+/* shifts */
+#define RX_SACFG_AN_SHIFT (31-30)
+#define RX_SACFG_EN_SHIFT (31-31)
+
+/**************************************************************************//**
+ @Description TX SC defines
+*//***************************************************************************/
+
+/* masks */
+#define TX_SCCFG_AN_MASK 0x000c0000
+#define TX_SCCFG_ASA_MASK 0x00020000
+#define TX_SCCFG_SCE_MASK 0x00010000
+#define TX_SCCFG_CO_MASK 0x00003f00
+#define TX_SCCFG_CE_MASK 0x00000010
+#define TX_SCCFG_PF_MASK 0x00000008
+#define TX_SCCFG_AIS_MASK 0x00000004
+#define TX_SCCFG_UES_MASK 0x00000002
+#define TX_SCCFG_USCB_MASK 0x00000001
+
+/* shifts */
+#define TX_SCCFG_AN_SHIFT (31-13)
+#define TX_SCCFG_ASA_SHIFT (31-14)
+#define TX_SCCFG_SCE_SHIFT (31-15)
+#define TX_SCCFG_CO_SHIFT (31-23)
+#define TX_SCCFG_CE_SHIFT (31-27)
+#define TX_SCCFG_PF_SHIFT (31-28)
+#define TX_SCCFG_AIS_SHIFT (31-29)
+#define TX_SCCFG_UES_SHIFT (31-30)
+#define TX_SCCFG_USCB_SHIFT (31-31)
+#define TX_SCCFG_CS_SHIFT (31-7)
+
+/**************************************************************************//**
+ @Description TX SA defines
+*//***************************************************************************/
+
+/* masks */
+#define TX_SACFG_ACTIVE 0x80000000
+
+
+typedef struct
+{
+ void (*f_Isr) (t_Handle h_Arg, uint32_t id);
+ t_Handle h_SrcHandle;
+} t_FmMacsecIntrSrc;
+
+typedef struct
+{
+ e_FmMacsecUnknownSciFrameTreatment unknownSciTreatMode;
+ bool invalidTagsDeliverUncontrolled;
+ bool changedTextWithNoEncryptDeliverUncontrolled;
+ bool onlyScbIsSetDeliverUncontrolled;
+ bool encryptWithNoChangedTextDiscardUncontrolled;
+ e_FmMacsecUntagFrameTreatment untagTreatMode;
+ uint32_t pnExhThr;
+ bool keysUnreadable;
+ bool byPassMode;
+ bool reservedSc0;
+ uint32_t sectagOverhead;
+ uint32_t mflSubtract;
+} t_FmMacsecDriverParam;
+
+typedef struct
+{
+ t_FmMacsecControllerDriver fmMacsecControllerDriver;
+ t_Handle h_Fm;
+ t_FmMacsecRegs *p_FmMacsecRegs;
+ t_Handle h_FmMac; /**< A handle to the FM MAC object related to */
+ char fmMacsecModuleName[MODULE_NAME_SIZE];
+ t_FmMacsecIntrSrc intrMng[NUM_OF_INTER_MODULE_EVENTS];
+ uint32_t events;
+ uint32_t exceptions;
+ uint32_t userExceptions;
+ t_FmMacsecExceptionsCallback *f_Exception; /**< Exception Callback Routine */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+ bool rxScTable[NUM_OF_RX_SC];
+ uint32_t numRxScAvailable;
+ bool txScTable[NUM_OF_TX_SC];
+ uint32_t numTxScAvailable;
+ t_Handle rxScSpinLock;
+ t_Handle txScSpinLock;
+ t_FmMacsecDriverParam *p_FmMacsecDriverParam;
+} t_FmMacsec;
+
+
+#endif /* __FM_MACSEC_MASTER_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c
new file mode 100644
index 000000000000..7c72dc98e7f1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c
@@ -0,0 +1,883 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec_secy.c
+
+ @Description FM MACSEC SECY driver routines implementation.
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+
+#include "fm_macsec_secy.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+static void FmMacsecSecYExceptionsIsr(t_Handle h_FmMacsecSecY, uint32_t id)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ UNUSED(id);
+ SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE);
+
+ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
+ p_FmMacsecSecY->f_Exception(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EX_FRAME_DISCARDED);
+}
+
+static void FmMacsecSecYEventsIsr(t_Handle h_FmMacsecSecY, uint32_t id)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ UNUSED(id);
+ SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE);
+
+ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
+ p_FmMacsecSecY->f_Event(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EV_NEXT_PN);
+}
+
+static t_Error CheckFmMacsecSecYParameters(t_FmMacsecSecY *p_FmMacsecSecY)
+{
+ if (!p_FmMacsecSecY->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
+
+ if (!p_FmMacsecSecY->f_Event)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Events callback not provided"));
+
+ if (!p_FmMacsecSecY->numOfRxSc)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Num of Rx Scs must be greater than '0'"));
+
+
+ return E_OK;
+}
+
+static t_Handle FmMacsecSecYCreateSc(t_FmMacsecSecY *p_FmMacsecSecY,
+ macsecSCI_t sci,
+ e_FmMacsecSecYCipherSuite cipherSuite,
+ e_ScType type)
+{
+ t_SecYSc *p_ScTable;
+ void *p_Params;
+ uint32_t numOfSc,i;
+ t_Error err = E_OK;
+ t_RxScParams rxScParams;
+ t_TxScParams txScParams;
+
+ ASSERT_COND(p_FmMacsecSecY);
+ ASSERT_COND(p_FmMacsecSecY->h_FmMacsec);
+
+ if (type == e_SC_RX)
+ {
+ memset(&rxScParams, 0, sizeof(rxScParams));
+ i = (NUM_OF_RX_SC - 1);
+ p_ScTable = p_FmMacsecSecY->p_RxSc;
+ numOfSc = p_FmMacsecSecY->numOfRxSc;
+ rxScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset;
+ rxScParams.replayProtect = p_FmMacsecSecY->replayProtect;
+ rxScParams.replayWindow = p_FmMacsecSecY->replayWindow;
+ rxScParams.validateFrames = p_FmMacsecSecY->validateFrames;
+ rxScParams.cipherSuite = cipherSuite;
+ p_Params = &rxScParams;
+ }
+ else
+ {
+ memset(&txScParams, 0, sizeof(txScParams));
+ i = (NUM_OF_TX_SC - 1);
+ p_ScTable = p_FmMacsecSecY->p_TxSc;
+ numOfSc = p_FmMacsecSecY->numOfTxSc;
+ txScParams.sciInsertionMode = p_FmMacsecSecY->sciInsertionMode;
+ txScParams.protectFrames = p_FmMacsecSecY->protectFrames;
+ txScParams.confidentialityEnable = p_FmMacsecSecY->confidentialityEnable;
+ txScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset;
+ txScParams.cipherSuite = cipherSuite;
+ p_Params = &txScParams;
+ }
+
+ for (i=0;i<numOfSc;i++)
+ if (!p_ScTable[i].inUse)
+ break;
+ if (i == numOfSc)
+ {
+ REPORT_ERROR(MAJOR, E_FULL, ("FM MACSEC SECY SC"));
+ return NULL;
+ }
+
+ if (type == e_SC_RX)
+ {
+ ((t_RxScParams *)p_Params)->scId = p_ScTable[i].scId;
+ ((t_RxScParams *)p_Params)->sci = sci;
+ if ((err = FmMacsecCreateRxSc(p_FmMacsecSecY->h_FmMacsec, (t_RxScParams *)p_Params)) != E_OK)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC"));
+ return NULL;
+ }
+ }
+ else
+ {
+ ((t_TxScParams *)p_Params)->scId = p_ScTable[i].scId;
+ ((t_TxScParams *)p_Params)->sci = sci;
+ if ((err = FmMacsecCreateTxSc(p_FmMacsecSecY->h_FmMacsec, (t_TxScParams *)p_Params)) != E_OK)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC"));
+ return NULL;
+ }
+ }
+
+ p_ScTable[i].inUse = TRUE;
+ return &p_ScTable[i];
+}
+
+static t_Error FmMacsecSecYDeleteSc(t_FmMacsecSecY *p_FmMacsecSecY, t_SecYSc *p_FmSecYSc, e_ScType type)
+{
+ t_Error err = E_OK;
+
+ ASSERT_COND(p_FmMacsecSecY);
+ ASSERT_COND(p_FmMacsecSecY->h_FmMacsec);
+ ASSERT_COND(p_FmSecYSc);
+
+ if (type == e_SC_RX)
+ {
+ if ((err = FmMacsecDeleteRxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+ else
+ if ((err = FmMacsecDeleteTxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->inUse = FALSE;
+
+ return err;
+}
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY;
+
+ /* Allocate FM MACSEC structure */
+ p_FmMacsecSecY = (t_FmMacsecSecY *) XX_Malloc(sizeof(t_FmMacsecSecY));
+ if (!p_FmMacsecSecY)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver structure"));
+ return NULL;
+ }
+ memset(p_FmMacsecSecY, 0, sizeof(t_FmMacsecSecY));
+
+ /* Allocate the FM MACSEC driver's parameters structure */
+ p_FmMacsecSecY->p_FmMacsecSecYDriverParam = (t_FmMacsecSecYDriverParam *)XX_Malloc(sizeof(t_FmMacsecSecYDriverParam));
+ if (!p_FmMacsecSecY->p_FmMacsecSecYDriverParam)
+ {
+ XX_Free(p_FmMacsecSecY);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver parameters"));
+ return NULL;
+ }
+ memset(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, 0, sizeof(t_FmMacsecSecYDriverParam));
+
+ /* Initialize FM MACSEC SECY parameters which will be kept by the driver */
+ p_FmMacsecSecY->h_FmMacsec = p_FmMacsecSecYParam->h_FmMacsec;
+ p_FmMacsecSecY->f_Event = p_FmMacsecSecYParam->f_Event;
+ p_FmMacsecSecY->f_Exception = p_FmMacsecSecYParam->f_Exception;
+ p_FmMacsecSecY->h_App = p_FmMacsecSecYParam->h_App;
+ p_FmMacsecSecY->confidentialityEnable = DEFAULT_confidentialityEnable;
+ p_FmMacsecSecY->confidentialityOffset = DEFAULT_confidentialityOffset;
+ p_FmMacsecSecY->validateFrames = DEFAULT_validateFrames;
+ p_FmMacsecSecY->replayProtect = DEFAULT_replayEnable;
+ p_FmMacsecSecY->replayWindow = DEFAULT_replayWindow;
+ p_FmMacsecSecY->protectFrames = DEFAULT_protectFrames;
+ p_FmMacsecSecY->sciInsertionMode = DEFAULT_sciInsertionMode;
+ p_FmMacsecSecY->isPointToPoint = DEFAULT_ptp;
+ p_FmMacsecSecY->numOfRxSc = p_FmMacsecSecYParam->numReceiveChannels;
+ p_FmMacsecSecY->numOfTxSc = DEFAULT_numOfTxSc;
+ p_FmMacsecSecY->exceptions = DEFAULT_exceptions;
+ p_FmMacsecSecY->events = DEFAULT_events;
+
+ memcpy(&p_FmMacsecSecY->p_FmMacsecSecYDriverParam->txScParams,
+ &p_FmMacsecSecYParam->txScParams,
+ sizeof(t_FmMacsecSecYSCParams));
+ return p_FmMacsecSecY;
+}
+
+t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam = NULL;
+ uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i, j;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_HANDLE);
+
+ CHECK_INIT_PARAMETERS(p_FmMacsecSecY, CheckFmMacsecSecYParameters);
+
+ p_FmMacsecSecYDriverParam = p_FmMacsecSecY->p_FmMacsecSecYDriverParam;
+
+ if ((p_FmMacsecSecY->isPointToPoint) &&
+ ((err = FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, TRUE)) != E_OK))
+ RETURN_ERROR(MAJOR, err, ("Can't set Poin-to-Point"));
+
+ /* Rx Sc Allocation */
+ p_FmMacsecSecY->p_RxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc);
+ if (!p_FmMacsecSecY->p_RxSc)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC"));
+ memset(p_FmMacsecSecY->p_RxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc);
+ if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK)
+ {
+ if (p_FmMacsecSecY->p_TxSc)
+ XX_Free(p_FmMacsecSecY->p_TxSc);
+ if (p_FmMacsecSecY->p_RxSc)
+ XX_Free(p_FmMacsecSecY->p_RxSc);
+ return ERROR_CODE(err);
+ }
+ for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++)
+ {
+ p_FmMacsecSecY->p_RxSc[i].scId = rxScIds[i];
+ p_FmMacsecSecY->p_RxSc[i].type = e_SC_RX;
+ for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++)
+ p_FmMacsecSecY->p_RxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
+ }
+
+ /* Tx Sc Allocation */
+ p_FmMacsecSecY->p_TxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc);
+ if (!p_FmMacsecSecY->p_TxSc)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC"));
+ memset(p_FmMacsecSecY->p_TxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc);
+
+ if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK)
+ {
+ if (p_FmMacsecSecY->p_TxSc)
+ XX_Free(p_FmMacsecSecY->p_TxSc);
+ if (p_FmMacsecSecY->p_RxSc)
+ XX_Free(p_FmMacsecSecY->p_RxSc);
+ return ERROR_CODE(err);
+ }
+ for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++)
+ {
+ p_FmMacsecSecY->p_TxSc[i].scId = txScIds[i];
+ p_FmMacsecSecY->p_TxSc[i].type = e_SC_TX;
+ for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++)
+ p_FmMacsecSecY->p_TxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
+ FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec,
+ e_FM_MACSEC_MOD_SC_TX,
+ (uint8_t)txScIds[i],
+ e_FM_INTR_TYPE_ERR,
+ FmMacsecSecYExceptionsIsr,
+ p_FmMacsecSecY);
+ FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec,
+ e_FM_MACSEC_MOD_SC_TX,
+ (uint8_t)txScIds[i],
+ e_FM_INTR_TYPE_NORMAL,
+ FmMacsecSecYEventsIsr,
+ p_FmMacsecSecY);
+
+ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
+ FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], TRUE);
+ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
+ FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], TRUE);
+ }
+
+ FmMacsecSecYCreateSc(p_FmMacsecSecY,
+ p_FmMacsecSecYDriverParam->txScParams.sci,
+ p_FmMacsecSecYDriverParam->txScParams.cipherSuite,
+ e_SC_TX);
+ XX_Free(p_FmMacsecSecYDriverParam);
+ p_FmMacsecSecY->p_FmMacsecSecYDriverParam = NULL;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_Error err = E_OK;
+ uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ if (p_FmMacsecSecY->isPointToPoint)
+ FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, FALSE);
+ if (p_FmMacsecSecY->p_RxSc)
+ {
+ for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++)
+ rxScIds[i] = p_FmMacsecSecY->p_RxSc[i].scId;
+ if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK)
+ return ERROR_CODE(err);
+ XX_Free(p_FmMacsecSecY->p_RxSc);
+ }
+ if (p_FmMacsecSecY->p_TxSc)
+ {
+ FmMacsecSecYDeleteSc(p_FmMacsecSecY, &p_FmMacsecSecY->p_TxSc[0], e_SC_TX);
+
+ for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++) {
+ txScIds[i] = p_FmMacsecSecY->p_TxSc[i].scId;
+ FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec,
+ e_FM_MACSEC_MOD_SC_TX,
+ (uint8_t)txScIds[i],
+ e_FM_INTR_TYPE_ERR);
+ FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec,
+ e_FM_MACSEC_MOD_SC_TX,
+ (uint8_t)txScIds[i],
+ e_FM_INTR_TYPE_NORMAL);
+
+ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED)
+ FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], FALSE);
+ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN)
+ FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], FALSE);
+ }
+
+ if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK)
+ return ERROR_CODE(err);
+ XX_Free(p_FmMacsecSecY->p_TxSc);
+ }
+
+ XX_Free(p_FmMacsecSecY);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->sciInsertionMode = sciInsertionMode;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->protectFrames = protectFrames;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->replayProtect = replayProtect;
+ p_FmMacsecSecY->replayWindow = replayWindow;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->validateFrames = validateFrames;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->confidentialityEnable = confidentialityEnable;
+ p_FmMacsecSecY->confidentialityOffset = confidentialityOffset;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ p_FmMacsecSecY->numOfRxSc = 1;
+ p_FmMacsecSecY->isPointToPoint = TRUE;
+ p_FmMacsecSecY->sciInsertionMode = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP;
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsecSecY->exceptions |= bitMask;
+ else
+ p_FmMacsecSecY->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+
+ GET_EVENT_FLAG(bitMask, event);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmMacsecSecY->events |= bitMask;
+ else
+ p_FmMacsecSecY->events &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event"));
+
+ return E_OK;
+}
+
+t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_ScParams, E_NULL_POINTER, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE, NULL);
+
+ return FmMacsecSecYCreateSc(p_FmMacsecSecY, p_ScParams->sci, p_ScParams->cipherSuite, e_SC_RX);
+}
+
+t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+
+ return FmMacsecSecYDeleteSc(p_FmMacsecSecY, p_FmSecYSc, e_SC_RX);
+}
+
+t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already assigned",an));
+
+ if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, an, lowestPn, key)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an));
+
+ if ((err = FmMacsecDeleteRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->numOfSa--;
+ p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
+ /* TODO - check if statistics need to be read*/
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->sa[an].active = TRUE;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->sa[an].active = FALSE;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if ((err = FmMacsecRxSaUpdateNextPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtNextPN)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if ((err = FmMacsecRxSaUpdateLowestPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtLowestPN)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if (p_FmSecYSc->sa[an].active)
+ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ /* TODO - statistics should be read */
+
+ if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, an, 1, key)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ if (p_FmSecYSc->sa[an].active)
+ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return err;
+}
+
+
+t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, err, ("An %d is already assigned",an));
+
+ if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, key)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an));
+
+ if ((err = FmMacsecDeleteTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ p_FmSecYSc->numOfSa--;
+ p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE;
+ /* TODO - check if statistics need to be read*/
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ macsecAN_t currentAn;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(nextActiveAn < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec,
+ p_FmSecYSc->scId,
+ &currentAn)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec,
+ p_FmSecYSc->scId,
+ p_FmSecYSc->sa[nextActiveAn].saId,
+ nextActiveAn)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ /* TODO - statistics should be read */
+
+ if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[currentAn].saId, key)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE);
+
+ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an));
+
+ if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec,
+ p_FmSecYSc->scId,
+ p_FmSecYSc->sa[an].saId,
+ an)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE);
+
+ if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec,
+ p_FmSecYSc->scId,
+ p_An)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId)
+{
+ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((t_FmMacsecSecY *)h_FmMacsecSecY)->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!((t_FmMacsecSecY *)h_FmMacsecSecY)->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+#ifdef DISABLE_SANITY_CHECKS
+ UNUSED(h_FmMacsecSecY);
+#endif /* DISABLE_SANITY_CHECKS */
+
+ *p_ScPhysId = p_FmSecYSc->scId;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId)
+{
+ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY;
+ t_SecYSc *p_FmSecYSc;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE);
+ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0];
+ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE);
+
+ *p_ScPhysId = p_FmSecYSc->scId;
+ return err;
+}
+
+t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(exception);UNUSED(enable);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(event);UNUSED(enable);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(p_Statistics);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(an);UNUSED(p_Statistics);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
+t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics)
+{
+ UNUSED(h_FmMacsecSecY);UNUSED(an);UNUSED(p_Statistics);
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h
new file mode 100644
index 000000000000..0cf624e68e2a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fm_macsec_secy.h
+
+ @Description FM MACSEC SecY internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_MACSEC_SECY_H
+#define __FM_MACSEC_SECY_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+
+#include "fm_macsec.h"
+
+
+/**************************************************************************//**
+ @Description Exceptions
+*//***************************************************************************/
+
+#define FM_MACSEC_SECY_EX_FRAME_DISCARDED 0x80000000
+
+#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \
+ case e_FM_MACSEC_SECY_EX_FRAME_DISCARDED: \
+ bitMask = FM_MACSEC_SECY_EX_FRAME_DISCARDED; break; \
+ default: bitMask = 0;break;}
+
+/**************************************************************************//**
+ @Description Events
+*//***************************************************************************/
+
+#define FM_MACSEC_SECY_EV_NEXT_PN 0x80000000
+
+#define GET_EVENT_FLAG(bitMask, event) switch (event){ \
+ case e_FM_MACSEC_SECY_EV_NEXT_PN: \
+ bitMask = FM_MACSEC_SECY_EV_NEXT_PN; break; \
+ default: bitMask = 0;break;}
+
+/**************************************************************************//**
+ @Description Defaults
+*//***************************************************************************/
+
+#define DEFAULT_exceptions (FM_MACSEC_SECY_EX_FRAME_DISCARDED)
+#define DEFAULT_events (FM_MACSEC_SECY_EV_NEXT_PN)
+#define DEFAULT_numOfTxSc 1
+#define DEFAULT_confidentialityEnable FALSE
+#define DEFAULT_confidentialityOffset 0
+#define DEFAULT_sciInsertionMode e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG
+#define DEFAULT_validateFrames e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT
+#define DEFAULT_replayEnable FALSE
+#define DEFAULT_replayWindow 0
+#define DEFAULT_protectFrames TRUE
+#define DEFAULT_ptp FALSE
+
+/**************************************************************************//**
+ @Description General defines
+*//***************************************************************************/
+
+#define SECY_AN_FREE_VALUE MAX_NUM_OF_SA_PER_SC
+
+
+typedef struct {
+ e_ScSaId saId;
+ bool active;
+ union {
+ t_FmMacsecSecYRxSaStatistics rxSaStatistics;
+ t_FmMacsecSecYTxSaStatistics txSaStatistics;
+ };
+} t_SecYSa;
+
+typedef struct {
+ bool inUse;
+ uint32_t scId;
+ e_ScType type;
+ uint8_t numOfSa;
+ t_SecYSa sa[MAX_NUM_OF_SA_PER_SC];
+ union {
+ t_FmMacsecSecYRxScStatistics rxScStatistics;
+ t_FmMacsecSecYTxScStatistics txScStatistics;
+ };
+} t_SecYSc;
+
+typedef struct {
+ t_FmMacsecSecYSCParams txScParams; /**< Tx SC Params */
+} t_FmMacsecSecYDriverParam;
+
+typedef struct {
+ t_Handle h_FmMacsec;
+ bool confidentialityEnable; /**< TRUE - confidentiality protection and integrity protection
+ FALSE - no confidentiality protection, only integrity protection*/
+ uint16_t confidentialityOffset; /**< The number of initial octets of each MSDU without confidentiality protection
+ common values are 0, 30, and 50 */
+ bool replayProtect; /**< replay protection function mode */
+ uint32_t replayWindow; /**< the size of the replay window */
+ e_FmMacsecValidFrameBehavior validateFrames; /**< validation function mode */
+ e_FmMacsecSciInsertionMode sciInsertionMode;
+ bool protectFrames;
+ bool isPointToPoint;
+ e_FmMacsecSecYCipherSuite cipherSuite; /**< Cipher suite to be used for this SecY */
+ uint32_t numOfRxSc; /**< Number of receive channels */
+ uint32_t numOfTxSc; /**< Number of transmit channels */
+ t_SecYSc *p_RxSc;
+ t_SecYSc *p_TxSc;
+ uint32_t events;
+ uint32_t exceptions;
+ t_FmMacsecSecYExceptionsCallback *f_Exception; /**< TODO */
+ t_FmMacsecSecYEventsCallback *f_Event; /**< TODO */
+ t_Handle h_App;
+ t_FmMacsecSecYStatistics statistics;
+ t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam;
+} t_FmMacsecSecY;
+
+
+#endif /* __FM_MACSEC_SECY_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
new file mode 100644
index 000000000000..65e8344d185e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile
@@ -0,0 +1,24 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+
+obj-y += fsl-ncsw-PFM1.o
+
+fsl-ncsw-PFM1-objs := fm.o fm_muram.o fman.o
+
+obj-y += MAC/
+obj-y += Pcd/
+obj-y += SP/
+obj-y += Port/
+obj-y += HC/
+obj-y += MACSEC/
+
+obj-$(CONFIG_FSL_SDK_FMAN_RTC_API) += Rtc/
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile
new file mode 100644
index 000000000000..62fbd73c8797
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-Pcd.o
+
+fsl-ncsw-Pcd-objs := fman_kg.o fman_prs.o fm_cc.o fm_kg.o fm_pcd.o fm_plcr.o fm_prs.o fm_manip.o
+
+ifeq ($(CONFIG_FMAN_V3H),y)
+fsl-ncsw-Pcd-objs += fm_replic.o
+endif
+ifeq ($(CONFIG_FMAN_V3L),y)
+fsl-ncsw-Pcd-objs += fm_replic.o
+endif
+ifeq ($(CONFIG_FMAN_ARM),y)
+fsl-ncsw-Pcd-objs += fm_replic.o
+endif
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h
new file mode 100644
index 000000000000..335ee6819188
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+ /**************************************************************************//**
+ @File crc64.h
+
+ @Description brief This file contains the CRC64 Table, and __inline__
+ functions used for calculating crc.
+*//***************************************************************************/
+#ifndef __CRC64_H
+#define __CRC64_H
+
+#include "std_ext.h"
+
+
+#define BITS_PER_BYTE 8
+
+#define CRC64_EXPON_ECMA_182 0xC96C5795D7870F42ULL
+#define CRC64_DEFAULT_INITVAL 0xFFFFFFFFFFFFFFFFULL
+
+#define CRC64_BYTE_MASK 0xFF
+#define CRC64_TABLE_ENTRIES ( 1 << BITS_PER_BYTE )
+#define CRC64_ODD_MASK 1
+
+
+/**
+ \brief '64 bit crc' Table
+ */
+struct crc64_t {
+ uint64_t initial; /**< Initial seed */
+ uint64_t table[CRC64_TABLE_ENTRIES]; /**< CRC table entries */
+};
+
+
+static struct crc64_t CRC64_ECMA_182 = {
+ CRC64_DEFAULT_INITVAL,
+ {
+ 0x0000000000000000ULL,
+ 0xb32e4cbe03a75f6fULL,
+ 0xf4843657a840a05bULL,
+ 0x47aa7ae9abe7ff34ULL,
+ 0x7bd0c384ff8f5e33ULL,
+ 0xc8fe8f3afc28015cULL,
+ 0x8f54f5d357cffe68ULL,
+ 0x3c7ab96d5468a107ULL,
+ 0xf7a18709ff1ebc66ULL,
+ 0x448fcbb7fcb9e309ULL,
+ 0x0325b15e575e1c3dULL,
+ 0xb00bfde054f94352ULL,
+ 0x8c71448d0091e255ULL,
+ 0x3f5f08330336bd3aULL,
+ 0x78f572daa8d1420eULL,
+ 0xcbdb3e64ab761d61ULL,
+ 0x7d9ba13851336649ULL,
+ 0xceb5ed8652943926ULL,
+ 0x891f976ff973c612ULL,
+ 0x3a31dbd1fad4997dULL,
+ 0x064b62bcaebc387aULL,
+ 0xb5652e02ad1b6715ULL,
+ 0xf2cf54eb06fc9821ULL,
+ 0x41e11855055bc74eULL,
+ 0x8a3a2631ae2dda2fULL,
+ 0x39146a8fad8a8540ULL,
+ 0x7ebe1066066d7a74ULL,
+ 0xcd905cd805ca251bULL,
+ 0xf1eae5b551a2841cULL,
+ 0x42c4a90b5205db73ULL,
+ 0x056ed3e2f9e22447ULL,
+ 0xb6409f5cfa457b28ULL,
+ 0xfb374270a266cc92ULL,
+ 0x48190ecea1c193fdULL,
+ 0x0fb374270a266cc9ULL,
+ 0xbc9d3899098133a6ULL,
+ 0x80e781f45de992a1ULL,
+ 0x33c9cd4a5e4ecdceULL,
+ 0x7463b7a3f5a932faULL,
+ 0xc74dfb1df60e6d95ULL,
+ 0x0c96c5795d7870f4ULL,
+ 0xbfb889c75edf2f9bULL,
+ 0xf812f32ef538d0afULL,
+ 0x4b3cbf90f69f8fc0ULL,
+ 0x774606fda2f72ec7ULL,
+ 0xc4684a43a15071a8ULL,
+ 0x83c230aa0ab78e9cULL,
+ 0x30ec7c140910d1f3ULL,
+ 0x86ace348f355aadbULL,
+ 0x3582aff6f0f2f5b4ULL,
+ 0x7228d51f5b150a80ULL,
+ 0xc10699a158b255efULL,
+ 0xfd7c20cc0cdaf4e8ULL,
+ 0x4e526c720f7dab87ULL,
+ 0x09f8169ba49a54b3ULL,
+ 0xbad65a25a73d0bdcULL,
+ 0x710d64410c4b16bdULL,
+ 0xc22328ff0fec49d2ULL,
+ 0x85895216a40bb6e6ULL,
+ 0x36a71ea8a7ace989ULL,
+ 0x0adda7c5f3c4488eULL,
+ 0xb9f3eb7bf06317e1ULL,
+ 0xfe5991925b84e8d5ULL,
+ 0x4d77dd2c5823b7baULL,
+ 0x64b62bcaebc387a1ULL,
+ 0xd7986774e864d8ceULL,
+ 0x90321d9d438327faULL,
+ 0x231c512340247895ULL,
+ 0x1f66e84e144cd992ULL,
+ 0xac48a4f017eb86fdULL,
+ 0xebe2de19bc0c79c9ULL,
+ 0x58cc92a7bfab26a6ULL,
+ 0x9317acc314dd3bc7ULL,
+ 0x2039e07d177a64a8ULL,
+ 0x67939a94bc9d9b9cULL,
+ 0xd4bdd62abf3ac4f3ULL,
+ 0xe8c76f47eb5265f4ULL,
+ 0x5be923f9e8f53a9bULL,
+ 0x1c4359104312c5afULL,
+ 0xaf6d15ae40b59ac0ULL,
+ 0x192d8af2baf0e1e8ULL,
+ 0xaa03c64cb957be87ULL,
+ 0xeda9bca512b041b3ULL,
+ 0x5e87f01b11171edcULL,
+ 0x62fd4976457fbfdbULL,
+ 0xd1d305c846d8e0b4ULL,
+ 0x96797f21ed3f1f80ULL,
+ 0x2557339fee9840efULL,
+ 0xee8c0dfb45ee5d8eULL,
+ 0x5da24145464902e1ULL,
+ 0x1a083bacedaefdd5ULL,
+ 0xa9267712ee09a2baULL,
+ 0x955cce7fba6103bdULL,
+ 0x267282c1b9c65cd2ULL,
+ 0x61d8f8281221a3e6ULL,
+ 0xd2f6b4961186fc89ULL,
+ 0x9f8169ba49a54b33ULL,
+ 0x2caf25044a02145cULL,
+ 0x6b055fede1e5eb68ULL,
+ 0xd82b1353e242b407ULL,
+ 0xe451aa3eb62a1500ULL,
+ 0x577fe680b58d4a6fULL,
+ 0x10d59c691e6ab55bULL,
+ 0xa3fbd0d71dcdea34ULL,
+ 0x6820eeb3b6bbf755ULL,
+ 0xdb0ea20db51ca83aULL,
+ 0x9ca4d8e41efb570eULL,
+ 0x2f8a945a1d5c0861ULL,
+ 0x13f02d374934a966ULL,
+ 0xa0de61894a93f609ULL,
+ 0xe7741b60e174093dULL,
+ 0x545a57dee2d35652ULL,
+ 0xe21ac88218962d7aULL,
+ 0x5134843c1b317215ULL,
+ 0x169efed5b0d68d21ULL,
+ 0xa5b0b26bb371d24eULL,
+ 0x99ca0b06e7197349ULL,
+ 0x2ae447b8e4be2c26ULL,
+ 0x6d4e3d514f59d312ULL,
+ 0xde6071ef4cfe8c7dULL,
+ 0x15bb4f8be788911cULL,
+ 0xa6950335e42fce73ULL,
+ 0xe13f79dc4fc83147ULL,
+ 0x521135624c6f6e28ULL,
+ 0x6e6b8c0f1807cf2fULL,
+ 0xdd45c0b11ba09040ULL,
+ 0x9aefba58b0476f74ULL,
+ 0x29c1f6e6b3e0301bULL,
+ 0xc96c5795d7870f42ULL,
+ 0x7a421b2bd420502dULL,
+ 0x3de861c27fc7af19ULL,
+ 0x8ec62d7c7c60f076ULL,
+ 0xb2bc941128085171ULL,
+ 0x0192d8af2baf0e1eULL,
+ 0x4638a2468048f12aULL,
+ 0xf516eef883efae45ULL,
+ 0x3ecdd09c2899b324ULL,
+ 0x8de39c222b3eec4bULL,
+ 0xca49e6cb80d9137fULL,
+ 0x7967aa75837e4c10ULL,
+ 0x451d1318d716ed17ULL,
+ 0xf6335fa6d4b1b278ULL,
+ 0xb199254f7f564d4cULL,
+ 0x02b769f17cf11223ULL,
+ 0xb4f7f6ad86b4690bULL,
+ 0x07d9ba1385133664ULL,
+ 0x4073c0fa2ef4c950ULL,
+ 0xf35d8c442d53963fULL,
+ 0xcf273529793b3738ULL,
+ 0x7c0979977a9c6857ULL,
+ 0x3ba3037ed17b9763ULL,
+ 0x888d4fc0d2dcc80cULL,
+ 0x435671a479aad56dULL,
+ 0xf0783d1a7a0d8a02ULL,
+ 0xb7d247f3d1ea7536ULL,
+ 0x04fc0b4dd24d2a59ULL,
+ 0x3886b22086258b5eULL,
+ 0x8ba8fe9e8582d431ULL,
+ 0xcc0284772e652b05ULL,
+ 0x7f2cc8c92dc2746aULL,
+ 0x325b15e575e1c3d0ULL,
+ 0x8175595b76469cbfULL,
+ 0xc6df23b2dda1638bULL,
+ 0x75f16f0cde063ce4ULL,
+ 0x498bd6618a6e9de3ULL,
+ 0xfaa59adf89c9c28cULL,
+ 0xbd0fe036222e3db8ULL,
+ 0x0e21ac88218962d7ULL,
+ 0xc5fa92ec8aff7fb6ULL,
+ 0x76d4de52895820d9ULL,
+ 0x317ea4bb22bfdfedULL,
+ 0x8250e80521188082ULL,
+ 0xbe2a516875702185ULL,
+ 0x0d041dd676d77eeaULL,
+ 0x4aae673fdd3081deULL,
+ 0xf9802b81de97deb1ULL,
+ 0x4fc0b4dd24d2a599ULL,
+ 0xfceef8632775faf6ULL,
+ 0xbb44828a8c9205c2ULL,
+ 0x086ace348f355aadULL,
+ 0x34107759db5dfbaaULL,
+ 0x873e3be7d8faa4c5ULL,
+ 0xc094410e731d5bf1ULL,
+ 0x73ba0db070ba049eULL,
+ 0xb86133d4dbcc19ffULL,
+ 0x0b4f7f6ad86b4690ULL,
+ 0x4ce50583738cb9a4ULL,
+ 0xffcb493d702be6cbULL,
+ 0xc3b1f050244347ccULL,
+ 0x709fbcee27e418a3ULL,
+ 0x3735c6078c03e797ULL,
+ 0x841b8ab98fa4b8f8ULL,
+ 0xadda7c5f3c4488e3ULL,
+ 0x1ef430e13fe3d78cULL,
+ 0x595e4a08940428b8ULL,
+ 0xea7006b697a377d7ULL,
+ 0xd60abfdbc3cbd6d0ULL,
+ 0x6524f365c06c89bfULL,
+ 0x228e898c6b8b768bULL,
+ 0x91a0c532682c29e4ULL,
+ 0x5a7bfb56c35a3485ULL,
+ 0xe955b7e8c0fd6beaULL,
+ 0xaeffcd016b1a94deULL,
+ 0x1dd181bf68bdcbb1ULL,
+ 0x21ab38d23cd56ab6ULL,
+ 0x9285746c3f7235d9ULL,
+ 0xd52f0e859495caedULL,
+ 0x6601423b97329582ULL,
+ 0xd041dd676d77eeaaULL,
+ 0x636f91d96ed0b1c5ULL,
+ 0x24c5eb30c5374ef1ULL,
+ 0x97eba78ec690119eULL,
+ 0xab911ee392f8b099ULL,
+ 0x18bf525d915feff6ULL,
+ 0x5f1528b43ab810c2ULL,
+ 0xec3b640a391f4fadULL,
+ 0x27e05a6e926952ccULL,
+ 0x94ce16d091ce0da3ULL,
+ 0xd3646c393a29f297ULL,
+ 0x604a2087398eadf8ULL,
+ 0x5c3099ea6de60cffULL,
+ 0xef1ed5546e415390ULL,
+ 0xa8b4afbdc5a6aca4ULL,
+ 0x1b9ae303c601f3cbULL,
+ 0x56ed3e2f9e224471ULL,
+ 0xe5c372919d851b1eULL,
+ 0xa26908783662e42aULL,
+ 0x114744c635c5bb45ULL,
+ 0x2d3dfdab61ad1a42ULL,
+ 0x9e13b115620a452dULL,
+ 0xd9b9cbfcc9edba19ULL,
+ 0x6a978742ca4ae576ULL,
+ 0xa14cb926613cf817ULL,
+ 0x1262f598629ba778ULL,
+ 0x55c88f71c97c584cULL,
+ 0xe6e6c3cfcadb0723ULL,
+ 0xda9c7aa29eb3a624ULL,
+ 0x69b2361c9d14f94bULL,
+ 0x2e184cf536f3067fULL,
+ 0x9d36004b35545910ULL,
+ 0x2b769f17cf112238ULL,
+ 0x9858d3a9ccb67d57ULL,
+ 0xdff2a94067518263ULL,
+ 0x6cdce5fe64f6dd0cULL,
+ 0x50a65c93309e7c0bULL,
+ 0xe388102d33392364ULL,
+ 0xa4226ac498dedc50ULL,
+ 0x170c267a9b79833fULL,
+ 0xdcd7181e300f9e5eULL,
+ 0x6ff954a033a8c131ULL,
+ 0x28532e49984f3e05ULL,
+ 0x9b7d62f79be8616aULL,
+ 0xa707db9acf80c06dULL,
+ 0x14299724cc279f02ULL,
+ 0x5383edcd67c06036ULL,
+ 0xe0ada17364673f59ULL
+ }
+};
+
+
+/**
+ \brief Initializes the crc seed
+ */
+static __inline__ uint64_t crc64_init(void)
+{
+ return CRC64_ECMA_182.initial;
+}
+
+/**
+ \brief Computes 64 bit the crc
+ \param[in] data Pointer to the Data in the frame
+ \param[in] len Length of the Data
+ \param[in] crc seed
+ \return calculated crc
+ */
+static __inline__ uint64_t crc64_compute(void const *data,
+ uint32_t len,
+ uint64_t seed)
+{
+ uint32_t i;
+ uint64_t crc = seed;
+ uint8_t *bdata = (uint8_t *) data;
+
+ for (i = 0; i < len; i++)
+ crc =
+ CRC64_ECMA_182.
+ table[(crc ^ *bdata++) & CRC64_BYTE_MASK] ^ (crc >> 8);
+
+ return crc;
+}
+
+
+#endif /* __CRC64_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
new file mode 100644
index 000000000000..8b8221755760
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c
@@ -0,0 +1,7583 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_cc.c
+
+ @Description FM Coarse Classifier implementation
+ *//***************************************************************************/
+#include <linux/math64.h>
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_muram_ext.h"
+
+#include "fm_common.h"
+#include "fm_pcd.h"
+#include "fm_hc.h"
+#include "fm_cc.h"
+#include "crc64.h"
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+
+static t_Error CcRootTryLock(t_Handle h_FmPcdCcTree)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+
+ ASSERT_COND(h_FmPcdCcTree);
+
+ if (FmPcdLockTryLock(p_FmPcdCcTree->p_Lock))
+ return E_OK;
+
+ return ERROR_CODE(E_BUSY);
+}
+
+static void CcRootReleaseLock(t_Handle h_FmPcdCcTree)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+
+ ASSERT_COND(h_FmPcdCcTree);
+
+ FmPcdLockUnlock(p_FmPcdCcTree->p_Lock);
+}
+
+static void UpdateNodeOwner(t_FmPcdCcNode *p_CcNode, bool add)
+{
+ uint32_t intFlags;
+
+ ASSERT_COND(p_CcNode);
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ if (add)
+ p_CcNode->owners++;
+ else
+ {
+ ASSERT_COND(p_CcNode->owners);
+ p_CcNode->owners--;
+ }
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+}
+
+static __inline__ t_FmPcdStatsObj* DequeueStatsObj(t_List *p_List)
+{
+ t_FmPcdStatsObj *p_StatsObj = NULL;
+ t_List *p_Next;
+
+ if (!LIST_IsEmpty(p_List))
+ {
+ p_Next = LIST_FIRST(p_List);
+ p_StatsObj = LIST_OBJECT(p_Next, t_FmPcdStatsObj, node);
+ ASSERT_COND(p_StatsObj);
+ LIST_DelAndInit(p_Next);
+ }
+
+ return p_StatsObj;
+}
+
+static __inline__ void EnqueueStatsObj(t_List *p_List,
+ t_FmPcdStatsObj *p_StatsObj)
+{
+ LIST_AddToTail(&p_StatsObj->node, p_List);
+}
+
+static void FreeStatObjects(t_List *p_List, t_Handle h_FmMuram)
+{
+ t_FmPcdStatsObj *p_StatsObj;
+
+ while (!LIST_IsEmpty(p_List))
+ {
+ p_StatsObj = DequeueStatsObj(p_List);
+ ASSERT_COND(p_StatsObj);
+
+ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
+ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters);
+
+ XX_Free(p_StatsObj);
+ }
+}
+
+static t_FmPcdStatsObj* GetStatsObj(t_FmPcdCcNode *p_CcNode)
+{
+ t_FmPcdStatsObj* p_StatsObj;
+ t_Handle h_FmMuram;
+
+ ASSERT_COND(p_CcNode);
+
+ /* If 'maxNumOfKeys' was passed, all statistics object were preallocated
+ upon node initialization */
+ if (p_CcNode->maxNumOfKeys)
+ {
+ p_StatsObj = DequeueStatsObj(&p_CcNode->availableStatsLst);
+
+ /* Clean statistics counters & ADs */
+ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
+ }
+ else
+ {
+ h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram;
+ ASSERT_COND(h_FmMuram);
+
+ p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj));
+ if (!p_StatsObj)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("statistics object"));
+ return NULL;
+ }
+
+ p_StatsObj->h_StatsAd = (t_Handle)FM_MURAM_AllocMem(
+ h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_StatsObj->h_StatsAd)
+ {
+ XX_Free(p_StatsObj);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics ADs"));
+ return NULL;
+ }
+ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ p_StatsObj->h_StatsCounters = (t_Handle)FM_MURAM_AllocMem(
+ h_FmMuram, p_CcNode->countersArraySize,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_StatsObj->h_StatsCounters)
+ {
+ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
+ XX_Free(p_StatsObj);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics counters"));
+ return NULL;
+ }
+ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
+ }
+
+ return p_StatsObj;
+}
+
+static void PutStatsObj(t_FmPcdCcNode *p_CcNode, t_FmPcdStatsObj *p_StatsObj)
+{
+ t_Handle h_FmMuram;
+
+ ASSERT_COND(p_CcNode);
+ ASSERT_COND(p_StatsObj);
+
+ /* If 'maxNumOfKeys' was passed, all statistics object were preallocated
+ upon node initialization and now will be enqueued back to the list */
+ if (p_CcNode->maxNumOfKeys)
+ {
+ /* Clean statistics counters */
+ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize);
+
+ /* Clean statistics ADs */
+ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj);
+ }
+ else
+ {
+ h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram;
+ ASSERT_COND(h_FmMuram);
+
+ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd);
+ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters);
+
+ XX_Free(p_StatsObj);
+ }
+}
+
+static void SetStatsCounters(t_AdOfTypeStats *p_StatsAd,
+ uint32_t statsCountersAddr)
+{
+ uint32_t tmp = (statsCountersAddr & FM_PCD_AD_STATS_COUNTERS_ADDR_MASK);
+
+ WRITE_UINT32(p_StatsAd->statsTableAddr, tmp);
+}
+
+
+static void UpdateStatsAd(t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
+ t_Handle h_Ad, uint64_t physicalMuramBase)
+{
+ t_AdOfTypeStats *p_StatsAd;
+ uint32_t statsCountersAddr, nextActionAddr, tmp;
+#if (DPAA_VERSION >= 11)
+ uint32_t frameLengthRangesAddr;
+#endif /* (DPAA_VERSION >= 11) */
+
+ p_StatsAd = (t_AdOfTypeStats *)p_FmPcdCcStatsParams->h_StatsAd;
+
+ tmp = FM_PCD_AD_STATS_TYPE;
+
+#if (DPAA_VERSION >= 11)
+ if (p_FmPcdCcStatsParams->h_StatsFLRs)
+ {
+ frameLengthRangesAddr = (uint32_t)((XX_VirtToPhys(
+ p_FmPcdCcStatsParams->h_StatsFLRs) - physicalMuramBase));
+ tmp |= (frameLengthRangesAddr & FM_PCD_AD_STATS_FLR_ADDR_MASK);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ WRITE_UINT32(p_StatsAd->profileTableAddr, tmp);
+
+ nextActionAddr = (uint32_t)((XX_VirtToPhys(h_Ad) - physicalMuramBase));
+ tmp = 0;
+ tmp |= (uint32_t)((nextActionAddr << FM_PCD_AD_STATS_NEXT_ACTION_SHIFT)
+ & FM_PCD_AD_STATS_NEXT_ACTION_MASK);
+ tmp |= (FM_PCD_AD_STATS_NAD_EN | FM_PCD_AD_STATS_OP_CODE);
+
+#if (DPAA_VERSION >= 11)
+ if (p_FmPcdCcStatsParams->h_StatsFLRs)
+ tmp |= FM_PCD_AD_STATS_FLR_EN;
+#endif /* (DPAA_VERSION >= 11) */
+
+ WRITE_UINT32(p_StatsAd->nextActionIndx, tmp);
+
+ statsCountersAddr = (uint32_t)((XX_VirtToPhys(
+ p_FmPcdCcStatsParams->h_StatsCounters) - physicalMuramBase));
+ SetStatsCounters(p_StatsAd, statsCountersAddr);
+}
+
+static void FillAdOfTypeContLookup(t_Handle h_Ad,
+ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
+ t_Handle h_FmPcd, t_Handle p_CcNode,
+ t_Handle h_Manip, t_Handle h_FrmReplic)
+{
+ t_FmPcdCcNode *p_Node = (t_FmPcdCcNode *)p_CcNode;
+ t_AdOfTypeContLookup *p_AdContLookup = (t_AdOfTypeContLookup *)h_Ad;
+ t_Handle h_TmpAd;
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t tmpReg32;
+ t_Handle p_AdNewPtr = NULL;
+
+ UNUSED(h_Manip);
+ UNUSED(h_FrmReplic);
+
+ /* there are 3 cases handled in this routine of building a "Continue lookup" type AD.
+ * Case 1: No Manip. The action descriptor is built within the match table.
+ * p_AdResult = p_AdNewPtr;
+ * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized
+ * either in the FmPcdManipUpdateAdResultForCc routine or it was already
+ * initialized and returned here.
+ * p_AdResult (within the match table) will be initialized after
+ * this routine returns and point to the existing AD.
+ * Case 3: Manip exists. The action descriptor is built within the match table.
+ * FmPcdManipUpdateAdContLookupForCc returns a NULL p_AdNewPtr.
+ */
+
+ /* As default, the "new" ptr is the current one. i.e. the content of the result
+ * AD will be written into the match table itself (case (1))*/
+ p_AdNewPtr = p_AdContLookup;
+
+ /* Initialize an action descriptor, if current statistics mode requires an Ad */
+ if (p_FmPcdCcStatsParams)
+ {
+ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd);
+ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters);
+
+ /* Swapping addresses between statistics Ad and the current lookup AD */
+ h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd;
+ p_FmPcdCcStatsParams->h_StatsAd = h_Ad;
+ h_Ad = h_TmpAd;
+
+ p_AdNewPtr = h_Ad;
+ p_AdContLookup = h_Ad;
+
+ /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */
+ UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase);
+ }
+
+#if DPAA_VERSION >= 11
+ if (h_Manip && h_FrmReplic)
+ FmPcdManipUpdateAdContLookupForCc(
+ h_Manip,
+ h_Ad,
+ &p_AdNewPtr,
+ (uint32_t)((XX_VirtToPhys(
+ FrmReplicGroupGetSourceTableDescriptor(h_FrmReplic))
+ - p_FmPcd->physicalMuramBase)));
+ else
+ if (h_FrmReplic)
+ FrmReplicGroupUpdateAd(h_FrmReplic, h_Ad, &p_AdNewPtr);
+ else
+#endif /* (DPAA_VERSION >= 11) */
+ if (h_Manip)
+ FmPcdManipUpdateAdContLookupForCc(
+ h_Manip,
+ h_Ad,
+ &p_AdNewPtr,
+
+#ifdef FM_CAPWAP_SUPPORT
+ /*no check for opcode of manip - this step can be reached only with capwap_applic_specific*/
+ (uint32_t)((XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase))
+#else /* not FM_CAPWAP_SUPPORT */
+ (uint32_t)((XX_VirtToPhys(p_Node->h_Ad)
+ - p_FmPcd->physicalMuramBase))
+#endif /* not FM_CAPWAP_SUPPORT */
+ );
+
+ /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */
+ if (p_AdNewPtr)
+ {
+ /* cases (1) & (2) */
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ tmpReg32 |=
+ p_Node->sizeOfExtraction ? ((p_Node->sizeOfExtraction - 1) << 24) :
+ 0;
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Node->h_AdTable)
+ - p_FmPcd->physicalMuramBase);
+ WRITE_UINT32(p_AdContLookup->ccAdBase, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= p_Node->numOfKeys << 24;
+ tmpReg32 |= (p_Node->lclMask ? FM_PCD_AD_CONT_LOOKUP_LCL_MASK : 0);
+ tmpReg32 |=
+ p_Node->h_KeysMatchTable ? (uint32_t)(XX_VirtToPhys(
+ p_Node->h_KeysMatchTable) - p_FmPcd->physicalMuramBase) :
+ 0;
+ WRITE_UINT32(p_AdContLookup->matchTblPtr, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= p_Node->prsArrayOffset << 24;
+ tmpReg32 |= p_Node->offset << 16;
+ tmpReg32 |= p_Node->parseCode;
+ WRITE_UINT32(p_AdContLookup->pcAndOffsets, tmpReg32);
+
+ MemCpy8((void*)&p_AdContLookup->gmask, p_Node->p_GlblMask,
+ CC_GLBL_MASK_SIZE);
+ }
+}
+
+static t_Error AllocAndFillAdForContLookupManip(t_Handle h_CcNode)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_CcNode);
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ if (!p_CcNode->h_Ad)
+ {
+ if (p_CcNode->maxNumOfKeys)
+ p_CcNode->h_Ad = p_CcNode->h_TmpAd;
+ else
+ p_CcNode->h_Ad = (t_Handle)FM_MURAM_AllocMem(
+ ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram,
+ FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ if (!p_CcNode->h_Ad)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC action descriptor"));
+
+ MemSet8(p_CcNode->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ FillAdOfTypeContLookup(p_CcNode->h_Ad, NULL, p_CcNode->h_FmPcd,
+ p_CcNode, NULL, NULL);
+ }
+ else
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ return E_OK;
+}
+
+static t_Error SetRequiredAction1(
+ t_Handle h_FmPcd, uint32_t requiredAction,
+ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp,
+ t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree)
+{
+ t_AdOfTypeResult *p_AdTmp = (t_AdOfTypeResult *)h_AdTmp;
+ uint32_t tmpReg32;
+ t_Error err;
+ t_FmPcdCcNode *p_CcNode;
+ int i = 0;
+ uint16_t tmp = 0;
+ uint16_t profileId;
+ uint8_t relativeSchemeId, physicalSchemeId;
+ t_CcNodeInformation ccNodeInfo;
+
+ for (i = 0; i < numOfEntries; i++)
+ {
+ if (i == 0)
+ h_AdTmp = PTR_MOVE(h_AdTmp, i*FM_PCD_CC_AD_ENTRY_SIZE);
+ else
+ h_AdTmp = PTR_MOVE(h_AdTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ switch (p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.nextEngine)
+ {
+ case (e_FM_PCD_CC):
+ if (requiredAction)
+ {
+ p_CcNode =
+ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.ccParams.h_CcNode;
+ ASSERT_COND(p_CcNode);
+ if (p_CcNode->shadowAction == requiredAction)
+ break;
+ if ((requiredAction & UPDATE_CC_WITH_TREE)
+ && !(p_CcNode->shadowAction & UPDATE_CC_WITH_TREE))
+ {
+
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = h_Tree;
+ EnqueueNodeInfoToRelevantLst(&p_CcNode->ccTreesLst,
+ &ccNodeInfo, NULL);
+ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
+ UPDATE_CC_WITH_TREE;
+ }
+ if ((requiredAction & UPDATE_CC_SHADOW_CLEAR)
+ && !(p_CcNode->shadowAction & UPDATE_CC_SHADOW_CLEAR))
+ {
+
+ p_CcNode->shadowAction = 0;
+ }
+
+ if ((requiredAction & UPDATE_CC_WITH_DELETE_TREE)
+ && !(p_CcNode->shadowAction
+ & UPDATE_CC_WITH_DELETE_TREE))
+ {
+ DequeueNodeInfoFromRelevantLst(&p_CcNode->ccTreesLst,
+ h_Tree, NULL);
+ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
+ UPDATE_CC_WITH_DELETE_TREE;
+ }
+ if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
+ != e_FM_PCD_INVALID)
+ tmp = (uint8_t)(p_CcNode->numOfKeys + 1);
+ else
+ tmp = p_CcNode->numOfKeys;
+ err = SetRequiredAction1(h_FmPcd, requiredAction,
+ p_CcNode->keyAndNextEngineParams,
+ p_CcNode->h_AdTable, tmp, h_Tree);
+ if (err != E_OK)
+ return err;
+ if (requiredAction != UPDATE_CC_SHADOW_CLEAR)
+ p_CcNode->shadowAction |= requiredAction;
+ }
+ break;
+
+ case (e_FM_PCD_KG):
+ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
+ & UPDATE_NIA_ENQ_WITHOUT_DMA))
+ {
+ physicalSchemeId =
+ FmPcdKgGetSchemeId(
+ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme);
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(
+ h_FmPcd, physicalSchemeId);
+ if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+ if (!FmPcdKgIsSchemeValidSw(
+ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Invalid direct scheme."));
+ if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("For this action scheme has to be direct."));
+ err =
+ FmPcdKgCcGetSetParams(
+ h_FmPcd,
+ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme,
+ requiredAction, 0);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
+ requiredAction;
+ }
+ break;
+
+ case (e_FM_PCD_PLCR):
+ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
+ & UPDATE_NIA_ENQ_WITHOUT_DMA))
+ {
+ if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.overrideParams)
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("In this initialization only overrideFqid can be initialized"));
+ if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.sharedProfile)
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("In this initialization only overrideFqid can be initialized"));
+ err =
+ FmPcdPlcrGetAbsoluteIdByProfileParams(
+ h_FmPcd,
+ e_FM_PCD_PLCR_SHARED,
+ NULL,
+ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.newRelativeProfileId,
+ &profileId);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ err = FmPcdPlcrCcGetSetParams(h_FmPcd, profileId,
+ requiredAction);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
+ requiredAction;
+ }
+ break;
+
+ case (e_FM_PCD_DONE):
+ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction
+ & UPDATE_NIA_ENQ_WITHOUT_DMA))
+ {
+ tmpReg32 = GET_UINT32(p_AdTmp->nia);
+ if ((tmpReg32 & GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd))
+ != GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("Next engine was previously assigned not as PCD_DONE"));
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+ WRITE_UINT32(p_AdTmp->nia, tmpReg32);
+ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |=
+ requiredAction;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return E_OK;
+}
+
+static t_Error SetRequiredAction(
+ t_Handle h_FmPcd, uint32_t requiredAction,
+ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp,
+ t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree)
+{
+ t_Error err = SetRequiredAction1(h_FmPcd, requiredAction,
+ p_CcKeyAndNextEngineParamsTmp, h_AdTmp,
+ numOfEntries, h_Tree);
+ if (err != E_OK)
+ return err;
+ return SetRequiredAction1(h_FmPcd, UPDATE_CC_SHADOW_CLEAR,
+ p_CcKeyAndNextEngineParamsTmp, h_AdTmp,
+ numOfEntries, h_Tree);
+}
+
+static t_Error ReleaseModifiedDataStructure(
+ t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst,
+ t_List *h_FmPcdNewPointersLst,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
+ bool useShadowStructs)
+{
+ t_List *p_Pos;
+ t_Error err = E_OK;
+ t_CcNodeInformation ccNodeInfo, *p_CcNodeInformation;
+ t_Handle h_Muram;
+ t_FmPcdCcNode *p_FmPcdCcNextNode, *p_FmPcdCcWorkingOnNode;
+ t_List *p_UpdateLst;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_AdditionalParams->h_CurrentNode,
+ E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdOldPointersLst, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdNewPointersLst, E_INVALID_HANDLE);
+
+ /* We don't update subtree of the new node with new tree because it was done in the previous stage */
+ if (p_AdditionalParams->h_NodeForAdd)
+ {
+ p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForAdd;
+
+ if (!p_AdditionalParams->tree)
+ p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst;
+ else
+ p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst;
+
+ p_CcNodeInformation = FindNodeInfoInReleventLst(
+ p_UpdateLst, p_AdditionalParams->h_CurrentNode,
+ p_FmPcdCcNextNode->h_Spinlock);
+
+ if (p_CcNodeInformation)
+ p_CcNodeInformation->index++;
+ else
+ {
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = (t_Handle)p_AdditionalParams->h_CurrentNode;
+ ccNodeInfo.index = 1;
+ EnqueueNodeInfoToRelevantLst(p_UpdateLst, &ccNodeInfo,
+ p_FmPcdCcNextNode->h_Spinlock);
+ }
+ if (p_AdditionalParams->h_ManipForAdd)
+ {
+ p_CcNodeInformation = FindNodeInfoInReleventLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(
+ p_AdditionalParams->h_ManipForAdd),
+ p_AdditionalParams->h_CurrentNode,
+ FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForAdd));
+
+ if (p_CcNodeInformation)
+ p_CcNodeInformation->index++;
+ else
+ {
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode =
+ (t_Handle)p_AdditionalParams->h_CurrentNode;
+ ccNodeInfo.index = 1;
+ EnqueueNodeInfoToRelevantLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(
+ p_AdditionalParams->h_ManipForAdd),
+ &ccNodeInfo,
+ FmPcdManipGetSpinlock(
+ p_AdditionalParams->h_ManipForAdd));
+ }
+ }
+ }
+
+ if (p_AdditionalParams->h_NodeForRmv)
+ {
+ p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForRmv;
+
+ if (!p_AdditionalParams->tree)
+ {
+ p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst;
+ p_FmPcdCcWorkingOnNode =
+ (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode);
+
+ for (p_Pos = LIST_FIRST(&p_FmPcdCcWorkingOnNode->ccTreesLst);
+ p_Pos != (&p_FmPcdCcWorkingOnNode->ccTreesLst); p_Pos =
+ LIST_NEXT(p_Pos))
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+
+ ASSERT_COND(p_CcNodeInformation->h_CcNode);
+
+ err =
+ SetRequiredAction(
+ h_FmPcd,
+ UPDATE_CC_WITH_DELETE_TREE,
+ &((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex],
+ PTR_MOVE(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable, p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
+ 1, p_CcNodeInformation->h_CcNode);
+ }
+ }
+ else
+ {
+ p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst;
+
+ err =
+ SetRequiredAction(
+ h_FmPcd,
+ UPDATE_CC_WITH_DELETE_TREE,
+ &((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex],
+ UINT_TO_PTR(((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->ccTreeBaseAddr + p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
+ 1, p_AdditionalParams->h_CurrentNode);
+ }
+ if (err)
+ return err;
+
+ /* We remove from the subtree of the removed node tree because it wasn't done in the previous stage
+ Update ccPrevNodesLst or ccTreeIdLst of the removed node
+ Update of the node owner */
+ p_CcNodeInformation = FindNodeInfoInReleventLst(
+ p_UpdateLst, p_AdditionalParams->h_CurrentNode,
+ p_FmPcdCcNextNode->h_Spinlock);
+
+ ASSERT_COND(p_CcNodeInformation);
+ ASSERT_COND(p_CcNodeInformation->index);
+
+ p_CcNodeInformation->index--;
+
+ if (p_CcNodeInformation->index == 0)
+ DequeueNodeInfoFromRelevantLst(p_UpdateLst,
+ p_AdditionalParams->h_CurrentNode,
+ p_FmPcdCcNextNode->h_Spinlock);
+
+ UpdateNodeOwner(p_FmPcdCcNextNode, FALSE);
+
+ if (p_AdditionalParams->h_ManipForRmv)
+ {
+ p_CcNodeInformation = FindNodeInfoInReleventLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(
+ p_AdditionalParams->h_ManipForRmv),
+ p_AdditionalParams->h_CurrentNode,
+ FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForRmv));
+
+ ASSERT_COND(p_CcNodeInformation);
+ ASSERT_COND(p_CcNodeInformation->index);
+
+ p_CcNodeInformation->index--;
+
+ if (p_CcNodeInformation->index == 0)
+ DequeueNodeInfoFromRelevantLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(
+ p_AdditionalParams->h_ManipForRmv),
+ p_AdditionalParams->h_CurrentNode,
+ FmPcdManipGetSpinlock(
+ p_AdditionalParams->h_ManipForRmv));
+ }
+ }
+
+ if (p_AdditionalParams->h_ManipForRmv)
+ FmPcdManipUpdateOwner(p_AdditionalParams->h_ManipForRmv, FALSE);
+
+ if (p_AdditionalParams->p_StatsObjForRmv)
+ PutStatsObj((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode),
+ p_AdditionalParams->p_StatsObjForRmv);
+
+#if (DPAA_VERSION >= 11)
+ if (p_AdditionalParams->h_FrmReplicForRmv)
+ FrmReplicGroupUpdateOwner(p_AdditionalParams->h_FrmReplicForRmv,
+ FALSE/* remove */);
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (!useShadowStructs)
+ {
+ h_Muram = FmPcdGetMuramHandle(h_FmPcd);
+ ASSERT_COND(h_Muram);
+
+ if ((p_AdditionalParams->tree && !((t_FmPcd *)h_FmPcd)->p_CcShadow)
+ || (!p_AdditionalParams->tree
+ && !((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->maxNumOfKeys))
+ {
+ /* We release new AD which was allocated and updated for copy from to actual AD */
+ for (p_Pos = LIST_FIRST(h_FmPcdNewPointersLst);
+ p_Pos != (h_FmPcdNewPointersLst); p_Pos = LIST_NEXT(p_Pos))
+ {
+
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+ ASSERT_COND(p_CcNodeInformation->h_CcNode);
+ FM_MURAM_FreeMem(h_Muram, p_CcNodeInformation->h_CcNode);
+ }
+ }
+
+ /* Free Old data structure if it has to be freed - new data structure was allocated*/
+ if (p_AdditionalParams->p_AdTableOld)
+ FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_AdTableOld);
+
+ if (p_AdditionalParams->p_KeysMatchTableOld)
+ FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_KeysMatchTableOld);
+ }
+
+ /* Update current modified node with changed fields if it's required*/
+ if (!p_AdditionalParams->tree)
+ {
+ if (p_AdditionalParams->p_AdTableNew)
+ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable =
+ p_AdditionalParams->p_AdTableNew;
+
+ if (p_AdditionalParams->p_KeysMatchTableNew)
+ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_KeysMatchTable =
+ p_AdditionalParams->p_KeysMatchTableNew;
+
+ /* Locking node's spinlock before updating 'keys and next engine' structure,
+ as it maybe used to retrieve keys statistics */
+ intFlags =
+ XX_LockIntrSpinlock(
+ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock);
+
+ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->numOfKeys =
+ p_AdditionalParams->numOfKeys;
+
+ memcpy(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams,
+ &p_AdditionalParams->keyAndNextEngineParams,
+ sizeof(t_FmPcdCcKeyAndNextEngineParams) * (CC_MAX_NUM_OF_KEYS));
+
+ XX_UnlockIntrSpinlock(
+ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock,
+ intFlags);
+ }
+ else
+ {
+ uint8_t numEntries =
+ ((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->numOfEntries;
+ ASSERT_COND(numEntries < FM_PCD_MAX_NUM_OF_CC_GROUPS);
+ memcpy(&((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams,
+ &p_AdditionalParams->keyAndNextEngineParams,
+ sizeof(t_FmPcdCcKeyAndNextEngineParams) * numEntries);
+ }
+
+ ReleaseLst(h_FmPcdOldPointersLst);
+ ReleaseLst(h_FmPcdNewPointersLst);
+
+ XX_Free(p_AdditionalParams);
+
+ return E_OK;
+}
+
+static t_Handle BuildNewAd(
+ t_Handle h_Ad,
+ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams,
+ t_FmPcdCcNode *p_CcNode,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_FmPcdCcNodeTmp;
+ t_Handle h_OrigAd = NULL;
+
+ p_FmPcdCcNodeTmp = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode));
+ if (!p_FmPcdCcNodeTmp)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcNodeTmp"));
+ return NULL;
+ }
+ memset(p_FmPcdCcNodeTmp, 0, sizeof(t_FmPcdCcNode));
+
+ p_FmPcdCcNodeTmp->numOfKeys = p_FmPcdModifyCcKeyAdditionalParams->numOfKeys;
+ p_FmPcdCcNodeTmp->h_KeysMatchTable =
+ p_FmPcdModifyCcKeyAdditionalParams->p_KeysMatchTableNew;
+ p_FmPcdCcNodeTmp->h_AdTable =
+ p_FmPcdModifyCcKeyAdditionalParams->p_AdTableNew;
+
+ p_FmPcdCcNodeTmp->lclMask = p_CcNode->lclMask;
+ p_FmPcdCcNodeTmp->parseCode = p_CcNode->parseCode;
+ p_FmPcdCcNodeTmp->offset = p_CcNode->offset;
+ p_FmPcdCcNodeTmp->prsArrayOffset = p_CcNode->prsArrayOffset;
+ p_FmPcdCcNodeTmp->ctrlFlow = p_CcNode->ctrlFlow;
+ p_FmPcdCcNodeTmp->ccKeySizeAccExtraction = p_CcNode->ccKeySizeAccExtraction;
+ p_FmPcdCcNodeTmp->sizeOfExtraction = p_CcNode->sizeOfExtraction;
+ p_FmPcdCcNodeTmp->glblMaskSize = p_CcNode->glblMaskSize;
+ p_FmPcdCcNodeTmp->p_GlblMask = p_CcNode->p_GlblMask;
+
+ if (p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC)
+ {
+ if (p_FmPcdCcNextEngineParams->h_Manip)
+ {
+ h_OrigAd = p_CcNode->h_Ad;
+ if (AllocAndFillAdForContLookupManip(
+ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
+ != E_OK)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ XX_Free(p_FmPcdCcNodeTmp);
+ return NULL;
+ }
+ }
+ FillAdOfTypeContLookup(h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp,
+ h_OrigAd ? NULL : p_FmPcdCcNextEngineParams->h_Manip, NULL);
+ }
+
+#if (DPAA_VERSION >= 11)
+ if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_FR)
+ && (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic))
+ {
+ FillAdOfTypeContLookup(
+ h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp,
+ p_FmPcdCcNextEngineParams->h_Manip,
+ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ XX_Free(p_FmPcdCcNodeTmp);
+
+ return E_OK;
+}
+
+static t_Error DynamicChangeHc(
+ t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
+ bool useShadowStructs)
+{
+ t_List *p_PosOld, *p_PosNew;
+ uint32_t oldAdAddrOffset, newAdAddrOffset;
+ uint16_t i = 0;
+ t_Error err = E_OK;
+ uint8_t numOfModifiedPtr;
+
+ ASSERT_COND(h_FmPcd);
+ ASSERT_COND(h_OldPointersLst);
+ ASSERT_COND(h_NewPointersLst);
+
+ numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst);
+
+ if (numOfModifiedPtr)
+ {
+ p_PosNew = LIST_FIRST(h_NewPointersLst);
+ p_PosOld = LIST_FIRST(h_OldPointersLst);
+
+ /* Retrieve address of new AD */
+ newAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd,
+ p_PosNew);
+ if (newAdAddrOffset == (uint32_t)ILLEGAL_BASE)
+ {
+ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
+ h_NewPointersLst,
+ p_AdditionalParams, useShadowStructs);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("New AD address"));
+ }
+
+ for (i = 0; i < numOfModifiedPtr; i++)
+ {
+ /* Retrieve address of current AD */
+ oldAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd,
+ p_PosOld);
+ if (oldAdAddrOffset == (uint32_t)ILLEGAL_BASE)
+ {
+ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
+ h_NewPointersLst,
+ p_AdditionalParams,
+ useShadowStructs);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old AD address"));
+ }
+
+ /* Invoke host command to copy from new AD to old AD */
+ err = FmHcPcdCcDoDynamicChange(((t_FmPcd *)h_FmPcd)->h_Hc,
+ oldAdAddrOffset, newAdAddrOffset);
+ if (err)
+ {
+ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
+ h_NewPointersLst,
+ p_AdditionalParams,
+ useShadowStructs);
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("For part of nodes changes are done - situation is danger"));
+ }
+
+ p_PosOld = LIST_NEXT(p_PosOld);
+ }
+ }
+ return E_OK;
+}
+
+static t_Error DoDynamicChange(
+ t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams,
+ bool useShadowStructs)
+{
+ t_FmPcdCcNode *p_CcNode =
+ (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode);
+ t_List *p_PosNew;
+ t_CcNodeInformation *p_CcNodeInfo;
+ t_FmPcdCcNextEngineParams nextEngineParams;
+ t_Handle h_Ad;
+ uint32_t keySize;
+ t_Error err = E_OK;
+ uint8_t numOfModifiedPtr;
+
+ ASSERT_COND(h_FmPcd);
+
+ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
+
+ numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst);
+
+ if (numOfModifiedPtr)
+ {
+
+ p_PosNew = LIST_FIRST(h_NewPointersLst);
+
+ /* Invoke host-command to copy from the new Ad to existing Ads */
+ err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst,
+ p_AdditionalParams, useShadowStructs);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (useShadowStructs)
+ {
+ /* When the host-command above has ended, the old structures are 'free'and we can update
+ them by copying from the new shadow structures. */
+ if (p_CcNode->lclMask)
+ keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction);
+ else
+ keySize = p_CcNode->ccKeySizeAccExtraction;
+
+ MemCpy8(p_AdditionalParams->p_KeysMatchTableOld,
+ p_AdditionalParams->p_KeysMatchTableNew,
+ p_CcNode->maxNumOfKeys * keySize * sizeof(uint8_t));
+
+ MemCpy8(
+ p_AdditionalParams->p_AdTableOld,
+ p_AdditionalParams->p_AdTableNew,
+ (uint32_t)((p_CcNode->maxNumOfKeys + 1)
+ * FM_PCD_CC_AD_ENTRY_SIZE));
+
+ /* Retrieve the address of the allocated Ad */
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_PosNew);
+ h_Ad = p_CcNodeInfo->h_CcNode;
+
+ /* Build a new Ad that holds the old (now updated) structures */
+ p_AdditionalParams->p_KeysMatchTableNew =
+ p_AdditionalParams->p_KeysMatchTableOld;
+ p_AdditionalParams->p_AdTableNew = p_AdditionalParams->p_AdTableOld;
+
+ nextEngineParams.nextEngine = e_FM_PCD_CC;
+ nextEngineParams.params.ccParams.h_CcNode = (t_Handle)p_CcNode;
+
+ BuildNewAd(h_Ad, p_AdditionalParams, p_CcNode, &nextEngineParams);
+
+ /* HC to copy from the new Ad (old updated structures) to current Ad (uses shadow structures) */
+ err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst,
+ p_AdditionalParams, useShadowStructs);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ err = ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst,
+ h_NewPointersLst,
+ p_AdditionalParams, useShadowStructs);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+#ifdef FM_CAPWAP_SUPPORT
+static bool IsCapwapApplSpecific(t_Handle h_Node)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_Node;
+ bool isManipForCapwapApplSpecificBuild = FALSE;
+ int i = 0;
+
+ ASSERT_COND(h_Node);
+ /* assumption that this function called only for INDEXED_FLOW_ID - so no miss*/
+ for (i = 0; i < p_CcNode->numOfKeys; i++)
+ {
+ if ( p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip &&
+ FmPcdManipIsCapwapApplSpecific(p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip))
+ {
+ isManipForCapwapApplSpecificBuild = TRUE;
+ break;
+ }
+ }
+ return isManipForCapwapApplSpecificBuild;
+
+}
+#endif /* FM_CAPWAP_SUPPORT */
+
+static t_Error CcUpdateParam(
+ t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort,
+ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParams,
+ uint16_t numOfEntries, t_Handle h_Ad, bool validate, uint16_t level,
+ t_Handle h_FmTree, bool modify)
+{
+ t_FmPcdCcNode *p_CcNode;
+ t_Error err;
+ uint16_t tmp = 0;
+ int i = 0;
+ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree;
+
+ level++;
+
+ if (p_CcTree->h_IpReassemblyManip)
+ {
+ err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort,
+ p_CcTree->h_IpReassemblyManip, NULL, validate,
+ level, h_FmTree, modify);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_CcTree->h_CapwapReassemblyManip)
+ {
+ err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort,
+ p_CcTree->h_CapwapReassemblyManip, NULL, validate,
+ level, h_FmTree, modify);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (numOfEntries)
+ {
+ for (i = 0; i < numOfEntries; i++)
+ {
+ if (i == 0)
+ h_Ad = PTR_MOVE(h_Ad, i*FM_PCD_CC_AD_ENTRY_SIZE);
+ else
+ h_Ad = PTR_MOVE(h_Ad, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ p_CcNode =
+ p_CcKeyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
+ ASSERT_COND(p_CcNode);
+
+ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ {
+ err =
+ FmPcdManipUpdate(
+ h_FmPcd,
+ NULL,
+ h_FmPort,
+ p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip,
+ h_Ad, validate, level, h_FmTree, modify);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
+ != e_FM_PCD_INVALID)
+ tmp = (uint8_t)(p_CcNode->numOfKeys + 1);
+ else
+ tmp = p_CcNode->numOfKeys;
+
+ err = CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort,
+ p_CcNode->keyAndNextEngineParams, tmp,
+ p_CcNode->h_AdTable, validate, level,
+ h_FmTree, modify);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ else
+ {
+ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ {
+ err =
+ FmPcdManipUpdate(
+ h_FmPcd,
+ NULL,
+ h_FmPort,
+ p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip,
+ h_Ad, validate, level, h_FmTree, modify);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+ }
+ }
+
+ return E_OK;
+}
+
+static ccPrivateInfo_t IcDefineCode(t_FmPcdCcNodeParams *p_CcNodeParam)
+{
+ switch (p_CcNodeParam->extractCcParams.extractNonHdr.action)
+ {
+ case (e_FM_PCD_ACTION_EXACT_MATCH):
+ switch (p_CcNodeParam->extractCcParams.extractNonHdr.src)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_KEY):
+ return CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH;
+ case (e_FM_PCD_EXTRACT_FROM_HASH):
+ return CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH;
+ default:
+ return CC_PRIVATE_INFO_NONE;
+ }
+
+ case (e_FM_PCD_ACTION_INDEXED_LOOKUP):
+ switch (p_CcNodeParam->extractCcParams.extractNonHdr.src)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_HASH):
+ return CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP;
+ case (e_FM_PCD_EXTRACT_FROM_FLOW_ID):
+ return CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP;
+ default:
+ return CC_PRIVATE_INFO_NONE;
+ }
+
+ default:
+ break;
+ }
+
+ return CC_PRIVATE_INFO_NONE;
+}
+
+static t_CcNodeInformation * DequeueAdditionalInfoFromRelevantLst(
+ t_List *p_List)
+{
+ t_CcNodeInformation *p_CcNodeInfo = NULL;
+
+ if (!LIST_IsEmpty(p_List))
+ {
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_List->p_Next);
+ LIST_DelAndInit(&p_CcNodeInfo->node);
+ }
+
+ return p_CcNodeInfo;
+}
+
+void ReleaseLst(t_List *p_List)
+{
+ t_CcNodeInformation *p_CcNodeInfo = NULL;
+
+ if (!LIST_IsEmpty(p_List))
+ {
+ p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List);
+ while (p_CcNodeInfo)
+ {
+ XX_Free(p_CcNodeInfo);
+ p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List);
+ }
+ }
+
+ LIST_Del(p_List);
+}
+
+static void DeleteNode(t_FmPcdCcNode *p_CcNode)
+{
+ uint32_t i;
+
+ if (!p_CcNode)
+ return;
+
+ if (p_CcNode->p_GlblMask)
+ {
+ XX_Free(p_CcNode->p_GlblMask);
+ p_CcNode->p_GlblMask = NULL;
+ }
+
+ if (p_CcNode->h_KeysMatchTable)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
+ p_CcNode->h_KeysMatchTable);
+ p_CcNode->h_KeysMatchTable = NULL;
+ }
+
+ if (p_CcNode->h_AdTable)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
+ p_CcNode->h_AdTable);
+ p_CcNode->h_AdTable = NULL;
+ }
+
+ if (p_CcNode->h_Ad)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
+ p_CcNode->h_Ad);
+ p_CcNode->h_Ad = NULL;
+ p_CcNode->h_TmpAd = NULL;
+ }
+
+ if (p_CcNode->h_StatsFLRs)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
+ p_CcNode->h_StatsFLRs);
+ p_CcNode->h_StatsFLRs = NULL;
+ }
+
+ if (p_CcNode->h_Spinlock)
+ {
+ XX_FreeSpinlock(p_CcNode->h_Spinlock);
+ p_CcNode->h_Spinlock = NULL;
+ }
+
+ /* Restore the original counters pointer instead of the mutual pointer (mutual to all hash buckets) */
+ if (p_CcNode->isHashBucket
+ && (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE))
+ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].p_StatsObj->h_StatsCounters =
+ p_CcNode->h_PrivMissStatsCounters;
+
+ /* Releasing all currently used statistics objects, including 'miss' entry */
+ for (i = 0; i < p_CcNode->numOfKeys + 1; i++)
+ if (p_CcNode->keyAndNextEngineParams[i].p_StatsObj)
+ PutStatsObj(p_CcNode,
+ p_CcNode->keyAndNextEngineParams[i].p_StatsObj);
+
+ if (!LIST_IsEmpty(&p_CcNode->availableStatsLst))
+ {
+ t_Handle h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd);
+ ASSERT_COND(h_FmMuram);
+
+ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
+ }
+
+ LIST_Del(&p_CcNode->availableStatsLst);
+
+ ReleaseLst(&p_CcNode->availableStatsLst);
+ ReleaseLst(&p_CcNode->ccPrevNodesLst);
+ ReleaseLst(&p_CcNode->ccTreeIdLst);
+ ReleaseLst(&p_CcNode->ccTreesLst);
+
+ XX_Free(p_CcNode);
+}
+
+static void DeleteTree(t_FmPcdCcTree *p_FmPcdTree, t_FmPcd *p_FmPcd)
+{
+ if (p_FmPcdTree)
+ {
+ if (p_FmPcdTree->ccTreeBaseAddr)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd),
+ UINT_TO_PTR(p_FmPcdTree->ccTreeBaseAddr));
+ p_FmPcdTree->ccTreeBaseAddr = 0;
+ }
+
+ ReleaseLst(&p_FmPcdTree->fmPortsLst);
+
+ XX_Free(p_FmPcdTree);
+ }
+}
+
+static void GetCcExtractKeySize(uint8_t parseCodeRealSize,
+ uint8_t *parseCodeCcSize)
+{
+ if ((parseCodeRealSize > 0) && (parseCodeRealSize < 2))
+ *parseCodeCcSize = 1;
+ else
+ if (parseCodeRealSize == 2)
+ *parseCodeCcSize = 2;
+ else
+ if ((parseCodeRealSize > 2) && (parseCodeRealSize <= 4))
+ *parseCodeCcSize = 4;
+ else
+ if ((parseCodeRealSize > 4) && (parseCodeRealSize <= 8))
+ *parseCodeCcSize = 8;
+ else
+ if ((parseCodeRealSize > 8) && (parseCodeRealSize <= 16))
+ *parseCodeCcSize = 16;
+ else
+ if ((parseCodeRealSize > 16)
+ && (parseCodeRealSize <= 24))
+ *parseCodeCcSize = 24;
+ else
+ if ((parseCodeRealSize > 24)
+ && (parseCodeRealSize <= 32))
+ *parseCodeCcSize = 32;
+ else
+ if ((parseCodeRealSize > 32)
+ && (parseCodeRealSize <= 40))
+ *parseCodeCcSize = 40;
+ else
+ if ((parseCodeRealSize > 40)
+ && (parseCodeRealSize <= 48))
+ *parseCodeCcSize = 48;
+ else
+ if ((parseCodeRealSize > 48)
+ && (parseCodeRealSize <= 56))
+ *parseCodeCcSize = 56;
+ else
+ *parseCodeCcSize = 0;
+}
+
+static void GetSizeHeaderField(e_NetHeaderType hdr, t_FmPcdFields field,
+ uint8_t *parseCodeRealSize)
+{
+ switch (hdr)
+ {
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_DA):
+ *parseCodeRealSize = 6;
+ break;
+
+ case (NET_HEADER_FIELD_ETH_SA):
+ *parseCodeRealSize = 6;
+ break;
+
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ *parseCodeRealSize = 2;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_PPPoE):
+ switch (field.pppoe)
+ {
+ case (NET_HEADER_FIELD_PPPoE_PID):
+ *parseCodeRealSize = 2;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ *parseCodeRealSize = 2;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported2"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_MPLS):
+ switch (field.mpls)
+ {
+ case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
+ *parseCodeRealSize = 4;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported3"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_IPv4):
+ switch (field.ipv4)
+ {
+ case (NET_HEADER_FIELD_IPv4_DST_IP):
+ case (NET_HEADER_FIELD_IPv4_SRC_IP):
+ *parseCodeRealSize = 4;
+ break;
+
+ case (NET_HEADER_FIELD_IPv4_TOS):
+ case (NET_HEADER_FIELD_IPv4_PROTO):
+ *parseCodeRealSize = 1;
+ break;
+
+ case (NET_HEADER_FIELD_IPv4_DST_IP
+ | NET_HEADER_FIELD_IPv4_SRC_IP):
+ *parseCodeRealSize = 8;
+ break;
+
+ case (NET_HEADER_FIELD_IPv4_TTL):
+ *parseCodeRealSize = 1;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported4"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_IPv6):
+ switch (field.ipv6)
+ {
+ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL
+ | NET_HEADER_FIELD_IPv6_TC):
+ *parseCodeRealSize = 4;
+ break;
+
+ case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
+ case (NET_HEADER_FIELD_IPv6_HOP_LIMIT):
+ *parseCodeRealSize = 1;
+ break;
+
+ case (NET_HEADER_FIELD_IPv6_DST_IP):
+ case (NET_HEADER_FIELD_IPv6_SRC_IP):
+ *parseCodeRealSize = 16;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_IP):
+ switch (field.ip)
+ {
+ case (NET_HEADER_FIELD_IP_DSCP):
+ case (NET_HEADER_FIELD_IP_PROTO):
+ *parseCodeRealSize = 1;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_GRE):
+ switch (field.gre)
+ {
+ case (NET_HEADER_FIELD_GRE_TYPE):
+ *parseCodeRealSize = 2;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported6"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_MINENCAP):
+ switch (field.minencap)
+ {
+ case (NET_HEADER_FIELD_MINENCAP_TYPE):
+ *parseCodeRealSize = 1;
+ break;
+
+ case (NET_HEADER_FIELD_MINENCAP_DST_IP):
+ case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
+ *parseCodeRealSize = 4;
+ break;
+
+ case (NET_HEADER_FIELD_MINENCAP_SRC_IP
+ | NET_HEADER_FIELD_MINENCAP_DST_IP):
+ *parseCodeRealSize = 8;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported7"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_TCP):
+ switch (field.tcp)
+ {
+ case (NET_HEADER_FIELD_TCP_PORT_SRC):
+ case (NET_HEADER_FIELD_TCP_PORT_DST):
+ *parseCodeRealSize = 2;
+ break;
+
+ case (NET_HEADER_FIELD_TCP_PORT_SRC
+ | NET_HEADER_FIELD_TCP_PORT_DST):
+ *parseCodeRealSize = 4;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported8"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ case (HEADER_TYPE_UDP):
+ switch (field.udp)
+ {
+ case (NET_HEADER_FIELD_UDP_PORT_SRC):
+ case (NET_HEADER_FIELD_UDP_PORT_DST):
+ *parseCodeRealSize = 2;
+ break;
+
+ case (NET_HEADER_FIELD_UDP_PORT_SRC
+ | NET_HEADER_FIELD_UDP_PORT_DST):
+ *parseCodeRealSize = 4;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported9"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported10"));
+ *parseCodeRealSize = CC_SIZE_ILLEGAL;
+ break;
+ }
+}
+
+t_Error ValidateNextEngineParams(
+ t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
+ e_FmPcdCcStatsMode statsMode)
+{
+ uint16_t absoluteProfileId;
+ t_Error err = E_OK;
+ uint8_t relativeSchemeId;
+
+ if ((statsMode == e_FM_PCD_CC_STATS_MODE_NONE)
+ && (p_FmPcdCcNextEngineParams->statisticsEn))
+ RETURN_ERROR(
+ MAJOR,
+ E_CONFLICT,
+ ("Statistics are requested for a key, but statistics mode was set"
+ "to 'NONE' upon initialization"));
+
+ switch (p_FmPcdCcNextEngineParams->nextEngine)
+ {
+ case (e_FM_PCD_INVALID):
+ err = E_NOT_SUPPORTED;
+ break;
+
+ case (e_FM_PCD_DONE):
+ if ((p_FmPcdCcNextEngineParams->params.enqueueParams.action
+ == e_FM_PCD_ENQ_FRAME)
+ && p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
+ {
+ if (!p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid)
+ RETURN_ERROR(
+ MAJOR,
+ E_CONFLICT,
+ ("When overrideFqid is set, newFqid must not be zero"));
+ if (p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid
+ & ~0x00FFFFFF)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("fqidForCtrlFlow must be between 1 and 2^24-1"));
+ }
+ break;
+
+ case (e_FM_PCD_KG):
+ relativeSchemeId =
+ FmPcdKgGetRelativeSchemeId(
+ h_FmPcd,
+ FmPcdKgGetSchemeId(
+ p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme));
+ if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+ if (!FmPcdKgIsSchemeValidSw(
+ p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("not valid schemeIndex in KG next engine param"));
+ if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("CC Node may point only to a scheme that is always direct."));
+ break;
+
+ case (e_FM_PCD_PLCR):
+ if (p_FmPcdCcNextEngineParams->params.plcrParams.overrideParams)
+ {
+ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
+ if (p_FmPcdCcNextEngineParams->params.plcrParams.sharedProfile)
+ {
+ err =
+ FmPcdPlcrGetAbsoluteIdByProfileParams(
+ h_FmPcd,
+ e_FM_PCD_PLCR_SHARED,
+ NULL,
+ p_FmPcdCcNextEngineParams->params.plcrParams.newRelativeProfileId,
+ &absoluteProfileId);
+ if (err)
+ RETURN_ERROR(MAJOR, err,
+ ("Shared profile offset is out of range"));
+ if (!FmPcdPlcrIsProfileValid(h_FmPcd, absoluteProfileId))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Invalid profile"));
+ }
+ }
+ break;
+
+ case (e_FM_PCD_HASH):
+ p_FmPcdCcNextEngineParams->nextEngine = e_FM_PCD_CC;
+ /* fall through */
+ case (e_FM_PCD_CC):
+ if (!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
+ RETURN_ERROR(MAJOR, E_NULL_POINTER,
+ ("handler to next Node is NULL"));
+ break;
+
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_FR):
+ if (!p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)
+ err = E_NOT_SUPPORTED;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Next engine is not correct"));
+ }
+
+
+ return err;
+}
+
+static uint8_t GetGenParseCode(e_FmPcdExtractFrom src,
+ uint32_t offset, bool glblMask,
+ uint8_t *parseArrayOffset, bool fromIc,
+ ccPrivateInfo_t icCode)
+{
+ if (!fromIc)
+ {
+ switch (src)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_FRAME_START):
+ if (glblMask)
+ return CC_PC_GENERIC_WITH_MASK;
+ else
+ return CC_PC_GENERIC_WITHOUT_MASK;
+
+ case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE):
+ *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET;
+ if (offset)
+ return CC_PR_OFFSET;
+ else
+ return CC_PR_WITHOUT_OFFSET;
+
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
+ return CC_PC_ILLEGAL;
+ }
+ }
+ else
+ {
+ switch (icCode)
+ {
+ case (CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH):
+ *parseArrayOffset = 0x50;
+ return CC_PC_GENERIC_IC_GMASK;
+
+ case (CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH):
+ *parseArrayOffset = 0x48;
+ return CC_PC_GENERIC_IC_GMASK;
+
+ case (CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP):
+ *parseArrayOffset = 0x48;
+ return CC_PC_GENERIC_IC_HASH_INDEXED;
+
+ case (CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP):
+ *parseArrayOffset = 0x16;
+ return CC_PC_GENERIC_IC_HASH_INDEXED;
+
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
+ break;
+ }
+ }
+
+ return CC_PC_ILLEGAL;
+}
+
+static uint8_t GetFullFieldParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex index,
+ t_FmPcdFields field)
+{
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ return CC_PC_ILLEGAL;
+
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_DA):
+ return CC_PC_FF_MACDST;
+ case (NET_HEADER_FIELD_ETH_SA):
+ return CC_PC_FF_MACSRC;
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ return CC_PC_FF_ETYPE;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_TCI1;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return CC_PC_FF_TCI2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_MPLS):
+ switch (field.mpls)
+ {
+ case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_MPLS1;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return CC_PC_FF_MPLS_LAST;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index"));
+ return CC_PC_ILLEGAL;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_IPv4):
+ switch (field.ipv4)
+ {
+ case (NET_HEADER_FIELD_IPv4_DST_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV4DST1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV4DST2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return CC_PC_ILLEGAL;
+ case (NET_HEADER_FIELD_IPv4_TOS):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV4IPTOS_TC1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV4IPTOS_TC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return CC_PC_ILLEGAL;
+ case (NET_HEADER_FIELD_IPv4_PROTO):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV4PTYPE1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV4PTYPE2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return CC_PC_ILLEGAL;
+ case (NET_HEADER_FIELD_IPv4_SRC_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV4SRC1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV4SRC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return CC_PC_ILLEGAL;
+ case (NET_HEADER_FIELD_IPv4_SRC_IP
+ | NET_HEADER_FIELD_IPv4_DST_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV4SRC1_IPV4DST1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV4SRC2_IPV4DST2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return CC_PC_ILLEGAL;
+ case (NET_HEADER_FIELD_IPv4_TTL):
+ return CC_PC_FF_IPV4TTL;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_IPv6):
+ switch (field.ipv6)
+ {
+ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL
+ | NET_HEADER_FIELD_IPv6_TC):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return CC_PC_ILLEGAL;
+
+ case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV6PTYPE1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV6PTYPE2;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return CC_PC_FF_IPPID;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return CC_PC_ILLEGAL;
+
+ case (NET_HEADER_FIELD_IPv6_DST_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV6DST1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV6DST2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return CC_PC_ILLEGAL;
+
+ case (NET_HEADER_FIELD_IPv6_SRC_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPV6SRC1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return CC_PC_FF_IPV6SRC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return CC_PC_ILLEGAL;
+
+ case (NET_HEADER_FIELD_IPv6_HOP_LIMIT):
+ return CC_PC_FF_IPV6HOP_LIMIT;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_IP):
+ switch (field.ip)
+ {
+ case (NET_HEADER_FIELD_IP_DSCP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE)
+ || (index == e_FM_PCD_HDR_INDEX_1))
+ return CC_PC_FF_IPDSCP;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index"));
+ return CC_PC_ILLEGAL;
+
+ case (NET_HEADER_FIELD_IP_PROTO):
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return CC_PC_FF_IPPID;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index"));
+ return CC_PC_ILLEGAL;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_GRE):
+ switch (field.gre)
+ {
+ case (NET_HEADER_FIELD_GRE_TYPE):
+ return CC_PC_FF_GREPTYPE;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_MINENCAP):
+ switch (field.minencap)
+ {
+ case (NET_HEADER_FIELD_MINENCAP_TYPE):
+ return CC_PC_FF_MINENCAP_PTYPE;
+
+ case (NET_HEADER_FIELD_MINENCAP_DST_IP):
+ return CC_PC_FF_MINENCAP_IPDST;
+
+ case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
+ return CC_PC_FF_MINENCAP_IPSRC;
+
+ case (NET_HEADER_FIELD_MINENCAP_SRC_IP
+ | NET_HEADER_FIELD_MINENCAP_DST_IP):
+ return CC_PC_FF_MINENCAP_IPSRC_IPDST;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_TCP):
+ switch (field.tcp)
+ {
+ case (NET_HEADER_FIELD_TCP_PORT_SRC):
+ return CC_PC_FF_L4PSRC;
+
+ case (NET_HEADER_FIELD_TCP_PORT_DST):
+ return CC_PC_FF_L4PDST;
+
+ case (NET_HEADER_FIELD_TCP_PORT_DST
+ | NET_HEADER_FIELD_TCP_PORT_SRC):
+ return CC_PC_FF_L4PSRC_L4PDST;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_PPPoE):
+ switch (field.pppoe)
+ {
+ case (NET_HEADER_FIELD_PPPoE_PID):
+ return CC_PC_FF_PPPPID;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ case (HEADER_TYPE_UDP):
+ switch (field.udp)
+ {
+ case (NET_HEADER_FIELD_UDP_PORT_SRC):
+ return CC_PC_FF_L4PSRC;
+
+ case (NET_HEADER_FIELD_UDP_PORT_DST):
+ return CC_PC_FF_L4PDST;
+
+ case (NET_HEADER_FIELD_UDP_PORT_DST
+ | NET_HEADER_FIELD_UDP_PORT_SRC):
+ return CC_PC_FF_L4PSRC_L4PDST;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+}
+
+static uint8_t GetPrParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex,
+ uint32_t offset, bool glblMask,
+ uint8_t *parseArrayOffset)
+{
+ bool offsetRelevant = FALSE;
+
+ if (offset)
+ offsetRelevant = TRUE;
+
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ return CC_PC_ILLEGAL;
+
+ case (HEADER_TYPE_ETH):
+ *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET;
+ break;
+
+ case (HEADER_TYPE_USER_DEFINED_SHIM1):
+ if (offset || glblMask)
+ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET;
+ else
+ return CC_PC_PR_SHIM1;
+ break;
+
+ case (HEADER_TYPE_USER_DEFINED_SHIM2):
+ if (offset || glblMask)
+ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET;
+ else
+ return CC_PC_PR_SHIM2;
+ break;
+
+ case (HEADER_TYPE_LLC_SNAP):
+ *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET;
+ break;
+
+ case (HEADER_TYPE_PPPoE):
+ *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET;
+ break;
+
+ case (HEADER_TYPE_MPLS):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET;
+ else
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
+ return CC_PC_ILLEGAL;
+ }
+ break;
+
+ case (HEADER_TYPE_IPv4):
+ case (HEADER_TYPE_IPv6):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_IP1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
+ *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET;
+ else
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
+ return CC_PC_ILLEGAL;
+ }
+ break;
+
+ case (HEADER_TYPE_MINENCAP):
+ *parseArrayOffset = CC_PC_PR_MINENC_OFFSET;
+ break;
+
+ case (HEADER_TYPE_GRE):
+ *parseArrayOffset = CC_PC_PR_GRE_OFFSET;
+ break;
+
+ case (HEADER_TYPE_TCP):
+ case (HEADER_TYPE_UDP):
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP):
+ case (HEADER_TYPE_DCCP):
+ case (HEADER_TYPE_SCTP):
+ *parseArrayOffset = CC_PC_PR_L4_OFFSET;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header for this type of operation"));
+ return CC_PC_ILLEGAL;
+ }
+
+ if (offsetRelevant)
+ return CC_PR_OFFSET;
+ else
+ return CC_PR_WITHOUT_OFFSET;
+}
+
+static uint8_t GetFieldParseCode(e_NetHeaderType hdr, t_FmPcdFields field,
+ uint32_t offset, uint8_t *parseArrayOffset,
+ e_FmPcdHdrIndex hdrIndex)
+{
+ bool offsetRelevant = FALSE;
+
+ if (offset)
+ offsetRelevant = TRUE;
+
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ break;
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+ break;
+
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET;
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return CC_PC_ILLEGAL;
+ }
+ break;
+
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal header "));
+ return CC_PC_ILLEGAL;
+ }
+
+ if (offsetRelevant)
+ return CC_PR_OFFSET;
+ else
+ return CC_PR_WITHOUT_OFFSET;
+}
+
+static void FillAdOfTypeResult(t_Handle h_Ad,
+ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
+ t_FmPcd *p_FmPcd,
+ t_FmPcdCcNextEngineParams *p_CcNextEngineParams)
+{
+ t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult *)h_Ad;
+ t_Handle h_TmpAd;
+ uint32_t tmp = 0, tmpNia = 0;
+ uint16_t profileId;
+ t_Handle p_AdNewPtr = NULL;
+ t_Error err = E_OK;
+
+ /* There are 3 cases handled in this routine of building a "result" type AD.
+ * Case 1: No Manip. The action descriptor is built within the match table.
+ * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized
+ * either in the FmPcdManipUpdateAdResultForCc routine or it was already
+ * initialized and returned here.
+ * p_AdResult (within the match table) will be initialized after
+ * this routine returns and point to the existing AD.
+ * Case 3: Manip exists. The action descriptor is built within the match table.
+ * FmPcdManipUpdateAdResultForCc returns a NULL p_AdNewPtr.
+ *
+ * If statistics were enabled and the statistics mode of this node requires
+ * a statistics Ad, it will be placed after the result Ad and before the
+ * manip Ad, if manip Ad exists here.
+ */
+
+ /* As default, the "new" ptr is the current one. i.e. the content of the result
+ * AD will be written into the match table itself (case (1))*/
+ p_AdNewPtr = p_AdResult;
+
+ /* Initialize an action descriptor, if current statistics mode requires an Ad */
+ if (p_FmPcdCcStatsParams)
+ {
+ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd);
+ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters);
+
+ /* Swapping addresses between statistics Ad and the current lookup AD addresses */
+ h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd;
+ p_FmPcdCcStatsParams->h_StatsAd = h_Ad;
+ h_Ad = h_TmpAd;
+
+ p_AdNewPtr = h_Ad;
+ p_AdResult = h_Ad;
+
+ /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */
+ UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase);
+ }
+
+ /* Create manip and return p_AdNewPtr to either a new descriptor or NULL */
+ if (p_CcNextEngineParams->h_Manip)
+ FmPcdManipUpdateAdResultForCc(p_CcNextEngineParams->h_Manip,
+ p_CcNextEngineParams, h_Ad, &p_AdNewPtr);
+
+ /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */
+ if (p_AdNewPtr)
+ {
+ /* case (1) and (2) */
+ switch (p_CcNextEngineParams->nextEngine)
+ {
+ case (e_FM_PCD_DONE):
+ if (p_CcNextEngineParams->params.enqueueParams.action
+ == e_FM_PCD_ENQ_FRAME)
+ {
+ if (p_CcNextEngineParams->params.enqueueParams.overrideFqid)
+ {
+ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
+ tmp |=
+ p_CcNextEngineParams->params.enqueueParams.newFqid;
+#if (DPAA_VERSION >= 11)
+ tmp |=
+ (p_CcNextEngineParams->params.enqueueParams.newRelativeStorageProfileId
+ & FM_PCD_AD_RESULT_VSP_MASK)
+ << FM_PCD_AD_RESULT_VSP_SHIFT;
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ else
+ {
+ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
+ tmp |= FM_PCD_AD_RESULT_PLCR_DIS;
+ }
+ }
+
+ if (p_CcNextEngineParams->params.enqueueParams.action
+ == e_FM_PCD_DROP_FRAME)
+ tmpNia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
+ else
+ tmpNia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
+ break;
+
+ case (e_FM_PCD_KG):
+ if (p_CcNextEngineParams->params.kgParams.overrideFqid)
+ {
+ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
+ tmp |= p_CcNextEngineParams->params.kgParams.newFqid;
+#if (DPAA_VERSION >= 11)
+ tmp |=
+ (p_CcNextEngineParams->params.kgParams.newRelativeStorageProfileId
+ & FM_PCD_AD_RESULT_VSP_MASK)
+ << FM_PCD_AD_RESULT_VSP_SHIFT;
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ else
+ {
+ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
+ tmp |= FM_PCD_AD_RESULT_PLCR_DIS;
+ }
+ tmpNia = NIA_KG_DIRECT;
+ tmpNia |= NIA_ENG_KG;
+ tmpNia |= NIA_KG_CC_EN;
+ tmpNia |= FmPcdKgGetSchemeId(
+ p_CcNextEngineParams->params.kgParams.h_DirectScheme);
+ break;
+
+ case (e_FM_PCD_PLCR):
+ if (p_CcNextEngineParams->params.plcrParams.overrideParams)
+ {
+ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE;
+
+ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
+ if (p_CcNextEngineParams->params.plcrParams.sharedProfile)
+ {
+ tmpNia |= NIA_PLCR_ABSOLUTE;
+ err = FmPcdPlcrGetAbsoluteIdByProfileParams(
+ (t_Handle)p_FmPcd,
+ e_FM_PCD_PLCR_SHARED,
+ NULL,
+ p_CcNextEngineParams->params.plcrParams.newRelativeProfileId,
+ &profileId);
+
+ if (err != E_OK) {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return;
+ }
+
+ }
+ else
+ profileId =
+ p_CcNextEngineParams->params.plcrParams.newRelativeProfileId;
+
+ tmp |= p_CcNextEngineParams->params.plcrParams.newFqid;
+#if (DPAA_VERSION >= 11)
+ tmp |=
+ (p_CcNextEngineParams->params.plcrParams.newRelativeStorageProfileId
+ & FM_PCD_AD_RESULT_VSP_MASK)
+ << FM_PCD_AD_RESULT_VSP_SHIFT;
+#endif /* (DPAA_VERSION >= 11) */
+ WRITE_UINT32(
+ p_AdResult->plcrProfile,
+ (uint32_t)((uint32_t)profileId << FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT));
+ }
+ else
+ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE;
+
+ tmpNia |=
+ NIA_ENG_PLCR
+ | p_CcNextEngineParams->params.plcrParams.newRelativeProfileId;
+ break;
+
+ default:
+ return;
+ }WRITE_UINT32(p_AdResult->fqid, tmp);
+
+ if (p_CcNextEngineParams->h_Manip)
+ {
+ tmp = GET_UINT32(p_AdResult->plcrProfile);
+ tmp |= (uint32_t)(XX_VirtToPhys(p_AdNewPtr)
+ - (p_FmPcd->physicalMuramBase)) >> 4;
+ WRITE_UINT32(p_AdResult->plcrProfile, tmp);
+
+ tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE;
+ tmpNia |= FM_PCD_AD_RESULT_NADEN;
+ }
+
+#if (DPAA_VERSION >= 11)
+ tmpNia |= FM_PCD_AD_RESULT_NO_OM_VSPE;
+#endif /* (DPAA_VERSION >= 11) */
+ WRITE_UINT32(p_AdResult->nia, tmpNia);
+ }
+}
+
+static t_Error CcUpdateParams(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_Handle h_FmTree,
+ bool validate)
+{
+ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree;
+
+ return CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort,
+ p_CcTree->keyAndNextEngineParams,
+ p_CcTree->numOfEntries,
+ UINT_TO_PTR(p_CcTree->ccTreeBaseAddr), validate, 0,
+ h_FmTree, FALSE);
+}
+
+
+static void ReleaseNewNodeCommonPart(
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
+{
+ if (p_AdditionalInfo->p_AdTableNew)
+ FM_MURAM_FreeMem(
+ FmPcdGetMuramHandle(
+ ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd),
+ p_AdditionalInfo->p_AdTableNew);
+
+ if (p_AdditionalInfo->p_KeysMatchTableNew)
+ FM_MURAM_FreeMem(
+ FmPcdGetMuramHandle(
+ ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd),
+ p_AdditionalInfo->p_KeysMatchTableNew);
+}
+
+static t_Error UpdateGblMask(t_FmPcdCcNode *p_CcNode, uint8_t keySize,
+ uint8_t *p_Mask)
+{
+ uint8_t prvGlblMaskSize = p_CcNode->glblMaskSize;
+
+ if (p_Mask && !p_CcNode->glblMaskUpdated && (keySize <= 4)
+ && !p_CcNode->lclMask)
+ {
+ if (p_CcNode->parseCode && (p_CcNode->parseCode != CC_PC_FF_TCI1)
+ && (p_CcNode->parseCode != CC_PC_FF_TCI2)
+ && (p_CcNode->parseCode != CC_PC_FF_MPLS1)
+ && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST)
+ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1)
+ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2)
+ && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1)
+ && (p_CcNode->parseCode != CC_PC_FF_IPDSCP)
+ && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2))
+ {
+ p_CcNode->glblMaskSize = 0;
+ p_CcNode->lclMask = TRUE;
+ }
+ else
+ {
+ memcpy(p_CcNode->p_GlblMask, p_Mask, (sizeof(uint8_t)) * keySize);
+ p_CcNode->glblMaskUpdated = TRUE;
+ p_CcNode->glblMaskSize = 4;
+ }
+ }
+ else
+ if (p_Mask && (keySize <= 4) && !p_CcNode->lclMask)
+ {
+ if (memcmp(p_CcNode->p_GlblMask, p_Mask, keySize) != 0)
+ {
+ p_CcNode->lclMask = TRUE;
+ p_CcNode->glblMaskSize = 0;
+ }
+ }
+ else
+ if (!p_Mask && p_CcNode->glblMaskUpdated && (keySize <= 4))
+ {
+ uint32_t tmpMask = 0xffffffff;
+ if (memcmp(p_CcNode->p_GlblMask, &tmpMask, 4) != 0)
+ {
+ p_CcNode->lclMask = TRUE;
+ p_CcNode->glblMaskSize = 0;
+ }
+ }
+ else
+ if (p_Mask)
+ {
+ p_CcNode->lclMask = TRUE;
+ p_CcNode->glblMaskSize = 0;
+ }
+
+ /* In static mode (maxNumOfKeys > 0), local mask is supported
+ only is mask support was enabled at initialization */
+ if (p_CcNode->maxNumOfKeys && (!p_CcNode->maskSupport) && p_CcNode->lclMask)
+ {
+ p_CcNode->lclMask = FALSE;
+ p_CcNode->glblMaskSize = prvGlblMaskSize;
+ return ERROR_CODE(E_NOT_SUPPORTED);
+ }
+
+ return E_OK;
+}
+
+static __inline__ t_Handle GetNewAd(t_Handle h_FmPcdCcNodeOrTree, bool isTree)
+{
+ t_FmPcd *p_FmPcd;
+ t_Handle h_Ad;
+
+ if (isTree)
+ p_FmPcd = (t_FmPcd *)(((t_FmPcdCcTree *)h_FmPcdCcNodeOrTree)->h_FmPcd);
+ else
+ p_FmPcd = (t_FmPcd *)(((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_FmPcd);
+
+ if ((isTree && p_FmPcd->p_CcShadow)
+ || (!isTree && ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->maxNumOfKeys))
+ {
+ /* The allocated shadow is divided as follows:
+ 0 . . . 16 . . .
+ ---------------------------------------------------
+ | Shadow | Shadow Keys | Shadow Next |
+ | Ad | Match Table | Engine Table |
+ | (16 bytes) | (maximal size) | (maximal size) |
+ ---------------------------------------------------
+ */
+ if (!p_FmPcd->p_CcShadow)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
+ return NULL;
+ }
+
+ h_Ad = p_FmPcd->p_CcShadow;
+ }
+ else
+ {
+ h_Ad = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd),
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!h_Ad)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node action descriptor"));
+ return NULL;
+ }
+ }
+
+ return h_Ad;
+}
+
+static t_Error BuildNewNodeCommonPart(
+ t_FmPcdCcNode *p_CcNode, int *size,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ if (p_CcNode->lclMask)
+ *size = 2 * p_CcNode->ccKeySizeAccExtraction;
+ else
+ *size = p_CcNode->ccKeySizeAccExtraction;
+
+ if (p_CcNode->maxNumOfKeys == 0)
+ {
+ p_AdditionalInfo->p_AdTableNew = (t_Handle)FM_MURAM_AllocMem(
+ FmPcdGetMuramHandle(p_FmPcd),
+ (uint32_t)((p_AdditionalInfo->numOfKeys + 1)
+ * FM_PCD_CC_AD_ENTRY_SIZE),
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_AdditionalInfo->p_AdTableNew)
+ RETURN_ERROR(
+ MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC node action descriptors table"));
+
+ p_AdditionalInfo->p_KeysMatchTableNew = (t_Handle)FM_MURAM_AllocMem(
+ FmPcdGetMuramHandle(p_FmPcd),
+ (uint32_t)(*size * sizeof(uint8_t)
+ * (p_AdditionalInfo->numOfKeys + 1)),
+ FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN);
+ if (!p_AdditionalInfo->p_KeysMatchTableNew)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd),
+ p_AdditionalInfo->p_AdTableNew);
+ p_AdditionalInfo->p_AdTableNew = NULL;
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC node key match table"));
+ }
+
+ MemSet8(
+ (uint8_t*)p_AdditionalInfo->p_AdTableNew,
+ 0,
+ (uint32_t)((p_AdditionalInfo->numOfKeys + 1)
+ * FM_PCD_CC_AD_ENTRY_SIZE));
+ MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0,
+ *size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1));
+ }
+ else
+ {
+ /* The allocated shadow is divided as follows:
+ 0 . . . 16 . . .
+ ---------------------------------------------------
+ | Shadow | Shadow Keys | Shadow Next |
+ | Ad | Match Table | Engine Table |
+ | (16 bytes) | (maximal size) | (maximal size) |
+ ---------------------------------------------------
+ */
+
+ if (!p_FmPcd->p_CcShadow)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
+
+ p_AdditionalInfo->p_KeysMatchTableNew =
+ PTR_MOVE(p_FmPcd->p_CcShadow, FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdditionalInfo->p_AdTableNew =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, p_CcNode->keysMatchTableMaxSize);
+
+ MemSet8(
+ (uint8_t*)p_AdditionalInfo->p_AdTableNew,
+ 0,
+ (uint32_t)((p_CcNode->maxNumOfKeys + 1)
+ * FM_PCD_CC_AD_ENTRY_SIZE));
+ MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0,
+ (*size) * sizeof(uint8_t) * (p_CcNode->maxNumOfKeys));
+ }
+
+ p_AdditionalInfo->p_AdTableOld = p_CcNode->h_AdTable;
+ p_AdditionalInfo->p_KeysMatchTableOld = p_CcNode->h_KeysMatchTable;
+
+ return E_OK;
+}
+
+static t_Error BuildNewNodeAddOrMdfyKeyAndNextEngine(
+ t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
+ t_FmPcdCcKeyParams *p_KeyParams,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo, bool add)
+{
+ t_Error err = E_OK;
+ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
+ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
+ int size;
+ int i = 0, j = 0;
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t requiredAction = 0;
+ bool prvLclMask;
+ t_CcNodeInformation *p_CcNodeInformation;
+ t_FmPcdCcStatsParams statsParams = { 0 };
+ t_List *p_Pos;
+ t_FmPcdStatsObj *p_StatsObj;
+
+ /* Check that new NIA is legal */
+ err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams,
+ p_CcNode->statisticsMode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ prvLclMask = p_CcNode->lclMask;
+
+ /* Check that new key is not require update of localMask */
+ err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction,
+ p_KeyParams->p_Mask);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ /* Update internal data structure with new next engine for the given index */
+ memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams,
+ &p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams));
+
+ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key,
+ p_KeyParams->p_Key, p_CcNode->userSizeOfExtraction);
+
+ if ((p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ if (p_KeyParams->p_Mask)
+ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask,
+ p_KeyParams->p_Mask, p_CcNode->userSizeOfExtraction);
+ else
+ memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF,
+ p_CcNode->userSizeOfExtraction);
+
+ /* Update numOfKeys */
+ if (add)
+ p_AdditionalInfo->numOfKeys = (uint8_t)(p_CcNode->numOfKeys + 1);
+ else
+ p_AdditionalInfo->numOfKeys = (uint8_t)p_CcNode->numOfKeys;
+
+ /* Allocate new tables in MURAM: keys match table and action descriptors table */
+ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /* Check that manip is legal and what requiredAction is necessary for this manip */
+ if (p_KeyParams->ccNextEngineParams.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_KeyParams->ccNextEngineParams, &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction =
+ requiredAction;
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |=
+ UPDATE_CC_WITH_TREE;
+
+ /* Update new Ad and new Key Table according to new requirement */
+ i = 0;
+ for (j = 0; j < p_AdditionalInfo->numOfKeys; j++)
+ {
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE);
+
+ if (j == keyIndex)
+ {
+ if (p_KeyParams->ccNextEngineParams.statisticsEn)
+ {
+ /* Allocate a statistics object that holds statistics AD and counters.
+ - For added key - New statistics AD and counters pointer need to be allocated
+ new statistics object. If statistics were enabled, we need to replace the
+ existing descriptor with a new descriptor with nullified counters.
+ */
+ p_StatsObj = GetStatsObj(p_CcNode);
+ ASSERT_COND(p_StatsObj);
+
+ /* Store allocated statistics object */
+ ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS);
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
+ p_StatsObj;
+
+ statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
+ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
+#if (DPAA_VERSION >= 11)
+ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
+
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Building action descriptor for the received new key */
+ NextStepAd(p_AdTableNewTmp, &statsParams,
+ &p_KeyParams->ccNextEngineParams, p_FmPcd);
+ }
+ else
+ {
+ /* Building action descriptor for the received new key */
+ NextStepAd(p_AdTableNewTmp, NULL,
+ &p_KeyParams->ccNextEngineParams, p_FmPcd);
+ }
+
+ /* Copy the received new key into keys match table */
+ p_KeysMatchTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size*sizeof(uint8_t));
+
+ MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeyParams->p_Key,
+ p_CcNode->userSizeOfExtraction);
+
+ /* Update mask for the received new key */
+ if (p_CcNode->lclMask)
+ {
+ if (p_KeyParams->p_Mask)
+ {
+ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ p_KeyParams->p_Mask,
+ p_CcNode->userSizeOfExtraction);
+ }
+ else
+ if (p_CcNode->ccKeySizeAccExtraction > 4)
+ {
+ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ 0xff, p_CcNode->userSizeOfExtraction);
+ }
+ else
+ {
+ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->p_GlblMask,
+ p_CcNode->userSizeOfExtraction);
+ }
+ }
+
+ /* If key modification requested, the old entry is omitted and replaced by the new parameters */
+ if (!add)
+ i++;
+ }
+ else
+ {
+ /* Copy existing action descriptors to the newly allocated Ad table */
+ p_AdTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE);
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp,
+ FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Copy existing keys and their masks to the newly allocated keys match table */
+ p_KeysMatchTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
+ p_KeysMatchTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, i * size * sizeof(uint8_t));
+
+ if (p_CcNode->lclMask)
+ {
+ if (prvLclMask)
+ {
+ MemCpy8(
+ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
+ PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->ccKeySizeAccExtraction);
+ }
+ else
+ {
+ p_KeysMatchTableOldTmp =
+ PTR_MOVE(p_CcNode->h_KeysMatchTable,
+ i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t));
+
+ if (p_CcNode->ccKeySizeAccExtraction > 4)
+ {
+ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ 0xff, p_CcNode->userSizeOfExtraction);
+ }
+ else
+ {
+ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->p_GlblMask,
+ p_CcNode->userSizeOfExtraction);
+ }
+ }
+ }
+
+ MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
+ p_CcNode->ccKeySizeAccExtraction);
+
+ i++;
+ }
+ }
+
+ /* Miss action descriptor */
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i * FM_PCD_CC_AD_ENTRY_SIZE);
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ if (!LIST_IsEmpty(&p_CcNode->ccTreesLst))
+ {
+ LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst)
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+ ASSERT_COND(p_CcNodeInformation->h_CcNode);
+ /* Update the manipulation which has to be updated from parameters of the port */
+ /* It's has to be updated with restrictions defined in the function */
+ err =
+ SetRequiredAction(
+ p_CcNode->h_FmPcd,
+ p_CcNode->shadowAction
+ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
+ 1, p_CcNodeInformation->h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ err =
+ CcUpdateParam(
+ p_CcNode->h_FmPcd,
+ NULL,
+ NULL,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
+ 1,
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE),
+ TRUE, p_CcNodeInformation->index,
+ p_CcNodeInformation->h_CcNode, TRUE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+ }
+
+ if (p_CcNode->lclMask)
+ memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
+
+ if (p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForAdd =
+ p_KeyParams->ccNextEngineParams.params.ccParams.h_CcNode;
+ if (p_KeyParams->ccNextEngineParams.h_Manip)
+ p_AdditionalInfo->h_ManipForAdd =
+ p_KeyParams->ccNextEngineParams.h_Manip;
+
+#if (DPAA_VERSION >= 11)
+ if ((p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_FR)
+ && (p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForAdd =
+ p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (!add)
+ {
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
+
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
+ p_AdditionalInfo->h_ManipForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
+
+ /* If statistics were previously enabled, store the old statistics object to be released */
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ {
+ p_AdditionalInfo->p_StatsObjForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
+ }
+
+#if (DPAA_VERSION >= 11)
+ if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ return E_OK;
+}
+
+static t_Error BuildNewNodeRemoveKey(
+ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
+ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
+{
+ int i = 0, j = 0;
+ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
+ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
+ int size;
+ t_Error err = E_OK;
+
+ /*save new numOfKeys*/
+ p_AdditionalInfo->numOfKeys = (uint16_t)(p_CcNode->numOfKeys - 1);
+
+ /*function which allocates in the memory new KeyTbl, AdTbl*/
+ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /*update new Ad and new Key Table according to new requirement*/
+ for (i = 0, j = 0; j < p_CcNode->numOfKeys; i++, j++)
+ {
+ if (j == keyIndex)
+ j++;
+
+ if (j == p_CcNode->numOfKeys)
+ break;
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE);
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ p_KeysMatchTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, j * size * sizeof(uint8_t));
+ p_KeysMatchTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, i * size * sizeof(uint8_t));
+ MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
+ size * sizeof(uint8_t));
+ }
+
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE);
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
+
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
+ p_AdditionalInfo->h_ManipForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
+
+ /* If statistics were previously enabled, store the old statistics object to be released */
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ {
+ p_AdditionalInfo->p_StatsObjForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
+ }
+
+#if (DPAA_VERSION >= 11)
+ if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+
+ return E_OK;
+}
+
+static t_Error BuildNewNodeModifyKey(
+ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, uint8_t *p_Key,
+ uint8_t *p_Mask, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ t_Error err = E_OK;
+ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp;
+ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp;
+ int size;
+ int i = 0, j = 0;
+ bool prvLclMask;
+ t_FmPcdStatsObj *p_StatsObj, tmpStatsObj;
+ p_AdditionalInfo->numOfKeys = p_CcNode->numOfKeys;
+
+ prvLclMask = p_CcNode->lclMask;
+
+ /* Check that new key is not require update of localMask */
+ err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, p_Mask);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ /* Update internal data structure with new next engine for the given index */
+ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, p_Key,
+ p_CcNode->userSizeOfExtraction);
+
+ if (p_Mask)
+ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, p_Mask,
+ p_CcNode->userSizeOfExtraction);
+ else
+ memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF,
+ p_CcNode->userSizeOfExtraction);
+
+ /*function which build in the memory new KeyTbl, AdTbl*/
+ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /*fill the New AdTable and New KeyTable*/
+ for (j = 0, i = 0; j < p_AdditionalInfo->numOfKeys; j++, i++)
+ {
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdTableOldTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE);
+
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ if (j == keyIndex)
+ {
+ ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS);
+ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ {
+ /* As statistics were enabled, we need to update the existing
+ statistics descriptor with a new nullified counters. */
+ p_StatsObj = GetStatsObj(p_CcNode);
+ ASSERT_COND(p_StatsObj);
+
+ SetStatsCounters(
+ p_AdTableNewTmp,
+ (uint32_t)((XX_VirtToPhys(p_StatsObj->h_StatsCounters)
+ - p_FmPcd->physicalMuramBase)));
+
+ tmpStatsObj.h_StatsAd = p_StatsObj->h_StatsAd;
+ tmpStatsObj.h_StatsCounters = p_StatsObj->h_StatsCounters;
+
+ /* As we need to replace only the counters, we build a new statistics
+ object that holds the old AD and the new counters - this will be the
+ currently used statistics object.
+ The newly allocated AD is not required and may be released back to
+ the available objects with the previous counters pointer. */
+ p_StatsObj->h_StatsAd =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd;
+
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd =
+ tmpStatsObj.h_StatsAd;
+
+ /* Store allocated statistics object */
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
+ p_StatsObj;
+
+ /* As statistics were previously enabled, store the old statistics object to be released */
+ p_AdditionalInfo->p_StatsObjForRmv =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj;
+ }
+
+ p_KeysMatchTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
+
+ MemCpy8(p_KeysMatchTableNewTmp, p_Key,
+ p_CcNode->userSizeOfExtraction);
+
+ if (p_CcNode->lclMask)
+ {
+ if (p_Mask)
+ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ p_Mask, p_CcNode->userSizeOfExtraction);
+ else
+ if (p_CcNode->ccKeySizeAccExtraction > 4)
+ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ 0xff, p_CcNode->userSizeOfExtraction);
+ else
+ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->p_GlblMask,
+ p_CcNode->userSizeOfExtraction);
+ }
+ }
+ else
+ {
+ p_KeysMatchTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t));
+ p_KeysMatchTableOldTmp =
+ PTR_MOVE(p_CcNode->h_KeysMatchTable, i * size * sizeof(uint8_t));
+
+ if (p_CcNode->lclMask)
+ {
+ if (prvLclMask)
+ MemCpy8(
+ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
+ PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->userSizeOfExtraction);
+ else
+ {
+ p_KeysMatchTableOldTmp =
+ PTR_MOVE(p_CcNode->h_KeysMatchTable,
+ i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t));
+
+ if (p_CcNode->ccKeySizeAccExtraction > 4)
+ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp,
+ p_CcNode->ccKeySizeAccExtraction),
+ 0xff, p_CcNode->userSizeOfExtraction);
+ else
+ MemCpy8(
+ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction),
+ p_CcNode->p_GlblMask,
+ p_CcNode->userSizeOfExtraction);
+ }
+ }
+ MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp,
+ p_CcNode->ccKeySizeAccExtraction);
+ }
+ }
+
+ p_AdTableNewTmp =
+ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE);
+ p_AdTableOldTmp = PTR_MOVE(p_CcNode->h_AdTable, i * FM_PCD_CC_AD_ENTRY_SIZE);
+
+ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ return E_OK;
+}
+
+static t_Error BuildNewNodeModifyNextEngine(
+ t_Handle h_FmPcd, t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_CcNextEngineParams, t_List *h_OldLst,
+ t_List *h_NewLst, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo)
+{
+ t_Error err = E_OK;
+ uint32_t requiredAction = 0;
+ t_List *p_Pos;
+ t_CcNodeInformation *p_CcNodeInformation, ccNodeInfo;
+ t_Handle p_Ad;
+ t_FmPcdCcNode *p_FmPcdCcNode1 = NULL;
+ t_FmPcdCcTree *p_FmPcdCcTree = NULL;
+ t_FmPcdStatsObj *p_StatsObj;
+ t_FmPcdCcStatsParams statsParams = { 0 };
+
+ ASSERT_COND(p_CcNextEngineParams);
+
+ /* check that new NIA is legal */
+ if (!p_AdditionalInfo->tree)
+ err = ValidateNextEngineParams(
+ h_FmPcd, p_CcNextEngineParams,
+ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->statisticsMode);
+ else
+ /* Statistics are not supported for CC root */
+ err = ValidateNextEngineParams(h_FmPcd, p_CcNextEngineParams,
+ e_FM_PCD_CC_STATS_MODE_NONE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /* Update internal data structure for next engine per index (index - key) */
+ memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams,
+ p_CcNextEngineParams, sizeof(t_FmPcdCcNextEngineParams));
+
+ /* Check that manip is legal and what requiredAction is necessary for this manip */
+ if (p_CcNextEngineParams->h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(p_CcNextEngineParams,
+ &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ if (!p_AdditionalInfo->tree)
+ {
+ p_FmPcdCcNode1 = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree;
+ p_AdditionalInfo->numOfKeys = p_FmPcdCcNode1->numOfKeys;
+ p_Ad = p_FmPcdCcNode1->h_AdTable;
+
+ if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForRmv =
+ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
+
+ if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
+ p_AdditionalInfo->h_ManipForRmv =
+ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
+
+#if (DPAA_VERSION >= 11)
+ if ((p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForRmv =
+ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ else
+ {
+ p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree;
+ p_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
+
+ if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForRmv =
+ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode;
+
+ if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip)
+ p_AdditionalInfo->h_ManipForRmv =
+ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip;
+
+#if (DPAA_VERSION >= 11)
+ if ((p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForRmv =
+ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_CC)
+ && p_CcNextEngineParams->h_Manip)
+ {
+ err = AllocAndFillAdForContLookupManip(
+ p_CcNextEngineParams->params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ ASSERT_COND(p_Ad);
+
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = PTR_MOVE(p_Ad, keyIndex * FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* If statistics were enabled, this Ad is the statistics Ad. Need to follow its
+ nextAction to retrieve the actual Nia-Ad. If statistics should remain enabled,
+ only the actual Nia-Ad should be modified. */
+ if ((!p_AdditionalInfo->tree)
+ && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ && (p_CcNextEngineParams->statisticsEn))
+ ccNodeInfo.h_CcNode =
+ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd;
+
+ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
+
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ p_Ad = GetNewAd(h_FmPcdCcNodeOrTree, p_AdditionalInfo->tree);
+ if (!p_Ad)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC node action descriptor"));
+ MemSet8((uint8_t *)p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* If statistics were not enabled before, but requested now - Allocate a statistics
+ object that holds statistics AD and counters. */
+ if ((!p_AdditionalInfo->tree)
+ && (!((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ && (p_CcNextEngineParams->statisticsEn))
+ {
+ p_StatsObj = GetStatsObj((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree);
+ ASSERT_COND(p_StatsObj);
+
+ /* Store allocated statistics object */
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj =
+ p_StatsObj;
+
+ statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
+ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
+
+#if (DPAA_VERSION >= 11)
+ statsParams.h_StatsFLRs =
+ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_StatsFLRs;
+
+#endif /* (DPAA_VERSION >= 11) */
+
+ NextStepAd(p_Ad, &statsParams, p_CcNextEngineParams, h_FmPcd);
+ }
+ else
+ NextStepAd(p_Ad, NULL, p_CcNextEngineParams, h_FmPcd);
+
+ ccNodeInfo.h_CcNode = p_Ad;
+ EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL);
+
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction =
+ requiredAction;
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |=
+ UPDATE_CC_WITH_TREE;
+
+ if (!p_AdditionalInfo->tree)
+ {
+ ASSERT_COND(p_FmPcdCcNode1);
+ if (!LIST_IsEmpty(&p_FmPcdCcNode1->ccTreesLst))
+ {
+ LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode1->ccTreesLst)
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+
+ ASSERT_COND(p_CcNodeInformation->h_CcNode);
+ /* Update the manipulation which has to be updated from parameters of the port
+ it's has to be updated with restrictions defined in the function */
+
+ err =
+ SetRequiredAction(
+ p_FmPcdCcNode1->h_FmPcd,
+ p_FmPcdCcNode1->shadowAction
+ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
+ p_Ad, 1, p_CcNodeInformation->h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ err = CcUpdateParam(
+ p_FmPcdCcNode1->h_FmPcd, NULL, NULL,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], 1,
+ p_Ad, TRUE, p_CcNodeInformation->index,
+ p_CcNodeInformation->h_CcNode, TRUE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+ }
+ }
+ else
+ {
+ ASSERT_COND(p_FmPcdCcTree);
+
+ err =
+ SetRequiredAction(
+ h_FmPcd,
+ p_FmPcdCcTree->requiredAction
+ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
+ p_Ad, 1, (t_Handle)p_FmPcdCcTree);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ err = CcUpdateParam(h_FmPcd, NULL, NULL,
+ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex],
+ 1, p_Ad, TRUE, 0, (t_Handle)p_FmPcdCcTree, TRUE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ if (p_CcNextEngineParams->nextEngine == e_FM_PCD_CC)
+ p_AdditionalInfo->h_NodeForAdd =
+ p_CcNextEngineParams->params.ccParams.h_CcNode;
+ if (p_CcNextEngineParams->h_Manip)
+ p_AdditionalInfo->h_ManipForAdd = p_CcNextEngineParams->h_Manip;
+
+ /* If statistics were previously enabled, but now are disabled,
+ store the old statistics object to be released */
+ if ((!p_AdditionalInfo->tree)
+ && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ && (!p_CcNextEngineParams->statisticsEn))
+ {
+ p_AdditionalInfo->p_StatsObjForRmv =
+ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj;
+
+
+ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = NULL;
+ }
+#if (DPAA_VERSION >= 11)
+ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_FR)
+ && (p_CcNextEngineParams->params.frParams.h_FrmReplic))
+ p_AdditionalInfo->h_FrmReplicForAdd =
+ p_CcNextEngineParams->params.frParams.h_FrmReplic;
+#endif /* (DPAA_VERSION >= 11) */
+
+ return E_OK;
+}
+
+static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(
+ t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst,
+ t_FmPcdCcNextEngineParams **p_NextEngineParams)
+{
+ t_CcNodeInformation *p_CcNodeInformation;
+ t_FmPcdCcNode *p_NodePtrOnCurrentMdfNode = NULL;
+ t_List *p_Pos;
+ int i = 0;
+ t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/;
+ t_CcNodeInformation ccNodeInfo;
+
+ LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccPrevNodesLst)
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+ p_NodePtrOnCurrentMdfNode =
+ (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode;
+
+ ASSERT_COND(p_NodePtrOnCurrentMdfNode);
+
+ /* Search in the previous node which exact index points on this current modified node for getting AD */
+ for (i = 0; i < p_NodePtrOnCurrentMdfNode->numOfKeys + 1; i++)
+ {
+ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode
+ == (t_Handle)p_CrntMdfNode)
+ {
+ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ p_AdTablePtOnCrntCurrentMdfNode = p_CrntMdfNode->h_Ad;
+ else
+ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj)
+ p_AdTablePtOnCrntCurrentMdfNode =
+ p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd;
+ else
+ p_AdTablePtOnCrntCurrentMdfNode =
+ PTR_MOVE(p_NodePtrOnCurrentMdfNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
+
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode;
+ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
+
+ if (!(*p_NextEngineParams))
+ *p_NextEngineParams =
+ &p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams;
+ }
+ }
+ }
+
+ ASSERT_COND(i != p_NodePtrOnCurrentMdfNode->numOfKeys);
+ }
+}
+
+static void UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(
+ t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst,
+ t_FmPcdCcNextEngineParams **p_NextEngineParams)
+{
+ t_CcNodeInformation *p_CcNodeInformation;
+ t_FmPcdCcTree *p_TreePtrOnCurrentMdfNode = NULL;
+ t_List *p_Pos;
+ int i = 0;
+ t_Handle p_AdTableTmp;
+ t_CcNodeInformation ccNodeInfo;
+
+ LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccTreeIdLst)
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+ p_TreePtrOnCurrentMdfNode =
+ (t_FmPcdCcTree *)p_CcNodeInformation->h_CcNode;
+
+ ASSERT_COND(p_TreePtrOnCurrentMdfNode);
+
+ /*search in the trees which exact index points on this current modified node for getting AD */
+ for (i = 0; i < p_TreePtrOnCurrentMdfNode->numOfEntries; i++)
+ {
+ if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode
+ == (t_Handle)p_CrntMdfNode)
+ {
+ p_AdTableTmp =
+ UINT_TO_PTR(p_TreePtrOnCurrentMdfNode->ccTreeBaseAddr + i*FM_PCD_CC_AD_ENTRY_SIZE);
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = p_AdTableTmp;
+ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL);
+
+ if (!(*p_NextEngineParams))
+ *p_NextEngineParams =
+ &p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams;
+ }
+ }
+ }
+
+ ASSERT_COND(i == p_TreePtrOnCurrentMdfNode->numOfEntries);
+ }
+}
+
+static t_FmPcdModifyCcKeyAdditionalParams * ModifyNodeCommonPart(
+ t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex,
+ e_ModifyState modifyState, bool ttlCheck, bool hashCheck, bool tree)
+{
+ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams;
+ int i = 0, j = 0;
+ bool wasUpdate = FALSE;
+ t_FmPcdCcNode *p_CcNode = NULL;
+ t_FmPcdCcTree *p_FmPcdCcTree;
+ uint16_t numOfKeys;
+ t_FmPcdCcKeyAndNextEngineParams *p_KeyAndNextEngineParams;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcdCcNodeOrTree, E_INVALID_HANDLE, NULL);
+
+ if (!tree)
+ {
+ p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree;
+ numOfKeys = p_CcNode->numOfKeys;
+
+ /* node has to be pointed by another node or tree */
+
+ p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc(
+ sizeof(t_FmPcdCcKeyAndNextEngineParams) * (numOfKeys + 1));
+ if (!p_KeyAndNextEngineParams)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure"));
+ return NULL;
+ }
+ memcpy(p_KeyAndNextEngineParams, p_CcNode->keyAndNextEngineParams,
+ (numOfKeys + 1) * sizeof(t_FmPcdCcKeyAndNextEngineParams));
+
+ if (ttlCheck)
+ {
+ if ((p_CcNode->parseCode == CC_PC_FF_IPV4TTL)
+ || (p_CcNode->parseCode == CC_PC_FF_IPV6HOP_LIMIT))
+ {
+ XX_Free(p_KeyAndNextEngineParams);
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_FF_IPV4TTL or CC_PC_FF_IPV6HOP_LIMIT can not be used for this operation"));
+ return NULL;
+ }
+ }
+
+ if (hashCheck)
+ {
+ if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)
+ {
+ XX_Free(p_KeyAndNextEngineParams);
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_GENERIC_IC_HASH_INDEXED can not be used for this operation"));
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree;
+ numOfKeys = p_FmPcdCcTree->numOfEntries;
+
+ p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc(
+ sizeof(t_FmPcdCcKeyAndNextEngineParams)
+ * FM_PCD_MAX_NUM_OF_CC_GROUPS);
+ if (!p_KeyAndNextEngineParams)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure"));
+ return NULL;
+ }
+ memcpy(p_KeyAndNextEngineParams,
+ p_FmPcdCcTree->keyAndNextEngineParams,
+ FM_PCD_MAX_NUM_OF_CC_GROUPS
+ * sizeof(t_FmPcdCcKeyAndNextEngineParams));
+ }
+
+ p_FmPcdModifyCcKeyAdditionalParams =
+ (t_FmPcdModifyCcKeyAdditionalParams *)XX_Malloc(
+ sizeof(t_FmPcdModifyCcKeyAdditionalParams));
+ if (!p_FmPcdModifyCcKeyAdditionalParams)
+ {
+ XX_Free(p_KeyAndNextEngineParams);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of internal data structure FAILED"));
+ return NULL;
+ }
+ memset(p_FmPcdModifyCcKeyAdditionalParams, 0,
+ sizeof(t_FmPcdModifyCcKeyAdditionalParams));
+
+ p_FmPcdModifyCcKeyAdditionalParams->h_CurrentNode = h_FmPcdCcNodeOrTree;
+ p_FmPcdModifyCcKeyAdditionalParams->savedKeyIndex = keyIndex;
+
+ while (i < numOfKeys)
+ {
+ if ((j == keyIndex) && !wasUpdate)
+ {
+ if (modifyState == e_MODIFY_STATE_ADD)
+ j++;
+ else
+ if (modifyState == e_MODIFY_STATE_REMOVE)
+ i++;
+ wasUpdate = TRUE;
+ }
+ else
+ {
+ memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j],
+ p_KeyAndNextEngineParams + i,
+ sizeof(t_FmPcdCcKeyAndNextEngineParams));
+ i++;
+ j++;
+ }
+ }
+
+ if (keyIndex == numOfKeys)
+ {
+ if (modifyState == e_MODIFY_STATE_ADD)
+ j++;
+ }
+
+ memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j],
+ p_KeyAndNextEngineParams + numOfKeys,
+ sizeof(t_FmPcdCcKeyAndNextEngineParams));
+
+ XX_Free(p_KeyAndNextEngineParams);
+
+ return p_FmPcdModifyCcKeyAdditionalParams;
+}
+
+static t_Error UpdatePtrWhichPointOnCrntMdfNode(
+ t_FmPcdCcNode *p_CcNode,
+ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams,
+ t_List *h_OldLst, t_List *h_NewLst)
+{
+ t_FmPcdCcNextEngineParams *p_NextEngineParams = NULL;
+ t_CcNodeInformation ccNodeInfo = { 0 };
+ t_Handle h_NewAd;
+ t_Handle h_OrigAd = NULL;
+
+ /* Building a list of all action descriptors that point to the previous node */
+ if (!LIST_IsEmpty(&p_CcNode->ccPrevNodesLst))
+ UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst,
+ &p_NextEngineParams);
+
+ if (!LIST_IsEmpty(&p_CcNode->ccTreeIdLst))
+ UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst,
+ &p_NextEngineParams);
+
+ /* This node must be found as next engine of one of its previous nodes or trees*/
+ if (p_NextEngineParams)
+ {
+ /* Building a new action descriptor that points to the modified node */
+ h_NewAd = GetNewAd(p_CcNode, FALSE);
+ if (!h_NewAd)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ MemSet8(h_NewAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ h_OrigAd = p_CcNode->h_Ad;
+ BuildNewAd(h_NewAd, p_FmPcdModifyCcKeyAdditionalParams, p_CcNode,
+ p_NextEngineParams);
+
+ ccNodeInfo.h_CcNode = h_NewAd;
+ EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL);
+
+ if (p_NextEngineParams->h_Manip && !h_OrigAd)
+ FmPcdManipUpdateOwner(p_NextEngineParams->h_Manip, FALSE);
+ }
+ return E_OK;
+}
+
+static void UpdateCcRootOwner(t_FmPcdCcTree *p_FmPcdCcTree, bool add)
+{
+ ASSERT_COND(p_FmPcdCcTree);
+
+ /* this routine must be protected by the calling routine! */
+
+ if (add)
+ p_FmPcdCcTree->owners++;
+ else
+ {
+ ASSERT_COND(p_FmPcdCcTree->owners);
+ p_FmPcdCcTree->owners--;
+ }
+}
+
+static t_Error CheckAndSetManipParamsWithCcNodeParams(t_FmPcdCcNode *p_CcNode)
+{
+ t_Error err = E_OK;
+ int i = 0;
+
+ for (i = 0; i < p_CcNode->numOfKeys; i++)
+ {
+ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ {
+ err =
+ FmPcdManipCheckParamsWithCcNodeParams(
+ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
+ (t_Handle)p_CcNode);
+ if (err)
+ return err;
+ }
+ }
+
+ return err;
+}
+static t_Error ValidateAndCalcStatsParams(t_FmPcdCcNode *p_CcNode,
+ t_FmPcdCcNodeParams *p_CcNodeParam,
+ uint32_t *p_NumOfRanges,
+ uint32_t *p_CountersArraySize)
+{
+ e_FmPcdCcStatsMode statisticsMode = p_CcNode->statisticsMode;
+ uint32_t i;
+
+ UNUSED(p_CcNodeParam);
+
+ switch (statisticsMode)
+ {
+ case e_FM_PCD_CC_STATS_MODE_NONE:
+ for (i = 0; i < p_CcNode->numOfKeys; i++)
+ if (p_CcNodeParam->keysParams.keyParams[i].ccNextEngineParams.statisticsEn)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Statistics cannot be enabled for key %d when statistics mode was set to 'NONE'", i));
+ return E_OK;
+
+ case e_FM_PCD_CC_STATS_MODE_FRAME:
+ case e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME:
+ *p_NumOfRanges = 1;
+ *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE;
+ return E_OK;
+
+#if (DPAA_VERSION >= 11)
+ case e_FM_PCD_CC_STATS_MODE_RMON:
+ {
+ uint16_t *p_FrameLengthRanges =
+ p_CcNodeParam->keysParams.frameLengthRanges;
+ uint32_t i;
+
+ if (p_FrameLengthRanges[0] <= 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode"));
+
+ if (p_FrameLengthRanges[0] == 0xFFFF)
+ {
+ *p_NumOfRanges = 1;
+ *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE;
+ return E_OK;
+ }
+
+ for (i = 1; i < FM_PCD_CC_STATS_MAX_NUM_OF_FLR; i++)
+ {
+ if (p_FrameLengthRanges[i - 1] >= p_FrameLengthRanges[i])
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Frame length range must be larger at least by 1 from preceding range"));
+
+ /* Stop when last range is reached */
+ if (p_FrameLengthRanges[i] == 0xFFFF)
+ break;
+ }
+
+ if ((i >= FM_PCD_CC_STATS_MAX_NUM_OF_FLR)
+ || (p_FrameLengthRanges[i] != 0xFFFF))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Last Frame length range must be 0xFFFF"));
+
+ *p_NumOfRanges = i + 1;
+
+ /* Allocate an extra counter for byte count, as counters
+ array always begins with byte count */
+ *p_CountersArraySize = (*p_NumOfRanges + 1)
+ * FM_PCD_CC_STATS_COUNTER_SIZE;
+
+ }
+ return E_OK;
+#endif /* (DPAA_VERSION >= 11) */
+
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode"));
+ }
+}
+
+static t_Error CheckParams(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam,
+ t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc)
+{
+ int tmp = 0;
+ t_FmPcdCcKeyParams *p_KeyParams;
+ t_Error err;
+ uint32_t requiredAction = 0;
+
+ /* Validate statistics parameters */
+ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
+ &(p_CcNode->numOfStatsFLRs),
+ &(p_CcNode->countersArraySize));
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
+
+ /* Validate next engine parameters on Miss */
+ err = ValidateNextEngineParams(
+ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ p_CcNode->statisticsMode);
+ if (err)
+ RETURN_ERROR(MAJOR, err,
+ ("For this node MissNextEngineParams are not valid"));
+
+ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams,
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction =
+ requiredAction;
+
+ if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
+ {
+ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
+
+ if (!p_KeyParams->p_Key)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_Key is not initialized"));
+
+ err = ValidateNextEngineParams(h_FmPcd,
+ &p_KeyParams->ccNextEngineParams,
+ p_CcNode->statisticsMode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ err = UpdateGblMask(p_CcNode, p_CcNodeParam->keysParams.keySize,
+ p_KeyParams->p_Mask);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ if (p_KeyParams->ccNextEngineParams.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_KeyParams->ccNextEngineParams, &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ /* Store 'key' parameters - key, mask (if passed by the user) */
+ memcpy(p_CcNode->keyAndNextEngineParams[tmp].key, p_KeyParams->p_Key,
+ p_CcNodeParam->keysParams.keySize);
+
+ if (p_KeyParams->p_Mask)
+ memcpy(p_CcNode->keyAndNextEngineParams[tmp].mask,
+ p_KeyParams->p_Mask, p_CcNodeParam->keysParams.keySize);
+ else
+ memset((void *)(p_CcNode->keyAndNextEngineParams[tmp].mask), 0xFF,
+ p_CcNodeParam->keysParams.keySize);
+
+ /* Store next engine parameters */
+ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
+ &p_KeyParams->ccNextEngineParams,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction;
+
+ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+ }
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (p_CcNode->maxNumOfKeys < p_CcNode->numOfKeys)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Number of keys exceed the provided maximal number of keys"));
+ }
+
+ *isKeyTblAlloc = TRUE;
+
+ return E_OK;
+}
+
+static t_Error Ipv4TtlOrIpv6HopLimitCheckParams(
+ t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam,
+ t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc)
+{
+ int tmp = 0;
+ t_FmPcdCcKeyParams *p_KeyParams;
+ t_Error err;
+ uint8_t key = 0x01;
+ uint32_t requiredAction = 0;
+
+ if (p_CcNode->numOfKeys != 1)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'numOfKeys' is 1"));
+
+ if ((p_CcNodeParam->keysParams.maxNumOfKeys)
+ && (p_CcNodeParam->keysParams.maxNumOfKeys != 1))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'maxNumOfKeys' is 1"));
+
+ /* Validate statistics parameters */
+ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
+ &(p_CcNode->numOfStatsFLRs),
+ &(p_CcNode->countersArraySize));
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
+
+ err = ValidateNextEngineParams(
+ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ p_CcNodeParam->keysParams.statisticsMode);
+ if (err)
+ RETURN_ERROR(MAJOR, err,
+ ("For this node MissNextEngineParams are not valid"));
+
+ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams,
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction =
+ requiredAction;
+
+ if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
+ {
+ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
+
+ if (p_KeyParams->p_Mask)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Mask can not be initialized"));
+
+ if (memcmp(p_KeyParams->p_Key, &key, 1) != 0)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Key has to be 1"));
+
+ err = ValidateNextEngineParams(h_FmPcd,
+ &p_KeyParams->ccNextEngineParams,
+ p_CcNode->statisticsMode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+
+ if (p_KeyParams->ccNextEngineParams.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_KeyParams->ccNextEngineParams, &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+
+ /* Store 'key' parameters - key (fixed to 0x01), key size of 1 byte and full mask */
+ p_CcNode->keyAndNextEngineParams[tmp].key[0] = key;
+ p_CcNode->keyAndNextEngineParams[tmp].mask[0] = 0xFF;
+
+ /* Store NextEngine parameters */
+ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
+ &p_KeyParams->ccNextEngineParams,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+ p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction;
+ }
+
+ *isKeyTblAlloc = FALSE;
+
+ return E_OK;
+}
+
+static t_Error IcHashIndexedCheckParams(t_Handle h_FmPcd,
+ t_FmPcdCcNodeParams *p_CcNodeParam,
+ t_FmPcdCcNode *p_CcNode,
+ bool *isKeyTblAlloc)
+{
+ int tmp = 0, countOnes = 0;
+ t_FmPcdCcKeyParams *p_KeyParams;
+ t_Error err;
+ uint16_t glblMask = p_CcNodeParam->extractCcParams.extractNonHdr.icIndxMask;
+ uint16_t countMask = (uint16_t)(glblMask >> 4);
+ uint32_t requiredAction = 0;
+
+ if (glblMask & 0x000f)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("icIndxMask has to be with last nibble 0"));
+
+ while (countMask)
+ {
+ countOnes++;
+ countMask = (uint16_t)(countMask >> 1);
+ }
+
+ if (!POWER_OF_2(p_CcNode->numOfKeys))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For Node of the type INDEXED numOfKeys has to be powerOfTwo"));
+
+ if (p_CcNode->numOfKeys != ((uint32_t)1 << countOnes))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For Node of the type IC_HASH_INDEXED numOfKeys has to be powerOfTwo"));
+
+ if (p_CcNodeParam->keysParams.maxNumOfKeys
+ && (p_CcNodeParam->keysParams.maxNumOfKeys != p_CcNode->numOfKeys))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For Node of the type INDEXED 'maxNumOfKeys' should be 0 or equal 'numOfKeys'"));
+
+ /* Validate statistics parameters */
+ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam,
+ &(p_CcNode->numOfStatsFLRs),
+ &(p_CcNode->countersArraySize));
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters"));
+
+ err = ValidateNextEngineParams(
+ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ p_CcNode->statisticsMode);
+ if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED)
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("MissNextEngineParams for the node of the type IC_INDEX_HASH has to be UnInitialized"));
+
+ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
+ {
+ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
+
+ if (p_KeyParams->p_Mask || p_KeyParams->p_Key)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For Node of the type IC_HASH_INDEXED p_Key or p_Mask has to be NULL"));
+
+ if ((glblMask & (tmp * 16)) == (tmp * 16))
+ {
+ err = ValidateNextEngineParams(h_FmPcd,
+ &p_KeyParams->ccNextEngineParams,
+ p_CcNode->statisticsMode);
+ if (err)
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("This index has to be initialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask "));
+
+ if (p_KeyParams->ccNextEngineParams.h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_KeyParams->ccNextEngineParams, &requiredAction);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ p_CcNode->keyAndNextEngineParams[tmp].requiredAction =
+ requiredAction;
+ }
+
+ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams,
+ &p_KeyParams->ccNextEngineParams,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ RETURN_ERROR(MAJOR, err, (NO_MSG));
+ }
+ }
+ else
+ {
+ err = ValidateNextEngineParams(h_FmPcd,
+ &p_KeyParams->ccNextEngineParams,
+ p_CcNode->statisticsMode);
+ if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED)
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("This index has to be UnInitialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask"));
+ }
+ }
+
+ *isKeyTblAlloc = FALSE;
+ cpu_to_be16s(&glblMask);
+ memcpy(PTR_MOVE(p_CcNode->p_GlblMask, 2), &glblMask, 2);
+
+ return E_OK;
+}
+
+static t_Error ModifyNextEngineParamNode(
+ t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("keyIndex > previously cleared last index + 1"));
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_CHANGE, FALSE,
+ FALSE, FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys
+ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcNextEngineParams,
+ &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams);
+ if (err)
+ {
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, FALSE);
+
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+static t_Error FindKeyIndex(t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key,
+ uint8_t *p_Mask, uint16_t *p_KeyIndex)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint8_t tmpMask[FM_PCD_MAX_SIZE_OF_KEY];
+ uint16_t i;
+
+ ASSERT_COND(p_Key);
+ ASSERT_COND(p_KeyIndex);
+ ASSERT_COND(keySize < FM_PCD_MAX_SIZE_OF_KEY);
+
+ if (keySize != p_CcNode->userSizeOfExtraction)
+ RETURN_ERROR(
+ MINOR, E_INVALID_VALUE,
+ ("Key size doesn't match the extraction size of the node"));
+
+ /* If user didn't pass a mask for this key, we'll look for full extraction mask */
+ if (!p_Mask)
+ memset(tmpMask, 0xFF, keySize);
+
+ for (i = 0; i < p_CcNode->numOfKeys; i++)
+ {
+ /* Comparing received key */
+ if (memcmp(p_Key, p_CcNode->keyAndNextEngineParams[i].key, keySize)
+ == 0)
+ {
+ if (p_Mask)
+ {
+ /* If a user passed a mask for this key, it must match to the existing key's mask for a correct match */
+ if (memcmp(p_Mask, p_CcNode->keyAndNextEngineParams[i].mask,
+ keySize) == 0)
+ {
+ *p_KeyIndex = i;
+ return E_OK;
+ }
+ }
+ else
+ {
+ /* If user didn't pass a mask for this key, check if the existing key mask is full extraction */
+ if (memcmp(tmpMask, p_CcNode->keyAndNextEngineParams[i].mask,
+ keySize) == 0)
+ {
+ *p_KeyIndex = i;
+ return E_OK;
+ }
+ }
+ }
+ }
+
+ return ERROR_CODE(E_NOT_FOUND);
+}
+
+static t_Error CalcAndUpdateCcShadow(t_FmPcdCcNode *p_CcNode,
+ bool isKeyTblAlloc,
+ uint32_t *p_MatchTableSize,
+ uint32_t *p_AdTableSize)
+{
+ uint32_t shadowSize;
+ t_Error err;
+
+ /* Calculate keys table maximal size - each entry consists of a key and a mask,
+ (if local mask support is requested) */
+ *p_MatchTableSize = p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)
+ * p_CcNode->maxNumOfKeys;
+
+ if (p_CcNode->maskSupport)
+ *p_MatchTableSize *= 2;
+
+ /* Calculate next action descriptors table, including one more entry for miss */
+ *p_AdTableSize = (uint32_t)((p_CcNode->maxNumOfKeys + 1)
+ * FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Calculate maximal shadow size of this node.
+ All shadow structures will be used for runtime modifications host command. If
+ keys table was allocated for this node, the keys table and next engines table may
+ be modified in run time (entries added or removed), so shadow tables are requires.
+ Otherwise, the only supported runtime modification is a specific next engine update
+ and this requires shadow memory of a single AD */
+
+ /* Shadow size should be enough to hold the following 3 structures:
+ * 1 - an action descriptor */
+ shadowSize = FM_PCD_CC_AD_ENTRY_SIZE;
+
+ /* 2 - keys match table, if was allocated for the current node */
+ if (isKeyTblAlloc)
+ shadowSize += *p_MatchTableSize;
+
+ /* 3 - next action descriptors table */
+ shadowSize += *p_AdTableSize;
+
+ /* Update shadow to the calculated size */
+ err = FmPcdUpdateCcShadow(p_CcNode->h_FmPcd, (uint32_t)shadowSize,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (err != E_OK)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node shadow"));
+ }
+
+ return E_OK;
+}
+
+static t_Error AllocStatsObjs(t_FmPcdCcNode *p_CcNode)
+{
+ t_FmPcdStatsObj *p_StatsObj;
+ t_Handle h_FmMuram, h_StatsAd, h_StatsCounters;
+ uint32_t i;
+
+ h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd);
+ if (!h_FmMuram)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM"));
+
+ /* Allocate statistics ADs and statistics counter. An extra pair (AD + counters)
+ will be allocated to support runtime modifications */
+ for (i = 0; i < p_CcNode->maxNumOfKeys + 2; i++)
+ {
+ /* Allocate list object structure */
+ p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj));
+ if (!p_StatsObj)
+ {
+ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Statistics object"));
+ }
+ memset(p_StatsObj, 0, sizeof(t_FmPcdStatsObj));
+
+ /* Allocate statistics AD from MURAM */
+ h_StatsAd = (t_Handle)FM_MURAM_AllocMem(h_FmMuram,
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!h_StatsAd)
+ {
+ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
+ XX_Free(p_StatsObj);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for statistics ADs"));
+ }
+ MemSet8(h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Allocate statistics counters from MURAM */
+ h_StatsCounters = (t_Handle)FM_MURAM_AllocMem(
+ h_FmMuram, p_CcNode->countersArraySize,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!h_StatsCounters)
+ {
+ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram);
+ FM_MURAM_FreeMem(h_FmMuram, h_StatsAd);
+ XX_Free(p_StatsObj);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for statistics counters"));
+ }
+ MemSet8(h_StatsCounters, 0, p_CcNode->countersArraySize);
+
+ p_StatsObj->h_StatsAd = h_StatsAd;
+ p_StatsObj->h_StatsCounters = h_StatsCounters;
+
+ EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj);
+ }
+
+ return E_OK;
+}
+
+static t_Error MatchTableGetKeyStatistics(
+ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics)
+{
+ uint32_t *p_StatsCounters, i;
+
+ if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Statistics were not enabled for this match table"));
+
+ if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Statistics were not enabled for this key"));
+
+ memset(p_KeyStatistics, 0, sizeof(t_FmPcdCcKeyStatistics));
+
+ p_StatsCounters =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters;
+ ASSERT_COND(p_StatsCounters);
+
+ p_KeyStatistics->byteCount = GET_UINT32(*p_StatsCounters);
+
+ for (i = 1; i <= p_CcNode->numOfStatsFLRs; i++)
+ {
+ p_StatsCounters =
+ PTR_MOVE(p_StatsCounters, FM_PCD_CC_STATS_COUNTER_SIZE);
+
+ p_KeyStatistics->frameCount += GET_UINT32(*p_StatsCounters);
+
+#if (DPAA_VERSION >= 11)
+ p_KeyStatistics->frameLengthRangeCount[i - 1] =
+ GET_UINT32(*p_StatsCounters);
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ return E_OK;
+}
+
+static t_Error MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode,
+ t_FmPcdCcNodeParams *p_CcNodeParam)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdCcNode *p_FmPcdCcNextNode;
+ t_Error err = E_OK;
+ uint32_t tmp, keySize;
+ bool glblMask = FALSE;
+ t_FmPcdCcKeyParams *p_KeyParams;
+ t_Handle h_FmMuram, p_KeysMatchTblTmp, p_AdTableTmp;
+#if (DPAA_VERSION >= 11)
+ t_Handle h_StatsFLRs;
+#endif /* (DPAA_VERSION >= 11) */
+ bool fullField = FALSE;
+ ccPrivateInfo_t icCode = CC_PRIVATE_INFO_NONE;
+ bool isKeyTblAlloc, fromIc = FALSE;
+ uint32_t matchTableSize, adTableSize;
+ t_CcNodeInformation ccNodeInfo, *p_CcInformation;
+ t_FmPcdStatsObj *p_StatsObj;
+ t_FmPcdCcStatsParams statsParams = { 0 };
+ t_Handle h_Manip;
+
+ ASSERT_COND(h_FmPcd);
+ ASSERT_COND(p_CcNode);
+ ASSERT_COND(p_CcNodeParam);
+
+ p_CcNode->p_GlblMask = (t_Handle)XX_Malloc(
+ CC_GLBL_MASK_SIZE * sizeof(uint8_t));
+ memset(p_CcNode->p_GlblMask, 0, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
+
+ p_CcNode->h_FmPcd = h_FmPcd;
+ p_CcNode->numOfKeys = p_CcNodeParam->keysParams.numOfKeys;
+ p_CcNode->maxNumOfKeys = p_CcNodeParam->keysParams.maxNumOfKeys;
+ p_CcNode->maskSupport = p_CcNodeParam->keysParams.maskSupport;
+ p_CcNode->statisticsMode = p_CcNodeParam->keysParams.statisticsMode;
+
+ /* For backward compatibility - even if statistics mode is nullified,
+ we'll fix it to frame mode so we can support per-key request for
+ statistics using 'statisticsEn' in next engine parameters */
+ if (!p_CcNode->maxNumOfKeys
+ && (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE))
+ p_CcNode->statisticsMode = e_FM_PCD_CC_STATS_MODE_FRAME;
+
+ h_FmMuram = FmPcdGetMuramHandle(h_FmPcd);
+ if (!h_FmMuram)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM"));
+
+ INIT_LIST(&p_CcNode->ccPrevNodesLst);
+ INIT_LIST(&p_CcNode->ccTreeIdLst);
+ INIT_LIST(&p_CcNode->ccTreesLst);
+ INIT_LIST(&p_CcNode->availableStatsLst);
+
+ p_CcNode->h_Spinlock = XX_InitSpinlock();
+ if (!p_CcNode->h_Spinlock)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC node spinlock"));
+ }
+
+ if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_BY_HDR)
+ && ((p_CcNodeParam->extractCcParams.extractByHdr.hdr
+ == HEADER_TYPE_IPv4)
+ || (p_CcNodeParam->extractCcParams.extractByHdr.hdr
+ == HEADER_TYPE_IPv6))
+ && (p_CcNodeParam->extractCcParams.extractByHdr.type
+ == e_FM_PCD_EXTRACT_FULL_FIELD)
+ && ((p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv6
+ == NET_HEADER_FIELD_IPv6_HOP_LIMIT)
+ || (p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv4
+ == NET_HEADER_FIELD_IPv4_TTL)))
+ {
+ err = Ipv4TtlOrIpv6HopLimitCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
+ &isKeyTblAlloc);
+ glblMask = FALSE;
+ }
+ else
+ if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_NON_HDR)
+ && ((p_CcNodeParam->extractCcParams.extractNonHdr.src
+ == e_FM_PCD_EXTRACT_FROM_KEY)
+ || (p_CcNodeParam->extractCcParams.extractNonHdr.src
+ == e_FM_PCD_EXTRACT_FROM_HASH)
+ || (p_CcNodeParam->extractCcParams.extractNonHdr.src
+ == e_FM_PCD_EXTRACT_FROM_FLOW_ID)))
+ {
+ if ((p_CcNodeParam->extractCcParams.extractNonHdr.src
+ == e_FM_PCD_EXTRACT_FROM_FLOW_ID)
+ && (p_CcNodeParam->extractCcParams.extractNonHdr.offset != 0))
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("In the case of the extraction from e_FM_PCD_EXTRACT_FROM_FLOW_ID offset has to be 0"));
+ }
+
+ icCode = IcDefineCode(p_CcNodeParam);
+ fromIc = TRUE;
+ if (icCode == CC_PRIVATE_INFO_NONE)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("user asked extraction from IC and field in internal context or action wasn't initialized in the right way"));
+ }
+
+ if ((icCode == CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP)
+ || (icCode == CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP))
+ {
+ err = IcHashIndexedCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
+ &isKeyTblAlloc);
+ glblMask = TRUE;
+ }
+ else
+ {
+ err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode,
+ &isKeyTblAlloc);
+ if (p_CcNode->glblMaskSize)
+ glblMask = TRUE;
+ }
+ }
+ else
+ {
+ err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, &isKeyTblAlloc);
+ if (p_CcNode->glblMaskSize)
+ glblMask = TRUE;
+ }
+
+ if (err)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ switch (p_CcNodeParam->extractCcParams.type)
+ {
+ case (e_FM_PCD_EXTRACT_BY_HDR):
+ switch (p_CcNodeParam->extractCcParams.extractByHdr.type)
+ {
+ case (e_FM_PCD_EXTRACT_FULL_FIELD):
+ p_CcNode->parseCode =
+ GetFullFieldParseCode(
+ p_CcNodeParam->extractCcParams.extractByHdr.hdr,
+ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex,
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField);
+ GetSizeHeaderField(
+ p_CcNodeParam->extractCcParams.extractByHdr.hdr,
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField,
+ &p_CcNode->sizeOfExtraction);
+ fullField = TRUE;
+ if ((p_CcNode->parseCode != CC_PC_FF_TCI1)
+ && (p_CcNode->parseCode != CC_PC_FF_TCI2)
+ && (p_CcNode->parseCode != CC_PC_FF_MPLS1)
+ && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST)
+ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1)
+ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2)
+ && (p_CcNode->parseCode
+ != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1)
+ && (p_CcNode->parseCode != CC_PC_FF_IPDSCP)
+ && (p_CcNode->parseCode
+ != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2)
+ && glblMask)
+ {
+ glblMask = FALSE;
+ p_CcNode->glblMaskSize = 4;
+ p_CcNode->lclMask = TRUE;
+ }
+ break;
+
+ case (e_FM_PCD_EXTRACT_FROM_HDR):
+ p_CcNode->sizeOfExtraction =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.size;
+ p_CcNode->offset =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset;
+ p_CcNode->userOffset =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset;
+ p_CcNode->parseCode =
+ GetPrParseCode(
+ p_CcNodeParam->extractCcParams.extractByHdr.hdr,
+ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex,
+ p_CcNode->offset, glblMask,
+ &p_CcNode->prsArrayOffset);
+ break;
+
+ case (e_FM_PCD_EXTRACT_FROM_FIELD):
+ p_CcNode->offset =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset;
+ p_CcNode->userOffset =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset;
+ p_CcNode->sizeOfExtraction =
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.size;
+ p_CcNode->parseCode =
+ GetFieldParseCode(
+ p_CcNodeParam->extractCcParams.extractByHdr.hdr,
+ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.field,
+ p_CcNode->offset,
+ &p_CcNode->prsArrayOffset,
+ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex);
+ break;
+
+ default:
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+
+ case (e_FM_PCD_EXTRACT_NON_HDR):
+ /* get the field code for the generic extract */
+ p_CcNode->sizeOfExtraction =
+ p_CcNodeParam->extractCcParams.extractNonHdr.size;
+ p_CcNode->offset =
+ p_CcNodeParam->extractCcParams.extractNonHdr.offset;
+ p_CcNode->userOffset =
+ p_CcNodeParam->extractCcParams.extractNonHdr.offset;
+ p_CcNode->parseCode = GetGenParseCode(
+ p_CcNodeParam->extractCcParams.extractNonHdr.src,
+ p_CcNode->offset, glblMask, &p_CcNode->prsArrayOffset,
+ fromIc, icCode);
+
+ if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)
+ {
+ if ((p_CcNode->offset + p_CcNode->sizeOfExtraction) > 8)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_SELECTION,
+ ("when node of the type CC_PC_GENERIC_IC_HASH_INDEXED offset + size can not be bigger then size of HASH 64 bits (8 bytes)"));
+ }
+ }
+ if ((p_CcNode->parseCode == CC_PC_GENERIC_IC_GMASK)
+ || (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED))
+ {
+ p_CcNode->offset += p_CcNode->prsArrayOffset;
+ p_CcNode->prsArrayOffset = 0;
+ }
+ break;
+
+ default:
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ if (p_CcNode->parseCode == CC_PC_ILLEGAL)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("illegal extraction type"));
+ }
+
+ if ((p_CcNode->sizeOfExtraction > FM_PCD_MAX_SIZE_OF_KEY)
+ || !p_CcNode->sizeOfExtraction)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("sizeOfExatrction can not be greater than 56 and not 0"));
+ }
+
+ if (p_CcNodeParam->keysParams.keySize != p_CcNode->sizeOfExtraction)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("keySize has to be equal to sizeOfExtraction"));
+ }
+
+ p_CcNode->userSizeOfExtraction = p_CcNode->sizeOfExtraction;
+
+ if (!glblMask)
+ memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t));
+
+ err = CheckAndSetManipParamsWithCcNodeParams(p_CcNode);
+ if (err != E_OK)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("keySize has to be equal to sizeOfExtraction"));
+ }
+
+ /* Calculating matching table entry size by rounding up the user-defined size of extraction to valid entry size */
+ GetCcExtractKeySize(p_CcNode->sizeOfExtraction,
+ &p_CcNode->ccKeySizeAccExtraction);
+
+ /* If local mask is used, it is stored next to each key in the keys match table */
+ if (p_CcNode->lclMask)
+ keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction);
+ else
+ keySize = p_CcNode->ccKeySizeAccExtraction;
+
+ /* Update CC shadow with maximal size required by this node */
+ if (p_CcNode->maxNumOfKeys)
+ {
+ err = CalcAndUpdateCcShadow(p_CcNode, isKeyTblAlloc, &matchTableSize,
+ &adTableSize);
+ if (err != E_OK)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ p_CcNode->keysMatchTableMaxSize = matchTableSize;
+
+ if (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE)
+ {
+ err = AllocStatsObjs(p_CcNode);
+ if (err != E_OK)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ /* If manipulation will be initialized before this node, it will use the table
+ descriptor in the AD table of previous node and this node will need an extra
+ AD as his table descriptor. */
+ p_CcNode->h_TmpAd = (t_Handle)FM_MURAM_AllocMem(
+ h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_CcNode->h_TmpAd)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC action descriptor"));
+ }
+ }
+ else
+ {
+ matchTableSize = (uint32_t)(keySize * sizeof(uint8_t)
+ * (p_CcNode->numOfKeys + 1));
+ adTableSize = (uint32_t)(FM_PCD_CC_AD_ENTRY_SIZE
+ * (p_CcNode->numOfKeys + 1));
+ }
+
+#if (DPAA_VERSION >= 11)
+ switch (p_CcNode->statisticsMode)
+ {
+
+ case e_FM_PCD_CC_STATS_MODE_RMON:
+ /* If RMON statistics or RMON conditional statistics modes are requested,
+ allocate frame length ranges array */
+ p_CcNode->h_StatsFLRs = FM_MURAM_AllocMem(
+ h_FmMuram,
+ (uint32_t)(p_CcNode->numOfStatsFLRs)
+ * FM_PCD_CC_STATS_FLR_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+
+ if (!p_CcNode->h_StatsFLRs)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(
+ MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC frame length ranges array"));
+ }
+
+ /* Initialize using value received from the user */
+ for (tmp = 0; tmp < p_CcNode->numOfStatsFLRs; tmp++)
+ {
+ uint16_t flr =
+ cpu_to_be16(p_CcNodeParam->keysParams.frameLengthRanges[tmp]);
+
+ h_StatsFLRs =
+ PTR_MOVE(p_CcNode->h_StatsFLRs, tmp * FM_PCD_CC_STATS_FLR_SIZE);
+
+ MemCpy8(h_StatsFLRs,
+ &flr,
+ FM_PCD_CC_STATS_FLR_SIZE);
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Allocate keys match table. Not required for some CC nodes, for example for IPv4 TTL
+ identification, IPv6 hop count identification, etc. */
+ if (isKeyTblAlloc)
+ {
+ p_CcNode->h_KeysMatchTable = (t_Handle)FM_MURAM_AllocMem(
+ h_FmMuram, matchTableSize, FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN);
+ if (!p_CcNode->h_KeysMatchTable)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC node key match table"));
+ }
+ MemSet8((uint8_t *)p_CcNode->h_KeysMatchTable, 0, matchTableSize);
+ }
+
+ /* Allocate action descriptors table */
+ p_CcNode->h_AdTable = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, adTableSize,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_CcNode->h_AdTable)
+ {
+ DeleteNode(p_CcNode);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC node action descriptors table"));
+ }
+ MemSet8((uint8_t *)p_CcNode->h_AdTable, 0, adTableSize);
+
+ p_KeysMatchTblTmp = p_CcNode->h_KeysMatchTable;
+ p_AdTableTmp = p_CcNode->h_AdTable;
+
+ /* For each key, create the key and the next step AD */
+ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++)
+ {
+ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp];
+
+ if (p_KeysMatchTblTmp)
+ {
+ /* Copy the key */
+ MemCpy8((void*)p_KeysMatchTblTmp, p_KeyParams->p_Key,
+ p_CcNode->sizeOfExtraction);
+
+ /* Copy the key mask or initialize it to 0xFF..F */
+ if (p_CcNode->lclMask && p_KeyParams->p_Mask)
+ {
+ MemCpy8(PTR_MOVE(p_KeysMatchTblTmp,
+ p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */
+ p_KeyParams->p_Mask, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */
+ }
+ else
+ if (p_CcNode->lclMask)
+ {
+ MemSet8(PTR_MOVE(p_KeysMatchTblTmp,
+ p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */
+ 0xff, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */
+ }
+
+ p_KeysMatchTblTmp =
+ PTR_MOVE(p_KeysMatchTblTmp, keySize * sizeof(uint8_t));
+ }
+
+ /* Create the next action descriptor in the match table */
+ if (p_KeyParams->ccNextEngineParams.statisticsEn)
+ {
+ p_StatsObj = GetStatsObj(p_CcNode);
+ ASSERT_COND(p_StatsObj);
+
+ statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
+ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
+#if (DPAA_VERSION >= 11)
+ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
+
+#endif /* (DPAA_VERSION >= 11) */
+ NextStepAd(p_AdTableTmp, &statsParams,
+ &p_KeyParams->ccNextEngineParams, p_FmPcd);
+
+ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj;
+ }
+ else
+ {
+ NextStepAd(p_AdTableTmp, NULL, &p_KeyParams->ccNextEngineParams,
+ p_FmPcd);
+
+ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL;
+ }
+
+ p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+ }
+
+ /* Update next engine for the 'miss' entry */
+ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.statisticsEn)
+ {
+ p_StatsObj = GetStatsObj(p_CcNode);
+ ASSERT_COND(p_StatsObj);
+
+ /* All 'bucket' nodes of a hash table should share the same statistics counters,
+ allocated by the hash table. So, if this node is a bucket of a hash table,
+ we'll replace the locally allocated counters with the shared counters. */
+ if (p_CcNode->isHashBucket)
+ {
+ ASSERT_COND(p_CcNode->h_MissStatsCounters);
+
+ /* Store original counters pointer and replace it with mutual preallocated pointer */
+ p_CcNode->h_PrivMissStatsCounters = p_StatsObj->h_StatsCounters;
+ p_StatsObj->h_StatsCounters = p_CcNode->h_MissStatsCounters;
+ }
+
+ statsParams.h_StatsAd = p_StatsObj->h_StatsAd;
+ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters;
+#if (DPAA_VERSION >= 11)
+ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs;
+
+#endif /* (DPAA_VERSION >= 11) */
+
+ NextStepAd(p_AdTableTmp, &statsParams,
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ p_FmPcd);
+
+ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj;
+ }
+ else
+ {
+ NextStepAd(p_AdTableTmp, NULL,
+ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss,
+ p_FmPcd);
+
+ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL;
+ }
+
+ /* This parameter will be used to initialize the "key length" field in the action descriptor
+ that points to this node and it should be 0 for full field extraction */
+ if (fullField == TRUE)
+ p_CcNode->sizeOfExtraction = 0;
+
+ for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++)
+ {
+ if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ p_FmPcdCcNextNode =
+ (t_FmPcdCcNode*)p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode;
+ p_CcInformation = FindNodeInfoInReleventLst(
+ &p_FmPcdCcNextNode->ccPrevNodesLst, (t_Handle)p_CcNode,
+ p_FmPcdCcNextNode->h_Spinlock);
+ if (!p_CcInformation)
+ {
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = (t_Handle)p_CcNode;
+ ccNodeInfo.index = 1;
+ EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccPrevNodesLst,
+ &ccNodeInfo,
+ p_FmPcdCcNextNode->h_Spinlock);
+ }
+ else
+ p_CcInformation->index++;
+
+ if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip)
+ {
+ h_Manip =
+ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip;
+ p_CcInformation = FindNodeInfoInReleventLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(h_Manip),
+ (t_Handle)p_CcNode, FmPcdManipGetSpinlock(h_Manip));
+ if (!p_CcInformation)
+ {
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = (t_Handle)p_CcNode;
+ ccNodeInfo.index = 1;
+ EnqueueNodeInfoToRelevantLst(
+ FmPcdManipGetNodeLstPointedOnThisManip(h_Manip),
+ &ccNodeInfo, FmPcdManipGetSpinlock(h_Manip));
+ }
+ else
+ p_CcInformation->index++;
+ }
+ }
+ }
+
+ p_AdTableTmp = p_CcNode->h_AdTable;
+
+ if (!FmPcdLockTryLockAll(h_FmPcd))
+ {
+ FM_PCD_MatchTableDelete((t_Handle)p_CcNode);
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ /* Required action for each next engine */
+ for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++)
+ {
+ if (p_CcNode->keyAndNextEngineParams[tmp].requiredAction)
+ {
+ err = SetRequiredAction(
+ h_FmPcd,
+ p_CcNode->keyAndNextEngineParams[tmp].requiredAction,
+ &p_CcNode->keyAndNextEngineParams[tmp], p_AdTableTmp, 1,
+ NULL);
+ if (err)
+ {
+ FmPcdLockUnlockAll(h_FmPcd);
+ FM_PCD_MatchTableDelete((t_Handle)p_CcNode);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+ }
+ }
+
+ FmPcdLockUnlockAll(h_FmPcd);
+
+ return E_OK;
+}
+/************************** End of static functions **************************/
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info,
+ t_Handle h_Spinlock)
+{
+ t_CcNodeInformation *p_CcInformation;
+ t_List *p_Pos;
+ uint32_t intFlags;
+
+ intFlags = XX_LockIntrSpinlock(h_Spinlock);
+
+ for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List);
+ p_Pos = LIST_NEXT(p_Pos))
+ {
+ p_CcInformation = CC_NODE_F_OBJECT(p_Pos);
+
+ ASSERT_COND(p_CcInformation->h_CcNode);
+
+ if (p_CcInformation->h_CcNode == h_Info)
+ {
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+ return p_CcInformation;
+ }
+ }
+
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+
+ return NULL;
+}
+
+void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo,
+ t_Handle h_Spinlock)
+{
+ t_CcNodeInformation *p_CcInformation;
+ uint32_t intFlags = 0;
+
+ p_CcInformation = (t_CcNodeInformation *)XX_Malloc(
+ sizeof(t_CcNodeInformation));
+
+ if (p_CcInformation)
+ {
+ memset(p_CcInformation, 0, sizeof(t_CcNodeInformation));
+ memcpy(p_CcInformation, p_CcInfo, sizeof(t_CcNodeInformation));
+ INIT_LIST(&p_CcInformation->node);
+
+ if (h_Spinlock)
+ intFlags = XX_LockIntrSpinlock(h_Spinlock);
+
+ LIST_AddToTail(&p_CcInformation->node, p_List);
+
+ if (h_Spinlock)
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+ }
+ else
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Node Information"));
+}
+
+void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info,
+ t_Handle h_Spinlock)
+{
+ t_CcNodeInformation *p_CcInformation = NULL;
+ uint32_t intFlags = 0;
+ t_List *p_Pos;
+
+ if (h_Spinlock)
+ intFlags = XX_LockIntrSpinlock(h_Spinlock);
+
+ if (LIST_IsEmpty(p_List))
+ {
+ XX_RestoreAllIntr(intFlags);
+ return;
+ }
+
+ for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List);
+ p_Pos = LIST_NEXT(p_Pos))
+ {
+ p_CcInformation = CC_NODE_F_OBJECT(p_Pos);
+ ASSERT_COND(p_CcInformation);
+ ASSERT_COND(p_CcInformation->h_CcNode);
+ if (p_CcInformation->h_CcNode == h_Info)
+ break;
+ }
+
+ if (p_CcInformation)
+ {
+ LIST_DelAndInit(&p_CcInformation->node);
+ XX_Free(p_CcInformation);
+ }
+
+ if (h_Spinlock)
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+}
+
+void NextStepAd(t_Handle h_Ad, t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
+ t_FmPcd *p_FmPcd)
+{
+ switch (p_FmPcdCcNextEngineParams->nextEngine)
+ {
+ case (e_FM_PCD_KG):
+ case (e_FM_PCD_PLCR):
+ case (e_FM_PCD_DONE):
+ /* if NIA is not CC, create a "result" type AD */
+ FillAdOfTypeResult(h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
+ p_FmPcdCcNextEngineParams);
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_FR):
+ if (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)
+ {
+ FillAdOfTypeContLookup(
+ h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
+ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
+ p_FmPcdCcNextEngineParams->h_Manip,
+ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic);
+ FrmReplicGroupUpdateOwner(
+ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic,
+ TRUE/* add */);
+ }
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+
+ case (e_FM_PCD_CC):
+ /* if NIA is not CC, create a TD to continue the CC lookup */
+ FillAdOfTypeContLookup(
+ h_Ad, p_FmPcdCcStatsParams, p_FmPcd,
+ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
+ p_FmPcdCcNextEngineParams->h_Manip, NULL);
+
+ UpdateNodeOwner(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode,
+ TRUE);
+ break;
+
+ default:
+ return;
+ }
+}
+
+t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree,
+ t_Handle h_NetEnv, t_Handle h_IpReassemblyManip,
+ bool createSchemes)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
+ t_FmPcdCcNextEngineParams nextEngineParams;
+ t_NetEnvParams netEnvParams;
+ t_Handle h_Ad;
+ bool isIpv6Present;
+ uint8_t ipv4GroupId, ipv6GroupId;
+ t_Error err;
+
+ ASSERT_COND(p_FmPcdCcTree);
+
+ /* this routine must be protected by the calling routine! */
+
+ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
+ memset(&netEnvParams, 0, sizeof(t_NetEnvParams));
+
+ h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
+
+ isIpv6Present = FmPcdManipIpReassmIsIpv6Hdr(h_IpReassemblyManip);
+
+ if (isIpv6Present
+ && (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR"));
+
+ if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR"));
+
+ nextEngineParams.nextEngine = e_FM_PCD_DONE;
+ nextEngineParams.h_Manip = h_IpReassemblyManip;
+
+ /* Lock tree */
+ err = CcRootTryLock(p_FmPcdCcTree);
+ if (err)
+ return ERROR_CODE(E_BUSY);
+
+ if (p_FmPcdCcTree->h_IpReassemblyManip == h_IpReassemblyManip)
+ {
+ CcRootReleaseLock(p_FmPcdCcTree);
+ return E_OK;
+ }
+
+ if ((p_FmPcdCcTree->h_IpReassemblyManip)
+ && (p_FmPcdCcTree->h_IpReassemblyManip != h_IpReassemblyManip))
+ {
+ CcRootReleaseLock(p_FmPcdCcTree);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("This tree was previously updated with different IPR"));
+ }
+
+ /* Initialize IPR for the first time for this tree */
+ if (isIpv6Present)
+ {
+ ipv6GroupId = p_FmPcdCcTree->numOfGrps++;
+ p_FmPcdCcTree->fmPcdGroupParam[ipv6GroupId].baseGroupEntry =
+ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2);
+
+ if (createSchemes)
+ {
+ err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv,
+ p_FmPcdCcTree,
+ h_IpReassemblyManip, FALSE,
+ ipv6GroupId);
+ if (err)
+ {
+ p_FmPcdCcTree->numOfGrps--;
+ CcRootReleaseLock(p_FmPcdCcTree);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ NextStepAd(
+ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-2) * FM_PCD_CC_AD_ENTRY_SIZE),
+ NULL, &nextEngineParams, h_FmPcd);
+ }
+
+ ipv4GroupId = p_FmPcdCcTree->numOfGrps++;
+ p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].totalBitsMask = 0;
+ p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].baseGroupEntry =
+ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1);
+
+ if (createSchemes)
+ {
+ err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, p_FmPcdCcTree,
+ h_IpReassemblyManip, TRUE,
+ ipv4GroupId);
+ if (err)
+ {
+ p_FmPcdCcTree->numOfGrps--;
+ if (isIpv6Present)
+ {
+ p_FmPcdCcTree->numOfGrps--;
+ FmPcdManipDeleteIpReassmSchemes(h_IpReassemblyManip);
+ }
+ CcRootReleaseLock(p_FmPcdCcTree);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ NextStepAd(
+ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE),
+ NULL, &nextEngineParams, h_FmPcd);
+
+ p_FmPcdCcTree->h_IpReassemblyManip = h_IpReassemblyManip;
+
+ CcRootReleaseLock(p_FmPcdCcTree);
+
+ return E_OK;
+}
+
+t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree,
+ t_Handle h_NetEnv, t_Handle h_ReassemblyManip,
+ bool createSchemes)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
+ t_FmPcdCcNextEngineParams nextEngineParams;
+ t_NetEnvParams netEnvParams;
+ t_Handle h_Ad;
+ uint8_t groupId;
+ t_Error err;
+
+ ASSERT_COND(p_FmPcdCcTree);
+
+ /* this routine must be protected by the calling routine! */
+ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams));
+ memset(&netEnvParams, 0, sizeof(t_NetEnvParams));
+
+ h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
+
+ if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need one free entries for CPR"));
+
+ nextEngineParams.nextEngine = e_FM_PCD_DONE;
+ nextEngineParams.h_Manip = h_ReassemblyManip;
+
+ /* Lock tree */
+ err = CcRootTryLock(p_FmPcdCcTree);
+ if (err)
+ return ERROR_CODE(E_BUSY);
+
+ if (p_FmPcdCcTree->h_CapwapReassemblyManip == h_ReassemblyManip)
+ {
+ CcRootReleaseLock(p_FmPcdCcTree);
+ return E_OK;
+ }
+
+ if ((p_FmPcdCcTree->h_CapwapReassemblyManip)
+ && (p_FmPcdCcTree->h_CapwapReassemblyManip != h_ReassemblyManip))
+ {
+ CcRootReleaseLock(p_FmPcdCcTree);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("This tree was previously updated with different CPR"));
+ }
+
+ groupId = p_FmPcdCcTree->numOfGrps++;
+ p_FmPcdCcTree->fmPcdGroupParam[groupId].baseGroupEntry =
+ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1);
+
+ if (createSchemes)
+ {
+ err = FmPcdManipBuildCapwapReassmScheme(h_FmPcd, h_NetEnv,
+ p_FmPcdCcTree,
+ h_ReassemblyManip, groupId);
+ if (err)
+ {
+ p_FmPcdCcTree->numOfGrps--;
+ CcRootReleaseLock(p_FmPcdCcTree);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ NextStepAd(
+ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE),
+ NULL, &nextEngineParams, h_FmPcd);
+
+ p_FmPcdCcTree->h_CapwapReassemblyManip = h_ReassemblyManip;
+
+ CcRootReleaseLock(p_FmPcdCcTree);
+
+ return E_OK;
+}
+
+t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
+
+ ASSERT_COND(p_FmPcdCcTree);
+
+ return p_FmPcdCcTree->h_FmPcdCcSavedManipParams;
+}
+
+void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree,
+ t_Handle h_SavedManipParams)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree;
+
+ ASSERT_COND(p_FmPcdCcTree);
+
+ p_FmPcdCcTree->h_FmPcdCcSavedManipParams = h_SavedManipParams;
+}
+
+uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+
+ ASSERT_COND(p_CcNode);
+
+ return p_CcNode->parseCode;
+}
+
+uint8_t FmPcdCcGetOffset(t_Handle h_CcNode)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+
+ ASSERT_COND(p_CcNode);
+
+ return p_CcNode->offset;
+}
+
+uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+
+ ASSERT_COND(p_CcNode);
+
+ return p_CcNode->numOfKeys;
+}
+
+t_Error FmPcdCcModifyNextEngineParamTree(
+ t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+ t_FmPcd *p_FmPcd;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ uint16_t keyIndex;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((grpId <= 7), E_INVALID_VALUE);
+
+ if (grpId >= p_FmPcdCcTree->numOfGrps)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
+ ("grpId you asked > numOfGroup of relevant tree"));
+
+ if (index >= p_FmPcdCcTree->fmPcdGroupParam[grpId].numOfEntriesInGroup)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("index > numOfEntriesInGroup"));
+
+ p_FmPcd = (t_FmPcd *)h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ keyIndex = (uint16_t)(p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry
+ + index);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_FmPcdCcTree, keyIndex,
+ e_MODIFY_STATE_CHANGE, FALSE,
+ FALSE, TRUE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ p_ModifyKeyParams->tree = TRUE;
+
+ if (p_FmPcd->p_CcShadow
+ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = BuildNewNodeModifyNextEngine(p_FmPcd, p_FmPcdCcTree, keyIndex,
+ p_FmPcdCcNextEngineParams,
+ &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams);
+ if (err)
+ {
+ XX_Free(p_ModifyKeyParams);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, FALSE);
+
+ if (p_FmPcd->p_CcShadow)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+
+}
+
+t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ uint16_t keyIndex)
+{
+
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ bool useShadowStructs = FALSE;
+ t_Error err = E_OK;
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("impossible to remove key when numOfKeys <= keyIndex"));
+
+ if (p_CcNode->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("handler to FmPcd is different from the handle provided at node initialization time"));
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_REMOVE, TRUE, TRUE,
+ FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ useShadowStructs = TRUE;
+ }
+
+ err = BuildNewNodeRemoveKey(p_CcNode, keyIndex, p_ModifyKeyParams);
+ if (err)
+ {
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
+ &h_OldPointersLst,
+ &h_NewPointersLst);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, useShadowStructs);
+
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key,
+ uint8_t *p_Mask)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ uint16_t tmpKeyIndex;
+ bool useShadowStructs = FALSE;
+ t_Error err = E_OK;
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("keyIndex > previously cleared last index + 1"));
+
+ if (keySize != p_CcNode->userSizeOfExtraction)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("size for ModifyKey has to be the same as defined in SetNode"));
+
+ if (p_CcNode->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("handler to FmPcd is different from the handle provided at node initialization time"));
+
+ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_Key, p_Mask, &tmpKeyIndex);
+ if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
+ RETURN_ERROR(
+ MINOR,
+ E_ALREADY_EXISTS,
+ ("The received key and mask pair was already found in the match table of the provided node"));
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_CHANGE, TRUE, TRUE,
+ FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ useShadowStructs = TRUE;
+ }
+
+ err = BuildNewNodeModifyKey(p_CcNode, keyIndex, p_Key, p_Mask,
+ p_ModifyKeyParams);
+ if (err)
+ {
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
+ &h_OldPointersLst,
+ &h_NewPointersLst);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, useShadowStructs);
+
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+t_Error FmPcdCcModifyMissNextEngineParamNode(
+ t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ uint16_t keyIndex;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_VALUE);
+
+ keyIndex = p_CcNode->numOfKeys;
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_CHANGE, FALSE, TRUE,
+ FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys
+ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcNextEngineParams,
+ &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams);
+ if (err)
+ {
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, FALSE);
+
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ uint16_t keyIndex, uint8_t keySize,
+ t_FmPcdCcKeyParams *p_FmPcdCcKeyParams)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ bool useShadowStructs = FALSE;
+ uint16_t tmpKeyIndex;
+ t_Error err = E_OK;
+
+ if (keyIndex > p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
+ ("keyIndex > previously cleared last index + 1"));
+
+ if (keySize != p_CcNode->userSizeOfExtraction)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("keySize has to be defined as it was defined in initialization step"));
+
+ if (p_CcNode->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("handler to FmPcd is different from the handle provided at node initialization time"));
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (p_CcNode->numOfKeys == p_CcNode->maxNumOfKeys)
+ RETURN_ERROR(
+ MAJOR,
+ E_FULL,
+ ("number of keys exceeds the maximal number of keys provided at node initialization time"));
+ }
+ else
+ if (p_CcNode->numOfKeys == FM_PCD_MAX_NUM_OF_KEYS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("number of keys can not be larger than %d", FM_PCD_MAX_NUM_OF_KEYS));
+
+ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key,
+ p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex);
+ if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
+ RETURN_ERROR(
+ MAJOR,
+ E_ALREADY_EXISTS,
+ ("The received key and mask pair was already found in the match table of the provided node"));
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_ADD, TRUE, TRUE,
+ FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ useShadowStructs = TRUE;
+ }
+
+ err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcKeyParams,
+ p_ModifyKeyParams, TRUE);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
+ &h_OldPointersLst,
+ &h_NewPointersLst);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, useShadowStructs);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ uint16_t keyIndex, uint8_t keySize,
+ t_FmPcdCcKeyParams *p_FmPcdCcKeyParams)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_FmPcd *p_FmPcd;
+ t_List h_OldPointersLst, h_NewPointersLst;
+ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams;
+ uint16_t tmpKeyIndex;
+ bool useShadowStructs = FALSE;
+ t_Error err = E_OK;
+
+ if (keyIndex > p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("keyIndex > previously cleared last index + 1"));
+
+ if (keySize != p_CcNode->userSizeOfExtraction)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("keySize has to be defined as it was defined in initialization step"));
+
+ if (p_CcNode->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("handler to FmPcd is different from the handle provided at node initialization time"));
+
+ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key,
+ p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex);
+ if (GET_ERROR_TYPE(err) != E_NOT_FOUND)
+ RETURN_ERROR(
+ MINOR,
+ E_ALREADY_EXISTS,
+ ("The received key and mask pair was already found in the match table of the provided node"));
+
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+
+ INIT_LIST(&h_OldPointersLst);
+ INIT_LIST(&h_NewPointersLst);
+
+ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex,
+ e_MODIFY_STATE_CHANGE, TRUE, TRUE,
+ FALSE);
+ if (!p_ModifyKeyParams)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_CcNode->maxNumOfKeys)
+ {
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ {
+ XX_Free(p_ModifyKeyParams);
+ return ERROR_CODE(E_BUSY);
+ }
+
+ useShadowStructs = TRUE;
+ }
+
+ err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcKeyParams,
+ p_ModifyKeyParams, FALSE);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams,
+ &h_OldPointersLst,
+ &h_NewPointersLst);
+ if (err)
+ {
+ ReleaseNewNodeCommonPart(p_ModifyKeyParams);
+ XX_Free(p_ModifyKeyParams);
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst,
+ p_ModifyKeyParams, useShadowStructs);
+
+ if (p_CcNode->maxNumOfKeys)
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ ReleaseLst(&h_OldPointersLst);
+ ReleaseLst(&h_NewPointersLst);
+
+ return err;
+}
+
+uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd,
+ t_Handle h_Pointer)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_CcNodeInformation *p_CcNodeInfo;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE,
+ (uint32_t)ILLEGAL_BASE);
+
+ p_CcNodeInfo = CC_NODE_F_OBJECT(h_Pointer);
+
+ return (uint32_t)(XX_VirtToPhys(p_CcNodeInfo->h_CcNode)
+ - p_FmPcd->physicalMuramBase);
+}
+
+t_Error FmPcdCcGetGrpParams(t_Handle h_FmPcdCcTree, uint8_t grpId,
+ uint32_t *p_GrpBits, uint8_t *p_GrpBase)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
+
+ if (grpId >= p_FmPcdCcTree->numOfGrps)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
+ ("grpId you asked > numOfGroup of relevant tree"));
+
+ *p_GrpBits = p_FmPcdCcTree->fmPcdGroupParam[grpId].totalBitsMask;
+ *p_GrpBase = p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry;
+
+ return E_OK;
+}
+
+t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPcdCcTree, uint32_t *p_Offset,
+ t_Handle h_FmPort)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
+
+ /* this routine must be protected by the calling routine by locking all PCD modules! */
+
+ err = CcUpdateParams(h_FmPcd, h_PcdParams, h_FmPort, h_FmPcdCcTree, TRUE);
+
+ if (err == E_OK)
+ UpdateCcRootOwner(p_FmPcdCcTree, TRUE);
+
+ *p_Offset = (uint32_t)(XX_VirtToPhys(
+ UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr))
+ - p_FmPcd->physicalMuramBase);
+
+ return err;
+}
+
+t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree)
+{
+ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree;
+
+ /* this routine must be protected by the calling routine by locking all PCD modules! */
+
+ UNUSED(h_FmPcd);
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE);
+
+ UpdateCcRootOwner(p_FmPcdCcTree, FALSE);
+
+ return E_OK;
+}
+
+t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode,
+ t_List *p_List)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode;
+ t_List *p_Pos, *p_Tmp;
+ t_CcNodeInformation *p_CcNodeInfo, nodeInfo;
+ uint32_t intFlags;
+ t_Error err = E_OK;
+
+ intFlags = FmPcdLock(h_FmPcd);
+
+ LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst)
+ {
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
+ ASSERT_COND(p_CcNodeInfo->h_CcNode);
+
+ err = CcRootTryLock(p_CcNodeInfo->h_CcNode);
+
+ if (err)
+ {
+ LIST_FOR_EACH(p_Tmp, &p_CcNode->ccTreesLst)
+ {
+ if (p_Tmp == p_Pos)
+ break;
+
+ CcRootReleaseLock(p_CcNodeInfo->h_CcNode);
+ }
+ break;
+ }
+
+ memset(&nodeInfo, 0, sizeof(t_CcNodeInformation));
+ nodeInfo.h_CcNode = p_CcNodeInfo->h_CcNode;
+ EnqueueNodeInfoToRelevantLst(p_List, &nodeInfo, NULL);
+ }
+
+ FmPcdUnlock(h_FmPcd, intFlags);
+ CORE_MemoryBarrier();
+
+ return err;
+}
+
+void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List)
+{
+ t_List *p_Pos;
+ t_CcNodeInformation *p_CcNodeInfo;
+ t_Handle h_FmPcdCcTree;
+ uint32_t intFlags;
+
+ intFlags = FmPcdLock(h_FmPcd);
+
+ LIST_FOR_EACH(p_Pos, p_List)
+ {
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
+ h_FmPcdCcTree = p_CcNodeInfo->h_CcNode;
+ CcRootReleaseLock(h_FmPcdCcTree);
+ }
+
+ ReleaseLst(p_List);
+
+ FmPcdUnlock(h_FmPcd, intFlags);
+ CORE_MemoryBarrier();
+}
+
+t_Error FmPcdUpdateCcShadow(t_FmPcd *p_FmPcd, uint32_t size, uint32_t align)
+{
+ uint32_t intFlags;
+ uint32_t newSize = 0, newAlign = 0;
+ bool allocFail = FALSE;
+
+ ASSERT_COND(p_FmPcd);
+
+ if (!size)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("size must be larger then 0"));
+
+ if (!POWER_OF_2(align))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("alignment must be power of 2"));
+
+ newSize = p_FmPcd->ccShadowSize;
+ newAlign = p_FmPcd->ccShadowAlign;
+
+ /* Check if current shadow is large enough to hold the requested size */
+ if (size > p_FmPcd->ccShadowSize)
+ newSize = size;
+
+ /* Check if current shadow matches the requested alignment */
+ if (align > p_FmPcd->ccShadowAlign)
+ newAlign = align;
+
+ /* If a bigger shadow size or bigger shadow alignment are required,
+ a new shadow will be allocated */
+ if ((newSize != p_FmPcd->ccShadowSize)
+ || (newAlign != p_FmPcd->ccShadowAlign))
+ {
+ intFlags = FmPcdLock(p_FmPcd);
+
+ if (p_FmPcd->p_CcShadow)
+ {
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->p_CcShadow);
+ p_FmPcd->ccShadowSize = 0;
+ p_FmPcd->ccShadowAlign = 0;
+ }
+
+ p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd),
+ newSize, newAlign);
+ if (!p_FmPcd->p_CcShadow)
+ {
+ allocFail = TRUE;
+
+ /* If new shadow size allocation failed,
+ re-allocate with previous parameters */
+ p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(
+ FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->ccShadowSize,
+ p_FmPcd->ccShadowAlign);
+ }
+
+ FmPcdUnlock(p_FmPcd, intFlags);
+
+ if (allocFail)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for CC Shadow memory"));
+
+ p_FmPcd->ccShadowSize = newSize;
+ p_FmPcd->ccShadowAlign = newAlign;
+ }
+
+ return E_OK;
+}
+
+#if (DPAA_VERSION >= 11)
+void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node,
+ t_Handle h_ReplicGroup,
+ t_List *p_AdTables,
+ uint32_t *p_NumOfAdTables)
+{
+ t_FmPcdCcNode *p_CurrentNode = (t_FmPcdCcNode *)h_Node;
+ int i = 0;
+ void * p_AdTable;
+ t_CcNodeInformation ccNodeInfo;
+
+ ASSERT_COND(h_Node);
+ *p_NumOfAdTables = 0;
+
+ /* search in the current node which exact index points on this current replicator group for getting AD */
+ for (i = 0; i < p_CurrentNode->numOfKeys + 1; i++)
+ {
+ if ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic
+ == (t_Handle)h_ReplicGroup)))
+ {
+ /* save the current ad table in the list */
+ /* this entry uses the input replicator group */
+ p_AdTable =
+ PTR_MOVE(p_CurrentNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = p_AdTable;
+ EnqueueNodeInfoToRelevantLst(p_AdTables, &ccNodeInfo, NULL);
+ (*p_NumOfAdTables)++;
+ }
+ }
+
+ ASSERT_COND(i != p_CurrentNode->numOfKeys);
+}
+#endif /* (DPAA_VERSION >= 11) */
+/*********************** End of inter-module routines ************************/
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+
+t_Handle FM_PCD_CcRootBuild(t_Handle h_FmPcd,
+ t_FmPcdCcTreeParams *p_PcdGroupsParam)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_Error err = E_OK;
+ int i = 0, j = 0, k = 0;
+ t_FmPcdCcTree *p_FmPcdCcTree;
+ uint8_t numOfEntries;
+ t_Handle p_CcTreeTmp;
+ t_FmPcdCcGrpParams *p_FmPcdCcGroupParams;
+ t_FmPcdCcKeyAndNextEngineParams *p_Params, *p_KeyAndNextEngineParams;
+ t_NetEnvParams netEnvParams;
+ uint8_t lastOne = 0;
+ uint32_t requiredAction = 0;
+ t_FmPcdCcNode *p_FmPcdCcNextNode;
+ t_CcNodeInformation ccNodeInfo, *p_CcInformation;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_PcdGroupsParam, E_INVALID_HANDLE, NULL);
+
+ if (p_PcdGroupsParam->numOfGrps > FM_PCD_MAX_NUM_OF_CC_GROUPS)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfGrps should not exceed %d", FM_PCD_MAX_NUM_OF_CC_GROUPS));
+ return NULL;
+ }
+
+ p_FmPcdCcTree = (t_FmPcdCcTree*)XX_Malloc(sizeof(t_FmPcdCcTree));
+ if (!p_FmPcdCcTree)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("PCD tree structure"));
+ return NULL;
+ }
+ memset(p_FmPcdCcTree, 0, sizeof(t_FmPcdCcTree));
+ p_FmPcdCcTree->h_FmPcd = h_FmPcd;
+
+ p_Params = (t_FmPcdCcKeyAndNextEngineParams*)XX_Malloc(
+ FM_PCD_MAX_NUM_OF_CC_GROUPS
+ * sizeof(t_FmPcdCcKeyAndNextEngineParams));
+ memset(p_Params,
+ 0,
+ FM_PCD_MAX_NUM_OF_CC_GROUPS
+ * sizeof(t_FmPcdCcKeyAndNextEngineParams));
+
+ INIT_LIST(&p_FmPcdCcTree->fmPortsLst);
+
+#ifdef FM_CAPWAP_SUPPORT
+ if ((p_PcdGroupsParam->numOfGrps == 1) &&
+ (p_PcdGroupsParam->ccGrpParams[0].numOfDistinctionUnits == 0) &&
+ (p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].nextEngine == e_FM_PCD_CC) &&
+ p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode &&
+ IsCapwapApplSpecific(p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode))
+ {
+ p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip = FmPcdManipApplSpecificBuild();
+ if (!p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip)
+ {
+ DeleteTree(p_FmPcdCcTree,p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ return NULL;
+ }
+ }
+#endif /* FM_CAPWAP_SUPPORT */
+
+ numOfEntries = 0;
+ p_FmPcdCcTree->netEnvId = FmPcdGetNetEnvId(p_PcdGroupsParam->h_NetEnv);
+
+ for (i = 0; i < p_PcdGroupsParam->numOfGrps; i++)
+ {
+ p_FmPcdCcGroupParams = &p_PcdGroupsParam->ccGrpParams[i];
+
+ if (p_FmPcdCcGroupParams->numOfDistinctionUnits
+ > FM_PCD_MAX_NUM_OF_CC_UNITS)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("numOfDistinctionUnits (group %d) should not exceed %d", i, FM_PCD_MAX_NUM_OF_CC_UNITS));
+ return NULL;
+ }
+
+ p_FmPcdCcTree->fmPcdGroupParam[i].baseGroupEntry = numOfEntries;
+ p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup = (uint8_t)(0x01
+ << p_FmPcdCcGroupParams->numOfDistinctionUnits);
+ numOfEntries += p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
+ if (numOfEntries > FM_PCD_MAX_NUM_OF_CC_GROUPS)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfEntries can not be larger than %d", FM_PCD_MAX_NUM_OF_CC_GROUPS));
+ return NULL;
+ }
+
+ if (lastOne)
+ {
+ if (p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup > lastOne)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_CONFLICT, ("numOfEntries per group must be set in descending order"));
+ return NULL;
+ }
+ }
+
+ lastOne = p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
+
+ netEnvParams.netEnvId = p_FmPcdCcTree->netEnvId;
+ netEnvParams.numOfDistinctionUnits =
+ p_FmPcdCcGroupParams->numOfDistinctionUnits;
+
+ memcpy(netEnvParams.unitIds, &p_FmPcdCcGroupParams->unitIds,
+ (sizeof(uint8_t)) * p_FmPcdCcGroupParams->numOfDistinctionUnits);
+
+ err = PcdGetUnitsVector(p_FmPcd, &netEnvParams);
+ if (err)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+
+ p_FmPcdCcTree->fmPcdGroupParam[i].totalBitsMask = netEnvParams.vector;
+ for (j = 0; j < p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup;
+ j++)
+ {
+ err = ValidateNextEngineParams(
+ h_FmPcd,
+ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
+ e_FM_PCD_CC_STATS_MODE_NONE);
+ if (err)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, err, (NO_MSG));
+ return NULL;
+ }
+
+ if (p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j].h_Manip)
+ {
+ err = FmPcdManipCheckParamsForCcNextEngine(
+ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
+ &requiredAction);
+ if (err)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ return NULL;
+ }
+ }
+ p_KeyAndNextEngineParams = p_Params + k;
+
+ memcpy(&p_KeyAndNextEngineParams->nextEngineParams,
+ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j],
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ if ((p_KeyAndNextEngineParams->nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ && p_KeyAndNextEngineParams->nextEngineParams.h_Manip)
+ {
+ err =
+ AllocAndFillAdForContLookupManip(
+ p_KeyAndNextEngineParams->nextEngineParams.params.ccParams.h_CcNode);
+ if (err)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree"));
+ return NULL;
+ }
+ }
+
+ requiredAction |= UPDATE_CC_WITH_TREE;
+ p_KeyAndNextEngineParams->requiredAction = requiredAction;
+
+ k++;
+ }
+ }
+
+ p_FmPcdCcTree->numOfEntries = (uint8_t)k;
+ p_FmPcdCcTree->numOfGrps = p_PcdGroupsParam->numOfGrps;
+
+ p_FmPcdCcTree->ccTreeBaseAddr =
+ PTR_TO_UINT(FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd),
+ (uint32_t)( FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE),
+ FM_PCD_CC_TREE_ADDR_ALIGN));
+ if (!p_FmPcdCcTree->ccTreeBaseAddr)
+ {
+ DeleteTree(p_FmPcdCcTree, p_FmPcd);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree"));
+ return NULL;
+ }
+ MemSet8(
+ UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr), 0,
+ (uint32_t)(FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE));
+
+ p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
+
+ for (i = 0; i < numOfEntries; i++)
+ {
+ p_KeyAndNextEngineParams = p_Params + i;
+
+ NextStepAd(p_CcTreeTmp, NULL,
+ &p_KeyAndNextEngineParams->nextEngineParams, p_FmPcd);
+
+ p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ memcpy(&p_FmPcdCcTree->keyAndNextEngineParams[i],
+ p_KeyAndNextEngineParams,
+ sizeof(t_FmPcdCcKeyAndNextEngineParams));
+
+ if (p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ p_FmPcdCcNextNode =
+ (t_FmPcdCcNode*)p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
+ p_CcInformation = FindNodeInfoInReleventLst(
+ &p_FmPcdCcNextNode->ccTreeIdLst, (t_Handle)p_FmPcdCcTree,
+ p_FmPcdCcNextNode->h_Spinlock);
+
+ if (!p_CcInformation)
+ {
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcTree;
+ ccNodeInfo.index = 1;
+ EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccTreeIdLst,
+ &ccNodeInfo,
+ p_FmPcdCcNextNode->h_Spinlock);
+ }
+ else
+ p_CcInformation->index++;
+ }
+ }
+
+ FmPcdIncNetEnvOwners(h_FmPcd, p_FmPcdCcTree->netEnvId);
+ p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ FM_PCD_CcRootDelete(p_FmPcdCcTree);
+ XX_Free(p_Params);
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return NULL;
+ }
+
+ for (i = 0; i < numOfEntries; i++)
+ {
+ if (p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction)
+ {
+ err = SetRequiredAction(
+ h_FmPcd,
+ p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction,
+ &p_FmPcdCcTree->keyAndNextEngineParams[i], p_CcTreeTmp, 1,
+ p_FmPcdCcTree);
+ if (err)
+ {
+ FmPcdLockUnlockAll(p_FmPcd);
+ FM_PCD_CcRootDelete(p_FmPcdCcTree);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+ return NULL;
+ }
+ p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE);
+ }
+ }
+
+ FmPcdLockUnlockAll(p_FmPcd);
+ p_FmPcdCcTree->p_Lock = FmPcdAcquireLock(p_FmPcd);
+ if (!p_FmPcdCcTree->p_Lock)
+ {
+ FM_PCD_CcRootDelete(p_FmPcdCcTree);
+ XX_Free(p_Params);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM CC lock"));
+ return NULL;
+ }
+
+ XX_Free(p_Params);
+
+ return p_FmPcdCcTree;
+}
+
+t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree;
+ int i = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE);
+ p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ FmPcdDecNetEnvOwners(p_FmPcd, p_CcTree->netEnvId);
+
+ if (p_CcTree->owners)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_SELECTION,
+ ("the tree with this ID can not be removed because this tree is occupied, first - unbind this tree"));
+
+ /* Delete ip-reassembly schemes if exist */
+ if (p_CcTree->h_IpReassemblyManip)
+ {
+ FmPcdManipDeleteIpReassmSchemes(p_CcTree->h_IpReassemblyManip);
+ FmPcdManipUpdateOwner(p_CcTree->h_IpReassemblyManip, FALSE);
+ }
+
+ /* Delete capwap-reassembly schemes if exist */
+ if (p_CcTree->h_CapwapReassemblyManip)
+ {
+ FmPcdManipDeleteCapwapReassmSchemes(p_CcTree->h_CapwapReassemblyManip);
+ FmPcdManipUpdateOwner(p_CcTree->h_CapwapReassemblyManip, FALSE);
+ }
+
+ for (i = 0; i < p_CcTree->numOfEntries; i++)
+ {
+ if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ UpdateNodeOwner(
+ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
+ FALSE);
+
+ if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ FmPcdManipUpdateOwner(
+ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
+ FALSE);
+
+#ifdef FM_CAPWAP_SUPPORT
+ if ((p_CcTree->numOfGrps == 1) &&
+ (p_CcTree->fmPcdGroupParam[0].numOfEntriesInGroup == 1) &&
+ (p_CcTree->keyAndNextEngineParams[0].nextEngineParams.nextEngine == e_FM_PCD_CC) &&
+ p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode &&
+ IsCapwapApplSpecific(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode))
+ {
+ if (FM_PCD_ManipNodeDelete(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.h_Manip) != E_OK)
+ return E_INVALID_STATE;
+ }
+#endif /* FM_CAPWAP_SUPPORT */
+
+#if (DPAA_VERSION >= 11)
+ if ((p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic))
+ FrmReplicGroupUpdateOwner(
+ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic,
+ FALSE);
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ if (p_CcTree->p_Lock)
+ FmPcdReleaseLock(p_CcTree->h_FmPcd, p_CcTree->p_Lock);
+
+ DeleteTree(p_CcTree, p_FmPcd);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_CcRootModifyNextEngine(
+ t_Handle h_CcTree, uint8_t grpId, uint8_t index,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE);
+ p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcModifyNextEngineParamTree(p_FmPcd, p_CcTree, grpId, index,
+ p_FmPcdCcNextEngineParams);
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ if (err)
+ {
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd,
+ t_FmPcdCcNodeParams *p_CcNodeParam)
+{
+ t_FmPcdCcNode *p_CcNode;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_CcNodeParam, E_NULL_POINTER, NULL);
+
+ p_CcNode = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode));
+ if (!p_CcNode)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+ return NULL;
+ }
+ memset(p_CcNode, 0, sizeof(t_FmPcdCcNode));
+
+ err = MatchTableSet(h_FmPcd, p_CcNode, p_CcNodeParam);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ break;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return NULL;
+
+ default:
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+
+ return p_CcNode;
+}
+
+t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ int i = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode->h_FmPcd, E_INVALID_HANDLE);
+
+ if (p_CcNode->owners)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("This node cannot be removed because it is occupied; first unbind this node"));
+
+ for (i = 0; i < p_CcNode->numOfKeys; i++)
+ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ UpdateNodeOwner(
+ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
+ FALSE);
+
+ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ UpdateNodeOwner(
+ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode,
+ FALSE);
+
+ /* Handle also Miss entry */
+ for (i = 0; i < p_CcNode->numOfKeys + 1; i++)
+ {
+ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)
+ FmPcdManipUpdateOwner(
+ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip,
+ FALSE);
+
+#if (DPAA_VERSION >= 11)
+ if ((p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_FR)
+ && (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic))
+ {
+ FrmReplicGroupUpdateOwner(
+ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic,
+ FALSE);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ DeleteNode(p_CcNode);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode, uint16_t keyIndex,
+ uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (keyIndex == FM_PCD_LAST_KEY_INDEX)
+ keyIndex = p_CcNode->numOfKeys;
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcAddKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_KeyParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode, uint16_t keyIndex,
+ uint8_t keySize, uint8_t *p_Key,
+ uint8_t *p_Mask)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_Key, p_Mask);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableModifyNextEngine(
+ t_Handle h_CcNode, uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcNextEngineParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableModifyMissNextEngine(
+ t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcModifyMissNextEngineParamNode(p_FmPcd, p_CcNode,
+ p_FmPcdCcNextEngineParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, p_CcNode, keyIndex, keySize,
+ p_KeyParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode, uint8_t keySize,
+ uint8_t *p_Key, uint8_t *p_Mask)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint16_t keyIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
+ if (GET_ERROR_TYPE(err) != E_OK)
+ {
+ FmPcdLockUnlockAll(p_FmPcd);
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("The received key and mask pair was not found in the match table of the provided node"));
+ }
+
+ err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableFindNModifyNextEngine(
+ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint16_t keyIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
+ if (GET_ERROR_TYPE(err) != E_OK)
+ {
+ FmPcdLockUnlockAll(p_FmPcd);
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("The received key and mask pair was not found in the match table of the provided node"));
+ }
+
+ err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex,
+ p_FmPcdCcNextEngineParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine(
+ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
+ t_FmPcdCcKeyParams *p_KeyParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint16_t keyIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
+ if (GET_ERROR_TYPE(err) != E_OK)
+ {
+ FmPcdLockUnlockAll(p_FmPcd);
+ RETURN_ERROR(
+ MAJOR,
+ err,
+ ("The received key and mask pair was not found in the match table of the provided node"));
+ }
+
+ err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, h_CcNode, keyIndex, keySize,
+ p_KeyParams);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode, uint8_t keySize,
+ uint8_t *p_Key, uint8_t *p_Mask,
+ uint8_t *p_NewKey, uint8_t *p_NewMask)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ t_List h_List;
+ uint16_t keyIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_NewKey, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ INIT_LIST(&h_List);
+
+ err = FmPcdCcNodeTreeTryLock(p_FmPcd, p_CcNode, &h_List);
+ if (err)
+ {
+ DBG(TRACE, ("Node's trees lock failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
+ if (GET_ERROR_TYPE(err) != E_OK)
+ {
+ FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List);
+ RETURN_ERROR(MAJOR, err,
+ ("The received key and mask pair was not found in the "
+ "match table of the provided node"));
+ }
+
+ err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_NewKey,
+ p_NewMask);
+
+ FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List);
+
+ switch(GET_ERROR_TYPE(err)
+) {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+t_Error FM_PCD_MatchTableGetNextEngine(
+ t_Handle h_CcNode, uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+
+ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("keyIndex exceeds current number of keys"));
+
+ if (keyIndex > (FM_PCD_MAX_NUM_OF_KEYS - 1))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("keyIndex can not be larger than %d", (FM_PCD_MAX_NUM_OF_KEYS - 1)));
+
+ memcpy(p_FmPcdCcNextEngineParams,
+ &p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ return E_OK;
+}
+
+
+uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint32_t *p_StatsCounters, frameCount;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_VALUE(p_CcNode, E_INVALID_HANDLE, 0);
+
+ if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this match table"));
+ return 0;
+ }
+
+ if ((p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_FRAME)
+ && (p_CcNode->statisticsMode
+ != e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Frame count is not supported in the statistics mode of this match table"));
+ return 0;
+ }
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ {
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("The provided keyIndex exceeds the number of keys in this match table"));
+ return 0;
+ }
+
+ if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj)
+ {
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this key"));
+ return 0;
+ }
+
+ p_StatsCounters =
+ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters;
+ ASSERT_COND(p_StatsCounters);
+
+ /* The first counter is byte counter, so we need to advance to the next counter */
+ frameCount = GET_UINT32(*(uint32_t *)(PTR_MOVE(p_StatsCounters,
+ FM_PCD_CC_STATS_COUNTER_SIZE)));
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ return frameCount;
+}
+
+t_Error FM_PCD_MatchTableGetKeyStatistics(
+ t_Handle h_CcNode, uint16_t keyIndex,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint32_t intFlags;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ if (keyIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("The provided keyIndex exceeds the number of keys in this match table"));
+
+ err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics);
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_MatchTableGetMissStatistics(
+ t_Handle h_CcNode, t_FmPcdCcKeyStatistics *p_MissStatistics)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint32_t intFlags;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER);
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ err = MatchTableGetKeyStatistics(p_CcNode, p_CcNode->numOfKeys,
+ p_MissStatistics);
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_MatchTableFindNGetKeyStatistics(
+ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint16_t keyIndex;
+ uint32_t intFlags;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
+
+ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock);
+
+ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex);
+ if (GET_ERROR_TYPE(err) != E_OK)
+ {
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, err,
+ ("The received key and mask pair was not found in the "
+ "match table of the provided node"));
+ }
+
+ ASSERT_COND(keyIndex < p_CcNode->numOfKeys);
+
+ err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics);
+
+ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags);
+
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode,
+ uint8_t keySize, uint8_t *p_Key,
+ uint8_t hashShift,
+ t_Handle *p_CcNodeBucketHandle,
+ uint8_t *p_BucketIndex,
+ uint16_t *p_LastIndex)
+{
+ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode;
+ uint16_t glblMask;
+ uint64_t crc64 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(
+ p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED,
+ E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_CcNodeBucketHandle, E_NULL_POINTER);
+
+ memcpy(&glblMask, PTR_MOVE(p_CcNode->p_GlblMask, 2), 2);
+ be16_to_cpus(&glblMask);
+
+ crc64 = crc64_init();
+ crc64 = crc64_compute(p_Key, keySize, crc64);
+ crc64 >>= hashShift;
+
+ *p_BucketIndex = (uint8_t)(((crc64 >> (8 * (6 - p_CcNode->userOffset)))
+ & glblMask) >> 4);
+ if (*p_BucketIndex >= p_CcNode->numOfKeys)
+ RETURN_ERROR(MINOR, E_NOT_IN_RANGE, ("bucket index!"));
+
+ *p_CcNodeBucketHandle =
+ p_CcNode->keyAndNextEngineParams[*p_BucketIndex].nextEngineParams.params.ccParams.h_CcNode;
+ if (!*p_CcNodeBucketHandle)
+ RETURN_ERROR(MINOR, E_NOT_FOUND, ("bucket!"));
+
+ *p_LastIndex = ((t_FmPcdCcNode *)*p_CcNodeBucketHandle)->numOfKeys;
+
+ return E_OK;
+}
+
+t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param)
+{
+ t_FmPcdCcNode *p_CcNodeHashTbl;
+ t_FmPcdCcNodeParams *p_IndxHashCcNodeParam, *p_ExactMatchCcNodeParam;
+ t_FmPcdCcNode *p_CcNode;
+ t_Handle h_MissStatsCounters = NULL;
+ t_FmPcdCcKeyParams *p_HashKeyParams;
+ int i;
+ uint16_t numOfSets, numOfWays, countMask, onesCount = 0;
+ bool statsEnForMiss = FALSE;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_Param, E_NULL_POINTER, NULL);
+
+ if (p_Param->maxNumOfKeys == 0)
+ {
+ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Max number of keys must be higher then 0"));
+ return NULL;
+ }
+
+ if (p_Param->hashResMask == 0)
+ {
+ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Hash result mask must differ from 0"));
+ return NULL;
+ }
+
+ /*Fix: QorIQ SDK / QSDK-2131*/
+ if (p_Param->ccNextEngineParamsForMiss.nextEngine == e_FM_PCD_INVALID)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Next PCD Engine for on-miss entry is invalid. On-miss entry is always required. You can use e_FM_PCD_DONE."));
+ return NULL;
+ }
+
+#if (DPAA_VERSION >= 11)
+ if (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_RMON)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("RMON statistics mode is not supported for hash table"));
+ return NULL;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ p_ExactMatchCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc(
+ sizeof(t_FmPcdCcNodeParams));
+ if (!p_ExactMatchCcNodeParam)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_ExactMatchCcNodeParam"));
+ return NULL;
+ }
+ memset(p_ExactMatchCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams));
+
+ p_IndxHashCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc(
+ sizeof(t_FmPcdCcNodeParams));
+ if (!p_IndxHashCcNodeParam)
+ {
+ XX_Free(p_ExactMatchCcNodeParam);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_IndxHashCcNodeParam"));
+ return NULL;
+ }
+ memset(p_IndxHashCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams));
+
+ /* Calculate number of sets and number of ways of the hash table */
+ countMask = (uint16_t)(p_Param->hashResMask >> 4);
+ while (countMask)
+ {
+ onesCount++;
+ countMask = (uint16_t)(countMask >> 1);
+ }
+
+ numOfSets = (uint16_t)(1 << onesCount);
+ numOfWays = (uint16_t)DIV_CEIL(p_Param->maxNumOfKeys, numOfSets);
+
+ if (p_Param->maxNumOfKeys % numOfSets)
+ DBG(INFO, ("'maxNumOfKeys' is not a multiple of hash number of ways, so number of ways will be rounded up"));
+
+ if ((p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_FRAME)
+ || (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME))
+ {
+ /* Allocating a statistics counters table that will be used by all
+ 'miss' entries of the hash table */
+ h_MissStatsCounters = (t_Handle)FM_MURAM_AllocMem(
+ FmPcdGetMuramHandle(h_FmPcd), 2 * FM_PCD_CC_STATS_COUNTER_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!h_MissStatsCounters)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics table for hash miss"));
+ XX_Free(p_IndxHashCcNodeParam);
+ XX_Free(p_ExactMatchCcNodeParam);
+ return NULL;
+ }
+ memset(h_MissStatsCounters, 0, (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
+
+ /* Always enable statistics for 'miss', so that a statistics AD will be
+ initialized from the start. We'll store the requested 'statistics enable'
+ value and it will be used when statistics are read by the user. */
+ statsEnForMiss = p_Param->ccNextEngineParamsForMiss.statisticsEn;
+ p_Param->ccNextEngineParamsForMiss.statisticsEn = TRUE;
+ }
+
+ /* Building exact-match node params, will be used to create the hash buckets */
+ p_ExactMatchCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR;
+
+ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.src =
+ e_FM_PCD_EXTRACT_FROM_KEY;
+ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.action =
+ e_FM_PCD_ACTION_EXACT_MATCH;
+ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.offset = 0;
+ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.size =
+ p_Param->matchKeySize;
+
+ p_ExactMatchCcNodeParam->keysParams.maxNumOfKeys = numOfWays;
+ p_ExactMatchCcNodeParam->keysParams.maskSupport = FALSE;
+ p_ExactMatchCcNodeParam->keysParams.statisticsMode =
+ p_Param->statisticsMode;
+ p_ExactMatchCcNodeParam->keysParams.numOfKeys = 0;
+ p_ExactMatchCcNodeParam->keysParams.keySize = p_Param->matchKeySize;
+ p_ExactMatchCcNodeParam->keysParams.ccNextEngineParamsForMiss =
+ p_Param->ccNextEngineParamsForMiss;
+
+ p_HashKeyParams = p_IndxHashCcNodeParam->keysParams.keyParams;
+
+ for (i = 0; i < numOfSets; i++)
+ {
+ /* Each exact-match node will be marked as a 'bucket' and provided with
+ a pointer to statistics counters, to be used for 'miss' entry
+ statistics */
+ p_CcNode = (t_FmPcdCcNode *)XX_Malloc(sizeof(t_FmPcdCcNode));
+ if (!p_CcNode)
+ break;
+ memset(p_CcNode, 0, sizeof(t_FmPcdCcNode));
+
+ p_CcNode->isHashBucket = TRUE;
+ p_CcNode->h_MissStatsCounters = h_MissStatsCounters;
+
+ err = MatchTableSet(h_FmPcd, p_CcNode, p_ExactMatchCcNodeParam);
+ if (err)
+ break;
+
+ p_HashKeyParams[i].ccNextEngineParams.nextEngine = e_FM_PCD_CC;
+ p_HashKeyParams[i].ccNextEngineParams.statisticsEn = FALSE;
+ p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode =
+ p_CcNode;
+ }
+
+ if (i < numOfSets)
+ {
+ for (i = i - 1; i >= 0; i--)
+ FM_PCD_MatchTableDelete(
+ p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode);
+
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters);
+
+ REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG);
+ XX_Free(p_IndxHashCcNodeParam);
+ XX_Free(p_ExactMatchCcNodeParam);
+ return NULL;
+ }
+
+ /* Creating indexed-hash CC node */
+ p_IndxHashCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR;
+ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.src =
+ e_FM_PCD_EXTRACT_FROM_HASH;
+ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.action =
+ e_FM_PCD_ACTION_INDEXED_LOOKUP;
+ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.icIndxMask =
+ p_Param->hashResMask;
+ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.offset =
+ p_Param->hashShift;
+ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.size = 2;
+
+ p_IndxHashCcNodeParam->keysParams.maxNumOfKeys = numOfSets;
+ p_IndxHashCcNodeParam->keysParams.maskSupport = FALSE;
+ p_IndxHashCcNodeParam->keysParams.statisticsMode =
+ e_FM_PCD_CC_STATS_MODE_NONE;
+ /* Number of keys of this node is number of sets of the hash */
+ p_IndxHashCcNodeParam->keysParams.numOfKeys = numOfSets;
+ p_IndxHashCcNodeParam->keysParams.keySize = 2;
+
+ p_CcNodeHashTbl = FM_PCD_MatchTableSet(h_FmPcd, p_IndxHashCcNodeParam);
+
+ if (p_CcNodeHashTbl)
+ {
+ p_CcNodeHashTbl->kgHashShift = p_Param->kgHashShift;
+
+ /* Storing the allocated counters for buckets 'miss' in the hash table
+ and if statistics for miss were enabled. */
+ p_CcNodeHashTbl->h_MissStatsCounters = h_MissStatsCounters;
+ p_CcNodeHashTbl->statsEnForMiss = statsEnForMiss;
+ }
+
+ XX_Free(p_IndxHashCcNodeParam);
+ XX_Free(p_ExactMatchCcNodeParam);
+
+ return p_CcNodeHashTbl;
+}
+
+t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_FmPcd;
+ t_Handle *p_HashBuckets, h_MissStatsCounters;
+ uint16_t i, numOfBuckets;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+
+ /* Store all hash buckets before the hash is freed */
+ numOfBuckets = p_HashTbl->numOfKeys;
+
+ p_HashBuckets = (t_Handle *)XX_Malloc(numOfBuckets * sizeof(t_Handle));
+ if (!p_HashBuckets)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+
+ for (i = 0; i < numOfBuckets; i++)
+ p_HashBuckets[i] =
+ p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
+
+ h_FmPcd = p_HashTbl->h_FmPcd;
+ h_MissStatsCounters = p_HashTbl->h_MissStatsCounters;
+
+ /* Free the hash */
+ err = FM_PCD_MatchTableDelete(p_HashTbl);
+
+ /* Free each hash bucket */
+ for (i = 0; i < numOfBuckets; i++)
+ err |= FM_PCD_MatchTableDelete(p_HashBuckets[i]);
+
+ XX_Free(p_HashBuckets);
+
+ /* Free statistics counters for 'miss', if these were allocated */
+ if (h_MissStatsCounters)
+ FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters);
+
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl, uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+ uint8_t bucketIndex;
+ uint16_t lastIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_KeyParams->p_Key, E_NULL_POINTER);
+
+ if (p_KeyParams->p_Mask)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Keys masks not supported for hash table"));
+
+ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize,
+ p_KeyParams->p_Key,
+ p_HashTbl->kgHashShift,
+ &h_HashBucket, &bucketIndex,
+ &lastIndex);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return FM_PCD_MatchTableAddKey(h_HashBucket, FM_PCD_LAST_KEY_INDEX, keySize,
+ p_KeyParams);
+}
+
+t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl, uint8_t keySize,
+ uint8_t *p_Key)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+ uint8_t bucketIndex;
+ uint16_t lastIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+
+ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
+ p_HashTbl->kgHashShift,
+ &h_HashBucket, &bucketIndex,
+ &lastIndex);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return FM_PCD_MatchTableFindNRemoveKey(h_HashBucket, keySize, p_Key, NULL);
+}
+
+t_Error FM_PCD_HashTableModifyNextEngine(
+ t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+ uint8_t bucketIndex;
+ uint16_t lastIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+
+ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
+ p_HashTbl->kgHashShift,
+ &h_HashBucket, &bucketIndex,
+ &lastIndex);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return FM_PCD_MatchTableFindNModifyNextEngine(h_HashBucket, keySize, p_Key,
+ NULL,
+ p_FmPcdCcNextEngineParams);
+}
+
+t_Error FM_PCD_HashTableModifyMissNextEngine(
+ t_Handle h_HashTbl,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+ uint8_t i;
+ bool nullifyMissStats = FALSE;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(h_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+
+ if ((!p_HashTbl->h_MissStatsCounters)
+ && (p_FmPcdCcNextEngineParams->statisticsEn))
+ RETURN_ERROR(
+ MAJOR,
+ E_CONFLICT,
+ ("Statistics are requested for a key, but statistics mode was set"
+ "to 'NONE' upon initialization"));
+
+ if (p_HashTbl->h_MissStatsCounters)
+ {
+ if ((!p_HashTbl->statsEnForMiss)
+ && (p_FmPcdCcNextEngineParams->statisticsEn))
+ nullifyMissStats = TRUE;
+
+ if ((p_HashTbl->statsEnForMiss)
+ && (!p_FmPcdCcNextEngineParams->statisticsEn))
+ {
+ p_HashTbl->statsEnForMiss = FALSE;
+ p_FmPcdCcNextEngineParams->statisticsEn = TRUE;
+ }
+ }
+
+ for (i = 0; i < p_HashTbl->numOfKeys; i++)
+ {
+ h_HashBucket =
+ p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode;
+
+ err = FM_PCD_MatchTableModifyMissNextEngine(h_HashBucket,
+ p_FmPcdCcNextEngineParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (nullifyMissStats)
+ {
+ memset(p_HashTbl->h_MissStatsCounters, 0,
+ (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
+ memset(p_HashTbl->h_MissStatsCounters, 0,
+ (2 * FM_PCD_CC_STATS_COUNTER_SIZE));
+ p_HashTbl->statsEnForMiss = TRUE;
+ }
+
+ return E_OK;
+}
+
+
+t_Error FM_PCD_HashTableGetMissNextEngine(
+ t_Handle h_HashTbl,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_FmPcdCcNode *p_HashBucket;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+
+ /* Miss next engine of each bucket was initialized with the next engine of the hash table */
+ p_HashBucket =
+ p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode;
+
+ memcpy(p_FmPcdCcNextEngineParams,
+ &p_HashBucket->keyAndNextEngineParams[p_HashBucket->numOfKeys].nextEngineParams,
+ sizeof(t_FmPcdCcNextEngineParams));
+
+ return E_OK;
+}
+
+t_Error FM_PCD_HashTableFindNGetKeyStatistics(
+ t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+ uint8_t bucketIndex;
+ uint16_t lastIndex;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER);
+
+ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key,
+ p_HashTbl->kgHashShift,
+ &h_HashBucket, &bucketIndex,
+ &lastIndex);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return FM_PCD_MatchTableFindNGetKeyStatistics(h_HashBucket, keySize, p_Key,
+ NULL, p_KeyStatistics);
+}
+
+t_Error FM_PCD_HashTableGetMissStatistics(
+ t_Handle h_HashTbl, t_FmPcdCcKeyStatistics *p_MissStatistics)
+{
+ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl;
+ t_Handle h_HashBucket;
+
+ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER);
+
+ if (!p_HashTbl->statsEnForMiss)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Statistics were not enabled for miss"));
+
+ h_HashBucket =
+ p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode;
+
+ return FM_PCD_MatchTableGetMissStatistics(h_HashBucket, p_MissStatistics);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h
new file mode 100644
index 000000000000..3456bb565fd7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_cc.h
+
+ @Description FM PCD CC ...
+*//***************************************************************************/
+#ifndef __FM_CC_H
+#define __FM_CC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "fm_pcd.h"
+
+
+/***********************************************************************/
+/* Coarse classification defines */
+/***********************************************************************/
+
+#define CC_MAX_NUM_OF_KEYS (FM_PCD_MAX_NUM_OF_KEYS + 1)
+
+#define CC_PC_FF_MACDST 0x00
+#define CC_PC_FF_MACSRC 0x01
+#define CC_PC_FF_ETYPE 0x02
+
+#define CC_PC_FF_TCI1 0x03
+#define CC_PC_FF_TCI2 0x04
+
+#define CC_PC_FF_MPLS1 0x06
+#define CC_PC_FF_MPLS_LAST 0x07
+
+#define CC_PC_FF_IPV4DST1 0x08
+#define CC_PC_FF_IPV4DST2 0x16
+#define CC_PC_FF_IPV4IPTOS_TC1 0x09
+#define CC_PC_FF_IPV4IPTOS_TC2 0x17
+#define CC_PC_FF_IPV4PTYPE1 0x0A
+#define CC_PC_FF_IPV4PTYPE2 0x18
+#define CC_PC_FF_IPV4SRC1 0x0b
+#define CC_PC_FF_IPV4SRC2 0x19
+#define CC_PC_FF_IPV4SRC1_IPV4DST1 0x0c
+#define CC_PC_FF_IPV4SRC2_IPV4DST2 0x1a
+#define CC_PC_FF_IPV4TTL 0x29
+
+
+#define CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1 0x0d /*TODO - CLASS - what is it? TOS*/
+#define CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2 0x1b
+#define CC_PC_FF_IPV6PTYPE1 0x0e
+#define CC_PC_FF_IPV6PTYPE2 0x1c
+#define CC_PC_FF_IPV6DST1 0x0f
+#define CC_PC_FF_IPV6DST2 0x1d
+#define CC_PC_FF_IPV6SRC1 0x10
+#define CC_PC_FF_IPV6SRC2 0x1e
+#define CC_PC_FF_IPV6HOP_LIMIT 0x2a
+#define CC_PC_FF_IPPID 0x24
+#define CC_PC_FF_IPDSCP 0x76
+
+#define CC_PC_FF_GREPTYPE 0x11
+
+#define CC_PC_FF_MINENCAP_PTYPE 0x12
+#define CC_PC_FF_MINENCAP_IPDST 0x13
+#define CC_PC_FF_MINENCAP_IPSRC 0x14
+#define CC_PC_FF_MINENCAP_IPSRC_IPDST 0x15
+
+#define CC_PC_FF_L4PSRC 0x1f
+#define CC_PC_FF_L4PDST 0x20
+#define CC_PC_FF_L4PSRC_L4PDST 0x21
+
+#define CC_PC_FF_PPPPID 0x05
+
+#define CC_PC_PR_SHIM1 0x22
+#define CC_PC_PR_SHIM2 0x23
+
+#define CC_PC_GENERIC_WITHOUT_MASK 0x27
+#define CC_PC_GENERIC_WITH_MASK 0x28
+#define CC_PC_GENERIC_IC_GMASK 0x2B
+#define CC_PC_GENERIC_IC_HASH_INDEXED 0x2C
+#define CC_PC_GENERIC_IC_AGING_MASK 0x2D
+
+#define CC_PR_OFFSET 0x25
+#define CC_PR_WITHOUT_OFFSET 0x26
+
+#define CC_PC_PR_ETH_OFFSET 19
+#define CC_PC_PR_USER_DEFINED_SHIM1_OFFSET 16
+#define CC_PC_PR_USER_DEFINED_SHIM2_OFFSET 17
+#define CC_PC_PR_USER_LLC_SNAP_OFFSET 20
+#define CC_PC_PR_VLAN1_OFFSET 21
+#define CC_PC_PR_VLAN2_OFFSET 22
+#define CC_PC_PR_PPPOE_OFFSET 24
+#define CC_PC_PR_MPLS1_OFFSET 25
+#define CC_PC_PR_MPLS_LAST_OFFSET 26
+#define CC_PC_PR_IP1_OFFSET 27
+#define CC_PC_PR_IP_LAST_OFFSET 28
+#define CC_PC_PR_MINENC_OFFSET 28
+#define CC_PC_PR_L4_OFFSET 30
+#define CC_PC_PR_GRE_OFFSET 29
+#define CC_PC_PR_ETYPE_LAST_OFFSET 23
+#define CC_PC_PR_NEXT_HEADER_OFFSET 31
+
+#define CC_PC_ILLEGAL 0xff
+#define CC_SIZE_ILLEGAL 0
+
+#define FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN 16
+#define FM_PCD_CC_AD_TABLE_ALIGN 16
+#define FM_PCD_CC_AD_ENTRY_SIZE 16
+#define FM_PCD_CC_NUM_OF_KEYS 255
+#define FM_PCD_CC_TREE_ADDR_ALIGN 256
+
+#define FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE 0x00000000
+#define FM_PCD_AD_RESULT_DATA_FLOW_TYPE 0x80000000
+#define FM_PCD_AD_RESULT_PLCR_DIS 0x20000000
+#define FM_PCD_AD_RESULT_EXTENDED_MODE 0x80000000
+#define FM_PCD_AD_RESULT_NADEN 0x20000000
+#define FM_PCD_AD_RESULT_STATISTICS_EN 0x40000000
+
+#define FM_PCD_AD_CONT_LOOKUP_TYPE 0x40000000
+#define FM_PCD_AD_CONT_LOOKUP_LCL_MASK 0x00800000
+
+#define FM_PCD_AD_STATS_TYPE 0x40000000
+#define FM_PCD_AD_STATS_FLR_ADDR_MASK 0x00FFFFFF
+#define FM_PCD_AD_STATS_COUNTERS_ADDR_MASK 0x00FFFFFF
+#define FM_PCD_AD_STATS_NEXT_ACTION_MASK 0xFFFF0000
+#define FM_PCD_AD_STATS_NEXT_ACTION_SHIFT 12
+#define FM_PCD_AD_STATS_NAD_EN 0x00008000
+#define FM_PCD_AD_STATS_OP_CODE 0x00000036
+#define FM_PCD_AD_STATS_FLR_EN 0x00004000
+#define FM_PCD_AD_STATS_COND_EN 0x00002000
+
+
+
+#define FM_PCD_AD_BYPASS_TYPE 0xc0000000
+
+#define FM_PCD_AD_TYPE_MASK 0xc0000000
+#define FM_PCD_AD_OPCODE_MASK 0x0000000f
+
+#define FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT 16
+#if (DPAA_VERSION >= 11)
+#define FM_PCD_AD_RESULT_VSP_SHIFT 24
+#define FM_PCD_AD_RESULT_NO_OM_VSPE 0x02000000
+#define FM_PCD_AD_RESULT_VSP_MASK 0x3f
+#define FM_PCD_AD_NCSPFQIDM_MASK 0x80000000
+#endif /* (DPAA_VERSION >= 11) */
+
+#define GLBL_MASK_FOR_HASH_INDEXED 0xfff00000
+#define CC_GLBL_MASK_SIZE 4
+#define CC_AGING_MASK_SIZE 4
+
+typedef uint32_t ccPrivateInfo_t; /**< private info of CC: */
+
+#define CC_PRIVATE_INFO_NONE 0
+#define CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP 0x80000000
+#define CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH 0x40000000
+#define CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH 0x20000000
+#define CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP 0x10000000
+
+#define CC_BUILD_AGING_MASK(numOfKeys) ((((1LL << ((numOfKeys) + 1)) - 1)) << (31 - (numOfKeys)))
+/***********************************************************************/
+/* Memory map */
+/***********************************************************************/
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+typedef struct
+{
+ volatile uint32_t fqid;
+ volatile uint32_t plcrProfile;
+ volatile uint32_t nia;
+ volatile uint32_t res;
+} t_AdOfTypeResult;
+
+typedef struct
+{
+ volatile uint32_t ccAdBase;
+ volatile uint32_t matchTblPtr;
+ volatile uint32_t pcAndOffsets;
+ volatile uint32_t gmask;
+} t_AdOfTypeContLookup;
+
+typedef struct
+{
+ volatile uint32_t profileTableAddr;
+ volatile uint32_t reserved;
+ volatile uint32_t nextActionIndx;
+ volatile uint32_t statsTableAddr;
+} t_AdOfTypeStats;
+
+typedef union
+{
+ volatile t_AdOfTypeResult adResult;
+ volatile t_AdOfTypeContLookup adContLookup;
+} t_Ad;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/***********************************************************************/
+/* Driver's internal structures */
+/***********************************************************************/
+
+typedef struct t_FmPcdStatsObj
+{
+ t_Handle h_StatsAd;
+ t_Handle h_StatsCounters;
+ t_List node;
+} t_FmPcdStatsObj;
+
+typedef struct
+{
+ uint8_t key[FM_PCD_MAX_SIZE_OF_KEY];
+ uint8_t mask[FM_PCD_MAX_SIZE_OF_KEY];
+
+ t_FmPcdCcNextEngineParams nextEngineParams;
+ uint32_t requiredAction;
+ uint32_t shadowAction;
+
+ t_FmPcdStatsObj *p_StatsObj;
+
+} t_FmPcdCcKeyAndNextEngineParams;
+
+typedef struct
+{
+ t_Handle p_Ad;
+ e_FmPcdEngine fmPcdEngine;
+ bool adAllocated;
+ bool isTree;
+
+ uint32_t myInfo;
+ t_List *h_CcNextNodesLst;
+ t_Handle h_AdditionalInfo;
+ t_Handle h_Node;
+} t_FmPcdModifyCcAdditionalParams;
+
+typedef struct
+{
+ t_Handle p_AdTableNew;
+ t_Handle p_KeysMatchTableNew;
+ t_Handle p_AdTableOld;
+ t_Handle p_KeysMatchTableOld;
+ uint16_t numOfKeys;
+ t_Handle h_CurrentNode;
+ uint16_t savedKeyIndex;
+ t_Handle h_NodeForAdd;
+ t_Handle h_NodeForRmv;
+ t_Handle h_ManipForRmv;
+ t_Handle h_ManipForAdd;
+ t_FmPcdStatsObj *p_StatsObjForRmv;
+#if (DPAA_VERSION >= 11)
+ t_Handle h_FrmReplicForAdd;
+ t_Handle h_FrmReplicForRmv;
+#endif /* (DPAA_VERSION >= 11) */
+ bool tree;
+
+ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS];
+} t_FmPcdModifyCcKeyAdditionalParams;
+
+typedef struct
+{
+ t_Handle h_Manip;
+ t_Handle h_CcNode;
+} t_CcNextEngineInfo;
+
+typedef struct
+{
+ uint16_t numOfKeys;
+ uint16_t maxNumOfKeys;
+
+ bool maskSupport;
+ uint32_t keysMatchTableMaxSize;
+
+ e_FmPcdCcStatsMode statisticsMode;
+ uint32_t numOfStatsFLRs;
+ uint32_t countersArraySize;
+
+ bool isHashBucket; /**< Valid for match table node that is a bucket of a hash table only */
+ t_Handle h_MissStatsCounters; /**< Valid for hash table node and match table that is a bucket;
+ Holds the statistics counters allocated by the hash table and
+ are shared by all hash table buckets; */
+ t_Handle h_PrivMissStatsCounters; /**< Valid for match table node that is a bucket of a hash table only;
+ Holds the statistics counters that were allocated for this node
+ and replaced by the shared counters (allocated by the hash table); */
+ bool statsEnForMiss; /**< Valid for hash table node only; TRUE is statistics are currently
+ enabled for hash 'miss', FALSE otherwise; This parameter effects the
+ returned statistics count to user, statistics AD always present for 'miss'
+ for all hash buckets; */
+ bool glblMaskUpdated;
+ t_Handle p_GlblMask;
+ bool lclMask;
+ uint8_t parseCode;
+ uint8_t offset;
+ uint8_t prsArrayOffset;
+ bool ctrlFlow;
+ uint16_t owners;
+
+ uint8_t ccKeySizeAccExtraction;
+ uint8_t sizeOfExtraction;
+ uint8_t glblMaskSize;
+
+ t_Handle h_KeysMatchTable;
+ t_Handle h_AdTable;
+ t_Handle h_StatsAds;
+ t_Handle h_TmpAd;
+ t_Handle h_Ad;
+ t_Handle h_StatsFLRs;
+
+ t_List availableStatsLst;
+
+ t_List ccPrevNodesLst;
+
+ t_List ccTreeIdLst;
+ t_List ccTreesLst;
+
+ t_Handle h_FmPcd;
+ uint32_t shadowAction;
+ uint8_t userSizeOfExtraction;
+ uint8_t userOffset;
+ uint8_t kgHashShift; /* used in hash-table */
+
+ t_Handle h_Spinlock;
+
+ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS];
+} t_FmPcdCcNode;
+
+typedef struct
+{
+ t_FmPcdCcNode *p_FmPcdCcNode;
+ bool occupied;
+ uint16_t owners;
+ volatile bool lock;
+} t_FmPcdCcNodeArray;
+
+typedef struct
+{
+ uint8_t numOfEntriesInGroup;
+ uint32_t totalBitsMask;
+ uint8_t baseGroupEntry;
+} t_FmPcdCcGroupParam;
+
+typedef struct
+{
+ t_Handle h_FmPcd;
+ uint8_t netEnvId;
+ uintptr_t ccTreeBaseAddr;
+ uint8_t numOfGrps;
+ t_FmPcdCcGroupParam fmPcdGroupParam[FM_PCD_MAX_NUM_OF_CC_GROUPS];
+ t_List fmPortsLst;
+ t_FmPcdLock *p_Lock;
+ uint8_t numOfEntries;
+ uint16_t owners;
+ t_Handle h_FmPcdCcSavedManipParams;
+ bool modifiedState;
+ uint32_t requiredAction;
+ t_Handle h_IpReassemblyManip;
+ t_Handle h_CapwapReassemblyManip;
+
+ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[FM_PCD_MAX_NUM_OF_CC_GROUPS];
+} t_FmPcdCcTree;
+
+
+t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List);
+void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List);
+t_Error FmPcdUpdateCcShadow (t_FmPcd *p_FmPcd, uint32_t size, uint32_t align);
+
+
+#endif /* __FM_CC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
new file mode 100644
index 000000000000..811a0de9c700
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c
@@ -0,0 +1,3246 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_kg.c
+
+ @Description FM PCD ...
+*//***************************************************************************/
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "net_ext.h"
+#include "fm_port_ext.h"
+
+#include "fm_common.h"
+#include "fm_pcd.h"
+#include "fm_hc.h"
+#include "fm_pcd_ipc.h"
+#include "fm_kg.h"
+#include "fsl_fman_kg.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+static uint32_t KgHwLock(t_Handle h_FmPcdKg)
+{
+ ASSERT_COND(h_FmPcdKg);
+ return XX_LockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock);
+}
+
+static void KgHwUnlock(t_Handle h_FmPcdKg, uint32_t intFlags)
+{
+ ASSERT_COND(h_FmPcdKg);
+ XX_UnlockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock, intFlags);
+}
+
+static uint32_t KgSchemeLock(t_Handle h_Scheme)
+{
+ ASSERT_COND(h_Scheme);
+ return FmPcdLockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
+}
+
+static void KgSchemeUnlock(t_Handle h_Scheme, uint32_t intFlags)
+{
+ ASSERT_COND(h_Scheme);
+ FmPcdUnlockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock, intFlags);
+}
+
+static bool KgSchemeFlagTryLock(t_Handle h_Scheme)
+{
+ ASSERT_COND(h_Scheme);
+ return FmPcdLockTryLock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
+}
+
+static void KgSchemeFlagUnlock(t_Handle h_Scheme)
+{
+ ASSERT_COND(h_Scheme);
+ FmPcdLockUnlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock);
+}
+
+static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t fmkg_ar)
+{
+
+ struct fman_kg_regs *regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ if (fman_kg_write_ar_wait(regs, fmkg_ar))
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation"));
+
+ return E_OK;
+}
+
+static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code)
+{
+ int i;
+
+ switch (code)
+ {
+ case (KG_SCH_GEN_PARSE_RESULT_N_FQID):
+ case (KG_SCH_GEN_DEFAULT):
+ case (KG_SCH_GEN_NEXTHDR):
+ for (i=0 ; i<numOfSwDefaults ; i++)
+ if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_NOT_FROM_DATA)
+ return swDefaults[i].dfltSelect;
+ break;
+ case (KG_SCH_GEN_SHIM1):
+ case (KG_SCH_GEN_SHIM2):
+ case (KG_SCH_GEN_IP_PID_NO_V):
+ case (KG_SCH_GEN_ETH_NO_V):
+ case (KG_SCH_GEN_SNAP_NO_V):
+ case (KG_SCH_GEN_VLAN1_NO_V):
+ case (KG_SCH_GEN_VLAN2_NO_V):
+ case (KG_SCH_GEN_ETH_TYPE_NO_V):
+ case (KG_SCH_GEN_PPP_NO_V):
+ case (KG_SCH_GEN_MPLS1_NO_V):
+ case (KG_SCH_GEN_MPLS_LAST_NO_V):
+ case (KG_SCH_GEN_L3_NO_V):
+ case (KG_SCH_GEN_IP2_NO_V):
+ case (KG_SCH_GEN_GRE_NO_V):
+ case (KG_SCH_GEN_L4_NO_V):
+ for (i=0 ; i<numOfSwDefaults ; i++)
+ if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V)
+ return swDefaults[i].dfltSelect;
+ break;
+ case (KG_SCH_GEN_START_OF_FRM):
+ case (KG_SCH_GEN_ETH):
+ case (KG_SCH_GEN_SNAP):
+ case (KG_SCH_GEN_VLAN1):
+ case (KG_SCH_GEN_VLAN2):
+ case (KG_SCH_GEN_ETH_TYPE):
+ case (KG_SCH_GEN_PPP):
+ case (KG_SCH_GEN_MPLS1):
+ case (KG_SCH_GEN_MPLS2):
+ case (KG_SCH_GEN_MPLS3):
+ case (KG_SCH_GEN_MPLS_LAST):
+ case (KG_SCH_GEN_IPV4):
+ case (KG_SCH_GEN_IPV6):
+ case (KG_SCH_GEN_IPV4_TUNNELED):
+ case (KG_SCH_GEN_IPV6_TUNNELED):
+ case (KG_SCH_GEN_MIN_ENCAP):
+ case (KG_SCH_GEN_GRE):
+ case (KG_SCH_GEN_TCP):
+ case (KG_SCH_GEN_UDP):
+ case (KG_SCH_GEN_IPSEC_AH):
+ case (KG_SCH_GEN_SCTP):
+ case (KG_SCH_GEN_DCCP):
+ case (KG_SCH_GEN_IPSEC_ESP):
+ for (i=0 ; i<numOfSwDefaults ; i++)
+ if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA)
+ return swDefaults[i].dfltSelect;
+ break;
+ default:
+ break;
+ }
+
+ return e_FM_PCD_KG_DFLT_ILLEGAL;
+}
+
+static uint8_t GetGenCode(e_FmPcdExtractFrom src, uint8_t *p_Offset)
+{
+ *p_Offset = 0;
+
+ switch (src)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_FRAME_START):
+ return KG_SCH_GEN_START_OF_FRM;
+ case (e_FM_PCD_EXTRACT_FROM_DFLT_VALUE):
+ return KG_SCH_GEN_DEFAULT;
+ case (e_FM_PCD_EXTRACT_FROM_PARSE_RESULT):
+ return KG_SCH_GEN_PARSE_RESULT_N_FQID;
+ case (e_FM_PCD_EXTRACT_FROM_ENQ_FQID):
+ *p_Offset = 32;
+ return KG_SCH_GEN_PARSE_RESULT_N_FQID;
+ case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE):
+ return KG_SCH_GEN_NEXTHDR;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src"));
+ return 0;
+ }
+}
+
+static uint8_t GetGenHdrCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, bool ignoreProtocolValidation)
+{
+ if (!ignoreProtocolValidation)
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ /* Else fall through */
+ case (HEADER_TYPE_ETH):
+ return KG_SCH_GEN_ETH;
+ case (HEADER_TYPE_LLC_SNAP):
+ return KG_SCH_GEN_SNAP;
+ case (HEADER_TYPE_PPPoE):
+ return KG_SCH_GEN_PPP;
+ case (HEADER_TYPE_MPLS):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_MPLS1;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
+ return KG_SCH_GEN_MPLS2;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_3)
+ return KG_SCH_GEN_MPLS3;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_GEN_MPLS_LAST;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
+ return 0;
+ case (HEADER_TYPE_IPv4):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_IPV4;
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_GEN_IPV4_TUNNELED;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 header index"));
+ return 0;
+ case (HEADER_TYPE_IPv6):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_IPV6;
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_GEN_IPV6_TUNNELED;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 header index"));
+ return 0;
+ case (HEADER_TYPE_GRE):
+ return KG_SCH_GEN_GRE;
+ case (HEADER_TYPE_TCP):
+ return KG_SCH_GEN_TCP;
+ case (HEADER_TYPE_UDP):
+ return KG_SCH_GEN_UDP;
+ case (HEADER_TYPE_IPSEC_AH):
+ return KG_SCH_GEN_IPSEC_AH;
+ case (HEADER_TYPE_IPSEC_ESP):
+ return KG_SCH_GEN_IPSEC_ESP;
+ case (HEADER_TYPE_SCTP):
+ return KG_SCH_GEN_SCTP;
+ case (HEADER_TYPE_DCCP):
+ return KG_SCH_GEN_DCCP;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ else
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ /* Else fall through */
+ case (HEADER_TYPE_ETH):
+ return KG_SCH_GEN_ETH_NO_V;
+ case (HEADER_TYPE_LLC_SNAP):
+ return KG_SCH_GEN_SNAP_NO_V;
+ case (HEADER_TYPE_PPPoE):
+ return KG_SCH_GEN_PPP_NO_V;
+ case (HEADER_TYPE_MPLS):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_MPLS1_NO_V;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_GEN_MPLS_LAST_NO_V;
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_3) )
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Indexed MPLS Extraction not supported"));
+ else
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index"));
+ return 0;
+ case (HEADER_TYPE_IPv4):
+ /* fall through */
+ case (HEADER_TYPE_IPv6):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_L3_NO_V;
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_GEN_IP2_NO_V;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index"));
+ /* fall through */
+ case (HEADER_TYPE_MINENCAP):
+ return KG_SCH_GEN_IP2_NO_V;
+ case (HEADER_TYPE_USER_DEFINED_L3):
+ return KG_SCH_GEN_L3_NO_V;
+ case (HEADER_TYPE_GRE):
+ return KG_SCH_GEN_GRE_NO_V;
+ case (HEADER_TYPE_TCP):
+ case (HEADER_TYPE_UDP):
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP):
+ case (HEADER_TYPE_SCTP):
+ case (HEADER_TYPE_DCCP):
+ return KG_SCH_GEN_L4_NO_V;
+ case (HEADER_TYPE_USER_DEFINED_SHIM1):
+ return KG_SCH_GEN_SHIM1;
+ case (HEADER_TYPE_USER_DEFINED_SHIM2):
+ return KG_SCH_GEN_SHIM2;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+}
+static t_GenericCodes GetGenFieldCode(e_NetHeaderType hdr, t_FmPcdFields field, bool ignoreProtocolValidation, e_FmPcdHdrIndex hdrIndex)
+{
+ if (!ignoreProtocolValidation)
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ break;
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ return KG_SCH_GEN_ETH_TYPE;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_VLAN1;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_GEN_VLAN2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_MPLS):
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP):
+ case (HEADER_TYPE_LLC_SNAP):
+ case (HEADER_TYPE_PPPoE):
+ case (HEADER_TYPE_IPv4):
+ case (HEADER_TYPE_IPv6):
+ case (HEADER_TYPE_GRE):
+ case (HEADER_TYPE_MINENCAP):
+ case (HEADER_TYPE_USER_DEFINED_L3):
+ case (HEADER_TYPE_TCP):
+ case (HEADER_TYPE_UDP):
+ case (HEADER_TYPE_SCTP):
+ case (HEADER_TYPE_DCCP):
+ case (HEADER_TYPE_USER_DEFINED_L4):
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ default:
+ break;
+
+ }
+ else
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ break;
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ return KG_SCH_GEN_ETH_TYPE_NO_V;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI) :
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_GEN_VLAN1_NO_V;
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_GEN_VLAN2_NO_V;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_IPv4):
+ switch (field.ipv4)
+ {
+ case (NET_HEADER_FIELD_IPv4_PROTO):
+ return KG_SCH_GEN_IP_PID_NO_V;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_IPv6):
+ switch (field.ipv6)
+ {
+ case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
+ return KG_SCH_GEN_IP_PID_NO_V;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ break;
+ case (HEADER_TYPE_MPLS):
+ case (HEADER_TYPE_LLC_SNAP):
+ case (HEADER_TYPE_PPPoE):
+ case (HEADER_TYPE_GRE):
+ case (HEADER_TYPE_MINENCAP):
+ case (HEADER_TYPE_USER_DEFINED_L3):
+ case (HEADER_TYPE_TCP):
+ case (HEADER_TYPE_UDP):
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP):
+ case (HEADER_TYPE_SCTP):
+ case (HEADER_TYPE_DCCP):
+ case (HEADER_TYPE_USER_DEFINED_L4):
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ default:
+ break;
+ }
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Header not supported"));
+ return 0;
+}
+
+static t_KnownFieldsMasks GetKnownProtMask(t_FmPcd *p_FmPcd, e_NetHeaderType hdr, e_FmPcdHdrIndex index, t_FmPcdFields field)
+{
+ UNUSED(p_FmPcd);
+
+ switch (hdr)
+ {
+ case (HEADER_TYPE_NONE):
+ ASSERT_COND(FALSE);
+ break;
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_DA):
+ return KG_SCH_KN_MACDST;
+ case (NET_HEADER_FIELD_ETH_SA):
+ return KG_SCH_KN_MACSRC;
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ return KG_SCH_KN_ETYPE;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_LLC_SNAP):
+ switch (field.llcSnap)
+ {
+ case (NET_HEADER_FIELD_LLC_SNAP_TYPE):
+ return KG_SCH_KN_ETYPE;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_TCI1;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_KN_TCI2;
+ else
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_MPLS):
+ switch (field.mpls)
+ {
+ case (NET_HEADER_FIELD_MPLS_LABEL_STACK):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_MPLS1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return KG_SCH_KN_MPLS2;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+ return KG_SCH_KN_MPLS_LAST;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index"));
+ return 0;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_IPv4):
+ switch (field.ipv4)
+ {
+ case (NET_HEADER_FIELD_IPv4_SRC_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPSRC1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPSRC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv4_DST_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPDST1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPDST2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv4_PROTO):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_PTYPE1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_PTYPE2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv4_TOS):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPTOS_TC1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPTOS_TC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index"));
+ return 0;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_IPv6):
+ switch (field.ipv6)
+ {
+ case (NET_HEADER_FIELD_IPv6_SRC_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPSRC1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPSRC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv6_DST_IP):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPDST1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPDST2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv6_NEXT_HDR):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_PTYPE1;
+ if (index == e_FM_PCD_HDR_INDEX_2)
+ return KG_SCH_KN_PTYPE2;
+ if (index == e_FM_PCD_HDR_INDEX_LAST)
+#ifdef FM_KG_NO_IPPID_SUPPORT
+ if (p_FmPcd->fmRevInfo.majorRev < 6)
+ return KG_SCH_KN_PTYPE2;
+#endif /* FM_KG_NO_IPPID_SUPPORT */
+ return KG_SCH_KN_IPPID;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return (KG_SCH_KN_IPV6FL1 | KG_SCH_KN_IPTOS_TC1);
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return (KG_SCH_KN_IPV6FL2 | KG_SCH_KN_IPTOS_TC2);
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_TC):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPTOS_TC1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPTOS_TC2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ case (NET_HEADER_FIELD_IPv6_FL):
+ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1))
+ return KG_SCH_KN_IPV6FL1;
+ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST))
+ return KG_SCH_KN_IPV6FL2;
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index"));
+ return 0;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_GRE):
+ switch (field.gre)
+ {
+ case (NET_HEADER_FIELD_GRE_TYPE):
+ return KG_SCH_KN_GREPTYPE;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_MINENCAP):
+ switch (field.minencap)
+ {
+ case (NET_HEADER_FIELD_MINENCAP_SRC_IP):
+ return KG_SCH_KN_IPSRC2;
+ case (NET_HEADER_FIELD_MINENCAP_DST_IP):
+ return KG_SCH_KN_IPDST2;
+ case (NET_HEADER_FIELD_MINENCAP_TYPE):
+ return KG_SCH_KN_PTYPE2;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_TCP):
+ switch (field.tcp)
+ {
+ case (NET_HEADER_FIELD_TCP_PORT_SRC):
+ return KG_SCH_KN_L4PSRC;
+ case (NET_HEADER_FIELD_TCP_PORT_DST):
+ return KG_SCH_KN_L4PDST;
+ case (NET_HEADER_FIELD_TCP_FLAGS):
+ return KG_SCH_KN_TFLG;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_UDP):
+ switch (field.udp)
+ {
+ case (NET_HEADER_FIELD_UDP_PORT_SRC):
+ return KG_SCH_KN_L4PSRC;
+ case (NET_HEADER_FIELD_UDP_PORT_DST):
+ return KG_SCH_KN_L4PDST;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_IPSEC_AH):
+ switch (field.ipsecAh)
+ {
+ case (NET_HEADER_FIELD_IPSEC_AH_SPI):
+ return KG_SCH_KN_IPSEC_SPI;
+ case (NET_HEADER_FIELD_IPSEC_AH_NH):
+ return KG_SCH_KN_IPSEC_NH;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_IPSEC_ESP):
+ switch (field.ipsecEsp)
+ {
+ case (NET_HEADER_FIELD_IPSEC_ESP_SPI):
+ return KG_SCH_KN_IPSEC_SPI;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_SCTP):
+ switch (field.sctp)
+ {
+ case (NET_HEADER_FIELD_SCTP_PORT_SRC):
+ return KG_SCH_KN_L4PSRC;
+ case (NET_HEADER_FIELD_SCTP_PORT_DST):
+ return KG_SCH_KN_L4PDST;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_DCCP):
+ switch (field.dccp)
+ {
+ case (NET_HEADER_FIELD_DCCP_PORT_SRC):
+ return KG_SCH_KN_L4PSRC;
+ case (NET_HEADER_FIELD_DCCP_PORT_DST):
+ return KG_SCH_KN_L4PDST;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ case (HEADER_TYPE_PPPoE):
+ switch (field.pppoe)
+ {
+ case (NET_HEADER_FIELD_PPPoE_PID):
+ return KG_SCH_KN_PPPID;
+ case (NET_HEADER_FIELD_PPPoE_SID):
+ return KG_SCH_KN_PPPSID;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+ }
+ default:
+ break;
+
+ }
+
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported"));
+ return 0;
+}
+
+
+static uint8_t GetKnownFieldId(uint32_t bitMask)
+{
+ uint8_t cnt = 0;
+
+ while (bitMask)
+ if (bitMask & 0x80000000)
+ break;
+ else
+ {
+ cnt++;
+ bitMask <<= 1;
+ }
+ return cnt;
+
+}
+
+static uint8_t GetExtractedOrMask(uint8_t bitOffset, bool fqid)
+{
+ uint8_t i, mask, numOfOnesToClear, walking1Mask = 1;
+
+ /* bitOffset 1-7 --> mask 0x1-0x7F */
+ if (bitOffset<8)
+ {
+ mask = 0;
+ for (i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1)
+ mask |= walking1Mask;
+ }
+ else
+ {
+ mask = 0xFF;
+ numOfOnesToClear = 0;
+ if (fqid && bitOffset>24)
+ /* bitOffset 25-31 --> mask 0xFE-0x80 */
+ numOfOnesToClear = (uint8_t)(bitOffset-24);
+ else
+ /* bitOffset 9-15 --> mask 0xFE-0x80 */
+ if (!fqid && bitOffset>8)
+ numOfOnesToClear = (uint8_t)(bitOffset-8);
+ for (i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1)
+ mask &= ~walking1Mask;
+ /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/
+ }
+ return mask;
+}
+
+static void IncSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
+{
+ t_FmPcdKg *p_FmPcdKg;
+ t_FmPcdKgScheme *p_Scheme;
+ uint32_t intFlags;
+ uint8_t relativeSchemeId;
+ int i;
+
+ p_FmPcdKg = p_FmPcd->p_FmPcdKg;
+
+ /* for each scheme - update owners counters */
+ for (i = 0; i < p_BindPort->numOfSchemes; i++)
+ {
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
+ ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES);
+
+ p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId];
+
+ /* increment owners number */
+ intFlags = KgSchemeLock(p_Scheme);
+ p_Scheme->owners++;
+ KgSchemeUnlock(p_Scheme, intFlags);
+ }
+}
+
+static void DecSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort)
+{
+ t_FmPcdKg *p_FmPcdKg;
+ t_FmPcdKgScheme *p_Scheme;
+ uint32_t intFlags;
+ uint8_t relativeSchemeId;
+ int i;
+
+ p_FmPcdKg = p_FmPcd->p_FmPcdKg;
+
+ /* for each scheme - update owners counters */
+ for (i = 0; i < p_BindPort->numOfSchemes; i++)
+ {
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
+ ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES);
+
+ p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId];
+
+ /* increment owners number */
+ ASSERT_COND(p_Scheme->owners);
+ intFlags = KgSchemeLock(p_Scheme);
+ p_Scheme->owners--;
+ KgSchemeUnlock(p_Scheme, intFlags);
+ }
+}
+
+static void UpdateRequiredActionFlag(t_FmPcdKgScheme *p_Scheme, bool set)
+{
+ /* this routine is locked by the calling routine */
+ ASSERT_COND(p_Scheme);
+ ASSERT_COND(p_Scheme->valid);
+
+ if (set)
+ p_Scheme->requiredActionFlag = TRUE;
+ else
+ {
+ p_Scheme->requiredAction = 0;
+ p_Scheme->requiredActionFlag = FALSE;
+ }
+}
+
+static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add)
+{
+ struct fman_kg_regs *p_KgRegs;
+
+ uint32_t tmpKgarReg = 0, intFlags;
+ t_Error err = E_OK;
+
+ /* The calling routine had locked the port, so for each port only one core can access
+ * (so we don't need a lock here) */
+
+ if (p_FmPcd->h_Hc)
+ return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add);
+
+ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId);
+ /* lock a common KG reg */
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ err = WriteKgarWait(p_FmPcd, tmpKgarReg);
+ if (err)
+ {
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ fman_kg_write_sp(p_KgRegs, spReg, add);
+
+ tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId);
+
+ err = WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ return err;
+}
+
+static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg)
+{
+ struct fman_kg_regs *p_KgRegs;
+ uint32_t tmpKgarReg, intFlags;
+ t_Error err;
+
+ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg);
+ return err;
+ }
+
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ fman_kg_write_cpp(p_KgRegs, cppReg);
+ tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId);
+ err = WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+
+ return err;
+}
+
+static uint32_t BuildCppReg(t_FmPcd *p_FmPcd, uint8_t clsPlanGrpId)
+{
+ uint32_t tmpKgpeCpp;
+
+ tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8);
+ tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_KG_PE_CPP_MASK_SHIFT);
+
+ return tmpKgpeCpp;
+}
+
+static t_Error BindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
+{
+ uint32_t tmpKgpeCpp = 0;
+
+ tmpKgpeCpp = BuildCppReg(p_FmPcd, clsPlanGrpId);
+ return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp);
+}
+
+static void UnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId)
+{
+ KgWriteCpp(p_FmPcd, hardwarePortId, 0);
+}
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+static uint32_t __attribute__((unused)) ReadClsPlanBlockActionReg(uint8_t grpId)
+{
+ return (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_READ |
+ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
+ DUMMY_PORT_ID |
+ ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
+ FM_PCD_KG_KGAR_WSEL_MASK);
+
+ /* if we ever want to write 1 by 1, use:
+ sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));
+ */
+}
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+static void PcdKgErrorException(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t event,schemeIndexes = 0, index = 0;
+ struct fman_kg_regs *p_KgRegs;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+ fman_kg_get_event(p_KgRegs, &event, &schemeIndexes);
+
+ if (event & FM_EX_KG_DOUBLE_ECC)
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC);
+ if (event & FM_EX_KG_KEYSIZE_OVERFLOW)
+ {
+ if (schemeIndexes)
+ {
+ while (schemeIndexes)
+ {
+ if (schemeIndexes & 0x1)
+ p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index));
+ schemeIndexes >>= 1;
+ index+=1;
+ }
+ }
+ else /* this should happen only when interrupt is forced. */
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW);
+ }
+}
+
+static t_Error KgInitGuest(t_FmPcd *p_FmPcd)
+{
+ t_Error err = E_OK;
+ t_FmPcdIpcKgSchemesParams kgAlloc;
+ uint32_t replyLength;
+ t_FmPcdIpcReply reply;
+ t_FmPcdIpcMsg msg;
+
+ ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID);
+
+ /* in GUEST_PARTITION, we use the IPC */
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams));
+ kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
+ kgAlloc.guestId = p_FmPcd->guestId;
+ msg.msgId = FM_PCD_ALLOC_KG_SCHEMES;
+ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
+ replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(kgAlloc),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t));
+
+ return (t_Error)reply.error;
+}
+
+static t_Error KgInitMaster(t_FmPcd *p_FmPcd)
+{
+ t_Error err = E_OK;
+ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+
+ if (p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC)
+ FmEnableRamsEcc(p_FmPcd->h_Fm);
+
+ fman_kg_init(p_Regs, p_FmPcd->exceptions, GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd));
+
+ /* register even if no interrupts enabled, to allow future enablement */
+ FmRegisterIntr(p_FmPcd->h_Fm,
+ e_FM_MOD_KG,
+ 0,
+ e_FM_INTR_TYPE_ERR,
+ PcdKgErrorException,
+ p_FmPcd);
+
+ fman_kg_enable_scheme_interrupts(p_Regs);
+
+ if (p_FmPcd->p_FmPcdKg->numOfSchemes)
+ {
+ err = FmPcdKgAllocSchemes(p_FmPcd,
+ p_FmPcd->p_FmPcdKg->numOfSchemes,
+ p_FmPcd->guestId,
+ p_FmPcd->p_FmPcdKg->schemesIds);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+static void ValidateSchemeSw(t_FmPcdKgScheme *p_Scheme)
+{
+ ASSERT_COND(!p_Scheme->valid);
+ if (p_Scheme->netEnvId != ILLEGAL_NETENV)
+ FmPcdIncNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId);
+ p_Scheme->valid = TRUE;
+}
+
+static t_Error InvalidateSchemeSw(t_FmPcdKgScheme *p_Scheme)
+{
+ if (p_Scheme->owners)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to"));
+
+ if (p_Scheme->netEnvId != ILLEGAL_NETENV)
+ FmPcdDecNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId);
+ p_Scheme->valid = FALSE;
+
+ return E_OK;
+}
+
+static t_Error BuildSchemeRegs(t_FmPcdKgScheme *p_Scheme,
+ t_FmPcdKgSchemeParams *p_SchemeParams,
+ struct fman_kg_scheme_regs *p_SchemeRegs)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Scheme->h_FmPcd);
+ uint32_t grpBits = 0;
+ uint8_t grpBase;
+ bool direct=TRUE, absolute=FALSE;
+ uint16_t profileId=0, numOfProfiles=0, relativeProfileId;
+ t_Error err = E_OK;
+ int i = 0;
+ t_NetEnvParams netEnvParams;
+ uint32_t tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp;
+ t_FmPcdKgKeyExtractAndHashParams *p_KeyAndHash = NULL;
+ uint8_t j, curr, idx;
+ uint8_t id, shift=0, code=0, offset=0, size=0;
+ t_FmPcdExtractEntry *p_Extract = NULL;
+ t_FmPcdKgExtractedOrParams *p_ExtractOr;
+ bool generic = FALSE;
+ t_KnownFieldsMasks bitMask;
+ e_FmPcdKgExtractDfltSelect swDefault = (e_FmPcdKgExtractDfltSelect)0;
+ t_FmPcdKgSchemesExtracts *p_LocalExtractsArray;
+ uint8_t numOfSwDefaults = 0;
+ t_FmPcdKgExtractDflt swDefaults[NUM_OF_SW_DEFAULTS];
+ uint8_t currGenId = 0;
+
+ memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt));
+ memset(p_SchemeRegs, 0, sizeof(struct fman_kg_scheme_regs));
+
+ if (p_SchemeParams->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS));
+
+ /* by netEnv parameters, get match vector */
+ if (!p_SchemeParams->alwaysDirect)
+ {
+ p_Scheme->netEnvId = FmPcdGetNetEnvId(p_SchemeParams->netEnvParams.h_NetEnv);
+ netEnvParams.netEnvId = p_Scheme->netEnvId;
+ netEnvParams.numOfDistinctionUnits = p_SchemeParams->netEnvParams.numOfDistinctionUnits;
+ memcpy(netEnvParams.unitIds, p_SchemeParams->netEnvParams.unitIds, (sizeof(uint8_t))*p_SchemeParams->netEnvParams.numOfDistinctionUnits);
+ err = PcdGetUnitsVector(p_FmPcd, &netEnvParams);
+ if (err)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ p_Scheme->matchVector = netEnvParams.vector;
+ }
+ else
+ {
+ p_Scheme->matchVector = SCHEME_ALWAYS_DIRECT;
+ p_Scheme->netEnvId = ILLEGAL_NETENV;
+ }
+
+ if (p_SchemeParams->nextEngine == e_FM_PCD_INVALID)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid"));
+
+ if (p_SchemeParams->bypassFqidGeneration)
+ {
+#ifdef FM_KG_NO_BYPASS_FQID_GEN
+ if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration."));
+#endif /* FM_KG_NO_BYPASS_FQID_GEN */
+ if (p_SchemeParams->baseFqid)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID"));
+ }
+ else
+ if (!p_SchemeParams->baseFqid)
+ DBG(WARNING, ("baseFqid is 0."));
+
+ if (p_SchemeParams->nextEngine == e_FM_PCD_PLCR)
+ {
+ direct = p_SchemeParams->kgNextEngineParams.plcrProfile.direct;
+ p_Scheme->directPlcr = direct;
+ absolute = (bool)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE);
+ if (!direct && absolute)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared."));
+
+ if (direct)
+ {
+ profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId;
+ numOfProfiles = 1;
+ }
+ else
+ {
+ profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
+ shift = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
+ numOfProfiles = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
+ }
+ }
+
+ if (p_SchemeParams->nextEngine == e_FM_PCD_CC)
+ {
+#ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN
+ if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && (p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
+ {
+ if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration."));
+ }
+#endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */
+
+ err = FmPcdCcGetGrpParams(p_SchemeParams->kgNextEngineParams.cc.h_CcTree,
+ p_SchemeParams->kgNextEngineParams.cc.grpId,
+ &grpBits,
+ &grpBase);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ p_Scheme->ccUnits = grpBits;
+
+ if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) &&
+ (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration))
+ {
+ if (p_SchemeParams->kgNextEngineParams.cc.plcrProfile.sharedProfile)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification."));
+ absolute = FALSE;
+ direct = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.direct;
+ if (direct)
+ {
+ profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId;
+ numOfProfiles = 1;
+ }
+ else
+ {
+ profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
+ shift = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift;
+ numOfProfiles = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles;
+ }
+ }
+ }
+
+ /* if policer is used directly after KG, or after CC */
+ if ((p_SchemeParams->nextEngine == e_FM_PCD_PLCR) ||
+ ((p_SchemeParams->nextEngine == e_FM_PCD_CC) &&
+ (p_SchemeParams->kgNextEngineParams.cc.plcrNext) &&
+ (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)))
+ {
+ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */
+ if (absolute)
+ {
+ /* for absolute direct policy only, */
+ relativeProfileId = profileId;
+ err = FmPcdPlcrGetAbsoluteIdByProfileParams((t_Handle)p_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset"));
+ if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileId))
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid."));
+ p_Scheme->relativeProfileId = profileId;
+ }
+ else
+ {
+ /* save relative profile id's for later check */
+ p_Scheme->nextRelativePlcrProfile = TRUE;
+ p_Scheme->relativeProfileId = profileId;
+ p_Scheme->numOfProfiles = numOfProfiles;
+ }
+ }
+ else
+ {
+ /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration
+ is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */
+ if (p_SchemeParams->bypassFqidGeneration && p_SchemeParams->numOfUsedExtractedOrs)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID"));
+ if (p_SchemeParams->bypassFqidGeneration &&
+ p_SchemeParams->useHash &&
+ p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID"));
+ }
+
+ /* configure all 21 scheme registers */
+ tmpReg = KG_SCH_MODE_EN;
+ switch (p_SchemeParams->nextEngine)
+ {
+ case (e_FM_PCD_PLCR):
+ /* add to mode register - NIA */
+ tmpReg |= KG_SCH_MODE_NIA_PLCR;
+ tmpReg |= NIA_ENG_PLCR;
+ tmpReg |= (uint32_t)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0);
+ /* initialize policer profile command - */
+ /* configure kgse_ppc */
+ if (direct)
+ /* use profileId as base, other fields are 0 */
+ p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
+ else
+ {
+ if (shift > MAX_PP_SHIFT)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
+
+ if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
+
+ ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
+ ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
+ ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
+ ppcTmp |= (uint32_t)profileId;
+
+ p_SchemeRegs->kgse_ppc = ppcTmp;
+ }
+ break;
+ case (e_FM_PCD_CC):
+ /* mode reg - define NIA */
+ tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC);
+
+ p_SchemeRegs->kgse_ccbs = grpBits;
+ tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT);
+
+ if (p_SchemeParams->kgNextEngineParams.cc.plcrNext)
+ {
+ if (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)
+ {
+ /* find out if absolute or relative */
+ if (absolute)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow"));
+ if (direct)
+ {
+ /* mask = 0, base = directProfileId */
+ p_SchemeRegs->kgse_ppc = (uint32_t)profileId;
+ }
+ else
+ {
+ if (shift > MAX_PP_SHIFT)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT));
+ if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
+
+ ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH;
+ ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW;
+ ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT);
+ ppcTmp |= (uint32_t)profileId;
+
+ p_SchemeRegs->kgse_ppc = ppcTmp;
+ }
+ }
+ }
+ break;
+ case (e_FM_PCD_DONE):
+ if (p_SchemeParams->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME)
+ tmpReg |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
+ else
+ tmpReg |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported"));
+ }
+ p_SchemeRegs->kgse_mode = tmpReg;
+
+ p_SchemeRegs->kgse_mv = p_Scheme->matchVector;
+
+#if (DPAA_VERSION >= 11)
+ if (p_SchemeParams->overrideStorageProfile)
+ {
+ p_SchemeRegs->kgse_om |= KG_SCH_OM_VSPE;
+
+ if (p_SchemeParams->storageProfile.direct)
+ {
+ profileId = p_SchemeParams->storageProfile.profileSelect.directRelativeProfileId;
+ shift = 0;
+ numOfProfiles = 1;
+ }
+ else
+ {
+ profileId = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase;
+ shift = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetShift;
+ numOfProfiles = p_SchemeParams->storageProfile.profileSelect.indirectProfile.numOfProfiles;
+ }
+ if (shift > MAX_SP_SHIFT)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_SP_SHIFT));
+
+ if (!numOfProfiles || !POWER_OF_2(numOfProfiles))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2"));
+
+ tmpReg = (uint32_t)shift << KG_SCH_VSP_SHIFT;
+ tmpReg |= ((uint32_t)(numOfProfiles-1) << KG_SCH_VSP_MASK_SHIFT);
+ tmpReg |= (uint32_t)profileId;
+
+
+ p_SchemeRegs->kgse_vsp = tmpReg;
+
+ p_Scheme->vspe = TRUE;
+
+ }
+ else
+ p_SchemeRegs->kgse_vsp = KG_SCH_VSP_NO_KSP_EN;
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_SchemeParams->useHash)
+ {
+ p_KeyAndHash = &p_SchemeParams->keyExtractAndHashParams;
+
+ if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range"));
+
+ /* configure kgse_dv0 */
+ p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0;
+
+ /* configure kgse_dv1 */
+ p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1;
+
+ if (!p_SchemeParams->bypassFqidGeneration)
+ {
+ if (!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2"));
+ if ((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_SchemeParams->baseFqid)
+ DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues."));
+ }
+
+ /* configure kgse_ekdv */
+ tmpReg = 0;
+ for ( i=0 ;i<p_KeyAndHash->numOfUsedDflts ; i++)
+ {
+ switch (p_KeyAndHash->dflts[i].type)
+ {
+ case (e_FM_PCD_KG_MAC_ADDR):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT);
+ break;
+ case (e_FM_PCD_KG_TCI):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT);
+ break;
+ case (e_FM_PCD_KG_ENET_TYPE):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT);
+ break;
+ case (e_FM_PCD_KG_PPP_SESSION_ID):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT);
+ break;
+ case (e_FM_PCD_KG_PPP_PROTOCOL_ID):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT);
+ break;
+ case (e_FM_PCD_KG_MPLS_LABEL):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT);
+ break;
+ case (e_FM_PCD_KG_IP_ADDR):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT);
+ break;
+ case (e_FM_PCD_KG_PROTOCOL_TYPE):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT);
+ break;
+ case (e_FM_PCD_KG_IP_TOS_TC):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT);
+ break;
+ case (e_FM_PCD_KG_IPV6_FLOW_LABEL):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
+ break;
+ case (e_FM_PCD_KG_IPSEC_SPI):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT);
+ break;
+ case (e_FM_PCD_KG_L4_PORT):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT);
+ break;
+ case (e_FM_PCD_KG_TCP_FLAG):
+ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT);
+ break;
+ case (e_FM_PCD_KG_GENERIC_FROM_DATA):
+ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA;
+ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
+ numOfSwDefaults ++;
+ break;
+ case (e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V):
+ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V;
+ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
+ numOfSwDefaults ++;
+ break;
+ case (e_FM_PCD_KG_GENERIC_NOT_FROM_DATA):
+ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA;
+ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect;
+ numOfSwDefaults ++;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ }
+ p_SchemeRegs->kgse_ekdv = tmpReg;
+
+ p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts));
+ if (!p_LocalExtractsArray)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+
+ /* configure kgse_ekfc and kgse_gec */
+ knownTmp = 0;
+ for ( i=0 ;i<p_KeyAndHash->numOfUsedExtracts ; i++)
+ {
+ p_Extract = &p_KeyAndHash->extractArray[i];
+ switch (p_Extract->type)
+ {
+ case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
+ knownTmp |= KG_SCH_KN_PORT_ID;
+ /* save in driver structure */
+ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID);
+ p_LocalExtractsArray->extractsArray[i].known = TRUE;
+ break;
+ case (e_FM_PCD_EXTRACT_BY_HDR):
+ switch (p_Extract->extractByHdr.hdr)
+ {
+#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ case (HEADER_TYPE_UDP_LITE):
+ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
+ break;
+#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+ case (HEADER_TYPE_UDP_ENCAP_ESP):
+ switch (p_Extract->extractByHdr.type)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_HDR):
+ /* case where extraction from ESP only */
+ if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE)
+ {
+ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
+ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE;
+ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
+ }
+ else
+ {
+ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
+ p_Extract->extractByHdr.ignoreProtocolValidation = FALSE;
+ }
+ break;
+ case (e_FM_PCD_EXTRACT_FROM_FIELD):
+ switch (p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp)
+ {
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
+ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
+ break;
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
+ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
+ /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/
+ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
+ break;
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
+ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
+ p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET;
+ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
+ break;
+ }
+ break;
+ case (e_FM_PCD_EXTRACT_FULL_FIELD):
+ switch (p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp)
+ {
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN):
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM):
+ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP;
+ break;
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI):
+ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
+ p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE;
+ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET;
+ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
+ break;
+ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM):
+ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP);
+ p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE;
+ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET;
+ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE;
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ switch (p_Extract->extractByHdr.type)
+ {
+ case (e_FM_PCD_EXTRACT_FROM_HDR):
+ generic = TRUE;
+ /* get the header code for the generic extract */
+ code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation);
+ /* set generic register fields */
+ offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset;
+ size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size;
+ break;
+ case (e_FM_PCD_EXTRACT_FROM_FIELD):
+ generic = TRUE;
+ /* get the field code for the generic extract */
+ code = GetGenFieldCode(p_Extract->extractByHdr.hdr,
+ p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex);
+ offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset;
+ size = p_Extract->extractByHdr.extractByHdrType.fromField.size;
+ break;
+ case (e_FM_PCD_EXTRACT_FULL_FIELD):
+ if (!p_Extract->extractByHdr.ignoreProtocolValidation)
+ {
+ /* if we have a known field for it - use it, otherwise use generic */
+ bitMask = GetKnownProtMask(p_FmPcd, p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex,
+ p_Extract->extractByHdr.extractByHdrType.fullField);
+ if (bitMask)
+ {
+ knownTmp |= bitMask;
+ /* save in driver structure */
+ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask);
+ p_LocalExtractsArray->extractsArray[i].known = TRUE;
+ }
+ else
+ generic = TRUE;
+ }
+ else
+ generic = TRUE;
+ if (generic)
+ {
+ /* tmp - till we cover more headers under generic */
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported"));
+ }
+ break;
+ default:
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+ case (e_FM_PCD_EXTRACT_NON_HDR):
+ /* use generic */
+ generic = TRUE;
+ offset = 0;
+ /* get the field code for the generic extract */
+ code = GetGenCode(p_Extract->extractNonHdr.src, &offset);
+ offset += p_Extract->extractNonHdr.offset;
+ size = p_Extract->extractNonHdr.size;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ if (generic)
+ {
+ /* set generic register fields */
+ if (currGenId >= FM_KG_NUM_OF_GENERIC_REGS)
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
+ }
+ if (!code)
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
+ }
+
+ genTmp = KG_SCH_GEN_VALID;
+ genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
+ genTmp |= offset;
+ if ((size > MAX_KG_SCH_SIZE) || (size < 1))
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)"));
+ }
+ genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT);
+ swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code);
+ if (swDefault == e_FM_PCD_KG_DFLT_ILLEGAL)
+ DBG(WARNING, ("No sw default configured"));
+ else
+ genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT;
+
+ genTmp |= KG_SCH_GEN_MASK;
+ p_SchemeRegs->kgse_gec[currGenId] = genTmp;
+ /* save in driver structure */
+ p_LocalExtractsArray->extractsArray[i].id = currGenId++;
+ p_LocalExtractsArray->extractsArray[i].known = FALSE;
+ generic = FALSE;
+ }
+ }
+ p_SchemeRegs->kgse_ekfc = knownTmp;
+
+ selectTmp = 0;
+ maskTmp = 0xFFFFFFFF;
+ /* configure kgse_bmch, kgse_bmcl and kgse_fqb */
+
+ if (p_KeyAndHash->numOfUsedMasks > FM_PCD_KG_NUM_OF_EXTRACT_MASKS)
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS));
+ }
+ for ( i=0 ;i<p_KeyAndHash->numOfUsedMasks ; i++)
+ {
+ /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */
+ id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id;
+ /* Get the shift of the select field (depending on i) */
+ GET_MASK_SEL_SHIFT(shift,i);
+ if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known)
+ selectTmp |= id << shift;
+ else
+ selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift;
+
+ /* Get the shift of the offset field (depending on i) - may
+ be in kgse_bmch or in kgse_fqb (depending on i) */
+ GET_MASK_OFFSET_SHIFT(shift,i);
+ if (i<=1)
+ selectTmp |= p_KeyAndHash->masks[i].offset << shift;
+ else
+ fqbTmp |= p_KeyAndHash->masks[i].offset << shift;
+
+ /* Get the shift of the mask field (depending on i) */
+ GET_MASK_SHIFT(shift,i);
+ /* pass all bits */
+ maskTmp |= KG_SCH_BITMASK_MASK << shift;
+ /* clear bits that need masking */
+ maskTmp &= ~(0xFF << shift) ;
+ /* set mask bits */
+ maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ;
+ }
+ p_SchemeRegs->kgse_bmch = selectTmp;
+ p_SchemeRegs->kgse_bmcl = maskTmp;
+ /* kgse_fqb will be written t the end of the routine */
+
+ /* configure kgse_hc */
+ if (p_KeyAndHash->hashShift > MAX_HASH_SHIFT)
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT));
+ }
+ if (p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT)
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT));
+ }
+
+ tmpReg = 0;
+
+ tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift);
+ tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT;
+
+ if (p_KeyAndHash->symmetricHash)
+ {
+ if ((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) ||
+ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) ||
+ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) ||
+ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST)))
+ {
+ XX_Free(p_LocalExtractsArray);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing"));
+ }
+ tmpReg |= KG_SCH_HASH_CONFIG_SYM;
+ }
+ p_SchemeRegs->kgse_hc = tmpReg;
+
+ /* build the return array describing the order of the extractions */
+
+ /* the last currGenId places of the array
+ are for generic extracts that are always last.
+ We now sort for the calculation of the order of the known
+ extractions we sort the known extracts between orderedArray[0] and
+ orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1].
+ for the calculation of the order of the generic extractions we use:
+ num_of_generic - currGenId
+ num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId
+ first_generic_index = num_of_known */
+ curr = 0;
+ for (i=0;i<p_KeyAndHash->numOfUsedExtracts ; i++)
+ {
+ if (p_LocalExtractsArray->extractsArray[i].known)
+ {
+ ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId));
+ j = curr;
+ /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original
+ index in the user's extractions array */
+ /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1]
+ location */
+ while ((j > 0) && (p_LocalExtractsArray->extractsArray[i].id <
+ p_LocalExtractsArray->extractsArray[p_Scheme->orderedArray[j-1]].id))
+ {
+ p_Scheme->orderedArray[j] =
+ p_Scheme->orderedArray[j-1];
+ j--;
+ }
+ p_Scheme->orderedArray[j] = (uint8_t)i;
+ curr++;
+ }
+ else
+ {
+ /* index is first_generic_index + generic index (id) */
+ idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id);
+ ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY);
+ p_Scheme->orderedArray[idx]= (uint8_t)i;
+ }
+ }
+ XX_Free(p_LocalExtractsArray);
+ }
+ else
+ {
+ /* clear all unused registers: */
+ p_SchemeRegs->kgse_ekfc = 0;
+ p_SchemeRegs->kgse_ekdv = 0;
+ p_SchemeRegs->kgse_bmch = 0;
+ p_SchemeRegs->kgse_bmcl = 0;
+ p_SchemeRegs->kgse_hc = 0;
+ p_SchemeRegs->kgse_dv0 = 0;
+ p_SchemeRegs->kgse_dv1 = 0;
+ }
+
+ if (p_SchemeParams->bypassFqidGeneration)
+ p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID;
+
+ /* configure kgse_spc */
+ if ( p_SchemeParams->schemeCounter.update)
+ p_SchemeRegs->kgse_spc = p_SchemeParams->schemeCounter.value;
+
+
+ /* check that are enough generic registers */
+ if (p_SchemeParams->numOfUsedExtractedOrs + currGenId > FM_KG_NUM_OF_GENERIC_REGS)
+ RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used"));
+
+ /* extracted OR mask on Qid */
+ for ( i=0 ;i<p_SchemeParams->numOfUsedExtractedOrs ; i++)
+ {
+
+ p_Scheme->extractedOrs = TRUE;
+ /* configure kgse_gec[i] */
+ p_ExtractOr = &p_SchemeParams->extractedOrs[i];
+ switch (p_ExtractOr->type)
+ {
+ case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO):
+ code = KG_SCH_GEN_PARSE_RESULT_N_FQID;
+ offset = 0;
+ break;
+ case (e_FM_PCD_EXTRACT_BY_HDR):
+ /* get the header code for the generic extract */
+ code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation);
+ /* set generic register fields */
+ offset = p_ExtractOr->extractionOffset;
+ break;
+ case (e_FM_PCD_EXTRACT_NON_HDR):
+ /* get the field code for the generic extract */
+ offset = 0;
+ code = GetGenCode(p_ExtractOr->src, &offset);
+ offset += p_ExtractOr->extractionOffset;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ /* set generic register fields */
+ if (!code)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
+ genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID;
+ genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT);
+ genTmp |= offset;
+ if (!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile"));
+
+ /************************************************************************************
+ bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter
+ in the following way:
+
+ Driver API and implementation:
+ ==============================
+ FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID.
+ if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that
+ are not overlapping FQID.
+ ------------------------
+ | FQID (24) |
+ ------------------------
+ --------
+ | | extracted OR byte
+ --------
+
+ Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the
+ PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that
+ are not overlapping PP id.
+
+ --------
+ | PP (8) |
+ --------
+ --------
+ | | extracted OR byte
+ --------
+
+ HW implementation
+ =================
+ FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located
+ as the highest byte of that word and may be rotated to effect any part os the FQID or
+ the PP.
+ ------------------------ --------
+ | FQID (24) || PP (8) |
+ ------------------------ --------
+ --------
+ | | extracted OR byte
+ --------
+
+ ************************************************************************************/
+
+ if (p_ExtractOr->bitOffsetInFqid)
+ {
+ if (p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET )
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)"));
+ if (p_ExtractOr->bitOffsetInFqid<8)
+ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT);
+ else
+ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT);
+ p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE);
+ }
+ else /* effect policer profile */
+ {
+ if (p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET )
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)"));
+ p_Scheme->bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile;
+ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT);
+ p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE);
+ }
+
+ genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT);
+ /* clear bits that need masking */
+ genTmp &= ~KG_SCH_GEN_MASK ;
+ /* set mask bits */
+ genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT);
+ p_SchemeRegs->kgse_gec[currGenId++] = genTmp;
+
+ }
+ /* clear all unused GEC registers */
+ for ( i=currGenId ;i<FM_KG_NUM_OF_GENERIC_REGS ; i++)
+ p_SchemeRegs->kgse_gec[i] = 0;
+
+ /* add base Qid for this scheme */
+ /* add configuration for kgse_fqb */
+ if (p_SchemeParams->baseFqid & ~0x00FFFFFF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1"));
+
+ fqbTmp |= p_SchemeParams->baseFqid;
+ p_SchemeRegs->kgse_fqb = fqbTmp;
+
+ p_Scheme->nextEngine = p_SchemeParams->nextEngine;
+ p_Scheme->doneAction = p_SchemeParams->kgNextEngineParams.doneAction;
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp;
+ t_FmPcdIpcKgClsPlanParams kgAlloc;
+ t_Error err = E_OK;
+ uint32_t oredVectors = 0;
+ int i, j;
+
+ /* this routine is protected by the calling routine ! */
+ if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected."));
+
+ /* find a new clsPlan group */
+ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++)
+ if (!p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used)
+ break;
+ if (i == FM_MAX_NUM_OF_PORTS)
+ RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available."));
+
+ p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE;
+
+ p_Grp->clsPlanGrpId = (uint8_t)i;
+
+ if (p_Grp->numOfOptions == 0)
+ p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i;
+
+ p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i];
+ p_ClsPlanGrp->netEnvId = p_Grp->netEnvId;
+ p_ClsPlanGrp->owners = 0;
+ FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId);
+ if (p_Grp->numOfOptions != 0)
+ FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId);
+
+ p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1 << p_Grp->numOfOptions);
+ /* a minimal group of 8 is required */
+ if (p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP)
+ p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP;
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry);
+
+ if (err)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG);
+ }
+ else
+ {
+ t_FmPcdIpcMsg msg;
+ uint32_t replyLength;
+ t_FmPcdIpcReply reply;
+
+ /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ memset(&kgAlloc, 0, sizeof(kgAlloc));
+ kgAlloc.guestId = p_FmPcd->guestId;
+ kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
+ msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN;
+ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
+ replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry));
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(kgAlloc),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ if ((t_Error)reply.error != E_OK)
+ RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG);
+
+ p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody);
+ }
+
+ /* build classification plan entries parameters */
+ p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry;
+ p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp;
+
+ oredVectors = 0;
+ for (i = 0; i<p_Grp->numOfOptions; i++)
+ {
+ oredVectors |= p_Grp->optVectors[i];
+ /* save an array of used options - the indexes represent the power of 2 index */
+ p_ClsPlanGrp->optArray[i] = p_Grp->options[i];
+ }
+ /* set the classification plan relevant entries so that all bits
+ * relevant to the list of options is cleared
+ */
+ for (j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
+ p_ClsPlanSet->vectors[j] = ~oredVectors;
+
+ for (i = 0; i<p_Grp->numOfOptions; i++)
+ {
+ /* option i got the place 2^i in the clsPlan array. all entries that
+ * have bit i set, should have the vector bit cleared. So each option
+ * has one location that it is exclusive (1,2,4,8...) and represent the
+ * presence of that option only, and other locations that represent a
+ * combination of options.
+ * e.g:
+ * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2
+ * now represents a frame with ethernet-BC header - so the bit
+ * representing ethernet-BC should be set and all other option bits
+ * should be cleared.
+ * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit
+ * vector[1] set, but they also have other bits set:
+ * 3=1+2, options 0 and 1
+ * 6=2+4, options 1 and 2
+ * 7=1+2+4, options 0,1,and 2
+ * 10=2+8, options 1 and 3
+ * etc.
+ * */
+
+ /* now for each option (i), we set their bits in all entries (j)
+ * that contain bit 2^i.
+ */
+ for (j = 0; j<p_ClsPlanGrp->sizeOfGrp; j++)
+ {
+ if (j & (1<<i))
+ p_ClsPlanSet->vectors[j] |= p_Grp->optVectors[i];
+ }
+ }
+
+ return E_OK;
+}
+
+void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdIpcKgClsPlanParams kgAlloc;
+ t_Error err;
+ t_FmPcdIpcMsg msg;
+ uint32_t replyLength;
+ t_FmPcdIpcReply reply;
+
+ /* check that no port is bound to this clsPlan */
+ if (p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners)
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to"));
+ return;
+ }
+
+ FmPcdSetClsPlanGrpId(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId, ILLEGAL_CLS_PLAN);
+
+ if (grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
+ p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
+ else
+ FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId);
+
+ /* free blocks */
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ KgFreeClsPlanEntries(h_FmPcd,
+ p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp,
+ p_FmPcd->guestId,
+ p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry);
+ else /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */
+ {
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ kgAlloc.guestId = p_FmPcd->guestId;
+ kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp;
+ kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry;
+ msg.msgId = FM_PCD_FREE_KG_CLSPLAN;
+ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
+ replyLength = sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(kgAlloc),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+ if (replyLength != sizeof(uint32_t))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return;
+ }
+ if ((t_Error)reply.error != E_OK)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed"));
+ return;
+ }
+ }
+
+ /* clear clsPlan driver structure */
+ memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp));
+}
+
+t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t j, schemesPerPortVector = 0;
+ t_FmPcdKgScheme *p_Scheme;
+ uint8_t i, relativeSchemeId;
+ uint32_t tmp, walking1Mask;
+ uint8_t swPortIndex = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+
+ /* for each scheme */
+ for (i = 0; i<p_BindPort->numOfSchemes; i++)
+ {
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]);
+ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ if (add)
+ {
+ p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
+ if (!FmPcdKgIsSchemeValidSw(p_Scheme))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid."));
+ /* check netEnvId of the port against the scheme netEnvId */
+ if ((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId"));
+
+ /* if next engine is private port policer profile, we need to check that it is valid */
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId);
+ if (p_Scheme->nextRelativePlcrProfile)
+ {
+ for (j = 0;j<p_Scheme->numOfProfiles;j++)
+ {
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort);
+ if (p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range"));
+ if (!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j)))
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid."));
+ }
+ }
+ if (!p_BindPort->useClsPlan)
+ {
+ /* This check may be redundant as port is a assigned to the whole NetEnv */
+
+ /* if this port does not use clsPlan, it may not be bound to schemes with units that contain
+ cls plan options. Schemes that are used only directly, should not be checked.
+ it also may not be bound to schemes that go to CC with units that are options - so we OR
+ the match vector and the grpBits (= ccUnits) */
+ if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits)
+ {
+ uint8_t netEnvId;
+ walking1Mask = 0x80000000;
+ netEnvId = (p_Scheme->netEnvId == ILLEGAL_NETENV)? p_BindPort->netEnvId:p_Scheme->netEnvId;
+ tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector;
+ tmp |= p_Scheme->ccUnits;
+ while (tmp)
+ {
+ if (tmp & walking1Mask)
+ {
+ tmp &= ~walking1Mask;
+ if (!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, netEnvId, walking1Mask))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options"));
+ }
+ walking1Mask >>= 1;
+ }
+ }
+ }
+ }
+ /* build vector */
+ schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]);
+ }
+
+ *p_SpReg = schemesPerPortVector;
+
+ return E_OK;
+}
+
+t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t spReg;
+ t_Error err = E_OK;
+
+ err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ IncSchemeOwners(p_FmPcd, p_SchemeBind);
+
+ return E_OK;
+}
+
+t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t spReg;
+ t_Error err = E_OK;
+
+ err = FmPcdKgBuildBindPortToSchemes(p_FmPcd, p_SchemeBind, &spReg, FALSE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ DecSchemeOwners(p_FmPcd, p_SchemeBind);
+
+ return E_OK;
+}
+
+bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme)
+{
+ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme;
+
+ return p_Scheme->valid;
+}
+
+bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ if (p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint8_t i, j;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
+
+ /* This routine is issued only on master core of master partition -
+ either directly or through IPC, so no need for lock */
+
+ for (j = 0, i = 0; i < FM_PCD_KG_NUM_OF_SCHEMES && j < numOfSchemes; i++)
+ {
+ if (!p_FmPcd->p_FmPcdKg->schemesMng[i].allocated)
+ {
+ p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE;
+ p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId;
+ p_SchemesIds[j] = i;
+ j++;
+ }
+ }
+
+ if (j != numOfSchemes)
+ {
+ /* roll back */
+ for (j--; j; j--)
+ {
+ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE;
+ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0;
+ p_SchemesIds[j] = 0;
+ }
+
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found"));
+ }
+
+ return E_OK;
+}
+
+t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint8_t i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE);
+
+ /* This routine is issued only on master core of master partition -
+ either directly or through IPC */
+
+ for (i = 0; i < numOfSchemes; i++)
+ {
+ if (!p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated"));
+ }
+ if (p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. "));
+ }
+ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE;
+ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0;
+ }
+
+ return E_OK;
+}
+
+t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint8_t numOfBlocks, blocksFound=0, first=0;
+ uint8_t i, j;
+
+ /* This routine is issued only on master core of master partition -
+ either directly or through IPC, so no need for lock */
+
+ if (!numOfClsPlanEntries)
+ return E_OK;
+
+ if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8"));
+
+ numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
+
+ /* try to find consequent blocks */
+ first = 0;
+ for (i = 0; i < FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;)
+ {
+ if (!p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated)
+ {
+ blocksFound++;
+ i++;
+ if (blocksFound == numOfBlocks)
+ break;
+ }
+ else
+ {
+ blocksFound = 0;
+ /* advance i to the next aligned address */
+ first = i = (uint8_t)(first + numOfBlocks);
+ }
+ }
+
+ if (blocksFound == numOfBlocks)
+ {
+ *p_First = (uint8_t)(first * CLS_PLAN_NUM_PER_GRP);
+ for (j = first; j < (first + numOfBlocks); j++)
+ {
+ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE;
+ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId;
+ }
+ return E_OK;
+ }
+ else
+ RETURN_ERROR(MINOR, E_FULL, ("No resources for clsPlan"));
+}
+
+void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint8_t numOfBlocks;
+ uint8_t i, baseBlock;
+
+#ifdef DISABLE_ASSERTIONS
+UNUSED(guestId);
+#endif /* DISABLE_ASSERTIONS */
+
+ /* This routine is issued only on master core of master partition -
+ either directly or through IPC, so no need for lock */
+
+ numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP);
+ ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP));
+
+ baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP);
+ for (i=baseBlock;i<baseBlock+numOfBlocks;i++)
+ {
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated);
+ ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId);
+ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE;
+ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0;
+ }
+}
+
+void KgEnable(t_FmPcd *p_FmPcd)
+{
+ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ fman_kg_enable(p_Regs);
+}
+
+void KgDisable(t_FmPcd *p_FmPcd)
+{
+ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ fman_kg_disable(p_Regs);
+}
+
+void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ struct fman_kg_cp_regs *p_FmPcdKgPortRegs;
+ uint32_t tmpKgarReg = 0, intFlags;
+ uint16_t i, j;
+
+ /* This routine is protected by the calling routine ! */
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->clsPlanRegs;
+
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ for (i=p_Set->baseEntry;i<p_Set->baseEntry+p_Set->numOfClsPlanEntries;i+=8)
+ {
+ tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP));
+
+ for (j = i; j < i+8; j++)
+ {
+ ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1));
+ WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]);
+ }
+
+ if (WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED"));
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ return;
+ }
+ }
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+}
+
+t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
+{
+ t_FmPcdKg *p_FmPcdKg;
+
+ UNUSED(p_FmPcd);
+
+ if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES));
+ return NULL;
+ }
+
+ p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg));
+ if (!p_FmPcdKg)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED"));
+ return NULL;
+ }
+ memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg));
+
+
+ if (FmIsMaster(p_FmPcd->h_Fm))
+ {
+ p_FmPcdKg->p_FmPcdKgRegs = (struct fman_kg_regs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm));
+ p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions;
+ p_FmPcdKg->p_IndirectAccessRegs = (u_FmPcdKgIndirectAccessRegs *)&p_FmPcdKg->p_FmPcdKgRegs->fmkg_indirect[0];
+ }
+
+ p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes;
+ if ((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes)
+ {
+ p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES;
+ DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES"));
+ }
+
+ p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN;
+
+ return p_FmPcdKg;
+}
+
+t_Error KgInit(t_FmPcd *p_FmPcd)
+{
+ t_Error err = E_OK;
+
+ p_FmPcd->p_FmPcdKg->h_HwSpinlock = XX_InitSpinlock();
+ if (!p_FmPcd->p_FmPcdKg->h_HwSpinlock)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM KG HW spinlock"));
+
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ err = KgInitMaster(p_FmPcd);
+ else
+ err = KgInitGuest(p_FmPcd);
+
+ if (err != E_OK)
+ {
+ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
+ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
+ }
+
+ return err;
+}
+
+t_Error KgFree(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdIpcKgSchemesParams kgAlloc;
+ t_Error err = E_OK;
+ t_FmPcdIpcMsg msg;
+ uint32_t replyLength;
+ t_FmPcdIpcReply reply;
+
+ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR);
+
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ err = FmPcdKgFreeSchemes(p_FmPcd,
+ p_FmPcd->p_FmPcdKg->numOfSchemes,
+ p_FmPcd->guestId,
+ p_FmPcd->p_FmPcdKg->schemesIds);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
+ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
+
+ return E_OK;
+ }
+
+ /* guest */
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes;
+ kgAlloc.guestId = p_FmPcd->guestId;
+ ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES);
+ memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds, (sizeof(uint8_t))*kgAlloc.numOfSchemes);
+ msg.msgId = FM_PCD_FREE_KG_SCHEMES;
+ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc));
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(kgAlloc),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+
+ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock)
+ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock);
+
+ return (t_Error)reply.error;
+}
+
+t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdKgInterModuleClsPlanGrpParams grpParams, *p_GrpParams;
+ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp;
+ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet;
+ t_Error err;
+
+ /* This function is issued only from FM_PORT_SetPcd which locked all PCD modules,
+ so no need for lock here */
+
+ memset(&grpParams, 0, sizeof(grpParams));
+ grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN;
+ p_GrpParams = &grpParams;
+
+ p_GrpParams->netEnvId = netEnvId;
+
+ /* Get from the NetEnv the information of the clsPlan (can be already created,
+ * or needs to build) */
+ err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams);
+ if (err)
+ RETURN_ERROR(MINOR,err,NO_MSG);
+
+ if (p_GrpParams->grpExists)
+ {
+ /* this group was already updated (at least) in SW */
+ *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
+ }
+ else
+ {
+ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
+ if (!p_ClsPlanSet)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
+ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
+ /* Build (in SW) the clsPlan parameters, including the vectors to be written to HW */
+ err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet);
+ if (err)
+ {
+ XX_Free(p_ClsPlanSet);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+ *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId;
+
+ if (p_FmPcd->h_Hc)
+ {
+ /* write clsPlan entries to memory */
+ err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet);
+ if (err)
+ {
+ XX_Free(p_ClsPlanSet);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+ else
+ /* write clsPlan entries to memory */
+ KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
+
+ XX_Free(p_ClsPlanSet);
+ }
+
+ /* Set caller parameters */
+
+ /* mark if this is an empty classification group */
+ if (*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId)
+ *p_IsEmptyClsPlanGrp = TRUE;
+ else
+ *p_IsEmptyClsPlanGrp = FALSE;
+
+ p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId];
+
+ /* increment owners number */
+ p_ClsPlanGrp->owners++;
+
+ /* copy options array for port */
+ memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t));
+
+ /* bind port to the new or existing group */
+ err = BindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId];
+ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet;
+ t_Error err;
+
+ /* This function is issued only from FM_PORT_DeletePcd which locked all PCD modules,
+ so no need for lock here */
+
+ UnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId);
+
+ /* decrement owners number */
+ ASSERT_COND(p_ClsPlanGrp->owners);
+ p_ClsPlanGrp->owners--;
+
+ if (!p_ClsPlanGrp->owners)
+ {
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId);
+ return err;
+ }
+ else
+ {
+ /* clear clsPlan entries in memory */
+ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet));
+ if (!p_ClsPlanSet)
+ {
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set"));
+ }
+ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet));
+
+ p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry;
+ p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp;
+ KgSetClsPlan(p_FmPcd, p_ClsPlanSet);
+ XX_Free(p_ClsPlanSet);
+
+ FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId);
+ }
+ }
+ return E_OK;
+}
+
+uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction;
+}
+
+uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredActionFlag;
+}
+
+bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr;
+}
+
+
+uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId;
+}
+
+bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ if ((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs &&
+ p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) ||
+ p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile)
+ return TRUE;
+ else
+ return FALSE;
+
+}
+
+e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t relativeSchemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine;
+}
+
+e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid);
+
+ return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction;
+}
+
+void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction)
+{
+ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme;
+
+ /* this routine is protected by calling routine */
+
+ ASSERT_COND(p_Scheme->valid);
+
+ p_Scheme->requiredAction |= requiredAction;
+}
+
+bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg)
+{
+ return (bool)!!(schemeModeReg & KG_SCH_MODE_EN);
+}
+
+uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter)
+{
+ return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) |
+ FM_KG_KGAR_GO |
+ FM_KG_KGAR_WRITE |
+ FM_KG_KGAR_SEL_SCHEME_ENTRY |
+ DUMMY_PORT_ID |
+ (updateCounter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT:0));
+}
+
+uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId)
+{
+ return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) |
+ FM_KG_KGAR_GO |
+ FM_KG_KGAR_READ |
+ FM_KG_KGAR_SEL_SCHEME_ENTRY |
+ DUMMY_PORT_ID |
+ FM_KG_KGAR_SCM_WSEL_UPDATE_CNT);
+
+}
+
+uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId)
+{
+ return (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_WRITE |
+ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
+ DUMMY_PORT_ID |
+ ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) |
+ FM_PCD_KG_KGAR_WSEL_MASK);
+
+ /* if we ever want to write 1 by 1, use:
+ sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));
+ */
+}
+
+uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId)
+{
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_WRITE |
+ FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
+ hardwarePortId |
+ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
+}
+
+uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId)
+{
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_READ |
+ FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
+ hardwarePortId |
+ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
+}
+
+uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId)
+{
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_WRITE |
+ FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
+ hardwarePortId |
+ FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
+}
+
+uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry;
+}
+
+uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp;
+}
+
+
+uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme)
+{
+ return ((t_FmPcdKgScheme*)h_Scheme)->schemeId;
+
+}
+
+#if (DPAA_VERSION >= 11)
+bool FmPcdKgGetVspe(t_Handle h_Scheme)
+{
+ return ((t_FmPcdKgScheme*)h_Scheme)->vspe;
+
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint8_t i;
+
+ for (i = 0;i<p_FmPcd->p_FmPcdKg->numOfSchemes;i++)
+ if (p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId)
+ return i;
+
+ if (i == p_FmPcd->p_FmPcdKg->numOfSchemes)
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range"));
+
+ return FM_PCD_KG_NUM_OF_SCHEMES;
+}
+
+t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd);
+
+ /* check that schemeId is in range */
+ if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId));
+ return NULL;
+ }
+
+ if (!FmPcdKgIsSchemeValidSw(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]))
+ return NULL;
+
+ return &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
+}
+
+bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme)
+{
+ return (((t_FmPcdKgScheme*)h_Scheme)->owners == 0)?FALSE:TRUE;
+}
+
+t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint8_t relativeSchemeId, physicalSchemeId;
+ uint32_t tmpKgarReg, tmpReg32 = 0, intFlags;
+ t_Error err;
+ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
+
+ /* Calling function locked all PCD modules, so no need to lock here */
+
+ if (!FmPcdKgIsSchemeValidSw(h_Scheme))
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction, value);
+
+ UpdateRequiredActionFlag(h_Scheme,TRUE);
+ FmPcdKgUpdateRequiredAction(h_Scheme,requiredAction);
+ return err;
+ }
+
+ physicalSchemeId = p_Scheme->schemeId;
+
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
+ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredActionFlag ||
+ !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction))
+ {
+ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ {
+ switch (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine)
+ {
+ case (e_FM_PCD_DONE):
+ if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME)
+ {
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
+ ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA);
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ }
+ break;
+ case (e_FM_PCD_PLCR):
+ if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr ||
+ (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs &&
+ p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) ||
+ p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile)
+ {
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared"));
+ }
+ err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction);
+ if (err)
+ {
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME"));
+ }
+ }
+ if (requiredAction & UPDATE_KG_NIA_CC_WA)
+ {
+ if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine == e_FM_PCD_CC)
+ {
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
+ ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
+ tmpReg32 &= ~NIA_FM_CTL_AC_CC;
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_FM_CTL_AC_PRE_CC);
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ }
+ }
+ if (requiredAction & UPDATE_KG_OPT_MODE)
+ {
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_om, value);
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ }
+ if (requiredAction & UPDATE_KG_NIA)
+ {
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode);
+ tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK);
+ tmpReg32 |= value;
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32);
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ }
+ }
+
+ UpdateRequiredActionFlag(h_Scheme, TRUE);
+ FmPcdKgUpdateRequiredAction(h_Scheme, requiredAction);
+
+ return E_OK;
+}
+/*********************** End of inter-module routines ************************/
+
+
+/****************************************/
+/* API routines */
+/****************************************/
+
+t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_SchemeParams)
+{
+ t_FmPcd *p_FmPcd;
+ struct fman_kg_scheme_regs schemeRegs;
+ struct fman_kg_scheme_regs *p_MemRegs;
+ uint8_t i;
+ t_Error err = E_OK;
+ uint32_t tmpKgarReg;
+ uint32_t intFlags;
+ uint8_t physicalSchemeId, relativeSchemeId = 0;
+ t_FmPcdKgScheme *p_Scheme;
+
+ if (p_SchemeParams->modify)
+ {
+ p_Scheme = (t_FmPcdKgScheme *)p_SchemeParams->id.h_Scheme;
+ p_FmPcd = p_Scheme->h_FmPcd;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL);
+
+ if (!FmPcdKgIsSchemeValidSw(p_Scheme))
+ {
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS,
+ ("Scheme is invalid"));
+ return NULL;
+ }
+
+ if (!KgSchemeFlagTryLock(p_Scheme))
+ {
+ DBG(TRACE, ("Scheme Try Lock - BUSY"));
+ /* Signal to caller BUSY condition */
+ p_SchemeParams->id.h_Scheme = NULL;
+ return NULL;
+ }
+ }
+ else
+ {
+ p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL);
+
+ relativeSchemeId = p_SchemeParams->id.relativeSchemeId;
+ /* check that schemeId is in range */
+ if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId));
+ return NULL;
+ }
+
+ p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId];
+ if (FmPcdKgIsSchemeValidSw(p_Scheme))
+ {
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS,
+ ("Scheme id (%d)!", relativeSchemeId));
+ return NULL;
+ }
+ /* Clear all fields, scheme may have beed previously used */
+ memset(p_Scheme, 0, sizeof(t_FmPcdKgScheme));
+
+ p_Scheme->schemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId];
+ p_Scheme->h_FmPcd = p_FmPcd;
+
+ p_Scheme->p_Lock = FmPcdAcquireLock(p_FmPcd);
+ if (!p_Scheme->p_Lock)
+ REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM KG Scheme lock obj!"));
+ }
+
+ err = BuildSchemeRegs((t_Handle)p_Scheme, p_SchemeParams, &schemeRegs);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ if (p_SchemeParams->modify)
+ KgSchemeFlagUnlock(p_Scheme);
+ if (!p_SchemeParams->modify &&
+ p_Scheme->p_Lock)
+ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
+ return NULL;
+ }
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdKgSetScheme(p_FmPcd->h_Hc,
+ (t_Handle)p_Scheme,
+ &schemeRegs,
+ p_SchemeParams->schemeCounter.update);
+ if (p_SchemeParams->modify)
+ KgSchemeFlagUnlock(p_Scheme);
+ if (err)
+ {
+ if (!p_SchemeParams->modify &&
+ p_Scheme->p_Lock)
+ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
+ return NULL;
+ }
+ if (!p_SchemeParams->modify)
+ ValidateSchemeSw(p_Scheme);
+ return (t_Handle)p_Scheme;
+ }
+
+ physicalSchemeId = p_Scheme->schemeId;
+
+ /* configure all 21 scheme registers */
+ p_MemRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs;
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WRITE_UINT32(p_MemRegs->kgse_ppc, schemeRegs.kgse_ppc);
+ WRITE_UINT32(p_MemRegs->kgse_ccbs, schemeRegs.kgse_ccbs);
+ WRITE_UINT32(p_MemRegs->kgse_mode, schemeRegs.kgse_mode);
+ WRITE_UINT32(p_MemRegs->kgse_mv, schemeRegs.kgse_mv);
+ WRITE_UINT32(p_MemRegs->kgse_dv0, schemeRegs.kgse_dv0);
+ WRITE_UINT32(p_MemRegs->kgse_dv1, schemeRegs.kgse_dv1);
+ WRITE_UINT32(p_MemRegs->kgse_ekdv, schemeRegs.kgse_ekdv);
+ WRITE_UINT32(p_MemRegs->kgse_ekfc, schemeRegs.kgse_ekfc);
+ WRITE_UINT32(p_MemRegs->kgse_bmch, schemeRegs.kgse_bmch);
+ WRITE_UINT32(p_MemRegs->kgse_bmcl, schemeRegs.kgse_bmcl);
+ WRITE_UINT32(p_MemRegs->kgse_hc, schemeRegs.kgse_hc);
+ WRITE_UINT32(p_MemRegs->kgse_spc, schemeRegs.kgse_spc);
+ WRITE_UINT32(p_MemRegs->kgse_fqb, schemeRegs.kgse_fqb);
+ WRITE_UINT32(p_MemRegs->kgse_om, schemeRegs.kgse_om);
+ WRITE_UINT32(p_MemRegs->kgse_vsp, schemeRegs.kgse_vsp);
+ for (i=0 ; i<FM_KG_NUM_OF_GENERIC_REGS ; i++)
+ WRITE_UINT32(p_MemRegs->kgse_gec[i], schemeRegs.kgse_gec[i]);
+
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_SchemeParams->schemeCounter.update);
+
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+
+ if (!p_SchemeParams->modify)
+ ValidateSchemeSw(p_Scheme);
+ else
+ KgSchemeFlagUnlock(p_Scheme);
+
+ return (t_Handle)p_Scheme;
+}
+
+t_Error FM_PCD_KgSchemeDelete(t_Handle h_Scheme)
+{
+ t_FmPcd *p_FmPcd;
+ uint8_t physicalSchemeId;
+ uint32_t tmpKgarReg, intFlags;
+ t_Error err = E_OK;
+ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme;
+
+ SANITY_CHECK_RETURN_ERROR(h_Scheme, E_INVALID_HANDLE);
+
+ p_FmPcd = (t_FmPcd*)(p_Scheme->h_FmPcd);
+
+ UpdateRequiredActionFlag(h_Scheme, FALSE);
+
+ /* check that no port is bound to this scheme */
+ err = InvalidateSchemeSw(h_Scheme);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme);
+ if (p_Scheme->p_Lock)
+ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
+ return err;
+ }
+
+ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
+
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ /* clear mode register, including enable bit */
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, 0);
+
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE);
+
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+
+ if (p_Scheme->p_Lock)
+ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock);
+
+ return E_OK;
+}
+
+uint32_t FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme)
+{
+ t_FmPcd *p_FmPcd;
+ uint32_t tmpKgarReg, spc, intFlags;
+ uint8_t physicalSchemeId;
+
+ SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0);
+
+ p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd);
+ if (p_FmPcd->h_Hc)
+ return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme);
+
+ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
+
+ if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
+ spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+
+ return spc;
+}
+
+t_Error FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value)
+{
+ t_FmPcd *p_FmPcd;
+ uint32_t tmpKgarReg, intFlags;
+ uint8_t physicalSchemeId;
+
+ SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0);
+
+ p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd);
+
+ if (!FmPcdKgIsSchemeValidSw(h_Scheme))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid."));
+
+ if (p_FmPcd->h_Hc)
+ return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value);
+
+ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId;
+ /* check that schemeId is in range */
+ if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES)
+ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+
+ /* read specified scheme into scheme registers */
+ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId);
+ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg);
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN))
+ {
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid"));
+ }
+
+ /* change counter value */
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc, value);
+
+ /* call indirect command for scheme write */
+ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE);
+
+ WriteKgarWait(p_FmPcd, tmpKgarReg);
+ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ struct fman_kg_regs *p_Regs;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
+
+ p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+ if (!FmIsMaster(p_FmPcd->h_Fm))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!"));
+
+ WRITE_UINT32(p_Regs->fmkg_fdor,payloadOffset);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ struct fman_kg_regs *p_Regs;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER);
+
+ p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs;
+
+ if (!FmIsMaster(p_FmPcd->h_Fm))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!"));
+
+ if (valueId == 0)
+ WRITE_UINT32(p_Regs->fmkg_gdv0r,value);
+ else
+ WRITE_UINT32(p_Regs->fmkg_gdv1r,value);
+ return E_OK;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h
new file mode 100644
index 000000000000..cb7521a11397
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_kg.h
+
+ @Description FM KG private header
+*//***************************************************************************/
+#ifndef __FM_KG_H
+#define __FM_KG_H
+
+#include "std_ext.h"
+
+/***********************************************************************/
+/* Keygen defines */
+/***********************************************************************/
+/* maskes */
+#if (DPAA_VERSION >= 11)
+#define KG_SCH_VSP_SHIFT_MASK 0x0003f000
+#define KG_SCH_OM_VSPE 0x00000001
+#define KG_SCH_VSP_NO_KSP_EN 0x80000000
+
+#define MAX_SP_SHIFT 23
+#define KG_SCH_VSP_MASK_SHIFT 12
+#define KG_SCH_VSP_SHIFT 24
+#endif /* (DPAA_VERSION >= 11) */
+
+typedef uint32_t t_KnownFieldsMasks;
+#define KG_SCH_KN_PORT_ID 0x80000000
+#define KG_SCH_KN_MACDST 0x40000000
+#define KG_SCH_KN_MACSRC 0x20000000
+#define KG_SCH_KN_TCI1 0x10000000
+#define KG_SCH_KN_TCI2 0x08000000
+#define KG_SCH_KN_ETYPE 0x04000000
+#define KG_SCH_KN_PPPSID 0x02000000
+#define KG_SCH_KN_PPPID 0x01000000
+#define KG_SCH_KN_MPLS1 0x00800000
+#define KG_SCH_KN_MPLS2 0x00400000
+#define KG_SCH_KN_MPLS_LAST 0x00200000
+#define KG_SCH_KN_IPSRC1 0x00100000
+#define KG_SCH_KN_IPDST1 0x00080000
+#define KG_SCH_KN_PTYPE1 0x00040000
+#define KG_SCH_KN_IPTOS_TC1 0x00020000
+#define KG_SCH_KN_IPV6FL1 0x00010000
+#define KG_SCH_KN_IPSRC2 0x00008000
+#define KG_SCH_KN_IPDST2 0x00004000
+#define KG_SCH_KN_PTYPE2 0x00002000
+#define KG_SCH_KN_IPTOS_TC2 0x00001000
+#define KG_SCH_KN_IPV6FL2 0x00000800
+#define KG_SCH_KN_GREPTYPE 0x00000400
+#define KG_SCH_KN_IPSEC_SPI 0x00000200
+#define KG_SCH_KN_IPSEC_NH 0x00000100
+#define KG_SCH_KN_IPPID 0x00000080
+#define KG_SCH_KN_L4PSRC 0x00000004
+#define KG_SCH_KN_L4PDST 0x00000002
+#define KG_SCH_KN_TFLG 0x00000001
+
+typedef uint8_t t_GenericCodes;
+#define KG_SCH_GEN_SHIM1 0x70
+#define KG_SCH_GEN_DEFAULT 0x10
+#define KG_SCH_GEN_PARSE_RESULT_N_FQID 0x20
+#define KG_SCH_GEN_START_OF_FRM 0x40
+#define KG_SCH_GEN_SHIM2 0x71
+#define KG_SCH_GEN_IP_PID_NO_V 0x72
+#define KG_SCH_GEN_ETH 0x03
+#define KG_SCH_GEN_ETH_NO_V 0x73
+#define KG_SCH_GEN_SNAP 0x04
+#define KG_SCH_GEN_SNAP_NO_V 0x74
+#define KG_SCH_GEN_VLAN1 0x05
+#define KG_SCH_GEN_VLAN1_NO_V 0x75
+#define KG_SCH_GEN_VLAN2 0x06
+#define KG_SCH_GEN_VLAN2_NO_V 0x76
+#define KG_SCH_GEN_ETH_TYPE 0x07
+#define KG_SCH_GEN_ETH_TYPE_NO_V 0x77
+#define KG_SCH_GEN_PPP 0x08
+#define KG_SCH_GEN_PPP_NO_V 0x78
+#define KG_SCH_GEN_MPLS1 0x09
+#define KG_SCH_GEN_MPLS2 0x19
+#define KG_SCH_GEN_MPLS3 0x29
+#define KG_SCH_GEN_MPLS1_NO_V 0x79
+#define KG_SCH_GEN_MPLS_LAST 0x0a
+#define KG_SCH_GEN_MPLS_LAST_NO_V 0x7a
+#define KG_SCH_GEN_IPV4 0x0b
+#define KG_SCH_GEN_IPV6 0x1b
+#define KG_SCH_GEN_L3_NO_V 0x7b
+#define KG_SCH_GEN_IPV4_TUNNELED 0x0c
+#define KG_SCH_GEN_IPV6_TUNNELED 0x1c
+#define KG_SCH_GEN_MIN_ENCAP 0x2c
+#define KG_SCH_GEN_IP2_NO_V 0x7c
+#define KG_SCH_GEN_GRE 0x0d
+#define KG_SCH_GEN_GRE_NO_V 0x7d
+#define KG_SCH_GEN_TCP 0x0e
+#define KG_SCH_GEN_UDP 0x1e
+#define KG_SCH_GEN_IPSEC_AH 0x2e
+#define KG_SCH_GEN_SCTP 0x3e
+#define KG_SCH_GEN_DCCP 0x4e
+#define KG_SCH_GEN_IPSEC_ESP 0x6e
+#define KG_SCH_GEN_L4_NO_V 0x7e
+#define KG_SCH_GEN_NEXTHDR 0x7f
+/* shifts */
+#define KG_SCH_PP_SHIFT_HIGH_SHIFT 27
+#define KG_SCH_PP_SHIFT_LOW_SHIFT 12
+#define KG_SCH_PP_MASK_SHIFT 16
+#define KG_SCH_MODE_CCOBASE_SHIFT 24
+#define KG_SCH_DEF_MAC_ADDR_SHIFT 30
+#define KG_SCH_DEF_TCI_SHIFT 28
+#define KG_SCH_DEF_ENET_TYPE_SHIFT 26
+#define KG_SCH_DEF_PPP_SESSION_ID_SHIFT 24
+#define KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT 22
+#define KG_SCH_DEF_MPLS_LABEL_SHIFT 20
+#define KG_SCH_DEF_IP_ADDR_SHIFT 18
+#define KG_SCH_DEF_PROTOCOL_TYPE_SHIFT 16
+#define KG_SCH_DEF_IP_TOS_TC_SHIFT 14
+#define KG_SCH_DEF_IPV6_FLOW_LABEL_SHIFT 12
+#define KG_SCH_DEF_IPSEC_SPI_SHIFT 10
+#define KG_SCH_DEF_L4_PORT_SHIFT 8
+#define KG_SCH_DEF_TCP_FLAG_SHIFT 6
+#define KG_SCH_HASH_CONFIG_SHIFT_SHIFT 24
+#define KG_SCH_GEN_MASK_SHIFT 16
+#define KG_SCH_GEN_HT_SHIFT 8
+#define KG_SCH_GEN_SIZE_SHIFT 24
+#define KG_SCH_GEN_DEF_SHIFT 29
+#define FM_PCD_KG_KGAR_NUM_SHIFT 16
+
+/* others */
+#define NUM_OF_SW_DEFAULTS 3
+#define MAX_PP_SHIFT 23
+#define MAX_KG_SCH_SIZE 16
+#define MASK_FOR_GENERIC_BASE_ID 0x20
+#define MAX_HASH_SHIFT 40
+#define MAX_KG_SCH_FQID_BIT_OFFSET 31
+#define MAX_KG_SCH_PP_BIT_OFFSET 15
+#define MAX_DIST_FQID_SHIFT 23
+
+#define GET_MASK_SEL_SHIFT(shift,i) \
+switch (i) { \
+ case (0):shift = 26;break; \
+ case (1):shift = 20;break; \
+ case (2):shift = 10;break; \
+ case (3):shift = 4;break; \
+ default: \
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \
+}
+
+#define GET_MASK_OFFSET_SHIFT(shift,i) \
+switch (i) { \
+ case (0):shift = 16;break; \
+ case (1):shift = 0;break; \
+ case (2):shift = 28;break; \
+ case (3):shift = 24;break; \
+ default: \
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \
+}
+
+#define GET_MASK_SHIFT(shift,i) \
+switch (i) { \
+ case (0):shift = 24;break; \
+ case (1):shift = 16;break; \
+ case (2):shift = 8;break; \
+ case (3):shift = 0;break; \
+ default: \
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \
+}
+
+/***********************************************************************/
+/* Keygen defines */
+/***********************************************************************/
+
+#define KG_DOUBLE_MEANING_REGS_OFFSET 0x100
+#define NO_VALIDATION 0x70
+#define KG_ACTION_REG_TO 1024
+#define KG_MAX_PROFILE 255
+#define SCHEME_ALWAYS_DIRECT 0xFFFFFFFF
+
+
+#endif /* __FM_KG_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
new file mode 100644
index 000000000000..d79e8723a1c1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c
@@ -0,0 +1,5572 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_manip.c
+
+ @Description FM PCD manip ...
+ *//***************************************************************************/
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_port_ext.h"
+#include "fm_muram_ext.h"
+#include "memcpy_ext.h"
+
+#include "fm_common.h"
+#include "fm_hc.h"
+#include "fm_manip.h"
+
+/****************************************/
+/* static functions */
+/****************************************/
+static t_Handle GetManipInfo(t_FmPcdManip *p_Manip, e_ManipInfo manipInfo)
+{
+ t_FmPcdManip *p_CurManip = p_Manip;
+
+ if (!MANIP_IS_UNIFIED(p_Manip))
+ p_CurManip = p_Manip;
+ else
+ {
+ /* go to first unified */
+ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
+ p_CurManip = p_CurManip->h_PrevManip;
+ }
+
+ switch (manipInfo)
+ {
+ case (e_MANIP_HMCT):
+ return p_CurManip->p_Hmct;
+ case (e_MANIP_HMTD):
+ return p_CurManip->h_Ad;
+ case (e_MANIP_HANDLER_TABLE_OWNER):
+ return (t_Handle)p_CurManip;
+ default:
+ return NULL;
+ }
+}
+
+static uint16_t GetHmctSize(t_FmPcdManip *p_Manip)
+{
+ uint16_t size = 0;
+ t_FmPcdManip *p_CurManip = p_Manip;
+
+ if (!MANIP_IS_UNIFIED(p_Manip))
+ return p_Manip->tableSize;
+
+ /* accumulate sizes, starting with the first node */
+ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
+ p_CurManip = p_CurManip->h_PrevManip;
+
+ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
+ {
+ size += p_CurManip->tableSize;
+ p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip;
+ }
+ size += p_CurManip->tableSize; /* add last size */
+
+ return (size);
+}
+
+static uint16_t GetDataSize(t_FmPcdManip *p_Manip)
+{
+ uint16_t size = 0;
+ t_FmPcdManip *p_CurManip = p_Manip;
+
+ if (!MANIP_IS_UNIFIED(p_Manip))
+ return p_Manip->dataSize;
+
+ /* accumulate sizes, starting with the first node */
+ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip))
+ p_CurManip = p_CurManip->h_PrevManip;
+
+ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
+ {
+ size += p_CurManip->dataSize;
+ p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip;
+ }
+ size += p_CurManip->dataSize; /* add last size */
+
+ return (size);
+}
+
+static t_Error CalculateTableSize(t_FmPcdManipParams *p_FmPcdManipParams,
+ uint16_t *p_TableSize, uint8_t *p_DataSize)
+{
+ uint8_t localDataSize, remain, tableSize = 0, dataSize = 0;
+
+ if (p_FmPcdManipParams->u.hdr.rmv)
+ {
+ switch (p_FmPcdManipParams->u.hdr.rmvParams.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_GENERIC):
+ tableSize += HMCD_BASIC_SIZE;
+ break;
+ case (e_FM_PCD_MANIP_RMV_BY_HDR):
+ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
+#endif /* (DPAA_VERSION >= 11) */
+ tableSize += HMCD_BASIC_SIZE;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown byHdr.type"));
+ }
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown rmvParams.type"));
+ }
+ }
+
+ if (p_FmPcdManipParams->u.hdr.insrt)
+ {
+ switch (p_FmPcdManipParams->u.hdr.insrtParams.type)
+ {
+ case (e_FM_PCD_MANIP_INSRT_GENERIC):
+ remain =
+ (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
+ % 4);
+ if (remain)
+ localDataSize =
+ (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
+ + 4 - remain);
+ else
+ localDataSize =
+ p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size;
+ tableSize += (uint8_t)(HMCD_BASIC_SIZE + localDataSize);
+ break;
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR):
+ {
+ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type)
+ {
+
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
+ tableSize += HMCD_BASIC_SIZE + HMCD_PTR_SIZE;
+ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2)
+ {
+ case (e_FM_PCD_MANIP_HDR_INSRT_MPLS):
+ case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE):
+ dataSize +=
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+ }
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
+ tableSize +=
+ (HMCD_BASIC_SIZE + HMCD_PTR_SIZE
+ + HMCD_PARAM_SIZE
+ + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size);
+ dataSize += 2;
+ break;
+
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
+ tableSize += (HMCD_BASIC_SIZE + HMCD_L4_HDR_SIZE);
+
+ break;
+
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
+ tableSize +=
+ (HMCD_BASIC_SIZE
+ + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown byHdr.type"));
+ }
+ }
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown insrtParams.type"));
+ }
+ }
+
+ if (p_FmPcdManipParams->u.hdr.fieldUpdate)
+ {
+ switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type)
+ {
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN):
+ tableSize += HMCD_BASIC_SIZE;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
+ {
+ tableSize += HMCD_PTR_SIZE;
+ dataSize += DSCP_TO_VLAN_TABLE_SIZE;
+ }
+ break;
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4):
+ tableSize += HMCD_BASIC_SIZE;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_ID)
+ {
+ tableSize += HMCD_PARAM_SIZE;
+ dataSize += 2;
+ }
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_SRC)
+ tableSize += HMCD_IPV4_ADDR_SIZE;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_DST)
+ tableSize += HMCD_IPV4_ADDR_SIZE;
+ break;
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6):
+ tableSize += HMCD_BASIC_SIZE;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV6_SRC)
+ tableSize += HMCD_IPV6_ADDR_SIZE;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV6_DST)
+ tableSize += HMCD_IPV6_ADDR_SIZE;
+ break;
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP):
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ == HDR_MANIP_TCP_UDP_CHECKSUM)
+ /* we implement this case with the update-checksum descriptor */
+ tableSize += HMCD_BASIC_SIZE;
+ else
+ /* we implement this case with the TCP/UDP-update descriptor */
+ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown fieldUpdateParams.type"));
+ }
+ }
+
+ if (p_FmPcdManipParams->u.hdr.custom)
+ {
+ switch (p_FmPcdManipParams->u.hdr.customParams.type)
+ {
+ case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE):
+ {
+ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE + HMCD_PARAM_SIZE;
+ dataSize +=
+ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize;
+ if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
+ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
+ && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id))
+ dataSize += 2;
+ }
+ break;
+ case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE):
+ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown customParams.type"));
+ }
+ }
+
+ *p_TableSize = tableSize;
+ *p_DataSize = dataSize;
+
+ return E_OK;
+}
+
+static t_Error GetPrOffsetByHeaderOrField(t_FmManipHdrInfo *p_HdrInfo,
+ uint8_t *parseArrayOffset)
+{
+ e_NetHeaderType hdr = p_HdrInfo->hdr;
+ e_FmPcdHdrIndex hdrIndex = p_HdrInfo->hdrIndex;
+ bool byField = p_HdrInfo->byField;
+ t_FmPcdFields field;
+
+ if (byField)
+ field = p_HdrInfo->fullField;
+
+ if (byField)
+ {
+ switch (hdr)
+ {
+ case (HEADER_TYPE_ETH):
+ switch (field.eth)
+ {
+ case (NET_HEADER_FIELD_ETH_TYPE):
+ *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET;
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("Header manipulation of the type Ethernet with this field not supported"));
+ }
+ break;
+ case (HEADER_TYPE_VLAN):
+ switch (field.vlan)
+ {
+ case (NET_HEADER_FIELD_VLAN_TCI):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET;
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("Header manipulation of the type VLAN with this field not supported"));
+ }
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("Header manipulation of this header by field not supported"));
+ }
+ }
+ else
+ {
+ switch (hdr)
+ {
+ case (HEADER_TYPE_ETH):
+ *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET;
+ break;
+ case (HEADER_TYPE_USER_DEFINED_SHIM1):
+ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET;
+ break;
+ case (HEADER_TYPE_USER_DEFINED_SHIM2):
+ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET;
+ break;
+ case (HEADER_TYPE_LLC_SNAP):
+ *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET;
+ break;
+ case (HEADER_TYPE_PPPoE):
+ *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET;
+ break;
+ case (HEADER_TYPE_MPLS):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)
+ *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET;
+ break;
+ case (HEADER_TYPE_IPv4):
+ case (HEADER_TYPE_IPv6):
+ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE)
+ || (hdrIndex == e_FM_PCD_HDR_INDEX_1))
+ *parseArrayOffset = CC_PC_PR_IP1_OFFSET;
+ else
+ if (hdrIndex == e_FM_PCD_HDR_INDEX_2)
+ *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET;
+ break;
+ case (HEADER_TYPE_MINENCAP):
+ *parseArrayOffset = CC_PC_PR_MINENC_OFFSET;
+ break;
+ case (HEADER_TYPE_GRE):
+ *parseArrayOffset = CC_PC_PR_GRE_OFFSET;
+ break;
+ case (HEADER_TYPE_TCP):
+ case (HEADER_TYPE_UDP):
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP):
+ case (HEADER_TYPE_DCCP):
+ case (HEADER_TYPE_SCTP):
+ *parseArrayOffset = CC_PC_PR_L4_OFFSET;
+ break;
+ case (HEADER_TYPE_CAPWAP):
+ case (HEADER_TYPE_CAPWAP_DTLS):
+ *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET;
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("Header manipulation of this header is not supported"));
+ }
+ }
+ return E_OK;
+}
+
+static t_Error BuildHmct(t_FmPcdManip *p_Manip,
+ t_FmPcdManipParams *p_FmPcdManipParams,
+ uint8_t *p_DestHmct, uint8_t *p_DestData, bool new)
+{
+ uint32_t *p_TmpHmct = (uint32_t*)p_DestHmct, *p_LocalData;
+ uint32_t tmpReg = 0, *p_Last = NULL, tmp_ipv6_addr;
+ uint8_t remain, i, size = 0, origSize, *p_UsrData = NULL, *p_TmpData =
+ p_DestData;
+ t_Handle h_FmPcd = p_Manip->h_FmPcd;
+ uint8_t j = 0;
+
+ if (p_FmPcdManipParams->u.hdr.rmv)
+ {
+ if (p_FmPcdManipParams->u.hdr.rmvParams.type
+ == e_FM_PCD_MANIP_RMV_GENERIC)
+ {
+ /* initialize HMCD */
+ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_RMV) << HMCD_OC_SHIFT;
+ /* tmp, should be conditional */
+ tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.offset
+ << HMCD_RMV_OFFSET_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.size
+ << HMCD_RMV_SIZE_SHIFT;
+ }
+ else
+ if (p_FmPcdManipParams->u.hdr.rmvParams.type
+ == e_FM_PCD_MANIP_RMV_BY_HDR)
+ {
+ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
+ {
+ uint8_t hmcdOpt;
+
+ /* initialize HMCD */
+ tmpReg = (uint32_t)(HMCD_OPCODE_L2_RMV) << HMCD_OC_SHIFT;
+
+ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.specificL2)
+ {
+ case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET):
+ hmcdOpt = HMCD_RMV_L2_ETHERNET;
+ break;
+ case (e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS):
+ hmcdOpt = HMCD_RMV_L2_STACKED_QTAGS;
+ break;
+ case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS):
+ hmcdOpt = HMCD_RMV_L2_ETHERNET_AND_MPLS;
+ break;
+ case (e_FM_PCD_MANIP_HDR_RMV_MPLS):
+ hmcdOpt = HMCD_RMV_L2_MPLS;
+ break;
+ case (e_FM_PCD_MANIP_HDR_RMV_PPPOE):
+ hmcdOpt = HMCD_RMV_L2_PPPOE;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+ }
+ tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT;
+ break;
+ }
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
+ tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_RMV)
+ << HMCD_OC_SHIFT;
+ break;
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
+ {
+ uint8_t prsArrayOffset;
+ t_Error err = E_OK;
+
+ tmpReg = (uint32_t)(HMCD_OPCODE_RMV_TILL)
+ << HMCD_OC_SHIFT;
+
+ err =
+ GetPrOffsetByHeaderOrField(
+ &p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo,
+ &prsArrayOffset);
+ ASSERT_COND(!err);
+ /* was previously checked */
+
+ tmpReg |= ((uint32_t)prsArrayOffset << 16);
+ }
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("manip header remove by hdr type!"));
+ }
+ }
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+ /* advance to next command */
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+ }
+
+ if (p_FmPcdManipParams->u.hdr.insrt)
+ {
+ if (p_FmPcdManipParams->u.hdr.insrtParams.type
+ == e_FM_PCD_MANIP_INSRT_GENERIC)
+ {
+ /* initialize HMCD */
+ if (p_FmPcdManipParams->u.hdr.insrtParams.u.generic.replace)
+ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_REPLACE)
+ << HMCD_OC_SHIFT;
+ else
+ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_INSRT) << HMCD_OC_SHIFT;
+
+ tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.offset
+ << HMCD_INSRT_OFFSET_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size
+ << HMCD_INSRT_SIZE_SHIFT;
+
+ size = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size;
+ p_UsrData = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.p_Data;
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ /* initialize data to be inserted */
+ /* if size is not a multiple of 4, padd with 0's */
+ origSize = size;
+ remain = (uint8_t)(size % 4);
+ if (remain)
+ {
+ size += (uint8_t)(4 - remain);
+ p_LocalData = (uint32_t *)XX_Malloc(size);
+ memset((uint8_t *)p_LocalData, 0, size);
+ memcpy((uint8_t *)p_LocalData, p_UsrData, origSize);
+ }
+ else
+ p_LocalData = (uint32_t*)p_UsrData;
+
+ /* initialize data and advance pointer to next command */
+ MemCpy8(p_TmpHmct, p_LocalData, size);
+ p_TmpHmct += size / sizeof(uint32_t);
+
+ if (remain)
+ XX_Free(p_LocalData);
+ }
+
+ else
+ if (p_FmPcdManipParams->u.hdr.insrtParams.type
+ == e_FM_PCD_MANIP_INSRT_BY_HDR)
+ {
+ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
+ {
+ uint8_t hmcdOpt;
+
+ /* initialize HMCD */
+ tmpReg = (uint32_t)(HMCD_OPCODE_L2_INSRT)
+ << HMCD_OC_SHIFT;
+
+ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2)
+ {
+ case (e_FM_PCD_MANIP_HDR_INSRT_MPLS):
+ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.update)
+ hmcdOpt = HMCD_INSRT_N_UPDATE_L2_MPLS;
+ else
+ hmcdOpt = HMCD_INSRT_L2_MPLS;
+ break;
+ case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE):
+ hmcdOpt = HMCD_INSRT_L2_PPPOE;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG);
+ }
+ tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT;
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ /* set size and pointer of user's data */
+ size =
+ (uint8_t)p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size;
+
+ ASSERT_COND(p_TmpData);
+ MemCpy8(
+ p_TmpData,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.p_Data,
+ size);
+ tmpReg =
+ (size << HMCD_INSRT_L2_SIZE_SHIFT)
+ | (uint32_t)(XX_VirtToPhys(p_TmpData)
+ - (((t_FmPcd*)h_FmPcd)->physicalMuramBase));
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ p_TmpData += size;
+ }
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
+ tmpReg = (uint32_t)(HMCD_OPCODE_IP_INSRT)
+ << HMCD_OC_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.calcL4Checksum)
+ tmpReg |= HMCD_IP_L4_CS_CALC;
+ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.mappingMode
+ == e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS)
+ tmpReg |= HMCD_IP_OR_QOS;
+ tmpReg |=
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastPidOffset
+ & HMCD_IP_LAST_PID_MASK;
+ tmpReg |=
+ ((p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
+ << HMCD_IP_SIZE_SHIFT)
+ & HMCD_IP_SIZE_MASK);
+ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.dontFragOverwrite)
+ tmpReg |= HMCD_IP_DF_MODE;
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ /* set IP id */
+ ASSERT_COND(p_TmpData);
+ WRITE_UINT16(
+ *(uint16_t*)p_TmpData,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.id);
+ WRITE_UINT32(
+ *p_TmpHmct,
+ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
+ p_TmpData += 2;
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+
+ WRITE_UINT8(*p_TmpHmct, p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastDstOffset);
+ p_TmpHmct += HMCD_PARAM_SIZE / 4;
+
+ MemCpy8(
+ p_TmpHmct,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.p_Data,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size);
+ p_TmpHmct +=
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
+ / 4;
+ break;
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
+ tmpReg = HMCD_INSRT_UDP_LITE;
+ /* fall through */
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
+ tmpReg |= (uint32_t)(HMCD_OPCODE_UDP_INSRT)
+ << HMCD_OC_SHIFT;
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ MemCpy8(
+ p_TmpHmct,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
+ p_TmpHmct +=
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
+ / 4;
+ break;
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
+ tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_INSRT)
+ << HMCD_OC_SHIFT;
+ tmpReg |= HMCD_CAPWAP_INSRT;
+
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ MemCpy8(
+ p_TmpHmct,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data,
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size);
+ p_TmpHmct +=
+ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
+ / 4;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("manip header insert by header type!"));
+
+ }
+ }
+ }
+
+ if (p_FmPcdManipParams->u.hdr.fieldUpdate)
+ {
+ switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type)
+ {
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN):
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_VLAN_PRI_UPDATE)
+ << HMCD_OC_SHIFT;
+
+ /* set mode & table pointer */
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
+ {
+ /* set Mode */
+ tmpReg |= (uint32_t)(HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI)
+ << HMCD_VLAN_PRI_REP_MODE_SHIFT;
+ /* set VPRI default */
+ tmpReg |=
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal;
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+ /* write the table pointer into the Manip descriptor */
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ tmpReg = 0;
+ ASSERT_COND(p_TmpData);
+ for (i = 0; i < HMCD_DSCP_VALUES; i++)
+ {
+ /* first we build from each 8 values a 32bit register */
+ tmpReg |=
+ (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i])
+ << (32 - 4 * (j + 1));
+ j++;
+ /* Than we write this register to the next table word
+ * (i=7-->word 0, i=15-->word 1,... i=63-->word 7) */
+ if ((i % 8) == 7)
+ {
+ WRITE_UINT32(*((uint32_t*)p_TmpData + (i+1)/8-1),
+ tmpReg);
+ tmpReg = 0;
+ j = 0;
+ }
+ }
+
+ WRITE_UINT32(
+ *p_TmpHmct,
+ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)));
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+
+ p_TmpData += DSCP_TO_VLAN_TABLE_SIZE;
+ }
+ else
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI)
+ {
+ /* set Mode */
+ /* line commented out as it has no-side-effect ('0' value). */
+ /*tmpReg |= HMCD_VLAN_PRI_UPDATE << HMCD_VLAN_PRI_REP_MODE_SHIFT*/;
+ /* set VPRI parameter */
+ tmpReg |=
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri;
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+ }
+ break;
+
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4):
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_IPV4_UPDATE) << HMCD_OC_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_TTL)
+ tmpReg |= HMCD_IPV4_UPDATE_TTL;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_TOS)
+ {
+ tmpReg |= HMCD_IPV4_UPDATE_TOS;
+ tmpReg |=
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.tos
+ << HMCD_IPV4_UPDATE_TOS_SHIFT;
+ }
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_ID)
+ tmpReg |= HMCD_IPV4_UPDATE_ID;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_SRC)
+ tmpReg |= HMCD_IPV4_UPDATE_SRC;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_DST)
+ tmpReg |= HMCD_IPV4_UPDATE_DST;
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_ID)
+ {
+ ASSERT_COND(p_TmpData);
+ WRITE_UINT16(
+ *(uint16_t*)p_TmpData,
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.id);
+ WRITE_UINT32(
+ *p_TmpHmct,
+ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
+ p_TmpData += 2;
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ }
+
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_SRC)
+ {
+ WRITE_UINT32(
+ *p_TmpHmct,
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.src);
+ p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4;
+ }
+
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates
+ & HDR_MANIP_IPV4_DST)
+ {
+ WRITE_UINT32(
+ *p_TmpHmct,
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.dst);
+ p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4;
+ }
+ break;
+
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6):
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_IPV6_UPDATE) << HMCD_OC_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_HL)
+ tmpReg |= HMCD_IPV6_UPDATE_HL;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_TC)
+ {
+ tmpReg |= HMCD_IPV6_UPDATE_TC;
+ tmpReg |=
+ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.trafficClass
+ << HMCD_IPV6_UPDATE_TC_SHIFT;
+ }
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_SRC)
+ tmpReg |= HMCD_IPV6_UPDATE_SRC;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_DST)
+ tmpReg |= HMCD_IPV6_UPDATE_DST;
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_SRC)
+ {
+ for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4)
+ {
+ memcpy(&tmp_ipv6_addr,
+ &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.src[i],
+ sizeof(uint32_t));
+ WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr);
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ }
+ }
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates
+ & HDR_MANIP_IPV6_DST)
+ {
+ for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4)
+ {
+ memcpy(&tmp_ipv6_addr,
+ &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.dst[i],
+ sizeof(uint32_t));
+ WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr);
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ }
+ }
+ break;
+
+ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP):
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ == HDR_MANIP_TCP_UDP_CHECKSUM)
+ {
+ /* we implement this case with the update-checksum descriptor */
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_CHECKSUM)
+ << HMCD_OC_SHIFT;
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+ }
+ else
+ {
+ /* we implement this case with the TCP/UDP update descriptor */
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_UPDATE)
+ << HMCD_OC_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ & HDR_MANIP_TCP_UDP_DST)
+ tmpReg |= HMCD_TCP_UDP_UPDATE_DST;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ & HDR_MANIP_TCP_UDP_SRC)
+ tmpReg |= HMCD_TCP_UDP_UPDATE_SRC;
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ tmpReg = 0;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ & HDR_MANIP_TCP_UDP_SRC)
+ tmpReg |=
+ ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.src)
+ << HMCD_TCP_UDP_UPDATE_SRC_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates
+ & HDR_MANIP_TCP_UDP_DST)
+ tmpReg |=
+ ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.dst);
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ }
+ break;
+
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown fieldUpdateParams.type"));
+ }
+ }
+
+ if (p_FmPcdManipParams->u.hdr.custom)
+ {
+ switch (p_FmPcdManipParams->u.hdr.customParams.type)
+ {
+ case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE):
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_REPLACE_IP) << HMCD_OC_SHIFT;
+
+ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.decTtlHl)
+ tmpReg |= HMCD_IP_REPLACE_TTL_HL;
+ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
+ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6)
+ /* line commented out as it has no-side-effect ('0' value). */
+ /*tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV4*/;
+ else
+ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
+ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
+ {
+ tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV6;
+ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)
+ tmpReg |= HMCD_IP_REPLACE_ID;
+ }
+ else
+ RETURN_ERROR(
+ MINOR,
+ E_NOT_SUPPORTED,
+ ("One flag out of HDR_MANIP_IP_REPLACE_IPV4, HDR_MANIP_IP_REPLACE_IPV6 - must be set."));
+
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE / 4;
+
+ size =
+ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize;
+ ASSERT_COND(p_TmpData);
+ MemCpy8(
+ p_TmpData,
+ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdr,
+ size);
+ tmpReg = (uint32_t)(size << HMCD_IP_REPLACE_L3HDRSIZE_SHIFT);
+ tmpReg |= (uint32_t)(XX_VirtToPhys(p_TmpData)
+ - (((t_FmPcd*)h_FmPcd)->physicalMuramBase));
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ p_TmpData += size;
+
+ if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType
+ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4)
+ && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id))
+ {
+ WRITE_UINT16(
+ *(uint16_t*)p_TmpData,
+ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.id);
+ WRITE_UINT32(
+ *p_TmpHmct,
+ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)));
+ p_TmpData += 2;
+ }
+ p_TmpHmct += HMCD_PTR_SIZE / 4;
+ break;
+ case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE):
+ /* set opcode */
+ tmpReg = (uint32_t)(HMCD_OPCODE_GEN_FIELD_REPLACE) << HMCD_OC_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.size << HMCD_GEN_FIELD_SIZE_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset << HMCD_GEN_FIELD_SRC_OFF_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset << HMCD_GEN_FIELD_DST_OFF_SHIFT;
+ if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask)
+ tmpReg |= HMCD_GEN_FIELD_MASK_EN;
+
+ /* write the first 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ /* save a pointer to the "last" indication word */
+ p_Last = p_TmpHmct;
+
+ p_TmpHmct += HMCD_BASIC_SIZE/4;
+
+ if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask)
+ {
+ tmpReg = p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask << HMCD_GEN_FIELD_MASK_SHIFT;
+ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.maskOffset << HMCD_GEN_FIELD_MASK_OFF_SHIFT;
+ /* write the next 4 bytes of the descriptor */
+ WRITE_UINT32(*p_TmpHmct, tmpReg);
+ }
+ p_TmpHmct += HMCD_PARAM_SIZE/4;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("Unknown customParams.type"));
+ }
+ }
+
+ /* If this node has a nextManip, and no parsing is required, the old table must be copied to the new table
+ the old table and should be freed */
+ if (p_FmPcdManipParams->h_NextManip
+ && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR)
+ && (MANIP_DONT_REPARSE(p_Manip)))
+ {
+ if (new)
+ {
+ /* If this is the first time this manip is created we need to free unused memory. If it
+ * is a dynamic changes case, the memory used is either the CC shadow or the existing
+ * table - no allocation, no free */
+ MANIP_UPDATE_UNIFIED_POSITION(p_FmPcdManipParams->h_NextManip);
+
+ p_Manip->unifiedPosition = e_MANIP_UNIFIED_FIRST;
+ }
+ }
+ else
+ {
+ ASSERT_COND(p_Last);
+ /* set the "last" indication on the last command of the current table */
+ WRITE_UINT32(*p_Last, GET_UINT32(*p_Last) | HMCD_LAST);
+ }
+
+ return E_OK;
+}
+
+static t_Error CreateManipActionNew(t_FmPcdManip *p_Manip,
+ t_FmPcdManipParams *p_FmPcdManipParams)
+{
+ t_FmPcdManip *p_CurManip;
+ t_Error err;
+ uint32_t nextSize = 0, totalSize;
+ uint16_t tmpReg;
+ uint8_t *p_OldHmct, *p_TmpHmctPtr, *p_TmpDataPtr;
+
+ /* set Manip structure */
+
+ p_Manip->dontParseAfterManip =
+ p_FmPcdManipParams->u.hdr.dontParseAfterManip;
+
+ if (p_FmPcdManipParams->h_NextManip)
+ { /* Next Header manipulation exists */
+ p_Manip->nextManipType = MANIP_GET_TYPE(p_FmPcdManipParams->h_NextManip);
+
+ if ((p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) && p_Manip->dontParseAfterManip)
+ nextSize = (uint32_t)(GetHmctSize(p_FmPcdManipParams->h_NextManip)
+ + GetDataSize(p_FmPcdManipParams->h_NextManip));
+ else /* either parsing is required or next manip is Frag; no table merging. */
+ p_Manip->cascaded = TRUE;
+ /* pass up the "cascaded" attribute. The whole chain is cascaded
+ * if something is cascaded along the way. */
+ if (MANIP_IS_CASCADED(p_FmPcdManipParams->h_NextManip))
+ p_Manip->cascaded = TRUE;
+ }
+
+ /* Allocate new table */
+ /* calculate table size according to manip parameters */
+ err = CalculateTableSize(p_FmPcdManipParams, &p_Manip->tableSize,
+ &p_Manip->dataSize);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ totalSize = (uint16_t)(p_Manip->tableSize + p_Manip->dataSize + nextSize);
+
+ p_Manip->p_Hmct = (uint8_t*)FM_MURAM_AllocMem(
+ ((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, totalSize, 4);
+ if (!p_Manip->p_Hmct)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc failed"));
+
+ if (p_Manip->dataSize)
+ p_Manip->p_Data =
+ (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, (p_Manip->tableSize + nextSize));
+
+ /* update shadow size to allow runtime replacement of Header manipulation */
+ /* The allocated shadow is divided as follows:
+ 0 . . . 16 . . .
+ --------------------------------
+ | Shadow | Shadow HMTD |
+ | HMTD | Match Table |
+ | (16 bytes) | (maximal size) |
+ --------------------------------
+ */
+
+ err = FmPcdUpdateCcShadow(p_Manip->h_FmPcd, (uint32_t)(totalSize + 16),
+ (uint16_t)FM_PCD_CC_AD_TABLE_ALIGN);
+ if (err != E_OK)
+ {
+ FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM allocation for HdrManip node shadow"));
+ }
+
+ if (p_FmPcdManipParams->h_NextManip
+ && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR)
+ && (MANIP_DONT_REPARSE(p_Manip)))
+ {
+ p_OldHmct = (uint8_t *)GetManipInfo(p_FmPcdManipParams->h_NextManip,
+ e_MANIP_HMCT);
+ p_CurManip = p_FmPcdManipParams->h_NextManip;
+ /* Run till the last Manip (which is the first to configure) */
+ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
+ p_CurManip = p_CurManip->h_NextManip;
+
+ while (p_CurManip)
+ {
+ /* If this is a unified table, point to the part of the table
+ * which is the relative offset in HMCT.
+ */
+ p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct,
+ (p_Manip->tableSize +
+ (PTR_TO_UINT(p_CurManip->p_Hmct) -
+ PTR_TO_UINT(p_OldHmct))));
+ if (p_CurManip->p_Data)
+ p_TmpDataPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct,
+ (p_Manip->tableSize +
+ (PTR_TO_UINT(p_CurManip->p_Data) -
+ PTR_TO_UINT(p_OldHmct))));
+ else
+ p_TmpDataPtr = NULL;
+
+ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
+ p_TmpDataPtr, FALSE);
+ /* update old manip table pointer */
+ MANIP_SET_HMCT_PTR(p_CurManip, p_TmpHmctPtr);
+ MANIP_SET_DATA_PTR(p_CurManip, p_TmpDataPtr);
+
+ p_CurManip = p_CurManip->h_PrevManip;
+ }
+ /* We copied the HMCT to create a new large HMCT so we can free the old one */
+ FM_MURAM_FreeMem(MANIP_GET_MURAM(p_FmPcdManipParams->h_NextManip),
+ p_OldHmct);
+ }
+
+ /* Fill table */
+ err = BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct,
+ p_Manip->p_Data, TRUE);
+ if (err)
+ {
+ FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ /* Build HMTD (table descriptor) */
+ tmpReg = HMTD_CFG_TYPE; /* NADEN = 0 */
+
+ /* add parseAfterManip */
+ if (!p_Manip->dontParseAfterManip)
+ tmpReg |= HMTD_CFG_PRS_AFTER_HM;
+
+ /* create cascade */
+ /*if (p_FmPcdManipParams->h_NextManip
+ && (!MANIP_DONT_REPARSE(p_Manip) || (p_Manip->nextManipType != e_FM_PCD_MANIP_HDR)))*/
+ if (p_Manip->cascaded)
+ {
+ uint16_t nextAd;
+ /* indicate that there's another HM table descriptor */
+ tmpReg |= HMTD_CFG_NEXT_AD_EN;
+ /* get address of next HMTD (table descriptor; h_Ad).
+ * If the next HMTD was removed due to table unifing, get the address
+ * of the "next next" as written in the h_Ad of the next h_Manip node.
+ */
+ if (p_Manip->unifiedPosition != e_MANIP_UNIFIED_FIRST)
+ nextAd = (uint16_t)((uint32_t)(XX_VirtToPhys(MANIP_GET_HMTD_PTR(p_FmPcdManipParams->h_NextManip)) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4);
+ else
+ nextAd = ((t_Hmtd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad)->nextAdIdx;
+
+ WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->nextAdIdx, nextAd);
+ }
+
+ WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->cfg, tmpReg);
+ WRITE_UINT32(
+ ((t_Hmtd *)p_Manip->h_Ad)->hmcdBasePtr,
+ (uint32_t)(XX_VirtToPhys(p_Manip->p_Hmct) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)));
+
+ WRITE_UINT8(((t_Hmtd *)p_Manip->h_Ad)->opCode, HMAN_OC);
+
+ if (p_Manip->unifiedPosition == e_MANIP_UNIFIED_FIRST)
+ {
+ /* The HMTD of the next Manip is never going to be used */
+ if (((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->muramAllocate)
+ FM_MURAM_FreeMem(
+ ((t_FmPcd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_FmPcd)->h_FmMuram,
+ ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad);
+ else
+ XX_Free(((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad);
+ ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad = NULL;
+ }
+
+ return E_OK;
+}
+
+static t_Error CreateManipActionShadow(t_FmPcdManip *p_Manip,
+ t_FmPcdManipParams *p_FmPcdManipParams)
+{
+ uint8_t *p_WholeHmct, *p_TmpHmctPtr, newDataSize, *p_TmpDataPtr = NULL;
+ uint16_t newSize;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+ t_Error err;
+ t_FmPcdManip *p_CurManip = p_Manip;
+
+ err = CalculateTableSize(p_FmPcdManipParams, &newSize, &newDataSize);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ /* check coherency of new table parameters */
+ if (newSize > p_Manip->tableSize)
+ RETURN_ERROR(
+ MINOR,
+ E_INVALID_VALUE,
+ ("New Hdr Manip configuration requires larger size than current one (command table)."));
+ if (newDataSize > p_Manip->dataSize)
+ RETURN_ERROR(
+ MINOR,
+ E_INVALID_VALUE,
+ ("New Hdr Manip configuration requires larger size than current one (data)."));
+ if (p_FmPcdManipParams->h_NextManip)
+ RETURN_ERROR(
+ MINOR, E_INVALID_VALUE,
+ ("New Hdr Manip configuration can not contain h_NextManip."));
+ if (MANIP_IS_UNIFIED(p_Manip) && (newSize != p_Manip->tableSize))
+ RETURN_ERROR(
+ MINOR,
+ E_INVALID_VALUE,
+ ("New Hdr Manip configuration in a chained manipulation requires different size than current one."));
+ if (p_Manip->dontParseAfterManip
+ != p_FmPcdManipParams->u.hdr.dontParseAfterManip)
+ RETURN_ERROR(
+ MINOR,
+ E_INVALID_VALUE,
+ ("New Hdr Manip configuration differs in dontParseAfterManip value."));
+
+ p_Manip->tableSize = newSize;
+ p_Manip->dataSize = newDataSize;
+
+ /* Build the new table in the shadow */
+ if (!MANIP_IS_UNIFIED(p_Manip))
+ {
+ p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16);
+ if (p_Manip->p_Data)
+ p_TmpDataPtr =
+ (uint8_t*)PTR_MOVE(p_TmpHmctPtr,
+ (PTR_TO_UINT(p_Manip->p_Data) - PTR_TO_UINT(p_Manip->p_Hmct)));
+
+ BuildHmct(p_Manip, p_FmPcdManipParams, p_TmpHmctPtr, p_Manip->p_Data,
+ FALSE);
+ }
+ else
+ {
+ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
+ ASSERT_COND(p_WholeHmct);
+
+ /* Run till the last Manip (which is the first to configure) */
+ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
+ p_CurManip = p_CurManip->h_NextManip;
+
+ while (p_CurManip)
+ {
+ /* If this is a non-head node in a unified table, point to the part of the shadow
+ * which is the relative offset in HMCT.
+ * else, point to the beginning of the
+ * shadow table (we save 16 for the HMTD.
+ */
+ p_TmpHmctPtr =
+ (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow,
+ (16 + PTR_TO_UINT(p_CurManip->p_Hmct) - PTR_TO_UINT(p_WholeHmct)));
+ if (p_CurManip->p_Data)
+ p_TmpDataPtr =
+ (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow,
+ (16 + PTR_TO_UINT(p_CurManip->p_Data) - PTR_TO_UINT(p_WholeHmct)));
+
+ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
+ p_TmpDataPtr, FALSE);
+ p_CurManip = p_CurManip->h_PrevManip;
+ }
+ }
+
+ return E_OK;
+}
+
+static t_Error CreateManipActionBackToOrig(
+ t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_FmPcdManipParams)
+{
+ uint8_t *p_WholeHmct = NULL, *p_TmpHmctPtr, *p_TmpDataPtr;
+ t_FmPcdManip *p_CurManip = p_Manip;
+
+ /* Build the new table in the shadow */
+ if (!MANIP_IS_UNIFIED(p_Manip))
+ BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, p_Manip->p_Data,
+ FALSE);
+ else
+ {
+ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
+ ASSERT_COND(p_WholeHmct);
+
+ /* Run till the last Manip (which is the first to configure) */
+ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip))
+ p_CurManip = p_CurManip->h_NextManip;
+
+ while (p_CurManip)
+ {
+ /* If this is a unified table, point to the part of the table
+ * which is the relative offset in HMCT.
+ */
+ p_TmpHmctPtr = p_CurManip->p_Hmct; /*- (uint32_t)p_WholeHmct*/
+ p_TmpDataPtr = p_CurManip->p_Data; /*- (uint32_t)p_WholeHmct*/
+
+ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr,
+ p_TmpDataPtr, FALSE);
+
+ p_CurManip = p_CurManip->h_PrevManip;
+ }
+ }
+
+ return E_OK;
+}
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+static t_Error UpdateManipIc(t_Handle h_Manip, uint8_t icOffset)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_Handle p_Ad;
+ uint32_t tmpReg32 = 0;
+ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
+
+ switch (p_Manip->opcode)
+ {
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET)
+ {
+ tmpReg32 =
+ *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets;
+ tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16);
+ *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets =
+ tmpReg32;
+ p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET;
+ p_Manip->icOffset = icOffset;
+ }
+ else
+ {
+ if (p_Manip->icOffset != icOffset)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("this manipulation was updated previously by different value"););
+ }
+ break;
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ if (p_Manip->h_Frag)
+ {
+ if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET)
+ {
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ tmpReg32 |= GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets);
+ tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16);
+ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, tmpReg32);
+ p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET;
+ p_Manip->icOffset = icOffset;
+ }
+ else
+ {
+ if (p_Manip->icOffset != icOffset)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("this manipulation was updated previousely by different value"););
+ }
+ }
+ break;
+ }
+
+ return E_OK;
+}
+
+static t_Error UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(
+ t_Handle h_FmPort, t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate)
+{
+
+ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad;
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ t_Error err;
+ uint32_t tmpReg32;
+
+ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(
+ (p_Manip->opcode & HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX),
+ E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_Manip->muramAllocate, E_INVALID_STATE);
+
+ if (p_Manip->updateParams)
+ {
+ if ((!(p_Manip->updateParams & OFFSET_OF_PR))
+ || (p_Manip->shadowUpdateParams & OFFSET_OF_PR))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("in this stage parameters from Port has not be updated"));
+
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO;
+ fmPortGetSetCcParams.setCcParams.psoSize = 16;
+
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("Parser result offset wasn't configured previousely"));
+#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
+ ASSERT_COND(!(fmPortGetSetCcParams.getCcParams.prOffset % 16));
+#endif
+ }
+ else
+ if (validate)
+ {
+ if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_PR))
+ || (p_Manip->updateParams & OFFSET_OF_PR))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("in this stage parameters from Port has be updated"));
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO;
+ fmPortGetSetCcParams.setCcParams.psoSize = 16;
+
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("Parser result offset wasn't configured previousely"));
+
+ }
+
+ ASSERT_COND(p_Ad);
+
+ if (p_Manip->updateParams & OFFSET_OF_PR)
+ {
+ tmpReg32 = 0;
+ tmpReg32 |= fmPortGetSetCcParams.getCcParams.prOffset;
+ WRITE_UINT32(p_Ad->matchTblPtr,
+ (GET_UINT32(p_Ad->matchTblPtr) | tmpReg32));
+ p_Manip->updateParams &= ~OFFSET_OF_PR;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
+ }
+ else
+ if (validate)
+ {
+ tmpReg32 = GET_UINT32(p_Ad->matchTblPtr);
+ if ((uint8_t)tmpReg32 != fmPortGetSetCcParams.getCcParams.prOffset)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("this manipulation was updated previousely by different value"););
+ }
+
+ return E_OK;
+}
+
+static t_Error UpdateModifyCapwapFragmenation(t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate,t_Handle h_FmTree)
+{
+ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad;
+ t_FmPcdCcSavedManipParams *p_SavedManipParams = NULL;
+ uint32_t tmpReg32 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
+
+ if (p_Manip->updateParams)
+ {
+
+ if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) ||
+ ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA)))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
+ p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree);
+ if (!p_SavedManipParams)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type"));
+ p_Manip->capwapFragParams.dataOffset = p_SavedManipParams->capwapParams.dataOffset;
+
+ tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets);
+ tmpReg32 |= ((uint32_t)p_Manip->capwapFragParams.dataOffset<< 16);
+ WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32);
+
+ p_Manip->updateParams &= ~OFFSET_OF_DATA;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
+ }
+ else if (validate)
+ {
+
+ p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree);
+ if (!p_SavedManipParams)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type"));
+ if (p_Manip->capwapFragParams.dataOffset != p_SavedManipParams->capwapParams.dataOffset)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value"));
+ }
+
+ return E_OK;
+}
+
+static t_Error UpdateInitCapwapFragmentation(t_Handle h_FmPort,
+ t_FmPcdManip *p_Manip,
+ t_Handle h_Ad,
+ bool validate,
+ t_Handle h_FmTree)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ t_Error err;
+ uint32_t tmpReg32 = 0;
+ t_FmPcdCcSavedManipParams *p_SavedManipParams;
+
+ UNUSED(h_Ad);
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) ||
+ (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
+
+ if (p_Manip->updateParams)
+ {
+ if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) ||
+ ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA)))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+ /* For CAPWAP Rassembly used FMAN_CTRL2 hardcoded - so for fragmentation its better to use FMAN_CTRL1 */
+ fmPortGetSetCcParams.setCcParams.orFmanCtrl = FPM_PORT_FM_CTL1;
+
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely"));
+
+ p_SavedManipParams = (t_FmPcdCcSavedManipParams *)XX_Malloc(sizeof(t_FmPcdCcSavedManipParams));
+ p_SavedManipParams->capwapParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
+
+#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
+ ASSERT_COND(!(p_SavedManipParams->capwapParams.dataOffset % 16));
+#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
+
+ FmPcdCcTreeSetSavedManipParams(h_FmTree, (t_Handle)p_SavedManipParams);
+ }
+ else if (validate)
+ {
+ if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)) ||
+ ((p_Manip->updateParams & OFFSET_OF_DATA)))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated"));
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely"));
+ }
+
+ if (p_Manip->updateParams)
+ {
+ tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets);
+ tmpReg32 |= ((uint32_t)fmPortGetSetCcParams.getCcParams.dataOffset<< 16);
+ WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32);
+
+ p_Manip->updateParams &= ~OFFSET_OF_DATA;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
+ p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
+ }
+ else if (validate)
+ {
+ if (p_Manip->capwapFragParams.dataOffset != fmPortGetSetCcParams.getCcParams.dataOffset)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value"));
+ }
+
+ return E_OK;
+}
+
+static t_Error UpdateInitCapwapReasm(t_Handle h_FmPcd,
+ t_Handle h_FmPort,
+ t_FmPcdManip *p_Manip,
+ t_Handle h_Ad,
+ bool validate)
+{
+ t_CapwapReasmPram *p_ReassmTbl;
+ t_Error err;
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ uint8_t i = 0;
+ uint16_t size;
+ uint32_t tmpReg32;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeoutParams;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Manip->frag,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST), E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc,E_INVALID_HANDLE);
+
+ if (p_Manip->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("handler of PCD previously was initiated by different value"));
+
+ UNUSED(h_Ad);
+
+ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
+ p_ReassmTbl = (t_CapwapReasmPram *)p_Manip->h_Frag;
+
+ if (p_Manip->updateParams)
+ {
+ if ((!(p_Manip->updateParams & NUM_OF_TASKS) &&
+ !(p_Manip->updateParams & OFFSET_OF_DATA) &&
+ !(p_Manip->updateParams & OFFSET_OF_PR) &&
+ !(p_Manip->updateParams & HW_PORT_ID)) ||
+ ((p_Manip->shadowUpdateParams & NUM_OF_TASKS) ||
+ (p_Manip->shadowUpdateParams & OFFSET_OF_DATA) || (p_Manip->shadowUpdateParams & OFFSET_OF_PR) ||
+ (p_Manip->shadowUpdateParams & HW_PORT_ID)))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated"));
+
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Num of tasks wasn't configured previousely"));
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previousely"));
+ if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated"));
+#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
+ ASSERT_COND((fmPortGetSetCcParams.getCcParams.dataOffset % 16) == 0);
+#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */
+ }
+ else if (validate)
+ {
+ if ((!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) &&
+ !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) &&
+ !(p_Manip->shadowUpdateParams & OFFSET_OF_PR) &&
+ !(p_Manip->shadowUpdateParams & HW_PORT_ID)) &&
+ ((p_Manip->updateParams & NUM_OF_TASKS) ||
+ (p_Manip->updateParams & OFFSET_OF_DATA) || (p_Manip->updateParams & OFFSET_OF_PR) ||
+ (p_Manip->updateParams & HW_PORT_ID)))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated"));
+
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams;
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("NumOfTasks wasn't configured previously"));
+ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previously"));
+ if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated"));
+ }
+
+ if (p_Manip->updateParams)
+ {
+ if (p_Manip->updateParams & NUM_OF_TASKS)
+ {
+ /*recommendation of Microcode team - (maxNumFramesInProcess * 2) */
+ size = (uint16_t)(p_Manip->capwapFragParams.maxNumFramesInProcess*2 + fmPortGetSetCcParams.getCcParams.numOfTasks);
+ if (size > 255)
+ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("numOfOpenReassmEntries + numOfTasks per port can not be greater than 256"));
+
+ p_Manip->capwapFragParams.numOfTasks = fmPortGetSetCcParams.getCcParams.numOfTasks;
+
+ /*p_ReassmFrmDescrIndxPoolTbl*/
+ p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl =
+ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)(size + 1),
+ 4);
+ if (!p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer index pool table"));
+
+ MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, 0, (uint32_t)(size + 1));
+
+ for ( i = 0; i < size; i++)
+ WRITE_UINT8(*(uint8_t *)PTR_MOVE(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, i), (uint8_t)(i+1));
+
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) - p_FmPcd->physicalMuramBase);
+
+ WRITE_UINT32(p_ReassmTbl->reasmFrmDescIndexPoolTblPtr, tmpReg32);
+
+ /*p_ReassmFrmDescrPoolTbl*/
+ p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl =
+ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)((size + 1) * FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE),
+ 4);
+
+ if (!p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer pool table"));
+
+ MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl, 0, (uint32_t)((size +1)* FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE));
+
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) - p_FmPcd->physicalMuramBase);
+
+ WRITE_UINT32(p_ReassmTbl->reasmFrmDescPoolTblPtr, tmpReg32);
+
+ /*p_TimeOutTbl*/
+
+ p_Manip->capwapFragParams.p_TimeOutTbl =
+ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)((size + 1)* FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE),
+ 4);
+
+ if (!p_Manip->capwapFragParams.p_TimeOutTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly timeout table"));
+
+ MemSet8(p_Manip->capwapFragParams.p_TimeOutTbl, 0, (uint16_t)((size + 1)*FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE));
+
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_TimeOutTbl) - p_FmPcd->physicalMuramBase);
+ WRITE_UINT32(p_ReassmTbl->timeOutTblPtr, tmpReg32);
+
+ p_Manip->updateParams &= ~NUM_OF_TASKS;
+ p_Manip->shadowUpdateParams |= NUM_OF_TASKS;
+ }
+
+ if (p_Manip->updateParams & OFFSET_OF_DATA)
+ {
+ p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset;
+ tmpReg32 = GET_UINT32(p_ReassmTbl->mode);
+ tmpReg32|= p_Manip->capwapFragParams.dataOffset;
+ WRITE_UINT32(p_ReassmTbl->mode, tmpReg32);
+ p_Manip->updateParams &= ~OFFSET_OF_DATA;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA;
+ }
+
+ if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR))
+ {
+ p_Manip->capwapFragParams.prOffset = fmPortGetSetCcParams.getCcParams.prOffset;
+
+ tmpReg32 = GET_UINT32(p_ReassmTbl->mode);
+ tmpReg32|= FM_PCD_MANIP_CAPWAP_REASM_PR_COPY;
+ WRITE_UINT32(p_ReassmTbl->mode, tmpReg32);
+
+ tmpReg32 = GET_UINT32(p_ReassmTbl->intStatsTblPtr);
+ tmpReg32 |= (uint32_t)p_Manip->capwapFragParams.prOffset << 24;
+ WRITE_UINT32(p_ReassmTbl->intStatsTblPtr, tmpReg32);
+ p_Manip->updateParams &= ~OFFSET_OF_PR;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
+ }
+ else
+ {
+ p_Manip->capwapFragParams.prOffset = 0xff;
+ p_Manip->updateParams &= ~OFFSET_OF_PR;
+ p_Manip->shadowUpdateParams |= OFFSET_OF_PR;
+ }
+
+ p_Manip->capwapFragParams.hwPortId = fmPortGetSetCcParams.getCcParams.hardwarePortId;
+ p_Manip->updateParams &= ~HW_PORT_ID;
+ p_Manip->shadowUpdateParams |= HW_PORT_ID;
+
+ /*timeout hc */
+ ccCapwapReassmTimeoutParams.fqidForTimeOutFrames = p_Manip->capwapFragParams.fqidForTimeOutFrames;
+ ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl = (uint32_t)p_Manip->capwapFragParams.hwPortId << 24;
+ ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl |= (uint32_t)((XX_VirtToPhys(p_ReassmTbl) - p_FmPcd->physicalMuramBase));
+ ccCapwapReassmTimeoutParams.timeoutRequestTime = (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_Manip->capwapFragParams.timeoutRoutineRequestTime)/2;
+ return FmHcPcdCcCapwapTimeoutReassm(p_FmPcd->h_Hc,&ccCapwapReassmTimeoutParams);
+ }
+
+ else if (validate)
+ {
+ if (fmPortGetSetCcParams.getCcParams.hardwarePortId != p_Manip->capwapFragParams.hwPortId)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Reassembly manipulation previously was assigned to another port"));
+ if (fmPortGetSetCcParams.getCcParams.numOfTasks != p_Manip->capwapFragParams.numOfTasks)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfTasks for this manipulation previously was defined by another value "));
+
+ if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR))
+ {
+ if (p_Manip->capwapFragParams.prOffset != fmPortGetSetCcParams.getCcParams.prOffset)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value "));
+ }
+ else
+ {
+ if (p_Manip->capwapFragParams.prOffset != 0xff)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value "));
+ }
+ if (fmPortGetSetCcParams.getCcParams.dataOffset != p_Manip->capwapFragParams.dataOffset)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Data offset previously was defined by another value "));
+ }
+
+ return E_OK;
+}
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = { 0 };
+ t_Error err = E_OK;
+ uint8_t result;
+ uint32_t bitFor1Micro, tsbs, log2num;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(h_ReasmCommonPramTbl);
+
+ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
+ if (bitFor1Micro == 0)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
+
+ bitFor1Micro = 32 - bitFor1Micro;
+ LOG2(FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH, log2num);
+ tsbs = bitFor1Micro - log2num;
+
+ ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys(
+ h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase);
+ ccReassmTimeoutParams.tsbs = (uint8_t)tsbs;
+ ccReassmTimeoutParams.activate = TRUE;
+ if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams,
+ &result)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ switch (result)
+ {
+ case (0):
+ return E_OK;
+ case (1):
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("failed to allocate TNUM"));
+ case (2):
+ RETURN_ERROR(
+ MAJOR, E_NO_MEMORY,
+ ("failed to allocate internal buffer from the HC-Port"));
+ case (3):
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("'Disable Timeout Task' with invalid IPRCPT"));
+ case (4):
+ RETURN_ERROR(MAJOR, E_FULL, ("too many timeout tasks"));
+ case (5):
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("invalid sub command"));
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ }
+ return E_OK;
+}
+
+static t_Error CreateReassCommonTable(t_FmPcdManip *p_Manip)
+{
+ uint32_t tmpReg32 = 0, i, bitFor1Micro;
+ uint64_t tmpReg64, size;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+ t_Error err = E_OK;
+
+ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
+ if (bitFor1Micro == 0)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
+
+ /* Allocation of the Reassembly Common Parameters table. This table is located in the
+ MURAM. Its size is 64 bytes and its base address should be 8-byte aligned. */
+ p_Manip->reassmParams.p_ReassCommonTbl =
+ (t_ReassCommonTbl *)FM_MURAM_AllocMem(
+ p_FmPcd->h_FmMuram,
+ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE,
+ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN);
+
+ if (!p_Manip->reassmParams.p_ReassCommonTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Reassembly common parameters table"));
+
+ MemSet8(p_Manip->reassmParams.p_ReassCommonTbl, 0,
+ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE);
+
+ /* Setting the TimeOut Mode.*/
+ tmpReg32 = 0;
+ if (p_Manip->reassmParams.timeOutMode
+ == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES)
+ tmpReg32 |= FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES;
+
+ /* Setting TimeOut FQID - Frames that time out are enqueued to this FQID.
+ In order to cause TimeOut frames to be discarded, this queue should be configured accordingly*/
+ tmpReg32 |= p_Manip->reassmParams.fqidForTimeOutFrames;
+ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeoutModeAndFqid,
+ tmpReg32);
+
+ /* Calculation the size of IP Reassembly Frame Descriptor - number of frames that are allowed to be reassembled simultaneously + 129.*/
+ size = p_Manip->reassmParams.maxNumFramesInProcess + 129;
+
+ /*Allocation of IP Reassembly Frame Descriptor Indexes Pool - This pool resides in the MURAM */
+ p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr =
+ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)(size * 2),
+ 256));
+ if (!p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)
+ RETURN_ERROR(
+ MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Reassembly frame descriptor indexes pool"));
+
+ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr),
+ 0, (uint32_t)(size * 2));
+
+ /* The entries in IP Reassembly Frame Descriptor Indexes Pool contains indexes starting with 1 up to
+ the maximum number of frames that are allowed to be reassembled simultaneously + 128.
+ The last entry in this pool must contain the index zero*/
+ for (i = 0; i < (size - 1); i++)
+ WRITE_UINT16(
+ *(uint16_t *)PTR_MOVE(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), (i<<1)),
+ (uint16_t)(i+1));
+
+ /* Sets the IP Reassembly Frame Descriptor Indexes Pool offset from MURAM */
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(
+ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr))
+ - p_FmPcd->physicalMuramBase);
+ WRITE_UINT32(
+ p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescIndexPoolTblPtr,
+ tmpReg32);
+
+ /* Allocation of the Reassembly Frame Descriptors Pool - This pool resides in external memory.
+ The number of entries in this pool should be equal to the number of entries in IP Reassembly Frame Descriptor Indexes Pool.*/
+ p_Manip->reassmParams.reassFrmDescrPoolTblAddr =
+ PTR_TO_UINT(XX_MallocSmart((uint32_t)(size * 64), p_Manip->reassmParams.dataMemId, 64));
+
+ if (!p_Manip->reassmParams.reassFrmDescrPoolTblAddr)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
+
+ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr), 0,
+ (uint32_t)(size * 64));
+
+ /* Sets the Reassembly Frame Descriptors Pool and liodn offset*/
+ tmpReg64 = (uint64_t)(XX_VirtToPhys(
+ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr)));
+ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_LIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
+ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_ELIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
+ WRITE_UINT32(
+ p_Manip->reassmParams.p_ReassCommonTbl->liodnAndReassFrmDescPoolPtrHi,
+ (uint32_t)(tmpReg64 >> 32));
+ WRITE_UINT32(
+ p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescPoolPtrLow,
+ (uint32_t)tmpReg64);
+
+ /*Allocation of the TimeOut table - This table resides in the MURAM.
+ The number of entries in this table is identical to the number of entries in the Reassembly Frame Descriptors Pool*/
+ p_Manip->reassmParams.timeOutTblAddr =
+ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, (uint32_t)(size * 8),8));
+
+ if (!p_Manip->reassmParams.timeOutTblAddr)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Reassembly timeout table"));
+
+ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr), 0,
+ (uint16_t)(size * 8));
+
+ /* Sets the TimeOut table offset from MURAM */
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(
+ UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr))
+ - p_FmPcd->physicalMuramBase);
+ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeOutTblPtr,
+ tmpReg32);
+
+ /* Sets the Expiration Delay */
+ tmpReg32 = 0;
+ tmpReg32 |= (((uint32_t)(1 << bitFor1Micro))
+ * p_Manip->reassmParams.timeoutThresholdForReassmProcess);
+ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->expirationDelay,
+ tmpReg32);
+
+ err = FmPcdRegisterReassmPort(p_FmPcd,
+ p_Manip->reassmParams.p_ReassCommonTbl);
+ if (err != E_OK)
+ {
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->reassmParams.p_ReassCommonTbl);
+ RETURN_ERROR(MAJOR, err, ("port registration"));
+ }
+
+ return err;
+}
+
+static t_Error CreateReassTable(t_FmPcdManip *p_Manip, e_NetHeaderType hdr)
+{
+ t_FmPcd *p_FmPcd = p_Manip->h_FmPcd;
+ uint32_t tmpReg32, autoLearnHashTblSize;
+ uint32_t numOfWays, setSize, setSizeCode, keySize;
+ uint32_t waySize, numOfSets, numOfEntries;
+ uint64_t tmpReg64;
+ uint16_t minFragSize;
+ uint16_t maxReassemSize;
+ uintptr_t *p_AutoLearnHashTblAddr, *p_AutoLearnSetLockTblAddr;
+ t_ReassTbl **p_ReassTbl;
+
+ switch (hdr)
+ {
+ case HEADER_TYPE_IPv4:
+ p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv4ReassTbl;
+ p_AutoLearnHashTblAddr =
+ &p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr;
+ p_AutoLearnSetLockTblAddr =
+ &p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr;
+ minFragSize = p_Manip->reassmParams.ip.minFragSize[0];
+ maxReassemSize = 0;
+ numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0];
+ keySize = 4 + 4 + 1 + 2; /* 3-tuple + IP-Id */
+ break;
+ case HEADER_TYPE_IPv6:
+ p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv6ReassTbl;
+ p_AutoLearnHashTblAddr =
+ &p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr;
+ p_AutoLearnSetLockTblAddr =
+ &p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr;
+ minFragSize = p_Manip->reassmParams.ip.minFragSize[1];
+ maxReassemSize = 0;
+ numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1];
+ keySize = 16 + 16 + 4; /* 2-tuple + IP-Id */
+ if (numOfWays > e_FM_PCD_MANIP_SIX_WAYS_HASH)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("num of ways"));
+ break;
+ case HEADER_TYPE_CAPWAP:
+ p_ReassTbl = &p_Manip->reassmParams.capwap.p_ReassTbl;
+ p_AutoLearnHashTblAddr =
+ &p_Manip->reassmParams.capwap.autoLearnHashTblAddr;
+ p_AutoLearnSetLockTblAddr =
+ &p_Manip->reassmParams.capwap.autoLearnSetLockTblAddr;
+ minFragSize = 0;
+ maxReassemSize = p_Manip->reassmParams.capwap.maxRessembledsSize;
+ numOfWays = p_Manip->reassmParams.capwap.numOfFramesPerHashEntry;
+ keySize = 4;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type"));
+ }
+ keySize += 2; /* 2 bytes reserved for RFDIndex */
+#if (DPAA_VERSION >= 11)
+ keySize += 2; /* 2 bytes reserved */
+#endif /* (DPAA_VERSION >= 11) */
+ waySize = ROUND_UP(keySize, 8);
+
+ /* Allocates the Reassembly Parameters Table - This table is located in the MURAM.*/
+ *p_ReassTbl = (t_ReassTbl *)FM_MURAM_AllocMem(
+ p_FmPcd->h_FmMuram, FM_PCD_MANIP_REASM_TABLE_SIZE,
+ FM_PCD_MANIP_REASM_TABLE_ALIGN);
+ if (!*p_ReassTbl)
+ RETURN_ERROR( MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Reassembly specific parameters table"));
+ memset(*p_ReassTbl, 0, sizeof(t_ReassTbl));
+
+ /* Sets the Reassembly common Parameters table offset from MURAM in the Reassembly Table descriptor*/
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->reassmParams.p_ReassCommonTbl)
+ - p_FmPcd->physicalMuramBase);
+ WRITE_UINT32((*p_ReassTbl)->reassCommonPrmTblPtr, tmpReg32);
+
+ /* Calculate set size (set size is rounded-up to next power of 2) */
+ NEXT_POWER_OF_2(numOfWays * waySize, setSize);
+
+ /* Get set size code */
+ LOG2(setSize, setSizeCode);
+
+ /* Sets ways number and set size code */
+ WRITE_UINT16((*p_ReassTbl)->waysNumAndSetSize,
+ (uint16_t)((numOfWays << 8) | setSizeCode));
+
+ /* It is recommended that the total number of entries in this table
+ (number of sets * number of ways) will be twice the number of frames that
+ are expected to be reassembled simultaneously.*/
+ numOfEntries = (uint32_t)(p_Manip->reassmParams.maxNumFramesInProcess * 2);
+
+ /* sets number calculation - number of entries = number of sets * number of ways */
+ numOfSets = numOfEntries / numOfWays;
+
+ /* Sets AutoLearnHashKeyMask*/
+ NEXT_POWER_OF_2(numOfSets, numOfSets);
+
+ WRITE_UINT16((*p_ReassTbl)->autoLearnHashKeyMask,
+ (uint16_t)(numOfSets - 1));
+
+ /* Allocation of Reassembly Automatic Learning Hash Table - This table resides in external memory.
+ The size of this table is determined by the number of sets and the set size.
+ Table size = set size * number of sets
+ This table base address should be aligned to SetSize.*/
+ autoLearnHashTblSize = numOfSets * setSize;
+
+ *p_AutoLearnHashTblAddr =
+ PTR_TO_UINT(XX_MallocSmart(autoLearnHashTblSize, p_Manip->reassmParams.dataMemId, setSize));
+ if (!*p_AutoLearnHashTblAddr)
+ {
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl);
+ *p_ReassTbl = NULL;
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
+ }
+ MemSet8(UINT_TO_PTR(*p_AutoLearnHashTblAddr), 0, autoLearnHashTblSize);
+
+ /* Sets the Reassembly Automatic Learning Hash Table and liodn offset */
+ tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_LIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
+ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_ELIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
+ tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnHashTblAddr));
+ WRITE_UINT32( (*p_ReassTbl)->liodnAlAndAutoLearnHashTblPtrHi,
+ (uint32_t)(tmpReg64 >> 32));
+ WRITE_UINT32((*p_ReassTbl)->autoLearnHashTblPtrLow, (uint32_t)tmpReg64);
+
+ /* Allocation of the Set Lock table - This table resides in external memory
+ The size of this table is (number of sets in the Reassembly Automatic Learning Hash table)*4 bytes.
+ This table resides in external memory and its base address should be 4-byte aligned */
+ *p_AutoLearnSetLockTblAddr =
+ PTR_TO_UINT(XX_MallocSmart((uint32_t)(numOfSets * 4), p_Manip->reassmParams.dataMemId, 4));
+ if (!*p_AutoLearnSetLockTblAddr)
+ {
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl);
+ *p_ReassTbl = NULL;
+ XX_FreeSmart(UINT_TO_PTR(*p_AutoLearnHashTblAddr));
+ *p_AutoLearnHashTblAddr = 0;
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED"));
+ }
+ MemSet8(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr), 0, (numOfSets * 4));
+
+ /* sets Set Lock table pointer and liodn offset*/
+ tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_LIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT);
+ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset
+ & FM_PCD_MANIP_REASM_ELIODN_MASK)
+ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT);
+ tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr));
+ WRITE_UINT32( (*p_ReassTbl)->liodnSlAndAutoLearnSetLockTblPtrHi,
+ (uint32_t)(tmpReg64 >> 32));
+ WRITE_UINT32((*p_ReassTbl)->autoLearnSetLockTblPtrLow, (uint32_t)tmpReg64);
+
+ /* Sets user's requested minimum fragment size (in Bytes) for First/Middle fragment */
+ WRITE_UINT16((*p_ReassTbl)->minFragSize, minFragSize);
+
+ WRITE_UINT16((*p_ReassTbl)->maxReassemblySize, maxReassemSize);
+
+ return E_OK;
+}
+
+static t_Error UpdateInitReasm(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_FmPcdManip *p_Manip,
+ t_Handle h_Ad, bool validate)
+{
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ uint32_t tmpReg32;
+ t_Error err;
+ t_FmPortPcdParams *p_PcdParams = (t_FmPortPcdParams *)h_PcdParams;
+#if (DPAA_VERSION >= 11)
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+#endif /* (DPAA_VERSION >= 11) */
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Manip->frag, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(
+ (p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY),
+ E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Manip->updateParams || h_PcdParams,
+ E_INVALID_HANDLE);
+
+ UNUSED(h_Ad);
+
+ if (!p_Manip->updateParams)
+ return E_OK;
+
+ if (p_Manip->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("handler of PCD previously was initiated by different value"));
+
+ if (p_Manip->updateParams)
+ {
+ if ((!(p_Manip->updateParams
+ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)))
+ || ((p_Manip->shadowUpdateParams
+ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("in this stage parameters from Port has not be updated"));
+
+ fmPortGetSetCcParams.setCcParams.type = 0;
+ if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
+ {
+ fmPortGetSetCcParams.setCcParams.type |= UPDATE_OFP_DPTE;
+ fmPortGetSetCcParams.setCcParams.ofpDpde = 0xF;
+ }
+ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams | FM_REV;
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (fmPortGetSetCcParams.getCcParams.type
+ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK | FM_REV))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("offset of the data wasn't configured previously"));
+ if (p_Manip->updateParams
+ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))
+ {
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint8_t *p_Ptr, i, totalNumOfTnums;
+
+ totalNumOfTnums =
+ (uint8_t)(fmPortGetSetCcParams.getCcParams.numOfTasks
+ + fmPortGetSetCcParams.getCcParams.numOfExtraTasks);
+
+ p_Manip->reassmParams.internalBufferPoolAddr =
+ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS),
+ BMI_FIFO_UNITS));
+ if (!p_Manip->reassmParams.internalBufferPoolAddr)
+ RETURN_ERROR(
+ MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Reassembly internal buffers pool"));
+ MemSet8(
+ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr),
+ 0, (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS));
+
+ p_Manip->reassmParams.internalBufferPoolManagementIndexAddr =
+ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)(5 + totalNumOfTnums),
+ 4));
+ if (!p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)
+ RETURN_ERROR(
+ MAJOR,
+ E_NO_MEMORY,
+ ("MURAM alloc for Reassembly internal buffers management"));
+
+ p_Ptr =
+ (uint8_t*)UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr);
+ WRITE_UINT32(
+ *(uint32_t*)p_Ptr,
+ (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)) - p_FmPcd->physicalMuramBase));
+ for (i = 0, p_Ptr += 4; i < totalNumOfTnums; i++, p_Ptr++)
+ WRITE_UINT8(*p_Ptr, i);
+ WRITE_UINT8(*p_Ptr, 0xFF);
+
+ tmpReg32 =
+ (4 << FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT)
+ | ((uint32_t)(XX_VirtToPhys(
+ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr))
+ - p_FmPcd->physicalMuramBase));
+ WRITE_UINT32(
+ p_Manip->reassmParams.p_ReassCommonTbl->internalBufferManagement,
+ tmpReg32);
+
+ p_Manip->updateParams &= ~(NUM_OF_TASKS | NUM_OF_EXTRA_TASKS
+ | DISCARD_MASK);
+ p_Manip->shadowUpdateParams |= (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS
+ | DISCARD_MASK);
+ }
+ }
+
+ if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
+ {
+ if (p_Manip->reassmParams.capwap.h_Scheme)
+ {
+ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
+ p_Manip->reassmParams.capwap.h_Scheme;
+ p_PcdParams->p_KgParams->numOfSchemes++;
+ }
+
+ }
+ else
+ {
+ if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
+ {
+ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
+ p_Manip->reassmParams.ip.h_Ipv4Scheme;
+ p_PcdParams->p_KgParams->numOfSchemes++;
+ }
+ if (p_Manip->reassmParams.ip.h_Ipv6Scheme)
+ {
+ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] =
+ p_Manip->reassmParams.ip.h_Ipv6Scheme;
+ p_PcdParams->p_KgParams->numOfSchemes++;
+ }
+#if (DPAA_VERSION >= 11)
+ if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev >= 6)
+ {
+ if ((err = FmPortSetGprFunc(h_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
+ (void**)&p_ParamsPage)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ tmpReg32 = NIA_ENG_KG;
+ if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
+ {
+ tmpReg32 |= NIA_KG_DIRECT;
+ tmpReg32 |= NIA_KG_CC_EN;
+ tmpReg32 |= FmPcdKgGetSchemeId(
+ p_Manip->reassmParams.ip.h_Ipv4Scheme);
+ WRITE_UINT32(p_ParamsPage->iprIpv4Nia, tmpReg32);
+ }
+ if (p_Manip->reassmParams.ip.h_Ipv6Scheme)
+ {
+ tmpReg32 &= ~NIA_AC_MASK;
+ tmpReg32 |= NIA_KG_DIRECT;
+ tmpReg32 |= NIA_KG_CC_EN;
+ tmpReg32 |= FmPcdKgGetSchemeId(
+ p_Manip->reassmParams.ip.h_Ipv6Scheme);
+ WRITE_UINT32(p_ParamsPage->iprIpv6Nia, tmpReg32);
+ }
+ }
+#else
+ if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev < 6)
+ {
+ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->discardMask,
+ fmPortGetSetCcParams.getCcParams.discardMask);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ return E_OK;
+}
+
+#if (DPAA_VERSION == 10)
+static t_Error FmPcdFragHcScratchPoolFill(t_Handle h_FmPcd, uint8_t scratchBpid)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams));
+
+ fmPcdCcFragScratchPoolCmdParams.numOfBuffers = NUM_OF_SCRATCH_POOL_BUFFERS;
+ fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid;
+ if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, TRUE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (fmPcdCcFragScratchPoolCmdParams.numOfBuffers != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Fill scratch pool failed,"
+ "Failed to release %d buffers to the BM (missing FBPRs)",
+ fmPcdCcFragScratchPoolCmdParams.numOfBuffers));
+
+ return E_OK;
+}
+
+static t_Error FmPcdFragHcScratchPoolEmpty(t_Handle h_FmPcd, uint8_t scratchBpid)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams));
+
+ fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid;
+ if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, FALSE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION == 10) */
+
+static void ReleaseManipHandler(t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd)
+{
+ if (p_Manip->h_Ad)
+ {
+ if (p_Manip->muramAllocate)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Ad);
+ else
+ XX_Free(p_Manip->h_Ad);
+ p_Manip->h_Ad = NULL;
+ }
+ if (p_Manip->p_Template)
+ {
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_Template);
+ p_Manip->p_Template = NULL;
+ }
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ if (p_Manip->h_Frag)
+ {
+ if (p_Manip->capwapFragParams.p_AutoLearnHashTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->capwapFragParams.p_AutoLearnHashTbl);
+ if (p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl);
+ if (p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl);
+ if (p_Manip->capwapFragParams.p_TimeOutTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->capwapFragParams.p_TimeOutTbl);
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Frag);
+
+ }
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ if (p_Manip->frag)
+ {
+ if (p_Manip->fragParams.p_Frag)
+ {
+#if (DPAA_VERSION == 10)
+ FmPcdFragHcScratchPoolEmpty((t_Handle)p_FmPcd, p_Manip->fragParams.scratchBpid);
+#endif /* (DPAA_VERSION == 10) */
+
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag);
+ }
+ }
+ else
+ if (p_Manip->reassm)
+ {
+ FmPcdUnregisterReassmPort(p_FmPcd,
+ p_Manip->reassmParams.p_ReassCommonTbl);
+
+ if (p_Manip->reassmParams.timeOutTblAddr)
+ FM_MURAM_FreeMem(
+ p_FmPcd->h_FmMuram,
+ UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr));
+ if (p_Manip->reassmParams.reassFrmDescrPoolTblAddr)
+ XX_FreeSmart(
+ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr));
+ if (p_Manip->reassmParams.p_ReassCommonTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->reassmParams.p_ReassCommonTbl);
+ if (p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)
+ FM_MURAM_FreeMem(
+ p_FmPcd->h_FmMuram,
+ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr));
+ if (p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)
+ FM_MURAM_FreeMem(
+ p_FmPcd->h_FmMuram,
+ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr));
+ if (p_Manip->reassmParams.internalBufferPoolAddr)
+ FM_MURAM_FreeMem(
+ p_FmPcd->h_FmMuram,
+ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr));
+ if (p_Manip->reassmParams.hdr == HEADER_TYPE_CAPWAP)
+ {
+
+ }
+ else
+ {
+ if (p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr)
+ XX_FreeSmart(
+ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr));
+ if (p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr)
+ XX_FreeSmart(
+ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr));
+ if (p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr)
+ XX_FreeSmart(
+ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr));
+ if (p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr)
+ XX_FreeSmart(
+ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr));
+ if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->reassmParams.ip.p_Ipv4ReassTbl);
+ if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram,
+ p_Manip->reassmParams.ip.p_Ipv6ReassTbl);
+ if (p_Manip->reassmParams.ip.h_Ipv6Ad)
+ XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv6Ad);
+ if (p_Manip->reassmParams.ip.h_Ipv4Ad)
+ XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv4Ad);
+ }
+ }
+
+ if (p_Manip->p_StatsTbl)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_StatsTbl);
+}
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_ManipParams)
+{
+ if (p_ManipParams->u.hdr.rmv)
+ {
+ switch (p_ManipParams->u.hdr.rmvParams.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR):
+ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START) :
+ if (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.include)
+ {
+ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP_DTLS) :
+ p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
+ p_Manip->muramAllocate = TRUE;
+ if (p_ManipParams->u.hdr.insrt)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for CAPWAP_DTLS_HDR remove can not be insrt manipualtion after"));
+ if (p_ManipParams->fragOrReasm)
+ {
+ if (!p_ManipParams->fragOrReasmParams.frag)
+ {
+ switch (p_ManipParams->fragOrReasmParams.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP):
+ p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("unsupported header for Reassembly"));
+ }
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for this type of manipulation frag can not be TRUE"));
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("non valid net header of remove location"));
+ }
+ }
+ else
+ {
+ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP_DTLS) :
+ case (HEADER_TYPE_CAPWAP) :
+ if (p_ManipParams->fragOrReasm || p_ManipParams->u.hdr.insrt)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for the type of remove e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_CAPWAP can not be insert or fragOrReasm TRUE"));
+ p_Manip->opcode = HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR;
+ p_Manip->muramAllocate = TRUE;
+ p_ManipParams->u.hdr.insrt = TRUE; //internal frame header
+ break;
+ default :
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
+ }
+ }
+ break;
+ default :
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation"));
+ }
+ }
+ else if (p_ManipParams->u.hdr.insrt)
+ {
+ switch (p_ManipParams->u.hdr.insrtParams.type)
+ {
+ case (e_FM_PCD_MANIP_INSRT_BY_TEMPLATE) :
+
+ p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
+ p_Manip->muramAllocate = FALSE;
+ if (p_ManipParams->fragOrReasm)
+ {
+ if (p_ManipParams->fragOrReasmParams.frag)
+ {
+ switch (p_ManipParams->fragOrReasmParams.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP):
+ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header for fragmentation"));
+ }
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,("can not reach this point"));
+ }
+ break;
+
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for only isert manipulation unsupported type"));
+ }
+ }
+ else if (p_ManipParams->fragOrReasm)
+ {
+ if (p_ManipParams->fragOrReasmParams.frag)
+ {
+ switch (p_ManipParams->fragOrReasmParams.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP):
+ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
+ p_Manip->muramAllocate = FALSE;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for fragmentation"));
+ }
+ }
+ else
+ {
+ switch (p_ManipParams->fragOrReasmParams.hdr)
+ {
+ case (HEADER_TYPE_CAPWAP):
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Reassembly has to be with additional operation - rmv = TRUE, type of remove - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION,type = e_FM_PCD_MANIP_LOC_BY_HDR, hdr = HEADER_TYPE_CAPWAP_DTLS"));
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for reassembly"));
+ }
+ }
+
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("User didn't ask for any manipulation"));
+
+ p_Manip->insrt = p_ManipParams->u.hdr.insrt;
+ p_Manip->rmv = p_ManipParams->u.hdr.rmv;
+
+ return E_OK;
+}
+
+#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip,
+ t_FmPcdManipParams *p_ManipParams)
+{
+ switch (p_ManipParams->type)
+ {
+ case e_FM_PCD_MANIP_HDR:
+ /* Check that next-manip is not already used */
+ if (p_ManipParams->h_NextManip)
+ {
+ if (!MANIP_IS_FIRST(p_ManipParams->h_NextManip))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("h_NextManip is already a part of another chain"));
+ if ((MANIP_GET_TYPE(p_ManipParams->h_NextManip)
+ != e_FM_PCD_MANIP_HDR) &&
+ (MANIP_GET_TYPE(p_ManipParams->h_NextManip)
+ != e_FM_PCD_MANIP_FRAG))
+ RETURN_ERROR(
+ MAJOR,
+ E_NOT_SUPPORTED,
+ ("For a Header Manipulation node - no support of h_NextManip of type other than Header Manipulation or Fragmentation."));
+ }
+
+ if (p_ManipParams->u.hdr.rmv)
+ {
+ switch (p_ManipParams->u.hdr.rmvParams.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR):
+ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2):
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP):
+ break;
+ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START):
+ {
+ t_Error err;
+ uint8_t prsArrayOffset;
+
+ err =
+ GetPrOffsetByHeaderOrField(
+ &p_ManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo,
+ &prsArrayOffset);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ break;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("invalid type of remove manipulation"));
+ }
+ break;
+ case (e_FM_PCD_MANIP_RMV_GENERIC):
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("invalid type of remove manipulation"));
+ }
+ p_Manip->opcode = HMAN_OC;
+ p_Manip->muramAllocate = TRUE;
+ p_Manip->rmv = TRUE;
+ }
+ else
+ if (p_ManipParams->u.hdr.insrt)
+ {
+ switch (p_ManipParams->u.hdr.insrtParams.type)
+ {
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR):
+ {
+ switch (p_ManipParams->u.hdr.insrtParams.u.byHdr.type)
+ {
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2):
+ /* nothing to check */
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP):
+ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size
+ % 4)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("IP inserted header must be of size which is a multiple of four bytes"));
+ break;
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP):
+ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
+ % 4)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("CAPWAP inserted header must be of size which is a multiple of four bytes"));
+ break;
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP):
+ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE):
+ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size
+ != 8)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Inserted header must be of size 8"));
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("unsupported insert by header type"));
+ }
+ }
+ case (e_FM_PCD_MANIP_INSRT_GENERIC):
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("for only insert manipulation unsupported type"));
+ }
+ p_Manip->opcode = HMAN_OC;
+ p_Manip->muramAllocate = TRUE;
+ p_Manip->insrt = TRUE;
+ }
+ else
+ if (p_ManipParams->u.hdr.fieldUpdate)
+ {
+ /* Check parameters */
+ if (p_ManipParams->u.hdr.fieldUpdateParams.type
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN)
+ {
+ if ((p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI)
+ && (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri
+ > 7))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("vpri should get values of 0-7 "));
+ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType
+ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN)
+ {
+ int i;
+
+ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal
+ > 7)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("vpriDefVal should get values of 0-7 "));
+ for (i = 0; i < FM_PCD_MANIP_DSCP_TO_VLAN_TRANS;
+ i++)
+ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i]
+ & 0xf0)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("dscpToVpriTabl value out of range (0-15)"));
+ }
+
+ }
+
+ p_Manip->opcode = HMAN_OC;
+ p_Manip->muramAllocate = TRUE;
+ p_Manip->fieldUpdate = TRUE;
+ }
+ else
+ if (p_ManipParams->u.hdr.custom)
+ {
+ if (p_ManipParams->u.hdr.customParams.type == e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE)
+ {
+
+ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.size == 0) ||
+ (p_ManipParams->u.hdr.customParams.u.genFieldReplace.size > 8))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("size should get values of 1-8 "));
+
+ if (p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset > 7)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("srcOffset should be <= 7"));
+
+ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset +
+ p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 8)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("(srcOffset + size) should be <= 8"));
+
+ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset +
+ p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 256)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("(dstOffset + size) should be <= 256"));
+
+ }
+
+ p_Manip->opcode = HMAN_OC;
+ p_Manip->muramAllocate = TRUE;
+ p_Manip->custom = TRUE;
+ }
+ break;
+ case e_FM_PCD_MANIP_REASSEM:
+ if (p_ManipParams->h_NextManip)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("next manip with reassembly"));
+ switch (p_ManipParams->u.reassem.hdr)
+ {
+ case (HEADER_TYPE_IPv4):
+ p_Manip->reassmParams.hdr = HEADER_TYPE_IPv4;
+ p_Manip->opcode = HMAN_OC_IP_REASSEMBLY;
+ break;
+ case (HEADER_TYPE_IPv6):
+ p_Manip->reassmParams.hdr = HEADER_TYPE_IPv6;
+ p_Manip->opcode = HMAN_OC_IP_REASSEMBLY;
+ break;
+#if (DPAA_VERSION >= 11)
+ case (HEADER_TYPE_CAPWAP):
+ p_Manip->reassmParams.hdr = HEADER_TYPE_CAPWAP;
+ p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("header for reassembly"));
+ }
+ break;
+ case e_FM_PCD_MANIP_FRAG:
+ if (p_ManipParams->h_NextManip)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("next manip with fragmentation"));
+ switch (p_ManipParams->u.frag.hdr)
+ {
+ case (HEADER_TYPE_IPv4):
+ case (HEADER_TYPE_IPv6):
+ p_Manip->opcode = HMAN_OC_IP_FRAGMENTATION;
+ break;
+#if (DPAA_VERSION >= 11)
+ case (HEADER_TYPE_CAPWAP):
+ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("header for fragmentation"));
+ }
+ p_Manip->muramAllocate = TRUE;
+ break;
+ case e_FM_PCD_MANIP_SPECIAL_OFFLOAD:
+ switch (p_ManipParams->u.specialOffload.type)
+ {
+ case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC):
+ p_Manip->opcode = HMAN_OC_IPSEC_MANIP;
+ p_Manip->muramAllocate = TRUE;
+ break;
+#if (DPAA_VERSION >= 11)
+ case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP):
+ p_Manip->opcode = HMAN_OC_CAPWAP_MANIP;
+ p_Manip->muramAllocate = TRUE;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("special offload type"));
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("manip type"));
+ }
+
+ return E_OK;
+}
+#endif /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+
+static t_Error UpdateIndxStats(t_Handle h_FmPcd,
+ t_Handle h_FmPort,
+ t_FmPcdManip *p_Manip)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t tmpReg32 = 0;
+ t_AdOfTypeContLookup *p_Ad;
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ if (p_Manip->h_FmPcd != h_FmPcd)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("handler of PCD previously was initiated by different value"));
+
+ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
+
+ if (!p_Manip->p_StatsTbl)
+ {
+
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC;
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ tmpReg32 = GET_UINT32(p_Ad->ccAdBase);
+
+ p_Manip->p_StatsTbl =
+ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)p_Manip->owner * FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE,
+ 4);
+ if (!p_Manip->p_StatsTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation indexed statistics table"));
+
+ MemSet8(p_Manip->p_StatsTbl, 0, (uint32_t)(p_Manip->owner * 4));
+
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->p_StatsTbl) - p_FmPcd->physicalMuramBase);
+
+ if (p_Manip->cnia)
+ tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_CNIA;
+
+ tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_DPD;
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+ }
+ else
+ {
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC;
+ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+static t_Error RmvHdrTillSpecLocNOrInsrtIntFrmHdr(t_FmPcdManipHdrRmvParams *p_ManipParams, t_FmPcdManip *p_Manip)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t tmpReg32 = 0;
+ uint8_t prsArrayOffset = 0;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ if (p_Manip->rmv)
+ {
+ err = GetPrOffsetByHeaderOrField(&p_ManipParams->u.byHdr.u.fromStartByHdr.hdrInfo, &prsArrayOffset);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ tmpReg32 |= (uint32_t)prsArrayOffset << 24;
+ tmpReg32 |= HMAN_RMV_HDR;
+ }
+
+ if (p_Manip->insrt)
+ tmpReg32 |= HMAN_INSRT_INT_FRM_HDR;
+
+ tmpReg32 |= (uint32_t)HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR;
+
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ return E_OK;
+}
+
+static t_Error MvIntFrameHeaderFromFrameToBufferPrefix(t_FmPcdManip *p_Manip,
+ bool caamUsed)
+{
+ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ uint32_t tmpReg32 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Ad, E_INVALID_HANDLE);
+
+ p_Manip->updateParams |= OFFSET_OF_PR | INTERNAL_CONTEXT_OFFSET;
+
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ *(uint32_t *)&p_Ad->ccAdBase = tmpReg32;
+
+ tmpReg32 = 0;
+ tmpReg32 |= HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX;
+ tmpReg32 |= (uint32_t)0x16 << 16;
+ *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32;
+
+ if (caamUsed)
+ *(uint32_t *)&p_Ad->gmask = 0xf0000000;
+
+ return E_OK;
+}
+
+static t_Error CapwapRmvDtlsHdr(t_FmPcd *p_FmPcd, t_FmPcdManip *p_Manip)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t tmpReg32 = 0;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ tmpReg32 = 0;
+ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+
+
+ if (p_Manip->h_Frag)
+ {
+ p_Manip->updateParams |= INTERNAL_CONTEXT_OFFSET;
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase));
+ }
+
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ return err;
+}
+
+static t_Error CapwapReassembly(t_CapwapReassemblyParams *p_ManipParams,
+ t_FmPcdManip *p_Manip,
+ t_FmPcd *p_FmPcd,
+ uint8_t poolId)
+{
+ t_Handle p_Table;
+ uint32_t tmpReg32 = 0;
+ int i = 0;
+ uint8_t log2Num;
+ uint8_t numOfSets;
+ uint32_t j = 0;
+ uint32_t bitFor1Micro;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ if (!p_FmPcd->h_Hc)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("hc port has to be initialized in this mode"));
+ if (!POWER_OF_2(p_ManipParams->timeoutRoutineRequestTime))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("timeoutRoutineRequestTime has to be power of 2"));
+ if (!POWER_OF_2(p_ManipParams->maxNumFramesInProcess))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("maxNumFramesInProcess has to be power of 2"));
+ if (!p_ManipParams->timeoutRoutineRequestTime && p_ManipParams->timeoutThresholdForReassmProcess)
+ DBG(WARNING, ("if timeoutRoutineRequestTime 0, timeoutThresholdForReassmProcess is uselessly"));
+ if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH)
+ {
+ if ((p_ManipParams->maxNumFramesInProcess < 4) ||
+ (p_ManipParams->maxNumFramesInProcess > 512))
+ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_EIGHT_WAYS_HASH maxNumFramesInProcess has to be in the range 4-512"));
+ }
+ else
+ {
+ if ((p_ManipParams->maxNumFramesInProcess < 8) ||
+ (p_ManipParams->maxNumFramesInProcess > 2048))
+ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_FOUR_WAYS_HASH maxNumFramesInProcess has to be in the range 8-2048"));
+ }
+
+ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
+ if (bitFor1Micro == 0)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
+
+ p_Manip->updateParams |= (NUM_OF_TASKS | OFFSET_OF_PR | OFFSET_OF_DATA | HW_PORT_ID);
+
+ p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE,
+ FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN);
+ if (!p_Manip->h_Frag)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc CAPWAP reassembly parameters table"));
+
+ MemSet8(p_Manip->h_Frag, 0, FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE);
+
+ p_Table = (t_CapwapReasmPram *)p_Manip->h_Frag;
+
+ p_Manip->capwapFragParams.p_AutoLearnHashTbl =
+ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE),
+ FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN);
+
+ if (!p_Manip->capwapFragParams.p_AutoLearnHashTbl)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,("MURAM alloc for CAPWAP automatic learning hash table"));
+
+ MemSet8(p_Manip->capwapFragParams.p_AutoLearnHashTbl, 0, (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE));
+
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_AutoLearnHashTbl) - p_FmPcd->physicalMuramBase);
+
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->autoLearnHashTblPtr, tmpReg32);
+
+ tmpReg32 = 0;
+ if (p_ManipParams->timeOutMode == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES)
+ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES;
+ if (p_ManipParams->haltOnDuplicationFrag)
+ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG;
+ if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH)
+ {
+ i = 8;
+ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS;
+ }
+ else
+ i = 4;
+
+ numOfSets = (uint8_t)((p_ManipParams->maxNumFramesInProcess * 2) / i);
+ LOG2(numOfSets, log2Num);
+ tmpReg32 |= (uint32_t)(log2Num - 1) << 24;
+
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->mode, tmpReg32);
+
+ for (j=0; j<p_ManipParams->maxNumFramesInProcess*2; j++)
+ if (((j / i) % 2)== 0)
+ WRITE_UINT32(*(uint32_t *)PTR_MOVE(p_Manip->capwapFragParams.p_AutoLearnHashTbl, j * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), 0x80000000);
+
+ tmpReg32 = 0x00008000;
+ tmpReg32 |= (uint32_t)poolId << 16;
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->bufferPoolIdAndRisc1SetIndexes, tmpReg32);
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc23SetIndexes, 0x80008000);
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc4SetIndexesAndExtendedStatsTblPtr, 0x80000000);
+
+ p_Manip->capwapFragParams.maxNumFramesInProcess = p_ManipParams->maxNumFramesInProcess;
+
+ p_Manip->capwapFragParams.sgBpid = poolId;
+
+ p_Manip->capwapFragParams.fqidForTimeOutFrames = p_ManipParams->fqidForTimeOutFrames;
+ p_Manip->capwapFragParams.timeoutRoutineRequestTime = p_ManipParams->timeoutRoutineRequestTime;
+ p_Manip->capwapFragParams.bitFor1Micro = bitFor1Micro;
+
+ tmpReg32 = 0;
+ tmpReg32 |= (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_ManipParams->timeoutThresholdForReassmProcess);
+ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->expirationDelay, tmpReg32);
+
+ return E_OK;
+}
+
+static t_Error CapwapFragmentation(t_CapwapFragmentationParams *p_ManipParams,
+ t_FmPcdManip *p_Manip,
+ t_FmPcd *p_FmPcd,
+ uint8_t poolId)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t tmpReg32 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+
+ p_Manip->updateParams |= OFFSET_OF_DATA;
+
+ p_Manip->frag = TRUE;
+
+ p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->h_Frag)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP fragmentation table descriptor"));
+
+ MemSet8(p_Manip->h_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag;
+
+ tmpReg32 = 0;
+ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION;
+
+ if (p_ManipParams->headerOptionsCompr)
+ tmpReg32 |= FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN;
+ tmpReg32 |= ((uint32_t)poolId << 8);
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
+ p_Manip->capwapFragParams.sgBpid = poolId;
+
+ return E_OK;
+}
+
+static t_Error IndxStats(t_FmPcdStatsParams *p_StatsParams,t_FmPcdManip *p_Manip,t_FmPcd *p_FmPcd)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t tmpReg32 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+
+ UNUSED(p_FmPcd);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ tmpReg32 = 0;
+ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_INDEXED_STATS;
+ if (p_StatsParams->type == e_FM_PCD_STATS_PER_FLOWID)
+ tmpReg32 |= (uint32_t)0x16 << 16;
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ return E_OK;
+}
+
+static t_Error InsrtHdrByTempl(t_FmPcdManipHdrInsrtParams *p_ManipParams, t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd)
+{
+ t_FmPcdManipHdrInsrtByTemplateParams *p_InsrtByTemplate = &p_ManipParams->u.byTemplate;
+ uint8_t tmpReg8 = 0xff;
+ t_AdOfTypeContLookup *p_Ad;
+ bool ipModify = FALSE;
+ uint32_t tmpReg32 = 0, tmpRegNia = 0;
+ uint16_t tmpReg16 = 0;
+ t_Error err = E_OK;
+ uint8_t extraAddedBytes = 0, blockSize = 0, extraAddedBytesAlignedToBlockSize = 0, log2Num = 0;
+ uint8_t *p_Template = NULL;
+
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd,E_NULL_POINTER);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ if (p_Manip->insrt)
+ {
+ if ((!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp) ||
+ (!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterVlan))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : asking for header template modifications with no template for insertion (template size)"));
+
+ if (p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp && (p_InsrtByTemplate->size <= p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : size of template < ipOuterOffset"));
+
+ if (p_InsrtByTemplate->size > 128)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size of header template for insertion can not be more than 128"));
+
+ if (p_InsrtByTemplate->size)
+ {
+ p_Manip->p_Template = (uint8_t *)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram,
+ p_InsrtByTemplate->size,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if(!p_Manip->p_Template)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation in MURAM FAILED"));
+
+ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->p_Template) - (p_FmPcd->physicalMuramBase));
+ tmpReg32 |= (uint32_t)p_InsrtByTemplate->size << 24;
+ *(uint32_t *)&p_Ad->matchTblPtr = tmpReg32;
+ }
+
+ tmpReg32 = 0;
+
+ p_Template = (uint8_t *)XX_Malloc(p_InsrtByTemplate->size * sizeof(uint8_t));
+
+ if (!p_Template)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("XX_Malloc allocation FAILED"));
+
+ memcpy(p_Template, p_InsrtByTemplate->hdrTemplate, p_InsrtByTemplate->size * sizeof(uint8_t));
+
+ if (p_InsrtByTemplate->modifyOuterIp)
+ {
+ ipModify = TRUE;
+
+ tmpReg8 = (uint8_t)p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset];
+
+ if((tmpReg8 & 0xf0) == 0x40)
+ tmpReg8 = 4;
+ else if((tmpReg8 & 0xf0) == 0x60)
+ tmpReg8 = 6;
+ else
+ tmpReg8 = 0xff;
+
+ if (tmpReg8 != 0xff)
+ {
+ if(p_InsrtByTemplate->modifyOuterIpParams.dscpEcn & 0xff00)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IPV4 present in header template, dscpEcn has to be only 1 byte"));
+ if(p_InsrtByTemplate->modifyOuterIpParams.recalculateLength)
+ {
+
+ if((p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize) > 255)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("extra Byte added can not be more than 256 bytes"));
+ extraAddedBytes = (uint8_t) (p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize);
+ blockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.blockSize;
+ extraAddedBytesAlignedToBlockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize;
+ /*IP header template - IP totalLength -
+ (1 byte) extraByteForIp = headerTemplateSize - ipOffset + insertedBytesAfterThisStage ,
+ in the case of SEC insertedBytesAfterThisStage - SEC trailer (21/31) + header(13)
+ second byte - extraByteForIp = headerTemplate - ipOffset + insertedBytesAfterThisStage*/
+ }
+ if (blockSize)
+ {
+ if (!POWER_OF_2(blockSize))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("inputFrmPaddingUpToBlockSize has to be power of 2"));
+ }
+
+ }
+ if (tmpReg8 == 4)
+ {
+ if ((IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset) > p_InsrtByTemplate->size)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IP present in header template, user asked for IP modifications but ipOffset + ipTotalLengthFieldOffset in header template bigger than template size"));
+
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_DSCECN_FIELD_OFFSET_FROM_IP] = (uint8_t)p_InsrtByTemplate->modifyOuterIpParams.dscpEcn;
+
+ if (blockSize)
+ blockSize -= 1;
+
+ if ((p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes) > 255)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes has to be less than 255"));
+
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP + 1] = blockSize; // IPV6 - in AD instead of SEQ IND
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes);// for IPV6 decrement additional 40 bytes of IPV6 heade size
+
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP] = 0x00;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize;
+
+ /*IP header template - relevant only for ipv4 CheckSum = 0*/
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP] = 0x00;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + 1] = 0x00;
+
+ /*UDP checksum has to be 0*/
+ if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent)
+ {
+ if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template"));
+
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP ] = 0x00;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00;
+
+ }
+
+ if (p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId > 7)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("ipIdentGenId has to be one out of 8 sequence number generators (0 - 7) for IP identification field"));
+
+ tmpRegNia |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId<<24;
+ }
+ else if (tmpReg8 == 6)
+ {
+ /*TODO - add check for maximum value of blockSize;*/
+ if (blockSize)
+ LOG2(blockSize, log2Num);
+ tmpRegNia |= (uint32_t)log2Num << 24;
+
+ // for IPV6 decrement additional 40 bytes of IPV6 heade size - because IPV6 header size is not included in payloadLength
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes - 40);
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize;
+ if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent)
+ {
+ if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template"));
+ if (p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_NEXT_HEADER_OFFSET_FROM_IP] != 0x88)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("OUr suppport is only IPv6/UDPLite"));
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP] = 0x00;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP + 1] = 0x08;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP] = 0x00;
+ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00;
+ }
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("IP version supported only IPV4"));
+ }
+
+ tmpReg32 = tmpReg16 = tmpReg8 = 0;
+ /*TODO - check it*/
+ if (p_InsrtByTemplate->modifyOuterVlan)
+ {
+ if (p_InsrtByTemplate->modifyOuterVlanParams.vpri & ~0x07)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but VPRI more than 3 bits"));
+
+ memcpy(&tmpReg16, &p_Template[VLAN_TAG_FIELD_OFFSET_FROM_ETH], 2*(sizeof(uint8_t)));
+ if ((tmpReg16 != 0x9100) && (tmpReg16!= 0x9200) && (tmpReg16 != 0x8100))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but Tag Protocol identifier is not VLAN "));
+
+ memcpy(&tmpReg8, &p_Template[14],1*(sizeof(uint8_t)));
+ tmpReg8 &= 0x1f;
+ tmpReg8 |= (uint8_t)(p_InsrtByTemplate->modifyOuterVlanParams.vpri << 5);
+
+ p_Template[14] = tmpReg8;
+ }
+
+ MemCpy8(p_Manip->p_Template, p_Template, p_InsrtByTemplate->size);
+
+ XX_Free(p_Template);
+ }
+
+ tmpReg32 = 0;
+ if (p_Manip->h_Frag)
+ {
+ tmpRegNia |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase));
+ tmpReg32 |= (uint32_t)p_Manip->sizeForFragmentation << 16;
+ }
+ else
+ tmpReg32 = 0xffff0000;
+
+ if (ipModify)
+ tmpReg32 |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset << 8;
+ else
+ tmpReg32 |= (uint32_t)0x0000ff00;
+
+ tmpReg32 |= (uint32_t)HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
+ *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32;
+
+ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ *(uint32_t *)&p_Ad->ccAdBase = tmpRegNia;
+
+ return err;
+}
+
+static t_Error CheckStatsParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdStatsParams *p_StatsParams)
+{
+
+ switch (p_StatsParams->type)
+ {
+ case (e_FM_PCD_STATS_PER_FLOWID):
+ p_Manip->opcode = HMAN_OC_CAPWAP_INDEXED_STATS;
+ p_Manip->muramAllocate = TRUE;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported statistics type"));
+ }
+
+ return E_OK;
+}
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+static t_Error FillReassmManipParams(t_FmPcdManip *p_Manip, e_NetHeaderType hdr)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+ uint32_t tmpReg32;
+ t_Error err = E_OK;
+
+ /* Creates the Reassembly Parameters table. It contains parameters that are specific to either the IPv4 reassembly
+ function or to the IPv6 reassembly function. If both IPv4 reassembly and IPv6 reassembly are required, then
+ two separate IP Reassembly Parameter tables are required.*/
+ if ((err = CreateReassTable(p_Manip, hdr)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /* Sets the first Ad register (ccAdBase) - Action Descriptor Type and Pointer to the Reassembly Parameters Table offset from MURAM*/
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+
+ /* Gets the required Action descriptor table pointer */
+ switch (hdr)
+ {
+ case HEADER_TYPE_IPv4:
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv4Ad;
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(
+ p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
+ - (p_FmPcd->physicalMuramBase));
+ break;
+ case HEADER_TYPE_IPv6:
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv6Ad;
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(
+ p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
+ - (p_FmPcd->physicalMuramBase));
+ break;
+ case HEADER_TYPE_CAPWAP:
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.capwap.h_Ad;
+ tmpReg32 |= (uint32_t)(XX_VirtToPhys(
+ p_Manip->reassmParams.capwap.p_ReassTbl)
+ - (p_FmPcd->physicalMuramBase));
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type"));
+ }
+
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ /* Sets the second Ad register (matchTblPtr) - Buffer pool ID (BPID for V2) and Scatter/Gather table offset*/
+ /* mark the Scatter/Gather table offset to be set later on when the port will be known */
+ p_Manip->updateParams = (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK);
+
+ if ((hdr == HEADER_TYPE_IPv6) || (hdr == HEADER_TYPE_IPv4))
+ {
+#if (DPAA_VERSION == 10)
+ tmpReg32 = (uint32_t)(p_Manip->reassmParams.sgBpid << 8);
+ WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32);
+#endif /* (DPAA_VERSION == 10) */
+#if (DPAA_VERSION >= 11)
+ if (p_Manip->reassmParams.ip.nonConsistentSpFqid != 0)
+ {
+ tmpReg32 = FM_PCD_AD_NCSPFQIDM_MASK
+ | (uint32_t)(p_Manip->reassmParams.ip.nonConsistentSpFqid);
+ WRITE_UINT32(p_Ad->gmask, tmpReg32);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ /* Sets the third Ad register (pcAndOffsets)- IP Reassemble Operation Code*/
+ tmpReg32 = 0;
+ tmpReg32 |= (uint32_t)HMAN_OC_IP_REASSEMBLY;
+ }
+#if (DPAA_VERSION >= 11)
+ else
+ if (hdr == HEADER_TYPE_CAPWAP)
+ {
+ tmpReg32 = 0;
+ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_REASSEMBLY;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ p_Manip->reassm = TRUE;
+
+ return E_OK;
+}
+
+static t_Error SetIpv4ReassmManip(t_FmPcdManip *p_Manip)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+
+ /* Allocation if IPv4 Action descriptor */
+ p_Manip->reassmParams.ip.h_Ipv4Ad = (t_Handle)XX_MallocSmart(
+ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->reassmParams.ip.h_Ipv4Ad)
+ {
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("Allocation of IPv4 table descriptor"));
+ }
+
+ memset(p_Manip->reassmParams.ip.h_Ipv4Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */
+ return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv4);
+}
+
+static t_Error SetIpv6ReassmManip(t_FmPcdManip *p_Manip)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+
+ /* Allocation if IPv6 Action descriptor */
+ p_Manip->reassmParams.ip.h_Ipv6Ad = (t_Handle)XX_MallocSmart(
+ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->reassmParams.ip.h_Ipv6Ad)
+ {
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("Allocation of IPv6 table descriptor"));
+ }
+
+ memset(p_Manip->reassmParams.ip.h_Ipv6Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */
+ return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv6);
+}
+
+static t_Error IpReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams,
+ t_FmPcdManip *p_Manip)
+{
+ uint32_t maxSetNumber = 10000;
+ t_FmPcdManipReassemIpParams reassmManipParams =
+ p_ManipReassmParams->u.ipReassem;
+ t_Error res;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc,
+ E_INVALID_HANDLE);
+
+ /* Check validation of user's parameter.*/
+ if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000)
+ || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("timeoutThresholdForReassmProcess should be 1msec - 8sec"));
+ /* It is recommended that the total number of entries in this table (number of sets * number of ways)
+ will be twice the number of frames that are expected to be reassembled simultaneously.*/
+ if (reassmManipParams.maxNumFramesInProcess
+ > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)"));
+
+ if ((p_ManipReassmParams->hdr == HEADER_TYPE_IPv6)
+ && (reassmManipParams.minFragSize[1] < 256))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("minFragSize[1] must be >= 256"));
+
+ /* Saves user's reassembly manipulation parameters */
+ p_Manip->reassmParams.ip.relativeSchemeId[0] =
+ reassmManipParams.relativeSchemeId[0];
+ p_Manip->reassmParams.ip.relativeSchemeId[1] =
+ reassmManipParams.relativeSchemeId[1];
+ p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0] =
+ reassmManipParams.numOfFramesPerHashEntry[0];
+ p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1] =
+ reassmManipParams.numOfFramesPerHashEntry[1];
+ p_Manip->reassmParams.ip.minFragSize[0] = reassmManipParams.minFragSize[0];
+ p_Manip->reassmParams.ip.minFragSize[1] = reassmManipParams.minFragSize[1];
+ p_Manip->reassmParams.maxNumFramesInProcess =
+ reassmManipParams.maxNumFramesInProcess;
+ p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode;
+ p_Manip->reassmParams.fqidForTimeOutFrames =
+ reassmManipParams.fqidForTimeOutFrames;
+ p_Manip->reassmParams.timeoutThresholdForReassmProcess =
+ reassmManipParams.timeoutThresholdForReassmProcess;
+ p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId;
+ p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset;
+#if (DPAA_VERSION == 10)
+ p_Manip->reassmParams.sgBpid = reassmManipParams.sgBpid;
+#endif /* (DPAA_VERSION == 10) */
+#if (DPAA_VERSION >= 11)
+ if (reassmManipParams.nonConsistentSpFqid != 0)
+ {
+ p_Manip->reassmParams.ip.nonConsistentSpFqid =
+ reassmManipParams.nonConsistentSpFqid;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Creates and initializes the IP Reassembly common parameter table */
+ CreateReassCommonTable(p_Manip);
+
+ /* Creation of IPv4 reassembly manipulation */
+ if ((p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6)
+ || (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv4))
+ {
+ res = SetIpv4ReassmManip(p_Manip);
+ if (res != E_OK)
+ return res;
+ }
+
+ /* Creation of IPv6 reassembly manipulation */
+ if (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6)
+ {
+ res = SetIpv6ReassmManip(p_Manip);
+ if (res != E_OK)
+ return res;
+ }
+
+ return E_OK;
+}
+
+static void setIpReassmSchemeParams(t_FmPcd* p_FmPcd,
+ t_FmPcdKgSchemeParams *p_Scheme,
+ t_Handle h_CcTree, bool ipv4,
+ uint8_t groupId)
+{
+ uint32_t j;
+ uint8_t res;
+
+ /* Configures scheme's network environment parameters */
+ p_Scheme->netEnvParams.numOfDistinctionUnits = 2;
+ if (ipv4)
+ res = FmPcdNetEnvGetUnitId(
+ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
+ HEADER_TYPE_IPv4, FALSE, 0);
+ else
+ res = FmPcdNetEnvGetUnitId(
+ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
+ HEADER_TYPE_IPv6, FALSE, 0);
+ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ p_Scheme->netEnvParams.unitIds[0] = res;
+
+ res = FmPcdNetEnvGetUnitId(
+ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
+ HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0);
+ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ p_Scheme->netEnvParams.unitIds[1] = res;
+
+ /* Configures scheme's next engine parameters*/
+ p_Scheme->nextEngine = e_FM_PCD_CC;
+ p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree;
+ p_Scheme->kgNextEngineParams.cc.grpId = groupId;
+ p_Scheme->useHash = TRUE;
+
+ /* Configures scheme's key*/
+ if (ipv4 == TRUE)
+ {
+ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 4;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FULL_FIELD;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr =
+ HEADER_TYPE_IPv4;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv4 =
+ NET_HEADER_FIELD_IPv4_DST_IP;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FULL_FIELD;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr =
+ HEADER_TYPE_IPv4;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv4 =
+ NET_HEADER_FIELD_IPv4_SRC_IP;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FULL_FIELD;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr =
+ HEADER_TYPE_IPv4;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fullField.ipv4 =
+ NET_HEADER_FIELD_IPv4_PROTO;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.hdr =
+ HEADER_TYPE_IPv4;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.ignoreProtocolValidation =
+ FALSE;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.size =
+ 2;
+ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.offset =
+ 4;
+ }
+ else /* IPv6 */
+ {
+ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 3;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FULL_FIELD;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr =
+ HEADER_TYPE_IPv6;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv6 =
+ NET_HEADER_FIELD_IPv6_DST_IP;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FULL_FIELD;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr =
+ HEADER_TYPE_IPv6;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv6 =
+ NET_HEADER_FIELD_IPv6_SRC_IP;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].type =
+ e_FM_PCD_EXTRACT_BY_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr =
+ HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type =
+ e_FM_PCD_EXTRACT_FROM_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.size =
+ 4;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.offset =
+ 4;
+ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.ignoreProtocolValidation =
+ TRUE;
+ }
+
+ p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x01020304;
+ p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x11121314;
+ p_Scheme->keyExtractAndHashParams.numOfUsedDflts =
+ FM_PCD_KG_NUM_OF_DEFAULT_GROUPS;
+ for (j = 0; j < FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; j++)
+ {
+ p_Scheme->keyExtractAndHashParams.dflts[j].type =
+ (e_FmPcdKgKnownFieldsDfltTypes)j; /* all types */
+ p_Scheme->keyExtractAndHashParams.dflts[j].dfltSelect =
+ e_FM_PCD_KG_DFLT_GBL_0;
+ }
+}
+
+static t_Error IpReassemblyStats(t_FmPcdManip *p_Manip,
+ t_FmPcdManipReassemIpStats *p_Stats)
+{
+ ASSERT_COND(p_Manip);
+ ASSERT_COND(p_Stats);
+ ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl);
+
+ p_Stats->timeout =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter);
+ p_Stats->rfdPoolBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter);
+ p_Stats->internalBufferBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy);
+ p_Stats->externalBufferBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy);
+ p_Stats->sgFragments =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter);
+ p_Stats->dmaSemaphoreDepletion =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter);
+#if (DPAA_VERSION >= 11)
+ p_Stats->nonConsistentSp =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter);
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl)
+ {
+ p_Stats->specificHdrStatistics[0].successfullyReassembled =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSuccessfullyReasmFramesCounter);
+ p_Stats->specificHdrStatistics[0].validFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalValidFragmentCounter);
+ p_Stats->specificHdrStatistics[0].processedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalProcessedFragCounter);
+ p_Stats->specificHdrStatistics[0].malformedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMalformdFragCounter);
+ p_Stats->specificHdrStatistics[0].autoLearnBusy =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSetBusyCounter);
+ p_Stats->specificHdrStatistics[0].discardedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalDiscardedFragsCounter);
+ p_Stats->specificHdrStatistics[0].moreThan16Fragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMoreThan16FramesCounter);
+ }
+ if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl)
+ {
+ p_Stats->specificHdrStatistics[1].successfullyReassembled =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSuccessfullyReasmFramesCounter);
+ p_Stats->specificHdrStatistics[1].validFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalValidFragmentCounter);
+ p_Stats->specificHdrStatistics[1].processedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalProcessedFragCounter);
+ p_Stats->specificHdrStatistics[1].malformedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMalformdFragCounter);
+ p_Stats->specificHdrStatistics[1].autoLearnBusy =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSetBusyCounter);
+ p_Stats->specificHdrStatistics[1].discardedFragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalDiscardedFragsCounter);
+ p_Stats->specificHdrStatistics[1].moreThan16Fragments =
+ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMoreThan16FramesCounter);
+ }
+ return E_OK;
+}
+
+static t_Error IpFragmentationStats(t_FmPcdManip *p_Manip,
+ t_FmPcdManipFragIpStats *p_Stats)
+{
+ t_AdOfTypeContLookup *p_Ad;
+
+ ASSERT_COND(p_Manip);
+ ASSERT_COND(p_Stats);
+ ASSERT_COND(p_Manip->h_Ad);
+ ASSERT_COND(p_Manip->fragParams.p_Frag);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ p_Stats->totalFrames = GET_UINT32(p_Ad->gmask);
+ p_Stats->fragmentedFrames = GET_UINT32(p_Manip->fragParams.p_Frag->ccAdBase)
+ & 0x00ffffff;
+ p_Stats->generatedFragments =
+ GET_UINT32(p_Manip->fragParams.p_Frag->matchTblPtr);
+
+ return E_OK;
+}
+
+static t_Error IpFragmentation(t_FmPcdManipFragIpParams *p_ManipParams,
+ t_FmPcdManip *p_Manip)
+{
+ uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0;
+ t_FmPcd *p_FmPcd;
+#if (DPAA_VERSION == 10)
+ t_Error err = E_OK;
+#endif /* (DPAA_VERSION == 10) */
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF,
+ E_INVALID_VALUE);
+
+ p_FmPcd = p_Manip->h_FmPcd;
+ /* Allocation of fragmentation Action Descriptor */
+ p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem(
+ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->fragParams.p_Frag)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Fragmentation table descriptor"));
+ MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Prepare the third Ad register (pcAndOffsets)- OperationCode */
+ pcAndOffsetsReg = (uint32_t)HMAN_OC_IP_FRAGMENTATION;
+
+ /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/
+ ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE;
+ ccAdBaseReg |= (p_ManipParams->dontFragAction
+ << FM_PCD_MANIP_IP_FRAG_DF_SHIFT);
+
+
+ /* Set Scatter/Gather BPid */
+ if (p_ManipParams->sgBpidEn)
+ {
+ ccAdBaseReg |= FM_PCD_MANIP_IP_FRAG_SG_BDID_EN;
+ pcAndOffsetsReg |= ((p_ManipParams->sgBpid
+ << FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT)
+ & FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK);
+ }
+
+ /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */
+ gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr))
+ - p_FmPcd->physicalMuramBase);
+#if (DPAA_VERSION == 10)
+ gmaskReg |= p_ManipParams->scratchBpid << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
+#else
+ gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
+#endif /* (DPAA_VERSION == 10) */
+
+ /* Set all Ad registers */
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg);
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg);
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg);
+
+ /* Saves user's fragmentation manipulation parameters */
+ p_Manip->frag = TRUE;
+ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
+
+#if (DPAA_VERSION == 10)
+ p_Manip->fragParams.scratchBpid = p_ManipParams->scratchBpid;
+
+ /* scratch buffer pool initialization */
+ if ((err = FmPcdFragHcScratchPoolFill((t_Handle)p_FmPcd, p_ManipParams->scratchBpid)) != E_OK)
+ {
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag);
+ p_Manip->fragParams.p_Frag = NULL;
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+#endif /* (DPAA_VERSION == 10) */
+
+ return E_OK;
+}
+
+static t_Error IPManip(t_FmPcdManip *p_Manip)
+{
+ t_Error err = E_OK;
+ t_FmPcd *p_FmPcd;
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t tmpReg32 = 0, tmpRegNia = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ p_FmPcd = p_Manip->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ tmpReg32 = FM_PCD_MANIP_IP_NO_FRAGMENTATION;
+ if (p_Manip->frag == TRUE)
+ {
+ tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag)
+ - (p_FmPcd->physicalMuramBase));
+ tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation
+ << FM_PCD_MANIP_IP_MTU_SHIFT;
+ }
+
+ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ tmpReg32 |= HMAN_OC_IP_MANIP;
+
+#if (DPAA_VERSION >= 11)
+ tmpRegNia |= FM_PCD_MANIP_IP_CNIA;
+#endif /* (DPAA_VERSION >= 11) */
+
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+ WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia);
+ WRITE_UINT32(p_Ad->gmask, 0);
+ /* Total frame counter - MUST be initialized to zero.*/
+
+ return err;
+}
+
+static t_Error UpdateInitIpFrag(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_FmPcdManip *p_Manip,
+ t_Handle h_Ad, bool validate)
+{
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION),
+ E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+
+ UNUSED(h_FmPcd);
+ UNUSED(h_Ad);
+ UNUSED(h_PcdParams);
+ UNUSED(validate);
+ UNUSED(p_Manip);
+
+ fmPortGetSetCcParams.setCcParams.type = 0;
+ fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE;
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset)
+ DBG(WARNING, ("manipExtraSpace must be larger than '0'"));
+
+ return E_OK;
+}
+
+static t_Error IPSecManip(t_FmPcdManipParams *p_ManipParams,
+ t_FmPcdManip *p_Manip)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ t_FmPcdManipSpecialOffloadIPSecParams *p_IPSecParams;
+ t_Error err = E_OK;
+ uint32_t tmpReg32 = 0;
+ uint32_t power;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
+
+ p_IPSecParams = &p_ManipParams->u.specialOffload.u.ipsec;
+
+ SANITY_CHECK_RETURN_ERROR(
+ !p_IPSecParams->variableIpHdrLen || p_IPSecParams->decryption,
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(
+ !p_IPSecParams->variableIpVersion || !p_IPSecParams->decryption,
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(
+ !p_IPSecParams->variableIpVersion || p_IPSecParams->outerIPHdrLen,
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(
+ !p_IPSecParams->arwSize || p_IPSecParams->arwAddr,
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(
+ !p_IPSecParams->arwSize || p_IPSecParams->decryption,
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR((p_IPSecParams->arwSize % 16) == 0, E_INVALID_VALUE);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ tmpReg32 |= (p_IPSecParams->decryption) ? FM_PCD_MANIP_IPSEC_DEC : 0;
+ tmpReg32 |= (p_IPSecParams->ecnCopy) ? FM_PCD_MANIP_IPSEC_ECN_EN : 0;
+ tmpReg32 |= (p_IPSecParams->dscpCopy) ? FM_PCD_MANIP_IPSEC_DSCP_EN : 0;
+ tmpReg32 |=
+ (p_IPSecParams->variableIpHdrLen) ? FM_PCD_MANIP_IPSEC_VIPL_EN : 0;
+ tmpReg32 |=
+ (p_IPSecParams->variableIpVersion) ? FM_PCD_MANIP_IPSEC_VIPV_EN : 0;
+ if (p_IPSecParams->arwSize)
+ tmpReg32 |= (uint32_t)((XX_VirtToPhys(UINT_TO_PTR(p_IPSecParams->arwAddr))-FM_MM_MURAM)
+ & (FM_MURAM_SIZE-1));
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ tmpReg32 = 0;
+ if (p_IPSecParams->arwSize) {
+ NEXT_POWER_OF_2((p_IPSecParams->arwSize + 32), power);
+ LOG2(power, power);
+ tmpReg32 = (p_IPSecParams->arwSize | (power - 5)) << FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT;
+ }
+
+ if (p_ManipParams->h_NextManip)
+ tmpReg32 |=
+ (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)-
+ (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4;
+ WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32);
+
+ tmpReg32 = HMAN_OC_IPSEC_MANIP;
+ tmpReg32 |= p_IPSecParams->outerIPHdrLen
+ << FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT;
+ if (p_ManipParams->h_NextManip)
+ tmpReg32 |= FM_PCD_MANIP_IPSEC_NADEN;
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ return err;
+}
+
+static t_Error SetCapwapReassmManip(t_FmPcdManip *p_Manip)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd;
+
+ /* Allocation if CAPWAP Action descriptor */
+ p_Manip->reassmParams.capwap.h_Ad = (t_Handle)XX_MallocSmart(
+ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->reassmParams.capwap.h_Ad)
+ {
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("Allocation of CAPWAP table descriptor"));
+ }
+
+ memset(p_Manip->reassmParams.capwap.h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Fill reassembly manipulation parameter in the Reassembly Action Descriptor */
+ return FillReassmManipParams(p_Manip, HEADER_TYPE_CAPWAP);
+}
+
+static void setCapwapReassmSchemeParams(t_FmPcd* p_FmPcd,
+ t_FmPcdKgSchemeParams *p_Scheme,
+ t_Handle h_CcTree, uint8_t groupId)
+{
+ uint8_t res;
+
+ /* Configures scheme's network environment parameters */
+ p_Scheme->netEnvParams.numOfDistinctionUnits = 1;
+ res = FmPcdNetEnvGetUnitId(
+ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv),
+ HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0);
+ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ p_Scheme->netEnvParams.unitIds[0] = res;
+
+ /* Configures scheme's next engine parameters*/
+ p_Scheme->nextEngine = e_FM_PCD_CC;
+ p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree;
+ p_Scheme->kgNextEngineParams.cc.grpId = groupId;
+ p_Scheme->useHash = TRUE;
+
+ /* Configures scheme's key*/
+ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 2;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].type =
+ e_FM_PCD_EXTRACT_NON_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.src =
+ e_FM_PCD_EXTRACT_FROM_PARSE_RESULT;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.action =
+ e_FM_PCD_ACTION_NONE;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.offset = 20;
+ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.size = 4;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].type =
+ e_FM_PCD_EXTRACT_NON_HDR;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.src =
+ e_FM_PCD_EXTRACT_FROM_DFLT_VALUE;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.action =
+ e_FM_PCD_ACTION_NONE;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.offset = 0;
+ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.size = 1;
+
+ p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x0;
+ p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x0;
+ p_Scheme->keyExtractAndHashParams.numOfUsedDflts = 1;
+ p_Scheme->keyExtractAndHashParams.dflts[0].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA;
+ p_Scheme->keyExtractAndHashParams.dflts[0].dfltSelect = e_FM_PCD_KG_DFLT_PRIVATE_0;
+}
+
+#if (DPAA_VERSION >= 11)
+static t_Error CapwapReassemblyStats(t_FmPcdManip *p_Manip,
+ t_FmPcdManipReassemCapwapStats *p_Stats)
+{
+ ASSERT_COND(p_Manip);
+ ASSERT_COND(p_Stats);
+ ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl);
+
+ p_Stats->timeout =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter);
+ p_Stats->rfdPoolBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter);
+ p_Stats->internalBufferBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy);
+ p_Stats->externalBufferBusy =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy);
+ p_Stats->sgFragments =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter);
+ p_Stats->dmaSemaphoreDepletion =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter);
+ p_Stats->exceedMaxReassemblyFrameLen =
+ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter);
+
+ p_Stats->successfullyReassembled =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSuccessfullyReasmFramesCounter);
+ p_Stats->validFragments =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalValidFragmentCounter);
+ p_Stats->processedFragments =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalProcessedFragCounter);
+ p_Stats->malformedFragments =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMalformdFragCounter);
+ p_Stats->autoLearnBusy =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSetBusyCounter);
+ p_Stats->discardedFragments =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalDiscardedFragsCounter);
+ p_Stats->moreThan16Fragments =
+ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMoreThan16FramesCounter);
+
+ return E_OK;
+}
+
+static t_Error CapwapFragmentationStats(t_FmPcdManip *p_Manip,
+ t_FmPcdManipFragCapwapStats *p_Stats)
+{
+ t_AdOfTypeContLookup *p_Ad;
+
+ ASSERT_COND(p_Manip);
+ ASSERT_COND(p_Stats);
+ ASSERT_COND(p_Manip->h_Ad);
+ ASSERT_COND(p_Manip->fragParams.p_Frag);
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ p_Stats->totalFrames = GET_UINT32(p_Ad->gmask);
+
+ return E_OK;
+}
+
+static t_Error CapwapReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams,
+ t_FmPcdManip *p_Manip)
+{
+ uint32_t maxSetNumber = 10000;
+ t_FmPcdManipReassemCapwapParams reassmManipParams =
+ p_ManipReassmParams->u.capwapReassem;
+ t_Error res;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc,
+ E_INVALID_HANDLE);
+
+ /* Check validation of user's parameter.*/
+ if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000)
+ || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("timeoutThresholdForReassmProcess should be 1msec - 8sec"));
+ /* It is recommended that the total number of entries in this table (number of sets * number of ways)
+ will be twice the number of frames that are expected to be reassembled simultaneously.*/
+ if (reassmManipParams.maxNumFramesInProcess
+ > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)"));
+
+ /* Saves user's reassembly manipulation parameters */
+ p_Manip->reassmParams.capwap.relativeSchemeId =
+ reassmManipParams.relativeSchemeId;
+ p_Manip->reassmParams.capwap.numOfFramesPerHashEntry =
+ reassmManipParams.numOfFramesPerHashEntry;
+ p_Manip->reassmParams.capwap.maxRessembledsSize =
+ reassmManipParams.maxReassembledFrameLength;
+ p_Manip->reassmParams.maxNumFramesInProcess =
+ reassmManipParams.maxNumFramesInProcess;
+ p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode;
+ p_Manip->reassmParams.fqidForTimeOutFrames =
+ reassmManipParams.fqidForTimeOutFrames;
+ p_Manip->reassmParams.timeoutThresholdForReassmProcess =
+ reassmManipParams.timeoutThresholdForReassmProcess;
+ p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId;
+ p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset;
+
+ /* Creates and initializes the Reassembly common parameter table */
+ CreateReassCommonTable(p_Manip);
+
+ res = SetCapwapReassmManip(p_Manip);
+ if (res != E_OK)
+ return res;
+
+ return E_OK;
+}
+
+static t_Error CapwapFragmentation(t_FmPcdManipFragCapwapParams *p_ManipParams,
+ t_FmPcdManip *p_Manip)
+{
+ t_FmPcd *p_FmPcd;
+ t_AdOfTypeContLookup *p_Ad;
+ uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0;
+ uint32_t tmpReg32 = 0, tmpRegNia = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF,
+ E_INVALID_VALUE);
+ p_FmPcd = p_Manip->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ /* Allocation of fragmentation Action Descriptor */
+ p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem(
+ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->fragParams.p_Frag)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("MURAM alloc for Fragmentation table descriptor"));
+ MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Prepare the third Ad register (pcAndOffsets)- OperationCode */
+ pcAndOffsetsReg = (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION;
+
+ /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/
+ ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE;
+ ccAdBaseReg |=
+ (p_ManipParams->compressModeEn) ? FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN :
+ 0;
+
+ /* Set Scatter/Gather BPid */
+ if (p_ManipParams->sgBpidEn)
+ {
+ ccAdBaseReg |= FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN;
+ pcAndOffsetsReg |= ((p_ManipParams->sgBpid
+ << FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT)
+ & FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK);
+ }
+
+ /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */
+ gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr))
+ - p_FmPcd->physicalMuramBase);
+ gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID;
+
+ /* Set all Ad registers */
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg);
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg);
+ WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg);
+
+ /* Saves user's fragmentation manipulation parameters */
+ p_Manip->frag = TRUE;
+ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation;
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+
+ tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag)
+ - (p_FmPcd->physicalMuramBase));
+ tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation
+ << FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT;
+
+ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ tmpReg32 |= HMAN_OC_CAPWAP_FRAG_CHECK;
+
+ tmpRegNia |= FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA;
+
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+ WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia);
+ WRITE_UINT32(p_Ad->gmask, 0);
+ /* Total frame counter - MUST be initialized to zero.*/
+
+ return E_OK;
+}
+
+static t_Error UpdateInitCapwapFrag(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_FmPcdManip *p_Manip,
+ t_Handle h_Ad, bool validate)
+{
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION),
+ E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+
+ UNUSED(h_FmPcd);
+ UNUSED(h_Ad);
+ UNUSED(h_PcdParams);
+ UNUSED(validate);
+ UNUSED(p_Manip);
+
+ fmPortGetSetCcParams.setCcParams.type = 0;
+ fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE;
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset)
+ DBG(WARNING, ("manipExtraSpace must be larger than '0'"));
+
+ return E_OK;
+}
+
+static t_Error CapwapManip(t_FmPcdManipParams *p_ManipParams,
+ t_FmPcdManip *p_Manip)
+{
+ t_AdOfTypeContLookup *p_Ad;
+ t_FmPcdManipSpecialOffloadCapwapParams *p_Params;
+ t_Error err = E_OK;
+ uint32_t tmpReg32 = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
+
+ p_Params = &p_ManipParams->u.specialOffload.u.capwap;
+
+ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad;
+ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE;
+ tmpReg32 |= (p_Params->dtls) ? FM_PCD_MANIP_CAPWAP_DTLS : 0;
+ /* TODO - add 'qosSrc' */
+ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32);
+
+ tmpReg32 = HMAN_OC_CAPWAP_MANIP;
+ if (p_ManipParams->h_NextManip)
+ {
+ WRITE_UINT32(
+ p_Ad->matchTblPtr,
+ (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4);
+
+ tmpReg32 |= FM_PCD_MANIP_CAPWAP_NADEN;
+ }
+
+ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32);
+
+ return err;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+static t_Handle ManipOrStatsSetNode(t_Handle h_FmPcd, t_Handle *p_Params,
+ bool stats)
+{
+ t_FmPcdManip *p_Manip;
+ t_Error err;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+
+ p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip));
+ if (!p_Manip)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+ return NULL;
+ }
+ memset(p_Manip, 0, sizeof(t_FmPcdManip));
+
+ p_Manip->type = ((t_FmPcdManipParams *)p_Params)->type;
+ memcpy((uint8_t*)&p_Manip->manipParams, p_Params,
+ sizeof(p_Manip->manipParams));
+
+ if (!stats)
+ err = CheckManipParamsAndSetType(p_Manip,
+ (t_FmPcdManipParams *)p_Params);
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ else
+ err = CheckStatsParamsAndSetType(p_Manip, (t_FmPcdStatsParams *)p_Params);
+#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ else
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Statistics node!"));
+ XX_Free(p_Manip);
+ return NULL;
+ }
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Invalid header manipulation type"));
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ if ((p_Manip->opcode != HMAN_OC_IP_REASSEMBLY) && (p_Manip->opcode != HMAN_OC_CAPWAP_REASSEMBLY))
+ {
+ /* In Case of reassembly manipulation the reassembly action descriptor will
+ be defines later on */
+ if (p_Manip->muramAllocate)
+ {
+ p_Manip->h_Ad = (t_Handle)FM_MURAM_AllocMem(
+ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_Manip->h_Ad)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation action descriptor"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ MemSet8(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+ }
+ else
+ {
+ p_Manip->h_Ad = (t_Handle)XX_Malloc(
+ FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
+ if (!p_Manip->h_Ad)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
+ }
+ }
+
+ p_Manip->h_FmPcd = h_FmPcd;
+
+ return p_Manip;
+}
+
+static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip(
+ t_FmPcdManip *p_CrntMdfManip, t_List *h_NodesLst)
+{
+ t_CcNodeInformation *p_CcNodeInformation;
+ t_FmPcdCcNode *p_NodePtrOnCurrentMdfManip = NULL;
+ t_List *p_Pos;
+ int i = 0;
+ t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/;
+ t_CcNodeInformation ccNodeInfo;
+
+ LIST_FOR_EACH(p_Pos, &p_CrntMdfManip->nodesLst)
+ {
+ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos);
+ p_NodePtrOnCurrentMdfManip =
+ (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode;
+
+ ASSERT_COND(p_NodePtrOnCurrentMdfManip);
+
+ /* Search in the previous node which exact index points on this current modified node for getting AD */
+ for (i = 0; i < p_NodePtrOnCurrentMdfManip->numOfKeys + 1; i++)
+ {
+ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.nextEngine
+ == e_FM_PCD_CC)
+ {
+ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.h_Manip
+ == (t_Handle)p_CrntMdfManip)
+ {
+ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj)
+ p_AdTablePtOnCrntCurrentMdfNode =
+ p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd;
+ else
+ p_AdTablePtOnCrntCurrentMdfNode =
+ PTR_MOVE(p_NodePtrOnCurrentMdfManip->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE);
+
+ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation));
+ ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode;
+ EnqueueNodeInfoToRelevantLst(h_NodesLst, &ccNodeInfo, NULL);
+ }
+ }
+ }
+
+ ASSERT_COND(i != p_NodePtrOnCurrentMdfManip->numOfKeys);
+ }
+}
+
+static void BuildHmtd(uint8_t *p_Dest, uint8_t *p_Src, uint8_t *p_Hmcd,
+ t_FmPcd *p_FmPcd)
+{
+ t_Error err;
+
+ /* Copy the HMTD */
+ MemCpy8(p_Dest, (uint8_t*)p_Src, 16);
+ /* Replace the HMCT table pointer */
+ WRITE_UINT32(
+ ((t_Hmtd *)p_Dest)->hmcdBasePtr,
+ (uint32_t)(XX_VirtToPhys(p_Hmcd) - ((t_FmPcd*)p_FmPcd)->physicalMuramBase));
+ /* Call Host Command to replace HMTD by a new HMTD */
+ err = FmHcPcdCcDoDynamicChange(
+ p_FmPcd->h_Hc,
+ (uint32_t)(XX_VirtToPhys(p_Src) - p_FmPcd->physicalMuramBase),
+ (uint32_t)(XX_VirtToPhys(p_Dest) - p_FmPcd->physicalMuramBase));
+ if (err)
+ REPORT_ERROR(MINOR, err, ("Failed in dynamic manip change, continued to the rest of the owners."));
+}
+
+static t_Error FmPcdManipInitUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_Handle h_Manip,
+ t_Handle h_Ad, bool validate, int level,
+ t_Handle h_FmTree)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
+
+ UNUSED(level);
+ UNUSED(h_FmTree);
+
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ err = UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(h_FmPort,
+ p_Manip,
+ h_Ad,
+ validate);
+ break;
+ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
+ if (!p_Manip->h_Frag)
+ break;
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ err = UpdateInitCapwapFragmentation(h_FmPort, p_Manip, h_Ad, validate, h_FmTree);
+ break;
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ if (p_Manip->h_Frag)
+ err = UpdateInitCapwapReasm(h_FmPcd, h_FmPort, p_Manip, h_Ad, validate);
+ break;
+ case (HMAN_OC_CAPWAP_INDEXED_STATS):
+ err = UpdateIndxStats(h_FmPcd, h_FmPort, p_Manip);
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ case (HMAN_OC_IP_REASSEMBLY):
+ err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad,
+ validate);
+ break;
+ case (HMAN_OC_IP_FRAGMENTATION):
+ err = UpdateInitIpFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip,
+ h_Ad, validate);
+ break;
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ err = UpdateInitCapwapFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip,
+ h_Ad, validate);
+ break;
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad,
+ validate);
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ return E_OK;
+ }
+
+ return err;
+}
+
+static t_Error FmPcdManipModifyUpdate(t_Handle h_Manip, t_Handle h_Ad,
+ bool validate, int level,
+ t_Handle h_FmTree)
+{
+
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_Error err = E_OK;
+
+ UNUSED(level);
+
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("modify node with this type of manipulation is not suppported"));
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+
+ if (p_Manip->h_Frag)
+ {
+ if (!(p_Manip->shadowUpdateParams & NUM_OF_TASKS)
+ && !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)
+ && !(p_Manip->shadowUpdateParams & OFFSET_OF_PR))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("modify node with this type of manipulation requires manipulation be updated previously in SetPcd function"));
+ }
+ break;
+ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
+ if (p_Manip->h_Frag)
+ err = UpdateModifyCapwapFragmenation(p_Manip, h_Ad, validate, h_FmTree);
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ default:
+ return E_OK;
+ }
+
+ return err;
+}
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams,
+ t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad,
+ bool validate, int level, t_Handle h_FmTree,
+ bool modify)
+{
+ t_Error err;
+
+ if (!modify)
+ err = FmPcdManipInitUpdate(h_FmPcd, h_PcdParams, h_FmPort, h_Manip,
+ h_Ad, validate, level, h_FmTree);
+ else
+ err = FmPcdManipModifyUpdate(h_Manip, h_Ad, validate, level, h_FmTree);
+
+ return err;
+}
+
+void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add)
+{
+
+ uint32_t intFlags;
+
+ intFlags = XX_LockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock);
+ if (add)
+ ((t_FmPcdManip *)h_Manip)->owner++;
+ else
+ {
+ ASSERT_COND(((t_FmPcdManip *)h_Manip)->owner);
+ ((t_FmPcdManip *)h_Manip)->owner--;
+ }
+ XX_UnlockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock, intFlags);
+}
+
+t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip)
+{
+ ASSERT_COND(h_Manip);
+ return &((t_FmPcdManip *)h_Manip)->nodesLst;
+}
+
+t_List *FmPcdManipGetSpinlock(t_Handle h_Manip)
+{
+ ASSERT_COND(h_Manip);
+ return ((t_FmPcdManip *)h_Manip)->h_Spinlock;
+}
+
+t_Error FmPcdManipCheckParamsForCcNextEngine(
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
+ uint32_t *requiredAction)
+{
+ t_FmPcdManip *p_Manip;
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ t_Error err = E_OK;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))*/
+ bool pointFromCc = TRUE;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams->h_Manip,
+ E_NULL_POINTER);
+
+ p_Manip = (t_FmPcdManip *)(p_FmPcdCcNextEngineParams->h_Manip);
+ *requiredAction = 0;
+
+ while (p_Manip)
+ {
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_CAPWAP_INDEXED_STATS):
+ if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE"));
+ if (p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
+ p_Manip->cnia = TRUE;
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA;
+ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
+ p_Manip->ownerTmp++;
+ break;
+ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
+ if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
+ && !p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE with fqidForCtrlFlow FALSE"));
+ p_Manip->ownerTmp++;
+ break;
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_CC)
+ && (FmPcdCcGetParseCode(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)
+ != CC_PC_GENERIC_IC_HASH_INDEXED))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation next engine has to be CC and action = e_FM_PCD_ACTION_INDEXED_LOOKUP"));
+ err = UpdateManipIc(p_FmPcdCcNextEngineParams->h_Manip,
+ FmPcdCcGetOffset(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode));
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA;
+ break;
+ #endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ case (HMAN_OC_IP_FRAGMENTATION):
+ case (HMAN_OC_IP_REASSEMBLY):
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+#endif /* (DPAA_VERSION >= 11) */
+ if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE"));
+ p_Manip->ownerTmp++;
+ break;
+ case (HMAN_OC_IPSEC_MANIP):
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_MANIP):
+#endif /* (DPAA_VERSION >= 11) */
+ p_Manip->ownerTmp++;
+ break;
+ case (HMAN_OC):
+ if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC)
+ && MANIP_IS_CASCADED(p_Manip))
+ RETURN_ERROR(
+ MINOR,
+ E_INVALID_STATE,
+ ("Can't have a cascaded manipulation when and Next Engine is CC"));
+ if (!MANIP_IS_FIRST(p_Manip) && pointFromCc)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("h_Manip is already used and may not be shared (no sharing of non-head manip nodes)"));
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("invalid type of header manipulation for this state"));
+ }
+ p_Manip = p_Manip->h_NextManip;
+ pointFromCc = FALSE;
+ }
+ return E_OK;
+}
+
+
+t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip,
+ t_Handle h_FmPcdCcNode)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcNode, E_INVALID_HANDLE);
+
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_CAPWAP_INDEXED_STATS):
+ if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("The manipulation of the type statistics flowId if exist has to be pointed by all numOfKeys"));
+ break;
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ if (p_Manip->h_Frag)
+ {
+ if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("The manipulation of the type remove DTLS if exist has to be pointed by all numOfKeys"));
+ err = UpdateManipIc(h_Manip, FmPcdCcGetOffset(h_FmPcdCcNode));
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ default:
+ break;
+ }
+
+ return err;
+}
+
+void FmPcdManipUpdateAdResultForCc(
+ t_Handle h_Manip, t_FmPcdCcNextEngineParams *p_CcNextEngineParams,
+ t_Handle p_Ad, t_Handle *p_AdNewPtr)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+
+ /* This routine creates a Manip AD and can return in "p_AdNewPtr"
+ * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */
+
+ ASSERT_COND(p_Manip);
+ ASSERT_COND(p_CcNextEngineParams);
+ ASSERT_COND(p_Ad);
+ ASSERT_COND(p_AdNewPtr);
+
+ FmPcdManipUpdateOwner(h_Manip, TRUE);
+
+ /* According to "type", either build & initialize a new AD (p_AdNew) or initialize
+ * p_Ad ( the AD in the match table) and set p_AdNew = NULL. */
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ case (HMAN_OC_CAPWAP_INDEXED_STATS):
+ *p_AdNewPtr = p_Manip->h_Ad;
+ break;
+ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->fqid,
+ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->fqid);
+ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->plcrProfile,
+ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->plcrProfile);
+ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->nia,
+ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->nia);
+ *p_AdNewPtr = NULL;
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ case (HMAN_OC_IPSEC_MANIP):
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_MANIP):
+#endif /* (DPAA_VERSION >= 11) */
+ *p_AdNewPtr = p_Manip->h_Ad;
+ break;
+ case (HMAN_OC_IP_FRAGMENTATION):
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+#endif /* (DPAA_VERSION >= 11) */
+ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_DONE)
+ && (!p_CcNextEngineParams->params.enqueueParams.overrideFqid))
+ {
+ memcpy((uint8_t *)p_Ad, (uint8_t *)p_Manip->h_Ad,
+ sizeof(t_AdOfTypeContLookup));
+#if (DPAA_VERSION >= 11)
+ WRITE_UINT32(
+ ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
+ GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) & ~FM_PCD_MANIP_IP_CNIA);
+#endif /* (DPAA_VERSION >= 11) */
+ *p_AdNewPtr = NULL;
+ }
+ else
+ *p_AdNewPtr = p_Manip->h_Ad;
+ break;
+ case (HMAN_OC_IP_REASSEMBLY):
+ if (FmPcdManipIpReassmIsIpv6Hdr(p_Manip))
+ {
+ if (!p_Manip->reassmParams.ip.ipv6Assigned)
+ {
+ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv6Ad;
+ p_Manip->reassmParams.ip.ipv6Assigned = TRUE;
+ FmPcdManipUpdateOwner(h_Manip, FALSE);
+ }
+ else
+ {
+ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad;
+ p_Manip->reassmParams.ip.ipv6Assigned = FALSE;
+ }
+ }
+ else
+ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad;
+ memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr,
+ sizeof(t_AdOfTypeContLookup));
+ *p_AdNewPtr = NULL;
+ break;
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ *p_AdNewPtr = p_Manip->reassmParams.capwap.h_Ad;
+ memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr,
+ sizeof(t_AdOfTypeContLookup));
+ *p_AdNewPtr = NULL;
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+ case (HMAN_OC):
+ /* Allocate and initialize HMTD */
+ *p_AdNewPtr = p_Manip->h_Ad;
+ break;
+ default:
+ break;
+ }
+}
+
+void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad,
+ t_Handle *p_AdNewPtr,
+ uint32_t adTableOffset)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+
+ /* This routine creates a Manip AD and can return in "p_AdNewPtr"
+ * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */
+ ASSERT_COND(p_Manip);
+
+ FmPcdManipUpdateOwner(h_Manip, TRUE);
+
+ switch (p_Manip->opcode)
+ {
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
+ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->ccAdBase);
+ WRITE_UINT32(
+ ((t_AdOfTypeContLookup *)p_Ad)->matchTblPtr,
+ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->matchTblPtr);
+ WRITE_UINT32(
+ ((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets,
+ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->pcAndOffsets);
+ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->gmask,
+ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->gmask);
+ WRITE_UINT32(
+ ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase,
+ (GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) | adTableOffset));
+ *p_AdNewPtr = NULL;
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ case (HMAN_OC):
+ /* Initialize HMTD within the match table*/
+ MemSet8(p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+ /* copy the existing HMTD *//* ask Alla - memcpy??? */
+ memcpy((uint8_t*)p_Ad, p_Manip->h_Ad, sizeof(t_Hmtd));
+ /* update NADEN to be "1"*/
+ WRITE_UINT16(
+ ((t_Hmtd *)p_Ad)->cfg,
+ (uint16_t)(GET_UINT16(((t_Hmtd *)p_Ad)->cfg) | HMTD_CFG_NEXT_AD_EN));
+ /* update next action descriptor */
+ WRITE_UINT16(((t_Hmtd *)p_Ad)->nextAdIdx,
+ (uint16_t)(adTableOffset >> 4));
+ /* mark that Manip's HMTD is not used */
+ *p_AdNewPtr = NULL;
+ break;
+
+ default:
+ break;
+ }
+}
+
+t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv,
+ t_Handle h_CcTree, t_Handle h_Manip,
+ bool isIpv4, uint8_t groupId)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_FmPcdKgSchemeParams *p_SchemeParams = NULL;
+ t_Handle h_Scheme;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(h_NetEnv);
+ ASSERT_COND(p_Manip);
+
+ /* scheme was already build, no need to check for IPv6 */
+ if (p_Manip->reassmParams.ip.h_Ipv4Scheme)
+ return E_OK;
+
+ if (isIpv4) {
+ h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[0]);
+ if (h_Scheme) {
+ /* scheme was found */
+ p_Manip->reassmParams.ip.h_Ipv4Scheme = h_Scheme;
+ return E_OK;
+ }
+ } else {
+ h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[1]);
+ if (h_Scheme) {
+ /* scheme was found */
+ p_Manip->reassmParams.ip.h_Ipv6Scheme = h_Scheme;
+ return E_OK;
+ }
+ }
+
+ p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams));
+ if (!p_SchemeParams)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("Memory allocation failed for scheme"));
+
+ /* Configures the IPv4 or IPv6 scheme*/
+ memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams));
+ p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv;
+ p_SchemeParams->id.relativeSchemeId = (uint8_t)(
+ (isIpv4 == TRUE) ? p_Manip->reassmParams.ip.relativeSchemeId[0] :
+ p_Manip->reassmParams.ip.relativeSchemeId[1]);
+ p_SchemeParams->schemeCounter.update = TRUE;
+#if (DPAA_VERSION >= 11)
+ p_SchemeParams->alwaysDirect = TRUE;
+ p_SchemeParams->bypassFqidGeneration = TRUE;
+#else
+ p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids = 1;
+ p_SchemeParams->baseFqid = 0xFFFFFF; /*TODO- baseFqid*/
+#endif /* (DPAA_VERSION >= 11) */
+
+ setIpReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, isIpv4, groupId);
+
+ /* Sets the new scheme */
+ if (isIpv4)
+ p_Manip->reassmParams.ip.h_Ipv4Scheme = FM_PCD_KgSchemeSet(
+ p_FmPcd, p_SchemeParams);
+ else
+ p_Manip->reassmParams.ip.h_Ipv6Scheme = FM_PCD_KgSchemeSet(
+ p_FmPcd, p_SchemeParams);
+
+ XX_Free(p_SchemeParams);
+
+ return E_OK;
+}
+
+t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+
+ ASSERT_COND(p_Manip);
+
+ if ((p_Manip->reassmParams.ip.h_Ipv4Scheme) &&
+ !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv4Scheme))
+ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv4Scheme);
+
+ if ((p_Manip->reassmParams.ip.h_Ipv6Scheme) &&
+ !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv6Scheme))
+ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv6Scheme);
+
+ return E_OK;
+}
+
+bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+
+ ASSERT_COND(p_Manip);
+
+ return (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6);
+}
+
+t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv,
+ t_Handle h_CcTree, t_Handle h_Manip,
+ uint8_t groupId)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ t_FmPcdKgSchemeParams *p_SchemeParams = NULL;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(h_NetEnv);
+ ASSERT_COND(p_Manip);
+
+ /* scheme was already build, no need to check for IPv6 */
+ if (p_Manip->reassmParams.capwap.h_Scheme)
+ return E_OK;
+
+ p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams));
+ if (!p_SchemeParams)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY,
+ ("Memory allocation failed for scheme"));
+
+ memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams));
+ p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv;
+ p_SchemeParams->id.relativeSchemeId =
+ (uint8_t)p_Manip->reassmParams.capwap.relativeSchemeId;
+ p_SchemeParams->schemeCounter.update = TRUE;
+ p_SchemeParams->bypassFqidGeneration = TRUE;
+
+ setCapwapReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, groupId);
+
+ p_Manip->reassmParams.capwap.h_Scheme = FM_PCD_KgSchemeSet(p_FmPcd,
+ p_SchemeParams);
+
+ XX_Free(p_SchemeParams);
+
+ return E_OK;
+}
+
+t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+
+ ASSERT_COND(p_Manip);
+
+ if (p_Manip->reassmParams.capwap.h_Scheme)
+ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.capwap.h_Scheme);
+
+ return E_OK;
+}
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+t_Handle FmPcdManipApplSpecificBuild(void)
+{
+ t_FmPcdManip *p_Manip;
+
+ p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip));
+ if (!p_Manip)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+ return NULL;
+ }
+ memset(p_Manip, 0, sizeof(t_FmPcdManip));
+
+ p_Manip->opcode = HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX;
+ p_Manip->muramAllocate = FALSE;
+
+ p_Manip->h_Ad = (t_Handle)XX_Malloc(FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
+ if (!p_Manip->h_Ad)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor"));
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t));
+
+ /*treatFdStatusFieldsAsErrors = TRUE hardcoded - assumption its always come after CAAM*/
+ /*Application specific = type of flowId index, move internal frame header from data to IC,
+ SEC errors check*/
+ if (MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE)!= E_OK)
+ {
+ XX_Free(p_Manip->h_Ad);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+ return p_Manip;
+}
+
+bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip;
+ ASSERT_COND(h_Manip);
+
+ return (bool)((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST) ? TRUE : FALSE);
+}
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+/*********************** End of inter-module routines ************************/
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+
+t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd,
+ t_FmPcdManipParams *p_ManipParams)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdManip *p_Manip;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_ManipParams, E_INVALID_HANDLE, NULL);
+
+ p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_ManipParams, FALSE);
+ if (!p_Manip)
+ return NULL;
+
+ if (((p_Manip->opcode == HMAN_OC_IP_REASSEMBLY)
+ || (p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION)
+ || (p_Manip->opcode == HMAN_OC)
+ || (p_Manip->opcode == HMAN_OC_IPSEC_MANIP)
+#if (DPAA_VERSION >= 11)
+ || (p_Manip->opcode == HMAN_OC_CAPWAP_MANIP)
+ || (p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION)
+ || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY)
+#endif /* (DPAA_VERSION >= 11) */
+ ) && (!FmPcdIsAdvancedOffloadSupported(p_FmPcd)))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));
+ XX_Free(p_Manip);
+ return NULL;
+ }
+ p_Manip->h_Spinlock = XX_InitSpinlock();
+ if (!p_Manip->h_Spinlock)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }INIT_LIST(&p_Manip->nodesLst);
+
+ switch (p_Manip->opcode)
+ {
+ case (HMAN_OC_IP_REASSEMBLY):
+ /* IpReassembly */
+ err = IpReassembly(&p_ManipParams->u.reassem, p_Manip);
+ break;
+ case (HMAN_OC_IP_FRAGMENTATION):
+ /* IpFragmentation */
+ err = IpFragmentation(&p_ManipParams->u.frag.u.ipFrag, p_Manip);
+ if (err)
+ break;
+ err = IPManip(p_Manip);
+ break;
+ case (HMAN_OC_IPSEC_MANIP):
+ err = IPSecManip(p_ManipParams, p_Manip);
+ break;
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ /* CapwapReassembly */
+ err = CapwapReassembly(&p_ManipParams->u.reassem, p_Manip);
+ break;
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ /* CapwapFragmentation */
+ err = CapwapFragmentation(&p_ManipParams->u.frag.u.capwapFrag,
+ p_Manip);
+ break;
+ case (HMAN_OC_CAPWAP_MANIP):
+ err = CapwapManip(p_ManipParams, p_Manip);
+ break;
+#endif /* (DPAA_VERSION >= 11) */
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR):
+ /* HmanType1 */
+ err = RmvHdrTillSpecLocNOrInsrtIntFrmHdr(&p_ManipParams->u.hdr.rmvParams, p_Manip);
+ break;
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ err = CapwapFragmentation(&p_ManipParams->fragOrReasmParams.u.capwapFragParams,
+ p_Manip,
+ p_FmPcd,
+ p_ManipParams->fragOrReasmParams.sgBpid);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+ if (p_Manip->insrt)
+ p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER;
+ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER):
+ /* HmanType2 + if user asked only for fragmentation still need to allocate HmanType2 */
+ err = InsrtHdrByTempl(&p_ManipParams->u.hdr.insrtParams, p_Manip, p_FmPcd);
+ break;
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ err = CapwapReassembly(&p_ManipParams->fragOrReasmParams.u.capwapReasmParams,
+ p_Manip,
+ p_FmPcd,
+ p_ManipParams->fragOrReasmParams.sgBpid);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+ if (p_Manip->rmv)
+ p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST;
+ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST):
+ /*CAPWAP decapsulation + if user asked only for reassembly still need to allocate CAPWAP decapsulation*/
+ err = CapwapRmvDtlsHdr(p_FmPcd, p_Manip);
+ break;
+ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX):
+ /*Application Specific type 1*/
+ err = MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE);
+ break;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ case (HMAN_OC):
+ /* New Manip */
+ err = CreateManipActionNew(p_Manip, p_ManipParams);
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ if (p_ManipParams->h_NextManip)
+ {
+ /* in the check routine we've verified that h_NextManip has no owners
+ * and that only supported types are allowed. */
+ p_Manip->h_NextManip = p_ManipParams->h_NextManip;
+ /* save a "prev" pointer in h_NextManip */
+ MANIP_SET_PREV(p_Manip->h_NextManip, p_Manip);
+ FmPcdManipUpdateOwner(p_Manip->h_NextManip, TRUE);
+ }
+
+ return p_Manip;
+}
+
+t_Error FM_PCD_ManipNodeReplace(t_Handle h_Manip,
+ t_FmPcdManipParams *p_ManipParams)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip, *p_FirstManip;
+ t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Manip->h_FmPcd);
+ t_Error err;
+ uint8_t *p_WholeHmct = NULL, *p_ShadowHmct = NULL, *p_Hmtd = NULL;
+ t_List lstOfNodeshichPointsOnCrntMdfManip, *p_Pos;
+ t_CcNodeInformation *p_CcNodeInfo;
+ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE);
+
+ INIT_LIST(&lstOfNodeshichPointsOnCrntMdfManip);
+
+ if ((p_ManipParams->type != e_FM_PCD_MANIP_HDR)
+ || (p_Manip->type != e_FM_PCD_MANIP_HDR))
+ RETURN_ERROR(
+ MINOR,
+ E_NOT_SUPPORTED,
+ ("FM_PCD_ManipNodeReplace Functionality supported only for Header Manipulation."));
+
+ ASSERT_COND(p_Manip->opcode == HMAN_OC);
+ ASSERT_COND(p_Manip->manipParams.h_NextManip == p_Manip->h_NextManip);
+ memcpy((uint8_t*)&p_Manip->manipParams, p_ManipParams,
+ sizeof(p_Manip->manipParams));
+ p_Manip->manipParams.h_NextManip = p_Manip->h_NextManip;
+
+ /* The replacement of the HdrManip depends on the node type.*/
+ /*
+ * (1) If this is an independent node, all its owners should be updated.
+ *
+ * (2) If it is the head of a cascaded chain (it does not have a "prev" but
+ * it has a "next" and it has a "cascaded" indication), the next
+ * node remains unchanged, and the behavior is as in (1).
+ *
+ * (3) If it is not the head, but a part of a cascaded chain, in can be
+ * also replaced as a regular node with just one owner.
+ *
+ * (4) If it is a part of a chain implemented as a unified table, the
+ * whole table is replaced and the owners of the head node must be updated.
+ *
+ */
+ /* lock shadow */
+ if (!p_FmPcd->p_CcShadow)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated"));
+
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ return ERROR_CODE(E_BUSY);
+
+ /* this routine creates a new manip action in the CC Shadow. */
+ err = CreateManipActionShadow(p_Manip, p_ManipParams);
+ if (err)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ /* If the owners list is empty (these are NOT the "owners" counter, but pointers from CC)
+ * replace only HMTD and no lcok is required. Otherwise
+ * lock the whole PCD
+ * In case 4 MANIP_IS_UNIFIED_NON_FIRST(p_Manip) - Use the head node instead. */
+ if (!FmPcdLockTryLockAll(p_FmPcd))
+ {
+ DBG(TRACE, ("FmPcdLockTryLockAll failed"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ p_ShadowHmct = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16);
+
+ p_FirstManip = (t_FmPcdManip*)GetManipInfo(p_Manip,
+ e_MANIP_HANDLER_TABLE_OWNER);
+ ASSERT_COND(p_FirstManip);
+
+ if (!LIST_IsEmpty(&p_FirstManip->nodesLst))
+ UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip(
+ p_FirstManip, &lstOfNodeshichPointsOnCrntMdfManip);
+
+ p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD);
+ ASSERT_COND(p_Hmtd);
+ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_ShadowHmct,
+ ((t_FmPcd*)(p_Manip->h_FmPcd)));
+
+ LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip)
+ {
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
+ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode,
+ p_ShadowHmct, ((t_FmPcd*)(p_Manip->h_FmPcd)));
+ }
+
+ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT);
+ ASSERT_COND(p_WholeHmct);
+
+ /* re-build the HMCT n the original location */
+ err = CreateManipActionBackToOrig(p_Manip, p_ManipParams);
+ if (err)
+ {
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD);
+ ASSERT_COND(p_Hmtd);
+ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_WholeHmct,
+ ((t_FmPcd*)p_Manip->h_FmPcd));
+
+ /* If LIST > 0, create a list of p_Ad's that point to the HMCT. Join also t_HMTD to this list.
+ * For each p_Hmct (from list+fixed):
+ * call Host Command to replace HMTD by a new one */LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip)
+ {
+ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos);
+ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode,
+ p_WholeHmct, ((t_FmPcd*)(p_Manip->h_FmPcd)));
+ }
+
+
+ ReleaseLst(&lstOfNodeshichPointsOnCrntMdfManip);
+
+ FmPcdLockUnlockAll(p_FmPcd);
+
+ /* unlock shadow */
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+
+ if (p_Manip->owner)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("This manipulation node not be removed because this node is occupied, first - unbind this node "));
+
+ if (p_Manip->h_NextManip)
+ {
+ MANIP_SET_PREV(p_Manip->h_NextManip, NULL);
+ FmPcdManipUpdateOwner(p_Manip->h_NextManip, FALSE);
+ }
+
+ if (p_Manip->p_Hmct
+ && (MANIP_IS_UNIFIED_FIRST(p_Manip) || !MANIP_IS_UNIFIED(p_Manip)))
+ FM_MURAM_FreeMem(((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram,
+ p_Manip->p_Hmct);
+
+ if (p_Manip->h_Spinlock)
+ {
+ XX_FreeSpinlock(p_Manip->h_Spinlock);
+ p_Manip->h_Spinlock = NULL;
+ }
+
+ ReleaseManipHandler(p_Manip, p_Manip->h_FmPcd);
+
+ XX_Free(h_ManipNode);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode,
+ t_FmPcdManipStats *p_FmPcdManipStats)
+{
+ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode;
+
+ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdManipStats, E_NULL_POINTER);
+
+ switch (p_Manip->opcode)
+ {
+ case (HMAN_OC_IP_REASSEMBLY):
+ return IpReassemblyStats(p_Manip,
+ &p_FmPcdManipStats->u.reassem.u.ipReassem);
+ case (HMAN_OC_IP_FRAGMENTATION):
+ return IpFragmentationStats(p_Manip,
+ &p_FmPcdManipStats->u.frag.u.ipFrag);
+#if (DPAA_VERSION >= 11)
+ case (HMAN_OC_CAPWAP_REASSEMBLY):
+ return CapwapReassemblyStats(
+ p_Manip, &p_FmPcdManipStats->u.reassem.u.capwapReassem);
+ case (HMAN_OC_CAPWAP_FRAGMENTATION):
+ return CapwapFragmentationStats(
+ p_Manip, &p_FmPcdManipStats->u.frag.u.capwapFrag);
+#endif /* (DPAA_VERSION >= 11) */
+ default:
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("no statistics to this type of manip"));
+ }
+
+ return E_OK;
+}
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_StatsParams)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdManip *p_Manip;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE,NULL);
+ SANITY_CHECK_RETURN_VALUE(p_StatsParams,E_INVALID_HANDLE,NULL);
+
+ p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_StatsParams, TRUE);
+ if (!p_Manip)
+ return NULL;
+
+ switch (p_Manip->opcode)
+ {
+ case (HMAN_OC_CAPWAP_INDEXED_STATS):
+ /* Indexed statistics */
+ err = IndxStats(p_StatsParams, p_Manip, p_FmPcd);
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED Statistics type"));
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ ReleaseManipHandler(p_Manip, p_FmPcd);
+ XX_Free(p_Manip);
+ return NULL;
+ }
+
+ return p_Manip;
+}
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h
new file mode 100644
index 000000000000..853bb834dedf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_manip.h
+
+ @Description FM PCD manip...
+*//***************************************************************************/
+#ifndef __FM_MANIP_H
+#define __FM_MANIP_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "fm_cc.h"
+
+
+/***********************************************************************/
+/* Header manipulations defines */
+/***********************************************************************/
+
+#define NUM_OF_SCRATCH_POOL_BUFFERS 1000 /*TODO - Change it!!*/
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+#define HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR 0x2e
+#define HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER 0x31
+#define HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX 0x2f
+#define HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST 0x30
+#define HMAN_OC_CAPWAP_REASSEMBLY 0x11 /* dummy */
+#define HMAN_OC_CAPWAP_INDEXED_STATS 0x32 /* dummy */
+#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33
+#else
+#define HMAN_OC_CAPWAP_MANIP 0x2F
+#define HMAN_OC_CAPWAP_FRAG_CHECK 0x2E
+#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33
+#define HMAN_OC_CAPWAP_REASSEMBLY 0x30
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+#define HMAN_OC_IP_MANIP 0x34
+#define HMAN_OC_IP_FRAGMENTATION 0x74
+#define HMAN_OC_IP_REASSEMBLY 0xB4
+#define HMAN_OC_IPSEC_MANIP 0xF4
+#define HMAN_OC 0x35
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+#define HMAN_RMV_HDR 0x80000000
+#define HMAN_INSRT_INT_FRM_HDR 0x40000000
+
+#define UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP 6
+#define UDP_CHECKSUM_FIELD_SIZE 2
+#define UDP_LENGTH_FIELD_OFFSET_FROM_UDP 4
+
+#define IPv4_DSCECN_FIELD_OFFSET_FROM_IP 1
+#define IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP 2
+#define IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP 10
+#define VLAN_TAG_FIELD_OFFSET_FROM_ETH 12
+#define IPv4_ID_FIELD_OFFSET_FROM_IP 4
+
+#define IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP 4
+#define IPv6_NEXT_HEADER_OFFSET_FROM_IP 6
+
+#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE 0x80
+#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN 8
+#define FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE 32
+#define FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE 4
+#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE 8
+
+
+#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES 0x40000000
+#define FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG 0x10000000
+#define FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS 0x08000000
+#define FM_PCD_MANIP_CAPWAP_REASM_PR_COPY 0x00800000
+
+#define FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN 0x80000000
+
+#define FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE 4
+#define FM_PCD_MANIP_INDEXED_STATS_CNIA 0x20000000
+#define FM_PCD_MANIP_INDEXED_STATS_DPD 0x10000000
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+#if (DPAA_VERSION >= 11)
+#define FM_PCD_MANIP_CAPWAP_DTLS 0x00040000
+#define FM_PCD_MANIP_CAPWAP_NADEN 0x20000000
+
+#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT 16
+#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_NO_FRAGMENTATION 0xFFFF0000
+#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA 0x20000000
+
+#define FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN 0x04000000
+#define FM_PCD_MANIP_CAPWAP_FRAG_SCRATCH_BPID 24
+#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN 0x08000000
+#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK 0xFF000000
+#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT 24
+#endif /* (DPAA_VERSION >= 11) */
+
+#define FM_PCD_MANIP_REASM_TABLE_SIZE 0x40
+#define FM_PCD_MANIP_REASM_TABLE_ALIGN 8
+
+#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE 64
+#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN 8
+#define FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES 0x80000000
+#define FM_PCD_MANIP_REASM_COUPLING_ENABLE 0x40000000
+#define FM_PCD_MANIP_REASM_COUPLING_MASK 0xFF000000
+#define FM_PCD_MANIP_REASM_COUPLING_SHIFT 24
+#define FM_PCD_MANIP_REASM_LIODN_MASK 0x0000003F
+#define FM_PCD_MANIP_REASM_LIODN_SHIFT 56
+#define FM_PCD_MANIP_REASM_ELIODN_MASK 0x000003c0
+#define FM_PCD_MANIP_REASM_ELIODN_SHIFT 38
+#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_MASK 0x000000FF
+#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT 24
+#define FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH 1024
+
+#define FM_PCD_MANIP_IP_MTU_SHIFT 16
+#define FM_PCD_MANIP_IP_NO_FRAGMENTATION 0xFFFF0000
+#define FM_PCD_MANIP_IP_CNIA 0x20000000
+
+#define FM_PCD_MANIP_IP_FRAG_DF_SHIFT 28
+#define FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID 24
+#define FM_PCD_MANIP_IP_FRAG_SG_BDID_EN 0x08000000
+#define FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK 0xFF000000
+#define FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT 24
+
+#define FM_PCD_MANIP_IPSEC_DEC 0x10000000
+#define FM_PCD_MANIP_IPSEC_VIPV_EN 0x08000000
+#define FM_PCD_MANIP_IPSEC_ECN_EN 0x04000000
+#define FM_PCD_MANIP_IPSEC_DSCP_EN 0x02000000
+#define FM_PCD_MANIP_IPSEC_VIPL_EN 0x01000000
+#define FM_PCD_MANIP_IPSEC_NADEN 0x20000000
+
+#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_MASK 0x00FF0000
+#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT 16
+
+#define FM_PCD_MANIP_IPSEC_ARW_SIZE_MASK 0xFFFF0000
+#define FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT 16
+
+#define e_FM_MANIP_IP_INDX 1
+
+#define HMCD_OPCODE_GENERIC_RMV 0x01
+#define HMCD_OPCODE_GENERIC_INSRT 0x02
+#define HMCD_OPCODE_GENERIC_REPLACE 0x05
+#define HMCD_OPCODE_L2_RMV 0x08
+#define HMCD_OPCODE_L2_INSRT 0x09
+#define HMCD_OPCODE_VLAN_PRI_UPDATE 0x0B
+#define HMCD_OPCODE_IPV4_UPDATE 0x0C
+#define HMCD_OPCODE_IPV6_UPDATE 0x10
+#define HMCD_OPCODE_TCP_UDP_UPDATE 0x0E
+#define HMCD_OPCODE_TCP_UDP_CHECKSUM 0x14
+#define HMCD_OPCODE_REPLACE_IP 0x12
+#define HMCD_OPCODE_RMV_TILL 0x15
+#define HMCD_OPCODE_UDP_INSRT 0x16
+#define HMCD_OPCODE_IP_INSRT 0x17
+#define HMCD_OPCODE_CAPWAP_RMV 0x18
+#define HMCD_OPCODE_CAPWAP_INSRT 0x18
+#define HMCD_OPCODE_GEN_FIELD_REPLACE 0x19
+
+#define HMCD_LAST 0x00800000
+
+#define HMCD_DSCP_VALUES 64
+
+#define HMCD_BASIC_SIZE 4
+#define HMCD_PTR_SIZE 4
+#define HMCD_PARAM_SIZE 4
+#define HMCD_IPV4_ADDR_SIZE 4
+#define HMCD_IPV6_ADDR_SIZE 0x10
+#define HMCD_L4_HDR_SIZE 8
+
+#define HMCD_CAPWAP_INSRT 0x00010000
+#define HMCD_INSRT_UDP_LITE 0x00010000
+#define HMCD_IP_ID_MASK 0x0000FFFF
+#define HMCD_IP_SIZE_MASK 0x0000FF00
+#define HMCD_IP_SIZE_SHIFT 8
+#define HMCD_IP_LAST_PID_MASK 0x000000FF
+#define HMCD_IP_OR_QOS 0x00010000
+#define HMCD_IP_L4_CS_CALC 0x00040000
+#define HMCD_IP_DF_MODE 0x00400000
+
+
+#define HMCD_OC_SHIFT 24
+
+#define HMCD_RMV_OFFSET_SHIFT 0
+#define HMCD_RMV_SIZE_SHIFT 8
+
+#define HMCD_INSRT_OFFSET_SHIFT 0
+#define HMCD_INSRT_SIZE_SHIFT 8
+
+#define HMTD_CFG_TYPE 0x4000
+#define HMTD_CFG_EXT_HMCT 0x0080
+#define HMTD_CFG_PRS_AFTER_HM 0x0040
+#define HMTD_CFG_NEXT_AD_EN 0x0020
+
+#define HMCD_RMV_L2_ETHERNET 0
+#define HMCD_RMV_L2_STACKED_QTAGS 1
+#define HMCD_RMV_L2_ETHERNET_AND_MPLS 2
+#define HMCD_RMV_L2_MPLS 3
+#define HMCD_RMV_L2_PPPOE 4
+
+#define HMCD_INSRT_L2_MPLS 0
+#define HMCD_INSRT_N_UPDATE_L2_MPLS 1
+#define HMCD_INSRT_L2_PPPOE 2
+#define HMCD_INSRT_L2_SIZE_SHIFT 24
+
+#define HMCD_L2_MODE_SHIFT 16
+
+#define HMCD_VLAN_PRI_REP_MODE_SHIFT 16
+#define HMCD_VLAN_PRI_UPDATE 0
+#define HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI 1
+
+#define HMCD_IPV4_UPDATE_TTL 0x00000001
+#define HMCD_IPV4_UPDATE_TOS 0x00000002
+#define HMCD_IPV4_UPDATE_DST 0x00000020
+#define HMCD_IPV4_UPDATE_SRC 0x00000040
+#define HMCD_IPV4_UPDATE_ID 0x00000080
+#define HMCD_IPV4_UPDATE_TOS_SHIFT 8
+
+#define HMCD_IPV6_UPDATE_HL 0x00000001
+#define HMCD_IPV6_UPDATE_TC 0x00000002
+#define HMCD_IPV6_UPDATE_DST 0x00000040
+#define HMCD_IPV6_UPDATE_SRC 0x00000080
+#define HMCD_IPV6_UPDATE_TC_SHIFT 8
+
+#define HMCD_TCP_UDP_UPDATE_DST 0x00004000
+#define HMCD_TCP_UDP_UPDATE_SRC 0x00008000
+#define HMCD_TCP_UDP_UPDATE_SRC_SHIFT 16
+
+#define HMCD_IP_REPLACE_REPLACE_IPV4 0x00000000
+#define HMCD_IP_REPLACE_REPLACE_IPV6 0x00010000
+#define HMCD_IP_REPLACE_TTL_HL 0x00200000
+#define HMCD_IP_REPLACE_ID 0x00400000
+
+#define HMCD_IP_REPLACE_L3HDRSIZE_SHIFT 24
+
+#define HMCD_GEN_FIELD_SIZE_SHIFT 16
+#define HMCD_GEN_FIELD_SRC_OFF_SHIFT 8
+#define HMCD_GEN_FIELD_DST_OFF_SHIFT 0
+#define HMCD_GEN_FIELD_MASK_EN 0x00400000
+
+#define HMCD_GEN_FIELD_MASK_OFF_SHIFT 16
+#define HMCD_GEN_FIELD_MASK_SHIFT 24
+
+#define DSCP_TO_VLAN_TABLE_SIZE 32
+
+#define MANIP_GET_HMCT_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->tableSize)
+#define MANIP_GET_DATA_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->dataSize)
+
+#define MANIP_GET_HMCT_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Hmct)
+#define MANIP_GET_DATA_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Data)
+
+#define MANIP_SET_HMCT_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Hmct = h_NewPtr)
+#define MANIP_SET_DATA_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Data = h_NewPtr)
+
+#define MANIP_GET_HMTD_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->h_Ad)
+#define MANIP_DONT_REPARSE(h_Manip) (((t_FmPcdManip *)h_Manip)->dontParseAfterManip)
+#define MANIP_SET_PREV(h_Manip, h_Prev) (((t_FmPcdManip *)h_Manip)->h_PrevManip = h_Prev)
+#define MANIP_GET_OWNERS(h_Manip) (((t_FmPcdManip *)h_Manip)->owner)
+#define MANIP_GET_TYPE(h_Manip) (((t_FmPcdManip *)h_Manip)->type)
+#define MANIP_SET_UNIFIED_TBL_PTR_INDICATION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedTablePtr = TRUE)
+#define MANIP_GET_MURAM(h_Manip) (((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram)
+#define MANIP_FREE_HMTD(h_Manip) \
+ {if (((t_FmPcdManip *)h_Manip)->muramAllocate) \
+ FM_MURAM_FreeMem(((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram, ((t_FmPcdManip *)h_Manip)->h_Ad);\
+ else \
+ XX_Free(((t_FmPcdManip *)h_Manip)->h_Ad); \
+ ((t_FmPcdManip *)h_Manip)->h_Ad = NULL; \
+ }
+/* position regarding Manip SW structure */
+#define MANIP_IS_FIRST(h_Manip) (!(((t_FmPcdManip *)h_Manip)->h_PrevManip))
+#define MANIP_IS_CASCADED(h_Manip) (((t_FmPcdManip *)h_Manip)->cascaded)
+#define MANIP_IS_UNIFIED(h_Manip) (!(((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE))
+#define MANIP_IS_UNIFIED_NON_FIRST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID) || \
+ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST))
+#define MANIP_IS_UNIFIED_NON_LAST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) ||\
+ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID))
+#define MANIP_IS_UNIFIED_FIRST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST)
+#define MANIP_IS_UNIFIED_LAST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST)
+
+#define MANIP_UPDATE_UNIFIED_POSITION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition = \
+ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)? \
+ e_MANIP_UNIFIED_LAST : e_MANIP_UNIFIED_MID)
+
+typedef enum e_ManipUnifiedPosition {
+ e_MANIP_UNIFIED_NONE = 0,
+ e_MANIP_UNIFIED_FIRST,
+ e_MANIP_UNIFIED_MID,
+ e_MANIP_UNIFIED_LAST
+} e_ManipUnifiedPosition;
+
+typedef enum e_ManipInfo {
+ e_MANIP_HMTD,
+ e_MANIP_HMCT,
+ e_MANIP_HANDLER_TABLE_OWNER
+}e_ManipInfo;
+/***********************************************************************/
+/* Memory map */
+/***********************************************************************/
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+typedef struct t_CapwapReasmPram {
+ volatile uint32_t mode;
+ volatile uint32_t autoLearnHashTblPtr;
+ volatile uint32_t intStatsTblPtr;
+ volatile uint32_t reasmFrmDescPoolTblPtr;
+ volatile uint32_t reasmFrmDescIndexPoolTblPtr;
+ volatile uint32_t timeOutTblPtr;
+ volatile uint32_t bufferPoolIdAndRisc1SetIndexes;
+ volatile uint32_t risc23SetIndexes;
+ volatile uint32_t risc4SetIndexesAndExtendedStatsTblPtr;
+ volatile uint32_t extendedStatsTblPtr;
+ volatile uint32_t expirationDelay;
+ volatile uint32_t totalProcessedFragCounter;
+ volatile uint32_t totalUnsuccessfulReasmFramesCounter;
+ volatile uint32_t totalDuplicatedFragCounter;
+ volatile uint32_t totalMalformdFragCounter;
+ volatile uint32_t totalTimeOutCounter;
+ volatile uint32_t totalSetBusyCounter;
+ volatile uint32_t totalRfdPoolBusyCounter;
+ volatile uint32_t totalDiscardedFragsCounter;
+ volatile uint32_t totalMoreThan16FramesCounter;
+ volatile uint32_t internalBufferBusy;
+ volatile uint32_t externalBufferBusy;
+ volatile uint32_t reserved1[4];
+} t_CapwapReasmPram;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+typedef _Packed struct t_ReassTbl {
+ volatile uint16_t waysNumAndSetSize;
+ volatile uint16_t autoLearnHashKeyMask;
+ volatile uint32_t reassCommonPrmTblPtr;
+ volatile uint32_t liodnAlAndAutoLearnHashTblPtrHi;
+ volatile uint32_t autoLearnHashTblPtrLow;
+ volatile uint32_t liodnSlAndAutoLearnSetLockTblPtrHi;
+ volatile uint32_t autoLearnSetLockTblPtrLow;
+ volatile uint16_t minFragSize; /* Not relevant for CAPWAP*/
+ volatile uint16_t maxReassemblySize; /* Only relevant for CAPWAP*/
+ volatile uint32_t totalSuccessfullyReasmFramesCounter;
+ volatile uint32_t totalValidFragmentCounter;
+ volatile uint32_t totalProcessedFragCounter;
+ volatile uint32_t totalMalformdFragCounter;
+ volatile uint32_t totalSetBusyCounter;
+ volatile uint32_t totalDiscardedFragsCounter;
+ volatile uint32_t totalMoreThan16FramesCounter;
+ volatile uint32_t reserved2[2];
+} _PackedType t_ReassTbl;
+
+typedef struct t_ReassCommonTbl {
+ volatile uint32_t timeoutModeAndFqid;
+ volatile uint32_t reassFrmDescIndexPoolTblPtr;
+ volatile uint32_t liodnAndReassFrmDescPoolPtrHi;
+ volatile uint32_t reassFrmDescPoolPtrLow;
+ volatile uint32_t timeOutTblPtr;
+ volatile uint32_t expirationDelay;
+ volatile uint32_t internalBufferManagement;
+ volatile uint32_t reserved2;
+ volatile uint32_t totalTimeOutCounter;
+ volatile uint32_t totalRfdPoolBusyCounter;
+ volatile uint32_t totalInternalBufferBusy;
+ volatile uint32_t totalExternalBufferBusy;
+ volatile uint32_t totalSgFragmentCounter;
+ volatile uint32_t totalDmaSemaphoreDepletionCounter;
+ volatile uint32_t totalNCSPCounter;
+ volatile uint32_t discardMask;
+} t_ReassCommonTbl;
+
+typedef _Packed struct t_Hmtd {
+ volatile uint16_t cfg;
+ volatile uint8_t eliodnOffset;
+ volatile uint8_t extHmcdBasePtrHi;
+ volatile uint32_t hmcdBasePtr;
+ volatile uint16_t nextAdIdx;
+ volatile uint8_t res1;
+ volatile uint8_t opCode;
+ volatile uint32_t res2;
+} _PackedType t_Hmtd;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/***********************************************************************/
+/* Driver's internal structures */
+/***********************************************************************/
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+typedef struct
+{
+ t_Handle p_AutoLearnHashTbl;
+ t_Handle p_ReassmFrmDescrPoolTbl;
+ t_Handle p_ReassmFrmDescrIndxPoolTbl;
+ t_Handle p_TimeOutTbl;
+ uint16_t maxNumFramesInProcess;
+ uint8_t numOfTasks;
+ //uint8_t poolId;
+ uint8_t prOffset;
+ uint16_t dataOffset;
+ uint8_t sgBpid;
+ uint8_t hwPortId;
+ uint32_t fqidForTimeOutFrames;
+ uint32_t timeoutRoutineRequestTime;
+ uint32_t bitFor1Micro;
+} t_CapwapFragParams;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+
+typedef struct
+{
+ t_AdOfTypeContLookup *p_Frag;
+#if (DPAA_VERSION == 10)
+ uint8_t scratchBpid;
+#endif /* (DPAA_VERSION == 10) */
+} t_FragParams;
+
+typedef struct t_ReassmParams
+{
+ e_NetHeaderType hdr; /* Header selection */
+ t_ReassCommonTbl *p_ReassCommonTbl;
+ uintptr_t reassFrmDescrIndxPoolTblAddr;
+ uintptr_t reassFrmDescrPoolTblAddr;
+ uintptr_t timeOutTblAddr;
+ uintptr_t internalBufferPoolManagementIndexAddr;
+ uintptr_t internalBufferPoolAddr;
+ uint32_t maxNumFramesInProcess;
+ uint8_t sgBpid;
+ uint8_t dataMemId;
+ uint16_t dataLiodnOffset;
+ uint32_t fqidForTimeOutFrames;
+ e_FmPcdManipReassemTimeOutMode timeOutMode;
+ uint32_t timeoutThresholdForReassmProcess;
+ union {
+ struct {
+ t_Handle h_Ipv4Ad;
+ t_Handle h_Ipv6Ad;
+ bool ipv6Assigned;
+ t_ReassTbl *p_Ipv4ReassTbl;
+ t_ReassTbl *p_Ipv6ReassTbl;
+ uintptr_t ipv4AutoLearnHashTblAddr;
+ uintptr_t ipv6AutoLearnHashTblAddr;
+ uintptr_t ipv4AutoLearnSetLockTblAddr;
+ uintptr_t ipv6AutoLearnSetLockTblAddr;
+ uint16_t minFragSize[2];
+ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry[2];
+ uint8_t relativeSchemeId[2];
+ t_Handle h_Ipv4Scheme;
+ t_Handle h_Ipv6Scheme;
+ uint32_t nonConsistentSpFqid;
+ } ip;
+ struct {
+ t_Handle h_Ad;
+ t_ReassTbl *p_ReassTbl;
+ uintptr_t autoLearnHashTblAddr;
+ uintptr_t autoLearnSetLockTblAddr;
+ uint16_t maxRessembledsSize;
+ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry;
+ uint8_t relativeSchemeId;
+ t_Handle h_Scheme;
+ } capwap;
+ };
+} t_ReassmParams;
+
+typedef struct{
+ e_FmPcdManipType type;
+ t_FmPcdManipParams manipParams;
+ bool muramAllocate;
+ t_Handle h_Ad;
+ uint32_t opcode;
+ bool rmv;
+ bool insrt;
+ t_Handle h_NextManip;
+ t_Handle h_PrevManip;
+ e_FmPcdManipType nextManipType;
+ /* HdrManip parameters*/
+ uint8_t *p_Hmct;
+ uint8_t *p_Data;
+ bool dontParseAfterManip;
+ bool fieldUpdate;
+ bool custom;
+ uint16_t tableSize;
+ uint8_t dataSize;
+ bool cascaded;
+ e_ManipUnifiedPosition unifiedPosition;
+ /* end HdrManip */
+ uint8_t *p_Template;
+ uint16_t owner;
+ uint32_t updateParams;
+ uint32_t shadowUpdateParams;
+ bool frag;
+ bool reassm;
+ uint16_t sizeForFragmentation;
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+ t_Handle h_Frag;
+ t_CapwapFragParams capwapFragParams;
+#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */
+ union {
+ t_ReassmParams reassmParams;
+ t_FragParams fragParams;
+ };
+ uint8_t icOffset;
+ uint16_t ownerTmp;
+ bool cnia;
+ t_Handle p_StatsTbl;
+ t_Handle h_FmPcd;
+ t_List nodesLst;
+ t_Handle h_Spinlock;
+} t_FmPcdManip;
+
+typedef struct t_FmPcdCcSavedManipParams
+{
+ union
+ {
+ struct
+ {
+ uint16_t dataOffset;
+ //uint8_t poolId;
+ }capwapParams;
+ struct
+ {
+ uint16_t dataOffset;
+ uint8_t poolId;
+ }ipParams;
+ };
+
+} t_FmPcdCcSavedManipParams;
+
+
+#endif /* __FM_MANIP_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c
new file mode 100644
index 000000000000..91f70a1a290e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c
@@ -0,0 +1,2095 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_pcd.c
+
+ @Description FM PCD ...
+*//***************************************************************************/
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "xx_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+#include "net_ext.h"
+#include "fm_ext.h"
+#include "fm_pcd_ext.h"
+
+#include "fm_common.h"
+#include "fm_pcd.h"
+#include "fm_pcd_ipc.h"
+#include "fm_hc.h"
+#include "fm_muram_ext.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+static t_Error CheckFmPcdParameters(t_FmPcd *p_FmPcd)
+{
+ if (!p_FmPcd->h_Fm)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("h_Fm has to be initialized"));
+
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ if (p_FmPcd->p_FmPcdKg && !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG"));
+
+ if (p_FmPcd->p_FmPcdPlcr && !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG"));
+
+ if (!p_FmPcd->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdExceptions has to be initialized"));
+
+ if ((!p_FmPcd->f_FmPcdIndexedException) && (p_FmPcd->p_FmPcdPlcr || p_FmPcd->p_FmPcdKg))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdIndexedException has to be initialized"));
+
+ if (p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit > PRS_MAX_CYCLE_LIMIT)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("prsMaxParseCycleLimit has to be less than 8191"));
+ }
+
+ return E_OK;
+}
+
+static volatile bool blockingFlag = FALSE;
+static void IpcMsgCompletionCB(t_Handle h_FmPcd,
+ uint8_t *p_Msg,
+ uint8_t *p_Reply,
+ uint32_t replyLength,
+ t_Error status)
+{
+ UNUSED(h_FmPcd);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status);
+ blockingFlag = FALSE;
+}
+
+static t_Error IpcMsgHandlerCB(t_Handle h_FmPcd,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+ t_FmPcdIpcMsg *p_IpcMsg = (t_FmPcdIpcMsg*)p_Msg;
+ t_FmPcdIpcReply *p_IpcReply = (t_FmPcdIpcReply*)p_Reply;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE);
+
+#ifdef DISABLE_SANITY_CHECKS
+ UNUSED(msgLength);
+#endif /* DISABLE_SANITY_CHECKS */
+
+ ASSERT_COND(p_Msg);
+
+ memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_PCD_MAX_REPLY_SIZE));
+ *p_ReplyLength = 0;
+
+ switch (p_IpcMsg->msgId)
+ {
+ case (FM_PCD_MASTER_IS_ALIVE):
+ *(uint8_t*)(p_IpcReply->replyBody) = 1;
+ p_IpcReply->error = E_OK;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ case (FM_PCD_MASTER_IS_ENABLED):
+ /* count partitions registrations */
+ if (p_FmPcd->enabled)
+ p_FmPcd->numOfEnabledGuestPartitionsPcds++;
+ *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)p_FmPcd->enabled;
+ p_IpcReply->error = E_OK;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ case (FM_PCD_GUEST_DISABLE):
+ if (p_FmPcd->numOfEnabledGuestPartitionsPcds)
+ {
+ p_FmPcd->numOfEnabledGuestPartitionsPcds--;
+ p_IpcReply->error = E_OK;
+ }
+ else
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE,("Trying to disable an unregistered partition"));
+ p_IpcReply->error = E_INVALID_STATE;
+ }
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ case (FM_PCD_GET_COUNTER):
+ {
+ e_FmPcdCounters inCounter;
+ uint32_t outCounter;
+
+ memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t));
+ outCounter = FM_PCD_GetCounter(h_FmPcd, inCounter);
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t));
+ p_IpcReply->error = E_OK;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ case (FM_PCD_ALLOC_KG_SCHEMES):
+ {
+ t_FmPcdIpcKgSchemesParams ipcSchemesParams;
+
+ memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams));
+ err = FmPcdKgAllocSchemes(h_FmPcd,
+ ipcSchemesParams.numOfSchemes,
+ ipcSchemesParams.guestId,
+ p_IpcReply->replyBody);
+ p_IpcReply->error = err;
+ *p_ReplyLength = sizeof(uint32_t) + ipcSchemesParams.numOfSchemes*sizeof(uint8_t);
+ break;
+ }
+ case (FM_PCD_FREE_KG_SCHEMES):
+ {
+ t_FmPcdIpcKgSchemesParams ipcSchemesParams;
+
+ memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams));
+ err = FmPcdKgFreeSchemes(h_FmPcd,
+ ipcSchemesParams.numOfSchemes,
+ ipcSchemesParams.guestId,
+ ipcSchemesParams.schemesIds);
+ p_IpcReply->error = err;
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_PCD_ALLOC_KG_CLSPLAN):
+ {
+ t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams;
+
+ memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams));
+ err = KgAllocClsPlanEntries(h_FmPcd,
+ ipcKgClsPlanParams.numOfClsPlanEntries,
+ ipcKgClsPlanParams.guestId,
+ p_IpcReply->replyBody);
+ p_IpcReply->error = err;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ }
+ case (FM_PCD_FREE_KG_CLSPLAN):
+ {
+ t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams;
+
+ memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams));
+ KgFreeClsPlanEntries(h_FmPcd,
+ ipcKgClsPlanParams.numOfClsPlanEntries,
+ ipcKgClsPlanParams.guestId,
+ ipcKgClsPlanParams.clsPlanBase);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_PCD_ALLOC_PROFILES):
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ uint16_t base;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ base = PlcrAllocProfilesForPartition(h_FmPcd,
+ ipcAllocParams.base,
+ ipcAllocParams.num,
+ ipcAllocParams.guestId);
+ memcpy(p_IpcReply->replyBody, (uint16_t*)&base, sizeof(uint16_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t);
+ break;
+ }
+ case (FM_PCD_FREE_PROFILES):
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ PlcrFreeProfilesForPartition(h_FmPcd,
+ ipcAllocParams.base,
+ ipcAllocParams.num,
+ ipcAllocParams.guestId);
+ break;
+ }
+ case (FM_PCD_SET_PORT_PROFILES):
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ PlcrSetPortProfiles(h_FmPcd,
+ ipcAllocParams.guestId,
+ ipcAllocParams.num,
+ ipcAllocParams.base);
+ break;
+ }
+ case (FM_PCD_CLEAR_PORT_PROFILES):
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ PlcrClearPortProfiles(h_FmPcd,
+ ipcAllocParams.guestId);
+ break;
+ }
+ case (FM_PCD_GET_SW_PRS_OFFSET):
+ {
+ t_FmPcdIpcSwPrsLable ipcSwPrsLable;
+ uint32_t swPrsOffset;
+
+ memcpy((uint8_t*)&ipcSwPrsLable, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSwPrsLable));
+ swPrsOffset =
+ FmPcdGetSwPrsOffset(h_FmPcd,
+ (e_NetHeaderType)ipcSwPrsLable.enumHdr,
+ ipcSwPrsLable.indexPerHdr);
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&swPrsOffset, sizeof(uint32_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ case (FM_PCD_PRS_INC_PORT_STATS):
+ {
+ t_FmPcdIpcPrsIncludePort ipcPrsIncludePort;
+
+ memcpy((uint8_t*)&ipcPrsIncludePort, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPrsIncludePort));
+ PrsIncludePortInStatistics(h_FmPcd,
+ ipcPrsIncludePort.hardwarePortId,
+ ipcPrsIncludePort.include);
+ break;
+ }
+ default:
+ *p_ReplyLength = 0;
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
+ }
+ return E_OK;
+}
+
+static uint32_t NetEnvLock(t_Handle h_NetEnv)
+{
+ ASSERT_COND(h_NetEnv);
+ return XX_LockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock);
+}
+
+static void NetEnvUnlock(t_Handle h_NetEnv, uint32_t intFlags)
+{
+ ASSERT_COND(h_NetEnv);
+ XX_UnlockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock, intFlags);
+}
+
+static void EnqueueLockToFreeLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock)
+{
+ uint32_t intFlags;
+
+ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
+ LIST_AddToTail(&p_Lock->node, &p_FmPcd->freeLocksLst);
+ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
+}
+
+static t_FmPcdLock * DequeueLockFromFreeLst(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdLock *p_Lock = NULL;
+ uint32_t intFlags;
+
+ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
+ if (!LIST_IsEmpty(&p_FmPcd->freeLocksLst))
+ {
+ p_Lock = FM_PCD_LOCK_OBJ(p_FmPcd->freeLocksLst.p_Next);
+ LIST_DelAndInit(&p_Lock->node);
+ }
+ if (p_FmPcd->h_Spinlock)
+ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
+
+ return p_Lock;
+}
+
+static void EnqueueLockToAcquiredLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock)
+{
+ uint32_t intFlags;
+
+ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
+ LIST_AddToTail(&p_Lock->node, &p_FmPcd->acquiredLocksLst);
+ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
+}
+
+static t_Error FillFreeLocksLst(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdLock *p_Lock;
+ int i;
+
+ for (i=0; i<10; i++)
+ {
+ p_Lock = (t_FmPcdLock *)XX_Malloc(sizeof(t_FmPcdLock));
+ if (!p_Lock)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("FM-PCD lock obj!"));
+ memset(p_Lock, 0, sizeof(t_FmPcdLock));
+ INIT_LIST(&p_Lock->node);
+ p_Lock->h_Spinlock = XX_InitSpinlock();
+ if (!p_Lock->h_Spinlock)
+ {
+ XX_Free(p_Lock);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("FM-PCD spinlock obj!"));
+ }
+ EnqueueLockToFreeLst(p_FmPcd, p_Lock);
+ }
+
+ return E_OK;
+}
+
+static void ReleaseFreeLocksLst(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdLock *p_Lock;
+
+ p_Lock = DequeueLockFromFreeLst(p_FmPcd);
+ while (p_Lock)
+ {
+ XX_FreeSpinlock(p_Lock->h_Spinlock);
+ XX_Free(p_Lock);
+ p_Lock = DequeueLockFromFreeLst(p_FmPcd);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId)
+{
+ ASSERT_COND(p_FmPcd);
+ p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = clsPlanGrpId;
+}
+
+t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams)
+{
+ uint8_t netEnvId = p_GrpParams->netEnvId;
+ int i, k, j;
+
+ ASSERT_COND(p_FmPcd);
+ if (p_FmPcd->netEnvs[netEnvId].clsPlanGrpId != ILLEGAL_CLS_PLAN)
+ {
+ p_GrpParams->grpExists = TRUE;
+ p_GrpParams->clsPlanGrpId = p_FmPcd->netEnvs[netEnvId].clsPlanGrpId;
+ return E_OK;
+ }
+
+ for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++)
+ {
+ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
+ {
+ /* if an option exists, add it to the opts list */
+ if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
+ {
+ /* check if this option already exists, add if it doesn't */
+ for (j = 0;j<p_GrpParams->numOfOptions;j++)
+ {
+ if (p_GrpParams->options[j] == p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
+ break;
+ }
+ p_GrpParams->optVectors[j] |= p_FmPcd->netEnvs[netEnvId].unitsVectors[i];
+ if (j == p_GrpParams->numOfOptions)
+ {
+ p_GrpParams->options[p_GrpParams->numOfOptions] = p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt;
+ p_GrpParams->numOfOptions++;
+ }
+ }
+ }
+ }
+
+ if (p_GrpParams->numOfOptions == 0)
+ {
+ if (p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId != ILLEGAL_CLS_PLAN)
+ {
+ p_GrpParams->grpExists = TRUE;
+ p_GrpParams->clsPlanGrpId = p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId;
+ }
+ }
+
+ return E_OK;
+
+}
+
+t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector)
+{
+ uint8_t j,k;
+
+ *p_Vector = 0;
+
+ ASSERT_COND(p_FmPcd);
+ for (j=0; ((j < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[0].hdr != HEADER_TYPE_NONE)); j++)
+ {
+ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
+ {
+ if (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].opt == opt)
+ *p_Vector |= p_FmPcd->netEnvs[netEnvId].unitsVectors[j];
+ }
+ }
+
+ if (!*p_Vector)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested option was not defined for this Network Environment Characteristics module"));
+ else
+ return E_OK;
+}
+
+t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params)
+{
+ int i;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(p_Params->netEnvId < FM_MAX_NUM_OF_PORTS);
+
+ p_Params->vector = 0;
+ for (i=0; i<p_Params->numOfDistinctionUnits ;i++)
+ {
+ if (p_FmPcd->netEnvs[p_Params->netEnvId].units[p_Params->unitIds[i]].hdrs[0].hdr == HEADER_TYPE_NONE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested unit was not defined for this Network Environment Characteristics module"));
+ ASSERT_COND(p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]);
+ p_Params->vector |= p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]];
+ }
+
+ return E_OK;
+}
+
+bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector)
+{
+ int i=0, k;
+
+ ASSERT_COND(p_FmPcd);
+ /* check whether a given unit may be used by non-clsPlan users. */
+ /* first, recognize the unit by its vector */
+ while (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)
+ {
+ if (p_FmPcd->netEnvs[netEnvId].unitsVectors[i] == unitVector)
+ {
+ for (k=0;
+ ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE));
+ k++)
+ /* check that no option exists */
+ if ((protocolOpt_t)p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt)
+ return FALSE;
+ break;
+ }
+ i++;
+ }
+ /* assert that a unit was found to mach the vector */
+ ASSERT_COND(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE);
+
+ return TRUE;
+}
+bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ int i, k;
+
+ ASSERT_COND(p_FmPcd);
+
+ for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++)
+ {
+ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++)
+ if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr)
+ return TRUE;
+ }
+ for (i=0; ((i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE)); i++)
+ {
+ if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt)
+{
+ uint8_t i, k;
+
+ ASSERT_COND(p_FmPcd);
+
+ if (interchangeable)
+ {
+ for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ {
+ for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
+ {
+ if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt == opt))
+
+ return i;
+ }
+ }
+ }
+ else
+ {
+ for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr == hdr) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].opt == opt) &&
+ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[1].hdr == HEADER_TYPE_NONE))
+ return i;
+
+ for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) &&
+ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++)
+ if ((p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) &&
+ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].opt == opt))
+ return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr;
+ }
+
+ return FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS;
+}
+
+t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = {0};
+ uint8_t result;
+ t_Error err = E_OK;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(h_ReasmCommonPramTbl);
+
+ ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys(h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase);
+ ccReassmTimeoutParams.activate = FALSE; /*Disable Timeout Task*/
+
+ if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, &result)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ switch (result)
+ {
+ case (0):
+ return E_OK;
+ case (1):
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, (""));
+ case (2):
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, (""));
+ case (3):
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Disable Timeout Task with invalid IPRCPT"));
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr)
+{
+ int i;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(netEnvId < FM_MAX_NUM_OF_PORTS);
+
+ for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS)
+ && (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++)
+ {
+ if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr)
+ return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr;
+ }
+
+ return HEADER_TYPE_NONE;
+}
+
+void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint16_t swPortIndex = 0;
+
+ ASSERT_COND(h_FmPcd);
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort = h_FmPort;
+}
+
+uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(h_FmPcd);
+ return p_FmPcd->netEnvs[netEnvId].lcvs[hdrNum];
+}
+
+uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(h_FmPcd);
+ return p_FmPcd->netEnvs[netEnvId].macsecVector;
+}
+
+uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv)
+{
+ return ((t_FmPcdNetEnv*)h_NetEnv)->netEnvId;
+}
+
+void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId)
+{
+ uint32_t intFlags;
+
+ ASSERT_COND(h_FmPcd);
+
+ intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]);
+ ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners++;
+ NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags);
+}
+
+void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId)
+{
+ uint32_t intFlags;
+
+ ASSERT_COND(h_FmPcd);
+ ASSERT_COND(((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners);
+
+ intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]);
+ ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners--;
+ NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags);
+}
+
+uint32_t FmPcdLock(t_Handle h_FmPcd)
+{
+ ASSERT_COND(h_FmPcd);
+ return XX_LockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock);
+}
+
+void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags)
+{
+ ASSERT_COND(h_FmPcd);
+ XX_UnlockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock, intFlags);
+}
+
+t_FmPcdLock * FmPcdAcquireLock(t_Handle h_FmPcd)
+{
+ t_FmPcdLock *p_Lock;
+ ASSERT_COND(h_FmPcd);
+ p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd);
+ if (!p_Lock)
+ {
+ FillFreeLocksLst(h_FmPcd);
+ p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd);
+ }
+
+ if (p_Lock)
+ EnqueueLockToAcquiredLst((t_FmPcd*)h_FmPcd, p_Lock);
+ return p_Lock;
+}
+
+void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock)
+{
+ uint32_t intFlags;
+ ASSERT_COND(h_FmPcd);
+ intFlags = FmPcdLock(h_FmPcd);
+ LIST_DelAndInit(&p_Lock->node);
+ FmPcdUnlock(h_FmPcd, intFlags);
+ EnqueueLockToFreeLst((t_FmPcd*)h_FmPcd, p_Lock);
+}
+
+bool FmPcdLockTryLockAll(t_Handle h_FmPcd)
+{
+ uint32_t intFlags;
+ t_List *p_Pos, *p_SavedPos=NULL;
+
+ ASSERT_COND(h_FmPcd);
+ intFlags = FmPcdLock(h_FmPcd);
+ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
+ {
+ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
+ if (!FmPcdLockTryLock(p_Lock))
+ {
+ p_SavedPos = p_Pos;
+ break;
+ }
+ }
+ if (p_SavedPos)
+ {
+ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
+ {
+ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
+ if (p_Pos == p_SavedPos)
+ break;
+ FmPcdLockUnlock(p_Lock);
+ }
+ }
+ FmPcdUnlock(h_FmPcd, intFlags);
+
+ CORE_MemoryBarrier();
+
+ if (p_SavedPos)
+ return FALSE;
+
+ return TRUE;
+}
+
+void FmPcdLockUnlockAll(t_Handle h_FmPcd)
+{
+ uint32_t intFlags;
+ t_List *p_Pos;
+
+ ASSERT_COND(h_FmPcd);
+ intFlags = FmPcdLock(h_FmPcd);
+ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst)
+ {
+ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos);
+ p_Lock->flag = FALSE;
+ }
+ FmPcdUnlock(h_FmPcd, intFlags);
+
+ CORE_MemoryBarrier();
+}
+
+t_Error FmPcdHcSync(t_Handle h_FmPcd)
+{
+ ASSERT_COND(h_FmPcd);
+ ASSERT_COND(((t_FmPcd*)h_FmPcd)->h_Hc);
+
+ return FmHcPcdSync(((t_FmPcd*)h_FmPcd)->h_Hc);
+}
+
+t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd)
+{
+ ASSERT_COND(h_FmPcd);
+ return ((t_FmPcd*)h_FmPcd)->h_Hc;
+}
+
+bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd)
+{
+ ASSERT_COND(h_FmPcd);
+ return ((t_FmPcd*)h_FmPcd)->advancedOffloadSupport;
+}
+/*********************** End of inter-module routines ************************/
+
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+
+t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams)
+{
+ t_FmPcd *p_FmPcd = NULL;
+ t_FmPhysAddr physicalMuramBase;
+ uint8_t i;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcdParams, E_INVALID_HANDLE,NULL);
+
+ p_FmPcd = (t_FmPcd *) XX_Malloc(sizeof(t_FmPcd));
+ if (!p_FmPcd)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD"));
+ return NULL;
+ }
+ memset(p_FmPcd, 0, sizeof(t_FmPcd));
+
+ p_FmPcd->p_FmPcdDriverParam = (t_FmPcdDriverParam *) XX_Malloc(sizeof(t_FmPcdDriverParam));
+ if (!p_FmPcd->p_FmPcdDriverParam)
+ {
+ XX_Free(p_FmPcd);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Driver Param"));
+ return NULL;
+ }
+ memset(p_FmPcd->p_FmPcdDriverParam, 0, sizeof(t_FmPcdDriverParam));
+
+ p_FmPcd->h_Fm = p_FmPcdParams->h_Fm;
+ p_FmPcd->guestId = FmGetGuestId(p_FmPcd->h_Fm);
+ p_FmPcd->h_FmMuram = FmGetMuramHandle(p_FmPcd->h_Fm);
+ if (p_FmPcd->h_FmMuram)
+ {
+ FmGetPhysicalMuramBase(p_FmPcdParams->h_Fm, &physicalMuramBase);
+ p_FmPcd->physicalMuramBase = (uint64_t)((uint64_t)(&physicalMuramBase)->low | ((uint64_t)(&physicalMuramBase)->high << 32));
+ }
+
+ for (i = 0; i<FM_MAX_NUM_OF_PORTS; i++)
+ p_FmPcd->netEnvs[i].clsPlanGrpId = ILLEGAL_CLS_PLAN;
+
+ if (p_FmPcdParams->useHostCommand)
+ {
+ t_FmHcParams hcParams;
+
+ memset(&hcParams, 0, sizeof(hcParams));
+ hcParams.h_Fm = p_FmPcd->h_Fm;
+ hcParams.h_FmPcd = (t_Handle)p_FmPcd;
+ memcpy((uint8_t*)&hcParams.params, (uint8_t*)&p_FmPcdParams->hc, sizeof(t_FmPcdHcParams));
+ p_FmPcd->h_Hc = FmHcConfigAndInit(&hcParams);
+ if (!p_FmPcd->h_Hc)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD HC"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("No Host Command defined for a guest partition."));
+
+ if (p_FmPcdParams->kgSupport)
+ {
+ p_FmPcd->p_FmPcdKg = (t_FmPcdKg *)KgConfig(p_FmPcd, p_FmPcdParams);
+ if (!p_FmPcd->p_FmPcdKg)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Keygen"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+ }
+
+ if (p_FmPcdParams->plcrSupport)
+ {
+ p_FmPcd->p_FmPcdPlcr = (t_FmPcdPlcr *)PlcrConfig(p_FmPcd, p_FmPcdParams);
+ if (!p_FmPcd->p_FmPcdPlcr)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Policer"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+ }
+
+ if (p_FmPcdParams->prsSupport)
+ {
+ p_FmPcd->p_FmPcdPrs = (t_FmPcdPrs *)PrsConfig(p_FmPcd, p_FmPcdParams);
+ if (!p_FmPcd->p_FmPcdPrs)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Parser"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+ }
+
+ p_FmPcd->h_Spinlock = XX_InitSpinlock();
+ if (!p_FmPcd->h_Spinlock)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD spinlock"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+ INIT_LIST(&p_FmPcd->freeLocksLst);
+ INIT_LIST(&p_FmPcd->acquiredLocksLst);
+
+ p_FmPcd->numOfEnabledGuestPartitionsPcds = 0;
+
+ p_FmPcd->f_Exception = p_FmPcdParams->f_Exception;
+ p_FmPcd->f_FmPcdIndexedException = p_FmPcdParams->f_ExceptionId;
+ p_FmPcd->h_App = p_FmPcdParams->h_App;
+
+ p_FmPcd->p_CcShadow = NULL;
+ p_FmPcd->ccShadowSize = 0;
+ p_FmPcd->ccShadowAlign = 0;
+
+ p_FmPcd->h_ShadowSpinlock = XX_InitSpinlock();
+ if (!p_FmPcd->h_ShadowSpinlock)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD shadow spinlock"));
+ FM_PCD_Free(p_FmPcd);
+ return NULL;
+ }
+
+ return p_FmPcd;
+}
+
+t_Error FM_PCD_Init(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+ t_FmPcdIpcMsg msg;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+
+ FM_GetRevision(p_FmPcd->h_Fm, &p_FmPcd->fmRevInfo);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ {
+ memset(p_FmPcd->fmPcdIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint (p_FmPcd->fmPcdIpcHandlerModuleName, "FM_PCD_%d_%d", FmGetId(p_FmPcd->h_Fm), NCSW_MASTER_ID) != 10)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm), p_FmPcd->guestId) != (p_FmPcd->guestId<10 ? 10:11))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+
+ p_FmPcd->h_IpcSession = XX_IpcInitSession(p_FmPcd->fmPcdIpcHandlerModuleName, p_FmPcd->fmPcdModuleName);
+ if (p_FmPcd->h_IpcSession)
+ {
+ t_FmPcdIpcReply reply;
+ uint32_t replyLength;
+ uint8_t isMasterAlive = 0;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_PCD_MASTER_IS_ALIVE;
+ msg.msgBody[0] = p_FmPcd->guestId;
+ blockingFlag = TRUE;
+
+ do
+ {
+ replyLength = sizeof(uint32_t) + sizeof(isMasterAlive);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(p_FmPcd->guestId),
+ (uint8_t*)&reply,
+ &replyLength,
+ IpcMsgCompletionCB,
+ h_FmPcd)) != E_OK)
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ while (blockingFlag) ;
+ if (replyLength != (sizeof(uint32_t) + sizeof(isMasterAlive)))
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ isMasterAlive = *(uint8_t*)(reply.replyBody);
+ } while (!isMasterAlive);
+ }
+ }
+
+ CHECK_INIT_PARAMETERS(p_FmPcd, CheckFmPcdParameters);
+
+ if (p_FmPcd->p_FmPcdKg)
+ {
+ err = KgInit(p_FmPcd);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_FmPcd->p_FmPcdPlcr)
+ {
+ err = PlcrInit(p_FmPcd);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_FmPcd->p_FmPcdPrs)
+ {
+ err = PrsInit(p_FmPcd);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ /* register to inter-core messaging mechanism */
+ memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm),NCSW_MASTER_ID) != 10)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ err = XX_IpcRegisterMsgHandler(p_FmPcd->fmPcdModuleName, IpcMsgHandlerCB, p_FmPcd, FM_PCD_MAX_REPLY_SIZE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /* IPv6 Frame-Id used for fragmentation */
+ p_FmPcd->ipv6FrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 4, 4));
+ if (!p_FmPcd->ipv6FrameIdAddr)
+ {
+ FM_PCD_Free(p_FmPcd);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for IPv6 Frame-Id"));
+ }
+ IOMemSet32(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr), 0, 4);
+
+ /* CAPWAP Frame-Id used for fragmentation */
+ p_FmPcd->capwapFrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 2, 4));
+ if (!p_FmPcd->capwapFrameIdAddr)
+ {
+ FM_PCD_Free(p_FmPcd);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CAPWAP Frame-Id"));
+ }
+ IOMemSet32(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr), 0, 2);
+
+ XX_Free(p_FmPcd->p_FmPcdDriverParam);
+ p_FmPcd->p_FmPcdDriverParam = NULL;
+
+ FmRegisterPcd(p_FmPcd->h_Fm, p_FmPcd);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_Free(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd =(t_FmPcd *)h_FmPcd;
+ t_Error err = E_OK;
+
+ if (p_FmPcd->ipv6FrameIdAddr)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr));
+
+ if (p_FmPcd->capwapFrameIdAddr)
+ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr));
+
+ if (p_FmPcd->enabled)
+ FM_PCD_Disable(p_FmPcd);
+
+ if (p_FmPcd->p_FmPcdDriverParam)
+ {
+ XX_Free(p_FmPcd->p_FmPcdDriverParam);
+ p_FmPcd->p_FmPcdDriverParam = NULL;
+ }
+
+ if (p_FmPcd->p_FmPcdKg)
+ {
+ if ((err = KgFree(p_FmPcd)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ XX_Free(p_FmPcd->p_FmPcdKg);
+ p_FmPcd->p_FmPcdKg = NULL;
+ }
+
+ if (p_FmPcd->p_FmPcdPlcr)
+ {
+ PlcrFree(p_FmPcd);
+ XX_Free(p_FmPcd->p_FmPcdPlcr);
+ p_FmPcd->p_FmPcdPlcr = NULL;
+ }
+
+ if (p_FmPcd->p_FmPcdPrs)
+ {
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ PrsFree(p_FmPcd);
+ XX_Free(p_FmPcd->p_FmPcdPrs);
+ p_FmPcd->p_FmPcdPrs = NULL;
+ }
+
+ if (p_FmPcd->h_Hc)
+ {
+ FmHcFree(p_FmPcd->h_Hc);
+ p_FmPcd->h_Hc = NULL;
+ }
+
+ XX_IpcUnregisterMsgHandler(p_FmPcd->fmPcdModuleName);
+
+ FmUnregisterPcd(p_FmPcd->h_Fm);
+
+ ReleaseFreeLocksLst(p_FmPcd);
+
+ if (p_FmPcd->h_Spinlock)
+ XX_FreeSpinlock(p_FmPcd->h_Spinlock);
+
+ if (p_FmPcd->h_ShadowSpinlock)
+ XX_FreeSpinlock(p_FmPcd->h_ShadowSpinlock);
+
+ XX_Free(p_FmPcd);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigException - guest mode!"));
+
+ GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_FmPcd->exceptions |= bitMask;
+ else
+ p_FmPcd->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE);
+
+ return FmHcSetFramesDataMemory(p_FmPcd->h_Hc, memId);
+}
+
+t_Error FM_PCD_Enable(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+
+ if (p_FmPcd->enabled)
+ return E_OK;
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ p_FmPcd->h_IpcSession)
+ {
+ uint8_t enabled;
+ t_FmPcdIpcMsg msg;
+ t_FmPcdIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_PCD_MASTER_IS_ENABLED;
+ replyLength = sizeof(uint32_t) + sizeof(enabled);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t) + sizeof(enabled))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ p_FmPcd->enabled = (bool)!!(*(uint8_t*)(reply.replyBody));
+ if (!p_FmPcd->enabled)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-PCD master should be enabled first!"));
+
+ return E_OK;
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ if (p_FmPcd->p_FmPcdKg)
+ KgEnable(p_FmPcd);
+
+ if (p_FmPcd->p_FmPcdPlcr)
+ PlcrEnable(p_FmPcd);
+
+ if (p_FmPcd->p_FmPcdPrs)
+ PrsEnable(p_FmPcd);
+
+ p_FmPcd->enabled = TRUE;
+
+ return E_OK;
+}
+
+t_Error FM_PCD_Disable(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+
+ if (!p_FmPcd->enabled)
+ return E_OK;
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_FmPcdIpcMsg msg;
+ t_FmPcdIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_PCD_GUEST_DISABLE;
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ if (reply.error == E_OK)
+ p_FmPcd->enabled = FALSE;
+
+ return (t_Error)(reply.error);
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ if (p_FmPcd->numOfEnabledGuestPartitionsPcds != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Trying to disable a master partition PCD while"
+ "guest partitions are still enabled!"));
+
+ if (p_FmPcd->p_FmPcdKg)
+ KgDisable(p_FmPcd);
+
+ if (p_FmPcd->p_FmPcdPlcr)
+ PlcrDisable(p_FmPcd);
+
+ if (p_FmPcd->p_FmPcdPrs)
+ PrsDisable(p_FmPcd);
+
+ p_FmPcd->enabled = FALSE;
+
+ return E_OK;
+}
+
+t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t intFlags, specialUnits = 0;
+ uint8_t bitId = 0;
+ uint8_t i, j, k;
+ uint8_t netEnvCurrId;
+ uint8_t ipsecAhUnit = 0,ipsecEspUnit = 0;
+ bool ipsecAhExists = FALSE, ipsecEspExists = FALSE, shim1Selected = FALSE;
+ uint8_t hdrNum;
+ t_FmPcdNetEnvParams *p_ModifiedNetEnvParams;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_STATE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_NetEnvParams, E_NULL_POINTER, NULL);
+
+ intFlags = FmPcdLock(p_FmPcd);
+
+ /* find a new netEnv */
+ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++)
+ if (!p_FmPcd->netEnvs[i].used)
+ break;
+
+ if (i== FM_MAX_NUM_OF_PORTS)
+ {
+ REPORT_ERROR(MAJOR, E_FULL,("No more than %d netEnv's allowed.", FM_MAX_NUM_OF_PORTS));
+ FmPcdUnlock(p_FmPcd, intFlags);
+ return NULL;
+ }
+
+ p_FmPcd->netEnvs[i].used = TRUE;
+ FmPcdUnlock(p_FmPcd, intFlags);
+
+ /* As anyone doesn't have handle of this netEnv yet, no need
+ to protect it with spinlocks */
+
+ p_ModifiedNetEnvParams = (t_FmPcdNetEnvParams *)XX_Malloc(sizeof(t_FmPcdNetEnvParams));
+ if (!p_ModifiedNetEnvParams)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FmPcdNetEnvParams"));
+ return NULL;
+ }
+
+ memcpy(p_ModifiedNetEnvParams, p_NetEnvParams, sizeof(t_FmPcdNetEnvParams));
+ p_NetEnvParams = p_ModifiedNetEnvParams;
+
+ netEnvCurrId = (uint8_t)i;
+
+ /* clear from previous use */
+ memset(&p_FmPcd->netEnvs[netEnvCurrId].units, 0, FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS * sizeof(t_FmPcdIntDistinctionUnit));
+ memset(&p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs, 0, FM_PCD_MAX_NUM_OF_ALIAS_HDRS * sizeof(t_FmPcdNetEnvAliases));
+ memcpy(&p_FmPcd->netEnvs[netEnvCurrId].units, p_NetEnvParams->units, p_NetEnvParams->numOfDistinctionUnits*sizeof(t_FmPcdIntDistinctionUnit));
+
+ p_FmPcd->netEnvs[netEnvCurrId].netEnvId = netEnvCurrId;
+ p_FmPcd->netEnvs[netEnvCurrId].h_FmPcd = p_FmPcd;
+
+ p_FmPcd->netEnvs[netEnvCurrId].clsPlanGrpId = ILLEGAL_CLS_PLAN;
+
+ /* check that header with opt is not interchanged with the same header */
+ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ {
+ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
+ {
+ /* if an option exists, check that other headers are not the same header
+ without option */
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt)
+ {
+ for (j = 0; (j < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr != HEADER_TYPE_NONE); j++)
+ {
+ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr == p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr) &&
+ !p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].opt)
+ {
+ REPORT_ERROR(MINOR, E_FULL,
+ ("Illegal unit - header with opt may not be interchangeable with the same header without opt"));
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+
+ /* Specific headers checking */
+ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ {
+ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
+ {
+ /* Some headers pairs may not be defined on different units as the parser
+ doesn't distinguish */
+ /* IPSEC_AH and IPSEC_SPI can't be 2 units, */
+ /* check that header with opt is not interchanged with the same header */
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_AH)
+ {
+ if (ipsecEspExists && (ipsecEspUnit != i))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units"));
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ else
+ {
+ ipsecAhUnit = i;
+ ipsecAhExists = TRUE;
+ }
+ }
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_ESP)
+ {
+ if (ipsecAhExists && (ipsecAhUnit != i))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units"));
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ else
+ {
+ ipsecEspUnit = i;
+ ipsecEspExists = TRUE;
+ }
+ }
+ /* ENCAP_ESP */
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_ENCAP_ESP)
+ {
+ /* IPSec UDP encapsulation is currently set to use SHIM1 */
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_ENCAP_ESP;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM1;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM1;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
+ }
+#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ /* UDP_LITE */
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_LITE)
+ {
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_LITE;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_UDP;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_UDP;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
+ }
+#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+ /* IP FRAG */
+ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv4) &&
+ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV4_FRAG_1))
+ {
+ /* If IPv4+Frag, we need to set 2 units - SHIM 2 and IPv4. We first set SHIM2, and than check if
+ * IPv4 exists. If so we don't need to set an extra unit
+ * We consider as "having IPv4" any IPv4 without interchangable headers
+ * but including any options. */
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv4;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV4_FRAG_1;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
+
+ /* check if IPv4 header exists by itself */
+ if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv4, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ {
+ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv4;
+ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0;
+ }
+ }
+ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv6) &&
+ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV6_FRAG_1))
+ {
+ /* If IPv6+Frag, we need to set 2 units - SHIM 2 and IPv6. We first set SHIM2, and than check if
+ * IPv4 exists. If so we don't need to set an extra unit
+ * We consider as "having IPv6" any IPv6 without interchangable headers
+ * but including any options. */
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv6;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV6_FRAG_1;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
+
+ /* check if IPv6 header exists by itself */
+ if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv6, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ {
+ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv6;
+ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0;
+ }
+ }
+#if (DPAA_VERSION >= 11)
+ /* CAPWAP FRAG */
+ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_CAPWAP) &&
+ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == CAPWAP_FRAG_1))
+ {
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_CAPWAP;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = CAPWAP_FRAG_1;
+ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2;
+ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ }
+
+ /* if private header (shim), check that no other headers specified */
+ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ {
+ if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
+ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[1].hdr != HEADER_TYPE_NONE)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header may not be interchanged with other headers"));
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < p_NetEnvParams->numOfDistinctionUnits; i++)
+ {
+ if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
+ switch (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)
+ {
+ case (HEADER_TYPE_USER_DEFINED_SHIM1):
+ if (shim1Selected)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header cannot be selected with UDP_IPSEC_ESP"));
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ shim1Selected = TRUE;
+ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000001;
+ break;
+ case (HEADER_TYPE_USER_DEFINED_SHIM2):
+ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000002;
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested SHIM not supported"));
+ }
+ else
+ {
+ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = (uint32_t)(0x80000000 >> bitId++);
+
+ if (IS_SPECIAL_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
+ p_FmPcd->netEnvs[netEnvCurrId].macsecVector = p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i];
+ }
+ }
+
+ /* define a set of hardware parser LCV's according to the defined netenv */
+
+ /* set an array of LCV's for each header in the netEnv */
+ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++)
+ {
+ /* private headers have no LCV in the hard parser */
+ if (!IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr))
+ {
+ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
+ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++)
+ {
+ hdrNum = GetPrsHdrNum(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr);
+ if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM))
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG);
+ XX_Free(p_ModifiedNetEnvParams);
+ return NULL;
+ }
+ p_FmPcd->netEnvs[netEnvCurrId].lcvs[hdrNum] |= p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i];
+ }
+ }
+ }
+ XX_Free(p_ModifiedNetEnvParams);
+
+ p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock = XX_InitSpinlock();
+ if (!p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd NetEnv spinlock"));
+ return NULL;
+ }
+ return &p_FmPcd->netEnvs[netEnvCurrId];
+}
+
+t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv)
+{
+ t_FmPcdNetEnv *p_NetEnv = (t_FmPcdNetEnv*)h_NetEnv;
+ t_FmPcd *p_FmPcd = p_NetEnv->h_FmPcd;
+ uint32_t intFlags;
+ uint8_t netEnvId = p_NetEnv->netEnvId;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+
+ /* check that no port is bound to this netEnv */
+ if (p_FmPcd->netEnvs[netEnvId].owners)
+ {
+ RETURN_ERROR(MINOR, E_INVALID_STATE,
+ ("Trying to delete a netEnv that has ports/schemes/trees/clsPlanGrps bound to"));
+ }
+
+ intFlags = FmPcdLock(p_FmPcd);
+
+ p_FmPcd->netEnvs[netEnvId].used = FALSE;
+ p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = ILLEGAL_CLS_PLAN;
+
+ memset(p_FmPcd->netEnvs[netEnvId].units, 0, sizeof(t_FmPcdIntDistinctionUnit)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ memset(p_FmPcd->netEnvs[netEnvId].unitsVectors, 0, sizeof(uint32_t)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ memset(p_FmPcd->netEnvs[netEnvId].lcvs, 0, sizeof(uint32_t)*FM_PCD_PRS_NUM_OF_HDRS);
+
+ if (p_FmPcd->netEnvs[netEnvId].h_Spinlock)
+ XX_FreeSpinlock(p_FmPcd->netEnvs[netEnvId].h_Spinlock);
+
+ FmPcdUnlock(p_FmPcd, intFlags);
+ return E_OK;
+}
+
+void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN(h_FmPcd, E_INVALID_STATE);
+
+ FmHcTxConf(p_FmPcd->h_Hc, p_Fd);
+}
+
+t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmCtrlCodeRevisionInfo revInfo;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_STATE);
+
+ if ((err = FM_GetFmanCtrlCodeRevision(p_FmPcd->h_Fm, &revInfo)) != E_OK)
+ {
+ DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision."));
+ revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER;
+ }
+ if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Fman ctrl code package"));
+
+ if (!p_FmPcd->h_Hc)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("HC must be initialized in this mode"));
+
+ p_FmPcd->advancedOffloadSupport = TRUE;
+
+ return E_OK;
+}
+
+uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t outCounter = 0;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
+
+ switch (counter)
+ {
+ case (e_FM_PCD_KG_COUNTERS_TOTAL):
+ if (!p_FmPcd->p_FmPcdKg)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("KeyGen is not activated"));
+ return 0;
+ }
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs &&
+ !p_FmPcd->h_IpcSession)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+ return 0;
+ }
+ break;
+
+ case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
+ case (e_FM_PCD_PLCR_COUNTERS_RED):
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
+ case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
+ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
+ if (!p_FmPcd->p_FmPcdPlcr)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Policer is not activated"));
+ return 0;
+ }
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs &&
+ !p_FmPcd->h_IpcSession)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in \"guest-mode\" without neither IPC nor mapped register!"));
+ return 0;
+ }
+
+ /* check that counters are enabled */
+ if (p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs &&
+ !(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
+ return 0;
+ }
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs ||
+ ((p_FmPcd->guestId != NCSW_MASTER_ID) && p_FmPcd->h_IpcSession));
+ break;
+
+ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
+ if (!p_FmPcd->p_FmPcdPrs)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Parser is not activated"));
+ return 0;
+ }
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ !p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs &&
+ !p_FmPcd->h_IpcSession)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+ return 0;
+ }
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported type of counter"));
+ return 0;
+ }
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_FmPcdIpcMsg msg;
+ t_FmPcdIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_PCD_GET_COUNTER;
+ memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t));
+ replyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(uint32_t),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t) + sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+
+ memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t));
+ return outCounter;
+ }
+
+ switch (counter)
+ {
+ /* Parser statistics */
+ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds);
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs);
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs);
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs);
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs);
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres);
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres);
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres);
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres);
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs);
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs);
+ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs);
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs);
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs);
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs);
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs);
+ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
+ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs);
+ case (e_FM_PCD_KG_COUNTERS_TOTAL):
+ return GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc);
+
+ /* Policer statistics */
+ case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt);
+ case (e_FM_PCD_PLCR_COUNTERS_RED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt);
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt);
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt);
+ case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt);
+ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
+ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt);
+ }
+ return 0;
+}
+
+t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t bitMask = 0, tmpReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetException - guest mode!"));
+
+ GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception);
+
+ if (bitMask)
+ {
+ if (enable)
+ p_FmPcd->exceptions |= bitMask;
+ else
+ p_FmPcd->exceptions &= ~bitMask;
+
+ switch (exception)
+ {
+ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
+ if (!p_FmPcd->p_FmPcdKg)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working"));
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
+ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
+ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
+ if (!p_FmPcd->p_FmPcdPlcr)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working"));
+ break;
+ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
+ if (!p_FmPcd->p_FmPcdPrs)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - parser is not working"));
+ break;
+ }
+
+ switch (exception)
+ {
+ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer);
+ if (enable)
+ tmpReg |= FM_EX_KG_DOUBLE_ECC;
+ else
+ tmpReg &= ~FM_EX_KG_DOUBLE_ECC;
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg);
+ break;
+ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer);
+ if (enable)
+ tmpReg |= FM_EX_KG_KEYSIZE_OVERFLOW;
+ else
+ tmpReg &= ~FM_EX_KG_KEYSIZE_OVERFLOW;
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg);
+ break;
+ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer);
+ if (enable)
+ tmpReg |= FM_PCD_PRS_DOUBLE_ECC;
+ else
+ tmpReg &= ~FM_PCD_PRS_DOUBLE_ECC;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer, tmpReg);
+ break;
+ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever);
+ if (enable)
+ tmpReg |= FM_PCD_PRS_SINGLE_ECC;
+ else
+ tmpReg &= ~FM_PCD_PRS_SINGLE_ECC;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever, tmpReg);
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
+ if (enable)
+ tmpReg |= FM_PCD_PLCR_DOUBLE_ECC;
+ else
+ tmpReg &= ~FM_PCD_PLCR_DOUBLE_ECC;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg);
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
+ if (enable)
+ tmpReg |= FM_PCD_PLCR_INIT_ENTRY_ERROR;
+ else
+ tmpReg &= ~FM_PCD_PLCR_INIT_ENTRY_ERROR;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg);
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
+ if (enable)
+ tmpReg |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
+ else
+ tmpReg &= ~FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg);
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
+ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
+ if (enable)
+ tmpReg |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
+ else
+ tmpReg &= ~FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg);
+ break;
+ }
+ /* for ECC exceptions driver automatically enables ECC mechanism, if disabled.
+ Driver may disable them automatically, depending on driver's status */
+ if (enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC)))
+ FmEnableRamsEcc(p_FmPcd->h_Fm);
+ if (!enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) |
+ (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC)))
+ FmDisableRamsEcc(p_FmPcd->h_Fm);
+ }
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ForceIntr - guest mode!"));
+
+ switch (exception)
+ {
+ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW):
+ if (!p_FmPcd->p_FmPcdKg)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working"));
+ break;
+ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR):
+ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE):
+ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE):
+ if (!p_FmPcd->p_FmPcdPlcr)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working"));
+ break;
+ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC):
+ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC):
+ if (!p_FmPcd->p_FmPcdPrs)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt -parsrer is not working"));
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid interrupt requested"));
+ }
+ switch (exception)
+ {
+ case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC:
+ if (!(p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_DOUBLE_ECC);
+ break;
+ case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW:
+ if (!(p_FmPcd->exceptions & FM_EX_KG_KEYSIZE_OVERFLOW))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_KEYSIZE_OVERFLOW);
+ break;
+ case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_DOUBLE_ECC);
+ break;
+ case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_INIT_ENTRY_ERROR);
+ break;
+ case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE);
+ break;
+ case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE:
+ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE);
+ break;
+ }
+
+ return E_OK;
+}
+
+
+t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ModifyCounter - guest mode!"));
+
+ switch (counter)
+ {
+ case (e_FM_PCD_KG_COUNTERS_TOTAL):
+ if (!p_FmPcd->p_FmPcdKg)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - KeyGen is not working"));
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
+ case (e_FM_PCD_PLCR_COUNTERS_RED):
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
+ case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
+ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
+ if (!p_FmPcd->p_FmPcdPlcr)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - Policer is not working"));
+ if (!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN))
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
+ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
+ if (!p_FmPcd->p_FmPcdPrs)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter"));
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter"));
+ }
+ switch (counter)
+ {
+ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs, value);
+ break;
+ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs, value);
+ break;
+ case (e_FM_PCD_KG_COUNTERS_TOTAL):
+ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc,value);
+ break;
+
+ /*Policer counters*/
+ case (e_FM_PCD_PLCR_COUNTERS_YELLOW):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt, value);
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_RED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt, value);
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt, value);
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt, value);
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_TOTAL):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt, value);
+ break;
+ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH):
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt, value);
+ break;
+ }
+
+ return E_OK;
+}
+
+t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ return FmHcGetPort(p_FmPcd->h_Hc);
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h
new file mode 100644
index 000000000000..27ec9c5bf672
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_pcd.h
+
+ @Description FM PCD ...
+*//***************************************************************************/
+#ifndef __FM_PCD_H
+#define __FM_PCD_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_common.h"
+#include "fsl_fman_prs.h"
+#include "fsl_fman_kg.h"
+
+#define __ERR_MODULE__ MODULE_FM_PCD
+
+
+/****************************/
+/* Defaults */
+/****************************/
+#define DEFAULT_plcrAutoRefresh FALSE
+#define DEFAULT_fmPcdKgErrorExceptions (FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW)
+#define DEFAULT_fmPcdPlcrErrorExceptions (FM_PCD_EX_PLCR_DOUBLE_ECC | FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)
+#define DEFAULT_fmPcdPlcrExceptions 0
+#define DEFAULT_fmPcdPrsErrorExceptions (FM_PCD_EX_PRS_DOUBLE_ECC)
+
+#define DEFAULT_fmPcdPrsExceptions FM_PCD_EX_PRS_SINGLE_ECC
+#define DEFAULT_numOfUsedProfilesPerWindow 16
+#define DEFAULT_numOfSharedPlcrProfiles 4
+
+/****************************/
+/* Network defines */
+/****************************/
+#define UDP_HEADER_SIZE 8
+
+#define ESP_SPI_OFFSET 0
+#define ESP_SPI_SIZE 4
+#define ESP_SEQ_NUM_OFFSET ESP_SPI_SIZE
+#define ESP_SEQ_NUM_SIZE 4
+
+/****************************/
+/* General defines */
+/****************************/
+#define ILLEGAL_CLS_PLAN 0xff
+#define ILLEGAL_NETENV 0xff
+
+#define FM_PCD_MAX_NUM_OF_ALIAS_HDRS 3
+
+/****************************/
+/* Error defines */
+/****************************/
+
+#define FM_PCD_EX_PLCR_DOUBLE_ECC 0x20000000
+#define FM_PCD_EX_PLCR_INIT_ENTRY_ERROR 0x10000000
+#define FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE 0x08000000
+#define FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE 0x04000000
+
+#define GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception) \
+switch (exception){ \
+ case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: \
+ bitMask = FM_EX_KG_DOUBLE_ECC; break; \
+ case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: \
+ bitMask = FM_PCD_EX_PLCR_DOUBLE_ECC; break; \
+ case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: \
+ bitMask = FM_EX_KG_KEYSIZE_OVERFLOW; break; \
+ case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: \
+ bitMask = FM_PCD_EX_PLCR_INIT_ENTRY_ERROR; break; \
+ case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: \
+ bitMask = FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE; break; \
+ case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: \
+ bitMask = FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE; break; \
+ case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: \
+ bitMask = FM_PCD_EX_PRS_DOUBLE_ECC; break; \
+ case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: \
+ bitMask = FM_PCD_EX_PRS_SINGLE_ECC; break; \
+ default: bitMask = 0;break;}
+
+/***********************************************************************/
+/* Policer defines */
+/***********************************************************************/
+#define FM_PCD_PLCR_GCR_STEN 0x40000000
+#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000
+#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000
+#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000
+#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000
+
+/***********************************************************************/
+/* Memory map */
+/***********************************************************************/
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+
+typedef struct {
+/* General Configuration and Status Registers */
+ volatile uint32_t fmpl_gcr; /* 0x000 FMPL_GCR - FM Policer General Configuration */
+ volatile uint32_t fmpl_gsr; /* 0x004 FMPL_GSR - FM Policer Global Status Register */
+ volatile uint32_t fmpl_evr; /* 0x008 FMPL_EVR - FM Policer Event Register */
+ volatile uint32_t fmpl_ier; /* 0x00C FMPL_IER - FM Policer Interrupt Enable Register */
+ volatile uint32_t fmpl_ifr; /* 0x010 FMPL_IFR - FM Policer Interrupt Force Register */
+ volatile uint32_t fmpl_eevr; /* 0x014 FMPL_EEVR - FM Policer Error Event Register */
+ volatile uint32_t fmpl_eier; /* 0x018 FMPL_EIER - FM Policer Error Interrupt Enable Register */
+ volatile uint32_t fmpl_eifr; /* 0x01C FMPL_EIFR - FM Policer Error Interrupt Force Register */
+/* Global Statistic Counters */
+ volatile uint32_t fmpl_rpcnt; /* 0x020 FMPL_RPC - FM Policer RED Packets Counter */
+ volatile uint32_t fmpl_ypcnt; /* 0x024 FMPL_YPC - FM Policer YELLOW Packets Counter */
+ volatile uint32_t fmpl_rrpcnt; /* 0x028 FMPL_RRPC - FM Policer Recolored RED Packet Counter */
+ volatile uint32_t fmpl_rypcnt; /* 0x02C FMPL_RYPC - FM Policer Recolored YELLOW Packet Counter */
+ volatile uint32_t fmpl_tpcnt; /* 0x030 FMPL_TPC - FM Policer Total Packet Counter */
+ volatile uint32_t fmpl_flmcnt; /* 0x034 FMPL_FLMC - FM Policer Frame Length Mismatch Counter */
+ volatile uint32_t fmpl_res0[21]; /* 0x038 - 0x08B Reserved */
+/* Profile RAM Access Registers */
+ volatile uint32_t fmpl_par; /* 0x08C FMPL_PAR - FM Policer Profile Action Register*/
+ t_FmPcdPlcrProfileRegs profileRegs;
+/* Error Capture Registers */
+ volatile uint32_t fmpl_serc; /* 0x100 FMPL_SERC - FM Policer Soft Error Capture */
+ volatile uint32_t fmpl_upcr; /* 0x104 FMPL_UPCR - FM Policer Uninitialized Profile Capture Register */
+ volatile uint32_t fmpl_res2; /* 0x108 Reserved */
+/* Debug Registers */
+ volatile uint32_t fmpl_res3[61]; /* 0x10C-0x200 Reserved Debug*/
+/* Profile Selection Mapping Registers Per Port-ID (n=1-11, 16) */
+ volatile uint32_t fmpl_dpmr; /* 0x200 FMPL_DPMR - FM Policer Default Mapping Register */
+ volatile uint32_t fmpl_pmr[63]; /*+default 0x204-0x2FF FMPL_PMR1 - FMPL_PMR63, - FM Policer Profile Mapping Registers.
+ (for port-ID 1-11, only for supported Port-ID registers) */
+} t_FmPcdPlcrRegs;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/***********************************************************************/
+/* Driver's internal structures */
+/***********************************************************************/
+
+typedef struct {
+ bool known;
+ uint8_t id;
+} t_FmPcdKgSchemesExtractsEntry;
+
+typedef struct {
+ t_FmPcdKgSchemesExtractsEntry extractsArray[FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
+} t_FmPcdKgSchemesExtracts;
+
+typedef struct {
+ t_Handle h_Manip;
+ bool keepRes;
+ e_FmPcdEngine nextEngine;
+ uint8_t parseCode;
+} t_FmPcdInfoForManip;
+
+/**************************************************************************//**
+ @Description A structure of parameters to communicate
+ between the port and PCD regarding the KG scheme.
+*//***************************************************************************/
+typedef struct {
+ uint8_t netEnvId; /* in */
+ uint8_t numOfDistinctionUnits; /* in */
+ uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* in */
+ uint32_t vector; /* out */
+} t_NetEnvParams;
+
+typedef struct {
+ bool allocated;
+ uint8_t ownerId; /* guestId for KG in multi-partition only.
+ portId for PLCR in any environment */
+} t_FmPcdAllocMng;
+
+typedef struct {
+ volatile bool lock;
+ bool used;
+ uint8_t owners;
+ uint8_t netEnvId;
+ uint8_t guestId;
+ uint8_t baseEntry;
+ uint16_t sizeOfGrp;
+ protocolOpt_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
+} t_FmPcdKgClsPlanGrp;
+
+typedef struct {
+ t_Handle h_FmPcd;
+ uint8_t schemeId;
+ t_FmPcdLock *p_Lock;
+ bool valid;
+ uint8_t netEnvId;
+ uint8_t owners;
+ uint32_t matchVector;
+ uint32_t ccUnits;
+ bool nextRelativePlcrProfile;
+ uint16_t relativeProfileId;
+ uint16_t numOfProfiles;
+ t_FmPcdKgKeyOrder orderedArray;
+ e_FmPcdEngine nextEngine;
+ e_FmPcdDoneAction doneAction;
+ bool requiredActionFlag;
+ uint32_t requiredAction;
+ bool extractedOrs;
+ uint8_t bitOffsetInPlcrProfile;
+ bool directPlcr;
+#if (DPAA_VERSION >= 11)
+ bool vspe;
+#endif
+} t_FmPcdKgScheme;
+
+typedef union {
+ struct fman_kg_scheme_regs schemeRegs;
+ struct fman_kg_pe_regs portRegs;
+ struct fman_kg_cp_regs clsPlanRegs;
+} u_FmPcdKgIndirectAccessRegs;
+
+typedef struct {
+ struct fman_kg_regs *p_FmPcdKgRegs;
+ uint32_t schemeExceptionsBitMask;
+ uint8_t numOfSchemes;
+ t_Handle h_HwSpinlock;
+ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
+ t_FmPcdKgScheme schemes[FM_PCD_KG_NUM_OF_SCHEMES];
+ t_FmPcdKgClsPlanGrp clsPlanGrps[FM_MAX_NUM_OF_PORTS];
+ uint8_t emptyClsPlanGrpId;
+ t_FmPcdAllocMng schemesMng[FM_PCD_KG_NUM_OF_SCHEMES]; /* only for MASTER ! */
+ t_FmPcdAllocMng clsPlanBlocksMng[FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP];
+ u_FmPcdKgIndirectAccessRegs *p_IndirectAccessRegs;
+} t_FmPcdKg;
+
+typedef struct {
+ uint16_t profilesBase;
+ uint16_t numOfProfiles;
+ t_Handle h_FmPort;
+} t_FmPcdPlcrMapParam;
+
+typedef struct {
+ uint16_t absoluteProfileId;
+ t_Handle h_FmPcd;
+ bool valid;
+ t_FmPcdLock *p_Lock;
+ t_FmPcdAllocMng profilesMng;
+ bool requiredActionFlag;
+ uint32_t requiredAction;
+ e_FmPcdEngine nextEngineOnGreen; /**< Green next engine type */
+ u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Green next engine params */
+
+ e_FmPcdEngine nextEngineOnYellow; /**< Yellow next engine type */
+ u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Yellow next engine params */
+
+ e_FmPcdEngine nextEngineOnRed; /**< Red next engine type */
+ u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Red next engine params */
+} t_FmPcdPlcrProfile;
+
+typedef struct {
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
+ uint16_t partPlcrProfilesBase;
+ uint16_t partNumOfPlcrProfiles;
+ t_FmPcdPlcrProfile profiles[FM_PCD_PLCR_NUM_ENTRIES];
+ uint16_t numOfSharedProfiles;
+ uint16_t sharedProfilesIds[FM_PCD_PLCR_NUM_ENTRIES];
+ t_FmPcdPlcrMapParam portsMapping[FM_MAX_NUM_OF_PORTS];
+ t_Handle h_HwSpinlock;
+ t_Handle h_SwSpinlock;
+} t_FmPcdPlcr;
+
+typedef struct {
+ uint32_t *p_SwPrsCode;
+ uint32_t *p_CurrSwPrs;
+ uint8_t currLabel;
+ struct fman_prs_regs *p_FmPcdPrsRegs;
+ t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS];
+ uint32_t fmPcdPrsPortIdStatistics;
+} t_FmPcdPrs;
+
+typedef struct {
+ struct {
+ e_NetHeaderType hdr;
+ protocolOpt_t opt; /* only one option !! */
+ } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS];
+} t_FmPcdIntDistinctionUnit;
+
+typedef struct {
+ e_NetHeaderType hdr;
+ protocolOpt_t opt; /* only one option !! */
+ e_NetHeaderType aliasHdr;
+} t_FmPcdNetEnvAliases;
+
+typedef struct {
+ uint8_t netEnvId;
+ t_Handle h_FmPcd;
+ t_Handle h_Spinlock;
+ bool used;
+ uint8_t owners;
+ uint8_t clsPlanGrpId;
+ t_FmPcdIntDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
+ uint32_t unitsVectors[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
+ uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS];
+ uint32_t macsecVector;
+ t_FmPcdNetEnvAliases aliasHdrs[FM_PCD_MAX_NUM_OF_ALIAS_HDRS];
+} t_FmPcdNetEnv;
+
+typedef struct {
+ struct fman_prs_cfg dfltCfg;
+ bool plcrAutoRefresh;
+ uint16_t prsMaxParseCycleLimit;
+} t_FmPcdDriverParam;
+
+typedef struct {
+ t_Handle h_Fm;
+ t_Handle h_FmMuram;
+ t_FmRevisionInfo fmRevInfo;
+
+ uint64_t physicalMuramBase;
+
+ t_Handle h_Spinlock;
+ t_List freeLocksLst;
+ t_List acquiredLocksLst;
+
+ t_Handle h_IpcSession; /* relevant for guest only */
+ bool enabled;
+ uint8_t guestId; /**< Guest Partition Id */
+ uint8_t numOfEnabledGuestPartitionsPcds;
+ char fmPcdModuleName[MODULE_NAME_SIZE];
+ char fmPcdIpcHandlerModuleName[MODULE_NAME_SIZE]; /* relevant for guest only - this is the master's name */
+ t_FmPcdNetEnv netEnvs[FM_MAX_NUM_OF_PORTS];
+ t_FmPcdKg *p_FmPcdKg;
+ t_FmPcdPlcr *p_FmPcdPlcr;
+ t_FmPcdPrs *p_FmPcdPrs;
+
+ void *p_CcShadow; /**< CC MURAM shadow */
+ uint32_t ccShadowSize;
+ uint32_t ccShadowAlign;
+ volatile bool shadowLock;
+ t_Handle h_ShadowSpinlock;
+
+ t_Handle h_Hc;
+
+ uint32_t exceptions;
+ t_FmPcdExceptionCallback *f_Exception;
+ t_FmPcdIdExceptionCallback *f_FmPcdIndexedException;
+ t_Handle h_App;
+ uintptr_t ipv6FrameIdAddr;
+ uintptr_t capwapFrameIdAddr;
+ bool advancedOffloadSupport;
+
+ t_FmPcdDriverParam *p_FmPcdDriverParam;
+} t_FmPcd;
+
+#if (DPAA_VERSION >= 11)
+typedef uint8_t t_FmPcdFrmReplicUpdateType;
+#define FRM_REPLIC_UPDATE_COUNTER 0x01
+#define FRM_REPLIC_UPDATE_INFO 0x02
+#endif /* (DPAA_VERSION >= 11) */
+/***********************************************************************/
+/* PCD internal routines */
+/***********************************************************************/
+
+t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector);
+t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params);
+bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector);
+t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams);
+void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId);
+e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
+uint8_t FmPcdNetEnvGetUnitIdForSingleHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
+uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt);
+
+t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, bool isIpv4, uint8_t groupId);
+t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip);
+t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, uint8_t groupId);
+t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip);
+bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip);
+
+t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams);
+t_Error KgInit(t_FmPcd *p_FmPcd);
+t_Error KgFree(t_FmPcd *p_FmPcd);
+void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set);
+bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId);
+void KgEnable(t_FmPcd *p_FmPcd);
+void KgDisable(t_FmPcd *p_FmPcd);
+t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First);
+void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base);
+
+/* only for MULTI partittion */
+t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds);
+t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds);
+/* only for SINGLE partittion */
+t_Error KgBindPortToSchemes(t_Handle h_FmPcd , uint8_t hardwarePortId, uint32_t spReg);
+
+t_FmPcdLock *FmPcdAcquireLock(t_Handle h_FmPcd);
+void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock);
+
+t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams);
+t_Error PlcrInit(t_FmPcd *p_FmPcd);
+t_Error PlcrFree(t_FmPcd *p_FmPcd);
+void PlcrEnable(t_FmPcd *p_FmPcd);
+void PlcrDisable(t_FmPcd *p_FmPcd);
+uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId);
+void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId);
+t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd,
+ uint8_t hardwarePortId,
+ uint16_t numOfProfiles,
+ uint16_t base);
+t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId);
+
+t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams);
+t_Error PrsInit(t_FmPcd *p_FmPcd);
+void PrsEnable(t_FmPcd *p_FmPcd);
+void PrsDisable(t_FmPcd *p_FmPcd);
+void PrsFree(t_FmPcd *p_FmPcd );
+t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include);
+
+t_Error FmPcdCcGetGrpParams(t_Handle treeId, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase);
+uint8_t FmPcdCcGetOffset(t_Handle h_CcNode);
+uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode);
+uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode);
+t_Error ValidateNextEngineParams(t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, e_FmPcdCcStatsMode supportedStatsMode);
+
+void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add);
+t_Error FmPcdManipCheckParamsForCcNextEngine(t_FmPcdCcNextEngineParams *p_InfoForManip, uint32_t *requiredAction);
+void FmPcdManipUpdateAdResultForCc(t_Handle h_Manip,
+ t_FmPcdCcNextEngineParams *p_CcNextEngineParams,
+ t_Handle p_Ad,
+ t_Handle *p_AdNewPtr);
+void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew, uint32_t adTableOffset);
+void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add);
+t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, t_Handle h_FmPcdCcNode);
+#ifdef FM_CAPWAP_SUPPORT
+t_Handle FmPcdManipApplSpecificBuild(void);
+bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip);
+#endif /* FM_CAPWAP_SUPPORT */
+#if (DPAA_VERSION >= 11)
+void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup);
+void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, bool add);
+void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, void *p_Ad, t_Handle *h_AdNew);
+
+void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node,
+ t_Handle h_ReplicGroup,
+ t_List *p_AdTables,
+ uint32_t *p_NumOfAdTables);
+#endif /* (DPAA_VERSION >= 11) */
+
+void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, t_Handle h_Spinlock);
+void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock);
+t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock);
+t_List *FmPcdManipGetSpinlock(t_Handle h_Manip);
+t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip);
+
+typedef struct
+{
+ t_Handle h_StatsAd;
+ t_Handle h_StatsCounters;
+#if (DPAA_VERSION >= 11)
+ t_Handle h_StatsFLRs;
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPcdCcStatsParams;
+
+void NextStepAd(t_Handle h_Ad,
+ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams,
+ t_FmPcd *p_FmPcd);
+void ReleaseLst(t_List *p_List);
+
+static __inline__ t_Handle FmPcdGetMuramHandle(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ ASSERT_COND(p_FmPcd);
+ return p_FmPcd->h_FmMuram;
+}
+
+static __inline__ uint64_t FmPcdGetMuramPhysBase(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ ASSERT_COND(p_FmPcd);
+ return p_FmPcd->physicalMuramBase;
+}
+
+static __inline__ uint32_t FmPcdLockSpinlock(t_FmPcdLock *p_Lock)
+{
+ ASSERT_COND(p_Lock);
+ return XX_LockIntrSpinlock(p_Lock->h_Spinlock);
+}
+
+static __inline__ void FmPcdUnlockSpinlock(t_FmPcdLock *p_Lock, uint32_t flags)
+{
+ ASSERT_COND(p_Lock);
+ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, flags);
+}
+
+static __inline__ bool FmPcdLockTryLock(t_FmPcdLock *p_Lock)
+{
+ uint32_t intFlags;
+
+ ASSERT_COND(p_Lock);
+ intFlags = XX_LockIntrSpinlock(p_Lock->h_Spinlock);
+ if (p_Lock->flag)
+ {
+ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags);
+ return FALSE;
+ }
+ p_Lock->flag = TRUE;
+ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags);
+ return TRUE;
+}
+
+static __inline__ void FmPcdLockUnlock(t_FmPcdLock *p_Lock)
+{
+ ASSERT_COND(p_Lock);
+ p_Lock->flag = FALSE;
+}
+
+
+#endif /* __FM_PCD_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h
new file mode 100644
index 000000000000..325d3e335f02
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_pcd_ipc.h
+
+ @Description FM PCD Inter-Partition prototypes, structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_PCD_IPC_H
+#define __FM_PCD_IPC_H
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description Structure for getting a sw parser address according to a label
+ Fields commented 'IN' are passed by the port module to be used
+ by the FM module.
+ Fields commented 'OUT' will be filled by FM before returning to port.
+*//***************************************************************************/
+typedef _Packed struct t_FmPcdIpcSwPrsLable
+{
+ uint32_t enumHdr; /**< IN. The existence of this header will invoke
+ the sw parser code. */
+ uint8_t indexPerHdr; /**< IN. Normally 0, if more than one sw parser
+ attachments for the same header, use this
+
+ index to distinguish between them. */
+} _PackedType t_FmPcdIpcSwPrsLable;
+
+/**************************************************************************//**
+ @Description Structure for port-PCD communication.
+ Fields commented 'IN' are passed by the port module to be used
+ by the FM module.
+ Fields commented 'OUT' will be filled by FM before returning to port.
+ Some fields are optional (depending on configuration) and
+ will be analized by the port and FM modules accordingly.
+*//***************************************************************************/
+
+typedef struct t_FmPcdIpcKgSchemesParams
+{
+ uint8_t guestId;
+ uint8_t numOfSchemes;
+ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
+} _PackedType t_FmPcdIpcKgSchemesParams;
+
+typedef struct t_FmPcdIpcKgClsPlanParams
+{
+ uint8_t guestId;
+ uint16_t numOfClsPlanEntries;
+ uint8_t clsPlanBase;
+} _PackedType t_FmPcdIpcKgClsPlanParams;
+
+typedef _Packed struct t_FmPcdIpcPrsIncludePort
+{
+ uint8_t hardwarePortId;
+ bool include;
+} _PackedType t_FmPcdIpcPrsIncludePort;
+
+
+#define FM_PCD_MAX_REPLY_SIZE 16
+#define FM_PCD_MAX_MSG_SIZE 36
+#define FM_PCD_MAX_REPLY_BODY_SIZE 36
+
+typedef _Packed struct {
+ uint32_t msgId;
+ uint8_t msgBody[FM_PCD_MAX_MSG_SIZE];
+} _PackedType t_FmPcdIpcMsg;
+
+typedef _Packed struct t_FmPcdIpcReply {
+ uint32_t error;
+ uint8_t replyBody[FM_PCD_MAX_REPLY_BODY_SIZE];
+} _PackedType t_FmPcdIpcReply;
+
+typedef _Packed struct t_FmIpcResourceAllocParams {
+ uint8_t guestId;
+ uint16_t base;
+ uint16_t num;
+}_PackedType t_FmIpcResourceAllocParams;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+
+/**************************************************************************//**
+ @Function FM_PCD_ALLOC_KG_SCHEMES
+
+ @Description Used by FM PCD front-end in order to allocate KG resources
+
+ @Param[in/out] t_FmPcdIpcKgAllocParams Pointer
+*//***************************************************************************/
+#define FM_PCD_ALLOC_KG_SCHEMES 3
+
+/**************************************************************************//**
+ @Function FM_PCD_FREE_KG_SCHEMES
+
+ @Description Used by FM PCD front-end in order to Free KG resources
+
+ @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer
+*//***************************************************************************/
+#define FM_PCD_FREE_KG_SCHEMES 4
+
+/**************************************************************************//**
+ @Function FM_PCD_ALLOC_PROFILES
+
+ @Description Used by FM PCD front-end in order to allocate Policer profiles
+
+ @Param[in/out] t_FmIpcResourceAllocParams Pointer
+*//***************************************************************************/
+#define FM_PCD_ALLOC_PROFILES 5
+
+/**************************************************************************//**
+ @Function FM_PCD_FREE_PROFILES
+
+ @Description Used by FM PCD front-end in order to Free Policer profiles
+
+ @Param[in/out] t_FmIpcResourceAllocParams Pointer
+*//***************************************************************************/
+#define FM_PCD_FREE_PROFILES 6
+
+/**************************************************************************//**
+ @Function FM_PCD_SET_PORT_PROFILES
+
+ @Description Used by FM PCD front-end in order to allocate Policer profiles
+ for specific port
+
+ @Param[in/out] t_FmIpcResourceAllocParams Pointer
+*//***************************************************************************/
+#define FM_PCD_SET_PORT_PROFILES 7
+
+/**************************************************************************//**
+ @Function FM_PCD_CLEAR_PORT_PROFILES
+
+ @Description Used by FM PCD front-end in order to allocate Policer profiles
+ for specific port
+
+ @Param[in/out] t_FmIpcResourceAllocParams Pointer
+*//***************************************************************************/
+#define FM_PCD_CLEAR_PORT_PROFILES 8
+
+/**************************************************************************//**
+ @Function FM_PCD_GET_PHYS_MURAM_BASE
+
+ @Description Used by FM PCD front-end in order to get MURAM base address
+
+ @Param[in/out] t_FmPcdIcPhysAddr Pointer
+*//***************************************************************************/
+#define FM_PCD_GET_PHYS_MURAM_BASE 9
+
+/**************************************************************************//**
+ @Function FM_PCD_GET_SW_PRS_OFFSET
+
+ @Description Used by FM front-end to get the SW parser offset of the start of
+ code relevant to a given label.
+
+ @Param[in/out] t_FmPcdIpcSwPrsLable Pointer
+*//***************************************************************************/
+#define FM_PCD_GET_SW_PRS_OFFSET 10
+
+/**************************************************************************//**
+ @Function FM_PCD_MASTER_IS_ENABLED
+
+ @Description Used by FM front-end in order to verify
+ PCD enablement.
+
+ @Param[in] bool Pointer
+*//***************************************************************************/
+#define FM_PCD_MASTER_IS_ENABLED 15
+
+/**************************************************************************//**
+ @Function FM_PCD_GUEST_DISABLE
+
+ @Description Used by FM front-end to inform back-end when
+ front-end PCD is disabled
+
+ @Param[in] None
+*//***************************************************************************/
+#define FM_PCD_GUEST_DISABLE 16
+
+/**************************************************************************//**
+ @Function FM_PCD_FREE_KG_CLSPLAN
+
+ @Description Used by FM PCD front-end in order to Free KG classification plan entries
+
+ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer
+*//***************************************************************************/
+#define FM_PCD_FREE_KG_CLSPLAN 22
+
+/**************************************************************************//**
+ @Function FM_PCD_ALLOC_KG_CLSPLAN
+
+ @Description Used by FM PCD front-end in order to allocate KG classification plan entries
+
+ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer
+*//***************************************************************************/
+#define FM_PCD_ALLOC_KG_CLSPLAN 23
+
+/**************************************************************************//**
+ @Function FM_PCD_MASTER_IS_ALIVE
+
+ @Description Used by FM front-end to check that back-end exists
+
+ @Param[in] None
+*//***************************************************************************/
+#define FM_PCD_MASTER_IS_ALIVE 24
+
+/**************************************************************************//**
+ @Function FM_PCD_GET_COUNTER
+
+ @Description Used by FM front-end to read PCD counters
+
+ @Param[in/out] t_FmPcdIpcGetCounter Pointer
+*//***************************************************************************/
+#define FM_PCD_GET_COUNTER 25
+
+/**************************************************************************//**
+ @Function FM_PCD_PRS_INC_PORT_STATS
+
+ @Description Used by FM front-end to set/clear statistics for port
+
+ @Param[in/out] t_FmPcdIpcPrsIncludePort Pointer
+*//***************************************************************************/
+#define FM_PCD_PRS_INC_PORT_STATS 26
+
+#if (DPAA_VERSION >= 11)
+/* TODO - doc */
+#define FM_PCD_ALLOC_SP 27
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/** @} */ /* end of FM_PCD_IPC_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_PCD_IPC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c
new file mode 100644
index 000000000000..e3753305a75f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c
@@ -0,0 +1,1847 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_plcr.c
+
+ @Description FM PCD POLICER...
+*//***************************************************************************/
+#include <linux/math64.h>
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "net_ext.h"
+#include "fm_ext.h"
+
+#include "fm_common.h"
+#include "fm_pcd.h"
+#include "fm_hc.h"
+#include "fm_pcd_ipc.h"
+#include "fm_plcr.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+static uint32_t PlcrProfileLock(t_Handle h_Profile)
+{
+ ASSERT_COND(h_Profile);
+ return FmPcdLockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
+}
+
+static void PlcrProfileUnlock(t_Handle h_Profile, uint32_t intFlags)
+{
+ ASSERT_COND(h_Profile);
+ FmPcdUnlockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock, intFlags);
+}
+
+static bool PlcrProfileFlagTryLock(t_Handle h_Profile)
+{
+ ASSERT_COND(h_Profile);
+ return FmPcdLockTryLock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
+}
+
+static void PlcrProfileFlagUnlock(t_Handle h_Profile)
+{
+ ASSERT_COND(h_Profile);
+ FmPcdLockUnlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock);
+}
+
+static uint32_t PlcrHwLock(t_Handle h_FmPcdPlcr)
+{
+ ASSERT_COND(h_FmPcdPlcr);
+ return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock);
+}
+
+static void PlcrHwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags)
+{
+ ASSERT_COND(h_FmPcdPlcr);
+ XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock, intFlags);
+}
+
+static uint32_t PlcrSwLock(t_Handle h_FmPcdPlcr)
+{
+ ASSERT_COND(h_FmPcdPlcr);
+ return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock);
+}
+
+static void PlcrSwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags)
+{
+ ASSERT_COND(h_FmPcdPlcr);
+ XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock, intFlags);
+}
+
+static bool IsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint16_t i;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE);
+
+ for (i=0;i<p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;i++)
+ if (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId)
+ return TRUE;
+ return FALSE;
+}
+
+static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction)
+{
+ uint32_t nia;
+ uint16_t absoluteProfileId;
+ uint8_t relativeSchemeId, physicalSchemeId;
+
+ nia = FM_PCD_PLCR_NIA_VALID;
+
+ switch (nextEngine)
+ {
+ case e_FM_PCD_DONE :
+ switch (p_NextEngineParams->action)
+ {
+ case e_FM_PCD_DROP_FRAME :
+ nia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd);
+ break;
+ case e_FM_PCD_ENQ_FRAME:
+ nia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+ case e_FM_PCD_KG:
+ physicalSchemeId = FmPcdKgGetSchemeId(p_NextEngineParams->h_DirectScheme);
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId);
+ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
+ if (!FmPcdKgIsSchemeValidSw(p_NextEngineParams->h_DirectScheme))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme."));
+ if (!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct."));
+ nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicalSchemeId;
+ break;
+ case e_FM_PCD_PLCR:
+ absoluteProfileId = ((t_FmPcdPlcrProfile *)p_NextEngineParams->h_Profile)->absoluteProfileId;
+ if (!IsProfileShared(p_FmPcd, absoluteProfileId))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile"));
+ if (!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile "));
+ nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ *nextAction = nia;
+
+ return E_OK;
+}
+
+static uint32_t CalcFPP(uint32_t fpp)
+{
+ if (fpp > 15)
+ return 15 - (0x1f - fpp);
+ else
+ return 16 + fpp;
+}
+
+static void GetInfoRateReg(e_FmPcdPlcrRateMode rateMode,
+ uint32_t rate,
+ uint64_t tsuInTenthNano,
+ uint32_t fppShift,
+ uint64_t *p_Integer,
+ uint64_t *p_Fraction)
+{
+ uint64_t tmp, div;
+
+ if (rateMode == e_FM_PCD_PLCR_BYTE_MODE)
+ {
+ /* now we calculate the initial integer for the bigger rate */
+ /* from Kbps to Bytes/TSU */
+ tmp = (uint64_t)rate;
+ tmp *= 1000; /* kb --> b */
+ tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
+
+ div = 1000000000; /* nano */
+ div *= 10; /* 10 nano */
+ div *= 8; /* bit to byte */
+ }
+ else
+ {
+ /* now we calculate the initial integer for the bigger rate */
+ /* from Kbps to Bytes/TSU */
+ tmp = (uint64_t)rate;
+ tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
+
+ div = 1000000000; /* nano */
+ div *= 10; /* 10 nano */
+ }
+ *p_Integer = div64_u64(tmp<<fppShift, div);
+
+ /* for calculating the fraction, we will recalculate cir and deduct the integer.
+ * For precision, we will multiply by 2^16. we do not divid back, since we write
+ * this value as fraction - see spec.
+ */
+ *p_Fraction = div64_u64(((tmp<<fppShift)<<16) - ((*p_Integer<<16)*div), div);
+}
+
+/* .......... */
+
+static void CalcRates(uint32_t bitFor1Micro,
+ t_FmPcdPlcrNonPassthroughAlgParams *p_NonPassthroughAlgParam,
+ uint32_t *cir,
+ uint32_t *cbs,
+ uint32_t *pir_eir,
+ uint32_t *pbs_ebs,
+ uint32_t *fpp)
+{
+ uint64_t integer, fraction;
+ uint32_t temp, tsuInTenthNanos;
+ uint8_t fppShift=0;
+
+ /* we want the tsu to count 10 nano for better precision normally tsu is 3.9 nano, now we will get 39 */
+ tsuInTenthNanos = (uint32_t)(1000*10/(1 << bitFor1Micro));
+
+ /* we choose the faster rate to calibrate fpp */
+ /* The meaning of this step:
+ * when fppShift is 0 it means all TS bits are treated as integer and TSU is the TS LSB count.
+ * In this configuration we calculate the integer and fraction that represent the higher infoRate
+ * When this is done, we can tell where we have "spare" unused bits and optimize the division of TS
+ * into "integer" and "fraction" where the logic is - as many bits as possible for integer at
+ * high rate, as many bits as possible for fraction at low rate.
+ */
+ if (p_NonPassthroughAlgParam->committedInfoRate > p_NonPassthroughAlgParam->peakOrExcessInfoRate)
+ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
+ else
+ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
+
+ /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and
+ * the LSB bits are for the fraction */
+ temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF);
+ /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll
+ * take max FP = 31.
+ * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is
+ * limited by the 10G physical port.
+ */
+ if (temp != 0)
+ {
+ /* In this case, the largest rate integer is non 0, if it does not occupy all (high) 16
+ * bits of the PIR_EIR we can use this fact and enlarge it to occupy all 16 bits.
+ * The logic is to have as many bits for integer in the higher rates, but if we have "0"s
+ * in the integer part of the cir/pir register, than these bits are wasted. So we want
+ * to use these bits for the fraction. in this way we will have for fraction - the number
+ * of "0" bits and the rest - for integer.
+ * In other words: For each bit we shift it in PIR_EIR, we move the FP in the TS
+ * one bit to the left - preserving the relationship and achieving more bits
+ * for integer in the TS.
+ */
+
+ /* count zeroes left of the higher used bit (in order to shift the value such that
+ * unused bits may be used for fraction).
+ */
+ while ((temp & 0x80000000) == 0)
+ {
+ temp = temp << 1;
+ fppShift++;
+ }
+ if (fppShift > 15)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small"));
+ return;
+ }
+ }
+ else
+ {
+ temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */
+ if (!temp)
+ /* integer and fraction are 0, we set FP to its max val */
+ fppShift = 31;
+ else
+ {
+ /* integer was 0 but fraction is not. FP is 16 for the fraction,
+ * + all left zeroes of the fraction. */
+ fppShift=16;
+ /* count zeroes left of the higher used bit (in order to shift the value such that
+ * unused bits may be used for fraction).
+ */
+ while ((temp & 0x8000) == 0)
+ {
+ temp = temp << 1;
+ fppShift++;
+ }
+ }
+ }
+
+ /*
+ * This means that the FM TS register will now be used so that 'fppShift' bits are for
+ * fraction and the rest for integer */
+ /* now we re-calculate cir and pir_eir with the calculated FP */
+ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
+ *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
+ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
+ *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
+
+ *cbs = p_NonPassthroughAlgParam->committedBurstSize;
+ *pbs_ebs = p_NonPassthroughAlgParam->peakOrExcessBurstSize;
+
+ /* convert FP as it should be written to reg.
+ * 0-15 --> 16-31
+ * 16-31 --> 0-15
+ */
+ *fpp = CalcFPP(fppShift);
+}
+
+static void WritePar(t_FmPcd *p_FmPcd, uint32_t par)
+{
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par);
+
+ while (GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ;
+}
+
+static t_Error BuildProfileRegs(t_FmPcd *p_FmPcd,
+ t_FmPcdPlcrProfileParams *p_ProfileParams,
+ t_FmPcdPlcrProfileRegs *p_PlcrRegs)
+{
+ t_Error err = E_OK;
+ uint32_t pemode, gnia, ynia, rnia, bitFor1Micro;
+
+ ASSERT_COND(p_FmPcd);
+
+ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);
+ if (bitFor1Micro == 0)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale"));
+
+/* Set G, Y, R Nia */
+ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnGreen, &(p_ProfileParams->paramsOnGreen), &gnia);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnYellow, &(p_ProfileParams->paramsOnYellow), &ynia);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnRed, &(p_ProfileParams->paramsOnRed), &rnia);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+/* Mode fmpl_pemode */
+ pemode = FM_PCD_PLCR_PEMODE_PI;
+
+ switch (p_ProfileParams->algSelection)
+ {
+ case e_FM_PCD_PLCR_PASS_THROUGH:
+ p_PlcrRegs->fmpl_pecir = 0;
+ p_PlcrRegs->fmpl_pecbs = 0;
+ p_PlcrRegs->fmpl_pepepir_eir = 0;
+ p_PlcrRegs->fmpl_pepbs_ebs = 0;
+ p_PlcrRegs->fmpl_pelts = 0;
+ p_PlcrRegs->fmpl_pects = 0;
+ p_PlcrRegs->fmpl_pepts_ets = 0;
+ pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK;
+ switch (p_ProfileParams->colorMode)
+ {
+ case e_FM_PCD_PLCR_COLOR_BLIND:
+ pemode |= FM_PCD_PLCR_PEMODE_CBLND;
+ switch (p_ProfileParams->color.dfltColor)
+ {
+ case e_FM_PCD_PLCR_GREEN:
+ pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK;
+ break;
+ case e_FM_PCD_PLCR_YELLOW:
+ pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y;
+ break;
+ case e_FM_PCD_PLCR_RED:
+ pemode |= FM_PCD_PLCR_PEMODE_DEFC_R;
+ break;
+ case e_FM_PCD_PLCR_OVERRIDE:
+ pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ break;
+ case e_FM_PCD_PLCR_COLOR_AWARE:
+ pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+
+ case e_FM_PCD_PLCR_RFC_2698:
+ /* Select algorithm MODE[ALG] = "01" */
+ pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698;
+ if (p_ProfileParams->nonPassthroughAlgParams.committedInfoRate > p_ProfileParams->nonPassthroughAlgParams.peakOrExcessInfoRate)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than committedInfoRate."));
+ goto cont_rfc;
+ case e_FM_PCD_PLCR_RFC_4115:
+ /* Select algorithm MODE[ALG] = "10" */
+ pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115;
+cont_rfc:
+ /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */
+ switch (p_ProfileParams->colorMode)
+ {
+ case e_FM_PCD_PLCR_COLOR_BLIND:
+ pemode |= FM_PCD_PLCR_PEMODE_CBLND;
+ break;
+ case e_FM_PCD_PLCR_COLOR_AWARE:
+ pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
+ /*In color aware more select override color interpretation (MODE[OVCLR]) */
+ switch (p_ProfileParams->color.override)
+ {
+ case e_FM_PCD_PLCR_GREEN:
+ pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK;
+ break;
+ case e_FM_PCD_PLCR_YELLOW:
+ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y;
+ break;
+ case e_FM_PCD_PLCR_RED:
+ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R;
+ break;
+ case e_FM_PCD_PLCR_OVERRIDE:
+ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */
+ switch (p_ProfileParams->nonPassthroughAlgParams.rateMode)
+ {
+ case e_FM_PCD_PLCR_BYTE_MODE :
+ pemode &= ~FM_PCD_PLCR_PEMODE_PKT;
+ switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.frameLengthSelection)
+ {
+ case e_FM_PCD_PLCR_L2_FRM_LEN:
+ pemode |= FM_PCD_PLCR_PEMODE_FLS_L2;
+ break;
+ case e_FM_PCD_PLCR_L3_FRM_LEN:
+ pemode |= FM_PCD_PLCR_PEMODE_FLS_L3;
+ break;
+ case e_FM_PCD_PLCR_L4_FRM_LEN:
+ pemode |= FM_PCD_PLCR_PEMODE_FLS_L4;
+ break;
+ case e_FM_PCD_PLCR_FULL_FRM_LEN:
+ pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection)
+ {
+ case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN:
+ pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS;
+ break;
+ case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN:
+ pemode |= FM_PCD_PLCR_PEMODE_RBFLS;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ break;
+ case e_FM_PCD_PLCR_PACKET_MODE :
+ pemode |= FM_PCD_PLCR_PEMODE_PKT;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET
+ mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE
+ mode with high traffic rates move the fixed point to the right to increase integer accuracy. */
+
+ /* Configure Traffic Parameters*/
+ {
+ uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0;
+
+ CalcRates(bitFor1Micro, &p_ProfileParams->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp);
+
+ /* Set Committed Information Rate (CIR) */
+ p_PlcrRegs->fmpl_pecir = cir;
+ /* Set Committed Burst Size (CBS). */
+ p_PlcrRegs->fmpl_pecbs = cbs;
+ /* Set Peak Information Rate (PIR_EIR used as PIR) */
+ p_PlcrRegs->fmpl_pepepir_eir = pir_eir;
+ /* Set Peak Burst Size (PBS_EBS used as PBS) */
+ p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs;
+
+ /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */
+ /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */
+ p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF;
+ /* Committed Rate Token Bucket Size (CTS) */
+ p_PlcrRegs->fmpl_pects = 0xFFFFFFFF;
+
+ /* Set the FPP based on calculation */
+ pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT);
+ }
+ break; /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ p_PlcrRegs->fmpl_pemode = pemode;
+
+ p_PlcrRegs->fmpl_pegnia = gnia;
+ p_PlcrRegs->fmpl_peynia = ynia;
+ p_PlcrRegs->fmpl_pernia = rnia;
+
+ /* Zero Counters */
+ p_PlcrRegs->fmpl_pegpc = 0;
+ p_PlcrRegs->fmpl_peypc = 0;
+ p_PlcrRegs->fmpl_perpc = 0;
+ p_PlcrRegs->fmpl_perypc = 0;
+ p_PlcrRegs->fmpl_perrpc = 0;
+
+ return E_OK;
+}
+
+static t_Error AllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
+{
+ uint32_t profilesFound;
+ uint16_t i, k=0;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ if (!numOfProfiles)
+ return E_OK;
+
+ if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
+
+ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
+ /* Find numOfProfiles free profiles (may be spread) */
+ profilesFound = 0;
+ for (i=0;i<FM_PCD_PLCR_NUM_ENTRIES; i++)
+ if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
+ {
+ profilesFound++;
+ profilesIds[k] = i;
+ k++;
+ if (profilesFound == numOfProfiles)
+ break;
+ }
+
+ if (profilesFound != numOfProfiles)
+ {
+ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG);
+ }
+
+ for (i = 0;i<k;i++)
+ {
+ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE;
+ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0;
+ }
+ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ return E_OK;
+}
+
+static void FreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
+{
+ uint16_t i;
+
+ SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
+
+ ASSERT_COND(numOfProfiles);
+
+ for (i=0; i < numOfProfiles; i++)
+ {
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated);
+ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE;
+ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = p_FmPcd->guestId;
+ }
+}
+
+static void UpdateRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool set)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ /* this routine is protected by calling routine */
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ if (set)
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = TRUE;
+ else
+ {
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = 0;
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = FALSE;
+ }
+}
+
+/*********************************************/
+/*............Policer Exception..............*/
+/*********************************************/
+static void EventsCB(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t event, mask, force;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr);
+ mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
+
+ event &= mask;
+
+ /* clear the forced events */
+ force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr);
+ if (force & event)
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event);
+
+
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event);
+
+ if (event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE)
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE);
+ if (event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE);
+}
+
+/* ..... */
+
+static void ErrorExceptionsCB(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t event, force, captureReg, mask;
+
+ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
+ event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr);
+ mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
+
+ event &= mask;
+
+ /* clear the forced events */
+ force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr);
+ if (force & event)
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event);
+
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event);
+
+ if (event & FM_PCD_PLCR_DOUBLE_ECC)
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC);
+ if (event & FM_PCD_PLCR_INIT_ENTRY_ERROR)
+ {
+ captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr);
+ /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP);
+ p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK);
+ p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ;
+ p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/
+ p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK));
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP);
+ }
+}
+
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
+{
+ t_FmPcdPlcr *p_FmPcdPlcr;
+ uint16_t i=0;
+
+ UNUSED(p_FmPcd);
+ UNUSED(p_FmPcdParams);
+
+ p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr));
+ if (!p_FmPcdPlcr)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED"));
+ return NULL;
+ }
+ memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr));
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ p_FmPcdPlcr->p_FmPcdPlcrRegs = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm));
+ p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = DEFAULT_plcrAutoRefresh;
+ p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions);
+ }
+
+ p_FmPcdPlcr->numOfSharedProfiles = DEFAULT_numOfSharedPlcrProfiles;
+
+ p_FmPcdPlcr->partPlcrProfilesBase = p_FmPcdParams->partPlcrProfilesBase;
+ p_FmPcdPlcr->partNumOfPlcrProfiles = p_FmPcdParams->partNumOfPlcrProfiles;
+ /* for backward compatabilty. if no policer profile, will set automatically to the max */
+ if ((p_FmPcd->guestId == NCSW_MASTER_ID) &&
+ (p_FmPcdPlcr->partNumOfPlcrProfiles == 0))
+ p_FmPcdPlcr->partNumOfPlcrProfiles = FM_PCD_PLCR_NUM_ENTRIES;
+
+ for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; i++)
+ p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
+
+ return p_FmPcdPlcr;
+}
+
+t_Error PlcrInit(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam;
+ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
+ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ t_Error err = E_OK;
+ uint32_t tmpReg32 = 0;
+ uint16_t base;
+
+ if ((p_FmPcdPlcr->partPlcrProfilesBase + p_FmPcdPlcr->partNumOfPlcrProfiles) > FM_PCD_PLCR_NUM_ENTRIES)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partPlcrProfilesBase+partNumOfPlcrProfiles out of range!!!"));
+
+ p_FmPcdPlcr->h_HwSpinlock = XX_InitSpinlock();
+ if (!p_FmPcdPlcr->h_HwSpinlock)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer HW spinlock"));
+
+ p_FmPcdPlcr->h_SwSpinlock = XX_InitSpinlock();
+ if (!p_FmPcdPlcr->h_SwSpinlock)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer SW spinlock"));
+
+ base = PlcrAllocProfilesForPartition(p_FmPcd,
+ p_FmPcdPlcr->partPlcrProfilesBase,
+ p_FmPcdPlcr->partNumOfPlcrProfiles,
+ p_FmPcd->guestId);
+ if (base == (uint16_t)ILLEGAL_BASE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ if (p_FmPcdPlcr->numOfSharedProfiles)
+ {
+ err = AllocSharedProfiles(p_FmPcd,
+ p_FmPcdPlcr->numOfSharedProfiles,
+ p_FmPcdPlcr->sharedProfilesIds);
+ if (err)
+ RETURN_ERROR(MAJOR, err,NO_MSG);
+ }
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ return E_OK;
+
+ /**********************FMPL_GCR******************/
+ tmpReg32 = 0;
+ tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
+ if (p_Param->plcrAutoRefresh)
+ tmpReg32 |= FM_PCD_PLCR_GCR_DAR;
+ tmpReg32 |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd);
+
+ WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32);
+ /**********************FMPL_GCR******************/
+
+ /**********************FMPL_EEVR******************/
+ WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR));
+ /**********************FMPL_EEVR******************/
+ /**********************FMPL_EIER******************/
+ tmpReg32 = 0;
+ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)
+ {
+ FmEnableRamsEcc(p_FmPcd->h_Fm);
+ tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC;
+ }
+ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)
+ tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR;
+ WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32);
+ /**********************FMPL_EIER******************/
+
+ /**********************FMPL_EVR******************/
+ WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE));
+ /**********************FMPL_EVR******************/
+ /**********************FMPL_IER******************/
+ tmpReg32 = 0;
+ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)
+ tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
+ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE)
+ tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
+ WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32);
+ /**********************FMPL_IER******************/
+
+ /* register even if no interrupts enabled, to allow future enablement */
+ FmRegisterIntr(p_FmPcd->h_Fm,
+ e_FM_MOD_PLCR,
+ 0,
+ e_FM_INTR_TYPE_ERR,
+ ErrorExceptionsCB,
+ p_FmPcd);
+ FmRegisterIntr(p_FmPcd->h_Fm,
+ e_FM_MOD_PLCR,
+ 0,
+ e_FM_INTR_TYPE_NORMAL,
+ EventsCB,
+ p_FmPcd);
+
+ /* driver initializes one DFLT profile at the last entry*/
+ /**********************FMPL_DPMR******************/
+ tmpReg32 = 0;
+ WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32);
+ p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE;
+
+ return E_OK;
+}
+
+t_Error PlcrFree(t_FmPcd *p_FmPcd)
+{
+ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR);
+ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL);
+
+ if (p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles)
+ FreeSharedProfiles(p_FmPcd,
+ p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles,
+ p_FmPcd->p_FmPcdPlcr->sharedProfilesIds);
+
+ if (p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles)
+ PlcrFreeProfilesForPartition(p_FmPcd,
+ p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase,
+ p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles,
+ p_FmPcd->guestId);
+
+ if (p_FmPcd->p_FmPcdPlcr->h_SwSpinlock)
+ XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_SwSpinlock);
+
+ if (p_FmPcd->p_FmPcdPlcr->h_HwSpinlock)
+ XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_HwSpinlock);
+
+ return E_OK;
+}
+
+void PlcrEnable(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+
+ WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN);
+}
+
+void PlcrDisable(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+
+ WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN);
+}
+
+uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId)
+{
+ uint32_t intFlags;
+ uint16_t profilesFound = 0;
+ int i = 0;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr);
+
+ if (!numOfProfiles)
+ return 0;
+
+ if ((numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES) ||
+ (base + numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES))
+ return (uint16_t)ILLEGAL_BASE;
+
+ if (p_FmPcd->h_IpcSession)
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmPcdIpcMsg msg;
+ t_FmPcdIpcReply reply;
+ t_Error err;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = p_FmPcd->guestId;
+ ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles;
+ ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase;
+ msg.msgId = FM_PCD_ALLOC_PROFILES;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ replyLength = sizeof(uint32_t) + sizeof(uint16_t);
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if ((err != E_OK) ||
+ (replyLength != (sizeof(uint32_t) + sizeof(uint16_t))))
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return (uint16_t)ILLEGAL_BASE;
+ }
+ else
+ memcpy((uint8_t*)&p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, reply.replyBody, sizeof(uint16_t));
+ if (p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase == (uint16_t)ILLEGAL_BASE)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return (uint16_t)ILLEGAL_BASE;
+ }
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ {
+ DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!"));
+ return (uint16_t)ILLEGAL_BASE;
+ }
+
+ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock);
+ for (i=base; i<(base+numOfProfiles); i++)
+ if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE)
+ profilesFound++;
+ else
+ break;
+
+ if (profilesFound == numOfProfiles)
+ for (i=base; i<(base+numOfProfiles); i++)
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = guestId;
+ else
+ {
+ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
+ return (uint16_t)ILLEGAL_BASE;
+ }
+ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags);
+
+ return base;
+}
+
+void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId)
+{
+ int i = 0;
+
+ ASSERT_COND(p_FmPcd);
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr);
+
+ if (p_FmPcd->h_IpcSession)
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmPcdIpcMsg msg;
+ t_Error err;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = p_FmPcd->guestId;
+ ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles;
+ ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase;
+ msg.msgId = FM_PCD_FREE_PROFILES;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return;
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ {
+ DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!"));
+ return;
+ }
+
+ for (i=base; i<(base+numOfProfiles); i++)
+ {
+ if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == guestId)
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
+ else
+ DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition"));
+ }
+}
+
+t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd,
+ uint8_t hardwarePortId,
+ uint16_t numOfProfiles,
+ uint16_t base)
+{
+ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ uint32_t log2Num, tmpReg32;
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ !p_Regs &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmPcdIpcMsg msg;
+ t_Error err;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = hardwarePortId;
+ ipcAllocParams.num = numOfProfiles;
+ ipcAllocParams.base = base;
+ msg.msgId = FM_PCD_SET_PORT_PROFILES;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (!p_Regs)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ if (GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("The requesting port has already an allocated profiles window."));
+
+ /**********************FMPL_PMRx******************/
+ LOG2((uint64_t)numOfProfiles, log2Num);
+ tmpReg32 = base;
+ tmpReg32 |= log2Num << 16;
+ tmpReg32 |= FM_PCD_PLCR_PMR_V;
+ WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32);
+
+ return E_OK;
+}
+
+t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId)
+{
+ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ !p_Regs &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmPcdIpcMsg msg;
+ t_Error err;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = hardwarePortId;
+ msg.msgId = FM_PCD_CLEAR_PORT_PROFILES;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (!p_Regs)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+ WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0);
+
+ return E_OK;
+}
+
+t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+ uint32_t profilesFound;
+ uint32_t intFlags;
+ uint16_t i, first, swPortIndex = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ if (!numOfProfiles)
+ return E_OK;
+
+ ASSERT_COND(hardwarePortId);
+
+ if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
+
+ if (!POWER_OF_2(numOfProfiles))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2."));
+
+ first = 0;
+ profilesFound = 0;
+ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
+
+ for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; )
+ {
+ if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
+ {
+ profilesFound++;
+ i++;
+ if (profilesFound == numOfProfiles)
+ break;
+ }
+ else
+ {
+ profilesFound = 0;
+ /* advance i to the next aligned address */
+ i = first = (uint16_t)(first + numOfProfiles);
+ }
+ }
+
+ if (profilesFound == numOfProfiles)
+ {
+ for (i=first; i<first + numOfProfiles; i++)
+ {
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE;
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId;
+ }
+ }
+ else
+ {
+ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+ RETURN_ERROR(MINOR, E_FULL, ("No profiles."));
+ }
+ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ err = PlcrSetPortProfiles(p_FmPcd, hardwarePortId, numOfProfiles, first);
+ if (err)
+ {
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles;
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = first;
+
+ return E_OK;
+}
+
+t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_Error err = E_OK;
+ uint32_t intFlags;
+ uint16_t i, swPortIndex = 0;
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ err = PlcrClearPortProfiles(p_FmPcd, hardwarePortId);
+ if (err)
+ RETURN_ERROR(MAJOR, err,NO_MSG);
+
+ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr);
+ for (i=p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
+ i<(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase +
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles);
+ i++)
+ {
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId);
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated);
+
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE;
+ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = p_FmPcd->guestId;
+ }
+ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0;
+ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0;
+
+ return E_OK;
+}
+
+t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ uint32_t tmpReg32, intFlags;
+ t_Error err;
+
+ /* Calling function locked all PCD modules, so no need to lock here */
+
+ if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range"));
+
+ if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileIndx))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid"));
+
+ /*intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx]);*/
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction);
+
+ UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE);
+ FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction);
+
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+ return err;
+ }
+
+ /* lock the HW because once we read the registers we don't want them to be changed
+ * by another access. (We can copy to a tmp location and release the lock!) */
+
+ intFlags = PlcrHwLock(p_FmPcdPlcr);
+ WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
+
+ if (!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredActionFlag ||
+ !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction))
+ {
+ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
+ {
+ if ((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) ||
+ (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) ||
+ (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE))
+ {
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+ RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE"));
+ }
+
+ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME)
+ {
+ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia);
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32);
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
+ WritePar(p_FmPcd, tmpReg32);
+ }
+
+ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME)
+ {
+ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia);
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32);
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
+ WritePar(p_FmPcd, tmpReg32);
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+ }
+
+ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME)
+ {
+ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia);
+ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
+ {
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
+ }
+ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32);
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
+ WritePar(p_FmPcd, tmpReg32);
+
+ }
+ }
+ }
+ PlcrHwUnlock(p_FmPcdPlcr, intFlags);
+
+ UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE);
+ FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction);
+
+ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/
+
+ return E_OK;
+}
+
+uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag;
+}
+
+uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction;
+}
+
+bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
+
+ ASSERT_COND(absoluteProfileId < FM_PCD_PLCR_NUM_ENTRIES);
+
+ return p_FmPcdPlcr->profiles[absoluteProfileId].valid;
+}
+
+void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t intFlags;
+
+ ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]);
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE;
+ PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags);
+}
+
+void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]);
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE;
+ PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags);
+}
+
+uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile)
+{
+ return ((t_FmPcdPlcrProfile*)h_Profile)->absoluteProfileId;
+}
+
+t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd,
+ e_FmPcdProfileTypeSelection profileType,
+ t_Handle h_FmPort,
+ uint16_t relativeProfile,
+ uint16_t *p_AbsoluteId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
+ uint8_t i;
+
+ switch (profileType)
+ {
+ case e_FM_PCD_PLCR_PORT_PRIVATE:
+ /* get port PCD id from port handle */
+ for (i=0;i<FM_MAX_NUM_OF_PORTS;i++)
+ if (p_FmPcd->p_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort)
+ break;
+ if (i == FM_MAX_NUM_OF_PORTS)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle."));
+
+ if (!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles"));
+ if (relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
+ *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile);
+ break;
+ case e_FM_PCD_PLCR_SHARED:
+ if (relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
+ *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]);
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type"));
+ }
+
+ return E_OK;
+}
+
+uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint16_t swPortIndex = 0;
+
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
+}
+
+uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint16_t swPortIndex = 0;
+
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles;
+
+}
+uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId)
+{
+ return (uint32_t)(FM_PCD_PLCR_PAR_GO |
+ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT));
+}
+
+uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId)
+{
+ return (uint32_t)(FM_PCD_PLCR_PAR_GO |
+ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
+ FM_PCD_PLCR_PAR_PWSEL_MASK);
+}
+
+bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg)
+{
+
+ if (profileModeReg & FM_PCD_PLCR_PEMODE_PI)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId)
+{
+ return (uint32_t)(FM_PCD_PLCR_PAR_GO |
+ FM_PCD_PLCR_PAR_R |
+ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
+ FM_PCD_PLCR_PAR_PWSEL_MASK);
+}
+
+uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter)
+{
+ switch (counter)
+ {
+ case (e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER):
+ return FM_PCD_PLCR_PAR_PWSEL_PEGPC;
+ case (e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER):
+ return FM_PCD_PLCR_PAR_PWSEL_PEYPC;
+ case (e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) :
+ return FM_PCD_PLCR_PAR_PWSEL_PERPC;
+ case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) :
+ return FM_PCD_PLCR_PAR_PWSEL_PERYPC;
+ case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) :
+ return FM_PCD_PLCR_PAR_PWSEL_PERRPC;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ return 0;
+ }
+}
+
+uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red)
+{
+
+ uint32_t tmpReg32 = 0;
+
+ if (green)
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
+ if (yellow)
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
+ if (red)
+ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
+
+ return tmpReg32;
+}
+
+void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ /* this routine is protected by calling routine */
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
+
+ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction |= requiredAction;
+}
+
+/*********************** End of inter-module routines ************************/
+
+
+/**************************************************/
+/*............Policer API.........................*/
+/**************************************************/
+
+t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
+
+ if (!FmIsMaster(p_FmPcd->h_Fm))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!"));
+
+ p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable;
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
+
+ p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles;
+
+ return E_OK;
+}
+
+t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t tmpReg32;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
+
+ if (!FmIsMaster(p_FmPcd->h_Fm))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!"));
+
+ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr);
+ if (enable)
+ tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
+ else
+ tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN;
+
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32);
+ return E_OK;
+}
+
+t_Handle FM_PCD_PlcrProfileSet(t_Handle h_FmPcd,
+ t_FmPcdPlcrProfileParams *p_ProfileParams)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
+ t_FmPcdPlcrProfileRegs plcrProfileReg;
+ uint32_t intFlags;
+ uint16_t absoluteProfileId;
+ t_Error err = E_OK;
+ uint32_t tmpReg32;
+ t_FmPcdPlcrProfile *p_Profile;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+
+ if (p_ProfileParams->modify)
+ {
+ p_Profile = (t_FmPcdPlcrProfile *)p_ProfileParams->id.h_Profile;
+ p_FmPcd = p_Profile->h_FmPcd;
+ absoluteProfileId = p_Profile->absoluteProfileId;
+ if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
+ return NULL;
+ }
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL);
+
+ /* Try lock profile using flag */
+ if (!PlcrProfileFlagTryLock(p_Profile))
+ {
+ DBG(TRACE, ("Profile Try Lock - BUSY"));
+ /* Signal to caller BUSY condition */
+ p_ProfileParams->id.h_Profile = NULL;
+ return NULL;
+ }
+ }
+ else
+ {
+ p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL);
+
+ /* SMP: needs to be protected only if another core now changes the windows */
+ err = FmPcdPlcrGetAbsoluteIdByProfileParams(h_FmPcd,
+ p_ProfileParams->id.newParams.profileType,
+ p_ProfileParams->id.newParams.h_FmPort,
+ p_ProfileParams->id.newParams.relativeProfileId,
+ &absoluteProfileId);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return NULL;
+ }
+
+ if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
+ return NULL;
+ }
+
+ if (FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId))
+ {
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used"));
+ return NULL;
+ }
+
+ /* initialize profile struct */
+ p_Profile = &p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId];
+
+ p_Profile->h_FmPcd = p_FmPcd;
+ p_Profile->absoluteProfileId = absoluteProfileId;
+
+ p_Profile->p_Lock = FmPcdAcquireLock(p_FmPcd);
+ if (!p_Profile->p_Lock)
+ REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Policer Profile lock obj!"));
+ }
+
+ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
+
+ p_Profile->nextEngineOnGreen = p_ProfileParams->nextEngineOnGreen;
+ memcpy(&p_Profile->paramsOnGreen, &(p_ProfileParams->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams));
+
+ p_Profile->nextEngineOnYellow = p_ProfileParams->nextEngineOnYellow;
+ memcpy(&p_Profile->paramsOnYellow, &(p_ProfileParams->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams));
+
+ p_Profile->nextEngineOnRed = p_ProfileParams->nextEngineOnRed;
+ memcpy(&p_Profile->paramsOnRed, &(p_ProfileParams->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams));
+
+ memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrProfileRegs));
+
+ /* build the policer profile registers */
+ err = BuildProfileRegs(h_FmPcd, p_ProfileParams, &plcrProfileReg);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ if (p_ProfileParams->modify)
+ /* unlock */
+ PlcrProfileFlagUnlock(p_Profile);
+ if (!p_ProfileParams->modify &&
+ p_Profile->p_Lock)
+ /* release allocated Profile lock */
+ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
+ return NULL;
+ }
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, (t_Handle)p_Profile, &plcrProfileReg);
+ if (p_ProfileParams->modify)
+ PlcrProfileFlagUnlock(p_Profile);
+ if (err)
+ {
+ /* release the allocated scheme lock */
+ if (!p_ProfileParams->modify &&
+ p_Profile->p_Lock)
+ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
+
+ return NULL;
+ }
+ if (!p_ProfileParams->modify)
+ FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId);
+ return (t_Handle)p_Profile;
+ }
+
+ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL);
+
+ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir , plcrProfileReg.fmpl_pecir);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs , plcrProfileReg.fmpl_pecbs);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts , plcrProfileReg.fmpl_pelts);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects , plcrProfileReg.fmpl_pects);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc , plcrProfileReg.fmpl_pegpc);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc , plcrProfileReg.fmpl_peypc);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc , plcrProfileReg.fmpl_perpc);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc);
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc);
+
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId);
+ WritePar(p_FmPcd, tmpReg32);
+
+ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ if (!p_ProfileParams->modify)
+ FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId);
+ else
+ PlcrProfileFlagUnlock(p_Profile);
+
+ return (t_Handle)p_Profile;
+}
+
+t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile)
+{
+ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
+ t_FmPcd *p_FmPcd;
+ uint16_t profileIndx;
+ uint32_t tmpReg32, intFlags;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
+ p_FmPcd = p_Profile->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ profileIndx = p_Profile->absoluteProfileId;
+
+ UpdateRequiredActionFlag(p_FmPcd, profileIndx, FALSE);
+
+ FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx);
+
+ if (p_FmPcd->h_Hc)
+ {
+ err = FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile);
+ if (p_Profile->p_Lock)
+ /* release allocated Profile lock */
+ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
+
+ return err;
+ }
+
+ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
+ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI);
+
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx);
+ WritePar(p_FmPcd, tmpReg32);
+ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+
+ if (p_Profile->p_Lock)
+ /* release allocated Profile lock */
+ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock);
+
+ /* we do not memset profile as all its fields are being re-initialized at "set",
+ * plus its allocation information is still valid. */
+ return E_OK;
+}
+
+/***************************************************/
+/*............Policer Profile Counter..............*/
+/***************************************************/
+uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter)
+{
+ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
+ t_FmPcd *p_FmPcd;
+ uint16_t profileIndx;
+ uint32_t intFlags, counterVal = 0;
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
+
+ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
+ p_FmPcd = p_Profile->h_FmPcd;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+
+ if (p_FmPcd->h_Hc)
+ return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter);
+
+ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0);
+
+ profileIndx = p_Profile->absoluteProfileId;
+
+ if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
+ return 0;
+ }
+ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
+ WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
+
+ switch (counter)
+ {
+ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
+ counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc));
+ break;
+ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
+ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
+ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
+ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
+ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc);
+ break;
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ break;
+ }
+ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ return counterVal;
+}
+
+t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value)
+{
+ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile;
+ t_FmPcd *p_FmPcd;
+ uint16_t profileIndx;
+ uint32_t tmpReg32, intFlags;
+ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
+
+ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE);
+
+ p_FmPcd = p_Profile->h_FmPcd;
+ profileIndx = p_Profile->absoluteProfileId;
+
+ if (p_FmPcd->h_Hc)
+ return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value);
+
+ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+ SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE);
+
+ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr);
+ switch (counter)
+ {
+ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value);
+ break;
+ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
+ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value);
+ break;
+ default:
+ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ /* Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM =
+ * Profile Number, PWSEL=0xFFFF (select all words).
+ */
+ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
+ tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter);
+ WritePar(p_FmPcd, tmpReg32);
+ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags);
+
+ return E_OK;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h
new file mode 100644
index 000000000000..2bb8b969956c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_plcr.h
+
+ @Description FM Policer private header
+*//***************************************************************************/
+#ifndef __FM_PLCR_H
+#define __FM_PLCR_H
+
+#include "std_ext.h"
+
+
+/***********************************************************************/
+/* Policer defines */
+/***********************************************************************/
+
+#define FM_PCD_PLCR_PAR_GO 0x80000000
+#define FM_PCD_PLCR_PAR_PWSEL_MASK 0x0000FFFF
+#define FM_PCD_PLCR_PAR_R 0x40000000
+
+/* shifts */
+#define FM_PCD_PLCR_PAR_PNUM_SHIFT 16
+
+/* masks */
+#define FM_PCD_PLCR_PEMODE_PI 0x80000000
+#define FM_PCD_PLCR_PEMODE_CBLND 0x40000000
+#define FM_PCD_PLCR_PEMODE_ALG_MASK 0x30000000
+#define FM_PCD_PLCR_PEMODE_ALG_RFC2698 0x10000000
+#define FM_PCD_PLCR_PEMODE_ALG_RFC4115 0x20000000
+#define FM_PCD_PLCR_PEMODE_DEFC_MASK 0x0C000000
+#define FM_PCD_PLCR_PEMODE_DEFC_Y 0x04000000
+#define FM_PCD_PLCR_PEMODE_DEFC_R 0x08000000
+#define FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE 0x0C000000
+#define FM_PCD_PLCR_PEMODE_OVCLR_MASK 0x03000000
+#define FM_PCD_PLCR_PEMODE_OVCLR_Y 0x01000000
+#define FM_PCD_PLCR_PEMODE_OVCLR_R 0x02000000
+#define FM_PCD_PLCR_PEMODE_OVCLR_G_NC 0x03000000
+#define FM_PCD_PLCR_PEMODE_PKT 0x00800000
+#define FM_PCD_PLCR_PEMODE_FPP_MASK 0x001F0000
+#define FM_PCD_PLCR_PEMODE_FPP_SHIFT 16
+#define FM_PCD_PLCR_PEMODE_FLS_MASK 0x0000F000
+#define FM_PCD_PLCR_PEMODE_FLS_L2 0x00003000
+#define FM_PCD_PLCR_PEMODE_FLS_L3 0x0000B000
+#define FM_PCD_PLCR_PEMODE_FLS_L4 0x0000E000
+#define FM_PCD_PLCR_PEMODE_FLS_FULL 0x0000F000
+#define FM_PCD_PLCR_PEMODE_RBFLS 0x00000800
+#define FM_PCD_PLCR_PEMODE_TRA 0x00000004
+#define FM_PCD_PLCR_PEMODE_TRB 0x00000002
+#define FM_PCD_PLCR_PEMODE_TRC 0x00000001
+#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000
+#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000
+#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000
+#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000
+
+#define FM_PCD_PLCR_NIA_VALID 0x80000000
+
+#define FM_PCD_PLCR_GCR_EN 0x80000000
+#define FM_PCD_PLCR_GCR_STEN 0x40000000
+#define FM_PCD_PLCR_GCR_DAR 0x20000000
+#define FM_PCD_PLCR_GCR_DEFNIA 0x00FFFFFF
+#define FM_PCD_PLCR_NIA_ABS 0x00000100
+
+#define FM_PCD_PLCR_GSR_BSY 0x80000000
+#define FM_PCD_PLCR_GSR_DQS 0x60000000
+#define FM_PCD_PLCR_GSR_RPB 0x20000000
+#define FM_PCD_PLCR_GSR_FQS 0x0C000000
+#define FM_PCD_PLCR_GSR_LPALG 0x0000C000
+#define FM_PCD_PLCR_GSR_LPCA 0x00003000
+#define FM_PCD_PLCR_GSR_LPNUM 0x000000FF
+
+#define FM_PCD_PLCR_EVR_PSIC 0x80000000
+#define FM_PCD_PLCR_EVR_AAC 0x40000000
+
+#define FM_PCD_PLCR_PAR_PSI 0x20000000
+#define FM_PCD_PLCR_PAR_PNUM 0x00FF0000
+/* PWSEL Selctive select options */
+#define FM_PCD_PLCR_PAR_PWSEL_PEMODE 0x00008000 /* 0 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEGNIA 0x00004000 /* 1 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEYNIA 0x00002000 /* 2 */
+#define FM_PCD_PLCR_PAR_PWSEL_PERNIA 0x00001000 /* 3 */
+#define FM_PCD_PLCR_PAR_PWSEL_PECIR 0x00000800 /* 4 */
+#define FM_PCD_PLCR_PAR_PWSEL_PECBS 0x00000400 /* 5 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEPIR_EIR 0x00000200 /* 6 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEPBS_EBS 0x00000100 /* 7 */
+#define FM_PCD_PLCR_PAR_PWSEL_PELTS 0x00000080 /* 8 */
+#define FM_PCD_PLCR_PAR_PWSEL_PECTS 0x00000040 /* 9 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEPTS_ETS 0x00000020 /* 10 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEGPC 0x00000010 /* 11 */
+#define FM_PCD_PLCR_PAR_PWSEL_PEYPC 0x00000008 /* 12 */
+#define FM_PCD_PLCR_PAR_PWSEL_PERPC 0x00000004 /* 13 */
+#define FM_PCD_PLCR_PAR_PWSEL_PERYPC 0x00000002 /* 14 */
+#define FM_PCD_PLCR_PAR_PWSEL_PERRPC 0x00000001 /* 15 */
+
+#define FM_PCD_PLCR_PAR_PMR_BRN_1TO1 0x0000 /* - Full bit replacement. {PBNUM[0:N-1]
+ 1-> 2^N specific locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_2TO2 0x1 /* - {PBNUM[0:N-2],PNUM[N-1]}.
+ 2-> 2^(N-1) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_4TO4 0x2 /* - {PBNUM[0:N-3],PNUM[N-2:N-1]}.
+ 4-> 2^(N-2) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_8TO8 0x3 /* - {PBNUM[0:N-4],PNUM[N-3:N-1]}.
+ 8->2^(N-3) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_16TO16 0x4 /* - {PBNUM[0:N-5],PNUM[N-4:N-1]}.
+ 16-> 2^(N-4) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_32TO32 0x5 /* {PBNUM[0:N-6],PNUM[N-5:N-1]}.
+ 32-> 2^(N-5) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_64TO64 0x6 /* {PBNUM[0:N-7],PNUM[N-6:N-1]}.
+ 64-> 2^(N-6) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_128TO128 0x7 /* {PBNUM[0:N-8],PNUM[N-7:N-1]}.
+ 128-> 2^(N-7) base locations. */
+#define FM_PCD_PLCR_PAR_PMR_BRN_256TO256 0x8 /* - No bit replacement for N=8. {PNUM[N-8:N-1]}.
+ When N=8 this option maps all 256 profiles by the DISPATCH bus into one group. */
+
+#define FM_PCD_PLCR_PMR_V 0x80000000
+#define PLCR_ERR_ECC_CAP 0x80000000
+#define PLCR_ERR_ECC_TYPE_DOUBLE 0x40000000
+#define PLCR_ERR_ECC_PNUM_MASK 0x00000FF0
+#define PLCR_ERR_ECC_OFFSET_MASK 0x0000000F
+
+#define PLCR_ERR_UNINIT_CAP 0x80000000
+#define PLCR_ERR_UNINIT_NUM_MASK 0x000000FF
+#define PLCR_ERR_UNINIT_PID_MASK 0x003f0000
+#define PLCR_ERR_UNINIT_ABSOLUTE_MASK 0x00008000
+
+/* shifts */
+#define PLCR_ERR_ECC_PNUM_SHIFT 4
+#define PLCR_ERR_UNINIT_PID_SHIFT 16
+
+#define FM_PCD_PLCR_PMR_BRN_SHIFT 16
+
+#define PLCR_PORT_WINDOW_SIZE(hardwarePortId)
+
+
+#endif /* __FM_PLCR_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c
new file mode 100644
index 000000000000..ff4f0a2f23cb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_pcd.c
+
+ @Description FM PCD ...
+*//***************************************************************************/
+#include <linux/math64.h>
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "net_ext.h"
+
+#include "fm_common.h"
+#include "fm_pcd.h"
+#include "fm_pcd_ipc.h"
+#include "fm_prs.h"
+#include "fsl_fman_prs.h"
+
+
+static void PcdPrsErrorException(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t event, ev_mask;
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ ev_mask = fman_prs_get_err_ev_mask(PrsRegs);
+
+ event = fman_prs_get_err_event(PrsRegs, ev_mask);
+
+ fman_prs_ack_err_event(PrsRegs, event);
+
+ DBG(TRACE, ("parser error - 0x%08x\n",event));
+
+ if(event & FM_PCD_PRS_DOUBLE_ECC)
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC);
+}
+
+static void PcdPrsException(t_Handle h_FmPcd)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ uint32_t event, ev_mask;
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ ev_mask = fman_prs_get_expt_ev_mask(PrsRegs);
+ event = fman_prs_get_expt_event(PrsRegs, ev_mask);
+
+ ASSERT_COND(event & FM_PCD_PRS_SINGLE_ECC);
+
+ DBG(TRACE, ("parser event - 0x%08x\n",event));
+
+ fman_prs_ack_expt_event(PrsRegs, event);
+
+ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC);
+}
+
+t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams)
+{
+ t_FmPcdPrs *p_FmPcdPrs;
+ uintptr_t baseAddr;
+
+ UNUSED(p_FmPcd);
+ UNUSED(p_FmPcdParams);
+
+ p_FmPcdPrs = (t_FmPcdPrs *) XX_Malloc(sizeof(t_FmPcdPrs));
+ if (!p_FmPcdPrs)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Parser structure allocation FAILED"));
+ return NULL;
+ }
+ memset(p_FmPcdPrs, 0, sizeof(t_FmPcdPrs));
+ fman_prs_defconfig(&p_FmPcd->p_FmPcdDriverParam->dfltCfg);
+
+ if (p_FmPcd->guestId == NCSW_MASTER_ID)
+ {
+ baseAddr = FmGetPcdPrsBaseAddr(p_FmPcdParams->h_Fm);
+ p_FmPcdPrs->p_SwPrsCode = (uint32_t *)UINT_TO_PTR(baseAddr);
+ p_FmPcdPrs->p_FmPcdPrsRegs = (struct fman_prs_regs *)UINT_TO_PTR(baseAddr + PRS_REGS_OFFSET);
+ }
+
+ p_FmPcdPrs->fmPcdPrsPortIdStatistics = p_FmPcd->p_FmPcdDriverParam->dfltCfg.port_id_stat;
+ p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = p_FmPcd->p_FmPcdDriverParam->dfltCfg.max_prs_cyc_lim;
+ p_FmPcd->exceptions |= p_FmPcd->p_FmPcdDriverParam->dfltCfg.prs_exceptions;
+
+ return p_FmPcdPrs;
+}
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ static uint8_t swPrsPatch[] = SW_PRS_UDP_LITE_PATCH;
+#else
+ static uint8_t swPrsPatch[] = SW_PRS_OFFLOAD_PATCH;
+#endif /* FM_CAPWAP_SUPPORT */
+
+t_Error PrsInit(t_FmPcd *p_FmPcd)
+{
+ t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam;
+ uint32_t *p_TmpCode;
+ uint32_t *p_LoadTarget = (uint32_t *)PTR_MOVE(p_FmPcd->p_FmPcdPrs->p_SwPrsCode,
+ FM_PCD_SW_PRS_SIZE-FM_PCD_PRS_SW_PATCHES_SIZE);
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+ uint32_t i;
+
+ ASSERT_COND(sizeof(swPrsPatch) <= (FM_PCD_PRS_SW_PATCHES_SIZE-FM_PCD_PRS_SW_TAIL_SIZE));
+
+ /* nothing to do in guest-partition */
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ return E_OK;
+
+ p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(sizeof(swPrsPatch),4), 0, sizeof(uint32_t));
+ if (!p_TmpCode)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED"));
+ memset((uint8_t *)p_TmpCode, 0, ROUND_UP(sizeof(swPrsPatch),4));
+ memcpy((uint8_t *)p_TmpCode, (uint8_t *)swPrsPatch, sizeof(swPrsPatch));
+
+ fman_prs_init(PrsRegs, &p_Param->dfltCfg);
+
+ /* register even if no interrupts enabled, to allow future enablement */
+ FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR, PcdPrsErrorException, p_FmPcd);
+
+ /* register even if no interrupts enabled, to allow future enablement */
+ FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL, PcdPrsException, p_FmPcd);
+
+ if(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC)
+ FmEnableRamsEcc(p_FmPcd->h_Fm);
+
+ if(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)
+ FmEnableRamsEcc(p_FmPcd->h_Fm);
+
+ /* load sw parser Ip-Frag patch */
+ for (i=0; i<DIV_CEIL(sizeof(swPrsPatch), 4); i++)
+ WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i]));
+
+ XX_FreeSmart(p_TmpCode);
+
+ return E_OK;
+}
+
+void PrsFree(t_FmPcd *p_FmPcd)
+{
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR);
+ /* register even if no interrupts enabled, to allow future enablement */
+ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL);
+}
+
+void PrsEnable(t_FmPcd *p_FmPcd)
+{
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ fman_prs_enable(PrsRegs);
+}
+
+void PrsDisable(t_FmPcd *p_FmPcd)
+{
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ fman_prs_disable(PrsRegs);
+}
+
+int PrsIsEnabled(t_FmPcd *p_FmPcd)
+{
+ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID);
+ return fman_prs_is_enabled(PrsRegs);
+}
+
+t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include)
+{
+ struct fman_prs_regs *PrsRegs;
+ uint32_t bitMask = 0;
+ uint8_t prsPortId;
+
+ SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
+
+ PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+ GET_FM_PCD_PRS_PORT_ID(prsPortId, hardwarePortId);
+ GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId);
+
+ if (include)
+ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics |= bitMask;
+ else
+ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics &= ~bitMask;
+
+ fman_prs_set_stst_port_msk(PrsRegs,
+ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics);
+
+ return E_OK;
+}
+
+t_Error FmPcdPrsIncludePortInStatistics(t_Handle h_FmPcd, uint8_t hardwarePortId, bool include)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_FmPcdIpcPrsIncludePort prsIncludePortParams;
+ t_FmPcdIpcMsg msg;
+
+ prsIncludePortParams.hardwarePortId = hardwarePortId;
+ prsIncludePortParams.include = include;
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_PCD_PRS_INC_PORT_STATS;
+ memcpy(msg.msgBody, &prsIncludePortParams, sizeof(prsIncludePortParams));
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(prsIncludePortParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ return PrsIncludePortInStatistics(p_FmPcd, hardwarePortId, include);
+}
+
+uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
+ t_FmPcdPrsLabelParams *p_Label;
+ int i;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE, 0);
+
+ if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
+ p_FmPcd->h_IpcSession)
+ {
+ t_Error err = E_OK;
+ t_FmPcdIpcSwPrsLable labelParams;
+ t_FmPcdIpcMsg msg;
+ uint32_t prsOffset = 0;
+ t_FmPcdIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&reply, 0, sizeof(reply));
+ memset(&msg, 0, sizeof(msg));
+ labelParams.enumHdr = (uint32_t)hdr;
+ labelParams.indexPerHdr = indexPerHdr;
+ msg.msgId = FM_PCD_GET_SW_PRS_OFFSET;
+ memcpy(msg.msgBody, &labelParams, sizeof(labelParams));
+ replyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(labelParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t) + sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+
+ memcpy((uint8_t*)&prsOffset, reply.replyBody, sizeof(uint32_t));
+ return prsOffset;
+ }
+ else if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ ASSERT_COND(p_FmPcd->p_FmPcdPrs->currLabel < FM_PCD_PRS_NUM_OF_LABELS);
+
+ for (i=0; i<p_FmPcd->p_FmPcdPrs->currLabel; i++)
+ {
+ p_Label = &p_FmPcd->p_FmPcdPrs->labelsTable[i];
+
+ if ((hdr == p_Label->hdr) && (indexPerHdr == p_Label->indexPerHdr))
+ return p_Label->instructionOffset;
+ }
+
+ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Sw Parser attachment Not found"));
+ return (uint32_t)ILLEGAL_BASE;
+}
+
+void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ struct fman_prs_regs *PrsRegs;
+
+ SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE);
+
+ PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs;
+
+
+ if(p_FmPcd->guestId != NCSW_MASTER_ID)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPrsStatistics - guest mode!"));
+ return;
+ }
+
+ fman_prs_set_stst(PrsRegs, enable);
+}
+
+t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+ uint32_t *p_LoadTarget;
+ uint32_t *p_TmpCode;
+ int i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_SwPrs, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_HANDLE);
+
+ if (p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode!"));
+
+ if (!p_SwPrs->override)
+ {
+ if(p_FmPcd->p_FmPcdPrs->p_CurrSwPrs > p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SW parser base must be larger than current loaded code"));
+ }
+ else
+ p_FmPcd->p_FmPcdPrs->currLabel = 0;
+
+ if (p_SwPrs->size > FM_PCD_SW_PRS_SIZE - FM_PCD_PRS_SW_TAIL_SIZE - p_SwPrs->base*2)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size may not be larger than MAX_SW_PRS_CODE_SIZE"));
+
+ if (p_FmPcd->p_FmPcdPrs->currLabel + p_SwPrs->numOfLabels > FM_PCD_PRS_NUM_OF_LABELS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceeded number of labels allowed "));
+
+ p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(p_SwPrs->size,4), 0, sizeof(uint32_t));
+ if (!p_TmpCode)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED"));
+ memset((uint8_t *)p_TmpCode, 0, ROUND_UP(p_SwPrs->size,4));
+ memcpy((uint8_t *)p_TmpCode, p_SwPrs->p_Code, p_SwPrs->size);
+
+ /* save sw parser labels */
+ memcpy(&p_FmPcd->p_FmPcdPrs->labelsTable[p_FmPcd->p_FmPcdPrs->currLabel],
+ p_SwPrs->labelsTable,
+ p_SwPrs->numOfLabels*sizeof(t_FmPcdPrsLabelParams));
+ p_FmPcd->p_FmPcdPrs->currLabel += p_SwPrs->numOfLabels;
+
+ /* load sw parser code */
+ p_LoadTarget = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4;
+
+ for(i=0; i<DIV_CEIL(p_SwPrs->size, 4); i++)
+ WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i]));
+
+ p_FmPcd->p_FmPcdPrs->p_CurrSwPrs =
+ p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4 + ROUND_UP(p_SwPrs->size,4);
+
+ /* copy data parameters */
+ for (i=0;i<FM_PCD_PRS_NUM_OF_HDRS;i++)
+ WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+PRS_SW_DATA/4+i), p_SwPrs->swPrsDataParams[i]);
+
+ /* Clear last 4 bytes */
+ WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+(PRS_SW_DATA-FM_PCD_PRS_SW_TAIL_SIZE)/4), 0);
+
+ XX_FreeSmart(p_TmpCode);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value)
+{
+ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
+
+ if(p_FmPcd->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPrsMaxCycleLimit - guest mode!"));
+
+ p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = value;
+
+ return E_OK;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h
new file mode 100644
index 000000000000..056f225ef221
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_prs.h
+
+ @Description FM Parser private header
+ *//***************************************************************************/
+#ifndef __FM_PRS_H
+#define __FM_PRS_H
+
+#include "std_ext.h"
+
+/***********************************************************************/
+/* SW parser IP_FRAG patch */
+/***********************************************************************/
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+#define SW_PRS_UDP_LITE_PATCH \
+{\
+ 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x50,0x2C,0x40,0x00,0x31,0x92,0x50,0x2C, \
+ 0x00,0x88,0x18,0x2F,0x00,0x01,0x1B,0xFE,0x18,0x71, \
+ 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \
+ 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x60,0x4F, \
+ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
+ 0x00,0x01,0x07,0x01,0x60,0x3B,0x00,0x00,0x30,0xD0, \
+ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x40,0x4C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
+ 0x00,0x06,0x18,0x5D,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
+ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
+ 0x00,0x08,0x28,0x1A,0x60,0x37,0x00,0x00,0x30,0xF2, \
+ 0x18,0x5D,0x06,0x00,0x29,0x1E,0x30,0xF2,0x2F,0x0E, \
+ 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x2F,0x0E, \
+ 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \
+ 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \
+ 0x2F,0x0E,0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80, \
+ 0x00,0x02,0x00,0x00,0x97,0x9E,0x40,0x7E,0x00,0x08, \
+ 0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE,0x00,0x00, \
+ 0x9F,0x9E,0x40,0xB3,0x00,0x00,0x02,0x1F,0x00,0x08, \
+ 0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0,0x60,0x9F, \
+ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
+ 0x00,0x01,0x07,0x01,0x60,0x8B,0x00,0x00,0x30,0xD0, \
+ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x40,0x9C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
+ 0x00,0x06,0x18,0xAD,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
+ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
+ 0x00,0x08,0x28,0x1A,0x60,0x87,0x00,0x00,0x30,0xF2, \
+ 0x18,0xAD,0x06,0x00,0x29,0x1E,0x30,0xF2,0x50,0xB3, \
+ 0xFF,0xFF,0x18,0xB8,0x08,0x16,0x00,0x54,0x00,0x01, \
+ 0x1B,0xFE,0x18,0xC5,0x32,0xF1,0x28,0x5D,0x32,0xF1, \
+ 0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00,0x8F,0x9F, \
+ 0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01,0x1B,0xFF, \
+ 0x00,0x01,0x1B,0xFF \
+}
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+#if (DPAA_VERSION == 10)
+/* Version: 106.1.9 */
+#define SW_PRS_OFFLOAD_PATCH \
+{ \
+ 0x31,0x52,0x00,0xDA,0x0A,0x00,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x43,0x0A,0x00,0x00,0x00,0x01,0x1B,0xFE, \
+ 0x00,0x00,0x99,0x00,0x53,0x13,0x00,0x00,0x00,0x00, \
+ 0x9F,0x98,0x53,0x13,0x00,0x00,0x1B,0x23,0x33,0xF1, \
+ 0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x01, \
+ 0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80,0x1F,0xFF, \
+ 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x06,0x00, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x2F,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x00,0x40, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x00,0x00, \
+ 0x00,0x00,0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55, \
+ 0x00,0x28,0x28,0x43,0x30,0x7E,0x43,0x45,0x00,0x00, \
+ 0x30,0x7E,0x43,0x45,0x00,0x3C,0x1B,0x5D,0x32,0x11, \
+ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x83,0x8F, \
+ 0x2F,0x0F,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
+ 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \
+ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
+ 0x28,0x43,0x06,0x00,0x1B,0x3E,0x30,0x7E,0x53,0x79, \
+ 0x00,0x2B,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \
+ 0x00,0x00,0x87,0x8F,0x28,0x23,0x06,0x00,0x32,0x11, \
+ 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \
+ 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \
+ 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x00,0x01, \
+ 0x1B,0xFE,0x00,0x00,0x9B,0x8E,0x53,0x90,0x00,0x00, \
+ 0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23,0x06,0x00, \
+ 0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28,0x00,0x00, \
+ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
+ 0x28,0x43,0x06,0x00,0x00,0x01,0x1B,0xFE,0x32,0xC1, \
+ 0x00,0x55,0x00,0x28,0x28,0x43,0x1B,0xCF,0x00,0x00, \
+ 0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55,0x00,0x28, \
+ 0x28,0x43,0x30,0x7E,0x43,0xBF,0x00,0x2C,0x32,0x11, \
+ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \
+ 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
+ 0x00,0x81,0x00,0x00,0x83,0x8F,0x2F,0x0F,0x06,0x00, \
+ 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01, \
+ 0x00,0x81,0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50, \
+ 0x00,0x01,0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00, \
+ 0x1B,0x9C,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \
+ 0x00,0x00,0x00,0x01,0x32,0xC1,0x32,0xF0,0x00,0x4A, \
+ 0x00,0x80,0x1F,0xFF,0x00,0x01,0x1B,0xFE, \
+}
+
+#else
+#define SW_PRS_OFFLOAD_PATCH \
+{ \
+ 0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x51,0x16,0x08,0x4B,0x31,0x53,0x00,0xFB, \
+ 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x2B, \
+ 0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA,0x0A,0x00, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x20,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFE,0x00,0x00,0x99,0x00,0x51,0x29, \
+ 0x00,0x00,0x00,0x00,0x9F,0x98,0x51,0x29,0x00,0x00, \
+ 0x19,0x44,0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F, \
+ 0x00,0x20,0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00, \
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3, \
+ 0x29,0x8F,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \
+ 0x00,0x00,0x00,0x01,0x1B,0xFE,0x00,0x01,0x1B,0xFE, \
+ 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x51,0x52,0x40,0x00,0x31,0x92,0x51,0x52, \
+ 0x00,0x88,0x19,0x55,0x08,0x05,0x00,0x00,0x19,0x99, \
+ 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \
+ 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x61,0x75, \
+ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \
+ 0x00,0x01,0x07,0x01,0x61,0x61,0x00,0x00,0x30,0xD0, \
+ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x41,0x72,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \
+ 0x00,0x06,0x19,0x83,0x00,0x00,0x9F,0xFF,0x30,0xF2, \
+ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \
+ 0x00,0x08,0x28,0x1A,0x61,0x5D,0x00,0x00,0x30,0xF2, \
+ 0x19,0x83,0x06,0x00,0x29,0x1E,0x30,0xF2,0x29,0x0E, \
+ 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x29,0x0E, \
+ 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \
+ 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \
+ 0x29,0x0E,0x08,0x05,0x00,0x01,0x31,0x52,0x00,0xDA, \
+ 0x0E,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xAF, \
+ 0x04,0x4B,0x31,0x53,0x00,0xFB,0xFF,0xF0,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x29,0x2B,0x33,0xF1,0x00,0xFB, \
+ 0x00,0xDF,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7F, \
+ 0x31,0x52,0x00,0xDA,0x06,0x00,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x41,0xB9,0x00,0x00,0x00,0x01,0x1B,0xFE, \
+ 0x31,0x52,0x00,0xDA,0x00,0x40,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x42,0x06,0x00,0x00,0x00,0x00,0x9B,0x8F, \
+ 0x28,0x01,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \
+ 0x30,0x00,0x41,0xEB,0x00,0x2C,0x32,0x11,0x32,0xC0, \
+ 0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F,0x28,0x23, \
+ 0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \
+ 0x00,0x00,0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11, \
+ 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \
+ 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \
+ 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x19,0xC8, \
+ 0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F,0x00,0x20, \
+ 0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00,0x01,0x00, \
+ 0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3,0x29,0x8F, \
+ 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFE,0x30,0x50,0x52,0x0B,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \
+ 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x42,0x18, \
+ 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \
+ 0x00,0x00,0x9F,0x9E,0x42,0x4D,0x00,0x00,0x02,0x1F, \
+ 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \
+ 0x62,0x39,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \
+ 0x00,0x52,0x00,0x01,0x07,0x01,0x62,0x25,0x00,0x00, \
+ 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x42,0x36,0x00,0x00,0x02,0x8F,0x00,0x00, \
+ 0x30,0xF2,0x00,0x06,0x1A,0x47,0x00,0x00,0x9F,0xFF, \
+ 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \
+ 0x00,0x52,0x00,0x08,0x28,0x1A,0x62,0x21,0x00,0x00, \
+ 0x30,0xF2,0x1A,0x47,0x06,0x00,0x29,0x1E,0x30,0xF2, \
+ 0x52,0x4D,0xFF,0xFF,0x1A,0x52,0x08,0x16,0x00,0x54, \
+ 0x00,0x01,0x1B,0xFE,0x1A,0x5F,0x32,0xF1,0x28,0x5D, \
+ 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \
+ 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \
+ 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x31,0x52,0x00,0xDA, \
+ 0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x6D, \
+ 0x40,0x00,0x31,0x92,0x52,0x6D,0x00,0x88,0x1A,0x70, \
+ 0x08,0x05,0x00,0x00,0x1A,0xB4,0x02,0x1F,0x00,0x08, \
+ 0x00,0x83,0x02,0x1F,0x00,0x20,0x28,0x1B,0x00,0x05, \
+ 0x29,0x1F,0x30,0xD0,0x62,0x90,0x00,0x07,0x00,0x05, \
+ 0x00,0x00,0xC3,0x8F,0x00,0x52,0x00,0x01,0x07,0x01, \
+ 0x62,0x7C,0x00,0x00,0x30,0xD0,0x00,0xDA,0x00,0x01, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x8D,0x00,0x00, \
+ 0x02,0x8F,0x00,0x00,0x30,0xF2,0x00,0x06,0x1A,0x9E, \
+ 0x00,0x00,0x9F,0xFF,0x30,0xF2,0x00,0x06,0x29,0x1E, \
+ 0x07,0x08,0x30,0xD0,0x00,0x52,0x00,0x08,0x28,0x1A, \
+ 0x62,0x78,0x00,0x00,0x30,0xF2,0x1A,0x9E,0x06,0x00, \
+ 0x29,0x1E,0x30,0xF2,0x29,0x0E,0x30,0x72,0x00,0x00, \
+ 0x9B,0x8F,0x00,0x06,0x29,0x0E,0x32,0xF1,0x32,0xB0, \
+ 0x00,0x4F,0x00,0x57,0x00,0x28,0x00,0x00,0x97,0x9E, \
+ 0x00,0x4E,0x30,0x72,0x00,0x06,0x29,0x0E,0x08,0x05, \
+ 0x00,0x01,0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x52,0xCA,0x04,0x4B,0x31,0x53, \
+ 0x00,0xFB,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x29,0x2B,0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA, \
+ 0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xD4, \
+ 0x00,0x00,0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA, \
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x37, \
+ 0x00,0x00,0x00,0x00,0x9B,0x8F,0x28,0x01,0x32,0xC1, \
+ 0x00,0x55,0x00,0x28,0x28,0x43,0x30,0x00,0x42,0xEA, \
+ 0x00,0x00,0x30,0x00,0x42,0xEA,0x00,0x3C,0x1B,0x02, \
+ 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00, \
+ 0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11,0x32,0xC0, \
+ 0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11, \
+ 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \
+ 0x00,0x4D,0x28,0x43,0x06,0x00,0x1A,0xE3,0x30,0x00, \
+ 0x43,0x20,0x00,0x2B,0x00,0x00,0x9B,0x8E,0x43,0x0E, \
+ 0x00,0x00,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \
+ 0x1B,0x1F,0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23, \
+ 0x06,0x00,0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28, \
+ 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \
+ 0x00,0x4D,0x28,0x43,0x06,0x00,0x1B,0x37,0x32,0x11, \
+ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \
+ 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \
+ 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \
+ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \
+ 0x28,0x43,0x06,0x00,0x30,0x50,0x53,0x3C,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \
+ 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x43,0x49, \
+ 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \
+ 0x00,0x00,0x9F,0x9E,0x43,0x7E,0x00,0x00,0x02,0x1F, \
+ 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \
+ 0x63,0x6A,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \
+ 0x00,0x52,0x00,0x01,0x07,0x01,0x63,0x56,0x00,0x00, \
+ 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x43,0x67,0x00,0x00,0x02,0x8F,0x00,0x00, \
+ 0x30,0xF2,0x00,0x06,0x1B,0x78,0x00,0x00,0x9F,0xFF, \
+ 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \
+ 0x00,0x52,0x00,0x08,0x28,0x1A,0x63,0x52,0x00,0x00, \
+ 0x30,0xF2,0x1B,0x78,0x06,0x00,0x29,0x1E,0x30,0xF2, \
+ 0x53,0x7E,0xFF,0xFF,0x1B,0x83,0x08,0x16,0x00,0x54, \
+ 0x00,0x01,0x1B,0xFE,0x1B,0x90,0x32,0xF1,0x28,0x5D, \
+ 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \
+ 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \
+ 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x08,0x07,0x00,0x02, \
+ 0x00,0x00,0x8D,0x80,0x53,0x9C,0x00,0x01,0x30,0x71, \
+ 0x00,0x55,0x00,0x01,0x28,0x0F,0x00,0x00,0x8D,0x00, \
+ 0x53,0xA4,0x00,0x01,0x30,0x71,0x00,0x55,0x00,0x01, \
+ 0x28,0x0F,0x00,0x00,0x83,0x8E,0x53,0xB9,0x00,0x00, \
+ 0x00,0x00,0x86,0x08,0x30,0x71,0x00,0x7B,0x03,0xB9, \
+ 0x33,0xB4,0x00,0xDA,0xFF,0xFF,0x00,0x0F,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x86,0x09,0x01,0x03,0x00,0x7D, \
+ 0x03,0xB9,0x1B,0xC8,0x33,0xD1,0x00,0xF9,0x00,0x10, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7B,0x09,0x5F, \
+ 0x00,0x1A,0x00,0x00,0x09,0x4F,0x00,0x1A,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFF,0x00,0x00,0x8C,0x00,0x53,0xF0, \
+ 0x00,0x01,0x34,0xF5,0x00,0xFB,0xFF,0xFF,0x00,0x7F, \
+ 0x00,0x00,0x00,0x00,0x2A,0x9F,0x00,0x00,0x93,0x8F, \
+ 0x28,0x49,0x00,0x00,0x97,0x8F,0x28,0x4B,0x34,0x61, \
+ 0x28,0x4D,0x34,0x71,0x28,0x4F,0x34,0xB7,0x00,0xF9, \
+ 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97, \
+ 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \
+ 0x00,0x01,0x1B,0xFF,0x00,0x01,0x1B,0xFF, \
+}
+#endif /* (DPAA_VERSION == 10) */
+
+/****************************/
+/* Parser defines */
+/****************************/
+#define FM_PCD_PRS_SW_TAIL_SIZE 4 /**< Number of bytes that must be cleared at
+ the end of the SW parser area */
+
+/* masks */
+#define PRS_ERR_CAP 0x80000000
+#define PRS_ERR_TYPE_DOUBLE 0x40000000
+#define PRS_ERR_SINGLE_ECC_CNT_MASK 0x00FF0000
+#define PRS_ERR_ADDR_MASK 0x000001FF
+
+/* others */
+#define PRS_MAX_CYCLE_LIMIT 8191
+#define PRS_SW_DATA 0x00000800
+#define PRS_REGS_OFFSET 0x00000840
+
+#define GET_FM_PCD_PRS_PORT_ID(prsPortId,hardwarePortId) \
+ prsPortId = (uint8_t)(hardwarePortId & 0x0f)
+
+#define GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId) \
+ bitMask = 0x80000000>>prsPortId
+
+#endif /* __FM_PRS_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c
new file mode 100644
index 000000000000..ee82f73014b6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_replic.c
+
+ @Description FM frame replicator
+*//***************************************************************************/
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_muram_ext.h"
+#include "fm_common.h"
+#include "fm_hc.h"
+#include "fm_replic.h"
+#include "fm_cc.h"
+#include "list_ext.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+static uint8_t GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ uint32_t memberIndex,
+ bool isAddOperation)
+{
+ uint8_t memberPosition;
+ uint32_t lastMemberIndex;
+
+ ASSERT_COND(p_ReplicGroup);
+
+ /* the last member index is different between add and remove operation -
+ in case of remove - this is exactly the last member index
+ in case of add - this is the last member index + 1 - e.g.
+ if we have 4 members, the index of the actual last member is 3(because the
+ index starts from 0) therefore in order to add a new member as the last
+ member we shall use memberIndex = 4 and not 3
+ */
+ if (isAddOperation)
+ lastMemberIndex = p_ReplicGroup->numOfEntries;
+ else
+ lastMemberIndex = p_ReplicGroup->numOfEntries-1;
+
+ /* last */
+ if (memberIndex == lastMemberIndex)
+ memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX;
+ else
+ {
+ /* first */
+ if (memberIndex == 0)
+ memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX;
+ else
+ {
+ /* middle */
+ ASSERT_COND(memberIndex < lastMemberIndex);
+ memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX;
+ }
+ }
+ return memberPosition;
+}
+
+static t_Error MemberCheckParams(t_Handle h_FmPcd,
+ t_FmPcdCcNextEngineParams *p_MemberParams)
+{
+ t_Error err;
+
+
+ if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) &&
+ (p_MemberParams->nextEngine != e_FM_PCD_KG) &&
+ (p_MemberParams->nextEngine != e_FM_PCD_PLCR))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer"));
+
+ /* check the regular parameters of the next engine */
+ err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("member next engine parameters"));
+
+ return E_OK;
+}
+
+static t_Error CheckParams(t_Handle h_FmPcd,
+ t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
+{
+ int i;
+ t_Error err;
+
+ /* check that max num of entries is at least 2 */
+ if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES))
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
+
+ /* check that number of entries is greater than zero */
+ if (!p_ReplicGroupParam->numOfEntries)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero"));
+
+ /* check that max num of entries is equal or greater than number of entries */
+ if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries"));
+
+ for (i=0; i<p_ReplicGroupParam->numOfEntries; i++)
+ {
+ err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("member check parameters"));
+ }
+ return E_OK;
+}
+
+static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
+{
+ t_FmPcdFrmReplicMember *p_ReplicMember = NULL;
+ t_List *p_Next;
+
+ if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList))
+ {
+ p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList);
+ p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node);
+ ASSERT_COND(p_ReplicMember);
+ LIST_DelAndInit(p_Next);
+ }
+ return p_ReplicMember;
+}
+
+static void PutAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_ReplicMember)
+{
+ LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList);
+}
+
+static void AddMemberToList(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_CurrentMember,
+ t_List *p_ListHead)
+{
+ LIST_Add(&p_CurrentMember->node, p_ListHead);
+
+ p_ReplicGroup->numOfEntries++;
+}
+
+static void RemoveMemberFromList(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_CurrentMember)
+{
+ ASSERT_COND(p_ReplicGroup->numOfEntries);
+ LIST_DelAndInit(&p_CurrentMember->node);
+ p_ReplicGroup->numOfEntries--;
+}
+
+static void LinkSourceToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_AdOfTypeContLookup *p_SourceTd,
+ t_FmPcdFrmReplicMember *p_ReplicMember)
+{
+ t_FmPcd *p_FmPcd;
+
+ ASSERT_COND(p_SourceTd);
+ ASSERT_COND(p_ReplicMember);
+ ASSERT_COND(p_ReplicGroup);
+ ASSERT_COND(p_ReplicGroup->h_FmPcd);
+
+ /* Link the first member in the group to the source TD */
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+
+ WRITE_UINT32(p_SourceTd->matchTblPtr,
+ (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) -
+ p_FmPcd->physicalMuramBase));
+}
+
+static void LinkMemberToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_CurrentMember,
+ t_FmPcdFrmReplicMember *p_NextMember)
+{
+ t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd;
+ t_AdOfTypeResult *p_NextReplicAd = NULL;
+ t_FmPcd *p_FmPcd;
+ uint32_t offset = 0;
+
+ /* Check if the next member exists or it's NULL (- means that this is the last member) */
+ if (p_NextMember)
+ {
+ p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd;
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+ offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase));
+ offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT);
+ }
+
+ /* link the current AD to point to the AD of the next member */
+ WRITE_UINT32(p_CurrReplicAd->res, offset);
+}
+
+static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ void *p_OldDescriptor,
+ void *p_NewDescriptor)
+{
+ t_Handle h_Hc;
+ t_Error err;
+ t_FmPcd *p_FmPcd;
+
+ ASSERT_COND(p_ReplicGroup);
+ ASSERT_COND(p_ReplicGroup->h_FmPcd);
+ ASSERT_COND(p_OldDescriptor);
+ ASSERT_COND(p_NewDescriptor);
+
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+ h_Hc = FmPcdGetHcHandle(p_FmPcd);
+ if (!h_Hc)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command"));
+
+ err = FmHcPcdCcDoDynamicChange(h_Hc,
+ (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase),
+ (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase));
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Dynamic change host command"));
+
+ return E_OK;
+}
+
+static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last)
+{
+ t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd;
+ uint32_t tmp;
+
+ tmp = GET_UINT32(p_CurrReplicAd->plcrProfile);
+ if (last)
+ /* clear the NL bit in case it's the last member in the group*/
+ WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT));
+ else
+ /* set the NL bit in case it's not the last member in the group */
+ WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT));
+
+ /* set FR bit in the action descriptor */
+ tmp = GET_UINT32(p_CurrReplicAd->nia);
+ WRITE_UINT32(p_CurrReplicAd->nia,
+ (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE ));
+}
+
+static void BuildSourceTd(void *p_Ad)
+{
+ t_AdOfTypeContLookup *p_SourceTd;
+
+ ASSERT_COND(p_Ad);
+
+ p_SourceTd = (t_AdOfTypeContLookup *)p_Ad;
+
+ IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* initialize the source table descriptor */
+ WRITE_UINT32(p_SourceTd->ccAdBase, FM_PCD_AD_CONT_LOOKUP_TYPE);
+ WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE);
+}
+
+static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_NextMember,
+ t_FmPcdFrmReplicMember *p_CurrentMember,
+ bool sourceDescriptor,
+ bool last)
+{
+ t_FmPcd *p_FmPcd;
+ t_FmPcdFrmReplicMember shadowMember;
+ t_Error err;
+
+ ASSERT_COND(p_ReplicGroup);
+ ASSERT_COND(p_ReplicGroup->h_FmPcd);
+
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+ ASSERT_COND(p_FmPcd->p_CcShadow);
+
+ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
+ return ERROR_CODE(E_BUSY);
+
+ if (sourceDescriptor)
+ {
+ BuildSourceTd(p_FmPcd->p_CcShadow);
+ LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember);
+
+ /* Modify the source table descriptor according to the prepared shadow descriptor */
+ err = ModifyDescriptor(p_ReplicGroup,
+ p_ReplicGroup->p_SourceTd,
+ p_FmPcd->p_CcShadow/* new prepared source td */);
+
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor"));
+
+ }
+ else
+ {
+ IO2IOCpy32(p_FmPcd->p_CcShadow,
+ p_CurrentMember->p_MemberAd,
+ FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* update the last bit in the shadow ad */
+ FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last);
+
+ shadowMember.p_MemberAd = p_FmPcd->p_CcShadow;
+
+ /* update the next FR member index */
+ LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember);
+
+ /* Modify the next member according to the prepared shadow descriptor */
+ err = ModifyDescriptor(p_ReplicGroup,
+ p_CurrentMember->p_MemberAd,
+ p_FmPcd->p_CcShadow);
+
+ RELEASE_LOCK(p_FmPcd->shadowLock);
+ if (err)
+ RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor"));
+ }
+
+
+ return E_OK;
+}
+
+static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ uint16_t memberIndex)
+{
+ int i=0;
+ t_List *p_Pos;
+ t_FmPcdFrmReplicMember *p_Member = NULL;
+
+ LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList)
+ {
+ if (i == memberIndex)
+ {
+ p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node);
+ return p_Member;
+ }
+ i++;
+ }
+ return p_Member;
+}
+
+static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
+{
+ t_FmPcdFrmReplicMember *p_CurrentMember;
+ t_Handle h_Muram;
+
+ ASSERT_COND(p_ReplicGroup);
+
+ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
+ ASSERT_COND(h_Muram);
+
+ /* Initialize an internal structure of a member to add to the available members list */
+ p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember));
+ if (!p_CurrentMember)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member"));
+
+ memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember));
+
+ /* Allocate the member AD */
+ p_CurrentMember->p_MemberAd =
+ (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram,
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_CurrentMember->p_MemberAd)
+ {
+ XX_Free(p_CurrentMember);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table"));
+ }
+ IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ /* Add the new member to the available members list */
+ LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList));
+
+ return E_OK;
+}
+
+static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdCcNextEngineParams *p_MemberParams,
+ bool last)
+{
+ t_FmPcdFrmReplicMember *p_CurrentMember = NULL;
+
+ ASSERT_COND(p_ReplicGroup);
+
+ /* Get an available member from the internal members list */
+ p_CurrentMember = GetAvailableMember(p_ReplicGroup);
+ if (!p_CurrentMember)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member"));
+ return NULL;
+ }
+ p_CurrentMember->h_Manip = NULL;
+
+ /* clear the Ad of the new member */
+ IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+ INIT_LIST(&p_CurrentMember->node);
+
+ /* Initialize the Ad of the member */
+ NextStepAd(p_CurrentMember->p_MemberAd,
+ NULL,
+ p_MemberParams,
+ p_ReplicGroup->h_FmPcd);
+
+ /* save Manip handle (for free needs) */
+ if (p_MemberParams->h_Manip)
+ p_CurrentMember->h_Manip = p_MemberParams->h_Manip;
+
+ /* Initialize the relevant frame replicator fields in the AD */
+ FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last);
+
+ return p_CurrentMember;
+}
+
+static void FreeMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ t_FmPcdFrmReplicMember *p_Member)
+{
+ /* Note: Can't free the member AD just returns the member to the available
+ member list - therefore only memset the AD */
+
+ /* zero the AD */
+ IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
+
+
+ /* return the member to the available members list */
+ PutAvailableMember(p_ReplicGroup, p_Member);
+}
+
+static t_Error RemoveMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,
+ uint16_t memberIndex)
+{
+ t_FmPcd *p_FmPcd = NULL;
+ t_FmPcdFrmReplicMember *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL;
+ t_Error err;
+ uint8_t memberPosition;
+
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+ ASSERT_COND(p_FmPcd);
+ UNUSED(p_FmPcd);
+
+ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
+ ASSERT_COND(p_CurrentMember);
+
+ /* determine the member position in the group */
+ memberPosition = GetMemberPosition(p_ReplicGroup,
+ memberIndex,
+ FALSE/*remove operation*/);
+
+ switch (memberPosition)
+ {
+ case FRM_REPLIC_FIRST_MEMBER_INDEX:
+ p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
+ ASSERT_COND(p_NextMember);
+
+ /* update the source td itself by using a host command */
+ err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
+ p_NextMember,
+ NULL,
+ TRUE/*sourceDescriptor*/,
+ FALSE/*last*/);
+ break;
+
+ case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
+ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
+ ASSERT_COND(p_PreviousMember);
+
+ p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
+ ASSERT_COND(p_NextMember);
+
+ err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
+ p_NextMember,
+ p_PreviousMember,
+ FALSE/*sourceDescriptor*/,
+ FALSE/*last*/);
+
+ break;
+
+ case FRM_REPLIC_LAST_MEMBER_INDEX:
+ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
+ ASSERT_COND(p_PreviousMember);
+
+ err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
+ NULL,
+ p_PreviousMember,
+ FALSE/*sourceDescriptor*/,
+ TRUE/*last*/);
+ break;
+
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member"));
+ }
+
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (p_CurrentMember->h_Manip)
+ {
+ FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
+ p_CurrentMember->h_Manip = NULL;
+ }
+
+ /* remove the member from the driver internal members list */
+ RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
+
+ /* return the member to the available members list */
+ FreeMember(p_ReplicGroup, p_CurrentMember);
+
+ return E_OK;
+}
+
+static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup)
+{
+ int i, j;
+ t_Handle h_Muram;
+ t_FmPcdFrmReplicMember *p_Member, *p_CurrentMember;
+
+ if (p_ReplicGroup)
+ {
+ ASSERT_COND(p_ReplicGroup->h_FmPcd);
+ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
+ ASSERT_COND(h_Muram);
+
+ /* free the source table descriptor */
+ if (p_ReplicGroup->p_SourceTd)
+ {
+ FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd);
+ p_ReplicGroup->p_SourceTd = NULL;
+ }
+
+ /* Remove all members from the members linked list (hw and sw) and
+ return the members to the available members list */
+ if (p_ReplicGroup->numOfEntries)
+ {
+ j = p_ReplicGroup->numOfEntries-1;
+
+ /* manually removal of the member because there are no owners of
+ this group */
+ for (i=j; i>=0; i--)
+ {
+ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/);
+ ASSERT_COND(p_CurrentMember);
+
+ if (p_CurrentMember->h_Manip)
+ {
+ FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
+ p_CurrentMember->h_Manip = NULL;
+ }
+
+ /* remove the member from the internal driver members list */
+ RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
+
+ /* return the member to the available members list */
+ FreeMember(p_ReplicGroup, p_CurrentMember);
+ }
+ }
+
+ /* Free members AD */
+ for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
+ {
+ p_Member = GetAvailableMember(p_ReplicGroup);
+ ASSERT_COND(p_Member);
+ if (p_Member->p_MemberAd)
+ {
+ FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd);
+ p_Member->p_MemberAd = NULL;
+ }
+ XX_Free(p_Member);
+ }
+
+ /* release the group lock */
+ if (p_ReplicGroup->p_Lock)
+ FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock);
+
+ /* free the replicator group */
+ XX_Free(p_ReplicGroup);
+ }
+}
+
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+
+/* NOTE: the inter-module routines are locked by cc in case of using them */
+void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+ ASSERT_COND(p_ReplicGroup);
+
+ return (p_ReplicGroup->p_SourceTd);
+}
+
+void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup,
+ void *p_Ad,
+ t_Handle *h_AdNew)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+ t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad;
+ t_FmPcd *p_FmPcd;
+
+ ASSERT_COND(p_ReplicGroup);
+ p_FmPcd = p_ReplicGroup->h_FmPcd;
+
+ /* build a bypass ad */
+ WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE |
+ (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase));
+
+ *h_AdNew = NULL;
+}
+
+void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup,
+ bool add)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+ ASSERT_COND(p_ReplicGroup);
+
+ /* update the group owner counter */
+ if (add)
+ p_ReplicGroup->owners++;
+ else
+ {
+ ASSERT_COND(p_ReplicGroup->owners);
+ p_ReplicGroup->owners--;
+ }
+}
+
+t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+
+ ASSERT_COND(h_ReplicGroup);
+
+ if (FmPcdLockTryLock(p_ReplicGroup->p_Lock))
+ return E_OK;
+
+ return ERROR_CODE(E_BUSY);
+}
+
+void FrmReplicGroupUnlock(t_Handle h_ReplicGroup)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+
+ ASSERT_COND(h_ReplicGroup);
+
+ FmPcdLockUnlock(p_ReplicGroup->p_Lock);
+}
+/*********************** End of inter-module routines ************************/
+
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd,
+ t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup;
+ t_FmPcdFrmReplicMember *p_CurrentMember, *p_NextMember = NULL;
+ int i;
+ t_Error err;
+ bool last = FALSE;
+ t_Handle h_Muram;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL);
+
+ if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));
+ return NULL;
+ }
+
+ err = CheckParams(h_FmPcd, p_ReplicGroupParam);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, (NO_MSG));
+ return NULL;
+ }
+
+ p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup));
+ if (!p_ReplicGroup)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
+ return NULL;
+ }
+ memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup));
+
+ /* initialize lists for internal driver use */
+ INIT_LIST(&p_ReplicGroup->availableMembersList);
+ INIT_LIST(&p_ReplicGroup->membersList);
+
+ p_ReplicGroup->h_FmPcd = h_FmPcd;
+
+ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
+ ASSERT_COND(h_Muram);
+
+ /* initialize the group lock */
+ p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd);
+ if (!p_ReplicGroup->p_Lock)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock"));
+ DeleteGroup(p_ReplicGroup);
+ return NULL;
+ }
+
+ /* Allocate the frame replicator source table descriptor */
+ p_ReplicGroup->p_SourceTd =
+ (t_Handle)FM_MURAM_AllocMem(h_Muram,
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (!p_ReplicGroup->p_SourceTd)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor"));
+ DeleteGroup(p_ReplicGroup);
+ return NULL;
+ }
+
+ /* update the shadow size - required for the host commands */
+ err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd,
+ FM_PCD_CC_AD_ENTRY_SIZE,
+ FM_PCD_CC_AD_TABLE_ALIGN);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, ("Update CC shadow"));
+ DeleteGroup(p_ReplicGroup);
+ return NULL;
+ }
+
+ p_ReplicGroup->maxNumOfEntries = p_ReplicGroupParam->maxNumOfEntries;
+
+ /* Allocate the maximal number of members ADs and Statistics AD for the group
+ It prevents allocation of Muram in run-time */
+ for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
+ {
+ err = AllocMember(p_ReplicGroup);
+ if (err)
+ {
+ REPORT_ERROR(MAJOR, err, ("allocate a new member"));
+ DeleteGroup(p_ReplicGroup);
+ return NULL;
+ }
+ }
+
+ /* Initialize the members linked lists:
+ (hw - the one that is used by the FMan controller and
+ sw - the one that is managed by the driver internally) */
+ for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--)
+ {
+ /* check if this is the last member in the group */
+ if (i == (p_ReplicGroupParam->numOfEntries-1))
+ last = TRUE;
+ else
+ last = FALSE;
+
+ /* Initialize a new member */
+ p_CurrentMember = InitMember(p_ReplicGroup,
+ &(p_ReplicGroupParam->nextEngineParams[i]),
+ last);
+ if (!p_CurrentMember)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
+ DeleteGroup(p_ReplicGroup);
+ return NULL;
+ }
+
+ /* Build the members group - link two consecutive members in the hw linked list */
+ LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember);
+
+ /* update the driver internal members list to be compatible to the hw members linked list */
+ AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList);
+
+ p_NextMember = p_CurrentMember;
+ }
+
+ /* initialize the source table descriptor */
+ BuildSourceTd(p_ReplicGroup->p_SourceTd);
+
+ /* link the source table descriptor to point to the first member in the group */
+ LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember);
+
+ return p_ReplicGroup;
+}
+
+t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
+
+ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
+
+ if (p_ReplicGroup->owners)
+ RETURN_ERROR(MAJOR,
+ E_INVALID_STATE,
+ ("the group has owners and can't be deleted"));
+
+ DeleteGroup(p_ReplicGroup);
+
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* API Run-time Frame replicator Control unit functions */
+/*****************************************************************************/
+t_Error FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup,
+ uint16_t memberIndex,
+ t_FmPcdCcNextEngineParams *p_MemberParams)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
+ t_FmPcdFrmReplicMember *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL;
+ t_Error err;
+ uint8_t memberPosition;
+
+ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE);
+
+ /* group lock */
+ err = FrmReplicGroupTryLock(p_ReplicGroup);
+ if (GET_ERROR_TYPE(err) == E_BUSY)
+ return ERROR_CODE(E_BUSY);
+
+ if (memberIndex > p_ReplicGroup->numOfEntries)
+ {
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("memberIndex is greater than the members in the list"));
+ }
+
+ if (memberIndex >= p_ReplicGroup->maxNumOfEntries)
+ {
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group"));
+ }
+
+ if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)
+ {
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("numOfEntries with new entry can not be larger than %d\n",
+ FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
+ }
+
+ err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams);
+ if (err)
+ {
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, err, ("member check parameters in add operation"));
+ }
+ /* determine the member position in the group */
+ memberPosition = GetMemberPosition(p_ReplicGroup,
+ memberIndex,
+ TRUE/* add operation */);
+
+ /* Initialize a new member */
+ p_NewMember = InitMember(p_ReplicGroup,
+ p_MemberParams,
+ (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE));
+ if (!p_NewMember)
+ {
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
+ }
+
+ switch (memberPosition)
+ {
+ case FRM_REPLIC_FIRST_MEMBER_INDEX:
+ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
+ ASSERT_COND(p_CurrentMember);
+
+ LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
+
+ /* update the internal group source TD */
+ LinkSourceToMember(p_ReplicGroup,
+ p_ReplicGroup->p_SourceTd,
+ p_NewMember);
+
+ /* add member to the internal sw member list */
+ AddMemberToList(p_ReplicGroup,
+ p_NewMember,
+ &p_ReplicGroup->membersList);
+ break;
+
+ case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
+ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
+ ASSERT_COND(p_CurrentMember);
+
+ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
+ ASSERT_COND(p_PreviousMember);
+
+ LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
+ LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
+
+ AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
+ break;
+
+ case FRM_REPLIC_LAST_MEMBER_INDEX:
+ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
+ ASSERT_COND(p_PreviousMember);
+
+ LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
+ FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/);
+
+ /* add the new member to the internal sw member list */
+ AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
+ break;
+
+ default:
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member"));
+
+ }
+
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+
+ return E_OK;
+}
+
+t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup,
+ uint16_t memberIndex)
+{
+ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
+
+ /* lock */
+ err = FrmReplicGroupTryLock(p_ReplicGroup);
+ if (GET_ERROR_TYPE(err) == E_BUSY)
+ return ERROR_CODE(E_BUSY);
+
+ if (memberIndex >= p_ReplicGroup->numOfEntries)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove"));
+
+ /* Design decision: group must contain at least one member
+ No possibility to remove the last member from the group */
+ if (p_ReplicGroup->numOfEntries == 1)
+ RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group."));
+
+ err = RemoveMember(p_ReplicGroup, memberIndex);
+
+ /* unlock */
+ FrmReplicGroupUnlock(p_ReplicGroup);
+
+ switch (GET_ERROR_TYPE(err))
+ {
+ case E_OK:
+ return E_OK;
+
+ case E_BUSY:
+ DBG(TRACE, ("E_BUSY error"));
+ return ERROR_CODE(E_BUSY);
+
+ default:
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+}
+
+/*********************** End of API routines ************************/
+
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h
new file mode 100644
index 000000000000..0e8e8bc00cb2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_replic.h
+
+ @Description FM frame replicator
+*//***************************************************************************/
+#ifndef __FM_REPLIC_H
+#define __FM_REPLIC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+
+
+#define FRM_REPLIC_SOURCE_TD_OPCODE 0x75
+#define NEXT_FRM_REPLIC_ADDR_SHIFT 4
+#define NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT 16
+#define FRM_REPLIC_FR_BIT 0x08000000
+#define FRM_REPLIC_NL_BIT 0x10000000
+#define FRM_REPLIC_INVALID_MEMBER_INDEX 0xffff
+#define FRM_REPLIC_FIRST_MEMBER_INDEX 0
+
+#define FRM_REPLIC_MIDDLE_MEMBER_INDEX 1
+#define FRM_REPLIC_LAST_MEMBER_INDEX 2
+
+#define SOURCE_TD_ITSELF_OPTION 0x01
+#define SOURCE_TD_COPY_OPTION 0x02
+#define SOURCE_TD_ITSELF_AND_COPY_OPTION SOURCE_TD_ITSELF_OPTION | SOURCE_TD_COPY_OPTION
+#define SOURCE_TD_NONE 0x04
+
+/*typedef enum e_SourceTdOption
+{
+ e_SOURCE_TD_NONE = 0,
+ e_SOURCE_TD_ITSELF_OPTION = 1,
+ e_SOURCE_TD_COPY_OPTION = 2,
+ e_SOURCE_TD_ITSELF_AND_COPY_OPTION = e_SOURCE_TD_ITSELF_OPTION | e_SOURCE_TD_COPY_OPTION
+} e_SourceTdOption;
+*/
+
+typedef struct
+{
+ volatile uint32_t type;
+ volatile uint32_t frGroupPointer;
+ volatile uint32_t operationCode;
+ volatile uint32_t reserved;
+} t_FrmReplicGroupSourceAd;
+
+typedef struct t_FmPcdFrmReplicMember
+{
+ void *p_MemberAd; /**< pointer to the member AD */
+ void *p_StatisticsAd;/**< pointer to the statistics AD of the member */
+ t_Handle h_Manip; /**< manip handle - need for free routines */
+ t_List node;
+} t_FmPcdFrmReplicMember;
+
+typedef struct t_FmPcdFrmReplicGroup
+{
+ t_Handle h_FmPcd;
+
+ uint8_t maxNumOfEntries;/**< maximal number of members in the group */
+ uint8_t numOfEntries; /**< actual number of members in the group */
+ uint16_t owners; /**< how many keys share this frame replicator group */
+ void *p_SourceTd; /**< pointer to the frame replicator source table descriptor */
+ t_List membersList; /**< the members list - should reflect the order of the members as in the hw linked list*/
+ t_List availableMembersList;/**< list of all the available members in the group */
+ t_FmPcdLock *p_Lock;
+} t_FmPcdFrmReplicGroup;
+
+
+#endif /* __FM_REPLIC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
new file mode 100644
index 000000000000..9939a755ab31
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c
@@ -0,0 +1,890 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "fsl_fman_kg.h"
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+
+static uint32_t build_ar_bind_scheme(uint8_t hwport_id, bool write)
+{
+ uint32_t rw;
+
+ rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ rw |
+ FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
+ hwport_id |
+ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
+}
+
+static void clear_pe_all_scheme(struct fman_kg_regs *regs, uint8_t hwport_id)
+{
+ uint32_t ar;
+
+ fman_kg_write_sp(regs, 0xffffffff, 0);
+
+ ar = build_ar_bind_scheme(hwport_id, TRUE);
+ fman_kg_write_ar_wait(regs, ar);
+}
+
+static uint32_t build_ar_bind_cls_plan(uint8_t hwport_id, bool write)
+{
+ uint32_t rw;
+
+ rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ rw |
+ FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
+ hwport_id |
+ FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
+}
+
+static void clear_pe_all_cls_plan(struct fman_kg_regs *regs, uint8_t hwport_id)
+{
+ uint32_t ar;
+
+ fman_kg_write_cpp(regs, 0);
+
+ ar = build_ar_bind_cls_plan(hwport_id, TRUE);
+ fman_kg_write_ar_wait(regs, ar);
+}
+
+static uint8_t get_gen_ht_code(enum fman_kg_gen_extract_src src,
+ bool no_validation,
+ uint8_t *offset)
+{
+ int code;
+
+ switch (src) {
+ case E_FMAN_KG_GEN_EXTRACT_ETH:
+ code = no_validation ? 0x73 : 0x3;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_ETYPE:
+ code = no_validation ? 0x77 : 0x7;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_SNAP:
+ code = no_validation ? 0x74 : 0x4;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1:
+ code = no_validation ? 0x75 : 0x5;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N:
+ code = no_validation ? 0x76 : 0x6;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_PPPoE:
+ code = no_validation ? 0x78 : 0x8;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_MPLS_1:
+ code = no_validation ? 0x79 : 0x9;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_MPLS_2:
+ code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x19;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_MPLS_3:
+ code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x29;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_MPLS_N:
+ code = no_validation ? 0x7a : 0xa;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPv4_1:
+ code = no_validation ? 0x7b : 0xb;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPv6_1:
+ code = no_validation ? 0x7b : 0x1b;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPv4_2:
+ code = no_validation ? 0x7c : 0xc;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPv6_2:
+ code = no_validation ? 0x7c : 0x1c;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_MINENCAP:
+ code = no_validation ? 0x7c : 0x2c;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IP_PID:
+ code = no_validation ? 0x72 : 0x2;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_GRE:
+ code = no_validation ? 0x7d : 0xd;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_TCP:
+ code = no_validation ? 0x7e : 0xe;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_UDP:
+ code = no_validation ? 0x7e : 0x1e;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_SCTP:
+ code = no_validation ? 0x7e : 0x3e;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_DCCP:
+ code = no_validation ? 0x7e : 0x4e;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPSEC_AH:
+ code = no_validation ? 0x7e : 0x2e;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP:
+ code = no_validation ? 0x7e : 0x6e;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_SHIM_1:
+ code = 0x70;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_SHIM_2:
+ code = 0x71;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_FROM_DFLT:
+ code = 0x10;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START:
+ code = 0x40;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT:
+ code = 0x20;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE:
+ code = 0x7f;
+ break;
+
+ case E_FMAN_KG_GEN_EXTRACT_FROM_FQID:
+ code = 0x20;
+ *offset += 0x20;
+ break;
+
+ default:
+ code = FM_KG_SCH_GEN_HT_INVALID;
+ }
+
+ return (uint8_t)code;
+}
+
+static uint32_t build_ar_scheme(uint8_t scheme,
+ uint8_t hwport_id,
+ bool update_counter,
+ bool write)
+{
+ uint32_t rw;
+
+ rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ rw |
+ FM_KG_KGAR_SEL_SCHEME_ENTRY |
+ hwport_id |
+ ((uint32_t)scheme << FM_KG_KGAR_NUM_SHIFT) |
+ (update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0));
+}
+
+static uint32_t build_ar_cls_plan(uint8_t grp,
+ uint8_t entries_mask,
+ uint8_t hwport_id,
+ bool write)
+{
+ uint32_t rw;
+
+ rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
+
+ return (uint32_t)(FM_KG_KGAR_GO |
+ rw |
+ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
+ hwport_id |
+ ((uint32_t)grp << FM_KG_KGAR_NUM_SHIFT) |
+ ((uint32_t)entries_mask << FM_KG_KGAR_WSEL_SHIFT));
+}
+
+int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar)
+{
+ iowrite32be(fmkg_ar, &regs->fmkg_ar);
+ /* Wait for GO to be idle and read error */
+ while ((fmkg_ar = ioread32be(&regs->fmkg_ar)) & FM_KG_KGAR_GO) ;
+ if (fmkg_ar & FM_PCD_KG_KGAR_ERR)
+ return -EINVAL;
+ return 0;
+}
+
+void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add)
+{
+
+ struct fman_kg_pe_regs *kgpe_regs;
+ uint32_t tmp;
+
+ kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
+ tmp = ioread32be(&kgpe_regs->fmkg_pe_sp);
+
+ if (add)
+ tmp |= sp;
+ else /* clear */
+ tmp &= ~sp;
+
+ iowrite32be(tmp, &kgpe_regs->fmkg_pe_sp);
+
+}
+
+void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp)
+{
+ struct fman_kg_pe_regs *kgpe_regs;
+
+ kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
+
+ iowrite32be(cpp, &kgpe_regs->fmkg_pe_cpp);
+}
+
+void fman_kg_get_event(struct fman_kg_regs *regs,
+ uint32_t *event,
+ uint32_t *scheme_idx)
+{
+ uint32_t mask, force;
+
+ *event = ioread32be(&regs->fmkg_eer);
+ mask = ioread32be(&regs->fmkg_eeer);
+ *scheme_idx = ioread32be(&regs->fmkg_seer);
+ *scheme_idx &= ioread32be(&regs->fmkg_seeer);
+
+ *event &= mask;
+
+ /* clear the forced events */
+ force = ioread32be(&regs->fmkg_feer);
+ if (force & *event)
+ iowrite32be(force & ~*event ,&regs->fmkg_feer);
+
+ iowrite32be(*event, &regs->fmkg_eer);
+ iowrite32be(*scheme_idx, &regs->fmkg_seer);
+}
+
+
+void fman_kg_init(struct fman_kg_regs *regs,
+ uint32_t exceptions,
+ uint32_t dflt_nia)
+{
+ uint32_t tmp;
+ int i;
+
+ iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW,
+ &regs->fmkg_eer);
+
+ tmp = 0;
+ if (exceptions & FM_EX_KG_DOUBLE_ECC)
+ tmp |= FM_EX_KG_DOUBLE_ECC;
+
+ if (exceptions & FM_EX_KG_KEYSIZE_OVERFLOW)
+ tmp |= FM_EX_KG_KEYSIZE_OVERFLOW;
+
+ iowrite32be(tmp, &regs->fmkg_eeer);
+ iowrite32be(0, &regs->fmkg_fdor);
+ iowrite32be(0, &regs->fmkg_gdv0r);
+ iowrite32be(0, &regs->fmkg_gdv1r);
+ iowrite32be(dflt_nia, &regs->fmkg_gcr);
+
+ /* Clear binding between ports to schemes and classification plans
+ * so that all ports are not bound to any scheme/classification plan */
+ for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) {
+ clear_pe_all_scheme(regs, (uint8_t)i);
+ clear_pe_all_cls_plan(regs, (uint8_t)i);
+ }
+}
+
+void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs)
+{
+ /* enable and enable all scheme interrupts */
+ iowrite32be(0xFFFFFFFF, &regs->fmkg_seer);
+ iowrite32be(0xFFFFFFFF, &regs->fmkg_seeer);
+}
+
+void fman_kg_enable(struct fman_kg_regs *regs)
+{
+ iowrite32be(ioread32be(&regs->fmkg_gcr) | FM_KG_KGGCR_EN,
+ &regs->fmkg_gcr);
+}
+
+void fman_kg_disable(struct fman_kg_regs *regs)
+{
+ iowrite32be(ioread32be(&regs->fmkg_gcr) & ~FM_KG_KGGCR_EN,
+ &regs->fmkg_gcr);
+}
+
+void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset)
+{
+ iowrite32be(offset, &regs->fmkg_fdor);
+}
+
+void fman_kg_set_dflt_val(struct fman_kg_regs *regs,
+ uint8_t def_id,
+ uint32_t val)
+{
+ if(def_id == 0)
+ iowrite32be(val, &regs->fmkg_gdv0r);
+ else
+ iowrite32be(val, &regs->fmkg_gdv1r);
+}
+
+
+void fman_kg_set_exception(struct fman_kg_regs *regs,
+ uint32_t exception,
+ bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->fmkg_eeer);
+
+ if (enable) {
+ tmp |= exception;
+ } else {
+ tmp &= ~exception;
+ }
+
+ iowrite32be(tmp, &regs->fmkg_eeer);
+}
+
+void fman_kg_get_exception(struct fman_kg_regs *regs,
+ uint32_t *events,
+ uint32_t *scheme_ids,
+ bool clear)
+{
+ uint32_t mask;
+
+ *events = ioread32be(&regs->fmkg_eer);
+ mask = ioread32be(&regs->fmkg_eeer);
+ *events &= mask;
+
+ *scheme_ids = 0;
+
+ if (*events & FM_EX_KG_KEYSIZE_OVERFLOW) {
+ *scheme_ids = ioread32be(&regs->fmkg_seer);
+ mask = ioread32be(&regs->fmkg_seeer);
+ *scheme_ids &= mask;
+ }
+
+ if (clear) {
+ iowrite32be(*scheme_ids, &regs->fmkg_seer);
+ iowrite32be(*events, &regs->fmkg_eer);
+ }
+}
+
+void fman_kg_get_capture(struct fman_kg_regs *regs,
+ struct fman_kg_ex_ecc_attr *ecc_attr,
+ bool clear)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->fmkg_serc);
+
+ if (tmp & KG_FMKG_SERC_CAP) {
+ /* Captured data is valid */
+ ecc_attr->valid = TRUE;
+ ecc_attr->double_ecc =
+ (bool)((tmp & KG_FMKG_SERC_CET) ? TRUE : FALSE);
+ ecc_attr->single_ecc_count =
+ (uint8_t)((tmp & KG_FMKG_SERC_CNT_MSK) >>
+ KG_FMKG_SERC_CNT_SHIFT);
+ ecc_attr->addr = (uint16_t)(tmp & KG_FMKG_SERC_ADDR_MSK);
+
+ if (clear)
+ iowrite32be(KG_FMKG_SERC_CAP, &regs->fmkg_serc);
+ } else {
+ /* No ECC error is captured */
+ ecc_attr->valid = FALSE;
+ }
+}
+
+int fman_kg_build_scheme(struct fman_kg_scheme_params *params,
+ struct fman_kg_scheme_regs *scheme_regs)
+{
+ struct fman_kg_extract_params *extract_params;
+ struct fman_kg_gen_extract_params *gen_params;
+ uint32_t tmp_reg, i, select, mask, fqb;
+ uint8_t offset, shift, ht;
+
+ /* Zero out all registers so no need to care about unused ones */
+ memset(scheme_regs, 0, sizeof(struct fman_kg_scheme_regs));
+
+ /* Mode register */
+ tmp_reg = fm_kg_build_nia(params->next_engine,
+ params->next_engine_action);
+ if (tmp_reg == KG_NIA_INVALID) {
+ return -EINVAL;
+ }
+
+ if (params->next_engine == E_FMAN_PCD_PLCR) {
+ tmp_reg |= FMAN_KG_SCH_MODE_NIA_PLCR;
+ }
+ else if (params->next_engine == E_FMAN_PCD_CC) {
+ tmp_reg |= (uint32_t)params->cc_params.base_offset <<
+ FMAN_KG_SCH_MODE_CCOBASE_SHIFT;
+ }
+
+ tmp_reg |= FMAN_KG_SCH_MODE_EN;
+ scheme_regs->kgse_mode = tmp_reg;
+
+ /* Match vector */
+ scheme_regs->kgse_mv = params->match_vector;
+
+ extract_params = &params->extract_params;
+
+ /* Scheme default values registers */
+ scheme_regs->kgse_dv0 = extract_params->def_scheme_0;
+ scheme_regs->kgse_dv1 = extract_params->def_scheme_1;
+
+ /* Extract Known Fields Command register */
+ scheme_regs->kgse_ekfc = extract_params->known_fields;
+
+ /* Entry Extract Known Default Value register */
+ tmp_reg = 0;
+ tmp_reg |= extract_params->known_fields_def.mac_addr <<
+ FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.vlan_tci <<
+ FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.etype <<
+ FMAN_KG_SCH_DEF_ETYPE_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ppp_sid <<
+ FMAN_KG_SCH_DEF_PPP_SID_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ppp_pid <<
+ FMAN_KG_SCH_DEF_PPP_PID_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.mpls <<
+ FMAN_KG_SCH_DEF_MPLS_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ip_addr <<
+ FMAN_KG_SCH_DEF_IP_ADDR_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ptype <<
+ FMAN_KG_SCH_DEF_PTYPE_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ip_tos_tc <<
+ FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ipv6_fl <<
+ FMAN_KG_SCH_DEF_IPv6_FL_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.ipsec_spi <<
+ FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.l4_port <<
+ FMAN_KG_SCH_DEF_L4_PORT_SHIFT;
+ tmp_reg |= extract_params->known_fields_def.tcp_flg <<
+ FMAN_KG_SCH_DEF_TCP_FLG_SHIFT;
+
+ scheme_regs->kgse_ekdv = tmp_reg;
+
+ /* Generic extract registers */
+ if (extract_params->gen_extract_num > FM_KG_NUM_OF_GENERIC_REGS) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < extract_params->gen_extract_num; i++) {
+ gen_params = extract_params->gen_extract + i;
+
+ tmp_reg = FMAN_KG_SCH_GEN_VALID;
+ tmp_reg |= (uint32_t)gen_params->def_val <<
+ FMAN_KG_SCH_GEN_DEF_SHIFT;
+
+ if (gen_params->type == E_FMAN_KG_HASH_EXTRACT) {
+ if ((gen_params->extract > FMAN_KG_SCH_GEN_SIZE_MAX) ||
+ (gen_params->extract == 0)) {
+ return -EINVAL;
+ }
+ } else {
+ tmp_reg |= FMAN_KG_SCH_GEN_OR;
+ }
+
+ tmp_reg |= (uint32_t)gen_params->extract <<
+ FMAN_KG_SCH_GEN_SIZE_SHIFT;
+ tmp_reg |= (uint32_t)gen_params->mask <<
+ FMAN_KG_SCH_GEN_MASK_SHIFT;
+
+ offset = gen_params->offset;
+ ht = get_gen_ht_code(gen_params->src,
+ gen_params->no_validation,
+ &offset);
+ tmp_reg |= (uint32_t)ht << FMAN_KG_SCH_GEN_HT_SHIFT;
+ tmp_reg |= offset;
+
+ scheme_regs->kgse_gec[i] = tmp_reg;
+ }
+
+ /* Masks registers */
+ if (extract_params->masks_num > FM_KG_EXTRACT_MASKS_NUM) {
+ return -EINVAL;
+ }
+
+ select = 0;
+ mask = 0;
+ fqb = 0;
+ for (i = 0; i < extract_params->masks_num; i++) {
+ /* MCSx fields */
+ KG_GET_MASK_SEL_SHIFT(shift, i);
+ if (extract_params->masks[i].is_known) {
+ /* Mask known field */
+ select |= extract_params->masks[i].field_or_gen_idx <<
+ shift;
+ } else {
+ /* Mask generic extract */
+ select |= (extract_params->masks[i].field_or_gen_idx +
+ FM_KG_MASK_SEL_GEN_BASE) << shift;
+ }
+
+ /* MOx fields - spread between se_bmch and se_fqb registers */
+ KG_GET_MASK_OFFSET_SHIFT(shift, i);
+ if (i < 2) {
+ select |= (uint32_t)extract_params->masks[i].offset <<
+ shift;
+ } else {
+ fqb |= (uint32_t)extract_params->masks[i].offset <<
+ shift;
+ }
+
+ /* BMx fields */
+ KG_GET_MASK_SHIFT(shift, i);
+ mask |= (uint32_t)extract_params->masks[i].mask << shift;
+ }
+
+ /* Finish with rest of BMx fileds -
+ * don't mask bits for unused masks by setting
+ * corresponding BMx field = 0xFF */
+ for (i = extract_params->masks_num; i < FM_KG_EXTRACT_MASKS_NUM; i++) {
+ KG_GET_MASK_SHIFT(shift, i);
+ mask |= 0xFF << shift;
+ }
+
+ scheme_regs->kgse_bmch = select;
+ scheme_regs->kgse_bmcl = mask;
+
+ /* Finish with FQB register initialization.
+ * Check fqid is 24-bit value. */
+ if (params->base_fqid & ~0x00FFFFFF) {
+ return -EINVAL;
+ }
+
+ fqb |= params->base_fqid;
+ scheme_regs->kgse_fqb = fqb;
+
+ /* Hash Configuration register */
+ tmp_reg = 0;
+ if (params->hash_params.use_hash) {
+ /* Check hash mask is 24-bit value */
+ if (params->hash_params.mask & ~0x00FFFFFF) {
+ return -EINVAL;
+ }
+
+ /* Hash function produces 64-bit value, 24 bits of that
+ * are used to generate fq_id and policer profile.
+ * Thus, maximal shift is 40 bits to allow 24 bits out of 64.
+ */
+ if (params->hash_params.shift_r > FMAN_KG_SCH_HASH_HSHIFT_MAX) {
+ return -EINVAL;
+ }
+
+ tmp_reg |= params->hash_params.mask;
+ tmp_reg |= (uint32_t)params->hash_params.shift_r <<
+ FMAN_KG_SCH_HASH_HSHIFT_SHIFT;
+
+ if (params->hash_params.sym) {
+ tmp_reg |= FMAN_KG_SCH_HASH_SYM;
+ }
+
+ }
+
+ if (params->bypass_fqid_gen) {
+ tmp_reg |= FMAN_KG_SCH_HASH_NO_FQID_GEN;
+ }
+
+ scheme_regs->kgse_hc = tmp_reg;
+
+ /* Policer Profile register */
+ if (params->policer_params.bypass_pp_gen) {
+ tmp_reg = 0;
+ } else {
+ /* Lower 8 bits of 24-bits extracted from hash result
+ * are used for policer profile generation.
+ * That leaves maximum shift value = 23. */
+ if (params->policer_params.shift > FMAN_KG_SCH_PP_SHIFT_MAX) {
+ return -EINVAL;
+ }
+
+ tmp_reg = params->policer_params.base;
+ tmp_reg |= ((uint32_t)params->policer_params.shift <<
+ FMAN_KG_SCH_PP_SH_SHIFT) &
+ FMAN_KG_SCH_PP_SH_MASK;
+ tmp_reg |= ((uint32_t)params->policer_params.shift <<
+ FMAN_KG_SCH_PP_SL_SHIFT) &
+ FMAN_KG_SCH_PP_SL_MASK;
+ tmp_reg |= (uint32_t)params->policer_params.mask <<
+ FMAN_KG_SCH_PP_MASK_SHIFT;
+ }
+
+ scheme_regs->kgse_ppc = tmp_reg;
+
+ /* Coarse Classification Bit Select register */
+ if (params->next_engine == E_FMAN_PCD_CC) {
+ scheme_regs->kgse_ccbs = params->cc_params.qlcv_bits_sel;
+ }
+
+ /* Packets Counter register */
+ if (params->update_counter) {
+ scheme_regs->kgse_spc = params->counter_value;
+ }
+
+ return 0;
+}
+
+int fman_kg_write_scheme(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ struct fman_kg_scheme_regs *scheme_regs,
+ bool update_counter)
+{
+ struct fman_kg_scheme_regs *kgse_regs;
+ uint32_t tmp_reg;
+ int err, i;
+
+ /* Write indirect scheme registers */
+ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
+
+ iowrite32be(scheme_regs->kgse_mode, &kgse_regs->kgse_mode);
+ iowrite32be(scheme_regs->kgse_ekfc, &kgse_regs->kgse_ekfc);
+ iowrite32be(scheme_regs->kgse_ekdv, &kgse_regs->kgse_ekdv);
+ iowrite32be(scheme_regs->kgse_bmch, &kgse_regs->kgse_bmch);
+ iowrite32be(scheme_regs->kgse_bmcl, &kgse_regs->kgse_bmcl);
+ iowrite32be(scheme_regs->kgse_fqb, &kgse_regs->kgse_fqb);
+ iowrite32be(scheme_regs->kgse_hc, &kgse_regs->kgse_hc);
+ iowrite32be(scheme_regs->kgse_ppc, &kgse_regs->kgse_ppc);
+ iowrite32be(scheme_regs->kgse_spc, &kgse_regs->kgse_spc);
+ iowrite32be(scheme_regs->kgse_dv0, &kgse_regs->kgse_dv0);
+ iowrite32be(scheme_regs->kgse_dv1, &kgse_regs->kgse_dv1);
+ iowrite32be(scheme_regs->kgse_ccbs, &kgse_regs->kgse_ccbs);
+ iowrite32be(scheme_regs->kgse_mv, &kgse_regs->kgse_mv);
+
+ for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++)
+ iowrite32be(scheme_regs->kgse_gec[i], &kgse_regs->kgse_gec[i]);
+
+ /* Write AR (Action register) */
+ tmp_reg = build_ar_scheme(scheme_id, hwport_id, update_counter, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ return err;
+}
+
+int fman_kg_delete_scheme(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id)
+{
+ struct fman_kg_scheme_regs *kgse_regs;
+ uint32_t tmp_reg;
+ int err, i;
+
+ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
+
+ /* Clear all registers including enable bit in mode register */
+ for (i = 0; i < (sizeof(struct fman_kg_scheme_regs)) / 4; ++i) {
+ iowrite32be(0, ((uint32_t *)kgse_regs + i));
+ }
+
+ /* Write AR (Action register) */
+ tmp_reg = build_ar_scheme(scheme_id, hwport_id, FALSE, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ return err;
+}
+
+int fman_kg_get_scheme_counter(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ uint32_t *counter)
+{
+ struct fman_kg_scheme_regs *kgse_regs;
+ uint32_t tmp_reg;
+ int err;
+
+ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
+
+ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+
+ if (err != 0)
+ return err;
+
+ *counter = ioread32be(&kgse_regs->kgse_spc);
+
+ return 0;
+}
+
+int fman_kg_set_scheme_counter(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ uint32_t counter)
+{
+ struct fman_kg_scheme_regs *kgse_regs;
+ uint32_t tmp_reg;
+ int err;
+
+ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
+
+ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
+
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ if (err != 0)
+ return err;
+
+ /* Keygen indirect access memory contains all scheme_id registers
+ * by now. Change only counter value. */
+ iowrite32be(counter, &kgse_regs->kgse_spc);
+
+ /* Write back scheme registers */
+ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+
+ return err;
+}
+
+uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs)
+{
+ return ioread32be(&regs->fmkg_tpc);
+}
+
+int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params,
+ struct fman_kg_cp_regs *cls_plan_regs)
+{
+ uint8_t entries_set, entry_bit;
+ int i;
+
+ /* Zero out all group's register */
+ memset(cls_plan_regs, 0, sizeof(struct fman_kg_cp_regs));
+
+ /* Go over all classification entries in params->entries_mask and
+ * configure the corresponding cpe register */
+ entries_set = params->entries_mask;
+ for (i = 0; entries_set; i++) {
+ entry_bit = (uint8_t)(0x80 >> i);
+ if ((entry_bit & entries_set) == 0)
+ continue;
+ entries_set ^= entry_bit;
+ cls_plan_regs->kgcpe[i] = params->mask_vector[i];
+ }
+
+ return 0;
+}
+
+int fman_kg_write_cls_plan(struct fman_kg_regs *regs,
+ uint8_t grp_id,
+ uint8_t entries_mask,
+ uint8_t hwport_id,
+ struct fman_kg_cp_regs *cls_plan_regs)
+{
+ struct fman_kg_cp_regs *kgcpe_regs;
+ uint32_t tmp_reg;
+ int i, err;
+
+ /* Check group index is valid and the group isn't empty */
+ if (grp_id >= FM_KG_CLS_PLAN_GRPS_NUM)
+ return -EINVAL;
+
+ /* Write indirect classification plan registers */
+ kgcpe_regs = (struct fman_kg_cp_regs *)&(regs->fmkg_indirect[0]);
+
+ for (i = 0; i < FM_KG_NUM_CLS_PLAN_ENTR; i++) {
+ iowrite32be(cls_plan_regs->kgcpe[i], &kgcpe_regs->kgcpe[i]);
+ }
+
+ tmp_reg = build_ar_cls_plan(grp_id, entries_mask, hwport_id, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ return err;
+}
+
+int fman_kg_write_bind_schemes(struct fman_kg_regs *regs,
+ uint8_t hwport_id,
+ uint32_t schemes)
+{
+ struct fman_kg_pe_regs *kg_pe_regs;
+ uint32_t tmp_reg;
+ int err;
+
+ kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
+
+ iowrite32be(schemes, &kg_pe_regs->fmkg_pe_sp);
+
+ tmp_reg = build_ar_bind_scheme(hwport_id, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ return err;
+}
+
+int fman_kg_build_bind_cls_plans(uint8_t grp_base,
+ uint8_t grp_mask,
+ uint32_t *bind_cls_plans)
+{
+ /* Check grp_base and grp_mask are 5-bits values */
+ if ((grp_base & ~0x0000001F) || (grp_mask & ~0x0000001F))
+ return -EINVAL;
+
+ *bind_cls_plans = (uint32_t) ((grp_mask << FMAN_KG_PE_CPP_MASK_SHIFT) | grp_base);
+ return 0;
+}
+
+
+int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs,
+ uint8_t hwport_id,
+ uint32_t bind_cls_plans)
+{
+ struct fman_kg_pe_regs *kg_pe_regs;
+ uint32_t tmp_reg;
+ int err;
+
+ kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
+
+ iowrite32be(bind_cls_plans, &kg_pe_regs->fmkg_pe_cpp);
+
+ tmp_reg = build_ar_bind_cls_plan(hwport_id, TRUE);
+ err = fman_kg_write_ar_wait(regs, tmp_reg);
+ return err;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c
new file mode 100644
index 000000000000..108779dbaf40
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_prs.h"
+
+uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->fmpr_perr) & ev_mask;
+}
+
+uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs)
+{
+ return ioread32be(&regs->fmpr_perer);
+}
+
+void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event)
+{
+ iowrite32be(event, &regs->fmpr_perr);
+}
+
+uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->fmpr_pevr) & ev_mask;
+}
+
+uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs)
+{
+ return ioread32be(&regs->fmpr_pever);
+}
+
+void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event)
+{
+ iowrite32be(event, &regs->fmpr_pevr);
+}
+
+void fman_prs_defconfig(struct fman_prs_cfg *cfg)
+{
+ cfg->port_id_stat = 0;
+ cfg->max_prs_cyc_lim = DEFAULT_MAX_PRS_CYC_LIM;
+ cfg->prs_exceptions = 0x03000000;
+}
+
+int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg)
+{
+ uint32_t tmp;
+
+ iowrite32be(cfg->max_prs_cyc_lim, &regs->fmpr_rpclim);
+ iowrite32be((FM_PCD_PRS_SINGLE_ECC | FM_PCD_PRS_PORT_IDLE_STS),
+ &regs->fmpr_pevr);
+
+ if (cfg->prs_exceptions & FM_PCD_EX_PRS_SINGLE_ECC)
+ iowrite32be(FM_PCD_PRS_SINGLE_ECC, &regs->fmpr_pever);
+ else
+ iowrite32be(0, &regs->fmpr_pever);
+
+ iowrite32be(FM_PCD_PRS_DOUBLE_ECC, &regs->fmpr_perr);
+
+ tmp = 0;
+ if (cfg->prs_exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)
+ tmp |= FM_PCD_PRS_DOUBLE_ECC;
+ iowrite32be(tmp, &regs->fmpr_perer);
+
+ iowrite32be(cfg->port_id_stat, &regs->fmpr_ppsc);
+
+ return 0;
+}
+
+void fman_prs_enable(struct fman_prs_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->fmpr_rpimac) | FM_PCD_PRS_RPIMAC_EN;
+ iowrite32be(tmp, &regs->fmpr_rpimac);
+}
+
+void fman_prs_disable(struct fman_prs_regs *regs)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&regs->fmpr_rpimac) & ~FM_PCD_PRS_RPIMAC_EN;
+ iowrite32be(tmp, &regs->fmpr_rpimac);
+}
+
+int fman_prs_is_enabled(struct fman_prs_regs *regs)
+{
+ return ioread32be(&regs->fmpr_rpimac) & FM_PCD_PRS_RPIMAC_EN;
+}
+
+void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk)
+{
+ iowrite32be(pid_msk, &regs->fmpr_ppsc);
+}
+
+void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable)
+{
+ if (enable)
+ iowrite32be(FM_PCD_PRS_PPSC_ALL_PORTS, &regs->fmpr_ppsc);
+ else
+ iowrite32be(0, &regs->fmpr_ppsc);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile
new file mode 100644
index 000000000000..7d928e0a4aac
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-Pcd.o
+
+fsl-ncsw-Pcd-objs := fm_port.o fm_port_im.o fman_port.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
new file mode 100644
index 000000000000..73a28bf5b163
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c
@@ -0,0 +1,6442 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_port.c
+
+ @Description FM driver routines implementation.
+ *//***************************************************************************/
+#include "error_ext.h"
+#include "std_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+#include "fm_muram_ext.h"
+
+#include "fman_common.h"
+#include "fm_port.h"
+#include "fm_port_dsar.h"
+#include "common/general.h"
+
+/****************************************/
+/* static functions */
+/****************************************/
+static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort);
+
+static t_Error CheckInitParameters(t_FmPort *p_FmPort)
+{
+ t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam;
+ struct fman_port_cfg *p_DfltConfig = &p_Params->dfltCfg;
+ t_Error ans = E_OK;
+ uint32_t unusedMask;
+
+ if (p_FmPort->imEn)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ > 2)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoDeqPipelineDepth for IM 10G can't be larger than 2"));
+
+ if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK)
+ return ERROR_CODE(ans);
+ }
+ else
+ {
+ /****************************************/
+ /* Rx only */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ /* external buffer pools */
+ if (!p_Params->extBufPools.numOfPoolsUsed)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined"));
+
+ if (FmSpCheckBufPoolsParams(&p_Params->extBufPools,
+ p_Params->p_BackupBmPools,
+ &p_Params->bufPoolDepletion) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ /* Check that part of IC that needs copying is small enough to enter start margin */
+ if (p_Params->intContext.size
+ && (p_Params->intContext.size
+ + p_Params->intContext.extBufOffset
+ > p_Params->bufMargins.startMargins))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("intContext.size is larger than start margins"));
+
+ if ((p_Params->liodnOffset != (uint16_t)DPAA_LIODN_DONT_OVERRIDE)
+ && (p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
+
+#ifdef FM_NO_BACKUP_POOLS
+ if ((p_FmPort->fmRevInfo.majorRev != 4) && (p_FmPort->fmRevInfo.majorRev < 6))
+ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("BackupBmPools"));
+#endif /* FM_NO_BACKUP_POOLS */
+ }
+
+ /****************************************/
+ /* Non Rx ports */
+ /****************************************/
+ else
+ {
+ if (p_Params->deqSubPortal >= FM_MAX_NUM_OF_SUB_PORTALS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ (" deqSubPortal has to be in the range of 0 - %d", FM_MAX_NUM_OF_SUB_PORTALS));
+
+ /* to protect HW internal-context from overwrite */
+ if ((p_Params->intContext.size)
+ && (p_Params->intContext.intContextOffset
+ < MIN_TX_INT_OFFSET))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET));
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ /* in O/H DEFAULT_notSupported indicates that it is not supported and should not be checked */
+ || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ != DEFAULT_notSupported))
+ {
+ /* Check that not larger than 8 */
+ if ((!p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth)
+ || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ > MAX_FIFO_PIPELINE_DEPTH))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH));
+ }
+ }
+
+ /****************************************/
+ /* Rx Or Offline Parsing */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ {
+ if (!p_Params->dfltFqid)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("dfltFqid must be between 1 and 2^24-1"));
+#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004)
+ if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16"));
+#endif /* defined(FM_CAPWAP_SUPPORT) && ... */
+ }
+
+ /****************************************/
+ /* All ports */
+ /****************************************/
+ /* common BMI registers values */
+ /* Check that Queue Id is not larger than 2^24, and is not 0 */
+ if ((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("errFqid must be between 1 and 2^24-1"));
+ if (p_Params->dfltFqid & ~0x00FFFFFF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("dfltFqid must be between 1 and 2^24-1"));
+ }
+
+ /****************************************/
+ /* Rx only */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ if (p_DfltConfig->rx_pri_elevation % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS));
+ if ((p_DfltConfig->rx_pri_elevation < BMI_FIFO_UNITS)
+ || (p_DfltConfig->rx_pri_elevation > MAX_PORT_FIFO_SIZE))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("rxFifoPriElevationLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
+ if (p_DfltConfig->rx_fifo_thr % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS));
+ if ((p_DfltConfig->rx_fifo_thr < BMI_FIFO_UNITS)
+ || (p_DfltConfig->rx_fifo_thr > MAX_PORT_FIFO_SIZE))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("rxFifoThreshold has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
+
+ /* Check that not larger than 16 */
+ if (p_DfltConfig->rx_cut_end_bytes > FRAME_END_DATA_SIZE)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE));
+
+ if (FmSpCheckBufMargins(&p_Params->bufMargins) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ /* extra FIFO size (allowed only to Rx ports) */
+ if (p_Params->setSizeOfFifo
+ && (p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS));
+
+ if (p_Params->bufPoolDepletion.poolsGrpModeEnable
+ && !p_Params->bufPoolDepletion.numOfPools)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("bufPoolDepletion.numOfPools can not be 0 when poolsGrpModeEnable=TRUE"));
+#ifdef FM_CSI_CFED_LIMIT
+ if (p_FmPort->fmRevInfo.majorRev == 4)
+ {
+ /* Check that not larger than 16 */
+ if (p_DfltConfig->rx_cut_end_bytes + p_DfltConfig->checksum_bytes_ignore > FRAME_END_DATA_SIZE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE));
+ }
+#endif /* FM_CSI_CFED_LIMIT */
+ }
+
+ /****************************************/
+ /* Non Rx ports */
+ /****************************************/
+ /* extra FIFO size (allowed only to Rx ports) */
+ else
+ if (p_FmPort->fifoBufs.extra)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ (" No fifoBufs.extra for non Rx ports"));
+
+ /****************************************/
+ /* Tx only */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
+ {
+ if (p_DfltConfig->tx_fifo_min_level % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS));
+ if (p_DfltConfig->tx_fifo_min_level > (MAX_PORT_FIFO_SIZE - 256))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("txFifoMinFillLevel has to be in the range of 0 - %d", (MAX_PORT_FIFO_SIZE - 256)));
+ if (p_DfltConfig->tx_fifo_low_comf_level % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS));
+ if ((p_DfltConfig->tx_fifo_low_comf_level < BMI_FIFO_UNITS)
+ || (p_DfltConfig->tx_fifo_low_comf_level > MAX_PORT_FIFO_SIZE))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("txFifoLowComfLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
+
+ if (p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ > 2)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("fifoDeqPipelineDepth for 1G can't be larger than 2"));
+ }
+
+ /****************************************/
+ /* Non Tx Ports */
+ /****************************************/
+ /* If discard override was selected , no frames may be discarded. */
+ else
+ if (p_DfltConfig->discard_override && p_Params->errorsToDiscard)
+ RETURN_ERROR(
+ MAJOR,
+ E_CONFLICT,
+ ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue)."));
+
+ /****************************************/
+ /* Rx and Offline parsing */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ unusedMask = BMI_STATUS_OP_MASK_UNUSED;
+ else
+ unusedMask = BMI_STATUS_RX_MASK_UNUSED;
+
+ /* Check that no common bits with BMI_STATUS_MASK_UNUSED */
+ if (p_Params->errorsToDiscard & unusedMask)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("errorsToDiscard contains undefined bits"));
+ }
+
+ /****************************************/
+ /* Offline Ports */
+ /****************************************/
+#ifdef FM_OP_OPEN_DMA_MIN_LIMIT
+ if ((p_FmPort->fmRevInfo.majorRev >= 6)
+ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ && p_Params->setNumOfOpenDmas
+ && (p_FmPort->openDmas.num < MIN_NUM_OF_OP_DMAS))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For Offline port, openDmas.num can't be smaller than %d", MIN_NUM_OF_OP_DMAS));
+#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */
+
+ /****************************************/
+ /* Offline & HC Ports */
+ /****************************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
+ {
+#ifndef FM_FRAME_END_PARAMS_FOR_OP
+ if ((p_FmPort->fmRevInfo.majorRev < 6) &&
+ (p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore != DEFAULT_notSupported))
+ /* this is an indication that user called config for this mode which is not supported in this integration */
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("cheksumLastBytesIgnore is available for Rx & Tx ports only"));
+#endif /* !FM_FRAME_END_PARAMS_FOR_OP */
+
+#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
+ if ((!((p_FmPort->fmRevInfo.majorRev == 4) ||
+ (p_FmPort->fmRevInfo.majorRev >= 6))) &&
+ (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth != DEFAULT_notSupported))
+ /* this is an indication that user called config for this mode which is not supported in this integration */
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("fifoDeqPipelineDepth is available for Tx ports only"));
+#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
+ }
+
+ /****************************************/
+ /* All ports */
+ /****************************************/
+ /* Check that not larger than 16 */
+ if ((p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE)
+ && ((p_Params->cheksumLastBytesIgnore != DEFAULT_notSupported)))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE));
+
+ if (FmSpCheckIntContextParams(&p_Params->intContext) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ /* common BMI registers values */
+ if (p_Params->setNumOfTasks
+ && ((!p_FmPort->tasks.num)
+ || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS));
+ if (p_Params->setNumOfTasks
+ && (p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS));
+ if (p_Params->setNumOfOpenDmas
+ && ((!p_FmPort->openDmas.num)
+ || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS));
+ if (p_Params->setNumOfOpenDmas
+ && (p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS));
+ if (p_Params->setSizeOfFifo
+ && (!p_FmPort->fifoBufs.num
+ || (p_FmPort->fifoBufs.num > MAX_PORT_FIFO_SIZE)))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoBufs.num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
+ if (p_Params->setSizeOfFifo && (p_FmPort->fifoBufs.num % BMI_FIFO_UNITS))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS));
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_FmPort->fmRevInfo.majorRev == 4)
+ if (p_FmPort->p_FmPortDriverParam->deqPrefetchOption != DEFAULT_notSupported)
+ /* this is an indication that user called config for this mode which is not supported in this integration */
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("deqPrefetchOption"));
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ return E_OK;
+}
+
+static t_Error VerifySizeOfFifo(t_FmPort *p_FmPort)
+{
+ uint32_t minFifoSizeRequired = 0, optFifoSizeForB2B = 0;
+
+ /*************************/
+ /* TX PORTS */
+ /*************************/
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
+ {
+ minFifoSizeRequired =
+ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
+ + (3 * BMI_FIFO_UNITS));
+ if (!p_FmPort->imEn)
+ minFifoSizeRequired +=
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ * BMI_FIFO_UNITS;
+
+ optFifoSizeForB2B = minFifoSizeRequired;
+
+ /* Add some margin for back-to-back capability to improve performance,
+ allows the hardware to pipeline new frame dma while the previous
+ frame not yet transmitted. */
+ if (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ optFifoSizeForB2B += 3 * BMI_FIFO_UNITS;
+ else
+ optFifoSizeForB2B += 2 * BMI_FIFO_UNITS;
+ }
+
+ /*************************/
+ /* RX IM PORTS */
+ /*************************/
+ else
+ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ && p_FmPort->imEn)
+ {
+ optFifoSizeForB2B =
+ minFifoSizeRequired =
+ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
+ + (4 * BMI_FIFO_UNITS));
+ }
+
+ /*************************/
+ /* RX non-IM PORTS */
+ /*************************/
+ else
+ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ && !p_FmPort->imEn)
+ {
+ if (p_FmPort->fmRevInfo.majorRev == 4)
+ {
+ if (p_FmPort->rxPoolsParams.numOfPools == 1)
+ minFifoSizeRequired = 8 * BMI_FIFO_UNITS;
+ else
+ minFifoSizeRequired =
+ (uint32_t)(ROUND_UP(p_FmPort->rxPoolsParams.secondLargestBufSize, BMI_FIFO_UNITS)
+ + (7 * BMI_FIFO_UNITS));
+ }
+ else
+ {
+#if (DPAA_VERSION >= 11)
+ minFifoSizeRequired =
+ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
+ + (5 * BMI_FIFO_UNITS));
+ /* 4 according to spec + 1 for FOF>0 */
+#else
+ minFifoSizeRequired = (uint32_t)
+ (ROUND_UP(MIN(p_FmPort->maxFrameLength, p_FmPort->rxPoolsParams.largestBufSize), BMI_FIFO_UNITS)
+ + (7*BMI_FIFO_UNITS));
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ optFifoSizeForB2B = minFifoSizeRequired;
+
+ /* Add some margin for back-to-back capability to improve performance,
+ allows the hardware to pipeline new frame dma while the previous
+ frame not yet transmitted. */
+ if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ optFifoSizeForB2B += 8 * BMI_FIFO_UNITS;
+ else
+ optFifoSizeForB2B += 3 * BMI_FIFO_UNITS;
+ }
+
+ /* For O/H ports, check fifo size and update if necessary */
+ else
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
+ {
+#if (DPAA_VERSION >= 11)
+ optFifoSizeForB2B =
+ minFifoSizeRequired =
+ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS)
+ + ((p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth
+ + 5) * BMI_FIFO_UNITS));
+ /* 4 according to spec + 1 for FOF>0 */
+#else
+ optFifoSizeForB2B = minFifoSizeRequired = (uint32_t)((p_FmPort->tasks.num + 2) * BMI_FIFO_UNITS);
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ ASSERT_COND(minFifoSizeRequired > 0);
+ ASSERT_COND(optFifoSizeForB2B >= minFifoSizeRequired);
+
+ /* Verify the size */
+ if (p_FmPort->fifoBufs.num < minFifoSizeRequired)
+ DBG(INFO,
+ ("FIFO size is %d and should be enlarged to %d bytes",p_FmPort->fifoBufs.num, minFifoSizeRequired));
+ else if (p_FmPort->fifoBufs.num < optFifoSizeForB2B)
+ DBG(INFO,
+ ("For back-to-back frames processing, FIFO size is %d and needs to enlarge to %d bytes", p_FmPort->fifoBufs.num, optFifoSizeForB2B));
+
+ return E_OK;
+}
+
+static void FmPortDriverParamFree(t_FmPort *p_FmPort)
+{
+ if (p_FmPort->p_FmPortDriverParam)
+ {
+ XX_Free(p_FmPort->p_FmPortDriverParam);
+ p_FmPort->p_FmPortDriverParam = NULL;
+ }
+}
+
+static t_Error SetExtBufferPools(t_FmPort *p_FmPort)
+{
+ t_FmExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools;
+ t_FmBufPoolDepletion *p_BufPoolDepletion =
+ &p_FmPort->p_FmPortDriverParam->bufPoolDepletion;
+ uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ uint16_t sizesArray[BM_MAX_NUM_OF_POOLS];
+ int i = 0, j = 0, err;
+ struct fman_port_bpools bpools;
+
+ memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
+ memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS);
+ memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmExtPools));
+
+ FmSpSetBufPoolsInAscOrderOfBufSizes(p_ExtBufPools, orderedArray,
+ sizesArray);
+
+ /* Prepare flibs bpools structure */
+ memset(&bpools, 0, sizeof(struct fman_port_bpools));
+ bpools.count = p_ExtBufPools->numOfPoolsUsed;
+ bpools.counters_enable = TRUE;
+ for (i = 0; i < p_ExtBufPools->numOfPoolsUsed; i++)
+ {
+ bpools.bpool[i].bpid = orderedArray[i];
+ bpools.bpool[i].size = sizesArray[orderedArray[i]];
+ /* functionality available only for some derivatives (limited by config) */
+ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
+ for (j = 0;
+ j
+ < p_FmPort->p_FmPortDriverParam->p_BackupBmPools->numOfBackupPools;
+ j++)
+ if (orderedArray[i]
+ == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j])
+ {
+ bpools.bpool[i].is_backup = TRUE;
+ break;
+ }
+ }
+
+ /* save pools parameters for later use */
+ p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed;
+ p_FmPort->rxPoolsParams.largestBufSize =
+ sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]];
+ if (p_ExtBufPools->numOfPoolsUsed > 1)
+ p_FmPort->rxPoolsParams.secondLargestBufSize =
+ sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]];
+
+ /* FMBM_RMPD reg. - pool depletion */
+ if (p_BufPoolDepletion->poolsGrpModeEnable)
+ {
+ bpools.grp_bp_depleted_num = p_BufPoolDepletion->numOfPools;
+ for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++)
+ {
+ if (p_BufPoolDepletion->poolsToConsider[i])
+ {
+ for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++)
+ {
+ if (i == orderedArray[j])
+ {
+ bpools.bpool[j].grp_bp_depleted = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (p_BufPoolDepletion->singlePoolModeEnable)
+ {
+ for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++)
+ {
+ if (p_BufPoolDepletion->poolsToConsiderForSingleMode[i])
+ {
+ for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++)
+ {
+ if (i == orderedArray[j])
+ {
+ bpools.bpool[j].single_bp_depleted = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+#if (DPAA_VERSION >= 11)
+ /* fill QbbPEV */
+ if (p_BufPoolDepletion->poolsGrpModeEnable
+ || p_BufPoolDepletion->singlePoolModeEnable)
+ {
+ for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++)
+ {
+ if (p_BufPoolDepletion->pfcPrioritiesEn[i] == TRUE)
+ {
+ bpools.bpool[i].pfc_priorities_en = TRUE;
+ }
+ }
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Issue flibs function */
+ err = fman_port_set_bpools(&p_FmPort->port, &bpools);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpools"));
+
+ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
+ XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools);
+
+ return E_OK;
+}
+
+static t_Error ClearPerfCnts(t_FmPort *p_FmPort)
+{
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0);
+ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0);
+ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0);
+ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0);
+ return E_OK;
+}
+
+static t_Error InitLowLevelDriver(t_FmPort *p_FmPort)
+{
+ t_FmPortDriverParam *p_DriverParams = p_FmPort->p_FmPortDriverParam;
+ struct fman_port_params portParams;
+ uint32_t tmpVal;
+ t_Error err;
+
+ /* Set up flibs parameters and issue init function */
+
+ memset(&portParams, 0, sizeof(struct fman_port_params));
+ portParams.discard_mask = p_DriverParams->errorsToDiscard;
+ portParams.dflt_fqid = p_DriverParams->dfltFqid;
+ portParams.err_fqid = p_DriverParams->errFqid;
+ portParams.deq_sp = p_DriverParams->deqSubPortal;
+ portParams.dont_release_buf = p_DriverParams->dontReleaseBuf;
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ portParams.err_mask = (RX_ERRS_TO_ENQ & ~portParams.discard_mask);
+ if (!p_FmPort->imEn)
+ {
+ if (p_DriverParams->forwardReuseIntContext)
+ p_DriverParams->dfltCfg.rx_fd_bits =
+ (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24);
+ }
+ break;
+
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ portParams.err_mask = (OP_ERRS_TO_ENQ & ~portParams.discard_mask);
+ break;
+ break;
+
+ default:
+ break;
+ }
+
+ tmpVal =
+ (uint32_t)(
+ (p_FmPort->internalBufferOffset % OFFSET_UNITS) ? (p_FmPort->internalBufferOffset
+ / OFFSET_UNITS + 1) :
+ (p_FmPort->internalBufferOffset / OFFSET_UNITS));
+ p_FmPort->internalBufferOffset = (uint8_t)(tmpVal * OFFSET_UNITS);
+ p_DriverParams->dfltCfg.int_buf_start_margin =
+ p_FmPort->internalBufferOffset;
+
+ p_DriverParams->dfltCfg.ext_buf_start_margin =
+ p_DriverParams->bufMargins.startMargins;
+ p_DriverParams->dfltCfg.ext_buf_end_margin =
+ p_DriverParams->bufMargins.endMargins;
+
+ p_DriverParams->dfltCfg.ic_ext_offset =
+ p_DriverParams->intContext.extBufOffset;
+ p_DriverParams->dfltCfg.ic_int_offset =
+ p_DriverParams->intContext.intContextOffset;
+ p_DriverParams->dfltCfg.ic_size = p_DriverParams->intContext.size;
+
+ p_DriverParams->dfltCfg.stats_counters_enable = TRUE;
+ p_DriverParams->dfltCfg.perf_counters_enable = TRUE;
+ p_DriverParams->dfltCfg.queue_counters_enable = TRUE;
+
+ p_DriverParams->dfltCfg.perf_cnt_params.task_val =
+ (uint8_t)p_FmPort->tasks.num;
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING ||
+ p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 0;
+ else
+ p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 1;
+ p_DriverParams->dfltCfg.perf_cnt_params.dma_val =
+ (uint8_t)p_FmPort->openDmas.num;
+ p_DriverParams->dfltCfg.perf_cnt_params.fifo_val = p_FmPort->fifoBufs.num;
+
+ if (0
+ != fman_port_init(&p_FmPort->port, &p_DriverParams->dfltCfg,
+ &portParams))
+ RETURN_ERROR(MAJOR, E_NO_DEVICE, ("fman_port_init"));
+
+ if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK))
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ else
+ {
+ // from QMIInit
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ {
+ if (p_DriverParams->deqPrefetchOption == e_FM_PORT_DEQ_NO_PREFETCH)
+ FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId,
+ FALSE);
+ else
+ FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId,
+ TRUE);
+ }
+ }
+ /* The code bellow is a trick so the FM will not release the buffer
+ to BM nor will try to enqueue the frame to QM */
+ if (((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) && (!p_FmPort->imEn))
+ {
+ if (!p_DriverParams->dfltFqid && p_DriverParams->dontReleaseBuf)
+ {
+ /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to
+ * act according to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release
+ * buffers to BM regardless of fmbm_tfene
+ */
+ WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tcfqid, 0xFFFFFF);
+ WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tfene,
+ NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE);
+ }
+ }
+
+ return E_OK;
+}
+
+static bool CheckRxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
+{
+ UNUSED(p_FmPort);
+
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_CYCLE):
+ case (e_FM_PORT_COUNTERS_TASK_UTIL):
+ case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
+ case (e_FM_PORT_COUNTERS_DMA_UTIL):
+ case (e_FM_PORT_COUNTERS_FIFO_UTIL):
+ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
+ case (e_FM_PORT_COUNTERS_FRAME):
+ case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
+ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
+ case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
+ case (e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER):
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static bool CheckTxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
+{
+ UNUSED(p_FmPort);
+
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_CYCLE):
+ case (e_FM_PORT_COUNTERS_TASK_UTIL):
+ case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
+ case (e_FM_PORT_COUNTERS_DMA_UTIL):
+ case (e_FM_PORT_COUNTERS_FIFO_UTIL):
+ case (e_FM_PORT_COUNTERS_FRAME):
+ case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
+ case (e_FM_PORT_COUNTERS_LENGTH_ERR):
+ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
+ case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static bool CheckOhBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter)
+{
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_CYCLE):
+ case (e_FM_PORT_COUNTERS_TASK_UTIL):
+ case (e_FM_PORT_COUNTERS_DMA_UTIL):
+ case (e_FM_PORT_COUNTERS_FIFO_UTIL):
+ case (e_FM_PORT_COUNTERS_FRAME):
+ case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
+ case (e_FM_PORT_COUNTERS_WRED_DISCARD):
+ case (e_FM_PORT_COUNTERS_LENGTH_ERR):
+ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
+ case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
+ return TRUE;
+ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ return FALSE;
+ else
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static t_Error BmiPortCheckAndGetCounterType(
+ t_FmPort *p_FmPort, e_FmPortCounters counter,
+ enum fman_port_stats_counters *p_StatsType,
+ enum fman_port_perf_counters *p_PerfType, bool *p_IsStats)
+{
+ volatile uint32_t *p_Reg;
+ bool isValid;
+
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_Reg = &p_FmPort->port.bmi_regs->rx.fmbm_rstc;
+ isValid = CheckRxBmiCounter(p_FmPort, counter);
+ break;
+ case (e_FM_PORT_TYPE_TX_10G):
+ case (e_FM_PORT_TYPE_TX):
+ p_Reg = &p_FmPort->port.bmi_regs->tx.fmbm_tstc;
+ isValid = CheckTxBmiCounter(p_FmPort, counter);
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ p_Reg = &p_FmPort->port.bmi_regs->oh.fmbm_ostc;
+ isValid = CheckOhBmiCounter(p_FmPort, counter);
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type"));
+ }
+
+ if (!isValid)
+ RETURN_ERROR(MINOR, E_INVALID_STATE,
+ ("Requested counter is not available for this port type"));
+
+ /* check that counters are enabled */
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_CYCLE):
+ case (e_FM_PORT_COUNTERS_TASK_UTIL):
+ case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
+ case (e_FM_PORT_COUNTERS_DMA_UTIL):
+ case (e_FM_PORT_COUNTERS_FIFO_UTIL):
+ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
+ /* performance counters - may be read when disabled */
+ *p_IsStats = FALSE;
+ break;
+ case (e_FM_PORT_COUNTERS_FRAME):
+ case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
+ case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
+ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
+ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
+ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
+ case (e_FM_PORT_COUNTERS_LENGTH_ERR):
+ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
+ case (e_FM_PORT_COUNTERS_WRED_DISCARD):
+ *p_IsStats = TRUE;
+ if (!(GET_UINT32(*p_Reg) & BMI_COUNTERS_EN))
+ RETURN_ERROR(MINOR, E_INVALID_STATE,
+ ("Requested counter was not enabled"));
+ break;
+ default:
+ break;
+ }
+
+ /* Set counter */
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_CYCLE):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_CYCLE;
+ break;
+ case (e_FM_PORT_COUNTERS_TASK_UTIL):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_TASK_UTIL;
+ break;
+ case (e_FM_PORT_COUNTERS_QUEUE_UTIL):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_QUEUE_UTIL;
+ break;
+ case (e_FM_PORT_COUNTERS_DMA_UTIL):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_DMA_UTIL;
+ break;
+ case (e_FM_PORT_COUNTERS_FIFO_UTIL):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_FIFO_UTIL;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION):
+ *p_PerfType = E_FMAN_PORT_PERF_CNT_RX_PAUSE;
+ break;
+ case (e_FM_PORT_COUNTERS_FRAME):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_FRAME;
+ break;
+ case (e_FM_PORT_COUNTERS_DISCARD_FRAME):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_DISCARD;
+ break;
+ case (e_FM_PORT_COUNTERS_DEALLOC_BUF):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_DEALLOC_BUF;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_FILTERED_FRAME;
+ break;
+ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_DMA_ERR;
+ break;
+ case (e_FM_PORT_COUNTERS_WRED_DISCARD):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_WRED_DISCARD;
+ break;
+ case (e_FM_PORT_COUNTERS_LENGTH_ERR):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_LEN_ERR;
+ break;
+ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT):
+ *p_StatsType = E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT;
+ break;
+ default:
+ break;
+ }
+
+ return E_OK;
+}
+
+static t_Error AdditionalPrsParams(t_FmPort *p_FmPort,
+ t_FmPcdPrsAdditionalHdrParams *p_HdrParams,
+ uint32_t *p_SoftSeqAttachReg)
+{
+ uint8_t hdrNum, Ipv4HdrNum;
+ u_FmPcdHdrPrsOpts *p_prsOpts;
+ uint32_t tmpReg = *p_SoftSeqAttachReg, tmpPrsOffset;
+
+ if (IS_PRIVATE_HEADER(p_HdrParams->hdr)
+ || IS_SPECIAL_HEADER(p_HdrParams->hdr))
+ RETURN_ERROR(
+ MAJOR, E_NOT_SUPPORTED,
+ ("No additional parameters for private or special headers."));
+
+ if (p_HdrParams->errDisable)
+ tmpReg |= PRS_HDR_ERROR_DIS;
+
+ /* Set parser options */
+ if (p_HdrParams->usePrsOpts)
+ {
+ p_prsOpts = &p_HdrParams->prsOpts;
+ switch (p_HdrParams->hdr)
+ {
+ case (HEADER_TYPE_MPLS):
+ if (p_prsOpts->mplsPrsOptions.labelInterpretationEnable)
+ tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN;
+ hdrNum = GetPrsHdrNum(p_prsOpts->mplsPrsOptions.nextParse);
+ if (hdrNum == ILLEGAL_HDR_NUM)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ Ipv4HdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ if (hdrNum < Ipv4HdrNum)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Header must be equal or higher than IPv4"));
+ tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE)
+ << PRS_HDR_MPLS_NEXT_HDR_SHIFT;
+ break;
+ case (HEADER_TYPE_PPPoE):
+ if (p_prsOpts->pppoePrsOptions.enableMTUCheck)
+ tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN;
+ break;
+ case (HEADER_TYPE_IPv6):
+ if (p_prsOpts->ipv6PrsOptions.routingHdrEnable)
+ tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_EN;
+ break;
+ case (HEADER_TYPE_TCP):
+ if (p_prsOpts->tcpPrsOptions.padIgnoreChecksum)
+ tmpReg |= PRS_HDR_TCP_PAD_REMOVAL;
+ else
+ tmpReg &= ~PRS_HDR_TCP_PAD_REMOVAL;
+ break;
+ case (HEADER_TYPE_UDP):
+ if (p_prsOpts->udpPrsOptions.padIgnoreChecksum)
+ tmpReg |= PRS_HDR_UDP_PAD_REMOVAL;
+ else
+ tmpReg &= ~PRS_HDR_UDP_PAD_REMOVAL;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header"));
+ }
+ }
+
+ /* set software parsing (address is divided in 2 since parser uses 2 byte access. */
+ if (p_HdrParams->swPrsEnable)
+ {
+ tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr,
+ p_HdrParams->indexPerHdr);
+ if (tmpPrsOffset == ILLEGAL_BASE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset);
+ }
+ *p_SoftSeqAttachReg = tmpReg;
+
+ return E_OK;
+}
+
+static uint32_t GetPortSchemeBindParams(
+ t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint32_t walking1Mask = 0x80000000, tmp;
+ uint8_t idx = 0;
+
+ p_SchemeBind->netEnvId = p_FmPort->netEnvId;
+ p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId;
+ p_SchemeBind->useClsPlan = p_FmPort->useClsPlan;
+ p_SchemeBind->numOfSchemes = 0;
+ tmp = p_FmPort->schemesPerPortVector;
+ if (tmp)
+ {
+ while (tmp)
+ {
+ if (tmp & walking1Mask)
+ {
+ p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = idx;
+ p_SchemeBind->numOfSchemes++;
+ tmp &= ~walking1Mask;
+ }
+ walking1Mask >>= 1;
+ idx++;
+ }
+ }
+
+ return tmp;
+}
+
+static void FmPortCheckNApplyMacsec(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ volatile uint32_t *p_BmiCfgReg = NULL;
+ uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC;
+ uint32_t lcv, walking1Mask = 0x80000000;
+ uint8_t cnt = 0;
+
+ ASSERT_COND(p_FmPort);
+ ASSERT_COND(p_FmPort->h_FmPcd);
+ ASSERT_COND(!p_FmPort->p_FmPortDriverParam);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ return;
+
+ p_BmiCfgReg = &p_FmPort->port.bmi_regs->rx.fmbm_rcfg;
+ /* get LCV for MACSEC */
+ if ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId))
+ != 0)
+ {
+ while (!(lcv & walking1Mask))
+ {
+ cnt++;
+ walking1Mask >>= 1;
+ }
+
+ macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT;
+ WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn);
+ }
+}
+
+static t_Error SetPcd(t_FmPort *p_FmPort, t_FmPortPcdParams *p_PcdParams)
+{
+ t_Error err = E_OK;
+ uint32_t tmpReg;
+ volatile uint32_t *p_BmiNia = NULL;
+ volatile uint32_t *p_BmiPrsNia = NULL;
+ volatile uint32_t *p_BmiPrsStartOffset = NULL;
+ volatile uint32_t *p_BmiInitPrsResult = NULL;
+ volatile uint32_t *p_BmiCcBase = NULL;
+ uint16_t hdrNum, L3HdrNum, greHdrNum;
+ int i;
+ bool isEmptyClsPlanGrp;
+ uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS];
+ uint16_t absoluteProfileId;
+ uint8_t physicalSchemeId;
+ uint32_t ccTreePhysOffset;
+ t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
+ uint32_t initialSwPrs = 0;
+
+ ASSERT_COND(p_FmPort);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independant mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ p_FmPort->netEnvId = FmPcdGetNetEnvId(p_PcdParams->h_NetEnv);
+
+ p_FmPort->pcdEngines = 0;
+
+ /* initialize p_FmPort->pcdEngines field in port's structure */
+ switch (p_PcdParams->pcdSupport)
+ {
+ case (e_FM_PORT_PCD_SUPPORT_NONE):
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected"));
+ case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PLCR_ONLY):
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR):
+ p_FmPort->pcdEngines |= FM_PCD_PRS;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_CC_ONLY):
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ break;
+#ifdef FM_CAPWAP_SUPPORT
+ case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG):
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR):
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+ p_FmPort->pcdEngines |= FM_PCD_KG;
+ p_FmPort->pcdEngines |= FM_PCD_PLCR;
+ break;
+#endif /* FM_CAPWAP_SUPPORT */
+
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport"));
+ }
+
+ if ((p_FmPort->pcdEngines & FM_PCD_PRS)
+ && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams
+ > FM_PCD_PRS_NUM_OF_HDRS))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS));
+
+ /* check that parameters exist for each and only each defined engine */
+ if ((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams)
+ || (!!(p_FmPort->pcdEngines & FM_PCD_KG)
+ != !!p_PcdParams->p_KgParams)
+ || (!!(p_FmPort->pcdEngines & FM_PCD_CC)
+ != !!p_PcdParams->p_CcParams))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("PCD initialization structure is not consistent with pcdSupport"));
+
+ /* get PCD registers pointers */
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+ p_BmiPrsNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
+ p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->rx.fmbm_rprai[0];
+ p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ p_BmiPrsNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
+ p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->oh.fmbm_oprai[0];
+ p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ }
+
+ /* set PCD port parameter */
+ if (p_FmPort->pcdEngines & FM_PCD_CC)
+ {
+ err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams,
+ p_PcdParams->p_CcParams->h_CcTree,
+ &ccTreePhysOffset, p_FmPort);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset);
+ p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree;
+ }
+
+ if (p_FmPort->pcdEngines & FM_PCD_KG)
+ {
+ if (p_PcdParams->p_KgParams->numOfSchemes == 0)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("For ports using Keygen, at least one scheme must be bound. "));
+
+ err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd,
+ p_FmPort->hardwarePortId,
+ p_FmPort->netEnvId,
+ p_FmPort->optArray,
+ &p_FmPort->clsPlanGrpId,
+ &isEmptyClsPlanGrp);
+ if (err)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("FmPcdKgSetOrBindToClsPlanGrp failed. "));
+
+ p_FmPort->useClsPlan = !isEmptyClsPlanGrp;
+
+ schemeBind.netEnvId = p_FmPort->netEnvId;
+ schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
+ schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes;
+ schemeBind.useClsPlan = p_FmPort->useClsPlan;
+
+ /* for each scheme */
+ for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++)
+ {
+ ASSERT_COND(p_PcdParams->p_KgParams->h_Schemes[i]);
+ physicalSchemeId = FmPcdKgGetSchemeId(
+ p_PcdParams->p_KgParams->h_Schemes[i]);
+ schemeBind.schemesIds[i] = physicalSchemeId;
+ /* build vector */
+ p_FmPort->schemesPerPortVector |= 1
+ << (31 - (uint32_t)physicalSchemeId);
+#if (DPAA_VERSION >= 11)
+ /*because of the state that VSPE is defined per port - all PCD path should be according to this requirement
+ if !VSPE - in port, for relevant scheme VSPE can not be set*/
+ if (!p_FmPort->vspe
+ && FmPcdKgGetVspe((p_PcdParams->p_KgParams->h_Schemes[i])))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("VSPE is not at port level"));
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /***************************/
+ /* configure NIA after BMI */
+ /***************************/
+ /* rfne may contain FDCS bits, so first we read them. */
+ p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK;
+
+ /* If policer is used directly after BMI or PRS */
+ if ((p_FmPort->pcdEngines & FM_PCD_PLCR)
+ && ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY)
+ || (p_PcdParams->pcdSupport
+ == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR)))
+ {
+ if (!p_PcdParams->p_PlcrParams->h_Profile)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Profile should be initialized"));
+
+ absoluteProfileId = (uint16_t)FmPcdPlcrProfileGetAbsoluteId(
+ p_PcdParams->p_PlcrParams->h_Profile);
+
+ if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Private port profile not valid."));
+
+ tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE);
+
+ if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */
+ /* update BMI HPNIA */
+ WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg));
+ else
+ /* e_FM_PCD_SUPPORT_PLCR_ONLY */
+ /* update BMI NIA */
+ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR);
+ }
+
+ /* if CC is used directly after BMI */
+ if ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY)
+#ifdef FM_CAPWAP_SUPPORT
+ || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG)
+ || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR)
+#endif /* FM_CAPWAP_SUPPORT */
+ )
+ {
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_OPERATION,
+ ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only"));
+ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC);
+ /* check that prs start offset == RIM[FOF] */
+ }
+
+ if (p_FmPort->pcdEngines & FM_PCD_PRS)
+ {
+ ASSERT_COND(p_PcdParams->p_PrsParams);
+#if (DPAA_VERSION >= 11)
+ if (p_PcdParams->p_PrsParams->firstPrsHdr == HEADER_TYPE_CAPWAP)
+ hdrNum = OFFLOAD_SW_PATCH_CAPWAP_LABEL;
+ else
+ {
+#endif /* (DPAA_VERSION >= 11) */
+ /* if PRS is used it is always first */
+ hdrNum = GetPrsHdrNum(p_PcdParams->p_PrsParams->firstPrsHdr);
+ if (hdrNum == ILLEGAL_HDR_NUM)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header."));
+#if (DPAA_VERSION >= 11)
+ }
+#endif /* (DPAA_VERSION >= 11) */
+ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum));
+ /* set after parser NIA */
+ tmpReg = 0;
+ switch (p_PcdParams->pcdSupport)
+ {
+ case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY):
+ WRITE_UINT32(*p_BmiPrsNia,
+ GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd));
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC):
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR):
+ tmpReg = NIA_KG_CC_EN;
+ /* fall through */
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG):
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR):
+ if (p_PcdParams->p_KgParams->directScheme)
+ {
+ physicalSchemeId = FmPcdKgGetSchemeId(
+ p_PcdParams->p_KgParams->h_DirectScheme);
+ /* check that this scheme was bound to this port */
+ for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++)
+ if (p_PcdParams->p_KgParams->h_DirectScheme
+ == p_PcdParams->p_KgParams->h_Schemes[i])
+ break;
+ if (i == p_PcdParams->p_KgParams->numOfSchemes)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("Direct scheme is not one of the port selected schemes."));
+ tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId);
+ }
+ WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg);
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC):
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR):
+ WRITE_UINT32(*p_BmiPrsNia,
+ (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC));
+ break;
+ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR):
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support"));
+ }
+
+ /* set start parsing offset */
+ WRITE_UINT32(*p_BmiPrsStartOffset,
+ p_PcdParams->p_PrsParams->parsingOffset);
+
+ /************************************/
+ /* Parser port parameters */
+ /************************************/
+ /* stop before configuring */
+ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP);
+ /* wait for parser to be in idle state */
+ while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE)
+ ;
+
+ /* set soft seq attachment register */
+ memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t));
+
+ /* set protocol options */
+ for (i = 0; p_FmPort->optArray[i]; i++)
+ switch (p_FmPort->optArray[i])
+ {
+ case (ETH_BROADCAST):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_BC_SHIFT;
+ break;
+ case (ETH_MULTICAST):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_MC_SHIFT;
+ break;
+ case (VLAN_STACKED):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_VLAN);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_VLAN_STACKED_SHIFT;
+ break;
+ case (MPLS_STACKED):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_MPLS_STACKED_SHIFT;
+ break;
+ case (IPV4_BROADCAST_1):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_BC_SHIFT;
+ break;
+ case (IPV4_MULTICAST_1):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_MC_SHIFT;
+ break;
+ case (IPV4_UNICAST_2):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_UC_SHIFT;
+ break;
+ case (IPV4_MULTICAST_BROADCAST_2):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_MC_BC_SHIFT;
+ break;
+ case (IPV6_MULTICAST_1):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_1_MC_SHIFT;
+ break;
+ case (IPV6_UNICAST_2):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_UC_SHIFT;
+ break;
+ case (IPV6_MULTICAST_2):
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_MC_SHIFT;
+ break;
+ }
+
+ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId,
+ HEADER_TYPE_UDP_ENCAP_ESP))
+ {
+ if (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams == FM_PCD_PRS_NUM_OF_HDRS)
+ RETURN_ERROR(
+ MINOR, E_INVALID_VALUE,
+ ("If HEADER_TYPE_UDP_ENCAP_ESP is used, numOfHdrsWithAdditionalParams may be up to FM_PCD_PRS_NUM_OF_HDRS - 1"));
+
+ p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr =
+ HEADER_TYPE_UDP;
+ p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable =
+ TRUE;
+ p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++;
+ }
+
+ /* set MPLS default next header - HW reset workaround */
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS);
+ tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN;
+ L3HdrNum = GetPrsHdrNum(HEADER_TYPE_USER_DEFINED_L3);
+ tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT;
+
+ /* for GRE, disable errors */
+ greHdrNum = GetPrsHdrNum(HEADER_TYPE_GRE);
+ tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS;
+
+ /* For UDP remove PAD from L4 checksum calculation */
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_UDP);
+ tmpHxs[hdrNum] |= PRS_HDR_UDP_PAD_REMOVAL;
+ /* For TCP remove PAD from L4 checksum calculation */
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_TCP);
+ tmpHxs[hdrNum] |= PRS_HDR_TCP_PAD_REMOVAL;
+
+ /* config additional params for specific headers */
+ for (i = 0; i < p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams;
+ i++)
+ {
+ /* case for using sw parser as the initial NIA address, before
+ * HW parsing
+ */
+ if ((p_PcdParams->p_PrsParams->additionalParams[i].hdr == HEADER_TYPE_NONE) &&
+ p_PcdParams->p_PrsParams->additionalParams[i].swPrsEnable)
+ {
+ initialSwPrs = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, HEADER_TYPE_NONE,
+ p_PcdParams->p_PrsParams->additionalParams[i].indexPerHdr);
+ if (initialSwPrs == ILLEGAL_BASE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ /* clear parser first HXS */
+ p_FmPort->savedBmiNia &= ~BMI_RFNE_HXS_MASK; /* 0x000000FF */
+ /* rewrite with soft parser start */
+ p_FmPort->savedBmiNia |= initialSwPrs;
+ continue;
+ }
+
+ hdrNum =
+ GetPrsHdrNum(p_PcdParams->p_PrsParams->additionalParams[i].hdr);
+ if (hdrNum == ILLEGAL_HDR_NUM)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ if (hdrNum == NO_HDR_NUM)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("Private headers may not use additional parameters"));
+
+ err = AdditionalPrsParams(
+ p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i],
+ &tmpHxs[hdrNum]);
+ if (err)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+ }
+
+ /* Check if ip-reassembly port - need to link sw-parser code */
+ if (p_FmPort->h_IpReassemblyManip)
+ {
+ /* link to sw parser code for IP Frag - only if no other code is applied. */
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4);
+ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
+ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv4_IPR_LABEL);
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
+ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPR_LABEL);
+ } else {
+ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_LITE))
+ {
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
+ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL);
+ } else if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)
+ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)))
+ {
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
+ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL);
+ }
+ }
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId,
+ HEADER_TYPE_UDP_LITE))
+ {
+ /* link to sw parser code for udp lite - only if no other code is applied. */
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN))
+ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | UDP_LITE_SW_PATCH_LABEL);
+ }
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+ for (i = 0; i < FM_PCD_PRS_NUM_OF_HDRS; i++)
+ {
+ /* For all header set LCV as taken from netEnv*/
+ WRITE_UINT32(
+ p_FmPort->p_FmPortPrsRegs->hdrs[i].lcv,
+ FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i));
+ /* set HXS register according to default+Additional params+protocol options */
+ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach,
+ tmpHxs[i]);
+ }
+
+ /* set tpid. */
+ tmpReg = PRS_TPID_DFLT;
+ if (p_PcdParams->p_PrsParams->setVlanTpid1)
+ {
+ tmpReg &= PRS_TPID2_MASK;
+ tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1
+ << PRS_PCTPID_SHIFT;
+ }
+ if (p_PcdParams->p_PrsParams->setVlanTpid2)
+ {
+ tmpReg &= PRS_TPID1_MASK;
+ tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2;
+ }WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg);
+
+ /* enable parser */
+ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0);
+
+ if (p_PcdParams->p_PrsParams->prsResultPrivateInfo)
+ p_FmPort->privateInfo =
+ p_PcdParams->p_PrsParams->prsResultPrivateInfo;
+
+ } /* end parser */
+ else {
+ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)
+ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ {
+ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6);
+ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[hdrNum].softSeqAttach,
+ (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL));
+ }
+
+ WRITE_UINT32(*p_BmiPrsStartOffset, 0);
+
+ p_FmPort->privateInfo = 0;
+ }
+
+ FmPortCheckNApplyMacsec(p_FmPort);
+
+ WRITE_UINT32(
+ *p_BmiPrsStartOffset,
+ GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset);
+
+ /* set initial parser result - used for all engines */
+ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++)
+ {
+ if (!i)
+ WRITE_UINT32(
+ *(p_BmiInitPrsResult),
+ (uint32_t)(((uint32_t)p_FmPort->privateInfo << BMI_PR_PORTID_SHIFT) | BMI_PRS_RESULT_HIGH));
+ else
+ {
+ if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2)
+ WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH);
+ else
+ WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW);
+ }
+ }
+
+ return E_OK;
+}
+
+static t_Error DeletePcd(t_FmPort *p_FmPort)
+{
+ t_Error err = E_OK;
+ volatile uint32_t *p_BmiNia = NULL;
+ volatile uint32_t *p_BmiPrsStartOffset = NULL;
+
+ ASSERT_COND(p_FmPort);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independant mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ if (!p_FmPort->pcdEngines)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port"));
+
+ /* get PCD registers pointers */
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ }
+
+ if ((GET_UINT32(*p_BmiNia) & GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
+ != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("port has to be detached previousely"));
+
+ WRITE_UINT32(*p_BmiPrsStartOffset, 0);
+
+ /* "cut" PCD out of the port's flow - go to BMI */
+ /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */
+
+ if (p_FmPort->pcdEngines & FM_PCD_PRS)
+ {
+ /* stop parser */
+ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP);
+ /* wait for parser to be in idle state */
+ while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE)
+ ;
+ }
+
+ if (p_FmPort->pcdEngines & FM_PCD_KG)
+ {
+ t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
+
+ /* unbind all schemes */
+ p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort,
+ &schemeBind);
+
+ err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd,
+ p_FmPort->hardwarePortId,
+ p_FmPort->clsPlanGrpId);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ p_FmPort->useClsPlan = FALSE;
+ }
+
+ if (p_FmPort->pcdEngines & FM_PCD_CC)
+ {
+ /* unbind - we need to get the treeId too */
+ err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ p_FmPort->pcdEngines = 0;
+
+ return E_OK;
+}
+
+static t_Error AttachPCD(t_FmPort *p_FmPort)
+{
+ volatile uint32_t *p_BmiNia = NULL;
+
+ ASSERT_COND(p_FmPort);
+
+ /* get PCD registers pointers */
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ else
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+
+ /* check that current NIA is BMI to BMI */
+ if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK)
+ != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME())
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("may be called only for ports in BMI-to-BMI state."));
+
+ if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
+ if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1,
+ p_FmPort->orFmanCtrl) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_CMNE)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ocmne,
+ p_FmPort->savedBmiCmne);
+ else
+ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcmne,
+ p_FmPort->savedBmiCmne);
+ }
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_PNEN)
+ WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen,
+ p_FmPort->savedQmiPnen);
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_FENE)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene,
+ p_FmPort->savedBmiFene);
+ else
+ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene,
+ p_FmPort->savedBmiFene);
+ }
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_FPNE)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne,
+ p_FmPort->savedBmiFpne);
+ else
+ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne,
+ p_FmPort->savedBmiFpne);
+ }
+
+ if (p_FmPort->requiredAction & UPDATE_OFP_DPTE)
+ {
+ ASSERT_COND(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING);
+
+ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp,
+ p_FmPort->savedBmiOfp);
+ }
+
+ WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia);
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_PNDN)
+ {
+ p_FmPort->origNonRxQmiRegsPndn =
+ GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn);
+ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn,
+ p_FmPort->savedNonRxQmiRegsPndn);
+ }
+
+ return E_OK;
+}
+
+static t_Error DetachPCD(t_FmPort *p_FmPort)
+{
+ volatile uint32_t *p_BmiNia = NULL;
+
+ ASSERT_COND(p_FmPort);
+
+ /* get PCD registers pointers */
+ if (p_FmPort->requiredAction & UPDATE_NIA_PNDN)
+ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn,
+ p_FmPort->origNonRxQmiRegsPndn);
+
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ else
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+
+ WRITE_UINT32(
+ *p_BmiNia,
+ (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME());
+
+ if (FmPcdGetHcHandle(p_FmPort->h_FmPcd))
+ FmPcdHcSync(p_FmPort->h_FmPcd);
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_FENE)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene,
+ NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR);
+ else
+ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene,
+ NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR);
+ }
+
+ if (p_FmPort->requiredAction & UPDATE_NIA_PNEN)
+ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pnen,
+ NIA_ENG_BMI | NIA_BMI_AC_RELEASE);
+
+ if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
+ if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2,
+ p_FmPort->orFmanCtrl) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ p_FmPort->requiredAction = 0;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ volatile uint32_t *p_BmiCfgReg = NULL;
+ uint32_t tmpReg;
+
+ SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only"));
+ return;
+ }
+
+ p_BmiCfgReg = &p_FmPort->port.bmi_regs->tx.fmbm_tfca;
+ tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK;
+ tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED;
+ tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT)
+ & BMI_CMD_ATTR_MACCMD_SC_MASK);
+
+ WRITE_UINT32(*p_BmiCfgReg, tmpReg);
+}
+
+uint8_t FmPortGetNetEnvId(t_Handle h_FmPort)
+{
+ return ((t_FmPort*)h_FmPort)->netEnvId;
+}
+
+uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort)
+{
+ return ((t_FmPort*)h_FmPort)->hardwarePortId;
+}
+
+uint32_t FmPortGetPcdEngines(t_Handle h_FmPort)
+{
+ return ((t_FmPort*)h_FmPort)->pcdEngines;
+}
+
+#if (DPAA_VERSION >= 11)
+t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc,
+ void **p_Value)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint32_t muramPageOffset;
+
+ ASSERT_COND(p_FmPort);
+ ASSERT_COND(p_Value);
+
+ if (p_FmPort->gprFunc != e_FM_PORT_GPR_EMPTY)
+ {
+ if (p_FmPort->gprFunc != gprFunc)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("gpr was assigned with different func"));
+ }
+ else
+ {
+ switch (gprFunc)
+ {
+ case (e_FM_PORT_GPR_MURAM_PAGE):
+ p_FmPort->p_ParamsPage = FM_MURAM_AllocMem(p_FmPort->h_FmMuram,
+ 256, 8);
+ if (!p_FmPort->p_ParamsPage)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for page"));
+
+ IOMemSet32(p_FmPort->p_ParamsPage, 0, 256);
+ muramPageOffset =
+ (uint32_t)(XX_VirtToPhys(p_FmPort->p_ParamsPage)
+ - p_FmPort->fmMuramPhysBaseAddr);
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ WRITE_UINT32(
+ p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr,
+ muramPageOffset);
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ WRITE_UINT32(
+ p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ogpr,
+ muramPageOffset);
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Invalid port type"));
+ }
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+ p_FmPort->gprFunc = gprFunc;
+ }
+
+ switch (p_FmPort->gprFunc)
+ {
+ case (e_FM_PORT_GPR_MURAM_PAGE):
+ *p_Value = p_FmPort->p_ParamsPage;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Error FmPortGetSetCcParams(t_Handle h_FmPort,
+ t_FmPortGetSetCcParams *p_CcParams)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int tmpInt;
+ volatile uint32_t *p_BmiPrsStartOffset = NULL;
+
+ /* this function called from Cc for pass and receive parameters port params between CC and PORT*/
+
+ if ((p_CcParams->getCcParams.type & OFFSET_OF_PR)
+ && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE))
+ {
+ p_CcParams->getCcParams.prOffset =
+ (uint8_t)p_FmPort->bufferOffsets.prsResultOffset;
+ p_CcParams->getCcParams.type &= ~OFFSET_OF_PR;
+ }
+ if (p_CcParams->getCcParams.type & HW_PORT_ID)
+ {
+ p_CcParams->getCcParams.hardwarePortId =
+ (uint8_t)p_FmPort->hardwarePortId;
+ p_CcParams->getCcParams.type &= ~HW_PORT_ID;
+ }
+ if ((p_CcParams->getCcParams.type & OFFSET_OF_DATA)
+ && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE))
+ {
+ p_CcParams->getCcParams.dataOffset =
+ (uint16_t)p_FmPort->bufferOffsets.dataOffset;
+ p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA;
+ }
+ if (p_CcParams->getCcParams.type & NUM_OF_TASKS)
+ {
+ p_CcParams->getCcParams.numOfTasks = (uint8_t)p_FmPort->tasks.num;
+ p_CcParams->getCcParams.type &= ~NUM_OF_TASKS;
+ }
+ if (p_CcParams->getCcParams.type & NUM_OF_EXTRA_TASKS)
+ {
+ p_CcParams->getCcParams.numOfExtraTasks =
+ (uint8_t)p_FmPort->tasks.extra;
+ p_CcParams->getCcParams.type &= ~NUM_OF_EXTRA_TASKS;
+ }
+ if (p_CcParams->getCcParams.type & FM_REV)
+ {
+ p_CcParams->getCcParams.revInfo.majorRev = p_FmPort->fmRevInfo.majorRev;
+ p_CcParams->getCcParams.revInfo.minorRev = p_FmPort->fmRevInfo.minorRev;
+ p_CcParams->getCcParams.type &= ~FM_REV;
+ }
+ if (p_CcParams->getCcParams.type & DISCARD_MASK)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ p_CcParams->getCcParams.discardMask =
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm);
+ else
+ p_CcParams->getCcParams.discardMask =
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm);
+ p_CcParams->getCcParams.type &= ~DISCARD_MASK;
+ }
+ if (p_CcParams->getCcParams.type & MANIP_EXTRA_SPACE)
+ {
+ p_CcParams->getCcParams.internalBufferOffset =
+ p_FmPort->internalBufferOffset;
+ p_CcParams->getCcParams.type &= ~MANIP_EXTRA_SPACE;
+ }
+ if (p_CcParams->getCcParams.type & GET_NIA_FPNE)
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ p_CcParams->getCcParams.nia =
+ GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne);
+ else
+ p_CcParams->getCcParams.nia =
+ GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne);
+ p_CcParams->getCcParams.type &= ~GET_NIA_FPNE;
+ }
+ if (p_CcParams->getCcParams.type & GET_NIA_PNDN)
+ {
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ p_CcParams->getCcParams.nia =
+ GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn);
+ p_CcParams->getCcParams.type &= ~GET_NIA_PNDN;
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)
+ && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY))
+ {
+ p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY;
+ p_FmPort->orFmanCtrl = p_CcParams->setCcParams.orFmanCtrl;
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN)
+ && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN))
+ {
+ p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia;
+ p_FmPort->requiredAction |= UPDATE_NIA_PNEN;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN)
+ {
+ if (p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("PNEN was defined previously different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN)
+ && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN))
+ {
+ p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia;
+ p_FmPort->requiredAction |= UPDATE_NIA_PNDN;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_NIA_PNDN)
+ {
+ if (p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("PNDN was defined previously different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_NIA_FENE)
+ && (p_CcParams->setCcParams.overwrite
+ || !(p_FmPort->requiredAction & UPDATE_NIA_FENE)))
+ {
+ p_FmPort->savedBmiFene = p_CcParams->setCcParams.nia;
+ p_FmPort->requiredAction |= UPDATE_NIA_FENE;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_NIA_FENE)
+ {
+ if (p_FmPort->savedBmiFene != p_CcParams->setCcParams.nia)
+ RETURN_ERROR( MAJOR, E_INVALID_STATE,
+ ("xFENE was defined previously different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_NIA_FPNE)
+ && !(p_FmPort->requiredAction & UPDATE_NIA_FPNE))
+ {
+ p_FmPort->savedBmiFpne = p_CcParams->setCcParams.nia;
+ p_FmPort->requiredAction |= UPDATE_NIA_FPNE;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_NIA_FPNE)
+ {
+ if (p_FmPort->savedBmiFpne != p_CcParams->setCcParams.nia)
+ RETURN_ERROR( MAJOR, E_INVALID_STATE,
+ ("xFPNE was defined previously different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_NIA_CMNE)
+ && !(p_FmPort->requiredAction & UPDATE_NIA_CMNE))
+ {
+ p_FmPort->savedBmiCmne = p_CcParams->setCcParams.nia;
+ p_FmPort->requiredAction |= UPDATE_NIA_CMNE;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_NIA_CMNE)
+ {
+ if (p_FmPort->savedBmiCmne != p_CcParams->setCcParams.nia)
+ RETURN_ERROR( MAJOR, E_INVALID_STATE,
+ ("xCMNE was defined previously different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_PSO)
+ && !(p_FmPort->requiredAction & UPDATE_PSO))
+ {
+ /* get PCD registers pointers */
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ }
+
+ /* set start parsing offset */
+ tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset)
+ + p_CcParams->setCcParams.psoSize;
+ if (tmpInt > 0)
+ WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt);
+
+ p_FmPort->requiredAction |= UPDATE_PSO;
+ p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize;
+ }
+ else
+ if (p_CcParams->setCcParams.type & UPDATE_PSO)
+ {
+ if (p_FmPort->savedPrsStartOffset
+ != p_CcParams->setCcParams.psoSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("parser start offset was defoned previousley different"));
+ }
+
+ if ((p_CcParams->setCcParams.type & UPDATE_OFP_DPTE)
+ && !(p_FmPort->requiredAction & UPDATE_OFP_DPTE))
+ {
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ p_FmPort->savedBmiOfp = GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp);
+ p_FmPort->savedBmiOfp &= ~BMI_FIFO_PIPELINE_DEPTH_MASK;
+ p_FmPort->savedBmiOfp |= p_CcParams->setCcParams.ofpDpde
+ << BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ p_FmPort->requiredAction |= UPDATE_OFP_DPTE;
+ }
+
+ return E_OK;
+}
+/*********************** End of inter-module routines ************************/
+
+/****************************************/
+/* API Init unit functions */
+/****************************************/
+
+t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams)
+{
+ t_FmPort *p_FmPort;
+ uintptr_t baseAddr = p_FmPortParams->baseAddr;
+ uint32_t tmpReg;
+
+ /* Allocate FM structure */
+ p_FmPort = (t_FmPort *)XX_Malloc(sizeof(t_FmPort));
+ if (!p_FmPort)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure"));
+ return NULL;
+ }
+ memset(p_FmPort, 0, sizeof(t_FmPort));
+
+ /* Allocate the FM driver's parameters structure */
+ p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc(
+ sizeof(t_FmPortDriverParam));
+ if (!p_FmPort->p_FmPortDriverParam)
+ {
+ XX_Free(p_FmPort);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters"));
+ return NULL;
+ }
+ memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam));
+
+ /* Initialize FM port parameters which will be kept by the driver */
+ p_FmPort->portType = p_FmPortParams->portType;
+ p_FmPort->portId = p_FmPortParams->portId;
+ p_FmPort->pcdEngines = FM_PCD_NONE;
+ p_FmPort->f_Exception = p_FmPortParams->f_Exception;
+ p_FmPort->h_App = p_FmPortParams->h_App;
+ p_FmPort->h_Fm = p_FmPortParams->h_Fm;
+
+ /* get FM revision */
+ FM_GetRevision(p_FmPort->h_Fm, &p_FmPort->fmRevInfo);
+
+ /* calculate global portId number */
+ p_FmPort->hardwarePortId = SwPortIdToHwPortId(p_FmPort->portType,
+ p_FmPortParams->portId,
+ p_FmPort->fmRevInfo.majorRev,
+ p_FmPort->fmRevInfo.minorRev);
+
+ if (p_FmPort->fmRevInfo.majorRev >= 6)
+ {
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ && (p_FmPortParams->portId != FM_OH_PORT_ID))
+ DBG(WARNING,
+ ("Port ID %d is recommended for HC port. Overwriting HW defaults to be suitable for HC.",
+ FM_OH_PORT_ID));
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ && (p_FmPortParams->portId == FM_OH_PORT_ID))
+ DBG(WARNING, ("Use non-zero portId for OP port due to insufficient resources on portId 0."));
+ }
+
+ /* Set up FM port parameters for initialization phase only */
+
+ /* First, fill in flibs struct */
+ fman_port_defconfig(&p_FmPort->p_FmPortDriverParam->dfltCfg,
+ (enum fman_port_type)p_FmPort->portType);
+ /* Overwrite some integration specific parameters */
+ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation =
+ DEFAULT_PORT_rxFifoPriElevationLevel;
+ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr =
+ DEFAULT_PORT_rxFifoThreshold;
+
+#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006)
+ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = TRUE;
+#else
+ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = FALSE;
+#endif
+ if ((p_FmPort->fmRevInfo.majorRev == 6)
+ && (p_FmPort->fmRevInfo.minorRev == 0))
+ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = TRUE;
+ else
+ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = FALSE;
+
+ /* Excessive Threshold register - exists for pre-FMv3 chips only */
+ if (p_FmPort->fmRevInfo.majorRev < 6)
+ {
+#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC
+ p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register =
+ TRUE;
+#endif
+ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = FALSE;
+ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = FALSE;
+ }
+ else
+ {
+ p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register =
+ FALSE;
+ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = TRUE;
+ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = TRUE;
+ }
+ if (p_FmPort->fmRevInfo.majorRev == 4)
+ p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = FALSE;
+ else
+ p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = TRUE;
+
+ /* Continue with other parameters */
+ p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr;
+ /* set memory map pointers */
+ p_FmPort->p_FmPortQmiRegs =
+ (t_FmPortQmiRegs *)UINT_TO_PTR(baseAddr + QMI_PORT_REGS_OFFSET);
+ p_FmPort->p_FmPortBmiRegs =
+ (u_FmPortBmiRegs *)UINT_TO_PTR(baseAddr + BMI_PORT_REGS_OFFSET);
+ p_FmPort->p_FmPortPrsRegs =
+ (t_FmPortPrsRegs *)UINT_TO_PTR(baseAddr + PRS_PORT_REGS_OFFSET);
+
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize =
+ DEFAULT_PORT_bufferPrefixContent_privDataSize;
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult =
+ DEFAULT_PORT_bufferPrefixContent_passPrsResult;
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp =
+ DEFAULT_PORT_bufferPrefixContent_passTimeStamp;
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo =
+ DEFAULT_PORT_bufferPrefixContent_passTimeStamp;
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign =
+ DEFAULT_PORT_bufferPrefixContent_dataAlign;
+ /* p_FmPort->p_FmPortDriverParam->dmaSwapData = (e_FmDmaSwapOption)DEFAULT_PORT_dmaSwapData;
+ p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaIntContextCacheAttr;
+ p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaHeaderCacheAttr;
+ p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaScatterGatherCacheAttr;
+ p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = DEFAULT_PORT_dmaWriteOptimize;
+ */
+ p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase;
+ p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore =
+ DEFAULT_PORT_cheksumLastBytesIgnore;
+
+ p_FmPort->maxFrameLength = DEFAULT_PORT_maxFrameLength;
+ /* resource distribution. */
+ p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)
+ * BMI_FIFO_UNITS;
+ p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraNumOfFifoBufs
+ * BMI_FIFO_UNITS;
+ p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType);
+ p_FmPort->openDmas.extra =
+ DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType);
+ p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType);
+ p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType);
+
+
+#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+ if ((p_FmPort->fmRevInfo.majorRev == 6)
+ && (p_FmPort->fmRevInfo.minorRev == 0)
+ && ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)))
+ {
+ p_FmPort->openDmas.num = 16;
+ p_FmPort->openDmas.extra = 0;
+ }
+#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
+
+ /* Port type specific initialization: */
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX):
+ case (e_FM_PORT_TYPE_RX_10G):
+ /* Initialize FM port parameters for initialization phase only */
+ p_FmPort->p_FmPortDriverParam->cutBytesFromEnd =
+ DEFAULT_PORT_cutBytesFromEnd;
+ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE;
+ p_FmPort->p_FmPortDriverParam->frmDiscardOverride =
+ DEFAULT_PORT_frmDiscardOverride;
+
+ tmpReg =
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfp);
+ p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel =
+ (((tmpReg & BMI_RX_FIFO_PRI_ELEVATION_MASK)
+ >> BMI_RX_FIFO_PRI_ELEVATION_SHIFT) + 1)
+ * BMI_FIFO_UNITS;
+ p_FmPort->p_FmPortDriverParam->rxFifoThreshold = (((tmpReg
+ & BMI_RX_FIFO_THRESHOLD_MASK)
+ >> BMI_RX_FIFO_THRESHOLD_SHIFT) + 1) * BMI_FIFO_UNITS;
+
+ p_FmPort->p_FmPortDriverParam->bufMargins.endMargins =
+ DEFAULT_PORT_BufMargins_endMargins;
+ p_FmPort->p_FmPortDriverParam->errorsToDiscard =
+ DEFAULT_PORT_errorsToDiscard;
+ p_FmPort->p_FmPortDriverParam->forwardReuseIntContext =
+ DEFAULT_PORT_forwardIntContextReuse;
+#if (DPAA_VERSION >= 11)
+ p_FmPort->p_FmPortDriverParam->noScatherGather =
+ DEFAULT_PORT_noScatherGather;
+#endif /* (DPAA_VERSION >= 11) */
+ break;
+
+ case (e_FM_PORT_TYPE_TX):
+ p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE;
+#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
+ tmpReg = 0x00001013;
+ WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp,
+ tmpReg);
+#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */
+
+ /* fall through */
+ case (e_FM_PORT_TYPE_TX_10G):
+ tmpReg =
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp);
+ p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = ((tmpReg
+ & BMI_TX_FIFO_MIN_FILL_MASK)
+ >> BMI_TX_FIFO_MIN_FILL_SHIFT) * BMI_FIFO_UNITS;
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
+ (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK)
+ >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1);
+ p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = (((tmpReg
+ & BMI_TX_LOW_COMF_MASK) >> BMI_TX_LOW_COMF_SHIFT) + 1)
+ * BMI_FIFO_UNITS;
+
+ p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType;
+ p_FmPort->p_FmPortDriverParam->deqPrefetchOption =
+ DEFAULT_PORT_deqPrefetchOption;
+ p_FmPort->p_FmPortDriverParam->deqHighPriority =
+ (bool)((p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqHighPriority_1G :
+ DEFAULT_PORT_deqHighPriority_10G);
+ p_FmPort->p_FmPortDriverParam->deqByteCnt =
+ (uint16_t)(
+ (p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqByteCnt_1G :
+ DEFAULT_PORT_deqByteCnt_10G);
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_FmPort->p_FmPortDriverParam->errorsToDiscard =
+ DEFAULT_PORT_errorsToDiscard;
+#if (DPAA_VERSION >= 11)
+ p_FmPort->p_FmPortDriverParam->noScatherGather =
+ DEFAULT_PORT_noScatherGather;
+#endif /* (DPAA_VERSION >= 11) */
+ /* fall through */
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ p_FmPort->p_FmPortDriverParam->deqPrefetchOption =
+ DEFAULT_PORT_deqPrefetchOption_HC;
+ p_FmPort->p_FmPortDriverParam->deqHighPriority =
+ DEFAULT_PORT_deqHighPriority_1G;
+ p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType;
+ p_FmPort->p_FmPortDriverParam->deqByteCnt =
+ DEFAULT_PORT_deqByteCnt_1G;
+
+ tmpReg =
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofp);
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
+ (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK)
+ >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ && (p_FmPortParams->portId != FM_OH_PORT_ID))
+ {
+ /* Overwrite HC defaults */
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
+ DEFAULT_PORT_fifoDeqPipelineDepth_OH;
+ }
+
+#ifndef FM_FRAME_END_PARAMS_FOR_OP
+ if (p_FmPort->fmRevInfo.majorRev < 6)
+ p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_notSupported;
+#endif /* !FM_FRAME_END_PARAMS_FOR_OP */
+
+#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
+ if (!((p_FmPort->fmRevInfo.majorRev == 4) ||
+ (p_FmPort->fmRevInfo.majorRev >= 6)))
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = DEFAULT_notSupported;
+#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
+ break;
+
+ default:
+ XX_Free(p_FmPort->p_FmPortDriverParam);
+ XX_Free(p_FmPort);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ return NULL;
+ }
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_FmPort->fmRevInfo.majorRev == 4)
+ p_FmPort->p_FmPortDriverParam->deqPrefetchOption = (e_FmPortDeqPrefetchOption)DEFAULT_notSupported;
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ p_FmPort->imEn = p_FmPortParams->independentModeEnable;
+
+ if (p_FmPort->imEn)
+ {
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G))
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
+ DEFAULT_PORT_fifoDeqPipelineDepth_IM;
+ FmPortConfigIM(p_FmPort, p_FmPortParams);
+ }
+ else
+ {
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX):
+ case (e_FM_PORT_TYPE_RX_10G):
+ /* Initialize FM port parameters for initialization phase only */
+ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools,
+ &p_FmPortParams->specificParams.rxParams.extBufPools,
+ sizeof(t_FmExtPools));
+ p_FmPort->p_FmPortDriverParam->errFqid =
+ p_FmPortParams->specificParams.rxParams.errFqid;
+ p_FmPort->p_FmPortDriverParam->dfltFqid =
+ p_FmPortParams->specificParams.rxParams.dfltFqid;
+ p_FmPort->p_FmPortDriverParam->liodnOffset =
+ p_FmPortParams->specificParams.rxParams.liodnOffset;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ case (e_FM_PORT_TYPE_TX):
+ case (e_FM_PORT_TYPE_TX_10G):
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ p_FmPort->p_FmPortDriverParam->errFqid =
+ p_FmPortParams->specificParams.nonRxParams.errFqid;
+ p_FmPort->p_FmPortDriverParam->deqSubPortal =
+ (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel
+ & QMI_DEQ_CFG_SUBPORTAL_MASK);
+ p_FmPort->p_FmPortDriverParam->dfltFqid =
+ p_FmPortParams->specificParams.nonRxParams.dfltFqid;
+ break;
+ default:
+ XX_Free(p_FmPort->p_FmPortDriverParam);
+ XX_Free(p_FmPort);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ return NULL;
+ }
+ }
+
+ memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint(
+ p_FmPort->name,
+ "FM-%d-port-%s-%d",
+ FmGetId(p_FmPort->h_Fm),
+ ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? "OH" :
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX ? "1g-RX" :
+ (p_FmPort->portType == e_FM_PORT_TYPE_TX ? "1g-TX" :
+ (p_FmPort->portType
+ == e_FM_PORT_TYPE_RX_10G ? "10g-RX" :
+ "10g-TX")))),
+ p_FmPort->portId) == 0)
+ {
+ XX_Free(p_FmPort->p_FmPortDriverParam);
+ XX_Free(p_FmPort);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ return NULL;
+ }
+
+ p_FmPort->h_Spinlock = XX_InitSpinlock();
+ if (!p_FmPort->h_Spinlock)
+ {
+ XX_Free(p_FmPort->p_FmPortDriverParam);
+ XX_Free(p_FmPort);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ return NULL;
+ }
+
+ return p_FmPort;
+}
+
+t_FmPort *rx_port = 0;
+t_FmPort *tx_port = 0;
+
+/**************************************************************************//**
+ @Function FM_PORT_Init
+
+ @Description Initializes the FM module
+
+ @Param[in] h_FmPort - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+ *//***************************************************************************/
+t_Error FM_PORT_Init(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_FmPortDriverParam *p_DriverParams;
+ t_Error errCode;
+ t_FmInterModulePortInitParams fmParams;
+ t_FmRevisionInfo revInfo;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ errCode = FmSpBuildBufferStructure(
+ &p_FmPort->p_FmPortDriverParam->intContext,
+ &p_FmPort->p_FmPortDriverParam->bufferPrefixContent,
+ &p_FmPort->p_FmPortDriverParam->bufMargins,
+ &p_FmPort->bufferOffsets, &p_FmPort->internalBufferOffset);
+ if (errCode != E_OK)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+ if ((p_FmPort->p_FmPortDriverParam->bcbWorkaround) &&
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ {
+ p_FmPort->p_FmPortDriverParam->errorsToDiscard |= FM_PORT_FRM_ERR_PHYSICAL;
+ if (!p_FmPort->fifoBufs.num)
+ p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)*BMI_FIFO_UNITS;
+ p_FmPort->fifoBufs.num += 4*KILOBYTE;
+ }
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+ CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters);
+
+ p_DriverParams = p_FmPort->p_FmPortDriverParam;
+
+ /* Set up flibs port structure */
+ memset(&p_FmPort->port, 0, sizeof(struct fman_port));
+ p_FmPort->port.type = (enum fman_port_type)p_FmPort->portType;
+ FM_GetRevision(p_FmPort->h_Fm, &revInfo);
+ p_FmPort->port.fm_rev_maj = revInfo.majorRev;
+ p_FmPort->port.fm_rev_min = revInfo.minorRev;
+ p_FmPort->port.bmi_regs =
+ (union fman_port_bmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + BMI_PORT_REGS_OFFSET);
+ p_FmPort->port.qmi_regs =
+ (struct fman_port_qmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + QMI_PORT_REGS_OFFSET);
+ p_FmPort->port.ext_pools_num = (uint8_t)((revInfo.majorRev == 4) ? 4 : 8);
+ p_FmPort->port.im_en = p_FmPort->imEn;
+ p_FmPort->p_FmPortPrsRegs =
+ (t_FmPortPrsRegs *)UINT_TO_PTR(p_DriverParams->baseAddr + PRS_PORT_REGS_OFFSET);
+
+ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) && !p_FmPort->imEn)
+ {
+ /* Call the external Buffer routine which also checks fifo
+ size and updates it if necessary */
+ /* define external buffer pools and pool depletion*/
+ errCode = SetExtBufferPools(p_FmPort);
+ if (errCode)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+ /* check if the largest external buffer pool is large enough */
+ if (p_DriverParams->bufMargins.startMargins + MIN_EXT_BUF_SIZE
+ + p_DriverParams->bufMargins.endMargins
+ > p_FmPort->rxPoolsParams.largestBufSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", p_DriverParams->bufMargins.startMargins, p_DriverParams->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize));
+ }
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ {
+ {
+#ifdef FM_NO_OP_OBSERVED_POOLS
+ t_FmRevisionInfo revInfo;
+
+ FM_GetRevision(p_FmPort->h_Fm, &revInfo);
+ if ((revInfo.majorRev == 4) && (p_DriverParams->enBufPoolDepletion))
+#endif /* FM_NO_OP_OBSERVED_POOLS */
+ {
+ /* define external buffer pools */
+ errCode = SetExtBufferPools(p_FmPort);
+ if (errCode)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+ }
+ }
+ }
+
+ /************************************************************/
+ /* Call FM module routine for communicating parameters */
+ /************************************************************/
+ memset(&fmParams, 0, sizeof(fmParams));
+ fmParams.hardwarePortId = p_FmPort->hardwarePortId;
+ fmParams.portType = (e_FmPortType)p_FmPort->portType;
+ fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num;
+ fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra;
+ fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num;
+ fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra;
+
+ if (p_FmPort->fifoBufs.num)
+ {
+ errCode = VerifySizeOfFifo(p_FmPort);
+ if (errCode != E_OK)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+ }
+ fmParams.sizeOfFifo = p_FmPort->fifoBufs.num;
+ fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra;
+ fmParams.independentMode = p_FmPort->imEn;
+ fmParams.liodnOffset = p_DriverParams->liodnOffset;
+ fmParams.liodnBase = p_DriverParams->liodnBase;
+ fmParams.deqPipelineDepth =
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth;
+ fmParams.maxFrameLength = p_FmPort->maxFrameLength;
+#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ||
+ (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
+ {
+ if (!((p_FmPort->fmRevInfo.majorRev == 4) ||
+ (p_FmPort->fmRevInfo.majorRev >= 6)))
+ /* HC ports do not have fifoDeqPipelineDepth, but it is needed only
+ * for deq threshold calculation.
+ */
+ fmParams.deqPipelineDepth = 2;
+ }
+#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */
+
+ errCode = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams);
+ if (errCode)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+
+ /* get params for use in init */
+ p_FmPort->fmMuramPhysBaseAddr =
+ (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low)
+ | ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32));
+ p_FmPort->h_FmMuram = FmGetMuramHandle(p_FmPort->h_Fm);
+
+ errCode = InitLowLevelDriver(p_FmPort);
+ if (errCode != E_OK)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+
+ FmPortDriverParamFree(p_FmPort);
+
+#if (DPAA_VERSION >= 11)
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ {
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+
+ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
+ (void**)&p_ParamsPage);
+ ASSERT_COND(p_ParamsPage);
+
+ WRITE_UINT32(p_ParamsPage->misc, FM_CTL_PARAMS_PAGE_ALWAYS_ON);
+#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ {
+ WRITE_UINT32(
+ p_ParamsPage->misc,
+ (GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OP_FIX_EN));
+ WRITE_UINT32(
+ p_ParamsPage->discardMask,
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm));
+ }
+#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */
+#ifdef FM_ERROR_VSP_NO_MATCH_SW006
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(
+ p_ParamsPage->errorsDiscardMask,
+ (GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem)));
+ else
+ WRITE_UINT32(
+ p_ParamsPage->errorsDiscardMask,
+ (GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem)));
+#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_FmPort->deepSleepVars.autoResMaxSizes)
+ FmPortConfigAutoResForDeepSleepSupport1(p_FmPort);
+ return E_OK;
+}
+
+/**************************************************************************//**
+ @Function FM_PORT_Free
+
+ @Description Frees all resources that were assigned to FM module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmPort - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+ *//***************************************************************************/
+t_Error FM_PORT_Free(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_FmInterModulePortFreeParams fmParams;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+
+ if (p_FmPort->pcdEngines)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first."));
+
+ if (p_FmPort->enabled)
+ {
+ if (FM_PORT_Disable(p_FmPort) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED"));
+ }
+
+ if (p_FmPort->imEn)
+ FmPortImFree(p_FmPort);
+
+ FmPortDriverParamFree(p_FmPort);
+
+ memset(&fmParams, 0, sizeof(fmParams));
+ fmParams.hardwarePortId = p_FmPort->hardwarePortId;
+ fmParams.portType = (e_FmPortType)p_FmPort->portType;
+ fmParams.deqPipelineDepth =
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth;
+
+ FmFreePortParams(p_FmPort->h_Fm, &fmParams);
+
+#if (DPAA_VERSION >= 11)
+ if (FmVSPFreeForPort(p_FmPort->h_Fm, p_FmPort->portType, p_FmPort->portId)
+ != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("VSP free of port FAILED"));
+
+ if (p_FmPort->p_ParamsPage)
+ FM_MURAM_FreeMem(p_FmPort->h_FmMuram, p_FmPort->p_ParamsPage);
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_FmPort->h_Spinlock)
+ XX_FreeSpinlock(p_FmPort->h_Spinlock);
+
+ XX_Free(p_FmPort);
+
+ return E_OK;
+}
+
+/*************************************************/
+/* API Advanced Init unit functions */
+/*************************************************/
+
+t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->setNumOfOpenDmas = TRUE;
+ memcpy(&p_FmPort->openDmas, p_OpenDmas, sizeof(t_FmPortRsrc));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc));
+ p_FmPort->p_FmPortDriverParam->setNumOfTasks = TRUE;
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->setSizeOfFifo = TRUE;
+ memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_high_pri = highPri;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("not available for Rx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_type =
+ (enum fman_port_deq_type)deqType;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDeqPrefetchOption(
+ t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("not available for Rx ports"));
+ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_prefetch_opt =
+ (enum fman_port_deq_prefetch)deqPrefetchOption;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort,
+ t_FmBackupBmPools *p_BackupBmPools)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->p_BackupBmPools =
+ (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools));
+ if (!p_FmPort->p_FmPortDriverParam->p_BackupBmPools)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed"));
+ memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools,
+ sizeof(t_FmBackupBmPools));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("not available for Rx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_byte_cnt = deqByteCnt;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigBufferPrefixContent(
+ t_Handle h_FmPort, t_FmBufferPrefixContent *p_FmBufferPrefixContent)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent,
+ p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent));
+ /* if dataAlign was not initialized by user, we return to driver's default */
+ if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign)
+ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign =
+ DEFAULT_PORT_bufferPrefixContent_dataAlign;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort,
+ uint8_t checksumLastBytesIgnore)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.checksum_bytes_ignore =
+ checksumLastBytesIgnore;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort,
+ uint8_t cutBytesFromEnd)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_cut_end_bytes = cutBytesFromEnd;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort,
+ t_FmBufPoolDepletion *p_BufPoolDepletion)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE;
+ memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion,
+ sizeof(t_FmBufPoolDepletion));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigObservedPoolDepletion(
+ t_Handle h_FmPort,
+ t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for OP ports only"));
+
+ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE;
+ memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion,
+ &p_FmPortObservedBufPoolDepletion->poolDepletionParams,
+ sizeof(t_FmBufPoolDepletion));
+ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools,
+ &p_FmPortObservedBufPoolDepletion->poolsParams,
+ sizeof(t_FmExtPools));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for OP ports only"));
+
+ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmExtPools,
+ sizeof(t_FmExtPools));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Tx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ p_FmPort->p_FmPortDriverParam->dfltCfg.color = (enum fman_port_color)color;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("Not available for Tx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.sync_req = syncReq;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("Not available for Tx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.discard_override = override;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort,
+ fmPortFrameErrSelect_t errs)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_swap_data =
+ (enum fman_port_dma_swap)swapData;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort,
+ e_FmDmaCacheOption intContextCacheAttr)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_ic_stash_on =
+ (bool)(intContextCacheAttr == e_FM_DMA_STASH);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort,
+ e_FmDmaCacheOption headerCacheAttr)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_header_stash_on =
+ (bool)(headerCacheAttr == e_FM_DMA_STASH);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDmaScatterGatherAttr(
+ t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_sg_stash_on =
+ (bool)(scatterGatherCacheAttr == e_FM_DMA_STASH);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("Not available for Tx ports"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_write_optimize = optimize;
+
+ return E_OK;
+}
+
+#if (DPAA_VERSION >= 11)
+t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ UNUSED(noScatherGather);
+ UNUSED(p_FmPort);
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->noScatherGather = noScatherGather;
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort,
+ bool forwardReuse)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->maxFrameLength = length;
+
+ return E_OK;
+}
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->p_FmPortDriverParam->bcbWorkaround = TRUE;
+
+ return E_OK;
+}
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+/****************************************************/
+/* Hidden-DEBUG Only API */
+/****************************************************/
+
+t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort,
+ uint32_t minFillLevel)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Tx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_min_level = minFillLevel;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort,
+ uint8_t deqPipelineDepth)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("Not available for Rx ports"));
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("Not available for IM ports!"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth =
+ deqPipelineDepth;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort,
+ uint32_t fifoLowComfLevel)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_TX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Tx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_low_comf_level =
+ fifoLowComfLevel;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = fifoThreshold;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort,
+ uint32_t priElevationLevel)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = priElevationLevel;
+
+ return E_OK;
+}
+/****************************************************/
+/* API Run-time Control unit functions */
+/****************************************************/
+
+t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort,
+ t_FmPortRsrc *p_NumOfOpenDmas)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS))
+ RETURN_ERROR( MAJOR, E_INVALID_VALUE,
+ ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS));
+ if (p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS));
+ err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
+ (uint8_t*)&p_NumOfOpenDmas->num,
+ (uint8_t*)&p_NumOfOpenDmas->extra, FALSE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ /* only driver uses host command port, so ASSERT rather than RETURN_ERROR */
+ ASSERT_COND(p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND);
+
+ if ((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS));
+ if (p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS));
+
+ err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
+ (uint8_t*)&p_NumOfTasks->num,
+ (uint8_t*)&p_NumOfTasks->extra, FALSE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /* update driver's struct */
+ memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc));
+ return E_OK;
+}
+
+t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if (!p_SizeOfFifo->num || (p_SizeOfFifo->num > MAX_PORT_FIFO_SIZE))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("SizeOfFifo-num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE));
+ if (p_SizeOfFifo->num % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS));
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ /* extra FIFO size (allowed only to Rx ports) */
+ if (p_SizeOfFifo->extra % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS));
+ }
+ else
+ if (p_SizeOfFifo->extra)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ (" No SizeOfFifo-extra for non Rx ports"));
+
+ memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc));
+
+ /* we do not change user's parameter */
+ err = VerifySizeOfFifo(p_FmPort);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ err = FmSetSizeOfFifo(p_FmPort->h_Fm, p_FmPort->hardwarePortId,
+ &p_SizeOfFifo->num, &p_SizeOfFifo->extra, FALSE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ 0);
+
+ return p_FmPort->bufferOffsets.dataOffset;
+}
+
+uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ NULL);
+
+ if (p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset);
+}
+
+t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ NULL);
+
+ if (p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset);
+}
+
+uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ NULL);
+
+ if (p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset);
+}
+
+uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ NULL);
+
+ if (p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset);
+}
+
+t_Error FM_PORT_Disable(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ FmPortImDisable(p_FmPort);
+
+ err = fman_port_disable(&p_FmPort->port);
+ if (err == -EBUSY)
+ {
+ DBG(WARNING, ("%s: BMI or QMI is Busy. Port forced down",
+ p_FmPort->name));
+ }
+ else
+ if (err != 0)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_disable"));
+ }
+
+ p_FmPort->enabled = FALSE;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_Enable(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ /* Used by FM_PORT_Free routine as indication
+ if to disable port. Thus set it to TRUE prior
+ to enabling itself. This way if part of enable
+ process fails there will be still things
+ to disable during Free. For example, if BMI
+ enable succeeded but QMI failed, still BMI
+ needs to be disabled by Free. */
+ p_FmPort->enabled = TRUE;
+
+ if (p_FmPort->imEn)
+ FmPortImEnable(p_FmPort);
+
+ err = fman_port_enable(&p_FmPort->port);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_enable"));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint8_t factor, countUnitBit;
+ uint16_t baseGran;
+ struct fman_port_rate_limiter params;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_TX_10G):
+ case (e_FM_PORT_TYPE_TX):
+ baseGran = BMI_RATE_LIMIT_GRAN_TX;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ baseGran = BMI_RATE_LIMIT_GRAN_OP;
+ break;
+ default:
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Tx and Offline parsing ports only"));
+ }
+
+ countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */
+ /* normally, we use 1 usec as the reference count */
+ factor = 1;
+ /* if ratelimit is too small for a 1usec factor, multiply the factor */
+ while (p_RateLimit->rateLimit < baseGran / factor)
+ {
+ if (countUnitBit == 31)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small"));
+
+ countUnitBit++;
+ factor <<= 1;
+ }
+ /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/
+ if (p_RateLimit->rateLimit
+ > ((uint32_t)baseGran * (1 << 10) * (uint32_t)factor))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large"));
+
+ if (!p_RateLimit->maxBurstSize
+ || (p_RateLimit->maxBurstSize > BMI_RATE_LIMIT_MAX_BURST_SIZE))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("maxBurstSize must be between 1K and %dk", BMI_RATE_LIMIT_MAX_BURST_SIZE));
+
+ params.count_1micro_bit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm);
+ params.high_burst_size_gran = FALSE;
+ params.burst_size = p_RateLimit->maxBurstSize;
+ params.rate = p_RateLimit->rateLimit;
+ params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE;
+
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ {
+#ifndef FM_NO_ADVANCED_RATE_LIMITER
+
+ if ((p_FmPort->fmRevInfo.majorRev == 4)
+ || (p_FmPort->fmRevInfo.majorRev >= 6))
+ {
+ params.high_burst_size_gran = TRUE;
+ }
+ else
+#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */
+ {
+ if (p_RateLimit->rateLimitDivider
+ != e_FM_PORT_DUAL_RATE_LIMITER_NONE)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("FM_PORT_ConfigDualRateLimitScaleDown"));
+
+ if (p_RateLimit->maxBurstSize % 1000)
+ {
+ p_RateLimit->maxBurstSize =
+ (uint16_t)((p_RateLimit->maxBurstSize / 1000) + 1);
+ DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000));
+ }
+ else
+ p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize
+ / 1000);
+ }
+ params.rate_factor =
+ (enum fman_port_rate_limiter_scale_down)p_RateLimit->rateLimitDivider;
+ params.burst_size = p_RateLimit->maxBurstSize;
+ }
+
+ err = fman_port_set_rate_limiter(&p_FmPort->port, &params);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter"));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Tx and Offline parsing ports only"));
+
+ err = fman_port_delete_rate_limiter(&p_FmPort->port);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter"));
+ return E_OK;
+}
+
+t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio,
+ uint8_t wq)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint32_t tmpReg;
+ uint32_t wqTmpReg;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("PFC mapping is available for Tx ports only"));
+
+ if (prio > 7)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
+ ("PFC priority (%d) is out of range (0-7)", prio));
+ if (wq > 7)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
+ ("WQ (%d) is out of range (0-7)", wq));
+
+ tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0]);
+ tmpReg &= ~(0xf << ((7 - prio) * 4));
+ wqTmpReg = ((uint32_t)wq << ((7 - prio) * 4));
+ tmpReg |= wqTmpReg;
+
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0],
+ tmpReg);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ fman_port_set_queue_cnt_mode(&p_FmPort->port, enable);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ err = fman_port_set_perf_cnt_mode(&p_FmPort->port, enable);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_mode"));
+ return E_OK;
+}
+
+t_Error FM_PORT_SetPerformanceCountersParams(
+ t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ struct fman_port_perf_cnt_params params;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+
+ /* check parameters */
+ if (!p_FmPortPerformanceCnt->taskCompVal
+ || (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("taskCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->taskCompVal, p_FmPort->tasks.num));
+ if (!p_FmPortPerformanceCnt->dmaCompVal
+ || (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("dmaCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->dmaCompVal, p_FmPort->openDmas.num));
+ if (!p_FmPortPerformanceCnt->fifoCompVal
+ || (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoCompVal (%d) has to be in the range of 256 - %d (current value)!", p_FmPortPerformanceCnt->fifoCompVal, p_FmPort->fifoBufs.num));
+ if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("fifoCompVal (%d) has to be divisible by %d", p_FmPortPerformanceCnt->fifoCompVal, BMI_FIFO_UNITS));
+
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ if (!p_FmPortPerformanceCnt->queueCompVal
+ || (p_FmPortPerformanceCnt->queueCompVal
+ > MAX_PERFORMANCE_RX_QUEUE_COMP))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", MAX_PERFORMANCE_RX_QUEUE_COMP));
+ break;
+ case (e_FM_PORT_TYPE_TX_10G):
+ case (e_FM_PORT_TYPE_TX):
+ if (!p_FmPortPerformanceCnt->queueCompVal
+ || (p_FmPortPerformanceCnt->queueCompVal
+ > MAX_PERFORMANCE_TX_QUEUE_COMP))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", MAX_PERFORMANCE_TX_QUEUE_COMP));
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ if (p_FmPortPerformanceCnt->queueCompVal)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("performanceCnt.queueCompVal is not relevant for H/O ports."));
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ }
+
+ params.task_val = p_FmPortPerformanceCnt->taskCompVal;
+ params.queue_val = p_FmPortPerformanceCnt->queueCompVal;
+ params.dma_val = p_FmPortPerformanceCnt->dmaCompVal;
+ params.fifo_val = p_FmPortPerformanceCnt->fifoCompVal;
+
+ err = fman_port_set_perf_cnt_params(&p_FmPort->port, &params);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_params"));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_FmPortPerformanceCnt currParams, savedParams;
+ t_Error err;
+ bool underTest, failed = FALSE;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+
+ XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n",
+ p_FmPort->portType, p_FmPort->portId);
+
+ currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num;
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND))
+ currParams.queueCompVal = 0;
+ else
+ currParams.queueCompVal = 1;
+ currParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num;
+ currParams.fifoCompVal = p_FmPort->fifoBufs.num;
+
+ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
+ ClearPerfCnts(p_FmPort);
+ if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams))
+ != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ FM_PORT_SetPerformanceCounters(p_FmPort, TRUE);
+ XX_UDelay(1000000);
+ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
+ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL))
+ {
+ XX_Print(
+ "Max num of defined port tasks (%d) utilized - Please enlarge\n",
+ p_FmPort->tasks.num);
+ failed = TRUE;
+ }
+ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL))
+ {
+ XX_Print(
+ "Max num of defined port openDmas (%d) utilized - Please enlarge\n",
+ p_FmPort->openDmas.num);
+ failed = TRUE;
+ }
+ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL))
+ {
+ XX_Print(
+ "Max size of defined port fifo (%d) utilized - Please enlarge\n",
+ p_FmPort->fifoBufs.num);
+ failed = TRUE;
+ }
+ if (failed)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ memset(&savedParams, 0, sizeof(savedParams));
+ while (TRUE)
+ {
+ underTest = FALSE;
+ if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal)
+ {
+ currParams.taskCompVal--;
+ underTest = TRUE;
+ }
+ if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal)
+ {
+ currParams.dmaCompVal--;
+ underTest = TRUE;
+ }
+ if ((currParams.fifoCompVal != BMI_FIFO_UNITS)
+ && !savedParams.fifoCompVal)
+ {
+ currParams.fifoCompVal -= BMI_FIFO_UNITS;
+ underTest = TRUE;
+ }
+ if (!underTest)
+ break;
+
+ ClearPerfCnts(p_FmPort);
+ if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams))
+ != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ FM_PORT_SetPerformanceCounters(p_FmPort, TRUE);
+ XX_UDelay(1000000);
+ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE);
+
+ if (!savedParams.taskCompVal
+ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL))
+ savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal + 2);
+ if (!savedParams.dmaCompVal
+ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL))
+ savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal + 2);
+ if (!savedParams.fifoCompVal
+ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL))
+ savedParams.fifoCompVal = currParams.fifoCompVal
+ + (2 * BMI_FIFO_UNITS);
+ }
+
+ XX_Print("best vals: tasks %d, dmas %d, fifos %d\n",
+ savedParams.taskCompVal, savedParams.dmaCompVal,
+ savedParams.fifoCompVal);
+ return E_OK;
+}
+
+t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ err = fman_port_set_stats_cnt_mode(&p_FmPort->port, enable);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_stats_cnt_mode"));
+ return E_OK;
+}
+
+t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ volatile uint32_t *p_ErrDiscard = NULL;
+ int err;
+
+ UNUSED(p_ErrDiscard);
+ err = fman_port_set_err_mask(&p_FmPort->port, (uint32_t)errs);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_err_mask"));
+
+#ifdef FM_ERROR_VSP_NO_MATCH_SW006
+ if (p_FmPort->fmRevInfo.majorRev >= 6)
+ {
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+
+ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
+ (void**)&p_ParamsPage);
+ ASSERT_COND(p_ParamsPage);
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_ErrDiscard =
+ &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_ErrDiscard =
+ &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm;
+ break;
+ default:
+ RETURN_ERROR(
+ MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+ }
+ WRITE_UINT32(p_ParamsPage->errorsDiscardMask,
+ GET_UINT32(*p_ErrDiscard) | errs);
+ }
+#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId,
+ bool enable)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(poolId<BM_MAX_NUM_OF_POOLS, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ err = fman_port_set_bpool_cnt_mode(&p_FmPort->port, poolId, enable);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpool_cnt_mode"));
+ return E_OK;
+}
+
+t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)){
+ p_BmiStats->cntCycle =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
+ /* fmbm_rccn */
+ p_BmiStats->cntTaskUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
+ /* fmbm_rtuc */
+ p_BmiStats->cntQueueUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL);
+ /* fmbm_rrquc */
+ p_BmiStats->cntDmaUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
+ /* fmbm_rduc */
+ p_BmiStats->cntFifoUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
+ /* fmbm_rfuc */
+ p_BmiStats->cntRxPauseActivation =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION);
+ /* fmbm_rpac */
+ p_BmiStats->cntFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
+ /* fmbm_rfrc */
+ p_BmiStats->cntDiscardFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
+ /* fmbm_rfdc */
+ p_BmiStats->cntDeallocBuf =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
+ /* fmbm_rbdc */
+ p_BmiStats->cntRxBadFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_BAD_FRAME);
+ /* fmbm_rfbc */
+ p_BmiStats->cntRxLargeFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LARGE_FRAME);
+ /* fmbm_rlfc */
+ p_BmiStats->cntRxFilterFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME);
+ /* fmbm_rffc */
+ p_BmiStats->cntRxListDmaErr =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR);
+ /* fmbm_rfldec */
+ p_BmiStats->cntRxOutOfBuffersDiscard =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD);
+ /* fmbm_rodc */
+ p_BmiStats->cntWredDiscard = 0;
+ p_BmiStats->cntLengthErr = 0;
+ p_BmiStats->cntUnsupportedFormat = 0;
+ }
+ else if ((p_FmPort->portType == e_FM_PORT_TYPE_TX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)){
+ p_BmiStats->cntCycle =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
+ /* fmbm_tccn */
+ p_BmiStats->cntTaskUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
+ /* fmbm_ttuc */
+ p_BmiStats->cntQueueUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL);
+ /* fmbm_ttcquc */
+ p_BmiStats->cntDmaUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
+ /* fmbm_tduc */
+ p_BmiStats->cntFifoUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
+ /* fmbm_tfuc */
+ p_BmiStats->cntRxPauseActivation = 0;
+ p_BmiStats->cntFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
+ /* fmbm_tfrc */
+ p_BmiStats->cntDiscardFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
+ /* fmbm_tfdc */
+ p_BmiStats->cntDeallocBuf =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
+ /* fmbm_tbdc */
+ p_BmiStats->cntRxBadFrame = 0;
+ p_BmiStats->cntRxLargeFrame = 0;
+ p_BmiStats->cntRxFilterFrame = 0;
+ p_BmiStats->cntRxListDmaErr = 0;
+ p_BmiStats->cntRxOutOfBuffersDiscard = 0;
+ p_BmiStats->cntWredDiscard = 0;
+ p_BmiStats->cntLengthErr =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR);
+ /* fmbm_tfledc */
+ p_BmiStats->cntUnsupportedFormat =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT);
+ /* fmbm_tfufdc */
+ }
+ else if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) {
+ p_BmiStats->cntCycle =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE);
+ /* fmbm_occn */
+ p_BmiStats->cntTaskUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL);
+ /* fmbm_otuc */
+ p_BmiStats->cntQueueUtil = 0;
+ p_BmiStats->cntDmaUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL);
+ /* fmbm_oduc */
+ p_BmiStats->cntFifoUtil =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL);
+ /* fmbm_ofuc*/
+ p_BmiStats->cntRxPauseActivation = 0;
+ p_BmiStats->cntFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME);
+ /* fmbm_ofrc */
+ p_BmiStats->cntDiscardFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME);
+ /* fmbm_ofdc */
+ p_BmiStats->cntDeallocBuf =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF);
+ /* fmbm_obdc*/
+ p_BmiStats->cntRxBadFrame = 0;
+ p_BmiStats->cntRxLargeFrame = 0;
+ p_BmiStats->cntRxFilterFrame =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME);
+ /* fmbm_offc */
+ p_BmiStats->cntRxListDmaErr =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR);
+ /* fmbm_ofldec */
+ p_BmiStats->cntRxOutOfBuffersDiscard =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD);
+ /* fmbm_rodc */
+ p_BmiStats->cntWredDiscard =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_WRED_DISCARD);
+ /* fmbm_ofwdc */
+ p_BmiStats->cntLengthErr =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR);
+ /* fmbm_ofledc */
+ p_BmiStats->cntUnsupportedFormat =
+ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT);
+ /* fmbm_ofufdc */
+ }
+ return E_OK;
+}
+
+uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ bool bmiCounter = FALSE;
+ enum fman_port_stats_counters statsType;
+ enum fman_port_perf_counters perfType;
+ enum fman_port_qmi_counters queueType;
+ bool isStats;
+ t_Error errCode;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
+ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
+ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
+ /* check that counter is available for the port type */
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE,
+ ("Requested counter is not available for Rx ports"));
+ return 0;
+ }
+ bmiCounter = FALSE;
+ break;
+ case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+ bmiCounter = FALSE;
+ break;
+ default: /* BMI counters (or error - will be checked in BMI routine )*/
+ bmiCounter = TRUE;
+ break;
+ }
+
+ if (bmiCounter)
+ {
+ errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType,
+ &perfType, &isStats);
+ if (errCode != E_OK)
+ {
+ REPORT_ERROR(MINOR, errCode, NO_MSG);
+ return 0;
+ }
+ if (isStats)
+ return fman_port_get_stats_counter(&p_FmPort->port, statsType);
+ else
+ return fman_port_get_perf_counter(&p_FmPort->port, perfType);
+ }
+ else /* QMI counter */
+ {
+ /* check that counters are enabled */
+ if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc)
+ & QMI_PORT_CFG_EN_COUNTERS))
+
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled"));
+ return 0;
+ }
+
+ /* Set counter */
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+ queueType = E_FMAN_PORT_ENQ_TOTAL;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
+ queueType = E_FMAN_PORT_DEQ_TOTAL;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
+ queueType = E_FMAN_PORT_DEQ_FROM_DFLT;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
+ queueType = E_FMAN_PORT_DEQ_CONFIRM;
+ break;
+ default:
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available"));
+ return 0;
+ }
+
+ return fman_port_get_qmi_counter(&p_FmPort->port, queueType);
+ }
+
+ return 0;
+}
+
+t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter,
+ uint32_t value)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ bool bmiCounter = FALSE;
+ enum fman_port_stats_counters statsType;
+ enum fman_port_perf_counters perfType;
+ enum fman_port_qmi_counters queueType;
+ bool isStats;
+ t_Error errCode;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
+ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
+ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
+ /* check that counter is available for the port type */
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX)
+ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ RETURN_ERROR(
+ MINOR, E_INVALID_STATE,
+ ("Requested counter is not available for Rx ports"));
+ /* fall through */
+ case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+ bmiCounter = FALSE;
+ break;
+ default: /* BMI counters (or error - will be checked in BMI routine )*/
+ bmiCounter = TRUE;
+ break;
+ }
+
+ if (bmiCounter)
+ {
+ errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType,
+ &perfType, &isStats);
+ if (errCode != E_OK)
+ {
+ RETURN_ERROR(MINOR, errCode, NO_MSG);
+ }
+ if (isStats)
+ fman_port_set_stats_counter(&p_FmPort->port, statsType, value);
+ else
+ fman_port_set_perf_counter(&p_FmPort->port, perfType, value);
+ }
+ else /* QMI counter */
+ {
+ /* check that counters are enabled */
+ if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc)
+ & QMI_PORT_CFG_EN_COUNTERS))
+ {
+ RETURN_ERROR(MINOR, E_INVALID_STATE,
+ ("Requested counter was not enabled"));
+ }
+
+ /* Set counter */
+ switch (counter)
+ {
+ case (e_FM_PORT_COUNTERS_ENQ_TOTAL):
+ queueType = E_FMAN_PORT_ENQ_TOTAL;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_TOTAL):
+ queueType = E_FMAN_PORT_DEQ_TOTAL;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT):
+ queueType = E_FMAN_PORT_DEQ_FROM_DFLT;
+ break;
+ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM):
+ queueType = E_FMAN_PORT_DEQ_CONFIRM;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Requested counter is not available"));
+ }
+
+ fman_port_set_qmi_counter(&p_FmPort->port, queueType, value);
+ }
+
+ return E_OK;
+}
+
+uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports"));
+ return 0;
+ }
+ return fman_port_get_bpool_counter(&p_FmPort->port, poolId);
+}
+
+t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId,
+ uint32_t value)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ RETURN_ERROR( MINOR, E_INVALID_STATE,
+ ("Requested counter is not available for non-Rx ports"));
+
+ fman_port_set_bpool_counter(&p_FmPort->port, poolId, value);
+ return E_OK;
+}
+bool FM_PORT_IsStalled(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err;
+ bool isStalled;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE);
+ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE,
+ FALSE);
+
+ err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return TRUE;
+ }
+ return isStalled;
+}
+
+t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId);
+}
+
+t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for Rx ports only"));
+
+ if (l4Checksum)
+ err = fman_port_modify_rx_fd_bits(
+ &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24),
+ TRUE);
+ else
+ err = fman_port_modify_rx_fd_bits(
+ &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24),
+ FALSE);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_modify_rx_fd_bits"));
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+/* API Run-time PCD Control unit functions */
+/*****************************************************************************/
+
+#if (DPAA_VERSION >= 11)
+t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_VSPParams)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+ volatile uint32_t *p_BmiStorageProfileId = NULL, *p_BmiVspe = NULL;
+ uint32_t tmpReg = 0, tmp = 0;
+ uint16_t hwStoragePrflId;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->h_Fm, E_INVALID_HANDLE);
+ /*for numOfProfiles = 0 don't call this function*/
+ SANITY_CHECK_RETURN_ERROR(p_VSPParams->numOfProfiles, E_INVALID_VALUE);
+ /*dfltRelativeId should be in the range of numOfProfiles*/
+ SANITY_CHECK_RETURN_ERROR(
+ p_VSPParams->dfltRelativeId < p_VSPParams->numOfProfiles,
+ E_INVALID_VALUE);
+ /*p_FmPort should be from Rx type or OP*/
+ SANITY_CHECK_RETURN_ERROR(
+ ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)),
+ E_INVALID_VALUE);
+ /*port should be disabled*/
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->enabled, E_INVALID_STATE);
+ /*if its called for Rx port relevant Tx Port should be passed (initialized) too and it should be disabled*/
+ SANITY_CHECK_RETURN_ERROR(
+ ((p_VSPParams->h_FmTxPort && !((t_FmPort *)(p_VSPParams->h_FmTxPort))->enabled) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)),
+ E_INVALID_VALUE);
+ /*should be called before SetPCD - this port should be without PCD*/
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->pcdEngines, E_INVALID_STATE);
+
+ /*alloc window of VSPs for this port*/
+ err = FmVSPAllocForPort(p_FmPort->h_Fm, p_FmPort->portType,
+ p_FmPort->portId, p_VSPParams->numOfProfiles);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /*get absolute VSP ID for dfltRelative*/
+ err = FmVSPGetAbsoluteProfileId(p_FmPort->h_Fm, p_FmPort->portType,
+ p_FmPort->portId,
+ p_VSPParams->dfltRelativeId,
+ &hwStoragePrflId);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ /*fill relevant registers for p_FmPort and relative TxPort in the case p_FmPort from Rx type*/
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiStorageProfileId =
+ &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid);
+ p_BmiVspe =
+ &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfne);
+
+ tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK;
+ tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT;
+ WRITE_UINT32(*p_BmiStorageProfileId, tmpReg);
+
+ tmpReg = GET_UINT32(*p_BmiVspe);
+ WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN);
+
+ p_BmiStorageProfileId =
+ &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid;
+ p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpp;
+ hwStoragePrflId = p_VSPParams->dfltRelativeId;
+ break;
+
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ tmpReg = NIA_ENG_BMI | NIA_BMI_AC_FETCH_ALL_FRAME;
+ WRITE_UINT32( p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn,
+ tmpReg);
+
+ p_BmiStorageProfileId =
+ &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofqid;
+ p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opp;
+ tmp |= BMI_EBD_EN;
+ break;
+
+ default:
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+ }
+
+ p_FmPort->vspe = TRUE;
+ p_FmPort->dfltRelativeId = p_VSPParams->dfltRelativeId;
+
+ tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK;
+ tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT;
+ WRITE_UINT32(*p_BmiStorageProfileId, tmpReg);
+
+ tmpReg = GET_UINT32(*p_BmiVspe);
+ WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN | tmp);
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+
+ p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm);
+ ASSERT_COND(p_FmPort->h_FmPcd);
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ if (numOfProfiles)
+ {
+ err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd,
+ p_FmPort->hardwarePortId, numOfProfiles);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ /* set the port handle within the PCD policer, even if no profiles defined */
+ FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId);
+
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId);
+
+ RELEASE_LOCK(p_FmPort->lock);
+
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_PcdKgModifyInitialScheme(t_Handle h_FmPort,
+ t_FmPcdKgSchemeSelect *p_FmPcdKgScheme)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ volatile uint32_t *p_BmiHpnia = NULL;
+ uint32_t tmpReg;
+ uint8_t relativeSchemeId;
+ uint8_t physicalSchemeId;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
+ E_INVALID_STATE);
+
+ tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC) ? NIA_KG_CC_EN : 0);
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
+ break;
+ default:
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+ }
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ /* if we want to change to direct scheme, we need to check that this scheme is valid */
+ if (p_FmPcdKgScheme->direct)
+ {
+ physicalSchemeId = FmPcdKgGetSchemeId(p_FmPcdKgScheme->h_DirectScheme);
+ /* check that this scheme is bound to this port */
+ if (!(p_FmPort->schemesPerPortVector
+ & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId))))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(
+ MAJOR, E_INVALID_STATE,
+ ("called with a scheme that is not bound to this port"));
+ }
+
+ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd,
+ physicalSchemeId);
+ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE,
+ ("called with invalid Scheme "));
+ }
+
+ if (!FmPcdKgIsSchemeValidSw(p_FmPcdKgScheme->h_DirectScheme))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("called with uninitialized Scheme "));
+ }
+
+ WRITE_UINT32(
+ *p_BmiHpnia,
+ NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId);
+ }
+ else
+ /* change to indirect scheme */
+ WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg);
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_PcdPlcrModifyInitialProfile(t_Handle h_FmPort,
+ t_Handle h_Profile)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ volatile uint32_t *p_BmiNia;
+ volatile uint32_t *p_BmiHpnia;
+ uint32_t tmpReg;
+ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile);
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR,
+ E_INVALID_STATE);
+
+ /* check relevance of this routine - only when policer is used
+ directly after BMI or Parser */
+ if ((p_FmPort->pcdEngines & FM_PCD_KG)
+ || (p_FmPort->pcdEngines & FM_PCD_CC))
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR"));
+
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+ p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne;
+ tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne;
+ tmpReg = 0;
+ break;
+ default:
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+ }
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile"));
+ }
+
+ tmpReg |= (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId);
+
+ if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */
+ {
+ /* update BMI HPNIA */
+ WRITE_UINT32(*p_BmiHpnia, tmpReg);
+ }
+ else /* e_FM_PCD_SUPPORT_PLCR_ONLY */
+ {
+ /* rfne may contain FDCS bits, so first we read them. */
+ tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK);
+ /* update BMI NIA */
+ WRITE_UINT32(*p_BmiNia, tmpReg);
+ }RELEASE_LOCK(p_FmPort->lock);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_PcdCcModifyTree(t_Handle h_FmPort, t_Handle h_CcTree)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+ volatile uint32_t *p_BmiCcBase = NULL;
+ volatile uint32_t *p_BmiNia = NULL;
+ uint32_t ccTreePhysOffset;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(h_CcTree, E_INVALID_HANDLE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independent mode ports only"));
+
+ /* get PCD registers pointers */
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne;
+ break;
+ default:
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+ }
+
+ /* check that current NIA is BMI to BMI */
+ if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK)
+ != GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("may be called only for ports in BMI-to-BMI state."));
+
+ if (p_FmPort->pcdEngines & FM_PCD_CC)
+ {
+ if (p_FmPort->h_IpReassemblyManip)
+ {
+ err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, h_CcTree, NULL,
+ p_FmPort->h_IpReassemblyManip, FALSE);
+ if (err != E_OK)
+ {
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+ else
+ if (p_FmPort->h_CapwapReassemblyManip)
+ {
+ err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, h_CcTree, NULL,
+ p_FmPort->h_CapwapReassemblyManip,
+ FALSE);
+ if (err != E_OK)
+ {
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+ switch (p_FmPort->portType)
+ {
+ case (e_FM_PORT_TYPE_RX_10G):
+ case (e_FM_PORT_TYPE_RX):
+ p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb;
+ break;
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb;
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type"));
+ }
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+ err = FmPcdCcBindTree(p_FmPort->h_FmPcd, NULL, h_CcTree,
+ &ccTreePhysOffset, h_FmPort);
+ if (err)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset);
+
+ p_FmPort->ccTreeId = h_CcTree;
+ RELEASE_LOCK(p_FmPort->lock);
+ }
+ else
+ RETURN_ERROR( MAJOR, E_INVALID_STATE,
+ ("Coarse Classification not defined for this port."));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_AttachPCD(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independent mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ if (p_FmPort->h_ReassemblyTree)
+ p_FmPort->pcdEngines |= FM_PCD_CC;
+
+ err = AttachPCD(h_FmPort);
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return err;
+}
+
+t_Error FM_PORT_DetachPCD(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independent mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = DetachPCD(h_FmPort);
+ if (err != E_OK)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_FmPort->h_ReassemblyTree)
+ p_FmPort->pcdEngines &= ~FM_PCD_CC;
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParam)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+ t_FmPortPcdParams modifiedPcdParams, *p_PcdParams;
+ t_FmPcdCcTreeParams *p_FmPcdCcTreeParams;
+ t_FmPortPcdCcParams fmPortPcdCcParams;
+ t_FmPortGetSetCcParams fmPortGetSetCcParams;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_PcdParam, E_NULL_POINTER);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independent mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm);
+ ASSERT_COND(p_FmPort->h_FmPcd);
+
+ if (p_PcdParam->p_CcParams && !p_PcdParam->p_CcParams->h_CcTree)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE,
+ ("Tree handle must be given if CC is required"));
+
+ memcpy(&modifiedPcdParams, p_PcdParam, sizeof(t_FmPortPcdParams));
+ p_PcdParams = &modifiedPcdParams;
+ if ((p_PcdParams->h_IpReassemblyManip)
+#if (DPAA_VERSION >= 11)
+ || (p_PcdParams->h_CapwapReassemblyManip)
+#endif /* (DPAA_VERSION >= 11) */
+ )
+ {
+ if ((p_PcdParams->pcdSupport != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
+ && (p_PcdParams->pcdSupport
+ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC)
+ && (p_PcdParams->pcdSupport
+ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR)
+ && (p_PcdParams->pcdSupport
+ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR( MAJOR, E_INVALID_STATE,
+ ("pcdSupport must have KG for supporting Reassembly"));
+ }
+ p_FmPort->h_IpReassemblyManip = p_PcdParams->h_IpReassemblyManip;
+#if (DPAA_VERSION >= 11)
+ if ((p_PcdParams->h_IpReassemblyManip)
+ && (p_PcdParams->h_CapwapReassemblyManip))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("Either IP-R or CAPWAP-R is allowed"));
+ if ((p_PcdParams->h_CapwapReassemblyManip)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("CAPWAP-R is allowed only on offline-port"));
+ if (p_PcdParams->h_CapwapReassemblyManip)
+ p_FmPort->h_CapwapReassemblyManip =
+ p_PcdParams->h_CapwapReassemblyManip;
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (!p_PcdParams->p_CcParams)
+ {
+ if (!((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
+ || (p_PcdParams->pcdSupport
+ == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR)))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_STATE,
+ ("PCD initialization structure is not consistent with pcdSupport"));
+ }
+
+ /* No user-tree, need to build internal tree */
+ p_FmPcdCcTreeParams = (t_FmPcdCcTreeParams*)XX_Malloc(
+ sizeof(t_FmPcdCcTreeParams));
+ if (!p_FmPcdCcTreeParams)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcTreeParams"));
+ memset(p_FmPcdCcTreeParams, 0, sizeof(t_FmPcdCcTreeParams));
+ p_FmPcdCcTreeParams->h_NetEnv = p_PcdParams->h_NetEnv;
+ p_FmPort->h_ReassemblyTree = FM_PCD_CcRootBuild(
+ p_FmPort->h_FmPcd, p_FmPcdCcTreeParams);
+
+ if (!p_FmPort->h_ReassemblyTree)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ XX_Free(p_FmPcdCcTreeParams);
+ RETURN_ERROR( MAJOR, E_INVALID_HANDLE,
+ ("FM_PCD_CcBuildTree for Reassembly failed"));
+ }
+ if (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG)
+ p_PcdParams->pcdSupport =
+ e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC;
+ else
+ p_PcdParams->pcdSupport =
+ e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR;
+
+ memset(&fmPortPcdCcParams, 0, sizeof(t_FmPortPcdCcParams));
+ fmPortPcdCcParams.h_CcTree = p_FmPort->h_ReassemblyTree;
+ p_PcdParams->p_CcParams = &fmPortPcdCcParams;
+ XX_Free(p_FmPcdCcTreeParams);
+ }
+
+ if (p_FmPort->h_IpReassemblyManip)
+ err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd,
+ p_PcdParams->p_CcParams->h_CcTree,
+ p_PcdParams->h_NetEnv,
+ p_FmPort->h_IpReassemblyManip, TRUE);
+#if (DPAA_VERSION >= 11)
+ else
+ if (p_FmPort->h_CapwapReassemblyManip)
+ err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd,
+ p_PcdParams->p_CcParams->h_CcTree,
+ p_PcdParams->h_NetEnv,
+ p_FmPort->h_CapwapReassemblyManip,
+ TRUE);
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (err != E_OK)
+ {
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd))
+ {
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ DBG(TRACE, ("Try LockAll - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = SetPcd(h_FmPort, p_PcdParams);
+ if (err)
+ {
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if ((p_FmPort->pcdEngines & FM_PCD_PRS)
+ && (p_PcdParams->p_PrsParams->includeInPrsStatistics))
+ {
+ err = FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd,
+ p_FmPort->hardwarePortId, TRUE);
+ if (err)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ p_FmPort->includeInPrsStatistics = TRUE;
+ }
+
+ FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId);
+
+ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
+ {
+ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
+
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ {
+#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
+ if ((p_FmPort->fmRevInfo.majorRev < 6) &&
+ (p_FmPort->pcdEngines & FM_PCD_KG))
+ {
+ int i;
+ for (i = 0; i<p_PcdParams->p_KgParams->numOfSchemes; i++)
+ /* The following function must be locked */
+ FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd,
+ p_PcdParams->p_KgParams->h_Schemes[i],
+ UPDATE_KG_NIA_CC_WA,
+ 0);
+ }
+#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */
+
+#if (DPAA_VERSION >= 11)
+ {
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+
+ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
+ (void**)&p_ParamsPage);
+ ASSERT_COND(p_ParamsPage);
+ WRITE_UINT32(p_ParamsPage->postBmiFetchNia,
+ p_FmPort->savedBmiNia);
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Set post-bmi-fetch nia */
+ p_FmPort->savedBmiNia &= BMI_RFNE_FDCS_MASK;
+ p_FmPort->savedBmiNia |= (NIA_FM_CTL_AC_POST_BMI_FETCH
+ | NIA_ENG_FM_CTL);
+
+ /* Set pre-bmi-fetch nia */
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN;
+#if (DPAA_VERSION >= 11)
+ fmPortGetSetCcParams.setCcParams.nia =
+ (NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME | NIA_ENG_FM_CTL);
+#else
+ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER | NIA_ENG_FM_CTL);
+#endif /* (DPAA_VERSION >= 11) */
+ if ((err = FmPortGetSetCcParams(p_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+
+ /* Set pop-to-next-step nia */
+#if (DPAA_VERSION == 10)
+ if (p_FmPort->fmRevInfo.majorRev < 6)
+ {
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN;
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+ }
+ else
+ {
+#endif /* (DPAA_VERSION == 10) */
+ fmPortGetSetCcParams.getCcParams.type = GET_NIA_FPNE;
+#if (DPAA_VERSION == 10)
+ }
+#endif /* (DPAA_VERSION == 10) */
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /* Set post-bmi-prepare-to-enq nia */
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE;
+ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ
+ | NIA_ENG_FM_CTL);
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if ((p_FmPort->h_IpReassemblyManip)
+ || (p_FmPort->h_CapwapReassemblyManip))
+ {
+#if (DPAA_VERSION == 10)
+ if (p_FmPort->fmRevInfo.majorRev < 6)
+ {
+ /* Overwrite post-bmi-prepare-to-enq nia */
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE;
+ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ_ORR | NIA_ENG_FM_CTL | NIA_ORDER_RESTOR);
+ fmPortGetSetCcParams.setCcParams.overwrite = TRUE;
+ }
+ else
+ {
+#endif /* (DPAA_VERSION == 10) */
+ /* Set the ORR bit (for order-restoration) */
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FPNE;
+ fmPortGetSetCcParams.setCcParams.nia =
+ fmPortGetSetCcParams.getCcParams.nia | NIA_ORDER_RESTOR;
+#if (DPAA_VERSION == 10)
+ }
+#endif /* (DPAA_VERSION == 10) */
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ }
+ }
+ else
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+
+#if (DPAA_VERSION >= 11)
+ {
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+
+ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams));
+
+ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_CMNE;
+ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
+ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP
+ | NIA_ENG_FM_CTL;
+ else
+ fmPortGetSetCcParams.setCcParams.nia =
+ NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP | NIA_ENG_FM_CTL;
+ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams))
+ != E_OK)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE,
+ (void**)&p_ParamsPage);
+ ASSERT_COND(p_ParamsPage);
+
+ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd))
+ WRITE_UINT32(
+ p_ParamsPage->misc,
+ GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN);
+
+ if ((p_FmPort->h_IpReassemblyManip)
+ || (p_FmPort->h_CapwapReassemblyManip))
+ {
+ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ WRITE_UINT32(
+ p_ParamsPage->discardMask,
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm));
+ else
+ WRITE_UINT32(
+ p_ParamsPage->discardMask,
+ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm));
+ }
+#ifdef FM_ERROR_VSP_NO_MATCH_SW006
+ if (p_FmPort->vspe)
+ WRITE_UINT32(
+ p_ParamsPage->misc,
+ GET_UINT32(p_ParamsPage->misc) | (p_FmPort->dfltRelativeId & FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK));
+#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ err = AttachPCD(h_FmPort);
+ if (err)
+ {
+ DeletePcd(p_FmPort);
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return err;
+}
+
+t_Error FM_PORT_DeletePCD(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+
+ if (p_FmPort->imEn)
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION,
+ ("available for non-independant mode ports only"));
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR( MAJOR, E_INVALID_OPERATION,
+ ("available for Rx and offline parsing ports only"));
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = DetachPCD(h_FmPort);
+ if (err)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId);
+
+ /* we do it anyway, instead of checking if included */
+ if ((p_FmPort->pcdEngines & FM_PCD_PRS) && p_FmPort->includeInPrsStatistics)
+ {
+ FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd,
+ p_FmPort->hardwarePortId, FALSE);
+ p_FmPort->includeInPrsStatistics = FALSE;
+ }
+
+ if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd))
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ DBG(TRACE, ("Try LockAll - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = DeletePcd(h_FmPort);
+ FmPcdLockUnlockAll(p_FmPort->h_FmPcd);
+ if (err)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ if (p_FmPort->h_ReassemblyTree)
+ {
+ err = FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree);
+ if (err)
+ {
+ RELEASE_LOCK(p_FmPort->lock);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ p_FmPort->h_ReassemblyTree = NULL;
+ }RELEASE_LOCK(p_FmPort->lock);
+
+ return err;
+}
+
+t_Error FM_PORT_PcdKgBindSchemes(t_Handle h_FmPort,
+ t_FmPcdPortSchemesParams *p_PortScheme)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
+ t_Error err = E_OK;
+ uint32_t tmpScmVec = 0;
+ int i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
+ E_INVALID_STATE);
+
+ schemeBind.netEnvId = p_FmPort->netEnvId;
+ schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
+ schemeBind.numOfSchemes = p_PortScheme->numOfSchemes;
+ schemeBind.useClsPlan = p_FmPort->useClsPlan;
+ for (i = 0; i < schemeBind.numOfSchemes; i++)
+ {
+ schemeBind.schemesIds[i] = FmPcdKgGetSchemeId(
+ p_PortScheme->h_Schemes[i]);
+ /* build vector */
+ tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]);
+ }
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
+ if (err == E_OK)
+ p_FmPort->schemesPerPortVector |= tmpScmVec;
+
+#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
+ if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) &&
+ (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
+ (p_FmPort->fmRevInfo.majorRev < 6))
+ {
+ for (i=0; i<p_PortScheme->numOfSchemes; i++)
+ FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, p_PortScheme->h_Schemes[i], UPDATE_KG_NIA_CC_WA, 0);
+ }
+#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */
+
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return err;
+}
+
+t_Error FM_PORT_PcdKgUnbindSchemes(t_Handle h_FmPort,
+ t_FmPcdPortSchemesParams *p_PortScheme)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_FmPcdKgInterModuleBindPortToSchemes schemeBind;
+ t_Error err = E_OK;
+ uint32_t tmpScmVec = 0;
+ int i;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG,
+ E_INVALID_STATE);
+
+ schemeBind.netEnvId = p_FmPort->netEnvId;
+ schemeBind.hardwarePortId = p_FmPort->hardwarePortId;
+ schemeBind.numOfSchemes = p_PortScheme->numOfSchemes;
+ for (i = 0; i < schemeBind.numOfSchemes; i++)
+ {
+ schemeBind.schemesIds[i] = FmPcdKgGetSchemeId(
+ p_PortScheme->h_Schemes[i]);
+ /* build vector */
+ tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]);
+ }
+
+ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock))
+ {
+ DBG(TRACE, ("FM Port Try Lock - BUSY"));
+ return ERROR_CODE(E_BUSY);
+ }
+
+ err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind);
+ if (err == E_OK)
+ p_FmPort->schemesPerPortVector &= ~tmpScmVec;
+ RELEASE_LOCK(p_FmPort->lock);
+
+ return err;
+}
+
+t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort,
+ t_FmPortCongestionGrps *p_CongestionGrps)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint8_t priorityTmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS];
+ uint8_t mod, index;
+ uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM];
+ int err;
+#if (DPAA_VERSION >= 11)
+ int j;
+#endif /* (DPAA_VERSION >= 11) */
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+
+ /* un-necessary check of the indexes; probably will be needed in the future when there
+ will be more CGs available ....
+ for (i=0; i<p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
+ if (p_CongestionGrps->congestionGrpsToConsider[i] >= FM_PORT_NUM_OF_CONGESTION_GRPS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("CG id!"));
+ */
+
+#ifdef FM_NO_OP_OBSERVED_CGS
+ if ((p_FmPort->fmRevInfo.majorRev != 4) &&
+ (p_FmPort->fmRevInfo.majorRev < 6))
+ {
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
+ (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only"));
+ }
+ else
+#endif /* FM_NO_OP_OBSERVED_CGS */
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("Available for Rx & OP ports only"));
+
+ /* Prepare groups map array */
+ memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t));
+ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
+ {
+ index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32);
+ mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32);
+ if (p_FmPort->fmRevInfo.majorRev != 4)
+ grpsMap[7 - index] |= (uint32_t)(1 << mod);
+ else
+ grpsMap[0] |= (uint32_t)(1 << mod);
+ }
+
+ memset(&priorityTmpArray, 0,
+ FM_PORT_NUM_OF_CONGESTION_GRPS * sizeof(uint8_t));
+
+ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
+ {
+#if (DPAA_VERSION >= 11)
+ for (j = 0; j < FM_MAX_NUM_OF_PFC_PRIORITIES; j++)
+ if (p_CongestionGrps->pfcPrioritiesEn[i][j])
+ priorityTmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] |=
+ (0x01 << (FM_MAX_NUM_OF_PFC_PRIORITIES - j - 1));
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+#if (DPAA_VERSION >= 11)
+ for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS; i++)
+ {
+ err = FmSetCongestionGroupPFCpriority(p_FmPort->h_Fm, i,
+ priorityTmpArray[i]);
+ if (err)
+ return err;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ err = fman_port_add_congestion_grps(&p_FmPort->port, grpsMap);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_add_congestion_grps"));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort,
+ t_FmPortCongestionGrps *p_CongestionGrps)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint8_t mod, index;
+ uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM];
+ int err;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+
+ {
+#ifdef FM_NO_OP_OBSERVED_CGS
+ t_FmRevisionInfo revInfo;
+
+ FM_GetRevision(p_FmPort->h_Fm, &revInfo);
+ if (revInfo.majorRev != 4)
+ {
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
+ (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only"));
+ }
+ else
+#endif /* FM_NO_OP_OBSERVED_CGS */
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)
+ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("Available for Rx & OP ports only"));
+ }
+
+ /* Prepare groups map array */
+ memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t));
+ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
+ {
+ index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32);
+ mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32);
+ if (p_FmPort->fmRevInfo.majorRev != 4)
+ grpsMap[7 - index] |= (uint32_t)(1 << mod);
+ else
+ grpsMap[0] |= (uint32_t)(1 << mod);
+ }
+
+#if (DPAA_VERSION >= 11)
+ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++)
+ {
+ t_Error err = FmSetCongestionGroupPFCpriority(
+ p_FmPort->h_Fm, p_CongestionGrps->congestionGrpsToConsider[i],
+ 0);
+ if (err)
+ return err;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ err = fman_port_remove_congestion_grps(&p_FmPort->port, grpsMap);
+ if (err != 0)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("fman_port_remove_congestion_grps"));
+ return E_OK;
+}
+
+#if (DPAA_VERSION >= 11)
+t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort,
+ uint32_t *p_Ipv4OptionsCount)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(
+ (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING),
+ E_INVALID_VALUE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_ParamsPage, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_Ipv4OptionsCount, E_NULL_POINTER);
+
+ *p_Ipv4OptionsCount = GET_UINT32(p_FmPort->p_ParamsPage->ipfOptionsCounter);
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx,
+ t_FmPortDsarTablesSizes *params)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
+ p_FmPort->deepSleepVars.autoResMaxSizes = XX_Malloc(
+ sizeof(struct t_FmPortDsarTablesSizes));
+ memcpy(p_FmPort->deepSleepVars.autoResMaxSizes, params,
+ sizeof(struct t_FmPortDsarTablesSizes));
+ return E_OK;
+}
+
+static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort)
+{
+ uint32_t *param_page;
+ t_FmPortDsarTablesSizes *params = p_FmPort->deepSleepVars.autoResMaxSizes;
+ t_ArCommonDesc *ArCommonDescPtr;
+ uint32_t size = sizeof(t_ArCommonDesc);
+ // ARP
+ // should put here if (params->max_num_of_arp_entries)?
+ size = ROUND_UP(size,4);
+ size += sizeof(t_DsarArpDescriptor);
+ size += sizeof(t_DsarArpBindingEntry) * params->maxNumOfArpEntries;
+ size += sizeof(t_DsarArpStatistics);
+ //ICMPV4
+ size = ROUND_UP(size,4);
+ size += sizeof(t_DsarIcmpV4Descriptor);
+ size += sizeof(t_DsarIcmpV4BindingEntry) * params->maxNumOfEchoIpv4Entries;
+ size += sizeof(t_DsarIcmpV4Statistics);
+ //ICMPV6
+ size = ROUND_UP(size,4);
+ size += sizeof(t_DsarIcmpV6Descriptor);
+ size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfEchoIpv6Entries;
+ size += sizeof(t_DsarIcmpV6Statistics);
+ //ND
+ size = ROUND_UP(size,4);
+ size += sizeof(t_DsarNdDescriptor);
+ size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfNdpEntries;
+ size += sizeof(t_DsarIcmpV6Statistics);
+ //SNMP
+ size = ROUND_UP(size,4);
+ size += sizeof(t_DsarSnmpDescriptor);
+ size += sizeof(t_DsarSnmpIpv4AddrTblEntry)
+ * params->maxNumOfSnmpIPV4Entries;
+ size += sizeof(t_DsarSnmpIpv6AddrTblEntry)
+ * params->maxNumOfSnmpIPV6Entries;
+ size += sizeof(t_OidsTblEntry) * params->maxNumOfSnmpOidEntries;
+ size += params->maxNumOfSnmpOidChar;
+ size += sizeof(t_DsarIcmpV6Statistics);
+ //filters
+ size = ROUND_UP(size,4);
+ size += params->maxNumOfIpProtFiltering;
+ size = ROUND_UP(size,4);
+ size += params->maxNumOfUdpPortFiltering * sizeof(t_PortTblEntry);
+ size = ROUND_UP(size,4);
+ size += params->maxNumOfTcpPortFiltering * sizeof(t_PortTblEntry);
+
+ // add here for more protocols
+
+ // statistics
+ size = ROUND_UP(size,4);
+ size += sizeof(t_ArStatistics);
+
+ ArCommonDescPtr = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, size, 0x10);
+
+ param_page =
+ XX_PhysToVirt(
+ p_FmPort->fmMuramPhysBaseAddr
+ + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
+ WRITE_UINT32(
+ *param_page,
+ (uint32_t)(XX_VirtToPhys(ArCommonDescPtr) - p_FmPort->fmMuramPhysBaseAddr));
+ return E_OK;
+}
+
+t_FmPortDsarTablesSizes* FM_PORT_GetDsarTablesMaxSizes(t_Handle h_FmPortRx)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
+ return p_FmPort->deepSleepVars.autoResMaxSizes;
+}
+
+struct arOffsets
+{
+ uint32_t arp;
+ uint32_t nd;
+ uint32_t icmpv4;
+ uint32_t icmpv6;
+ uint32_t snmp;
+ uint32_t stats;
+ uint32_t filtIp;
+ uint32_t filtUdp;
+ uint32_t filtTcp;
+};
+
+static uint32_t AR_ComputeOffsets(struct arOffsets* of,
+ struct t_FmPortDsarParams *params,
+ t_FmPort *p_FmPort)
+{
+ uint32_t size = sizeof(t_ArCommonDesc);
+ // ARP
+ if (params->p_AutoResArpInfo)
+ {
+ size = ROUND_UP(size,4);
+ of->arp = size;
+ size += sizeof(t_DsarArpDescriptor);
+ size += sizeof(t_DsarArpBindingEntry)
+ * params->p_AutoResArpInfo->tableSize;
+ size += sizeof(t_DsarArpStatistics);
+ }
+ // ICMPV4
+ if (params->p_AutoResEchoIpv4Info)
+ {
+ size = ROUND_UP(size,4);
+ of->icmpv4 = size;
+ size += sizeof(t_DsarIcmpV4Descriptor);
+ size += sizeof(t_DsarIcmpV4BindingEntry)
+ * params->p_AutoResEchoIpv4Info->tableSize;
+ size += sizeof(t_DsarIcmpV4Statistics);
+ }
+ // ICMPV6
+ if (params->p_AutoResEchoIpv6Info)
+ {
+ size = ROUND_UP(size,4);
+ of->icmpv6 = size;
+ size += sizeof(t_DsarIcmpV6Descriptor);
+ size += sizeof(t_DsarIcmpV6BindingEntry)
+ * params->p_AutoResEchoIpv6Info->tableSize;
+ size += sizeof(t_DsarIcmpV6Statistics);
+ }
+ // ND
+ if (params->p_AutoResNdpInfo)
+ {
+ size = ROUND_UP(size,4);
+ of->nd = size;
+ size += sizeof(t_DsarNdDescriptor);
+ size += sizeof(t_DsarIcmpV6BindingEntry)
+ * (params->p_AutoResNdpInfo->tableSizeAssigned
+ + params->p_AutoResNdpInfo->tableSizeTmp);
+ size += sizeof(t_DsarIcmpV6Statistics);
+ }
+ // SNMP
+ if (params->p_AutoResSnmpInfo)
+ {
+ size = ROUND_UP(size,4);
+ of->snmp = size;
+ size += sizeof(t_DsarSnmpDescriptor);
+ size += sizeof(t_DsarSnmpIpv4AddrTblEntry)
+ * params->p_AutoResSnmpInfo->numOfIpv4Addresses;
+ size += sizeof(t_DsarSnmpIpv6AddrTblEntry)
+ * params->p_AutoResSnmpInfo->numOfIpv6Addresses;
+ size += sizeof(t_OidsTblEntry) * params->p_AutoResSnmpInfo->oidsTblSize;
+ size += p_FmPort->deepSleepVars.autoResMaxSizes->maxNumOfSnmpOidChar;
+ size += sizeof(t_DsarIcmpV6Statistics);
+ }
+ //filters
+ size = ROUND_UP(size,4);
+ if (params->p_AutoResFilteringInfo)
+ {
+ of->filtIp = size;
+ size += params->p_AutoResFilteringInfo->ipProtTableSize;
+ size = ROUND_UP(size,4);
+ of->filtUdp = size;
+ size += params->p_AutoResFilteringInfo->udpPortsTableSize
+ * sizeof(t_PortTblEntry);
+ size = ROUND_UP(size,4);
+ of->filtTcp = size;
+ size += params->p_AutoResFilteringInfo->tcpPortsTableSize
+ * sizeof(t_PortTblEntry);
+ }
+ // add here for more protocols
+ // statistics
+ size = ROUND_UP(size,4);
+ of->stats = size;
+ size += sizeof(t_ArStatistics);
+ return size;
+}
+
+uint32_t* ARDesc;
+void PrsEnable(t_Handle p_FmPcd);
+void PrsDisable(t_Handle p_FmPcd);
+int PrsIsEnabled(t_Handle p_FmPcd);
+t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd);
+
+static t_Error DsarCheckParams(t_FmPortDsarParams *params,
+ t_FmPortDsarTablesSizes *sizes)
+{
+ bool macInit = FALSE;
+ uint8_t mac[6];
+ int i = 0;
+
+ // check table sizes
+ if (params->p_AutoResArpInfo
+ && sizes->maxNumOfArpEntries < params->p_AutoResArpInfo->tableSize)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Arp table size exceeds the configured maximum size."));
+ if (params->p_AutoResEchoIpv4Info
+ && sizes->maxNumOfEchoIpv4Entries
+ < params->p_AutoResEchoIpv4Info->tableSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: EchoIpv4 table size exceeds the configured maximum size."));
+ if (params->p_AutoResNdpInfo
+ && sizes->maxNumOfNdpEntries
+ < params->p_AutoResNdpInfo->tableSizeAssigned
+ + params->p_AutoResNdpInfo->tableSizeTmp)
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: NDP table size exceeds the configured maximum size."));
+ if (params->p_AutoResEchoIpv6Info
+ && sizes->maxNumOfEchoIpv6Entries
+ < params->p_AutoResEchoIpv6Info->tableSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: EchoIpv6 table size exceeds the configured maximum size."));
+ if (params->p_AutoResSnmpInfo
+ && sizes->maxNumOfSnmpOidEntries
+ < params->p_AutoResSnmpInfo->oidsTblSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: Snmp Oid table size exceeds the configured maximum size."));
+ if (params->p_AutoResSnmpInfo
+ && sizes->maxNumOfSnmpIPV4Entries
+ < params->p_AutoResSnmpInfo->numOfIpv4Addresses)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: Snmp ipv4 table size exceeds the configured maximum size."));
+ if (params->p_AutoResSnmpInfo
+ && sizes->maxNumOfSnmpIPV6Entries
+ < params->p_AutoResSnmpInfo->numOfIpv6Addresses)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: Snmp ipv6 table size exceeds the configured maximum size."));
+ if (params->p_AutoResFilteringInfo)
+ {
+ if (sizes->maxNumOfIpProtFiltering
+ < params->p_AutoResFilteringInfo->ipProtTableSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: ip filter table size exceeds the configured maximum size."));
+ if (sizes->maxNumOfTcpPortFiltering
+ < params->p_AutoResFilteringInfo->udpPortsTableSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: udp filter table size exceeds the configured maximum size."));
+ if (sizes->maxNumOfUdpPortFiltering
+ < params->p_AutoResFilteringInfo->tcpPortsTableSize)
+ RETURN_ERROR(
+ MAJOR,
+ E_INVALID_VALUE,
+ ("DSAR: tcp filter table size exceeds the configured maximum size."));
+ }
+ /* check only 1 MAC address is configured (this is what ucode currently supports) */
+ if (params->p_AutoResArpInfo && params->p_AutoResArpInfo->tableSize)
+ {
+ memcpy(mac, params->p_AutoResArpInfo->p_AutoResTable[0].mac, 6);
+ i = 1;
+ macInit = TRUE;
+
+ for (; i < params->p_AutoResArpInfo->tableSize; i++)
+ if (memcmp(mac, params->p_AutoResArpInfo->p_AutoResTable[i].mac, 6))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Only 1 mac address is currently supported."));
+ }
+ if (params->p_AutoResEchoIpv4Info
+ && params->p_AutoResEchoIpv4Info->tableSize)
+ {
+ i = 0;
+ if (!macInit)
+ {
+ memcpy(mac, params->p_AutoResEchoIpv4Info->p_AutoResTable[0].mac,
+ 6);
+ i = 1;
+ macInit = TRUE;
+ }
+ for (; i < params->p_AutoResEchoIpv4Info->tableSize; i++)
+ if (memcmp(mac,
+ params->p_AutoResEchoIpv4Info->p_AutoResTable[i].mac, 6))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Only 1 mac address is currently supported."));
+ }
+ if (params->p_AutoResEchoIpv6Info
+ && params->p_AutoResEchoIpv6Info->tableSize)
+ {
+ i = 0;
+ if (!macInit)
+ {
+ memcpy(mac, params->p_AutoResEchoIpv6Info->p_AutoResTable[0].mac,
+ 6);
+ i = 1;
+ macInit = TRUE;
+ }
+ for (; i < params->p_AutoResEchoIpv6Info->tableSize; i++)
+ if (memcmp(mac,
+ params->p_AutoResEchoIpv6Info->p_AutoResTable[i].mac, 6))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Only 1 mac address is currently supported."));
+ }
+ if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeAssigned)
+ {
+ i = 0;
+ if (!macInit)
+ {
+ memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableAssigned[0].mac,
+ 6);
+ i = 1;
+ macInit = TRUE;
+ }
+ for (; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++)
+ if (memcmp(mac,
+ params->p_AutoResNdpInfo->p_AutoResTableAssigned[i].mac,
+ 6))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Only 1 mac address is currently supported."));
+ }
+ if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeTmp)
+ {
+ i = 0;
+ if (!macInit)
+ {
+ memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[0].mac, 6);
+ i = 1;
+ }
+ for (; i < params->p_AutoResNdpInfo->tableSizeTmp; i++)
+ if (memcmp(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[i].mac,
+ 6))
+ RETURN_ERROR(
+ MAJOR, E_INVALID_VALUE,
+ ("DSAR: Only 1 mac address is currently supported."));
+ }
+ return E_OK;
+}
+
+static int GetBERLen(uint8_t* buf)
+{
+ if (*buf & 0x80)
+ {
+ if ((*buf & 0x7F) == 1)
+ return buf[1];
+ else
+ return *(uint16_t*)&buf[1]; // assuming max len is 2
+ }
+ else
+ return buf[0];
+}
+#define TOTAL_BER_LEN(len) (len < 128) ? len + 2 : len + 3
+
+#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C
+#define SCFG_FMCLKDPSLPCR_DS_VAL 0x08402000
+#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000
+static int fm_soc_suspend(void)
+{
+ uint32_t *fmclk, tmp32;
+ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
+ tmp32 = GET_UINT32(*fmclk);
+ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL);
+ tmp32 = GET_UINT32(*fmclk);
+ iounmap(fmclk);
+ return 0;
+}
+
+void fm_clk_down(void)
+{
+ uint32_t *fmclk, tmp32;
+ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
+ tmp32 = GET_UINT32(*fmclk);
+ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL | 0x40000000);
+ tmp32 = GET_UINT32(*fmclk);
+ iounmap(fmclk);
+}
+
+t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params)
+{
+ int i, j;
+ t_Error err;
+ uint32_t nia;
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
+ t_FmPort *p_FmPortTx = (t_FmPort *)params->h_FmPortTx;
+ t_DsarArpDescriptor *ArpDescriptor;
+ t_DsarIcmpV4Descriptor* ICMPV4Descriptor;
+ t_DsarIcmpV6Descriptor* ICMPV6Descriptor;
+ t_DsarNdDescriptor* NDDescriptor;
+
+ uint64_t fmMuramVirtBaseAddr = (uint64_t)PTR_TO_UINT(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr));
+ uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
+ t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page)));
+ struct arOffsets* of;
+ uint8_t tmp = 0;
+ t_FmGetSetParams fmGetSetParams;
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
+ fmGetSetParams.setParams.sleep = 1;
+
+ err = DsarCheckParams(params, p_FmPort->deepSleepVars.autoResMaxSizes);
+ if (err != E_OK)
+ return err;
+
+ p_FmPort->deepSleepVars.autoResOffsets = XX_Malloc(sizeof(struct arOffsets));
+ of = (struct arOffsets *)p_FmPort->deepSleepVars.autoResOffsets;
+ IOMemSet32(ArCommonDescPtr, 0, AR_ComputeOffsets(of, params, p_FmPort));
+
+ // common
+ WRITE_UINT8(ArCommonDescPtr->arTxPort, p_FmPortTx->hardwarePortId);
+ nia = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); // bmi nia
+ if ((nia & 0x007C0000) == 0x00440000) // bmi nia is parser
+ WRITE_UINT32(ArCommonDescPtr->activeHPNIA, GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne));
+ else
+ WRITE_UINT32(ArCommonDescPtr->activeHPNIA, nia);
+ WRITE_UINT16(ArCommonDescPtr->snmpPort, 161);
+
+ // ARP
+ if (params->p_AutoResArpInfo)
+ {
+ t_DsarArpBindingEntry* arp_bindings;
+ ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp);
+ WRITE_UINT32(ArCommonDescPtr->p_ArpDescriptor, PTR_TO_UINT(ArpDescriptor) - fmMuramVirtBaseAddr);
+ arp_bindings = (t_DsarArpBindingEntry*)(PTR_TO_UINT(ArpDescriptor) + sizeof(t_DsarArpDescriptor));
+ if (params->p_AutoResArpInfo->enableConflictDetection)
+ WRITE_UINT16(ArpDescriptor->control, 1);
+ else
+ WRITE_UINT16(ArpDescriptor->control, 0);
+ if (params->p_AutoResArpInfo->tableSize)
+ {
+ t_FmPortDsarArpEntry* arp_entry = params->p_AutoResArpInfo->p_AutoResTable;
+ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]);
+ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]);
+ WRITE_UINT16(ArpDescriptor->numOfBindings, params->p_AutoResArpInfo->tableSize);
+
+ for (i = 0; i < params->p_AutoResArpInfo->tableSize; i++)
+ {
+ WRITE_UINT32(arp_bindings[i].ipv4Addr, arp_entry[i].ipAddress);
+ if (arp_entry[i].isVlan)
+ WRITE_UINT16(arp_bindings[i].vlanId, arp_entry[i].vid & 0xFFF);
+ }
+ WRITE_UINT32(ArpDescriptor->p_Bindings, PTR_TO_UINT(arp_bindings) - fmMuramVirtBaseAddr);
+ }
+ WRITE_UINT32(ArpDescriptor->p_Statistics, PTR_TO_UINT(arp_bindings) +
+ sizeof(t_DsarArpBindingEntry) * params->p_AutoResArpInfo->tableSize - fmMuramVirtBaseAddr);
+ }
+
+ // ICMPV4
+ if (params->p_AutoResEchoIpv4Info)
+ {
+ t_DsarIcmpV4BindingEntry* icmpv4_bindings;
+ ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4);
+ WRITE_UINT32(ArCommonDescPtr->p_IcmpV4Descriptor, PTR_TO_UINT(ICMPV4Descriptor) - fmMuramVirtBaseAddr);
+ icmpv4_bindings = (t_DsarIcmpV4BindingEntry*)(PTR_TO_UINT(ICMPV4Descriptor) + sizeof(t_DsarIcmpV4Descriptor));
+ WRITE_UINT16(ICMPV4Descriptor->control, 0);
+ if (params->p_AutoResEchoIpv4Info->tableSize)
+ {
+ t_FmPortDsarArpEntry* arp_entry = params->p_AutoResEchoIpv4Info->p_AutoResTable;
+ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]);
+ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]);
+ WRITE_UINT16(ICMPV4Descriptor->numOfBindings, params->p_AutoResEchoIpv4Info->tableSize);
+
+ for (i = 0; i < params->p_AutoResEchoIpv4Info->tableSize; i++)
+ {
+ WRITE_UINT32(icmpv4_bindings[i].ipv4Addr, arp_entry[i].ipAddress);
+ if (arp_entry[i].isVlan)
+ WRITE_UINT16(icmpv4_bindings[i].vlanId, arp_entry[i].vid & 0xFFF);
+ }
+ WRITE_UINT32(ICMPV4Descriptor->p_Bindings, PTR_TO_UINT(icmpv4_bindings) - fmMuramVirtBaseAddr);
+ }
+ WRITE_UINT32(ICMPV4Descriptor->p_Statistics, PTR_TO_UINT(icmpv4_bindings) +
+ sizeof(t_DsarIcmpV4BindingEntry) * params->p_AutoResEchoIpv4Info->tableSize - fmMuramVirtBaseAddr);
+ }
+
+ // ICMPV6
+ if (params->p_AutoResEchoIpv6Info)
+ {
+ t_DsarIcmpV6BindingEntry* icmpv6_bindings;
+ ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6);
+ WRITE_UINT32(ArCommonDescPtr->p_IcmpV6Descriptor, PTR_TO_UINT(ICMPV6Descriptor) - fmMuramVirtBaseAddr);
+ icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(ICMPV6Descriptor) + sizeof(t_DsarIcmpV6Descriptor));
+ WRITE_UINT16(ICMPV6Descriptor->control, 0);
+ if (params->p_AutoResEchoIpv6Info->tableSize)
+ {
+ t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResEchoIpv6Info->p_AutoResTable;
+ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]);
+ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]);
+ WRITE_UINT16(ICMPV6Descriptor->numOfBindings, params->p_AutoResEchoIpv6Info->tableSize);
+
+ for (i = 0; i < params->p_AutoResEchoIpv6Info->tableSize; i++)
+ {
+ for (j = 0; j < 4; j++)
+ WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
+ if (ndp_entry[i].isVlan)
+ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
+ }
+ WRITE_UINT32(ICMPV6Descriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr);
+ }
+ WRITE_UINT32(ICMPV6Descriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) +
+ sizeof(t_DsarIcmpV6BindingEntry) * params->p_AutoResEchoIpv6Info->tableSize - fmMuramVirtBaseAddr);
+ }
+
+ // ND
+ if (params->p_AutoResNdpInfo)
+ {
+ t_DsarIcmpV6BindingEntry* icmpv6_bindings;
+ NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd);
+ WRITE_UINT32(ArCommonDescPtr->p_NdDescriptor, PTR_TO_UINT(NDDescriptor) - fmMuramVirtBaseAddr);
+ icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(NDDescriptor) + sizeof(t_DsarNdDescriptor));
+ if (params->p_AutoResNdpInfo->enableConflictDetection)
+ WRITE_UINT16(NDDescriptor->control, 1);
+ else
+ WRITE_UINT16(NDDescriptor->control, 0);
+ if (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp)
+ {
+ t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableAssigned;
+ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]);
+ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]);
+ WRITE_UINT16(NDDescriptor->numOfBindings, params->p_AutoResNdpInfo->tableSizeAssigned
+ + params->p_AutoResNdpInfo->tableSizeTmp);
+
+ for (i = 0; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++)
+ {
+ for (j = 0; j < 4; j++)
+ WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
+ if (ndp_entry[i].isVlan)
+ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
+ }
+ ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableTmp;
+ for (i = 0; i < params->p_AutoResNdpInfo->tableSizeTmp; i++)
+ {
+ for (j = 0; j < 4; j++)
+ WRITE_UINT32(icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[j], ndp_entry[i].ipAddress[j]);
+ if (ndp_entry[i].isVlan)
+ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan
+ }
+ WRITE_UINT32(NDDescriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr);
+ }
+ WRITE_UINT32(NDDescriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + sizeof(t_DsarIcmpV6BindingEntry)
+ * (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp)
+ - fmMuramVirtBaseAddr);
+ WRITE_UINT32(NDDescriptor->solicitedAddr, 0xFFFFFFFF);
+ }
+
+ // SNMP
+ if (params->p_AutoResSnmpInfo)
+ {
+ t_FmPortDsarSnmpInfo *snmpSrc = params->p_AutoResSnmpInfo;
+ t_DsarSnmpIpv4AddrTblEntry* snmpIpv4Addr;
+ t_DsarSnmpIpv6AddrTblEntry* snmpIpv6Addr;
+ t_OidsTblEntry* snmpOid;
+ uint8_t *charPointer;
+ int len;
+ t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp);
+ WRITE_UINT32(ArCommonDescPtr->p_SnmpDescriptor, PTR_TO_UINT(SnmpDescriptor) - fmMuramVirtBaseAddr);
+ WRITE_UINT16(SnmpDescriptor->control, snmpSrc->control);
+ WRITE_UINT16(SnmpDescriptor->maxSnmpMsgLength, snmpSrc->maxSnmpMsgLength);
+ snmpIpv4Addr = (t_DsarSnmpIpv4AddrTblEntry*)(PTR_TO_UINT(SnmpDescriptor) + sizeof(t_DsarSnmpDescriptor));
+ if (snmpSrc->numOfIpv4Addresses)
+ {
+ t_FmPortDsarSnmpIpv4AddrTblEntry* snmpIpv4AddrSrc = snmpSrc->p_Ipv4AddrTbl;
+ WRITE_UINT16(SnmpDescriptor->numOfIpv4Addresses, snmpSrc->numOfIpv4Addresses);
+ for (i = 0; i < snmpSrc->numOfIpv4Addresses; i++)
+ {
+ WRITE_UINT32(snmpIpv4Addr[i].ipv4Addr, snmpIpv4AddrSrc[i].ipv4Addr);
+ if (snmpIpv4AddrSrc[i].isVlan)
+ WRITE_UINT16(snmpIpv4Addr[i].vlanId, snmpIpv4AddrSrc[i].vid & 0xFFF);
+ }
+ WRITE_UINT32(SnmpDescriptor->p_Ipv4AddrTbl, PTR_TO_UINT(snmpIpv4Addr) - fmMuramVirtBaseAddr);
+ }
+ snmpIpv6Addr = (t_DsarSnmpIpv6AddrTblEntry*)(PTR_TO_UINT(snmpIpv4Addr)
+ + sizeof(t_DsarSnmpIpv4AddrTblEntry) * snmpSrc->numOfIpv4Addresses);
+ if (snmpSrc->numOfIpv6Addresses)
+ {
+ t_FmPortDsarSnmpIpv6AddrTblEntry* snmpIpv6AddrSrc = snmpSrc->p_Ipv6AddrTbl;
+ WRITE_UINT16(SnmpDescriptor->numOfIpv6Addresses, snmpSrc->numOfIpv6Addresses);
+ for (i = 0; i < snmpSrc->numOfIpv6Addresses; i++)
+ {
+ for (j = 0; j < 4; j++)
+ WRITE_UINT32(snmpIpv6Addr[i].ipv6Addr[j], snmpIpv6AddrSrc[i].ipv6Addr[j]);
+ if (snmpIpv6AddrSrc[i].isVlan)
+ WRITE_UINT16(snmpIpv6Addr[i].vlanId, snmpIpv6AddrSrc[i].vid & 0xFFF);
+ }
+ WRITE_UINT32(SnmpDescriptor->p_Ipv6AddrTbl, PTR_TO_UINT(snmpIpv6Addr) - fmMuramVirtBaseAddr);
+ }
+ snmpOid = (t_OidsTblEntry*)(PTR_TO_UINT(snmpIpv6Addr)
+ + sizeof(t_DsarSnmpIpv6AddrTblEntry) * snmpSrc->numOfIpv6Addresses);
+ charPointer = (uint8_t*)(PTR_TO_UINT(snmpOid)
+ + sizeof(t_OidsTblEntry) * snmpSrc->oidsTblSize);
+ len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdOnlyCommunityStr[1]));
+ Mem2IOCpy32(charPointer, snmpSrc->p_RdOnlyCommunityStr, len);
+ WRITE_UINT32(SnmpDescriptor->p_RdOnlyCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
+ charPointer += len;
+ len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdWrCommunityStr[1]));
+ Mem2IOCpy32(charPointer, snmpSrc->p_RdWrCommunityStr, len);
+ WRITE_UINT32(SnmpDescriptor->p_RdWrCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
+ charPointer += len;
+ WRITE_UINT32(SnmpDescriptor->oidsTblSize, snmpSrc->oidsTblSize);
+ WRITE_UINT32(SnmpDescriptor->p_OidsTbl, PTR_TO_UINT(snmpOid) - fmMuramVirtBaseAddr);
+ for (i = 0; i < snmpSrc->oidsTblSize; i++)
+ {
+ WRITE_UINT16(snmpOid->oidSize, snmpSrc->p_OidsTbl[i].oidSize);
+ WRITE_UINT16(snmpOid->resSize, snmpSrc->p_OidsTbl[i].resSize);
+ Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].oidVal, snmpSrc->p_OidsTbl[i].oidSize);
+ WRITE_UINT32(snmpOid->p_Oid, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
+ charPointer += snmpSrc->p_OidsTbl[i].oidSize;
+ if (snmpSrc->p_OidsTbl[i].resSize <= 4)
+ WRITE_UINT32(snmpOid->resValOrPtr, *snmpSrc->p_OidsTbl[i].resVal);
+ else
+ {
+ Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].resVal, snmpSrc->p_OidsTbl[i].resSize);
+ WRITE_UINT32(snmpOid->resValOrPtr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
+ charPointer += snmpSrc->p_OidsTbl[i].resSize;
+ }
+ snmpOid++;
+ }
+ charPointer = UINT_TO_PTR(ROUND_UP(PTR_TO_UINT(charPointer),4));
+ WRITE_UINT32(SnmpDescriptor->p_Statistics, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr);
+ }
+
+ // filtering
+ if (params->p_AutoResFilteringInfo)
+ {
+ if (params->p_AutoResFilteringInfo->ipProtPassOnHit)
+ tmp |= IP_PROT_TBL_PASS_MASK;
+ if (params->p_AutoResFilteringInfo->udpPortPassOnHit)
+ tmp |= UDP_PORT_TBL_PASS_MASK;
+ if (params->p_AutoResFilteringInfo->tcpPortPassOnHit)
+ tmp |= TCP_PORT_TBL_PASS_MASK;
+ WRITE_UINT8(ArCommonDescPtr->filterControl, tmp);
+ WRITE_UINT16(ArCommonDescPtr->tcpControlPass, params->p_AutoResFilteringInfo->tcpFlagsMask);
+
+ // ip filtering
+ if (params->p_AutoResFilteringInfo->ipProtTableSize)
+ {
+ uint8_t* ip_tbl = (uint8_t*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtIp);
+ WRITE_UINT8(ArCommonDescPtr->ipProtocolTblSize, params->p_AutoResFilteringInfo->ipProtTableSize);
+ for (i = 0; i < params->p_AutoResFilteringInfo->ipProtTableSize; i++)
+ WRITE_UINT8(ip_tbl[i], params->p_AutoResFilteringInfo->p_IpProtTablePtr[i]);
+ WRITE_UINT32(ArCommonDescPtr->p_IpProtocolFiltTbl, PTR_TO_UINT(ip_tbl) - fmMuramVirtBaseAddr);
+ }
+
+ // udp filtering
+ if (params->p_AutoResFilteringInfo->udpPortsTableSize)
+ {
+ t_PortTblEntry* udp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtUdp);
+ WRITE_UINT8(ArCommonDescPtr->udpPortTblSize, params->p_AutoResFilteringInfo->udpPortsTableSize);
+ for (i = 0; i < params->p_AutoResFilteringInfo->udpPortsTableSize; i++)
+ {
+ WRITE_UINT32(udp_tbl[i].Ports,
+ (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPort << 16) +
+ params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPort);
+ WRITE_UINT32(udp_tbl[i].PortsMask,
+ (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPortMask << 16) +
+ params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPortMask);
+ }
+ WRITE_UINT32(ArCommonDescPtr->p_UdpPortFiltTbl, PTR_TO_UINT(udp_tbl) - fmMuramVirtBaseAddr);
+ }
+
+ // tcp filtering
+ if (params->p_AutoResFilteringInfo->tcpPortsTableSize)
+ {
+ t_PortTblEntry* tcp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtTcp);
+ WRITE_UINT8(ArCommonDescPtr->tcpPortTblSize, params->p_AutoResFilteringInfo->tcpPortsTableSize);
+ for (i = 0; i < params->p_AutoResFilteringInfo->tcpPortsTableSize; i++)
+ {
+ WRITE_UINT32(tcp_tbl[i].Ports,
+ (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPort << 16) +
+ params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPort);
+ WRITE_UINT32(tcp_tbl[i].PortsMask,
+ (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPortMask << 16) +
+ params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPortMask);
+ }
+ WRITE_UINT32(ArCommonDescPtr->p_TcpPortFiltTbl, PTR_TO_UINT(tcp_tbl) - fmMuramVirtBaseAddr);
+ }
+ }
+ // common stats
+ WRITE_UINT32(ArCommonDescPtr->p_ArStats, PTR_TO_UINT(ArCommonDescPtr) + of->stats - fmMuramVirtBaseAddr);
+
+ // get into Deep Sleep sequence:
+
+ // Ensures that FMan do not enter the idle state. This is done by programing
+ // FMDPSLPCR[FM_STOP] to one.
+ fm_soc_suspend();
+
+ ARDesc = UINT_TO_PTR(XX_VirtToPhys(ArCommonDescPtr));
+ return E_OK;
+
+}
+
+void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId);
+t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort)
+{
+ t_FmGetSetParams fmGetSetParams;
+ t_FmPort *p_FmPort = (t_FmPort *)h_DsarRxPort;
+ t_FmPort *p_FmPortTx = (t_FmPort *)h_DsarTxPort;
+ t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm);
+ t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd);
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FM_CLD;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+
+ /* Issue graceful stop to HC port */
+ FM_PORT_Disable(p_FmPortHc);
+
+ // config tx port
+ p_FmPort->deepSleepVars.fmbm_tcfg = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg);
+ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg) | BMI_PORT_CFG_IM | BMI_PORT_CFG_EN);
+ // ????
+ p_FmPort->deepSleepVars.fmbm_tcmne = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne);
+ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, 0xE);
+ // Stage 7:echo
+ p_FmPort->deepSleepVars.fmbm_rfpne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne);
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, 0x2E);
+ if (!PrsIsEnabled(h_FmPcd))
+ {
+ p_FmPort->deepSleepVars.dsarEnabledParser = TRUE;
+ PrsEnable(h_FmPcd);
+ }
+ else
+ p_FmPort->deepSleepVars.dsarEnabledParser = FALSE;
+
+ p_FmPort->deepSleepVars.fmbm_rfne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne);
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, 0x440000);
+
+ // save rcfg for restoring: accumulate mode is changed by ucode
+ p_FmPort->deepSleepVars.fmbm_rcfg = GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg);
+ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg | BMI_PORT_CFG_AM);
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
+ fmGetSetParams.setParams.sleep = 1;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+
+// ***** issue external request sync command
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_EXTC;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ // get
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.getParams.type = GET_FMFP_EXTC;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ if (fmGetSetParams.getParams.fmfp_extc != 0)
+ {
+ // clear
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_EXTC_CLEAR;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+}
+
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.getParams.type = GET_FMFP_EXTC | GET_FM_NPI;
+ do
+ {
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ } while (fmGetSetParams.getParams.fmfp_extc != 0 && fmGetSetParams.getParams.fm_npi == 0);
+ if (fmGetSetParams.getParams.fm_npi != 0)
+ XX_Print("FM: Sync did not finish\n");
+
+ // check that all stoped
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.getParams.type = GET_FMQM_GS | GET_FM_NPI;
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ while (fmGetSetParams.getParams.fmqm_gs & 0xF0000000)
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ if (fmGetSetParams.getParams.fmqm_gs == 0 && fmGetSetParams.getParams.fm_npi == 0)
+ XX_Print("FM: Sleeping\n");
+// FM_ChangeClock(p_FmPort->h_Fm, p_FmPort->hardwarePortId);
+
+ return E_OK;
+}
+
+EXPORT_SYMBOL(FM_PORT_EnterDsarFinal);
+
+void FM_PORT_Dsar_DumpRegs()
+{
+ uint32_t* hh = XX_PhysToVirt(PTR_TO_UINT(ARDesc));
+ DUMP_MEMORY(hh, 0x220);
+}
+
+void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
+ t_FmPort *p_FmPortTx = (t_FmPort *)h_FmPortTx;
+ t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm);
+ t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd);
+ t_FmGetSetParams fmGetSetParams;
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
+ fmGetSetParams.setParams.sleep = 0;
+ if (p_FmPort->deepSleepVars.autoResOffsets)
+ {
+ XX_Free(p_FmPort->deepSleepVars.autoResOffsets);
+ p_FmPort->deepSleepVars.autoResOffsets = 0;
+ }
+
+ if (p_FmPort->deepSleepVars.dsarEnabledParser)
+ PrsDisable(FmGetPcd(p_FmPort->h_Fm));
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, p_FmPort->deepSleepVars.fmbm_rfpne);
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, p_FmPort->deepSleepVars.fmbm_rfne);
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg);
+ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams);
+ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, p_FmPort->deepSleepVars.fmbm_tcmne);
+ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, p_FmPort->deepSleepVars.fmbm_tcfg);
+ FM_PORT_Enable(p_FmPortHc);
+}
+
+bool FM_PORT_IsInDsar(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPort;
+ return PTR_TO_UINT(p_FmPort->deepSleepVars.autoResOffsets);
+}
+
+t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats)
+{
+ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx;
+ struct arOffsets *of = (struct arOffsets*)p_FmPort->deepSleepVars.autoResOffsets;
+ uint8_t* fmMuramVirtBaseAddr = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr);
+ uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr));
+ t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page)));
+ t_DsarArpDescriptor *ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp);
+ t_DsarArpStatistics* arp_stats = (t_DsarArpStatistics*)(PTR_TO_UINT(ArpDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
+ t_DsarIcmpV4Descriptor* ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4);
+ t_DsarIcmpV4Statistics* icmpv4_stats = (t_DsarIcmpV4Statistics*)(PTR_TO_UINT(ICMPV4Descriptor->p_Statistics) + fmMuramVirtBaseAddr);
+ t_DsarNdDescriptor* NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd);
+ t_NdStatistics* nd_stats = (t_NdStatistics*)(PTR_TO_UINT(NDDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
+ t_DsarIcmpV6Descriptor* ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6);
+ t_DsarIcmpV6Statistics* icmpv6_stats = (t_DsarIcmpV6Statistics*)(PTR_TO_UINT(ICMPV6Descriptor->p_Statistics) + fmMuramVirtBaseAddr);
+ t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp);
+ t_DsarSnmpStatistics* snmp_stats = (t_DsarSnmpStatistics*)(PTR_TO_UINT(SnmpDescriptor->p_Statistics) + fmMuramVirtBaseAddr);
+ stats->arpArCnt = arp_stats->arCnt;
+ stats->echoIcmpv4ArCnt = icmpv4_stats->arCnt;
+ stats->ndpArCnt = nd_stats->arCnt;
+ stats->echoIcmpv6ArCnt = icmpv6_stats->arCnt;
+ stats->snmpGetCnt = snmp_stats->snmpGetReqCnt;
+ stats->snmpGetNextCnt = snmp_stats->snmpGetNextReqCnt;
+ return E_OK;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h
new file mode 100644
index 000000000000..85986f553c3f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h
@@ -0,0 +1,999 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_port.h
+
+ @Description FM Port internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_PORT_H
+#define __FM_PORT_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_port_ext.h"
+
+#include "fm_common.h"
+#include "fm_sp_common.h"
+#include "fsl_fman_sp.h"
+#include "fm_port_ext.h"
+#include "fsl_fman_port.h"
+
+#define __ERR_MODULE__ MODULE_FM_PORT
+
+
+#define MIN_EXT_BUF_SIZE 64
+#define DATA_ALIGNMENT 64
+#define MAX_LIODN_OFFSET 64
+#define MAX_PORT_FIFO_SIZE MIN(BMI_MAX_FIFO_SIZE, 1024*BMI_FIFO_UNITS)
+
+/**************************************************************************//**
+ @Description Memory Map defines
+*//***************************************************************************/
+#define BMI_PORT_REGS_OFFSET 0
+#define QMI_PORT_REGS_OFFSET 0x400
+#define PRS_PORT_REGS_OFFSET 0x800
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+#define DEFAULT_PORT_deqHighPriority_1G FALSE
+#define DEFAULT_PORT_deqHighPriority_10G TRUE
+#define DEFAULT_PORT_deqType e_FM_PORT_DEQ_TYPE1
+#define DEFAULT_PORT_deqPrefetchOption e_FM_PORT_DEQ_FULL_PREFETCH
+#define DEFAULT_PORT_deqPrefetchOption_HC e_FM_PORT_DEQ_NO_PREFETCH
+#define DEFAULT_PORT_deqByteCnt_10G 0x1400
+#define DEFAULT_PORT_deqByteCnt_1G 0x400
+#define DEFAULT_PORT_bufferPrefixContent_privDataSize DEFAULT_FM_SP_bufferPrefixContent_privDataSize
+#define DEFAULT_PORT_bufferPrefixContent_passPrsResult DEFAULT_FM_SP_bufferPrefixContent_passPrsResult
+#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp
+#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo
+#define DEFAULT_PORT_bufferPrefixContent_dataAlign DEFAULT_FM_SP_bufferPrefixContent_dataAlign
+#define DEFAULT_PORT_cheksumLastBytesIgnore 0
+#define DEFAULT_PORT_cutBytesFromEnd 4
+#define DEFAULT_PORT_fifoDeqPipelineDepth_IM 2
+
+#define DEFAULT_PORT_frmDiscardOverride FALSE
+
+#define DEFAULT_PORT_dmaSwapData (e_FmDmaSwapOption)DEFAULT_FMAN_SP_DMA_SWAP_DATA
+#define DEFAULT_PORT_dmaIntContextCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR
+#define DEFAULT_PORT_dmaHeaderCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR
+#define DEFAULT_PORT_dmaScatterGatherCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR
+#define DEFAULT_PORT_dmaWriteOptimize DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE
+
+#define DEFAULT_PORT_noScatherGather DEFAULT_FMAN_SP_NO_SCATTER_GATHER
+#define DEFAULT_PORT_forwardIntContextReuse FALSE
+#define DEFAULT_PORT_BufMargins_startMargins 32
+#define DEFAULT_PORT_BufMargins_endMargins 0
+#define DEFAULT_PORT_syncReq TRUE
+#define DEFAULT_PORT_syncReqForHc FALSE
+#define DEFAULT_PORT_color e_FM_PORT_COLOR_GREEN
+#define DEFAULT_PORT_errorsToDiscard FM_PORT_FRM_ERR_CLS_DISCARD
+/* #define DEFAULT_PORT_dualRateLimitScaleDown e_FM_PORT_DUAL_RATE_LIMITER_NONE */
+/* #define DEFAULT_PORT_rateLimitBurstSizeHighGranularity FALSE */
+#define DEFAULT_PORT_exception IM_EV_BSY
+#define DEFAULT_PORT_maxFrameLength 9600
+
+#define DEFAULT_notSupported 0xff
+
+#if (DPAA_VERSION < 11)
+#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE
+#define DEFAULT_PORT_rxFifoThreshold (MAX_PORT_FIFO_SIZE*3/4)
+
+#define DEFAULT_PORT_txFifoMinFillLevel 0
+#define DEFAULT_PORT_txFifoLowComfLevel (5*KILOBYTE)
+#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 1
+#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4
+
+#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2
+
+/* Host command port MUST NOT be changed to more than 1 !!! */
+#define DEFAULT_PORT_numOfTasks(type) \
+ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \
+ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 : \
+ ((((type) == e_FM_PORT_TYPE_RX) || \
+ ((type) == e_FM_PORT_TYPE_TX) || \
+ ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1))
+
+#define DEFAULT_PORT_extraNumOfTasks(type) \
+ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \
+ (((type) == e_FM_PORT_TYPE_RX) ? 2 : 0))
+
+#define DEFAULT_PORT_numOfOpenDmas(type) \
+ (uint32_t)((((type) == e_FM_PORT_TYPE_TX_10G) || \
+ ((type) == e_FM_PORT_TYPE_RX_10G)) ? 8 : 1 )
+
+#define DEFAULT_PORT_extraNumOfOpenDmas(type) \
+ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \
+ (((type) == e_FM_PORT_TYPE_RX) ? 1 : 0))
+
+#define DEFAULT_PORT_numOfFifoBufs(type) \
+ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \
+ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 48 : \
+ ((type) == e_FM_PORT_TYPE_RX) ? 45 : \
+ ((type) == e_FM_PORT_TYPE_TX) ? 44 : 8)
+
+#define DEFAULT_PORT_extraNumOfFifoBufs 0
+
+#else /* (DPAA_VERSION < 11) */
+/* Defaults are registers' reset values */
+#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE
+#define DEFAULT_PORT_rxFifoThreshold MAX_PORT_FIFO_SIZE
+
+#define DEFAULT_PORT_txFifoMinFillLevel 0
+#define DEFAULT_PORT_txFifoLowComfLevel (5 * KILOBYTE)
+#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 2
+#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4
+
+#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2
+
+#define DEFAULT_PORT_numOfTasks(type) \
+ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \
+ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 14 : \
+ (((type) == e_FM_PORT_TYPE_RX) || \
+ ((type) == e_FM_PORT_TYPE_TX)) ? 4 : \
+ ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? 6 : 1)
+
+#define DEFAULT_PORT_extraNumOfTasks(type) 0
+
+#define DEFAULT_PORT_numOfOpenDmas(type) \
+ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \
+ ((type) == e_FM_PORT_TYPE_TX_10G) ? 12 : \
+ ((type) == e_FM_PORT_TYPE_RX) ? 2 : \
+ ((type) == e_FM_PORT_TYPE_TX) ? 3 : \
+ ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 2 : 4)
+
+#define DEFAULT_PORT_extraNumOfOpenDmas(type) 0
+
+#define DEFAULT_PORT_numOfFifoBufs(type) \
+ (uint32_t) (((type) == e_FM_PORT_TYPE_RX_10G) ? 96 : \
+ ((type) == e_FM_PORT_TYPE_TX_10G) ? 64 : \
+ ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 10 : 50)
+
+#define DEFAULT_PORT_extraNumOfFifoBufs 0
+
+#endif /* (DPAA_VERSION < 11) */
+
+#define DEFAULT_PORT_txBdRingLength 16
+#define DEFAULT_PORT_rxBdRingLength 128
+#define DEFAULT_PORT_ImfwExtStructsMemId 0
+#define DEFAULT_PORT_ImfwExtStructsMemAttr MEMORY_ATTR_CACHEABLE
+
+#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32)
+
+/**************************************************************************//**
+ @Collection PCD Engines
+*//***************************************************************************/
+typedef uint32_t fmPcdEngines_t; /**< options as defined below: */
+
+#define FM_PCD_NONE 0 /**< No PCD Engine indicated */
+#define FM_PCD_PRS 0x80000000 /**< Parser indicated */
+#define FM_PCD_KG 0x40000000 /**< Keygen indicated */
+#define FM_PCD_CC 0x20000000 /**< Coarse classification indicated */
+#define FM_PCD_PLCR 0x10000000 /**< Policer indicated */
+#define FM_PCD_MANIP 0x08000000 /**< Manipulation indicated */
+/* @} */
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS 8
+#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256
+#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32)
+
+#define FM_OH_PORT_ID 0
+
+/***********************************************************************/
+/* SW parser OFFLOAD labels (offsets) */
+/***********************************************************************/
+#if (DPAA_VERSION == 10)
+#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x300
+#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x325
+#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x325
+#else
+#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x100
+/* Will be used for:
+ * 1. identify fragments
+ * 2. udp-lite
+ */
+#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x146
+/* Will be used for:
+ * 1. will identify the fragmentable area
+ * 2. udp-lite
+ */
+#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x261
+#define OFFLOAD_SW_PATCH_CAPWAP_LABEL 0x38d
+#endif /* (DPAA_VERSION == 10) */
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+#define UDP_LITE_SW_PATCH_LABEL 0x2E0
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+
+/**************************************************************************//**
+ @Description Memory Mapped Registers
+*//***************************************************************************/
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+typedef struct
+{
+ volatile uint32_t fmbm_rcfg; /**< Rx Configuration */
+ volatile uint32_t fmbm_rst; /**< Rx Status */
+ volatile uint32_t fmbm_rda; /**< Rx DMA attributes*/
+ volatile uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/
+ volatile uint32_t fmbm_rfed; /**< Rx Frame End Data*/
+ volatile uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/
+ volatile uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/
+ volatile uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/
+ volatile uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/
+ volatile uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/
+ volatile uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/
+ volatile uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/
+ volatile uint32_t fmbm_rpp; /**< Rx Policer Profile */
+ volatile uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */
+ volatile uint32_t fmbm_reth; /**< Rx Excessive Threshold */
+ volatile uint32_t reserved1[0x01];/**< (0x03C) */
+ volatile uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
+ /**< Rx Parse Results Array Initialization*/
+ volatile uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/
+ volatile uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/
+ volatile uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/
+ volatile uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/
+ volatile uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */
+ volatile uint32_t reserved2[0x02];/**< (0x074-0x078) */
+ volatile uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */
+ volatile uint32_t reserved3[0x20];/**< (0x080 0x0FF) */
+ volatile uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS];
+ /**< Buffer Manager pool Information-*/
+ volatile uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS];
+ /**< Allocate Counter-*/
+ volatile uint32_t reserved4[0x08];
+ /**< 0x130/0x140 - 0x15F reserved -*/
+ volatile uint32_t fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32];
+ /**< Congestion Group Map*/
+ volatile uint32_t fmbm_rmpd; /**< BM Pool Depletion */
+ volatile uint32_t reserved5[0x1F];/**< (0x184 0x1FF) */
+ volatile uint32_t fmbm_rstc; /**< Rx Statistics Counters*/
+ volatile uint32_t fmbm_rfrc; /**< Rx Frame Counter*/
+ volatile uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/
+ volatile uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/
+ volatile uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/
+ volatile uint32_t fmbm_rfcd; /**< Rx Frame Discard Counter*/
+ volatile uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/
+ volatile uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard Counter-*/
+ volatile uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter-*/
+ volatile uint32_t fmbm_rpec; /**< Rx RX Prepare to enqueue Counter-*/
+ volatile uint32_t reserved6[0x16];/**< (0x228 0x27F) */
+ volatile uint32_t fmbm_rpc; /**< Rx Performance Counters*/
+ volatile uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/
+ volatile uint32_t fmbm_rccn; /**< Rx Cycle Counter*/
+ volatile uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/
+ volatile uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization Counter*/
+ volatile uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/
+ volatile uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/
+ volatile uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/
+ volatile uint32_t reserved7[0x18];/**< (0x2A0-0x2FF) */
+ volatile uint32_t fmbm_rdcfg[0x3];/**< Rx Debug-*/
+ volatile uint32_t fmbm_rgpr; /**< Rx General Purpose Register. */
+ volatile uint32_t reserved8[0x3a];/**< (0x310-0x3FF) */
+} t_FmPortRxBmiRegs;
+
+typedef struct
+{
+ volatile uint32_t fmbm_tcfg; /**< Tx Configuration */
+ volatile uint32_t fmbm_tst; /**< Tx Status */
+ volatile uint32_t fmbm_tda; /**< Tx DMA attributes */
+ volatile uint32_t fmbm_tfp; /**< Tx FIFO Parameters */
+ volatile uint32_t fmbm_tfed; /**< Tx Frame End Data */
+ volatile uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */
+ volatile uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */
+ volatile uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */
+ volatile uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */
+ volatile uint32_t fmbm_tfeqid; /**< Tx Frame Error Queue ID */
+ volatile uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */
+ volatile uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */
+ volatile uint32_t fmbm_trlmt; /**< Tx Rate Limiter */
+ volatile uint32_t fmbm_tccb; /**< Tx Coarse Classification Base */
+ volatile uint32_t reserved0[0x0e];/**< (0x038-0x070) */
+ volatile uint32_t fmbm_tfne; /**< Tx Frame Next Engine */
+ volatile uint32_t fmbm_tpfcm[0x02];/**< Tx Priority based Flow Control (PFC) Mapping */
+ volatile uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */
+ volatile uint32_t reserved2[0x60];/**< (0x080-0x200) */
+ volatile uint32_t fmbm_tstc; /**< Tx Statistics Counters */
+ volatile uint32_t fmbm_tfrc; /**< Tx Frame Counter */
+ volatile uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */
+ volatile uint32_t fmbm_tfledc; /**< Tx Frame Length error discard counter */
+ volatile uint32_t fmbm_tfufdc; /**< Tx Frame unsupported format discard Counter */
+ volatile uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */
+ volatile uint32_t reserved3[0x1A];/**< (0x218-0x280) */
+ volatile uint32_t fmbm_tpc; /**< Tx Performance Counters*/
+ volatile uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/
+ volatile uint32_t fmbm_tccn; /**< Tx Cycle Counter*/
+ volatile uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/
+ volatile uint32_t fmbm_ttcquc; /**< Tx Transmit Confirm Queue Utilization Counter*/
+ volatile uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/
+ volatile uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/
+ volatile uint32_t reserved4[16]; /**< (0x29C-0x2FF) */
+ volatile uint32_t fmbm_tdcfg[0x3];/**< Tx Debug-*/
+ volatile uint32_t fmbm_tgpr; /**< O/H General Purpose Register */
+ volatile uint32_t reserved5[0x3a];/**< (0x310-0x3FF) */
+} t_FmPortTxBmiRegs;
+
+typedef struct
+{
+ volatile uint32_t fmbm_ocfg; /**< O/H Configuration */
+ volatile uint32_t fmbm_ost; /**< O/H Status */
+ volatile uint32_t fmbm_oda; /**< O/H DMA attributes */
+ volatile uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */
+ volatile uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */
+ volatile uint32_t fmbm_ofne; /**< O/H Frame Next Engine */
+ volatile uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */
+ volatile uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */
+ volatile uint32_t fmbm_opso; /**< O/H Parse Start Offset */
+ volatile uint32_t fmbm_opp; /**< O/H Policer Profile */
+ volatile uint32_t fmbm_occb; /**< O/H Coarse Classification base */
+ volatile uint32_t fmbm_oim; /**< O/H Internal margins*/
+ volatile uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/
+ volatile uint32_t fmbm_ofed; /**< O/H Frame End Data*/
+ volatile uint32_t reserved0[2]; /**< (0x038 - 0x03F) */
+ volatile uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS];
+ /**< O/H Parse Results Array Initialization */
+ volatile uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */
+ volatile uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */
+ volatile uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */
+ volatile uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */
+ volatile uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */
+ volatile uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */
+ volatile uint32_t fmbm_orlmt; /**< O/H Rate Limiter */
+ volatile uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */
+ volatile uint32_t reserved1[0x20];/**< (0x080 - 0x0FF) */
+ volatile uint32_t fmbm_oebmpi[2]; /**< Buffer Manager Observed Pool Information */
+ volatile uint32_t reserved2[0x16];/**< (0x108 - 0x15F) */
+ volatile uint32_t fmbm_ocgm; /**< Observed Congestion Group Map */
+ volatile uint32_t reserved3[0x7]; /**< (0x164 - 0x17F) */
+ volatile uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */
+ volatile uint32_t reserved4[0x1F];/**< (0x184 - 0x1FF) */
+ volatile uint32_t fmbm_ostc; /**< O/H Statistics Counters */
+ volatile uint32_t fmbm_ofrc; /**< O/H Frame Counter */
+ volatile uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */
+ volatile uint32_t fmbm_ofledc; /**< O/H Frames Length Error Discard Counter */
+ volatile uint32_t fmbm_ofufdc; /**< O/H Frames Unsupported Format Discard Counter */
+ volatile uint32_t fmbm_offc; /**< O/H Filter Frames Counter */
+ volatile uint32_t fmbm_ofwdc; /**< - Rx Frames WRED Discard Counter */
+ volatile uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Counter */
+ volatile uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */
+ volatile uint32_t fmbm_oodc; /**< O/H Out of Buffers Discard Counter */
+ volatile uint32_t fmbm_opec; /**< O/H Prepare to enqueue Counter */
+ volatile uint32_t reserved5[0x15];/**< ( - 0x27F) */
+ volatile uint32_t fmbm_opc; /**< O/H Performance Counters */
+ volatile uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */
+ volatile uint32_t fmbm_occn; /**< O/H Cycle Counter */
+ volatile uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */
+ volatile uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */
+ volatile uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */
+ volatile uint32_t reserved6[26]; /**< (0x298-0x2FF) */
+ volatile uint32_t fmbm_odcfg[0x3];/**< O/H Debug (only 1 in P1023) */
+ volatile uint32_t fmbm_ogpr; /**< O/H General Purpose Register. */
+ volatile uint32_t reserved7[0x3a];/**< (0x310 0x3FF) */
+} t_FmPortOhBmiRegs;
+
+typedef union
+{
+ t_FmPortRxBmiRegs rxPortBmiRegs;
+ t_FmPortTxBmiRegs txPortBmiRegs;
+ t_FmPortOhBmiRegs ohPortBmiRegs;
+} u_FmPortBmiRegs;
+
+typedef struct
+{
+ volatile uint32_t reserved1[2]; /**< 0xn024 - 0x02B */
+ volatile uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */
+ volatile uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */
+ volatile uint32_t fmqm_pndtfc; /**< PortID n Dequeue Total Frame Counter */
+ volatile uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID from Default Counter */
+ volatile uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */
+} t_FmPortNonRxQmiRegs;
+
+typedef struct
+{
+ volatile uint32_t fmqm_pnc; /**< PortID n Configuration Register */
+ volatile uint32_t fmqm_pns; /**< PortID n Status Register */
+ volatile uint32_t fmqm_pnts; /**< PortID n Task Status Register */
+ volatile uint32_t reserved0[4]; /**< 0xn00C - 0xn01B */
+ volatile uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */
+ volatile uint32_t fmqm_pnetfc; /**< PortID n Enqueue Total Frame Counter */
+ t_FmPortNonRxQmiRegs nonRxQmiRegs; /**< Registers for Tx Hc & Op ports */
+} t_FmPortQmiRegs;
+
+typedef struct
+{
+ struct
+ {
+ volatile uint32_t softSeqAttach; /**< Soft Sequence Attachment */
+ volatile uint32_t lcv; /**< Line-up Enable Confirmation Mask */
+ } hdrs[FM_PCD_PRS_NUM_OF_HDRS];
+ volatile uint32_t reserved0[0xde];
+ volatile uint32_t pcac; /**< Parse Internal Memory Configuration Access Control Register */
+ volatile uint32_t pctpid; /**< Parse Internal Memory Configured TPID Register */
+} t_FmPortPrsRegs;
+
+/**************************************************************************//*
+ @Description Basic buffer descriptor (BD) structure
+*//***************************************************************************/
+typedef _Packed struct
+{
+ volatile uint16_t status;
+ volatile uint16_t length;
+ volatile uint8_t reserved0[0x6];
+ volatile uint8_t reserved1[0x1];
+ volatile t_FmPhysAddr buff;
+} _PackedType t_FmImBd;
+
+typedef _Packed struct
+{
+ volatile uint16_t gen; /**< tbd */
+ volatile uint8_t reserved0[0x1];
+ volatile t_FmPhysAddr bdRingBase; /**< tbd */
+ volatile uint16_t bdRingSize; /**< tbd */
+ volatile uint16_t offsetIn; /**< tbd */
+ volatile uint16_t offsetOut; /**< tbd */
+ volatile uint8_t reserved1[0x12]; /**< 0x0e - 0x1f */
+} _PackedType t_FmPortImQd;
+
+typedef _Packed struct
+{
+ volatile uint32_t mode; /**< Mode register */
+ volatile uint32_t rxQdPtr; /**< tbd */
+ volatile uint32_t txQdPtr; /**< tbd */
+ volatile uint16_t mrblr; /**< tbd */
+ volatile uint16_t rxQdBsyCnt; /**< tbd */
+ volatile uint8_t reserved0[0x10]; /**< 0x10 - 0x1f */
+ t_FmPortImQd rxQd;
+ t_FmPortImQd txQd;
+ volatile uint8_t reserved1[0xa0]; /**< 0x60 - 0xff */
+} _PackedType t_FmPortImPram;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/**************************************************************************//**
+ @Description Registers bit fields
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description BMI defines
+*//***************************************************************************/
+#if (DPAA_VERSION >= 11)
+#define BMI_SP_ID_MASK 0xff000000
+#define BMI_SP_ID_SHIFT 24
+#define BMI_SP_EN 0x01000000
+#endif /* (DPAA_VERSION >= 11) */
+
+#define BMI_PORT_CFG_EN 0x80000000
+#define BMI_PORT_CFG_EN_MACSEC 0x00800000
+#define BMI_PORT_CFG_FDOVR 0x02000000
+#define BMI_PORT_CFG_IM 0x01000000
+#define BMI_PORT_CFG_AM 0x00000040
+#define BMI_PORT_STATUS_BSY 0x80000000
+#define BMI_COUNTERS_EN 0x80000000
+
+#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000
+#define BMI_PORT_RFNE_FRWD_RPD 0x40000000
+#define BMI_RFNE_FDCS_MASK 0xFF000000
+#define BMI_RFNE_HXS_MASK 0x000000FF
+
+#define BMI_CMD_MR_LEAC 0x00200000
+#define BMI_CMD_MR_SLEAC 0x00100000
+#define BMI_CMD_MR_MA 0x00080000
+#define BMI_CMD_MR_DEAS 0x00040000
+#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \
+ BMI_CMD_MR_SLEAC | \
+ BMI_CMD_MR_MA | \
+ BMI_CMD_MR_DEAS)
+#define BMI_CMD_ATTR_ORDER 0x80000000
+#define BMI_CMD_ATTR_SYNC 0x02000000
+#define BMI_CMD_ATTR_MODE_MISS_ALLIGN_ADDR_EN 0x00080000
+#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00
+#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000
+#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000
+#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00
+
+#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000
+#define BMI_STATUS_RX_MASK_UNUSED (uint32_t)(~(FM_PORT_FRM_ERR_DMA | \
+ FM_PORT_FRM_ERR_PHYSICAL | \
+ FM_PORT_FRM_ERR_SIZE | \
+ FM_PORT_FRM_ERR_CLS_DISCARD | \
+ FM_PORT_FRM_ERR_EXTRACTION | \
+ FM_PORT_FRM_ERR_NO_SCHEME | \
+ FM_PORT_FRM_ERR_COLOR_RED | \
+ FM_PORT_FRM_ERR_COLOR_YELLOW | \
+ FM_PORT_FRM_ERR_ILL_PLCR | \
+ FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \
+ FM_PORT_FRM_ERR_PRS_TIMEOUT | \
+ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \
+ FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \
+ FM_PORT_FRM_ERR_PRS_HDR_ERR | \
+ FM_PORT_FRM_ERR_IPRE | \
+ FM_PORT_FRM_ERR_IPR_NCSP | \
+ FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW))
+
+#define BMI_STATUS_OP_MASK_UNUSED (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \
+ ~(FM_PORT_FRM_ERR_LENGTH | \
+ FM_PORT_FRM_ERR_NON_FM | \
+ FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT))
+
+#define BMI_RATE_LIMIT_EN 0x80000000
+#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000
+#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001
+#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002
+#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003
+
+#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000
+
+#define BMI_PRS_RESULT_HIGH 0x00000000
+#define BMI_PRS_RESULT_LOW 0xFFFFFFFF
+
+
+#define RX_ERRS_TO_ENQ (FM_PORT_FRM_ERR_DMA | \
+ FM_PORT_FRM_ERR_PHYSICAL | \
+ FM_PORT_FRM_ERR_SIZE | \
+ FM_PORT_FRM_ERR_EXTRACTION | \
+ FM_PORT_FRM_ERR_NO_SCHEME | \
+ FM_PORT_FRM_ERR_ILL_PLCR | \
+ FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \
+ FM_PORT_FRM_ERR_PRS_TIMEOUT | \
+ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \
+ FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \
+ FM_PORT_FRM_ERR_PRS_HDR_ERR | \
+ FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \
+ FM_PORT_FRM_ERR_IPRE)
+
+#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \
+ FM_PORT_FRM_ERR_LENGTH | \
+ FM_PORT_FRM_ERR_NON_FM | \
+ FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)
+
+
+#define BMI_RX_FIFO_PRI_ELEVATION_MASK 0x03FF0000
+#define BMI_RX_FIFO_THRESHOLD_MASK 0x000003FF
+#define BMI_TX_FIFO_MIN_FILL_MASK 0x03FF0000
+#define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000F000
+#define BMI_TX_LOW_COMF_MASK 0x000003FF
+
+/* shifts */
+#define BMI_PORT_CFG_MS_SEL_SHIFT 16
+#define BMI_DMA_ATTR_IC_CACHE_SHIFT FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT
+#define BMI_DMA_ATTR_HDR_CACHE_SHIFT FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT
+#define BMI_DMA_ATTR_SG_CACHE_SHIFT FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT
+
+#define BMI_IM_FOF_SHIFT 28
+#define BMI_PR_PORTID_SHIFT 24
+
+#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16
+#define BMI_RX_FIFO_THRESHOLD_SHIFT 0
+
+#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24
+#define BMI_RX_FRAME_END_CUT_SHIFT 16
+
+#define BMI_IC_SIZE_SHIFT FMAN_SP_IC_SIZE_SHIFT
+
+#define BMI_INT_BUF_MARG_SHIFT 28
+
+#define BMI_EXT_BUF_MARG_END_SHIFT FMAN_SP_EXT_BUF_MARG_END_SHIFT
+
+#define BMI_CMD_ATTR_COLOR_SHIFT 26
+#define BMI_CMD_ATTR_COM_MODE_SHIFT 16
+#define BMI_CMD_ATTR_MACCMD_SHIFT 8
+#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15
+#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12
+#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8
+
+#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24
+
+#define BMI_TX_FIFO_MIN_FILL_SHIFT 16
+#define BMI_TX_LOW_COMF_SHIFT 0
+
+#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24
+#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16
+#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12
+#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0
+
+#define BMI_MAX_BURST_SHIFT 16
+#define BMI_COUNT_RATE_UNIT_SHIFT 16
+
+/* sizes */
+#define FRAME_END_DATA_SIZE 16
+#define FRAME_OFFSET_UNITS 16
+#define MIN_TX_INT_OFFSET 16
+#define MAX_FRAME_OFFSET 64
+#define MAX_FIFO_PIPELINE_DEPTH 8
+#define MAX_PERFORMANCE_TASK_COMP 64
+#define MAX_PERFORMANCE_TX_QUEUE_COMP 8
+#define MAX_PERFORMANCE_RX_QUEUE_COMP 64
+#define MAX_PERFORMANCE_DMA_COMP 16
+#define MAX_NUM_OF_TASKS 64
+#define MAX_NUM_OF_EXTRA_TASKS 8
+#define MAX_NUM_OF_DMAS 16
+#define MAX_NUM_OF_EXTRA_DMAS 8
+#define MAX_BURST_SIZE 1024
+#define MIN_NUM_OF_OP_DMAS 2
+
+
+/**************************************************************************//**
+ @Description QMI defines
+*//***************************************************************************/
+/* masks */
+#define QMI_PORT_CFG_EN 0x80000000
+#define QMI_PORT_CFG_EN_COUNTERS 0x10000000
+#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000
+#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000
+
+#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000
+#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0
+#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0
+#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000
+
+#define QMI_DEQ_CFG_PRI 0x80000000
+#define QMI_DEQ_CFG_TYPE1 0x10000000
+#define QMI_DEQ_CFG_TYPE2 0x20000000
+#define QMI_DEQ_CFG_TYPE3 0x30000000
+
+#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f
+#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20
+
+/**************************************************************************//**
+ @Description PARSER defines
+*//***************************************************************************/
+/* masks */
+#define PRS_HDR_ERROR_DIS 0x00000800
+#define PRS_HDR_SW_PRS_EN 0x00000400
+#define PRS_CP_OFFSET_MASK 0x0000000F
+#define PRS_TPID1_MASK 0xFFFF0000
+#define PRS_TPID2_MASK 0x0000FFFF
+#define PRS_TPID_DFLT 0x91009100
+
+#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000
+#define PRS_HDR_IPV6_ROUTE_HDR_EN 0x00008000
+#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000
+#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000
+#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000
+#define PRS_CAC_STOP 0x00000001
+#define PRS_CAC_ACTIVE 0x00000100
+
+/* shifts */
+#define PRS_PCTPID_SHIFT 16
+#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22
+#define PRS_HDR_ETH_BC_SHIFT 28
+#define PRS_HDR_ETH_MC_SHIFT 24
+#define PRS_HDR_VLAN_STACKED_SHIFT 16
+#define PRS_HDR_MPLS_STACKED_SHIFT 16
+#define PRS_HDR_IPV4_1_BC_SHIFT 28
+#define PRS_HDR_IPV4_1_MC_SHIFT 24
+#define PRS_HDR_IPV4_2_UC_SHIFT 20
+#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16
+#define PRS_HDR_IPV6_1_MC_SHIFT 24
+#define PRS_HDR_IPV6_2_UC_SHIFT 20
+#define PRS_HDR_IPV6_2_MC_SHIFT 16
+
+#define PRS_HDR_ETH_BC_MASK 0x0fffffff
+#define PRS_HDR_ETH_MC_MASK 0xf0ffffff
+#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff
+#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff
+#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff
+#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff
+#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff
+#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff
+#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff
+#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff
+#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff
+
+/* others */
+#define PRS_HDR_ENTRY_SIZE 8
+#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF
+
+#define IPSEC_SW_PATCH_START 0x20
+#define SCTP_SW_PATCH_START 0x4D
+#define DCCP_SW_PATCH_START 0x41
+
+/**************************************************************************//**
+ @Description IM defines
+*//***************************************************************************/
+#define BD_R_E 0x80000000
+#define BD_L 0x08000000
+
+#define BD_RX_CRE 0x00080000
+#define BD_RX_FTL 0x00040000
+#define BD_RX_FTS 0x00020000
+#define BD_RX_OV 0x00010000
+
+#define BD_RX_ERRORS (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV)
+
+#define FM_IM_SIZEOF_BD sizeof(t_FmImBd)
+
+#define BD_STATUS_MASK 0xffff0000
+#define BD_LENGTH_MASK 0x0000ffff
+
+#define BD_STATUS_AND_LENGTH_SET(bd, val) WRITE_UINT32(*(volatile uint32_t*)(bd), (val))
+
+#define BD_STATUS_AND_LENGTH(bd) GET_UINT32(*(volatile uint32_t*)(bd))
+
+#define BD_GET(id) &p_FmPort->im.p_BdRing[id]
+
+#define IM_ILEGAL_BD_ID 0xffff
+
+/* others */
+#define IM_PRAM_ALIGN 0x100
+
+/* masks */
+#define IM_MODE_GBL 0x20000000
+#define IM_MODE_BO_MASK 0x18000000
+#define IM_MODE_BO_SHIFT 3
+#define IM_MODE_GRC_STP 0x00800000
+
+#define IM_MODE_SET_BO(val) (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK)
+
+#define IM_RXQD_BSYINTM 0x0008
+#define IM_RXQD_RXFINTM 0x0010
+#define IM_RXQD_FPMEVT_SEL_MASK 0x0003
+
+#define IM_EV_BSY 0x40000000
+#define IM_EV_RX 0x80000000
+
+
+/**************************************************************************//**
+ @Description Additional defines
+*//***************************************************************************/
+
+typedef struct {
+ t_Handle h_FmMuram;
+ t_FmPortImPram *p_FmPortImPram;
+ uint8_t fwExtStructsMemId;
+ uint32_t fwExtStructsMemAttr;
+ uint16_t bdRingSize;
+ t_FmImBd *p_BdRing;
+ t_Handle *p_BdShadow;
+ uint16_t currBdId;
+ uint16_t firstBdOfFrameId;
+
+ /* Rx port parameters */
+ uint8_t dataMemId; /**< Memory partition ID for data buffers */
+ uint32_t dataMemAttributes; /**< Memory attributes for data buffers */
+ t_BufferPoolInfo rxPool;
+ uint16_t mrblr;
+ uint16_t rxFrameAccumLength;
+ t_FmPortImRxStoreCallback *f_RxStore;
+
+ /* Tx port parameters */
+ uint32_t txFirstBdStatus;
+ t_FmPortImTxConfCallback *f_TxConf;
+} t_FmMacIm;
+
+
+typedef struct {
+ struct fman_port_cfg dfltCfg;
+ uint32_t dfltFqid;
+ uint32_t confFqid;
+ uint32_t errFqid;
+ uintptr_t baseAddr;
+ uint8_t deqSubPortal;
+ bool deqHighPriority;
+ e_FmPortDeqType deqType;
+ e_FmPortDeqPrefetchOption deqPrefetchOption;
+ uint16_t deqByteCnt;
+ uint8_t cheksumLastBytesIgnore;
+ uint8_t cutBytesFromEnd;
+ t_FmBufPoolDepletion bufPoolDepletion;
+ uint8_t pipelineDepth;
+ uint16_t fifoLowComfLevel;
+ bool frmDiscardOverride;
+ bool enRateLimit;
+ t_FmPortRateLimit rateLimit;
+ e_FmPortDualRateLimiterScaleDown rateLimitDivider;
+ bool enBufPoolDepletion;
+ uint16_t liodnOffset;
+ uint16_t liodnBase;
+ t_FmExtPools extBufPools;
+ e_FmDmaSwapOption dmaSwapData;
+ e_FmDmaCacheOption dmaIntContextCacheAttr;
+ e_FmDmaCacheOption dmaHeaderCacheAttr;
+ e_FmDmaCacheOption dmaScatterGatherCacheAttr;
+ bool dmaReadOptimize;
+ bool dmaWriteOptimize;
+ uint32_t txFifoMinFillLevel;
+ uint32_t txFifoLowComfLevel;
+ uint32_t rxFifoPriElevationLevel;
+ uint32_t rxFifoThreshold;
+ t_FmSpBufMargins bufMargins;
+ t_FmSpIntContextDataCopy intContext;
+ bool syncReq;
+ e_FmPortColor color;
+ fmPortFrameErrSelect_t errorsToDiscard;
+ fmPortFrameErrSelect_t errorsToEnq;
+ bool forwardReuseIntContext;
+ t_FmBufferPrefixContent bufferPrefixContent;
+ t_FmBackupBmPools *p_BackupBmPools;
+ bool dontReleaseBuf;
+ bool setNumOfTasks;
+ bool setNumOfOpenDmas;
+ bool setSizeOfFifo;
+#if (DPAA_VERSION >= 11)
+ bool noScatherGather;
+#endif /* (DPAA_VERSION >= 11) */
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+ bool bcbWorkaround;
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+} t_FmPortDriverParam;
+
+
+typedef struct t_FmPortRxPoolsParams
+{
+ uint8_t numOfPools;
+ uint16_t secondLargestBufSize;
+ uint16_t largestBufSize;
+} t_FmPortRxPoolsParams;
+
+typedef struct t_FmPortDsarVars {
+ t_Handle *autoResOffsets;
+ t_FmPortDsarTablesSizes *autoResMaxSizes;
+ uint32_t fmbm_tcfg;
+ uint32_t fmbm_tcmne;
+ uint32_t fmbm_rfne;
+ uint32_t fmbm_rfpne;
+ uint32_t fmbm_rcfg;
+ bool dsarEnabledParser;
+} t_FmPortDsarVars;
+typedef struct {
+ struct fman_port port;
+ t_Handle h_Fm;
+ t_Handle h_FmPcd;
+ t_Handle h_FmMuram;
+ t_FmRevisionInfo fmRevInfo;
+ uint8_t portId;
+ e_FmPortType portType;
+ int enabled;
+ char name[MODULE_NAME_SIZE];
+ uint8_t hardwarePortId;
+ uint16_t fmClkFreq;
+ t_FmPortQmiRegs *p_FmPortQmiRegs;
+ u_FmPortBmiRegs *p_FmPortBmiRegs;
+ t_FmPortPrsRegs *p_FmPortPrsRegs;
+ fmPcdEngines_t pcdEngines;
+ uint32_t savedBmiNia;
+ uint8_t netEnvId;
+ uint32_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
+ uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS];
+ uint8_t privateInfo;
+ uint32_t schemesPerPortVector;
+ bool useClsPlan;
+ uint8_t clsPlanGrpId;
+ t_Handle ccTreeId;
+ t_Handle completeArg;
+ void (*f_Complete)(t_Handle arg);
+ t_FmSpBufferOffsets bufferOffsets;
+ /* Independent-Mode parameters support */
+ bool imEn;
+ t_FmMacIm im;
+ volatile bool lock;
+ t_Handle h_Spinlock;
+ t_FmPortExceptionCallback *f_Exception;
+ t_Handle h_App;
+ uint8_t internalBufferOffset;
+ uint8_t fmanCtrlEventId;
+ uint32_t exceptions;
+ bool polling;
+ t_FmExtPools extBufPools;
+ uint32_t requiredAction;
+ uint32_t savedQmiPnen;
+ uint32_t savedBmiFene;
+ uint32_t savedBmiFpne;
+ uint32_t savedBmiCmne;
+ uint32_t savedBmiOfp;
+ uint32_t savedNonRxQmiRegsPndn;
+ uint32_t origNonRxQmiRegsPndn;
+ int savedPrsStartOffset;
+ bool includeInPrsStatistics;
+ uint16_t maxFrameLength;
+ t_FmFmanCtrl orFmanCtrl;
+ t_FmPortRsrc openDmas;
+ t_FmPortRsrc tasks;
+ t_FmPortRsrc fifoBufs;
+ t_FmPortRxPoolsParams rxPoolsParams;
+// bool explicitUserSizeOfFifo;
+ t_Handle h_IpReassemblyManip;
+ t_Handle h_CapwapReassemblyManip;
+ t_Handle h_ReassemblyTree;
+ uint64_t fmMuramPhysBaseAddr;
+#if (DPAA_VERSION >= 11)
+ bool vspe;
+ uint8_t dfltRelativeId;
+ e_FmPortGprFuncType gprFunc;
+ t_FmPcdCtrlParamsPage *p_ParamsPage;
+#endif /* (DPAA_VERSION >= 11) */
+ t_FmPortDsarVars deepSleepVars;
+ t_FmPortDriverParam *p_FmPortDriverParam;
+} t_FmPort;
+
+
+void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams);
+t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort);
+
+t_Error FmPortImInit(t_FmPort *p_FmPort);
+void FmPortImFree(t_FmPort *p_FmPort);
+
+t_Error FmPortImEnable (t_FmPort *p_FmPort);
+t_Error FmPortImDisable (t_FmPort *p_FmPort);
+t_Error FmPortImRx (t_FmPort *p_FmPort);
+
+void FmPortSetMacsecLcv(t_Handle h_FmPort);
+void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci);
+
+
+t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas);
+t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks);
+t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo);
+
+static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd)
+{
+ uint64_t physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32);
+ physAddr |= GET_UINT32(p_Bd->buff.low);
+
+ return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr));
+}
+
+static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value)
+{
+ WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32));
+ WRITE_UINT32(fmPhysAddr->low,(uint32_t)value);
+}
+
+static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer)
+{
+ uint64_t physAddr = (uint64_t)(f_VirtToPhys(p_Buffer));
+ SET_ADDR(&p_Bd->buff, physAddr);
+}
+
+static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id)
+{
+ if (id < p_FmPort->im.bdRingSize-1)
+ return (uint16_t)(id+1);
+ else
+ return 0;
+}
+
+void FM_PORT_Dsar_DumpRegs(void);
+
+
+#endif /* __FM_PORT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h
new file mode 100755
index 000000000000..95619eff0bee
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File fm_port_dsar.h
+
+ @Description Deep Sleep Auto Response project - common module header file.
+
+ Author - Eyal Harari
+
+ @Cautions See the FMan Controller spec and design document for more information.
+*//***************************************************************************/
+
+#ifndef __FM_PORT_DSAR_H_
+#define __FM_PORT_DSAR_H_
+
+#define DSAR_GETSER_MASK 0xFF0000FF
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
+ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+ uint16_t reserved;
+} _PackedType t_DsarArpBindingEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response Address Resolution Protocol Statistics Descriptor
+ Refer to the FMan Controller spec for more details.
+ 0x00 INVAL_CNT Invalid ARP IPv4-Ethernet counter
+ 0x04 ECHO_CNT Echo counter
+ 0x08 CD_CNT Conflict Detection counter
+ 0x0C AR_CNT Auto-Response counter
+ 0x10 RATM_CNT Replies Addressed To Me counter
+ 0x14 UKOP_CNT Unknown Operation counter
+ 0x18 NMTP_CNT Not my TPA counter
+ 0x1C NMVLAN_CNT Not My VLAN counter
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t invalCnt; /**< Invalid ARP IPv4-Ethernet counter. */
+ uint32_t echoCnt; /**< Echo counter. */
+ uint32_t cdCnt; /**< Conflict Detection counter. */
+ uint32_t arCnt; /**< Auto-Response counter. */
+ uint32_t ratmCnt; /**< Replies Addressed To Me counter. */
+ uint32_t ukopCnt; /**< Unknown Operation counter. */
+ uint32_t nmtpCnt; /**< Not my TPA counter. */
+ uint32_t nmVlanCnt; /**< Not My VLAN counter */
+} _PackedType t_DsarArpStatistics;
+
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response Address Resolution Protocol Descriptor
+ 0x0 0-15 Control bits [0-15]. Bit 15 = CDEN.
+ 0x2 0-15 NumOfBindings Number of entries in the binding list.
+ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an IPv4-MAC Addresses Bindings list.
+ 0x6 0-15
+ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ARP Descriptors statistics data structure.
+ 0xA 0-15
+ 0xC 0-15 Reserved Reserved. Must be cleared.
+ 0xE 015
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint16_t control; /** Control bits [0-15]. Bit 15 = CDEN */
+ uint16_t numOfBindings; /**< Number of VLAN-IPv4 */
+ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */
+ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */
+ uint32_t reserved1; /**< Reserved. */
+} _PackedType t_DsarArpDescriptor;
+
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
+ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+ uint16_t reserved;
+} _PackedType t_DsarIcmpV4BindingEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor
+ Refer to the FMan Controller spec for more details.
+ 0x00 INVAL_CNT Invalid ICMPv4 header counter
+ 0x04 NMVLAN_CNT Not My VLAN counter
+ 0x08 NMIP_CNT Not My IP counter
+ 0x0C AR_CNT Auto-Response counter
+ 0x10 CSERR_CNT Checksum Error counter
+ 0x14 Reserved Reserved
+ 0x18 Reserved Reserved
+ 0x1C Reserved Reserved
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */
+ uint32_t nmVlanCnt; /**< Not My VLAN counter */
+ uint32_t nmIpCnt; /**< Not My IP counter */
+ uint32_t arCnt; /**< Auto-Response counter */
+ uint32_t cserrCnt; /**< Checksum Error counter */
+ uint32_t reserved0; /**< Reserved */
+ uint32_t reserved1; /**< Reserved */
+ uint32_t reserved2; /**< Reserved */
+} _PackedType t_DsarIcmpV4Statistics;
+
+
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response ICMPv4 Descriptor
+ 0x0 0-15 Control bits [0-15]
+ 0x2 0-15 NumOfBindings Number of entries in the binding list.
+ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
+ 0x6 0-15
+ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
+ 0xA 0-15
+ 0xC 0-15 Reserved Reserved. Must be cleared.
+ 0xE 015
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint16_t control; /** Control bits [0-15]. */
+ uint16_t numOfBindings; /**< Number of VLAN-IPv4 */
+ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */
+ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */
+ uint32_t reserved1; /**< Reserved. */
+} _PackedType t_DsarIcmpV4Descriptor;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4)
+ The 4 left-most bits (15:12) of the VlanId parameter are control flags.
+ Flags[3:1] (VlanId[15:13]): Reserved, should be cleared.
+ Flags[0] (VlanId[12]): Temporary address.
+ • 0 - Assigned IP address.
+ • 1- Temporary (tentative) IP address.
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t ipv6Addr[4]; /*!< 3 * 32 bit IPv4 Address. */
+ uint16_t resFlags:4; /*!< reserved flags. should be cleared */
+ uint16_t vlanId:12; /*!< 12 bits VLAN ID. */
+ /*!< This field should be 0x000 for an entry with no VLAN tag or a null VLAN ID. */
+ uint16_t reserved;
+} _PackedType t_DsarIcmpV6BindingEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor
+ Refer to the FMan Controller spec for more details.
+ 0x00 INVAL_CNT Invalid ICMPv4 header counter
+ 0x04 NMVLAN_CNT Not My VLAN counter
+ 0x08 NMIP_CNT Not My IP counter
+ 0x0C AR_CNT Auto-Response counter
+ 0x10 CSERR_CNT Checksum Error counter
+ 0x14 MCAST_CNT Multicast counter
+ 0x18 Reserved Reserved
+ 0x1C Reserved Reserved
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */
+ uint32_t nmVlanCnt; /**< Not My VLAN counter */
+ uint32_t nmIpCnt; /**< Not My IP counter */
+ uint32_t arCnt; /**< Auto-Response counter */
+ uint32_t reserved1; /**< Reserved */
+ uint32_t reserved2; /**< Reserved */
+ uint32_t reserved3; /**< Reserved */
+ uint32_t reserved4; /**< Reserved */
+} _PackedType t_DsarIcmpV6Statistics;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response Neighbor Discovery Statistics Descriptor
+ 0x00 INVAL_CNT Invalid Neighbor Discovery message counter
+ 0x04 NMVLAN_CNT Not My VLAN counter
+ 0x08 NMIP_CNT Not My IP counter
+ 0x0C AR_CNT Auto-Response counter
+ 0x10 CSERR_CNT Checksum Error counter
+ 0x14 USADVERT_CNT Unsolicited Neighbor Advertisements counter
+ 0x18 NMMCAST_CNT Not My Multicast group counter
+ 0x1C NSLLA_CNT No Source Link-Layer Address counter. Indicates that there was a match on a Target
+ Address of a packet that its source IP address is a unicast address, but the ICMPv6
+ Source Link-layer Address option is omitted
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */
+ uint32_t nmVlanCnt; /**< Not My VLAN counter */
+ uint32_t nmIpCnt; /**< Not My IP counter */
+ uint32_t arCnt; /**< Auto-Response counter */
+ uint32_t reserved1; /**< Reserved */
+ uint32_t usadvertCnt; /**< Unsolicited Neighbor Advertisements counter */
+ uint32_t nmmcastCnt; /**< Not My Multicast group counter */
+ uint32_t nsllaCnt; /**< No Source Link-Layer Address counter */
+} _PackedType t_NdStatistics;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response ICMPv6 Descriptor
+ 0x0 0-15 Control bits [0-15]
+ 0x2 0-15 NumOfBindings Number of entries in the binding list.
+ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
+ 0x6 0-15
+ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
+ 0xA 0-15
+ 0xC 0-15 Reserved Reserved. Must be cleared.
+ 0xE 015
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint16_t control; /** Control bits [0-15]. */
+ uint16_t numOfBindings; /**< Number of VLAN-IPv6 */
+ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */
+ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */
+ uint32_t reserved1; /**< Reserved. */
+} _PackedType t_DsarIcmpV6Descriptor;
+
+
+/**************************************************************************//**
+ @Description Internet Control Message Protocol (ICMPv6) Echo message header
+ The fields names are taken from RFC 4443.
+*//***************************************************************************/
+/* 0 1 2 3 */
+/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */
+/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+/* | Type | Code | Checksum | */
+/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+/* | Identifier | Sequence Number | */
+/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+/* | Data ... */
+/* +-+-+-+-+- */
+typedef _Packed struct
+{
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint16_t identifier;
+ uint16_t sequenceNumber;
+} _PackedType t_IcmpV6EchoHdr;
+
+/**************************************************************************//**
+ @Description Internet Control Message Protocol (ICMPv6)
+ Neighbor Solicitation/Advertisement header
+ The fields names are taken from RFC 4861.
+ The R/S/O fields are valid for Neighbor Advertisement only
+*//***************************************************************************/
+/* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Code | Checksum |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |R|S|O| Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + +
+ * | |
+ * + Target Address +
+ * | |
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Options ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-
+ *
+ * Options Format:
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Length | Link-Layer Address ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Link-Layer Address |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+typedef _Packed struct
+{
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t router:1;
+ uint32_t solicited:1;
+ uint32_t override:1;
+ uint32_t reserved:29;
+ uint32_t targetAddr[4];
+ uint8_t optionType;
+ uint8_t optionLength;
+ uint8_t linkLayerAddr[6];
+} _PackedType t_IcmpV6NdHdr;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response ICMPv6 Descriptor
+ 0x0 0-15 Control bits [0-15]
+ 0x2 0-15 NumOfBindings Number of entries in the binding list.
+ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list.
+ 0x6 0-15
+ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure.
+ 0xA 0-15
+ 0xC 0-15 Reserved Reserved. Must be cleared.
+ 0xE 015
+
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint16_t control; /** Control bits [0-15]. */
+ uint16_t numOfBindings; /**< Number of VLAN-IPv6 */
+ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */
+ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */
+ uint32_t solicitedAddr; /**< Solicited Node Multicast Group Address */
+} _PackedType t_DsarNdDescriptor;
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response SNMP OIDs table entry
+
+*//***************************************************************************/
+typedef struct {
+ uint16_t oidSize; /**< Size in octets of the OID. */
+ uint16_t resSize; /**< Size in octets of the value that is attached to the OID. */
+ uint32_t p_Oid; /**< Pointer to the OID. OID is encoded in BER but type and length are excluded. */
+ uint32_t resValOrPtr; /**< Value (for up to 4 octets) or pointer to the Value. Encoded in BER. */
+ uint32_t reserved;
+} t_OidsTblEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef struct
+{
+ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
+ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+ uint16_t reserved;
+} t_DsarSnmpIpv4AddrTblEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+#pragma pack(push,1)
+typedef struct
+{
+ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */
+ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+ uint16_t reserved;
+} t_DsarSnmpIpv6AddrTblEntry;
+#pragma pack(pop)
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response SNMP statistics table
+
+*//***************************************************************************/
+typedef struct {
+ uint32_t snmpErrCnt; /**< Counts SNMP errors (wrong version, BER encoding, format). */
+ uint32_t snmpCommunityErrCnt; /**< Counts messages that were dropped due to insufficient permission. */
+ uint32_t snmpTotalDiscardCnt; /**< Counts any message that was dropped. */
+ uint32_t snmpGetReqCnt; /**< Counts the number of get-request messages */
+ uint32_t snmpGetNextReqCnt; /**< Counts the number of get-next-request messages */
+} t_DsarSnmpStatistics;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP Descriptor
+
+*//***************************************************************************/
+typedef struct
+{
+ uint16_t control; /**< Control bits [0-15]. */
+ uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */
+ uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */
+ uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */
+ uint32_t p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */
+ uint32_t p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */
+ uint32_t p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */
+ uint32_t p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */
+ uint32_t p_OidsTbl; /**< Pointer to OIDs table. */
+ uint32_t oidsTblSize; /**< Number of entries in OIDs table. */
+ uint32_t p_Statistics; /**< Pointer to SNMP statistics table. */
+} t_DsarSnmpDescriptor;
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response (Common) Statistics
+
+*//***************************************************************************/
+typedef _Packed struct {
+ uint32_t dsarDiscarded;
+ uint32_t dsarErrDiscarded;
+ uint32_t dsarFragDiscarded;
+ uint32_t dsarTunnelDiscarded;
+ uint32_t dsarArpDiscarded;
+ uint32_t dsarIpDiscarded;
+ uint32_t dsarTcpDiscarded;
+ uint32_t dsarUdpDiscarded;
+ uint32_t dsarIcmpV6ChecksumErr; /* ICMPv6 Checksum Error counter */
+ uint32_t dsarIcmpV6OtherType; /* ICMPv6 'Other' type (not Echo or Neighbor Solicitaion/Advertisement counter */
+ uint32_t dsarIcmpV4OtherType; /* ICMPv4 'Other' type (not Echo) counter */
+} _PackedType t_ArStatistics;
+
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response TCP/UDP port filter table entry
+
+*//***************************************************************************/
+typedef _Packed struct {
+ uint32_t Ports;
+ uint32_t PortsMask;
+} _PackedType t_PortTblEntry;
+
+
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response Common Parameters Descriptor
+
+*//***************************************************************************/
+typedef _Packed struct {
+ uint8_t arTxPort; /* 0x00 0-7 Auto Response Transmit Port number */
+ uint8_t controlBits; /* 0x00 8-15 Auto Response control bits */
+ uint16_t res1; /* 0x00 16-31 Reserved */
+ uint32_t activeHPNIA; /* 0x04 0-31 Active mode Hardware Parser NIA */
+ uint16_t snmpPort; /* 0x08 0-15 SNMP Port. */
+ uint8_t macStationAddr[6]; /* 0x08 16-31 and 0x0C 0-31 MAC Station Address */
+ uint8_t res2; /* 0x10 0-7 Reserved */
+ uint8_t filterControl; /* 0x10 8-15 Filtering Control Bits. */
+ uint16_t tcpControlPass; /* 0x10 16-31 TCP control pass flags */
+ uint8_t ipProtocolTblSize; /* 0x14 0-7 IP Protocol Table Size. */
+ uint8_t udpPortTblSize; /* 0x14 8-15 UDP Port Table Size. */
+ uint8_t tcpPortTblSize; /* 0x14 16-23 TCP Port Table Size. */
+ uint8_t res3; /* 0x14 24-31 Reserved */
+ uint32_t p_IpProtocolFiltTbl; /* 0x18 0-31 Pointer to IP Protocol Filter Table */
+ uint32_t p_UdpPortFiltTbl; /* 0x1C 0-31 Pointer to UDP Port Filter Table */
+ uint32_t p_TcpPortFiltTbl; /* 0x20 0-31 Pointer to TCP Port Filter Table */
+ uint32_t res4; /* 0x24 Reserved */
+ uint32_t p_ArpDescriptor; /* 0x28 0-31 ARP Descriptor Pointer. */
+ uint32_t p_NdDescriptor; /* 0x2C 0-31 Neighbor Discovery Descriptor. */
+ uint32_t p_IcmpV4Descriptor; /* 0x30 0-31 ICMPv4 Descriptor pointer. */
+ uint32_t p_IcmpV6Descriptor; /* 0x34 0-31 ICMPv6 Descriptor pointer. */
+ uint32_t p_SnmpDescriptor; /* 0x38 0-31 SNMP Descriptor pointer. */
+ uint32_t p_ArStats; /* 0x3C 0-31 Pointer to Auto Response Statistics */
+} _PackedType t_ArCommonDesc;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+/* t_ArCommonDesc.filterControl bits */
+#define IP_PROT_TBL_PASS_MASK 0x08
+#define UDP_PORT_TBL_PASS_MASK 0x04
+#define TCP_PORT_TBL_PASS_MASK 0x02
+
+/* Offset of TCF flags within TCP packet */
+#define TCP_FLAGS_OFFSET 12
+
+
+#endif /* __FM_PORT_DSAR_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c
new file mode 100644
index 000000000000..8de8f5fd9ddb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c
@@ -0,0 +1,753 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_port_im.c
+
+ @Description FM Port Independent-Mode ...
+*//***************************************************************************/
+#include "std_ext.h"
+#include "string_ext.h"
+#include "error_ext.h"
+#include "memcpy_ext.h"
+#include "fm_muram_ext.h"
+
+#include "fm_port.h"
+
+
+#define TX_CONF_STATUS_UNSENT 0x1
+
+
+typedef enum e_TxConfType
+{
+ e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */
+ ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */
+ ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */
+} e_TxConfType;
+
+
+static void ImException(t_Handle h_FmPort, uint32_t event)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) ||
+ !FmIsMaster(p_FmPort->h_Fm));
+
+ if (event & IM_EV_RX)
+ FmPortImRx(p_FmPort);
+ if ((event & IM_EV_BSY) && p_FmPort->f_Exception)
+ p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY);
+}
+
+
+static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType)
+{
+ t_Error retVal = E_BUSY;
+ uint32_t bdStatus;
+ uint16_t savedStartBdId, confBdId;
+
+ ASSERT_COND(p_FmPort);
+
+ /*
+ if (confType==e_TX_CONF_TYPE_CHECK)
+ return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY);
+ */
+
+ confBdId = savedStartBdId = p_FmPort->im.currBdId;
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId));
+
+ /* If R bit is set, we don't enter, or we break.
+ we run till we get to R, or complete the loop */
+ while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK))
+ {
+ if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */
+ BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0);
+
+ /* case 1: R bit is 0 and Length is set -> confirm! */
+ if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK))
+ {
+ if (p_FmPort->im.f_TxConf)
+ {
+ if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E))
+ p_FmPort->im.f_TxConf(p_FmPort->h_App,
+ BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)),
+ TX_CONF_STATUS_UNSENT,
+ p_FmPort->im.p_BdShadow[confBdId]);
+ else
+ p_FmPort->im.f_TxConf(p_FmPort->h_App,
+ BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)),
+ 0,
+ p_FmPort->im.p_BdShadow[confBdId]);
+ }
+ }
+ /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */
+
+ confBdId = GetNextBdId(p_FmPort, confBdId);
+ if (confBdId == savedStartBdId)
+ retVal = E_OK;
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId));
+ }
+
+ return retVal;
+}
+
+t_Error FmPortImEnable(t_FmPort *p_FmPort)
+{
+ uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode);
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP));
+ return E_OK;
+}
+
+t_Error FmPortImDisable(t_FmPort *p_FmPort)
+{
+ uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode);
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP));
+ return E_OK;
+}
+
+t_Error FmPortImRx(t_FmPort *p_FmPort)
+{
+ t_Handle h_CurrUserPriv, h_NewUserPriv;
+ uint32_t bdStatus;
+ volatile uint8_t buffPos;
+ uint16_t length;
+ uint16_t errors;
+ uint8_t *p_CurData, *p_Data;
+ uint32_t flags;
+
+ ASSERT_COND(p_FmPort);
+
+ flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock);
+ if (p_FmPort->lock)
+ {
+ XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags);
+ return E_OK;
+ }
+ p_FmPort->lock = TRUE;
+ XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags);
+
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
+
+ while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */
+ {
+ if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL)
+ {
+ p_FmPort->lock = FALSE;
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer"));
+ }
+
+ if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID)
+ p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId;
+
+ p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId));
+ h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId];
+ length = (uint16_t)((bdStatus & BD_L) ?
+ ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength):
+ (bdStatus & BD_LENGTH_MASK));
+ p_FmPort->im.rxFrameAccumLength += length;
+
+ /* determine whether buffer is first, last, first and last (single */
+ /* buffer frame) or middle (not first and not last) */
+ buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ?
+ ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) :
+ ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF));
+
+ if (bdStatus & BD_L)
+ {
+ p_FmPort->im.rxFrameAccumLength = 0;
+ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
+ }
+
+ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data);
+
+ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E);
+
+ errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16);
+ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv;
+
+ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4));
+ /* Pass the buffer if one of the conditions is true:
+ - There are no errors
+ - This is a part of a larger frame ( the application has already received some buffers ) */
+ if ((buffPos != SINGLE_BUF) || !errors)
+ {
+ if (p_FmPort->im.f_RxStore(p_FmPort->h_App,
+ p_CurData,
+ length,
+ errors,
+ buffPos,
+ h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE)
+ break;
+ }
+ else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool,
+ p_CurData,
+ h_CurrUserPriv))
+ {
+ p_FmPort->lock = FALSE;
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer"));
+ }
+
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
+ }
+ p_FmPort->lock = FALSE;
+ return E_OK;
+}
+
+void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams)
+{
+ ASSERT_COND(p_FmPort);
+
+ SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram;
+ p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset;
+ p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId;
+ p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes;
+
+ p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId;
+ p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr;
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool;
+ p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf;
+ p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf;
+ p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize;
+ p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt;
+ if (!p_FmPort->im.rxPool.f_PhysToVirt)
+ p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt;
+ p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys;
+ if (!p_FmPort->im.rxPool.f_VirtToPhys)
+ p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys;
+ p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore;
+
+ p_FmPort->im.mrblr = 0x8000;
+ while (p_FmPort->im.mrblr)
+ {
+ if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr)
+ break;
+ p_FmPort->im.mrblr >>= 1;
+ }
+ if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize)
+ DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr));
+ p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength;
+ p_FmPort->exceptions = DEFAULT_PORT_exception;
+ if (FmIsMaster(p_FmPort->h_Fm))
+ p_FmPort->polling = FALSE;
+ else
+ p_FmPort->polling = TRUE;
+ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ;
+ }
+ else
+ {
+ p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf;
+
+ p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength;
+ }
+}
+
+t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort)
+{
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) &&
+ (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) &&
+ (p_FmPort->portType != e_FM_PORT_TYPE_TX) &&
+ (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ if (!POWER_OF_2(p_FmPort->im.mrblr))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!"));
+ if (p_FmPort->im.mrblr < 256)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!"));
+ if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
+ }
+
+ return E_OK;
+}
+
+t_Error FmPortImInit(t_FmPort *p_FmPort)
+{
+ t_FmImBd *p_Bd=NULL;
+ t_Handle h_BufContext;
+ uint64_t tmpPhysBase;
+ uint16_t log2Num;
+ uint8_t *p_Data/*, *p_Tmp*/;
+ int i;
+ t_Error err;
+ uint16_t tmpReg16;
+ uint32_t tmpReg32;
+
+ ASSERT_COND(p_FmPort);
+
+ p_FmPort->im.p_FmPortImPram =
+ (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN);
+ if (!p_FmPort->im.p_FmPortImPram)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!"));
+ WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram));
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ p_FmPort->im.p_BdRing =
+ (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize),
+ p_FmPort->im.fwExtStructsMemId,
+ 4);
+ if (!p_FmPort->im.p_BdRing)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!"));
+ IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
+
+ p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
+ if (!p_FmPort->im.p_BdShadow)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!"));
+ memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
+
+ /* Initialize the Rx-BD ring */
+ for (i=0; i<p_FmPort->im.bdRingSize; i++)
+ {
+ p_Bd = BD_GET(i);
+ BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E);
+
+ if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer"));
+ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data);
+ p_FmPort->im.p_BdShadow[i] = h_BufContext;
+ }
+
+ if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) ||
+ (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE))
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2));
+ else
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2));
+
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr,
+ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
+ p_FmPort->fmMuramPhysBaseAddr + 0x20));
+
+ LOG2((uint64_t)p_FmPort->im.mrblr, log2Num);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num);
+
+ /* Initialize Rx QD */
+ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing));
+ SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
+
+ /* Update the IM PRAM address in the BMI */
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid,
+ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
+ p_FmPort->fmMuramPhysBaseAddr));
+ if (!p_FmPort->polling || p_FmPort->exceptions)
+ {
+ /* Allocate, configure and register interrupts */
+ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK));
+ tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK);
+ tmpReg32 = 0;
+
+ if (p_FmPort->exceptions & IM_EV_BSY)
+ {
+ tmpReg16 |= IM_RXQD_BSYINTM;
+ tmpReg32 |= IM_EV_BSY;
+ }
+ if (!p_FmPort->polling)
+ {
+ tmpReg16 |= IM_RXQD_RXFINTM;
+ tmpReg32 |= IM_EV_RX;
+ }
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
+
+ FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort);
+
+ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
+ }
+ else
+ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ;
+ }
+ else
+ {
+ p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4);
+ if (!p_FmPort->im.p_BdRing)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!"));
+ IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
+
+ p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
+ if (!p_FmPort->im.p_BdShadow)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!"));
+ memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize));
+ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
+
+ if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) ||
+ (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE))
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2));
+ else
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2));
+
+ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr,
+ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
+ p_FmPort->fmMuramPhysBaseAddr + 0x40));
+
+ /* Initialize Tx QD */
+ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing));
+ SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize));
+
+ /* Update the IM PRAM address in the BMI */
+ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid,
+ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) -
+ p_FmPort->fmMuramPhysBaseAddr));
+ }
+
+
+ return E_OK;
+}
+
+void FmPortImFree(t_FmPort *p_FmPort)
+{
+ uint32_t bdStatus;
+ uint8_t *p_CurData;
+
+ ASSERT_COND(p_FmPort);
+ ASSERT_COND(p_FmPort->im.p_FmPortImPram);
+
+ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ||
+ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ if (!p_FmPort->polling || p_FmPort->exceptions)
+ {
+ /* Deallocate and unregister interrupts */
+ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0);
+
+ FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
+
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0);
+
+ FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
+ }
+ /* Try first clean what has received */
+ FmPortImRx(p_FmPort);
+
+ /* Now, get rid of the the empty buffer! */
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
+
+ while (bdStatus & BD_R_E) /* while there is data in the Rx BD */
+ {
+ p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId));
+
+ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL);
+ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0);
+
+ p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool,
+ p_CurData,
+ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]);
+
+ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
+ }
+ }
+ else
+ TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH);
+
+ FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram);
+
+ if (p_FmPort->im.p_BdShadow)
+ XX_Free(p_FmPort->im.p_BdShadow);
+
+ if (p_FmPort->im.p_BdRing)
+ XX_FreeSmart(p_FmPort->im.p_BdRing);
+}
+
+
+t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->im.mrblr = newVal;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->im.bdRingSize = newVal;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->im.bdRingSize = newVal;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort,
+ uint8_t memId,
+ uint32_t memAttributes)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ p_FmPort->im.fwExtStructsMemId = memId;
+ p_FmPort->im.fwExtStructsMemAttr = memAttributes;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only"));
+
+ if (!FmIsMaster(p_FmPort->h_Fm))
+ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;"
+ "in guest-partitions, IM is always in polling!"));
+
+ p_FmPort->polling = TRUE;
+
+ return E_OK;
+}
+
+t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ t_Error err;
+ uint16_t tmpReg16;
+ uint32_t tmpReg32;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ if (exception == e_FM_PORT_EXCEPTION_IM_BUSY)
+ {
+ if (enable)
+ {
+ p_FmPort->exceptions |= IM_EV_BSY;
+ if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ)
+ {
+ /* Allocate, configure and register interrupts */
+ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK));
+
+ FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort);
+ tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM);
+ tmpReg32 = IM_EV_BSY;
+ }
+ else
+ {
+ tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM);
+ tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY;
+ }
+
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
+ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
+ }
+ else
+ {
+ p_FmPort->exceptions &= ~IM_EV_BSY;
+ if (!p_FmPort->exceptions && p_FmPort->polling)
+ {
+ FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
+ FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId);
+ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0);
+ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ;
+ }
+ else
+ {
+ tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM);
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16);
+ tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY;
+ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32);
+ }
+ }
+ }
+ else
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception."));
+
+ return E_OK;
+}
+
+t_Error FM_PORT_ImTx( t_Handle h_FmPort,
+ uint8_t *p_Data,
+ uint16_t length,
+ bool lastBuffer,
+ t_Handle h_BufContext)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+ uint16_t nextBdId;
+ uint32_t bdStatus, nextBdStatus;
+ bool firstBuffer;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId));
+ nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
+ nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId));
+
+ if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E))
+ {
+ /* Confirm the current BD - BD is available */
+ if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf))
+ p_FmPort->im.f_TxConf (p_FmPort->h_App,
+ BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)),
+ 0,
+ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]);
+
+ bdStatus = length;
+
+ /* if this is the first BD of a frame */
+ if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID)
+ {
+ firstBuffer = TRUE;
+ p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E);
+
+ if (!lastBuffer)
+ p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId;
+ }
+ else
+ firstBuffer = FALSE;
+
+ BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data);
+ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext;
+
+ /* deal with last */
+ if (lastBuffer)
+ {
+ /* if single buffer frame */
+ if (firstBuffer)
+ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L);
+ else
+ {
+ /* Set the last BD of the frame */
+ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L));
+ /* Set the first BD of the frame */
+ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus);
+ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
+ }
+ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4));
+ }
+ else if (!firstBuffer) /* mid frame buffer */
+ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E);
+
+ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId);
+ }
+ else
+ {
+ /* Discard current frame. Return error. */
+ if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID)
+ {
+ /* Error: No free BD */
+ /* Response: Discard current frame. Return error. */
+ uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId;
+
+ ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId);
+
+ /* Since firstInFrame is not NULL, one buffer at least has already been
+ inserted into the BD ring. Using do-while covers the situation of a
+ frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented
+ prior to testing whether or not it's equal to TxBd). */
+ do
+ {
+ BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0);
+ /* Advance BD pointer */
+ cleanBdId = GetNextBdId(p_FmPort, cleanBdId);
+ } while (cleanBdId != p_FmPort->im.currBdId);
+
+ p_FmPort->im.currBdId = cleanBdId;
+ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID;
+ }
+
+ return ERROR_CODE(E_FULL);
+ }
+
+ return E_OK;
+}
+
+void FM_PORT_ImTxConf(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK);
+}
+
+t_Error FM_PORT_ImRx(t_Handle h_FmPort)
+{
+ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE);
+
+ return FmPortImRx(p_FmPort);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
new file mode 100755
index 000000000000..aaca1d711c78
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c
@@ -0,0 +1,1570 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include "common/general.h"
+
+#include "fman_common.h"
+#include "fsl_fman_port.h"
+
+
+/* problem Eyal: the following should not be here*/
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+
+static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg)
+{
+ if (cfg->errata_A006675)
+ return NIA_ENG_FM_CTL |
+ NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME;
+ else
+ return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME;
+}
+
+static int init_bmi_rx(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
+ uint32_t tmp;
+
+ /* Rx Configuration register */
+ tmp = 0;
+ if (port->im_en)
+ tmp |= BMI_PORT_CFG_IM;
+ else if (cfg->discard_override)
+ tmp |= BMI_PORT_CFG_FDOVR;
+ iowrite32be(tmp, &regs->fmbm_rcfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ if (cfg->dma_write_optimize)
+ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
+ iowrite32be(tmp, &regs->fmbm_rda);
+
+ /* Rx FIFO parameters */
+ tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) <<
+ BMI_RX_FIFO_PRI_ELEVATION_SHIFT;
+ tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1;
+ iowrite32be(tmp, &regs->fmbm_rfp);
+
+ if (cfg->excessive_threshold_register)
+ /* always allow access to the extra resources */
+ iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, &regs->fmbm_reth);
+
+ /* Frame end data */
+ tmp = (uint32_t)cfg->checksum_bytes_ignore <<
+ BMI_RX_FRAME_END_CS_IGNORE_SHIFT;
+ tmp |= (uint32_t)cfg->rx_cut_end_bytes <<
+ BMI_RX_FRAME_END_CUT_SHIFT;
+ if (cfg->errata_A006320)
+ tmp &= 0xffe0ffff;
+ iowrite32be(tmp, &regs->fmbm_rfed);
+
+ /* Internal context parameters */
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, &regs->fmbm_ricp);
+
+ /* Internal buffer offset */
+ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
+ << BMI_INT_BUF_MARG_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_rim);
+
+ /* External buffer margins */
+ if (!port->im_en)
+ {
+ tmp = (uint32_t)cfg->ext_buf_start_margin <<
+ BMI_EXT_BUF_MARG_START_SHIFT;
+ tmp |= (uint32_t)cfg->ext_buf_end_margin;
+ if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather)
+ tmp |= BMI_SG_DISABLE;
+ iowrite32be(tmp, &regs->fmbm_rebm);
+ }
+
+ /* Frame attributes */
+ tmp = BMI_CMD_RX_MR_DEF;
+ if (!port->im_en)
+ {
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ if (cfg->sync_req)
+ tmp |= BMI_CMD_ATTR_SYNC;
+ }
+ iowrite32be(tmp, &regs->fmbm_rfca);
+
+ /* NIA */
+ if (port->im_en)
+ tmp = NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX;
+ else
+ {
+ tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
+ tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg);
+ }
+ iowrite32be(tmp, &regs->fmbm_rfne);
+
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->fmbm_rfene);
+
+ /* Default/error queues */
+ if (!port->im_en)
+ {
+ iowrite32be((params->dflt_fqid & 0x00FFFFFF), &regs->fmbm_rfqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_refqid);
+ }
+
+ /* Discard/error masks */
+ iowrite32be(params->discard_mask, &regs->fmbm_rfsdm);
+ iowrite32be(params->err_mask, &regs->fmbm_rfsem);
+
+ /* Statistics counters */
+ tmp = 0;
+ if (cfg->stats_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_rstc);
+
+ /* Performance counters */
+ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
+ tmp = 0;
+ if (cfg->perf_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_rpc);
+
+ return 0;
+}
+
+static int init_bmi_tx(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
+ uint32_t tmp;
+
+ /* Tx Configuration register */
+ tmp = 0;
+ if (port->im_en)
+ tmp |= BMI_PORT_CFG_IM;
+ iowrite32be(tmp, &regs->fmbm_tcfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ iowrite32be(tmp, &regs->fmbm_tda);
+
+ /* Tx FIFO parameters */
+ tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) <<
+ BMI_TX_FIFO_MIN_FILL_SHIFT;
+ tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
+ BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level /
+ FMAN_PORT_BMI_FIFO_UNITS - 1);
+ iowrite32be(tmp, &regs->fmbm_tfp);
+
+ /* Frame end data */
+ tmp = (uint32_t)cfg->checksum_bytes_ignore <<
+ BMI_FRAME_END_CS_IGNORE_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_tfed);
+
+ /* Internal context parameters */
+ if (!port->im_en)
+ {
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, &regs->fmbm_ticp);
+ }
+ /* Frame attributes */
+ tmp = BMI_CMD_TX_MR_DEF;
+ if (port->im_en)
+ tmp |= BMI_CMD_MR_DEAS;
+ else
+ {
+ tmp |= BMI_CMD_ATTR_ORDER;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ }
+ iowrite32be(tmp, &regs->fmbm_tfca);
+
+ /* Dequeue NIA + enqueue NIA */
+ if (port->im_en)
+ {
+ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, &regs->fmbm_tfdne);
+ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, &regs->fmbm_tfene);
+ }
+ else
+ {
+ iowrite32be(NIA_ENG_QMI_DEQ, &regs->fmbm_tfdne);
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, &regs->fmbm_tfene);
+ if (cfg->fmbm_tfne_has_features)
+ iowrite32be(!params->dflt_fqid ?
+ BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME :
+ NIA_BMI_AC_FETCH_ALL_FRAME, &regs->fmbm_tfne);
+ if (!params->dflt_fqid && params->dont_release_buf)
+ {
+ iowrite32be(0x00FFFFFF, &regs->fmbm_tcfqid);
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, &regs->fmbm_tfene);
+ if (cfg->fmbm_tfne_has_features)
+ iowrite32be(ioread32be(&regs->fmbm_tfne) & ~BMI_EBD_EN, &regs->fmbm_tfne);
+ }
+ }
+
+ /* Confirmation/error queues */
+ if (!port->im_en)
+ {
+ if (params->dflt_fqid || !params->dont_release_buf)
+ iowrite32be(params->dflt_fqid & 0x00FFFFFF, &regs->fmbm_tcfqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_tefqid);
+ }
+ /* Statistics counters */
+ tmp = 0;
+ if (cfg->stats_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_tstc);
+
+ /* Performance counters */
+ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
+ tmp = 0;
+ if (cfg->perf_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_tpc);
+
+ return 0;
+}
+
+static int init_bmi_oh(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
+ uint32_t tmp;
+
+ /* OP Configuration register */
+ tmp = 0;
+ if (cfg->discard_override)
+ tmp |= BMI_PORT_CFG_FDOVR;
+ iowrite32be(tmp, &regs->fmbm_ocfg);
+
+ /* DMA attributes */
+ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT;
+ if (cfg->dma_ic_stash_on)
+ tmp |= BMI_DMA_ATTR_IC_STASH_ON;
+ if (cfg->dma_header_stash_on)
+ tmp |= BMI_DMA_ATTR_HDR_STASH_ON;
+ if (cfg->dma_sg_stash_on)
+ tmp |= BMI_DMA_ATTR_SG_STASH_ON;
+ if (cfg->dma_write_optimize)
+ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE;
+ iowrite32be(tmp, &regs->fmbm_oda);
+
+ /* Tx FIFO parameters */
+ tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) <<
+ BMI_FIFO_PIPELINE_DEPTH_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_ofp);
+
+ /* Internal context parameters */
+ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_TO_EXT_SHIFT;
+ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) <<
+ BMI_IC_FROM_INT_SHIFT;
+ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS;
+ iowrite32be(tmp, &regs->fmbm_oicp);
+
+ /* Frame attributes */
+ tmp = BMI_CMD_OP_MR_DEF;
+ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT;
+ if (cfg->sync_req)
+ tmp |= BMI_CMD_ATTR_SYNC;
+ if (port->type == E_FMAN_PORT_TYPE_OP)
+ tmp |= BMI_CMD_ATTR_ORDER;
+ iowrite32be(tmp, &regs->fmbm_ofca);
+
+ /* Internal buffer offset */
+ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS)
+ << BMI_INT_BUF_MARG_SHIFT;
+ iowrite32be(tmp, &regs->fmbm_oim);
+
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_QMI_DEQ, &regs->fmbm_ofdne);
+
+ /* NIA and Enqueue NIA */
+ if (port->type == E_FMAN_PORT_TYPE_HC) {
+ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC,
+ &regs->fmbm_ofne);
+ iowrite32be(NIA_ENG_QMI_ENQ, &regs->fmbm_ofene);
+ } else {
+ iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg),
+ &regs->fmbm_ofne);
+ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR,
+ &regs->fmbm_ofene);
+ }
+
+ /* Default/error queues */
+ iowrite32be((params->dflt_fqid & 0x00FFFFFF), &regs->fmbm_ofqid);
+ iowrite32be((params->err_fqid & 0x00FFFFFF), &regs->fmbm_oefqid);
+
+ /* Discard/error masks */
+ if (port->type == E_FMAN_PORT_TYPE_OP) {
+ iowrite32be(params->discard_mask, &regs->fmbm_ofsdm);
+ iowrite32be(params->err_mask, &regs->fmbm_ofsem);
+ }
+
+ /* Statistics counters */
+ tmp = 0;
+ if (cfg->stats_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_ostc);
+
+ /* Performance counters */
+ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params);
+ tmp = 0;
+ if (cfg->perf_counters_enable)
+ tmp = BMI_COUNTERS_EN;
+ iowrite32be(tmp, &regs->fmbm_opc);
+
+ return 0;
+}
+
+static int init_qmi(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ struct fman_port_qmi_regs *regs = port->qmi_regs;
+ uint32_t tmp;
+
+ tmp = 0;
+ if (cfg->queue_counters_enable)
+ tmp |= QMI_PORT_CFG_EN_COUNTERS;
+ iowrite32be(tmp, &regs->fmqm_pnc);
+
+ /* Rx port configuration */
+ if ((port->type == E_FMAN_PORT_TYPE_RX) ||
+ (port->type == E_FMAN_PORT_TYPE_RX_10G)) {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, &regs->fmqm_pnen);
+ return 0;
+ }
+
+ /* Continue with Tx and O/H port configuration */
+ if ((port->type == E_FMAN_PORT_TYPE_TX) ||
+ (port->type == E_FMAN_PORT_TYPE_TX_10G)) {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE,
+ &regs->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, &regs->fmqm_pndn);
+ } else {
+ /* Enqueue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, &regs->fmqm_pnen);
+ /* Dequeue NIA */
+ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, &regs->fmqm_pndn);
+ }
+
+ /* Dequeue Configuration register */
+ tmp = 0;
+ if (cfg->deq_high_pri)
+ tmp |= QMI_DEQ_CFG_PRI;
+
+ switch (cfg->deq_type) {
+ case E_FMAN_PORT_DEQ_BY_PRI:
+ tmp |= QMI_DEQ_CFG_TYPE1;
+ break;
+ case E_FMAN_PORT_DEQ_ACTIVE_FQ:
+ tmp |= QMI_DEQ_CFG_TYPE2;
+ break;
+ case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS:
+ tmp |= QMI_DEQ_CFG_TYPE3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cfg->qmi_deq_options_support) {
+ if ((port->type == E_FMAN_PORT_TYPE_HC) &&
+ (cfg->deq_prefetch_opt != E_FMAN_PORT_DEQ_NO_PREFETCH))
+ return -EINVAL;
+
+ switch (cfg->deq_prefetch_opt) {
+ case E_FMAN_PORT_DEQ_NO_PREFETCH:
+ break;
+ case E_FMAN_PORT_DEQ_PART_PREFETCH:
+ tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL;
+ break;
+ case E_FMAN_PORT_DEQ_FULL_PREFETCH:
+ tmp |= QMI_DEQ_CFG_PREFETCH_FULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) <<
+ QMI_DEQ_CFG_SP_SHIFT;
+ tmp |= cfg->deq_byte_cnt;
+ iowrite32be(tmp, &regs->fmqm_pndc);
+
+ return 0;
+}
+
+static void get_rx_stats_reg(struct fman_port *port,
+ enum fman_port_stats_counters counter,
+ uint32_t **stats_reg)
+{
+ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
+
+ switch (counter) {
+ case E_FMAN_PORT_STATS_CNT_FRAME:
+ *stats_reg = &regs->fmbm_rfrc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DISCARD:
+ *stats_reg = &regs->fmbm_rfdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
+ *stats_reg = &regs->fmbm_rbdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME:
+ *stats_reg = &regs->fmbm_rfbc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME:
+ *stats_reg = &regs->fmbm_rlfc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF:
+ *stats_reg = &regs->fmbm_rodc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME:
+ *stats_reg = &regs->fmbm_rffc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DMA_ERR:
+ *stats_reg = &regs->fmbm_rfldec;
+ break;
+ default:
+ *stats_reg = NULL;
+ }
+}
+
+static void get_tx_stats_reg(struct fman_port *port,
+ enum fman_port_stats_counters counter,
+ uint32_t **stats_reg)
+{
+ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
+
+ switch (counter) {
+ case E_FMAN_PORT_STATS_CNT_FRAME:
+ *stats_reg = &regs->fmbm_tfrc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DISCARD:
+ *stats_reg = &regs->fmbm_tfdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
+ *stats_reg = &regs->fmbm_tbdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_LEN_ERR:
+ *stats_reg = &regs->fmbm_tfledc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT:
+ *stats_reg = &regs->fmbm_tfufdc;
+ break;
+ default:
+ *stats_reg = NULL;
+ }
+}
+
+static void get_oh_stats_reg(struct fman_port *port,
+ enum fman_port_stats_counters counter,
+ uint32_t **stats_reg)
+{
+ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
+
+ switch (counter) {
+ case E_FMAN_PORT_STATS_CNT_FRAME:
+ *stats_reg = &regs->fmbm_ofrc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DISCARD:
+ *stats_reg = &regs->fmbm_ofdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF:
+ *stats_reg = &regs->fmbm_obdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME:
+ *stats_reg = &regs->fmbm_offc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_DMA_ERR:
+ *stats_reg = &regs->fmbm_ofldec;
+ break;
+ case E_FMAN_PORT_STATS_CNT_LEN_ERR:
+ *stats_reg = &regs->fmbm_ofledc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT:
+ *stats_reg = &regs->fmbm_ofufdc;
+ break;
+ case E_FMAN_PORT_STATS_CNT_WRED_DISCARD:
+ *stats_reg = &regs->fmbm_ofwdc;
+ break;
+ default:
+ *stats_reg = NULL;
+ }
+}
+
+static void get_rx_perf_reg(struct fman_port *port,
+ enum fman_port_perf_counters counter,
+ uint32_t **perf_reg)
+{
+ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx;
+
+ switch (counter) {
+ case E_FMAN_PORT_PERF_CNT_CYCLE:
+ *perf_reg = &regs->fmbm_rccn;
+ break;
+ case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
+ *perf_reg = &regs->fmbm_rtuc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL:
+ *perf_reg = &regs->fmbm_rrquc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
+ *perf_reg = &regs->fmbm_rduc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
+ *perf_reg = &regs->fmbm_rfuc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_RX_PAUSE:
+ *perf_reg = &regs->fmbm_rpac;
+ break;
+ default:
+ *perf_reg = NULL;
+ }
+}
+
+static void get_tx_perf_reg(struct fman_port *port,
+ enum fman_port_perf_counters counter,
+ uint32_t **perf_reg)
+{
+ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx;
+
+ switch (counter) {
+ case E_FMAN_PORT_PERF_CNT_CYCLE:
+ *perf_reg = &regs->fmbm_tccn;
+ break;
+ case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
+ *perf_reg = &regs->fmbm_ttuc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL:
+ *perf_reg = &regs->fmbm_ttcquc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
+ *perf_reg = &regs->fmbm_tduc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
+ *perf_reg = &regs->fmbm_tfuc;
+ break;
+ default:
+ *perf_reg = NULL;
+ }
+}
+
+static void get_oh_perf_reg(struct fman_port *port,
+ enum fman_port_perf_counters counter,
+ uint32_t **perf_reg)
+{
+ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh;
+
+ switch (counter) {
+ case E_FMAN_PORT_PERF_CNT_CYCLE:
+ *perf_reg = &regs->fmbm_occn;
+ break;
+ case E_FMAN_PORT_PERF_CNT_TASK_UTIL:
+ *perf_reg = &regs->fmbm_otuc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_DMA_UTIL:
+ *perf_reg = &regs->fmbm_oduc;
+ break;
+ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL:
+ *perf_reg = &regs->fmbm_ofuc;
+ break;
+ default:
+ *perf_reg = NULL;
+ }
+}
+
+static void get_qmi_counter_reg(struct fman_port *port,
+ enum fman_port_qmi_counters counter,
+ uint32_t **queue_reg)
+{
+ struct fman_port_qmi_regs *regs = port->qmi_regs;
+
+ switch (counter) {
+ case E_FMAN_PORT_ENQ_TOTAL:
+ *queue_reg = &regs->fmqm_pnetfc;
+ break;
+ case E_FMAN_PORT_DEQ_TOTAL:
+ if ((port->type == E_FMAN_PORT_TYPE_RX) ||
+ (port->type == E_FMAN_PORT_TYPE_RX_10G))
+ /* Counter not available for Rx ports */
+ *queue_reg = NULL;
+ else
+ *queue_reg = &regs->fmqm_pndtfc;
+ break;
+ case E_FMAN_PORT_DEQ_FROM_DFLT:
+ if ((port->type == E_FMAN_PORT_TYPE_RX) ||
+ (port->type == E_FMAN_PORT_TYPE_RX_10G))
+ /* Counter not available for Rx ports */
+ *queue_reg = NULL;
+ else
+ *queue_reg = &regs->fmqm_pndfdc;
+ break;
+ case E_FMAN_PORT_DEQ_CONFIRM:
+ if ((port->type == E_FMAN_PORT_TYPE_RX) ||
+ (port->type == E_FMAN_PORT_TYPE_RX_10G))
+ /* Counter not available for Rx ports */
+ *queue_reg = NULL;
+ else
+ *queue_reg = &regs->fmqm_pndcc;
+ break;
+ default:
+ *queue_reg = NULL;
+ }
+}
+
+void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type)
+{
+ cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP;
+ cfg->dma_ic_stash_on = FALSE;
+ cfg->dma_header_stash_on = FALSE;
+ cfg->dma_sg_stash_on = FALSE;
+ cfg->dma_write_optimize = TRUE;
+ cfg->color = E_FMAN_PORT_COLOR_GREEN;
+ cfg->discard_override = FALSE;
+ cfg->checksum_bytes_ignore = 0;
+ cfg->rx_cut_end_bytes = 4;
+ cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
+ cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS);
+ cfg->rx_fd_bits = 0;
+ cfg->ic_ext_offset = 0;
+ cfg->ic_int_offset = 0;
+ cfg->ic_size = 0;
+ cfg->int_buf_start_margin = 0;
+ cfg->ext_buf_start_margin = 0;
+ cfg->ext_buf_end_margin = 0;
+ cfg->tx_fifo_min_level = 0;
+ cfg->tx_fifo_low_comf_level = (5 * KILOBYTE);
+ cfg->stats_counters_enable = TRUE;
+ cfg->perf_counters_enable = TRUE;
+ cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI;
+
+ if (type == E_FMAN_PORT_TYPE_HC) {
+ cfg->sync_req = FALSE;
+ cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_NO_PREFETCH;
+ } else {
+ cfg->sync_req = TRUE;
+ cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH;
+ }
+
+ if (type == E_FMAN_PORT_TYPE_TX_10G) {
+ cfg->tx_fifo_deq_pipeline_depth = 4;
+ cfg->deq_high_pri = TRUE;
+ cfg->deq_byte_cnt = 0x1400;
+ } else {
+ if ((type == E_FMAN_PORT_TYPE_HC) ||
+ (type == E_FMAN_PORT_TYPE_OP))
+ cfg->tx_fifo_deq_pipeline_depth = 2;
+ else
+ cfg->tx_fifo_deq_pipeline_depth = 1;
+
+ cfg->deq_high_pri = FALSE;
+ cfg->deq_byte_cnt = 0x400;
+ }
+ cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER;
+}
+
+static uint8_t fman_port_find_bpool(struct fman_port *port, uint8_t bpid)
+{
+ uint32_t *bp_reg, tmp;
+ uint8_t i, id;
+
+ /* Find the pool */
+ bp_reg = port->bmi_regs->rx.fmbm_ebmpi;
+ for (i = 0;
+ (i < port->ext_pools_num && (i < FMAN_PORT_MAX_EXT_POOLS_NUM));
+ i++) {
+ tmp = ioread32be(&bp_reg[i]);
+ id = (uint8_t)((tmp & BMI_EXT_BUF_POOL_ID_MASK) >>
+ BMI_EXT_BUF_POOL_ID_SHIFT);
+
+ if (id == bpid)
+ break;
+ }
+
+ return i;
+}
+
+int fman_port_init(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params)
+{
+ int err;
+
+ /* Init BMI registers */
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ err = init_bmi_rx(port, cfg, params);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ err = init_bmi_tx(port, cfg, params);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ err = init_bmi_oh(port, cfg, params);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (err)
+ return err;
+
+ /* Init QMI registers */
+ if (!port->im_en)
+ {
+ err = init_qmi(port, cfg, params);
+ return err;
+ }
+ return 0;
+}
+
+int fman_port_enable(struct fman_port *port)
+{
+ uint32_t *bmi_cfg_reg, tmp;
+ bool rx_port;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
+ rx_port = TRUE;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
+ rx_port = FALSE;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
+ rx_port = FALSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Enable QMI */
+ if (!rx_port) {
+ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN;
+ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
+ }
+
+ /* Enable BMI */
+ tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN;
+ iowrite32be(tmp, bmi_cfg_reg);
+
+ return 0;
+}
+
+int fman_port_disable(const struct fman_port *port)
+{
+ uint32_t *bmi_cfg_reg, *bmi_status_reg, tmp;
+ bool rx_port, failure = FALSE;
+ int count;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg;
+ bmi_status_reg = &port->bmi_regs->rx.fmbm_rst;
+ rx_port = TRUE;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg;
+ bmi_status_reg = &port->bmi_regs->tx.fmbm_tst;
+ rx_port = FALSE;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg;
+ bmi_status_reg = &port->bmi_regs->oh.fmbm_ost;
+ rx_port = FALSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable QMI */
+ if (!rx_port) {
+ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN;
+ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
+
+ /* Wait for QMI to finish FD handling */
+ count = 100;
+ do {
+ udelay(10);
+ tmp = ioread32be(&port->qmi_regs->fmqm_pns);
+ } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count);
+
+ if (count == 0)
+ {
+ /* Timeout */
+ failure = TRUE;
+ }
+ }
+
+ /* Disable BMI */
+ tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN;
+ iowrite32be(tmp, bmi_cfg_reg);
+
+ /* Wait for graceful stop end */
+ count = 500;
+ do {
+ udelay(10);
+ tmp = ioread32be(bmi_status_reg);
+ } while ((tmp & BMI_PORT_STATUS_BSY) && --count);
+
+ if (count == 0)
+ {
+ /* Timeout */
+ failure = TRUE;
+ }
+
+ if (failure)
+ return -EBUSY;
+
+ return 0;
+}
+
+int fman_port_set_bpools(const struct fman_port *port,
+ const struct fman_port_bpools *bp)
+{
+ uint32_t tmp, *bp_reg, *bp_depl_reg;
+ uint8_t i, max_bp_num;
+ bool grp_depl_used = FALSE, rx_port;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ max_bp_num = port->ext_pools_num;
+ rx_port = TRUE;
+ bp_reg = port->bmi_regs->rx.fmbm_ebmpi;
+ bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ if (port->fm_rev_maj != 4)
+ return -EINVAL;
+ max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM;
+ rx_port = FALSE;
+ bp_reg = port->bmi_regs->oh.fmbm_oebmpi;
+ bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rx_port) {
+ /* Check buffers are provided in ascending order */
+ for (i = 0;
+ (i < (bp->count-1) && (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1));
+ i++) {
+ if (bp->bpool[i].size > bp->bpool[i+1].size)
+ return -EINVAL;
+ }
+ }
+
+ /* Set up external buffers pools */
+ for (i = 0; i < bp->count; i++) {
+ tmp = BMI_EXT_BUF_POOL_VALID;
+ tmp |= ((uint32_t)bp->bpool[i].bpid <<
+ BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK;
+
+ if (rx_port) {
+ if (bp->counters_enable)
+ tmp |= BMI_EXT_BUF_POOL_EN_COUNTER;
+
+ if (bp->bpool[i].is_backup)
+ tmp |= BMI_EXT_BUF_POOL_BACKUP;
+
+ tmp |= (uint32_t)bp->bpool[i].size;
+ }
+
+ iowrite32be(tmp, &bp_reg[i]);
+ }
+
+ /* Clear unused pools */
+ for (i = bp->count; i < max_bp_num; i++)
+ iowrite32be(0, &bp_reg[i]);
+
+ /* Pools depletion */
+ tmp = 0;
+ for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) {
+ if (bp->bpool[i].grp_bp_depleted) {
+ grp_depl_used = TRUE;
+ tmp |= 0x80000000 >> i;
+ }
+
+ if (bp->bpool[i].single_bp_depleted)
+ tmp |= 0x80 >> i;
+
+ if (bp->bpool[i].pfc_priorities_en)
+ tmp |= 0x0100 << i;
+ }
+
+ if (grp_depl_used)
+ tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) <<
+ BMI_POOL_DEP_NUM_OF_POOLS_SHIFT;
+
+ iowrite32be(tmp, bp_depl_reg);
+ return 0;
+}
+
+int fman_port_set_rate_limiter(struct fman_port *port,
+ struct fman_port_rate_limiter *rate_limiter)
+{
+ uint32_t *rate_limit_reg, *rate_limit_scale_reg;
+ uint32_t granularity, tmp;
+ uint8_t usec_bit, factor;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ rate_limit_reg = &port->bmi_regs->tx.fmbm_trlmt;
+ rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts;
+ granularity = BMI_RATE_LIMIT_GRAN_TX;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ rate_limit_reg = &port->bmi_regs->oh.fmbm_orlmt;
+ rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts;
+ granularity = BMI_RATE_LIMIT_GRAN_OP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Factor is per 1 usec count */
+ factor = 1;
+ usec_bit = rate_limiter->count_1micro_bit;
+
+ /* If rate limit is too small for an 1usec factor, adjust timestamp
+ * scale and multiply the factor */
+ while (rate_limiter->rate < (granularity / factor)) {
+ if (usec_bit == 31)
+ /* Can't configure rate limiter - rate is too small */
+ return -EINVAL;
+
+ usec_bit++;
+ factor <<= 1;
+ }
+
+ /* Figure out register value. The "while" above quarantees that
+ * (rate_limiter->rate * factor / granularity) >= 1 */
+ tmp = (uint32_t)(rate_limiter->rate * factor / granularity - 1);
+
+ /* Check rate limit isn't too large */
+ if (tmp >= BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS)
+ return -EINVAL;
+
+ /* Check burst size is in allowed range */
+ if ((rate_limiter->burst_size == 0) ||
+ (rate_limiter->burst_size >
+ BMI_RATE_LIMIT_MAX_BURST_SIZE))
+ return -EINVAL;
+
+ tmp |= (uint32_t)(rate_limiter->burst_size - 1) <<
+ BMI_RATE_LIMIT_MAX_BURST_SHIFT;
+
+ if ((port->type == E_FMAN_PORT_TYPE_OP) &&
+ (port->fm_rev_maj == 4)) {
+ if (rate_limiter->high_burst_size_gran)
+ tmp |= BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN;
+ }
+
+ iowrite32be(tmp, rate_limit_reg);
+
+ /* Set up rate limiter scale register */
+ tmp = BMI_RATE_LIMIT_SCALE_EN;
+ tmp |= (31 - (uint32_t)usec_bit) << BMI_RATE_LIMIT_SCALE_TSBS_SHIFT;
+
+ if ((port->type == E_FMAN_PORT_TYPE_OP) &&
+ (port->fm_rev_maj == 4))
+ tmp |= rate_limiter->rate_factor;
+
+ iowrite32be(tmp, rate_limit_scale_reg);
+
+ return 0;
+}
+
+int fman_port_delete_rate_limiter(struct fman_port *port)
+{
+ uint32_t *rate_limit_scale_reg;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iowrite32be(0, rate_limit_scale_reg);
+ return 0;
+}
+
+int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask)
+{
+ uint32_t *err_mask_reg;
+
+ /* Obtain register address */
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ err_mask_reg = &port->bmi_regs->rx.fmbm_rfsem;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ err_mask_reg = &port->bmi_regs->oh.fmbm_ofsem;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iowrite32be(err_mask, err_mask_reg);
+ return 0;
+}
+
+int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask)
+{
+ uint32_t *discard_mask_reg;
+
+ /* Obtain register address */
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ discard_mask_reg = &port->bmi_regs->rx.fmbm_rfsdm;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ discard_mask_reg = &port->bmi_regs->oh.fmbm_ofsdm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iowrite32be(discard_mask, discard_mask_reg);
+ return 0;
+}
+
+int fman_port_modify_rx_fd_bits(struct fman_port *port,
+ uint8_t rx_fd_bits,
+ bool add)
+{
+ uint32_t tmp;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = ioread32be(&port->bmi_regs->rx.fmbm_rfne);
+
+ if (add)
+ tmp |= (uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT;
+ else
+ tmp &= ~((uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT);
+
+ iowrite32be(tmp, &port->bmi_regs->rx.fmbm_rfne);
+ return 0;
+}
+
+int fman_port_set_perf_cnt_params(struct fman_port *port,
+ struct fman_port_perf_cnt_params *params)
+{
+ uint32_t *pcp_reg, tmp;
+
+ /* Obtain register address and check parameters are in range */
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ pcp_reg = &port->bmi_regs->rx.fmbm_rpcp;
+ if ((params->queue_val == 0) ||
+ (params->queue_val > MAX_PERFORMANCE_RX_QUEUE_COMP))
+ return -EINVAL;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ pcp_reg = &port->bmi_regs->tx.fmbm_tpcp;
+ if ((params->queue_val == 0) ||
+ (params->queue_val > MAX_PERFORMANCE_TX_QUEUE_COMP))
+ return -EINVAL;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ pcp_reg = &port->bmi_regs->oh.fmbm_opcp;
+ if (params->queue_val != 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((params->task_val == 0) ||
+ (params->task_val > MAX_PERFORMANCE_TASK_COMP))
+ return -EINVAL;
+ if ((params->dma_val == 0) ||
+ (params->dma_val > MAX_PERFORMANCE_DMA_COMP))
+ return -EINVAL;
+ if ((params->fifo_val == 0) ||
+ ((params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS) >
+ MAX_PERFORMANCE_FIFO_COMP))
+ return -EINVAL;
+ tmp = (uint32_t)(params->task_val - 1) <<
+ BMI_PERFORMANCE_TASK_COMP_SHIFT;
+ tmp |= (uint32_t)(params->dma_val - 1) <<
+ BMI_PERFORMANCE_DMA_COMP_SHIFT;
+ tmp |= (uint32_t)(params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS - 1);
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ tmp |= (uint32_t)(params->queue_val - 1) <<
+ BMI_PERFORMANCE_QUEUE_COMP_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+
+ iowrite32be(tmp, pcp_reg);
+ return 0;
+}
+
+int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable)
+{
+ uint32_t *stats_reg, tmp;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ stats_reg = &port->bmi_regs->rx.fmbm_rstc;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ stats_reg = &port->bmi_regs->tx.fmbm_tstc;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ stats_reg = &port->bmi_regs->oh.fmbm_ostc;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = ioread32be(stats_reg);
+
+ if (enable)
+ tmp |= BMI_COUNTERS_EN;
+ else
+ tmp &= ~BMI_COUNTERS_EN;
+
+ iowrite32be(tmp, stats_reg);
+ return 0;
+}
+
+int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable)
+{
+ uint32_t *stats_reg, tmp;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ stats_reg = &port->bmi_regs->rx.fmbm_rpc;
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ stats_reg = &port->bmi_regs->tx.fmbm_tpc;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ stats_reg = &port->bmi_regs->oh.fmbm_opc;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = ioread32be(stats_reg);
+
+ if (enable)
+ tmp |= BMI_COUNTERS_EN;
+ else
+ tmp &= ~BMI_COUNTERS_EN;
+
+ iowrite32be(tmp, stats_reg);
+ return 0;
+}
+
+int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&port->qmi_regs->fmqm_pnc);
+
+ if (enable)
+ tmp |= QMI_PORT_CFG_EN_COUNTERS;
+ else
+ tmp &= ~QMI_PORT_CFG_EN_COUNTERS;
+
+ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc);
+ return 0;
+}
+
+int fman_port_set_bpool_cnt_mode(struct fman_port *port,
+ uint8_t bpid,
+ bool enable)
+{
+ uint8_t index;
+ uint32_t tmp;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Find the pool */
+ index = fman_port_find_bpool(port, bpid);
+ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
+ /* Not found */
+ return -EINVAL;
+
+ tmp = ioread32be(&port->bmi_regs->rx.fmbm_ebmpi[index]);
+
+ if (enable)
+ tmp |= BMI_EXT_BUF_POOL_EN_COUNTER;
+ else
+ tmp &= ~BMI_EXT_BUF_POOL_EN_COUNTER;
+
+ iowrite32be(tmp, &port->bmi_regs->rx.fmbm_ebmpi[index]);
+ return 0;
+}
+
+uint32_t fman_port_get_stats_counter(struct fman_port *port,
+ enum fman_port_stats_counters counter)
+{
+ uint32_t *stats_reg, ret_val;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ get_rx_stats_reg(port, counter, &stats_reg);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ get_tx_stats_reg(port, counter, &stats_reg);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ get_oh_stats_reg(port, counter, &stats_reg);
+ break;
+ default:
+ stats_reg = NULL;
+ }
+
+ if (stats_reg == NULL)
+ return 0;
+
+ ret_val = ioread32be(stats_reg);
+ return ret_val;
+}
+
+void fman_port_set_stats_counter(struct fman_port *port,
+ enum fman_port_stats_counters counter,
+ uint32_t value)
+{
+ uint32_t *stats_reg;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ get_rx_stats_reg(port, counter, &stats_reg);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ get_tx_stats_reg(port, counter, &stats_reg);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ get_oh_stats_reg(port, counter, &stats_reg);
+ break;
+ default:
+ stats_reg = NULL;
+ }
+
+ if (stats_reg == NULL)
+ return;
+
+ iowrite32be(value, stats_reg);
+}
+
+uint32_t fman_port_get_perf_counter(struct fman_port *port,
+ enum fman_port_perf_counters counter)
+{
+ uint32_t *perf_reg, ret_val;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ get_rx_perf_reg(port, counter, &perf_reg);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ get_tx_perf_reg(port, counter, &perf_reg);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ get_oh_perf_reg(port, counter, &perf_reg);
+ break;
+ default:
+ perf_reg = NULL;
+ }
+
+ if (perf_reg == NULL)
+ return 0;
+
+ ret_val = ioread32be(perf_reg);
+ return ret_val;
+}
+
+void fman_port_set_perf_counter(struct fman_port *port,
+ enum fman_port_perf_counters counter,
+ uint32_t value)
+{
+ uint32_t *perf_reg;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ get_rx_perf_reg(port, counter, &perf_reg);
+ break;
+ case E_FMAN_PORT_TYPE_TX:
+ case E_FMAN_PORT_TYPE_TX_10G:
+ get_tx_perf_reg(port, counter, &perf_reg);
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ case E_FMAN_PORT_TYPE_HC:
+ get_oh_perf_reg(port, counter, &perf_reg);
+ break;
+ default:
+ perf_reg = NULL;
+ }
+
+ if (perf_reg == NULL)
+ return;
+
+ iowrite32be(value, perf_reg);
+}
+
+uint32_t fman_port_get_qmi_counter(struct fman_port *port,
+ enum fman_port_qmi_counters counter)
+{
+ uint32_t *queue_reg, ret_val;
+
+ get_qmi_counter_reg(port, counter, &queue_reg);
+
+ if (queue_reg == NULL)
+ return 0;
+
+ ret_val = ioread32be(queue_reg);
+ return ret_val;
+}
+
+void fman_port_set_qmi_counter(struct fman_port *port,
+ enum fman_port_qmi_counters counter,
+ uint32_t value)
+{
+ uint32_t *queue_reg;
+
+ get_qmi_counter_reg(port, counter, &queue_reg);
+
+ if (queue_reg == NULL)
+ return;
+
+ iowrite32be(value, queue_reg);
+}
+
+uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid)
+{
+ uint8_t index;
+ uint32_t ret_val;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Find the pool */
+ index = fman_port_find_bpool(port, bpid);
+ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
+ /* Not found */
+ return 0;
+
+ ret_val = ioread32be(&port->bmi_regs->rx.fmbm_acnt[index]);
+ return ret_val;
+}
+
+void fman_port_set_bpool_counter(struct fman_port *port,
+ uint8_t bpid,
+ uint32_t value)
+{
+ uint8_t index;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ break;
+ default:
+ return;
+ }
+
+ /* Find the pool */
+ index = fman_port_find_bpool(port, bpid);
+ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM)
+ /* Not found */
+ return;
+
+ iowrite32be(value, &port->bmi_regs->rx.fmbm_acnt[index]);
+}
+
+int fman_port_add_congestion_grps(struct fman_port *port,
+ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM])
+{
+ int i;
+ uint32_t tmp, *grp_map_reg;
+ uint8_t max_grp_map_num;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ if (port->fm_rev_maj == 4)
+ max_grp_map_num = 1;
+ else
+ max_grp_map_num = FMAN_PORT_CG_MAP_NUM;
+ grp_map_reg = port->bmi_regs->rx.fmbm_rcgm;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ max_grp_map_num = 1;
+ if (port->fm_rev_maj != 4)
+ return -EINVAL;
+ grp_map_reg = port->bmi_regs->oh.fmbm_ocgm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = (max_grp_map_num - 1); i >= 0; i--) {
+ if (grps_map[i] == 0)
+ continue;
+ tmp = ioread32be(&grp_map_reg[i]);
+ tmp |= grps_map[i];
+ iowrite32be(tmp, &grp_map_reg[i]);
+ }
+
+ return 0;
+}
+
+int fman_port_remove_congestion_grps(struct fman_port *port,
+ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM])
+{
+ int i;
+ uint32_t tmp, *grp_map_reg;
+ uint8_t max_grp_map_num;
+
+ switch (port->type) {
+ case E_FMAN_PORT_TYPE_RX:
+ case E_FMAN_PORT_TYPE_RX_10G:
+ if (port->fm_rev_maj == 4)
+ max_grp_map_num = 1;
+ else
+ max_grp_map_num = FMAN_PORT_CG_MAP_NUM;
+ grp_map_reg = port->bmi_regs->rx.fmbm_rcgm;
+ break;
+ case E_FMAN_PORT_TYPE_OP:
+ max_grp_map_num = 1;
+ if (port->fm_rev_maj != 4)
+ return -EINVAL;
+ grp_map_reg = port->bmi_regs->oh.fmbm_ocgm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = (max_grp_map_num - 1); i >= 0; i--) {
+ if (grps_map[i] == 0)
+ continue;
+ tmp = ioread32be(&grp_map_reg[i]);
+ tmp &= ~grps_map[i];
+ iowrite32be(tmp, &grp_map_reg[i]);
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile
new file mode 100644
index 000000000000..d2c21d347538
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-RTC.o
+
+fsl-ncsw-RTC-objs := fm_rtc.o fman_rtc.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c
new file mode 100644
index 000000000000..99de427b3ae8
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_rtc.c
+
+ @Description FM RTC driver implementation.
+
+ @Cautions None
+*//***************************************************************************/
+#include <linux/math64.h>
+#include "error_ext.h"
+#include "debug_ext.h"
+#include "string_ext.h"
+#include "part_ext.h"
+#include "xx_ext.h"
+#include "ncsw_ext.h"
+
+#include "fm_rtc.h"
+#include "fm_common.h"
+
+
+
+/*****************************************************************************/
+static t_Error CheckInitParameters(t_FmRtc *p_Rtc)
+{
+ struct rtc_cfg *p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
+ int i;
+
+ if ((p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL) &&
+ (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) &&
+ (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR))
+ RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined"));
+
+ if (p_Rtc->outputClockDivisor == 0)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Divisor for output clock (should be positive)"));
+ }
+
+ for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++)
+ {
+ if ((p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) &&
+ (p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH))
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i));
+ }
+ }
+ for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++)
+ {
+ if ((p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) &&
+ (p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_RISING_EDGE))
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i));
+ }
+ }
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+static void RtcExceptions(t_Handle h_FmRtc)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+ struct rtc_regs *p_MemMap;
+ register uint32_t events;
+
+ ASSERT_COND(p_Rtc);
+ p_MemMap = p_Rtc->p_MemMap;
+
+ events = fman_rtc_check_and_clear_event(p_MemMap);
+ if (events & FMAN_RTC_TMR_TEVENT_ALM1)
+ {
+ if (p_Rtc->alarmParams[0].clearOnExpiration)
+ {
+ fman_rtc_set_timer_alarm_l(p_MemMap, 0, 0);
+ fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM1);
+ }
+ ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback);
+ p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0);
+ }
+ if (events & FMAN_RTC_TMR_TEVENT_ALM2)
+ {
+ if (p_Rtc->alarmParams[1].clearOnExpiration)
+ {
+ fman_rtc_set_timer_alarm_l(p_MemMap, 1, 0);
+ fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM2);
+ }
+ ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback);
+ p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1);
+ }
+ if (events & FMAN_RTC_TMR_TEVENT_PP1)
+ {
+ ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback);
+ p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0);
+ }
+ if (events & FMAN_RTC_TMR_TEVENT_PP2)
+ {
+ ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback);
+ p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1);
+ }
+ if (events & FMAN_RTC_TMR_TEVENT_ETS1)
+ {
+ ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback);
+ p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0);
+ }
+ if (events & FMAN_RTC_TMR_TEVENT_ETS2)
+ {
+ ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback);
+ p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1);
+ }
+}
+
+
+/*****************************************************************************/
+t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam)
+{
+ t_FmRtc *p_Rtc;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL);
+
+ /* Allocate memory for the FM RTC driver parameters */
+ p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc));
+ if (!p_Rtc)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure"));
+ return NULL;
+ }
+
+ memset(p_Rtc, 0, sizeof(t_FmRtc));
+
+ /* Allocate memory for the FM RTC driver parameters */
+ p_Rtc->p_RtcDriverParam = (struct rtc_cfg *)XX_Malloc(sizeof(struct rtc_cfg));
+ if (!p_Rtc->p_RtcDriverParam)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters"));
+ XX_Free(p_Rtc);
+ return NULL;
+ }
+
+ memset(p_Rtc->p_RtcDriverParam, 0, sizeof(struct rtc_cfg));
+
+ /* Store RTC configuration parameters */
+ p_Rtc->h_Fm = p_FmRtcParam->h_Fm;
+
+ /* Set default RTC configuration parameters */
+ fman_rtc_defconfig(p_Rtc->p_RtcDriverParam);
+
+ p_Rtc->outputClockDivisor = DEFAULT_OUTPUT_CLOCK_DIVISOR;
+ p_Rtc->p_RtcDriverParam->bypass = DEFAULT_BYPASS;
+ p_Rtc->clockPeriodNanoSec = DEFAULT_CLOCK_PERIOD; /* 1 usec */
+
+
+ /* Store RTC parameters in the RTC control structure */
+ p_Rtc->p_MemMap = (struct rtc_regs *)UINT_TO_PTR(p_FmRtcParam->baseAddress);
+ p_Rtc->h_App = p_FmRtcParam->h_App;
+
+ return p_Rtc;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_Init(t_Handle h_FmRtc)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+ struct rtc_cfg *p_RtcDriverParam;
+ struct rtc_regs *p_MemMap;
+ uint32_t freqCompensation = 0;
+ uint64_t tmpDouble;
+ bool init_freq_comp = FALSE;
+
+ p_RtcDriverParam = p_Rtc->p_RtcDriverParam;
+ p_MemMap = p_Rtc->p_MemMap;
+
+ if (CheckInitParameters(p_Rtc)!=E_OK)
+ RETURN_ERROR(MAJOR, E_CONFLICT,
+ ("Init Parameters are not Valid"));
+
+ /* TODO check that no timestamping MACs are working in this stage. */
+
+ /* find source clock frequency in Mhz */
+ if (p_Rtc->p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM)
+ p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->ext_src_clk_freq;
+ else
+ p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetMacClockFreq(p_Rtc->h_Fm));
+
+ /* if timer in Master mode Initialize TMR_CTRL */
+ /* We want the counter (TMR_CNT) to count in nano-seconds */
+ if (!p_RtcDriverParam->timer_slave_mode && p_Rtc->p_RtcDriverParam->bypass)
+ p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz);
+ else
+ {
+ /* Initialize TMR_ADD with the initial frequency compensation value:
+ freqCompensation = (2^32 / frequency ratio) */
+ /* frequency ratio = sorce clock/rtc clock =
+ * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */
+ init_freq_comp = TRUE;
+ freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000,
+ p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz);
+ }
+
+ /* check the legality of the relation between source and destination clocks */
+ /* should be larger than 1.0001 */
+ tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz;
+ if ((tmpDouble) <= 10001)
+ RETURN_ERROR(MAJOR, E_CONFLICT,
+ ("Invalid relation between source and destination clocks. Should be larger than 1.0001"));
+
+ fman_rtc_init(p_RtcDriverParam,
+ p_MemMap,
+ FM_RTC_NUM_OF_ALARMS,
+ FM_RTC_NUM_OF_PERIODIC_PULSES,
+ FM_RTC_NUM_OF_EXT_TRIGGERS,
+ init_freq_comp,
+ freqCompensation,
+ p_Rtc->outputClockDivisor);
+
+ /* Register the FM RTC interrupt */
+ FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc);
+
+ /* Free parameters structures */
+ XX_Free(p_Rtc->p_RtcDriverParam);
+ p_Rtc->p_RtcDriverParam = NULL;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_Free(t_Handle h_FmRtc)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+
+ if (p_Rtc->p_RtcDriverParam)
+ {
+ XX_Free(p_Rtc->p_RtcDriverParam);
+ }
+ else
+ {
+ FM_RTC_Disable(h_FmRtc);
+ }
+
+ /* Unregister FM RTC interrupt */
+ FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL);
+ XX_Free(p_Rtc);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc,
+ e_FmSrcClk srcClk,
+ uint32_t freqInMhz)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->p_RtcDriverParam->src_clk = (enum fman_src_clock)srcClk;
+ if (srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM)
+ p_Rtc->p_RtcDriverParam->ext_src_clk_freq = freqInMhz;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->clockPeriodNanoSec = period;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->p_RtcDriverParam->bypass = enabled;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->p_RtcDriverParam->invert_input_clk_phase = inverted;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->p_RtcDriverParam->invert_output_clk_phase = inverted;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->outputClockDivisor = divisor;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ p_Rtc->p_RtcDriverParam->pulse_realign = enable;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc,
+ uint8_t alarmId,
+ e_FmRtcAlarmPolarity alarmPolarity)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (alarmId >= FM_RTC_NUM_OF_ALARMS)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
+
+ p_Rtc->p_RtcDriverParam->alarm_polarity[alarmId] =
+ (enum fman_rtc_alarm_polarity)alarmPolarity;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc,
+ uint8_t triggerId,
+ e_FmRtcTriggerPolarity triggerPolarity)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
+ }
+
+ p_Rtc->p_RtcDriverParam->trigger_polarity[triggerId] =
+ (enum fman_rtc_trigger_polarity)triggerPolarity;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ fman_rtc_enable(p_Rtc->p_MemMap, resetClock);
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_Disable(t_Handle h_FmRtc)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ /* TODO A check must be added here, that no timestamping MAC's
+ * are working in this stage. */
+ fman_rtc_disable(p_Rtc->p_MemMap);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ fman_rtc_set_timer_offset(p_Rtc->p_MemMap, offset);
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+ uint64_t tmpAlarm;
+ bool enable = FALSE;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID"));
+ }
+
+ if (p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("Alarm time must be equal or larger than RTC period - %d nanoseconds",
+ p_Rtc->clockPeriodNanoSec));
+ tmpAlarm = p_FmRtcAlarmParams->alarmTime;
+ if (do_div(tmpAlarm, p_Rtc->clockPeriodNanoSec))
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("Alarm time must be a multiple of RTC period - %d nanoseconds",
+ p_Rtc->clockPeriodNanoSec));
+
+ if (p_FmRtcAlarmParams->f_AlarmCallback)
+ {
+ p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback;
+ p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration;
+ enable = TRUE;
+ }
+
+ fman_rtc_set_alarm(p_Rtc->p_MemMap, p_FmRtcAlarmParams->alarmId, (unsigned long)tmpAlarm, enable);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+ bool enable = FALSE;
+ uint64_t tmpFiper;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
+ }
+ if (fman_rtc_is_enabled(p_Rtc->p_MemMap))
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled."));
+ if (p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds",
+ p_Rtc->clockPeriodNanoSec));
+ tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod;
+ if (do_div(tmpFiper, p_Rtc->clockPeriodNanoSec))
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("Periodic pulse must be a multiple of RTC period - %d nanoseconds",
+ p_Rtc->clockPeriodNanoSec));
+ if (tmpFiper & 0xffffffff00000000LL)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
+ ("Periodic pulse/RTC Period must be smaller than 4294967296",
+ p_Rtc->clockPeriodNanoSec));
+
+ if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback)
+ {
+ p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback =
+ p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback;
+ enable = TRUE;
+ }
+ fman_rtc_set_periodic_pulse(p_Rtc->p_MemMap, p_FmRtcPeriodicPulseParams->periodicPulseId, (uint32_t)tmpFiper, enable);
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID"));
+ }
+
+ p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL;
+ fman_rtc_clear_periodic_pulse(p_Rtc->p_MemMap, periodicPulseId);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+ bool enable = FALSE;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
+ }
+
+ if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback)
+ {
+ p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback;
+ enable = TRUE;
+ }
+
+ fman_rtc_set_ext_trigger(p_Rtc->p_MemMap, p_FmRtcExternalTriggerParams->externalTriggerId, enable, p_FmRtcExternalTriggerParams->usePulseAsInput);
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID"));
+
+ p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL;
+
+ fman_rtc_clear_external_trigger(p_Rtc->p_MemMap, externalTriggerId);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc,
+ uint8_t triggerId,
+ uint64_t *p_TimeStamp)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS)
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID"));
+
+ *p_TimeStamp = fman_rtc_get_trigger_stamp(p_Rtc->p_MemMap, triggerId)*p_Rtc->clockPeriodNanoSec;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ *p_Ts = fman_rtc_get_timer(p_Rtc->p_MemMap)*p_Rtc->clockPeriodNanoSec;
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ do_div(ts, p_Rtc->clockPeriodNanoSec);
+ fman_rtc_set_timer(p_Rtc->p_MemMap, (int64_t)ts);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ *p_Compensation = fman_rtc_get_frequency_compensation(p_Rtc->p_MemMap);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ /* set the new freqCompensation */
+ fman_rtc_set_frequency_compensation(p_Rtc->p_MemMap, freqCompensation);
+
+ return E_OK;
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+/*****************************************************************************/
+t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ /* enable interrupt */
+ fman_rtc_enable_interupt(p_Rtc->p_MemMap, events);
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events)
+{
+ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc;
+
+ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE);
+
+ /* disable interrupt */
+ fman_rtc_disable_interupt(p_Rtc->p_MemMap, events);
+
+ return E_OK;
+}
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h
new file mode 100644
index 000000000000..843ca008ff8b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_rtc.h
+
+ @Description Memory map and internal definitions for FM RTC IEEE1588 Timer driver.
+
+ @Cautions None
+*//***************************************************************************/
+
+#ifndef __FM_RTC_H__
+#define __FM_RTC_H__
+
+#include "std_ext.h"
+#include "fm_rtc_ext.h"
+
+
+#define __ERR_MODULE__ MODULE_FM_RTC
+
+/* General definitions */
+
+#define ACCUMULATOR_OVERFLOW ((uint64_t)(1LL << 32))
+#define DEFAULT_OUTPUT_CLOCK_DIVISOR 0x00000002
+#define DEFAULT_BYPASS FALSE
+#define DEFAULT_CLOCK_PERIOD 1000
+
+
+
+typedef struct t_FmRtcAlarm
+{
+ t_FmRtcExceptionsCallback *f_AlarmCallback;
+ bool clearOnExpiration;
+} t_FmRtcAlarm;
+
+typedef struct t_FmRtcPeriodicPulse
+{
+ t_FmRtcExceptionsCallback *f_PeriodicPulseCallback;
+} t_FmRtcPeriodicPulse;
+
+typedef struct t_FmRtcExternalTrigger
+{
+ t_FmRtcExceptionsCallback *f_ExternalTriggerCallback;
+} t_FmRtcExternalTrigger;
+
+
+/**************************************************************************//**
+ @Description RTC FM driver control structure.
+*//***************************************************************************/
+typedef struct t_FmRtc
+{
+ t_Part *p_Part; /**< Pointer to the integration device */
+ t_Handle h_Fm;
+ t_Handle h_App; /**< Application handle */
+ struct rtc_regs *p_MemMap;
+ uint32_t clockPeriodNanoSec; /**< RTC clock period in nano-seconds (for FS mode) */
+ uint32_t srcClkFreqMhz;
+ uint16_t outputClockDivisor; /**< Output clock divisor (for FS mode) */
+ t_FmRtcAlarm alarmParams[FM_RTC_NUM_OF_ALARMS];
+ t_FmRtcPeriodicPulse periodicPulseParams[FM_RTC_NUM_OF_PERIODIC_PULSES];
+ t_FmRtcExternalTrigger externalTriggerParams[FM_RTC_NUM_OF_EXT_TRIGGERS];
+ struct rtc_cfg *p_RtcDriverParam; /**< RTC Driver parameters (for Init phase) */
+} t_FmRtc;
+
+
+#endif /* __FM_RTC_H__ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c
new file mode 100755
index 000000000000..acdf507e096d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_rtc.h"
+
+void fman_rtc_defconfig(struct rtc_cfg *cfg)
+{
+ int i;
+ cfg->src_clk = DEFAULT_SRC_CLOCK;
+ cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE;
+ cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE;
+ cfg->pulse_realign = DEFAULT_PULSE_REALIGN;
+ for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++)
+ cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY;
+ for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++)
+ cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY;
+}
+
+uint32_t fman_rtc_get_events(struct rtc_regs *regs)
+{
+ return ioread32be(&regs->tmr_tevent);
+}
+
+uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask)
+{
+ return ioread32be(&regs->tmr_tevent) & ev_mask;
+}
+
+uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs)
+{
+ return ioread32be(&regs->tmr_temask);
+}
+
+void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask)
+{
+ iowrite32be(mask, &regs->tmr_temask);
+}
+
+void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events)
+{
+ iowrite32be(events, &regs->tmr_tevent);
+}
+
+uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs)
+{
+ uint32_t event;
+
+ event = ioread32be(&regs->tmr_tevent);
+ event &= ioread32be(&regs->tmr_temask);
+
+ if (event)
+ iowrite32be(event, &regs->tmr_tevent);
+ return event;
+}
+
+uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs)
+{
+ return ioread32be(&regs->tmr_add);
+}
+
+void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val)
+{
+ iowrite32be(val, &regs->tmr_add);
+}
+
+void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events)
+{
+ fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events);
+}
+
+void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events)
+{
+ fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events);
+}
+
+void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val)
+{
+ iowrite32be(val, &regs->tmr_alarm[index].tmr_alarm_l);
+}
+
+void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val)
+{
+ iowrite32be(val, &regs->tmr_fiper[index]);
+}
+
+void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val)
+{
+ iowrite32be((uint32_t)val, &regs->tmr_alarm[index].tmr_alarm_l);
+ iowrite32be((uint32_t)(val >> 32), &regs->tmr_alarm[index].tmr_alarm_h);
+}
+
+void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val)
+{
+ iowrite32be((uint32_t)val, &regs->tmr_off_l);
+ iowrite32be((uint32_t)(val >> 32), &regs->tmr_off_h);
+}
+
+uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id)
+{
+ uint64_t time;
+ /* TMR_CNT_L must be read first to get an accurate value */
+ time = (uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_l);
+ time |= ((uint64_t)ioread32be(&regs->tmr_etts[id].tmr_etts_h)
+ << 32);
+
+ return time;
+}
+
+uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs)
+{
+ return ioread32be(&regs->tmr_ctrl);
+}
+
+void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val)
+{
+ iowrite32be(val, &regs->tmr_ctrl);
+}
+
+void fman_rtc_timers_soft_reset(struct rtc_regs *regs)
+{
+ fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR);
+ udelay(10);
+ fman_rtc_set_timer_ctrl(regs, 0);
+}
+
+void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,
+ int num_fipers, int num_ext_triggers, bool init_freq_comp,
+ uint32_t freq_compensation, uint32_t output_clock_divisor)
+{
+ uint32_t tmr_ctrl;
+ int i;
+
+ fman_rtc_timers_soft_reset(regs);
+
+ /* Set the source clock */
+ switch (cfg->src_clk) {
+ case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM:
+ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK;
+ break;
+ case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR:
+ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK;
+ break;
+ default:
+ /* Use a clock from the External TMR reference clock.*/
+ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK;
+ break;
+ }
+
+ /* whatever period the user picked, the timestamp will advance in '1'
+ * every time the period passed. */
+ tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) &
+ FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK);
+
+ if (cfg->invert_input_clk_phase)
+ tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH;
+ if (cfg->invert_output_clk_phase)
+ tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH;
+
+ for (i = 0; i < num_alarms; i++) {
+ if (cfg->alarm_polarity[i] ==
+ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW)
+ tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i);
+ }
+
+ for (i = 0; i < num_ext_triggers; i++)
+ if (cfg->trigger_polarity[i] ==
+ E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE)
+ tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i);
+
+ if (!cfg->timer_slave_mode && cfg->bypass)
+ tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP;
+
+ fman_rtc_set_timer_ctrl(regs, tmr_ctrl);
+ if (init_freq_comp)
+ fman_rtc_set_frequency_compensation(regs, freq_compensation);
+
+ /* Clear TMR_ALARM registers */
+ for (i = 0; i < num_alarms; i++)
+ fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL);
+
+ /* Clear TMR_TEVENT */
+ fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL);
+
+ /* Initialize TMR_TEMASK */
+ fman_rtc_set_interrupt_mask(regs, 0);
+
+ /* Clear TMR_FIPER registers */
+ for (i = 0; i < num_fipers; i++)
+ fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF);
+
+ /* Initialize TMR_PRSC */
+ iowrite32be(output_clock_divisor, &regs->tmr_prsc);
+
+ /* Clear TMR_OFF */
+ fman_rtc_set_timer_offset(regs, 0);
+}
+
+bool fman_rtc_is_enabled(struct rtc_regs *regs)
+{
+ return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE);
+}
+
+void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock)
+{
+ uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs);
+
+ /* TODO check that no timestamping MACs are working in this stage. */
+ if (reset_clock) {
+ fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR));
+
+ udelay(10);
+ /* Clear TMR_OFF */
+ fman_rtc_set_timer_offset(regs, 0);
+ }
+
+ fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE));
+}
+
+void fman_rtc_disable(struct rtc_regs *regs)
+{
+ fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs)
+ & ~(FMAN_RTC_TMR_CTRL_TE)));
+}
+
+void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id)
+{
+ uint32_t tmp_reg;
+ if (id == 0)
+ tmp_reg = FMAN_RTC_TMR_TEVENT_PP1;
+ else
+ tmp_reg = FMAN_RTC_TMR_TEVENT_PP2;
+ fman_rtc_disable_interupt(regs, tmp_reg);
+
+ tmp_reg = fman_rtc_get_timer_ctrl(regs);
+ if (tmp_reg & FMAN_RTC_TMR_CTRL_FS)
+ fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS);
+
+ fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF);
+}
+
+void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id)
+{
+ uint32_t tmpReg, tmp_ctrl;
+
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
+ else
+ tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
+ fman_rtc_disable_interupt(regs, tmpReg);
+
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
+ else
+ tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
+ tmp_ctrl = fman_rtc_get_timer_ctrl(regs);
+ if (tmp_ctrl & tmpReg)
+ fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg);
+}
+
+void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable)
+{
+ uint32_t tmpReg;
+ fman_rtc_set_timer_alarm(regs, id, val);
+ if (enable) {
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_TEVENT_ALM1;
+ else
+ tmpReg = FMAN_RTC_TMR_TEVENT_ALM2;
+ fman_rtc_enable_interupt(regs, tmpReg);
+ }
+}
+
+void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,
+ bool enable)
+{
+ uint32_t tmpReg;
+ fman_rtc_set_timer_fiper(regs, id, val);
+ if (enable) {
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_TEVENT_PP1;
+ else
+ tmpReg = FMAN_RTC_TMR_TEVENT_PP2;
+ fman_rtc_enable_interupt(regs, tmpReg);
+ }
+}
+
+void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,
+ bool use_pulse_as_input)
+{
+ uint32_t tmpReg;
+ if (enable) {
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;
+ else
+ tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;
+ fman_rtc_enable_interupt(regs, tmpReg);
+ }
+ if (use_pulse_as_input) {
+ if (id == 0)
+ tmpReg = FMAN_RTC_TMR_CTRL_PP1L;
+ else
+ tmpReg = FMAN_RTC_TMR_CTRL_PP2L;
+ fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg);
+ }
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile
new file mode 100644
index 000000000000..fae50ce440a2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+
+obj-y += fsl-ncsw-sp.o
+
+fsl-ncsw-sp-objs := fm_sp.o fman_sp.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c
new file mode 100644
index 000000000000..0994f34d392d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c
@@ -0,0 +1,757 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_sp.c
+
+ @Description FM PCD Storage profile ...
+*//***************************************************************************/
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+#include "net_ext.h"
+
+#include "fm_vsp_ext.h"
+#include "fm_sp.h"
+#include "fm_common.h"
+#include "fsl_fman_sp.h"
+
+
+#if (DPAA_VERSION >= 11)
+static t_Error CheckParamsGeneratedInternally(t_FmVspEntry *p_FmVspEntry)
+{
+ t_Error err = E_OK;
+
+ if ((err = FmSpCheckIntContextParams(&p_FmVspEntry->intContext))!= E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if ((err = FmSpCheckBufMargins(&p_FmVspEntry->bufMargins)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ return err;
+
+}
+
+static t_Error CheckParams(t_FmVspEntry *p_FmVspEntry)
+{
+ t_Error err = E_OK;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->h_Fm, E_INVALID_HANDLE);
+
+ if ((err = FmSpCheckBufPoolsParams(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools,
+ p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools,
+ p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)) != E_OK)
+
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset & ~FM_LIODN_OFFSET_MASK)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1));
+
+ err = FmVSPCheckRelativeProfile(p_FmVspEntry->h_Fm,
+ p_FmVspEntry->portType,
+ p_FmVspEntry->portId,
+ p_FmVspEntry->relativeProfileId);
+
+ return err;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/*****************************************************************************/
+/* Inter-module API routines */
+/*****************************************************************************/
+void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools,
+ uint8_t *orderedArray,
+ uint16_t *sizesArray)
+{
+ uint16_t bufSize = 0;
+ int i=0, j=0, k=0;
+
+ /* First we copy the external buffers pools information to an ordered local array */
+ for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++)
+ {
+ /* get pool size */
+ bufSize = p_FmExtPools->extBufPool[i].size;
+
+ /* keep sizes in an array according to poolId for direct access */
+ sizesArray[p_FmExtPools->extBufPool[i].id] = bufSize;
+
+ /* save poolId in an ordered array according to size */
+ for (j=0;j<=i;j++)
+ {
+ /* this is the next free place in the array */
+ if (j==i)
+ orderedArray[i] = p_FmExtPools->extBufPool[i].id;
+ else
+ {
+ /* find the right place for this poolId */
+ if (bufSize < sizesArray[orderedArray[j]])
+ {
+ /* move the poolIds one place ahead to make room for this poolId */
+ for (k=i;k>j;k--)
+ orderedArray[k] = orderedArray[k-1];
+
+ /* now k==j, this is the place for the new size */
+ orderedArray[k] = p_FmExtPools->extBufPool[i].id;
+ break;
+ }
+ }
+ }
+ }
+}
+
+t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools,
+ t_FmBackupBmPools *p_FmBackupBmPools,
+ t_FmBufPoolDepletion *p_FmBufPoolDepletion)
+{
+
+ int i = 0, j = 0;
+ bool found;
+ uint8_t count = 0;
+
+ if (p_FmExtPools)
+ {
+ if (p_FmExtPools->numOfPoolsUsed > FM_PORT_MAX_NUM_OF_EXT_POOLS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfPoolsUsed can't be larger than %d", FM_PORT_MAX_NUM_OF_EXT_POOLS));
+
+ for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++)
+ {
+ if (p_FmExtPools->extBufPool[i].id >= BM_MAX_NUM_OF_POOLS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].id can't be larger than %d", i, BM_MAX_NUM_OF_POOLS));
+ if (!p_FmExtPools->extBufPool[i].size)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].size is 0", i));
+ }
+ }
+ if (!p_FmExtPools && (p_FmBackupBmPools || p_FmBufPoolDepletion))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("backupBmPools ot bufPoolDepletion can not be defined without external pools"));
+
+ /* backup BM pools indication is valid only for some chip derivatives
+ (limited by the config routine) */
+ if (p_FmBackupBmPools)
+ {
+ if (p_FmBackupBmPools->numOfBackupPools >= p_FmExtPools->numOfPoolsUsed)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_BackupBmPools must be smaller than extBufPools.numOfPoolsUsed"));
+ found = FALSE;
+ for (i = 0;i<p_FmBackupBmPools->numOfBackupPools;i++)
+ {
+
+ for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
+ {
+ if (p_FmBackupBmPools->poolIds[i] == p_FmExtPools->extBufPool[j].id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("All p_BackupBmPools.poolIds must be included in extBufPools.extBufPool[n].id"));
+ else
+ found = FALSE;
+ }
+ }
+
+ /* up to extBufPools.numOfPoolsUsed pools may be defined */
+ if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->poolsGrpModeEnable)
+ {
+ if ((p_FmBufPoolDepletion->numOfPools > p_FmExtPools->numOfPoolsUsed))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools can't be larger than %d and can't be larger than numOfPoolsUsed", FM_PORT_MAX_NUM_OF_EXT_POOLS));
+
+ if (!p_FmBufPoolDepletion->numOfPools)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when poolsGrpModeEnable=TRUE"));
+
+ found = FALSE;
+ count = 0;
+ /* for each pool that is in poolsToConsider, check if it is defined
+ in extBufPool */
+ for (i=0;i<BM_MAX_NUM_OF_POOLS;i++)
+ {
+ if (p_FmBufPoolDepletion->poolsToConsider[i])
+ {
+ for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
+ {
+ if (i == p_FmExtPools->extBufPool[j].id)
+ {
+ found = TRUE;
+ count++;
+ break;
+ }
+ }
+ if (!found)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used."));
+ else
+ found = FALSE;
+ }
+ }
+ /* check that the number of pools that we have checked is equal to the number announced by the user */
+ if (count != p_FmBufPoolDepletion->numOfPools)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools is larger than the number of pools defined."));
+ }
+
+ if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->singlePoolModeEnable)
+ {
+ /* calculate vector for number of pools depletion */
+ found = FALSE;
+ count = 0;
+ for (i=0;i<BM_MAX_NUM_OF_POOLS;i++)
+ {
+ if (p_FmBufPoolDepletion->poolsToConsiderForSingleMode[i])
+ {
+ for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++)
+ {
+ if (i == p_FmExtPools->extBufPool[j].id)
+ {
+ found = TRUE;
+ count++;
+ break;
+ }
+ }
+ if (!found)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used."));
+ else
+ found = FALSE;
+ }
+ }
+ if (!count)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("No pools defined for single buffer mode pool depletion."));
+ }
+
+ return E_OK;
+}
+
+t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy)
+{
+ /* Check that divisible by 16 and not larger than 240 */
+ if (p_FmSpIntContextDataCopy->intContextOffset >MAX_INT_OFFSET)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset can't be larger than %d", MAX_INT_OFFSET));
+ if (p_FmSpIntContextDataCopy->intContextOffset % OFFSET_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset has to be divisible by %d", OFFSET_UNITS));
+
+ /* check that ic size+ic internal offset, does not exceed ic block size */
+ if (p_FmSpIntContextDataCopy->size + p_FmSpIntContextDataCopy->intContextOffset > MAX_IC_SIZE)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size + intContext.intContextOffset has to be smaller than %d", MAX_IC_SIZE));
+ /* Check that divisible by 16 and not larger than 256 */
+ if (p_FmSpIntContextDataCopy->size % OFFSET_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size has to be divisible by %d", OFFSET_UNITS));
+
+ /* Check that divisible by 16 and not larger than 4K */
+ if (p_FmSpIntContextDataCopy->extBufOffset > MAX_EXT_OFFSET)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset can't be larger than %d", MAX_EXT_OFFSET));
+ if (p_FmSpIntContextDataCopy->extBufOffset % OFFSET_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset has to be divisible by %d", OFFSET_UNITS));
+
+ return E_OK;
+}
+
+t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins)
+{
+ /* Check the margin definition */
+ if (p_FmSpBufMargins->startMargins > MAX_EXT_BUFFER_OFFSET)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET));
+ if (p_FmSpBufMargins->endMargins > MAX_EXT_BUFFER_OFFSET)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.endMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET));
+
+ return E_OK;
+}
+
+t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy,
+ t_FmBufferPrefixContent *p_BufferPrefixContent,
+ t_FmSpBufMargins *p_FmSpBufMargins,
+ t_FmSpBufferOffsets *p_FmSpBufferOffsets,
+ uint8_t *internalBufferOffset)
+{
+ uint32_t tmp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmSpIntContextDataCopy, E_INVALID_VALUE);
+ ASSERT_COND(p_FmSpIntContextDataCopy);
+ ASSERT_COND(p_BufferPrefixContent);
+ ASSERT_COND(p_FmSpBufMargins);
+ ASSERT_COND(p_FmSpBufferOffsets);
+
+ /* Align start of internal context data to 16 byte */
+ p_FmSpIntContextDataCopy->extBufOffset =
+ (uint16_t)((p_BufferPrefixContent->privDataSize & (OFFSET_UNITS-1)) ?
+ ((p_BufferPrefixContent->privDataSize + OFFSET_UNITS) & ~(uint16_t)(OFFSET_UNITS-1)) :
+ p_BufferPrefixContent->privDataSize);
+
+ /* Translate margin and intContext params to FM parameters */
+ /* Initialize with illegal value. Later we'll set legal values. */
+ p_FmSpBufferOffsets->prsResultOffset = (uint32_t)ILLEGAL_BASE;
+ p_FmSpBufferOffsets->timeStampOffset = (uint32_t)ILLEGAL_BASE;
+ p_FmSpBufferOffsets->hashResultOffset= (uint32_t)ILLEGAL_BASE;
+ p_FmSpBufferOffsets->pcdInfoOffset = (uint32_t)ILLEGAL_BASE;
+
+ /* Internally the driver supports 4 options
+ 1. prsResult/timestamp/hashResult selection (in fact 8 options, but for simplicity we'll
+ relate to it as 1).
+ 2. All IC context (from AD) not including debug.*/
+
+ /* This 'if' covers option 2. We copy from beginning of context. */
+ if (p_BufferPrefixContent->passAllOtherPCDInfo)
+ {
+ p_FmSpIntContextDataCopy->size = 128; /* must be aligned to 16 */
+ /* Start copying data after 16 bytes (FD) from the beginning of the internal context */
+ p_FmSpIntContextDataCopy->intContextOffset = 16;
+
+ if (p_BufferPrefixContent->passAllOtherPCDInfo)
+ p_FmSpBufferOffsets->pcdInfoOffset = p_FmSpIntContextDataCopy->extBufOffset;
+ if (p_BufferPrefixContent->passPrsResult)
+ p_FmSpBufferOffsets->prsResultOffset =
+ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 16);
+ if (p_BufferPrefixContent->passTimeStamp)
+ p_FmSpBufferOffsets->timeStampOffset =
+ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 48);
+ if (p_BufferPrefixContent->passHashResult)
+ p_FmSpBufferOffsets->hashResultOffset =
+ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 56);
+ }
+ else
+ {
+ /* This case covers the options under 1 */
+ /* Copy size must be in 16-byte granularity. */
+ p_FmSpIntContextDataCopy->size =
+ (uint16_t)((p_BufferPrefixContent->passPrsResult ? 32 : 0) +
+ ((p_BufferPrefixContent->passTimeStamp ||
+ p_BufferPrefixContent->passHashResult) ? 16 : 0));
+
+ /* Align start of internal context data to 16 byte */
+ p_FmSpIntContextDataCopy->intContextOffset =
+ (uint8_t)(p_BufferPrefixContent->passPrsResult ? 32 :
+ ((p_BufferPrefixContent->passTimeStamp ||
+ p_BufferPrefixContent->passHashResult) ? 64 : 0));
+
+ if (p_BufferPrefixContent->passPrsResult)
+ p_FmSpBufferOffsets->prsResultOffset = p_FmSpIntContextDataCopy->extBufOffset;
+ if (p_BufferPrefixContent->passTimeStamp)
+ p_FmSpBufferOffsets->timeStampOffset = p_BufferPrefixContent->passPrsResult ?
+ (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult)) :
+ p_FmSpIntContextDataCopy->extBufOffset;
+ if (p_BufferPrefixContent->passHashResult)
+ /* If PR is not requested, whether TS is requested or not, IC will be copied from TS */
+ p_FmSpBufferOffsets->hashResultOffset = p_BufferPrefixContent->passPrsResult ?
+ (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult) + 8) :
+ p_FmSpIntContextDataCopy->extBufOffset + 8;
+ }
+
+ if (p_FmSpIntContextDataCopy->size)
+ p_FmSpBufMargins->startMargins =
+ (uint16_t)(p_FmSpIntContextDataCopy->extBufOffset +
+ p_FmSpIntContextDataCopy->size);
+ else
+ /* No Internal Context passing, STartMargin is immediately after privateInfo */
+ p_FmSpBufMargins->startMargins = p_BufferPrefixContent->privDataSize;
+
+ /* save extra space for manip in both external and internal buffers */
+ if (p_BufferPrefixContent->manipExtraSpace)
+ {
+ uint8_t extraSpace;
+#ifdef FM_CAPWAP_SUPPORT
+ if ((p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE) >= 256)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("p_BufferPrefixContent->manipExtraSpace should be less than %d",
+ 256-CAPWAP_FRAG_EXTRA_SPACE));
+ extraSpace = (uint8_t)(p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE);
+#else
+ extraSpace = p_BufferPrefixContent->manipExtraSpace;
+#endif /* FM_CAPWAP_SUPPORT */
+ p_FmSpBufferOffsets->manipOffset = p_FmSpBufMargins->startMargins;
+ p_FmSpBufMargins->startMargins += extraSpace;
+ *internalBufferOffset = extraSpace;
+ }
+
+ /* align data start */
+ tmp = (uint32_t)(p_FmSpBufMargins->startMargins % p_BufferPrefixContent->dataAlign);
+ if (tmp)
+ p_FmSpBufMargins->startMargins += (p_BufferPrefixContent->dataAlign-tmp);
+ p_FmSpBufferOffsets->dataOffset = p_FmSpBufMargins->startMargins;
+
+ return E_OK;
+}
+/*********************** End of inter-module routines ************************/
+
+
+#if (DPAA_VERSION >= 11)
+/*****************************************************************************/
+/* API routines */
+/*****************************************************************************/
+t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams)
+{
+ t_FmVspEntry *p_FmVspEntry = NULL;
+ struct fm_storage_profile_params fm_vsp_params;
+
+ p_FmVspEntry = (t_FmVspEntry *)XX_Malloc(sizeof(t_FmVspEntry));
+ if (!p_FmVspEntry)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed"));
+ return NULL;
+ }
+ memset(p_FmVspEntry, 0, sizeof(t_FmVspEntry));
+
+ p_FmVspEntry->p_FmVspEntryDriverParams = (t_FmVspEntryDriverParams *)XX_Malloc(sizeof(t_FmVspEntryDriverParams));
+ if (!p_FmVspEntry->p_FmVspEntryDriverParams)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed"));
+ XX_Free(p_FmVspEntry);
+ return NULL;
+ }
+ memset(p_FmVspEntry->p_FmVspEntryDriverParams, 0, sizeof(t_FmVspEntryDriverParams));
+ fman_vsp_defconfig(&fm_vsp_params);
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = fm_vsp_params.header_cache_attr;
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = fm_vsp_params.int_context_cache_attr;
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = fm_vsp_params.scatter_gather_cache_attr;
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = fm_vsp_params.dma_swap_data;
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = fm_vsp_params.dma_write_optimize;
+ p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = fm_vsp_params.no_scather_gather;
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.privDataSize = DEFAULT_FM_SP_bufferPrefixContent_privDataSize;
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passPrsResult= DEFAULT_FM_SP_bufferPrefixContent_passPrsResult;
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passTimeStamp= DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp;
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passAllOtherPCDInfo
+ = DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp;
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign;
+ p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset = p_FmVspParams->liodnOffset;
+
+ memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, &p_FmVspParams->extBufPools, sizeof(t_FmExtPools));
+ p_FmVspEntry->h_Fm = p_FmVspParams->h_Fm;
+ p_FmVspEntry->portType = p_FmVspParams->portParams.portType;
+ p_FmVspEntry->portId = p_FmVspParams->portParams.portId;
+
+ p_FmVspEntry->relativeProfileId = p_FmVspParams->relativeProfileId;
+
+ return p_FmVspEntry;
+}
+
+t_Error FM_VSP_Init(t_Handle h_FmVsp)
+{
+
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp;
+ struct fm_storage_profile_params fm_vsp_params;
+ uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ uint16_t sizesArray[BM_MAX_NUM_OF_POOLS];
+ t_Error err;
+ uint16_t absoluteProfileId = 0;
+ int i = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams,E_INVALID_HANDLE);
+
+ CHECK_INIT_PARAMETERS(p_FmVspEntry, CheckParams);
+
+ memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS);
+ memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS);
+
+ err = FmSpBuildBufferStructure(&p_FmVspEntry->intContext,
+ &p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent,
+ &p_FmVspEntry->bufMargins,
+ &p_FmVspEntry->bufferOffsets,
+ &p_FmVspEntry->internalBufferOffset);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+
+ err = CheckParamsGeneratedInternally(p_FmVspEntry);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+
+ p_FmVspEntry->p_FmSpRegsBase =
+ (struct fm_pcd_storage_profile_regs *)FmGetVSPBaseAddr(p_FmVspEntry->h_Fm);
+ if (!p_FmVspEntry->p_FmSpRegsBase)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("impossible to initialize SpRegsBase"));
+
+ /* order external buffer pools in ascending order of buffer pools sizes */
+ FmSpSetBufPoolsInAscOrderOfBufSizes(&(p_FmVspEntry->p_FmVspEntryDriverParams)->extBufPools,
+ orderedArray,
+ sizesArray);
+
+ p_FmVspEntry->extBufPools.numOfPoolsUsed =
+ p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools.numOfPoolsUsed;
+ for (i = 0; i < p_FmVspEntry->extBufPools.numOfPoolsUsed; i++)
+ {
+ p_FmVspEntry->extBufPools.extBufPool[i].id = orderedArray[i];
+ p_FmVspEntry->extBufPools.extBufPool[i].size = sizesArray[orderedArray[i]];
+ }
+
+ /* on user responsibility to fill it according requirement */
+ memset(&fm_vsp_params, 0, sizeof(struct fm_storage_profile_params));
+ fm_vsp_params.dma_swap_data = p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData;
+ fm_vsp_params.int_context_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr;
+ fm_vsp_params.header_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr;
+ fm_vsp_params.scatter_gather_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr;
+ fm_vsp_params.dma_write_optimize = p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize;
+ fm_vsp_params.liodn_offset = p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset;
+ fm_vsp_params.no_scather_gather = p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather;
+
+ if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)
+ {
+ fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = TRUE;
+ fm_vsp_params.buf_pool_depletion.pools_grp_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsGrpModeEnable;
+ fm_vsp_params.buf_pool_depletion.num_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->numOfPools;
+ fm_vsp_params.buf_pool_depletion.pools_to_consider = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsider;
+ fm_vsp_params.buf_pool_depletion.single_pool_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->singlePoolModeEnable;
+ fm_vsp_params.buf_pool_depletion.pools_to_consider_for_single_mode = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsiderForSingleMode;
+ fm_vsp_params.buf_pool_depletion.has_pfc_priorities = TRUE;
+ fm_vsp_params.buf_pool_depletion.pfc_priorities_en = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->pfcPrioritiesEn;
+ }
+ else
+ fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = FALSE;
+
+ if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools)
+ {
+ fm_vsp_params.backup_pools.num_backup_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->numOfBackupPools;
+ fm_vsp_params.backup_pools.pool_ids = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->poolIds;
+ }
+ else
+ fm_vsp_params.backup_pools.num_backup_pools = 0;
+
+ fm_vsp_params.fm_ext_pools.num_pools_used = p_FmVspEntry->extBufPools.numOfPoolsUsed;
+ fm_vsp_params.fm_ext_pools.ext_buf_pool = (struct fman_ext_pool_params*)&p_FmVspEntry->extBufPools.extBufPool;
+ fm_vsp_params.buf_margins = (struct fman_sp_buf_margins*)&p_FmVspEntry->bufMargins;
+ fm_vsp_params.int_context = (struct fman_sp_int_context_data_copy*)&p_FmVspEntry->intContext;
+
+ /* no check on err - it was checked earlier */
+ FmVSPGetAbsoluteProfileId(p_FmVspEntry->h_Fm,
+ p_FmVspEntry->portType,
+ p_FmVspEntry->portId,
+ p_FmVspEntry->relativeProfileId,
+ &absoluteProfileId);
+
+ ASSERT_COND(p_FmVspEntry->p_FmSpRegsBase);
+ ASSERT_COND(fm_vsp_params.int_context);
+ ASSERT_COND(fm_vsp_params.buf_margins);
+ ASSERT_COND((absoluteProfileId <= FM_VSP_MAX_NUM_OF_ENTRIES));
+
+ /* Set all registers related to VSP */
+ fman_vsp_init(p_FmVspEntry->p_FmSpRegsBase, absoluteProfileId, &fm_vsp_params,FM_PORT_MAX_NUM_OF_EXT_POOLS, BM_MAX_NUM_OF_POOLS, FM_MAX_NUM_OF_PFC_PRIORITIES);
+
+ p_FmVspEntry->absoluteSpId = absoluteProfileId;
+
+ if (p_FmVspEntry->p_FmVspEntryDriverParams)
+ XX_Free(p_FmVspEntry->p_FmVspEntryDriverParams);
+ p_FmVspEntry->p_FmVspEntryDriverParams = NULL;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_Free(t_Handle h_FmVsp)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp;
+ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
+ XX_Free(p_FmVspEntry);
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp, t_FmBufferPrefixContent *p_FmBufferPrefixContent)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+ memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent));
+ /* if dataAlign was not initialized by user, we return to driver's default */
+ if (!p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign)
+ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = swapData;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp, e_FmDmaCacheOption intContextCacheAttr)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = intContextCacheAttr;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = headerCacheAttr;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp, e_FmDmaCacheOption scatterGatherCacheAttr)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = scatterGatherCacheAttr;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = optimize;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = noScatherGather;
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_BufPoolDepletion, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion = (t_FmBufPoolDepletion *)XX_Malloc(sizeof(t_FmBufPoolDepletion));
+ if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BufPoolDepletion allocation failed"));
+ memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion, p_BufPoolDepletion, sizeof(t_FmBufPoolDepletion));
+
+ return E_OK;
+}
+
+t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_BackupBmPools, E_INVALID_HANDLE);
+
+ p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools = (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools));
+ if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed"));
+ memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, p_BackupBmPools, sizeof(t_FmBackupBmPools));
+
+ return E_OK;
+}
+
+uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, 0);
+
+ return p_FmVspEntry->bufferOffsets.dataOffset;
+}
+
+uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
+
+ if (p_FmVspEntry->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.pcdInfoOffset);
+}
+
+t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
+
+ if (p_FmVspEntry->bufferOffsets.prsResultOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.prsResultOffset);
+}
+
+uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
+
+ if (p_FmVspEntry->bufferOffsets.timeStampOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint64_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.timeStampOffset);
+}
+
+uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data)
+{
+ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL);
+
+ if (p_FmVspEntry->bufferOffsets.hashResultOffset == ILLEGAL_BASE)
+ return NULL;
+
+ return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.hashResultOffset);
+}
+
+#endif /* (DPAA_VERSION >= 11) */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h
new file mode 100644
index 000000000000..9c171d85a5bb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_sp.h
+
+ @Description FM SP ...
+*//***************************************************************************/
+#ifndef __FM_SP_H
+#define __FM_SP_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "fm_sp_common.h"
+#include "fm_common.h"
+
+
+#define __ERR_MODULE__ MODULE_FM_SP
+
+typedef struct {
+ t_FmBufferPrefixContent bufferPrefixContent;
+ e_FmDmaSwapOption dmaSwapData;
+ e_FmDmaCacheOption dmaIntContextCacheAttr;
+ e_FmDmaCacheOption dmaHeaderCacheAttr;
+ e_FmDmaCacheOption dmaScatterGatherCacheAttr;
+ bool dmaWriteOptimize;
+ uint16_t liodnOffset;
+ bool noScatherGather;
+ t_FmBufPoolDepletion *p_BufPoolDepletion;
+ t_FmBackupBmPools *p_BackupBmPools;
+ t_FmExtPools extBufPools;
+} t_FmVspEntryDriverParams;
+
+typedef struct {
+ bool valid;
+ volatile bool lock;
+ uint8_t pointedOwners;
+ uint16_t absoluteSpId;
+ uint8_t internalBufferOffset;
+ t_FmSpBufMargins bufMargins;
+ t_FmSpIntContextDataCopy intContext;
+ t_FmSpBufferOffsets bufferOffsets;
+ t_Handle h_Fm;
+ e_FmPortType portType; /**< Port type */
+ uint8_t portId; /**< Port Id - relative to type */
+ uint8_t relativeProfileId;
+ struct fm_pcd_storage_profile_regs *p_FmSpRegsBase;
+ t_FmExtPools extBufPools;
+ t_FmVspEntryDriverParams *p_FmVspEntryDriverParams;
+} t_FmVspEntry;
+
+
+#endif /* __FM_SP_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c
new file mode 100755
index 000000000000..0f772e919792
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_sp.h"
+
+
+uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index)
+{
+ struct fm_pcd_storage_profile_regs *sp_regs;
+ sp_regs = &regs[index];
+ return ioread32be(&sp_regs->fm_sp_acnt);
+}
+
+void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index, uint32_t value)
+{
+ struct fm_pcd_storage_profile_regs *sp_regs;
+ sp_regs = &regs[index];
+ iowrite32be(value, &sp_regs->fm_sp_acnt);
+}
+
+void fman_vsp_defconfig(struct fm_storage_profile_params *cfg)
+{
+ cfg->dma_swap_data =
+ DEFAULT_FMAN_SP_DMA_SWAP_DATA;
+ cfg->int_context_cache_attr =
+ DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR;
+ cfg->header_cache_attr =
+ DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR;
+ cfg->scatter_gather_cache_attr =
+ DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR;
+ cfg->dma_write_optimize =
+ DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE;
+ cfg->no_scather_gather =
+ DEFAULT_FMAN_SP_NO_SCATTER_GATHER;
+}
+
+static inline uint32_t calc_vec_dep(int max_pools, bool *pools,
+ struct fman_ext_pools *ext_buf_pools, uint32_t mask)
+{
+ int i, j;
+ uint32_t vector = 0;
+ for (i = 0; i < max_pools; i++)
+ if (pools[i])
+ for (j = 0; j < ext_buf_pools->num_pools_used; j++)
+ if (i == ext_buf_pools->ext_buf_pool[j].id) {
+ vector |= mask >> j;
+ break;
+ }
+ return vector;
+}
+
+void fman_vsp_init(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index, struct fm_storage_profile_params *fm_vsp_params,
+ int port_max_num_of_ext_pools, int bm_max_num_of_pools,
+ int max_num_of_pfc_priorities)
+{
+ int i = 0, j = 0;
+ struct fm_pcd_storage_profile_regs *sp_regs;
+ uint32_t tmp_reg, vector;
+ struct fman_ext_pools *ext_buf_pools = &fm_vsp_params->fm_ext_pools;
+ struct fman_buf_pool_depletion *buf_pool_depletion =
+ &fm_vsp_params->buf_pool_depletion;
+ struct fman_backup_bm_pools *backup_pools =
+ &fm_vsp_params->backup_pools;
+ struct fman_sp_int_context_data_copy *int_context_data_copy =
+ fm_vsp_params->int_context;
+ struct fman_sp_buf_margins *external_buffer_margins =
+ fm_vsp_params->buf_margins;
+ bool no_scather_gather = fm_vsp_params->no_scather_gather;
+ uint16_t liodn_offset = fm_vsp_params->liodn_offset;
+
+ sp_regs = &regs[index];
+
+ /* fill external buffers manager pool information register*/
+ for (i = 0; i < ext_buf_pools->num_pools_used; i++) {
+ tmp_reg = FMAN_SP_EXT_BUF_POOL_VALID |
+ FMAN_SP_EXT_BUF_POOL_EN_COUNTER;
+ tmp_reg |= ((uint32_t)ext_buf_pools->ext_buf_pool[i].id <<
+ FMAN_SP_EXT_BUF_POOL_ID_SHIFT);
+ tmp_reg |= ext_buf_pools->ext_buf_pool[i].size;
+ /* functionality available only for some deriviatives
+ (limited by config) */
+ for (j = 0; j < backup_pools->num_backup_pools; j++)
+ if (ext_buf_pools->ext_buf_pool[i].id ==
+ backup_pools->pool_ids[j]) {
+ tmp_reg |= FMAN_SP_EXT_BUF_POOL_BACKUP;
+ break;
+ }
+ iowrite32be(tmp_reg, &sp_regs->fm_sp_ebmpi[i]);
+ }
+
+ /* clear unused pools */
+ for (i = ext_buf_pools->num_pools_used;
+ i < port_max_num_of_ext_pools; i++)
+ iowrite32be(0, &sp_regs->fm_sp_ebmpi[i]);
+
+ /* fill pool depletion register*/
+ tmp_reg = 0;
+ if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->pools_grp_mode_enable) {
+ /* calculate vector for number of pools depletion */
+ vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion->
+ pools_to_consider, ext_buf_pools, 0x80000000);
+
+ /* configure num of pools and vector for number of pools mode */
+ tmp_reg |= (((uint32_t)buf_pool_depletion->num_pools - 1) <<
+ FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT);
+ tmp_reg |= vector;
+ }
+
+ if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->single_pool_mode_enable) {
+ /* calculate vector for number of pools depletion */
+ vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion->
+ pools_to_consider_for_single_mode,
+ ext_buf_pools, 0x00000080);
+
+ /* configure num of pools and vector for number of pools mode */
+ tmp_reg |= vector;
+ }
+
+ /* fill QbbPEV */
+ if (buf_pool_depletion->buf_pool_depletion_enabled) {
+ vector = 0;
+ for (i = 0; i < max_num_of_pfc_priorities; i++)
+ if (buf_pool_depletion->pfc_priorities_en[i] == TRUE)
+ vector |= 0x00000100 << i;
+ tmp_reg |= vector;
+ }
+ iowrite32be(tmp_reg, &sp_regs->fm_sp_mpd);
+
+ /* fill dma attributes register */
+ tmp_reg = 0;
+ tmp_reg |= (uint32_t)fm_vsp_params->dma_swap_data <<
+ FMAN_SP_DMA_ATTR_SWP_SHIFT;
+ tmp_reg |= (uint32_t)fm_vsp_params->int_context_cache_attr <<
+ FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT;
+ tmp_reg |= (uint32_t)fm_vsp_params->header_cache_attr <<
+ FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT;
+ tmp_reg |= (uint32_t)fm_vsp_params->scatter_gather_cache_attr <<
+ FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT;
+ if (fm_vsp_params->dma_write_optimize)
+ tmp_reg |= FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE;
+ iowrite32be(tmp_reg, &sp_regs->fm_sp_da);
+
+ /* IC parameters - fill internal context parameters register */
+ tmp_reg = 0;
+ tmp_reg |= (((uint32_t)int_context_data_copy->ext_buf_offset/
+ OFFSET_UNITS) << FMAN_SP_IC_TO_EXT_SHIFT);
+ tmp_reg |= (((uint32_t)int_context_data_copy->int_context_offset/
+ OFFSET_UNITS) << FMAN_SP_IC_FROM_INT_SHIFT);
+ tmp_reg |= (((uint32_t)int_context_data_copy->size/OFFSET_UNITS) <<
+ FMAN_SP_IC_SIZE_SHIFT);
+ iowrite32be(tmp_reg, &sp_regs->fm_sp_icp);
+
+ /* buffer margins - fill external buffer margins register */
+ tmp_reg = 0;
+ tmp_reg |= (((uint32_t)external_buffer_margins->start_margins) <<
+ FMAN_SP_EXT_BUF_MARG_START_SHIFT);
+ tmp_reg |= (((uint32_t)external_buffer_margins->end_margins) <<
+ FMAN_SP_EXT_BUF_MARG_END_SHIFT);
+ if (no_scather_gather)
+ tmp_reg |= FMAN_SP_SG_DISABLE;
+ iowrite32be(tmp_reg, &sp_regs->fm_sp_ebm);
+
+ /* buffer margins - fill spliodn register */
+ iowrite32be(liodn_offset, &sp_regs->fm_sp_spliodn);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
new file mode 100644
index 000000000000..c96c2a12f29e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c
@@ -0,0 +1,5223 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm.c
+
+ @Description FM driver routines implementation.
+*//***************************************************************************/
+#include "std_ext.h"
+#include "error_ext.h"
+#include "xx_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+#include "fm_muram_ext.h"
+#include <linux/math64.h>
+
+#include "fm_common.h"
+#include "fm_ipc.h"
+#include "fm.h"
+#ifndef CONFIG_FMAN_ARM
+#include <linux/fsl/svr.h>
+#endif
+#include "fsl_fman.h"
+
+
+/****************************************/
+/* static functions */
+/****************************************/
+
+static volatile bool blockingFlag = FALSE;
+static void IpcMsgCompletionCB(t_Handle h_Fm,
+ uint8_t *p_Msg,
+ uint8_t *p_Reply,
+ uint32_t replyLength,
+ t_Error status)
+{
+ UNUSED(h_Fm);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status);
+ blockingFlag = FALSE;
+}
+
+static void FreeInitResources(t_Fm *p_Fm)
+{
+ if (p_Fm->camBaseAddr)
+ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr));
+ if (p_Fm->fifoBaseAddr)
+ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->fifoBaseAddr));
+ if (p_Fm->resAddr)
+ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->resAddr));
+}
+
+static bool IsFmanCtrlCodeLoaded(t_Fm *p_Fm)
+{
+ t_FMIramRegs *p_Iram;
+
+ ASSERT_COND(p_Fm);
+ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+
+ return (bool)!!(GET_UINT32(p_Iram->iready) & IRAM_READY);
+}
+
+static t_Error CheckFmParameters(t_Fm *p_Fm)
+{
+ if (IsFmanCtrlCodeLoaded(p_Fm) && !p_Fm->resetOnInit)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old FMan CTRL code is loaded; FM must be reset!"));
+#if (DPAA_VERSION < 11)
+ if (!p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats ||
+ (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats > DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("axiDbgNumOfBeats has to be in the range 1 - %d", DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS));
+#endif /* (DPAA_VERSION < 11) */
+ if (p_Fm->p_FmDriverParam->dma_cam_num_of_entries % DMA_CAM_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be divisble by %d", DMA_CAM_UNITS));
+// if (!p_Fm->p_FmDriverParam->dma_cam_num_of_entries || (p_Fm->p_FmDriverParam->dma_cam_num_of_entries > DMA_MODE_MAX_CAM_NUM_OF_ENTRIES))
+// RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be in the range 1 - %d", DMA_MODE_MAX_CAM_NUM_OF_ENTRIES));
+ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer > DMA_THRESH_MAX_COMMQ)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ));
+ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer > DMA_THRESH_MAX_COMMQ)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ));
+ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer >= p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer must be smaller than dma_comm_qtsh_asrt_emer"));
+#if (DPAA_VERSION < 11)
+ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
+ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
+ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer must be smaller than dma_read_buf_tsh_asrt_emer"));
+ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
+ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF));
+ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer must be smaller than dma_write_buf_tsh_asrt_emer"));
+#else /* (DPAA_VERSION >= 11) */
+ if ((p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_READ_EM)||
+ (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) ||
+ (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_dbg_cnt_mode value not supported by this integration."));
+ if ((p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_READ_EMERGENCY)||
+ (p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_WRITE_EMERGENCY))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("emergencyBusSelect value not supported by this integration."));
+ if (p_Fm->p_FmDriverParam->dma_stop_on_bus_error)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_stop_on_bus_error not supported by this integration."));
+#ifdef FM_AID_MODE_NO_TNUM_SW005
+ if (p_Fm->p_FmDriverParam->dma_aid_mode != E_FMAN_DMA_AID_OUT_PORT_ID)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_aid_mode not supported by this integration."));
+#endif /* FM_AID_MODE_NO_TNUM_SW005 */
+ if (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_axi_dbg_num_of_beats not supported by this integration."));
+#endif /* (DPAA_VERSION < 11) */
+
+ if (!p_Fm->p_FmStateStruct->fmClkFreq)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fmClkFreq must be set."));
+ if (USEC_TO_CLK(p_Fm->p_FmDriverParam->dma_watchdog, p_Fm->p_FmStateStruct->fmClkFreq) > DMA_MAX_WATCHDOG)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("dma_watchdog depends on FM clock. dma_watchdog(in microseconds) * clk (in Mhz), may not exceed 0x08x", DMA_MAX_WATCHDOG));
+
+#if (DPAA_VERSION >= 11)
+ if ((p_Fm->partVSPBase + p_Fm->partNumOfVSPs) > FM_VSP_MAX_NUM_OF_ENTRIES)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partVSPBase+partNumOfVSPs out of range!!!"));
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_Fm->p_FmStateStruct->totalFifoSize % BMI_FIFO_UNITS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be divisible by %d", BMI_FIFO_UNITS));
+ if (!p_Fm->p_FmStateStruct->totalFifoSize ||
+ (p_Fm->p_FmStateStruct->totalFifoSize > BMI_MAX_FIFO_SIZE))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("totalFifoSize (currently defined as %d) has to be in the range of 256 to %d",
+ p_Fm->p_FmStateStruct->totalFifoSize,
+ BMI_MAX_FIFO_SIZE));
+ if (!p_Fm->p_FmStateStruct->totalNumOfTasks ||
+ (p_Fm->p_FmStateStruct->totalNumOfTasks > BMI_MAX_NUM_OF_TASKS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfTasks number has to be in the range 1 - %d", BMI_MAX_NUM_OF_TASKS));
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if (!p_Fm->p_FmStateStruct->maxNumOfOpenDmas ||
+ (p_Fm->p_FmStateStruct->maxNumOfOpenDmas > BMI_MAX_NUM_OF_DMAS))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfOpenDmas number has to be in the range 1 - %d", BMI_MAX_NUM_OF_DMAS));
+#endif /* FM_HAS_TOTAL_DMAS */
+
+ if (p_Fm->p_FmDriverParam->disp_limit_tsh > FPM_MAX_DISP_LIMIT)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("disp_limit_tsh can't be greater than %d", FPM_MAX_DISP_LIMIT));
+
+ if (!p_Fm->f_Exception)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
+ if (!p_Fm->f_BusError)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
+
+#ifdef FM_NO_WATCHDOG
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 2) &&
+ (p_Fm->p_FmDriverParam->dma_watchdog))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("watchdog!"));
+#endif /* FM_NO_WATCHDOG */
+
+#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) &&
+ (p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("HaltOnEccError!"));
+#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */
+
+#ifdef FM_NO_TNUM_AGING
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) &&
+ (p_Fm->p_FmStateStruct->revInfo.majorRev < 6))
+ if (p_Fm->p_FmDriverParam->tnum_aging_period)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Tnum aging!"));
+#endif /* FM_NO_TNUM_AGING */
+
+ /* check that user did not set revision-dependent exceptions */
+#ifdef FM_NO_DISPATCH_RAM_ECC
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) &&
+ (p_Fm->p_FmStateStruct->revInfo.majorRev < 6))
+ if (p_Fm->userSetExceptions & FM_EX_BMI_DISPATCH_RAM_ECC)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_BMI_DISPATCH_RAM_ECC!"));
+#endif /* FM_NO_DISPATCH_RAM_ECC */
+
+#ifdef FM_QMI_NO_ECC_EXCEPTIONS
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev == 4)
+ if (p_Fm->userSetExceptions & (FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC))
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC/e_FM_EX_QMI_DOUBLE_ECC!"));
+#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
+
+#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ if (p_Fm->userSetExceptions & FM_EX_QMI_SINGLE_ECC)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC!"));
+#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
+
+ return E_OK;
+}
+
+
+static void SendIpcIsr(t_Fm *p_Fm, uint32_t macEvent, uint32_t pendingReg)
+{
+ ASSERT_COND(p_Fm->guestId == NCSW_MASTER_ID);
+
+ if (p_Fm->intrMng[macEvent].guestId == NCSW_MASTER_ID)
+ p_Fm->intrMng[macEvent].f_Isr(p_Fm->intrMng[macEvent].h_SrcHandle);
+
+ /* If the MAC is running on guest-partition and we have IPC session with it,
+ we inform him about the event through IPC; otherwise, we ignore the event. */
+ else if (p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId])
+ {
+ t_Error err;
+ t_FmIpcIsr fmIpcIsr;
+ t_FmIpcMsg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_GUEST_ISR;
+ fmIpcIsr.pendingReg = pendingReg;
+ fmIpcIsr.boolErr = FALSE;
+ memcpy(msg.msgBody, &fmIpcIsr, sizeof(fmIpcIsr));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(fmIpcIsr),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ }
+ else
+ DBG(TRACE, ("FM Guest mode, without IPC - can't call ISR!"));
+}
+
+static void BmiErrEvent(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
+
+
+ event = fman_get_bmi_err_event(bmi_rg);
+
+ if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STORAGE_PROFILE_ECC);
+ if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_LIST_RAM_ECC);
+ if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STATISTICS_RAM_ECC);
+ if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_DISPATCH_RAM_ECC);
+}
+
+static void QmiErrEvent(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
+
+ event = fman_get_qmi_err_event(qmi_rg);
+
+ if (event & QMI_ERR_INTR_EN_DOUBLE_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DOUBLE_ECC);
+ if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID);
+}
+
+static void DmaErrEvent(t_Fm *p_Fm)
+{
+ uint32_t status, com_id;
+ uint8_t tnum;
+ uint8_t hardwarePortId;
+ uint8_t relativePortId;
+ uint16_t liodn;
+ struct fman_dma_regs *dma_rg = p_Fm->p_FmDmaRegs;
+
+ status = fman_get_dma_err_event(dma_rg);
+
+ if (status & DMA_STATUS_BUS_ERR)
+ {
+ com_id = fman_get_dma_com_id(dma_rg);
+ hardwarePortId = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >> DMA_TRANSFER_PORTID_SHIFT));
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+ HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId);
+ tnum = (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >> DMA_TRANSFER_TNUM_SHIFT);
+ liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK);
+ ASSERT_COND(p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] != e_FM_PORT_TYPE_DUMMY);
+ p_Fm->f_BusError(p_Fm->h_App,
+ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId],
+ relativePortId,
+ fman_get_dma_addr(dma_rg),
+ tnum,
+ liodn);
+ }
+ if (status & DMA_STATUS_FM_SPDAT_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SINGLE_PORT_ECC);
+ if (status & DMA_STATUS_READ_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_READ_ECC);
+ if (status & DMA_STATUS_SYSTEM_WRITE_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SYSTEM_WRITE_ECC);
+ if (status & DMA_STATUS_FM_WRITE_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_FM_WRITE_ECC);
+ }
+
+static void FpmErrEvent(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ event = fman_get_fpm_err_event(fpm_rg);
+
+ if ((event & FPM_EV_MASK_DOUBLE_ECC) && (event & FPM_EV_MASK_DOUBLE_ECC_EN))
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_DOUBLE_ECC);
+ if ((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN))
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_STALL_ON_TASKS);
+ if ((event & FPM_EV_MASK_SINGLE_ECC) && (event & FPM_EV_MASK_SINGLE_ECC_EN))
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_SINGLE_ECC);
+}
+
+static void MuramErrIntr(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ event = fman_get_muram_err_event(fpm_rg);
+
+ if (event & FPM_RAM_MURAM_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_MURAM_ECC);
+}
+
+static void IramErrIntr(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ event = fman_get_iram_err_event(fpm_rg);
+
+ if (event & FPM_RAM_IRAM_ECC)
+ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_IRAM_ECC);
+}
+
+static void QmiEvent(t_Fm *p_Fm)
+{
+ uint32_t event;
+ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
+
+ event = fman_get_qmi_event(qmi_rg);
+
+ if (event & QMI_INTR_EN_SINGLE_ECC)
+ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_SINGLE_ECC);
+}
+
+static void UnimplementedIsr(t_Handle h_Arg)
+{
+ UNUSED(h_Arg);
+
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented ISR!"));
+}
+
+static void UnimplementedFmanCtrlIsr(t_Handle h_Arg, uint32_t event)
+{
+ UNUSED(h_Arg); UNUSED(event);
+
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented FmCtl ISR!"));
+}
+
+static void EnableTimeStamp(t_Fm *p_Fm)
+{
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ ASSERT_COND(p_Fm->p_FmStateStruct);
+ ASSERT_COND(p_Fm->p_FmStateStruct->count1MicroBit);
+
+ fman_enable_time_stamp(fpm_rg, p_Fm->p_FmStateStruct->count1MicroBit, p_Fm->p_FmStateStruct->fmClkFreq);
+
+ p_Fm->p_FmStateStruct->enabledTimeStamp = TRUE;
+}
+
+static t_Error ClearIRam(t_Fm *p_Fm)
+{
+ t_FMIramRegs *p_Iram;
+ int i;
+ int iram_size;
+
+ ASSERT_COND(p_Fm);
+ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+ iram_size = FM_IRAM_SIZE(p_Fm->p_FmStateStruct->revInfo.majorRev,p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+ /* Enable the auto-increment */
+ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
+
+ for (i=0; i < (iram_size/4); i++)
+ WRITE_UINT32(p_Iram->idata, 0xffffffff);
+
+ WRITE_UINT32(p_Iram->iadd, iram_size - 4);
+ CORE_MemoryBarrier();
+ while (GET_UINT32(p_Iram->idata) != 0xffffffff) ;
+
+ return E_OK;
+}
+
+static t_Error LoadFmanCtrlCode(t_Fm *p_Fm)
+{
+ t_FMIramRegs *p_Iram;
+ int i;
+ uint32_t tmp;
+ uint8_t compTo16;
+
+ ASSERT_COND(p_Fm);
+ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+
+ /* Enable the auto-increment */
+ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
+
+ for (i=0; i < (p_Fm->firmware.size / 4); i++)
+ WRITE_UINT32(p_Iram->idata, p_Fm->firmware.p_Code[i]);
+
+ compTo16 = (uint8_t)(p_Fm->firmware.size % 16);
+ if (compTo16)
+ for (i=0; i < ((16-compTo16) / 4); i++)
+ WRITE_UINT32(p_Iram->idata, 0xffffffff);
+
+ WRITE_UINT32(p_Iram->iadd,p_Fm->firmware.size-4);
+ while (GET_UINT32(p_Iram->iadd) != (p_Fm->firmware.size-4)) ;
+
+ /* verify that writing has completed */
+ while (GET_UINT32(p_Iram->idata) != p_Fm->firmware.p_Code[(p_Fm->firmware.size / 4)-1]) ;
+
+ if (p_Fm->fwVerify)
+ {
+ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE);
+ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ;
+ for (i=0; i < (p_Fm->firmware.size / 4); i++)
+ {
+ tmp = GET_UINT32(p_Iram->idata);
+ if (tmp != p_Fm->firmware.p_Code[i])
+ RETURN_ERROR(MAJOR, E_WRITE_FAILED,
+ ("UCode write error : write 0x%x, read 0x%x",
+ p_Fm->firmware.p_Code[i],tmp));
+ }
+ WRITE_UINT32(p_Iram->iadd, 0x0);
+ }
+
+ /* Enable patch from IRAM */
+ WRITE_UINT32(p_Iram->iready, IRAM_READY);
+ XX_UDelay(1000);
+
+ DBG(INFO, ("FMan-Controller code (ver %d.%d.%d) loaded to IRAM.",
+ ((uint16_t *)p_Fm->firmware.p_Code)[2],
+ ((uint8_t *)p_Fm->firmware.p_Code)[6],
+ ((uint8_t *)p_Fm->firmware.p_Code)[7]));
+
+ return E_OK;
+}
+
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+static t_Error FwNotResetErratumBugzilla6173WA(t_Fm *p_Fm)
+{
+ t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+ uint32_t tmpReg;
+ uint32_t savedSpliodn[63];
+
+ /* write to IRAM first location the debug instruction */
+ WRITE_UINT32(p_Iram->iadd, 0);
+ while (GET_UINT32(p_Iram->iadd) != 0) ;
+ WRITE_UINT32(p_Iram->idata, FM_FW_DEBUG_INSTRUCTION);
+
+ WRITE_UINT32(p_Iram->iadd, 0);
+ while (GET_UINT32(p_Iram->iadd) != 0) ;
+ while (GET_UINT32(p_Iram->idata) != FM_FW_DEBUG_INSTRUCTION) ;
+
+ /* Enable patch from IRAM */
+ WRITE_UINT32(p_Iram->iready, IRAM_READY);
+ CORE_MemoryBarrier();
+ XX_UDelay(100);
+ IO2MemCpy32((uint8_t *)savedSpliodn,
+ (uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn,
+ 63*sizeof(uint32_t));
+
+ /* reset FMAN */
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
+ CORE_MemoryBarrier();
+ XX_UDelay(100);
+
+ /* verify breakpoint debug status register */
+ tmpReg = GET_UINT32(*(uint32_t *)UINT_TO_PTR(p_Fm->baseAddr + FM_DEBUG_STATUS_REGISTER_OFFSET));
+ if (!tmpReg)
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid debug status register value is '0'"));
+
+ /*************************************/
+ /* Load FMan-Controller code to IRAM */
+ /*************************************/
+ ClearIRam(p_Fm);
+ if (p_Fm->firmware.p_Code &&
+ (LoadFmanCtrlCode(p_Fm) != E_OK))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ XX_UDelay(100);
+
+ /* reset FMAN again to start the microcode */
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
+ CORE_MemoryBarrier();
+ XX_UDelay(100);
+ Mem2IOCpy32((uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn,
+ (uint8_t *)savedSpliodn,
+ 63*sizeof(uint32_t));
+
+ if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs))
+ {
+ fman_resume(p_Fm->p_FmFpmRegs);
+ CORE_MemoryBarrier();
+ XX_UDelay(100);
+ }
+
+ return E_OK;
+}
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+static void GuestErrorIsr(t_Fm *p_Fm, uint32_t pending)
+{
+#define FM_G_CALL_1G_MAC_ERR_ISR(_id) \
+do { \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\
+} while (0)
+#define FM_G_CALL_10G_MAC_ERR_ISR(_id) \
+do { \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\
+} while (0)
+
+ /* error interrupts */
+ if (pending & ERR_INTR_EN_1G_MAC0)
+ FM_G_CALL_1G_MAC_ERR_ISR(0);
+ if (pending & ERR_INTR_EN_1G_MAC1)
+ FM_G_CALL_1G_MAC_ERR_ISR(1);
+ if (pending & ERR_INTR_EN_1G_MAC2)
+ FM_G_CALL_1G_MAC_ERR_ISR(2);
+ if (pending & ERR_INTR_EN_1G_MAC3)
+ FM_G_CALL_1G_MAC_ERR_ISR(3);
+ if (pending & ERR_INTR_EN_1G_MAC4)
+ FM_G_CALL_1G_MAC_ERR_ISR(4);
+ if (pending & ERR_INTR_EN_1G_MAC5)
+ FM_G_CALL_1G_MAC_ERR_ISR(5);
+ if (pending & ERR_INTR_EN_1G_MAC6)
+ FM_G_CALL_1G_MAC_ERR_ISR(6);
+ if (pending & ERR_INTR_EN_1G_MAC7)
+ FM_G_CALL_1G_MAC_ERR_ISR(7);
+ if (pending & ERR_INTR_EN_10G_MAC0)
+ FM_G_CALL_10G_MAC_ERR_ISR(0);
+ if (pending & ERR_INTR_EN_10G_MAC1)
+ FM_G_CALL_10G_MAC_ERR_ISR(1);
+}
+
+static void GuestEventIsr(t_Fm *p_Fm, uint32_t pending)
+{
+#define FM_G_CALL_1G_MAC_ISR(_id) \
+do { \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\
+} while (0)
+#define FM_G_CALL_10G_MAC_ISR(_id) \
+do { \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\
+} while (0)
+
+ if (pending & INTR_EN_1G_MAC0)
+ FM_G_CALL_1G_MAC_ISR(0);
+ if (pending & INTR_EN_1G_MAC1)
+ FM_G_CALL_1G_MAC_ISR(1);
+ if (pending & INTR_EN_1G_MAC2)
+ FM_G_CALL_1G_MAC_ISR(2);
+ if (pending & INTR_EN_1G_MAC3)
+ FM_G_CALL_1G_MAC_ISR(3);
+ if (pending & INTR_EN_1G_MAC4)
+ FM_G_CALL_1G_MAC_ISR(4);
+ if (pending & INTR_EN_1G_MAC5)
+ FM_G_CALL_1G_MAC_ISR(5);
+ if (pending & INTR_EN_1G_MAC6)
+ FM_G_CALL_1G_MAC_ISR(6);
+ if (pending & INTR_EN_1G_MAC7)
+ FM_G_CALL_1G_MAC_ISR(7);
+ if (pending & INTR_EN_10G_MAC0)
+ FM_G_CALL_10G_MAC_ISR(0);
+ if (pending & INTR_EN_10G_MAC1)
+ FM_G_CALL_10G_MAC_ISR(1);
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (pending & INTR_EN_TMR)
+ p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
+#endif
+}
+
+#if (DPAA_VERSION >= 11)
+static t_Error SetVSPWindow(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t baseStorageProfile,
+ uint8_t log2NumOfProfiles)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+
+ ASSERT_COND(h_Fm);
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->p_FmBmiRegs &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcVspSetPortWindow fmIpcVspSetPortWindow;
+ t_FmIpcMsg msg;
+ t_Error err = E_OK;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&fmIpcVspSetPortWindow, 0, sizeof(t_FmIpcVspSetPortWindow));
+ fmIpcVspSetPortWindow.hardwarePortId = hardwarePortId;
+ fmIpcVspSetPortWindow.baseStorageProfile = baseStorageProfile;
+ fmIpcVspSetPortWindow.log2NumOfProfiles = log2NumOfProfiles;
+ msg.msgId = FM_VSP_SET_PORT_WINDOW;
+ memcpy(msg.msgBody, &fmIpcVspSetPortWindow, sizeof(t_FmIpcVspSetPortWindow));
+
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (!p_Fm->p_FmBmiRegs)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ fman_set_vsp_window(p_Fm->p_FmBmiRegs,
+ hardwarePortId,
+ baseStorageProfile,
+ log2NumOfProfiles);
+
+ return E_OK;
+}
+
+static uint8_t AllocVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ uint8_t profilesFound = 0;
+ int i = 0;
+ uint32_t intFlags;
+
+ if (!numOfProfiles)
+ return E_OK;
+
+ if ((numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES) ||
+ (base + numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES))
+ return (uint8_t)ILLEGAL_BASE;
+
+ if (p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ t_Error err;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = p_Fm->guestId;
+ ipcAllocParams.num = p_Fm->partNumOfVSPs;
+ ipcAllocParams.base = p_Fm->partVSPBase;
+ msg.msgId = FM_VSP_ALLOC;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ replyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if ((err != E_OK) ||
+ (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))))
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ else
+ memcpy((uint8_t*)&p_Fm->partVSPBase, reply.replyBody, sizeof(uint8_t));
+ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!"));
+ return (uint8_t)ILLEGAL_BASE;
+ }
+
+ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
+ for (i = base; i < base + numOfProfiles; i++)
+ if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE)
+ profilesFound++;
+ else
+ break;
+
+ if (profilesFound == numOfProfiles)
+ for (i = base; i<base + numOfProfiles; i++)
+ p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = guestId;
+ else
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ return (uint8_t)ILLEGAL_BASE;
+ }
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+
+ return base;
+}
+
+static void FreeVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ int i = 0;
+
+ ASSERT_COND(p_Fm);
+
+ if (p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+ t_Error err;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams));
+ ipcAllocParams.guestId = p_Fm->guestId;
+ ipcAllocParams.num = p_Fm->partNumOfVSPs;
+ ipcAllocParams.base = p_Fm->partVSPBase;
+ msg.msgId = FM_VSP_FREE;
+ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams));
+ replyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return;
+ }
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!"));
+ return;
+ }
+
+ ASSERT_COND(p_Fm->p_FmSp);
+
+ for (i=base; i<numOfProfiles; i++)
+ {
+ if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == guestId)
+ p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
+ else
+ DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition"));
+ }
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+static t_Error FmGuestHandleIpcMsgCB(t_Handle h_Fm,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg;
+
+ UNUSED(p_Reply);
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((msgLength > sizeof(uint32_t)), E_INVALID_VALUE);
+
+#ifdef DISABLE_SANITY_CHECKS
+ UNUSED(msgLength);
+#endif /* DISABLE_SANITY_CHECKS */
+
+ ASSERT_COND(p_Msg);
+
+ *p_ReplyLength = 0;
+
+ switch (p_IpcMsg->msgId)
+ {
+ case (FM_GUEST_ISR):
+ {
+ t_FmIpcIsr ipcIsr;
+
+ memcpy((uint8_t*)&ipcIsr, p_IpcMsg->msgBody, sizeof(t_FmIpcIsr));
+ if (ipcIsr.boolErr)
+ GuestErrorIsr(p_Fm, ipcIsr.pendingReg);
+ else
+ GuestEventIsr(p_Fm, ipcIsr.pendingReg);
+ break;
+ }
+ default:
+ *p_ReplyLength = 0;
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
+ }
+ return E_OK;
+}
+
+static t_Error FmHandleIpcMsgCB(t_Handle h_Fm,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength)
+{
+ t_Error err;
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg;
+ t_FmIpcReply *p_IpcReply = (t_FmIpcReply*)p_Reply;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE);
+
+#ifdef DISABLE_SANITY_CHECKS
+ UNUSED(msgLength);
+#endif /* DISABLE_SANITY_CHECKS */
+
+ ASSERT_COND(p_IpcMsg);
+
+ memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_IPC_MAX_REPLY_SIZE));
+ *p_ReplyLength = 0;
+
+ switch (p_IpcMsg->msgId)
+ {
+ case (FM_GET_SET_PORT_PARAMS):
+ {
+ t_FmIpcPortInInitParams ipcInitParams;
+ t_FmInterModulePortInitParams initParams;
+ t_FmIpcPortOutInitParams ipcOutInitParams;
+
+ memcpy((uint8_t*)&ipcInitParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortInInitParams));
+ initParams.hardwarePortId = ipcInitParams.hardwarePortId;
+ initParams.portType = (e_FmPortType)ipcInitParams.enumPortType;
+ initParams.independentMode = (bool)(ipcInitParams.boolIndependentMode);
+ initParams.liodnOffset = ipcInitParams.liodnOffset;
+ initParams.numOfTasks = ipcInitParams.numOfTasks;
+ initParams.numOfExtraTasks = ipcInitParams.numOfExtraTasks;
+ initParams.numOfOpenDmas = ipcInitParams.numOfOpenDmas;
+ initParams.numOfExtraOpenDmas = ipcInitParams.numOfExtraOpenDmas;
+ initParams.sizeOfFifo = ipcInitParams.sizeOfFifo;
+ initParams.extraSizeOfFifo = ipcInitParams.extraSizeOfFifo;
+ initParams.deqPipelineDepth = ipcInitParams.deqPipelineDepth;
+ initParams.maxFrameLength = ipcInitParams.maxFrameLength;
+ initParams.liodnBase = ipcInitParams.liodnBase;
+
+ p_IpcReply->error = (uint32_t)FmGetSetPortParams(h_Fm, &initParams);
+
+ ipcOutInitParams.ipcPhysAddr.high = initParams.fmMuramPhysBaseAddr.high;
+ ipcOutInitParams.ipcPhysAddr.low = initParams.fmMuramPhysBaseAddr.low;
+ ipcOutInitParams.sizeOfFifo = initParams.sizeOfFifo;
+ ipcOutInitParams.extraSizeOfFifo = initParams.extraSizeOfFifo;
+ ipcOutInitParams.numOfTasks = initParams.numOfTasks;
+ ipcOutInitParams.numOfExtraTasks = initParams.numOfExtraTasks;
+ ipcOutInitParams.numOfOpenDmas = initParams.numOfOpenDmas;
+ ipcOutInitParams.numOfExtraOpenDmas = initParams.numOfExtraOpenDmas;
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcOutInitParams, sizeof(ipcOutInitParams));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams);
+ break;
+ }
+ case (FM_SET_SIZE_OF_FIFO):
+ {
+ t_FmIpcPortRsrcParams ipcPortRsrcParams;
+
+ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
+ p_IpcReply->error = (uint32_t)FmSetSizeOfFifo(h_Fm,
+ ipcPortRsrcParams.hardwarePortId,
+ &ipcPortRsrcParams.val,
+ &ipcPortRsrcParams.extra,
+ (bool)ipcPortRsrcParams.boolInitialConfig);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_SET_NUM_OF_TASKS):
+ {
+ t_FmIpcPortRsrcParams ipcPortRsrcParams;
+
+ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
+ p_IpcReply->error = (uint32_t)FmSetNumOfTasks(h_Fm, ipcPortRsrcParams.hardwarePortId,
+ (uint8_t*)&ipcPortRsrcParams.val,
+ (uint8_t*)&ipcPortRsrcParams.extra,
+ (bool)ipcPortRsrcParams.boolInitialConfig);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_SET_NUM_OF_OPEN_DMAS):
+ {
+ t_FmIpcPortRsrcParams ipcPortRsrcParams;
+
+ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams));
+ p_IpcReply->error = (uint32_t)FmSetNumOfOpenDmas(h_Fm, ipcPortRsrcParams.hardwarePortId,
+ (uint8_t*)&ipcPortRsrcParams.val,
+ (uint8_t*)&ipcPortRsrcParams.extra,
+ (bool)ipcPortRsrcParams.boolInitialConfig);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_RESUME_STALLED_PORT):
+ *p_ReplyLength = sizeof(uint32_t);
+ p_IpcReply->error = (uint32_t)FmResumeStalledPort(h_Fm, p_IpcMsg->msgBody[0]);
+ break;
+ case (FM_MASTER_IS_ALIVE):
+ {
+ uint8_t guestId = p_IpcMsg->msgBody[0];
+ /* build the FM master partition IPC address */
+ memset(p_Fm->fmIpcHandlerModuleName[guestId], 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint (p_Fm->fmIpcHandlerModuleName[guestId], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, guestId) != (guestId<10 ? 6:7))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ p_Fm->h_IpcSessions[guestId] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[guestId], p_Fm->fmModuleName);
+ if (p_Fm->h_IpcSessions[guestId] == NULL)
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Master IPC session for guest %d", guestId));
+ *(uint8_t*)(p_IpcReply->replyBody) = 1;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ }
+ case (FM_IS_PORT_STALLED):
+ {
+ bool tmp;
+
+ p_IpcReply->error = (uint32_t)FmIsPortStalled(h_Fm, p_IpcMsg->msgBody[0], &tmp);
+ *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)tmp;
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ }
+ case (FM_RESET_MAC):
+ {
+ t_FmIpcMacParams ipcMacParams;
+
+ memcpy((uint8_t*)&ipcMacParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacParams));
+ p_IpcReply->error = (uint32_t)FmResetMac(p_Fm,
+ (e_FmMacType)(ipcMacParams.enumType),
+ ipcMacParams.id);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+ }
+ case (FM_SET_MAC_MAX_FRAME):
+ {
+ t_FmIpcMacMaxFrameParams ipcMacMaxFrameParams;
+
+ memcpy((uint8_t*)&ipcMacMaxFrameParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacMaxFrameParams));
+ err = FmSetMacMaxFrame(p_Fm,
+ (e_FmMacType)(ipcMacMaxFrameParams.macParams.enumType),
+ ipcMacMaxFrameParams.macParams.id,
+ ipcMacMaxFrameParams.maxFrameLength);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ break;
+ }
+#if (DPAA_VERSION >= 11)
+ case (FM_VSP_ALLOC) :
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ uint8_t vspBase;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ vspBase = AllocVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId);
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&vspBase, sizeof(uint8_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ }
+ case (FM_VSP_FREE) :
+ {
+ t_FmIpcResourceAllocParams ipcAllocParams;
+ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams));
+ FreeVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId);
+ break;
+ }
+ case (FM_VSP_SET_PORT_WINDOW) :
+ {
+ t_FmIpcVspSetPortWindow ipcVspSetPortWindow;
+ memcpy(&ipcVspSetPortWindow, p_IpcMsg->msgBody, sizeof(t_FmIpcVspSetPortWindow));
+ err = SetVSPWindow(h_Fm,
+ ipcVspSetPortWindow.hardwarePortId,
+ ipcVspSetPortWindow.baseStorageProfile,
+ ipcVspSetPortWindow.log2NumOfProfiles);
+ return err;
+ }
+ case (FM_SET_CONG_GRP_PFC_PRIO) :
+ {
+ t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority;
+ memcpy(&fmIpcSetCongestionGroupPfcPriority, p_IpcMsg->msgBody, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
+ err = FmSetCongestionGroupPFCpriority(h_Fm,
+ fmIpcSetCongestionGroupPfcPriority.congestionGroupId,
+ fmIpcSetCongestionGroupPfcPriority.priorityBitMap);
+ return err;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ case (FM_FREE_PORT):
+ {
+ t_FmInterModulePortFreeParams portParams;
+ t_FmIpcPortFreeParams ipcPortParams;
+
+ memcpy((uint8_t*)&ipcPortParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFreeParams));
+ portParams.hardwarePortId = ipcPortParams.hardwarePortId;
+ portParams.portType = (e_FmPortType)(ipcPortParams.enumPortType);
+ portParams.deqPipelineDepth = ipcPortParams.deqPipelineDepth;
+ FmFreePortParams(h_Fm, &portParams);
+ break;
+ }
+ case (FM_REGISTER_INTR):
+ {
+ t_FmIpcRegisterIntr ipcRegIntr;
+
+ memcpy((uint8_t*)&ipcRegIntr, p_IpcMsg->msgBody, sizeof(ipcRegIntr));
+ p_Fm->intrMng[ipcRegIntr.event].guestId = ipcRegIntr.guestId;
+ break;
+ }
+ case (FM_GET_PARAMS):
+ {
+ t_FmIpcParams ipcParams;
+
+ /* Get clock frequency */
+ ipcParams.fmClkFreq = p_Fm->p_FmStateStruct->fmClkFreq;
+ ipcParams.fmMacClkFreq = p_Fm->p_FmStateStruct->fmMacClkFreq;
+
+ fman_get_revision(p_Fm->p_FmFpmRegs,&ipcParams.majorRev,&ipcParams.minorRev);
+
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcParams, sizeof(t_FmIpcParams));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams);
+ break;
+ }
+ case (FM_GET_FMAN_CTRL_CODE_REV):
+ {
+ t_FmCtrlCodeRevisionInfo fmanCtrlRevInfo;
+ t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo;
+
+ p_IpcReply->error = (uint32_t)FM_GetFmanCtrlCodeRevision(h_Fm, &fmanCtrlRevInfo);
+ ipcRevInfo.packageRev = fmanCtrlRevInfo.packageRev;
+ ipcRevInfo.majorRev = fmanCtrlRevInfo.majorRev;
+ ipcRevInfo.minorRev = fmanCtrlRevInfo.minorRev;
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_FmIpcFmanCtrlCodeRevisionInfo));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcFmanCtrlCodeRevisionInfo);
+ break;
+ }
+
+ case (FM_DMA_STAT):
+ {
+ t_FmDmaStatus dmaStatus;
+ t_FmIpcDmaStatus ipcDmaStatus;
+
+ FM_GetDmaStatus(h_Fm, &dmaStatus);
+ ipcDmaStatus.boolCmqNotEmpty = (uint8_t)dmaStatus.cmqNotEmpty;
+ ipcDmaStatus.boolBusError = (uint8_t)dmaStatus.busError;
+ ipcDmaStatus.boolReadBufEccError = (uint8_t)dmaStatus.readBufEccError;
+ ipcDmaStatus.boolWriteBufEccSysError = (uint8_t)dmaStatus.writeBufEccSysError;
+ ipcDmaStatus.boolWriteBufEccFmError = (uint8_t)dmaStatus.writeBufEccFmError;
+ ipcDmaStatus.boolSinglePortEccError = (uint8_t)dmaStatus.singlePortEccError;
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcDmaStatus, sizeof(t_FmIpcDmaStatus));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus);
+ break;
+ }
+ case (FM_ALLOC_FMAN_CTRL_EVENT_REG):
+ p_IpcReply->error = (uint32_t)FmAllocFmanCtrlEventReg(h_Fm, (uint8_t*)p_IpcReply->replyBody);
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ break;
+ case (FM_FREE_FMAN_CTRL_EVENT_REG):
+ FmFreeFmanCtrlEventReg(h_Fm, p_IpcMsg->msgBody[0]);
+ break;
+ case (FM_GET_TIMESTAMP_SCALE):
+ {
+ uint32_t timeStamp = FmGetTimeStampScale(h_Fm);
+
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&timeStamp, sizeof(uint32_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ case (FM_GET_COUNTER):
+ {
+ e_FmCounters inCounter;
+ uint32_t outCounter;
+
+ memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t));
+ outCounter = FM_GetCounter(h_Fm, inCounter);
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ case (FM_SET_FMAN_CTRL_EVENTS_ENABLE):
+ {
+ t_FmIpcFmanEvents ipcFmanEvents;
+
+ memcpy((uint8_t*)&ipcFmanEvents, p_IpcMsg->msgBody, sizeof(t_FmIpcFmanEvents));
+ FmSetFmanCtrlIntr(h_Fm,
+ ipcFmanEvents.eventRegId,
+ ipcFmanEvents.enableEvents);
+ break;
+ }
+ case (FM_GET_FMAN_CTRL_EVENTS_ENABLE):
+ {
+ uint32_t tmp = FmGetFmanCtrlIntr(h_Fm, p_IpcMsg->msgBody[0]);
+
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&tmp, sizeof(uint32_t));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ case (FM_GET_PHYS_MURAM_BASE):
+ {
+ t_FmPhysAddr physAddr;
+ t_FmIpcPhysAddr ipcPhysAddr;
+
+ FmGetPhysicalMuramBase(h_Fm, &physAddr);
+ ipcPhysAddr.high = physAddr.high;
+ ipcPhysAddr.low = physAddr.low;
+ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr));
+ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr);
+ break;
+ }
+ case (FM_ENABLE_RAM_ECC):
+ {
+ if (((err = FM_EnableRamsEcc(h_Fm)) != E_OK) ||
+ ((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, TRUE)) != E_OK) ||
+ ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, TRUE)) != E_OK))
+#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
+ UNUSED(err);
+#else
+ REPORT_ERROR(MINOR, err, NO_MSG);
+#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */
+ break;
+ }
+ case (FM_DISABLE_RAM_ECC):
+ {
+
+ if (((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, FALSE)) != E_OK) ||
+ ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, FALSE)) != E_OK) ||
+ ((err = FM_DisableRamsEcc(h_Fm)) != E_OK))
+#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
+ UNUSED(err);
+#else
+ REPORT_ERROR(MINOR, err, NO_MSG);
+#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */
+ break;
+ }
+ case (FM_SET_NUM_OF_FMAN_CTRL):
+ {
+ t_FmIpcPortNumOfFmanCtrls ipcPortNumOfFmanCtrls;
+
+ memcpy((uint8_t*)&ipcPortNumOfFmanCtrls, p_IpcMsg->msgBody, sizeof(t_FmIpcPortNumOfFmanCtrls));
+ err = FmSetNumOfRiscsPerPort(h_Fm,
+ ipcPortNumOfFmanCtrls.hardwarePortId,
+ ipcPortNumOfFmanCtrls.numOfFmanCtrls,
+ ipcPortNumOfFmanCtrls.orFmanCtrl);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ break;
+ }
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+ case (FM_10G_TX_ECC_WA):
+ p_IpcReply->error = (uint32_t)Fm10GTxEccWorkaround(h_Fm, p_IpcMsg->msgBody[0]);
+ *p_ReplyLength = sizeof(uint32_t);
+ break;
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+ default:
+ *p_ReplyLength = 0;
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
+ }
+ return E_OK;
+}
+
+
+/****************************************/
+/* Inter-Module functions */
+/****************************************/
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err = E_OK;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+ uint8_t rxHardwarePortId, txHardwarePortId;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_10G_TX_ECC_WA;
+ msg.msgBody[0] = macId;
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(macId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+
+ SANITY_CHECK_RETURN_ERROR((macId == 0), E_NOT_SUPPORTED);
+ SANITY_CHECK_RETURN_ERROR(IsFmanCtrlCodeLoaded(p_Fm), E_INVALID_STATE);
+
+ rxHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_RX_10G,
+ macId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ txHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_TX_10G,
+ macId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ if ((p_Fm->p_FmStateStruct->portsTypes[rxHardwarePortId] != e_FM_PORT_TYPE_DUMMY) ||
+ (p_Fm->p_FmStateStruct->portsTypes[txHardwarePortId] != e_FM_PORT_TYPE_DUMMY))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("MAC should be initialized prior to Rx and Tx ports!"));
+
+ return fman_set_erratum_10gmac_a004_wa(fpm_rg);
+}
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0);
+
+ return p_Fm->tnumAgingPeriod;
+}
+
+t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm,
+ uint8_t portNum,
+ bool preFetchConfigured)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ p_Fm->portsPreFetchConfigured[portNum] = TRUE;
+ p_Fm->portsPreFetchValue[portNum] = preFetchConfigured;
+
+ return E_OK;
+}
+
+t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm,
+ uint8_t portNum,
+ bool *p_PortConfigured,
+ bool *p_PreFetchConfigured)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ /* If the prefetch wasn't configured yet (not enable or disabled)
+ we return the value TRUE as it was already configured */
+ if (!p_Fm->portsPreFetchConfigured[portNum])
+ {
+ *p_PortConfigured = FALSE;
+ *p_PreFetchConfigured = FALSE;
+ }
+ else
+ {
+ *p_PortConfigured = TRUE;
+ *p_PreFetchConfigured = (p_Fm->portsPreFetchConfigured[portNum]);
+ }
+
+ return E_OK;
+}
+
+t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm,
+ uint32_t congestionGroupId,
+ uint8_t priorityBitMap)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ uint32_t regNum;
+
+ ASSERT_COND(h_Fm);
+
+ if (congestionGroupId > FM_PORT_NUM_OF_CONGESTION_GRPS)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Congestion group ID bigger than %d",
+ FM_PORT_NUM_OF_CONGESTION_GRPS));
+
+ if (p_Fm->guestId == NCSW_MASTER_ID)
+ {
+ ASSERT_COND(p_Fm->baseAddr);
+ regNum = (FM_PORT_NUM_OF_CONGESTION_GRPS - 1 - congestionGroupId) / 4;
+ fman_set_congestion_group_pfc_priority((uint32_t *)((p_Fm->baseAddr+FM_MM_CGP)),
+ congestionGroupId,
+ priorityBitMap,
+ regNum);
+ }
+ else if (p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&fmIpcSetCongestionGroupPfcPriority, 0, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
+ fmIpcSetCongestionGroupPfcPriority.congestionGroupId = congestionGroupId;
+ fmIpcSetCongestionGroupPfcPriority.priorityBitMap = priorityBitMap;
+
+ msg.msgId = FM_SET_CONG_GRP_PFC_PRIO;
+ memcpy(msg.msgBody, &fmIpcSetCongestionGroupPfcPriority, sizeof(t_FmIpcSetCongestionGroupPfcPriority));
+
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("guest without IPC!"));
+
+ return E_OK;
+}
+
+uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+
+ if (!p_Fm->baseAddr)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE,
+ ("No base-addr; probably Guest with IPC!"));
+ return 0;
+ }
+
+ return (p_Fm->baseAddr + FM_MM_PRS);
+}
+
+uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+
+ if (!p_Fm->baseAddr)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE,
+ ("No base-addr; probably Guest with IPC!"));
+ return 0;
+ }
+
+ return (p_Fm->baseAddr + FM_MM_KG);
+}
+
+uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+
+ if (!p_Fm->baseAddr)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE,
+ ("No base-addr; probably Guest with IPC!"));
+ return 0;
+ }
+
+ return (p_Fm->baseAddr + FM_MM_PLCR);
+}
+
+#if (DPAA_VERSION >= 11)
+uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+
+ return p_Fm->vspBaseAddr;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Handle FmGetMuramHandle(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL);
+
+ return (p_Fm->h_FmMuram);
+}
+
+void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *p_FmPhysAddr)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ if (p_Fm->fmMuramPhysBaseAddr)
+ {
+ /* General FM driver initialization */
+ p_FmPhysAddr->low = (uint32_t)p_Fm->fmMuramPhysBaseAddr;
+ p_FmPhysAddr->high = (uint8_t)((p_Fm->fmMuramPhysBaseAddr & 0x000000ff00000000LL) >> 32);
+ return;
+ }
+
+ ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID);
+
+ if (p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+ t_FmIpcPhysAddr ipcPhysAddr;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_PHYS_MURAM_BASE;
+ replyLength = sizeof(uint32_t) + sizeof(t_FmPhysAddr);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmPhysAddr)))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_VALUE,("IPC reply length mismatch"));
+ return;
+ }
+ memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr));
+ p_FmPhysAddr->high = ipcPhysAddr.high;
+ p_FmPhysAddr->low = ipcPhysAddr.low;
+ }
+ else
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+}
+
+#if (DPAA_VERSION >= 11)
+t_Error FmVSPAllocForPort (t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint8_t numOfVSPs)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_Error err = E_OK;
+ uint32_t profilesFound, intFlags;
+ uint8_t first, i;
+ uint8_t log2Num;
+ uint8_t swPortIndex=0, hardwarePortId;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ if (!numOfVSPs)
+ return E_OK;
+
+ if (numOfVSPs > FM_VSP_MAX_NUM_OF_ENTRIES)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles can not be bigger than %d.",FM_VSP_MAX_NUM_OF_ENTRIES));
+
+ if (!POWER_OF_2(numOfVSPs))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2."));
+
+ LOG2((uint64_t)numOfVSPs, log2Num);
+
+ if ((log2Num == 0) || (p_Fm->partVSPBase == 0))
+ first = 0;
+ else
+ first = 1<<log2Num;
+
+ if (first > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window"));
+
+ if (first < p_Fm->partVSPBase)
+ while (first < p_Fm->partVSPBase)
+ first = first + numOfVSPs;
+
+ if ((first + numOfVSPs) > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window"));
+
+ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
+ profilesFound = 0;
+ for (i=first; i < p_Fm->partVSPBase + p_Fm->partNumOfVSPs; )
+ {
+ if (!p_Fm->p_FmSp->profiles[i].profilesMng.allocated)
+ {
+ profilesFound++;
+ i++;
+ if (profilesFound == numOfVSPs)
+ break;
+ }
+ else
+ {
+ profilesFound = 0;
+ /* advance i to the next aligned address */
+ first = i = (uint8_t)(first + numOfVSPs);
+ }
+ }
+ if (profilesFound == numOfVSPs)
+ for (i = first; i<first + numOfVSPs; i++)
+ p_Fm->p_FmSp->profiles[i].profilesMng.allocated = TRUE;
+ else
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MINOR, E_FULL, ("No profiles."));
+ }
+
+ hardwarePortId = SwPortIdToHwPortId(portType,
+ portId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = numOfVSPs;
+ p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = first;
+
+ if ((err = SetVSPWindow(h_Fm,hardwarePortId, first,log2Num)) != E_OK)
+ for (i = first; i < first + numOfVSPs; i++)
+ p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE;
+
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+
+ return err;
+}
+
+t_Error FmVSPFreeForPort(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ uint8_t swPortIndex=0, hardwarePortId, first, numOfVSPs, i;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ hardwarePortId = SwPortIdToHwPortId(portType,
+ portId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ numOfVSPs = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles;
+ first = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase;
+
+ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
+ for (i = first; i < first + numOfVSPs; i++)
+ p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE;
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+
+ p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = 0;
+ p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = 0;
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint8_t i;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_ALLOC_FMAN_CTRL_EVENT_REG;
+ replyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+
+ *p_EventId = *(uint8_t*)(reply.replyBody);
+
+ return (t_Error)(reply.error);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++)
+ if (!p_Fm->usedEventRegs[i])
+ {
+ p_Fm->usedEventRegs[i] = TRUE;
+ *p_EventId = i;
+ break;
+ }
+
+ if (i==FM_NUM_OF_FMAN_CTRL_EVENT_REGS)
+ RETURN_ERROR(MAJOR, E_BUSY, ("No resource - FMan controller event register."));
+
+ return E_OK;
+}
+
+void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_FREE_FMAN_CTRL_EVENT_REG;
+ msg.msgBody[0] = eventId;
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(eventId),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+ return;
+ }
+
+ ((t_Fm*)h_Fm)->usedEventRegs[eventId] = FALSE;
+}
+
+void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->p_FmFpmRegs &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcFmanEvents fmanCtrl;
+ t_Error err;
+ t_FmIpcMsg msg;
+
+ fmanCtrl.eventRegId = eventRegId;
+ fmanCtrl.enableEvents = enableEvents;
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_SET_FMAN_CTRL_EVENTS_ENABLE;
+ memcpy(msg.msgBody, &fmanCtrl, sizeof(fmanCtrl));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(fmanCtrl),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+ else if (!p_Fm->p_FmFpmRegs)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+ return;
+ }
+
+ ASSERT_COND(eventRegId < FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
+ fman_set_ctrl_intr(fpm_rg, eventRegId, enableEvents);
+}
+
+uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->p_FmFpmRegs &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength, ctrlIntr;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_FMAN_CTRL_EVENTS_ENABLE;
+ msg.msgBody[0] = eventRegId;
+ replyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(eventRegId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return 0;
+ }
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
+ {
+ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return 0;
+ }
+ memcpy((uint8_t*)&ctrlIntr, reply.replyBody, sizeof(uint32_t));
+ return ctrlIntr;
+ }
+ else if (!p_Fm->p_FmFpmRegs)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+ return 0;
+ }
+
+ return fman_get_ctrl_intr(fpm_rg, eventRegId);
+}
+
+void FmRegisterIntr(t_Handle h_Fm,
+ e_FmEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType,
+ void (*f_Isr) (t_Handle h_Arg),
+ t_Handle h_Arg)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ int event = 0;
+
+ ASSERT_COND(h_Fm);
+
+ GET_FM_MODULE_EVENT(module, modId, intrType, event);
+ ASSERT_COND(event < e_FM_EV_DUMMY_LAST);
+
+ /* register in local FM structure */
+ p_Fm->intrMng[event].f_Isr = f_Isr;
+ p_Fm->intrMng[event].h_SrcHandle = h_Arg;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcRegisterIntr fmIpcRegisterIntr;
+ t_Error err;
+ t_FmIpcMsg msg;
+
+ /* register in Master FM structure */
+ fmIpcRegisterIntr.event = (uint32_t)event;
+ fmIpcRegisterIntr.guestId = p_Fm->guestId;
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_REGISTER_INTR;
+ memcpy(msg.msgBody, &fmIpcRegisterIntr, sizeof(fmIpcRegisterIntr));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(fmIpcRegisterIntr),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+}
+
+void FmUnregisterIntr(t_Handle h_Fm,
+ e_FmEventModules module,
+ uint8_t modId,
+ e_FmIntrType intrType)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ int event = 0;
+
+ ASSERT_COND(h_Fm);
+
+ GET_FM_MODULE_EVENT(module, modId,intrType, event);
+ ASSERT_COND(event < e_FM_EV_DUMMY_LAST);
+
+ p_Fm->intrMng[event].f_Isr = UnimplementedIsr;
+ p_Fm->intrMng[event].h_SrcHandle = NULL;
+}
+
+void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Arg, uint32_t event), t_Handle h_Arg)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode"));
+ return;
+ }
+
+ p_Fm->fmanCtrlIntr[eventRegId].f_Isr = f_Isr;
+ p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = h_Arg;
+}
+
+void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS);
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode"));
+ return;
+ }
+
+ p_Fm->fmanCtrlIntr[eventRegId].f_Isr = UnimplementedFmanCtrlIsr;
+ p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = NULL;
+}
+
+void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ if (p_Fm->h_Pcd)
+ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("PCD already set"));
+
+ p_Fm->h_Pcd = h_FmPcd;
+}
+
+void FmUnregisterPcd(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ if (!p_Fm->h_Pcd)
+ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("PCD handle!"));
+
+ p_Fm->h_Pcd = NULL;
+}
+
+t_Handle FmGetPcdHandle(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ return p_Fm->h_Pcd;
+}
+
+uint8_t FmGetId(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0xff);
+
+ return p_Fm->p_FmStateStruct->fmId;
+}
+
+t_Error FmReset(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET);
+ CORE_MemoryBarrier();
+ XX_UDelay(100);
+
+ return E_OK;
+}
+
+t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t numOfFmanCtrls,
+ t_FmFmanCtrl orFmanCtrl)
+{
+
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((numOfFmanCtrls > 0) && (numOfFmanCtrls < 3)) , E_INVALID_HANDLE);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->p_FmFpmRegs &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcPortNumOfFmanCtrls params;
+ t_FmIpcMsg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ params.hardwarePortId = hardwarePortId;
+ params.numOfFmanCtrls = numOfFmanCtrls;
+ params.orFmanCtrl = orFmanCtrl;
+ msg.msgId = FM_SET_NUM_OF_FMAN_CTRL;
+ memcpy(msg.msgBody, &params, sizeof(params));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(params),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (!p_Fm->p_FmFpmRegs)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ fman_set_num_of_riscs_per_port(fpm_rg, hardwarePortId, numOfFmanCtrls, orFmanCtrl);
+
+ return E_OK;
+}
+
+t_Error FmGetSetPortParams(t_Handle h_Fm, t_FmInterModulePortInitParams *p_PortParams)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err;
+ uint32_t intFlags;
+ uint8_t hardwarePortId = p_PortParams->hardwarePortId, macId;
+ struct fman_rg fman_rg;
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ t_FmIpcPortInInitParams portInParams;
+ t_FmIpcPortOutInitParams portOutParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ portInParams.hardwarePortId = p_PortParams->hardwarePortId;
+ portInParams.enumPortType = (uint32_t)p_PortParams->portType;
+ portInParams.boolIndependentMode= (uint8_t)p_PortParams->independentMode;
+ portInParams.liodnOffset = p_PortParams->liodnOffset;
+ portInParams.numOfTasks = p_PortParams->numOfTasks;
+ portInParams.numOfExtraTasks = p_PortParams->numOfExtraTasks;
+ portInParams.numOfOpenDmas = p_PortParams->numOfOpenDmas;
+ portInParams.numOfExtraOpenDmas = p_PortParams->numOfExtraOpenDmas;
+ portInParams.sizeOfFifo = p_PortParams->sizeOfFifo;
+ portInParams.extraSizeOfFifo = p_PortParams->extraSizeOfFifo;
+ portInParams.deqPipelineDepth = p_PortParams->deqPipelineDepth;
+ portInParams.maxFrameLength = p_PortParams->maxFrameLength;
+ portInParams.liodnBase = p_PortParams->liodnBase;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_SET_PORT_PARAMS;
+ memcpy(msg.msgBody, &portInParams, sizeof(portInParams));
+ replyLength = (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams));
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(portInParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ memcpy((uint8_t*)&portOutParams, reply.replyBody, sizeof(t_FmIpcPortOutInitParams));
+
+ p_PortParams->fmMuramPhysBaseAddr.high = portOutParams.ipcPhysAddr.high;
+ p_PortParams->fmMuramPhysBaseAddr.low = portOutParams.ipcPhysAddr.low;
+ p_PortParams->numOfTasks = portOutParams.numOfTasks;
+ p_PortParams->numOfExtraTasks = portOutParams.numOfExtraTasks;
+ p_PortParams->numOfOpenDmas = portOutParams.numOfOpenDmas;
+ p_PortParams->numOfExtraOpenDmas = portOutParams.numOfExtraOpenDmas;
+ p_PortParams->sizeOfFifo = portOutParams.sizeOfFifo;
+ p_PortParams->extraSizeOfFifo = portOutParams.extraSizeOfFifo;
+
+ return (t_Error)(reply.error);
+ }
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
+ if (p_PortParams->independentMode)
+ {
+ /* set port parameters */
+ p_Fm->independentMode = p_PortParams->independentMode;
+ /* disable dispatch limit */
+ fman_qmi_disable_dispatch_limit(fman_rg.fpm_rg);
+ }
+
+ if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ {
+ if (p_Fm->hcPortInitialized)
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Only one host command port is allowed."));
+ }
+ else
+ p_Fm->hcPortInitialized = TRUE;
+ }
+ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = p_PortParams->portType;
+
+ err = FmSetNumOfTasks(p_Fm, hardwarePortId, &p_PortParams->numOfTasks, &p_PortParams->numOfExtraTasks, TRUE);
+ if (err)
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+ if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) &&
+ (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G))
+ /* for transmit & O/H ports */
+ {
+ uint8_t enqTh;
+ uint8_t deqTh;
+
+ /* update qmi ENQ/DEQ threshold */
+ p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums += p_PortParams->deqPipelineDepth;
+ enqTh = fman_get_qmi_enq_th(fman_rg.qmi_rg);
+ /* if enqTh is too big, we reduce it to the max value that is still OK */
+ if (enqTh >= (QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums))
+ {
+ enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1);
+ fman_set_qmi_enq_th(fman_rg.qmi_rg, enqTh);
+ }
+
+ deqTh = fman_get_qmi_deq_th(fman_rg.qmi_rg);
+ /* if deqTh is too small, we enlarge it to the min value that is still OK.
+ deqTh may not be larger than 63 (QMI_MAX_NUM_OF_TNUMS-1). */
+ if ((deqTh <= p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums) && (deqTh < QMI_MAX_NUM_OF_TNUMS-1))
+ {
+ deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1);
+ fman_set_qmi_deq_th(fman_rg.qmi_rg, deqTh);
+ }
+ }
+
+#ifdef FM_LOW_END_RESTRICTION
+ if ((hardwarePortId==0x1) || (hardwarePortId==0x29))
+ {
+ if (p_Fm->p_FmStateStruct->lowEndRestriction)
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("OP #0 cannot work with Tx Port #1."));
+ }
+ else
+ p_Fm->p_FmStateStruct->lowEndRestriction = TRUE;
+ }
+#endif /* FM_LOW_END_RESTRICTION */
+
+ err = FmSetSizeOfFifo(p_Fm,
+ hardwarePortId,
+ &p_PortParams->sizeOfFifo,
+ &p_PortParams->extraSizeOfFifo,
+ TRUE);
+ if (err)
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ err = FmSetNumOfOpenDmas(p_Fm,
+ hardwarePortId,
+ &p_PortParams->numOfOpenDmas,
+ &p_PortParams->numOfExtraOpenDmas,
+ TRUE);
+ if (err)
+ {
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ fman_set_liodn_per_port(&fman_rg,
+ hardwarePortId,
+ p_PortParams->liodnBase,
+ p_PortParams->liodnOffset);
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
+ fman_set_order_restoration_per_port(fman_rg.fpm_rg,
+ hardwarePortId,
+ p_PortParams->independentMode,
+ !!((p_PortParams->portType==e_FM_PORT_TYPE_RX) || (p_PortParams->portType==e_FM_PORT_TYPE_RX_10G)));
+
+ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
+
+#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
+ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) ||
+ (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS);
+ if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId])
+ p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = p_PortParams->maxFrameLength;
+ else
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU"));
+ }
+ else
+#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
+ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) ||
+ (p_PortParams->portType == e_FM_PORT_TYPE_RX))
+ {
+ ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS);
+ if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId])
+ p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = p_PortParams->maxFrameLength;
+ else
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU"));
+ }
+
+ FmGetPhysicalMuramBase(p_Fm, &p_PortParams->fmMuramPhysBaseAddr);
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+
+ return E_OK;
+}
+
+void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t intFlags;
+ uint8_t hardwarePortId = p_PortParams->hardwarePortId;
+ uint8_t numOfTasks, numOfDmas, macId;
+ uint16_t sizeOfFifo;
+ t_Error err;
+ t_FmIpcPortFreeParams portParams;
+ t_FmIpcMsg msg;
+ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs;
+ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ portParams.hardwarePortId = p_PortParams->hardwarePortId;
+ portParams.enumPortType = (uint32_t)p_PortParams->portType;
+ portParams.deqPipelineDepth = p_PortParams->deqPipelineDepth;
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_FREE_PORT;
+ memcpy(msg.msgBody, &portParams, sizeof(portParams));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(portParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock);
+
+ if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ {
+ ASSERT_COND(p_Fm->hcPortInitialized);
+ p_Fm->hcPortInitialized = FALSE;
+ }
+
+ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = e_FM_PORT_TYPE_DUMMY;
+
+ /* free numOfTasks */
+ numOfTasks = fman_get_num_of_tasks(bmi_rg, hardwarePortId);
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= numOfTasks);
+ p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= numOfTasks;
+
+ /* free numOfOpenDmas */
+ numOfDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= numOfDmas);
+ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= numOfDmas;
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
+ {
+ /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */
+ fman_set_num_of_open_dmas(bmi_rg,
+ hardwarePortId,
+ 1,
+ 0,
+ (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize));
+ }
+#endif /* FM_HAS_TOTAL_DMAS */
+
+ /* free sizeOfFifo */
+ sizeOfFifo = fman_get_size_of_fifo(bmi_rg, hardwarePortId);
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= (sizeOfFifo * BMI_FIFO_UNITS));
+ p_Fm->p_FmStateStruct->accumulatedFifoSize -= (sizeOfFifo * BMI_FIFO_UNITS);
+
+#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+ if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) &&
+ (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G))
+ /* for transmit & O/H ports */
+ {
+ uint8_t enqTh;
+ uint8_t deqTh;
+
+ /* update qmi ENQ/DEQ threshold */
+ p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums -= p_PortParams->deqPipelineDepth;
+
+ /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller,
+ so we can enlarge enqTh */
+ enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1);
+
+ /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller,
+ so we can reduce deqTh */
+ deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1);
+
+ fman_set_qmi_enq_th(qmi_rg, enqTh);
+ fman_set_qmi_deq_th(qmi_rg, deqTh);
+ }
+
+ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
+
+#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
+ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) ||
+ (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G))
+ {
+ ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS);
+ p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = 0;
+ }
+ else
+#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
+ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) ||
+ (p_PortParams->portType == e_FM_PORT_TYPE_RX))
+ {
+ ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS);
+ p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = 0;
+ }
+
+#ifdef FM_LOW_END_RESTRICTION
+ if ((hardwarePortId==0x1) || (hardwarePortId==0x29))
+ p_Fm->p_FmStateStruct->lowEndRestriction = FALSE;
+#endif /* FM_LOW_END_RESTRICTION */
+ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags);
+}
+
+t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_IS_PORT_STALLED;
+ msg.msgBody[0] = hardwarePortId;
+ replyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(hardwarePortId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+
+ *p_IsStalled = (bool)!!(*(uint8_t*)(reply.replyBody));
+
+ return (t_Error)(reply.error);
+ }
+ else if (!p_Fm->baseAddr)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ *p_IsStalled = fman_is_port_stalled(fpm_rg, hardwarePortId);
+
+ return E_OK;
+}
+
+t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err;
+ bool isStalled;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_RESUME_STALLED_PORT;
+ msg.msgBody[0] = hardwarePortId;
+ replyLength = sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(hardwarePortId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+ else if (!p_Fm->baseAddr)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not available for this FM revision!"));
+
+ /* Get port status */
+ err = FmIsPortStalled(h_Fm, hardwarePortId, &isStalled);
+ if (err)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get port status"));
+ if (!isStalled)
+ return E_OK;
+
+ fman_resume_stalled_port(fpm_rg, hardwarePortId);
+
+ return E_OK;
+}
+
+t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err;
+ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs;
+
+#if (DPAA_VERSION >= 11)
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("FMan MAC reset!"));
+#endif /*(DPAA_VERSION >= 11)*/
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcMacParams macParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ macParams.id = macId;
+ macParams.enumType = (uint32_t)type;
+ msg.msgId = FM_RESET_MAC;
+ memcpy(msg.msgBody, &macParams, sizeof(macParams));
+ replyLength = sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(macParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+ else if (!p_Fm->baseAddr)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+
+ err = (t_Error)fman_reset_mac(fpm_rg, macId, !!(type == e_FM_MAC_10G));
+
+ if (err == -EBUSY)
+ return ERROR_CODE(E_TIMEOUT);
+ else if (err)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal MAC ID"));
+
+ return E_OK;
+}
+
+t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcMacMaxFrameParams macMaxFrameLengthParams;
+ t_Error err;
+ t_FmIpcMsg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ macMaxFrameLengthParams.macParams.id = macId;
+ macMaxFrameLengthParams.macParams.enumType = (uint32_t)type;
+ macMaxFrameLengthParams.maxFrameLength = (uint16_t)mtu;
+ msg.msgId = FM_SET_MAC_MAX_FRAME;
+ memcpy(msg.msgBody, &macMaxFrameLengthParams, sizeof(macMaxFrameLengthParams));
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(macMaxFrameLengthParams),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return E_OK;
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ /* if port is already initialized, check that MaxFrameLength is smaller
+ * or equal to the port's max */
+#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS))
+ if (type == e_FM_MAC_10G)
+ {
+ if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId])
+ || (p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] &&
+ (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId])))
+ p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId] = mtu;
+ else
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength"));
+
+ }
+ else
+#else
+ UNUSED(type);
+#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */
+ if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId])
+ || (p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] &&
+ (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId])))
+ p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId] = mtu;
+ else
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength"));
+
+ return E_OK;
+}
+
+uint16_t FmGetClockFreq(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ /* for multicore environment: this depends on the
+ * fact that fmClkFreq was properly initialized at "init". */
+ return p_Fm->p_FmStateStruct->fmClkFreq;
+}
+
+uint16_t FmGetMacClockFreq(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ return p_Fm->p_FmStateStruct->fmMacClkFreq;
+}
+
+uint32_t FmGetTimeStampScale(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength, timeStamp;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_TIMESTAMP_SCALE;
+ replyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return 0;
+ }
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return 0;
+ }
+
+ memcpy((uint8_t*)&timeStamp, reply.replyBody, sizeof(uint32_t));
+ return timeStamp;
+ }
+ else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->baseAddr)
+ {
+ if (!(GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_tsc1) & FPM_TS_CTL_EN))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("timestamp is not enabled!"));
+ return 0;
+ }
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ DBG(WARNING, ("No IPC - can't validate FM if timestamp enabled."));
+
+ return p_Fm->p_FmStateStruct->count1MicroBit;
+}
+
+t_Error FmEnableRamsEcc(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ p_Fm->p_FmStateStruct->ramsEccOwners++;
+ p_Fm->p_FmStateStruct->internalCall = TRUE;
+
+ return FM_EnableRamsEcc(p_Fm);
+}
+
+t_Error FmDisableRamsEcc(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ ASSERT_COND(p_Fm->p_FmStateStruct->ramsEccOwners);
+ p_Fm->p_FmStateStruct->ramsEccOwners--;
+
+ if (p_Fm->p_FmStateStruct->ramsEccOwners==0)
+ {
+ p_Fm->p_FmStateStruct->internalCall = TRUE;
+ return FM_DisableRamsEcc(p_Fm);
+ }
+
+ return E_OK;
+}
+
+uint8_t FmGetGuestId(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ return p_Fm->guestId;
+}
+
+bool FmIsMaster(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ return (p_Fm->guestId == NCSW_MASTER_ID);
+}
+
+t_Error FmSetSizeOfFifo(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint32_t *p_SizeOfFifo,
+ uint32_t *p_ExtraSizeOfFifo,
+ bool initialConfig)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_FmIpcPortRsrcParams rsrcParams;
+ t_Error err;
+ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
+ uint32_t sizeOfFifo = *p_SizeOfFifo, extraSizeOfFifo = *p_ExtraSizeOfFifo;
+ uint16_t currentVal = 0, currentExtraVal = 0;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ rsrcParams.hardwarePortId = hardwarePortId;
+ rsrcParams.val = sizeOfFifo;
+ rsrcParams.extra = extraSizeOfFifo;
+ rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_SET_SIZE_OF_FIFO;
+ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(rsrcParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+ else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->baseAddr)
+ {
+ DBG(WARNING, ("No IPC - can't validate FM total-fifo size."));
+ fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+
+ if (!initialConfig)
+ {
+ /* !initialConfig - runtime change of existing value.
+ * - read the current FIFO and extra FIFO size */
+ currentExtraVal = fman_get_size_of_extra_fifo(bmi_rg, hardwarePortId);
+ currentVal = fman_get_size_of_fifo(bmi_rg, hardwarePortId);
+ }
+
+ if (extraSizeOfFifo > currentExtraVal)
+ {
+ if (extraSizeOfFifo && !p_Fm->p_FmStateStruct->extraFifoPoolSize)
+ /* if this is the first time a port requires extraFifoPoolSize, the total extraFifoPoolSize
+ * must be initialized to 1 buffer per port
+ */
+ p_Fm->p_FmStateStruct->extraFifoPoolSize = FM_MAX_NUM_OF_RX_PORTS*BMI_FIFO_UNITS;
+
+ p_Fm->p_FmStateStruct->extraFifoPoolSize = MAX(p_Fm->p_FmStateStruct->extraFifoPoolSize, extraSizeOfFifo);
+ }
+
+ /* check that there are enough uncommitted fifo size */
+ if ((p_Fm->p_FmStateStruct->accumulatedFifoSize - currentVal + sizeOfFifo) >
+ (p_Fm->p_FmStateStruct->totalFifoSize - p_Fm->p_FmStateStruct->extraFifoPoolSize)){
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("Port request fifo size + accumulated size > total FIFO size:"));
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE,
+ ("port 0x%x requested %d bytes, extra size = %d, accumulated size = %d total size = %d",
+ hardwarePortId, sizeOfFifo, p_Fm->p_FmStateStruct->extraFifoPoolSize,
+ p_Fm->p_FmStateStruct->accumulatedFifoSize,
+ p_Fm->p_FmStateStruct->totalFifoSize));
+ }
+ else
+ {
+ /* update accumulated */
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= currentVal);
+ p_Fm->p_FmStateStruct->accumulatedFifoSize -= currentVal;
+ p_Fm->p_FmStateStruct->accumulatedFifoSize += sizeOfFifo;
+ fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo);
+ }
+
+ return E_OK;
+}
+
+t_Error FmSetNumOfTasks(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t *p_NumOfTasks,
+ uint8_t *p_NumOfExtraTasks,
+ bool initialConfig)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_Error err;
+ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
+ uint8_t currentVal = 0, currentExtraVal = 0, numOfTasks = *p_NumOfTasks, numOfExtraTasks = *p_NumOfExtraTasks;
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcPortRsrcParams rsrcParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ rsrcParams.hardwarePortId = hardwarePortId;
+ rsrcParams.val = numOfTasks;
+ rsrcParams.extra = numOfExtraTasks;
+ rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_SET_NUM_OF_TASKS;
+ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(rsrcParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+ else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->baseAddr)
+ {
+ DBG(WARNING, ("No IPC - can't validate FM total-num-of-tasks."));
+ fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+
+ if (!initialConfig)
+ {
+ /* !initialConfig - runtime change of existing value.
+ * - read the current number of tasks */
+ currentVal = fman_get_num_of_tasks(bmi_rg, hardwarePortId);
+ currentExtraVal = fman_get_num_extra_tasks(bmi_rg, hardwarePortId);
+ }
+
+ if (numOfExtraTasks > currentExtraVal)
+ p_Fm->p_FmStateStruct->extraTasksPoolSize =
+ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraTasksPoolSize, numOfExtraTasks);
+
+ /* check that there are enough uncommitted tasks */
+ if ((p_Fm->p_FmStateStruct->accumulatedNumOfTasks - currentVal + numOfTasks) >
+ (p_Fm->p_FmStateStruct->totalNumOfTasks - p_Fm->p_FmStateStruct->extraTasksPoolSize))
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
+ ("Requested numOfTasks and extra tasks pool for fm%d exceed total numOfTasks.",
+ p_Fm->p_FmStateStruct->fmId));
+ else
+ {
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= currentVal);
+ /* update accumulated */
+ p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= currentVal;
+ p_Fm->p_FmStateStruct->accumulatedNumOfTasks += numOfTasks;
+ fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks);
+ }
+
+ return E_OK;
+}
+
+t_Error FmSetNumOfOpenDmas(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t *p_NumOfOpenDmas,
+ uint8_t *p_NumOfExtraOpenDmas,
+ bool initialConfig)
+
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_Error err;
+ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs;
+ uint8_t numOfOpenDmas = *p_NumOfOpenDmas, numOfExtraOpenDmas = *p_NumOfExtraOpenDmas;
+ uint8_t totalNumDmas = 0, currentVal = 0, currentExtraVal = 0;
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcPortRsrcParams rsrcParams;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ rsrcParams.hardwarePortId = hardwarePortId;
+ rsrcParams.val = numOfOpenDmas;
+ rsrcParams.extra = numOfExtraOpenDmas;
+ rsrcParams.boolInitialConfig = (uint8_t)initialConfig;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_SET_NUM_OF_OPEN_DMAS;
+ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams));
+ replyLength = sizeof(uint32_t);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) + sizeof(rsrcParams),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != sizeof(uint32_t))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return (t_Error)(reply.error);
+ }
+#ifdef FM_HAS_TOTAL_DMAS
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("running in guest-mode without IPC!"));
+#else
+ else if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->baseAddr &&
+ (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6))
+ {
+ /*DBG(WARNING, ("No IPC - can't validate FM total-num-of-dmas."));*/
+
+ if (!numOfOpenDmas)
+ {
+ /* first config without explic it value: Do Nothing - reset value shouldn't be
+ changed, read register for port save */
+ *p_NumOfOpenDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
+ *p_NumOfExtraOpenDmas = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
+ }
+ else
+ /* whether it is the first time with explicit value, or runtime "set" - write register */
+ fman_set_num_of_open_dmas(bmi_rg,
+ hardwarePortId,
+ numOfOpenDmas,
+ numOfExtraOpenDmas,
+ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without neither IPC nor mapped register!"));
+#endif /* FM_HAS_TOTAL_DMAS */
+
+ if (!initialConfig)
+ {
+ /* !initialConfig - runtime change of existing value.
+ * - read the current number of open Dma's */
+ currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
+ currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
+ }
+
+#ifdef FM_NO_GUARANTEED_RESET_VALUES
+ /* it's illegal to be in a state where this is not the first set and no value is specified */
+ ASSERT_COND(initialConfig || numOfOpenDmas);
+ if (!numOfOpenDmas)
+ {
+ /* !numOfOpenDmas - first configuration according to values in regs.
+ * - read the current number of open Dma's */
+ currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId);
+ currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId);
+ /* This is the first configuration and user did not specify value (!numOfOpenDmas),
+ * reset values will be used and we just save these values for resource management */
+ p_Fm->p_FmStateStruct->extraOpenDmasPoolSize =
+ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, currentExtraVal);
+ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += currentVal;
+ *p_NumOfOpenDmas = currentVal;
+ *p_NumOfExtraOpenDmas = currentExtraVal;
+ return E_OK;
+ }
+#endif /* FM_NO_GUARANTEED_RESET_VALUES */
+
+ if (numOfExtraOpenDmas > currentExtraVal)
+ p_Fm->p_FmStateStruct->extraOpenDmasPoolSize =
+ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, numOfExtraOpenDmas);
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) &&
+ (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas >
+ p_Fm->p_FmStateStruct->maxNumOfOpenDmas))
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
+ ("Requested numOfOpenDmas for fm%d exceeds total numOfOpenDmas.",
+ p_Fm->p_FmStateStruct->fmId));
+#else
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) &&
+#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+ !((p_Fm->p_FmStateStruct->revInfo.majorRev == 6) &&
+ (p_Fm->p_FmStateStruct->revInfo.minorRev == 0)) &&
+#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */
+ (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > DMA_THRESH_MAX_COMMQ + 1))
+ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE,
+ ("Requested numOfOpenDmas for fm%d exceeds DMA Command queue (%d)",
+ p_Fm->p_FmStateStruct->fmId, DMA_THRESH_MAX_COMMQ+1));
+#endif /* FM_HAS_TOTAL_DMAS */
+ else
+ {
+ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= currentVal);
+ /* update acummulated */
+ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= currentVal;
+ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += numOfOpenDmas;
+
+#ifdef FM_HAS_TOTAL_DMAS
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)
+ totalNumDmas = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize);
+#endif /* FM_HAS_TOTAL_DMAS */
+ fman_set_num_of_open_dmas(bmi_rg,
+ hardwarePortId,
+ numOfOpenDmas,
+ numOfExtraOpenDmas,
+ totalNumDmas);
+ }
+
+ return E_OK;
+}
+
+#if (DPAA_VERSION >= 11)
+t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint16_t relativeProfile)
+{
+ t_Fm *p_Fm;
+ t_FmSp *p_FmPcdSp;
+ uint8_t swPortIndex=0, hardwarePortId;
+
+ ASSERT_COND(h_Fm);
+ p_Fm = (t_Fm*)h_Fm;
+
+ hardwarePortId = SwPortIdToHwPortId(portType,
+ portId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ ASSERT_COND(hardwarePortId);
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ p_FmPcdSp = p_Fm->p_FmSp;
+ ASSERT_COND(p_FmPcdSp);
+
+ if (!p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Port has no allocated profiles"));
+ if (relativeProfile >= p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles)
+ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE , ("Profile id is out of range"));
+
+ return E_OK;
+}
+
+t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint16_t relativeProfile,
+ uint16_t *p_AbsoluteId)
+{
+ t_Fm *p_Fm;
+ t_FmSp *p_FmPcdSp;
+ uint8_t swPortIndex=0, hardwarePortId;
+ t_Error err;
+
+ ASSERT_COND(h_Fm);
+ p_Fm = (t_Fm*)h_Fm;
+
+ err = FmVSPCheckRelativeProfile(h_Fm, portType, portId, relativeProfile);
+ if (err != E_OK)
+ return err;
+
+ hardwarePortId = SwPortIdToHwPortId(portType,
+ portId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+ ASSERT_COND(hardwarePortId);
+ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
+
+ p_FmPcdSp = p_Fm->p_FmSp;
+ ASSERT_COND(p_FmPcdSp);
+
+ *p_AbsoluteId = (uint16_t)(p_FmPcdSp->portsMapping[swPortIndex].profilesBase + relativeProfile);
+
+ return E_OK;
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+static t_Error InitFmDma(t_Fm *p_Fm)
+{
+ t_Error err;
+
+ err = (t_Error)fman_dma_init(p_Fm->p_FmDmaRegs, p_Fm->p_FmDriverParam);
+ if (err != E_OK)
+ return err;
+
+ /* Allocate MURAM for CAM */
+ p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
+ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY),
+ DMA_CAM_ALIGN));
+ if (!p_Fm->camBaseAddr)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed"));
+
+ WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr),
+ 0,
+ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY));
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev == 2)
+ {
+ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr));
+
+ p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
+ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128),
+ 64));
+ if (!p_Fm->camBaseAddr)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed"));
+
+ WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr),
+ 0,
+ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128));
+
+ switch(p_Fm->p_FmDriverParam->dma_cam_num_of_entries)
+ {
+ case (8):
+ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xff000000);
+ break;
+ case (16):
+ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffff0000);
+ break;
+ case (24):
+ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffff00);
+ break;
+ case (32):
+ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffffff);
+ break;
+ default:
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("wrong dma_cam_num_of_entries"));
+ }
+ }
+
+ p_Fm->p_FmDriverParam->cam_base_addr =
+ (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->camBaseAddr)) - p_Fm->fmMuramPhysBaseAddr);
+
+ return E_OK;
+}
+
+static t_Error InitFmFpm(t_Fm *p_Fm)
+{
+ return (t_Error)fman_fpm_init(p_Fm->p_FmFpmRegs, p_Fm->p_FmDriverParam);
+}
+
+static t_Error InitFmBmi(t_Fm *p_Fm)
+{
+ return (t_Error)fman_bmi_init(p_Fm->p_FmBmiRegs, p_Fm->p_FmDriverParam);
+}
+
+static t_Error InitFmQmi(t_Fm *p_Fm)
+{
+ return (t_Error)fman_qmi_init(p_Fm->p_FmQmiRegs, p_Fm->p_FmDriverParam);
+}
+
+static t_Error InitGuestMode(t_Fm *p_Fm)
+{
+ t_Error err = E_OK;
+ int i;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+
+ ASSERT_COND(p_Fm);
+ ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID);
+
+ /* build the FM guest partition IPC address */
+ if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, p_Fm->guestId) != (p_Fm->guestId<10 ? 6:7))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+
+ /* build the FM master partition IPC address */
+ memset(p_Fm->fmIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE);
+ if (Sprint (p_Fm->fmIpcHandlerModuleName[0], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+
+ for (i=0;i<e_FM_EV_DUMMY_LAST;i++)
+ p_Fm->intrMng[i].f_Isr = UnimplementedIsr;
+
+ p_Fm->h_IpcSessions[0] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[0], p_Fm->fmModuleName);
+ if (p_Fm->h_IpcSessions[0])
+ {
+ uint8_t isMasterAlive;
+ t_FmIpcParams ipcParams;
+
+ err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmGuestHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE);
+ if (err)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_MASTER_IS_ALIVE;
+ msg.msgBody[0] = p_Fm->guestId;
+ replyLength = sizeof(uint32_t) + sizeof(uint8_t);
+ do
+ {
+ blockingFlag = TRUE;
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId)+sizeof(p_Fm->guestId),
+ (uint8_t*)&reply,
+ &replyLength,
+ IpcMsgCompletionCB,
+ p_Fm)) != E_OK)
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ while (blockingFlag) ;
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ isMasterAlive = *(uint8_t*)(reply.replyBody);
+ } while (!isMasterAlive);
+
+ /* read FM parameters and save */
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_PARAMS;
+ replyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcParams)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ memcpy((uint8_t*)&ipcParams, reply.replyBody, sizeof(t_FmIpcParams));
+
+ p_Fm->p_FmStateStruct->fmClkFreq = ipcParams.fmClkFreq;
+ p_Fm->p_FmStateStruct->fmMacClkFreq = ipcParams.fmMacClkFreq;
+ p_Fm->p_FmStateStruct->revInfo.majorRev = ipcParams.majorRev;
+ p_Fm->p_FmStateStruct->revInfo.minorRev = ipcParams.minorRev;
+ }
+ else
+ {
+ DBG(WARNING, ("FM Guest mode - without IPC"));
+ if (!p_Fm->p_FmStateStruct->fmClkFreq)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No fmClkFreq configured for guest without IPC"));
+ if (p_Fm->baseAddr)
+ {
+ fman_get_revision(p_Fm->p_FmFpmRegs,
+ &p_Fm->p_FmStateStruct->revInfo.majorRev,
+ &p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+ }
+ }
+
+#if (DPAA_VERSION >= 11)
+ p_Fm->partVSPBase = AllocVSPsForPartition(p_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
+ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
+ DBG(WARNING, ("partition VSPs allocation is FAILED"));
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* General FM driver initialization */
+ if (p_Fm->baseAddr)
+ p_Fm->fmMuramPhysBaseAddr =
+ (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM)));
+
+ XX_Free(p_Fm->p_FmDriverParam);
+ p_Fm->p_FmDriverParam = NULL;
+
+ if ((p_Fm->guestId == NCSW_MASTER_ID) ||
+ (p_Fm->h_IpcSessions[0]))
+ {
+ FM_DisableRamsEcc(p_Fm);
+ FmMuramClear(p_Fm->h_FmMuram);
+ FM_EnableRamsEcc(p_Fm);
+ }
+
+ return E_OK;
+}
+
+static __inline__ enum fman_exceptions FmanExceptionTrans(e_FmExceptions exception)
+{
+ switch (exception) {
+ case e_FM_EX_DMA_BUS_ERROR:
+ return E_FMAN_EX_DMA_BUS_ERROR;
+ case e_FM_EX_DMA_READ_ECC:
+ return E_FMAN_EX_DMA_READ_ECC;
+ case e_FM_EX_DMA_SYSTEM_WRITE_ECC:
+ return E_FMAN_EX_DMA_SYSTEM_WRITE_ECC;
+ case e_FM_EX_DMA_FM_WRITE_ECC:
+ return E_FMAN_EX_DMA_FM_WRITE_ECC;
+ case e_FM_EX_FPM_STALL_ON_TASKS:
+ return E_FMAN_EX_FPM_STALL_ON_TASKS;
+ case e_FM_EX_FPM_SINGLE_ECC:
+ return E_FMAN_EX_FPM_SINGLE_ECC;
+ case e_FM_EX_FPM_DOUBLE_ECC:
+ return E_FMAN_EX_FPM_DOUBLE_ECC;
+ case e_FM_EX_QMI_SINGLE_ECC:
+ return E_FMAN_EX_QMI_SINGLE_ECC;
+ case e_FM_EX_QMI_DOUBLE_ECC:
+ return E_FMAN_EX_QMI_DOUBLE_ECC;
+ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
+ return E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID;
+ case e_FM_EX_BMI_LIST_RAM_ECC:
+ return E_FMAN_EX_BMI_LIST_RAM_ECC;
+ case e_FM_EX_BMI_STORAGE_PROFILE_ECC:
+ return E_FMAN_EX_BMI_STORAGE_PROFILE_ECC;
+ case e_FM_EX_BMI_STATISTICS_RAM_ECC:
+ return E_FMAN_EX_BMI_STATISTICS_RAM_ECC;
+ case e_FM_EX_BMI_DISPATCH_RAM_ECC:
+ return E_FMAN_EX_BMI_DISPATCH_RAM_ECC;
+ case e_FM_EX_IRAM_ECC:
+ return E_FMAN_EX_IRAM_ECC;
+ case e_FM_EX_MURAM_ECC:
+ return E_FMAN_EX_MURAM_ECC;
+ default:
+ return E_FMAN_EX_DMA_BUS_ERROR;
+ }
+}
+
+uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev)
+{
+ switch (type)
+ {
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ CHECK_PORT_ID_OH_PORTS(relativePortId);
+ return (uint8_t)(BASE_OH_PORTID + (relativePortId));
+ case (e_FM_PORT_TYPE_RX):
+ CHECK_PORT_ID_1G_RX_PORTS(relativePortId);
+ return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId));
+ case (e_FM_PORT_TYPE_RX_10G):
+ /* The 10G port in T1024 (FMan Version 6.4) is the first port.
+ * This is the reason why the 1G port offset is used.
+ */
+ if (majorRev == 6 && minorRev == 4)
+ {
+ CHECK_PORT_ID_1G_RX_PORTS(relativePortId);
+ return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId));
+ }
+ else
+ {
+ CHECK_PORT_ID_10G_RX_PORTS(relativePortId);
+ return (uint8_t)(BASE_10G_RX_PORTID + (relativePortId));
+ }
+ case (e_FM_PORT_TYPE_TX):
+ CHECK_PORT_ID_1G_TX_PORTS(relativePortId);
+ return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId));
+ case (e_FM_PORT_TYPE_TX_10G):
+ /* The 10G port in T1024 (FMan Version 6.4) is the first port.
+ * This is the reason why the 1G port offset is used.
+ */
+ if (majorRev == 6 && minorRev == 4)
+ {
+ CHECK_PORT_ID_1G_TX_PORTS(relativePortId);
+ return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId));
+ }
+ else
+ {
+ CHECK_PORT_ID_10G_TX_PORTS(relativePortId);
+ return (uint8_t)(BASE_10G_TX_PORTID + (relativePortId));
+ }
+ default:
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type"));
+ return 0;
+ }
+}
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+t_Error FmDumpPortRegs (t_Handle h_Fm, uint8_t hardwarePortId)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+
+ DECLARE_DUMP;
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(((p_Fm->guestId == NCSW_MASTER_ID) ||
+ p_Fm->baseAddr), E_INVALID_OPERATION);
+
+ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], ("fmbm_pp for port %u", (hardwarePortId)));
+ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], sizeof(uint32_t));
+
+ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], ("fmbm_pfs for port %u", (hardwarePortId )));
+ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], sizeof(uint32_t));
+
+ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], ("fmbm_spliodn for port %u", (hardwarePortId)));
+ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], sizeof(uint32_t));
+
+ DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], ("fmfp_ps for port %u", (hardwarePortId)));
+ DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], sizeof(uint32_t));
+
+ DUMP_TITLE(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], ("fmdmplr for port %u", (hardwarePortId)));
+ DUMP_MEMORY(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], sizeof(uint32_t));
+
+ return E_OK;
+}
+#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
+
+
+/*****************************************************************************/
+/* API Init unit functions */
+/*****************************************************************************/
+t_Handle FM_Config(t_FmParams *p_FmParam)
+{
+ t_Fm *p_Fm;
+ uint8_t i;
+ uintptr_t baseAddr;
+
+ SANITY_CHECK_RETURN_VALUE(p_FmParam, E_NULL_POINTER, NULL);
+ SANITY_CHECK_RETURN_VALUE(((p_FmParam->firmware.p_Code && p_FmParam->firmware.size) ||
+ (!p_FmParam->firmware.p_Code && !p_FmParam->firmware.size)),
+ E_INVALID_VALUE, NULL);
+
+ baseAddr = p_FmParam->baseAddr;
+
+ /* Allocate FM structure */
+ p_Fm = (t_Fm *) XX_Malloc(sizeof(t_Fm));
+ if (!p_Fm)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver structure"));
+ return NULL;
+ }
+ memset(p_Fm, 0, sizeof(t_Fm));
+
+ p_Fm->p_FmStateStruct = (t_FmStateStruct *) XX_Malloc(sizeof(t_FmStateStruct));
+ if (!p_Fm->p_FmStateStruct)
+ {
+ XX_Free(p_Fm);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Status structure"));
+ return NULL;
+ }
+ memset(p_Fm->p_FmStateStruct, 0, sizeof(t_FmStateStruct));
+
+ /* Initialize FM parameters which will be kept by the driver */
+ p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId;
+ p_Fm->guestId = p_FmParam->guestId;
+
+ for (i=0; i<FM_MAX_NUM_OF_HW_PORT_IDS; i++)
+ p_Fm->p_FmStateStruct->portsTypes[i] = e_FM_PORT_TYPE_DUMMY;
+
+ /* Allocate the FM driver's parameters structure */
+ p_Fm->p_FmDriverParam = (struct fman_cfg *)XX_Malloc(sizeof(struct fman_cfg));
+ if (!p_Fm->p_FmDriverParam)
+ {
+ XX_Free(p_Fm->p_FmStateStruct);
+ XX_Free(p_Fm);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver parameters"));
+ return NULL;
+ }
+ memset(p_Fm->p_FmDriverParam, 0, sizeof(struct fman_cfg));
+
+#if (DPAA_VERSION >= 11)
+ p_Fm->p_FmSp = (t_FmSp *)XX_Malloc(sizeof(t_FmSp));
+ if (!p_Fm->p_FmSp)
+ {
+ XX_Free(p_Fm->p_FmDriverParam);
+ XX_Free(p_Fm->p_FmStateStruct);
+ XX_Free(p_Fm);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("allocation for internal data structure failed"));
+ return NULL;
+ }
+ memset(p_Fm->p_FmSp, 0, sizeof(t_FmSp));
+
+ for (i=0; i<FM_VSP_MAX_NUM_OF_ENTRIES; i++)
+ p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE;
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* Initialize FM parameters which will be kept by the driver */
+ p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId;
+ p_Fm->h_FmMuram = p_FmParam->h_FmMuram;
+ p_Fm->h_App = p_FmParam->h_App;
+ p_Fm->p_FmStateStruct->fmClkFreq = p_FmParam->fmClkFreq;
+ p_Fm->p_FmStateStruct->fmMacClkFreq = p_FmParam->fmClkFreq / ((!p_FmParam->fmMacClkRatio)? 2: p_FmParam->fmMacClkRatio);
+ p_Fm->f_Exception = p_FmParam->f_Exception;
+ p_Fm->f_BusError = p_FmParam->f_BusError;
+ p_Fm->p_FmFpmRegs = (struct fman_fpm_regs *)UINT_TO_PTR(baseAddr + FM_MM_FPM);
+ p_Fm->p_FmBmiRegs = (struct fman_bmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI);
+ p_Fm->p_FmQmiRegs = (struct fman_qmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_QMI);
+ p_Fm->p_FmDmaRegs = (struct fman_dma_regs *)UINT_TO_PTR(baseAddr + FM_MM_DMA);
+ p_Fm->p_FmRegs = (struct fman_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI);
+ p_Fm->baseAddr = baseAddr;
+ p_Fm->p_FmStateStruct->irq = p_FmParam->irq;
+ p_Fm->p_FmStateStruct->errIrq = p_FmParam->errIrq;
+ p_Fm->hcPortInitialized = FALSE;
+ p_Fm->independentMode = FALSE;
+
+ p_Fm->h_Spinlock = XX_InitSpinlock();
+ if (!p_Fm->h_Spinlock)
+ {
+ XX_Free(p_Fm->p_FmDriverParam);
+ XX_Free(p_Fm->p_FmStateStruct);
+ XX_Free(p_Fm);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("can't allocate spinlock!"));
+ return NULL;
+ }
+
+#if (DPAA_VERSION >= 11)
+ p_Fm->partVSPBase = p_FmParam->partVSPBase;
+ p_Fm->partNumOfVSPs = p_FmParam->partNumOfVSPs;
+ p_Fm->vspBaseAddr = p_FmParam->vspBaseAddr;
+#endif /* (DPAA_VERSION >= 11) */
+
+ fman_defconfig(p_Fm->p_FmDriverParam,
+ !!(p_Fm->guestId == NCSW_MASTER_ID));
+/* overide macros dependent parameters */
+#ifdef FM_PEDANTIC_DMA
+ p_Fm->p_FmDriverParam->pedantic_dma = TRUE;
+ p_Fm->p_FmDriverParam->dma_aid_override = TRUE;
+#endif /* FM_PEDANTIC_DMA */
+#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ p_Fm->p_FmDriverParam->qmi_deq_option_support = TRUE;
+#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ p_Fm->p_FmStateStruct->ramsEccEnable = FALSE;
+ p_Fm->p_FmStateStruct->extraFifoPoolSize = 0;
+ p_Fm->p_FmStateStruct->exceptions = DEFAULT_exceptions;
+ p_Fm->resetOnInit = DEFAULT_resetOnInit;
+ p_Fm->f_ResetOnInitOverride = DEFAULT_resetOnInitOverrideCallback;
+ p_Fm->fwVerify = DEFAULT_VerifyUcode;
+ p_Fm->firmware.size = p_FmParam->firmware.size;
+ if (p_Fm->firmware.size)
+ {
+ p_Fm->firmware.p_Code = (uint32_t *)XX_Malloc(p_Fm->firmware.size);
+ if (!p_Fm->firmware.p_Code)
+ {
+ XX_FreeSpinlock(p_Fm->h_Spinlock);
+ XX_Free(p_Fm->p_FmStateStruct);
+ XX_Free(p_Fm->p_FmDriverParam);
+ XX_Free(p_Fm);
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM firmware code"));
+ return NULL;
+ }
+ memcpy(p_Fm->firmware.p_Code, p_FmParam->firmware.p_Code ,p_Fm->firmware.size);
+ }
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ return p_Fm;
+
+ /* read revision */
+ /* Chip dependent, will be configured in Init */
+ fman_get_revision(p_Fm->p_FmFpmRegs,
+ &p_Fm->p_FmStateStruct->revInfo.majorRev,
+ &p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+#ifdef FM_AID_MODE_NO_TNUM_SW005
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ p_Fm->p_FmDriverParam->dma_aid_mode = e_FM_DMA_AID_OUT_PORT_ID;
+#endif /* FM_AID_MODE_NO_TNUM_SW005 */
+#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4)
+ p_Fm->p_FmDriverParam->qmi_def_tnums_thresh = QMI_DEF_TNUMS_THRESH;
+#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+ p_Fm->p_FmStateStruct->totalFifoSize = 0;
+ p_Fm->p_FmStateStruct->totalNumOfTasks =
+ DEFAULT_totalNumOfTasks(p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+#ifdef FM_HAS_TOTAL_DMAS
+ p_Fm->p_FmStateStruct->maxNumOfOpenDmas = BMI_MAX_NUM_OF_DMAS;
+#endif /* FM_HAS_TOTAL_DMAS */
+#if (DPAA_VERSION < 11)
+ p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = DEFAULT_dmaCommQLow;
+ p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = DEFAULT_dmaCommQHigh;
+ p_Fm->p_FmDriverParam->dma_cam_num_of_entries = DEFAULT_dmaCamNumOfEntries;
+ p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = DEFAULT_dmaReadIntBufLow;
+ p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = DEFAULT_dmaReadIntBufHigh;
+ p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = DEFAULT_dmaWriteIntBufLow;
+ p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = DEFAULT_dmaWriteIntBufHigh;
+ p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = DEFAULT_axiDbgNumOfBeats;
+#endif /* (DPAA_VERSION < 11) */
+#ifdef FM_NO_TNUM_AGING
+ p_Fm->p_FmDriverParam->tnum_aging_period = 0;
+#endif
+ p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period;
+
+ return p_Fm;
+}
+
+/**************************************************************************//**
+ @Function FM_Init
+
+ @Description Initializes the FM module
+
+ @Param[in] h_Fm - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_Init(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_cfg *p_FmDriverParam = NULL;
+ t_Error err = E_OK;
+ int i;
+ t_FmRevisionInfo revInfo;
+ struct fman_rg fman_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ p_Fm->p_FmStateStruct->count1MicroBit = FM_TIMESTAMP_1_USEC_BIT;
+ p_Fm->p_FmDriverParam->num_of_fman_ctrl_evnt_regs = FM_NUM_OF_FMAN_CTRL_EVENT_REGS;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ return InitGuestMode(p_Fm);
+
+ /* if user didn't configured totalFifoSize - (totalFifoSize=0) we configure default
+ * according to chip. otherwise, we use user's configuration.
+ */
+ if (p_Fm->p_FmStateStruct->totalFifoSize == 0)
+ p_Fm->p_FmStateStruct->totalFifoSize = DEFAULT_totalFifoSize(p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+ CHECK_INIT_PARAMETERS(p_Fm, CheckFmParameters);
+
+ p_FmDriverParam = p_Fm->p_FmDriverParam;
+
+ FM_GetRevision(p_Fm, &revInfo);
+
+ /* clear revision-dependent non existing exception */
+#ifdef FM_NO_DISPATCH_RAM_ECC
+ if ((revInfo.majorRev != 4) &&
+ (revInfo.majorRev < 6))
+ p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC;
+#endif /* FM_NO_DISPATCH_RAM_ECC */
+
+#ifdef FM_QMI_NO_ECC_EXCEPTIONS
+ if (revInfo.majorRev == 4)
+ p_Fm->p_FmStateStruct->exceptions &= ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC);
+#endif /* FM_QMI_NO_ECC_EXCEPTIONS */
+
+#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION
+ if (revInfo.majorRev >= 6)
+ p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_QMI_SINGLE_ECC;
+#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */
+
+ FmMuramClear(p_Fm->h_FmMuram);
+
+ /* clear CPG */
+ IOMemSet32(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_CGP), 0, FM_PORT_NUM_OF_CONGESTION_GRPS);
+
+ /* add to the default exceptions the user's definitions */
+ p_Fm->p_FmStateStruct->exceptions |= p_Fm->userSetExceptions;
+
+ /* Reset the FM if required */
+ if (p_Fm->resetOnInit)
+ {
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+ if ((err = FwNotResetErratumBugzilla6173WA(p_Fm)) != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+#else /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+ if (p_Fm->f_ResetOnInitOverride)
+ {
+ /* Perform user specific FMan reset */
+ p_Fm->f_ResetOnInitOverride(h_Fm);
+ }
+ else
+ {
+ /* Perform FMan reset */
+ FmReset(h_Fm);
+ }
+
+ if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs))
+ {
+ fman_resume(p_Fm->p_FmFpmRegs);
+ XX_UDelay(100);
+ }
+#endif /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+ }
+
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+ if (!p_Fm->resetOnInit) /* Skip operations done in errata workaround */
+ {
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+ /* Load FMan-Controller code to IRAM */
+
+ ClearIRam(p_Fm);
+
+ if (p_Fm->firmware.p_Code && (LoadFmanCtrlCode(p_Fm) != E_OK))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+ }
+#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+#ifdef FM_CAPWAP_SUPPORT
+ /* save first 256 byte in MURAM */
+ p_Fm->resAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, 256, 0));
+ if (!p_Fm->resAddr)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for reserved Area failed"));
+
+ WRITE_BLOCK(UINT_TO_PTR(p_Fm->resAddr), 0, 256);
+#endif /* FM_CAPWAP_SUPPORT */
+
+#if (DPAA_VERSION >= 11)
+ p_Fm->partVSPBase = AllocVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
+ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE))
+ DBG(WARNING, ("partition VSPs allocation is FAILED"));
+#endif /* (DPAA_VERSION >= 11) */
+
+ /* General FM driver initialization */
+ p_Fm->fmMuramPhysBaseAddr =
+ (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM)));
+
+ for (i=0;i<e_FM_EV_DUMMY_LAST;i++)
+ p_Fm->intrMng[i].f_Isr = UnimplementedIsr;
+ for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++)
+ p_Fm->fmanCtrlIntr[i].f_Isr = UnimplementedFmanCtrlIsr;
+
+ p_FmDriverParam->exceptions = p_Fm->p_FmStateStruct->exceptions;
+
+ /**********************/
+ /* Init DMA Registers */
+ /**********************/
+ err = InitFmDma(p_Fm);
+ if (err != E_OK)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /**********************/
+ /* Init FPM Registers */
+ /**********************/
+ err = InitFmFpm(p_Fm);
+ if (err != E_OK)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /* define common resources */
+ /* allocate MURAM for FIFO according to total size */
+ p_Fm->fifoBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram,
+ p_Fm->p_FmStateStruct->totalFifoSize,
+ BMI_FIFO_ALIGN));
+ if (!p_Fm->fifoBaseAddr)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for BMI FIFO failed"));
+ }
+
+ p_FmDriverParam->fifo_base_addr = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->fifoBaseAddr)) - p_Fm->fmMuramPhysBaseAddr);
+ p_FmDriverParam->total_fifo_size = p_Fm->p_FmStateStruct->totalFifoSize;
+ p_FmDriverParam->total_num_of_tasks = p_Fm->p_FmStateStruct->totalNumOfTasks;
+ p_FmDriverParam->clk_freq = p_Fm->p_FmStateStruct->fmClkFreq;
+
+ /**********************/
+ /* Init BMI Registers */
+ /**********************/
+ err = InitFmBmi(p_Fm);
+ if (err != E_OK)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /**********************/
+ /* Init QMI Registers */
+ /**********************/
+ err = InitFmQmi(p_Fm);
+ if (err != E_OK)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /* build the FM master partition IPC address */
+ if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
+ }
+
+ err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE);
+ if (err)
+ {
+ FreeInitResources(p_Fm);
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+ }
+
+ /* Register the FM interrupts handlers */
+ if (p_Fm->p_FmStateStruct->irq != NO_IRQ)
+ {
+ XX_SetIntr(p_Fm->p_FmStateStruct->irq, FM_EventIsr, p_Fm);
+ XX_EnableIntr(p_Fm->p_FmStateStruct->irq);
+ }
+
+ if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ)
+ {
+ XX_SetIntr(p_Fm->p_FmStateStruct->errIrq, (void (*) (t_Handle))FM_ErrorIsr, p_Fm);
+ XX_EnableIntr(p_Fm->p_FmStateStruct->errIrq);
+ }
+
+ err = (t_Error)fman_enable(&fman_rg , p_FmDriverParam);
+ if (err != E_OK)
+ return err; /* FIXME */
+
+ EnableTimeStamp(p_Fm);
+
+ if (p_Fm->firmware.p_Code)
+ {
+ XX_Free(p_Fm->firmware.p_Code);
+ p_Fm->firmware.p_Code = NULL;
+ }
+
+ XX_Free(p_Fm->p_FmDriverParam);
+ p_Fm->p_FmDriverParam = NULL;
+
+ return E_OK;
+}
+
+/**************************************************************************//**
+ @Function FM_Free
+
+ @Description Frees all resources that were assigned to FM module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_Fm - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_Free(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_rg fman_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+#if (DPAA_VERSION >= 11)
+ FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
+
+ if (p_Fm->p_FmSp)
+ {
+ XX_Free(p_Fm->p_FmSp);
+ p_Fm->p_FmSp = NULL;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_Fm->fmModuleName[0] != 0)
+ XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName);
+
+ if (!p_Fm->recoveryMode)
+ XX_Free(p_Fm->p_FmStateStruct);
+
+ XX_Free(p_Fm);
+
+ return E_OK;
+ }
+
+ fman_free_resources(&fman_rg);
+
+ if ((p_Fm->guestId == NCSW_MASTER_ID) && (p_Fm->fmModuleName[0] != 0))
+ XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName);
+
+ if (p_Fm->p_FmStateStruct)
+ {
+ if (p_Fm->p_FmStateStruct->irq != NO_IRQ)
+ {
+ XX_DisableIntr(p_Fm->p_FmStateStruct->irq);
+ XX_FreeIntr(p_Fm->p_FmStateStruct->irq);
+ }
+ if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ)
+ {
+ XX_DisableIntr(p_Fm->p_FmStateStruct->errIrq);
+ XX_FreeIntr(p_Fm->p_FmStateStruct->errIrq);
+ }
+ }
+
+#if (DPAA_VERSION >= 11)
+ FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId);
+
+ if (p_Fm->p_FmSp)
+ {
+ XX_Free(p_Fm->p_FmSp);
+ p_Fm->p_FmSp = NULL;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ if (p_Fm->h_Spinlock)
+ XX_FreeSpinlock(p_Fm->h_Spinlock);
+
+ if (p_Fm->p_FmDriverParam)
+ {
+ if (p_Fm->firmware.p_Code)
+ XX_Free(p_Fm->firmware.p_Code);
+ XX_Free(p_Fm->p_FmDriverParam);
+ p_Fm->p_FmDriverParam = NULL;
+ }
+
+ FreeInitResources(p_Fm);
+
+ if (!p_Fm->recoveryMode && p_Fm->p_FmStateStruct)
+ XX_Free(p_Fm->p_FmStateStruct);
+
+ XX_Free(p_Fm);
+
+ return E_OK;
+}
+
+/*************************************************/
+/* API Advanced Init unit functions */
+/*************************************************/
+
+t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->resetOnInit = enable;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->f_ResetOnInitOverride = f_ResetOnInitOverride;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmStateStruct->totalFifoSize = totalFifoSize;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_dma_cache_override fsl_cache_override;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, cacheOverride)
+ p_Fm->p_FmDriverParam->dma_cache_override = fsl_cache_override;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_aid_override = aidOverride;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_dma_aid_mode fsl_aid_mode;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_AID_MODE_TRANS(fsl_aid_mode, aidMode);
+ p_Fm->p_FmDriverParam->dma_aid_mode = fsl_aid_mode;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+#if (DPAA_VERSION >= 11)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+#else
+ p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = axiDbgNumOfBeats;
+
+ return E_OK;
+#endif /* (DPAA_VERSION >= 11) */
+}
+
+t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_cam_num_of_entries = numOfEntries;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_dma_dbg_cnt_mode fsl_dma_dbg_cnt;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, fmDmaDbgCntMode);
+ p_Fm->p_FmDriverParam->dma_dbg_cnt_mode = fsl_dma_dbg_cnt;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_stop_on_bus_error = stop;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_dma_emergency_level fsl_dma_emer;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_DMA_EMER_TRANS(fsl_dma_emer, p_Emergency->emergencyLevel);
+ p_Fm->p_FmDriverParam->dma_en_emergency = TRUE;
+ p_Fm->p_FmDriverParam->dma_emergency_bus_select = (uint32_t)p_Emergency->emergencyBusSelect;
+ p_Fm->p_FmDriverParam->dma_emergency_level = fsl_dma_emer;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_en_emergency_smoother = TRUE;
+ p_Fm->p_FmDriverParam->dma_emergency_switch_counter = emergencyCnt;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_dma_err fsl_dma_err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_DMA_ERR_TRANS(fsl_dma_err, dmaErr);
+ p_Fm->p_FmDriverParam->dma_err = fsl_dma_err;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_catastrophic_err fsl_catastrophic_err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, catastrophicErr);
+ p_Fm->p_FmDriverParam->catastrophic_err = fsl_catastrophic_err;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+
+ p_Fm->p_FmDriverParam->en_muram_test_mode = TRUE;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE );
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+
+ p_Fm->p_FmDriverParam->en_iram_test_mode = TRUE;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->halt_on_external_activ = enable;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+
+ p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err = enable;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t bitMask = 0;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Fm->userSetExceptions |= bitMask;
+ else
+ p_Fm->p_FmStateStruct->exceptions &= ~bitMask;
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->external_ecc_rams_enable = enable;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->tnum_aging_period = tnumAgingPeriod;
+ p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period;
+
+ return E_OK;
+}
+
+/****************************************************/
+/* Hidden-DEBUG Only API */
+/****************************************************/
+
+t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->disp_limit_tsh = p_FmThresholds->dispLimit;
+ p_Fm->p_FmDriverParam->prs_disp_tsh = p_FmThresholds->prsDispTh;
+ p_Fm->p_FmDriverParam->plcr_disp_tsh = p_FmThresholds->plcrDispTh;
+ p_Fm->p_FmDriverParam->kg_disp_tsh = p_FmThresholds->kgDispTh;
+ p_Fm->p_FmDriverParam->bmi_disp_tsh = p_FmThresholds->bmiDispTh;
+ p_Fm->p_FmDriverParam->qmi_enq_disp_tsh = p_FmThresholds->qmiEnqDispTh;
+ p_Fm->p_FmDriverParam->qmi_deq_disp_tsh = p_FmThresholds->qmiDeqDispTh;
+ p_Fm->p_FmDriverParam->fm_ctl1_disp_tsh = p_FmThresholds->fmCtl1DispTh;
+ p_Fm->p_FmDriverParam->fm_ctl2_disp_tsh = p_FmThresholds->fmCtl2DispTh;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_sos_emergency = dmaSosEmergency;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
+
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+#if (DPAA_VERSION >= 11)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+#else
+ p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency;
+ p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency;
+
+ return E_OK;
+#endif
+}
+
+t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = p_FmDmaThresholds->assertEmergency;
+ p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = p_FmDmaThresholds->clearEmergency;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+#if (DPAA_VERSION >= 11)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!"));
+#else
+ p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency;
+ p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency;
+
+ return E_OK;
+#endif
+}
+
+t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchdogValue)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ p_Fm->p_FmDriverParam->dma_watchdog = watchdogValue;
+
+ return E_OK;
+}
+
+t_Error FM_ConfigEnableCounters(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+UNUSED(p_Fm);
+
+ return E_OK;
+}
+
+t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params)
+{
+ t_Fm* p_Fm = (t_Fm*)h_Fm;
+ if (p_Params->setParams.type & UPDATE_FM_CLD)
+ {
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_cld, GET_UINT32(
+ p_Fm->p_FmFpmRegs->fm_cld) | 0x00000800);
+ }
+ if (p_Params->setParams.type & CLEAR_IRAM_READY)
+ {
+ t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+ WRITE_UINT32(p_Iram->iready,GET_UINT32(p_Iram->iready) & ~IRAM_READY);
+ }
+ if (p_Params->setParams.type & UPDATE_FPM_EXTC)
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x80000000);
+ if (p_Params->setParams.type & UPDATE_FPM_EXTC_CLEAR)
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x00800000);
+ if (p_Params->setParams.type & UPDATE_FPM_BRKC_SLP)
+ {
+ if (p_Params->setParams.sleep)
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32(
+ p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_SLP);
+ else
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32(
+ p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_SLP);
+ }
+ if (p_Params->getParams.type & GET_FM_CLD)
+ p_Params->getParams.fm_cld = GET_UINT32(p_Fm->p_FmFpmRegs->fm_cld);
+ if (p_Params->getParams.type & GET_FMQM_GS)
+ p_Params->getParams.fmqm_gs = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gs);
+ if (p_Params->getParams.type & GET_FM_NPI)
+ p_Params->getParams.fm_npi = GET_UINT32(p_Fm->p_FmFpmRegs->fm_npi);
+ if (p_Params->getParams.type & GET_FMFP_EXTC)
+ p_Params->getParams.fmfp_extc = GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc);
+ return E_OK;
+}
+
+
+/****************************************************/
+/* API Run-time Control uint functions */
+/****************************************************/
+void FM_EventIsr(t_Handle h_Fm)
+{
+#define FM_M_CALL_1G_MAC_ISR(_id) \
+ { \
+ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].guestId) \
+ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id), pending); \
+ else \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\
+ }
+#define FM_M_CALL_10G_MAC_ISR(_id) \
+ { \
+ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].guestId) \
+ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id), pending); \
+ else \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\
+ }
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t pending, event;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+
+ /* normal interrupts */
+ pending = fman_get_normal_pending(fpm_rg);
+ if (!pending)
+ return;
+ if (pending & INTR_EN_WAKEUP) // this is a wake up from sleep interrupt
+ {
+ t_FmGetSetParams fmGetSetParams;
+ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams));
+ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP;
+ fmGetSetParams.setParams.sleep = 0;
+ FmGetSetParams(h_Fm, &fmGetSetParams);
+ }
+ if (pending & INTR_EN_QMI)
+ QmiEvent(p_Fm);
+ if (pending & INTR_EN_PRS)
+ p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle);
+ if (pending & INTR_EN_PLCR)
+ p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle);
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (pending & INTR_EN_TMR)
+ p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle);
+#endif
+
+ /* MAC events may belong to different partitions */
+ if (pending & INTR_EN_1G_MAC0)
+ FM_M_CALL_1G_MAC_ISR(0);
+ if (pending & INTR_EN_1G_MAC1)
+ FM_M_CALL_1G_MAC_ISR(1);
+ if (pending & INTR_EN_1G_MAC2)
+ FM_M_CALL_1G_MAC_ISR(2);
+ if (pending & INTR_EN_1G_MAC3)
+ FM_M_CALL_1G_MAC_ISR(3);
+ if (pending & INTR_EN_1G_MAC4)
+ FM_M_CALL_1G_MAC_ISR(4);
+ if (pending & INTR_EN_1G_MAC5)
+ FM_M_CALL_1G_MAC_ISR(5);
+ if (pending & INTR_EN_1G_MAC6)
+ FM_M_CALL_1G_MAC_ISR(6);
+ if (pending & INTR_EN_1G_MAC7)
+ FM_M_CALL_1G_MAC_ISR(7);
+ if (pending & INTR_EN_10G_MAC0)
+ FM_M_CALL_10G_MAC_ISR(0);
+ if (pending & INTR_EN_10G_MAC1)
+ FM_M_CALL_10G_MAC_ISR(1);
+
+ /* IM port events may belong to different partitions */
+ if (pending & INTR_EN_REV0)
+ {
+ event = fman_get_controller_event(fpm_rg, 0);
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_0].guestId)
+ /*TODO IPC ISR For Fman Ctrl */
+ ASSERT_COND(0);
+ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_0, pending); */
+ else
+ p_Fm->fmanCtrlIntr[0].f_Isr(p_Fm->fmanCtrlIntr[0].h_SrcHandle, event);
+
+ }
+ if (pending & INTR_EN_REV1)
+ {
+ event = fman_get_controller_event(fpm_rg, 1);
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_1].guestId)
+ /*TODO IPC ISR For Fman Ctrl */
+ ASSERT_COND(0);
+ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_1, pending); */
+ else
+ p_Fm->fmanCtrlIntr[1].f_Isr(p_Fm->fmanCtrlIntr[1].h_SrcHandle, event);
+ }
+ if (pending & INTR_EN_REV2)
+ {
+ event = fman_get_controller_event(fpm_rg, 2);
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_2].guestId)
+ /*TODO IPC ISR For Fman Ctrl */
+ ASSERT_COND(0);
+ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pending); */
+ else
+ p_Fm->fmanCtrlIntr[2].f_Isr(p_Fm->fmanCtrlIntr[2].h_SrcHandle, event);
+ }
+ if (pending & INTR_EN_REV3)
+ {
+ event = fman_get_controller_event(fpm_rg, 3);
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_3].guestId)
+ /*TODO IPC ISR For Fman Ctrl */
+ ASSERT_COND(0);
+ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pendin3); */
+ else
+ p_Fm->fmanCtrlIntr[3].f_Isr(p_Fm->fmanCtrlIntr[3].h_SrcHandle, event);
+ }
+#ifdef FM_MACSEC_SUPPORT
+ if (pending & INTR_EN_MACSEC_MAC0)
+ {
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].guestId)
+ SendIpcIsr(p_Fm, e_FM_EV_MACSEC_MAC0, pending);
+ else
+ p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].h_SrcHandle);
+ }
+#endif /* FM_MACSEC_SUPPORT */
+}
+
+t_Error FM_ErrorIsr(t_Handle h_Fm)
+{
+#define FM_M_CALL_1G_MAC_ERR_ISR(_id) \
+ { \
+ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].guestId) \
+ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id), pending); \
+ else \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\
+ }
+#define FM_M_CALL_10G_MAC_ERR_ISR(_id) \
+ { \
+ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].guestId) \
+ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id), pending); \
+ else \
+ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\
+ }
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t pending;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+
+ /* error interrupts */
+ pending = fman_get_fpm_error_interrupts(fpm_rg);
+ if (!pending)
+ return ERROR_CODE(E_EMPTY);
+
+ if (pending & ERR_INTR_EN_BMI)
+ BmiErrEvent(p_Fm);
+ if (pending & ERR_INTR_EN_QMI)
+ QmiErrEvent(p_Fm);
+ if (pending & ERR_INTR_EN_FPM)
+ FpmErrEvent(p_Fm);
+ if (pending & ERR_INTR_EN_DMA)
+ DmaErrEvent(p_Fm);
+ if (pending & ERR_INTR_EN_IRAM)
+ IramErrIntr(p_Fm);
+ if (pending & ERR_INTR_EN_MURAM)
+ MuramErrIntr(p_Fm);
+ if (pending & ERR_INTR_EN_PRS)
+ p_Fm->intrMng[e_FM_EV_ERR_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PRS].h_SrcHandle);
+ if (pending & ERR_INTR_EN_PLCR)
+ p_Fm->intrMng[e_FM_EV_ERR_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PLCR].h_SrcHandle);
+ if (pending & ERR_INTR_EN_KG)
+ p_Fm->intrMng[e_FM_EV_ERR_KG].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_KG].h_SrcHandle);
+
+ /* MAC events may belong to different partitions */
+ if (pending & ERR_INTR_EN_1G_MAC0)
+ FM_M_CALL_1G_MAC_ERR_ISR(0);
+ if (pending & ERR_INTR_EN_1G_MAC1)
+ FM_M_CALL_1G_MAC_ERR_ISR(1);
+ if (pending & ERR_INTR_EN_1G_MAC2)
+ FM_M_CALL_1G_MAC_ERR_ISR(2);
+ if (pending & ERR_INTR_EN_1G_MAC3)
+ FM_M_CALL_1G_MAC_ERR_ISR(3);
+ if (pending & ERR_INTR_EN_1G_MAC4)
+ FM_M_CALL_1G_MAC_ERR_ISR(4);
+ if (pending & ERR_INTR_EN_1G_MAC5)
+ FM_M_CALL_1G_MAC_ERR_ISR(5);
+ if (pending & ERR_INTR_EN_1G_MAC6)
+ FM_M_CALL_1G_MAC_ERR_ISR(6);
+ if (pending & ERR_INTR_EN_1G_MAC7)
+ FM_M_CALL_1G_MAC_ERR_ISR(7);
+ if (pending & ERR_INTR_EN_10G_MAC0)
+ FM_M_CALL_10G_MAC_ERR_ISR(0);
+ if (pending & ERR_INTR_EN_10G_MAC1)
+ FM_M_CALL_10G_MAC_ERR_ISR(1);
+
+#ifdef FM_MACSEC_SUPPORT
+ if (pending & ERR_INTR_EN_MACSEC_MAC0)
+ {
+ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].guestId)
+ SendIpcIsr(p_Fm, e_FM_EV_ERR_MACSEC_MAC0, pending);
+ else
+ p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].h_SrcHandle);
+ }
+#endif /* FM_MACSEC_SUPPORT */
+
+ return E_OK;
+}
+
+t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ int i;
+ uint8_t sum;
+ uint8_t hardwarePortId;
+ uint8_t weights[64];
+ uint8_t weight, maxPercent = 0;
+ struct fman_bmi_regs *bmi_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ bmi_rg = p_Fm->p_FmBmiRegs;
+
+ memset(weights, 0, (sizeof(uint8_t) * 64));
+
+ /* check that all ports add up to 100% */
+ sum = 0;
+ for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
+ sum +=p_PortsBandwidth->portsBandwidths[i].bandwidth;
+ if (sum != 100)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Sum of ports bandwidth differ from 100%"));
+
+ /* find highest percent */
+ for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
+ {
+ if (p_PortsBandwidth->portsBandwidths[i].bandwidth > maxPercent)
+ maxPercent = p_PortsBandwidth->portsBandwidths[i].bandwidth;
+ }
+
+ ASSERT_COND(maxPercent > 0); /* guaranteed by sum = 100 */
+
+ /* calculate weight for each port */
+ for (i=0; i < p_PortsBandwidth->numOfPorts; i++)
+ {
+ weight = (uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) / maxPercent);
+ /* we want even division between 1-to-PORT_MAX_WEIGHT. so if exact division
+ is not reached, we round up so that:
+ 0 until maxPercent/PORT_MAX_WEIGHT get "1"
+ maxPercent/PORT_MAX_WEIGHT+1 until (maxPercent/PORT_MAX_WEIGHT)*2 get "2"
+ ...
+ maxPercent - maxPercent/PORT_MAX_WEIGHT until maxPercent get "PORT_MAX_WEIGHT: */
+ if ((uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) % maxPercent))
+ weight++;
+
+ /* find the location of this port within the register */
+ hardwarePortId =
+ SwPortIdToHwPortId(p_PortsBandwidth->portsBandwidths[i].type,
+ p_PortsBandwidth->portsBandwidths[i].relativePortId,
+ p_Fm->p_FmStateStruct->revInfo.majorRev,
+ p_Fm->p_FmStateStruct->revInfo.minorRev);
+
+ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
+ weights[hardwarePortId] = weight;
+ }
+
+ fman_set_ports_bandwidth(bmi_rg, weights);
+
+ return E_OK;
+}
+
+t_Error FM_EnableRamsEcc(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ t_FmIpcMsg msg;
+ t_Error err;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_ENABLE_RAM_ECC;
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return E_OK;
+ }
+
+ if (!p_Fm->p_FmStateStruct->internalCall)
+ p_Fm->p_FmStateStruct->explicitEnable = TRUE;
+ p_Fm->p_FmStateStruct->internalCall = FALSE;
+
+ if (p_Fm->p_FmStateStruct->ramsEccEnable)
+ return E_OK;
+ else
+ {
+ fman_enable_rams_ecc(fpm_rg);
+ p_Fm->p_FmStateStruct->ramsEccEnable = TRUE;
+ }
+
+ return E_OK;
+}
+
+t_Error FM_DisableRamsEcc(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ bool explicitDisable = FALSE;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+
+ if (p_Fm->guestId != NCSW_MASTER_ID)
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msgId = FM_DISABLE_RAM_ECC;
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ NULL,
+ NULL,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ return E_OK;
+ }
+
+ if (!p_Fm->p_FmStateStruct->internalCall)
+ explicitDisable = TRUE;
+ p_Fm->p_FmStateStruct->internalCall = FALSE;
+
+ /* if rams are already disabled, or if rams were explicitly enabled and are
+ currently called indirectly (not explicitly), ignore this call. */
+ if (!p_Fm->p_FmStateStruct->ramsEccEnable ||
+ (p_Fm->p_FmStateStruct->explicitEnable && !explicitDisable))
+ return E_OK;
+ else
+ {
+ if (p_Fm->p_FmStateStruct->explicitEnable)
+ /* This is the case were both explicit are TRUE.
+ Turn off this flag for cases were following ramsEnable
+ routines are called */
+ p_Fm->p_FmStateStruct->explicitEnable = FALSE;
+
+ fman_enable_rams_ecc(fpm_rg);
+ p_Fm->p_FmStateStruct->ramsEccEnable = FALSE;
+ }
+
+ return E_OK;
+}
+
+t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t bitMask = 0;
+ enum fman_exceptions fslException;
+ struct fman_rg fman_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ GET_EXCEPTION_FLAG(bitMask, exception);
+ if (bitMask)
+ {
+ if (enable)
+ p_Fm->p_FmStateStruct->exceptions |= bitMask;
+ else
+ p_Fm->p_FmStateStruct->exceptions &= ~bitMask;
+
+ fslException = FmanExceptionTrans(exception);
+
+ return (t_Error)fman_set_exception(&fman_rg,
+ fslException,
+ enable);
+ }
+ else
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception"));
+
+ return E_OK;
+}
+
+t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ p_FmRevisionInfo->majorRev = p_Fm->p_FmStateStruct->revInfo.majorRev;
+ p_FmRevisionInfo->minorRev = p_Fm->p_FmStateStruct->revInfo.minorRev;
+
+ return E_OK;
+}
+
+t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_FMIramRegs *p_Iram;
+ uint32_t revInfo;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_RevisionInfo, E_NULL_POINTER);
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_Error err;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength;
+ t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_FMAN_CTRL_CODE_REV;
+ replyLength = sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo);
+ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo)))
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_FmCtrlCodeRevisionInfo));
+ p_RevisionInfo->packageRev = ipcRevInfo.packageRev;
+ p_RevisionInfo->majorRev = ipcRevInfo.majorRev;
+ p_RevisionInfo->minorRev = ipcRevInfo.minorRev;
+ return (t_Error)(reply.error);
+ }
+ else if (p_Fm->guestId != NCSW_MASTER_ID)
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("running in guest-mode without IPC!"));
+
+ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM);
+ WRITE_UINT32(p_Iram->iadd, 0x4);
+ while (GET_UINT32(p_Iram->iadd) != 0x4) ;
+ revInfo = GET_UINT32(p_Iram->idata);
+ p_RevisionInfo->packageRev = (uint16_t)((revInfo & 0xFFFF0000) >> 16);
+ p_RevisionInfo->majorRev = (uint8_t)((revInfo & 0x0000FF00) >> 8);
+ p_RevisionInfo->minorRev = (uint8_t)(revInfo & 0x000000FF);
+
+ return E_OK;
+}
+
+uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_Error err;
+ uint32_t counterValue;
+ struct fman_rg fman_rg;
+ enum fman_counters fsl_counter;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ uint32_t replyLength, outCounter;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_GET_COUNTER;
+ memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t));
+ replyLength = sizeof(uint32_t) + sizeof(uint32_t);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId) +sizeof(counterValue),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MAJOR, err, NO_MSG);
+ return 0;
+ }
+ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return 0;
+ }
+
+ memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t));
+ return outCounter;
+ }
+ else if (!p_Fm->baseAddr)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Either IPC or 'baseAddress' is required!"));
+ return 0;
+ }
+
+ /* When applicable (when there is an 'enable counters' bit,
+ check that counters are enabled */
+ switch (counter)
+ {
+ case (e_FM_COUNTERS_DEQ_1):
+ case (e_FM_COUNTERS_DEQ_2):
+ /* fall through */
+ case (e_FM_COUNTERS_DEQ_3):
+ if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) ||
+ (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6))
+ {
+ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested counter not supported"));
+ return 0;
+ }
+ /* fall through */
+ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
+ case (e_FM_COUNTERS_DEQ_0):
+ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
+ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
+ case (e_FM_COUNTERS_DEQ_FROM_FD):
+ /* fall through */
+ case (e_FM_COUNTERS_DEQ_CONFIRM):
+ if (!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Requested counter was not enabled"));
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ FMAN_COUNTERS_TRANS(fsl_counter, counter);
+ return fman_get_counter(&fman_rg, fsl_counter);
+}
+
+t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_rg fman_rg;
+ enum fman_counters fsl_counter;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ FMAN_COUNTERS_TRANS(fsl_counter, counter);
+ return (t_Error)fman_modify_counter(&fman_rg, fsl_counter, val);
+}
+
+void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_dma_regs *dma_rg;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ dma_rg = p_Fm->p_FmDmaRegs;
+
+ fman_set_dma_emergency(dma_rg, !!(muramPort==e_FM_DMA_MURAM_PORT_WRITE), enable);
+}
+
+void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_dma_regs *dma_rg;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ dma_rg = p_Fm->p_FmDmaRegs;
+
+ fman_set_dma_ext_bus_pri(dma_rg, pri);
+}
+
+void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ uint32_t dmaStatus;
+ struct fman_dma_regs *dma_rg;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ dma_rg = p_Fm->p_FmDmaRegs;
+
+ if ((p_Fm->guestId != NCSW_MASTER_ID) &&
+ !p_Fm->baseAddr &&
+ p_Fm->h_IpcSessions[0])
+ {
+ t_FmIpcDmaStatus ipcDmaStatus;
+ t_FmIpcMsg msg;
+ t_FmIpcReply reply;
+ t_Error err;
+ uint32_t replyLength;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&reply, 0, sizeof(reply));
+ msg.msgId = FM_DMA_STAT;
+ replyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus);
+ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0],
+ (uint8_t*)&msg,
+ sizeof(msg.msgId),
+ (uint8_t*)&reply,
+ &replyLength,
+ NULL,
+ NULL);
+ if (err != E_OK)
+ {
+ REPORT_ERROR(MINOR, err, NO_MSG);
+ return;
+ }
+ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus)))
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
+ return;
+ }
+ memcpy((uint8_t*)&ipcDmaStatus, reply.replyBody, sizeof(t_FmIpcDmaStatus));
+
+ p_FmDmaStatus->cmqNotEmpty = (bool)ipcDmaStatus.boolCmqNotEmpty; /**< Command queue is not empty */
+ p_FmDmaStatus->busError = (bool)ipcDmaStatus.boolBusError; /**< Bus error occurred */
+ p_FmDmaStatus->readBufEccError = (bool)ipcDmaStatus.boolReadBufEccError; /**< Double ECC error on buffer Read */
+ p_FmDmaStatus->writeBufEccSysError =(bool)ipcDmaStatus.boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */
+ p_FmDmaStatus->writeBufEccFmError = (bool)ipcDmaStatus.boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */
+ p_FmDmaStatus->singlePortEccError = (bool)ipcDmaStatus.boolSinglePortEccError; /**< Double ECC error on buffer write from FM side */
+ return;
+ }
+ else if (!p_Fm->baseAddr)
+ {
+ REPORT_ERROR(MINOR, E_NOT_SUPPORTED,
+ ("Either IPC or 'baseAddress' is required!"));
+ return;
+ }
+
+ dmaStatus = fman_get_dma_status(dma_rg);
+
+ p_FmDmaStatus->cmqNotEmpty = (bool)(dmaStatus & DMA_STATUS_CMD_QUEUE_NOT_EMPTY);
+ p_FmDmaStatus->busError = (bool)(dmaStatus & DMA_STATUS_BUS_ERR);
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ p_FmDmaStatus->singlePortEccError = (bool)(dmaStatus & DMA_STATUS_FM_SPDAT_ECC);
+ else
+ {
+ p_FmDmaStatus->readBufEccError = (bool)(dmaStatus & DMA_STATUS_READ_ECC);
+ p_FmDmaStatus->writeBufEccSysError = (bool)(dmaStatus & DMA_STATUS_SYSTEM_WRITE_ECC);
+ p_FmDmaStatus->writeBufEccFmError = (bool)(dmaStatus & DMA_STATUS_FM_WRITE_ECC);
+ }
+}
+
+void FM_Resume(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ struct fman_fpm_regs *fpm_rg;
+
+ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ fpm_rg = p_Fm->p_FmFpmRegs;
+
+ fman_resume(fpm_rg);
+}
+
+t_Error FM_GetSpecialOperationCoding(t_Handle h_Fm,
+ fmSpecialOperations_t spOper,
+ uint8_t *p_SpOperCoding)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ t_FmCtrlCodeRevisionInfo revInfo;
+ t_Error err;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR(p_SpOperCoding, E_NULL_POINTER);
+
+ if (!spOper)
+ {
+ *p_SpOperCoding = 0;
+ return E_OK;
+ }
+
+ if ((err = FM_GetFmanCtrlCodeRevision(p_Fm, &revInfo)) != E_OK)
+ {
+ DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision."));
+ revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER;
+ }
+ else if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Fman ctrl code package"));
+
+ switch (spOper)
+ {
+ case (FM_SP_OP_CAPWAP_DTLS_DEC):
+ *p_SpOperCoding = 9;
+ break;
+ case (FM_SP_OP_CAPWAP_DTLS_ENC):
+ *p_SpOperCoding = 10;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP):
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD):
+ *p_SpOperCoding = 5;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP):
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD):
+ *p_SpOperCoding = 6;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_RPD):
+ *p_SpOperCoding = 3;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN):
+ *p_SpOperCoding = 1;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_NO_ETH_HDR):
+ *p_SpOperCoding = 12;
+ break;
+ case (FM_SP_OP_IPSEC|FM_SP_OP_RPD):
+ *p_SpOperCoding = 4;
+ break;
+ case (FM_SP_OP_IPSEC):
+ *p_SpOperCoding = 2;
+ break;
+ case (FM_SP_OP_DCL4C):
+ *p_SpOperCoding = 7;
+ break;
+ case (FM_SP_OP_CLEAR_RPD):
+ *p_SpOperCoding = 8;
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+ }
+
+ return E_OK;
+}
+
+t_Error FM_CtrlMonStart(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_FmTrbRegs *p_MonRegs;
+ uint8_t i;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc,
+ GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_RDBG);
+
+ for (i = 0; i < FM_NUM_OF_CTRL; i++)
+ {
+ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i));
+
+ /* Reset control registers */
+ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_RESET);
+ WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET);
+
+ /* Configure: counter #1 counts all stalls in risc - ldsched stall
+ counter #2 counts all stalls in risc - other stall*/
+ WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET | TRB_TCRL_UTIL);
+
+ /* Enable monitoring */
+ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_ENABLE_COUNTERS);
+ }
+
+ return E_OK;
+}
+
+t_Error FM_CtrlMonStop(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_FmTrbRegs *p_MonRegs;
+ uint8_t i;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+
+ for (i = 0; i < FM_NUM_OF_CTRL; i++)
+ {
+ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i));
+ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_DISABLE_COUNTERS);
+ }
+
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc,
+ GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_RDBG);
+
+ return E_OK;
+}
+
+t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon)
+{
+ t_Fm *p_Fm = (t_Fm *)h_Fm;
+ t_FmTrbRegs *p_MonRegs;
+ uint64_t clkCnt, utilValue, effValue;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED);
+ SANITY_CHECK_RETURN_ERROR(p_Mon, E_NULL_POINTER);
+
+ if (fmCtrlIndex >= FM_NUM_OF_CTRL)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FM Controller index"));
+
+ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(fmCtrlIndex));
+
+ clkCnt = (uint64_t)
+ ((uint64_t)GET_UINT32(p_MonRegs->tpcch) << 32 | GET_UINT32(p_MonRegs->tpccl));
+
+ utilValue = (uint64_t)
+ ((uint64_t)GET_UINT32(p_MonRegs->tpc1h) << 32 | GET_UINT32(p_MonRegs->tpc1l));
+
+ effValue = (uint64_t)
+ ((uint64_t)GET_UINT32(p_MonRegs->tpc2h) << 32 | GET_UINT32(p_MonRegs->tpc2l));
+
+ p_Mon->percentCnt[0] = (uint8_t)div64_u64((clkCnt - utilValue) * 100, clkCnt);
+ if (clkCnt != utilValue)
+ p_Mon->percentCnt[1] = (uint8_t)div64_u64(((clkCnt - utilValue) - effValue) * 100, clkCnt - utilValue);
+ else
+ p_Mon->percentCnt[1] = 0;
+
+ return E_OK;
+}
+
+t_Handle FM_GetMuramHandle(t_Handle h_Fm)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+
+ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL);
+
+ return (p_Fm->h_FmMuram);
+}
+
+/****************************************************/
+/* Hidden-DEBUG Only API */
+/****************************************************/
+t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception)
+{
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ enum fman_exceptions fslException;
+ struct fman_rg fman_rg;
+
+ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE);
+
+ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs;
+ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs;
+ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs;
+ fman_rg.dma_rg = p_Fm->p_FmDmaRegs;
+
+ switch (exception)
+ {
+ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_QMI_SINGLE_ECC:
+ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_SINGLE_ECC not supported on this integration."));
+
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_QMI_DOUBLE_ECC:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_BMI_LIST_RAM_ECC:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_BMI_STORAGE_PROFILE_ECC:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STORAGE_PROFILE_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_BMI_STATISTICS_RAM_ECC:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ case e_FM_EX_BMI_DISPATCH_RAM_ECC:
+ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC))
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked"));
+ break;
+ default:
+ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced"));
+ }
+
+ fslException = FmanExceptionTrans(exception);
+ fman_force_intr (&fman_rg, fslException);
+
+ return E_OK;
+}
+
+t_Handle FmGetPcd(t_Handle h_Fm)
+{
+ return ((t_Fm*)h_Fm)->h_Pcd;
+}
+#if (DPAA_VERSION >= 11)
+extern void *g_MemacRegs;
+void fm_clk_down(void);
+uint32_t fman_memac_get_event(void *regs, uint32_t ev_mask);
+void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId)
+{
+ int macId;
+ uint32_t event, rcr;
+ t_Fm *p_Fm = (t_Fm*)h_Fm;
+ rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr);
+ rcr |= 0x04000000;
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr);
+
+ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId);
+ do
+ {
+ event = fman_memac_get_event(g_MemacRegs, 0xFFFFFFFF);
+ } while ((event & 0x00000020) == 0);
+ fm_clk_down();
+ rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr);
+ rcr &= ~0x04000000;
+ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr);
+}
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h
new file mode 100644
index 000000000000..0bded75dad15
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm.h
+
+ @Description FM internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_H
+#define __FM_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_ext.h"
+#include "fm_ipc.h"
+
+#include "fsl_fman.h"
+
+#define __ERR_MODULE__ MODULE_FM
+
+#define FM_MAX_NUM_OF_HW_PORT_IDS 64
+#define FM_MAX_NUM_OF_GUESTS 100
+
+/**************************************************************************//**
+ @Description Exceptions
+*//***************************************************************************/
+#define FM_EX_DMA_BUS_ERROR 0x80000000 /**< DMA bus error. */
+#define FM_EX_DMA_READ_ECC 0x40000000
+#define FM_EX_DMA_SYSTEM_WRITE_ECC 0x20000000
+#define FM_EX_DMA_FM_WRITE_ECC 0x10000000
+#define FM_EX_FPM_STALL_ON_TASKS 0x08000000 /**< Stall of tasks on FPM */
+#define FM_EX_FPM_SINGLE_ECC 0x04000000 /**< Single ECC on FPM */
+#define FM_EX_FPM_DOUBLE_ECC 0x02000000
+#define FM_EX_QMI_SINGLE_ECC 0x01000000 /**< Single ECC on FPM */
+#define FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000 /**< Dequeu from default queue id */
+#define FM_EX_QMI_DOUBLE_ECC 0x00400000
+#define FM_EX_BMI_LIST_RAM_ECC 0x00200000
+#define FM_EX_BMI_STORAGE_PROFILE_ECC 0x00100000
+#define FM_EX_BMI_STATISTICS_RAM_ECC 0x00080000
+#define FM_EX_IRAM_ECC 0x00040000
+#define FM_EX_MURAM_ECC 0x00020000
+#define FM_EX_BMI_DISPATCH_RAM_ECC 0x00010000
+#define FM_EX_DMA_SINGLE_PORT_ECC 0x00008000
+
+#define DMA_EMSR_EMSTR_MASK 0x0000FFFF
+
+#define DMA_THRESH_COMMQ_MASK 0xFF000000
+#define DMA_THRESH_READ_INT_BUF_MASK 0x007F0000
+#define DMA_THRESH_WRITE_INT_BUF_MASK 0x0000007F
+
+#define GET_EXCEPTION_FLAG(bitMask, exception) \
+switch (exception){ \
+ case e_FM_EX_DMA_BUS_ERROR: \
+ bitMask = FM_EX_DMA_BUS_ERROR; break; \
+ case e_FM_EX_DMA_SINGLE_PORT_ECC: \
+ bitMask = FM_EX_DMA_SINGLE_PORT_ECC; break; \
+ case e_FM_EX_DMA_READ_ECC: \
+ bitMask = FM_EX_DMA_READ_ECC; break; \
+ case e_FM_EX_DMA_SYSTEM_WRITE_ECC: \
+ bitMask = FM_EX_DMA_SYSTEM_WRITE_ECC; break; \
+ case e_FM_EX_DMA_FM_WRITE_ECC: \
+ bitMask = FM_EX_DMA_FM_WRITE_ECC; break; \
+ case e_FM_EX_FPM_STALL_ON_TASKS: \
+ bitMask = FM_EX_FPM_STALL_ON_TASKS; break; \
+ case e_FM_EX_FPM_SINGLE_ECC: \
+ bitMask = FM_EX_FPM_SINGLE_ECC; break; \
+ case e_FM_EX_FPM_DOUBLE_ECC: \
+ bitMask = FM_EX_FPM_DOUBLE_ECC; break; \
+ case e_FM_EX_QMI_SINGLE_ECC: \
+ bitMask = FM_EX_QMI_SINGLE_ECC; break; \
+ case e_FM_EX_QMI_DOUBLE_ECC: \
+ bitMask = FM_EX_QMI_DOUBLE_ECC; break; \
+ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: \
+ bitMask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; break; \
+ case e_FM_EX_BMI_LIST_RAM_ECC: \
+ bitMask = FM_EX_BMI_LIST_RAM_ECC; break; \
+ case e_FM_EX_BMI_STORAGE_PROFILE_ECC: \
+ bitMask = FM_EX_BMI_STORAGE_PROFILE_ECC; break; \
+ case e_FM_EX_BMI_STATISTICS_RAM_ECC: \
+ bitMask = FM_EX_BMI_STATISTICS_RAM_ECC; break; \
+ case e_FM_EX_BMI_DISPATCH_RAM_ECC: \
+ bitMask = FM_EX_BMI_DISPATCH_RAM_ECC; break; \
+ case e_FM_EX_IRAM_ECC: \
+ bitMask = FM_EX_IRAM_ECC; break; \
+ case e_FM_EX_MURAM_ECC: \
+ bitMask = FM_EX_MURAM_ECC; break; \
+ default: bitMask = 0;break; \
+}
+
+#define GET_FM_MODULE_EVENT(_mod, _id, _intrType, _event) \
+ switch (_mod) { \
+ case e_FM_MOD_PRS: \
+ if (_id) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS : e_FM_EV_PRS; \
+ break; \
+ case e_FM_MOD_KG: \
+ if (_id) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG : e_FM_EV_DUMMY_LAST; \
+ break; \
+ case e_FM_MOD_PLCR: \
+ if (_id) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR : e_FM_EV_PLCR; \
+ break; \
+ case e_FM_MOD_TMR: \
+ if (_id) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_TMR; \
+ break; \
+ case e_FM_MOD_10G_MAC: \
+ if (_id >= FM_MAX_NUM_OF_10G_MACS) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_10G_MAC0 + _id) : (e_FM_EV_10G_MAC0 + _id); \
+ break; \
+ case e_FM_MOD_1G_MAC: \
+ if (_id >= FM_MAX_NUM_OF_1G_MACS) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_1G_MAC0 + _id) : (e_FM_EV_1G_MAC0 + _id); \
+ break; \
+ case e_FM_MOD_MACSEC: \
+ switch (_id){ \
+ case (0): _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_MACSEC_MAC0:e_FM_EV_MACSEC_MAC0; \
+ break; \
+ } \
+ break; \
+ case e_FM_MOD_FMAN_CTRL: \
+ if (_intrType == e_FM_INTR_TYPE_ERR) _event = e_FM_EV_DUMMY_LAST; \
+ else _event = (e_FM_EV_FMAN_CTRL_0 + _id); \
+ break; \
+ default: _event = e_FM_EV_DUMMY_LAST; \
+ break; \
+ }
+
+#define FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, _cache_override) \
+ switch (_cache_override){ \
+ case e_FM_DMA_NO_CACHE_OR: \
+ fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \
+ case e_FM_DMA_NO_STASH_DATA: \
+ fsl_cache_override = E_FMAN_DMA_NO_STASH_DATA; break; \
+ case e_FM_DMA_MAY_STASH_DATA: \
+ fsl_cache_override = E_FMAN_DMA_MAY_STASH_DATA; break; \
+ case e_FM_DMA_STASH_DATA: \
+ fsl_cache_override = E_FMAN_DMA_STASH_DATA; break; \
+ default: \
+ fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \
+ }
+
+#define FMAN_AID_MODE_TRANS(fsl_aid_mode, _aid_mode) \
+ switch (_aid_mode){ \
+ case e_FM_DMA_AID_OUT_PORT_ID: \
+ fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \
+ case e_FM_DMA_AID_OUT_TNUM: \
+ fsl_aid_mode = E_FMAN_DMA_AID_OUT_TNUM; break; \
+ default: \
+ fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \
+ }
+
+#define FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, _dma_dbg_cnt) \
+ switch (_dma_dbg_cnt){ \
+ case e_FM_DMA_DBG_NO_CNT: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \
+ case e_FM_DMA_DBG_CNT_DONE: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_DONE; break; \
+ case e_FM_DMA_DBG_CNT_COMM_Q_EM: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_COMM_Q_EM; break; \
+ case e_FM_DMA_DBG_CNT_INT_READ_EM: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_READ_EM; break; \
+ case e_FM_DMA_DBG_CNT_INT_WRITE_EM: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_WRITE_EM ; break; \
+ case e_FM_DMA_DBG_CNT_FPM_WAIT: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_FPM_WAIT ; break; \
+ case e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC ; break; \
+ case e_FM_DMA_DBG_CNT_RAW_WAR_PROT: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT ; break; \
+ default: \
+ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \
+ }
+
+#define FMAN_DMA_EMER_TRANS(fsl_dma_emer, _dma_emer) \
+ switch (_dma_emer){ \
+ case e_FM_DMA_EM_EBS: \
+ fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \
+ case e_FM_DMA_EM_SOS: \
+ fsl_dma_emer = E_FMAN_DMA_EM_SOS; break; \
+ default: \
+ fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \
+ }
+
+#define FMAN_DMA_ERR_TRANS(fsl_dma_err, _dma_err) \
+ switch (_dma_err){ \
+ case e_FM_DMA_ERR_CATASTROPHIC: \
+ fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \
+ case e_FM_DMA_ERR_REPORT: \
+ fsl_dma_err = E_FMAN_DMA_ERR_REPORT; break; \
+ default: \
+ fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \
+ }
+
+#define FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, _catastrophic_err) \
+ switch (_catastrophic_err){ \
+ case e_FM_CATASTROPHIC_ERR_STALL_PORT: \
+ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \
+ case e_FM_CATASTROPHIC_ERR_STALL_TASK: \
+ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_TASK; break; \
+ default: \
+ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \
+ }
+
+#define FMAN_COUNTERS_TRANS(fsl_counters, _counters) \
+ switch (_counters){ \
+ case e_FM_COUNTERS_ENQ_TOTAL_FRAME: \
+ fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \
+ case e_FM_COUNTERS_DEQ_TOTAL_FRAME: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_TOTAL_FRAME; break; \
+ case e_FM_COUNTERS_DEQ_0: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_0; break; \
+ case e_FM_COUNTERS_DEQ_1: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_1; break; \
+ case e_FM_COUNTERS_DEQ_2: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_2; break; \
+ case e_FM_COUNTERS_DEQ_3: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_3; break; \
+ case e_FM_COUNTERS_DEQ_FROM_DEFAULT: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_DEFAULT; break; \
+ case e_FM_COUNTERS_DEQ_FROM_CONTEXT: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_CONTEXT; break; \
+ case e_FM_COUNTERS_DEQ_FROM_FD: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_FD; break; \
+ case e_FM_COUNTERS_DEQ_CONFIRM: \
+ fsl_counters = E_FMAN_COUNTERS_DEQ_CONFIRM; break; \
+ default: \
+ fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \
+ }
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+#define DEFAULT_exceptions (FM_EX_DMA_BUS_ERROR |\
+ FM_EX_DMA_READ_ECC |\
+ FM_EX_DMA_SYSTEM_WRITE_ECC |\
+ FM_EX_DMA_FM_WRITE_ECC |\
+ FM_EX_FPM_STALL_ON_TASKS |\
+ FM_EX_FPM_SINGLE_ECC |\
+ FM_EX_FPM_DOUBLE_ECC |\
+ FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID|\
+ FM_EX_BMI_LIST_RAM_ECC |\
+ FM_EX_BMI_STORAGE_PROFILE_ECC |\
+ FM_EX_BMI_STATISTICS_RAM_ECC |\
+ FM_EX_IRAM_ECC |\
+ FM_EX_MURAM_ECC |\
+ FM_EX_BMI_DISPATCH_RAM_ECC |\
+ FM_EX_QMI_DOUBLE_ECC |\
+ FM_EX_QMI_SINGLE_ECC)
+
+#define DEFAULT_eccEnable FALSE
+#ifdef FM_PEDANTIC_DMA
+#define DEFAULT_aidOverride TRUE
+#else
+#define DEFAULT_aidOverride FALSE
+#endif /* FM_PEDANTIC_DMA */
+#define DEFAULT_aidMode e_FM_DMA_AID_OUT_TNUM
+#define DEFAULT_dmaStopOnBusError FALSE
+#define DEFAULT_stopAtBusError FALSE
+#define DEFAULT_axiDbgNumOfBeats 1
+#define DEFAULT_dmaReadIntBufLow ((DMA_THRESH_MAX_BUF+1)/2)
+#define DEFAULT_dmaReadIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4)
+#define DEFAULT_dmaWriteIntBufLow ((DMA_THRESH_MAX_BUF+1)/2)
+#define DEFAULT_dmaWriteIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4)
+#define DEFAULT_catastrophicErr e_FM_CATASTROPHIC_ERR_STALL_PORT
+#define DEFAULT_dmaErr e_FM_DMA_ERR_CATASTROPHIC
+#define DEFAULT_resetOnInit FALSE
+#define DEFAULT_resetOnInitOverrideCallback NULL
+#define DEFAULT_haltOnExternalActivation FALSE /* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_haltOnUnrecoverableEccError FALSE /* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_externalEccRamsEnable FALSE
+#define DEFAULT_VerifyUcode FALSE
+
+#if (DPAA_VERSION < 11)
+#define DEFAULT_totalFifoSize(major, minor) \
+ (((major == 2) || (major == 5)) ? \
+ (100*KILOBYTE) : ((major == 4) ? \
+ (49*KILOBYTE) : (122*KILOBYTE)))
+#define DEFAULT_totalNumOfTasks(major, minor) \
+ BMI_MAX_NUM_OF_TASKS
+
+#define DEFAULT_dmaCommQLow ((DMA_THRESH_MAX_COMMQ+1)/2)
+#define DEFAULT_dmaCommQHigh ((DMA_THRESH_MAX_COMMQ+1)*3/4)
+#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR
+#define DEFAULT_dmaCamNumOfEntries 32
+#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT
+#define DEFAULT_dmaEnEmergency FALSE
+#define DEFAULT_dmaSosEmergency 0
+#define DEFAULT_dmaWatchdog 0 /* disabled */
+#define DEFAULT_dmaEnEmergencySmoother FALSE
+#define DEFAULT_dmaEmergencySwitchCounter 0
+
+#define DEFAULT_dispLimit 0
+#define DEFAULT_prsDispTh 16
+#define DEFAULT_plcrDispTh 16
+#define DEFAULT_kgDispTh 16
+#define DEFAULT_bmiDispTh 16
+#define DEFAULT_qmiEnqDispTh 16
+#define DEFAULT_qmiDeqDispTh 16
+#define DEFAULT_fmCtl1DispTh 16
+#define DEFAULT_fmCtl2DispTh 16
+
+#else /* (DPAA_VERSION < 11) */
+/* Defaults are registers' reset values */
+#define DEFAULT_totalFifoSize(major, minor) \
+ (((major == 6) && ((minor == 1) || (minor == 4))) ? \
+ (156*KILOBYTE) : (295*KILOBYTE))
+
+/* According to the default value of FMBM_CFG2[TNTSKS] */
+#define DEFAULT_totalNumOfTasks(major, minor) \
+ (((major == 6) && ((minor == 1) || (minor == 4))) ? 59 : 124)
+
+#define DEFAULT_dmaCommQLow 0x2A
+#define DEFAULT_dmaCommQHigh 0x3F
+#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR
+#define DEFAULT_dmaCamNumOfEntries 64
+#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT
+#define DEFAULT_dmaEnEmergency FALSE
+#define DEFAULT_dmaSosEmergency 0
+#define DEFAULT_dmaWatchdog 0 /* disabled */
+#define DEFAULT_dmaEnEmergencySmoother FALSE
+#define DEFAULT_dmaEmergencySwitchCounter 0
+
+#define DEFAULT_dispLimit 0
+#define DEFAULT_prsDispTh 16
+#define DEFAULT_plcrDispTh 16
+#define DEFAULT_kgDispTh 16
+#define DEFAULT_bmiDispTh 16
+#define DEFAULT_qmiEnqDispTh 16
+#define DEFAULT_qmiDeqDispTh 16
+#define DEFAULT_fmCtl1DispTh 16
+#define DEFAULT_fmCtl2DispTh 16
+#endif /* (DPAA_VERSION < 11) */
+
+#define FM_TIMESTAMP_1_USEC_BIT 8
+
+/**************************************************************************//**
+ @Collection Defines used for enabling/disabling FM interrupts
+ @{
+*//***************************************************************************/
+#define ERR_INTR_EN_DMA 0x00010000
+#define ERR_INTR_EN_FPM 0x80000000
+#define ERR_INTR_EN_BMI 0x00800000
+#define ERR_INTR_EN_QMI 0x00400000
+#define ERR_INTR_EN_PRS 0x00200000
+#define ERR_INTR_EN_KG 0x00100000
+#define ERR_INTR_EN_PLCR 0x00080000
+#define ERR_INTR_EN_MURAM 0x00040000
+#define ERR_INTR_EN_IRAM 0x00020000
+#define ERR_INTR_EN_10G_MAC0 0x00008000
+#define ERR_INTR_EN_10G_MAC1 0x00000040
+#define ERR_INTR_EN_1G_MAC0 0x00004000
+#define ERR_INTR_EN_1G_MAC1 0x00002000
+#define ERR_INTR_EN_1G_MAC2 0x00001000
+#define ERR_INTR_EN_1G_MAC3 0x00000800
+#define ERR_INTR_EN_1G_MAC4 0x00000400
+#define ERR_INTR_EN_1G_MAC5 0x00000200
+#define ERR_INTR_EN_1G_MAC6 0x00000100
+#define ERR_INTR_EN_1G_MAC7 0x00000080
+#define ERR_INTR_EN_MACSEC_MAC0 0x00000001
+
+#define INTR_EN_QMI 0x40000000
+#define INTR_EN_PRS 0x20000000
+#define INTR_EN_WAKEUP 0x10000000
+#define INTR_EN_PLCR 0x08000000
+#define INTR_EN_1G_MAC0 0x00080000
+#define INTR_EN_1G_MAC1 0x00040000
+#define INTR_EN_1G_MAC2 0x00020000
+#define INTR_EN_1G_MAC3 0x00010000
+#define INTR_EN_1G_MAC4 0x00000040
+#define INTR_EN_1G_MAC5 0x00000020
+#define INTR_EN_1G_MAC6 0x00000008
+#define INTR_EN_1G_MAC7 0x00000002
+#define INTR_EN_10G_MAC0 0x00200000
+#define INTR_EN_10G_MAC1 0x00100000
+#define INTR_EN_REV0 0x00008000
+#define INTR_EN_REV1 0x00004000
+#define INTR_EN_REV2 0x00002000
+#define INTR_EN_REV3 0x00001000
+#define INTR_EN_BRK 0x00000080
+#define INTR_EN_TMR 0x01000000
+#define INTR_EN_MACSEC_MAC0 0x00000001
+/* @} */
+
+/**************************************************************************//**
+ @Description Memory Mapped Registers
+*//***************************************************************************/
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+typedef struct
+{
+ volatile uint32_t iadd; /**< FM IRAM instruction address register */
+ volatile uint32_t idata; /**< FM IRAM instruction data register */
+ volatile uint32_t itcfg; /**< FM IRAM timing config register */
+ volatile uint32_t iready; /**< FM IRAM ready register */
+ volatile uint32_t res[0x1FFFC];
+} t_FMIramRegs;
+
+/* Trace buffer registers -
+ each FM Controller has its own trace buffer residing at FM_MM_TRB(fmCtrlIndex) offset */
+typedef struct t_FmTrbRegs
+{
+ volatile uint32_t tcrh;
+ volatile uint32_t tcrl;
+ volatile uint32_t tesr;
+ volatile uint32_t tecr0h;
+ volatile uint32_t tecr0l;
+ volatile uint32_t terf0h;
+ volatile uint32_t terf0l;
+ volatile uint32_t tecr1h;
+ volatile uint32_t tecr1l;
+ volatile uint32_t terf1h;
+ volatile uint32_t terf1l;
+ volatile uint32_t tpcch;
+ volatile uint32_t tpccl;
+ volatile uint32_t tpc1h;
+ volatile uint32_t tpc1l;
+ volatile uint32_t tpc2h;
+ volatile uint32_t tpc2l;
+ volatile uint32_t twdimr;
+ volatile uint32_t twicvr;
+ volatile uint32_t tar;
+ volatile uint32_t tdr;
+ volatile uint32_t tsnum1;
+ volatile uint32_t tsnum2;
+ volatile uint32_t tsnum3;
+ volatile uint32_t tsnum4;
+} t_FmTrbRegs;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description General defines
+*//***************************************************************************/
+#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL
+#define FM_FW_DEBUG_INSTRUCTION 0x6ffff805UL
+
+/**************************************************************************//**
+ @Description FPM defines
+*//***************************************************************************/
+/* masks */
+#define FPM_BRKC_RDBG 0x00000200
+#define FPM_BRKC_SLP 0x00000800
+/**************************************************************************//**
+ @Description BMI defines
+*//***************************************************************************/
+/* masks */
+#define BMI_INIT_START 0x80000000
+#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000
+#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000
+#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000
+#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000
+/**************************************************************************//**
+ @Description QMI defines
+*//***************************************************************************/
+/* masks */
+#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000
+#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000
+#define QMI_INTR_EN_SINGLE_ECC 0x80000000
+
+/**************************************************************************//**
+ @Description IRAM defines
+*//***************************************************************************/
+/* masks */
+#define IRAM_IADD_AIE 0x80000000
+#define IRAM_READY 0x80000000
+
+/**************************************************************************//**
+ @Description TRB defines
+*//***************************************************************************/
+/* masks */
+#define TRB_TCRH_RESET 0x04000000
+#define TRB_TCRH_ENABLE_COUNTERS 0x84008000
+#define TRB_TCRH_DISABLE_COUNTERS 0x8400C000
+#define TRB_TCRL_RESET 0x20000000
+#define TRB_TCRL_UTIL 0x00000460
+typedef struct {
+ void (*f_Isr) (t_Handle h_Arg, uint32_t event);
+ t_Handle h_SrcHandle;
+} t_FmanCtrlIntrSrc;
+
+
+typedef void (t_FmanCtrlIsr)( t_Handle h_Fm, uint32_t event);
+
+typedef struct
+{
+/***************************/
+/* Master/Guest parameters */
+/***************************/
+ uint8_t fmId;
+ e_FmPortType portsTypes[FM_MAX_NUM_OF_HW_PORT_IDS];
+ uint16_t fmClkFreq;
+ uint16_t fmMacClkFreq;
+ t_FmRevisionInfo revInfo;
+/**************************/
+/* Master Only parameters */
+/**************************/
+ bool enabledTimeStamp;
+ uint8_t count1MicroBit;
+ uint8_t totalNumOfTasks;
+ uint32_t totalFifoSize;
+ uint8_t maxNumOfOpenDmas;
+ uint8_t accumulatedNumOfTasks;
+ uint32_t accumulatedFifoSize;
+ uint8_t accumulatedNumOfOpenDmas;
+ uint8_t accumulatedNumOfDeqTnums;
+#ifdef FM_LOW_END_RESTRICTION
+ bool lowEndRestriction;
+#endif /* FM_LOW_END_RESTRICTION */
+ uint32_t exceptions;
+ int irq;
+ int errIrq;
+ bool ramsEccEnable;
+ bool explicitEnable;
+ bool internalCall;
+ uint8_t ramsEccOwners;
+ uint32_t extraFifoPoolSize;
+ uint8_t extraTasksPoolSize;
+ uint8_t extraOpenDmasPoolSize;
+#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)
+ uint16_t portMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS];
+ uint16_t macMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS];
+#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */
+ uint16_t portMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS];
+ uint16_t macMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS];
+} t_FmStateStruct;
+
+#if (DPAA_VERSION >= 11)
+typedef struct t_FmMapParam {
+ uint16_t profilesBase;
+ uint16_t numOfProfiles;
+ t_Handle h_FmPort;
+} t_FmMapParam;
+
+typedef struct t_FmAllocMng {
+ bool allocated;
+ uint8_t ownerId; /* guestId for KG in multi-partition only,
+ portId for PLCR in any environment */
+} t_FmAllocMng;
+
+typedef struct t_FmPcdSpEntry {
+ bool valid;
+ t_FmAllocMng profilesMng;
+} t_FmPcdSpEntry;
+
+typedef struct t_FmSp {
+ void *p_FmPcdStoragePrflRegs;
+ t_FmPcdSpEntry profiles[FM_VSP_MAX_NUM_OF_ENTRIES];
+ t_FmMapParam portsMapping[FM_MAX_NUM_OF_PORTS];
+} t_FmSp;
+#endif /* (DPAA_VERSION >= 11) */
+
+typedef struct t_Fm
+{
+/***************************/
+/* Master/Guest parameters */
+/***************************/
+/* locals for recovery */
+ uintptr_t baseAddr;
+
+/* un-needed for recovery */
+ t_Handle h_Pcd;
+ char fmModuleName[MODULE_NAME_SIZE];
+ char fmIpcHandlerModuleName[FM_MAX_NUM_OF_GUESTS][MODULE_NAME_SIZE];
+ t_Handle h_IpcSessions[FM_MAX_NUM_OF_GUESTS];
+ t_FmIntrSrc intrMng[e_FM_EV_DUMMY_LAST]; /* FM exceptions user callback */
+ uint8_t guestId;
+/**************************/
+/* Master Only parameters */
+/**************************/
+/* locals for recovery */
+ struct fman_fpm_regs *p_FmFpmRegs;
+ struct fman_bmi_regs *p_FmBmiRegs;
+ struct fman_qmi_regs *p_FmQmiRegs;
+ struct fman_dma_regs *p_FmDmaRegs;
+ struct fman_regs *p_FmRegs;
+ t_FmExceptionsCallback *f_Exception;
+ t_FmBusErrorCallback *f_BusError;
+ t_Handle h_App; /* Application handle */
+ t_Handle h_Spinlock;
+ bool recoveryMode;
+ t_FmStateStruct *p_FmStateStruct;
+ uint16_t tnumAgingPeriod;
+#if (DPAA_VERSION >= 11)
+ t_FmSp *p_FmSp;
+ uint8_t partNumOfVSPs;
+ uint8_t partVSPBase;
+ uintptr_t vspBaseAddr;
+#endif /* (DPAA_VERSION >= 11) */
+ bool portsPreFetchConfigured[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */
+ bool portsPreFetchValue[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */
+
+/* un-needed for recovery */
+ struct fman_cfg *p_FmDriverParam;
+ t_Handle h_FmMuram;
+ uint64_t fmMuramPhysBaseAddr;
+ bool independentMode;
+ bool hcPortInitialized;
+ uintptr_t camBaseAddr; /* save for freeing */
+ uintptr_t resAddr;
+ uintptr_t fifoBaseAddr; /* save for freeing */
+ t_FmanCtrlIntrSrc fmanCtrlIntr[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; /* FM exceptions user callback */
+ bool usedEventRegs[FM_NUM_OF_FMAN_CTRL_EVENT_REGS];
+ t_FmFirmwareParams firmware;
+ bool fwVerify;
+ bool resetOnInit;
+ t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride;
+ uint32_t userSetExceptions;
+} t_Fm;
+
+
+#endif /* __FM_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h
new file mode 100644
index 000000000000..7ce36a767e25
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_ipc.h
+
+ @Description FM Inter-Partition prototypes, structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_IPC_H
+#define __FM_IPC_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_IPC_grp FM Inter-Partition messaging Unit
+
+ @Description FM Inter-Partition messaging unit API definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description enum for defining MAC types
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description A structure of parameters for specifying a MAC.
+*//***************************************************************************/
+typedef _Packed struct
+{
+ uint8_t id;
+ uint32_t enumType;
+} _PackedType t_FmIpcMacParams;
+
+/**************************************************************************//**
+ @Description A structure of parameters for specifying a MAC.
+*//***************************************************************************/
+typedef _Packed struct
+{
+ t_FmIpcMacParams macParams;
+ uint16_t maxFrameLength;
+} _PackedType t_FmIpcMacMaxFrameParams;
+
+/**************************************************************************//**
+ @Description FM physical Address
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPhysAddr
+{
+ volatile uint8_t high;
+ volatile uint32_t low;
+} _PackedType t_FmIpcPhysAddr;
+
+
+typedef _Packed struct t_FmIpcPortOutInitParams {
+ uint8_t numOfTasks; /**< OUT */
+ uint8_t numOfExtraTasks; /**< OUT */
+ uint8_t numOfOpenDmas; /**< OUT */
+ uint8_t numOfExtraOpenDmas; /**< OUT */
+ uint32_t sizeOfFifo; /**< OUT */
+ uint32_t extraSizeOfFifo; /**< OUT */
+ t_FmIpcPhysAddr ipcPhysAddr; /**< OUT */
+} _PackedType t_FmIpcPortOutInitParams;
+
+/**************************************************************************//**
+ @Description Structure for IPC communication during FM_PORT_Init.
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPortInInitParams {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ uint32_t enumPortType; /**< IN. Port type */
+ uint8_t boolIndependentMode;/**< IN. TRUE if FM Port operates in independent mode */
+ uint16_t liodnOffset; /**< IN. Port's requested resource */
+ uint8_t numOfTasks; /**< IN. Port's requested resource */
+ uint8_t numOfExtraTasks; /**< IN. Port's requested resource */
+ uint8_t numOfOpenDmas; /**< IN. Port's requested resource */
+ uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */
+ uint32_t sizeOfFifo; /**< IN. Port's requested resource */
+ uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */
+ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */
+ uint16_t maxFrameLength; /**< IN. Port's max frame length. */
+ uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1.
+ LIODN base for this port, to be
+ used together with LIODN offset. */
+} _PackedType t_FmIpcPortInInitParams;
+
+
+/**************************************************************************//**
+ @Description Structure for IPC communication between port and FM
+ regarding tasks and open DMA resources management.
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPortRsrcParams {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ uint32_t val; /**< IN. Port's requested resource */
+ uint32_t extra; /**< IN. Port's requested resource */
+ uint8_t boolInitialConfig;
+} _PackedType t_FmIpcPortRsrcParams;
+
+
+/**************************************************************************//**
+ @Description Structure for IPC communication between port and FM
+ regarding tasks and open DMA resources management.
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPortFifoParams {
+ t_FmIpcPortRsrcParams rsrcParams;
+ uint32_t enumPortType;
+ uint8_t boolIndependentMode;
+ uint8_t deqPipelineDepth;
+ uint8_t numOfPools;
+ uint16_t secondLargestBufSize;
+ uint16_t largestBufSize;
+ uint8_t boolInitialConfig;
+} _PackedType t_FmIpcPortFifoParams;
+
+/**************************************************************************//**
+ @Description Structure for port-FM communication during FM_PORT_Free.
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPortFreeParams {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ uint32_t enumPortType; /**< IN. Port type */
+ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */
+} _PackedType t_FmIpcPortFreeParams;
+
+/**************************************************************************//**
+ @Description Structure for defining DMA status
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcDmaStatus {
+ uint8_t boolCmqNotEmpty; /**< Command queue is not empty */
+ uint8_t boolBusError; /**< Bus error occurred */
+ uint8_t boolReadBufEccError; /**< Double ECC error on buffer Read */
+ uint8_t boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */
+ uint8_t boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */
+ uint8_t boolSinglePortEccError; /**< Single port ECC error from FM side */
+} _PackedType t_FmIpcDmaStatus;
+
+typedef _Packed struct t_FmIpcRegisterIntr
+{
+ uint8_t guestId; /* IN */
+ uint32_t event; /* IN */
+} _PackedType t_FmIpcRegisterIntr;
+
+typedef _Packed struct t_FmIpcIsr
+{
+ uint8_t boolErr; /* IN */
+ uint32_t pendingReg; /* IN */
+} _PackedType t_FmIpcIsr;
+
+/**************************************************************************//**
+ @Description structure for returning FM parameters
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcParams {
+ uint16_t fmClkFreq; /**< OUT: FM Clock frequency */
+ uint16_t fmMacClkFreq; /**< OUT: FM MAC clock frequence */
+ uint8_t majorRev; /**< OUT: FM Major revision */
+ uint8_t minorRev; /**< OUT: FM Minor revision */
+} _PackedType t_FmIpcParams;
+
+
+/**************************************************************************//**
+ @Description structure for returning Fman Ctrl Code revision information
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcFmanCtrlCodeRevisionInfo {
+ uint16_t packageRev; /**< OUT: Package revision */
+ uint8_t majorRev; /**< OUT: Major revision */
+ uint8_t minorRev; /**< OUT: Minor revision */
+} _PackedType t_FmIpcFmanCtrlCodeRevisionInfo;
+
+/**************************************************************************//**
+ @Description Structure for defining Fm number of Fman controlers
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcPortNumOfFmanCtrls {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ uint8_t numOfFmanCtrls; /**< IN. Port type */
+ t_FmFmanCtrl orFmanCtrl; /**< IN. fman controller for order restoration*/
+} t_FmIpcPortNumOfFmanCtrls;
+
+/**************************************************************************//**
+ @Description structure for setting Fman contriller events
+*//***************************************************************************/
+typedef _Packed struct t_FmIpcFmanEvents {
+ uint8_t eventRegId; /**< IN: Fman controller event register id */
+ uint32_t enableEvents; /**< IN/OUT: required enabled events mask */
+} _PackedType t_FmIpcFmanEvents;
+
+typedef _Packed struct t_FmIpcResourceAllocParams {
+ uint8_t guestId;
+ uint16_t base;
+ uint16_t num;
+}_PackedType t_FmIpcResourceAllocParams;
+
+typedef _Packed struct t_FmIpcVspSetPortWindow {
+ uint8_t hardwarePortId;
+ uint8_t baseStorageProfile;
+ uint8_t log2NumOfProfiles;
+}_PackedType t_FmIpcVspSetPortWindow;
+
+typedef _Packed struct t_FmIpcSetCongestionGroupPfcPriority {
+ uint32_t congestionGroupId;
+ uint8_t priorityBitMap;
+}_PackedType t_FmIpcSetCongestionGroupPfcPriority;
+
+#define FM_IPC_MAX_REPLY_BODY_SIZE 20
+#define FM_IPC_MAX_REPLY_SIZE (FM_IPC_MAX_REPLY_BODY_SIZE + sizeof(uint32_t))
+#define FM_IPC_MAX_MSG_SIZE 30
+
+typedef _Packed struct t_FmIpcMsg
+{
+ uint32_t msgId;
+ uint8_t msgBody[FM_IPC_MAX_MSG_SIZE];
+} _PackedType t_FmIpcMsg;
+
+typedef _Packed struct t_FmIpcReply
+{
+ uint32_t error;
+ uint8_t replyBody[FM_IPC_MAX_REPLY_BODY_SIZE];
+} _PackedType t_FmIpcReply;
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/***************************************************************************/
+/************************ FRONT-END-TO-BACK-END*****************************/
+/***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_GET_TIMESTAMP_SCALE
+
+ @Description Used by FM front-end.
+
+ @Param[out] uint32_t Pointer
+*//***************************************************************************/
+#define FM_GET_TIMESTAMP_SCALE 1
+
+/**************************************************************************//**
+ @Function FM_GET_COUNTER
+
+ @Description Used by FM front-end.
+
+ @Param[in/out] t_FmIpcGetCounter Pointer
+*//***************************************************************************/
+#define FM_GET_COUNTER 2
+
+/**************************************************************************//**
+ @Function FM_GET_SET_PORT_PARAMS
+
+ @Description Used by FM front-end for the PORT module in order to set and get
+ parameters in/from master FM module on FM PORT initialization time.
+
+ @Param[in/out] t_FmIcPortInitParams Pointer
+*//***************************************************************************/
+#define FM_GET_SET_PORT_PARAMS 4
+
+/**************************************************************************//**
+ @Function FM_FREE_PORT
+
+ @Description Used by FM front-end for the PORT module when a port is freed
+ to free all FM PORT resources.
+
+ @Param[in] uint8_t Pointer
+*//***************************************************************************/
+#define FM_FREE_PORT 5
+
+/**************************************************************************//**
+ @Function FM_RESET_MAC
+
+ @Description Used by front-end for the MAC module to reset the MAC registers
+
+ @Param[in] t_FmIpcMacParams Pointer .
+*//***************************************************************************/
+#define FM_RESET_MAC 6
+
+/**************************************************************************//**
+ @Function FM_RESUME_STALLED_PORT
+
+ @Description Used by FM front-end for the PORT module in order to
+ release a stalled FM Port.
+
+ @Param[in] uint8_t Pointer
+*//***************************************************************************/
+#define FM_RESUME_STALLED_PORT 7
+
+/**************************************************************************//**
+ @Function FM_IS_PORT_STALLED
+
+ @Description Used by FM front-end for the PORT module in order to check whether
+ an FM port is stalled.
+
+ @Param[in/out] t_FmIcPortIsStalled Pointer
+*//***************************************************************************/
+#define FM_IS_PORT_STALLED 8
+
+/**************************************************************************//**
+ @Function FM_GET_PARAMS
+
+ @Description Used by FM front-end for the PORT module in order to dump
+ return FM parameters.
+
+ @Param[in] uint8_t Pointer
+*//***************************************************************************/
+#define FM_GET_PARAMS 10
+
+/**************************************************************************//**
+ @Function FM_REGISTER_INTR
+
+ @Description Used by FM front-end to register an interrupt handler to
+ be called upon interrupt for guest.
+
+ @Param[out] t_FmIpcRegisterIntr Pointer
+*//***************************************************************************/
+#define FM_REGISTER_INTR 11
+
+/**************************************************************************//**
+ @Function FM_DMA_STAT
+
+ @Description Used by FM front-end to read the FM DMA status.
+
+ @Param[out] t_FmIpcDmaStatus Pointer
+*//***************************************************************************/
+#define FM_DMA_STAT 13
+
+/**************************************************************************//**
+ @Function FM_ALLOC_FMAN_CTRL_EVENT_REG
+
+ @Description Used by FM front-end to allocate event register.
+
+ @Param[out] Event register id Pointer
+*//***************************************************************************/
+#define FM_ALLOC_FMAN_CTRL_EVENT_REG 14
+
+/**************************************************************************//**
+ @Function FM_FREE_FMAN_CTRL_EVENT_REG
+
+ @Description Used by FM front-end to free locate event register.
+
+ @Param[in] uint8_t Pointer - Event register id
+*//***************************************************************************/
+#define FM_FREE_FMAN_CTRL_EVENT_REG 15
+
+/**************************************************************************//**
+ @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE
+
+ @Description Used by FM front-end to enable events in the FPM
+ Fman controller event register.
+
+ @Param[in] t_FmIpcFmanEvents Pointer
+*//***************************************************************************/
+#define FM_SET_FMAN_CTRL_EVENTS_ENABLE 16
+
+/**************************************************************************//**
+ @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE
+
+ @Description Used by FM front-end to enable events in the FPM
+ Fman controller event register.
+
+ @Param[in/out] t_FmIpcFmanEvents Pointer
+*//***************************************************************************/
+#define FM_GET_FMAN_CTRL_EVENTS_ENABLE 17
+
+/**************************************************************************//**
+ @Function FM_SET_MAC_MAX_FRAME
+
+ @Description Used by FM front-end to set MAC's MTU/RTU's in
+ back-end.
+
+ @Param[in/out] t_FmIpcMacMaxFrameParams Pointer
+*//***************************************************************************/
+#define FM_SET_MAC_MAX_FRAME 18
+
+/**************************************************************************//**
+ @Function FM_GET_PHYS_MURAM_BASE
+
+ @Description Used by FM front-end in order to get MURAM base address
+
+ @Param[in/out] t_FmIpcPhysAddr Pointer
+*//***************************************************************************/
+#define FM_GET_PHYS_MURAM_BASE 19
+
+/**************************************************************************//**
+ @Function FM_MASTER_IS_ALIVE
+
+ @Description Used by FM front-end in order to verify Master is up
+
+ @Param[in/out] bool
+*//***************************************************************************/
+#define FM_MASTER_IS_ALIVE 20
+
+#define FM_ENABLE_RAM_ECC 21
+#define FM_DISABLE_RAM_ECC 22
+#define FM_SET_NUM_OF_FMAN_CTRL 23
+#define FM_SET_SIZE_OF_FIFO 24
+#define FM_SET_NUM_OF_TASKS 25
+#define FM_SET_NUM_OF_OPEN_DMAS 26
+#define FM_VSP_ALLOC 27
+#define FM_VSP_FREE 28
+#define FM_VSP_SET_PORT_WINDOW 29
+#define FM_GET_FMAN_CTRL_CODE_REV 30
+#define FM_SET_CONG_GRP_PFC_PRIO 31
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+#define FM_10G_TX_ECC_WA 100
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+/***************************************************************************/
+/************************ BACK-END-TO-FRONT-END*****************************/
+/***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_GUEST_ISR
+
+ @Description Used by FM back-end to report an interrupt to the front-end.
+
+ @Param[out] t_FmIpcIsr Pointer
+*//***************************************************************************/
+#define FM_GUEST_ISR 1
+
+
+
+/** @} */ /* end of FM_IPC_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_IPC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c
new file mode 100644
index 000000000000..0bc67cb74b99
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File FM_muram.c
+
+ @Description FM MURAM ...
+*//***************************************************************************/
+#include "error_ext.h"
+#include "std_ext.h"
+#include "mm_ext.h"
+#include "string_ext.h"
+#include "sprint_ext.h"
+#include "fm_muram_ext.h"
+#include "fm_common.h"
+
+#define __ERR_MODULE__ MODULE_FM_MURAM
+
+
+typedef struct
+{
+ t_Handle h_Mem;
+ uintptr_t baseAddr;
+ uint32_t size;
+} t_FmMuram;
+
+
+void FmMuramClear(t_Handle h_FmMuram)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+
+ SANITY_CHECK_RETURN(h_FmMuram, E_INVALID_HANDLE);
+ IOMemSet32(UINT_TO_PTR(p_FmMuram->baseAddr), 0, p_FmMuram->size);
+}
+
+
+t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size)
+{
+ t_Handle h_Mem;
+ t_FmMuram *p_FmMuram;
+
+ if (!baseAddress)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress 0 is not supported"));
+ return NULL;
+ }
+
+ if (baseAddress%4)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress not 4 bytes aligned!"));
+ return NULL;
+ }
+
+ /* Allocate FM MURAM structure */
+ p_FmMuram = (t_FmMuram *) XX_Malloc(sizeof(t_FmMuram));
+ if (!p_FmMuram)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MURAM driver structure"));
+ return NULL;
+ }
+ memset(p_FmMuram, 0, sizeof(t_FmMuram));
+
+
+ if ((MM_Init(&h_Mem, baseAddress, size) != E_OK) || (!h_Mem))
+ {
+ XX_Free(p_FmMuram);
+ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM partition!!!"));
+ return NULL;
+ }
+
+ /* Initialize FM MURAM parameters which will be kept by the driver */
+ p_FmMuram->baseAddr = baseAddress;
+ p_FmMuram->size = size;
+ p_FmMuram->h_Mem = h_Mem;
+
+ return p_FmMuram;
+}
+
+t_Error FM_MURAM_Free(t_Handle h_FmMuram)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+
+ if (p_FmMuram->h_Mem)
+ MM_Free(p_FmMuram->h_Mem);
+
+ XX_Free(h_FmMuram);
+
+ return E_OK;
+}
+
+void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+ uintptr_t addr;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL);
+
+ addr = (uintptr_t)MM_Get(p_FmMuram->h_Mem, size, align ,"FM MURAM");
+
+ if (addr == ILLEGAL_BASE)
+ return NULL;
+
+ return UINT_TO_PTR(addr);
+}
+
+void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+ uintptr_t addr;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL);
+ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL);
+
+ addr = (uintptr_t)MM_GetForce(p_FmMuram->h_Mem, base, size, "FM MURAM");
+
+ if (addr == ILLEGAL_BASE)
+ return NULL;
+
+ return UINT_TO_PTR(addr);
+}
+
+t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+
+ SANITY_CHECK_RETURN_ERROR(h_FmMuram, E_INVALID_HANDLE);
+ SANITY_CHECK_RETURN_ERROR(p_FmMuram->h_Mem, E_INVALID_HANDLE);
+
+ if (MM_Put(p_FmMuram->h_Mem, PTR_TO_UINT(ptr)) == 0)
+ RETURN_ERROR(MINOR, E_INVALID_ADDRESS, ("memory pointer!!!"));
+
+ return E_OK;
+}
+
+uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram)
+{
+ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram;
+
+ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, 0);
+ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, 0);
+
+ return MM_GetFreeMemSize(p_FmMuram->h_Mem);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
new file mode 100755
index 000000000000..76d229342ca9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c
@@ -0,0 +1,1400 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "error_ext.h"
+#include <linux/math64.h>
+#include "fsl_fman.h"
+#include "dpaa_integration_ext.h"
+
+uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&bmi_rg->fmbm_ievr);
+ mask = ioread32be(&bmi_rg->fmbm_ier);
+ event &= mask;
+ /* clear the forced events */
+ force = ioread32be(&bmi_rg->fmbm_ifr);
+ if (force & event)
+ iowrite32be(force & ~event, &bmi_rg->fmbm_ifr);
+ /* clear the acknowledged events */
+ iowrite32be(event, &bmi_rg->fmbm_ievr);
+ return event;
+}
+
+uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&qmi_rg->fmqm_eie);
+ mask = ioread32be(&qmi_rg->fmqm_eien);
+ event &= mask;
+
+ /* clear the forced events */
+ force = ioread32be(&qmi_rg->fmqm_eif);
+ if (force & event)
+ iowrite32be(force & ~event, &qmi_rg->fmqm_eif);
+ /* clear the acknowledged events */
+ iowrite32be(event, &qmi_rg->fmqm_eie);
+ return event;
+}
+
+uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg)
+{
+ return ioread32be(&dma_rg->fmdmtcid);
+}
+
+uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg)
+{
+ uint64_t addr;
+
+ addr = (uint64_t)ioread32be(&dma_rg->fmdmtal);
+ addr |= ((uint64_t)(ioread32be(&dma_rg->fmdmtah)) << 32);
+
+ return addr;
+}
+
+uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg)
+{
+ uint32_t status, mask;
+
+ status = ioread32be(&dma_rg->fmdmsr);
+ mask = ioread32be(&dma_rg->fmdmmr);
+
+ /* clear DMA_STATUS_BUS_ERR if mask has no DMA_MODE_BER */
+ if ((mask & DMA_MODE_BER) != DMA_MODE_BER)
+ status &= ~DMA_STATUS_BUS_ERR;
+
+ /* clear relevant bits if mask has no DMA_MODE_ECC */
+ if ((mask & DMA_MODE_ECC) != DMA_MODE_ECC)
+ status &= ~(DMA_STATUS_FM_SPDAT_ECC |
+ DMA_STATUS_READ_ECC |
+ DMA_STATUS_SYSTEM_WRITE_ECC |
+ DMA_STATUS_FM_WRITE_ECC);
+
+ /* clear set events */
+ iowrite32be(status, &dma_rg->fmdmsr);
+
+ return status;
+}
+
+uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t event;
+
+ event = ioread32be(&fpm_rg->fmfp_ee);
+ /* clear the all occurred events */
+ iowrite32be(event, &fpm_rg->fmfp_ee);
+ return event;
+}
+
+uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t event, mask;
+
+ event = ioread32be(&fpm_rg->fm_rcr);
+ mask = ioread32be(&fpm_rg->fm_rie);
+
+ /* clear MURAM event bit (do not clear IRAM event) */
+ iowrite32be(event & ~FPM_RAM_IRAM_ECC, &fpm_rg->fm_rcr);
+
+ if ((mask & FPM_MURAM_ECC_ERR_EX_EN))
+ return event;
+ else
+ return 0;
+}
+
+uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t event, mask;
+
+ event = ioread32be(&fpm_rg->fm_rcr) ;
+ mask = ioread32be(&fpm_rg->fm_rie);
+ /* clear IRAM event bit (do not clear MURAM event) */
+ iowrite32be(event & ~FPM_RAM_MURAM_ECC,
+ &fpm_rg->fm_rcr);
+
+ if ((mask & FPM_IRAM_ECC_ERR_EX_EN))
+ return event;
+ else
+ return 0;
+}
+
+uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg)
+{
+ uint32_t event, mask, force;
+
+ event = ioread32be(&qmi_rg->fmqm_ie);
+ mask = ioread32be(&qmi_rg->fmqm_ien);
+ event &= mask;
+ /* clear the forced events */
+ force = ioread32be(&qmi_rg->fmqm_if);
+ if (force & event)
+ iowrite32be(force & ~event, &qmi_rg->fmqm_if);
+ /* clear the acknowledged events */
+ iowrite32be(event, &qmi_rg->fmqm_ie);
+ return event;
+}
+
+void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg,
+ uint8_t count1ubit,
+ uint16_t fm_clk_freq)
+{
+ uint32_t tmp;
+ uint64_t frac;
+ uint32_t intgr;
+ uint32_t ts_freq = (uint32_t)(1 << count1ubit); /* in Mhz */
+
+ /* configure timestamp so that bit 8 will count 1 microsecond
+ * Find effective count rate at TIMESTAMP least significant bits:
+ * Effective_Count_Rate = 1MHz x 2^8 = 256MHz
+ * Find frequency ratio between effective count rate and the clock:
+ * Effective_Count_Rate / CLK e.g. for 600 MHz clock:
+ * 256/600 = 0.4266666... */
+
+ intgr = ts_freq / fm_clk_freq;
+ /* we multiply by 2^16 to keep the fraction of the division
+ * we do not div back, since we write this value as a fraction
+ * see spec */
+
+ frac = ((uint64_t)ts_freq << 16) - ((uint64_t)intgr << 16) * fm_clk_freq;
+ /* we check remainder of the division in order to round up if not int */
+ if (do_div(frac, fm_clk_freq))
+ frac++;
+
+ tmp = (intgr << FPM_TS_INT_SHIFT) | (uint16_t)frac;
+ iowrite32be(tmp, &fpm_rg->fmfp_tsc2);
+
+ /* enable timestamp with original clock */
+ iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1);
+}
+
+uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_epi);
+}
+
+
+int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg)
+{
+ int timeout = 100;
+
+ iowrite32be(0x40000000, &fpm_rg->fmfp_extc);
+
+ while ((ioread32be(&fpm_rg->fmfp_extc) & 0x40000000) && --timeout)
+ udelay(10);
+
+ if (!timeout)
+ return -EBUSY;
+ return 0;
+}
+
+void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg,
+ uint8_t event_reg_id,
+ uint32_t enable_events)
+{
+ iowrite32be(enable_events, &fpm_rg->fmfp_cee[event_reg_id]);
+}
+
+uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id)
+{
+ return ioread32be(&fpm_rg->fmfp_cee[event_reg_id]);
+}
+
+void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg,
+ uint8_t port_id,
+ uint8_t num_fman_ctrls,
+ uint32_t or_fman_ctrl)
+{
+ uint32_t tmp = 0;
+
+ tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT);
+ /*TODO - maybe to put CTL# according to another criteria*/
+ if (num_fman_ctrls == 2)
+ tmp = FPM_PRT_FM_CTL2 | FPM_PRT_FM_CTL1;
+ /* order restoration */
+ tmp |= (or_fman_ctrl << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | or_fman_ctrl;
+
+ iowrite32be(tmp, &fpm_rg->fmfp_prc);
+}
+
+void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg,
+ uint8_t port_id,
+ bool independent_mode,
+ bool is_rx_port)
+{
+ uint32_t tmp = 0;
+
+ tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT);
+ if (independent_mode) {
+ if (is_rx_port)
+ tmp |= (FPM_PRT_FM_CTL1 <<
+ FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL1;
+ else
+ tmp |= (FPM_PRT_FM_CTL2 <<
+ FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL2;
+ } else {
+ tmp |= (FPM_PRT_FM_CTL2|FPM_PRT_FM_CTL1);
+
+ /* order restoration */
+ if (port_id % 2)
+ tmp |= (FPM_PRT_FM_CTL1 <<
+ FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
+ else
+ tmp |= (FPM_PRT_FM_CTL2 <<
+ FPM_PRC_ORA_FM_CTL_SEL_SHIFT);
+ }
+ iowrite32be(tmp, &fpm_rg->fmfp_prc);
+}
+
+uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg)
+{
+ return (uint8_t)ioread32be(&qmi_rg->fmqm_gc);
+}
+
+uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg)
+{
+ return (uint8_t)(ioread32be(&qmi_rg->fmqm_gc) >> 8);
+}
+
+void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_ENQ_MASK;
+ tmp_reg |= ((uint32_t)val << 8);
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val)
+{
+ uint32_t tmp_reg;
+
+ tmp_reg = ioread32be(&qmi_rg->fmqm_gc);
+ tmp_reg &= ~QMI_CFG_DEQ_MASK;
+ tmp_reg |= (uint32_t)val;
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc);
+}
+
+void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg)
+{
+ iowrite32be(0, &fpm_rg->fmfp_mxd);
+}
+
+void fman_set_liodn_per_port(struct fman_rg *fman_rg, uint8_t port_id,
+ uint16_t liodn_base,
+ uint16_t liodn_ofst)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return;
+
+ /* set LIODN base for this port */
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmplr[port_id / 2]);
+ if (port_id % 2) {
+ tmp &= ~FM_LIODN_BASE_MASK;
+ tmp |= (uint32_t)liodn_base;
+ } else {
+ tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT);
+ tmp |= (uint32_t)liodn_base << DMA_LIODN_SHIFT;
+ }
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]);
+ iowrite32be((uint32_t)liodn_ofst,
+ &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]);
+}
+
+bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id)
+{
+ return (bool)!!(ioread32be(&fpm_rg->fmfp_ps[port_id]) & FPM_PS_STALLED);
+}
+
+void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id)
+{
+ uint32_t tmp;
+
+ tmp = (uint32_t)((port_id << FPM_PORT_FM_CTL_PORTID_SHIFT) |
+ FPM_PRC_REALSE_STALLED);
+ iowrite32be(tmp, &fpm_rg->fmfp_prc);
+}
+
+int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t mac_id, bool is_10g)
+{
+ uint32_t msk, timeout = 100;
+
+ /* Get the relevant bit mask */
+ if (is_10g) {
+ switch (mac_id) {
+ case(0):
+ msk = FPM_RSTC_10G0_RESET;
+ break;
+ case(1):
+ msk = FPM_RSTC_10G1_RESET;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (mac_id) {
+ case(0):
+ msk = FPM_RSTC_1G0_RESET;
+ break;
+ case(1):
+ msk = FPM_RSTC_1G1_RESET;
+ break;
+ case(2):
+ msk = FPM_RSTC_1G2_RESET;
+ break;
+ case(3):
+ msk = FPM_RSTC_1G3_RESET;
+ break;
+ case(4):
+ msk = FPM_RSTC_1G4_RESET;
+ break;
+ case (5):
+ msk = FPM_RSTC_1G5_RESET;
+ break;
+ case (6):
+ msk = FPM_RSTC_1G6_RESET;
+ break;
+ case (7):
+ msk = FPM_RSTC_1G7_RESET;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* reset */
+ iowrite32be(msk, &fpm_rg->fm_rstc);
+ while ((ioread32be(&fpm_rg->fm_rstc) & msk) && --timeout)
+ udelay(10);
+
+ if (!timeout)
+ return -EBUSY;
+ return 0;
+}
+
+uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
+{
+ uint32_t tmp_reg;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]);
+ return (uint16_t)((tmp_reg & BMI_FIFO_SIZE_MASK) + 1);
+}
+
+uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg)
+{
+ uint32_t reg, res;
+
+ reg = ioread32be(&bmi_rg->fmbm_cfg1);
+ res = (reg >> BMI_CFG1_FIFO_SIZE_SHIFT) & 0x3ff;
+ return res * FMAN_BMI_FIFO_UNITS;
+}
+
+uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id)
+{
+ uint32_t tmp_reg;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id-1]);
+ return (uint16_t)((tmp_reg & BMI_EXTRA_FIFO_SIZE_MASK) >>
+ BMI_EXTRA_FIFO_SIZE_SHIFT);
+}
+
+void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint32_t sz_fifo,
+ uint32_t extra_sz_fifo)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return;
+
+ /* calculate reg */
+ tmp = (uint32_t)((sz_fifo / FMAN_BMI_FIFO_UNITS - 1) |
+ ((extra_sz_fifo / FMAN_BMI_FIFO_UNITS) <<
+ BMI_EXTRA_FIFO_SIZE_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pfs[port_id - 1]);
+}
+
+uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >>
+ BMI_NUM_OF_TASKS_SHIFT) + 1);
+}
+
+uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >>
+ BMI_EXTRA_NUM_OF_TASKS_SHIFT);
+}
+
+void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_tasks,
+ uint8_t num_extra_tasks)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return;
+
+ /* calculate reg */
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
+ ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK);
+ tmp |= (uint32_t)(((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) |
+ (num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
+}
+
+uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)(((tmp & BMI_NUM_OF_DMAS_MASK) >>
+ BMI_NUM_OF_DMAS_SHIFT) + 1);
+}
+
+uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id)
+{
+ uint32_t tmp;
+
+ if ((port_id > 63) || (port_id < 1))
+ return 0;
+
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]);
+ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_DMAS_MASK) >>
+ BMI_EXTRA_NUM_OF_DMAS_SHIFT);
+}
+
+void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_open_dmas,
+ uint8_t num_extra_open_dmas,
+ uint8_t total_num_dmas)
+{
+ uint32_t tmp = 0;
+
+ if ((port_id > 63) || (port_id < 1))
+ return;
+
+ /* calculate reg */
+ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) &
+ ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK);
+ tmp |= (uint32_t)(((num_open_dmas-1) << BMI_NUM_OF_DMAS_SHIFT) |
+ (num_extra_open_dmas << BMI_EXTRA_NUM_OF_DMAS_SHIFT));
+ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]);
+
+ /* update total num of DMA's with committed number of open DMAS,
+ * and max uncommitted pool. */
+ if (total_num_dmas)
+ {
+ tmp = ioread32be(&bmi_rg->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK;
+ tmp |= (uint32_t)(total_num_dmas - 1) << BMI_CFG2_DMAS_SHIFT;
+ iowrite32be(tmp, &bmi_rg->fmbm_cfg2);
+ }
+}
+
+void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t base_storage_profile,
+ uint8_t log2_num_of_profiles)
+{
+ uint32_t tmp = 0;
+ if ((port_id > 63) || (port_id < 1))
+ return;
+
+ tmp = ioread32be(&bmi_rg->fmbm_spliodn[port_id-1]);
+ tmp |= (uint32_t)((uint32_t)base_storage_profile & 0x3f) << 16;
+ tmp |= (uint32_t)log2_num_of_profiles << 28;
+ iowrite32be(tmp, &bmi_rg->fmbm_spliodn[port_id-1]);
+}
+
+void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg,
+ uint32_t congestion_group_id,
+ uint8_t priority_bit_map,
+ uint32_t reg_num)
+{
+ uint32_t offset, tmp = 0;
+
+ offset = (congestion_group_id%4)*8;
+
+ tmp = ioread32be(&cpg_rg[reg_num]);
+ tmp &= ~(0xFF<<offset);
+ tmp |= (uint32_t)priority_bit_map << offset;
+
+ iowrite32be(tmp,&cpg_rg[reg_num]);
+}
+
+/*****************************************************************************/
+/* API Init unit functions */
+/*****************************************************************************/
+void fman_defconfig(struct fman_cfg *cfg, bool is_master)
+{
+ memset(cfg, 0, sizeof(struct fman_cfg));
+
+ cfg->catastrophic_err = DEFAULT_CATASTROPHIC_ERR;
+ cfg->dma_err = DEFAULT_DMA_ERR;
+ cfg->halt_on_external_activ = DEFAULT_HALT_ON_EXTERNAL_ACTIVATION;
+ cfg->halt_on_unrecov_ecc_err = DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR;
+ cfg->en_iram_test_mode = FALSE;
+ cfg->en_muram_test_mode = FALSE;
+ cfg->external_ecc_rams_enable = DEFAULT_EXTERNAL_ECC_RAMS_ENABLE;
+
+ if (!is_master)
+ return;
+
+ cfg->dma_aid_override = DEFAULT_AID_OVERRIDE;
+ cfg->dma_aid_mode = DEFAULT_AID_MODE;
+ cfg->dma_comm_qtsh_clr_emer = DEFAULT_DMA_COMM_Q_LOW;
+ cfg->dma_comm_qtsh_asrt_emer = DEFAULT_DMA_COMM_Q_HIGH;
+ cfg->dma_cache_override = DEFAULT_CACHE_OVERRIDE;
+ cfg->dma_cam_num_of_entries = DEFAULT_DMA_CAM_NUM_OF_ENTRIES;
+ cfg->dma_dbg_cnt_mode = DEFAULT_DMA_DBG_CNT_MODE;
+ cfg->dma_en_emergency = DEFAULT_DMA_EN_EMERGENCY;
+ cfg->dma_sos_emergency = DEFAULT_DMA_SOS_EMERGENCY;
+ cfg->dma_watchdog = DEFAULT_DMA_WATCHDOG;
+ cfg->dma_en_emergency_smoother = DEFAULT_DMA_EN_EMERGENCY_SMOOTHER;
+ cfg->dma_emergency_switch_counter = DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER;
+ cfg->disp_limit_tsh = DEFAULT_DISP_LIMIT;
+ cfg->prs_disp_tsh = DEFAULT_PRS_DISP_TH;
+ cfg->plcr_disp_tsh = DEFAULT_PLCR_DISP_TH;
+ cfg->kg_disp_tsh = DEFAULT_KG_DISP_TH;
+ cfg->bmi_disp_tsh = DEFAULT_BMI_DISP_TH;
+ cfg->qmi_enq_disp_tsh = DEFAULT_QMI_ENQ_DISP_TH;
+ cfg->qmi_deq_disp_tsh = DEFAULT_QMI_DEQ_DISP_TH;
+ cfg->fm_ctl1_disp_tsh = DEFAULT_FM_CTL1_DISP_TH;
+ cfg->fm_ctl2_disp_tsh = DEFAULT_FM_CTL2_DISP_TH;
+
+ cfg->pedantic_dma = FALSE;
+ cfg->tnum_aging_period = DEFAULT_TNUM_AGING_PERIOD;
+ cfg->dma_stop_on_bus_error = FALSE;
+ cfg->qmi_deq_option_support = FALSE;
+}
+
+void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+
+ /* read the values from the registers as they are initialized by the HW with
+ * the required values.
+ */
+ tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg1);
+ cfg->total_fifo_size =
+ (((tmp_reg & BMI_TOTAL_FIFO_SIZE_MASK) >> BMI_CFG1_FIFO_SIZE_SHIFT) + 1) * FMAN_BMI_FIFO_UNITS;
+
+ tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg2);
+ cfg->total_num_of_tasks =
+ (uint8_t)(((tmp_reg & BMI_TOTAL_NUM_OF_TASKS_MASK) >> BMI_CFG2_TASKS_SHIFT) + 1);
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmtr);
+ cfg->dma_comm_qtsh_asrt_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT);
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmhy);
+ cfg->dma_comm_qtsh_clr_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT);
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmmr);
+ cfg->dma_cache_override = (enum fman_dma_cache_override)((tmp_reg & DMA_MODE_CACHE_OR_MASK) >> DMA_MODE_CACHE_OR_SHIFT);
+ cfg->dma_cam_num_of_entries = (uint8_t)((((tmp_reg & DMA_MODE_CEN_MASK) >> DMA_MODE_CEN_SHIFT) +1)*DMA_CAM_UNITS);
+ cfg->dma_aid_override = (bool)((tmp_reg & DMA_MODE_AID_OR)? TRUE:FALSE);
+ cfg->dma_dbg_cnt_mode = (enum fman_dma_dbg_cnt_mode)((tmp_reg & DMA_MODE_DBG_MASK) >> DMA_MODE_DBG_SHIFT);
+ cfg->dma_en_emergency = (bool)((tmp_reg & DMA_MODE_EB)? TRUE : FALSE);
+
+ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_mxd);
+ cfg->disp_limit_tsh = (uint8_t)((tmp_reg & FPM_DISP_LIMIT_MASK) >> FPM_DISP_LIMIT_SHIFT);
+
+ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist1);
+ cfg->prs_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PRS_MASK ) >> FPM_THR1_PRS_SHIFT);
+ cfg->plcr_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_KG_MASK ) >> FPM_THR1_KG_SHIFT);
+ cfg->kg_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PLCR_MASK ) >> FPM_THR1_PLCR_SHIFT);
+ cfg->bmi_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_BMI_MASK ) >> FPM_THR1_BMI_SHIFT);
+
+ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist2);
+ cfg->qmi_enq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_ENQ_MASK ) >> FPM_THR2_QMI_ENQ_SHIFT);
+ cfg->qmi_deq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_DEQ_MASK ) >> FPM_THR2_QMI_DEQ_SHIFT);
+ cfg->fm_ctl1_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL1_MASK ) >> FPM_THR2_FM_CTL1_SHIFT);
+ cfg->fm_ctl2_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL2_MASK ) >> FPM_THR2_FM_CTL2_SHIFT);
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmsetr);
+ cfg->dma_sos_emergency = tmp_reg;
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmwcr);
+ cfg->dma_watchdog = tmp_reg/cfg->clk_freq;
+
+ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmemsr);
+ cfg->dma_en_emergency_smoother = (bool)((tmp_reg & DMA_EMSR_EMSTR_MASK)? TRUE : FALSE);
+ cfg->dma_emergency_switch_counter = (tmp_reg & DMA_EMSR_EMSTR_MASK);
+}
+
+void fman_reset(struct fman_fpm_regs *fpm_rg)
+{
+ iowrite32be(FPM_RSTC_FM_RESET, &fpm_rg->fm_rstc);
+}
+
+/**************************************************************************//**
+ @Function FM_Init
+
+ @Description Initializes the FM module
+
+ @Param[in] h_Fm - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+
+ /**********************/
+ /* Init DMA Registers */
+ /**********************/
+ /* clear status reg events */
+ /* oren - check!!! */
+ tmp_reg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC |
+ DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC);
+ iowrite32be(ioread32be(&dma_rg->fmdmsr) | tmp_reg,
+ &dma_rg->fmdmsr);
+
+ /* configure mode register */
+ tmp_reg = 0;
+ tmp_reg |= cfg->dma_cache_override << DMA_MODE_CACHE_OR_SHIFT;
+ if (cfg->dma_aid_override)
+ tmp_reg |= DMA_MODE_AID_OR;
+ if (cfg->exceptions & FMAN_EX_DMA_BUS_ERROR)
+ tmp_reg |= DMA_MODE_BER;
+ if ((cfg->exceptions & FMAN_EX_DMA_SYSTEM_WRITE_ECC) |
+ (cfg->exceptions & FMAN_EX_DMA_READ_ECC) |
+ (cfg->exceptions & FMAN_EX_DMA_FM_WRITE_ECC))
+ tmp_reg |= DMA_MODE_ECC;
+ if (cfg->dma_stop_on_bus_error)
+ tmp_reg |= DMA_MODE_SBER;
+ if(cfg->dma_axi_dbg_num_of_beats)
+ tmp_reg |= (uint32_t)(DMA_MODE_AXI_DBG_MASK &
+ ((cfg->dma_axi_dbg_num_of_beats - 1) << DMA_MODE_AXI_DBG_SHIFT));
+
+ if (cfg->dma_en_emergency) {
+ tmp_reg |= cfg->dma_emergency_bus_select;
+ tmp_reg |= cfg->dma_emergency_level << DMA_MODE_EMER_LVL_SHIFT;
+ if (cfg->dma_en_emergency_smoother)
+ iowrite32be(cfg->dma_emergency_switch_counter,
+ &dma_rg->fmdmemsr);
+ }
+ tmp_reg |= ((cfg->dma_cam_num_of_entries / DMA_CAM_UNITS) - 1) <<
+ DMA_MODE_CEN_SHIFT;
+ tmp_reg |= DMA_MODE_SECURE_PROT;
+ tmp_reg |= cfg->dma_dbg_cnt_mode << DMA_MODE_DBG_SHIFT;
+ tmp_reg |= cfg->dma_aid_mode << DMA_MODE_AID_MODE_SHIFT;
+
+ if (cfg->pedantic_dma)
+ tmp_reg |= DMA_MODE_EMER_READ;
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmmr);
+
+ /* configure thresholds register */
+ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_asrt_emer <<
+ DMA_THRESH_COMMQ_SHIFT) |
+ ((uint32_t)cfg->dma_read_buf_tsh_asrt_emer <<
+ DMA_THRESH_READ_INT_BUF_SHIFT) |
+ ((uint32_t)cfg->dma_write_buf_tsh_asrt_emer);
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmtr);
+
+ /* configure hysteresis register */
+ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_clr_emer <<
+ DMA_THRESH_COMMQ_SHIFT) |
+ ((uint32_t)cfg->dma_read_buf_tsh_clr_emer <<
+ DMA_THRESH_READ_INT_BUF_SHIFT) |
+ ((uint32_t)cfg->dma_write_buf_tsh_clr_emer);
+
+ iowrite32be(tmp_reg, &dma_rg->fmdmhy);
+
+ /* configure emergency threshold */
+ iowrite32be(cfg->dma_sos_emergency, &dma_rg->fmdmsetr);
+
+ /* configure Watchdog */
+ iowrite32be((cfg->dma_watchdog * cfg->clk_freq),
+ &dma_rg->fmdmwcr);
+
+ iowrite32be(cfg->cam_base_addr, &dma_rg->fmdmebcr);
+
+ return 0;
+}
+
+int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+ int i;
+
+ /**********************/
+ /* Init FPM Registers */
+ /**********************/
+ tmp_reg = (uint32_t)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT);
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd);
+
+ tmp_reg = (((uint32_t)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) |
+ ((uint32_t)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) |
+ ((uint32_t)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) |
+ ((uint32_t)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT));
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1);
+
+ tmp_reg = (((uint32_t)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) |
+ ((uint32_t)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) |
+ ((uint32_t)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) |
+ ((uint32_t)cfg->fm_ctl2_disp_tsh << FPM_THR2_FM_CTL2_SHIFT));
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist2);
+
+ /* define exceptions and error behavior */
+ tmp_reg = 0;
+ /* Clear events */
+ tmp_reg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC |
+ FPM_EV_MASK_SINGLE_ECC);
+ /* enable interrupts */
+ if (cfg->exceptions & FMAN_EX_FPM_STALL_ON_TASKS)
+ tmp_reg |= FPM_EV_MASK_STALL_EN;
+ if (cfg->exceptions & FMAN_EX_FPM_SINGLE_ECC)
+ tmp_reg |= FPM_EV_MASK_SINGLE_ECC_EN;
+ if (cfg->exceptions & FMAN_EX_FPM_DOUBLE_ECC)
+ tmp_reg |= FPM_EV_MASK_DOUBLE_ECC_EN;
+ tmp_reg |= (cfg->catastrophic_err << FPM_EV_MASK_CAT_ERR_SHIFT);
+ tmp_reg |= (cfg->dma_err << FPM_EV_MASK_DMA_ERR_SHIFT);
+ if (!cfg->halt_on_external_activ)
+ tmp_reg |= FPM_EV_MASK_EXTERNAL_HALT;
+ if (!cfg->halt_on_unrecov_ecc_err)
+ tmp_reg |= FPM_EV_MASK_ECC_ERR_HALT;
+ iowrite32be(tmp_reg, &fpm_rg->fmfp_ee);
+
+ /* clear all fmCtls event registers */
+ for (i = 0; i < cfg->num_of_fman_ctrl_evnt_regs; i++)
+ iowrite32be(0xFFFFFFFF, &fpm_rg->fmfp_cev[i]);
+
+ /* RAM ECC - enable and clear events*/
+ /* first we need to clear all parser memory,
+ * as it is uninitialized and may cause ECC errors */
+ /* event bits */
+ tmp_reg = (FPM_RAM_MURAM_ECC | FPM_RAM_IRAM_ECC);
+ /* Rams enable not effected by RCR bit, but by a COP configuration */
+ if (cfg->external_ecc_rams_enable)
+ tmp_reg |= FPM_RAM_RAMS_ECC_EN_SRC_SEL;
+
+ /* enable test mode */
+ if (cfg->en_muram_test_mode)
+ tmp_reg |= FPM_RAM_MURAM_TEST_ECC;
+ if (cfg->en_iram_test_mode)
+ tmp_reg |= FPM_RAM_IRAM_TEST_ECC;
+ iowrite32be(tmp_reg, &fpm_rg->fm_rcr);
+
+ tmp_reg = 0;
+ if (cfg->exceptions & FMAN_EX_IRAM_ECC) {
+ tmp_reg |= FPM_IRAM_ECC_ERR_EX_EN;
+ fman_enable_rams_ecc(fpm_rg);
+ }
+ if (cfg->exceptions & FMAN_EX_NURAM_ECC) {
+ tmp_reg |= FPM_MURAM_ECC_ERR_EX_EN;
+ fman_enable_rams_ecc(fpm_rg);
+ }
+ iowrite32be(tmp_reg, &fpm_rg->fm_rie);
+
+ return 0;
+}
+
+int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+
+ /**********************/
+ /* Init BMI Registers */
+ /**********************/
+
+ /* define common resources */
+ tmp_reg = cfg->fifo_base_addr;
+ tmp_reg = tmp_reg / BMI_FIFO_ALIGN;
+
+ tmp_reg |= ((cfg->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) <<
+ BMI_CFG1_FIFO_SIZE_SHIFT);
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg1);
+
+ tmp_reg = ((uint32_t)(cfg->total_num_of_tasks - 1) <<
+ BMI_CFG2_TASKS_SHIFT);
+ /* num of DMA's will be dynamically updated when each port is set */
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg2);
+
+ /* define unmaskable exceptions, enable and clear events */
+ tmp_reg = 0;
+ iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC |
+ BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC |
+ BMI_ERR_INTR_EN_STATISTICS_RAM_ECC |
+ BMI_ERR_INTR_EN_DISPATCH_RAM_ECC,
+ &bmi_rg->fmbm_ievr);
+
+ if (cfg->exceptions & FMAN_EX_BMI_LIST_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_PIPELINE_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_STATISTICS_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ if (cfg->exceptions & FMAN_EX_BMI_DISPATCH_RAM_ECC)
+ tmp_reg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ iowrite32be(tmp_reg, &bmi_rg->fmbm_ier);
+
+ return 0;
+}
+
+int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg)
+{
+ uint32_t tmp_reg;
+ uint16_t period_in_fm_clocks;
+ uint8_t remainder;
+ /**********************/
+ /* Init QMI Registers */
+ /**********************/
+ /* Clear error interrupt events */
+
+ iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF,
+ &qmi_rg->fmqm_eie);
+ tmp_reg = 0;
+ if (cfg->exceptions & FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)
+ tmp_reg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ if (cfg->exceptions & FMAN_EX_QMI_DOUBLE_ECC)
+ tmp_reg |= QMI_ERR_INTR_EN_DOUBLE_ECC;
+ /* enable events */
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_eien);
+
+ if (cfg->tnum_aging_period) {
+ /* tnum_aging_period is in units of usec, p_FmClockFreq in Mhz */
+ period_in_fm_clocks = (uint16_t)
+ (cfg->tnum_aging_period * cfg->clk_freq);
+ /* period_in_fm_clocks must be a 64 multiply */
+ remainder = (uint8_t)(period_in_fm_clocks % 64);
+ if (remainder)
+ tmp_reg = (uint32_t)((period_in_fm_clocks / 64) + 1);
+ else{
+ tmp_reg = (uint32_t)(period_in_fm_clocks / 64);
+ if (!tmp_reg)
+ tmp_reg = 1;
+ }
+ tmp_reg <<= QMI_TAPC_TAP;
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_tapc);
+ }
+ tmp_reg = 0;
+ /* Clear interrupt events */
+ iowrite32be(QMI_INTR_EN_SINGLE_ECC, &qmi_rg->fmqm_ie);
+ if (cfg->exceptions & FMAN_EX_QMI_SINGLE_ECC)
+ tmp_reg |= QMI_INTR_EN_SINGLE_ECC;
+ /* enable events */
+ iowrite32be(tmp_reg, &qmi_rg->fmqm_ien);
+
+ return 0;
+}
+
+int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg)
+{
+ uint32_t cfg_reg = 0;
+
+ /**********************/
+ /* Enable all modules */
+ /**********************/
+ /* clear & enable global counters - calculate reg and save for later,
+ because it's the same reg for QMI enable */
+ cfg_reg = QMI_CFG_EN_COUNTERS;
+ if (cfg->qmi_deq_option_support)
+ cfg_reg |= (uint32_t)(((cfg->qmi_def_tnums_thresh) << 8) |
+ (uint32_t)cfg->qmi_def_tnums_thresh);
+
+ iowrite32be(BMI_INIT_START, &fman_rg->bmi_rg->fmbm_init);
+ iowrite32be(cfg_reg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN,
+ &fman_rg->qmi_rg->fmqm_gc);
+
+ return 0;
+}
+
+void fman_free_resources(struct fman_rg *fman_rg)
+{
+ /* disable BMI and QMI */
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_init);
+ iowrite32be(0, &fman_rg->qmi_rg->fmqm_gc);
+
+ /* release BMI resources */
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg2);
+ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg1);
+
+ /* disable ECC */
+ iowrite32be(0, &fman_rg->fpm_rg->fm_rcr);
+}
+
+/****************************************************/
+/* API Run-time Control uint functions */
+/****************************************************/
+uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_npi);
+}
+
+uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg, uint8_t reg_id)
+{
+ uint32_t event;
+
+ event = ioread32be(&fpm_rg->fmfp_fcev[reg_id]) &
+ ioread32be(&fpm_rg->fmfp_cee[reg_id]);
+ iowrite32be(event, &fpm_rg->fmfp_cev[reg_id]);
+
+ return event;
+}
+
+uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg)
+{
+ return ioread32be(&fpm_rg->fm_epi);
+}
+
+void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights)
+{
+ int i;
+ uint8_t shift;
+ uint32_t tmp = 0;
+
+ for (i = 0; i < 64; i++) {
+ if (weights[i] > 1) { /* no need to write 1 since it is 0 */
+ /* Add this port to tmp_reg */
+ /* (each 8 ports result in one register)*/
+ shift = (uint8_t)(32 - 4 * ((i % 8) + 1));
+ tmp |= ((weights[i] - 1) << shift);
+ }
+ if (i % 8 == 7) { /* last in this set */
+ iowrite32be(tmp, &bmi_rg->fmbm_arb[i / 8]);
+ tmp = 0;
+ }
+ }
+}
+
+void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_rcr);
+ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
+ iowrite32be(tmp | FPM_RAM_IRAM_ECC_EN,
+ &fpm_rg->fm_rcr);
+ else
+ iowrite32be(tmp | FPM_RAM_RAMS_ECC_EN |
+ FPM_RAM_IRAM_ECC_EN,
+ &fpm_rg->fm_rcr);
+}
+
+void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_rcr);
+ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL)
+ iowrite32be(tmp & ~FPM_RAM_IRAM_ECC_EN,
+ &fpm_rg->fm_rcr);
+ else
+ iowrite32be(tmp & ~(FPM_RAM_RAMS_ECC_EN | FPM_RAM_IRAM_ECC_EN),
+ &fpm_rg->fm_rcr);
+}
+
+int fman_set_exception(struct fman_rg *fman_rg,
+ enum fman_exceptions exception,
+ bool enable)
+{
+ uint32_t tmp;
+
+ switch (exception) {
+ case(E_FMAN_EX_DMA_BUS_ERROR):
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
+ if (enable)
+ tmp |= DMA_MODE_BER;
+ else
+ tmp &= ~DMA_MODE_BER;
+ /* disable bus error */
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
+ break;
+ case(E_FMAN_EX_DMA_READ_ECC):
+ case(E_FMAN_EX_DMA_SYSTEM_WRITE_ECC):
+ case(E_FMAN_EX_DMA_FM_WRITE_ECC):
+ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr);
+ if (enable)
+ tmp |= DMA_MODE_ECC;
+ else
+ tmp &= ~DMA_MODE_ECC;
+ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr);
+ break;
+ case(E_FMAN_EX_FPM_STALL_ON_TASKS):
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_STALL_EN;
+ else
+ tmp &= ~FPM_EV_MASK_STALL_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case(E_FMAN_EX_FPM_SINGLE_ECC):
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_SINGLE_ECC_EN;
+ else
+ tmp &= ~FPM_EV_MASK_SINGLE_ECC_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case(E_FMAN_EX_FPM_DOUBLE_ECC):
+ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee);
+ if (enable)
+ tmp |= FPM_EV_MASK_DOUBLE_ECC_EN;
+ else
+ tmp &= ~FPM_EV_MASK_DOUBLE_ECC_EN;
+ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee);
+ break;
+ case(E_FMAN_EX_QMI_SINGLE_ECC):
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_ien);
+ if (enable)
+ tmp |= QMI_INTR_EN_SINGLE_ECC;
+ else
+ tmp &= ~QMI_INTR_EN_SINGLE_ECC;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_ien);
+ break;
+ case(E_FMAN_EX_QMI_DOUBLE_ECC):
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
+ if (enable)
+ tmp |= QMI_ERR_INTR_EN_DOUBLE_ECC;
+ else
+ tmp &= ~QMI_ERR_INTR_EN_DOUBLE_ECC;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
+ break;
+ case(E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID):
+ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien);
+ if (enable)
+ tmp |= QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ else
+ tmp &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF;
+ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien);
+ break;
+ case(E_FMAN_EX_BMI_LIST_RAM_ECC):
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case(E_FMAN_EX_BMI_STORAGE_PROFILE_ECC):
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case(E_FMAN_EX_BMI_STATISTICS_RAM_ECC):
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case(E_FMAN_EX_BMI_DISPATCH_RAM_ECC):
+ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier);
+ if (enable)
+ tmp |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ else
+ tmp &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC;
+ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier);
+ break;
+ case(E_FMAN_EX_IRAM_ECC):
+ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
+ if (enable) {
+ /* enable ECC if not enabled */
+ fman_enable_rams_ecc(fman_rg->fpm_rg);
+ /* enable ECC interrupts */
+ tmp |= FPM_IRAM_ECC_ERR_EX_EN;
+ } else {
+ /* ECC mechanism may be disabled,
+ * depending on driver status */
+ fman_disable_rams_ecc(fman_rg->fpm_rg);
+ tmp &= ~FPM_IRAM_ECC_ERR_EX_EN;
+ }
+ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
+ break;
+ case(E_FMAN_EX_MURAM_ECC):
+ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie);
+ if (enable) {
+ /* enable ECC if not enabled */
+ fman_enable_rams_ecc(fman_rg->fpm_rg);
+ /* enable ECC interrupts */
+ tmp |= FPM_MURAM_ECC_ERR_EX_EN;
+ } else {
+ /* ECC mechanism may be disabled,
+ * depending on driver status */
+ fman_disable_rams_ecc(fman_rg->fpm_rg);
+ tmp &= ~FPM_MURAM_ECC_ERR_EX_EN;
+ }
+ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void fman_get_revision(struct fman_fpm_regs *fpm_rg,
+ uint8_t *major,
+ uint8_t *minor)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fm_ip_rev_1);
+ *major = (uint8_t)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT);
+ *minor = (uint8_t)((tmp & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT);
+
+}
+
+uint32_t fman_get_counter(struct fman_rg *fman_rg,
+ enum fman_counters reg_name)
+{
+ uint32_t ret_val;
+
+ switch (reg_name) {
+ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_etfc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dtfc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_0):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc0);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_1):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc1);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_2):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc2);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_3):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc3);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfdc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfcc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_FD):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dffc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_CONFIRM):
+ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dcc);
+ break;
+ default:
+ ret_val = 0;
+ }
+ return ret_val;
+}
+
+int fman_modify_counter(struct fman_rg *fman_rg,
+ enum fman_counters reg_name,
+ uint32_t val)
+{
+ /* When applicable (when there is an 'enable counters' bit,
+ * check that counters are enabled */
+ switch (reg_name) {
+ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
+ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
+ case(E_FMAN_COUNTERS_DEQ_0):
+ case(E_FMAN_COUNTERS_DEQ_1):
+ case(E_FMAN_COUNTERS_DEQ_2):
+ case(E_FMAN_COUNTERS_DEQ_3):
+ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
+ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
+ case(E_FMAN_COUNTERS_DEQ_FROM_FD):
+ case(E_FMAN_COUNTERS_DEQ_CONFIRM):
+ if (!(ioread32be(&fman_rg->qmi_rg->fmqm_gc) &
+ QMI_CFG_EN_COUNTERS))
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ /* Set counter */
+ switch (reg_name) {
+ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_etfc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dtfc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_0):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc0);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_1):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc1);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_2):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc2);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_3):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc3);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfdc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfcc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_FROM_FD):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dffc);
+ break;
+ case(E_FMAN_COUNTERS_DEQ_CONFIRM):
+ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dcc);
+ break;
+ case(E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT):
+ iowrite32be(val, &fman_rg->dma_rg->fmdmsefrc);
+ break;
+ case(E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT):
+ iowrite32be(val, &fman_rg->dma_rg->fmdmsqfrc);
+ break;
+ case(E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT):
+ iowrite32be(val, &fman_rg->dma_rg->fmdmssrc);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void fman_set_dma_emergency(struct fman_dma_regs *dma_rg,
+ bool is_write,
+ bool enable)
+{
+ uint32_t msk;
+
+ msk = (uint32_t)(is_write ? DMA_MODE_EMER_WRITE : DMA_MODE_EMER_READ);
+
+ if (enable)
+ iowrite32be(ioread32be(&dma_rg->fmdmmr) | msk,
+ &dma_rg->fmdmmr);
+ else /* disable */
+ iowrite32be(ioread32be(&dma_rg->fmdmmr) & ~msk,
+ &dma_rg->fmdmmr);
+}
+
+void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&dma_rg->fmdmmr) |
+ (pri << DMA_MODE_BUS_PRI_SHIFT);
+
+ iowrite32be(tmp, &dma_rg->fmdmmr);
+}
+
+uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg)
+{
+ return ioread32be(&dma_rg->fmdmsr);
+}
+
+void fman_force_intr(struct fman_rg *fman_rg,
+ enum fman_exceptions exception)
+{
+ switch (exception) {
+ case E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID:
+ iowrite32be(QMI_ERR_INTR_EN_DEQ_FROM_DEF,
+ &fman_rg->qmi_rg->fmqm_eif);
+ break;
+ case E_FMAN_EX_QMI_SINGLE_ECC:
+ iowrite32be(QMI_INTR_EN_SINGLE_ECC,
+ &fman_rg->qmi_rg->fmqm_if);
+ break;
+ case E_FMAN_EX_QMI_DOUBLE_ECC:
+ iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC,
+ &fman_rg->qmi_rg->fmqm_eif);
+ break;
+ case E_FMAN_EX_BMI_LIST_RAM_ECC:
+ iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC,
+ &fman_rg->bmi_rg->fmbm_ifr);
+ break;
+ case E_FMAN_EX_BMI_STORAGE_PROFILE_ECC:
+ iowrite32be(BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC,
+ &fman_rg->bmi_rg->fmbm_ifr);
+ break;
+ case E_FMAN_EX_BMI_STATISTICS_RAM_ECC:
+ iowrite32be(BMI_ERR_INTR_EN_STATISTICS_RAM_ECC,
+ &fman_rg->bmi_rg->fmbm_ifr);
+ break;
+ case E_FMAN_EX_BMI_DISPATCH_RAM_ECC:
+ iowrite32be(BMI_ERR_INTR_EN_DISPATCH_RAM_ECC,
+ &fman_rg->bmi_rg->fmbm_ifr);
+ break;
+ default:
+ break;
+ }
+}
+
+bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg)
+{
+ return (bool)!!(ioread32be(&qmi_rg->fmqm_gs) & QMI_GS_HALT_NOT_BUSY);
+}
+void fman_resume(struct fman_fpm_regs *fpm_rg)
+{
+ uint32_t tmp;
+
+ tmp = ioread32be(&fpm_rg->fmfp_ee);
+ /* clear tmp_reg event bits in order not to clear standing events */
+ tmp &= ~(FPM_EV_MASK_DOUBLE_ECC |
+ FPM_EV_MASK_STALL |
+ FPM_EV_MASK_SINGLE_ECC);
+ tmp |= FPM_EV_MASK_RELEASE_FM;
+
+ iowrite32be(tmp, &fpm_rg->fmfp_ee);
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h
new file mode 100644
index 000000000000..204840c9df39
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h
@@ -0,0 +1,1214 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_common.h
+
+ @Description FM internal structures and definitions.
+*//***************************************************************************/
+#ifndef __FM_COMMON_H
+#define __FM_COMMON_H
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_ext.h"
+#include "fm_port_ext.h"
+
+
+#define e_FM_PORT_TYPE_OH_HOST_COMMAND e_FM_PORT_TYPE_DUMMY
+
+#define CLS_PLAN_NUM_PER_GRP 8
+
+#define IP_OFFLOAD_PACKAGE_NUMBER 106
+#define CAPWAP_OFFLOAD_PACKAGE_NUMBER 108
+#define IS_OFFLOAD_PACKAGE(num) ((num == IP_OFFLOAD_PACKAGE_NUMBER) || (num == CAPWAP_OFFLOAD_PACKAGE_NUMBER))
+
+
+
+/**************************************************************************//**
+ @Description Modules registers offsets
+*//***************************************************************************/
+#define FM_MM_MURAM 0x00000000
+#define FM_MM_BMI 0x00080000
+#define FM_MM_QMI 0x00080400
+#define FM_MM_PRS 0x000c7000
+#define FM_MM_KG 0x000C1000
+#define FM_MM_DMA 0x000C2000
+#define FM_MM_FPM 0x000C3000
+#define FM_MM_PLCR 0x000C0000
+#define FM_MM_IMEM 0x000C4000
+#define FM_MM_CGP 0x000DB000
+#define FM_MM_TRB(i) (0x000D0200 + 0x400 * (i))
+#if (DPAA_VERSION >= 11)
+#define FM_MM_SP 0x000dc000
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/**************************************************************************//**
+ @Description Enum for inter-module interrupts registration
+*//***************************************************************************/
+typedef enum e_FmEventModules{
+ e_FM_MOD_PRS, /**< Parser event */
+ e_FM_MOD_KG, /**< Keygen event */
+ e_FM_MOD_PLCR, /**< Policer event */
+ e_FM_MOD_10G_MAC, /**< 10G MAC event */
+ e_FM_MOD_1G_MAC, /**< 1G MAC event */
+ e_FM_MOD_TMR, /**< Timer event */
+ e_FM_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */
+ e_FM_MOD_MACSEC,
+ e_FM_MOD_DUMMY_LAST
+} e_FmEventModules;
+
+/**************************************************************************//**
+ @Description Enum for interrupts types
+*//***************************************************************************/
+typedef enum e_FmIntrType {
+ e_FM_INTR_TYPE_ERR,
+ e_FM_INTR_TYPE_NORMAL
+} e_FmIntrType;
+
+/**************************************************************************//**
+ @Description Enum for inter-module interrupts registration
+*//***************************************************************************/
+typedef enum e_FmInterModuleEvent
+{
+ e_FM_EV_PRS = 0, /**< Parser event */
+ e_FM_EV_ERR_PRS, /**< Parser error event */
+ e_FM_EV_KG, /**< Keygen event */
+ e_FM_EV_ERR_KG, /**< Keygen error event */
+ e_FM_EV_PLCR, /**< Policer event */
+ e_FM_EV_ERR_PLCR, /**< Policer error event */
+ e_FM_EV_ERR_10G_MAC0, /**< 10G MAC 0 error event */
+ e_FM_EV_ERR_10G_MAC1, /**< 10G MAC 1 error event */
+ e_FM_EV_ERR_1G_MAC0, /**< 1G MAC 0 error event */
+ e_FM_EV_ERR_1G_MAC1, /**< 1G MAC 1 error event */
+ e_FM_EV_ERR_1G_MAC2, /**< 1G MAC 2 error event */
+ e_FM_EV_ERR_1G_MAC3, /**< 1G MAC 3 error event */
+ e_FM_EV_ERR_1G_MAC4, /**< 1G MAC 4 error event */
+ e_FM_EV_ERR_1G_MAC5, /**< 1G MAC 5 error event */
+ e_FM_EV_ERR_1G_MAC6, /**< 1G MAC 6 error event */
+ e_FM_EV_ERR_1G_MAC7, /**< 1G MAC 7 error event */
+ e_FM_EV_ERR_MACSEC_MAC0,
+ e_FM_EV_TMR, /**< Timer event */
+ e_FM_EV_10G_MAC0, /**< 10G MAC 0 event (Magic packet detection)*/
+ e_FM_EV_10G_MAC1, /**< 10G MAC 1 event (Magic packet detection)*/
+ e_FM_EV_1G_MAC0, /**< 1G MAC 0 event (Magic packet detection)*/
+ e_FM_EV_1G_MAC1, /**< 1G MAC 1 event (Magic packet detection)*/
+ e_FM_EV_1G_MAC2, /**< 1G MAC 2 (Magic packet detection)*/
+ e_FM_EV_1G_MAC3, /**< 1G MAC 3 (Magic packet detection)*/
+ e_FM_EV_1G_MAC4, /**< 1G MAC 4 (Magic packet detection)*/
+ e_FM_EV_1G_MAC5, /**< 1G MAC 5 (Magic packet detection)*/
+ e_FM_EV_1G_MAC6, /**< 1G MAC 6 (Magic packet detection)*/
+ e_FM_EV_1G_MAC7, /**< 1G MAC 7 (Magic packet detection)*/
+ e_FM_EV_MACSEC_MAC0, /**< MACSEC MAC 0 event */
+ e_FM_EV_FMAN_CTRL_0, /**< Fman controller event 0 */
+ e_FM_EV_FMAN_CTRL_1, /**< Fman controller event 1 */
+ e_FM_EV_FMAN_CTRL_2, /**< Fman controller event 2 */
+ e_FM_EV_FMAN_CTRL_3, /**< Fman controller event 3 */
+ e_FM_EV_DUMMY_LAST
+} e_FmInterModuleEvent;
+
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description PCD KG scheme registers
+*//***************************************************************************/
+typedef _Packed struct t_FmPcdPlcrProfileRegs {
+ volatile uint32_t fmpl_pemode; /* 0x090 FMPL_PEMODE - FM Policer Profile Entry Mode*/
+ volatile uint32_t fmpl_pegnia; /* 0x094 FMPL_PEGNIA - FM Policer Profile Entry GREEN Next Invoked Action*/
+ volatile uint32_t fmpl_peynia; /* 0x098 FMPL_PEYNIA - FM Policer Profile Entry YELLOW Next Invoked Action*/
+ volatile uint32_t fmpl_pernia; /* 0x09C FMPL_PERNIA - FM Policer Profile Entry RED Next Invoked Action*/
+ volatile uint32_t fmpl_pecir; /* 0x0A0 FMPL_PECIR - FM Policer Profile Entry Committed Information Rate*/
+ volatile uint32_t fmpl_pecbs; /* 0x0A4 FMPL_PECBS - FM Policer Profile Entry Committed Burst Size*/
+ volatile uint32_t fmpl_pepepir_eir; /* 0x0A8 FMPL_PEPIR_EIR - FM Policer Profile Entry Peak/Excess Information Rate*/
+ volatile uint32_t fmpl_pepbs_ebs; /* 0x0AC FMPL_PEPBS_EBS - FM Policer Profile Entry Peak/Excess Information Rate*/
+ volatile uint32_t fmpl_pelts; /* 0x0B0 FMPL_PELTS - FM Policer Profile Entry Last TimeStamp*/
+ volatile uint32_t fmpl_pects; /* 0x0B4 FMPL_PECTS - FM Policer Profile Entry Committed Token Status*/
+ volatile uint32_t fmpl_pepts_ets; /* 0x0B8 FMPL_PEPTS_ETS - FM Policer Profile Entry Peak/Excess Token Status*/
+ volatile uint32_t fmpl_pegpc; /* 0x0BC FMPL_PEGPC - FM Policer Profile Entry GREEN Packet Counter*/
+ volatile uint32_t fmpl_peypc; /* 0x0C0 FMPL_PEYPC - FM Policer Profile Entry YELLOW Packet Counter*/
+ volatile uint32_t fmpl_perpc; /* 0x0C4 FMPL_PERPC - FM Policer Profile Entry RED Packet Counter */
+ volatile uint32_t fmpl_perypc; /* 0x0C8 FMPL_PERYPC - FM Policer Profile Entry Recolored YELLOW Packet Counter*/
+ volatile uint32_t fmpl_perrpc; /* 0x0CC FMPL_PERRPC - FM Policer Profile Entry Recolored RED Packet Counter*/
+ volatile uint32_t fmpl_res1[12]; /* 0x0D0-0x0FF Reserved */
+} _PackedType t_FmPcdPlcrProfileRegs;
+
+
+typedef _Packed struct t_FmPcdCcCapwapReassmTimeoutParams {
+ volatile uint32_t portIdAndCapwapReassmTbl;
+ volatile uint32_t fqidForTimeOutFrames;
+ volatile uint32_t timeoutRequestTime;
+}_PackedType t_FmPcdCcCapwapReassmTimeoutParams;
+
+/**************************************************************************//**
+ @Description PCD CTRL Parameters Page
+*//***************************************************************************/
+typedef _Packed struct t_FmPcdCtrlParamsPage {
+ volatile uint8_t reserved0[16];
+ volatile uint32_t iprIpv4Nia;
+ volatile uint32_t iprIpv6Nia;
+ volatile uint8_t reserved1[24];
+ volatile uint32_t ipfOptionsCounter;
+ volatile uint8_t reserved2[12];
+ volatile uint32_t misc;
+ volatile uint32_t errorsDiscardMask;
+ volatile uint32_t discardMask;
+ volatile uint8_t reserved3[4];
+ volatile uint32_t postBmiFetchNia;
+ volatile uint8_t reserved4[172];
+} _PackedType t_FmPcdCtrlParamsPage;
+
+
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/*for UNDER_CONSTRUCTION_FM_RMU_USE_SEC its defined in fm_ext.h*/
+typedef uint32_t t_FmFmanCtrl;
+
+#define FPM_PORT_FM_CTL1 0x00000001
+#define FPM_PORT_FM_CTL2 0x00000002
+
+
+
+typedef struct t_FmPcdCcFragScratchPoolCmdParams {
+ uint32_t numOfBuffers;
+ uint8_t bufferPoolId;
+} t_FmPcdCcFragScratchPoolCmdParams;
+
+typedef struct t_FmPcdCcReassmTimeoutParams {
+ bool activate;
+ uint8_t tsbs;
+ uint32_t iprcpt;
+} t_FmPcdCcReassmTimeoutParams;
+
+typedef struct {
+ uint8_t baseEntry;
+ uint16_t numOfClsPlanEntries;
+ uint32_t vectors[FM_PCD_MAX_NUM_OF_CLS_PLANS];
+} t_FmPcdKgInterModuleClsPlanSet;
+
+/**************************************************************************//**
+ @Description Structure for binding a port to keygen schemes.
+*//***************************************************************************/
+typedef struct t_FmPcdKgInterModuleBindPortToSchemes {
+ uint8_t hardwarePortId;
+ uint8_t netEnvId;
+ bool useClsPlan; /**< TRUE if this port uses the clsPlan mechanism */
+ uint8_t numOfSchemes;
+ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES];
+} t_FmPcdKgInterModuleBindPortToSchemes;
+
+typedef struct {
+ uint32_t nextCcNodeInfo;
+ t_List node;
+} t_CcNodeInfo;
+
+typedef struct
+{
+ t_Handle h_CcNode;
+ uint16_t index;
+ t_List node;
+}t_CcNodeInformation;
+#define CC_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInformation, node)
+
+typedef enum e_ModifyState
+{
+ e_MODIFY_STATE_ADD = 0,
+ e_MODIFY_STATE_REMOVE,
+ e_MODIFY_STATE_CHANGE
+} e_ModifyState;
+
+typedef struct
+{
+ t_Handle h_Manip;
+ t_List node;
+}t_ManipInfo;
+#define CC_NEXT_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInfo, node)
+
+typedef struct {
+ uint32_t type;
+ uint8_t prOffset;
+ uint16_t dataOffset;
+ uint8_t internalBufferOffset;
+ uint8_t numOfTasks;
+ uint8_t numOfExtraTasks;
+ uint8_t hardwarePortId;
+ t_FmRevisionInfo revInfo;
+ uint32_t nia;
+ uint32_t discardMask;
+} t_GetCcParams;
+
+typedef struct {
+ uint32_t type;
+ int psoSize;
+ uint32_t nia;
+ t_FmFmanCtrl orFmanCtrl;
+ bool overwrite;
+ uint8_t ofpDpde;
+} t_SetCcParams;
+
+typedef struct {
+ t_GetCcParams getCcParams;
+ t_SetCcParams setCcParams;
+} t_FmPortGetSetCcParams;
+
+typedef struct {
+ uint32_t type;
+ bool sleep;
+} t_FmSetParams;
+
+typedef struct {
+ uint32_t type;
+ uint32_t fmqm_gs;
+ uint32_t fm_npi;
+ uint32_t fm_cld;
+ uint32_t fmfp_extc;
+} t_FmGetParams;
+
+typedef struct {
+ t_FmSetParams setParams;
+ t_FmGetParams getParams;
+} t_FmGetSetParams;
+
+t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params);
+
+static __inline__ bool TRY_LOCK(t_Handle h_Spinlock, volatile bool *p_Flag)
+{
+ uint32_t intFlags;
+ if (h_Spinlock)
+ intFlags = XX_LockIntrSpinlock(h_Spinlock);
+ else
+ intFlags = XX_DisableAllIntr();
+
+ if (*p_Flag)
+ {
+ if (h_Spinlock)
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+ else
+ XX_RestoreAllIntr(intFlags);
+ return FALSE;
+ }
+ *p_Flag = TRUE;
+
+ if (h_Spinlock)
+ XX_UnlockIntrSpinlock(h_Spinlock, intFlags);
+ else
+ XX_RestoreAllIntr(intFlags);
+
+ return TRUE;
+}
+
+#define RELEASE_LOCK(_flag) _flag = FALSE;
+
+/**************************************************************************//**
+ @Collection Defines used for manipulation CC and BMI
+ @{
+*//***************************************************************************/
+#define INTERNAL_CONTEXT_OFFSET 0x80000000
+#define OFFSET_OF_PR 0x40000000
+#define MANIP_EXTRA_SPACE 0x20000000
+#define NUM_OF_TASKS 0x10000000
+#define OFFSET_OF_DATA 0x08000000
+#define HW_PORT_ID 0x04000000
+#define FM_REV 0x02000000
+#define GET_NIA_FPNE 0x01000000
+#define GET_NIA_PNDN 0x00800000
+#define NUM_OF_EXTRA_TASKS 0x00400000
+#define DISCARD_MASK 0x00200000
+
+#define UPDATE_NIA_PNEN 0x80000000
+#define UPDATE_PSO 0x40000000
+#define UPDATE_NIA_PNDN 0x20000000
+#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000
+#define UPDATE_OFP_DPTE 0x08000000
+#define UPDATE_NIA_FENE 0x04000000
+#define UPDATE_NIA_CMNE 0x02000000
+#define UPDATE_NIA_FPNE 0x01000000
+/* @} */
+
+/**************************************************************************//**
+ @Collection Defines used for manipulation CC and CC
+ @{
+*//***************************************************************************/
+#define UPDATE_NIA_ENQ_WITHOUT_DMA 0x80000000
+#define UPDATE_CC_WITH_TREE 0x40000000
+#define UPDATE_CC_WITH_DELETE_TREE 0x20000000
+#define UPDATE_KG_NIA_CC_WA 0x10000000
+#define UPDATE_KG_OPT_MODE 0x08000000
+#define UPDATE_KG_NIA 0x04000000
+#define UPDATE_CC_SHADOW_CLEAR 0x02000000
+/* @} */
+
+#define UPDATE_FPM_BRKC_SLP 0x80000000
+#define UPDATE_FPM_EXTC 0x40000000
+#define UPDATE_FPM_EXTC_CLEAR 0x20000000
+#define GET_FMQM_GS 0x10000000
+#define GET_FM_NPI 0x08000000
+#define GET_FMFP_EXTC 0x04000000
+#define CLEAR_IRAM_READY 0x02000000
+#define UPDATE_FM_CLD 0x01000000
+#define GET_FM_CLD 0x00800000
+#define FM_MAX_NUM_OF_PORTS (FM_MAX_NUM_OF_OH_PORTS + \
+ FM_MAX_NUM_OF_1G_RX_PORTS + \
+ FM_MAX_NUM_OF_10G_RX_PORTS + \
+ FM_MAX_NUM_OF_1G_TX_PORTS + \
+ FM_MAX_NUM_OF_10G_TX_PORTS)
+
+#define MODULE_NAME_SIZE 30
+#define DUMMY_PORT_ID 0
+
+#define FM_LIODN_OFFSET_MASK 0x3FF
+
+/**************************************************************************//**
+ @Description NIA Description
+*//***************************************************************************/
+#define NIA_ENG_MASK 0x007C0000
+#define NIA_AC_MASK 0x0003ffff
+
+#define NIA_ORDER_RESTOR 0x00800000
+#define NIA_ENG_FM_CTL 0x00000000
+#define NIA_ENG_PRS 0x00440000
+#define NIA_ENG_KG 0x00480000
+#define NIA_ENG_PLCR 0x004C0000
+#define NIA_ENG_BMI 0x00500000
+#define NIA_ENG_QMI_ENQ 0x00540000
+#define NIA_ENG_QMI_DEQ 0x00580000
+
+#define NIA_FM_CTL_AC_CC 0x00000006
+#define NIA_FM_CTL_AC_HC 0x0000000C
+#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008
+#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A
+#define NIA_FM_CTL_AC_POP_TO_N_STEP 0x0000000e
+#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER 0x00000010
+#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME 0x00000018
+#define NIA_FM_CTL_AC_POST_BMI_FETCH 0x00000012
+#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME 0x0000001A
+#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME 0x0000001E
+#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR 0x00000014
+#define NIA_FM_CTL_AC_POST_BMI_ENQ 0x00000022
+#define NIA_FM_CTL_AC_PRE_CC 0x00000020
+#define NIA_FM_CTL_AC_POST_TX 0x00000024
+/* V3 only */
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028
+#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME 0x0000002A
+#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP 0x0000002C
+
+#define NIA_BMI_AC_ENQ_FRAME 0x00000002
+#define NIA_BMI_AC_TX_RELEASE 0x000002C0
+#define NIA_BMI_AC_RELEASE 0x000000C0
+#define NIA_BMI_AC_DISCARD 0x000000C1
+#define NIA_BMI_AC_TX 0x00000274
+#define NIA_BMI_AC_FETCH 0x00000208
+#define NIA_BMI_AC_MASK 0x000003FF
+
+#define NIA_KG_DIRECT 0x00000100
+#define NIA_KG_CC_EN 0x00000200
+#define NIA_PLCR_ABSOLUTE 0x00008000
+
+#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202
+
+#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006)
+#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \
+ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME))
+#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \
+ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME))
+#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)
+#else
+#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \
+ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \
+ (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))
+#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \
+ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \
+ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \
+ (NIA_ENG_BMI | NIA_BMI_AC_DISCARD))
+#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \
+ (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)
+#endif /* defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || ... */
+
+/**************************************************************************//**
+ @Description CTRL Parameters Page defines
+*//***************************************************************************/
+#define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000
+#define FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN 0x40000000
+#define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100
+
+#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK 0x0000003f
+
+/**************************************************************************//**
+ @Description Port Id defines
+*//***************************************************************************/
+#if (DPAA_VERSION == 10)
+#define BASE_OH_PORTID 1
+#else
+#define BASE_OH_PORTID 2
+#endif /* (DPAA_VERSION == 10) */
+#define BASE_1G_RX_PORTID 8
+#define BASE_10G_RX_PORTID 0x10
+#define BASE_1G_TX_PORTID 0x28
+#define BASE_10G_TX_PORTID 0x30
+
+#define FM_PCD_PORT_OH_BASE_INDX 0
+#define FM_PCD_PORT_1G_RX_BASE_INDX (FM_PCD_PORT_OH_BASE_INDX+FM_MAX_NUM_OF_OH_PORTS)
+#define FM_PCD_PORT_10G_RX_BASE_INDX (FM_PCD_PORT_1G_RX_BASE_INDX+FM_MAX_NUM_OF_1G_RX_PORTS)
+#define FM_PCD_PORT_1G_TX_BASE_INDX (FM_PCD_PORT_10G_RX_BASE_INDX+FM_MAX_NUM_OF_10G_RX_PORTS)
+#define FM_PCD_PORT_10G_TX_BASE_INDX (FM_PCD_PORT_1G_TX_BASE_INDX+FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#if (FM_MAX_NUM_OF_OH_PORTS > 0)
+#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \
+ if ((_relativePortId) >= FM_MAX_NUM_OF_OH_PORTS) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id"))
+#else
+#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id"))
+#endif
+#if (FM_MAX_NUM_OF_1G_RX_PORTS > 0)
+#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \
+ if ((_relativePortId) >= FM_MAX_NUM_OF_1G_RX_PORTS) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id"))
+#else
+#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id"))
+#endif
+#if (FM_MAX_NUM_OF_10G_RX_PORTS > 0)
+#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \
+ if ((_relativePortId) >= FM_MAX_NUM_OF_10G_RX_PORTS) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id"))
+#else
+#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id"))
+#endif
+#if (FM_MAX_NUM_OF_1G_TX_PORTS > 0)
+#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \
+ if ((_relativePortId) >= FM_MAX_NUM_OF_1G_TX_PORTS) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id"))
+#else
+#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id"))
+#endif
+#if (FM_MAX_NUM_OF_10G_TX_PORTS > 0)
+#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \
+ if ((_relativePortId) >= FM_MAX_NUM_OF_10G_TX_PORTS) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id"))
+#else
+#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id"))
+#endif
+
+uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev);
+
+#define HW_PORT_ID_TO_SW_PORT_ID(_relativePortId, hardwarePortId) \
+{ if (((hardwarePortId) >= BASE_OH_PORTID) && \
+ ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \
+ _relativePortId = (uint8_t)((hardwarePortId)-BASE_OH_PORTID); \
+ else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \
+ ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \
+ _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID); \
+ else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \
+ ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \
+ _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID); \
+ else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \
+ ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \
+ _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID); \
+ else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \
+ ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \
+ _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID); \
+ else { \
+ _relativePortId = (uint8_t)DUMMY_PORT_ID; \
+ ASSERT_COND(TRUE); \
+ } \
+}
+
+#define HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId) \
+do { \
+ if (((hardwarePortId) >= BASE_OH_PORTID) && ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \
+ swPortIndex = (uint8_t)((hardwarePortId)-BASE_OH_PORTID+FM_PCD_PORT_OH_BASE_INDX); \
+ else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \
+ ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \
+ swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID+FM_PCD_PORT_1G_RX_BASE_INDX); \
+ else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \
+ ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \
+ swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID+FM_PCD_PORT_10G_RX_BASE_INDX); \
+ else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \
+ ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \
+ swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID+FM_PCD_PORT_1G_TX_BASE_INDX); \
+ else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \
+ ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \
+ swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID+FM_PCD_PORT_10G_TX_BASE_INDX); \
+ else ASSERT_COND(FALSE); \
+} while (0)
+
+#define SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, swPortIndex) \
+do { \
+ if (((swPortIndex) >= FM_PCD_PORT_OH_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_1G_RX_BASE_INDX)) \
+ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_OH_BASE_INDX+BASE_OH_PORTID); \
+ else if (((swPortIndex) >= FM_PCD_PORT_1G_RX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_RX_BASE_INDX)) \
+ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_RX_BASE_INDX+BASE_1G_RX_PORTID); \
+ else if (((swPortIndex) >= FM_PCD_PORT_10G_RX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \
+ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_RX_BASE_INDX+BASE_10G_RX_PORTID); \
+ else if (((swPortIndex) >= FM_PCD_PORT_1G_TX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_TX_BASE_INDX)) \
+ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_TX_BASE_INDX+BASE_1G_TX_PORTID); \
+ else if (((swPortIndex) >= FM_PCD_PORT_10G_TX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \
+ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_TX_BASE_INDX+BASE_10G_TX_PORTID); \
+ else ASSERT_COND(FALSE); \
+} while (0)
+
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define BMI_FIFO_UNITS 0x100
+
+typedef struct {
+ void (*f_Isr) (t_Handle h_Arg);
+ t_Handle h_SrcHandle;
+ uint8_t guestId;
+} t_FmIntrSrc;
+
+#define ILLEGAL_HDR_NUM 0xFF
+#define NO_HDR_NUM FM_PCD_PRS_NUM_OF_HDRS
+
+#define IS_PRIVATE_HEADER(hdr) (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) || \
+ ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2))
+#define IS_SPECIAL_HEADER(hdr) ((hdr) == HEADER_TYPE_MACSEC)
+
+static __inline__ uint8_t GetPrsHdrNum(e_NetHeaderType hdr)
+{
+ switch (hdr)
+ { case (HEADER_TYPE_ETH): return 0;
+ case (HEADER_TYPE_LLC_SNAP): return 1;
+ case (HEADER_TYPE_VLAN): return 2;
+ case (HEADER_TYPE_PPPoE): return 3;
+ case (HEADER_TYPE_PPP): return 3;
+ case (HEADER_TYPE_MPLS): return 4;
+ case (HEADER_TYPE_IPv4): return 5;
+ case (HEADER_TYPE_IPv6): return 6;
+ case (HEADER_TYPE_GRE): return 7;
+ case (HEADER_TYPE_MINENCAP): return 8;
+ case (HEADER_TYPE_USER_DEFINED_L3): return 9;
+ case (HEADER_TYPE_TCP): return 10;
+ case (HEADER_TYPE_UDP): return 11;
+ case (HEADER_TYPE_IPSEC_AH):
+ case (HEADER_TYPE_IPSEC_ESP): return 12;
+ case (HEADER_TYPE_SCTP): return 13;
+ case (HEADER_TYPE_DCCP): return 14;
+ case (HEADER_TYPE_USER_DEFINED_L4): return 15;
+ case (HEADER_TYPE_USER_DEFINED_SHIM1):
+ case (HEADER_TYPE_USER_DEFINED_SHIM2):
+ case (HEADER_TYPE_MACSEC): return NO_HDR_NUM;
+ default:
+ return ILLEGAL_HDR_NUM;
+ }
+}
+
+#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries) ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0))))
+
+
+/**************************************************************************//**
+ @Description A structure for initializing a keygen classification plan group
+*//***************************************************************************/
+typedef struct t_FmPcdKgInterModuleClsPlanGrpParams {
+ uint8_t netEnvId; /* IN */
+ bool grpExists; /* OUT (unused in FmPcdKgBuildClsPlanGrp)*/
+ uint8_t clsPlanGrpId; /* OUT */
+ bool emptyClsPlanGrp; /* OUT */
+ uint8_t numOfOptions; /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
+ protocolOpt_t options[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
+ /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
+ uint32_t optVectors[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)];
+ /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/
+} t_FmPcdKgInterModuleClsPlanGrpParams;
+
+typedef struct t_FmPcdLock {
+ t_Handle h_Spinlock;
+ volatile bool flag;
+ t_List node;
+} t_FmPcdLock;
+#define FM_PCD_LOCK_OBJ(ptr) LIST_OBJECT(ptr, t_FmPcdLock, node)
+
+
+typedef t_Error (t_FmPortGetSetCcParamsCallback) (t_Handle h_FmPort,
+ t_FmPortGetSetCcParams *p_FmPortGetSetCcParams);
+
+
+/***********************************************************************/
+/* Common API for FM-PCD module */
+/***********************************************************************/
+t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd);
+uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr);
+uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum);
+uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId);
+void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId);
+void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId);
+uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv);
+void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId);
+uint32_t FmPcdLock(t_Handle h_FmPcd);
+void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags);
+bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr);
+t_Error FmPcdFragHcScratchPoolInit(t_Handle h_FmPcd, uint8_t scratchBpid);
+t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl);
+t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl);
+bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd);
+bool FmPcdLockTryLockAll(t_Handle h_FmPcd);
+void FmPcdLockUnlockAll(t_Handle h_FmPcd);
+t_Error FmPcdHcSync(t_Handle h_FmPcd);
+t_Handle FmGetPcd(t_Handle h_Fm);
+/***********************************************************************/
+/* Common API for FM-PCD KG module */
+/***********************************************************************/
+uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp);
+uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp);
+t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet);
+
+uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme);
+#if (DPAA_VERSION >= 11)
+bool FmPcdKgGetVspe(t_Handle h_Scheme);
+#endif /* (DPAA_VERSION >= 11) */
+uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId);
+void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId);
+t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_Scheme);
+t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPortToSchemes, uint32_t *p_SpReg, bool add);
+bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg);
+uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter);
+uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId);
+uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId);
+uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId);
+uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId);
+uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId);
+bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme);
+
+t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind);
+t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind);
+uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId);
+uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId);
+e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId);
+e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId);
+void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction);
+bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId);
+bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId);
+uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId);
+t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId);
+bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme);
+t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value);
+t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp);
+t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId);
+
+/***********************************************************************/
+/* Common API for FM-PCD parser module */
+/***********************************************************************/
+t_Error FmPcdPrsIncludePortInStatistics(t_Handle p_FmPcd, uint8_t hardwarePortId, bool include);
+
+/***********************************************************************/
+/* Common API for FM-PCD policer module */
+/***********************************************************************/
+t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles);
+t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId);
+bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId);
+uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId);
+uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId);
+uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter);
+uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId);
+uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId);
+uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile);
+t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd,
+ e_FmPcdProfileTypeSelection profileType,
+ t_Handle h_FmPort,
+ uint16_t relativeProfile,
+ uint16_t *p_AbsoluteId);
+void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg);
+uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red);
+void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction);
+t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx,uint32_t requiredAction);
+
+/***********************************************************************/
+/* Common API for FM-PCD CC module */
+/***********************************************************************/
+uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode);
+uint8_t FmPcdCcGetOffset(t_Handle h_CcNode);
+t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex);
+t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPCdCcKeyParams);
+t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask);
+t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams);
+t_Error FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+t_Error FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer);
+t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree);
+void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams);
+t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes);
+t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes);
+t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_CcTree, uint32_t *p_Offset,t_Handle h_FmPort);
+t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_CcTree);
+
+/***********************************************************************/
+/* Common API for FM-PCD Manip module */
+/***********************************************************************/
+t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, bool validate, int level, t_Handle h_FmTree, bool modify);
+
+/***********************************************************************/
+/* Common API for FM-Port module */
+/***********************************************************************/
+#if (DPAA_VERSION >= 11)
+typedef enum e_FmPortGprFuncType
+{
+ e_FM_PORT_GPR_EMPTY = 0,
+ e_FM_PORT_GPR_MURAM_PAGE
+} e_FmPortGprFuncType;
+
+t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, void **p_Value);
+#endif /* DPAA_VERSION >= 11) */
+t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_FmGetSetParams);
+t_Error FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_FmPortGetSetCcParams);
+uint8_t FmPortGetNetEnvId(t_Handle h_FmPort);
+uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort);
+uint32_t FmPortGetPcdEngines(t_Handle h_FmPort);
+void FmPortPcdKgSwUnbindClsPlanGrp (t_Handle h_FmPort);
+
+
+#if (DPAA_VERSION >= 11)
+t_Error FmPcdFrmReplicUpdate(t_Handle h_FmPcd, t_Handle h_FmPort, t_Handle h_FrmReplic);
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Function FmRegisterIntr
+
+ @Description Used to register an inter-module event handler to be processed by FM
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] mod The module that causes the event
+ @Param[in] modId Module id - if more than 1 instansiation of this
+ mode exists,0 otherwise.
+ @Param[in] intrType Interrupt type (error/normal) selection.
+ @Param[in] f_Isr The interrupt service routine.
+ @Param[in] h_Arg Argument to be passed to f_Isr.
+
+ @Return None.
+*//***************************************************************************/
+void FmRegisterIntr(t_Handle h_Fm,
+ e_FmEventModules mod,
+ uint8_t modId,
+ e_FmIntrType intrType,
+ void (*f_Isr) (t_Handle h_Arg),
+ t_Handle h_Arg);
+
+/**************************************************************************//**
+ @Function FmUnregisterIntr
+
+ @Description Used to un-register an inter-module event handler that was processed by FM
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] mod The module that causes the event
+ @Param[in] modId Module id - if more than 1 instansiation of this
+ mode exists,0 otherwise.
+ @Param[in] intrType Interrupt type (error/normal) selection.
+
+ @Return None.
+*//***************************************************************************/
+void FmUnregisterIntr(t_Handle h_Fm,
+ e_FmEventModules mod,
+ uint8_t modId,
+ e_FmIntrType intrType);
+
+/**************************************************************************//**
+ @Function FmRegisterFmCtlIntr
+
+ @Description Used to register to one of the fmCtl events in the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] eventRegId FmCtl event id (0-7).
+ @Param[in] f_Isr The interrupt service routine.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+void FmRegisterFmCtlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event));
+
+
+/**************************************************************************//**
+ @Description enum for defining MAC types
+*//***************************************************************************/
+typedef enum e_FmMacType {
+ e_FM_MAC_10G = 0, /**< 10G MAC */
+ e_FM_MAC_1G /**< 1G MAC */
+} e_FmMacType;
+
+/**************************************************************************//**
+ @Description Structure for port-FM communication during FM_PORT_Init.
+ Fields commented 'IN' are passed by the port module to be used
+ by the FM module.
+ Fields commented 'OUT' will be filled by FM before returning to port.
+ Some fields are optional (depending on configuration) and
+ will be analized by the port and FM modules accordingly.
+*//***************************************************************************/
+typedef struct t_FmInterModulePortInitParams {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ e_FmPortType portType; /**< IN. Port type */
+ bool independentMode; /**< IN. TRUE if FM Port operates in independent mode */
+ uint16_t liodnOffset; /**< IN. Port's requested resource */
+ uint8_t numOfTasks; /**< IN. Port's requested resource */
+ uint8_t numOfExtraTasks; /**< IN. Port's requested resource */
+ uint8_t numOfOpenDmas; /**< IN. Port's requested resource */
+ uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */
+ uint32_t sizeOfFifo; /**< IN. Port's requested resource */
+ uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */
+ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */
+ uint16_t maxFrameLength; /**< IN. Port's max frame length. */
+ uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1.
+ LIODN base for this port, to be
+ used together with LIODN offset. */
+ t_FmPhysAddr fmMuramPhysBaseAddr;/**< OUT. FM-MURAM physical address*/
+} t_FmInterModulePortInitParams;
+
+/**************************************************************************//**
+ @Description Structure for port-FM communication during FM_PORT_Free.
+*//***************************************************************************/
+typedef struct t_FmInterModulePortFreeParams {
+ uint8_t hardwarePortId; /**< IN. port Id */
+ e_FmPortType portType; /**< IN. Port type */
+ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */
+} t_FmInterModulePortFreeParams;
+
+/**************************************************************************//**
+ @Function FmGetPcdPrsBaseAddr
+
+ @Description Get the base address of the Parser from the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return Base address.
+*//***************************************************************************/
+uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetPcdKgBaseAddr
+
+ @Description Get the base address of the Keygen from the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return Base address.
+*//***************************************************************************/
+uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetPcdPlcrBaseAddr
+
+ @Description Get the base address of the Policer from the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return Base address.
+*//***************************************************************************/
+uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetMuramHandle
+
+ @Description Get the handle of the MURAM from the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return MURAM module handle.
+*//***************************************************************************/
+t_Handle FmGetMuramHandle(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetPhysicalMuramBase
+
+ @Description Get the physical base address of the MURAM from the FM module
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] fmPhysAddr Physical MURAM base
+
+ @Return Physical base address.
+*//***************************************************************************/
+void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *fmPhysAddr);
+
+/**************************************************************************//**
+ @Function FmGetTimeStampScale
+
+ @Description Used internally by other modules in order to get the timeStamp
+ period as requested by the application.
+
+ This function returns bit number that is incremented every 1 usec.
+ To calculate timestamp period in nsec, use
+ 1000 / (1 << FmGetTimeStampScale()).
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return Bit that counts 1 usec.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+uint32_t FmGetTimeStampScale(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmResumeStalledPort
+
+ @Description Used internally by FM port to release a stalled port.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] hardwarePortId HW port id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId);
+
+/**************************************************************************//**
+ @Function FmIsPortStalled
+
+ @Description Used internally by FM port to read the port's status.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] hardwarePortId HW port id.
+ @Param[in] p_IsStalled A pointer to the boolean port stalled state
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled);
+
+/**************************************************************************//**
+ @Function FmResetMac
+
+ @Description Used by MAC driver to reset the MAC registers
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] type MAC type.
+ @Param[in] macId MAC id - according to type.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId);
+
+/**************************************************************************//**
+ @Function FmGetClockFreq
+
+ @Description Used by MAC driver to get the FM clock frequency
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return clock-freq on success; 0 otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+uint16_t FmGetClockFreq(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetMacClockFreq
+
+ @Description Used by MAC driver to get the MAC clock frequency
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return clock-freq on success; 0 otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+uint16_t FmGetMacClockFreq(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetId
+
+ @Description Used by PCD driver to read rhe FM id
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+uint8_t FmGetId(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmReset
+
+ @Description Used to reset the FM
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FmReset(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FmGetSetPortParams
+
+ @Description Used by FM-PORT driver to pass and receive parameters between
+ PORT and FM modules.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in,out] p_PortParams A structure of FM Port parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams);
+
+/**************************************************************************//**
+ @Function FmFreePortParams
+
+ @Description Used by FM-PORT driver to free port's resources within the FM.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in,out] p_PortParams A structure of FM Port parameters.
+
+ @Return None.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams);
+
+/**************************************************************************//**
+ @Function FmSetNumOfRiscsPerPort
+
+ @Description Used by FM-PORT driver to pass parameter between
+ PORT and FM modules for working with number of RISC..
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] hardwarePortId hardware port Id.
+ @Param[in] numOfFmanCtrls number of Fman Controllers.
+ @Param[in] orFmanCtrl Fman Controller for order restoration.
+
+ @Return None.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls, t_FmFmanCtrl orFmanCtrl);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//*
+ @Function FmDumpPortRegs
+
+ @Description Dumps FM port registers which are part of FM common registers
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] hardwarePortId HW port id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only FM_Init().
+*//***************************************************************************/
+t_Error FmDumpPortRegs(t_Handle h_Fm,uint8_t hardwarePortId);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd);
+void FmUnregisterPcd(t_Handle h_Fm);
+t_Handle FmGetPcdHandle(t_Handle h_Fm);
+t_Error FmEnableRamsEcc(t_Handle h_Fm);
+t_Error FmDisableRamsEcc(t_Handle h_Fm);
+void FmGetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo);
+t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId);
+void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId);
+void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents);
+uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId);
+void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event), t_Handle h_Arg);
+void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId);
+t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu);
+bool FmIsMaster(t_Handle h_Fm);
+uint8_t FmGetGuestId(t_Handle h_Fm);
+uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm);
+t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool preFetchConfigured);
+t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool *p_PortConfigured, bool *p_PreFetchConfigured);
+
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId);
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+
+void FmMuramClear(t_Handle h_FmMuram);
+t_Error FmSetNumOfOpenDmas(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t *p_NumOfOpenDmas,
+ uint8_t *p_NumOfExtraOpenDmas,
+ bool initialConfig);
+t_Error FmSetNumOfTasks(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint8_t *p_NumOfTasks,
+ uint8_t *p_NumOfExtraTasks,
+ bool initialConfig);
+t_Error FmSetSizeOfFifo(t_Handle h_Fm,
+ uint8_t hardwarePortId,
+ uint32_t *p_SizeOfFifo,
+ uint32_t *p_ExtraSizeOfFifo,
+ bool initialConfig);
+
+t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm,
+ uint32_t congestionGroupId,
+ uint8_t priorityBitMap);
+
+#if (DPAA_VERSION >= 11)
+t_Error FmVSPAllocForPort(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint8_t numOfStorageProfiles);
+
+t_Error FmVSPFreeForPort(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId);
+
+t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint16_t relativeProfile,
+ uint16_t *p_AbsoluteId);
+t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint16_t relativeProfile);
+
+uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm);
+#endif /* (DPAA_VERSION >= 11) */
+
+
+#endif /* __FM_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h
new file mode 100644
index 000000000000..492aa8a3aa78
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __FM_HC_H
+#define __FM_HC_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "fsl_fman_kg.h"
+
+#define __ERR_MODULE__ MODULE_FM_PCD
+
+
+typedef struct t_FmHcParams {
+ t_Handle h_Fm;
+ t_Handle h_FmPcd;
+ t_FmPcdHcParams params;
+} t_FmHcParams;
+
+
+t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams);
+void FmHcFree(t_Handle h_FmHc);
+t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc,
+ uint8_t memId);
+t_Error FmHcDumpRegs(t_Handle h_FmHc);
+
+void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd);
+
+t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc,
+ t_Handle h_Scheme,
+ struct fman_kg_scheme_regs *p_SchemeRegs,
+ bool updateCounter);
+t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme);
+t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams );
+t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams);
+t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result);
+t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set);
+t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t clsPlanGrpId);
+
+t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value);
+uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme);
+
+t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset);
+
+t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs);
+t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile);
+
+t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value);
+uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter);
+
+t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add);
+t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg);
+
+t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value);
+t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction);
+
+t_Error FmHcPcdSync(t_Handle h_FmHc);
+t_Handle FmHcGetPort(t_Handle h_FmHc);
+
+
+
+
+#endif /* __FM_HC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h
new file mode 100644
index 000000000000..f9dd384bb685
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/******************************************************************************
+ @File fm_sp_common.h
+
+ @Description FM SP ...
+*//***************************************************************************/
+#ifndef __FM_SP_COMMON_H
+#define __FM_SP_COMMON_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "fm_ext.h"
+#include "fm_pcd_ext.h"
+#include "fsl_fman.h"
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+#define DEFAULT_FM_SP_bufferPrefixContent_privDataSize 0
+#define DEFAULT_FM_SP_bufferPrefixContent_passPrsResult FALSE
+#define DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp FALSE
+#define DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo FALSE
+#define DEFAULT_FM_SP_bufferPrefixContent_dataAlign 64
+
+/**************************************************************************//**
+ @Description structure for defining internal context copying
+*//***************************************************************************/
+typedef struct
+{
+ uint16_t extBufOffset; /**< Offset in External buffer to which internal
+ context is copied to (Rx) or taken from (Tx, Op). */
+ uint8_t intContextOffset; /**< Offset within internal context to copy from
+ (Rx) or to copy to (Tx, Op). */
+ uint16_t size; /**< Internal offset size to be copied */
+} t_FmSpIntContextDataCopy;
+
+/**************************************************************************//**
+ @Description struct for defining external buffer margins
+*//***************************************************************************/
+typedef struct {
+ uint16_t startMargins; /**< Number of bytes to be left at the beginning
+ of the external buffer (must be divisible by 16) */
+ uint16_t endMargins; /**< number of bytes to be left at the end
+ of the external buffer(must be divisible by 16) */
+} t_FmSpBufMargins;
+
+typedef struct {
+ uint32_t dataOffset;
+ uint32_t prsResultOffset;
+ uint32_t timeStampOffset;
+ uint32_t hashResultOffset;
+ uint32_t pcdInfoOffset;
+ uint32_t manipOffset;
+} t_FmSpBufferOffsets;
+
+
+t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmPortIntContextDataCopy,
+ t_FmBufferPrefixContent *p_BufferPrefixContent,
+ t_FmSpBufMargins *p_FmPortBufMargins,
+ t_FmSpBufferOffsets *p_FmPortBufferOffsets,
+ uint8_t *internalBufferOffset);
+
+t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy);
+t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools,
+ t_FmBackupBmPools *p_FmBackupBmPools,
+ t_FmBufPoolDepletion *p_FmBufPoolDepletion);
+t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins);
+void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, uint8_t *orderedArray, uint16_t *sizesArray);
+
+t_Error FmPcdSpAllocProfiles(t_Handle h_FmPcd,
+ uint8_t hardwarePortId,
+ uint16_t numOfStorageProfiles,
+ uint16_t *base,
+ uint8_t *log2Num);
+t_Error FmPcdSpGetAbsoluteProfileId(t_Handle h_FmPcd,
+ t_Handle h_FmPort,
+ uint16_t relativeProfile,
+ uint16_t *p_AbsoluteId);
+void SpInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+void SpValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId);
+
+
+#endif /* __FM_SP_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile b/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile
new file mode 100644
index 000000000000..d03a519c8d60
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+obj-y += fsl-ncsw-etc.o
+
+fsl-ncsw-etc-objs := mm.o memcpy.o sprint.o list.o error.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/error.c b/drivers/net/ethernet/freescale/sdk_fman/etc/error.c
new file mode 100644
index 000000000000..fead7f50f2ba
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/error.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/*
+
+ @File error.c
+
+ @Description General errors and events reporting utilities.
+*//***************************************************************************/
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+#include "error_ext.h"
+
+
+const char *dbgLevelStrings[] =
+{
+ "CRITICAL"
+ ,"MAJOR"
+ ,"MINOR"
+ ,"WARNING"
+ ,"INFO"
+ ,"TRACE"
+};
+
+
+char * ErrTypeStrings (e_ErrorType err)
+{
+ switch (err)
+ {
+ case (E_OK): return "OK";
+ case (E_WRITE_FAILED): return "Write Access Failed";
+ case (E_NO_DEVICE): return "No Device";
+ case (E_NOT_AVAILABLE): return "Resource Is Unavailable";
+ case (E_NO_MEMORY): return "Memory Allocation Failed";
+ case (E_INVALID_ADDRESS): return "Invalid Address";
+ case (E_BUSY): return "Resource Is Busy";
+ case (E_ALREADY_EXISTS): return "Resource Already Exists";
+ case (E_INVALID_OPERATION): return "Invalid Operation";
+ case (E_INVALID_VALUE): return "Invalid Value";
+ case (E_NOT_IN_RANGE): return "Value Out Of Range";
+ case (E_NOT_SUPPORTED): return "Unsupported Operation";
+ case (E_INVALID_STATE): return "Invalid State";
+ case (E_INVALID_HANDLE): return "Invalid Handle";
+ case (E_INVALID_ID): return "Invalid ID";
+ case (E_NULL_POINTER): return "Unexpected NULL Pointer";
+ case (E_INVALID_SELECTION): return "Invalid Selection";
+ case (E_INVALID_COMM_MODE): return "Invalid Communication Mode";
+ case (E_INVALID_MEMORY_TYPE): return "Invalid Memory Type";
+ case (E_INVALID_CLOCK): return "Invalid Clock";
+ case (E_CONFLICT): return "Conflict In Settings";
+ case (E_NOT_ALIGNED): return "Incorrect Alignment";
+ case (E_NOT_FOUND): return "Resource Not Found";
+ case (E_FULL): return "Resource Is Full";
+ case (E_EMPTY): return "Resource Is Empty";
+ case (E_ALREADY_FREE): return "Resource Already Free";
+ case (E_READ_FAILED): return "Read Access Failed";
+ case (E_INVALID_FRAME): return "Invalid Frame";
+ case (E_SEND_FAILED): return "Send Operation Failed";
+ case (E_RECEIVE_FAILED): return "Receive Operation Failed";
+ case (E_TIMEOUT): return "Operation Timed Out";
+ default:
+ break;
+ }
+ return NULL;
+}
+#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/list.c b/drivers/net/ethernet/freescale/sdk_fman/etc/list.c
new file mode 100644
index 000000000000..2d044be25a62
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/list.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File list.c
+
+ @Description Implementation of list.
+*//***************************************************************************/
+#include "std_ext.h"
+#include "list_ext.h"
+
+
+void LIST_Append(t_List *p_NewList, t_List *p_Head)
+{
+ t_List *p_First = LIST_FIRST(p_NewList);
+
+ if (p_First != p_NewList)
+ {
+ t_List *p_Last = LIST_LAST(p_NewList);
+ t_List *p_Cur = LIST_NEXT(p_Head);
+
+ LIST_PREV(p_First) = p_Head;
+ LIST_FIRST(p_Head) = p_First;
+ LIST_NEXT(p_Last) = p_Cur;
+ LIST_LAST(p_Cur) = p_Last;
+ }
+}
+
+
+int LIST_NumOfObjs(t_List *p_List)
+{
+ t_List *p_Tmp;
+ int numOfObjs = 0;
+
+ if (!LIST_IsEmpty(p_List))
+ LIST_FOR_EACH(p_Tmp, p_List)
+ numOfObjs++;
+
+ return numOfObjs;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c b/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c
new file mode 100644
index 000000000000..fa203ec7cebf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "std_ext.h"
+#include "xx_ext.h"
+#include "memcpy_ext.h"
+
+void * MemCpy8(void* pDst, void* pSrc, uint32_t size)
+{
+ int i;
+
+ for(i = 0; i < size; ++i)
+ *(((uint8_t*)(pDst)) + i) = *(((uint8_t*)(pSrc)) + i);
+
+ return pDst;
+}
+
+void * MemSet8(void* pDst, int c, uint32_t size)
+{
+ int i;
+
+ for(i = 0; i < size; ++i)
+ *(((uint8_t*)(pDst)) + i) = (uint8_t)(c);
+
+ return pDst;
+}
+
+void * MemCpy32(void* pDst,void* pSrc, uint32_t size)
+{
+ uint32_t leftAlign;
+ uint32_t rightAlign;
+ uint32_t lastWord;
+ uint32_t currWord;
+ uint32_t *p_Src32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Src8;
+ uint8_t *p_Dst8;
+
+ p_Src8 = (uint8_t*)(pSrc);
+ p_Dst8 = (uint8_t*)(pDst);
+ /* first copy byte by byte till the source first alignment
+ * this step is necessary to ensure we do not even try to access
+ * data which is before the source buffer, hence it is not ours.
+ */
+ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
+ {
+ *p_Dst8++ = *p_Src8++;
+ size--;
+ }
+
+ /* align destination (possibly disaligning source)*/
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ *p_Dst8++ = *p_Src8++;
+ size--;
+ }
+
+ /* dest is aligned and source is not necessarily aligned */
+ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
+ rightAlign = 32 - leftAlign;
+
+
+ if (leftAlign == 0)
+ {
+ /* source is also aligned */
+ p_Src32 = (uint32_t*)(p_Src8);
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ *p_Dst32++ = *p_Src32++;
+ size -= 4;
+ }
+ p_Src8 = (uint8_t*)(p_Src32);
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ }
+ else
+ {
+ /* source is not aligned (destination is aligned)*/
+ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ lastWord = *p_Src32++;
+ while(size >> 3) /* size >= 8 */
+ {
+ currWord = *p_Src32;
+ *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign);
+ lastWord = currWord;
+ p_Src32++;
+ p_Dst32++;
+ size -= 4;
+ }
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
+ }
+
+ /* complete the left overs */
+ while (size--)
+ *p_Dst8++ = *p_Src8++;
+
+ return pDst;
+}
+
+void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size)
+{
+ uint32_t leftAlign;
+ uint32_t rightAlign;
+ uint32_t lastWord;
+ uint32_t currWord;
+ uint32_t *p_Src32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Src8;
+ uint8_t *p_Dst8;
+
+ p_Src8 = (uint8_t*)(pSrc);
+ p_Dst8 = (uint8_t*)(pDst);
+ /* first copy byte by byte till the source first alignment
+ * this step is necessary to ensure we do not even try to access
+ * data which is before the source buffer, hence it is not ours.
+ */
+ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
+ {
+ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* align destination (possibly disaligning source)*/
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* dest is aligned and source is not necessarily aligned */
+ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
+ rightAlign = 32 - leftAlign;
+
+ if (leftAlign == 0)
+ {
+ /* source is also aligned */
+ p_Src32 = (uint32_t*)(p_Src8);
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ WRITE_UINT32(*p_Dst32, GET_UINT32(*p_Src32));
+ p_Dst32++;p_Src32++;
+ size -= 4;
+ }
+ p_Src8 = (uint8_t*)(p_Src32);
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ }
+ else
+ {
+ /* source is not aligned (destination is aligned)*/
+ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ lastWord = GET_UINT32(*p_Src32);
+ p_Src32++;
+ while(size >> 3) /* size >= 8 */
+ {
+ currWord = GET_UINT32(*p_Src32);
+ WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign));
+ lastWord = currWord;
+ p_Src32++;p_Dst32++;
+ size -= 4;
+ }
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
+ }
+
+ /* complete the left overs */
+ while (size--)
+ {
+ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8));
+ p_Dst8++;p_Src8++;
+ }
+
+ return pDst;
+}
+
+void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size)
+{
+ uint32_t leftAlign;
+ uint32_t rightAlign;
+ uint32_t lastWord;
+ uint32_t currWord;
+ uint32_t *p_Src32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Src8;
+ uint8_t *p_Dst8;
+
+ p_Src8 = (uint8_t*)(pSrc);
+ p_Dst8 = (uint8_t*)(pDst);
+ /* first copy byte by byte till the source first alignment
+ * this step is necessary to ensure we do not even try to access
+ * data which is before the source buffer, hence it is not ours.
+ */
+ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
+ {
+ WRITE_UINT8(*p_Dst8, *p_Src8);
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* align destination (possibly disaligning source)*/
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ WRITE_UINT8(*p_Dst8, *p_Src8);
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* dest is aligned and source is not necessarily aligned */
+ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
+ rightAlign = 32 - leftAlign;
+
+ if (leftAlign == 0)
+ {
+ /* source is also aligned */
+ p_Src32 = (uint32_t*)(p_Src8);
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ WRITE_UINT32(*p_Dst32, *p_Src32);
+ p_Dst32++;p_Src32++;
+ size -= 4;
+ }
+ p_Src8 = (uint8_t*)(p_Src32);
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ }
+ else
+ {
+ /* source is not aligned (destination is aligned)*/
+ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ lastWord = *p_Src32++;
+ while(size >> 3) /* size >= 8 */
+ {
+ currWord = *p_Src32;
+ WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign));
+ lastWord = currWord;
+ p_Src32++;p_Dst32++;
+ size -= 4;
+ }
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
+ }
+
+ /* complete the left overs */
+ while (size--)
+ {
+ WRITE_UINT8(*p_Dst8, *p_Src8);
+ p_Dst8++;p_Src8++;
+ }
+
+ return pDst;
+}
+
+void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size)
+{
+ uint32_t leftAlign;
+ uint32_t rightAlign;
+ uint32_t lastWord;
+ uint32_t currWord;
+ uint32_t *p_Src32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Src8;
+ uint8_t *p_Dst8;
+
+ p_Src8 = (uint8_t*)(pSrc);
+ p_Dst8 = (uint8_t*)(pDst);
+ /* first copy byte by byte till the source first alignment
+ * this step is necessary to ensure we do not even try to access
+ * data which is before the source buffer, hence it is not ours.
+ */
+ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */
+ {
+ *p_Dst8 = GET_UINT8(*p_Src8);
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* align destination (possibly disaligning source)*/
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ *p_Dst8 = GET_UINT8(*p_Src8);
+ p_Dst8++;p_Src8++;
+ size--;
+ }
+
+ /* dest is aligned and source is not necessarily aligned */
+ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */
+ rightAlign = 32 - leftAlign;
+
+ if (leftAlign == 0)
+ {
+ /* source is also aligned */
+ p_Src32 = (uint32_t*)(p_Src8);
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ *p_Dst32 = GET_UINT32(*p_Src32);
+ p_Dst32++;p_Src32++;
+ size -= 4;
+ }
+ p_Src8 = (uint8_t*)(p_Src32);
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ }
+ else
+ {
+ /* source is not aligned (destination is aligned)*/
+ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3));
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ lastWord = GET_UINT32(*p_Src32);
+ p_Src32++;
+ while(size >> 3) /* size >= 8 */
+ {
+ currWord = GET_UINT32(*p_Src32);
+ *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign);
+ lastWord = currWord;
+ p_Src32++;p_Dst32++;
+ size -= 4;
+ }
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3);
+ }
+
+ /* complete the left overs */
+ while (size--)
+ {
+ *p_Dst8 = GET_UINT8(*p_Src8);
+ p_Dst8++;p_Src8++;
+ }
+
+ return pDst;
+}
+
+void * MemCpy64(void* pDst,void* pSrc, uint32_t size)
+{
+ uint32_t leftAlign;
+ uint32_t rightAlign;
+ uint64_t lastWord;
+ uint64_t currWord;
+ uint64_t *pSrc64;
+ uint64_t *pDst64;
+ uint8_t *p_Src8;
+ uint8_t *p_Dst8;
+
+ p_Src8 = (uint8_t*)(pSrc);
+ p_Dst8 = (uint8_t*)(pDst);
+ /* first copy byte by byte till the source first alignment
+ * this step is necessarily to ensure we do not even try to access
+ * data which is before the source buffer, hence it is not ours.
+ */
+ while((PTR_TO_UINT(p_Src8) & 7) && size) /* (pSrc mod 8) > 0 and size > 0 */
+ {
+ *p_Dst8++ = *p_Src8++;
+ size--;
+ }
+
+ /* align destination (possibly disaligning source)*/
+ while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */
+ {
+ *p_Dst8++ = *p_Src8++;
+ size--;
+ }
+
+ /* dest is aligned and source is not necessarily aligned */
+ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 7) << 3); /* leftAlign = (pSrc mod 8)*8 */
+ rightAlign = 64 - leftAlign;
+
+
+ if (leftAlign == 0)
+ {
+ /* source is also aligned */
+ pSrc64 = (uint64_t*)(p_Src8);
+ pDst64 = (uint64_t*)(p_Dst8);
+ while (size >> 3) /* size >= 8 */
+ {
+ *pDst64++ = *pSrc64++;
+ size -= 8;
+ }
+ p_Src8 = (uint8_t*)(pSrc64);
+ p_Dst8 = (uint8_t*)(pDst64);
+ }
+ else
+ {
+ /* source is not aligned (destination is aligned)*/
+ pSrc64 = (uint64_t*)(p_Src8 - (leftAlign >> 3));
+ pDst64 = (uint64_t*)(p_Dst8);
+ lastWord = *pSrc64++;
+ while(size >> 4) /* size >= 16 */
+ {
+ currWord = *pSrc64;
+ *pDst64 = (lastWord << leftAlign) | (currWord >> rightAlign);
+ lastWord = currWord;
+ pSrc64++;
+ pDst64++;
+ size -= 8;
+ }
+ p_Dst8 = (uint8_t*)(pDst64);
+ p_Src8 = (uint8_t*)(pSrc64) - 8 + (leftAlign >> 3);
+ }
+
+ /* complete the left overs */
+ while (size--)
+ *p_Dst8++ = *p_Src8++;
+
+ return pDst;
+}
+
+void * MemSet32(void* pDst, uint8_t val, uint32_t size)
+{
+ uint32_t val32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Dst8;
+
+ p_Dst8 = (uint8_t*)(pDst);
+
+ /* generate four 8-bit val's in 32-bit container */
+ val32 = (uint32_t) val;
+ val32 |= (val32 << 8);
+ val32 |= (val32 << 16);
+
+ /* align destination to 32 */
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ *p_Dst8++ = val;
+ size--;
+ }
+
+ /* 32-bit chunks */
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ *p_Dst32++ = val32;
+ size -= 4;
+ }
+
+ /* complete the leftovers */
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ while (size--)
+ *p_Dst8++ = val;
+
+ return pDst;
+}
+
+void * IOMemSet32(void* pDst, uint8_t val, uint32_t size)
+{
+ uint32_t val32;
+ uint32_t *p_Dst32;
+ uint8_t *p_Dst8;
+
+ p_Dst8 = (uint8_t*)(pDst);
+
+ /* generate four 8-bit val's in 32-bit container */
+ val32 = (uint32_t) val;
+ val32 |= (val32 << 8);
+ val32 |= (val32 << 16);
+
+ /* align destination to 32 */
+ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */
+ {
+ WRITE_UINT8(*p_Dst8, val);
+ p_Dst8++;
+ size--;
+ }
+
+ /* 32-bit chunks */
+ p_Dst32 = (uint32_t*)(p_Dst8);
+ while (size >> 2) /* size >= 4 */
+ {
+ WRITE_UINT32(*p_Dst32, val32);
+ p_Dst32++;
+ size -= 4;
+ }
+
+ /* complete the leftovers */
+ p_Dst8 = (uint8_t*)(p_Dst32);
+ while (size--)
+ {
+ WRITE_UINT8(*p_Dst8, val);
+ p_Dst8++;
+ }
+
+ return pDst;
+}
+
+void * MemSet64(void* pDst, uint8_t val, uint32_t size)
+{
+ uint64_t val64;
+ uint64_t *pDst64;
+ uint8_t *p_Dst8;
+
+ p_Dst8 = (uint8_t*)(pDst);
+
+ /* generate four 8-bit val's in 32-bit container */
+ val64 = (uint64_t) val;
+ val64 |= (val64 << 8);
+ val64 |= (val64 << 16);
+ val64 |= (val64 << 24);
+ val64 |= (val64 << 32);
+
+ /* align destination to 64 */
+ while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */
+ {
+ *p_Dst8++ = val;
+ size--;
+ }
+
+ /* 64-bit chunks */
+ pDst64 = (uint64_t*)(p_Dst8);
+ while (size >> 4) /* size >= 8 */
+ {
+ *pDst64++ = val64;
+ size -= 8;
+ }
+
+ /* complete the leftovers */
+ p_Dst8 = (uint8_t*)(pDst64);
+ while (size--)
+ *p_Dst8++ = val;
+
+ return pDst;
+}
+
+void MemDisp(uint8_t *p, int size)
+{
+ uint32_t space = (uint32_t)(PTR_TO_UINT(p) & 0x3);
+ uint8_t *p_Limit;
+
+ if (space)
+ {
+ p_Limit = (p - space + 4);
+
+ XX_Print("0x%08X: ", (p - space));
+
+ while (space--)
+ {
+ XX_Print("--");
+ }
+ while (size && (p < p_Limit))
+ {
+ XX_Print("%02x", *(uint8_t*)p);
+ size--;
+ p++;
+ }
+
+ XX_Print(" ");
+ p_Limit += 12;
+
+ while ((size > 3) && (p < p_Limit))
+ {
+ XX_Print("%08x ", *(uint32_t*)p);
+ size -= 4;
+ p += 4;
+ }
+ XX_Print("\r\n");
+ }
+
+ while (size > 15)
+ {
+ XX_Print("0x%08X: %08x %08x %08x %08x\r\n",
+ p, *(uint32_t *)p, *(uint32_t *)(p + 4),
+ *(uint32_t *)(p + 8), *(uint32_t *)(p + 12));
+ size -= 16;
+ p += 16;
+ }
+
+ if (size)
+ {
+ XX_Print("0x%08X: ", p);
+
+ while (size > 3)
+ {
+ XX_Print("%08x ", *(uint32_t *)p);
+ size -= 4;
+ p += 4;
+ }
+ while (size)
+ {
+ XX_Print("%02x", *(uint8_t *)p);
+ size--;
+ p++;
+ }
+
+ XX_Print("\r\n");
+ }
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c
new file mode 100644
index 000000000000..9fcc46e0b26b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c
@@ -0,0 +1,1155 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "string_ext.h"
+#include "error_ext.h"
+#include "std_ext.h"
+#include "part_ext.h"
+#include "xx_ext.h"
+
+#include "mm.h"
+
+
+
+
+/**********************************************************************
+ * MM internal routines set *
+ **********************************************************************/
+
+/****************************************************************
+ * Routine: CreateBusyBlock
+ *
+ * Description:
+ * Initializes a new busy block of "size" bytes and started
+ * rom "base" address. Each busy block has a name that
+ * specified the purpose of the memory allocation.
+ *
+ * Arguments:
+ * base - base address of the busy block
+ * size - size of the busy block
+ * name - name that specified the busy block
+ *
+ * Return value:
+ * A pointer to new created structure returned on success;
+ * Otherwise, NULL.
+ ****************************************************************/
+static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name)
+{
+ t_BusyBlock *p_BusyBlock;
+ uint32_t n;
+
+ p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock));
+ if ( !p_BusyBlock )
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ return NULL;
+ }
+
+ p_BusyBlock->base = base;
+ p_BusyBlock->end = base + size;
+
+ n = strlen(name);
+ if (n >= MM_MAX_NAME_LEN)
+ n = MM_MAX_NAME_LEN - 1;
+ strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1);
+ p_BusyBlock->name[n] = '\0';
+ p_BusyBlock->p_Next = 0;
+
+ return p_BusyBlock;
+}
+
+/****************************************************************
+ * Routine: CreateNewBlock
+ *
+ * Description:
+ * Initializes a new memory block of "size" bytes and started
+ * from "base" address.
+ *
+ * Arguments:
+ * base - base address of the memory block
+ * size - size of the memory block
+ *
+ * Return value:
+ * A pointer to new created structure returned on success;
+ * Otherwise, NULL.
+ ****************************************************************/
+static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size)
+{
+ t_MemBlock *p_MemBlock;
+
+ p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock));
+ if ( !p_MemBlock )
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ return NULL;
+ }
+
+ p_MemBlock->base = base;
+ p_MemBlock->end = base+size;
+ p_MemBlock->p_Next = 0;
+
+ return p_MemBlock;
+}
+
+/****************************************************************
+ * Routine: CreateFreeBlock
+ *
+ * Description:
+ * Initializes a new free block of of "size" bytes and
+ * started from "base" address.
+ *
+ * Arguments:
+ * base - base address of the free block
+ * size - size of the free block
+ *
+ * Return value:
+ * A pointer to new created structure returned on success;
+ * Otherwise, NULL.
+ ****************************************************************/
+static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size)
+{
+ t_FreeBlock *p_FreeBlock;
+
+ p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock));
+ if ( !p_FreeBlock )
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ return NULL;
+ }
+
+ p_FreeBlock->base = base;
+ p_FreeBlock->end = base + size;
+ p_FreeBlock->p_Next = 0;
+
+ return p_FreeBlock;
+}
+
+/****************************************************************
+ * Routine: AddFree
+ *
+ * Description:
+ * Adds a new free block to the free lists. It updates each
+ * free list to include a new free block.
+ * Note, that all free block in each free list are ordered
+ * by their base address.
+ *
+ * Arguments:
+ * p_MM - pointer to the MM object
+ * base - base address of a given free block
+ * end - end address of a given free block
+ *
+ * Return value:
+ *
+ *
+ ****************************************************************/
+static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end)
+{
+ t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
+ uint64_t alignment;
+ uint64_t alignBase;
+ int i;
+
+ /* Updates free lists to include a just released block */
+ for (i=0; i <= MM_MAX_ALIGNMENT; i++)
+ {
+ p_PrevB = p_NewB = 0;
+ p_CurrB = p_MM->freeBlocks[i];
+
+ alignment = (uint64_t)(0x1 << i);
+ alignBase = MAKE_ALIGNED(base, alignment);
+
+ /* Goes to the next free list if there is no block to free */
+ if (alignBase >= end)
+ continue;
+
+ /* Looks for a free block that should be updated */
+ while ( p_CurrB )
+ {
+ if ( alignBase <= p_CurrB->end )
+ {
+ if ( end > p_CurrB->end )
+ {
+ t_FreeBlock *p_NextB;
+ while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end )
+ {
+ p_NextB = p_CurrB->p_Next;
+ p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
+ XX_Free(p_NextB);
+ }
+
+ p_NextB = p_CurrB->p_Next;
+ if ( !p_NextB || (p_NextB && end < p_NextB->base) )
+ {
+ p_CurrB->end = end;
+ }
+ else
+ {
+ p_CurrB->end = p_NextB->end;
+ p_CurrB->p_Next = p_NextB->p_Next;
+ XX_Free(p_NextB);
+ }
+ }
+ else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) )
+ {
+ if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+
+ p_NewB->p_Next = p_CurrB;
+ if (p_PrevB)
+ p_PrevB->p_Next = p_NewB;
+ else
+ p_MM->freeBlocks[i] = p_NewB;
+ break;
+ }
+
+ if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base))
+ {
+ p_CurrB->base = alignBase;
+ }
+
+ /* if size of the free block is less then alignment
+ * deletes that free block from the free list. */
+ if ( (p_CurrB->end - p_CurrB->base) < alignment)
+ {
+ if ( p_PrevB )
+ p_PrevB->p_Next = p_CurrB->p_Next;
+ else
+ p_MM->freeBlocks[i] = p_CurrB->p_Next;
+ XX_Free(p_CurrB);
+ p_CurrB = NULL;
+ }
+ break;
+ }
+ else
+ {
+ p_PrevB = p_CurrB;
+ p_CurrB = p_CurrB->p_Next;
+ }
+ }
+
+ /* If no free block found to be updated, insert a new free block
+ * to the end of the free list.
+ */
+ if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )
+ {
+ if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+
+ if (p_PrevB)
+ p_PrevB->p_Next = p_NewB;
+ else
+ p_MM->freeBlocks[i] = p_NewB;
+ }
+
+ /* Update boundaries of the new free block */
+ if ((alignment == 1) && !p_NewB)
+ {
+ if ( p_CurrB && base > p_CurrB->base )
+ base = p_CurrB->base;
+ if ( p_CurrB && end < p_CurrB->end )
+ end = p_CurrB->end;
+ }
+ }
+
+ return (E_OK);
+}
+
+/****************************************************************
+ * Routine: CutFree
+ *
+ * Description:
+ * Cuts a free block from holdBase to holdEnd from the free lists.
+ * That is, it updates all free lists of the MM object do
+ * not include a block of memory from holdBase to holdEnd.
+ * For each free lists it seek for a free block that holds
+ * either holdBase or holdEnd. If such block is found it updates it.
+ *
+ * Arguments:
+ * p_MM - pointer to the MM object
+ * holdBase - base address of the allocated block
+ * holdEnd - end address of the allocated block
+ *
+ * Return value:
+ * E_OK is returned on success,
+ * otherwise returns an error code.
+ *
+ ****************************************************************/
+static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)
+{
+ t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
+ uint64_t alignBase, base, end;
+ uint64_t alignment;
+ int i;
+
+ for (i=0; i <= MM_MAX_ALIGNMENT; i++)
+ {
+ p_PrevB = p_NewB = 0;
+ p_CurrB = p_MM->freeBlocks[i];
+
+ alignment = (uint64_t)(0x1 << i);
+ alignBase = MAKE_ALIGNED(holdEnd, alignment);
+
+ while ( p_CurrB )
+ {
+ base = p_CurrB->base;
+ end = p_CurrB->end;
+
+ if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )
+ {
+ if ( alignBase >= end ||
+ (alignBase < end && ((end-alignBase) < alignment)) )
+ {
+ if (p_PrevB)
+ p_PrevB->p_Next = p_CurrB->p_Next;
+ else
+ p_MM->freeBlocks[i] = p_CurrB->p_Next;
+ XX_Free(p_CurrB);
+ }
+ else
+ {
+ p_CurrB->base = alignBase;
+ }
+ break;
+ }
+ else if ( (holdBase > base) && (holdEnd <= end) )
+ {
+ if ( (holdBase-base) >= alignment )
+ {
+ if ( (alignBase < end) && ((end-alignBase) >= alignment) )
+ {
+ if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ p_NewB->p_Next = p_CurrB->p_Next;
+ p_CurrB->p_Next = p_NewB;
+ }
+ p_CurrB->end = holdBase;
+ }
+ else if ( (alignBase < end) && ((end-alignBase) >= alignment) )
+ {
+ p_CurrB->base = alignBase;
+ }
+ else
+ {
+ if (p_PrevB)
+ p_PrevB->p_Next = p_CurrB->p_Next;
+ else
+ p_MM->freeBlocks[i] = p_CurrB->p_Next;
+ XX_Free(p_CurrB);
+ }
+ break;
+ }
+ else
+ {
+ p_PrevB = p_CurrB;
+ p_CurrB = p_CurrB->p_Next;
+ }
+ }
+ }
+
+ return (E_OK);
+}
+
+/****************************************************************
+ * Routine: AddBusy
+ *
+ * Description:
+ * Adds a new busy block to the list of busy blocks. Note,
+ * that all busy blocks are ordered by their base address in
+ * the busy list.
+ *
+ * Arguments:
+ * MM - handler to the MM object
+ * p_NewBusyB - pointer to the a busy block
+ *
+ * Return value:
+ * None.
+ *
+ ****************************************************************/
+static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)
+{
+ t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;
+
+ /* finds a place of a new busy block in the list of busy blocks */
+ p_PrevBusyB = 0;
+ p_CurrBusyB = p_MM->busyBlocks;
+
+ while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )
+ {
+ p_PrevBusyB = p_CurrBusyB;
+ p_CurrBusyB = p_CurrBusyB->p_Next;
+ }
+
+ /* insert the new busy block into the list of busy blocks */
+ if ( p_CurrBusyB )
+ p_NewBusyB->p_Next = p_CurrBusyB;
+ if ( p_PrevBusyB )
+ p_PrevBusyB->p_Next = p_NewBusyB;
+ else
+ p_MM->busyBlocks = p_NewBusyB;
+}
+
+/****************************************************************
+ * Routine: CutBusy
+ *
+ * Description:
+ * Cuts a block from base to end from the list of busy blocks.
+ * This is done by updating the list of busy blocks do not
+ * include a given block, that block is going to be free. If a
+ * given block is a part of some other busy block, so that
+ * busy block is updated. If there are number of busy blocks
+ * included in the given block, so all that blocks are removed
+ * from the busy list and the end blocks are updated.
+ * If the given block devides some block into two parts, a new
+ * busy block is added to the busy list.
+ *
+ * Arguments:
+ * p_MM - pointer to the MM object
+ * base - base address of a given busy block
+ * end - end address of a given busy block
+ *
+ * Return value:
+ * E_OK on success, E_NOMEMORY otherwise.
+ *
+ ****************************************************************/
+static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)
+{
+ t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB;
+
+ p_CurrB = p_MM->busyBlocks;
+ p_PrevB = p_NewB = 0;
+
+ while ( p_CurrB )
+ {
+ if ( base < p_CurrB->end )
+ {
+ if ( end > p_CurrB->end )
+ {
+ t_BusyBlock *p_NextB;
+ while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )
+ {
+ p_NextB = p_CurrB->p_Next;
+ p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
+ XX_Free(p_NextB);
+ }
+
+ p_NextB = p_CurrB->p_Next;
+ if ( p_NextB && end > p_NextB->base )
+ {
+ p_NextB->base = end;
+ }
+ }
+
+ if ( base <= p_CurrB->base )
+ {
+ if ( end < p_CurrB->end && end > p_CurrB->base )
+ {
+ p_CurrB->base = end;
+ }
+ else if ( end >= p_CurrB->end )
+ {
+ if ( p_PrevB )
+ p_PrevB->p_Next = p_CurrB->p_Next;
+ else
+ p_MM->busyBlocks = p_CurrB->p_Next;
+ XX_Free(p_CurrB);
+ }
+ }
+ else
+ {
+ if ( end < p_CurrB->end && end > p_CurrB->base )
+ {
+ if ((p_NewB = CreateBusyBlock(end,
+ p_CurrB->end-end,
+ p_CurrB->name)) == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ p_NewB->p_Next = p_CurrB->p_Next;
+ p_CurrB->p_Next = p_NewB;
+ }
+ p_CurrB->end = base;
+ }
+ break;
+ }
+ else
+ {
+ p_PrevB = p_CurrB;
+ p_CurrB = p_CurrB->p_Next;
+ }
+ }
+
+ return (E_OK);
+}
+
+/****************************************************************
+ * Routine: MmGetGreaterAlignment
+ *
+ * Description:
+ * Allocates a block of memory according to the given size
+ * and the alignment. That routine is called from the MM_Get
+ * routine if the required alignment is greater then MM_MAX_ALIGNMENT.
+ * In that case, it goes over free blocks of 64 byte align list
+ * and checks if it has the required size of bytes of the required
+ * alignment. If no blocks found returns ILLEGAL_BASE.
+ * After the block is found and data is allocated, it calls
+ * the internal CutFree routine to update all free lists
+ * do not include a just allocated block. Of course, each
+ * free list contains a free blocks with the same alignment.
+ * It is also creates a busy block that holds
+ * information about an allocated block.
+ *
+ * Arguments:
+ * MM - handle to the MM object
+ * size - size of the MM
+ * alignment - index as a power of two defines
+ * a required alignment that is greater then 64.
+ * name - the name that specifies an allocated block.
+ *
+ * Return value:
+ * base address of an allocated block.
+ * ILLEGAL_BASE if can't allocate a block
+ *
+ ****************************************************************/
+static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)
+{
+ t_FreeBlock *p_FreeB;
+ t_BusyBlock *p_NewBusyB;
+ uint64_t holdBase, holdEnd, alignBase = 0;
+
+ /* goes over free blocks of the 64 byte alignment list
+ and look for a block of the suitable size and
+ base address according to the alignment. */
+ p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];
+
+ while ( p_FreeB )
+ {
+ alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);
+
+ /* the block is found if the aligned base inside the block
+ * and has the anough size. */
+ if ( alignBase >= p_FreeB->base &&
+ alignBase < p_FreeB->end &&
+ size <= (p_FreeB->end - alignBase) )
+ break;
+ else
+ p_FreeB = p_FreeB->p_Next;
+ }
+
+ /* If such block isn't found */
+ if ( !p_FreeB )
+ return (uint64_t)(ILLEGAL_BASE);
+
+ holdBase = alignBase;
+ holdEnd = alignBase + size;
+
+ /* init a new busy block */
+ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
+ return (uint64_t)(ILLEGAL_BASE);
+
+ /* calls Update routine to update a lists of free blocks */
+ if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
+ {
+ XX_Free(p_NewBusyB);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* insert the new busy block into the list of busy blocks */
+ AddBusy ( p_MM, p_NewBusyB );
+
+ return (holdBase);
+}
+
+
+/**********************************************************************
+ * MM API routines set *
+ **********************************************************************/
+
+/*****************************************************************************/
+t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)
+{
+ t_MM *p_MM;
+ uint64_t newBase, newSize;
+ int i;
+
+ if (!size)
+ {
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));
+ }
+
+ /* Initializes a new MM object */
+ p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));
+ if (!p_MM)
+ {
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ }
+
+ p_MM->h_Spinlock = XX_InitSpinlock();
+ if (!p_MM->h_Spinlock)
+ {
+ XX_Free(p_MM);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));
+ }
+
+ /* Initializes counter of free memory to total size */
+ p_MM->freeMemSize = size;
+
+ /* A busy list is empty */
+ p_MM->busyBlocks = 0;
+
+ /* Initializes a new memory block */
+ if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)
+ {
+ MM_Free(p_MM);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ }
+
+ /* Initializes a new free block for each free list*/
+ for (i=0; i <= MM_MAX_ALIGNMENT; i++)
+ {
+ newBase = MAKE_ALIGNED( base, (0x1 << i) );
+ newSize = size - (newBase - base);
+
+ if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)
+ {
+ MM_Free(p_MM);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ }
+ }
+
+ *h_MM = p_MM;
+
+ return (E_OK);
+}
+
+/*****************************************************************************/
+void MM_Free(t_Handle h_MM)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_MemBlock *p_MemBlock;
+ t_BusyBlock *p_BusyBlock;
+ t_FreeBlock *p_FreeBlock;
+ void *p_Block;
+ int i;
+
+ ASSERT_COND(p_MM);
+
+ /* release memory allocated for busy blocks */
+ p_BusyBlock = p_MM->busyBlocks;
+ while ( p_BusyBlock )
+ {
+ p_Block = p_BusyBlock;
+ p_BusyBlock = p_BusyBlock->p_Next;
+ XX_Free(p_Block);
+ }
+
+ /* release memory allocated for free blocks */
+ for (i=0; i <= MM_MAX_ALIGNMENT; i++)
+ {
+ p_FreeBlock = p_MM->freeBlocks[i];
+ while ( p_FreeBlock )
+ {
+ p_Block = p_FreeBlock;
+ p_FreeBlock = p_FreeBlock->p_Next;
+ XX_Free(p_Block);
+ }
+ }
+
+ /* release memory allocated for memory blocks */
+ p_MemBlock = p_MM->memBlocks;
+ while ( p_MemBlock )
+ {
+ p_Block = p_MemBlock;
+ p_MemBlock = p_MemBlock->p_Next;
+ XX_Free(p_Block);
+ }
+
+ if (p_MM->h_Spinlock)
+ XX_FreeSpinlock(p_MM->h_Spinlock);
+
+ /* release memory allocated for MM object itself */
+ XX_Free(p_MM);
+}
+
+/*****************************************************************************/
+uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_FreeBlock *p_FreeB;
+ t_BusyBlock *p_NewBusyB;
+ uint64_t holdBase, holdEnd, j, i = 0;
+ uint32_t intFlags;
+
+ SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);
+
+ /* checks that alignment value is greater then zero */
+ if (alignment == 0)
+ {
+ alignment = 1;
+ }
+
+ j = alignment;
+
+ /* checks if alignment is a power of two, if it correct and if the
+ required size is multiple of the given alignment. */
+ while ((j & 0x1) == 0)
+ {
+ i++;
+ j = j >> 1;
+ }
+
+ /* if the given alignment isn't power of two, returns an error */
+ if (j != 1)
+ {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));
+ return (uint64_t)ILLEGAL_BASE;
+ }
+
+ if (i > MM_MAX_ALIGNMENT)
+ {
+ return (MmGetGreaterAlignment(p_MM, size, alignment, name));
+ }
+
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+ /* look for a block of the size greater or equal to the required size. */
+ p_FreeB = p_MM->freeBlocks[i];
+ while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )
+ p_FreeB = p_FreeB->p_Next;
+
+ /* If such block is found */
+ if ( !p_FreeB )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ holdBase = p_FreeB->base;
+ holdEnd = holdBase + size;
+
+ /* init a new busy block */
+ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* calls Update routine to update a lists of free blocks */
+ if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ XX_Free(p_NewBusyB);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* Decreasing the allocated memory size from free memory size */
+ p_MM->freeMemSize -= size;
+
+ /* insert the new busy block into the list of busy blocks */
+ AddBusy ( p_MM, p_NewBusyB );
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (holdBase);
+}
+
+/*****************************************************************************/
+uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_FreeBlock *p_FreeB;
+ t_BusyBlock *p_NewBusyB;
+ uint32_t intFlags;
+ bool blockIsFree = FALSE;
+
+ ASSERT_COND(p_MM);
+
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+ p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the
+ free list with alignment 1 */
+
+ while ( p_FreeB )
+ {
+ if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )
+ {
+ blockIsFree = TRUE;
+ break;
+ }
+ else
+ p_FreeB = p_FreeB->p_Next;
+ }
+
+ if ( !blockIsFree )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* init a new busy block */
+ if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* calls Update routine to update a lists of free blocks */
+ if ( CutFree ( p_MM, base, base+size ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ XX_Free(p_NewBusyB);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* Decreasing the allocated memory size from free memory size */
+ p_MM->freeMemSize -= size;
+
+ /* insert the new busy block into the list of busy blocks */
+ AddBusy ( p_MM, p_NewBusyB );
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (base);
+}
+
+/*****************************************************************************/
+uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_FreeBlock *p_FreeB;
+ t_BusyBlock *p_NewBusyB;
+ uint64_t holdBase, holdEnd, j = alignment, i=0;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_MM);
+
+ /* checks if alignment is a power of two, if it correct and if the
+ required size is multiple of the given alignment. */
+ while ((j & 0x1) == 0)
+ {
+ i++;
+ j = j >> 1;
+ }
+
+ if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )
+ {
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+ p_FreeB = p_MM->freeBlocks[i];
+
+ /* look for the first block that contains the minimum
+ base address. If the whole required size may be fit
+ into it, use that block, otherwise look for the next
+ block of size greater or equal to the required size. */
+ while ( p_FreeB && (min >= p_FreeB->end))
+ p_FreeB = p_FreeB->p_Next;
+
+ /* If such block is found */
+ if ( !p_FreeB )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* if this block is large enough, use this block */
+ holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;
+ if ((holdBase + size) <= p_FreeB->end )
+ {
+ holdEnd = holdBase + size;
+ }
+ else
+ {
+ p_FreeB = p_FreeB->p_Next;
+ while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )
+ p_FreeB = p_FreeB->p_Next;
+
+ /* If such block is found */
+ if ( !p_FreeB )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ holdBase = p_FreeB->base;
+ holdEnd = holdBase + size;
+ }
+
+ /* init a new busy block */
+ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* calls Update routine to update a lists of free blocks */
+ if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ XX_Free(p_NewBusyB);
+ return (uint64_t)(ILLEGAL_BASE);
+ }
+
+ /* Decreasing the allocated memory size from free memory size */
+ p_MM->freeMemSize -= size;
+
+ /* insert the new busy block into the list of busy blocks */
+ AddBusy( p_MM, p_NewBusyB );
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (holdBase);
+}
+
+/*****************************************************************************/
+uint64_t MM_Put(t_Handle h_MM, uint64_t base)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_BusyBlock *p_BusyB, *p_PrevBusyB;
+ uint64_t size;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_MM);
+
+ /* Look for a busy block that have the given base value.
+ * That block will be returned back to the memory.
+ */
+ p_PrevBusyB = 0;
+
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+ p_BusyB = p_MM->busyBlocks;
+ while ( p_BusyB && base != p_BusyB->base )
+ {
+ p_PrevBusyB = p_BusyB;
+ p_BusyB = p_BusyB->p_Next;
+ }
+
+ if ( !p_BusyB )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(0);
+ }
+
+ if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(0);
+ }
+
+ /* removes a busy block form the list of busy blocks */
+ if ( p_PrevBusyB )
+ p_PrevBusyB->p_Next = p_BusyB->p_Next;
+ else
+ p_MM->busyBlocks = p_BusyB->p_Next;
+
+ size = p_BusyB->end - p_BusyB->base;
+
+ /* Adding the deallocated memory size to free memory size */
+ p_MM->freeMemSize += size;
+
+ XX_Free(p_BusyB);
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (size);
+}
+
+/*****************************************************************************/
+uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ uint64_t end = base + size;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_MM);
+
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+
+ if ( CutBusy( p_MM, base, end ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(0);
+ }
+
+ if ( AddFree ( p_MM, base, end ) != E_OK )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ return (uint64_t)(0);
+ }
+
+ /* Adding the deallocated memory size to free memory size */
+ p_MM->freeMemSize += size;
+
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (size);
+}
+
+/*****************************************************************************/
+t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_MemBlock *p_MemB, *p_NewMemB;
+ t_Error errCode;
+ uint32_t intFlags;
+
+ ASSERT_COND(p_MM);
+
+ /* find a last block in the list of memory blocks to insert a new
+ * memory block
+ */
+ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
+
+ p_MemB = p_MM->memBlocks;
+ while ( p_MemB->p_Next )
+ {
+ if ( base >= p_MemB->base && base < p_MemB->end )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
+ }
+ p_MemB = p_MemB->p_Next;
+ }
+ /* check for a last memory block */
+ if ( base >= p_MemB->base && base < p_MemB->end )
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
+ }
+
+ /* create a new memory block */
+ if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ }
+
+ /* append a new memory block to the end of the list of memory blocks */
+ p_MemB->p_Next = p_NewMemB;
+
+ /* add a new free block to the free lists */
+ errCode = AddFree(p_MM, base, base+size);
+ if (errCode)
+ {
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+ p_MemB->p_Next = 0;
+ XX_Free(p_NewMemB);
+ return ((t_Error)errCode);
+ }
+
+ /* Adding the new block size to free memory size */
+ p_MM->freeMemSize += size;
+
+ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
+
+ return (E_OK);
+}
+
+/*****************************************************************************/
+uint64_t MM_GetMemBlock(t_Handle h_MM, int index)
+{
+ t_MM *p_MM = (t_MM*)h_MM;
+ t_MemBlock *p_MemBlock;
+ int i;
+
+ ASSERT_COND(p_MM);
+
+ p_MemBlock = p_MM->memBlocks;
+ for (i=0; i < index; i++)
+ p_MemBlock = p_MemBlock->p_Next;
+
+ if ( p_MemBlock )
+ return (p_MemBlock->base);
+ else
+ return (uint64_t)ILLEGAL_BASE;
+}
+
+/*****************************************************************************/
+uint64_t MM_GetBase(t_Handle h_MM)
+{
+ t_MM *p_MM = (t_MM*)h_MM;
+ t_MemBlock *p_MemBlock;
+
+ ASSERT_COND(p_MM);
+
+ p_MemBlock = p_MM->memBlocks;
+ return p_MemBlock->base;
+}
+
+/*****************************************************************************/
+bool MM_InRange(t_Handle h_MM, uint64_t addr)
+{
+ t_MM *p_MM = (t_MM*)h_MM;
+ t_MemBlock *p_MemBlock;
+
+ ASSERT_COND(p_MM);
+
+ p_MemBlock = p_MM->memBlocks;
+
+ if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*****************************************************************************/
+uint64_t MM_GetFreeMemSize(t_Handle h_MM)
+{
+ t_MM *p_MM = (t_MM*)h_MM;
+
+ ASSERT_COND(p_MM);
+
+ return p_MM->freeMemSize;
+}
+
+/*****************************************************************************/
+void MM_Dump(t_Handle h_MM)
+{
+ t_MM *p_MM = (t_MM *)h_MM;
+ t_FreeBlock *p_FreeB;
+ t_BusyBlock *p_BusyB;
+ int i;
+
+ p_BusyB = p_MM->busyBlocks;
+ XX_Print("List of busy blocks:\n");
+ while (p_BusyB)
+ {
+ XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );
+ p_BusyB = p_BusyB->p_Next;
+ }
+
+ XX_Print("\nLists of free blocks according to alignment:\n");
+ for (i=0; i <= MM_MAX_ALIGNMENT; i++)
+ {
+ XX_Print("%d alignment:\n", (0x1 << i));
+ p_FreeB = p_MM->freeBlocks[i];
+ while (p_FreeB)
+ {
+ XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end);
+ p_FreeB = p_FreeB->p_Next;
+ }
+ XX_Print("\n");
+ }
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h
new file mode 100644
index 000000000000..43b2298fce5d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/****************************************************************
+ *
+ * File: mm.h
+ *
+ *
+ * Description:
+ * MM (Memory Management) object definitions.
+ * It also includes definitions of the Free Block, Busy Block
+ * and Memory Block structures used by the MM object.
+ *
+ ****************************************************************/
+
+#ifndef __MM_H
+#define __MM_H
+
+
+#include "mm_ext.h"
+
+#define __ERR_MODULE__ MODULE_MM
+
+
+#define MAKE_ALIGNED(addr, align) \
+ (((uint64_t)(addr) + ((align) - 1)) & (~(((uint64_t)align) - 1)))
+
+
+/* t_MemBlock data structure defines parameters of the Memory Block */
+typedef struct t_MemBlock
+{
+ struct t_MemBlock *p_Next; /* Pointer to the next memory block */
+
+ uint64_t base; /* Base address of the memory block */
+ uint64_t end; /* End address of the memory block */
+} t_MemBlock;
+
+
+/* t_FreeBlock data structure defines parameters of the Free Block */
+typedef struct t_FreeBlock
+{
+ struct t_FreeBlock *p_Next; /* Pointer to the next free block */
+
+ uint64_t base; /* Base address of the block */
+ uint64_t end; /* End address of the block */
+} t_FreeBlock;
+
+
+/* t_BusyBlock data structure defines parameters of the Busy Block */
+typedef struct t_BusyBlock
+{
+ struct t_BusyBlock *p_Next; /* Pointer to the next free block */
+
+ uint64_t base; /* Base address of the block */
+ uint64_t end; /* End address of the block */
+ char name[MM_MAX_NAME_LEN]; /* That block of memory was allocated for
+ something specified by the Name */
+} t_BusyBlock;
+
+
+/* t_MM data structure defines parameters of the MM object */
+typedef struct t_MM
+{
+ t_Handle h_Spinlock;
+
+ t_MemBlock *memBlocks; /* List of memory blocks (Memory list) */
+ t_BusyBlock *busyBlocks; /* List of busy blocks (Busy list) */
+ t_FreeBlock *freeBlocks[MM_MAX_ALIGNMENT + 1];
+ /* Alignment lists of free blocks (Free lists) */
+
+ uint64_t freeMemSize; /* Total size of free memory (in bytes) */
+} t_MM;
+
+
+#endif /* __MM_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c b/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c
new file mode 100644
index 000000000000..46d2956a2629
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/*------------------------------------------------------*/
+/* File: sprint.c */
+/* */
+/* Description: */
+/* Debug routines (externals) */
+/*------------------------------------------------------*/
+#include "string_ext.h"
+#include "stdlib_ext.h"
+#include "stdarg_ext.h"
+#include "sprint_ext.h"
+#include "std_ext.h"
+#include "xx_ext.h"
+
+
+int Sprint(char * buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsprintf(buf,fmt,args);
+ va_end(args);
+ return i;
+}
+
+int Snprint(char * buf, uint32_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf,size,fmt,args);
+ va_end(args);
+ return i;
+}
+
+#ifndef NCSW_VXWORKS
+int Sscan(const char * buf, const char * fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args,fmt);
+ i = vsscanf(buf,fmt,args);
+ va_end(args);
+ return i;
+}
+#endif /* NCSW_VXWORKS */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h
new file mode 100644
index 000000000000..435b0d2b0d9e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __dflags_h
+#define __dflags_h
+
+
+#define NCSW_LINUX
+
+#define T4240
+#define NCSW_PPC_CORE
+
+#define DEBUG_ERRORS 1
+
+#if defined(DEBUG)
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO
+
+#define DEBUG_XX_MALLOC
+#define DEBUG_MEM_LEAKS
+
+#else
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* (DEBUG) */
+
+#define REPORT_EVENTS 1
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+
+#endif /* __dflags_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h
new file mode 100644
index 000000000000..789eb87964f1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __dflags_h
+#define __dflags_h
+
+
+#define NCSW_LINUX
+
+#define NCSW_PPC_CORE
+
+#define DEBUG_ERRORS 1
+
+#if defined(DEBUG)
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO
+
+#define DEBUG_XX_MALLOC
+#define DEBUG_MEM_LEAKS
+
+#else
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* (DEBUG) */
+
+#define REPORT_EVENTS 1
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+
+#endif /* __dflags_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h
new file mode 100644
index 000000000000..a84d563116c6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/*------------------------------------------------------*/
+/* */
+/* File: crc_mac_addr_ext.h */
+/* */
+/* Description: */
+/* Define a macro that calculate the crc value of */
+/* an Ethernet MAC address (48 bitd address */
+/*------------------------------------------------------*/
+
+#ifndef __crc_mac_addr_ext_h
+#define __crc_mac_addr_ext_h
+
+#include "std_ext.h"
+
+
+static uint32_t crc_table[256] =
+{
+ 0x00000000,
+ 0x77073096,
+ 0xee0e612c,
+ 0x990951ba,
+ 0x076dc419,
+ 0x706af48f,
+ 0xe963a535,
+ 0x9e6495a3,
+ 0x0edb8832,
+ 0x79dcb8a4,
+ 0xe0d5e91e,
+ 0x97d2d988,
+ 0x09b64c2b,
+ 0x7eb17cbd,
+ 0xe7b82d07,
+ 0x90bf1d91,
+ 0x1db71064,
+ 0x6ab020f2,
+ 0xf3b97148,
+ 0x84be41de,
+ 0x1adad47d,
+ 0x6ddde4eb,
+ 0xf4d4b551,
+ 0x83d385c7,
+ 0x136c9856,
+ 0x646ba8c0,
+ 0xfd62f97a,
+ 0x8a65c9ec,
+ 0x14015c4f,
+ 0x63066cd9,
+ 0xfa0f3d63,
+ 0x8d080df5,
+ 0x3b6e20c8,
+ 0x4c69105e,
+ 0xd56041e4,
+ 0xa2677172,
+ 0x3c03e4d1,
+ 0x4b04d447,
+ 0xd20d85fd,
+ 0xa50ab56b,
+ 0x35b5a8fa,
+ 0x42b2986c,
+ 0xdbbbc9d6,
+ 0xacbcf940,
+ 0x32d86ce3,
+ 0x45df5c75,
+ 0xdcd60dcf,
+ 0xabd13d59,
+ 0x26d930ac,
+ 0x51de003a,
+ 0xc8d75180,
+ 0xbfd06116,
+ 0x21b4f4b5,
+ 0x56b3c423,
+ 0xcfba9599,
+ 0xb8bda50f,
+ 0x2802b89e,
+ 0x5f058808,
+ 0xc60cd9b2,
+ 0xb10be924,
+ 0x2f6f7c87,
+ 0x58684c11,
+ 0xc1611dab,
+ 0xb6662d3d,
+ 0x76dc4190,
+ 0x01db7106,
+ 0x98d220bc,
+ 0xefd5102a,
+ 0x71b18589,
+ 0x06b6b51f,
+ 0x9fbfe4a5,
+ 0xe8b8d433,
+ 0x7807c9a2,
+ 0x0f00f934,
+ 0x9609a88e,
+ 0xe10e9818,
+ 0x7f6a0dbb,
+ 0x086d3d2d,
+ 0x91646c97,
+ 0xe6635c01,
+ 0x6b6b51f4,
+ 0x1c6c6162,
+ 0x856530d8,
+ 0xf262004e,
+ 0x6c0695ed,
+ 0x1b01a57b,
+ 0x8208f4c1,
+ 0xf50fc457,
+ 0x65b0d9c6,
+ 0x12b7e950,
+ 0x8bbeb8ea,
+ 0xfcb9887c,
+ 0x62dd1ddf,
+ 0x15da2d49,
+ 0x8cd37cf3,
+ 0xfbd44c65,
+ 0x4db26158,
+ 0x3ab551ce,
+ 0xa3bc0074,
+ 0xd4bb30e2,
+ 0x4adfa541,
+ 0x3dd895d7,
+ 0xa4d1c46d,
+ 0xd3d6f4fb,
+ 0x4369e96a,
+ 0x346ed9fc,
+ 0xad678846,
+ 0xda60b8d0,
+ 0x44042d73,
+ 0x33031de5,
+ 0xaa0a4c5f,
+ 0xdd0d7cc9,
+ 0x5005713c,
+ 0x270241aa,
+ 0xbe0b1010,
+ 0xc90c2086,
+ 0x5768b525,
+ 0x206f85b3,
+ 0xb966d409,
+ 0xce61e49f,
+ 0x5edef90e,
+ 0x29d9c998,
+ 0xb0d09822,
+ 0xc7d7a8b4,
+ 0x59b33d17,
+ 0x2eb40d81,
+ 0xb7bd5c3b,
+ 0xc0ba6cad,
+ 0xedb88320,
+ 0x9abfb3b6,
+ 0x03b6e20c,
+ 0x74b1d29a,
+ 0xead54739,
+ 0x9dd277af,
+ 0x04db2615,
+ 0x73dc1683,
+ 0xe3630b12,
+ 0x94643b84,
+ 0x0d6d6a3e,
+ 0x7a6a5aa8,
+ 0xe40ecf0b,
+ 0x9309ff9d,
+ 0x0a00ae27,
+ 0x7d079eb1,
+ 0xf00f9344,
+ 0x8708a3d2,
+ 0x1e01f268,
+ 0x6906c2fe,
+ 0xf762575d,
+ 0x806567cb,
+ 0x196c3671,
+ 0x6e6b06e7,
+ 0xfed41b76,
+ 0x89d32be0,
+ 0x10da7a5a,
+ 0x67dd4acc,
+ 0xf9b9df6f,
+ 0x8ebeeff9,
+ 0x17b7be43,
+ 0x60b08ed5,
+ 0xd6d6a3e8,
+ 0xa1d1937e,
+ 0x38d8c2c4,
+ 0x4fdff252,
+ 0xd1bb67f1,
+ 0xa6bc5767,
+ 0x3fb506dd,
+ 0x48b2364b,
+ 0xd80d2bda,
+ 0xaf0a1b4c,
+ 0x36034af6,
+ 0x41047a60,
+ 0xdf60efc3,
+ 0xa867df55,
+ 0x316e8eef,
+ 0x4669be79,
+ 0xcb61b38c,
+ 0xbc66831a,
+ 0x256fd2a0,
+ 0x5268e236,
+ 0xcc0c7795,
+ 0xbb0b4703,
+ 0x220216b9,
+ 0x5505262f,
+ 0xc5ba3bbe,
+ 0xb2bd0b28,
+ 0x2bb45a92,
+ 0x5cb36a04,
+ 0xc2d7ffa7,
+ 0xb5d0cf31,
+ 0x2cd99e8b,
+ 0x5bdeae1d,
+ 0x9b64c2b0,
+ 0xec63f226,
+ 0x756aa39c,
+ 0x026d930a,
+ 0x9c0906a9,
+ 0xeb0e363f,
+ 0x72076785,
+ 0x05005713,
+ 0x95bf4a82,
+ 0xe2b87a14,
+ 0x7bb12bae,
+ 0x0cb61b38,
+ 0x92d28e9b,
+ 0xe5d5be0d,
+ 0x7cdcefb7,
+ 0x0bdbdf21,
+ 0x86d3d2d4,
+ 0xf1d4e242,
+ 0x68ddb3f8,
+ 0x1fda836e,
+ 0x81be16cd,
+ 0xf6b9265b,
+ 0x6fb077e1,
+ 0x18b74777,
+ 0x88085ae6,
+ 0xff0f6a70,
+ 0x66063bca,
+ 0x11010b5c,
+ 0x8f659eff,
+ 0xf862ae69,
+ 0x616bffd3,
+ 0x166ccf45,
+ 0xa00ae278,
+ 0xd70dd2ee,
+ 0x4e048354,
+ 0x3903b3c2,
+ 0xa7672661,
+ 0xd06016f7,
+ 0x4969474d,
+ 0x3e6e77db,
+ 0xaed16a4a,
+ 0xd9d65adc,
+ 0x40df0b66,
+ 0x37d83bf0,
+ 0xa9bcae53,
+ 0xdebb9ec5,
+ 0x47b2cf7f,
+ 0x30b5ffe9,
+ 0xbdbdf21c,
+ 0xcabac28a,
+ 0x53b39330,
+ 0x24b4a3a6,
+ 0xbad03605,
+ 0xcdd70693,
+ 0x54de5729,
+ 0x23d967bf,
+ 0xb3667a2e,
+ 0xc4614ab8,
+ 0x5d681b02,
+ 0x2a6f2b94,
+ 0xb40bbe37,
+ 0xc30c8ea1,
+ 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+
+#define GET_MAC_ADDR_CRC(addr, crc) \
+{ \
+ uint32_t i; \
+ uint8_t data; \
+ \
+ /* CRC calculation */ \
+ crc = 0xffffffff; \
+ for (i=0; i < 6; i++) \
+ { \
+ data = (uint8_t)(addr >> ((5-i)*8)); \
+ crc = crc^data; \
+ crc = crc_table[crc&0xff] ^ (crc>>8); \
+ } \
+} \
+
+/* Define a macro for getting the mirrored value of */
+/* a byte size number. (0x11010011 --> 0x11001011) */
+/* Sometimes the mirrored value of the CRC is required */
+static __inline__ uint8_t GetMirror(uint8_t n)
+{
+ uint8_t mirror[16] =
+ {
+ 0x00,
+ 0x08,
+ 0x04,
+ 0x0c,
+ 0x02,
+ 0x0a,
+ 0x06,
+ 0x0e,
+ 0x01,
+ 0x09,
+ 0x05,
+ 0x0d,
+ 0x03,
+ 0x0b,
+ 0x07,
+ 0x0f
+ };
+ return ((uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))));
+}
+
+static __inline__ uint32_t GetMirror32(uint32_t n)
+{
+ return (((uint32_t)GetMirror((uint8_t)(n))<<24) |
+ ((uint32_t)GetMirror((uint8_t)(n>>8))<<16) |
+ ((uint32_t)GetMirror((uint8_t)(n>>16))<<8) |
+ ((uint32_t)GetMirror((uint8_t)(n>>24))));
+}
+
+#define MIRROR GetMirror
+#define MIRROR_32 GetMirror32
+
+
+#endif /* __crc_mac_addr_ext_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h
new file mode 100644
index 000000000000..e6d9e932faa3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h
@@ -0,0 +1,210 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File dpaa_ext.h
+
+ @Description DPAA Application Programming Interface.
+*//***************************************************************************/
+#ifndef __DPAA_EXT_H
+#define __DPAA_EXT_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+
+
+/**************************************************************************//**
+ @Group DPAA_grp Data Path Acceleration Architecture API
+
+ @Description DPAA API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description Frame descriptor
+*//***************************************************************************/
+typedef _Packed struct t_DpaaFD {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ volatile uint8_t liodn;
+ volatile uint8_t bpid;
+ volatile uint8_t elion;
+ volatile uint8_t addrh;
+ volatile uint32_t addrl;
+#else
+ volatile uint32_t addrl;
+ volatile uint8_t addrh;
+ volatile uint8_t elion;
+ volatile uint8_t bpid;
+ volatile uint8_t liodn;
+ #endif
+ volatile uint32_t length; /**< Frame length */
+ volatile uint32_t status; /**< FD status */
+} _PackedType t_DpaaFD;
+
+/**************************************************************************//**
+ @Description enum for defining frame format
+*//***************************************************************************/
+typedef enum e_DpaaFDFormatType {
+ e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF = 0x0, /**< Simple frame Single buffer; Offset and
+ small length (9b OFFSET, 20b LENGTH) */
+ e_DPAA_FD_FORMAT_TYPE_LONG_SBSF = 0x2, /**< Simple frame, single buffer; big length
+ (29b LENGTH ,No OFFSET) */
+ e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF = 0x4, /**< Simple frame, Scatter Gather table; Offset
+ and small length (9b OFFSET, 20b LENGTH) */
+ e_DPAA_FD_FORMAT_TYPE_LONG_MBSF = 0x6, /**< Simple frame, Scatter Gather table;
+ big length (29b LENGTH ,No OFFSET) */
+ e_DPAA_FD_FORMAT_TYPE_COMPOUND = 0x1, /**< Compound Frame (29b CONGESTION-WEIGHT
+ No LENGTH or OFFSET) */
+ e_DPAA_FD_FORMAT_TYPE_DUMMY
+} e_DpaaFDFormatType;
+
+/**************************************************************************//**
+ @Collection Frame descriptor macros
+*//***************************************************************************/
+#define DPAA_FD_DD_MASK 0xc0000000 /**< FD DD field mask */
+#define DPAA_FD_PID_MASK 0x3f000000 /**< FD PID field mask */
+#define DPAA_FD_ELIODN_MASK 0x0000f000 /**< FD ELIODN field mask */
+#define DPAA_FD_BPID_MASK 0x00ff0000 /**< FD BPID field mask */
+#define DPAA_FD_ADDRH_MASK 0x000000ff /**< FD ADDRH field mask */
+#define DPAA_FD_ADDRL_MASK 0xffffffff /**< FD ADDRL field mask */
+#define DPAA_FD_FORMAT_MASK 0xe0000000 /**< FD FORMAT field mask */
+#define DPAA_FD_OFFSET_MASK 0x1ff00000 /**< FD OFFSET field mask */
+#define DPAA_FD_LENGTH_MASK 0x000fffff /**< FD LENGTH field mask */
+
+#define DPAA_FD_GET_ADDRH(fd) ((t_DpaaFD *)fd)->addrh /**< Macro to get FD ADDRH field */
+#define DPAA_FD_GET_ADDRL(fd) ((t_DpaaFD *)fd)->addrl /**< Macro to get FD ADDRL field */
+#define DPAA_FD_GET_PHYS_ADDR(fd) ((physAddress_t)(((uint64_t)DPAA_FD_GET_ADDRH(fd) << 32) | (uint64_t)DPAA_FD_GET_ADDRL(fd))) /**< Macro to get FD ADDR field */
+#define DPAA_FD_GET_FORMAT(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_FORMAT_MASK) >> (31-2)) /**< Macro to get FD FORMAT field */
+#define DPAA_FD_GET_OFFSET(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_OFFSET_MASK) >> (31-11)) /**< Macro to get FD OFFSET field */
+#define DPAA_FD_GET_LENGTH(fd) (((t_DpaaFD *)fd)->length & DPAA_FD_LENGTH_MASK) /**< Macro to get FD LENGTH field */
+#define DPAA_FD_GET_STATUS(fd) ((t_DpaaFD *)fd)->status /**< Macro to get FD STATUS field */
+#define DPAA_FD_GET_ADDR(fd) XX_PhysToVirt(DPAA_FD_GET_PHYS_ADDR(fd)) /**< Macro to get FD ADDR (virtual) */
+
+#define DPAA_FD_SET_ADDRH(fd,val) ((t_DpaaFD *)fd)->addrh = (val) /**< Macro to set FD ADDRH field */
+#define DPAA_FD_SET_ADDRL(fd,val) ((t_DpaaFD *)fd)->addrl = (val) /**< Macro to set FD ADDRL field */
+#define DPAA_FD_SET_ADDR(fd,val) \
+do { \
+ uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \
+ DPAA_FD_SET_ADDRH(fd, ((uint32_t)(physAddr >> 32))); \
+ DPAA_FD_SET_ADDRL(fd, (uint32_t)physAddr); \
+} while (0) /**< Macro to set FD ADDR field */
+#define DPAA_FD_SET_FORMAT(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_FORMAT_MASK) | (((val) << (31-2))& DPAA_FD_FORMAT_MASK))) /**< Macro to set FD FORMAT field */
+#define DPAA_FD_SET_OFFSET(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_OFFSET_MASK) | (((val) << (31-11))& DPAA_FD_OFFSET_MASK) )) /**< Macro to set FD OFFSET field */
+#define DPAA_FD_SET_LENGTH(fd,val) (((t_DpaaFD *)fd)->length = (((t_DpaaFD *)fd)->length & ~DPAA_FD_LENGTH_MASK) | ((val) & DPAA_FD_LENGTH_MASK)) /**< Macro to set FD LENGTH field */
+#define DPAA_FD_SET_STATUS(fd,val) ((t_DpaaFD *)fd)->status = (val) /**< Macro to set FD STATUS field */
+/* @} */
+
+/**************************************************************************//**
+ @Description Frame Scatter/Gather Table Entry
+*//***************************************************************************/
+typedef _Packed struct t_DpaaSGTE {
+ volatile uint32_t addrh; /**< Buffer Address high */
+ volatile uint32_t addrl; /**< Buffer Address low */
+ volatile uint32_t length; /**< Buffer length */
+ volatile uint32_t offset; /**< SGTE offset */
+} _PackedType t_DpaaSGTE;
+
+#define DPAA_NUM_OF_SG_TABLE_ENTRY 16
+
+/**************************************************************************//**
+ @Description Frame Scatter/Gather Table
+*//***************************************************************************/
+typedef _Packed struct t_DpaaSGT {
+ t_DpaaSGTE tableEntry[DPAA_NUM_OF_SG_TABLE_ENTRY];
+ /**< Structure that holds information about
+ a single S/G entry. */
+} _PackedType t_DpaaSGT;
+
+/**************************************************************************//**
+ @Description Compound Frame Table
+*//***************************************************************************/
+typedef _Packed struct t_DpaaCompTbl {
+ t_DpaaSGTE outputBuffInfo; /**< Structure that holds information about
+ the compound-frame output buffer;
+ NOTE: this may point to a S/G table */
+ t_DpaaSGTE inputBuffInfo; /**< Structure that holds information about
+ the compound-frame input buffer;
+ NOTE: this may point to a S/G table */
+} _PackedType t_DpaaCompTbl;
+
+/**************************************************************************//**
+ @Collection Frame Scatter/Gather Table Entry macros
+*//***************************************************************************/
+#define DPAA_SGTE_ADDRH_MASK 0x000000ff /**< SGTE ADDRH field mask */
+#define DPAA_SGTE_ADDRL_MASK 0xffffffff /**< SGTE ADDRL field mask */
+#define DPAA_SGTE_E_MASK 0x80000000 /**< SGTE Extension field mask */
+#define DPAA_SGTE_F_MASK 0x40000000 /**< SGTE Final field mask */
+#define DPAA_SGTE_LENGTH_MASK 0x3fffffff /**< SGTE LENGTH field mask */
+#define DPAA_SGTE_BPID_MASK 0x00ff0000 /**< SGTE BPID field mask */
+#define DPAA_SGTE_OFFSET_MASK 0x00001fff /**< SGTE OFFSET field mask */
+
+#define DPAA_SGTE_GET_ADDRH(sgte) (((t_DpaaSGTE *)sgte)->addrh & DPAA_SGTE_ADDRH_MASK) /**< Macro to get SGTE ADDRH field */
+#define DPAA_SGTE_GET_ADDRL(sgte) ((t_DpaaSGTE *)sgte)->addrl /**< Macro to get SGTE ADDRL field */
+#define DPAA_SGTE_GET_PHYS_ADDR(sgte) ((physAddress_t)(((uint64_t)DPAA_SGTE_GET_ADDRH(sgte) << 32) | (uint64_t)DPAA_SGTE_GET_ADDRL(sgte))) /**< Macro to get FD ADDR field */
+#define DPAA_SGTE_GET_EXTENSION(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_E_MASK) >> (31-0)) /**< Macro to get SGTE EXTENSION field */
+#define DPAA_SGTE_GET_FINAL(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_F_MASK) >> (31-1)) /**< Macro to get SGTE FINAL field */
+#define DPAA_SGTE_GET_LENGTH(sgte) (((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_LENGTH_MASK) /**< Macro to get SGTE LENGTH field */
+#define DPAA_SGTE_GET_BPID(sgte) ((((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_BPID_MASK) >> (31-15)) /**< Macro to get SGTE BPID field */
+#define DPAA_SGTE_GET_OFFSET(sgte) (((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_OFFSET_MASK) /**< Macro to get SGTE OFFSET field */
+#define DPAA_SGTE_GET_ADDR(sgte) XX_PhysToVirt(DPAA_SGTE_GET_PHYS_ADDR(sgte))
+
+#define DPAA_SGTE_SET_ADDRH(sgte,val) (((t_DpaaSGTE *)sgte)->addrh = ((((t_DpaaSGTE *)sgte)->addrh & ~DPAA_SGTE_ADDRH_MASK) | ((val) & DPAA_SGTE_ADDRH_MASK))) /**< Macro to set SGTE ADDRH field */
+#define DPAA_SGTE_SET_ADDRL(sgte,val) ((t_DpaaSGTE *)sgte)->addrl = (val) /**< Macro to set SGTE ADDRL field */
+#define DPAA_SGTE_SET_ADDR(sgte,val) \
+do { \
+ uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \
+ DPAA_SGTE_SET_ADDRH(sgte, ((uint32_t)(physAddr >> 32))); \
+ DPAA_SGTE_SET_ADDRL(sgte, (uint32_t)physAddr); \
+} while (0) /**< Macro to set SGTE ADDR field */
+#define DPAA_SGTE_SET_EXTENSION(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_E_MASK) | (((val) << (31-0))& DPAA_SGTE_E_MASK))) /**< Macro to set SGTE EXTENSION field */
+#define DPAA_SGTE_SET_FINAL(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_F_MASK) | (((val) << (31-1))& DPAA_SGTE_F_MASK))) /**< Macro to set SGTE FINAL field */
+#define DPAA_SGTE_SET_LENGTH(sgte,val) (((t_DpaaSGTE *)sgte)->length = (((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_LENGTH_MASK) | ((val) & DPAA_SGTE_LENGTH_MASK)) /**< Macro to set SGTE LENGTH field */
+#define DPAA_SGTE_SET_BPID(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_BPID_MASK) | (((val) << (31-15))& DPAA_SGTE_BPID_MASK))) /**< Macro to set SGTE BPID field */
+#define DPAA_SGTE_SET_OFFSET(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_OFFSET_MASK) | (((val) << (31-31))& DPAA_SGTE_OFFSET_MASK) )) /**< Macro to set SGTE OFFSET field */
+/* @} */
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+#define DPAA_LIODN_DONT_OVERRIDE (-1)
+
+/** @} */ /* end of DPAA_grp group */
+
+
+#endif /* __DPAA_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h
new file mode 100644
index 000000000000..a8a64386cc45
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h
@@ -0,0 +1,1731 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_ext.h
+
+ @Description FM Application Programming Interface.
+*//***************************************************************************/
+#ifndef __FM_EXT
+#define __FM_EXT
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "dpaa_ext.h"
+#include "fsl_fman_sp.h"
+
+/**************************************************************************//**
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_lib_grp FM library
+
+ @Description FM API functions, definitions and enums.
+
+ The FM module is the main driver module and is a mandatory module
+ for FM driver users. This module must be initialized first prior
+ to any other drivers modules.
+ The FM is a "singleton" module. It is responsible of the common
+ HW modules: FPM, DMA, common QMI and common BMI initializations and
+ run-time control routines. This module must be initialized always
+ when working with any of the FM modules.
+ NOTE - We assume that the FM library will be initialized only by core No. 0!
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Enum for defining port types
+*//***************************************************************************/
+typedef enum e_FmPortType {
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0, /**< Offline parsing port */
+ e_FM_PORT_TYPE_RX, /**< 1G Rx port */
+ e_FM_PORT_TYPE_RX_10G, /**< 10G Rx port */
+ e_FM_PORT_TYPE_TX, /**< 1G Tx port */
+ e_FM_PORT_TYPE_TX_10G, /**< 10G Tx port */
+ e_FM_PORT_TYPE_DUMMY
+} e_FmPortType;
+
+/**************************************************************************//**
+ @Collection General FM defines
+*//***************************************************************************/
+#define FM_MAX_NUM_OF_PARTITIONS 64 /**< Maximum number of partitions */
+#define FM_PHYS_ADDRESS_SIZE 6 /**< FM Physical address size */
+/* @} */
+
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(push,1)
+#endif /* defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Description FM physical Address
+*//***************************************************************************/
+typedef _Packed struct t_FmPhysAddr {
+ volatile uint8_t high; /**< High part of the physical address */
+ volatile uint32_t low; /**< Low part of the physical address */
+} _PackedType t_FmPhysAddr;
+
+/**************************************************************************//**
+ @Description Parse results memory layout
+*//***************************************************************************/
+typedef _Packed struct t_FmPrsResult {
+ volatile uint8_t lpid; /**< Logical port id */
+ volatile uint8_t shimr; /**< Shim header result */
+ volatile uint16_t l2r; /**< Layer 2 result */
+ volatile uint16_t l3r; /**< Layer 3 result */
+ volatile uint8_t l4r; /**< Layer 4 result */
+ volatile uint8_t cplan; /**< Classification plan id */
+ volatile uint16_t nxthdr; /**< Next Header */
+ volatile uint16_t cksum; /**< Running-sum */
+ volatile uint16_t flags_frag_off; /**< Flags & fragment-offset field of the last IP-header */
+ volatile uint8_t route_type; /**< Routing type field of a IPv6 routing extension header */
+ volatile uint8_t rhp_ip_valid; /**< Routing Extension Header Present; last bit is IP valid */
+ volatile uint8_t shim_off[2]; /**< Shim offset */
+ volatile uint8_t ip_pid_off; /**< IP PID (last IP-proto) offset */
+ volatile uint8_t eth_off; /**< ETH offset */
+ volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */
+ volatile uint8_t vlan_off[2]; /**< VLAN offset */
+ volatile uint8_t etype_off; /**< ETYPE offset */
+ volatile uint8_t pppoe_off; /**< PPP offset */
+ volatile uint8_t mpls_off[2]; /**< MPLS offset */
+ volatile uint8_t ip_off[2]; /**< IP offset */
+ volatile uint8_t gre_off; /**< GRE offset */
+ volatile uint8_t l4_off; /**< Layer 4 offset */
+ volatile uint8_t nxthdr_off; /**< Parser end point */
+} _PackedType t_FmPrsResult;
+
+/**************************************************************************//**
+ @Collection FM Parser results
+*//***************************************************************************/
+#define FM_PR_L2_VLAN_STACK 0x00000100 /**< Parse Result: VLAN stack */
+#define FM_PR_L2_ETHERNET 0x00008000 /**< Parse Result: Ethernet*/
+#define FM_PR_L2_VLAN 0x00004000 /**< Parse Result: VLAN */
+#define FM_PR_L2_LLC_SNAP 0x00002000 /**< Parse Result: LLC_SNAP */
+#define FM_PR_L2_MPLS 0x00001000 /**< Parse Result: MPLS */
+#define FM_PR_L2_PPPoE 0x00000800 /**< Parse Result: PPPoE */
+/* @} */
+
+/**************************************************************************//**
+ @Collection FM Frame descriptor macros
+*//***************************************************************************/
+#define FM_FD_CMD_FCO 0x80000000 /**< Frame queue Context Override */
+#define FM_FD_CMD_RPD 0x40000000 /**< Read Prepended Data */
+#define FM_FD_CMD_UPD 0x20000000 /**< Update Prepended Data */
+#define FM_FD_CMD_DTC 0x10000000 /**< Do L4 Checksum */
+#define FM_FD_CMD_DCL4C 0x10000000 /**< Didn't calculate L4 Checksum */
+#define FM_FD_CMD_CFQ 0x00ffffff /**< Confirmation Frame Queue */
+
+#define FM_FD_ERR_UNSUPPORTED_FORMAT 0x04000000 /**< Not for Rx-Port! Unsupported Format */
+#define FM_FD_ERR_LENGTH 0x02000000 /**< Not for Rx-Port! Length Error */
+#define FM_FD_ERR_DMA 0x01000000 /**< DMA Data error */
+
+#define FM_FD_IPR 0x00000001 /**< IPR frame (not error) */
+
+#define FM_FD_ERR_IPR_NCSP (0x00100000 | FM_FD_IPR) /**< IPR non-consistent-sp */
+#define FM_FD_ERR_IPR (0x00200000 | FM_FD_IPR) /**< IPR error */
+#define FM_FD_ERR_IPR_TO (0x00300000 | FM_FD_IPR) /**< IPR timeout */
+
+#ifdef FM_CAPWAP_SUPPORT
+#define FM_FD_ERR_CRE 0x00200000
+#define FM_FD_ERR_CHE 0x00100000
+#endif /* FM_CAPWAP_SUPPORT */
+
+#define FM_FD_ERR_PHYSICAL 0x00080000 /**< Rx FIFO overflow, FCS error, code error, running disparity
+ error (SGMII and TBI modes), FIFO parity error. PHY
+ Sequence error, PHY error control character detected. */
+#define FM_FD_ERR_SIZE 0x00040000 /**< Frame too long OR Frame size exceeds max_length_frame */
+#define FM_FD_ERR_CLS_DISCARD 0x00020000 /**< classification discard */
+#define FM_FD_ERR_EXTRACTION 0x00008000 /**< Extract Out of Frame */
+#define FM_FD_ERR_NO_SCHEME 0x00004000 /**< No Scheme Selected */
+#define FM_FD_ERR_KEYSIZE_OVERFLOW 0x00002000 /**< Keysize Overflow */
+#define FM_FD_ERR_COLOR_RED 0x00000800 /**< Frame color is red */
+#define FM_FD_ERR_COLOR_YELLOW 0x00000400 /**< Frame color is yellow */
+#define FM_FD_ERR_ILL_PLCR 0x00000200 /**< Illegal Policer Profile selected */
+#define FM_FD_ERR_PLCR_FRAME_LEN 0x00000100 /**< Policer frame length error */
+#define FM_FD_ERR_PRS_TIMEOUT 0x00000080 /**< Parser Time out Exceed */
+#define FM_FD_ERR_PRS_ILL_INSTRUCT 0x00000040 /**< Invalid Soft Parser instruction */
+#define FM_FD_ERR_PRS_HDR_ERR 0x00000020 /**< Header error was identified during parsing */
+#define FM_FD_ERR_BLOCK_LIMIT_EXCEEDED 0x00000008 /**< Frame parsed beyind 256 first bytes */
+
+#define FM_FD_TX_STATUS_ERR_MASK (FM_FD_ERR_UNSUPPORTED_FORMAT | \
+ FM_FD_ERR_LENGTH | \
+ FM_FD_ERR_DMA) /**< TX Error FD bits */
+
+#define FM_FD_RX_STATUS_ERR_MASK (FM_FD_ERR_UNSUPPORTED_FORMAT | \
+ FM_FD_ERR_LENGTH | \
+ FM_FD_ERR_DMA | \
+ FM_FD_ERR_IPR | \
+ FM_FD_ERR_IPR_TO | \
+ FM_FD_ERR_IPR_NCSP | \
+ FM_FD_ERR_PHYSICAL | \
+ FM_FD_ERR_SIZE | \
+ FM_FD_ERR_CLS_DISCARD | \
+ FM_FD_ERR_COLOR_RED | \
+ FM_FD_ERR_COLOR_YELLOW | \
+ FM_FD_ERR_ILL_PLCR | \
+ FM_FD_ERR_PLCR_FRAME_LEN | \
+ FM_FD_ERR_EXTRACTION | \
+ FM_FD_ERR_NO_SCHEME | \
+ FM_FD_ERR_KEYSIZE_OVERFLOW | \
+ FM_FD_ERR_PRS_TIMEOUT | \
+ FM_FD_ERR_PRS_ILL_INSTRUCT | \
+ FM_FD_ERR_PRS_HDR_ERR | \
+ FM_FD_ERR_BLOCK_LIMIT_EXCEEDED) /**< RX Error FD bits */
+
+#define FM_FD_RX_STATUS_ERR_NON_FM 0x00400000 /**< non Frame-Manager error */
+/* @} */
+
+/**************************************************************************//**
+ @Description Context A
+*//***************************************************************************/
+typedef _Packed struct t_FmContextA {
+ volatile uint32_t command; /**< ContextA Command */
+ volatile uint8_t res0[4]; /**< ContextA Reserved bits */
+} _PackedType t_FmContextA;
+
+/**************************************************************************//**
+ @Description Context B
+*//***************************************************************************/
+typedef uint32_t t_FmContextB;
+
+/**************************************************************************//**
+ @Collection Special Operation options
+*//***************************************************************************/
+typedef uint32_t fmSpecialOperations_t; /**< typedef for defining Special Operation options */
+
+#define FM_SP_OP_IPSEC 0x80000000 /**< activate features that related to IPSec (e.g fix Eth-type) */
+#define FM_SP_OP_IPSEC_UPDATE_UDP_LEN 0x40000000 /**< update the UDP-Len after Encryption */
+#define FM_SP_OP_IPSEC_MANIP 0x20000000 /**< handle the IPSec-manip options */
+#define FM_SP_OP_RPD 0x10000000 /**< Set the RPD bit */
+#define FM_SP_OP_DCL4C 0x08000000 /**< Set the DCL4C bit */
+#define FM_SP_OP_CHECK_SEC_ERRORS 0x04000000 /**< Check SEC errors */
+#define FM_SP_OP_CLEAR_RPD 0x02000000 /**< Clear the RPD bit */
+#define FM_SP_OP_CAPWAP_DTLS_ENC 0x01000000 /**< activate features that related to CAPWAP-DTLS post Encryption */
+#define FM_SP_OP_CAPWAP_DTLS_DEC 0x00800000 /**< activate features that related to CAPWAP-DTLS post Decryption */
+#define FM_SP_OP_IPSEC_NO_ETH_HDR 0x00400000 /**< activate features that related to IPSec without Eth hdr */
+/* @} */
+
+/**************************************************************************//**
+ @Collection Context A macros
+*//***************************************************************************/
+#define FM_CONTEXTA_OVERRIDE_MASK 0x80000000
+#define FM_CONTEXTA_ICMD_MASK 0x40000000
+#define FM_CONTEXTA_A1_VALID_MASK 0x20000000
+#define FM_CONTEXTA_MACCMD_MASK 0x00ff0000
+#define FM_CONTEXTA_MACCMD_VALID_MASK 0x00800000
+#define FM_CONTEXTA_MACCMD_SECURED_MASK 0x00100000
+#define FM_CONTEXTA_MACCMD_SC_MASK 0x000f0000
+#define FM_CONTEXTA_A1_MASK 0x0000ffff
+
+#define FM_CONTEXTA_GET_OVERRIDE(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_OVERRIDE_MASK) >> (31-0))
+#define FM_CONTEXTA_GET_ICMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_ICMD_MASK) >> (31-1))
+#define FM_CONTEXTA_GET_A1_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_VALID_MASK) >> (31-2))
+#define FM_CONTEXTA_GET_A1(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_MASK) >> (31-31))
+#define FM_CONTEXTA_GET_MACCMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_MASK) >> (31-15))
+#define FM_CONTEXTA_GET_MACCMD_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_VALID_MASK) >> (31-8))
+#define FM_CONTEXTA_GET_MACCMD_SECURED(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SECURED_MASK) >> (31-11))
+#define FM_CONTEXTA_GET_MACCMD_SECURE_CHANNEL(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SC_MASK) >> (31-15))
+
+#define FM_CONTEXTA_SET_OVERRIDE(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_OVERRIDE_MASK) | (((uint32_t)(val) << (31-0)) & FM_CONTEXTA_OVERRIDE_MASK) ))
+#define FM_CONTEXTA_SET_ICMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_ICMD_MASK) | (((val) << (31-1)) & FM_CONTEXTA_ICMD_MASK) ))
+#define FM_CONTEXTA_SET_A1_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_VALID_MASK) | (((val) << (31-2)) & FM_CONTEXTA_A1_VALID_MASK) ))
+#define FM_CONTEXTA_SET_A1(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_MASK) | (((val) << (31-31)) & FM_CONTEXTA_A1_MASK) ))
+#define FM_CONTEXTA_SET_MACCMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_MASK) ))
+#define FM_CONTEXTA_SET_MACCMD_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_VALID_MASK) | (((val) << (31-8)) & FM_CONTEXTA_MACCMD_VALID_MASK) ))
+#define FM_CONTEXTA_SET_MACCMD_SECURED(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SECURED_MASK) | (((val) << (31-11)) & FM_CONTEXTA_MACCMD_SECURED_MASK) ))
+#define FM_CONTEXTA_SET_MACCMD_SECURE_CHANNEL(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SC_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_SC_MASK) ))
+/* @} */
+
+/**************************************************************************//**
+ @Collection Context B macros
+*//***************************************************************************/
+#define FM_CONTEXTB_FQID_MASK 0x00ffffff
+
+#define FM_CONTEXTB_GET_FQID(contextB) (*((t_FmContextB *)contextB) & FM_CONTEXTB_FQID_MASK)
+#define FM_CONTEXTB_SET_FQID(contextB,val) (*((t_FmContextB *)contextB) = ((*((t_FmContextB *)contextB) & ~FM_CONTEXTB_FQID_MASK) | ((val) & FM_CONTEXTB_FQID_MASK)))
+/* @} */
+
+#if defined(__MWERKS__) && !defined(__GNUC__)
+#pragma pack(pop)
+#endif /* defined(__MWERKS__) && ... */
+
+
+/**************************************************************************//**
+ @Description FM Exceptions
+*//***************************************************************************/
+typedef enum e_FmExceptions {
+ e_FM_EX_DMA_BUS_ERROR = 0, /**< DMA bus error. */
+ e_FM_EX_DMA_READ_ECC, /**< Read Buffer ECC error (Valid for FM rev < 6)*/
+ e_FM_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC error on system side (Valid for FM rev < 6)*/
+ e_FM_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side (Valid for FM rev < 6)*/
+ e_FM_EX_DMA_SINGLE_PORT_ECC, /**< Single Port ECC error on FM side (Valid for FM rev > 6)*/
+ e_FM_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */
+ e_FM_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */
+ e_FM_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */
+ e_FM_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */
+ e_FM_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */
+ e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeue from unknown port id */
+ e_FM_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */
+ e_FM_EX_BMI_STORAGE_PROFILE_ECC, /**< Storage Profile ECC Error */
+ e_FM_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics Count RAM ECC Error Enable */
+ e_FM_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */
+ e_FM_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/
+ e_FM_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/
+} e_FmExceptions;
+
+/**************************************************************************//**
+ @Description Enum for defining port DMA swap mode
+*//***************************************************************************/
+typedef enum e_FmDmaSwapOption {
+ e_FM_DMA_NO_SWP = FMAN_DMA_NO_SWP, /**< No swap, transfer data as is.*/
+ e_FM_DMA_SWP_PPC_LE = FMAN_DMA_SWP_PPC_LE, /**< The transferred data should be swapped
+ in PowerPc Little Endian mode. */
+ e_FM_DMA_SWP_BE = FMAN_DMA_SWP_BE /**< The transferred data should be swapped
+ in Big Endian mode */
+} e_FmDmaSwapOption;
+
+/**************************************************************************//**
+ @Description Enum for defining port DMA cache attributes
+*//***************************************************************************/
+typedef enum e_FmDmaCacheOption {
+ e_FM_DMA_NO_STASH = FMAN_DMA_NO_STASH, /**< Cacheable, no Allocate (No Stashing) */
+ e_FM_DMA_STASH = FMAN_DMA_STASH /**< Cacheable and Allocate (Stashing on) */
+} e_FmDmaCacheOption;
+
+
+/**************************************************************************//**
+ @Group FM_init_grp FM Initialization Unit
+
+ @Description FM Initialization Unit
+
+ Initialization Flow
+ Initialization of the FM Module will be carried out by the application
+ according to the following sequence:
+ - Calling the configuration routine with basic parameters.
+ - Calling the advance initialization routines to change driver's defaults.
+ - Calling the initialization routine.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function t_FmExceptionsCallback
+
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] exception - The exception.
+*//***************************************************************************/
+typedef void (t_FmExceptionsCallback)(t_Handle h_App,
+ e_FmExceptions exception);
+
+
+/**************************************************************************//**
+ @Function t_FmBusErrorCallback
+
+ @Description Bus error user callback routine, will be called upon a
+ bus error, passing parameters describing the errors and the owner.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] portType - Port type (e_FmPortType)
+ @Param[in] portId - Port id - relative to type.
+ @Param[in] addr - Address that caused the error
+ @Param[in] tnum - Owner of error
+ @Param[in] liodn - Logical IO device number
+*//***************************************************************************/
+typedef void (t_FmBusErrorCallback) (t_Handle h_App,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint64_t addr,
+ uint8_t tnum,
+ uint16_t liodn);
+
+/**************************************************************************//**
+ @Description A structure for defining buffer prefix area content.
+*//***************************************************************************/
+typedef struct t_FmBufferPrefixContent {
+ uint16_t privDataSize; /**< Number of bytes to be left at the beginning
+ of the external buffer; Note that the private-area will
+ start from the base of the buffer address. */
+ bool passPrsResult; /**< TRUE to pass the parse result to/from the FM;
+ User may use FM_PORT_GetBufferPrsResult() in order to
+ get the parser-result from a buffer. */
+ bool passTimeStamp; /**< TRUE to pass the timeStamp to/from the FM
+ User may use FM_PORT_GetBufferTimeStamp() in order to
+ get the parser-result from a buffer. */
+ bool passHashResult; /**< TRUE to pass the KG hash result to/from the FM
+ User may use FM_PORT_GetBufferHashResult() in order to
+ get the parser-result from a buffer. */
+ bool passAllOtherPCDInfo;/**< Add all other Internal-Context information:
+ AD, hash-result, key, etc. */
+ uint16_t dataAlign; /**< 0 to use driver's default alignment [DEFAULT_FM_SP_bufferPrefixContent_dataAlign],
+ other value for selecting a data alignment (must be a power of 2);
+ if write optimization is used, must be >= 16. */
+ uint8_t manipExtraSpace; /**< Maximum extra size needed (insertion-size minus removal-size);
+ Note that this field impacts the size of the buffer-prefix
+ (i.e. it pushes the data offset);
+ This field is irrelevant if DPAA_VERSION==10 */
+} t_FmBufferPrefixContent;
+
+/**************************************************************************//**
+ @Description A structure of information about each of the external
+ buffer pools used by a port or storage-profile.
+*//***************************************************************************/
+typedef struct t_FmExtPoolParams {
+ uint8_t id; /**< External buffer pool id */
+ uint16_t size; /**< External buffer pool buffer size */
+} t_FmExtPoolParams;
+
+/**************************************************************************//**
+ @Description A structure for informing the driver about the external
+ buffer pools allocated in the BM and used by a port or a
+ storage-profile.
+*//***************************************************************************/
+typedef struct t_FmExtPools {
+ uint8_t numOfPoolsUsed; /**< Number of pools use by this port */
+ t_FmExtPoolParams extBufPool[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /**< Parameters for each port */
+} t_FmExtPools;
+
+/**************************************************************************//**
+ @Description A structure for defining backup BM Pools.
+*//***************************************************************************/
+typedef struct t_FmBackupBmPools {
+ uint8_t numOfBackupPools; /**< Number of BM backup pools -
+ must be smaller than the total number of
+ pools defined for the specified port.*/
+ uint8_t poolIds[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /**< numOfBackupPools pool id's, specifying which
+ pools should be used only as backup. Pool
+ id's specified here must be a subset of the
+ pools used by the specified port.*/
+} t_FmBackupBmPools;
+
+/**************************************************************************//**
+ @Description A structure for defining BM pool depletion criteria
+*//***************************************************************************/
+typedef struct t_FmBufPoolDepletion {
+ bool poolsGrpModeEnable; /**< select mode in which pause frames will be sent after
+ a number of pools (all together!) are depleted */
+ uint8_t numOfPools; /**< the number of depleted pools that will invoke
+ pause frames transmission. */
+ bool poolsToConsider[BM_MAX_NUM_OF_POOLS];
+ /**< For each pool, TRUE if it should be considered for
+ depletion (Note - this pool must be used by this port!). */
+ bool singlePoolModeEnable; /**< select mode in which pause frames will be sent after
+ a single-pool is depleted; */
+ bool poolsToConsiderForSingleMode[BM_MAX_NUM_OF_POOLS];
+ /**< For each pool, TRUE if it should be considered for
+ depletion (Note - this pool must be used by this port!) */
+#if (DPAA_VERSION >= 11)
+ bool pfcPrioritiesEn[FM_MAX_NUM_OF_PFC_PRIORITIES];
+ /**< This field is used by the MAC as the Priority Enable Vector in the PFC frame which is transmitted */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmBufPoolDepletion;
+
+/**************************************************************************//**
+ @Description A Structure for defining Ucode patch for loading.
+*//***************************************************************************/
+typedef struct t_FmFirmwareParams {
+ uint32_t size; /**< Size of uCode */
+ uint32_t *p_Code; /**< A pointer to the uCode */
+} t_FmFirmwareParams;
+
+/**************************************************************************//**
+ @Description A Structure for defining FM initialization parameters
+*//***************************************************************************/
+typedef struct t_FmParams {
+ uint8_t fmId; /**< Index of the FM */
+ uint8_t guestId; /**< FM Partition Id */
+ uintptr_t baseAddr; /**< A pointer to base of memory mapped FM registers (virtual);
+ this field is optional when the FM runs in "guest-mode"
+ (i.e. guestId != NCSW_MASTER_ID); in that case, the driver will
+ use the memory-map instead of calling the IPC where possible;
+ NOTE that this should include ALL common registers of the FM including
+ the PCD registers area (i.e. until the VSP pages - 880KB). */
+ t_Handle h_FmMuram; /**< A handle of an initialized MURAM object,
+ to be used by the FM. */
+ uint16_t fmClkFreq; /**< In Mhz;
+ Relevant when FM not runs in "guest-mode". */
+ uint16_t fmMacClkRatio; /**< FM MAC Clock ratio, for backward comparability:
+ when fmMacClkRatio = 0, ratio is 2:1
+ when fmMacClkRatio = 1, ratio is 1:1 */
+ t_FmExceptionsCallback *f_Exception; /**< An application callback routine to handle exceptions;
+ Relevant when FM not runs in "guest-mode". */
+ t_FmBusErrorCallback *f_BusError; /**< An application callback routine to handle exceptions;
+ Relevant when FM not runs in "guest-mode". */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks;
+ Relevant when FM not runs in "guest-mode". */
+ int irq; /**< FM interrupt source for normal events;
+ Relevant when FM not runs in "guest-mode". */
+ int errIrq; /**< FM interrupt source for errors;
+ Relevant when FM not runs in "guest-mode". */
+ t_FmFirmwareParams firmware; /**< The firmware parameters structure;
+ Relevant when FM not runs in "guest-mode". */
+
+#if (DPAA_VERSION >= 11)
+ uintptr_t vspBaseAddr; /**< A pointer to base of memory mapped FM VSP registers (virtual);
+ i.e. up to 24KB, depending on the specific chip. */
+ uint8_t partVSPBase; /**< The first Virtual-Storage-Profile-id dedicated to this partition.
+ NOTE: this parameter relevant only when working with multiple partitions. */
+ uint8_t partNumOfVSPs; /**< Number of VSPs dedicated to this partition.
+ NOTE: this parameter relevant only when working with multiple partitions. */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmParams;
+
+
+/**************************************************************************//**
+ @Function FM_Config
+
+ @Description Creates the FM module and returns its handle (descriptor).
+ This descriptor must be passed as first parameter to all other
+ FM function calls.
+
+ No actual initialization or configuration of FM hardware is
+ done by this routine. All FM parameters get default values that
+ may be changed by calling one or more of the advance config routines.
+
+ @Param[in] p_FmParams - A pointer to a data structure of mandatory FM parameters
+
+ @Return A handle to the FM object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_Config(t_FmParams *p_FmParams);
+
+/**************************************************************************//**
+ @Function FM_Init
+
+ @Description Initializes the FM module by defining the software structure
+ and configuring the hardware registers.
+
+ @Param[in] h_Fm - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_Init(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_Free
+
+ @Description Frees all resources that were assigned to FM module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_Fm - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_Free(t_Handle h_Fm);
+
+
+/**************************************************************************//**
+ @Group FM_advanced_init_grp FM Advanced Configuration Unit
+
+ @Description Advanced configuration routines are optional routines that may
+ be called in order to change the default driver settings.
+
+ Note: Advanced configuration routines are not available for guest partition.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Enum for selecting DMA debug mode
+*//***************************************************************************/
+typedef enum e_FmDmaDbgCntMode {
+ e_FM_DMA_DBG_NO_CNT = 0, /**< No counting */
+ e_FM_DMA_DBG_CNT_DONE, /**< Count DONE commands */
+ e_FM_DMA_DBG_CNT_COMM_Q_EM, /**< count command queue emergency signals */
+ e_FM_DMA_DBG_CNT_INT_READ_EM, /**< Count Internal Read buffer emergency signal */
+ e_FM_DMA_DBG_CNT_INT_WRITE_EM, /**< Count Internal Write buffer emergency signal */
+ e_FM_DMA_DBG_CNT_FPM_WAIT, /**< Count FPM WAIT signal */
+ e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors. */
+ e_FM_DMA_DBG_CNT_RAW_WAR_PROT /**< Number of times there was a need for RAW & WAR protection. */
+} e_FmDmaDbgCntMode;
+
+/**************************************************************************//**
+ @Description Enum for selecting DMA Cache Override
+*//***************************************************************************/
+typedef enum e_FmDmaCacheOverride {
+ e_FM_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */
+ e_FM_DMA_NO_STASH_DATA, /**< Data should not be stashed in system level cache */
+ e_FM_DMA_MAY_STASH_DATA, /**< Data may be stashed in system level cache */
+ e_FM_DMA_STASH_DATA /**< Data should be stashed in system level cache */
+} e_FmDmaCacheOverride;
+
+/**************************************************************************//**
+ @Description Enum for selecting DMA External Bus Priority
+*//***************************************************************************/
+typedef enum e_FmDmaExtBusPri {
+ e_FM_DMA_EXT_BUS_NORMAL = 0, /**< Normal priority */
+ e_FM_DMA_EXT_BUS_EBS, /**< AXI extended bus service priority */
+ e_FM_DMA_EXT_BUS_SOS, /**< AXI sos priority */
+ e_FM_DMA_EXT_BUS_EBS_AND_SOS /**< AXI ebs + sos priority */
+} e_FmDmaExtBusPri;
+
+/**************************************************************************//**
+ @Description Enum for choosing the field that will be output on AID
+*//***************************************************************************/
+typedef enum e_FmDmaAidMode {
+ e_FM_DMA_AID_OUT_PORT_ID = 0, /**< 4 LSB of PORT_ID */
+ e_FM_DMA_AID_OUT_TNUM /**< 4 LSB of TNUM */
+} e_FmDmaAidMode;
+
+/**************************************************************************//**
+ @Description Enum for selecting FPM Catastrophic error behavior
+*//***************************************************************************/
+typedef enum e_FmCatastrophicErr {
+ e_FM_CATASTROPHIC_ERR_STALL_PORT = 0, /**< Port_ID is stalled (only reset can release it) */
+ e_FM_CATASTROPHIC_ERR_STALL_TASK /**< Only erroneous task is stalled */
+} e_FmCatastrophicErr;
+
+/**************************************************************************//**
+ @Description Enum for selecting FPM DMA Error behavior
+*//***************************************************************************/
+typedef enum e_FmDmaErr {
+ e_FM_DMA_ERR_CATASTROPHIC = 0, /**< Dma error is treated as a catastrophic
+ error (e_FmCatastrophicErr)*/
+ e_FM_DMA_ERR_REPORT /**< Dma error is just reported */
+} e_FmDmaErr;
+
+/**************************************************************************//**
+ @Description Enum for selecting DMA Emergency level by BMI emergency signal
+*//***************************************************************************/
+typedef enum e_FmDmaEmergencyLevel {
+ e_FM_DMA_EM_EBS = 0, /**< EBS emergency */
+ e_FM_DMA_EM_SOS /**< SOS emergency */
+} e_FmDmaEmergencyLevel;
+
+/**************************************************************************//**
+ @Collection Enum for selecting DMA Emergency options
+*//***************************************************************************/
+typedef uint32_t fmEmergencyBus_t; /**< DMA emergency options */
+
+#define FM_DMA_MURAM_READ_EMERGENCY 0x00800000 /**< Enable emergency for MURAM1 */
+#define FM_DMA_MURAM_WRITE_EMERGENCY 0x00400000 /**< Enable emergency for MURAM2 */
+#define FM_DMA_EXT_BUS_EMERGENCY 0x00100000 /**< Enable emergency for external bus */
+/* @} */
+
+/**************************************************************************//**
+ @Description A structure for defining DMA emergency level
+*//***************************************************************************/
+typedef struct t_FmDmaEmergency {
+ fmEmergencyBus_t emergencyBusSelect; /**< An OR of the busses where emergency
+ should be enabled */
+ e_FmDmaEmergencyLevel emergencyLevel; /**< EBS/SOS */
+} t_FmDmaEmergency;
+
+/**************************************************************************//*
+ @Description structure for defining FM threshold
+*//***************************************************************************/
+typedef struct t_FmThresholds {
+ uint8_t dispLimit; /**< The number of times a frames may
+ be passed in the FM before assumed to
+ be looping. */
+ uint8_t prsDispTh; /**< This is the number pf packets that may be
+ queued in the parser dispatch queue*/
+ uint8_t plcrDispTh; /**< This is the number pf packets that may be
+ queued in the policer dispatch queue*/
+ uint8_t kgDispTh; /**< This is the number pf packets that may be
+ queued in the keygen dispatch queue*/
+ uint8_t bmiDispTh; /**< This is the number pf packets that may be
+ queued in the BMI dispatch queue*/
+ uint8_t qmiEnqDispTh; /**< This is the number pf packets that may be
+ queued in the QMI enqueue dispatch queue*/
+ uint8_t qmiDeqDispTh; /**< This is the number pf packets that may be
+ queued in the QMI dequeue dispatch queue*/
+ uint8_t fmCtl1DispTh; /**< This is the number pf packets that may be
+ queued in fmCtl1 dispatch queue*/
+ uint8_t fmCtl2DispTh; /**< This is the number pf packets that may be
+ queued in fmCtl2 dispatch queue*/
+} t_FmThresholds;
+
+/**************************************************************************//*
+ @Description structure for defining DMA thresholds
+*//***************************************************************************/
+typedef struct t_FmDmaThresholds {
+ uint8_t assertEmergency; /**< When this value is reached,
+ assert emergency (Threshold)*/
+ uint8_t clearEmergency; /**< After emergency is asserted, it is held
+ until this value is reached (Hystheresis) */
+} t_FmDmaThresholds;
+
+/**************************************************************************//**
+ @Function t_FmResetOnInitOverrideCallback
+
+ @Description FMan specific reset on init user callback routine,
+ will be used to override the standard FMan reset on init procedure
+
+ @Param[in] h_Fm - FMan handler
+*//***************************************************************************/
+typedef void (t_FmResetOnInitOverrideCallback)(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_ConfigResetOnInit
+
+ @Description Define whether to reset the FM before initialization.
+ Change the default configuration [DEFAULT_resetOnInit].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] enable When TRUE, FM will be reset before any initialization.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable);
+
+/**************************************************************************//**
+ @Function FM_ConfigResetOnInitOverrideCallback
+
+ @Description Define a special reset of FM before initialization.
+ Change the default configuration [DEFAULT_resetOnInitOverrideCallback].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] f_ResetOnInitOverride FM specific reset on init user callback routine.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride);
+
+/**************************************************************************//**
+ @Function FM_ConfigTotalFifoSize
+
+ @Description Define Total FIFO size for the whole FM.
+ Calling this routine changes the total Fifo size in the internal driver
+ data base from its default configuration [DEFAULT_totalFifoSize]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] totalFifoSize The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize);
+
+ /**************************************************************************//**
+ @Function FM_ConfigDmaCacheOverride
+
+ @Description Define cache override mode.
+ Calling this routine changes the cache override mode
+ in the internal driver data base from its default configuration [DEFAULT_cacheOverride]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] cacheOverride The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaAidOverride
+
+ @Description Define DMA AID override mode.
+ Calling this routine changes the AID override mode
+ in the internal driver data base from its default configuration [DEFAULT_aidOverride]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] aidOverride The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaAidMode
+
+ @Description Define DMA AID mode.
+ Calling this routine changes the AID mode in the internal
+ driver data base from its default configuration [DEFAULT_aidMode]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] aidMode The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaAxiDbgNumOfBeats
+
+ @Description Define DMA AXI number of beats.
+ Calling this routine changes the AXI number of beats in the internal
+ driver data base from its default configuration [DEFAULT_axiDbgNumOfBeats]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] axiDbgNumOfBeats The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaCamNumOfEntries
+
+ @Description Define number of CAM entries.
+ Calling this routine changes the number of CAM entries in the internal
+ driver data base from its default configuration [DEFAULT_dmaCamNumOfEntries].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] numOfEntries The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries);
+
+/**************************************************************************//**
+ @Function FM_ConfigEnableCounters
+
+ @Description Obsolete, always return E_OK.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_ConfigEnableCounters(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaDbgCounter
+
+ @Description Define DMA debug counter.
+ Calling this routine changes the number of the DMA debug counter in the internal
+ driver data base from its default configuration [DEFAULT_dmaDbgCntMode].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] fmDmaDbgCntMode An enum selecting the debug counter mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaStopOnBusErr
+
+ @Description Define bus error behavior.
+ Calling this routine changes the bus error behavior definition
+ in the internal driver data base from its default
+ configuration [DEFAULT_dmaStopOnBusError].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] stop TRUE to stop on bus error, FALSE to continue.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ Only if bus error is enabled.
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaEmergency
+
+ @Description Define DMA emergency.
+ Calling this routine changes the DMA emergency definition
+ in the internal driver data base from its default
+ configuration where's it's disabled.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_Emergency An OR mask of all required options.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency);
+
+/**************************************************************************//**
+ @Function FM_ConfigDmaErr
+
+ @Description DMA error treatment.
+ Calling this routine changes the DMA error treatment
+ in the internal driver data base from its default
+ configuration [DEFAULT_dmaErr].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] dmaErr The selected new choice.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr);
+
+/**************************************************************************//**
+ @Function FM_ConfigCatastrophicErr
+
+ @Description Define FM behavior on catastrophic error.
+ Calling this routine changes the FM behavior on catastrophic
+ error in the internal driver data base from its default
+ [DEFAULT_catastrophicErr].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] catastrophicErr The selected new choice.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr);
+
+/**************************************************************************//**
+ @Function FM_ConfigEnableMuramTestMode
+
+ @Description Enable MURAM test mode.
+ Calling this routine changes the internal driver data base
+ from its default selection of test mode where it's disabled.
+ This routine is only avaiable on old FM revisions (FMan v2).
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_ConfigEnableIramTestMode
+
+ @Description Enable IRAM test mode.
+ Calling this routine changes the internal driver data base
+ from its default selection of test mode where it's disabled.
+ This routine is only avaiable on old FM revisions (FMan v2).
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_ConfigHaltOnExternalActivation
+
+ @Description Define FM behavior on external halt activation.
+ Calling this routine changes the FM behavior on external halt
+ activation in the internal driver data base from its default
+ [DEFAULT_haltOnExternalActivation].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] enable TRUE to enable halt on external halt
+ activation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable);
+
+/**************************************************************************//**
+ @Function FM_ConfigHaltOnUnrecoverableEccError
+
+ @Description Define FM behavior on external halt activation.
+ Calling this routine changes the FM behavior on unrecoverable
+ ECC error in the internal driver data base from its default
+ [DEFAULT_haltOnUnrecoverableEccError].
+ This routine is only avaiable on old FM revisions (FMan v2).
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] enable TRUE to enable halt on unrecoverable Ecc error
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable);
+
+/**************************************************************************//**
+ @Function FM_ConfigException
+
+ @Description Define FM exceptions.
+ Calling this routine changes the exceptions defaults in the
+ internal driver data base where all exceptions are enabled.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_ConfigExternalEccRamsEnable
+
+ @Description Select external ECC enabling.
+ Calling this routine changes the ECC enabling control in the internal
+ driver data base from its default [DEFAULT_externalEccRamsEnable].
+ When this option is enabled Rams ECC enabling is not effected
+ by FM_EnableRamsEcc/FM_DisableRamsEcc, but by a JTAG.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] enable TRUE to enable this option.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable);
+
+/**************************************************************************//**
+ @Function FM_ConfigTnumAgingPeriod
+
+ @Description Define Tnum aging period.
+ Calling this routine changes the Tnum aging of dequeue TNUMs
+ in the QMI in the internal driver data base from its default
+ [DEFAULT_tnumAgingPeriod].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] tnumAgingPeriod Tnum Aging Period in microseconds.
+ Note that period is recalculated in units of
+ 64 FM clocks. Driver will pick the closest
+ possible period.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+ NOTE that if some MAC is configured for PFC, '0' value is NOT
+ allowed.
+*//***************************************************************************/
+t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod);
+
+/**************************************************************************//*
+ @Function FM_ConfigDmaEmergencySmoother
+
+ @Description Define DMA emergency smoother.
+ Calling this routine changes the definition of the minimum
+ amount of DATA beats transferred on the AXI READ and WRITE
+ ports before lowering the emergency level.
+ By default smoother is disabled.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] emergencyCnt emergency switching counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt);
+
+/**************************************************************************//*
+ @Function FM_ConfigThresholds
+
+ @Description Calling this routine changes the internal driver data base
+ from its default FM threshold configuration:
+ dispLimit: [DEFAULT_dispLimit]
+ prsDispTh: [DEFAULT_prsDispTh]
+ plcrDispTh: [DEFAULT_plcrDispTh]
+ kgDispTh: [DEFAULT_kgDispTh]
+ bmiDispTh: [DEFAULT_bmiDispTh]
+ qmiEnqDispTh: [DEFAULT_qmiEnqDispTh]
+ qmiDeqDispTh: [DEFAULT_qmiDeqDispTh]
+ fmCtl1DispTh: [DEFAULT_fmCtl1DispTh]
+ fmCtl2DispTh: [DEFAULT_fmCtl2DispTh]
+
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_FmThresholds A structure of threshold parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds);
+
+/**************************************************************************//*
+ @Function FM_ConfigDmaSosEmergencyThreshold
+
+ @Description Calling this routine changes the internal driver data base
+ from its default dma SOS emergency configuration [DEFAULT_dmaSosEmergency]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] dmaSosEmergency The selected new value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency);
+
+/**************************************************************************//*
+ @Function FM_ConfigDmaWriteBufThresholds
+
+ @Description Calling this routine changes the internal driver data base
+ from its default configuration of DMA write buffer threshold
+ assertEmergency: [DEFAULT_dmaWriteIntBufLow]
+ clearEmergency: [DEFAULT_dmaWriteIntBufHigh]
+ This routine is only avaiable on old FM revisions (FMan v2).
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior -
+ When 'assertEmergency' value is reached, emergency is asserted,
+ then it is held until 'clearEmergency' value is reached.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
+
+ /**************************************************************************//*
+ @Function FM_ConfigDmaCommQThresholds
+
+ @Description Calling this routine changes the internal driver data base
+ from its default configuration of DMA command queue threshold
+ assertEmergency: [DEFAULT_dmaCommQLow]
+ clearEmergency: [DEFAULT_dmaCommQHigh]
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior -
+ When 'assertEmergency' value is reached, emergency is asserted,
+ then it is held until 'clearEmergency' value is reached..
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
+
+/**************************************************************************//*
+ @Function FM_ConfigDmaReadBufThresholds
+
+ @Description Calling this routine changes the internal driver data base
+ from its default configuration of DMA read buffer threshold
+ assertEmergency: [DEFAULT_dmaReadIntBufLow]
+ clearEmergency: [DEFAULT_dmaReadIntBufHigh]
+ This routine is only avaiable on old FM revisions (FMan v2).
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior -
+ When 'assertEmergency' value is reached, emergency is asserted,
+ then it is held until 'clearEmergency' value is reached..
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds);
+
+/**************************************************************************//*
+ @Function FM_ConfigDmaWatchdog
+
+ @Description Calling this routine changes the internal driver data base
+ from its default watchdog configuration, which is disabled
+ [DEFAULT_dmaWatchdog].
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] watchDogValue The selected new value - in microseconds.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchDogValue);
+
+/** @} */ /* end of FM_advanced_init_grp group */
+/** @} */ /* end of FM_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_runtime_control_grp FM Runtime Control Unit
+
+ @Description FM Runtime control unit API functions, definitions and enums.
+ The FM driver provides a set of control routines.
+ These routines may only be called after the module was fully
+ initialized (both configuration and initialization routines were
+ called). They are typically used to get information from hardware
+ (status, counters/statistics, revision etc.), to modify a current
+ state or to force/enable a required action. Run-time control may
+ be called whenever necessary and as many times as needed.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Collection General FM defines.
+*//***************************************************************************/
+#define FM_MAX_NUM_OF_VALID_PORTS (FM_MAX_NUM_OF_OH_PORTS + \
+ FM_MAX_NUM_OF_1G_RX_PORTS + \
+ FM_MAX_NUM_OF_10G_RX_PORTS + \
+ FM_MAX_NUM_OF_1G_TX_PORTS + \
+ FM_MAX_NUM_OF_10G_TX_PORTS) /**< Number of available FM ports */
+/* @} */
+
+/**************************************************************************//*
+ @Description A Structure for Port bandwidth requirement. Port is identified
+ by type and relative id.
+*//***************************************************************************/
+typedef struct t_FmPortBandwidth {
+ e_FmPortType type; /**< FM port type */
+ uint8_t relativePortId; /**< Type relative port id */
+ uint8_t bandwidth; /**< bandwidth - (in term of percents) */
+} t_FmPortBandwidth;
+
+/**************************************************************************//*
+ @Description A Structure containing an array of Port bandwidth requirements.
+ The user should state the ports requiring bandwidth in terms of
+ percentage - i.e. all port's bandwidths in the array must add
+ up to 100.
+*//***************************************************************************/
+typedef struct t_FmPortsBandwidthParams {
+ uint8_t numOfPorts; /**< The number of relevant ports, which is the
+ number of valid entries in the array below */
+ t_FmPortBandwidth portsBandwidths[FM_MAX_NUM_OF_VALID_PORTS];
+ /**< for each port, it's bandwidth (all port's
+ bandwidths must add up to 100.*/
+} t_FmPortsBandwidthParams;
+
+/**************************************************************************//**
+ @Description DMA Emergency control on MURAM
+*//***************************************************************************/
+typedef enum e_FmDmaMuramPort {
+ e_FM_DMA_MURAM_PORT_WRITE, /**< MURAM write port */
+ e_FM_DMA_MURAM_PORT_READ /**< MURAM read port */
+} e_FmDmaMuramPort;
+
+/**************************************************************************//**
+ @Description Enum for defining FM counters
+*//***************************************************************************/
+typedef enum e_FmCounters {
+ e_FM_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI total enqueued frames counter */
+ e_FM_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI total dequeued frames counter */
+ e_FM_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */
+ e_FM_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */
+ e_FM_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */
+ e_FM_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */
+ e_FM_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI dequeue from default queue counter */
+ e_FM_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI dequeue from FQ context counter */
+ e_FM_COUNTERS_DEQ_FROM_FD, /**< QMI dequeue from FD command field counter */
+ e_FM_COUNTERS_DEQ_CONFIRM /**< QMI dequeue confirm counter */
+} e_FmCounters;
+
+/**************************************************************************//**
+ @Description A Structure for returning FM revision information
+*//***************************************************************************/
+typedef struct t_FmRevisionInfo {
+ uint8_t majorRev; /**< Major revision */
+ uint8_t minorRev; /**< Minor revision */
+} t_FmRevisionInfo;
+
+/**************************************************************************//**
+ @Description A Structure for returning FM ctrl code revision information
+*//***************************************************************************/
+typedef struct t_FmCtrlCodeRevisionInfo {
+ uint16_t packageRev; /**< Package revision */
+ uint8_t majorRev; /**< Major revision */
+ uint8_t minorRev; /**< Minor revision */
+} t_FmCtrlCodeRevisionInfo;
+
+/**************************************************************************//**
+ @Description A Structure for defining DMA status
+*//***************************************************************************/
+typedef struct t_FmDmaStatus {
+ bool cmqNotEmpty; /**< Command queue is not empty */
+ bool busError; /**< Bus error occurred */
+ bool readBufEccError; /**< Double ECC error on buffer Read (Valid for FM rev < 6)*/
+ bool writeBufEccSysError; /**< Double ECC error on buffer write from system side (Valid for FM rev < 6)*/
+ bool writeBufEccFmError; /**< Double ECC error on buffer write from FM side (Valid for FM rev < 6) */
+ bool singlePortEccError; /**< Single Port ECC error from FM side (Valid for FM rev >= 6)*/
+} t_FmDmaStatus;
+
+/**************************************************************************//**
+ @Description A Structure for obtaining FM controller monitor values
+*//***************************************************************************/
+typedef struct t_FmCtrlMon {
+ uint8_t percentCnt[2]; /**< Percentage value */
+} t_FmCtrlMon;
+
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_DumpRegs
+
+ @Description Dumps all FM registers
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success;
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_DumpRegs(t_Handle h_Fm);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+/**************************************************************************//**
+ @Function FM_SetException
+
+ @Description Calling this routine enables/disables the specified exception.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_EnableRamsEcc
+
+ @Description Enables ECC mechanism for all the different FM RAM's; E.g. IRAM,
+ MURAM, Parser, Keygen, Policer, etc.
+ Note:
+ If FM_ConfigExternalEccRamsEnable was called to enable external
+ setting of ECC, this routine effects IRAM ECC only.
+ This routine is also called by the driver if an ECC exception is
+ enabled.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_EnableRamsEcc(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_DisableRamsEcc
+
+ @Description Disables ECC mechanism for all the different FM RAM's; E.g. IRAM,
+ MURAM, Parser, Keygen, Policer, etc.
+ Note:
+ If FM_ConfigExternalEccRamsEnable was called to enable external
+ setting of ECC, this routine effects IRAM ECC only.
+ In opposed to FM_EnableRamsEcc, this routine must be called
+ explicitly to disable all Rams ECC.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Config() and before FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_DisableRamsEcc(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_GetRevision
+
+ @Description Returns the FM revision
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[out] p_FmRevisionInfo A structure of revision information parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo);
+
+/**************************************************************************//**
+ @Function FM_GetFmanCtrlCodeRevision
+
+ @Description Returns the Fman controller code revision
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[out] p_RevisionInfo A structure of revision information parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo);
+
+/**************************************************************************//**
+ @Function FM_GetCounter
+
+ @Description Reads one of the FM counters.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] counter The requested counter.
+
+ @Return Counter's current value.
+
+ @Cautions Allowed only following FM_Init().
+ Note that it is user's responsibility to call this routine only
+ for enabled counters, and there will be no indication if a
+ disabled counter is accessed.
+*//***************************************************************************/
+uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter);
+
+/**************************************************************************//**
+ @Function FM_ModifyCounter
+
+ @Description Sets a value to an enabled counter. Use "0" to reset the counter.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] counter The requested counter.
+ @Param[in] val The requested value to be written into the counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val);
+
+/**************************************************************************//**
+ @Function FM_Resume
+
+ @Description Release FM after halt FM command or after unrecoverable ECC error.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+void FM_Resume(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_SetDmaEmergency
+
+ @Description Manual emergency set
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] muramPort MURAM direction select.
+ @Param[in] enable TRUE to manually enable emergency, FALSE to disable.
+
+ @Return None.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable);
+
+/**************************************************************************//**
+ @Function FM_SetDmaExtBusPri
+
+ @Description Set the DMA external bus priority
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] pri External bus priority select
+
+ @Return None.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri);
+
+/**************************************************************************//**
+ @Function FM_GetDmaStatus
+
+ @Description Reads the DMA current status
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[out] p_FmDmaStatus A structure of DMA status parameters.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus);
+
+/**************************************************************************//**
+ @Function FM_ErrorIsr
+
+ @Description FM interrupt-service-routine for errors.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; E_EMPTY if no errors found in register, other
+ error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ErrorIsr(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_EventIsr
+
+ @Description FM interrupt-service-routine for normal events.
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+void FM_EventIsr(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_GetSpecialOperationCoding
+
+ @Description Return a specific coding according to the input mask.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] spOper special operation mask.
+ @Param[out] p_SpOperCoding special operation code.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_GetSpecialOperationCoding(t_Handle h_Fm,
+ fmSpecialOperations_t spOper,
+ uint8_t *p_SpOperCoding);
+
+/**************************************************************************//**
+ @Function FM_CtrlMonStart
+
+ @Description Start monitoring utilization of all available FM controllers.
+
+ In order to obtain FM controllers utilization the following sequence
+ should be used:
+ -# FM_CtrlMonStart()
+ -# FM_CtrlMonStop()
+ -# FM_CtrlMonGetCounters() - issued for each FM controller
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID).
+*//***************************************************************************/
+t_Error FM_CtrlMonStart(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_CtrlMonStop
+
+ @Description Stop monitoring utilization of all available FM controllers.
+
+ In order to obtain FM controllers utilization the following sequence
+ should be used:
+ -# FM_CtrlMonStart()
+ -# FM_CtrlMonStop()
+ -# FM_CtrlMonGetCounters() - issued for each FM controller
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID).
+*//***************************************************************************/
+t_Error FM_CtrlMonStop(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_CtrlMonGetCounters
+
+ @Description Obtain FM controller utilization parameters.
+
+ In order to obtain FM controllers utilization the following sequence
+ should be used:
+ -# FM_CtrlMonStart()
+ -# FM_CtrlMonStop()
+ -# FM_CtrlMonGetCounters() - issued for each FM controller
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] fmCtrlIndex FM Controller index for that utilization results
+ are requested.
+ @Param[in] p_Mon Pointer to utilization results structure.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID).
+*//***************************************************************************/
+t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon);
+
+
+/**************************************************************************//*
+ @Function FM_ForceIntr
+
+ @Description Causes an interrupt event on the requested source.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] exception An exception to be forced.
+
+ @Return E_OK on success; Error code if the exception is not enabled,
+ or is not able to create interrupt.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception);
+
+/**************************************************************************//*
+ @Function FM_SetPortsBandwidth
+
+ @Description Sets relative weights between ports when accessing common resources.
+
+ @Param[in] h_Fm A handle to an FM Module.
+ @Param[in] p_PortsBandwidth A structure of ports bandwidths in percentage, i.e.
+ total must equal 100.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth);
+
+/**************************************************************************//*
+ @Function FM_GetMuramHandle
+
+ @Description Gets the corresponding MURAM handle
+
+ @Param[in] h_Fm A handle to an FM Module.
+
+ @Return MURAM handle; NULL otherwise.
+
+ @Cautions Allowed only following FM_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Handle FM_GetMuramHandle(t_Handle h_Fm);
+
+/** @} */ /* end of FM_runtime_control_grp group */
+/** @} */ /* end of FM_lib_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#ifdef NCSW_BACKWARD_COMPATIBLE_API
+typedef t_FmFirmwareParams t_FmPcdFirmwareParams;
+typedef t_FmBufferPrefixContent t_FmPortBufferPrefixContent;
+typedef t_FmExtPoolParams t_FmPortExtPoolParams;
+typedef t_FmExtPools t_FmPortExtPools;
+typedef t_FmBackupBmPools t_FmPortBackupBmPools;
+typedef t_FmBufPoolDepletion t_FmPortBufPoolDepletion;
+typedef e_FmDmaSwapOption e_FmPortDmaSwapOption;
+typedef e_FmDmaCacheOption e_FmPortDmaCacheOption;
+
+#define FM_CONTEXTA_GET_OVVERIDE FM_CONTEXTA_GET_OVERRIDE
+#define FM_CONTEXTA_SET_OVVERIDE FM_CONTEXTA_SET_OVERRIDE
+
+#define e_FM_EX_BMI_PIPELINE_ECC e_FM_EX_BMI_STORAGE_PROFILE_ECC
+#define e_FM_PORT_DMA_NO_SWP e_FM_DMA_NO_SWP
+#define e_FM_PORT_DMA_SWP_PPC_LE e_FM_DMA_SWP_PPC_LE
+#define e_FM_PORT_DMA_SWP_BE e_FM_DMA_SWP_BE
+#define e_FM_PORT_DMA_NO_STASH e_FM_DMA_NO_STASH
+#define e_FM_PORT_DMA_STASH e_FM_DMA_STASH
+#endif /* NCSW_BACKWARD_COMPATIBLE_API */
+
+
+#endif /* __FM_EXT */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
new file mode 100644
index 000000000000..be99b7c9f93b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_mac_ext.h
+
+ @Description FM MAC ...
+*//***************************************************************************/
+#ifndef __FM_MAC_EXT_H
+#define __FM_MAC_EXT_H
+
+#include "std_ext.h"
+#include "enet_ext.h"
+
+
+/**************************************************************************//**
+
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_mac_grp FM MAC
+
+ @Description FM MAC API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+#define FM_MAC_NO_PFC 0xff
+
+
+/**************************************************************************//**
+ @Description FM MAC Exceptions
+*//***************************************************************************/
+typedef enum e_FmMacExceptions {
+ e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0 /**< 10GEC MDIO scan event interrupt */
+ ,e_FM_MAC_EX_10G_MDIO_CMD_CMPL /**< 10GEC MDIO command completion interrupt */
+ ,e_FM_MAC_EX_10G_REM_FAULT /**< 10GEC, mEMAC Remote fault interrupt */
+ ,e_FM_MAC_EX_10G_LOC_FAULT /**< 10GEC, mEMAC Local fault interrupt */
+ ,e_FM_MAC_EX_10G_1TX_ECC_ER /**< 10GEC, mEMAC Transmit frame ECC error interrupt */
+ ,e_FM_MAC_EX_10G_TX_FIFO_UNFL /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */
+ ,e_FM_MAC_EX_10G_TX_FIFO_OVFL /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */
+ ,e_FM_MAC_EX_10G_TX_ER /**< 10GEC Transmit frame error interrupt */
+ ,e_FM_MAC_EX_10G_RX_FIFO_OVFL /**< 10GEC, mEMAC Receive FIFO overflow interrupt */
+ ,e_FM_MAC_EX_10G_RX_ECC_ER /**< 10GEC, mEMAC Receive frame ECC error interrupt */
+ ,e_FM_MAC_EX_10G_RX_JAB_FRM /**< 10GEC Receive jabber frame interrupt */
+ ,e_FM_MAC_EX_10G_RX_OVRSZ_FRM /**< 10GEC Receive oversized frame interrupt */
+ ,e_FM_MAC_EX_10G_RX_RUNT_FRM /**< 10GEC Receive runt frame interrupt */
+ ,e_FM_MAC_EX_10G_RX_FRAG_FRM /**< 10GEC Receive fragment frame interrupt */
+ ,e_FM_MAC_EX_10G_RX_LEN_ER /**< 10GEC Receive payload length error interrupt */
+ ,e_FM_MAC_EX_10G_RX_CRC_ER /**< 10GEC Receive CRC error interrupt */
+ ,e_FM_MAC_EX_10G_RX_ALIGN_ER /**< 10GEC Receive alignment error interrupt */
+ ,e_FM_MAC_EX_1G_BAB_RX /**< dTSEC Babbling receive error */
+ ,e_FM_MAC_EX_1G_RX_CTL /**< dTSEC Receive control (pause frame) interrupt */
+ ,e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET /**< dTSEC Graceful transmit stop complete */
+ ,e_FM_MAC_EX_1G_BAB_TX /**< dTSEC Babbling transmit error */
+ ,e_FM_MAC_EX_1G_TX_CTL /**< dTSEC Transmit control (pause frame) interrupt */
+ ,e_FM_MAC_EX_1G_TX_ERR /**< dTSEC Transmit error */
+ ,e_FM_MAC_EX_1G_LATE_COL /**< dTSEC Late collision */
+ ,e_FM_MAC_EX_1G_COL_RET_LMT /**< dTSEC Collision retry limit */
+ ,e_FM_MAC_EX_1G_TX_FIFO_UNDRN /**< dTSEC Transmit FIFO underrun */
+ ,e_FM_MAC_EX_1G_MAG_PCKT /**< dTSEC Magic Packet detection */
+ ,e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET /**< dTSEC MII management read completion */
+ ,e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET /**< dTSEC MII management write completion */
+ ,e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET /**< dTSEC Graceful receive stop complete */
+ ,e_FM_MAC_EX_1G_TX_DATA_ERR /**< dTSEC Internal data error on transmit */
+ ,e_FM_MAC_EX_1G_RX_DATA_ERR /**< dTSEC Internal data error on receive */
+ ,e_FM_MAC_EX_1G_1588_TS_RX_ERR /**< dTSEC Time-Stamp Receive Error */
+ ,e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL /**< dTSEC MIB counter overflow */
+ ,e_FM_MAC_EX_TS_FIFO_ECC_ERR /**< mEMAC Time-stamp FIFO ECC error interrupt;
+ not supported on T4240/B4860 rev1 chips */
+ ,e_FM_MAC_EX_MAGIC_PACKET_INDICATION = e_FM_MAC_EX_1G_MAG_PCKT
+ /**< mEMAC Magic Packet Indication Interrupt */
+} e_FmMacExceptions;
+
+/**************************************************************************//**
+ @Description TM MAC statistics level
+*//***************************************************************************/
+typedef enum e_FmMacStatisticsLevel {
+ e_FM_MAC_NONE_STATISTICS = 0, /**< No statistics */
+ e_FM_MAC_PARTIAL_STATISTICS, /**< Only error counters are available; Optimized for performance */
+ e_FM_MAC_FULL_STATISTICS /**< All counters available; Not optimized for performance */
+} e_FmMacStatisticsLevel;
+
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Priority Flow Control Parameters
+*//***************************************************************************/
+typedef struct t_FmMacPfcParams {
+ bool pfcEnable; /**< Enable/Disable PFC */
+
+ uint16_t pauseQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES]; /**< Pause Quanta per priority to be sent in a pause frame. Each quanta represents a 512 bit-times*/
+
+ uint16_t pauseThresholdQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES];/**< Pause threshold per priority, when timer passes this threshold time a PFC frames is sent again if the port is still congested or BM pool in depletion*/
+
+
+} t_FmMacPfcParams;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Function t_FmMacExceptionCallback
+
+ @Description Fm Mac Exception Callback from FM MAC to the user
+
+ @Param[in] h_App - Handle to the upper layer handler
+
+ @Param[in] exceptions - The exception that occurred
+
+ @Return void.
+*//***************************************************************************/
+typedef void (t_FmMacExceptionCallback)(t_Handle h_App, e_FmMacExceptions exceptions);
+
+
+/**************************************************************************//**
+ @Description TM MAC statistics rfc3635
+*//***************************************************************************/
+typedef struct t_FmMacStatistics {
+/* RMON */
+ uint64_t eStatPkts64; /**< r-10G tr-DT 64 byte frame counter */
+ uint64_t eStatPkts65to127; /**< r-10G 65 to 127 byte frame counter */
+ uint64_t eStatPkts128to255; /**< r-10G 128 to 255 byte frame counter */
+ uint64_t eStatPkts256to511; /**< r-10G 256 to 511 byte frame counter */
+ uint64_t eStatPkts512to1023; /**< r-10G 512 to 1023 byte frame counter */
+ uint64_t eStatPkts1024to1518; /**< r-10G 1024 to 1518 byte frame counter */
+ uint64_t eStatPkts1519to1522; /**< r-10G 1519 to 1522 byte good frame count */
+/* */
+ uint64_t eStatFragments; /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/
+ uint64_t eStatJabbers; /**< Total number of packets longer than valid maximum length octets */
+ uint64_t eStatsDropEvents; /**< number of dropped packets due to internal errors of the MAC Client (during receive). */
+ uint64_t eStatCRCAlignErrors; /**< Incremented when frames of correct length but with CRC error are received.*/
+ uint64_t eStatUndersizePkts; /**< Incremented for frames under 64 bytes with a valid FCS and otherwise well formed;
+ This count does not include range length errors */
+ uint64_t eStatOversizePkts; /**< Incremented for frames which exceed 1518 (non VLAN) or 1522 (VLAN) and contains
+ a valid FCS and otherwise well formed */
+/* Pause */
+ uint64_t teStatPause; /**< Pause MAC Control received */
+ uint64_t reStatPause; /**< Pause MAC Control sent */
+/* MIB II */
+ uint64_t ifInOctets; /**< Total number of byte received. */
+ uint64_t ifInPkts; /**< Total number of packets received.*/
+ uint64_t ifInUcastPkts; /**< Total number of unicast frame received;
+ NOTE: this counter is not supported on dTSEC MAC */
+ uint64_t ifInMcastPkts; /**< Total number of multicast frame received*/
+ uint64_t ifInBcastPkts; /**< Total number of broadcast frame received */
+ uint64_t ifInDiscards; /**< Frames received, but discarded due to problems within the MAC RX. */
+ uint64_t ifInErrors; /**< Number of frames received with error:
+ - FIFO Overflow Error
+ - CRC Error
+ - Frame Too Long Error
+ - Alignment Error
+ - The dedicated Error Code (0xfe, not a code error) was received */
+ uint64_t ifOutOctets; /**< Total number of byte sent. */
+ uint64_t ifOutPkts; /**< Total number of packets sent .*/
+ uint64_t ifOutUcastPkts; /**< Total number of unicast frame sent;
+ NOTE: this counter is not supported on dTSEC MAC */
+ uint64_t ifOutMcastPkts; /**< Total number of multicast frame sent */
+ uint64_t ifOutBcastPkts; /**< Total number of multicast frame sent */
+ uint64_t ifOutDiscards; /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/
+ uint64_t ifOutErrors; /**< Number of frames transmitted with error:
+ - FIFO Overflow Error
+ - FIFO Underflow Error
+ - Other */
+} t_FmMacStatistics;
+
+/**************************************************************************//**
+ @Description FM MAC Frame Size Counters
+*//***************************************************************************/
+typedef struct t_FmMacFrameSizeCounters {
+
+ uint64_t count_pkts_64; /**< 64 byte frame counter */
+ uint64_t count_pkts_65_to_127; /**< 65 to 127 byte frame counter */
+ uint64_t count_pkts_128_to_255; /**< 128 to 255 byte frame counter */
+ uint64_t count_pkts_256_to_511; /**< 256 to 511 byte frame counter */
+ uint64_t count_pkts_512_to_1023; /**< 512 to 1023 byte frame counter */
+ uint64_t count_pkts_1024_to_1518; /**< 1024 to 1518 byte frame counter */
+ uint64_t count_pkts_1519_to_1522; /**< 1519 to 1522 byte good frame count */
+} t_FmMacFrameSizeCounters;
+
+/**************************************************************************//**
+ @Group FM_mac_init_grp FM MAC Initialization Unit
+
+ @Description FM MAC Initialization Unit
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description FM MAC config input
+*//***************************************************************************/
+typedef struct t_FmMacParams {
+ uintptr_t baseAddr; /**< Base of memory mapped FM MAC registers */
+ t_EnetAddr addr; /**< MAC address of device; First octet is sent first */
+ uint8_t macId; /**< MAC ID;
+ numbering of dTSEC and 1G-mEMAC:
+ 0 - FM_MAX_NUM_OF_1G_MACS;
+ numbering of 10G-MAC (TGEC) and 10G-mEMAC:
+ 0 - FM_MAX_NUM_OF_10G_MACS */
+ e_EnetMode enetMode; /**< Ethernet operation mode (MAC-PHY interface and speed);
+ Note that the speed should indicate the maximum rate that
+ this MAC should support rather than the actual speed;
+ i.e. user should use the FM_MAC_AdjustLink() routine to
+ provide accurate speed;
+ In case of mEMAC RGMII mode, the MAC is configured to RGMII
+ automatic mode, where actual speed/duplex mode information
+ is provided by PHY automatically in-band; FM_MAC_AdjustLink()
+ function should be used to switch to manual RGMII speed/duplex mode
+ configuration if RGMII PHY doesn't support in-band status signaling;
+ In addition, in mEMAC, in case where user is using the higher MACs
+ (i.e. the MACs that should support 10G), user should pass here
+ speed=10000 even if the interface is not allowing that (e.g. SGMII). */
+ t_Handle h_Fm; /**< A handle to the FM object this port related to */
+ int mdioIrq; /**< MDIO exceptions interrupt source - not valid for all
+ MACs; MUST be set to 'NO_IRQ' for MACs that don't have
+ mdio-irq, or for polling */
+ t_FmMacExceptionCallback *f_Event; /**< MDIO Events Callback Routine */
+ t_FmMacExceptionCallback *f_Exception; /**< Exception Callback Routine */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+} t_FmMacParams;
+
+
+/**************************************************************************//**
+ @Function FM_MAC_Config
+
+ @Description Creates descriptor for the FM MAC module.
+
+ The routine returns a handle (descriptor) to the FM MAC object.
+ This descriptor must be passed as first parameter to all other
+ FM MAC function calls.
+
+ No actual initialization or configuration of FM MAC hardware is
+ done by this routine.
+
+ @Param[in] p_FmMacParam - Pointer to data structure of parameters
+
+ @Retval Handle to FM MAC object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_MAC_Config(t_FmMacParams *p_FmMacParam);
+
+/**************************************************************************//**
+ @Function FM_MAC_Init
+
+ @Description Initializes the FM MAC module
+
+ @Param[in] h_FmMac - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MAC_Init(t_Handle h_FmMac);
+
+/**************************************************************************//**
+ @Function FM_Free
+
+ @Description Frees all resources that were assigned to FM MAC module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmMac - FM module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MAC_Free(t_Handle h_FmMac);
+
+
+/**************************************************************************//**
+ @Group FM_mac_advanced_init_grp FM MAC Advanced Configuration Unit
+
+ @Description Configuration functions used to change default values.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigResetOnInit
+
+ @Description Tell the driver whether to reset the FM MAC before initialization or
+ not. It changes the default configuration [DEFAULT_resetOnInit].
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable When TRUE, FM will be reset before any initialization.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigResetOnInit(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigLoopback
+
+ @Description Enable/Disable internal loopback mode
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigLoopback(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigMaxFrameLength
+
+ @Description Setup maximum Rx Frame Length (in 1G MAC, effects also Tx)
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] newVal MAX Frame length
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigMaxFrameLength(t_Handle h_FmMac, uint16_t newVal);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigWan
+
+ @Description ENABLE WAN mode in 10G-MAC
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigWan(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigPadAndCrc
+
+ @Description Config PAD and CRC mode
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+ Not supported on 10G-MAC (i.e. CRC & PAD are added automatically
+ by HW); on mEMAC, this routine supports only PAD (i.e. CRC is
+ added automatically by HW).
+*//***************************************************************************/
+t_Error FM_MAC_ConfigPadAndCrc(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigHalfDuplex
+
+ @Description Config Half Duplex Mode
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigHalfDuplex(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigTbiPhyAddr
+
+ @Description Configures the address of internal TBI PHY.
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] newVal TBI PHY address (1-31).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigTbiPhyAddr(t_Handle h_FmMac, uint8_t newVal);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigLengthCheck
+
+ @Description Configure the frame length checking.
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] enable TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigLengthCheck(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_ConfigException
+
+ @Description Change Exception selection from default
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] ex Type of the desired exceptions
+ @Param[in] enable TRUE to enable the specified exception, FALSE to disable it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ConfigException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
+
+#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac);
+#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */
+/** @} */ /* end of FM_mac_advanced_init_grp group */
+/** @} */ /* end of FM_mac_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_mac_runtime_control_grp FM MAC Runtime Control Unit
+
+ @Description FM MAC Runtime control unit API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MAC_Enable
+
+ @Description Enable the MAC
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] mode Mode of operation (RX, TX, Both)
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_Enable(t_Handle h_FmMac, e_CommMode mode);
+
+/**************************************************************************//**
+ @Function FM_MAC_Disable
+
+ @Description DISABLE the MAC
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+ @Param[in] mode Define what part to Disable (RX, TX or BOTH)
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_Disable(t_Handle h_FmMac, e_CommMode mode);
+
+/**************************************************************************//**
+ @Function FM_MAC_Resume
+
+ @Description Re-init the MAC after suspend
+
+ @Param[in] h_FmMac A handle to a FM MAC Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_Resume(t_Handle h_FmMac);
+
+/**************************************************************************//**
+ @Function FM_MAC_Enable1588TimeStamp
+
+ @Description Enables the TSU operation.
+
+ @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_Enable1588TimeStamp(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_MAC_Disable1588TimeStamp
+
+ @Description Disables the TSU operation.
+
+ @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_Disable1588TimeStamp(t_Handle h_Fm);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetTxAutoPauseFrames
+
+ @Description Enable/Disable transmission of Pause-Frames.
+ The routine changes the default configuration [DEFAULT_TX_PAUSE_TIME].
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] pauseTime - Pause quanta value used with transmitted pause frames.
+ Each quanta represents a 512 bit-times; Note that '0'
+ as an input here will be used as disabling the
+ transmission of the pause-frames.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac,
+ uint16_t pauseTime);
+
+ /**************************************************************************//**
+ @Function FM_MAC_SetTxPauseFrames
+
+ @Description Enable/Disable transmission of Pause-Frames.
+ The routine changes the default configuration:
+ pause-time - [DEFAULT_TX_PAUSE_TIME]
+ threshold-time - [0]
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] priority - the PFC class of service; use 'FM_MAC_NO_PFC'
+ to indicate legacy pause support (i.e. no PFC).
+ @Param[in] pauseTime - Pause quanta value used with transmitted pause frames.
+ Each quanta represents a 512 bit-times;
+ Note that '0' as an input here will be used as disabling the
+ transmission of the pause-frames.
+ @Param[in] threshTime - Pause Threshold equanta value used by the MAC to retransmit pause frame.
+ if the situation causing a pause frame to be sent didn't finish when the timer
+ reached the threshold quanta, the MAC will retransmit the pause frame.
+ Each quanta represents a 512 bit-times.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+ In order for PFC to work properly the user must configure
+ TNUM-aging in the tx-port it is recommended that pre-fetch and
+ rate limit in the tx port should be disabled;
+ PFC is supported only on new mEMAC; i.e. in MACs that don't have
+ PFC support (10G-MAC and dTSEC), user should use 'FM_MAC_NO_PFC'
+ in the 'priority' field.
+*//***************************************************************************/
+t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac,
+ uint8_t priority,
+ uint16_t pauseTime,
+ uint16_t threshTime);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetRxIgnorePauseFrames
+
+ @Description Enable/Disable ignoring of Pause-Frames.
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] en - boolean indicates whether to ignore the incoming pause
+ frames or not.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetRxIgnorePauseFrames(t_Handle h_FmMac, bool en);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetWakeOnLan
+
+ @Description Enable/Disable Wake On Lan support
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] en - boolean indicates whether to enable Wake On Lan
+ support or not.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetWakeOnLan(t_Handle h_FmMac, bool en);
+
+/**************************************************************************//**
+ @Function FM_MAC_ResetCounters
+
+ @Description reset all statistics counters
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ResetCounters(t_Handle h_FmMac);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetException
+
+ @Description Enable/Disable a specific Exception
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] ex - Type of the desired exceptions
+ @Param[in] enable - TRUE to enable the specified exception, FALSE to disable it.
+
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetStatistics
+
+ @Description Define Statistics level.
+ Where applicable, the routine also enables the MIB counters
+ overflow interrupt in order to keep counters accurate
+ and account for overflows.
+ This routine is relevant only for dTSEC.
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] statisticsLevel - Full statistics level provides all standard counters but may
+ reduce performance. Partial statistics provides only special
+ event counters (errors etc.). If selected, regular counters (such as
+ byte/packet) will be invalid and will return -1.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetStatistics(t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel);
+
+/**************************************************************************//**
+ @Function FM_MAC_GetStatistics
+
+ @Description get all statistics counters
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] p_Statistics - Structure with statistics
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_MAC_GetStatistics(t_Handle h_FmMac, t_FmMacStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MAC_GetFrameSizeCounters
+
+ @Description get MAC statistics counters for different frame size
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] p_FrameSizeCounters - Structure with counters
+ @Param[in] type - Type of counters to be read
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_Init().
+*//***************************************************************************/
+t_Error FM_MAC_GetFrameSizeCounters(t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type);
+
+/**************************************************************************//**
+ @Function FM_MAC_ModifyMacAddr
+
+ @Description Replace the main MAC Address
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] p_EnetAddr - Ethernet Mac address
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_ModifyMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+/**************************************************************************//**
+ @Function FM_MAC_AddHashMacAddr
+
+ @Description Add an Address to the hash table. This is for filter purpose only.
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] p_EnetAddr - Ethernet Mac address
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init(). It is a filter only address.
+ @Cautions Some address need to be filterd out in upper FM blocks.
+*//***************************************************************************/
+t_Error FM_MAC_AddHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+/**************************************************************************//**
+ @Function FM_MAC_RemoveHashMacAddr
+
+ @Description Delete an Address to the hash table. This is for filter purpose only.
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] p_EnetAddr - Ethernet Mac address
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_RemoveHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+/**************************************************************************//**
+ @Function FM_MAC_AddExactMatchMacAddr
+
+ @Description Add a unicast or multicast mac address for exact-match filtering
+ (8 on dTSEC, 2 for 10G-MAC)
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] p_EnetAddr - MAC Address to ADD
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_AddExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+/**************************************************************************//**
+ @Function FM_MAC_RemovelExactMatchMacAddr
+
+ @Description Remove a uni cast or multi cast mac address.
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] p_EnetAddr - MAC Address to remove
+
+ @Return E_OK on success; Error code otherwise..
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_RemovelExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr);
+
+/**************************************************************************//**
+ @Function FM_MAC_SetPromiscuous
+
+ @Description Enable/Disable MAC Promiscuous mode for ALL mac addresses.
+
+ @Param[in] h_FmMac - A handle to a FM MAC Module.
+ @Param[in] enable - TRUE to enable or FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_SetPromiscuous(t_Handle h_FmMac, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MAC_AdjustLink
+
+ @Description Adjusts the Ethernet link with new speed/duplex setup.
+ This routine is relevant for dTSEC and mEMAC.
+ In case of mEMAC, this routine is also used for manual
+ re-configuration of RGMII speed and duplex mode for
+ RGMII PHYs not supporting in-band status information
+ to MAC.
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] speed - Ethernet speed.
+ @Param[in] fullDuplex - TRUE for full-duplex mode;
+ FALSE for half-duplex mode.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex);
+
+/**************************************************************************//**
+ @Function FM_MAC_RestartAutoneg
+
+ @Description Restarts the auto-negotiation process.
+ When auto-negotiation process is invoked under traffic the
+ auto-negotiation process between the internal SGMII PHY and the
+ external PHY does not always complete successfully. Calling this
+ function will restart the auto-negotiation process that will end
+ successfully. It is recommended to call this function after issuing
+ auto-negotiation restart command to the Eth Phy.
+ This routine is relevant only for dTSEC.
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac);
+
+/**************************************************************************//**
+ @Function FM_MAC_GetId
+
+ @Description Return the MAC ID
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[out] p_MacId - MAC ID of device
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_GetId(t_Handle h_FmMac, uint32_t *p_MacId);
+
+/**************************************************************************//**
+ @Function FM_MAC_GetVesrion
+
+ @Description Return Mac HW chip version
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[out] p_MacVresion - Mac version as defined by the chip
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_GetVesrion(t_Handle h_FmMac, uint32_t *p_MacVresion);
+
+/**************************************************************************//**
+ @Function FM_MAC_MII_WritePhyReg
+
+ @Description Write data into Phy Register
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] phyAddr - Phy Address on the MII bus
+ @Param[in] reg - Register Number.
+ @Param[in] data - Data to write.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_MII_WritePhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data);
+
+/**************************************************************************//**
+ @Function FM_MAC_MII_ReadPhyReg
+
+ @Description Read data from Phy Register
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+ @Param[in] phyAddr - Phy Address on the MII bus
+ @Param[in] reg - Register Number.
+ @Param[out] p_Data - Data from PHY.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_MAC_DumpRegs
+
+ @Description Dump internal registers
+
+ @Param[in] h_FmMac - A handle to a FM Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MAC_Init().
+*//***************************************************************************/
+t_Error FM_MAC_DumpRegs(t_Handle h_FmMac);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+/** @} */ /* end of FM_mac_runtime_control_grp group */
+/** @} */ /* end of FM_mac_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_MAC_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h
new file mode 100644
index 000000000000..57925f1040b9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h
@@ -0,0 +1,1271 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File fm_macsec_ext.h
+
+ @Description FM MACSEC ...
+*//***************************************************************************/
+#ifndef __FM_MACSEC_EXT_H
+#define __FM_MACSEC_EXT_H
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_MACSEC_grp FM MACSEC
+
+ @Description FM MACSEC API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description MACSEC Exceptions
+*//***************************************************************************/
+typedef enum e_FmMacsecExceptions {
+ e_FM_MACSEC_EX_SINGLE_BIT_ECC, /**< Single bit ECC error */
+ e_FM_MACSEC_EX_MULTI_BIT_ECC /**< Multi bit ECC error */
+} e_FmMacsecExceptions;
+
+
+/**************************************************************************//**
+ @Group FM_MACSEC_init_grp FM-MACSEC Initialization Unit
+
+ @Description FM MACSEC Initialization Unit
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function t_FmMacsecExceptionsCallback
+
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+
+ @Param[in] h_App A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] exception The exception.
+*//***************************************************************************/
+typedef void (t_FmMacsecExceptionsCallback) ( t_Handle h_App,
+ e_FmMacsecExceptions exception);
+
+
+/**************************************************************************//**
+ @Description FM MACSEC config input
+*//***************************************************************************/
+typedef struct t_FmMacsecParams {
+ t_Handle h_Fm; /**< A handle to the FM object related to */
+ bool guestMode; /**< Partition-id */
+ union {
+ struct {
+ uint8_t fmMacId; /**< FM MAC id */
+ } guestParams;
+
+ struct {
+ uintptr_t baseAddr; /**< Base of memory mapped FM MACSEC registers */
+ t_Handle h_FmMac; /**< A handle to the FM MAC object related to */
+ t_FmMacsecExceptionsCallback *f_Exception; /**< Exception Callback Routine */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+ } nonGuestParams;
+ };
+} t_FmMacsecParams;
+
+/**************************************************************************//**
+ @Function FM_MACSEC_Config
+
+ @Description Creates descriptor for the FM MACSEC module;
+
+ The routine returns a handle (descriptor) to the FM MACSEC object;
+ This descriptor must be passed as first parameter to all other
+ FM MACSEC function calls;
+
+ No actual initialization or configuration of FM MACSEC hardware is
+ done by this routine.
+
+ @Param[in] p_FmMacsecParam Pointer to data structure of parameters.
+
+ @Retval Handle to FM MACSEC object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_Init
+
+ @Description Initializes the FM MACSEC module.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MACSEC_Init(t_Handle h_FmMacsec);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_Free
+
+ @Description Frees all resources that were assigned to FM MACSEC module;
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MACSEC_Free(t_Handle h_FmMacsec);
+
+
+/**************************************************************************//**
+ @Group FM_MACSEC_advanced_init_grp FM-MACSEC Advanced Configuration Unit
+
+ @Description Configuration functions used to change default values.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description enum for unknown sci frame treatment
+*//***************************************************************************/
+typedef enum e_FmMacsecUnknownSciFrameTreatment {
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH = 0, /**< Controlled port - Strict mode */
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED, /**< If C bit clear deliver on controlled port, else discard
+ Controlled port - Check or Disable mode */
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED, /**< Controlled port - Strict mode */
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED /**< If C bit set deliver on uncontrolled port and discard on controlled port,
+ else discard on uncontrolled port and deliver on controlled port
+ Controlled port - Check or Disable mode */
+} e_FmMacsecUnknownSciFrameTreatment;
+
+/**************************************************************************//**
+ @Description enum for untag frame treatment
+*//***************************************************************************/
+typedef enum e_FmMacsecUntagFrameTreatment {
+ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED = 0, /**< Controlled port - Strict mode */
+ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH, /**< Controlled port - Strict mode */
+ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED /**< Controlled port - Strict mode */
+} e_FmMacsecUntagFrameTreatment;
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigUnknownSciFrameTreatment
+
+ @Description Change the treatment for received frames with unknown sci from its default
+ configuration [DEFAULT_unknownSciFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] treatMode The selected mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigInvalidTagsFrameTreatment
+
+ @Description Change the treatment for received frames with invalid tags or
+ a zero value PN or an invalid ICV from its default configuration
+ [DEFAULT_invalidTagsFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard;
+ In both cases discard on the controlled port;
+ this provide Strict, Check or Disable mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment
+
+ @Description Change the treatment for received frames with the Encryption bit
+ set and the Changed Text bit clear from its default configuration
+ [DEFAULT_encryptWithNoChangedTextFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] discardUncontrolled If True discard on the uncontrolled port, else deliver;
+ In both cases discard on the controlled port;
+ this provide Strict, Check or Disable mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment
+
+ @Description Change the treatment for received frames with the Encryption bit
+ clear and the Changed Text bit set from its default configuration
+ [DEFAULT_changedTextWithNoEncryptFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard;
+ In both cases discard on the controlled port;
+ this provide Strict, Check or Disable mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigUntagFrameTreatment
+
+ @Description Change the treatment for received frames without the MAC security tag (SecTAG)
+ from its default configuration [DEFAULT_untagFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] treatMode The selected mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment
+
+ @Description Change the treatment for received frames with only SCB bit set
+ from its default configuration [DEFAULT_onlyScbIsSetFrameTreatment].
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard;
+ In both cases discard on the controlled port;
+ this provide Strict, Check or Disable mode.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigPnExhaustionThreshold
+
+ @Description It's provide the ability to configure a PN exhaustion threshold;
+ When the NextPn crosses this value an interrupt event
+ is asserted to warn that the active SA should re-key.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] pnExhThr If the threshold is reached, an interrupt event
+ is asserted to re-key.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigKeysUnreadable
+
+ @Description Turn on privacy mode; All the keys and their hash values can't be read any more;
+ Can not be cleared unless hard reset.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigSectagWithoutSCI
+
+ @Description Promise that all generated Sectag will be without SCI included.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_ConfigException
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of exceptions enablement;
+ By default all exceptions are enabled.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
+
+/** @} */ /* end of FM_MACSEC_advanced_init_grp group */
+/** @} */ /* end of FM_MACSEC_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_MACSEC_runtime_control_grp FM-MACSEC Runtime Control Data Unit
+
+ @Description FM MACSEC runtime control data unit API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MACSEC_GetRevision
+
+ @Description Return MACSEC HW chip revision
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[out] p_MacsecRevision MACSEC revision as defined by the chip.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_Enable
+
+ @Description This routine should be called after MACSEC is initialized for enabling all
+ MACSEC engines according to their existing configuration.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Init() and when MACSEC is disabled.
+*//***************************************************************************/
+t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_Disable
+
+ @Description This routine may be called when MACSEC is enabled in order to
+ disable all MACSEC engines; The MACSEC is working in bypass mode.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Init() and when MACSEC is enabled.
+*//***************************************************************************/
+t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SetException
+
+ @Description Calling this routine enables/disables the specified exception.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_MACSEC_DumpRegs
+
+ @Description Dump internal registers.
+
+ @Param[in] h_FmMacsec - FM MACSEC module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only after FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_DumpRegs(t_Handle h_FmMacsec);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+#ifdef VERIFICATION_SUPPORT
+/********************* VERIFICATION ONLY ********************************/
+/**************************************************************************//**
+ @Function FM_MACSEC_BackdoorSet
+
+ @Description Set register of the MACSEC memory map
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[out] offset Register offset.
+ @Param[out] value Value to write.
+
+
+ @Return None
+
+ @Cautions Allowed only following FM_MACSEC_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_BackdoorSet(t_Handle h_FmMacsec, uint32_t offset, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_BackdoorGet
+
+ @Description Read from register of the MACSEC memory map.
+
+ @Param[in] h_FmMacsec FM MACSEC module descriptor.
+ @Param[out] offset Register offset.
+
+ @Return Value read
+
+ @Cautions Allowed only following FM_MACSEC_Init().
+*//***************************************************************************/
+uint32_t FM_MACSEC_BackdoorGet(t_Handle h_FmMacsec, uint32_t offset);
+#endif /* VERIFICATION_SUPPORT */
+
+/** @} */ /* end of FM_MACSEC_runtime_control_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_MACSEC_SECY_grp FM-MACSEC SecY
+
+ @Description FM-MACSEC SecY API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+typedef uint8_t macsecSAKey_t[32];
+typedef uint64_t macsecSCI_t;
+typedef uint8_t macsecAN_t;
+
+/**************************************************************************//**
+@Description MACSEC SECY Cipher Suite
+*//***************************************************************************/
+typedef enum e_FmMacsecSecYCipherSuite {
+ e_FM_MACSEC_SECY_GCM_AES_128 = 0, /**< GCM-AES-128 */
+#if (DPAA_VERSION >= 11)
+ e_FM_MACSEC_SECY_GCM_AES_256 /**< GCM-AES-256 */
+#endif /* (DPAA_VERSION >= 11) */
+} e_FmMacsecSecYCipherSuite;
+
+/**************************************************************************//**
+ @Description MACSEC SECY Exceptions
+*//***************************************************************************/
+typedef enum e_FmMacsecSecYExceptions {
+ e_FM_MACSEC_SECY_EX_FRAME_DISCARDED /**< Frame Discarded */
+} e_FmMacsecSecYExceptions;
+
+/**************************************************************************//**
+ @Description MACSEC SECY Events
+*//***************************************************************************/
+typedef enum e_FmMacsecSecYEvents {
+ e_FM_MACSEC_SECY_EV_NEXT_PN /**< Next Packet Number exhaustion threshold reached */
+} e_FmMacsecSecYEvents;
+
+/**************************************************************************//**
+ @Collection MACSEC SECY Frame Discarded Descriptor error
+*//***************************************************************************/
+typedef uint8_t macsecTxScFrameDiscardedErrSelect_t; /**< typedef for defining Frame Discarded Descriptor errors */
+
+#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_NEXT_PN_ZERO 0x8000 /**< NextPn == 0 */
+#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_SC_DISBALE 0x4000 /**< SC is disable */
+/* @} */
+
+/**************************************************************************//**
+ @Function t_FmMacsecSecYExceptionsCallback
+
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+
+ @Param[in] h_App A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] exception The exception.
+*//***************************************************************************/
+typedef void (t_FmMacsecSecYExceptionsCallback) ( t_Handle h_App,
+ e_FmMacsecSecYExceptions exception);
+
+/**************************************************************************//**
+ @Function t_FmMacsecSecYEventsCallback
+
+ @Description Events user callback routine, will be called upon an
+ event passing the event identification.
+
+ @Param[in] h_App A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] event The event.
+*//***************************************************************************/
+typedef void (t_FmMacsecSecYEventsCallback) ( t_Handle h_App,
+ e_FmMacsecSecYEvents event);
+
+/**************************************************************************//**
+ @Description RFC2863 MIB
+*//***************************************************************************/
+typedef struct t_MIBStatistics {
+ uint64_t ifInOctets; /**< Total number of byte received */
+ uint64_t ifInPkts; /**< Total number of packets received */
+ uint64_t ifInMcastPkts; /**< Total number of multicast frame received */
+ uint64_t ifInBcastPkts; /**< Total number of broadcast frame received */
+ uint64_t ifInDiscards; /**< Frames received, but discarded due to problems within the MAC RX :
+ - InPktsNoTag,
+ - InPktsLate,
+ - InPktsOverrun */
+ uint64_t ifInErrors; /**< Number of frames received with error:
+ - InPktsBadTag,
+ - InPktsNoSCI,
+ - InPktsNotUsingSA
+ - InPktsNotValid */
+ uint64_t ifOutOctets; /**< Total number of byte sent */
+ uint64_t ifOutPkts; /**< Total number of packets sent */
+ uint64_t ifOutMcastPkts; /**< Total number of multicast frame sent */
+ uint64_t ifOutBcastPkts; /**< Total number of multicast frame sent */
+ uint64_t ifOutDiscards; /**< Frames received, but discarded due to problems within the MAC TX N/A! */
+ uint64_t ifOutErrors; /**< Number of frames transmitted with error:
+ - FIFO Overflow Error
+ - FIFO Underflow Error
+ - Other */
+} t_MIBStatistics;
+
+/**************************************************************************//**
+ @Description MACSEC SecY Rx SA Statistics
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYRxSaStatistics {
+ uint32_t inPktsOK; /**< The number of frames with resolved SCI, have passed all
+ frame validation frame validation with the validateFrame not set to disable */
+ uint32_t inPktsInvalid; /**< The number of frames with resolved SCI, that have failed frame
+ validation with the validateFrame set to check */
+ uint32_t inPktsNotValid; /**< The number of frames with resolved SCI, discarded on the controlled port,
+ that have failed frame validation with the validateFrame set to strict or the c bit is set */
+ uint32_t inPktsNotUsingSA; /**< The number of frames received with resolved SCI and discarded on disabled or
+ not provisioned SA with validateFrame in the strict mode or the C bit is set */
+ uint32_t inPktsUnusedSA; /**< The number of frames received with resolved SCI on disabled or not provisioned SA
+ with validateFrame not in the strict mode and the C bit is cleared */
+} t_FmMacsecSecYRxSaStatistics;
+
+/**************************************************************************//**
+ @Description MACSEC SecY Tx SA Statistics
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYTxSaStatistics {
+ uint64_t outPktsProtected; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, which were integrity protected */
+ uint64_t outPktsEncrypted; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, which were confidentiality protected */
+} t_FmMacsecSecYTxSaStatistics;
+
+/**************************************************************************//**
+ @Description MACSEC SecY Rx SC Statistics
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYRxScStatistics {
+ uint64_t inPktsUnchecked; /**< The number of frames with resolved SCI, delivered to the user of a controlled port,
+ that are not validated with the validateFrame set to disable */
+ uint64_t inPktsDelayed; /**< The number of frames with resolved SCI, delivered to the user of a controlled port,
+ that have their PN smaller than the lowest_PN with the validateFrame set to
+ disable or replayProtect disabled */
+ uint64_t inPktsLate; /**< The number of frames with resolved SCI, discarded on the controlled port,
+ that have their PN smaller than the lowest_PN with the validateFrame set to
+ Check or Strict and replayProtect enabled */
+ uint64_t inPktsOK; /**< The number of frames with resolved SCI, have passed all
+ frame validation frame validation with the validateFrame not set to disable */
+ uint64_t inPktsInvalid; /**< The number of frames with resolved SCI, that have failed frame
+ validation with the validateFrame set to check */
+ uint64_t inPktsNotValid; /**< The number of frames with resolved SCI, discarded on the controlled port,
+ that have failed frame validation with the validateFrame set to strict or the c bit is set */
+ uint64_t inPktsNotUsingSA; /**< The number of frames received with resolved SCI and discarded on disabled or
+ not provisioned SA with validateFrame in the strict mode or the C bit is set */
+ uint64_t inPktsUnusedSA; /**< The number of frames received with resolved SCI on disabled or not provisioned SA
+ with validateFrame not in the strict mode and the C bit is cleared */
+} t_FmMacsecSecYRxScStatistics;
+
+/**************************************************************************//**
+ @Description MACSEC SecY Tx SC Statistics
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYTxScStatistics {
+ uint64_t outPktsProtected; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, which were integrity protected */
+ uint64_t outPktsEncrypted; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, which were confidentiality protected */
+} t_FmMacsecSecYTxScStatistics;
+
+/**************************************************************************//**
+ @Description MACSEC SecY Statistics
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYStatistics {
+ t_MIBStatistics mibCtrlStatistics; /**< Controlled port MIB statistics */
+ t_MIBStatistics mibNonCtrlStatistics; /**< Uncontrolled port MIB statistics */
+/* Frame verification statistics */
+ uint64_t inPktsUntagged; /**< The number of received packets without the MAC security tag
+ (SecTAG) with validateFrames which is not in the strict mode */
+ uint64_t inPktsNoTag; /**< The number of received packets discarded without the
+ MAC security tag (SecTAG) with validateFrames which is in the strict mode */
+ uint64_t inPktsBadTag; /**< The number of received packets discarded with an invalid
+ SecTAG or a zero value PN or an invalid ICV */
+ uint64_t inPktsUnknownSCI; /**< The number of received packets with unknown SCI with the
+ condition : validateFrames is not in the strict mode and the
+ C bit in the SecTAG is not set */
+ uint64_t inPktsNoSCI; /**< The number of received packets discarded with unknown SCI
+ information with the condition : validateFrames is in the strict mode
+ or the C bit in the SecTAG is set */
+ uint64_t inPktsOverrun; /**< The number of packets discarded because the number of
+ received packets exceeded the cryptographic performance capabilities */
+/* Frame validation statistics */
+ uint64_t inOctetsValidated; /**< The number of octets of plaintext recovered from received frames with
+ resolved SCI that were integrity protected but not encrypted */
+ uint64_t inOctetsDecrypted; /**< The number of octets of plaintext recovered from received frames with
+ resolved SCI that were integrity protected and encrypted */
+/* Frame generation statistics */
+ uint64_t outPktsUntagged; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, with protectFrame false */
+ uint64_t outPktsTooLong; /**< The number of frames, that the user of the controlled port requested to
+ be transmitted, discarded due to length being larger than Maximum Frame Length (MACSEC_MFL) */
+/* Frame protection statistics */
+ uint64_t outOctetsProtected; /**< The number of octets of User Data in transmitted frames that were
+ integrity protected but not encrypted */
+ uint64_t outOctetsEncrypted; /**< The number of octets of User Data in transmitted frames that were
+ both integrity protected and encrypted */
+} t_FmMacsecSecYStatistics;
+
+
+/**************************************************************************//**
+ @Description MACSEC SecY SC Params
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYSCParams {
+ macsecSCI_t sci; /**< The secure channel identification of the SC */
+ e_FmMacsecSecYCipherSuite cipherSuite; /**< Cipher suite to be used for the SC */
+} t_FmMacsecSecYSCParams;
+
+/**************************************************************************//**
+ @Group FM_MACSEC_SECY_init_grp FM-MACSEC SecY Initialization Unit
+
+ @Description FM-MACSEC SecY Initialization Unit
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description enum for validate frames
+*//***************************************************************************/
+typedef enum e_FmMacsecValidFrameBehavior {
+ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE = 0, /**< disable the validation function */
+ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK, /**< enable the validation function but only for checking
+ without filtering out invalid frames */
+ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT /**< enable the validation function and also strictly filter
+ out those invalid frames */
+} e_FmMacsecValidFrameBehavior;
+
+/**************************************************************************//**
+ @Description enum for sci insertion
+*//***************************************************************************/
+typedef enum e_FmMacsecSciInsertionMode {
+ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG = 0, /**< explicit sci in the sectag */
+ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA, /**< mac sa is overwritten with the sci*/
+ e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP /**< implicit point-to-point sci (pre-shared) */
+} e_FmMacsecSciInsertionMode;
+
+/**************************************************************************//**
+ @Description FM MACSEC SecY config input
+*//***************************************************************************/
+typedef struct t_FmMacsecSecYParams {
+ t_Handle h_FmMacsec; /**< A handle to the FM MACSEC object */
+ t_FmMacsecSecYSCParams txScParams; /**< Tx SC Params */
+ uint32_t numReceiveChannels; /**< Number of receive channels dedicated to this SecY */
+ t_FmMacsecSecYExceptionsCallback *f_Exception; /**< Callback routine to be called by the driver upon SecY exception */
+ t_FmMacsecSecYEventsCallback *f_Event; /**< Callback routine to be called by the driver upon SecY event */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+} t_FmMacsecSecYParams;
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_Config
+
+ @Description Creates descriptor for the FM MACSEC SECY module;
+
+ The routine returns a handle (descriptor) to the FM MACSEC SECY object;
+ This descriptor must be passed as first parameter to all other
+ FM MACSEC SECY function calls;
+ No actual initialization or configuration of FM MACSEC SecY hardware is
+ done by this routine.
+
+ @Param[in] p_FmMacsecSecYParam Pointer to data structure of parameters.
+
+ @Return Handle to FM MACSEC SECY object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_Init
+
+ @Description Initializes the FM MACSEC SECY module.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_Free
+
+ @Description Frees all resources that were assigned to FM MACSEC SECY module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY);
+
+/**************************************************************************//**
+ @Group FM_MACSEC_SECY_advanced_init_grp FM-MACSEC SecY Advanced Configuration Unit
+
+ @Description Configuration functions used to change default values.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigSciInsertionMode
+
+ @Description Calling this routine changes the SCI-insertion-mode in the
+ internal driver data base from its default configuration
+ [DEFAULT_sciInsertionMode]
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] sciInsertionMode Sci insertion mode
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigProtectFrames
+
+ @Description Calling this routine changes the protect-frame mode in the
+ internal driver data base from its default configuration
+ [DEFAULT_protectFrames]
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] protectFrames If FALSE, frames are transmitted without modification
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigReplayWindow
+
+ @Description Calling this routine changes the replay-window settings in the
+ internal driver data base from its default configuration
+ [DEFAULT_replayEnable], [DEFAULT_replayWindow]
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] replayProtect; Replay protection function mode
+ @Param[in] replayWindow; The size of the replay window
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigValidationMode
+
+ @Description Calling this routine changes the frame-validation-behavior mode
+ in the internal driver data base from its default configuration
+ [DEFAULT_validateFrames]
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] validateFrames Validation function mode
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigConfidentiality
+
+ @Description Calling this routine changes the confidentiality settings in the
+ internal driver data base from its default configuration
+ [DEFAULT_confidentialityEnable], [DEFAULT_confidentialityOffset]
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] confidentialityEnable TRUE - confidentiality protection and integrity protection
+ FALSE - no confidentiality protection, only integrity protection
+ @Param[in] confidentialityOffset The number of initial octets of each MSDU without confidentiality protection
+ common values are 0, 30, and 50
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigPointToPoint
+
+ @Description configure this SecY to work in point-to-point mode, means that
+ it will have only one rx sc;
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init();
+ Can be called only once in a system; only the first secY that will call this
+ routine will be able to operate in Point-To-Point mode.
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigException
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of exceptions enablement;
+ By default all exceptions are enabled.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_ConfigEvent
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of events enablement;
+ By default all events are enabled.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] event The event to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable);
+
+/** @} */ /* end of FM_MACSEC_SECY_advanced_init_grp group */
+/** @} */ /* end of FM_MACSEC_SECY_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_MACSEC_SECY_runtime_control_grp FM-MACSEC SecY Runtime Control Unit
+
+ @Description FM MACSEC SECY Runtime control unit API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_CreateRxSc
+
+ @Description Create a receive secure channel.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] scParams secure channel params.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_DeleteRxSc
+
+ @Description Deleting an initialized secure channel.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_CreateRxSa
+
+ @Description Create a receive secure association for the secure channel;
+ the SA cannot be used to receive frames until FM_MACSEC_SECY_RxSaEnableReceive is called.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+ @Param[in] lowestPn the lowest acceptable PN value for a received frame.
+ @Param[in] key the desired key for this SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_DeleteRxSa
+
+ @Description Deleting an initialized secure association.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaEnableReceive
+
+ @Description Enabling the SA to receive frames.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaDisableReceive
+
+ @Description Disabling the SA from receive frames.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaUpdateNextPn
+
+ @Description Update the next packet number expected on RX;
+ The value of nextPN shall be set to the greater of its existing value and the
+ supplied of updtNextPN (802.1AE-2006 10.7.15).
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+ @Param[in] updtNextPN the next PN value for a received frame.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaUpdateLowestPn
+
+ @Description Update the lowest packet number expected on RX;
+ The value of lowestPN shall be set to the greater of its existing value and the
+ supplied of updtLowestPN (802.1AE-2006 10.7.15).
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+ @Param[in] updtLowestPN the lowest PN acceptable value for a received frame.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaModifyKey
+
+ @Description Modify the current key of the SA with a new one.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[in] an association number represent the SA.
+ @Param[in] key new key to replace the current key.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_CreateTxSa
+
+ @Description Create a transmit secure association for the secure channel;
+ the SA cannot be used to transmit frames until FM_MACSEC_SECY_TxSaSetActivate is called;
+ Only one SA can be active at a time.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] an association number represent the SA.
+ @Param[in] key the desired key for this SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_DeleteTxSa
+
+ @Description Deleting an initialized secure association.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] an association number represent the SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_TxSaModifyKey
+
+ @Description Modify the key of the inactive SA with a new one.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] nextActiveAn association number represent the next SA to be activated.
+ @Param[in] key new key to replace the current key.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_TxSaSetActive
+
+ @Description Set this SA to the active SA to be used on TX for SC;
+ only one SA can be active at a time.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] an association number represent the SA.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_TxSaGetActive
+
+ @Description Get the active SA that being used for TX.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[out] p_An the active an.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_GetStatistics
+
+ @Description get all statistics counters.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] p_Statistics Structure with statistics.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxScGetStatistics
+
+ @Description get all statistics counters.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc Rx Sc handle.
+ @Param[in] p_Statistics Structure with statistics.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_RxSaGetStatistics
+
+ @Description get all statistics counters
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc Rx Sc handle.
+ @Param[in] an association number represent the SA.
+ @Param[in] p_Statistics Structure with statistics.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_TxScGetStatistics
+
+ @Description get all statistics counters.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] p_Statistics Structure with statistics.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_TxSaGetStatistics
+
+ @Description get all statistics counters.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] an association number represent the SA.
+ @Param[in] p_Statistics Structure with statistics.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_SetException
+
+ @Description Calling this routine enables/disables the specified exception.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_SetEvent
+
+ @Description Calling this routine enables/disables the specified event.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] event The event to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_GetRxScPhysId
+
+ @Description return the physical id of the Secure Channel.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc.
+ @Param[out] p_ScPhysId the SC physical id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId);
+
+/**************************************************************************//**
+ @Function FM_MACSEC_SECY_GetTxScPhysId
+
+ @Description return the physical id of the Secure Channel.
+
+ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor.
+ @Param[out] p_ScPhysId the SC physical id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_MACSEC_SECY_Init().
+*//***************************************************************************/
+t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId);
+
+/** @} */ /* end of FM_MACSEC_SECY_runtime_control_grp group */
+/** @} */ /* end of FM_MACSEC_SECY_grp group */
+/** @} */ /* end of FM_MACSEC_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_MACSEC_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h
new file mode 100644
index 000000000000..ef62c8ef28d5
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_muram_ext.h
+
+ @Description FM MURAM Application Programming Interface.
+*//***************************************************************************/
+#ifndef __FM_MURAM_EXT
+#define __FM_MURAM_EXT
+
+#include "error_ext.h"
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_muram_grp FM MURAM
+
+ @Description FM MURAM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_muram_init_grp FM MURAM Initialization Unit
+
+ @Description FM MURAM initialization API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MURAM_ConfigAndInit
+
+ @Description Creates partition in the MURAM.
+
+ The routine returns a handle (descriptor) to the MURAM partition.
+ This descriptor must be passed as first parameter to all other
+ FM-MURAM function calls.
+
+ No actual initialization or configuration of FM_MURAM hardware is
+ done by this routine.
+
+ @Param[in] baseAddress - Pointer to base of memory mapped FM-MURAM.
+ @Param[in] size - Size of the FM-MURAM partition.
+
+ @Return Handle to FM-MURAM object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size);
+
+/**************************************************************************//**
+ @Function FM_MURAM_Free
+
+ @Description Frees all resources that were assigned to FM-MURAM module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmMuram - FM-MURAM module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MURAM_Free(t_Handle h_FmMuram);
+
+/** @} */ /* end of FM_muram_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_muram_ctrl_grp FM MURAM Control Unit
+
+ @Description FM MURAM control API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_MURAM_AllocMem
+
+ @Description Allocate some memory from FM-MURAM partition.
+
+ @Param[in] h_FmMuram - FM-MURAM module descriptor.
+ @Param[in] size - size of the memory to be allocated.
+ @Param[in] align - Alignment of the memory.
+
+ @Return address of the allocated memory; NULL otherwise.
+*//***************************************************************************/
+void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align);
+
+/**************************************************************************//**
+ @Function FM_MURAM_AllocMemForce
+
+ @Description Allocate some specific memory from FM-MURAM partition (according
+ to base).
+
+ @Param[in] h_FmMuram - FM-MURAM module descriptor.
+ @Param[in] base - the desired base-address to be allocated.
+ @Param[in] size - size of the memory to be allocated.
+
+ @Return address of the allocated memory; NULL otherwise.
+*//***************************************************************************/
+void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size);
+
+/**************************************************************************//**
+ @Function FM_MURAM_FreeMem
+
+ @Description Free an allocated memory from FM-MURAM partition.
+
+ @Param[in] h_FmMuram - FM-MURAM module descriptor.
+ @Param[in] ptr - A pointer to an allocated memory.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr);
+
+/**************************************************************************//**
+ @Function FM_MURAM_GetFreeMemSize
+
+ @Description Returns the size (in bytes) of free MURAM memory.
+
+ @Param[in] h_FmMuram - FM-MURAM module descriptor.
+
+ @Return Free MURAM memory size in bytes.
+*//***************************************************************************/
+uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram);
+
+/** @} */ /* end of FM_muram_ctrl_grp group */
+/** @} */ /* end of FM_muram_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+
+#endif /* __FM_MURAM_EXT */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h
new file mode 100644
index 000000000000..8d1c3d889451
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h
@@ -0,0 +1,3974 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_pcd_ext.h
+
+ @Description FM PCD API definitions
+*//***************************************************************************/
+#ifndef __FM_PCD_EXT
+#define __FM_PCD_EXT
+
+#include "std_ext.h"
+#include "net_ext.h"
+#include "list_ext.h"
+#include "fm_ext.h"
+#include "fsl_fman_kg.h"
+
+
+/**************************************************************************//**
+ @Group FM_grp Frame Manager API
+
+ @Description Frame Manager Application Programming Interface
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_PCD_grp FM PCD
+
+ @Description Frame Manager PCD (Parse-Classify-Distribute) API.
+
+ The FM PCD module is responsible for the initialization of all
+ global classifying FM modules. This includes the parser general and
+ common registers, the key generator global and common registers,
+ and the policer global and common registers.
+ In addition, the FM PCD SW module will initialize all required
+ key generator schemes, coarse classification flows, and policer
+ profiles. When FM module is configured to work with one of these
+ entities, it will register to it using the FM PORT API. The PCD
+ module will manage the PCD resources - i.e. resource management of
+ KeyGen schemes, etc.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Collection General PCD defines
+*//***************************************************************************/
+#define FM_PCD_MAX_NUM_OF_PRIVATE_HDRS 2 /**< Number of units/headers saved for user */
+
+#define FM_PCD_PRS_NUM_OF_HDRS 16 /**< Number of headers supported by HW parser */
+#define FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS (32 - FM_PCD_MAX_NUM_OF_PRIVATE_HDRS)
+ /**< Number of distinction units is limited by
+ register size (32 bits) minus reserved bits
+ for private headers. */
+#define FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS 4 /**< Maximum number of interchangeable headers
+ in a distinction unit */
+#define FM_PCD_KG_NUM_OF_GENERIC_REGS FM_KG_NUM_OF_GENERIC_REGS /**< Total number of generic KeyGen registers */
+#define FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY 35 /**< Max number allowed on any configuration;
+ For HW implementation reasons, in most
+ cases less than this will be allowed; The
+ driver will return an initialization error
+ if resource is unavailable. */
+#define FM_PCD_KG_NUM_OF_EXTRACT_MASKS 4 /**< Total number of masks allowed on KeyGen extractions. */
+#define FM_PCD_KG_NUM_OF_DEFAULT_GROUPS 16 /**< Number of default value logical groups */
+
+#define FM_PCD_PRS_NUM_OF_LABELS 32 /**< Maximum number of SW parser labels */
+#define FM_SW_PRS_MAX_IMAGE_SIZE (FM_PCD_SW_PRS_SIZE /*- FM_PCD_PRS_SW_OFFSET -FM_PCD_PRS_SW_TAIL_SIZE*/-FM_PCD_PRS_SW_PATCHES_SIZE)
+ /**< Maximum size of SW parser code */
+
+#define FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE 128 /**< Maximum size of insertion template for
+ insert manipulation */
+
+#if (DPAA_VERSION >= 11)
+#define FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES 64 /**< Maximum possible entries for frame replicator group */
+#endif /* (DPAA_VERSION >= 11) */
+/* @} */
+
+
+/**************************************************************************//**
+ @Group FM_PCD_init_grp FM PCD Initialization Unit
+
+ @Description Frame Manager PCD Initialization Unit API
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description PCD counters
+*//***************************************************************************/
+typedef enum e_FmPcdCounters {
+ e_FM_PCD_KG_COUNTERS_TOTAL, /**< KeyGen counter */
+ e_FM_PCD_PLCR_COUNTERS_RED, /**< Policer counter - counts the total number of RED packets that exit the Policer. */
+ e_FM_PCD_PLCR_COUNTERS_YELLOW, /**< Policer counter - counts the total number of YELLOW packets that exit the Policer. */
+ e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, /**< Policer counter - counts the number of packets that changed color to RED by the Policer;
+ This is a subset of e_FM_PCD_PLCR_COUNTERS_RED packet count, indicating active color changes. */
+ e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, /**< Policer counter - counts the number of packets that changed color to YELLOW by the Policer;
+ This is a subset of e_FM_PCD_PLCR_COUNTERS_YELLOW packet count, indicating active color changes. */
+ e_FM_PCD_PLCR_COUNTERS_TOTAL, /**< Policer counter - counts the total number of packets passed in the Policer. */
+ e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, /**< Policer counter - counts the number of packets with length mismatch. */
+ e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, /**< Parser counter - counts the number of times the parser block is dispatched. */
+ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L2 parse result is returned (including errors). */
+ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L3 parse result is returned (including errors). */
+ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L4 parse result is returned (including errors). */
+ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times SHIM parse result is returned (including errors). */
+ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L2 parse result is returned with errors. */
+ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L3 parse result is returned with errors. */
+ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L4 parse result is returned with errors. */
+ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times SHIM parse result is returned with errors. */
+ e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, /**< Parser counter - counts the number of cycles spent executing soft parser instruction (including stall cycles). */
+ e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, /**< Parser counter - counts the number of cycles stalled waiting for parser internal memory reads while executing soft parser instruction. */
+ e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, /**< Parser counter - counts the number of cycles spent executing hard parser (including stall cycles). */
+ e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory read. */
+ e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory read. */
+ e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory write. */
+ e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory write. */
+ e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES /**< FPM counter - counts the number of cycles stalled while performing a FPM Command. */
+} e_FmPcdCounters;
+
+/**************************************************************************//**
+ @Description PCD interrupts
+*//***************************************************************************/
+typedef enum e_FmPcdExceptions {
+ e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, /**< KeyGen double-bit ECC error is detected on internal memory read access. */
+ e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, /**< KeyGen scheme configuration error indicating a key size larger than 56 bytes. */
+ e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, /**< Policer double-bit ECC error has been detected on PRAM read access. */
+ e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, /**< Policer access to a non-initialized profile has been detected. */
+ e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, /**< Policer RAM self-initialization complete */
+ e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, /**< Policer atomic action complete */
+ e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, /**< Parser double-bit ECC error */
+ e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC /**< Parser single-bit ECC error */
+} e_FmPcdExceptions;
+
+
+/**************************************************************************//**
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] exception - The exception.
+ *//***************************************************************************/
+typedef void (t_FmPcdExceptionCallback) (t_Handle h_App, e_FmPcdExceptions exception);
+
+/**************************************************************************//**
+ @Description Exceptions user callback routine, will be called upon an exception
+ passing the exception identification.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] exception - The exception.
+ @Param[in] index - id of the relevant source (may be scheme or profile id).
+ *//***************************************************************************/
+typedef void (t_FmPcdIdExceptionCallback) ( t_Handle h_App,
+ e_FmPcdExceptions exception,
+ uint16_t index);
+
+/**************************************************************************//**
+ @Description A callback for enqueuing frame onto a QM queue.
+
+ @Param[in] h_QmArg - Application's handle passed to QM module on enqueue.
+ @Param[in] p_Fd - Frame descriptor for the frame.
+
+ @Return E_OK on success; Error code otherwise.
+ *//***************************************************************************/
+typedef t_Error (t_FmPcdQmEnqueueCallback) (t_Handle h_QmArg, void *p_Fd);
+
+/**************************************************************************//**
+ @Description Host-Command parameters structure.
+
+ When using Host command for PCD functionalities, a dedicated port
+ must be used. If this routine is called for a PCD in a single partition
+ environment, or it is the Master partition in a Multi-partition
+ environment, The port will be initialized by the PCD driver
+ initialization routine.
+ *//***************************************************************************/
+typedef struct t_FmPcdHcParams {
+ uintptr_t portBaseAddr; /**< Virtual Address of Host-Command Port memory mapped registers.*/
+ uint8_t portId; /**< Port Id (0-6 relative to Host-Command/Offline-Parsing ports);
+ NOTE: When configuring Host Command port for
+ FMANv3 devices (DPAA_VERSION 11 and higher),
+ portId=0 MUST be used. */
+ uint16_t liodnBase; /**< LIODN base for this port, to be used together with LIODN offset
+ (irrelevant for P4080 revision 1.0) */
+ uint32_t errFqid; /**< Host-Command Port error queue Id. */
+ uint32_t confFqid; /**< Host-Command Port confirmation queue Id. */
+ uint32_t qmChannel; /**< QM channel dedicated to this Host-Command port;
+ will be used by the FM for dequeue. */
+ t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< Callback routine for enqueuing a frame to the QM */
+ t_Handle h_QmArg; /**< Application's handle passed to QM module on enqueue */
+} t_FmPcdHcParams;
+
+/**************************************************************************//**
+ @Description The main structure for PCD initialization
+ *//***************************************************************************/
+typedef struct t_FmPcdParams {
+ bool prsSupport; /**< TRUE if Parser will be used for any of the FM ports. */
+ bool ccSupport; /**< TRUE if Coarse Classification will be used for any
+ of the FM ports. */
+ bool kgSupport; /**< TRUE if KeyGen will be used for any of the FM ports. */
+ bool plcrSupport; /**< TRUE if Policer will be used for any of the FM ports. */
+ t_Handle h_Fm; /**< A handle to the FM module. */
+ uint8_t numOfSchemes; /**< Number of schemes dedicated to this partition.
+ this parameter is relevant if 'kgSupport'=TRUE. */
+ bool useHostCommand; /**< Optional for single partition, Mandatory for Multi partition */
+ t_FmPcdHcParams hc; /**< Host Command parameters, relevant only if 'useHostCommand'=TRUE;
+ Relevant when FM not runs in "guest-mode". */
+
+ t_FmPcdExceptionCallback *f_Exception; /**< Callback routine for general PCD exceptions;
+ Relevant when FM not runs in "guest-mode". */
+ t_FmPcdIdExceptionCallback *f_ExceptionId; /**< Callback routine for specific KeyGen scheme or
+ Policer profile exceptions;
+ Relevant when FM not runs in "guest-mode". */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks;
+ Relevant when FM not runs in "guest-mode". */
+ uint8_t partPlcrProfilesBase; /**< The first policer-profile-id dedicated to this partition.
+ this parameter is relevant if 'plcrSupport'=TRUE.
+ NOTE: this parameter relevant only when working with multiple partitions. */
+ uint16_t partNumOfPlcrProfiles; /**< Number of policer-profiles dedicated to this partition.
+ this parameter is relevant if 'plcrSupport'=TRUE.
+ NOTE: this parameter relevant only when working with multiple partitions. */
+} t_FmPcdParams;
+
+
+/**************************************************************************//**
+ @Function FM_PCD_Config
+
+ @Description Basic configuration of the PCD module.
+ Creates descriptor for the FM PCD module.
+
+ @Param[in] p_FmPcdParams A structure of parameters for the initialization of PCD.
+
+ @Return A handle to the initialized module.
+*//***************************************************************************/
+t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_Init
+
+ @Description Initialization of the PCD module.
+
+ @Param[in] h_FmPcd - FM PCD module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PCD_Init(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_Free
+
+ @Description Frees all resources that were assigned to FM module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmPcd - FM PCD module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PCD_Free(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Group FM_PCD_advanced_cfg_grp FM PCD Advanced Configuration Unit
+
+ @Description Frame Manager PCD Advanced Configuration API.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_PCD_ConfigException
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of exceptions enabling.
+ [DEFAULT_numOfSharedPlcrProfiles].
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PCD_ConfigHcFramesDataMemory
+
+ @Description Configures memory-partition-id for FMan-Controller Host-Command
+ frames. Calling this routine changes the internal driver data
+ base from its default configuration [0].
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] memId Memory partition ID.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions This routine may be called only if 'useHostCommand' was TRUE
+ when FM_PCD_Config() routine was called.
+*//***************************************************************************/
+t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId);
+
+/**************************************************************************//**
+ @Function FM_PCD_ConfigPlcrNumOfSharedProfiles
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of exceptions enablement.
+ [DEFAULT_numOfSharedPlcrProfiles].
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] numOfSharedPlcrProfiles Number of profiles to
+ be shared between ports on this partition
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles);
+
+/**************************************************************************//**
+ @Function FM_PCD_ConfigPlcrAutoRefreshMode
+
+ @Description Calling this routine changes the internal driver data base
+ from its default selection of exceptions enablement.
+ By default auto-refresh is [DEFAULT_plcrAutoRefresh].
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] enable TRUE to enable, FALSE to disable
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PCD_ConfigPrsMaxCycleLimit
+
+ @Description Calling this routine changes the internal data structure for
+ the maximum parsing time from its default value
+ [DEFAULT_MAX_PRS_CYC_LIM].
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] value 0 to disable the mechanism, or new
+ maximum parsing time.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value);
+
+/** @} */ /* end of FM_PCD_advanced_cfg_grp group */
+/** @} */ /* end of FM_PCD_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_PCD_Runtime_grp FM PCD Runtime Unit
+
+ @Description Frame Manager PCD Runtime Unit API
+
+ The runtime control allows creation of PCD infrastructure modules
+ such as Network Environment Characteristics, Classification Plan
+ Groups and Coarse Classification Trees.
+ It also allows on-the-fly initialization, modification and removal
+ of PCD modules such as KeyGen schemes, coarse classification nodes
+ and Policer profiles.
+
+ In order to explain the programming model of the PCD driver interface
+ a few terms should be explained, and will be used below.
+ - Distinction Header - One of the 16 protocols supported by the FM parser,
+ or one of the SHIM headers (1 or 2). May be a header with a special
+ option (see below).
+ - Interchangeable Headers Group - This is a group of Headers recognized
+ by either one of them. For example, if in a specific context the user
+ chooses to treat IPv4 and IPV6 in the same way, they may create an
+ interchangeable Headers Unit consisting of these 2 headers.
+ - A Distinction Unit - a Distinction Header or an Interchangeable Headers
+ Group.
+ - Header with special option - applies to Ethernet, MPLS, VLAN, IPv4 and
+ IPv6, includes multicast, broadcast and other protocol specific options.
+ In terms of hardware it relates to the options available in the classification
+ plan.
+ - Network Environment Characteristics - a set of Distinction Units that define
+ the total recognizable header selection for a certain environment. This is
+ NOT the list of all headers that will ever appear in a flow, but rather
+ everything that needs distinction in a flow, where distinction is made by KeyGen
+ schemes and coarse classification action descriptors.
+
+ The PCD runtime modules initialization is done in stages. The first stage after
+ initializing the PCD module itself is to establish a Network Flows Environment
+ Definition. The application may choose to establish one or more such environments.
+ Later, when needed, the application will have to state, for some of its modules,
+ to which single environment it belongs.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description A structure for SW parser labels
+ *//***************************************************************************/
+typedef struct t_FmPcdPrsLabelParams {
+ uint32_t instructionOffset; /**< SW parser label instruction offset (2 bytes
+ resolution), relative to Parser RAM. */
+ e_NetHeaderType hdr; /**< The existence of this header will invoke
+ the SW parser code; Use HEADER_TYPE_NONE
+ to indicate that sw parser is to run
+ independent of the existence of any protocol
+ (run before HW parser). */
+ uint8_t indexPerHdr; /**< Normally 0, if more than one SW parser
+ attachments for the same header, use this
+ index to distinguish between them. */
+} t_FmPcdPrsLabelParams;
+
+/**************************************************************************//**
+ @Description A structure for SW parser
+ *//***************************************************************************/
+typedef struct t_FmPcdPrsSwParams {
+ bool override; /**< FALSE to invoke a check that nothing else
+ was loaded to this address, including
+ internal patches.
+ TRUE to override any existing code.*/
+ uint32_t size; /**< SW parser code size */
+ uint16_t base; /**< SW parser base (in instruction counts!
+ must be larger than 0x20)*/
+ uint8_t *p_Code; /**< SW parser code */
+ uint32_t swPrsDataParams[FM_PCD_PRS_NUM_OF_HDRS];
+ /**< SW parser data (parameters) */
+ uint8_t numOfLabels; /**< Number of labels for SW parser. */
+ t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS];
+ /**< SW parser labels table, containing
+ numOfLabels entries */
+} t_FmPcdPrsSwParams;
+
+
+/**************************************************************************//**
+ @Function FM_PCD_Enable
+
+ @Description This routine should be called after PCD is initialized for enabling all
+ PCD engines according to their existing configuration.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled.
+*//***************************************************************************/
+t_Error FM_PCD_Enable(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_Disable
+
+ @Description This routine may be called when PCD is enabled in order to
+ disable all PCD engines. It may be called
+ only when none of the ports in the system are using the PCD.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() and when PCD is enabled.
+*//***************************************************************************/
+t_Error FM_PCD_Disable(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_GetCounter
+
+ @Description Reads one of the FM PCD counters.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] counter The requested counter.
+
+ @Return Counter's current value.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ Note that it is user's responsibility to call this routine only
+ for enabled counters, and there will be no indication if a
+ disabled counter is accessed.
+*//***************************************************************************/
+uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter);
+
+/**************************************************************************//**
+@Function FM_PCD_PrsLoadSw
+
+@Description This routine may be called in order to load software parsing code.
+
+
+@Param[in] h_FmPcd FM PCD module descriptor.
+@Param[in] p_SwPrs A pointer to a structure of software
+ parser parameters, including the software
+ parser image.
+
+@Return E_OK on success; Error code otherwise.
+
+@Cautions Allowed only following FM_PCD_Init() and when PCD is disabled.
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs);
+
+/**************************************************************************//**
+@Function FM_PCD_SetAdvancedOffloadSupport
+
+@Description This routine must be called in order to support the following features:
+ IP-fragmentation, IP-reassembly, IPsec, Header-manipulation, frame-replicator.
+
+@Param[in] h_FmPcd FM PCD module descriptor.
+
+@Return E_OK on success; Error code otherwise.
+
+@Cautions Allowed only following FM_PCD_Init() and when PCD is disabled.
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSetDfltValue
+
+ @Description Calling this routine sets a global default value to be used
+ by the KeyGen when parser does not recognize a required
+ field/header.
+ By default default values are 0.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] valueId 0,1 - one of 2 global default values.
+ @Param[in] value The requested default value.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled.
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSetAdditionalDataAfterParsing
+
+ @Description Calling this routine allows the KeyGen to access data past
+ the parser finishing point.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] payloadOffset the number of bytes beyond the parser location.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled.
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset);
+
+/**************************************************************************//**
+ @Function FM_PCD_SetException
+
+ @Description Calling this routine enables/disables PCD interrupts.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PCD_ModifyCounter
+
+ @Description Sets a value to an enabled counter. Use "0" to reset the counter.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] counter The requested counter.
+ @Param[in] value The requested value to be written into the counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PCD_SetPlcrStatistics
+
+ @Description This routine may be used to enable/disable policer statistics
+ counter. By default the statistics is enabled.
+
+ @Param[in] h_FmPcd FM PCD module descriptor
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PCD_SetPrsStatistics
+
+ @Description Defines whether to gather parser statistics including all ports.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return None
+
+ @Cautions Allowed only following FM_PCD_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PCD_HcTxConf
+
+ @Description This routine should be called to confirm frames that were
+ received on the HC confirmation queue.
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+ @Param[in] p_Fd Frame descriptor of the received frame.
+
+ @Cautions Allowed only following FM_PCD_Init(). Allowed only if 'useHostCommand'
+ option was selected in the initialization.
+*//***************************************************************************/
+void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd);
+
+/**************************************************************************//*
+ @Function FM_PCD_ForceIntr
+
+ @Description Causes an interrupt event on the requested source.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] exception An exception to be forced.
+
+ @Return E_OK on success; Error code if the exception is not enabled,
+ or is not able to create interrupt.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_PCD_DumpRegs
+
+ @Description Dumps all PCD registers
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
+ are mapped.
+*//***************************************************************************/
+t_Error FM_PCD_DumpRegs(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgDumpRegs
+
+ @Description Dumps all PCD KG registers
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
+ are mapped.
+*//***************************************************************************/
+t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrDumpRegs
+
+ @Description Dumps all PCD Policer registers
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
+ are mapped.
+*//***************************************************************************/
+t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrProfileDumpRegs
+
+ @Description Dumps all PCD Policer profile registers
+
+ @Param[in] h_Profile A handle to a Policer profile.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
+ are mapped.
+*//***************************************************************************/
+t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_Profile);
+
+/**************************************************************************//**
+ @Function FM_PCD_PrsDumpRegs
+
+ @Description Dumps all PCD Parser registers
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers
+ are mapped.
+*//***************************************************************************/
+t_Error FM_PCD_PrsDumpRegs(t_Handle h_FmPcd);
+
+/**************************************************************************//**
+ @Function FM_PCD_HcDumpRegs
+
+ @Description Dumps HC Port registers
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+ NOTE: this routine may be called only for FM in master mode
+ (i.e. 'guestId'=NCSW_MASTER_ID).
+*//***************************************************************************/
+t_Error FM_PCD_HcDumpRegs(t_Handle h_FmPcd);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+
+
+/**************************************************************************//**
+ KeyGen FM_PCD_Runtime_build_grp FM PCD Runtime Building Unit
+
+ @Description Frame Manager PCD Runtime Building API
+
+ This group contains routines for setting, deleting and modifying
+ PCD resources, for defining the total PCD tree.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Collection Definitions of coarse classification
+ parameters as required by KeyGen (when coarse classification
+ is the next engine after this scheme).
+*//***************************************************************************/
+#define FM_PCD_MAX_NUM_OF_CC_TREES 8
+#define FM_PCD_MAX_NUM_OF_CC_GROUPS 16
+#define FM_PCD_MAX_NUM_OF_CC_UNITS 4
+#define FM_PCD_MAX_NUM_OF_KEYS 256
+#define FM_PCD_MAX_NUM_OF_FLOWS (4*KILOBYTE)
+#define FM_PCD_MAX_SIZE_OF_KEY 56
+#define FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP 16
+#define FM_PCD_LAST_KEY_INDEX 0xffff
+
+#define FM_PCD_MAX_NUM_OF_CC_NODES 255 /* Obsolete, not used - will be removed in the future */
+/* @} */
+
+/**************************************************************************//**
+ @Collection A set of definitions to allow protocol
+ special option description.
+*//***************************************************************************/
+typedef uint32_t protocolOpt_t; /**< A general type to define a protocol option. */
+
+typedef protocolOpt_t ethProtocolOpt_t; /**< Ethernet protocol options. */
+#define ETH_BROADCAST 0x80000000 /**< Ethernet Broadcast. */
+#define ETH_MULTICAST 0x40000000 /**< Ethernet Multicast. */
+
+typedef protocolOpt_t vlanProtocolOpt_t; /**< VLAN protocol options. */
+#define VLAN_STACKED 0x20000000 /**< Stacked VLAN. */
+
+typedef protocolOpt_t mplsProtocolOpt_t; /**< MPLS protocol options. */
+#define MPLS_STACKED 0x10000000 /**< Stacked MPLS. */
+
+typedef protocolOpt_t ipv4ProtocolOpt_t; /**< IPv4 protocol options. */
+#define IPV4_BROADCAST_1 0x08000000 /**< IPv4 Broadcast. */
+#define IPV4_MULTICAST_1 0x04000000 /**< IPv4 Multicast. */
+#define IPV4_UNICAST_2 0x02000000 /**< Tunneled IPv4 - Unicast. */
+#define IPV4_MULTICAST_BROADCAST_2 0x01000000 /**< Tunneled IPv4 - Broadcast/Multicast. */
+
+#define IPV4_FRAG_1 0x00000008 /**< IPV4 reassembly option.
+ IPV4 Reassembly manipulation requires network
+ environment with IPV4 header and IPV4_FRAG_1 option */
+
+typedef protocolOpt_t ipv6ProtocolOpt_t; /**< IPv6 protocol options. */
+#define IPV6_MULTICAST_1 0x00800000 /**< IPv6 Multicast. */
+#define IPV6_UNICAST_2 0x00400000 /**< Tunneled IPv6 - Unicast. */
+#define IPV6_MULTICAST_2 0x00200000 /**< Tunneled IPv6 - Multicast. */
+
+#define IPV6_FRAG_1 0x00000004 /**< IPV6 reassembly option.
+ IPV6 Reassembly manipulation requires network
+ environment with IPV6 header and IPV6_FRAG_1 option;
+ in case where fragment found, the fragment-extension offset
+ may be found at 'shim2' (in parser-result). */
+#if (DPAA_VERSION >= 11)
+typedef protocolOpt_t capwapProtocolOpt_t; /**< CAPWAP protocol options. */
+#define CAPWAP_FRAG_1 0x00000008 /**< CAPWAP reassembly option.
+ CAPWAP Reassembly manipulation requires network
+ environment with CAPWAP header and CAPWAP_FRAG_1 option;
+ in case where fragment found, the fragment-extension offset
+ may be found at 'shim2' (in parser-result). */
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/* @} */
+
+#define FM_PCD_MANIP_MAX_HDR_SIZE 256
+#define FM_PCD_MANIP_DSCP_TO_VLAN_TRANS 64
+
+/**************************************************************************//**
+ @Collection A set of definitions to support Header Manipulation selection.
+*//***************************************************************************/
+typedef uint32_t hdrManipFlags_t; /**< A general type to define a HMan update command flags. */
+
+typedef hdrManipFlags_t ipv4HdrManipUpdateFlags_t; /**< IPv4 protocol HMan update command flags. */
+
+#define HDR_MANIP_IPV4_TOS 0x80000000 /**< update TOS with the given value ('tos' field
+ of t_FmPcdManipHdrFieldUpdateIpv4) */
+#define HDR_MANIP_IPV4_ID 0x40000000 /**< update IP ID with the given value ('id' field
+ of t_FmPcdManipHdrFieldUpdateIpv4) */
+#define HDR_MANIP_IPV4_TTL 0x20000000 /**< Decrement TTL by 1 */
+#define HDR_MANIP_IPV4_SRC 0x10000000 /**< update IP source address with the given value
+ ('src' field of t_FmPcdManipHdrFieldUpdateIpv4) */
+#define HDR_MANIP_IPV4_DST 0x08000000 /**< update IP destination address with the given value
+ ('dst' field of t_FmPcdManipHdrFieldUpdateIpv4) */
+
+typedef hdrManipFlags_t ipv6HdrManipUpdateFlags_t; /**< IPv6 protocol HMan update command flags. */
+
+#define HDR_MANIP_IPV6_TC 0x80000000 /**< update Traffic Class address with the given value
+ ('trafficClass' field of t_FmPcdManipHdrFieldUpdateIpv6) */
+#define HDR_MANIP_IPV6_HL 0x40000000 /**< Decrement Hop Limit by 1 */
+#define HDR_MANIP_IPV6_SRC 0x20000000 /**< update IP source address with the given value
+ ('src' field of t_FmPcdManipHdrFieldUpdateIpv6) */
+#define HDR_MANIP_IPV6_DST 0x10000000 /**< update IP destination address with the given value
+ ('dst' field of t_FmPcdManipHdrFieldUpdateIpv6) */
+
+typedef hdrManipFlags_t tcpUdpHdrManipUpdateFlags_t;/**< TCP/UDP protocol HMan update command flags. */
+
+#define HDR_MANIP_TCP_UDP_SRC 0x80000000 /**< update TCP/UDP source address with the given value
+ ('src' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */
+#define HDR_MANIP_TCP_UDP_DST 0x40000000 /**< update TCP/UDP destination address with the given value
+ ('dst' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */
+#define HDR_MANIP_TCP_UDP_CHECKSUM 0x20000000 /**< update TCP/UDP checksum */
+
+/* @} */
+
+/**************************************************************************//**
+ @Description A type used for returning the order of the key extraction.
+ each value in this array represents the index of the extraction
+ command as defined by the user in the initialization extraction array.
+ The valid size of this array is the user define number of extractions
+ required (also marked by the second '0' in this array).
+*//***************************************************************************/
+typedef uint8_t t_FmPcdKgKeyOrder [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY];
+
+/**************************************************************************//**
+ @Description All PCD engines
+*//***************************************************************************/
+typedef enum e_FmPcdEngine {
+ e_FM_PCD_INVALID = 0, /**< Invalid PCD engine */
+ e_FM_PCD_DONE, /**< No PCD Engine indicated */
+ e_FM_PCD_KG, /**< KeyGen */
+ e_FM_PCD_CC, /**< Coarse classifier */
+ e_FM_PCD_PLCR, /**< Policer */
+ e_FM_PCD_PRS, /**< Parser */
+#if (DPAA_VERSION >= 11)
+ e_FM_PCD_FR, /**< Frame-Replicator */
+#endif /* (DPAA_VERSION >= 11) */
+ e_FM_PCD_HASH /**< Hash table */
+} e_FmPcdEngine;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting extraction by header types
+*//***************************************************************************/
+typedef enum e_FmPcdExtractByHdrType {
+ e_FM_PCD_EXTRACT_FROM_HDR, /**< Extract bytes from header */
+ e_FM_PCD_EXTRACT_FROM_FIELD, /**< Extract bytes from header field */
+ e_FM_PCD_EXTRACT_FULL_FIELD /**< Extract a full field */
+} e_FmPcdExtractByHdrType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting extraction source
+ (when it is not the header)
+*//***************************************************************************/
+typedef enum e_FmPcdExtractFrom {
+ e_FM_PCD_EXTRACT_FROM_FRAME_START, /**< KG & CC: Extract from beginning of frame */
+ e_FM_PCD_EXTRACT_FROM_DFLT_VALUE, /**< KG only: Extract from a default value */
+ e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE, /**< KG & CC: Extract from the point where parsing had finished */
+ e_FM_PCD_EXTRACT_FROM_KEY, /**< CC only: Field where saved KEY */
+ e_FM_PCD_EXTRACT_FROM_HASH, /**< CC only: Field where saved HASH */
+ e_FM_PCD_EXTRACT_FROM_PARSE_RESULT, /**< KG only: Extract from the parser result */
+ e_FM_PCD_EXTRACT_FROM_ENQ_FQID, /**< KG & CC: Extract from enqueue FQID */
+ e_FM_PCD_EXTRACT_FROM_FLOW_ID /**< CC only: Field where saved Dequeue FQID */
+} e_FmPcdExtractFrom;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting extraction type
+*//***************************************************************************/
+typedef enum e_FmPcdExtractType {
+ e_FM_PCD_EXTRACT_BY_HDR, /**< Extract according to header */
+ e_FM_PCD_EXTRACT_NON_HDR, /**< Extract from data that is not the header */
+ e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO /**< Extract private info as specified by user */
+} e_FmPcdExtractType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting default extraction value
+*//***************************************************************************/
+typedef enum e_FmPcdKgExtractDfltSelect {
+ e_FM_PCD_KG_DFLT_GBL_0, /**< Default selection is KG register 0 */
+ e_FM_PCD_KG_DFLT_GBL_1, /**< Default selection is KG register 1 */
+ e_FM_PCD_KG_DFLT_PRIVATE_0, /**< Default selection is a per scheme register 0 */
+ e_FM_PCD_KG_DFLT_PRIVATE_1, /**< Default selection is a per scheme register 1 */
+ e_FM_PCD_KG_DFLT_ILLEGAL /**< Illegal selection */
+} e_FmPcdKgExtractDfltSelect;
+
+/**************************************************************************//**
+ @Description Enumeration type defining all default groups - each group shares
+ a default value, one of four user-initialized values.
+*//***************************************************************************/
+typedef enum e_FmPcdKgKnownFieldsDfltTypes {
+ e_FM_PCD_KG_MAC_ADDR, /**< MAC Address */
+ e_FM_PCD_KG_TCI, /**< TCI field */
+ e_FM_PCD_KG_ENET_TYPE, /**< ENET Type */
+ e_FM_PCD_KG_PPP_SESSION_ID, /**< PPP Session id */
+ e_FM_PCD_KG_PPP_PROTOCOL_ID, /**< PPP Protocol id */
+ e_FM_PCD_KG_MPLS_LABEL, /**< MPLS label */
+ e_FM_PCD_KG_IP_ADDR, /**< IP address */
+ e_FM_PCD_KG_PROTOCOL_TYPE, /**< Protocol type */
+ e_FM_PCD_KG_IP_TOS_TC, /**< TOS or TC */
+ e_FM_PCD_KG_IPV6_FLOW_LABEL, /**< IPV6 flow label */
+ e_FM_PCD_KG_IPSEC_SPI, /**< IPSEC SPI */
+ e_FM_PCD_KG_L4_PORT, /**< L4 Port */
+ e_FM_PCD_KG_TCP_FLAG, /**< TCP Flag */
+ e_FM_PCD_KG_GENERIC_FROM_DATA, /**< grouping implemented by SW,
+ any data extraction that is not the full
+ field described above */
+ e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by SW,
+ any data extraction without validation */
+ e_FM_PCD_KG_GENERIC_NOT_FROM_DATA /**< grouping implemented by SW,
+ extraction from parser result or
+ direct use of default value */
+} e_FmPcdKgKnownFieldsDfltTypes;
+
+/**************************************************************************//**
+ @Description Enumeration type for defining header index for scenarios with
+ multiple (tunneled) headers
+*//***************************************************************************/
+typedef enum e_FmPcdHdrIndex {
+ e_FM_PCD_HDR_INDEX_NONE = 0, /**< used when multiple headers not used, also
+ to specify regular IP (not tunneled). */
+ e_FM_PCD_HDR_INDEX_1, /**< may be used for VLAN, MPLS, tunneled IP */
+ e_FM_PCD_HDR_INDEX_2, /**< may be used for MPLS, tunneled IP */
+ e_FM_PCD_HDR_INDEX_3, /**< may be used for MPLS */
+ e_FM_PCD_HDR_INDEX_LAST = 0xFF /**< may be used for VLAN, MPLS */
+} e_FmPcdHdrIndex;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the policer profile functional type
+*//***************************************************************************/
+typedef enum e_FmPcdProfileTypeSelection {
+ e_FM_PCD_PLCR_PORT_PRIVATE, /**< Port dedicated profile */
+ e_FM_PCD_PLCR_SHARED /**< Shared profile (shared within partition) */
+} e_FmPcdProfileTypeSelection;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the policer profile algorithm
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrAlgorithmSelection {
+ e_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */
+ e_FM_PCD_PLCR_RFC_2698, /**< Policer algorithm RFC 2698 */
+ e_FM_PCD_PLCR_RFC_4115 /**< Policer algorithm RFC 4115 */
+} e_FmPcdPlcrAlgorithmSelection;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting a policer profile color mode
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrColorMode {
+ e_FM_PCD_PLCR_COLOR_BLIND, /**< Color blind */
+ e_FM_PCD_PLCR_COLOR_AWARE /**< Color aware */
+} e_FmPcdPlcrColorMode;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting a policer profile color
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrColor {
+ e_FM_PCD_PLCR_GREEN, /**< Green color code */
+ e_FM_PCD_PLCR_YELLOW, /**< Yellow color code */
+ e_FM_PCD_PLCR_RED, /**< Red color code */
+ e_FM_PCD_PLCR_OVERRIDE /**< Color override code */
+} e_FmPcdPlcrColor;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the policer profile packet frame length selector
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrFrameLengthSelect {
+ e_FM_PCD_PLCR_L2_FRM_LEN, /**< L2 frame length */
+ e_FM_PCD_PLCR_L3_FRM_LEN, /**< L3 frame length */
+ e_FM_PCD_PLCR_L4_FRM_LEN, /**< L4 frame length */
+ e_FM_PCD_PLCR_FULL_FRM_LEN /**< Full frame length */
+} e_FmPcdPlcrFrameLengthSelect;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting roll-back frame
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrRollBackFrameSelect {
+ e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN, /**< Roll-back L2 frame length */
+ e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN /**< Roll-back Full frame length */
+} e_FmPcdPlcrRollBackFrameSelect;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the policer profile packet or byte mode
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrRateMode {
+ e_FM_PCD_PLCR_BYTE_MODE, /**< Byte mode */
+ e_FM_PCD_PLCR_PACKET_MODE /**< Packet mode */
+} e_FmPcdPlcrRateMode;
+
+/**************************************************************************//**
+ @Description Enumeration type for defining action of frame
+*//***************************************************************************/
+typedef enum e_FmPcdDoneAction {
+ e_FM_PCD_ENQ_FRAME = 0, /**< Enqueue frame */
+ e_FM_PCD_DROP_FRAME /**< Mark this frame as error frame and continue
+ to error flow; 'FM_PORT_FRM_ERR_CLS_DISCARD'
+ flag will be set for this frame. */
+} e_FmPcdDoneAction;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the policer counter
+*//***************************************************************************/
+typedef enum e_FmPcdPlcrProfileCounters {
+ e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER, /**< Green packets counter */
+ e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER, /**< Yellow packets counter */
+ e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER, /**< Red packets counter */
+ e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER, /**< Recolored yellow packets counter */
+ e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER /**< Recolored red packets counter */
+} e_FmPcdPlcrProfileCounters;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting the PCD action after extraction
+*//***************************************************************************/
+typedef enum e_FmPcdAction {
+ e_FM_PCD_ACTION_NONE, /**< NONE */
+ e_FM_PCD_ACTION_EXACT_MATCH, /**< Exact match on the selected extraction */
+ e_FM_PCD_ACTION_INDEXED_LOOKUP /**< Indexed lookup on the selected extraction */
+} e_FmPcdAction;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of insert manipulation
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrInsrtType {
+ e_FM_PCD_MANIP_INSRT_GENERIC, /**< Insert according to offset & size */
+ e_FM_PCD_MANIP_INSRT_BY_HDR, /**< Insert according to protocol */
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ e_FM_PCD_MANIP_INSRT_BY_TEMPLATE /**< Insert template to start of frame */
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+} e_FmPcdManipHdrInsrtType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of remove manipulation
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrRmvType {
+ e_FM_PCD_MANIP_RMV_GENERIC, /**< Remove according to offset & size */
+ e_FM_PCD_MANIP_RMV_BY_HDR /**< Remove according to offset & size */
+} e_FmPcdManipHdrRmvType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting specific L2 fields removal
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrRmvSpecificL2 {
+ e_FM_PCD_MANIP_HDR_RMV_ETHERNET, /**< Ethernet/802.3 MAC */
+ e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS, /**< stacked QTags */
+ e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS, /**< MPLS and Ethernet/802.3 MAC header until
+ the header which follows the MPLS header */
+ e_FM_PCD_MANIP_HDR_RMV_MPLS, /**< Remove MPLS header (Unlimited MPLS labels) */
+ e_FM_PCD_MANIP_HDR_RMV_PPPOE /**< Remove the PPPoE header and PPP protocol field. */
+} e_FmPcdManipHdrRmvSpecificL2;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting specific fields updates
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrFieldUpdateType {
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN, /**< VLAN updates */
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4, /**< IPV4 updates */
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6, /**< IPV6 updates */
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP, /**< TCP_UDP updates */
+} e_FmPcdManipHdrFieldUpdateType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting VLAN updates
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrFieldUpdateVlan {
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI, /**< Replace VPri of outer most VLAN tag. */
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN /**< DSCP to VLAN priority bits translation */
+} e_FmPcdManipHdrFieldUpdateVlan;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting specific L2 header insertion
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrInsrtSpecificL2 {
+ e_FM_PCD_MANIP_HDR_INSRT_MPLS, /**< Insert MPLS header (Unlimited MPLS labels) */
+ e_FM_PCD_MANIP_HDR_INSRT_PPPOE /**< Insert PPPOE */
+} e_FmPcdManipHdrInsrtSpecificL2;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Enumeration type for selecting QoS mapping mode
+
+ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE'
+ User should instruct the port to read the hash-result
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrQosMappingMode {
+ e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE = 0, /**< No mapping, QoS field will not be changed */
+ e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS, /**< QoS field will be overwritten by the last byte in the hash-result. */
+} e_FmPcdManipHdrQosMappingMode;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting QoS source
+
+ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_SRC_NONE'
+ User should left room for the hash-result on input/output buffer
+ and instruct the port to read/write the hash-result to the buffer (RPD should be set)
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrQosSrc {
+ e_FM_PCD_MANIP_HDR_QOS_SRC_NONE = 0, /**< TODO */
+ e_FM_PCD_MANIP_HDR_QOS_SRC_USER_DEFINED, /**< QoS will be taken from the last byte in the hash-result. */
+} e_FmPcdManipHdrQosSrc;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of header insertion
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrInsrtByHdrType {
+ e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2, /**< Specific L2 fields insertion */
+#if (DPAA_VERSION >= 11)
+ e_FM_PCD_MANIP_INSRT_BY_HDR_IP, /**< IP insertion */
+ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP, /**< UDP insertion */
+ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, /**< UDP lite insertion */
+ e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP /**< CAPWAP insertion */
+#endif /* (DPAA_VERSION >= 11) */
+} e_FmPcdManipHdrInsrtByHdrType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting specific customCommand
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrCustomType {
+ e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE, /**< Replace IPv4/IPv6 */
+ e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE, /**< Replace IPv4/IPv6 */
+} e_FmPcdManipHdrCustomType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting specific customCommand
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrCustomIpReplace {
+ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6, /**< Replace IPv4 by IPv6 */
+ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 /**< Replace IPv6 by IPv4 */
+} e_FmPcdManipHdrCustomIpReplace;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of header removal
+*//***************************************************************************/
+typedef enum e_FmPcdManipHdrRmvByHdrType {
+ e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2 = 0, /**< Specific L2 fields removal */
+#if (DPAA_VERSION >= 11)
+ e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP, /**< CAPWAP removal */
+#endif /* (DPAA_VERSION >= 11) */
+#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START, /**< Locate from data that is not the header */
+#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+} e_FmPcdManipHdrRmvByHdrType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of timeout mode
+*//***************************************************************************/
+typedef enum e_FmPcdManipReassemTimeOutMode {
+ e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES, /**< Limits the time of the reassembly process
+ from the first fragment to the last */
+ e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG /**< Limits the time of receiving the fragment */
+} e_FmPcdManipReassemTimeOutMode;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of WaysNumber mode
+*//***************************************************************************/
+typedef enum e_FmPcdManipReassemWaysNumber {
+ e_FM_PCD_MANIP_ONE_WAY_HASH = 1, /**< One way hash */
+ e_FM_PCD_MANIP_TWO_WAYS_HASH, /**< Two ways hash */
+ e_FM_PCD_MANIP_THREE_WAYS_HASH, /**< Three ways hash */
+ e_FM_PCD_MANIP_FOUR_WAYS_HASH, /**< Four ways hash */
+ e_FM_PCD_MANIP_FIVE_WAYS_HASH, /**< Five ways hash */
+ e_FM_PCD_MANIP_SIX_WAYS_HASH, /**< Six ways hash */
+ e_FM_PCD_MANIP_SEVEN_WAYS_HASH, /**< Seven ways hash */
+ e_FM_PCD_MANIP_EIGHT_WAYS_HASH /**< Eight ways hash */
+} e_FmPcdManipReassemWaysNumber;
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of statistics mode
+*//***************************************************************************/
+typedef enum e_FmPcdStatsType {
+ e_FM_PCD_STATS_PER_FLOWID = 0 /**< Flow ID is used as index for getting statistics */
+} e_FmPcdStatsType;
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting manipulation type
+*//***************************************************************************/
+typedef enum e_FmPcdManipType {
+ e_FM_PCD_MANIP_HDR = 0, /**< Header manipulation */
+ e_FM_PCD_MANIP_REASSEM, /**< Reassembly */
+ e_FM_PCD_MANIP_FRAG, /**< Fragmentation */
+ e_FM_PCD_MANIP_SPECIAL_OFFLOAD /**< Special Offloading */
+} e_FmPcdManipType;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of statistics mode
+*//***************************************************************************/
+typedef enum e_FmPcdCcStatsMode {
+ e_FM_PCD_CC_STATS_MODE_NONE = 0, /**< No statistics support */
+ e_FM_PCD_CC_STATS_MODE_FRAME, /**< Frame count statistics */
+ e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME, /**< Byte and frame count statistics */
+#if (DPAA_VERSION >= 11)
+ e_FM_PCD_CC_STATS_MODE_RMON, /**< Byte and frame length range count statistics;
+ This mode is supported only on B4860 device */
+#endif /* (DPAA_VERSION >= 11) */
+} e_FmPcdCcStatsMode;
+
+/**************************************************************************//**
+ @Description Enumeration type for determining the action in case an IP packet
+ is larger than MTU but its DF (Don't Fragment) bit is set.
+*//***************************************************************************/
+typedef enum e_FmPcdManipDontFragAction {
+ e_FM_PCD_MANIP_DISCARD_PACKET = 0, /**< Discard packet */
+ e_FM_PCD_MANIP_ENQ_TO_ERR_Q_OR_DISCARD_PACKET = e_FM_PCD_MANIP_DISCARD_PACKET,
+ /**< Obsolete, cannot enqueue to error queue;
+ In practice, selects to discard packets;
+ Will be removed in the future */
+ e_FM_PCD_MANIP_FRAGMENT_PACKET, /**< Fragment packet and continue normal processing */
+ e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG /**< Continue normal processing without fragmenting the packet */
+} e_FmPcdManipDontFragAction;
+
+/**************************************************************************//**
+ @Description Enumeration type for selecting type of special offload manipulation
+*//***************************************************************************/
+typedef enum e_FmPcdManipSpecialOffloadType {
+ e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC, /**< IPSec offload manipulation */
+#if (DPAA_VERSION >= 11)
+ e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP /**< CAPWAP offload manipulation */
+#endif /* (DPAA_VERSION >= 11) */
+} e_FmPcdManipSpecialOffloadType;
+
+
+/**************************************************************************//**
+ @Description A Union of protocol dependent special options
+*//***************************************************************************/
+typedef union u_FmPcdHdrProtocolOpt {
+ ethProtocolOpt_t ethOpt; /**< Ethernet options */
+ vlanProtocolOpt_t vlanOpt; /**< VLAN options */
+ mplsProtocolOpt_t mplsOpt; /**< MPLS options */
+ ipv4ProtocolOpt_t ipv4Opt; /**< IPv4 options */
+ ipv6ProtocolOpt_t ipv6Opt; /**< IPv6 options */
+#if (DPAA_VERSION >= 11)
+ capwapProtocolOpt_t capwapOpt; /**< CAPWAP options */
+#endif /* (DPAA_VERSION >= 11) */
+} u_FmPcdHdrProtocolOpt;
+
+/**************************************************************************//**
+ @Description A union holding protocol fields
+
+
+ Fields supported as "full fields":
+ HEADER_TYPE_ETH:
+ NET_HEADER_FIELD_ETH_DA
+ NET_HEADER_FIELD_ETH_SA
+ NET_HEADER_FIELD_ETH_TYPE
+
+ HEADER_TYPE_LLC_SNAP:
+ NET_HEADER_FIELD_LLC_SNAP_TYPE
+
+ HEADER_TYPE_VLAN:
+ NET_HEADER_FIELD_VLAN_TCI
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_LAST)
+
+ HEADER_TYPE_MPLS:
+ NET_HEADER_FIELD_MPLS_LABEL_STACK
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_2,
+ e_FM_PCD_HDR_INDEX_LAST)
+
+ HEADER_TYPE_IPv4:
+ NET_HEADER_FIELD_IPv4_SRC_IP
+ NET_HEADER_FIELD_IPv4_DST_IP
+ NET_HEADER_FIELD_IPv4_PROTO
+ NET_HEADER_FIELD_IPv4_TOS
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
+
+ HEADER_TYPE_IPv6:
+ NET_HEADER_FIELD_IPv6_SRC_IP
+ NET_HEADER_FIELD_IPv6_DST_IP
+ NET_HEADER_FIELD_IPv6_NEXT_HDR
+ NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC (must come together!)
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
+
+ (Note that starting from DPAA 1-1, NET_HEADER_FIELD_IPv6_NEXT_HDR applies to
+ the last next header indication, meaning the next L4, which may be
+ present at the Ipv6 last extension. On earlier revisions this field
+ applies to the Next-Header field of the main IPv6 header)
+
+ HEADER_TYPE_IP:
+ NET_HEADER_FIELD_IP_PROTO
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_LAST)
+ NET_HEADER_FIELD_IP_DSCP
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1)
+ HEADER_TYPE_GRE:
+ NET_HEADER_FIELD_GRE_TYPE
+
+ HEADER_TYPE_MINENCAP
+ NET_HEADER_FIELD_MINENCAP_SRC_IP
+ NET_HEADER_FIELD_MINENCAP_DST_IP
+ NET_HEADER_FIELD_MINENCAP_TYPE
+
+ HEADER_TYPE_TCP:
+ NET_HEADER_FIELD_TCP_PORT_SRC
+ NET_HEADER_FIELD_TCP_PORT_DST
+ NET_HEADER_FIELD_TCP_FLAGS
+
+ HEADER_TYPE_UDP:
+ NET_HEADER_FIELD_UDP_PORT_SRC
+ NET_HEADER_FIELD_UDP_PORT_DST
+
+ HEADER_TYPE_UDP_LITE:
+ NET_HEADER_FIELD_UDP_LITE_PORT_SRC
+ NET_HEADER_FIELD_UDP_LITE_PORT_DST
+
+ HEADER_TYPE_IPSEC_AH:
+ NET_HEADER_FIELD_IPSEC_AH_SPI
+ NET_HEADER_FIELD_IPSEC_AH_NH
+
+ HEADER_TYPE_IPSEC_ESP:
+ NET_HEADER_FIELD_IPSEC_ESP_SPI
+
+ HEADER_TYPE_SCTP:
+ NET_HEADER_FIELD_SCTP_PORT_SRC
+ NET_HEADER_FIELD_SCTP_PORT_DST
+
+ HEADER_TYPE_DCCP:
+ NET_HEADER_FIELD_DCCP_PORT_SRC
+ NET_HEADER_FIELD_DCCP_PORT_DST
+
+ HEADER_TYPE_PPPoE:
+ NET_HEADER_FIELD_PPPoE_PID
+ NET_HEADER_FIELD_PPPoE_SID
+
+ *****************************************************************
+ Fields supported as "from fields":
+ HEADER_TYPE_ETH (with or without validation):
+ NET_HEADER_FIELD_ETH_TYPE
+
+ HEADER_TYPE_VLAN (with or without validation):
+ NET_HEADER_FIELD_VLAN_TCI
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_LAST)
+
+ HEADER_TYPE_IPv4 (without validation):
+ NET_HEADER_FIELD_IPv4_PROTO
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
+
+ HEADER_TYPE_IPv6 (without validation):
+ NET_HEADER_FIELD_IPv6_NEXT_HDR
+ (index may apply:
+ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1,
+ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST)
+
+*//***************************************************************************/
+typedef union t_FmPcdFields {
+ headerFieldEth_t eth; /**< Ethernet */
+ headerFieldVlan_t vlan; /**< VLAN */
+ headerFieldLlcSnap_t llcSnap; /**< LLC SNAP */
+ headerFieldPppoe_t pppoe; /**< PPPoE */
+ headerFieldMpls_t mpls; /**< MPLS */
+ headerFieldIp_t ip; /**< IP */
+ headerFieldIpv4_t ipv4; /**< IPv4 */
+ headerFieldIpv6_t ipv6; /**< IPv6 */
+ headerFieldUdp_t udp; /**< UDP */
+ headerFieldUdpLite_t udpLite; /**< UDP Lite */
+ headerFieldTcp_t tcp; /**< TCP */
+ headerFieldSctp_t sctp; /**< SCTP */
+ headerFieldDccp_t dccp; /**< DCCP */
+ headerFieldGre_t gre; /**< GRE */
+ headerFieldMinencap_t minencap; /**< Minimal Encapsulation */
+ headerFieldIpsecAh_t ipsecAh; /**< IPSec AH */
+ headerFieldIpsecEsp_t ipsecEsp; /**< IPSec ESP */
+ headerFieldUdpEncapEsp_t udpEncapEsp; /**< UDP Encapsulation ESP */
+} t_FmPcdFields;
+
+/**************************************************************************//**
+ @Description Parameters for defining header extraction for key generation
+*//***************************************************************************/
+typedef struct t_FmPcdFromHdr {
+ uint8_t size; /**< Size in byte */
+ uint8_t offset; /**< Byte offset */
+} t_FmPcdFromHdr;
+
+/**************************************************************************//**
+ @Description Parameters for defining field extraction for key generation
+*//***************************************************************************/
+typedef struct t_FmPcdFromField {
+ t_FmPcdFields field; /**< Field selection */
+ uint8_t size; /**< Size in byte */
+ uint8_t offset; /**< Byte offset */
+} t_FmPcdFromField;
+
+/**************************************************************************//**
+ @Description Parameters for defining a single network environment unit
+
+ A distinction unit should be defined if it will later be used
+ by one or more PCD engines to distinguish between flows.
+*//***************************************************************************/
+typedef struct t_FmPcdDistinctionUnit {
+ struct {
+ e_NetHeaderType hdr; /**< One of the headers supported by the FM */
+ u_FmPcdHdrProtocolOpt opt; /**< Select only one option ! */
+ } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS];
+} t_FmPcdDistinctionUnit;
+
+/**************************************************************************//**
+ @Description Parameters for defining all different distinction units supported
+ by a specific PCD Network Environment Characteristics module.
+
+ Each unit represent a protocol or a group of protocols that may
+ be used later by the different PCD engines to distinguish
+ between flows.
+*//***************************************************************************/
+typedef struct t_FmPcdNetEnvParams {
+ uint8_t numOfDistinctionUnits; /**< Number of different units to be identified */
+ t_FmPcdDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /**< An array of numOfDistinctionUnits of the
+ different units to be identified */
+} t_FmPcdNetEnvParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a single extraction action when
+ creating a key
+*//***************************************************************************/
+typedef struct t_FmPcdExtractEntry {
+ e_FmPcdExtractType type; /**< Extraction type select */
+ union {
+ struct {
+ e_NetHeaderType hdr; /**< Header selection */
+ bool ignoreProtocolValidation;
+ /**< Ignore protocol validation */
+ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled
+ IP. Otherwise should be cleared. */
+ e_FmPcdExtractByHdrType type; /**< Header extraction type select */
+ union {
+ t_FmPcdFromHdr fromHdr; /**< Extract bytes from header parameters */
+ t_FmPcdFromField fromField; /**< Extract bytes from field parameters */
+ t_FmPcdFields fullField; /**< Extract full filed parameters */
+ } extractByHdrType;
+ } extractByHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */
+ struct {
+ e_FmPcdExtractFrom src; /**< Non-header extraction source */
+ e_FmPcdAction action; /**< Relevant for CC Only */
+ uint16_t icIndxMask; /**< Relevant only for CC when
+ action = e_FM_PCD_ACTION_INDEXED_LOOKUP;
+ Note that the number of bits that are set within
+ this mask must be log2 of the CC-node 'numOfKeys'.
+ Note that the mask cannot be set on the lower bits. */
+ uint8_t offset; /**< Byte offset */
+ uint8_t size; /**< Size in byte */
+ } extractNonHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */
+ };
+} t_FmPcdExtractEntry;
+
+/**************************************************************************//**
+ @Description Parameters for defining masks for each extracted field in the key.
+*//***************************************************************************/
+typedef struct t_FmPcdKgExtractMask {
+ uint8_t extractArrayIndex; /**< Index in the extraction array, as initialized by user */
+ uint8_t offset; /**< Byte offset */
+ uint8_t mask; /**< A byte mask (selected bits will be used) */
+} t_FmPcdKgExtractMask;
+
+/**************************************************************************//**
+ @Description Parameters for defining default selection per groups of fields
+*//***************************************************************************/
+typedef struct t_FmPcdKgExtractDflt {
+ e_FmPcdKgKnownFieldsDfltTypes type; /**< Default type select */
+ e_FmPcdKgExtractDfltSelect dfltSelect; /**< Default register select */
+} t_FmPcdKgExtractDflt;
+
+/**************************************************************************//**
+ @Description Parameters for defining key extraction and hashing
+*//***************************************************************************/
+typedef struct t_FmPcdKgKeyExtractAndHashParams {
+ uint32_t privateDflt0; /**< Scheme default register 0 */
+ uint32_t privateDflt1; /**< Scheme default register 1 */
+ uint8_t numOfUsedExtracts; /**< defines the valid size of the following array */
+ t_FmPcdExtractEntry extractArray [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; /**< An array of extractions definition. */
+ uint8_t numOfUsedDflts; /**< defines the valid size of the following array */
+ t_FmPcdKgExtractDflt dflts[FM_PCD_KG_NUM_OF_DEFAULT_GROUPS];
+ /**< For each extraction used in this scheme, specify the required
+ default register to be used when header is not found.
+ types not specified in this array will get undefined value. */
+ uint8_t numOfUsedMasks; /**< defines the valid size of the following array */
+ t_FmPcdKgExtractMask masks[FM_PCD_KG_NUM_OF_EXTRACT_MASKS];
+ uint8_t hashShift; /**< hash result right shift. Select the 24 bits out of the 64 hash
+ result. 0 means using the 24 LSB's, otherwise use the
+ 24 LSB's after shifting right.*/
+ uint32_t hashDistributionNumOfFqids; /**< must be > 1 and a power of 2. Represents the range
+ of queues for the key and hash functionality */
+ uint8_t hashDistributionFqidsShift; /**< selects the FQID bits that will be effected by the hash */
+ bool symmetricHash; /**< TRUE to generate the same hash for frames with swapped source and
+ destination fields on all layers; If TRUE, driver will check that for
+ all layers, if SRC extraction is selected, DST extraction must also be
+ selected, and vice versa. */
+} t_FmPcdKgKeyExtractAndHashParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a single FQID mask (extracted OR).
+*//***************************************************************************/
+typedef struct t_FmPcdKgExtractedOrParams {
+ e_FmPcdExtractType type; /**< Extraction type select */
+ union {
+ struct { /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */
+ e_NetHeaderType hdr;
+ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled
+ IP. Otherwise should be cleared.*/
+ bool ignoreProtocolValidation;
+ /**< continue extraction even if protocol is not recognized */
+ } extractByHdr; /**< Header to extract by */
+ e_FmPcdExtractFrom src; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */
+ };
+ uint8_t extractionOffset; /**< Offset for extraction (in bytes). */
+ e_FmPcdKgExtractDfltSelect dfltValue; /**< Select register from which extraction is taken if
+ field not found */
+ uint8_t mask; /**< Extraction mask (specified bits are used) */
+ uint8_t bitOffsetInFqid; /**< 0-31, Selects which bits of the 24 FQID bits to effect using
+ the extracted byte; Assume byte is placed as the 8 MSB's in
+ a 32 bit word where the lower bits
+ are the FQID; i.e if bitOffsetInFqid=1 than its LSB
+ will effect the FQID MSB, if bitOffsetInFqid=24 than the
+ extracted byte will effect the 8 LSB's of the FQID,
+ if bitOffsetInFqid=31 than the byte's MSB will effect
+ the FQID's LSB; 0 means - no effect on FQID;
+ Note that one, and only one of
+ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
+ extracted byte must effect either FQID or Policer profile).*/
+ uint8_t bitOffsetInPlcrProfile;
+ /**< 0-15, Selects which bits of the 8 policer profile id bits to
+ effect using the extracted byte; Assume byte is placed
+ as the 8 MSB's in a 16 bit word where the lower bits
+ are the policer profile id; i.e if bitOffsetInPlcrProfile=1
+ than its LSB will effect the profile MSB, if bitOffsetInFqid=8
+ than the extracted byte will effect the whole policer profile id,
+ if bitOffsetInFqid=15 than the byte's MSB will effect
+ the Policer Profile id's LSB;
+ 0 means - no effect on policer profile; Note that one, and only one of
+ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e,
+ extracted byte must effect either FQID or Policer profile).*/
+} t_FmPcdKgExtractedOrParams;
+
+/**************************************************************************//**
+ @Description Parameters for configuring a scheme counter
+*//***************************************************************************/
+typedef struct t_FmPcdKgSchemeCounter {
+ bool update; /**< FALSE to keep the current counter state
+ and continue from that point, TRUE to update/reset
+ the counter when the scheme is written. */
+ uint32_t value; /**< If update=TRUE, this value will be written into the
+ counter. clear this field to reset the counter. */
+} t_FmPcdKgSchemeCounter;
+
+/**************************************************************************//**
+ @Description Parameters for configuring a policer profile for a KeyGen scheme
+ (when policer is the next engine after this scheme).
+*//***************************************************************************/
+typedef struct t_FmPcdKgPlcrProfile {
+ bool sharedProfile; /**< TRUE if this profile is shared between ports
+ (managed by master partition); Must not be TRUE
+ if profile is after Coarse Classification*/
+ bool direct; /**< if TRUE, directRelativeProfileId only selects the profile
+ id, if FALSE fqidOffsetRelativeProfileIdBase is used
+ together with fqidOffsetShift and numOfProfiles
+ parameters, to define a range of profiles from
+ which the KeyGen result will determine the
+ destination policer profile. */
+ union {
+ uint16_t directRelativeProfileId; /**< Used if 'direct' is TRUE, to select policer profile.
+ should indicate the policer profile offset within the
+ port's policer profiles or shared window. */
+ struct {
+ uint8_t fqidOffsetShift; /**< Shift on the KeyGen create FQID offset (i.e. not the
+ final FQID - without the FQID base). */
+ uint8_t fqidOffsetRelativeProfileIdBase;
+ /**< The base of the FMan Port's relative Storage-Profile ID;
+ this value will be "OR'ed" with the KeyGen create FQID
+ offset (i.e. not the final FQID - without the FQID base);
+ the final result should indicate the Storage-Profile offset
+ within the FMan Port's relative Storage-Profiles window/
+ (or the SHARED window depends on 'sharedProfile'). */
+ uint8_t numOfProfiles; /**< Range of profiles starting at base */
+ } indirectProfile; /**< Indirect profile parameters */
+ } profileSelect; /**< Direct/indirect profile selection and parameters */
+} t_FmPcdKgPlcrProfile;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Parameters for configuring a storage profile for a KeyGen scheme.
+*//***************************************************************************/
+typedef struct t_FmPcdKgStorageProfile {
+ bool direct; /**< If TRUE, directRelativeProfileId only selects the
+ profile id;
+ If FALSE, fqidOffsetRelativeProfileIdBase is used
+ together with fqidOffsetShift and numOfProfiles
+ parameters to define a range of profiles from which
+ the KeyGen result will determine the destination
+ storage profile. */
+ union {
+ uint16_t directRelativeProfileId; /**< Used when 'direct' is TRUE, to select a storage profile;
+ should indicate the storage profile offset within the
+ port's storage profiles window. */
+ struct {
+ uint8_t fqidOffsetShift; /**< Shift on the KeyGen create FQID offset (i.e. not the
+ final FQID - without the FQID base). */
+ uint8_t fqidOffsetRelativeProfileIdBase;
+ /**< The base of the FMan Port's relative Storage-Profile ID;
+ this value will be "OR'ed" with the KeyGen create FQID
+ offset (i.e. not the final FQID - without the FQID base);
+ the final result should indicate the Storage-Profile offset
+ within the FMan Port's relative Storage-Profiles window. */
+ uint8_t numOfProfiles; /**< Range of profiles starting at base. */
+ } indirectProfile; /**< Indirect profile parameters. */
+ } profileSelect; /**< Direct/indirect profile selection and parameters. */
+} t_FmPcdKgStorageProfile;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Description Parameters for defining CC as the next engine after KeyGen
+*//***************************************************************************/
+typedef struct t_FmPcdKgCc {
+ t_Handle h_CcTree; /**< A handle to a CC Tree */
+ uint8_t grpId; /**< CC group id within the CC tree */
+ bool plcrNext; /**< TRUE if after CC, in case of data frame,
+ policing is required. */
+ bool bypassPlcrProfileGeneration; /**< TRUE to bypass KeyGen policer profile generation;
+ selected profile is the one set at port initialization. */
+ t_FmPcdKgPlcrProfile plcrProfile; /**< Valid only if plcrNext = TRUE and
+ bypassPlcrProfileGeneration = FALSE */
+} t_FmPcdKgCc;
+
+/**************************************************************************//**
+ @Description Parameters for defining initializing a KeyGen scheme
+*//***************************************************************************/
+typedef struct t_FmPcdKgSchemeParams {
+ bool modify; /**< TRUE to change an existing scheme */
+ union
+ {
+ uint8_t relativeSchemeId; /**< if modify=FALSE:Partition relative scheme id */
+ t_Handle h_Scheme; /**< if modify=TRUE: a handle of the existing scheme */
+ } id;
+ bool alwaysDirect; /**< This scheme is reached only directly, i.e. no need
+ for match vector; KeyGen will ignore it when matching */
+ struct { /**< HL Relevant only if alwaysDirect = FALSE */
+ t_Handle h_NetEnv; /**< A handle to the Network environment as returned
+ by FM_PCD_NetEnvCharacteristicsSet() */
+ uint8_t numOfDistinctionUnits; /**< Number of NetEnv units listed in unitIds array */
+ uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
+ /**< Indexes as passed to SetNetEnvCharacteristics array*/
+ } netEnvParams;
+ bool useHash; /**< use the KeyGen Hash functionality */
+ t_FmPcdKgKeyExtractAndHashParams keyExtractAndHashParams;
+ /**< used only if useHash = TRUE */
+ bool bypassFqidGeneration; /**< Normally - FALSE, TRUE to avoid FQID update in the IC;
+ In such a case FQID after KeyGen will be the default FQID
+ defined for the relevant port, or the FQID defined by CC
+ in cases where CC was the previous engine. */
+ uint32_t baseFqid; /**< Base FQID; Relevant only if bypassFqidGeneration = FALSE;
+ If hash is used and an even distribution is expected
+ according to hashDistributionNumOfFqids, baseFqid must be aligned to
+ hashDistributionNumOfFqids. */
+ uint8_t numOfUsedExtractedOrs; /**< Number of FQID masks listed in extractedOrs array */
+ t_FmPcdKgExtractedOrParams extractedOrs[FM_PCD_KG_NUM_OF_GENERIC_REGS];
+ /**< FM_PCD_KG_NUM_OF_GENERIC_REGS
+ registers are shared between qidMasks
+ functionality and some of the extraction
+ actions; Normally only some will be used
+ for qidMask. Driver will return error if
+ resource is full at initialization time. */
+
+#if (DPAA_VERSION >= 11)
+ bool overrideStorageProfile; /**< TRUE if KeyGen override previously decided storage profile */
+ t_FmPcdKgStorageProfile storageProfile; /**< Used when overrideStorageProfile TRUE */
+#endif /* (DPAA_VERSION >= 11) */
+
+ e_FmPcdEngine nextEngine; /**< may be BMI, PLCR or CC */
+ union { /**< depends on nextEngine */
+ e_FmPcdDoneAction doneAction; /**< Used when next engine is BMI (done) */
+ t_FmPcdKgPlcrProfile plcrProfile; /**< Used when next engine is PLCR */
+ t_FmPcdKgCc cc; /**< Used when next engine is CC */
+ } kgNextEngineParams;
+ t_FmPcdKgSchemeCounter schemeCounter; /**< A structure of parameters for updating
+ the scheme counter */
+} t_FmPcdKgSchemeParams;
+
+/**************************************************************************//**
+ @Collection Definitions for CC statistics
+*//***************************************************************************/
+#if (DPAA_VERSION >= 11)
+#define FM_PCD_CC_STATS_MAX_NUM_OF_FLR 10 /* Maximal supported number of frame length ranges */
+#define FM_PCD_CC_STATS_FLR_SIZE 2 /* Size in bytes of a frame length range limit */
+#endif /* (DPAA_VERSION >= 11) */
+#define FM_PCD_CC_STATS_COUNTER_SIZE 4 /* Size in bytes of a frame length range counter */
+/* @} */
+
+/**************************************************************************//**
+ @Description Parameters for defining CC as the next engine after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextCcParams {
+ t_Handle h_CcNode; /**< A handle of the next CC node */
+} t_FmPcdCcNextCcParams;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Parameters for defining Frame replicator as the next engine after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextFrParams {
+ t_Handle h_FrmReplic; /**< A handle of the next frame replicator group */
+} t_FmPcdCcNextFrParams;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Description Parameters for defining Policer as the next engine after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextPlcrParams {
+ bool overrideParams; /**< TRUE if CC override previously decided parameters*/
+ bool sharedProfile; /**< Relevant only if overrideParams=TRUE:
+ TRUE if this profile is shared between ports */
+ uint16_t newRelativeProfileId; /**< Relevant only if overrideParams=TRUE:
+ (otherwise profile id is taken from KeyGen);
+ This parameter should indicate the policer
+ profile offset within the port's
+ policer profiles or from SHARED window.*/
+ uint32_t newFqid; /**< Relevant only if overrideParams=TRUE:
+ FQID for enqueuing the frame;
+ In earlier chips if policer next engine is KEYGEN,
+ this parameter can be 0, because the KEYGEN
+ always decides the enqueue FQID.*/
+#if (DPAA_VERSION >= 11)
+ uint8_t newRelativeStorageProfileId;
+ /**< Indicates the relative storage profile offset within
+ the port's storage profiles window;
+ Relevant only if the port was configured with VSP. */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPcdCcNextPlcrParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining enqueue as the next action after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextEnqueueParams {
+ e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */
+ bool overrideFqid; /**< TRUE if CC override previously decided fqid and vspid,
+ relevant if action = e_FM_PCD_ENQ_FRAME */
+ uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
+ (otherwise FQID is taken from KeyGen),
+ relevant if action = e_FM_PCD_ENQ_FRAME */
+#if (DPAA_VERSION >= 11)
+ uint8_t newRelativeStorageProfileId;
+ /**< Valid if overrideFqid=TRUE, Indicates the relative virtual
+ storage profile offset within the port's storage profiles
+ window; Relevant only if the port was configured with VSP. */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPcdCcNextEnqueueParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining KeyGen as the next engine after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextKgParams {
+ bool overrideFqid; /**< TRUE if CC override previously decided fqid and vspid,
+ Note - this parameters irrelevant for earlier chips */
+ uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame
+ (otherwise FQID is taken from KeyGen),
+ Note - this parameters irrelevant for earlier chips */
+#if (DPAA_VERSION >= 11)
+ uint8_t newRelativeStorageProfileId;
+ /**< Valid if overrideFqid=TRUE, Indicates the relative virtual
+ storage profile offset within the port's storage profiles
+ window; Relevant only if the port was configured with VSP. */
+#endif /* (DPAA_VERSION >= 11) */
+
+ t_Handle h_DirectScheme; /**< Direct scheme handle to go to. */
+} t_FmPcdCcNextKgParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining the next engine after a CC node.
+*//***************************************************************************/
+typedef struct t_FmPcdCcNextEngineParams {
+ e_FmPcdEngine nextEngine; /**< User has to initialize parameters
+ according to nextEngine definition */
+ union {
+ t_FmPcdCcNextCcParams ccParams; /**< Parameters in case next engine is CC */
+ t_FmPcdCcNextPlcrParams plcrParams; /**< Parameters in case next engine is PLCR */
+ t_FmPcdCcNextEnqueueParams enqueueParams; /**< Parameters in case next engine is BMI */
+ t_FmPcdCcNextKgParams kgParams; /**< Parameters in case next engine is KG */
+#if (DPAA_VERSION >= 11)
+ t_FmPcdCcNextFrParams frParams; /**< Parameters in case next engine is FR */
+#endif /* (DPAA_VERSION >= 11) */
+ } params; /**< union used for all the next-engine parameters options */
+
+ t_Handle h_Manip; /**< Handle to Manipulation object.
+ Relevant if next engine is of type result
+ (e_FM_PCD_PLCR, e_FM_PCD_KG, e_FM_PCD_DONE) */
+
+ bool statisticsEn; /**< If TRUE, statistics counters are incremented
+ for each frame passing through this
+ Coarse Classification entry. */
+} t_FmPcdCcNextEngineParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a single CC key
+*//***************************************************************************/
+typedef struct t_FmPcdCcKeyParams {
+ uint8_t *p_Key; /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH;
+ pointer to the key of the size defined in keySize */
+ uint8_t *p_Mask; /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH;
+ pointer to the Mask per key of the size defined
+ in keySize. p_Key and p_Mask (if defined) has to be
+ of the same size defined in the keySize;
+ NOTE that if this value is equal for all entries whithin
+ this table, the driver will automatically use global-mask
+ (i.e. one common mask for all entries) instead of private
+ one; that is done in order to spare some memory and for
+ better performance. */
+ t_FmPcdCcNextEngineParams ccNextEngineParams;
+ /**< parameters for the next for the defined Key in
+ the p_Key */
+} t_FmPcdCcKeyParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining CC keys parameters
+ The driver supports two methods for CC node allocation: dynamic and static.
+ Static mode was created in order to prevent runtime alloc/free
+ of FMan memory (MURAM), which may cause fragmentation; in this mode,
+ the driver automatically allocates the memory according to
+ 'maxNumOfKeys' parameter. The driver calculates the maximal memory
+ size that may be used for this CC-Node taking into consideration
+ 'maskSupport' and 'statisticsMode' parameters.
+ When 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP in the extraction
+ parameters of this node, 'maxNumOfKeys' must be equal to 'numOfKeys'.
+ In dynamic mode, 'maxNumOfKeys' must be zero. At initialization,
+ all required structures are allocated according to 'numOfKeys'
+ parameter. During runtime modification, these structures are
+ re-allocated according to the updated number of keys.
+
+ Please note that 'action' and 'icIndxMask' mentioned in the
+ specific parameter explanations are passed in the extraction
+ parameters of the node (fields of extractCcParams.extractNonHdr).
+*//***************************************************************************/
+typedef struct t_KeysParams {
+ uint16_t maxNumOfKeys; /**< Maximum number of keys that will (ever) be used in this CC-Node;
+ A value of zero may be used for dynamic memory allocation. */
+ bool maskSupport; /**< This parameter is relevant only if a node is initialized with
+ 'action' = e_FM_PCD_ACTION_EXACT_MATCH and maxNumOfKeys > 0;
+ Should be TRUE to reserve table memory for key masks, even if
+ initial keys do not contain masks, or if the node was initialized
+ as 'empty' (without keys); this will allow user to add keys with
+ masks at runtime.
+ NOTE that if user want to use only global-masks (i.e. one common mask
+ for all the entries within this table, this parameter should set to 'FALSE'. */
+ e_FmPcdCcStatsMode statisticsMode; /**< Determines the supported statistics mode for all node's keys.
+ To enable statistics gathering, statistics should be enabled per
+ every key, using 'statisticsEn' in next engine parameters structure
+ of that key;
+ If 'maxNumOfKeys' is set, all required structures will be
+ preallocated for all keys. */
+#if (DPAA_VERSION >= 11)
+ uint16_t frameLengthRanges[FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
+ /**< Relevant only for 'RMON' statistics mode
+ (this feature is supported only on B4860 device);
+ Holds a list of programmable thresholds - for each received frame,
+ its length in bytes is examined against these range thresholds and
+ the appropriate counter is incremented by 1 - for example, to belong
+ to range i, the following should hold:
+ range i-1 threshold < frame length <= range i threshold
+ Each range threshold must be larger then its preceding range
+ threshold, and last range threshold must be 0xFFFF. */
+#endif /* (DPAA_VERSION >= 11) */
+ uint16_t numOfKeys; /**< Number of initial keys;
+ Note that in case of 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP,
+ this field should be power-of-2 of the number of bits that are
+ set in 'icIndxMask'. */
+ uint8_t keySize; /**< Size of key - for extraction of type FULL_FIELD, 'keySize' has
+ to be the standard size of the selected key; For other extraction
+ types, 'keySize' has to be as size of extraction; When 'action' =
+ e_FM_PCD_ACTION_INDEXED_LOOKUP, 'keySize' must be 2. */
+ t_FmPcdCcKeyParams keyParams[FM_PCD_MAX_NUM_OF_KEYS];
+ /**< An array with 'numOfKeys' entries, each entry specifies the
+ corresponding key parameters;
+ When 'action' = e_FM_PCD_ACTION_EXACT_MATCH, this value must not
+ exceed 255 (FM_PCD_MAX_NUM_OF_KEYS-1) as the last entry is saved
+ for the 'miss' entry. */
+ t_FmPcdCcNextEngineParams ccNextEngineParamsForMiss;
+ /**< Parameters for defining the next engine when a key is not matched;
+ Not relevant if action = e_FM_PCD_ACTION_INDEXED_LOOKUP. */
+} t_KeysParams;
+
+
+/**************************************************************************//**
+ @Description Parameters for defining a CC node
+*//***************************************************************************/
+typedef struct t_FmPcdCcNodeParams {
+ t_FmPcdExtractEntry extractCcParams; /**< Extraction parameters */
+ t_KeysParams keysParams; /**< Keys definition matching the selected extraction */
+} t_FmPcdCcNodeParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a hash table
+*//***************************************************************************/
+typedef struct t_FmPcdHashTableParams {
+ uint16_t maxNumOfKeys; /**< Maximum Number Of Keys that will (ever) be used in this Hash-table */
+ e_FmPcdCcStatsMode statisticsMode; /**< If not e_FM_PCD_CC_STATS_MODE_NONE, the required structures for the
+ requested statistics mode will be allocated according to maxNumOfKeys. */
+ uint8_t kgHashShift; /**< KG-Hash-shift as it was configured in the KG-scheme
+ that leads to this hash-table. */
+ uint16_t hashResMask; /**< Mask that will be used on the hash-result;
+ The number-of-sets for this hash will be calculated
+ as (2^(number of bits set in 'hashResMask'));
+ The 4 lower bits must be cleared. */
+ uint8_t hashShift; /**< Byte offset from the beginning of the KeyGen hash result to the
+ 2-bytes to be used as hash index. */
+ uint8_t matchKeySize; /**< Size of the exact match keys held by the hash buckets */
+
+ t_FmPcdCcNextEngineParams ccNextEngineParamsForMiss; /**< Parameters for defining the next engine when a key is not matched */
+
+} t_FmPcdHashTableParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a CC tree group.
+
+ This structure defines a CC group in terms of NetEnv units
+ and the action to be taken in each case. The unitIds list must
+ be given in order from low to high indices.
+
+ t_FmPcdCcNextEngineParams is a list of 2^numOfDistinctionUnits
+ structures where each defines the next action to be taken for
+ each units combination. for example:
+ numOfDistinctionUnits = 2
+ unitIds = {1,3}
+ p_NextEnginePerEntriesInGrp[0] = t_FmPcdCcNextEngineParams for the case that
+ unit 1 - not found; unit 3 - not found;
+ p_NextEnginePerEntriesInGrp[1] = t_FmPcdCcNextEngineParams for the case that
+ unit 1 - not found; unit 3 - found;
+ p_NextEnginePerEntriesInGrp[2] = t_FmPcdCcNextEngineParams for the case that
+ unit 1 - found; unit 3 - not found;
+ p_NextEnginePerEntriesInGrp[3] = t_FmPcdCcNextEngineParams for the case that
+ unit 1 - found; unit 3 - found;
+*//***************************************************************************/
+typedef struct t_FmPcdCcGrpParams {
+ uint8_t numOfDistinctionUnits; /**< Up to 4 */
+ uint8_t unitIds[FM_PCD_MAX_NUM_OF_CC_UNITS];
+ /**< Indices of the units as defined in
+ FM_PCD_NetEnvCharacteristicsSet() */
+ t_FmPcdCcNextEngineParams nextEnginePerEntriesInGrp[FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP];
+ /**< Maximum entries per group is 16 */
+} t_FmPcdCcGrpParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining CC tree groups
+*//***************************************************************************/
+typedef struct t_FmPcdCcTreeParams {
+ t_Handle h_NetEnv; /**< A handle to the Network environment as returned
+ by FM_PCD_NetEnvCharacteristicsSet() */
+ uint8_t numOfGrps; /**< Number of CC groups within the CC tree */
+ t_FmPcdCcGrpParams ccGrpParams[FM_PCD_MAX_NUM_OF_CC_GROUPS];
+ /**< Parameters for each group. */
+} t_FmPcdCcTreeParams;
+
+
+/**************************************************************************//**
+ @Description CC key statistics structure
+*//***************************************************************************/
+typedef struct t_FmPcdCcKeyStatistics {
+ uint32_t byteCount; /**< This counter reflects byte count of frames that
+ were matched by this key. */
+ uint32_t frameCount; /**< This counter reflects count of frames that
+ were matched by this key. */
+#if (DPAA_VERSION >= 11)
+ uint32_t frameLengthRangeCount[FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
+ /**< These counters reflect how many frames matched
+ this key in 'RMON' statistics mode:
+ Each counter holds the number of frames of a
+ specific frames length range, according to the
+ ranges provided at initialization. */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPcdCcKeyStatistics;
+
+/**************************************************************************//**
+ @Description Parameters for defining policer byte rate
+*//***************************************************************************/
+typedef struct t_FmPcdPlcrByteRateModeParams {
+ e_FmPcdPlcrFrameLengthSelect frameLengthSelection; /**< Frame length selection */
+ e_FmPcdPlcrRollBackFrameSelect rollBackFrameSelection; /**< relevant option only e_FM_PCD_PLCR_L2_FRM_LEN,
+ e_FM_PCD_PLCR_FULL_FRM_LEN */
+} t_FmPcdPlcrByteRateModeParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining the policer profile (based on
+ RFC-2698 or RFC-4115 attributes).
+*//***************************************************************************/
+typedef struct t_FmPcdPlcrNonPassthroughAlgParams {
+ e_FmPcdPlcrRateMode rateMode; /**< Byte mode or Packet mode */
+ t_FmPcdPlcrByteRateModeParams byteModeParams; /**< Valid for Byte NULL for Packet */
+ uint32_t committedInfoRate; /**< KBits/Second or Packets/Second */
+ uint32_t committedBurstSize; /**< Bytes/Packets */
+ uint32_t peakOrExcessInfoRate; /**< KBits/Second or Packets/Second */
+ uint32_t peakOrExcessBurstSize; /**< Bytes/Packets */
+} t_FmPcdPlcrNonPassthroughAlgParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining the next engine after policer
+*//***************************************************************************/
+typedef union u_FmPcdPlcrNextEngineParams {
+ e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */
+ t_Handle h_Profile; /**< Policer profile handle - used when next engine
+ is Policer, must be a SHARED profile */
+ t_Handle h_DirectScheme; /**< Direct scheme select - when next engine is KeyGen */
+} u_FmPcdPlcrNextEngineParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining the policer profile entry
+*//***************************************************************************/
+typedef struct t_FmPcdPlcrProfileParams {
+ bool modify; /**< TRUE to change an existing profile */
+ union {
+ struct {
+ e_FmPcdProfileTypeSelection profileType; /**< Type of policer profile */
+ t_Handle h_FmPort; /**< Relevant for per-port profiles only */
+ uint16_t relativeProfileId; /**< Profile id - relative to shared group or to port */
+ } newParams; /**< use it when modify = FALSE */
+ t_Handle h_Profile; /**< A handle to a profile - use it when modify=TRUE */
+ } id;
+ e_FmPcdPlcrAlgorithmSelection algSelection; /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */
+ e_FmPcdPlcrColorMode colorMode; /**< COLOR_BLIND, COLOR_AWARE */
+
+ union {
+ e_FmPcdPlcrColor dfltColor; /**< For Color-Blind Pass-Through mode; the policer will re-color
+ any incoming packet with the default value. */
+ e_FmPcdPlcrColor override; /**< For Color-Aware modes; the profile response to a
+ pre-color value of 2'b11. */
+ } color;
+
+ t_FmPcdPlcrNonPassthroughAlgParams nonPassthroughAlgParams; /**< RFC2698 or RFC4115 parameters */
+
+ e_FmPcdEngine nextEngineOnGreen; /**< Next engine for green-colored frames */
+ u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Next engine parameters for green-colored frames */
+
+ e_FmPcdEngine nextEngineOnYellow; /**< Next engine for yellow-colored frames */
+ u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Next engine parameters for yellow-colored frames */
+
+ e_FmPcdEngine nextEngineOnRed; /**< Next engine for red-colored frames */
+ u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Next engine parameters for red-colored frames */
+
+ bool trapProfileOnFlowA; /**< Obsolete - do not use */
+ bool trapProfileOnFlowB; /**< Obsolete - do not use */
+ bool trapProfileOnFlowC; /**< Obsolete - do not use */
+} t_FmPcdPlcrProfileParams;
+
+/**************************************************************************//**
+ @Description Parameters for selecting a location for requested manipulation
+*//***************************************************************************/
+typedef struct t_FmManipHdrInfo {
+ e_NetHeaderType hdr; /**< Header selection */
+ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled IP. Otherwise should be cleared. */
+ bool byField; /**< TRUE if the location of manipulation is according to some field in the specific header*/
+ t_FmPcdFields fullField; /**< Relevant only when byField = TRUE: Extract field */
+} t_FmManipHdrInfo;
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+/**************************************************************************//**
+ @Description Parameters for defining an insertion manipulation
+ of type e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtByTemplateParams {
+ uint8_t size; /**< Size of insert template to the start of the frame. */
+ uint8_t hdrTemplate[FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE];
+ /**< Array of the insertion template. */
+
+ bool modifyOuterIp; /**< TRUE if user want to modify some fields in outer IP. */
+ struct {
+ uint16_t ipOuterOffset; /**< Offset of outer IP in the insert template, relevant if modifyOuterIp = TRUE.*/
+ uint16_t dscpEcn; /**< value of dscpEcn in IP outer, relevant if modifyOuterIp = TRUE.
+ in IPV4 dscpEcn only byte - it has to be adjusted to the right*/
+ bool udpPresent; /**< TRUE if UDP is present in the insert template, relevant if modifyOuterIp = TRUE.*/
+ uint8_t udpOffset; /**< Offset in the insert template of UDP, relevant if modifyOuterIp = TRUE and udpPresent=TRUE.*/
+ uint8_t ipIdentGenId; /**< Used by FMan-CTRL to calculate IP-identification field,relevant if modifyOuterIp = TRUE.*/
+ bool recalculateLength; /**< TRUE if recalculate length has to be performed due to the engines in the path which can change the frame later, relevant if modifyOuterIp = TRUE.*/
+ struct {
+ uint8_t blockSize; /**< The CAAM block-size; Used by FMan-CTRL to calculate the IP Total Length field.*/
+ uint8_t extraBytesAddedAlignedToBlockSize; /**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length*/
+ uint8_t extraBytesAddedNotAlignedToBlockSize;/**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length.*/
+ } recalculateLengthParams; /**< Recalculate length parameters - relevant if modifyOuterIp = TRUE and recalculateLength = TRUE */
+ } modifyOuterIpParams; /**< Outer IP modification parameters - ignored if modifyOuterIp is FALSE */
+
+ bool modifyOuterVlan; /**< TRUE if user wants to modify VPri field in the outer VLAN header*/
+ struct {
+ uint8_t vpri; /**< Value of VPri, relevant if modifyOuterVlan = TRUE
+ VPri only 3 bits, it has to be adjusted to the right*/
+ } modifyOuterVlanParams;
+} t_FmPcdManipHdrInsrtByTemplateParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining CAPWAP fragmentation
+*//***************************************************************************/
+typedef struct t_CapwapFragmentationParams {
+ uint16_t sizeForFragmentation; /**< if length of the frame is greater than this value, CAPWAP fragmentation will be executed.*/
+ bool headerOptionsCompr; /**< TRUE - first fragment include the CAPWAP header options field,
+ and all other fragments exclude the CAPWAP options field,
+ FALSE - all fragments include CAPWAP header options field. */
+} t_CapwapFragmentationParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining CAPWAP reassembly
+*//***************************************************************************/
+typedef struct t_CapwapReassemblyParams {
+ uint16_t maxNumFramesInProcess; /**< Number of frames which can be reassembled concurrently; must be power of 2.
+ In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 4 - 512,
+ In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 8 - 2048 */
+ bool haltOnDuplicationFrag; /**< If TRUE, reassembly process will be halted due to duplicated fragment,
+ and all processed fragments will be enqueued with error indication;
+ If FALSE, only duplicated fragments will be enqueued with error indication. */
+
+ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by the reassembly process */
+ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process */
+ uint32_t timeoutRoutineRequestTime;
+ /**< Represents the time interval in microseconds between consecutive
+ timeout routine requests It has to be power of 2. */
+ uint32_t timeoutThresholdForReassmProcess;
+ /**< Time interval (microseconds) for marking frames in process as too old;
+ Frames in process are those for which at least one fragment was received
+ but not all fragments. */
+
+ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry;/**< Number of frames per hash entry (needed for the reassembly process) */
+} t_CapwapReassemblyParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining fragmentation/reassembly manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragOrReasmParams {
+ bool frag; /**< TRUE if using the structure for fragmentation,
+ otherwise this structure is used for reassembly */
+ uint8_t sgBpid; /**< Scatter/Gather buffer pool id;
+ Same LIODN number is used for these buffers as for
+ the received frames buffers, so buffers of this pool
+ need to be allocated in the same memory area as the
+ received buffers. If the received buffers arrive
+ from different sources, the Scatter/Gather BP id
+ should be mutual to all these sources. */
+ e_NetHeaderType hdr; /**< Header selection */
+ union {
+ t_CapwapFragmentationParams capwapFragParams; /**< Structure for CAPWAP fragmentation,
+ relevant if 'frag' = TRUE, 'hdr' = HEADER_TYPE_CAPWAP */
+ t_CapwapReassemblyParams capwapReasmParams; /**< Structure for CAPWAP reassembly,
+ relevant if 'frag' = FALSE, 'hdr' = HEADER_TYPE_CAPWAP */
+ } u;
+} t_FmPcdManipFragOrReasmParams;
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+
+/**************************************************************************//**
+ @Description Parameters for defining header removal by header type
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrRmvByHdrParams {
+ e_FmPcdManipHdrRmvByHdrType type; /**< Selection of header removal location */
+ union {
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ struct {
+ bool include; /**< If FALSE, remove until the specified header (not including the header);
+ If TRUE, remove also the specified header. */
+ t_FmManipHdrInfo hdrInfo;
+ } fromStartByHdr; /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
+#endif /* (DPAA_VERSION >= 11) || ... */
+#if (DPAA_VERSION >= 11)
+ t_FmManipHdrInfo hdrInfo; /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */
+#endif /* (DPAA_VERSION >= 11) */
+ e_FmPcdManipHdrRmvSpecificL2 specificL2; /**< Relevant when type = e_FM_PCD_MANIP_BY_HDR_SPECIFIC_L2;
+ Defines which L2 headers to remove. */
+ } u;
+} t_FmPcdManipHdrRmvByHdrParams;
+
+/**************************************************************************//**
+ @Description Parameters for configuring IP fragmentation manipulation
+
+ Restrictions:
+ - IP Fragmentation output fragments must not be forwarded to application directly.
+ - Maximum number of fragments per frame is 16.
+ - Fragmentation of IP fragments is not supported.
+ - IPv4 packets containing header Option fields are fragmented by copying all option
+ fields to each fragment, regardless of the copy bit value.
+ - Transmit confirmation is not supported.
+ - Fragmentation after SEC can't handle S/G frames.
+ - Fragmentation nodes must be set as the last PCD action (i.e. the
+ corresponding CC node key must have next engine set to e_FM_PCD_DONE).
+ - Only BMan buffers shall be used for frames to be fragmented.
+ - IPF does not support VSP. Therefore, on the same port where we have IPF
+ we cannot support VSP.
+ - NOTE: The following comment is relevant only for FMAN v3 devices: IPF
+ does not support VSP. Therefore, on the same port where we have IPF we
+ cannot support VSP.
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragIpParams {
+ uint16_t sizeForFragmentation; /**< If length of the frame is greater than this value,
+ IP fragmentation will be executed.*/
+#if (DPAA_VERSION == 10)
+ uint8_t scratchBpid; /**< Absolute buffer pool id according to BM configuration.*/
+#endif /* (DPAA_VERSION == 10) */
+ bool sgBpidEn; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
+ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
+ received frame's buffer. */
+ uint8_t sgBpid; /**< Scatter/Gather buffer pool id;
+ This parameters is relevant when 'sgBpidEn=TRUE';
+ Same LIODN number is used for these buffers as for the received frames buffers, so buffers
+ of this pool need to be allocated in the same memory area as the received buffers.
+ If the received buffers arrive from different sources, the Scatter/Gather BP id should be
+ mutual to all these sources. */
+ e_FmPcdManipDontFragAction dontFragAction; /**< Don't Fragment Action - If an IP packet is larger
+ than MTU and its DF bit is set, then this field will
+ determine the action to be taken.*/
+} t_FmPcdManipFragIpParams;
+
+/**************************************************************************//**
+ @Description Parameters for configuring IP reassembly manipulation.
+
+ This is a common structure for both IPv4 and IPv6 reassembly
+ manipulation. For reassembly of both IPv4 and IPv6, make sure to
+ set the 'hdr' field in t_FmPcdManipReassemParams to HEADER_TYPE_IPv6.
+
+ Restrictions:
+ - Application must define at least one scheme to catch the reassembled frames.
+ - Maximum number of fragments per frame is 16.
+ - Reassembly of IPv4 fragments containing Option fields is supported.
+
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemIpParams {
+ uint8_t relativeSchemeId[2]; /**< Partition relative scheme id:
+ relativeSchemeId[0] - Relative scheme ID for IPV4 Reassembly manipulation;
+ relativeSchemeId[1] - Relative scheme ID for IPV6 Reassembly manipulation;
+ NOTE: The following comment is relevant only for FMAN v2 devices:
+ Relative scheme ID for IPv4/IPv6 Reassembly manipulation must be smaller than
+ the user schemes id to ensure that the reassembly schemes will be first match;
+ Rest schemes, if defined, should have higher relative scheme ID. */
+#if (DPAA_VERSION >= 11)
+ uint32_t nonConsistentSpFqid; /**< In case that other fragments of the frame corresponds to different storage
+ profile than the opening fragment (Non-Consistent-SP state)
+ then one of two possible scenarios occurs:
+ if 'nonConsistentSpFqid != 0', the reassembled frame will be enqueued to
+ this fqid, otherwise a 'Non Consistent SP' bit will be set in the FD[status].*/
+#else
+ uint8_t sgBpid; /**< Buffer pool id for the S/G frame created by the reassembly process */
+#endif /* (DPAA_VERSION >= 11) */
+ uint8_t dataMemId; /**< Memory partition ID for the IPR's external tables structure */
+ uint16_t dataLiodnOffset; /**< LIODN offset for access the IPR's external tables structure. */
+ uint16_t minFragSize[2]; /**< Minimum fragment size:
+ minFragSize[0] - for ipv4, minFragSize[1] - for ipv6 */
+ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry[2];
+ /**< Number of frames per hash entry needed for reassembly process:
+ numOfFramesPerHashEntry[0] - for ipv4 (max value is e_FM_PCD_MANIP_EIGHT_WAYS_HASH);
+ numOfFramesPerHashEntry[1] - for ipv6 (max value is e_FM_PCD_MANIP_SIX_WAYS_HASH). */
+ uint16_t maxNumFramesInProcess; /**< Number of frames which can be processed by Reassembly in the same time;
+ Must be power of 2;
+ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 4 - 512;
+ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 8 - 2048. */
+ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by Reassembly process */
+ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process;
+ Recommended value for this field is 0; in this way timed-out frames will be discarded */
+ uint32_t timeoutThresholdForReassmProcess;
+ /**< Represents the time interval in microseconds which defines
+ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
+} t_FmPcdManipReassemIpParams;
+
+/**************************************************************************//**
+ @Description structure for defining IPSEC manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipSpecialOffloadIPSecParams {
+ bool decryption; /**< TRUE if being used in decryption direction;
+ FALSE if being used in encryption direction. */
+ bool ecnCopy; /**< TRUE to copy the ECN bits from inner/outer to outer/inner
+ (direction depends on the 'decryption' field). */
+ bool dscpCopy; /**< TRUE to copy the DSCP bits from inner/outer to outer/inner
+ (direction depends on the 'decryption' field). */
+ bool variableIpHdrLen; /**< TRUE for supporting variable IP header length in decryption. */
+ bool variableIpVersion; /**< TRUE for supporting both IP version on the same SA in encryption */
+ uint8_t outerIPHdrLen; /**< if 'variableIpVersion == TRUE' then this field must be set to non-zero value;
+ It is specifies the length of the outer IP header that was configured in the
+ corresponding SA. */
+ uint16_t arwSize; /**< if <> '0' then will perform ARW check for this SA;
+ The value must be a multiplication of 16 */
+ uintptr_t arwAddr; /**< if arwSize <> '0' then this field must be set to non-zero value;
+ MUST be allocated from FMAN's MURAM that the post-sec op-port belongs to;
+ Must be 4B aligned. Required MURAM size is 'NEXT_POWER_OF_2(arwSize+32))/8+4' Bytes */
+} t_FmPcdManipSpecialOffloadIPSecParams;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Parameters for configuring CAPWAP fragmentation manipulation
+
+ Restrictions:
+ - Maximum number of fragments per frame is 16.
+ - Transmit confirmation is not supported.
+ - Fragmentation nodes must be set as the last PCD action (i.e. the
+ corresponding CC node key must have next engine set to e_FM_PCD_DONE).
+ - Only BMan buffers shall be used for frames to be fragmented.
+ - NOTE: The following comment is relevant only for FMAN v3 devices: IPF
+ does not support VSP. Therefore, on the same port where we have IPF we
+ cannot support VSP.
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragCapwapParams {
+ uint16_t sizeForFragmentation; /**< If length of the frame is greater than this value,
+ CAPWAP fragmentation will be executed.*/
+ bool sgBpidEn; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation;
+ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the
+ received frame's buffer. */
+ uint8_t sgBpid; /**< Scatter/Gather buffer pool id;
+ This parameters is relevant when 'sgBpidEn=TRUE';
+ Same LIODN number is used for these buffers as for the received frames buffers, so buffers
+ of this pool need to be allocated in the same memory area as the received buffers.
+ If the received buffers arrive from different sources, the Scatter/Gather BP id should be
+ mutual to all these sources. */
+ bool compressModeEn; /**< CAPWAP Header Options Compress Enable mode;
+ When this mode is enabled then only the first fragment include the CAPWAP header options
+ field (if user provides it in the input frame) and all other fragments exclude the CAPWAP
+ options field (CAPWAP header is updated accordingly).*/
+} t_FmPcdManipFragCapwapParams;
+
+/**************************************************************************//**
+ @Description Parameters for configuring CAPWAP reassembly manipulation.
+
+ Restrictions:
+ - Application must define one scheme to catch the reassembled frames.
+ - Maximum number of fragments per frame is 16.
+
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemCapwapParams {
+ uint8_t relativeSchemeId; /**< Partition relative scheme id;
+ NOTE: this id must be smaller than the user schemes id to ensure that the reassembly scheme will be first match;
+ Rest schemes, if defined, should have higher relative scheme ID. */
+ uint8_t dataMemId; /**< Memory partition ID for the IPR's external tables structure */
+ uint16_t dataLiodnOffset; /**< LIODN offset for access the IPR's external tables structure. */
+ uint16_t maxReassembledFrameLength;/**< The maximum CAPWAP reassembled frame length in bytes;
+ If maxReassembledFrameLength == 0, any successful reassembled frame length is
+ considered as a valid length;
+ if maxReassembledFrameLength > 0, a successful reassembled frame which its length
+ exceeds this value is considered as an error frame (FD status[CRE] bit is set). */
+ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry;
+ /**< Number of frames per hash entry needed for reassembly process */
+ uint16_t maxNumFramesInProcess; /**< Number of frames which can be processed by reassembly in the same time;
+ Must be power of 2;
+ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 4 - 512;
+ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH,
+ maxNumFramesInProcess has to be in the range of 8 - 2048. */
+ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by Reassembly process */
+ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process;
+ Recommended value for this field is 0; in this way timed-out frames will be discarded */
+ uint32_t timeoutThresholdForReassmProcess;
+ /**< Represents the time interval in microseconds which defines
+ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/
+} t_FmPcdManipReassemCapwapParams;
+
+/**************************************************************************//**
+ @Description structure for defining CAPWAP manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipSpecialOffloadCapwapParams {
+ bool dtls; /**< TRUE if continue to SEC DTLS encryption */
+ e_FmPcdManipHdrQosSrc qosSrc; /**< TODO */
+} t_FmPcdManipSpecialOffloadCapwapParams;
+
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/**************************************************************************//**
+ @Description Parameters for defining special offload manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipSpecialOffloadParams {
+ e_FmPcdManipSpecialOffloadType type; /**< Type of special offload manipulation */
+ union
+ {
+ t_FmPcdManipSpecialOffloadIPSecParams ipsec; /**< Parameters for IPSec; Relevant when
+ type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC */
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipSpecialOffloadCapwapParams capwap; /**< Parameters for CAPWAP; Relevant when
+ type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP */
+#endif /* (DPAA_VERSION >= 11) */
+ } u;
+} t_FmPcdManipSpecialOffloadParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining insertion manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrt {
+ uint8_t size; /**< size of inserted section */
+ uint8_t *p_Data; /**< data to be inserted */
+} t_FmPcdManipHdrInsrt;
+
+
+/**************************************************************************//**
+ @Description Parameters for defining generic removal manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrRmvGenericParams {
+ uint8_t offset; /**< Offset from beginning of header to the start
+ location of the removal */
+ uint8_t size; /**< Size of removed section */
+} t_FmPcdManipHdrRmvGenericParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining generic insertion manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtGenericParams {
+ uint8_t offset; /**< Offset from beginning of header to the start
+ location of the insertion */
+ uint8_t size; /**< Size of inserted section */
+ bool replace; /**< TRUE to override (replace) existing data at
+ 'offset', FALSE to insert */
+ uint8_t *p_Data; /**< Pointer to data to be inserted */
+} t_FmPcdManipHdrInsrtGenericParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation VLAN DSCP To Vpri translation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateVlanDscpToVpri {
+ uint8_t dscpToVpriTable[FM_PCD_MANIP_DSCP_TO_VLAN_TRANS];
+ /**< A table of VPri values for each DSCP value;
+ The index is the DSCP value (0-0x3F) and the
+ value is the corresponding VPRI (0-15). */
+ uint8_t vpriDefVal; /**< 0-7, Relevant only if if updateType =
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN,
+ this field is the Q Tag default value if the
+ IP header is not found. */
+} t_FmPcdManipHdrFieldUpdateVlanDscpToVpri;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation VLAN fields updates
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateVlan {
+ e_FmPcdManipHdrFieldUpdateVlan updateType; /**< Selects VLAN update type */
+ union {
+ uint8_t vpri; /**< 0-7, Relevant only if If updateType =
+ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_PRI, this
+ is the new VLAN pri. */
+ t_FmPcdManipHdrFieldUpdateVlanDscpToVpri dscpToVpri; /**< Parameters structure, Relevant only if updateType
+ = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN. */
+ } u;
+} t_FmPcdManipHdrFieldUpdateVlan;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation IPV4 fields updates
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateIpv4 {
+ ipv4HdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */
+ uint8_t tos; /**< 8 bit New TOS; Relevant if validUpdates contains
+ HDR_MANIP_IPV4_TOS */
+ uint16_t id; /**< 16 bit New IP ID; Relevant only if validUpdates
+ contains HDR_MANIP_IPV4_ID */
+ uint32_t src; /**< 32 bit New IP SRC; Relevant only if validUpdates
+ contains HDR_MANIP_IPV4_SRC */
+ uint32_t dst; /**< 32 bit New IP DST; Relevant only if validUpdates
+ contains HDR_MANIP_IPV4_DST */
+} t_FmPcdManipHdrFieldUpdateIpv4;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation IPV6 fields updates
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateIpv6 {
+ ipv6HdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */
+ uint8_t trafficClass; /**< 8 bit New Traffic Class; Relevant if validUpdates contains
+ HDR_MANIP_IPV6_TC */
+ uint8_t src[NET_HEADER_FIELD_IPv6_ADDR_SIZE];
+ /**< 16 byte new IP SRC; Relevant only if validUpdates
+ contains HDR_MANIP_IPV6_SRC */
+ uint8_t dst[NET_HEADER_FIELD_IPv6_ADDR_SIZE];
+ /**< 16 byte new IP DST; Relevant only if validUpdates
+ contains HDR_MANIP_IPV6_DST */
+} t_FmPcdManipHdrFieldUpdateIpv6;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation TCP/UDP fields updates
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateTcpUdp {
+ tcpUdpHdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */
+ uint16_t src; /**< 16 bit New TCP/UDP SRC; Relevant only if validUpdates
+ contains HDR_MANIP_TCP_UDP_SRC */
+ uint16_t dst; /**< 16 bit New TCP/UDP DST; Relevant only if validUpdates
+ contains HDR_MANIP_TCP_UDP_DST */
+} t_FmPcdManipHdrFieldUpdateTcpUdp;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation fields updates
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrFieldUpdateParams {
+ e_FmPcdManipHdrFieldUpdateType type; /**< Type of header field update manipulation */
+ union {
+ t_FmPcdManipHdrFieldUpdateVlan vlan; /**< Parameters for VLAN update. Relevant when
+ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN */
+ t_FmPcdManipHdrFieldUpdateIpv4 ipv4; /**< Parameters for IPv4 update. Relevant when
+ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4 */
+ t_FmPcdManipHdrFieldUpdateIpv6 ipv6; /**< Parameters for IPv6 update. Relevant when
+ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6 */
+ t_FmPcdManipHdrFieldUpdateTcpUdp tcpUdp; /**< Parameters for TCP/UDP update. Relevant when
+ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP */
+ } u;
+} t_FmPcdManipHdrFieldUpdateParams;
+
+
+
+/**************************************************************************//**
+ @Description Parameters for defining custom header manipulation for generic field replacement
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrCustomGenFieldReplace {
+ uint8_t srcOffset; /**< Location of new data - Offset from
+ Parse Result (>= 16, srcOffset+size <= 32, ) */
+ uint8_t dstOffset; /**< Location of data to be overwritten - Offset from
+ start of frame (dstOffset + size <= 256). */
+ uint8_t size; /**< The number of bytes (<=16) to be replaced */
+ uint8_t mask; /**< Optional 1 byte mask. Set to select bits for
+ replacement (1 - bit will be replaced);
+ Clear to use field as is. */
+ uint8_t maskOffset; /**< Relevant if mask != 0;
+ Mask offset within the replaces "size" */
+} t_FmPcdManipHdrCustomGenFieldReplace;
+
+/**************************************************************************//**
+ @Description Parameters for defining custom header manipulation for IP replacement
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrCustomIpHdrReplace {
+ e_FmPcdManipHdrCustomIpReplace replaceType; /**< Selects replace update type */
+ bool decTtlHl; /**< Decrement TTL (IPV4) or Hop limit (IPV6) by 1 */
+ bool updateIpv4Id; /**< Relevant when replaceType =
+ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 */
+ uint16_t id; /**< 16 bit New IP ID; Relevant only if
+ updateIpv4Id = TRUE */
+ uint8_t hdrSize; /**< The size of the new IP header */
+ uint8_t hdr[FM_PCD_MANIP_MAX_HDR_SIZE];
+ /**< The new IP header */
+} t_FmPcdManipHdrCustomIpHdrReplace;
+
+/**************************************************************************//**
+ @Description Parameters for defining custom header manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrCustomParams {
+ e_FmPcdManipHdrCustomType type; /**< Type of header field update manipulation */
+ union {
+ t_FmPcdManipHdrCustomIpHdrReplace ipHdrReplace; /**< Parameters IP header replacement */
+ t_FmPcdManipHdrCustomGenFieldReplace genFieldReplace; /**< Parameters IP header replacement */
+ } u;
+} t_FmPcdManipHdrCustomParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining specific L2 insertion manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtSpecificL2Params {
+ e_FmPcdManipHdrInsrtSpecificL2 specificL2; /**< Selects which L2 headers to insert */
+ bool update; /**< TRUE to update MPLS header */
+ uint8_t size; /**< size of inserted section */
+ uint8_t *p_Data; /**< data to be inserted */
+} t_FmPcdManipHdrInsrtSpecificL2Params;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Parameters for defining IP insertion manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtIpParams {
+ bool calcL4Checksum; /**< Calculate L4 checksum. */
+ e_FmPcdManipHdrQosMappingMode mappingMode; /**< TODO */
+ uint8_t lastPidOffset; /**< the offset of the last Protocol within
+ the inserted header */
+ uint16_t id; /**< 16 bit New IP ID */
+ bool dontFragOverwrite;
+ /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte.
+ * This byte is configured to be overwritten when RPD is set. */
+ uint8_t lastDstOffset;
+ /**< IPv6 only. if routing extension exist, user should set the offset of the destination address
+ * in order to calculate UDP checksum pseudo header;
+ * Otherwise set it to '0'. */
+ t_FmPcdManipHdrInsrt insrt; /**< size and data to be inserted. */
+} t_FmPcdManipHdrInsrtIpParams;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Description Parameters for defining header insertion manipulation by header type
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtByHdrParams {
+ e_FmPcdManipHdrInsrtByHdrType type; /**< Selects manipulation type */
+ union {
+
+ t_FmPcdManipHdrInsrtSpecificL2Params specificL2Params;
+ /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2:
+ Selects which L2 headers to insert */
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipHdrInsrtIpParams ipParams; /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_IP */
+ t_FmPcdManipHdrInsrt insrt; /**< Used when type is one of e_FM_PCD_MANIP_INSRT_BY_HDR_UDP,
+ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, or
+ e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP */
+#endif /* (DPAA_VERSION >= 11) */
+ } u;
+} t_FmPcdManipHdrInsrtByHdrParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining header insertion manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrInsrtParams {
+ e_FmPcdManipHdrInsrtType type; /**< Type of insertion manipulation */
+ union {
+ t_FmPcdManipHdrInsrtByHdrParams byHdr; /**< Parameters for defining header insertion manipulation by header type,
+ relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_HDR */
+ t_FmPcdManipHdrInsrtGenericParams generic; /**< Parameters for defining generic header insertion manipulation,
+ relevant if 'type' = e_FM_PCD_MANIP_INSRT_GENERIC */
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ t_FmPcdManipHdrInsrtByTemplateParams byTemplate; /**< Parameters for defining header insertion manipulation by template,
+ relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_TEMPLATE */
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+ } u;
+} t_FmPcdManipHdrInsrtParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining header removal manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrRmvParams {
+ e_FmPcdManipHdrRmvType type; /**< Type of header removal manipulation */
+ union {
+ t_FmPcdManipHdrRmvByHdrParams byHdr; /**< Parameters for defining header removal manipulation by header type,
+ relevant if type = e_FM_PCD_MANIP_RMV_BY_HDR */
+ t_FmPcdManipHdrRmvGenericParams generic; /**< Parameters for defining generic header removal manipulation,
+ relevant if type = e_FM_PCD_MANIP_RMV_GENERIC */
+ } u;
+} t_FmPcdManipHdrRmvParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining header manipulation node
+*//***************************************************************************/
+typedef struct t_FmPcdManipHdrParams {
+ bool rmv; /**< TRUE, to define removal manipulation */
+ t_FmPcdManipHdrRmvParams rmvParams; /**< Parameters for removal manipulation, relevant if 'rmv' = TRUE */
+
+ bool insrt; /**< TRUE, to define insertion manipulation */
+ t_FmPcdManipHdrInsrtParams insrtParams; /**< Parameters for insertion manipulation, relevant if 'insrt' = TRUE */
+
+ bool fieldUpdate; /**< TRUE, to define field update manipulation */
+ t_FmPcdManipHdrFieldUpdateParams fieldUpdateParams; /**< Parameters for field update manipulation, relevant if 'fieldUpdate' = TRUE */
+
+ bool custom; /**< TRUE, to define custom manipulation */
+ t_FmPcdManipHdrCustomParams customParams; /**< Parameters for custom manipulation, relevant if 'custom' = TRUE */
+
+ bool dontParseAfterManip;/**< TRUE to de-activate the parser after the manipulation defined in this node.
+ Restrictions:
+ 1. MUST be set if the next engine after the CC is not another CC node
+ (but rather Policer or Keygen), and this is the last (no h_NextManip) in a chain
+ of manipulation nodes. This includes single nodes (i.e. no h_NextManip and
+ also never pointed as h_NextManip of other manipulation nodes)
+ 2. MUST be set if the next engine after the CC is another CC node, and
+ this is NOT the last manipulation node (i.e. it has h_NextManip).*/
+} t_FmPcdManipHdrParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining fragmentation manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragParams {
+ e_NetHeaderType hdr; /**< Header selection */
+ union {
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipFragCapwapParams capwapFrag; /**< Parameters for defining CAPWAP fragmentation,
+ relevant if 'hdr' = HEADER_TYPE_CAPWAP */
+#endif /* (DPAA_VERSION >= 11) */
+ t_FmPcdManipFragIpParams ipFrag; /**< Parameters for defining IP fragmentation,
+ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
+ } u;
+} t_FmPcdManipFragParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining reassembly manipulation
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemParams {
+ e_NetHeaderType hdr; /**< Header selection */
+ union {
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipReassemCapwapParams capwapReassem; /**< Parameters for defining CAPWAP reassembly,
+ relevant if 'hdr' = HEADER_TYPE_CAPWAP */
+#endif /* (DPAA_VERSION >= 11) */
+
+ t_FmPcdManipReassemIpParams ipReassem; /**< Parameters for defining IP reassembly,
+ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */
+ } u;
+} t_FmPcdManipReassemParams;
+
+/**************************************************************************//**
+ @Description Parameters for defining a manipulation node
+*//***************************************************************************/
+typedef struct t_FmPcdManipParams {
+ e_FmPcdManipType type; /**< Selects type of manipulation node */
+ union{
+ t_FmPcdManipHdrParams hdr; /**< Parameters for defining header manipulation node */
+ t_FmPcdManipReassemParams reassem; /**< Parameters for defining reassembly manipulation node */
+ t_FmPcdManipFragParams frag; /**< Parameters for defining fragmentation manipulation node */
+ t_FmPcdManipSpecialOffloadParams specialOffload; /**< Parameters for defining special offload manipulation node */
+ } u;
+
+ t_Handle h_NextManip; /**< Supported for Header Manipulation only;
+ Handle to another (previously defined) manipulation node;
+ Allows concatenation of manipulation actions;
+ This parameter is optional and may be NULL. */
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+ bool fragOrReasm; /**< TRUE, if defined fragmentation/reassembly manipulation */
+ t_FmPcdManipFragOrReasmParams fragOrReasmParams; /**< Parameters for fragmentation/reassembly manipulation,
+ relevant if fragOrReasm = TRUE */
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+} t_FmPcdManipParams;
+
+/**************************************************************************//**
+ @Description Structure for retrieving IP reassembly statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemIpStats {
+ /* common counters for both IPv4 and IPv6 */
+ uint32_t timeout; /**< Counts the number of timeout occurrences */
+ uint32_t rfdPoolBusy; /**< Counts the number of failed attempts to allocate
+ a Reassembly Frame Descriptor */
+ uint32_t internalBufferBusy; /**< Counts the number of times an internal buffer busy occurred */
+ uint32_t externalBufferBusy; /**< Counts the number of times external buffer busy occurred */
+ uint32_t sgFragments; /**< Counts the number of Scatter/Gather fragments */
+ uint32_t dmaSemaphoreDepletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */
+#if (DPAA_VERSION >= 11)
+ uint32_t nonConsistentSp; /**< Counts the number of Non Consistent Storage Profile events for
+ successfully reassembled frames */
+#endif /* (DPAA_VERSION >= 11) */
+ struct {
+ uint32_t successfullyReassembled; /**< Counts the number of successfully reassembled frames */
+ uint32_t validFragments; /**< Counts the total number of valid fragments that
+ have been processed for all frames */
+ uint32_t processedFragments; /**< Counts the number of processed fragments
+ (valid and error fragments) for all frames */
+ uint32_t malformedFragments; /**< Counts the number of malformed fragments processed for all frames */
+ uint32_t discardedFragments; /**< Counts the number of fragments discarded by the reassembly process */
+ uint32_t autoLearnBusy; /**< Counts the number of times a busy condition occurs when attempting
+ to access an IP-Reassembly Automatic Learning Hash set */
+ uint32_t moreThan16Fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame
+ exceeds 16 */
+ } specificHdrStatistics[2]; /**< slot '0' is for IPv4, slot '1' is for IPv6 */
+} t_FmPcdManipReassemIpStats;
+
+/**************************************************************************//**
+ @Description Structure for retrieving IP fragmentation statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragIpStats {
+ uint32_t totalFrames; /**< Number of frames that passed through the manipulation node */
+ uint32_t fragmentedFrames; /**< Number of frames that were fragmented */
+ uint32_t generatedFragments; /**< Number of fragments that were generated */
+} t_FmPcdManipFragIpStats;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Structure for retrieving CAPWAP reassembly statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemCapwapStats {
+ uint32_t timeout; /**< Counts the number of timeout occurrences */
+ uint32_t rfdPoolBusy; /**< Counts the number of failed attempts to allocate
+ a Reassembly Frame Descriptor */
+ uint32_t internalBufferBusy; /**< Counts the number of times an internal buffer busy occurred */
+ uint32_t externalBufferBusy; /**< Counts the number of times external buffer busy occurred */
+ uint32_t sgFragments; /**< Counts the number of Scatter/Gather fragments */
+ uint32_t dmaSemaphoreDepletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */
+ uint32_t successfullyReassembled; /**< Counts the number of successfully reassembled frames */
+ uint32_t validFragments; /**< Counts the total number of valid fragments that
+ have been processed for all frames */
+ uint32_t processedFragments; /**< Counts the number of processed fragments
+ (valid and error fragments) for all frames */
+ uint32_t malformedFragments; /**< Counts the number of malformed fragments processed for all frames */
+ uint32_t autoLearnBusy; /**< Counts the number of times a busy condition occurs when attempting
+ to access an Reassembly Automatic Learning Hash set */
+ uint32_t discardedFragments; /**< Counts the number of fragments discarded by the reassembly process */
+ uint32_t moreThan16Fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame
+ exceeds 16 */
+ uint32_t exceedMaxReassemblyFrameLen;/**< ounts the number of times that a successful reassembled frame
+ length exceeds MaxReassembledFrameLength value */
+} t_FmPcdManipReassemCapwapStats;
+
+/**************************************************************************//**
+ @Description Structure for retrieving CAPWAP fragmentation statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragCapwapStats {
+ uint32_t totalFrames; /**< Number of frames that passed through the manipulation node */
+ uint32_t fragmentedFrames; /**< Number of frames that were fragmented */
+ uint32_t generatedFragments; /**< Number of fragments that were generated */
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ uint8_t sgAllocationFailure; /**< Number of allocation failure of s/g buffers */
+#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */
+} t_FmPcdManipFragCapwapStats;
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Description Structure for retrieving reassembly statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipReassemStats {
+ union {
+ t_FmPcdManipReassemIpStats ipReassem; /**< Structure for IP reassembly statistics */
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipReassemCapwapStats capwapReassem; /**< Structure for CAPWAP reassembly statistics */
+#endif /* (DPAA_VERSION >= 11) */
+ } u;
+} t_FmPcdManipReassemStats;
+
+/**************************************************************************//**
+ @Description Structure for retrieving fragmentation statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipFragStats {
+ union {
+ t_FmPcdManipFragIpStats ipFrag; /**< Structure for IP fragmentation statistics */
+#if (DPAA_VERSION >= 11)
+ t_FmPcdManipFragCapwapStats capwapFrag; /**< Structure for CAPWAP fragmentation statistics */
+#endif /* (DPAA_VERSION >= 11) */
+ } u;
+} t_FmPcdManipFragStats;
+
+/**************************************************************************//**
+ @Description Structure for selecting manipulation statistics
+*//***************************************************************************/
+typedef struct t_FmPcdManipStats {
+ union {
+ t_FmPcdManipReassemStats reassem; /**< Structure for reassembly statistics */
+ t_FmPcdManipFragStats frag; /**< Structure for fragmentation statistics */
+ } u;
+} t_FmPcdManipStats;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description Parameters for defining frame replicator group and its members
+*//***************************************************************************/
+typedef struct t_FmPcdFrmReplicGroupParams {
+ uint8_t maxNumOfEntries; /**< Maximal number of members in the group;
+ Must be at least 2. */
+ uint8_t numOfEntries; /**< Number of members in the group;
+ Must be at least 1. */
+ t_FmPcdCcNextEngineParams nextEngineParams[FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES];
+ /**< Array of members' parameters */
+} t_FmPcdFrmReplicGroupParams;
+#endif /* (DPAA_VERSION >= 11) */
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+/**************************************************************************//**
+ @Description structure for defining statistics node
+*//***************************************************************************/
+typedef struct t_FmPcdStatsParams {
+ e_FmPcdStatsType type; /**< type of statistics node */
+} t_FmPcdStatsParams;
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+/**************************************************************************//**
+ @Function FM_PCD_NetEnvCharacteristicsSet
+
+ @Description Define a set of Network Environment Characteristics.
+
+ When setting an environment it is important to understand its
+ application. It is not meant to describe the flows that will run
+ on the ports using this environment, but what the user means TO DO
+ with the PCD mechanisms in order to parse-classify-distribute those
+ frames.
+ By specifying a distinction unit, the user means it would use that option
+ for distinction between frames at either a KeyGen scheme or a coarse
+ classification action descriptor. Using interchangeable headers to define a
+ unit means that the user is indifferent to which of the interchangeable
+ headers is present in the frame, and wants the distinction to be based
+ on the presence of either one of them.
+
+ Depending on context, there are limitations to the use of environments. A
+ port using the PCD functionality is bound to an environment. Some or even
+ all ports may share an environment but also an environment per port is
+ possible. When initializing a scheme, a classification plan group (see below),
+ or a coarse classification tree, one of the initialized environments must be
+ stated and related to. When a port is bound to a scheme, a classification
+ plan group, or a coarse classification tree, it MUST be bound to the same
+ environment.
+
+ The different PCD modules, may relate (for flows definition) ONLY on
+ distinction units as defined by their environment. When initializing a
+ scheme for example, it may not choose to select IPV4 as a match for
+ recognizing flows unless it was defined in the relating environment. In
+ fact, to guide the user through the configuration of the PCD, each module's
+ characterization in terms of flows is not done using protocol names, but using
+ environment indexes.
+
+ In terms of HW implementation, the list of distinction units sets the LCV vectors
+ and later used for match vector, classification plan vectors and coarse classification
+ indexing.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_NetEnvParams A structure of parameters for the initialization of
+ the network environment.
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_NetEnvCharacteristicsDelete
+
+ @Description Deletes a set of Network Environment Characteristics.
+
+ @Param[in] h_NetEnv A handle to the Network environment.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSchemeSet
+
+ @Description Initializing or modifying and enabling a scheme for the KeyGen.
+ This routine should be called for adding or modifying a scheme.
+ When a scheme needs modifying, the API requires that it will be
+ rewritten. In such a case 'modify' should be TRUE. If the
+ routine is called for a valid scheme and 'modify' is FALSE,
+ it will return error.
+
+ @Param[in] h_FmPcd If this is a new scheme - A handle to an FM PCD Module.
+ Otherwise NULL (ignored by driver).
+ @Param[in,out] p_SchemeParams A structure of parameters for defining the scheme
+
+ @Return A handle to the initialized scheme on success; NULL code otherwise.
+ When used as "modify" (rather than for setting a new scheme),
+ p_SchemeParams->id.h_Scheme will return NULL if action fails due to scheme
+ BUSY state.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd,
+ t_FmPcdKgSchemeParams *p_SchemeParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSchemeDelete
+
+ @Description Deleting an initialized scheme.
+
+ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet()
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
+*//***************************************************************************/
+t_Error FM_PCD_KgSchemeDelete(t_Handle h_Scheme);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSchemeGetCounter
+
+ @Description Reads scheme packet counter.
+
+ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet().
+
+ @Return Counter's current value.
+
+ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
+*//***************************************************************************/
+uint32_t FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme);
+
+/**************************************************************************//**
+ @Function FM_PCD_KgSchemeSetCounter
+
+ @Description Writes scheme packet counter.
+
+ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet().
+ @Param[in] value New scheme counter value - typically '0' for
+ resetting the counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet().
+*//***************************************************************************/
+t_Error FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrProfileSet
+
+ @Description Sets a profile entry in the policer profile table.
+ The routine overrides any existing value.
+
+ @Param[in] h_FmPcd A handle to an FM PCD Module.
+ @Param[in] p_Profile A structure of parameters for defining a
+ policer profile entry.
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+ When used as "modify" (rather than for setting a new profile),
+ p_Profile->id.h_Profile will return NULL if action fails due to profile
+ BUSY state.
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_PlcrProfileSet(t_Handle h_FmPcd,
+ t_FmPcdPlcrProfileParams *p_Profile);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrProfileDelete
+
+ @Description Delete a profile entry in the policer profile table.
+ The routine set entry to invalid.
+
+ @Param[in] h_Profile A handle to the profile.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrProfileGetCounter
+
+ @Description Sets an entry in the classification plan.
+ The routine overrides any existing value.
+
+ @Param[in] h_Profile A handle to the profile.
+ @Param[in] counter Counter selector.
+
+ @Return specific counter value.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile,
+ e_FmPcdPlcrProfileCounters counter);
+
+/**************************************************************************//**
+ @Function FM_PCD_PlcrProfileSetCounter
+
+ @Description Sets an entry in the classification plan.
+ The routine overrides any existing value.
+
+ @Param[in] h_Profile A handle to the profile.
+ @Param[in] counter Counter selector.
+ @Param[in] value value to set counter with.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile,
+ e_FmPcdPlcrProfileCounters counter,
+ uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PCD_CcRootBuild
+
+ @Description This routine must be called to define a complete coarse
+ classification tree. This is the way to define coarse
+ classification to a certain flow - the KeyGen schemes
+ may point only to trees defined in this way.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_Params A structure of parameters to define the tree.
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_CcRootBuild (t_Handle h_FmPcd,
+ t_FmPcdCcTreeParams *p_Params);
+
+/**************************************************************************//**
+ @Function FM_PCD_CcRootDelete
+
+ @Description Deleting an built tree.
+
+ @Param[in] h_CcTree A handle to a CC tree.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree);
+
+/**************************************************************************//**
+ @Function FM_PCD_CcRootModifyNextEngine
+
+ @Description Modify the Next Engine Parameters in the entry of the tree.
+
+ @Param[in] h_CcTree A handle to the tree
+ @Param[in] grpId A Group index in the tree
+ @Param[in] index Entry index in the group defined by grpId
+ @Param[in] p_FmPcdCcNextEngineParams Pointer to new next engine parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_CcBuildTree().
+*//***************************************************************************/
+t_Error FM_PCD_CcRootModifyNextEngine(t_Handle h_CcTree,
+ uint8_t grpId,
+ uint8_t index,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableSet
+
+ @Description This routine should be called for each CC (coarse classification)
+ node. The whole CC tree should be built bottom up so that each
+ node points to already defined nodes.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_Param A structure of parameters defining the CC node
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_Param);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableDelete
+
+ @Description Deleting an built node.
+
+ @Param[in] h_CcNode A handle to a CC node.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableModifyMissNextEngine
+
+ @Description Modify the Next Engine Parameters of the Miss key case of the node.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet();
+ Not relevant in the case the node is of type 'INDEXED_LOOKUP'.
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableModifyMissNextEngine(t_Handle h_CcNode,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableRemoveKey
+
+ @Description Remove the key (including next engine parameters of this key)
+ defined by the index of the relevant node.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for removing
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableAddKey
+
+ @Description Add the key (including next engine parameters of this key in the
+ index defined by the keyIndex. Note that 'FM_PCD_LAST_KEY_INDEX'
+ may be used by user that don't care about the position of the
+ key in the table - in that case, the key will be automatically
+ added by the driver in the last available entry.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for adding.
+ @Param[in] keySize Key size of added key
+ @Param[in] p_KeyParams A pointer to the parameters includes
+ new key with Next Engine Parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableModifyNextEngine
+
+ @Description Modify the Next Engine Parameters in the relevant key entry of the node.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for Next Engine modifications
+ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableModifyNextEngine(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableModifyKeyAndNextEngine
+
+ @Description Modify the key and Next Engine Parameters of this key in the
+ index defined by the keyIndex.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for adding
+ @Param[in] keySize Key size of added key
+ @Param[in] p_KeyParams A pointer to the parameters includes
+ modified key and modified Next Engine Parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableModifyKey
+
+ @Description Modify the key in the index defined by the keyIndex.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for adding
+ @Param[in] keySize Key size of added key
+ @Param[in] p_Key A pointer to the new key
+ @Param[in] p_Mask A pointer to the new mask if relevant,
+ otherwise pointer to NULL
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableFindNRemoveKey
+
+ @Description Remove the key (including next engine parameters of this key)
+ defined by the key and mask. Note that this routine will search
+ the node to locate the index of the required key (& mask) to remove.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keySize Key size of the one to remove.
+ @Param[in] p_Key A pointer to the requested key to remove.
+ @Param[in] p_Mask A pointer to the mask if relevant,
+ otherwise pointer to NULL
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableFindNModifyNextEngine
+
+ @Description Modify the Next Engine Parameters in the relevant key entry of
+ the node. Note that this routine will search the node to locate
+ the index of the required key (& mask) to modify.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keySize Key size of the one to modify.
+ @Param[in] p_Key A pointer to the requested key to modify.
+ @Param[in] p_Mask A pointer to the mask if relevant,
+ otherwise pointer to NULL
+ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableFindNModifyNextEngine(t_Handle h_CcNode,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableFindNModifyKeyAndNextEngine
+
+ @Description Modify the key and Next Engine Parameters of this key in the
+ index defined by the keyIndex. Note that this routine will search
+ the node to locate the index of the required key (& mask) to modify.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keySize Key size of the one to modify.
+ @Param[in] p_Key A pointer to the requested key to modify.
+ @Param[in] p_Mask A pointer to the mask if relevant,
+ otherwise pointer to NULL
+ @Param[in] p_KeyParams A pointer to the parameters includes
+ modified key and modified Next Engine Parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine(t_Handle h_CcNode,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask,
+ t_FmPcdCcKeyParams *p_KeyParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableFindNModifyKey
+
+ @Description Modify the key in the index defined by the keyIndex. Note that
+ this routine will search the node to locate the index of the
+ required key (& mask) to modify.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keySize Key size of the one to modify.
+ @Param[in] p_Key A pointer to the requested key to modify.
+ @Param[in] p_Mask A pointer to the mask if relevant,
+ otherwise pointer to NULL
+ @Param[in] p_NewKey A pointer to the new key
+ @Param[in] p_NewMask A pointer to the new mask if relevant,
+ otherwise pointer to NULL
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this
+ node and the nodes that lead to it.
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask,
+ uint8_t *p_NewKey,
+ uint8_t *p_NewMask);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableGetKeyCounter
+
+ @Description This routine may be used to get a counter of specific key in a CC
+ Node; This counter reflects how many frames passed that were matched
+ this key.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for adding
+
+ @Return The specific key counter.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+*//***************************************************************************/
+uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableGetKeyStatistics
+
+ @Description This routine may be used to get statistics counters of specific key
+ in a CC Node.
+
+ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
+ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
+ these counters reflect how many frames passed that were matched
+ this key; The total frames count will be returned in the counter
+ of the first range (as only one frame length range was defined).
+ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
+ frame count will be separated to frame length counters, based on
+ provided frame length ranges.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keyIndex Key index for adding
+ @Param[out] p_KeyStatistics Key statistics counters
+
+ @Return The specific key statistics.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableGetKeyStatistics(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableGetMissStatistics
+
+ @Description This routine may be used to get statistics counters of miss entry
+ in a CC Node.
+
+ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
+ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
+ these counters reflect how many frames were not matched to any
+ existing key and therefore passed through the miss entry; The
+ total frames count will be returned in the counter of the
+ first range (as only one frame length range was defined).
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[out] p_MissStatistics Statistics counters for 'miss'
+
+ @Return The statistics for 'miss'.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableGetMissStatistics(t_Handle h_CcNode,
+ t_FmPcdCcKeyStatistics *p_MissStatistics);
+
+/**************************************************************************//**
+ @Function FM_PCD_MatchTableFindNGetKeyStatistics
+
+ @Description This routine may be used to get statistics counters of specific key
+ in a CC Node.
+
+ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
+ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
+ these counters reflect how many frames passed that were matched
+ this key; The total frames count will be returned in the counter
+ of the first range (as only one frame length range was defined).
+ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
+ frame count will be separated to frame length counters, based on
+ provided frame length ranges.
+ Note that this routine will search the node to locate the index
+ of the required key based on received key parameters.
+
+ @Param[in] h_CcNode A handle to the node
+ @Param[in] keySize Size of the requested key
+ @Param[in] p_Key A pointer to the requested key
+ @Param[in] p_Mask A pointer to the mask if relevant,
+ otherwise pointer to NULL
+ @Param[out] p_KeyStatistics Key statistics counters
+
+ @Return The specific key statistics.
+
+ @Cautions Allowed only following FM_PCD_MatchTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableFindNGetKeyStatistics(t_Handle h_CcNode,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ uint8_t *p_Mask,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics);
+
+/**************************************************************************//*
+ @Function FM_PCD_MatchTableGetNextEngine
+
+ @Description Gets NextEngine of the relevant keyIndex.
+
+ @Param[in] h_CcNode A handle to the node.
+ @Param[in] keyIndex keyIndex in the relevant node.
+ @Param[out] p_FmPcdCcNextEngineParams here updated nextEngine parameters for
+ the relevant keyIndex of the CC Node
+ received as parameter to this function
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableGetNextEngine(t_Handle h_CcNode,
+ uint16_t keyIndex,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//*
+ @Function FM_PCD_MatchTableGetIndexedHashBucket
+
+ @Description This routine simulates KeyGen operation on the provided key and
+ calculates to which hash bucket it will be mapped.
+
+ @Param[in] h_CcNode A handle to the node.
+ @Param[in] kgKeySize Key size as it was configured in the KG
+ scheme that leads to this hash.
+ @Param[in] p_KgKey Pointer to the key; must be like the key
+ that the KG is generated, i.e. the same
+ extraction and with mask if exist.
+ @Param[in] kgHashShift Hash-shift as it was configured in the KG
+ scheme that leads to this hash.
+ @Param[out] p_CcNodeBucketHandle Pointer to the bucket of the provided key.
+ @Param[out] p_BucketIndex Index to the bucket of the provided key
+ @Param[out] p_LastIndex Pointer to last index in the bucket of the
+ provided key.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet()
+*//***************************************************************************/
+t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode,
+ uint8_t kgKeySize,
+ uint8_t *p_KgKey,
+ uint8_t kgHashShift,
+ t_Handle *p_CcNodeBucketHandle,
+ uint8_t *p_BucketIndex,
+ uint16_t *p_LastIndex);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableSet
+
+ @Description This routine initializes a hash table structure.
+ KeyGen hash result determines the hash bucket.
+ Next, KeyGen key is compared against all keys of this
+ bucket (exact match).
+ Number of sets (number of buckets) of the hash equals to the
+ number of 1-s in 'hashResMask' in the provided parameters.
+ Number of hash table ways is then calculated by dividing
+ 'maxNumOfKeys' equally between the hash sets. This is the maximal
+ number of keys that a hash bucket may hold.
+ The hash table is initialized empty and keys may be
+ added to it following the initialization. Keys masks are not
+ supported in current hash table implementation.
+ The initialized hash table can be integrated as a node in a
+ CC tree.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_Param A structure of parameters defining the hash table
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableDelete
+
+ @Description This routine deletes the provided hash table and released all
+ its allocated resources.
+
+ @Param[in] h_HashTbl A handle to a hash table
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableAddKey
+
+ @Description This routine adds the provided key (including next engine
+ parameters of this key) to the hash table.
+ The key is added as the last key of the bucket that it is
+ mapped to.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[in] keySize Key size of added key
+ @Param[in] p_KeyParams A pointer to the parameters includes
+ new key with next engine parameters; The pointer
+ to the key mask must be NULL, as masks are not
+ supported in hash table implementation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl,
+ uint8_t keySize,
+ t_FmPcdCcKeyParams *p_KeyParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableRemoveKey
+
+ @Description This routine removes the requested key (including next engine
+ parameters of this key) from the hash table.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[in] keySize Key size of the one to remove.
+ @Param[in] p_Key A pointer to the requested key to remove.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl,
+ uint8_t keySize,
+ uint8_t *p_Key);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableModifyNextEngine
+
+ @Description This routine modifies the next engine for the provided key. The
+ key should be previously added to the hash table.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[in] keySize Key size of the key to modify.
+ @Param[in] p_Key A pointer to the requested key to modify.
+ @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine
+ parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+*//***************************************************************************/
+t_Error FM_PCD_HashTableModifyNextEngine(t_Handle h_HashTbl,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableModifyMissNextEngine
+
+ @Description This routine modifies the next engine on key match miss.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine
+ parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+ When configuring nextEngine = e_FM_PCD_CC, note that
+ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different
+ from the currently changed table.
+*//***************************************************************************/
+t_Error FM_PCD_HashTableModifyMissNextEngine(t_Handle h_HashTbl,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//*
+ @Function FM_PCD_HashTableGetMissNextEngine
+
+ @Description Gets NextEngine in case of key match miss.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[out] p_FmPcdCcNextEngineParams Next engine parameters for the specified
+ hash table.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableGetMissNextEngine(t_Handle h_HashTbl,
+ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableFindNGetKeyStatistics
+
+ @Description This routine may be used to get statistics counters of specific key
+ in a hash table.
+
+ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
+ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
+ these counters reflect how many frames passed that were matched
+ this key; The total frames count will be returned in the counter
+ of the first range (as only one frame length range was defined).
+ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total
+ frame count will be separated to frame length counters, based on
+ provided frame length ranges.
+ Note that this routine will identify the bucket of this key in
+ the hash table and will search the bucket to locate the index
+ of the required key based on received key parameters.
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[in] keySize Size of the requested key
+ @Param[in] p_Key A pointer to the requested key
+ @Param[out] p_KeyStatistics Key statistics counters
+
+ @Return The specific key statistics.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableFindNGetKeyStatistics(t_Handle h_HashTbl,
+ uint8_t keySize,
+ uint8_t *p_Key,
+ t_FmPcdCcKeyStatistics *p_KeyStatistics);
+
+/**************************************************************************//**
+ @Function FM_PCD_HashTableGetMissStatistics
+
+ @Description This routine may be used to get statistics counters of 'miss'
+ entry of the a hash table.
+
+ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and
+ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node,
+ these counters reflect how many frames were not matched to any
+ existing key and therefore passed through the miss entry;
+
+ @Param[in] h_HashTbl A handle to a hash table
+ @Param[out] p_MissStatistics Statistics counters for 'miss'
+
+ @Return The statistics for 'miss'.
+
+ @Cautions Allowed only following FM_PCD_HashTableSet().
+*//***************************************************************************/
+t_Error FM_PCD_HashTableGetMissStatistics(t_Handle h_HashTbl,
+ t_FmPcdCcKeyStatistics *p_MissStatistics);
+
+/**************************************************************************//**
+ @Function FM_PCD_ManipNodeSet
+
+ @Description This routine should be called for defining a manipulation
+ node. A manipulation node must be defined before the CC node
+ that precedes it.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_FmPcdManipParams A structure of parameters defining the manipulation
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd, t_FmPcdManipParams *p_FmPcdManipParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_ManipNodeDelete
+
+ @Description Delete an existing manipulation node.
+
+ @Param[in] h_ManipNode A handle to a manipulation node.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_ManipNodeSet().
+*//***************************************************************************/
+t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode);
+
+/**************************************************************************//**
+ @Function FM_PCD_ManipGetStatistics
+
+ @Description Retrieve the manipulation statistics.
+
+ @Param[in] h_ManipNode A handle to a manipulation node.
+ @Param[out] p_FmPcdManipStats A structure for retrieving the manipulation statistics
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_ManipNodeSet().
+*//***************************************************************************/
+t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode, t_FmPcdManipStats *p_FmPcdManipStats);
+
+/**************************************************************************//**
+ @Function FM_PCD_ManipNodeReplace
+
+ @Description Change existing manipulation node to be according to new requirement.
+
+ @Param[in] h_ManipNode A handle to a manipulation node.
+ @Param[out] p_ManipParams A structure of parameters defining the change requirement
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_ManipNodeSet().
+*//***************************************************************************/
+t_Error FM_PCD_ManipNodeReplace(t_Handle h_ManipNode, t_FmPcdManipParams *p_ManipParams);
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Function FM_PCD_FrmReplicSetGroup
+
+ @Description Initialize a Frame Replicator group.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_FrmReplicGroupParam A structure of parameters for the initialization of
+ the frame replicator group.
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, t_FmPcdFrmReplicGroupParams *p_FrmReplicGroupParam);
+
+/**************************************************************************//**
+ @Function FM_PCD_FrmReplicDeleteGroup
+
+ @Description Delete a Frame Replicator group.
+
+ @Param[in] h_FrmReplicGroup A handle to the frame replicator group.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup().
+*//***************************************************************************/
+t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_FrmReplicGroup);
+
+/**************************************************************************//**
+ @Function FM_PCD_FrmReplicAddMember
+
+ @Description Add the member in the index defined by the memberIndex.
+
+ @Param[in] h_FrmReplicGroup A handle to the frame replicator group.
+ @Param[in] memberIndex member index for adding.
+ @Param[in] p_MemberParams A pointer to the new member parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
+*//***************************************************************************/
+t_Error FM_PCD_FrmReplicAddMember(t_Handle h_FrmReplicGroup,
+ uint16_t memberIndex,
+ t_FmPcdCcNextEngineParams *p_MemberParams);
+
+/**************************************************************************//**
+ @Function FM_PCD_FrmReplicRemoveMember
+
+ @Description Remove the member defined by the index from the relevant group.
+
+ @Param[in] h_FrmReplicGroup A handle to the frame replicator group.
+ @Param[in] memberIndex member index for removing.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group.
+*//***************************************************************************/
+t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_FrmReplicGroup,
+ uint16_t memberIndex);
+#endif /* (DPAA_VERSION >= 11) */
+
+#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT))
+/**************************************************************************//**
+ @Function FM_PCD_StatisticsSetNode
+
+ @Description This routine should be called for defining a statistics node.
+
+ @Param[in] h_FmPcd FM PCD module descriptor.
+ @Param[in] p_FmPcdstatsParams A structure of parameters defining the statistics
+
+ @Return A handle to the initialized object on success; NULL code otherwise.
+
+ @Cautions Allowed only following FM_PCD_Init().
+*//***************************************************************************/
+t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_FmPcdstatsParams);
+#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */
+
+/** @} */ /* end of FM_PCD_Runtime_build_grp group */
+/** @} */ /* end of FM_PCD_Runtime_grp group */
+/** @} */ /* end of FM_PCD_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#ifdef NCSW_BACKWARD_COMPATIBLE_API
+#define FM_PCD_MAX_NUM_OF_INTERCHANGABLE_HDRS FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS
+#define e_FM_PCD_MANIP_ONE_WAYS_HASH e_FM_PCD_MANIP_ONE_WAY_HASH
+#define e_FM_PCD_MANIP_TOW_WAYS_HASH e_FM_PCD_MANIP_TWO_WAYS_HASH
+
+#define e_FM_PCD_MANIP_FRAGMENT_PACKECT e_FM_PCD_MANIP_FRAGMENT_PACKET /* Feb13 */
+
+#define FM_PCD_SetNetEnvCharacteristics(_pcd, _params) \
+ FM_PCD_NetEnvCharacteristicsSet(_pcd, _params)
+#define FM_PCD_KgSetScheme(_pcd, _params) FM_PCD_KgSchemeSet(_pcd, _params)
+#define FM_PCD_CcBuildTree(_pcd, _params) FM_PCD_CcRootBuild(_pcd, _params)
+#define FM_PCD_CcSetNode(_pcd, _params) FM_PCD_MatchTableSet(_pcd, _params)
+#define FM_PCD_PlcrSetProfile(_pcd, _params) FM_PCD_PlcrProfileSet(_pcd, _params)
+#define FM_PCD_ManipSetNode(_pcd, _params) FM_PCD_ManipNodeSet(_pcd, _params)
+
+#define FM_PCD_DeleteNetEnvCharacteristics(_pcd, ...) \
+ FM_PCD_NetEnvCharacteristicsDelete(__VA_ARGS__)
+#define FM_PCD_KgDeleteScheme(_pcd, ...) \
+ FM_PCD_KgSchemeDelete(__VA_ARGS__)
+#define FM_PCD_KgGetSchemeCounter(_pcd, ...) \
+ FM_PCD_KgSchemeGetCounter(__VA_ARGS__)
+#define FM_PCD_KgSetSchemeCounter(_pcd, ...) \
+ FM_PCD_KgSchemeSetCounter(__VA_ARGS__)
+#define FM_PCD_PlcrDeleteProfile(_pcd, ...) \
+ FM_PCD_PlcrProfileDelete(__VA_ARGS__)
+#define FM_PCD_PlcrGetProfileCounter(_pcd, ...) \
+ FM_PCD_PlcrProfileGetCounter(__VA_ARGS__)
+#define FM_PCD_PlcrSetProfileCounter(_pcd, ...) \
+ FM_PCD_PlcrProfileSetCounter(__VA_ARGS__)
+#define FM_PCD_CcDeleteTree(_pcd, ...) \
+ FM_PCD_CcRootDelete(__VA_ARGS__)
+#define FM_PCD_CcTreeModifyNextEngine(_pcd, ...) \
+ FM_PCD_CcRootModifyNextEngine(__VA_ARGS__)
+#define FM_PCD_CcDeleteNode(_pcd, ...) \
+ FM_PCD_MatchTableDelete(__VA_ARGS__)
+#define FM_PCD_CcNodeModifyMissNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableModifyMissNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeRemoveKey(_pcd, ...) \
+ FM_PCD_MatchTableRemoveKey(__VA_ARGS__)
+#define FM_PCD_CcNodeAddKey(_pcd, ...) \
+ FM_PCD_MatchTableAddKey(__VA_ARGS__)
+#define FM_PCD_CcNodeModifyNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableModifyNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeModifyKeyAndNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableModifyKeyAndNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeModifyKey(_pcd, ...) \
+ FM_PCD_MatchTableModifyKey(__VA_ARGS__)
+#define FM_PCD_CcNodeFindNRemoveKey(_pcd, ...) \
+ FM_PCD_MatchTableFindNRemoveKey(__VA_ARGS__)
+#define FM_PCD_CcNodeFindNModifyNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableFindNModifyNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeFindNModifyKeyAndNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableFindNModifyKeyAndNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeFindNModifyKey(_pcd, ...) \
+ FM_PCD_MatchTableFindNModifyKey(__VA_ARGS__)
+#define FM_PCD_CcIndexedHashNodeGetBucket(_pcd, ...) \
+ FM_PCD_MatchTableGetIndexedHashBucket(__VA_ARGS__)
+#define FM_PCD_CcNodeGetNextEngine(_pcd, ...) \
+ FM_PCD_MatchTableGetNextEngine(__VA_ARGS__)
+#define FM_PCD_CcNodeGetKeyCounter(_pcd, ...) \
+ FM_PCD_MatchTableGetKeyCounter(__VA_ARGS__)
+#define FM_PCD_ManipDeleteNode(_pcd, ...) \
+ FM_PCD_ManipNodeDelete(__VA_ARGS__)
+#endif /* NCSW_BACKWARD_COMPATIBLE_API */
+
+
+#endif /* __FM_PCD_EXT */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h
new file mode 100644
index 000000000000..08a5aa59ab9d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h
@@ -0,0 +1,2608 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_port_ext.h
+
+ @Description FM-Port Application Programming Interface.
+*//***************************************************************************/
+#ifndef __FM_PORT_EXT
+#define __FM_PORT_EXT
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_ext.h"
+#include "net_ext.h"
+
+
+/**************************************************************************//**
+
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_PORT_grp FM Port
+
+ @Description FM Port API
+
+ The FM uses a general module called "port" to represent a Tx port
+ (MAC), an Rx port (MAC) or Offline Parsing port.
+ The number of ports in an FM varies between SOCs.
+ The SW driver manages these ports as sub-modules of the FM, i.e.
+ after an FM is initialized, its ports may be initialized and
+ operated upon.
+
+ The port is initialized aware of its type, but other functions on
+ a port may be indifferent to its type. When necessary, the driver
+ verifies coherence and returns error if applicable.
+
+ On initialization, user specifies the port type and it's index
+ (relative to the port's type) - always starting at 0.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description An enum for defining port PCD modes.
+ This enum defines the superset of PCD engines support - i.e. not
+ all engines have to be used, but all have to be enabled. The real
+ flow of a specific frame depends on the PCD configuration and the
+ frame headers and payload.
+ Note: the first engine and the first engine after the parser (if
+ exists) should be in order, the order is important as it will
+ define the flow of the port. However, as for the rest engines
+ (the ones that follows), the order is not important anymore as
+ it is defined by the PCD graph itself.
+*//***************************************************************************/
+typedef enum e_FmPortPcdSupport {
+ e_FM_PORT_PCD_SUPPORT_NONE = 0 /**< BMI to BMI, PCD is not used */
+ , e_FM_PORT_PCD_SUPPORT_PRS_ONLY /**< Use only Parser */
+ , e_FM_PORT_PCD_SUPPORT_PLCR_ONLY /**< Use only Policer */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR /**< Use Parser and Policer */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG /**< Use Parser and Keygen */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC /**< Use Parser, Keygen and Coarse Classification */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR
+ /**< Use all PCD engines */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR /**< Use Parser, Keygen and Policer */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC /**< Use Parser and Coarse Classification */
+ , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR /**< Use Parser and Coarse Classification and Policer */
+ , e_FM_PORT_PCD_SUPPORT_CC_ONLY /**< Use only Coarse Classification */
+#ifdef FM_CAPWAP_SUPPORT
+ , e_FM_PORT_PCD_SUPPORT_CC_AND_KG /**< Use Coarse Classification,and Keygen */
+ , e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR /**< Use Coarse Classification, Keygen and Policer */
+#endif /* FM_CAPWAP_SUPPORT */
+} e_FmPortPcdSupport;
+
+/**************************************************************************//**
+ @Description Port interrupts
+*//***************************************************************************/
+typedef enum e_FmPortExceptions {
+ e_FM_PORT_EXCEPTION_IM_BUSY /**< Independent-Mode Rx-BUSY */
+} e_FmPortExceptions;
+
+
+/**************************************************************************//**
+ @Collection General FM Port defines
+*//***************************************************************************/
+#define FM_PORT_PRS_RESULT_NUM_OF_WORDS 8 /**< Number of 4 bytes words in parser result */
+/* @} */
+
+/**************************************************************************//**
+ @Collection FM Frame error
+*//***************************************************************************/
+typedef uint32_t fmPortFrameErrSelect_t; /**< typedef for defining Frame Descriptor errors */
+
+#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT FM_FD_ERR_UNSUPPORTED_FORMAT /**< Not for Rx-Port! Unsupported Format */
+#define FM_PORT_FRM_ERR_LENGTH FM_FD_ERR_LENGTH /**< Not for Rx-Port! Length Error */
+#define FM_PORT_FRM_ERR_DMA FM_FD_ERR_DMA /**< DMA Data error */
+#define FM_PORT_FRM_ERR_NON_FM FM_FD_RX_STATUS_ERR_NON_FM /**< non Frame-Manager error; probably come from SEC that
+ was chained to FM */
+
+#define FM_PORT_FRM_ERR_IPRE (FM_FD_ERR_IPR & ~FM_FD_IPR) /**< IPR error */
+#define FM_PORT_FRM_ERR_IPR_NCSP (FM_FD_ERR_IPR_NCSP & ~FM_FD_IPR) /**< IPR non-consistent-sp */
+
+#define FM_PORT_FRM_ERR_IPFE 0 /**< Obsolete; will be removed in the future */
+
+#ifdef FM_CAPWAP_SUPPORT
+#define FM_PORT_FRM_ERR_CRE FM_FD_ERR_CRE
+#define FM_PORT_FRM_ERR_CHE FM_FD_ERR_CHE
+#endif /* FM_CAPWAP_SUPPORT */
+
+#define FM_PORT_FRM_ERR_PHYSICAL FM_FD_ERR_PHYSICAL /**< Rx FIFO overflow, FCS error, code error, running disparity
+ error (SGMII and TBI modes), FIFO parity error. PHY
+ Sequence error, PHY error control character detected. */
+#define FM_PORT_FRM_ERR_SIZE FM_FD_ERR_SIZE /**< Frame too long OR Frame size exceeds max_length_frame */
+#define FM_PORT_FRM_ERR_CLS_DISCARD FM_FD_ERR_CLS_DISCARD /**< indicates a classifier "drop" operation */
+#define FM_PORT_FRM_ERR_EXTRACTION FM_FD_ERR_EXTRACTION /**< Extract Out of Frame */
+#define FM_PORT_FRM_ERR_NO_SCHEME FM_FD_ERR_NO_SCHEME /**< No Scheme Selected */
+#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW FM_FD_ERR_KEYSIZE_OVERFLOW /**< Keysize Overflow */
+#define FM_PORT_FRM_ERR_COLOR_RED FM_FD_ERR_COLOR_RED /**< Frame color is red */
+#define FM_PORT_FRM_ERR_COLOR_YELLOW FM_FD_ERR_COLOR_YELLOW /**< Frame color is yellow */
+#define FM_PORT_FRM_ERR_ILL_PLCR FM_FD_ERR_ILL_PLCR /**< Illegal Policer Profile selected */
+#define FM_PORT_FRM_ERR_PLCR_FRAME_LEN FM_FD_ERR_PLCR_FRAME_LEN /**< Policer frame length error */
+#define FM_PORT_FRM_ERR_PRS_TIMEOUT FM_FD_ERR_PRS_TIMEOUT /**< Parser Time out Exceed */
+#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT FM_FD_ERR_PRS_ILL_INSTRUCT /**< Invalid Soft Parser instruction */
+#define FM_PORT_FRM_ERR_PRS_HDR_ERR FM_FD_ERR_PRS_HDR_ERR /**< Header error was identified during parsing */
+#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED FM_FD_ERR_BLOCK_LIMIT_EXCEEDED /**< Frame parsed beyind 256 first bytes */
+#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001 /**< FPM Frame Processing Timeout Exceeded */
+/* @} */
+
+
+
+/**************************************************************************//**
+ @Group FM_PORT_init_grp FM Port Initialization Unit
+
+ @Description FM Port Initialization Unit
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] exception - The exception.
+ *//***************************************************************************/
+typedef void (t_FmPortExceptionCallback) (t_Handle h_App, e_FmPortExceptions exception);
+
+/**************************************************************************//**
+ @Description User callback function called by driver with received data.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_App Application's handle originally specified to
+ the API Config function
+ @Param[in] p_Data A pointer to data received
+ @Param[in] length length of received data
+ @Param[in] status receive status and errors
+ @Param[in] position position of buffer in frame
+ @Param[in] h_BufContext A handle of the user acossiated with this buffer
+
+ @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx
+ operation for all ready data.
+ @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation.
+*//***************************************************************************/
+typedef e_RxStoreResponse (t_FmPortImRxStoreCallback) (t_Handle h_App,
+ uint8_t *p_Data,
+ uint16_t length,
+ uint16_t status,
+ uint8_t position,
+ t_Handle h_BufContext);
+
+/**************************************************************************//**
+ @Description User callback function called by driver when transmit completed.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_App Application's handle originally specified to
+ the API Config function
+ @Param[in] p_Data A pointer to data received
+ @Param[in] status transmit status and errors
+ @Param[in] lastBuffer is last buffer in frame
+ @Param[in] h_BufContext A handle of the user acossiated with this buffer
+ *//***************************************************************************/
+typedef void (t_FmPortImTxConfCallback) (t_Handle h_App,
+ uint8_t *p_Data,
+ uint16_t status,
+ t_Handle h_BufContext);
+
+/**************************************************************************//**
+ @Description A structure for additional Rx port parameters
+*//***************************************************************************/
+typedef struct t_FmPortRxParams {
+ uint32_t errFqid; /**< Error Queue Id. */
+ uint32_t dfltFqid; /**< Default Queue Id. */
+ uint16_t liodnOffset; /**< Port's LIODN offset. */
+ t_FmExtPools extBufPools; /**< Which external buffer pools are used
+ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. */
+} t_FmPortRxParams;
+
+/**************************************************************************//**
+ @Description A structure for additional non-Rx port parameters
+*//***************************************************************************/
+typedef struct t_FmPortNonRxParams {
+ uint32_t errFqid; /**< Error Queue Id. */
+ uint32_t dfltFqid; /**< For Tx - Default Confirmation queue,
+ 0 means no Tx confirmation for processed
+ frames. For OP port - default Rx queue. */
+ uint32_t qmChannel; /**< QM-channel dedicated to this port; will be used
+ by the FM for dequeue. */
+} t_FmPortNonRxParams;
+
+/**************************************************************************//**
+ @Description A structure for additional Rx port parameters
+*//***************************************************************************/
+typedef struct t_FmPortImRxTxParams {
+ t_Handle h_FmMuram; /**< A handle of the FM-MURAM partition */
+ uint16_t liodnOffset; /**< For Rx ports only. Port's LIODN Offset. */
+ uint8_t dataMemId; /**< Memory partition ID for data buffers */
+ uint32_t dataMemAttributes; /**< Memory attributes for data buffers */
+ t_BufferPoolInfo rxPoolParams; /**< For Rx ports only. */
+ t_FmPortImRxStoreCallback *f_RxStore; /**< For Rx ports only. */
+ t_FmPortImTxConfCallback *f_TxConf; /**< For Tx ports only. */
+} t_FmPortImRxTxParams;
+
+/**************************************************************************//**
+ @Description A union for additional parameters depending on port type
+*//***************************************************************************/
+typedef union u_FmPortSpecificParams {
+ t_FmPortImRxTxParams imRxTxParams; /**< Rx/Tx Independent-Mode port parameter structure */
+ t_FmPortRxParams rxParams; /**< Rx port parameters structure */
+ t_FmPortNonRxParams nonRxParams; /**< Non-Rx port parameters structure */
+} u_FmPortSpecificParams;
+
+/**************************************************************************//**
+ @Description A structure representing FM initialization parameters
+*//***************************************************************************/
+typedef struct t_FmPortParams {
+ uintptr_t baseAddr; /**< Virtual Address of memory mapped FM Port registers.*/
+ t_Handle h_Fm; /**< A handle to the FM object this port related to */
+ e_FmPortType portType; /**< Port type */
+ uint8_t portId; /**< Port Id - relative to type;
+ NOTE: When configuring Offline Parsing port for
+ FMANv3 devices (DPAA_VERSION 11 and higher),
+ it is highly recommended NOT to use portId=0 due to lack
+ of HW resources on portId=0. */
+ bool independentModeEnable;
+ /**< This port is Independent-Mode - Used for Rx/Tx ports only! */
+ uint16_t liodnBase; /**< Irrelevant for P4080 rev 1. LIODN base for this port, to be
+ used together with LIODN offset. */
+ u_FmPortSpecificParams specificParams; /**< Additional parameters depending on port
+ type. */
+
+ t_FmPortExceptionCallback *f_Exception; /**< Relevant for IM only Callback routine to be called on BUSY exception */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+} t_FmPortParams;
+
+
+/**************************************************************************//**
+ @Function FM_PORT_Config
+
+ @Description Creates a descriptor for the FM PORT module.
+
+ The routine returns a handle (descriptor) to the FM PORT object.
+ This descriptor must be passed as first parameter to all other
+ FM PORT function calls.
+
+ No actual initialization or configuration of FM hardware is
+ done by this routine.
+
+ @Param[in] p_FmPortParams - Pointer to data structure of parameters
+
+ @Retval Handle to FM object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams);
+
+/**************************************************************************//**
+ @Function FM_PORT_Init
+
+ @Description Initializes the FM PORT module by defining the software structure
+ and configuring the hardware registers.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PORT_Init(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_Free
+
+ @Description Frees all resources that were assigned to FM PORT module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PORT_Free(t_Handle h_FmPort);
+
+
+/**************************************************************************//**
+ @Group FM_PORT_advanced_init_grp FM Port Advanced Configuration Unit
+
+ @Description Configuration functions used to change default values.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description enum for defining QM frame dequeue
+*//***************************************************************************/
+typedef enum e_FmPortDeqType {
+ e_FM_PORT_DEQ_TYPE1, /**< Dequeue from the SP channel - with priority precedence,
+ and Intra-Class Scheduling respected. */
+ e_FM_PORT_DEQ_TYPE2, /**< Dequeue from the SP channel - with active FQ precedence,
+ and Intra-Class Scheduling respected. */
+ e_FM_PORT_DEQ_TYPE3 /**< Dequeue from the SP channel - with active FQ precedence,
+ and override Intra-Class Scheduling */
+} e_FmPortDeqType;
+
+/**************************************************************************//**
+ @Description enum for defining QM frame dequeue
+*//***************************************************************************/
+typedef enum e_FmPortDeqPrefetchOption {
+ e_FM_PORT_DEQ_NO_PREFETCH, /**< QMI preforms a dequeue action for a single frame
+ only when a dedicated portID Tnum is waiting. */
+ e_FM_PORT_DEQ_PARTIAL_PREFETCH, /**< QMI preforms a dequeue action for 3 frames when
+ one dedicated portId tnum is waiting. */
+ e_FM_PORT_DEQ_FULL_PREFETCH /**< QMI preforms a dequeue action for 3 frames when
+ no dedicated portId tnums are waiting. */
+
+} e_FmPortDeqPrefetchOption;
+
+/**************************************************************************//**
+ @Description enum for defining port default color
+*//***************************************************************************/
+typedef enum e_FmPortColor {
+ e_FM_PORT_COLOR_GREEN, /**< Default port color is green */
+ e_FM_PORT_COLOR_YELLOW, /**< Default port color is yellow */
+ e_FM_PORT_COLOR_RED, /**< Default port color is red */
+ e_FM_PORT_COLOR_OVERRIDE /**< Ignore color */
+} e_FmPortColor;
+
+/**************************************************************************//**
+ @Description A structure for defining Dual Tx rate limiting scale
+*//***************************************************************************/
+typedef enum e_FmPortDualRateLimiterScaleDown {
+ e_FM_PORT_DUAL_RATE_LIMITER_NONE = 0, /**< Use only single rate limiter */
+ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, /**< Divide high rate limiter by 2 */
+ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, /**< Divide high rate limiter by 4 */
+ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 /**< Divide high rate limiter by 8 */
+} e_FmPortDualRateLimiterScaleDown;
+
+
+/**************************************************************************//**
+ @Description A structure for defining FM port resources
+*//***************************************************************************/
+typedef struct t_FmPortRsrc {
+ uint32_t num; /**< Committed required resource */
+ uint32_t extra; /**< Extra (not committed) required resource */
+} t_FmPortRsrc;
+
+/**************************************************************************//**
+ @Description A structure for defining observed pool depletion
+*//***************************************************************************/
+typedef struct t_FmPortObservedBufPoolDepletion {
+ t_FmBufPoolDepletion poolDepletionParams;/**< parameters to define pool depletion */
+ t_FmExtPools poolsParams; /**< Which external buffer pools are observed
+ (up to FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS),
+ and their sizes. */
+} t_FmPortObservedBufPoolDepletion;
+
+/**************************************************************************//**
+ @Description A structure for defining Tx rate limiting
+*//***************************************************************************/
+typedef struct t_FmPortRateLimit {
+ uint16_t maxBurstSize; /**< in KBytes for Tx ports, in frames
+ for OP ports. (note that
+ for early chips burst size is
+ rounded up to a multiply of 1000 frames).*/
+ uint32_t rateLimit; /**< in Kb/sec for Tx ports, in frame/sec for
+ OP ports. Rate limit refers to
+ data rate (rather than line rate). */
+ e_FmPortDualRateLimiterScaleDown rateLimitDivider; /**< For OP ports only. Not-valid
+ for some earlier chip revisions */
+} t_FmPortRateLimit;
+
+/**************************************************************************//**
+ @Description A structure for defining the parameters of
+ the Rx port performance counters
+*//***************************************************************************/
+typedef struct t_FmPortPerformanceCnt {
+ uint8_t taskCompVal; /**< Task compare value */
+ uint8_t queueCompVal; /**< Rx queue/Tx confirm queue compare
+ value (unused for H/O) */
+ uint8_t dmaCompVal; /**< Dma compare value */
+ uint32_t fifoCompVal; /**< Fifo compare value (in bytes) */
+} t_FmPortPerformanceCnt;
+
+
+/**************************************************************************//**
+ @Description A structure for defining the sizes of the Deep Sleep
+ the Auto Response tables
+*//***************************************************************************/
+typedef struct t_FmPortDsarTablesSizes
+{
+ uint16_t maxNumOfArpEntries;
+ uint16_t maxNumOfEchoIpv4Entries;
+ uint16_t maxNumOfNdpEntries;
+ uint16_t maxNumOfEchoIpv6Entries;
+ uint16_t maxNumOfSnmpIPV4Entries;
+ uint16_t maxNumOfSnmpIPV6Entries;
+ uint16_t maxNumOfSnmpOidEntries;
+ uint16_t maxNumOfSnmpOidChar; /* total amount of character needed for the snmp table */
+
+ uint16_t maxNumOfIpProtFiltering;
+ uint16_t maxNumOfTcpPortFiltering;
+ uint16_t maxNumOfUdpPortFiltering;
+} t_FmPortDsarTablesSizes;
+
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDsarSupport
+
+ @Description This function will allocate the amount of MURAM needed for
+ this max number of entries for Deep Sleep Auto Response.
+ it will calculate all needed MURAM for autoresponse including
+ necesary common stuff.
+
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] params A pointer to a structure containing the maximum
+ sizes of the auto response tables
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, t_FmPortDsarTablesSizes *params);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigNumOfOpenDmas
+
+ @Description Calling this routine changes the max number of open DMA's
+ available for this port. It changes this parameter in the
+ internal driver data base from its default configuration
+ [OP: 1]
+ [1G-RX, 1G-TX: 1 (+1)]
+ [10G-RX, 10G-TX: 8 (+8)]
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_OpenDmas A pointer to a structure of parameters defining
+ the open DMA allocation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigNumOfTasks
+
+ @Description Calling this routine changes the max number of tasks
+ available for this port. It changes this parameter in the
+ internal driver data base from its default configuration
+ [OP: 1]
+ [1G-RX, 1G-TX: 3 (+2)]
+ [10G-RX, 10G-TX: 16 (+8)]
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_NumOfTasks A pointer to a structure of parameters defining
+ the tasks allocation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigSizeOfFifo
+
+ @Description Calling this routine changes the max FIFO size configured for this port.
+
+ This function changes the internal driver data base from its
+ default configuration. Please refer to the driver's User Guide for
+ information on default FIFO sizes in the various devices.
+ [OP: 2KB]
+ [1G-RX, 1G-TX: 11KB]
+ [10G-RX, 10G-TX: 12KB]
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_SizeOfFifo A pointer to a structure of parameters defining
+ the FIFO allocation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDeqHighPriority
+
+ @Description Calling this routine changes the dequeue priority in the
+ internal driver data base from its default configuration
+ 1G: [DEFAULT_PORT_deqHighPriority_1G]
+ 10G: [DEFAULT_PORT_deqHighPriority_10G]
+
+ May be used for Non-Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] highPri TRUE to select high priority, FALSE for normal operation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDeqType
+
+ @Description Calling this routine changes the dequeue type parameter in the
+ internal driver data base from its default configuration
+ [DEFAULT_PORT_deqType].
+
+ May be used for Non-Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] deqType According to QM definition.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDeqPrefetchOption
+
+ @Description Calling this routine changes the dequeue prefetch option parameter in the
+ internal driver data base from its default configuration
+ [DEFAULT_PORT_deqPrefetchOption]
+ Note: Available for some chips only
+
+ May be used for Non-Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] deqPrefetchOption New option
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDeqPrefetchOption(t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDeqByteCnt
+
+ @Description Calling this routine changes the dequeue byte count parameter in
+ the internal driver data base from its default configuration
+ 1G:[DEFAULT_PORT_deqByteCnt_1G].
+ 10G:[DEFAULT_PORT_deqByteCnt_10G].
+
+ May be used for Non-Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] deqByteCnt New byte count
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigBufferPrefixContent
+
+ @Description Defines the structure, size and content of the application buffer.
+ The prefix will
+ In Tx ports, if 'passPrsResult', the application
+ should set a value to their offsets in the prefix of
+ the FM will save the first 'privDataSize', than,
+ depending on 'passPrsResult' and 'passTimeStamp', copy parse result
+ and timeStamp, and the packet itself (in this order), to the
+ application buffer, and to offset.
+ Calling this routine changes the buffer margins definitions
+ in the internal driver data base from its default
+ configuration: Data size: [DEFAULT_PORT_bufferPrefixContent_privDataSize]
+ Pass Parser result: [DEFAULT_PORT_bufferPrefixContent_passPrsResult].
+ Pass timestamp: [DEFAULT_PORT_bufferPrefixContent_passTimeStamp].
+
+ May be used for all ports
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in,out] p_FmBufferPrefixContent A structure of parameters describing the
+ structure of the buffer.
+ Out parameter: Start margin - offset
+ of data from start of external buffer.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigBufferPrefixContent(t_Handle h_FmPort,
+ t_FmBufferPrefixContent *p_FmBufferPrefixContent);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigCheksumLastBytesIgnore
+
+ @Description Calling this routine changes the number of checksum bytes to ignore
+ parameter in the internal driver data base from its default configuration
+ [DEFAULT_PORT_cheksumLastBytesIgnore]
+
+ May be used by Tx & Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] cheksumLastBytesIgnore New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, uint8_t cheksumLastBytesIgnore);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigCutBytesFromEnd
+
+ @Description Calling this routine changes the number of bytes to cut from a
+ frame's end parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_cutBytesFromEnd]
+ Note that if the result of (frame length before chop - cutBytesFromEnd) is
+ less than 14 bytes, the chop operation is not executed.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] cutBytesFromEnd New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, uint8_t cutBytesFromEnd);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigPoolDepletion
+
+ @Description Calling this routine enables pause frame generation depending on the
+ depletion status of BM pools. It also defines the conditions to activate
+ this functionality. By default, this functionality is disabled.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_BufPoolDepletion A structure of pool depletion parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, t_FmBufPoolDepletion *p_BufPoolDepletion);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigObservedPoolDepletion
+
+ @Description Calling this routine enables a mechanism to stop port enqueue
+ depending on the depletion status of selected BM pools.
+ It also defines the conditions to activate
+ this functionality. By default, this functionality is disabled.
+
+ Note: Available for some chips only
+
+ May be used for OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmPortObservedBufPoolDepletion A structure of parameters for pool depletion.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigObservedPoolDepletion(t_Handle h_FmPort,
+ t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigExtBufPools
+
+ @Description This routine should be called for OP ports
+ that internally use BM buffer pools. In such cases, e.g. for fragmentation and
+ re-assembly, the FM needs new BM buffers. By calling this routine the user
+ specifies the BM buffer pools that should be used.
+
+ Note: Available for some chips only
+
+ May be used for OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmExtPools A structure of parameters for the external pools.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigBackupPools
+
+ @Description Calling this routine allows the configuration of some of the BM pools
+ defined for this port as backup pools.
+ A pool configured to be a backup pool will be used only if all other
+ enabled non-backup pools are depleted.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmPortBackupBmPools An array of pool id's. All pools specified here will
+ be defined as backup pools.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, t_FmBackupBmPools *p_FmPortBackupBmPools);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigFrmDiscardOverride
+
+ @Description Calling this routine changes the error frames destination parameter
+ in the internal driver data base from its default configuration:
+ override = [DEFAULT_PORT_frmDiscardOverride]
+
+ May be used for Rx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] override TRUE to override discarding of error frames and
+ enqueueing them to error queue.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigErrorsToDiscard
+
+ @Description Calling this routine changes the behaviour on error parameter
+ in the internal driver data base from its default configuration:
+ [DEFAULT_PORT_errorsToDiscard].
+ If a requested error was previously defined as "ErrorsToEnqueue" it's
+ definition will change and the frame will be discarded.
+ Errors that were not defined either as "ErrorsToEnqueue" nor as
+ "ErrorsToDiscard", will be forwarded to CPU.
+
+ May be used for Rx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] errs A list of errors to discard
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, fmPortFrameErrSelect_t errs);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDmaSwapData
+
+ @Description Calling this routine changes the DMA swap data aparameter
+ in the internal driver data base from its default
+ configuration [DEFAULT_PORT_dmaSwapData]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] swapData New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDmaIcCacheAttr
+
+ @Description Calling this routine changes the internal context cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_dmaIntContextCacheAttr]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] intContextCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, e_FmDmaCacheOption intContextCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDmaHdrAttr
+
+ @Description Calling this routine changes the header cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_dmaHeaderCacheAttr]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] headerCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, e_FmDmaCacheOption headerCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDmaScatterGatherAttr
+
+ @Description Calling this routine changes the scatter gather cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_dmaScatterGatherCacheAttr]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] scatterGatherCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDmaScatterGatherAttr(t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDmaWriteOptimize
+
+ @Description Calling this routine changes the write optimization
+ parameter in the internal driver data base
+ from its default configuration: By default optimize = [DEFAULT_PORT_dmaWriteOptimize].
+ Note:
+
+ 1. For head optimization, data alignment must be >= 16 (supported by default).
+
+ 3. For tail optimization, note that the optimization is performed by extending the write transaction
+ of the frame payload at the tail as needed to achieve optimal bus transfers, so that the last write
+ is extended to be on 16/64 bytes aligned block (chip dependent).
+
+ Relevant for non-Tx port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] optimize TRUE to enable optimization, FALSE for normal operation
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigNoScatherGather
+
+ @Description Calling this routine changes the noScatherGather parameter in internal driver data base
+ from its default configuration.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] noScatherGather (TRUE - frame is discarded if can not be stored in single buffer,
+ FALSE - frame can be stored in scatter gather (S/G) format).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDfltColor
+
+ @Description Calling this routine changes the internal default color parameter
+ in the internal driver data base
+ from its default configuration [DEFAULT_PORT_color]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] color New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigSyncReq
+
+ @Description Calling this routine changes the synchronization attribute parameter
+ in the internal driver data base from its default configuration:
+ syncReq = [DEFAULT_PORT_syncReq]
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] syncReq TRUE to request synchronization, FALSE otherwize.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigForwardReuseIntContext
+
+ @Description This routine is relevant for Rx ports that are routed to OP port.
+ It changes the internal context reuse option in the internal
+ driver data base from its default configuration:
+ reuse = [DEFAULT_PORT_forwardIntContextReuse]
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] reuse TRUE to reuse internal context on frames
+ forwarded to OP port.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, bool reuse);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigDontReleaseTxBufToBM
+
+ @Description This routine should be called if no Tx confirmation
+ is done, and yet buffers should not be released to the BM.
+ Normally, buffers are returned using the Tx confirmation
+ process. When Tx confirmation is not used (defFqid=0),
+ buffers are typically released to the BM. This routine
+ may be called to avoid this behavior and not release the
+ buffers.
+
+ May be used for Tx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigIMMaxRxBufLength
+
+ @Description Changes the maximum receive buffer length from its default
+ configuration: Closest rounded down power of 2 value of the
+ data buffer size.
+
+ The maximum receive buffer length directly affects the structure
+ of received frames (single- or multi-buffered) and the performance
+ of both the FM and the driver.
+
+ The selection between single- or multi-buffered frames should be
+ done according to the characteristics of the specific application.
+ The recommended mode is to use a single data buffer per packet,
+ as this mode provides the best performance. However, the user can
+ select to use multiple data buffers per packet.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] newVal Maximum receive buffer length (in bytes).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+ This routine is to be used only if Independent-Mode is enabled.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigIMRxBdRingLength
+
+ @Description Changes the receive BD ring length from its default
+ configuration:[DEFAULT_PORT_rxBdRingLength]
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] newVal The desired BD ring length.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+ This routine is to be used only if Independent-Mode is enabled.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigIMTxBdRingLength
+
+ @Description Changes the transmit BD ring length from its default
+ configuration:[DEFAULT_PORT_txBdRingLength]
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] newVal The desired BD ring length.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+ This routine is to be used only if Independent-Mode is enabled.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigIMFmanCtrlExternalStructsMemory
+
+ @Description Configures memory partition and attributes for FMan-Controller
+ data structures (e.g. BD rings).
+ Calling this routine changes the internal driver data base
+ from its default configuration
+ [DEFAULT_PORT_ImfwExtStructsMemId, DEFAULT_PORT_ImfwExtStructsMemAttr].
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] memId Memory partition ID.
+ @Param[in] memAttributes Memory attributes mask (a combination of MEMORY_ATTR_x flags).
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort,
+ uint8_t memId,
+ uint32_t memAttributes);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigIMPolling
+
+ @Description Changes the Rx flow from interrupt driven (default) to polling.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+ This routine is to be used only if Independent-Mode is enabled.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_ConfigMaxFrameLength
+
+ @Description Changes the definition of the max size of frame that should be
+ transmitted/received on this port from its default value [DEFAULT_PORT_maxFrameLength].
+ This parameter is used for confirmation of the minimum Fifo
+ size calculations and only for Tx ports or ports working in
+ independent mode. This should be larger than the maximum possible
+ MTU that will be used for this port (i.e. its MAC).
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] length Max size of frame
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+ This routine is to be used only if Independent-Mode is enabled.
+*//***************************************************************************/
+t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length);
+
+/**************************************************************************//*
+ @Function FM_PORT_ConfigTxFifoMinFillLevel
+
+ @Description Calling this routine changes the fifo minimum
+ fill level parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_txFifoMinFillLevel]
+
+ May be used for Tx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] minFillLevel New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, uint32_t minFillLevel);
+
+/**************************************************************************//*
+ @Function FM_PORT_ConfigFifoDeqPipelineDepth
+
+ @Description Calling this routine changes the fifo dequeue
+ pipeline depth parameter in the internal driver data base
+
+ from its default configuration: 1G ports: [DEFAULT_PORT_fifoDeqPipelineDepth_1G],
+ 10G port: [DEFAULT_PORT_fifoDeqPipelineDepth_10G],
+ OP port: [DEFAULT_PORT_fifoDeqPipelineDepth_OH]
+
+ May be used for Tx/OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] deqPipelineDepth New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, uint8_t deqPipelineDepth);
+
+/**************************************************************************//*
+ @Function FM_PORT_ConfigTxFifoLowComfLevel
+
+ @Description Calling this routine changes the fifo low comfort level
+ parameter in internal driver data base
+ from its default configuration [DEFAULT_PORT_txFifoLowComfLevel]
+
+ May be used for Tx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] fifoLowComfLevel New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, uint32_t fifoLowComfLevel);
+
+/**************************************************************************//*
+ @Function FM_PORT_ConfigRxFifoThreshold
+
+ @Description Calling this routine changes the threshold of the FIFO
+ fill level parameter in the internal driver data base
+ from its default configuration [DEFAULT_PORT_rxFifoThreshold]
+
+ If the total number of buffers which are
+ currently in use and associated with the
+ specific RX port exceed this threshold, the
+ BMI will signal the MAC to send a pause frame
+ over the link.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] fifoThreshold New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold);
+
+/**************************************************************************//*
+ @Function FM_PORT_ConfigRxFifoPriElevationLevel
+
+ @Description Calling this routine changes the priority elevation level
+ parameter in the internal driver data base from its default
+ configuration [DEFAULT_PORT_rxFifoPriElevationLevel]
+
+ If the total number of buffers which are currently in use and
+ associated with the specific RX port exceed the amount specified
+ in priElevationLevel, BMI will signal the main FM's DMA to
+ elevate the FM priority on the system bus.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] priElevationLevel New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, uint32_t priElevationLevel);
+
+#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+/**************************************************************************//*
+ @Function FM_PORT_ConfigBCBWorkaround
+
+ @Description Configures BCB errata workaround.
+
+ When BCB errata is applicable, the workaround is always
+ performed by FM Controller. Thus, this functions doesn't
+ actually enable errata workaround but rather allows driver
+ to perform adjustments required due to errata workaround
+ execution in FM controller.
+
+ Applying BCB workaround also configures FM_PORT_FRM_ERR_PHYSICAL
+ errors to be discarded. Thus FM_PORT_FRM_ERR_PHYSICAL can't be
+ set by FM_PORT_SetErrorsRoute() function.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort);
+#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//*
+ @Function FM_PORT_ConfigInternalBuffOffset
+
+ @Description Configures internal buffer offset.
+
+ May be used for Rx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] val New value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ConfigInternalBuffOffset(t_Handle h_FmPort, uint8_t val);
+#endif /* (DPAA_VERSION >= 11) */
+
+/** @} */ /* end of FM_PORT_advanced_init_grp group */
+/** @} */ /* end of FM_PORT_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_PORT_runtime_control_grp FM Port Runtime Control Unit
+
+ @Description FM Port Runtime control unit API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description enum for defining FM Port counters
+*//***************************************************************************/
+typedef enum e_FmPortCounters {
+ e_FM_PORT_COUNTERS_CYCLE, /**< BMI performance counter */
+ e_FM_PORT_COUNTERS_TASK_UTIL, /**< BMI performance counter */
+ e_FM_PORT_COUNTERS_QUEUE_UTIL, /**< BMI performance counter */
+ e_FM_PORT_COUNTERS_DMA_UTIL, /**< BMI performance counter */
+ e_FM_PORT_COUNTERS_FIFO_UTIL, /**< BMI performance counter */
+ e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION, /**< BMI Rx only performance counter */
+ e_FM_PORT_COUNTERS_FRAME, /**< BMI statistics counter */
+ e_FM_PORT_COUNTERS_DISCARD_FRAME, /**< BMI statistics counter */
+ e_FM_PORT_COUNTERS_DEALLOC_BUF, /**< BMI deallocate buffer statistics counter */
+ e_FM_PORT_COUNTERS_RX_BAD_FRAME, /**< BMI Rx only statistics counter */
+ e_FM_PORT_COUNTERS_RX_LARGE_FRAME, /**< BMI Rx only statistics counter */
+ e_FM_PORT_COUNTERS_RX_FILTER_FRAME, /**< BMI Rx & OP only statistics counter */
+ e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR, /**< BMI Rx, OP & HC only statistics counter */
+ e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, /**< BMI Rx, OP & HC statistics counter */
+ e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER, /**< BMI Rx, OP & HC only statistics counter */
+ e_FM_PORT_COUNTERS_WRED_DISCARD, /**< BMI OP & HC only statistics counter */
+ e_FM_PORT_COUNTERS_LENGTH_ERR, /**< BMI non-Rx statistics counter */
+ e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, /**< BMI non-Rx statistics counter */
+ e_FM_PORT_COUNTERS_DEQ_TOTAL, /**< QMI total QM dequeues counter */
+ e_FM_PORT_COUNTERS_ENQ_TOTAL, /**< QMI total QM enqueues counter */
+ e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI counter */
+ e_FM_PORT_COUNTERS_DEQ_CONFIRM /**< QMI counter */
+} e_FmPortCounters;
+
+typedef struct t_FmPortBmiStats {
+ uint32_t cntCycle;
+ uint32_t cntTaskUtil;
+ uint32_t cntQueueUtil;
+ uint32_t cntDmaUtil;
+ uint32_t cntFifoUtil;
+ uint32_t cntRxPauseActivation;
+ uint32_t cntFrame;
+ uint32_t cntDiscardFrame;
+ uint32_t cntDeallocBuf;
+ uint32_t cntRxBadFrame;
+ uint32_t cntRxLargeFrame;
+ uint32_t cntRxFilterFrame;
+ uint32_t cntRxListDmaErr;
+ uint32_t cntRxOutOfBuffersDiscard;
+ uint32_t cntWredDiscard;
+ uint32_t cntLengthErr;
+ uint32_t cntUnsupportedFormat;
+} t_FmPortBmiStats;
+
+/**************************************************************************//**
+ @Description Structure for Port id parameters.
+ Fields commented 'IN' are passed by the port module to be used
+ by the FM module.
+ Fields commented 'OUT' will be filled by FM before returning to port.
+*//***************************************************************************/
+typedef struct t_FmPortCongestionGrps {
+ uint16_t numOfCongestionGrpsToConsider; /**< The number of required CGs
+ to define the size of the following array */
+ uint8_t congestionGrpsToConsider[FM_PORT_NUM_OF_CONGESTION_GRPS];
+ /**< An array of CG indexes;
+ Note that the size of the array should be
+ 'numOfCongestionGrpsToConsider'. */
+#if (DPAA_VERSION >= 11)
+ bool pfcPrioritiesEn[FM_PORT_NUM_OF_CONGESTION_GRPS][FM_MAX_NUM_OF_PFC_PRIORITIES];
+ /**< a matrix that represents the map between the CG ids
+ defined in 'congestionGrpsToConsider' to the priorties
+ mapping array. */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPortCongestionGrps;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response ARP Entry
+*//***************************************************************************/
+typedef struct t_FmPortDsarArpEntry
+{
+ uint32_t ipAddress;
+ uint8_t mac[6];
+ bool isVlan;
+ uint16_t vid;
+} t_FmPortDsarArpEntry;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response ARP info
+*//***************************************************************************/
+typedef struct t_FmPortDsarArpInfo
+{
+ uint8_t tableSize;
+ t_FmPortDsarArpEntry *p_AutoResTable;
+ bool enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */
+} t_FmPortDsarArpInfo;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response NDP Entry
+*//***************************************************************************/
+typedef struct t_FmPortDsarNdpEntry
+{
+ uint32_t ipAddress[4];
+ uint8_t mac[6];
+ bool isVlan;
+ uint16_t vid;
+} t_FmPortDsarNdpEntry;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response NDP info
+*//***************************************************************************/
+typedef struct t_FmPortDsarNdpInfo
+{
+ uint32_t multicastGroup;
+
+ uint8_t tableSizeAssigned;
+ t_FmPortDsarNdpEntry *p_AutoResTableAssigned; /* This list refer to solicitation IP addresses.
+ Note that all IP adresses must be from the same multicast group.
+ This will be checked and if not operation will fail. */
+ uint8_t tableSizeTmp;
+ t_FmPortDsarNdpEntry *p_AutoResTableTmp; /* This list refer to temp IP addresses.
+ Note that all temp IP adresses must be from the same multicast group.
+ This will be checked and if not operation will fail. */
+
+ bool enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */
+
+} t_FmPortDsarNdpInfo;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response ICMPV4 info
+*//***************************************************************************/
+typedef struct t_FmPortDsarEchoIpv4Info
+{
+ uint8_t tableSize;
+ t_FmPortDsarArpEntry *p_AutoResTable;
+} t_FmPortDsarEchoIpv4Info;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response ICMPV6 info
+*//***************************************************************************/
+typedef struct t_FmPortDsarEchoIpv6Info
+{
+ uint8_t tableSize;
+ t_FmPortDsarNdpEntry *p_AutoResTable;
+} t_FmPortDsarEchoIpv6Info;
+
+/**************************************************************************//**
+@Description Deep Sleep Auto Response SNMP OIDs table entry
+
+*//***************************************************************************/
+typedef struct {
+ uint16_t oidSize;
+ uint8_t *oidVal; /* only the oid string */
+ uint16_t resSize;
+ uint8_t *resVal; /* resVal will be the entire reply,
+ i.e. "Type|Length|Value" */
+} t_FmPortDsarOidsEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef struct
+{
+ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */
+ bool isVlan;
+ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+} t_FmPortDsarSnmpIpv4AddrTblEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+typedef struct
+{
+ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */
+ bool isVlan;
+ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+} t_FmPortDsarSnmpIpv6AddrTblEntry;
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP Descriptor
+
+*//***************************************************************************/
+typedef struct
+{
+ uint16_t control; /**< Control bits [0-15]. */
+ uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */
+ uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */
+ uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */
+ t_FmPortDsarSnmpIpv4AddrTblEntry *p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */
+ t_FmPortDsarSnmpIpv6AddrTblEntry *p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */
+ uint8_t *p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */
+ uint8_t *p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */
+ t_FmPortDsarOidsEntry *p_OidsTbl; /**< Pointer to OIDs table. */
+ uint32_t oidsTblSize; /**< Number of entries in OIDs table. */
+} t_FmPortDsarSnmpInfo;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response filtering Entry
+*//***************************************************************************/
+typedef struct t_FmPortDsarFilteringEntry
+{
+ uint16_t srcPort;
+ uint16_t dstPort;
+ uint16_t srcPortMask;
+ uint16_t dstPortMask;
+} t_FmPortDsarFilteringEntry;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response filtering info
+*//***************************************************************************/
+typedef struct t_FmPortDsarFilteringInfo
+{
+ /* IP protocol filtering parameters */
+ uint8_t ipProtTableSize;
+ uint8_t *p_IpProtTablePtr;
+ bool ipProtPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped,
+ hit will pass the packet to UDP/TCP filters if needed and if not
+ to the classification tree. If the classification tree will pass
+ the packet to a queue it will cause a wake interupt.
+ When FALSE it the other way around. */
+ /* UDP port filtering parameters */
+ uint8_t udpPortsTableSize;
+ t_FmPortDsarFilteringEntry *p_UdpPortsTablePtr;
+ bool udpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped,
+ hit will pass the packet to classification tree.
+ If the classification tree will pass the packet to a queue it
+ will cause a wake interupt.
+ When FALSE it the other way around. */
+ /* TCP port filtering parameters */
+ uint16_t tcpFlagsMask;
+ uint8_t tcpPortsTableSize;
+ t_FmPortDsarFilteringEntry *p_TcpPortsTablePtr;
+ bool tcpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped,
+ hit will pass the packet to classification tree.
+ If the classification tree will pass the packet to a queue it
+ will cause a wake interupt.
+ When FALSE it the other way around. */
+} t_FmPortDsarFilteringInfo;
+
+/**************************************************************************//**
+ @Description Structure for Deep Sleep Auto Response parameters
+*//***************************************************************************/
+typedef struct t_FmPortDsarParams
+{
+ t_Handle h_FmPortTx;
+ t_FmPortDsarArpInfo *p_AutoResArpInfo;
+ t_FmPortDsarEchoIpv4Info *p_AutoResEchoIpv4Info;
+ t_FmPortDsarNdpInfo *p_AutoResNdpInfo;
+ t_FmPortDsarEchoIpv6Info *p_AutoResEchoIpv6Info;
+ t_FmPortDsarSnmpInfo *p_AutoResSnmpInfo;
+ t_FmPortDsarFilteringInfo *p_AutoResFilteringInfo;
+} t_FmPortDsarParams;
+
+/**************************************************************************//**
+ @Function FM_PORT_EnterDsar
+
+ @Description Enter Deep Sleep Auto Response mode.
+ This function write the apropriate values to in the relevant
+ tables in the MURAM.
+
+ @Param[in] h_FmPortRx - FM PORT module descriptor
+ @Param[in] params - Auto Response parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params);
+
+/**************************************************************************//**
+ @Function FM_PORT_EnterDsarFinal
+
+ @Description Enter Deep Sleep Auto Response mode.
+ This function sets the Tx port in independent mode as needed
+ and redirect the receive flow to go through the
+ Dsar Fman-ctrl code
+
+ @Param[in] h_DsarRxPort - FM Rx PORT module descriptor
+ @Param[in] h_DsarTxPort - FM Tx PORT module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_ExitDsar
+
+ @Description Exit Deep Sleep Auto Response mode.
+ This function reverse the AR mode and put the ports back into
+ their original wake mode
+
+ @Param[in] h_FmPortRx - FM PORT Rx module descriptor
+ @Param[in] h_FmPortTx - FM PORT Tx module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_EnterDsar().
+*//***************************************************************************/
+void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx);
+
+/**************************************************************************//**
+ @Function FM_PORT_IsInDsar
+
+ @Description This function returns TRUE if the port was set as Auto Response
+ and FALSE if not. Once Exit AR mode it will return FALSE as well
+ until re-enabled once more.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+bool FM_PORT_IsInDsar(t_Handle h_FmPort);
+
+typedef struct t_FmPortDsarStats
+{
+ uint32_t arpArCnt;
+ uint32_t echoIcmpv4ArCnt;
+ uint32_t ndpArCnt;
+ uint32_t echoIcmpv6ArCnt;
+ uint32_t snmpGetCnt;
+ uint32_t snmpGetNextCnt;
+} t_FmPortDsarStats;
+
+/**************************************************************************//**
+ @Function FM_PORT_GetDsarStats
+
+ @Description Return statistics for Deep Sleep Auto Response
+
+ @Param[in] h_FmPortRx - FM PORT module descriptor
+ @Param[out] stats - structure containing the statistics counters
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats);
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_PORT_DumpRegs
+
+ @Description Dump all regs.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_DumpRegs(t_Handle h_FmPort);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBufferDataOffset
+
+ @Description Relevant for Rx ports.
+ Returns the data offset from the beginning of the data buffer
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+
+ @Return data offset.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBufferICInfo
+
+ @Description Returns the Internal Context offset from the beginning of the data buffer
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return Internal context info pointer on success, NULL if 'allOtherInfo' was not
+ configured for this port.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBufferPrsResult
+
+ @Description Returns the pointer to the parse result in the data buffer.
+ In Rx ports this is relevant after reception, if parse
+ result is configured to be part of the data passed to the
+ application. For non Rx ports it may be used to get the pointer
+ of the area in the buffer where parse result should be
+ initialized - if so configured.
+ See FM_PORT_ConfigBufferPrefixContent for data buffer prefix
+ configuration.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return Parse result pointer on success, NULL if parse result was not
+ configured for this port.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBufferTimeStamp
+
+ @Description Returns the time stamp in the data buffer.
+ Relevant for Rx ports for getting the buffer time stamp.
+ See FM_PORT_ConfigBufferPrefixContent for data buffer prefix
+ configuration.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return A pointer to the hash result on success, NULL otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBufferHashResult
+
+ @Description Given a data buffer, on the condition that hash result was defined
+ as a part of the buffer content (see FM_PORT_ConfigBufferPrefixContent)
+ this routine will return the pointer to the hash result location in the
+ buffer prefix.
+
+ @Param[in] h_FmPort - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return A pointer to the hash result on success, NULL otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_PORT_Disable
+
+ @Description Gracefully disable an FM port. The port will not start new tasks after all
+ tasks associated with the port are terminated.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ This is a blocking routine, it returns after port is
+ gracefully stopped, i.e. the port will not except new frames,
+ but it will finish all frames or tasks which were already began
+*//***************************************************************************/
+t_Error FM_PORT_Disable(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_Enable
+
+ @Description A runtime routine provided to allow disable/enable of port.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_Enable(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetRateLimit
+
+ @Description Calling this routine enables rate limit algorithm.
+ By default, this functionality is disabled.
+ Note that rate-limit mechanism uses the FM time stamp.
+ The selected rate limit specified here would be
+ rounded DOWN to the nearest 16M.
+
+ May be used for Tx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_RateLimit A structure of rate limit parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ If rate limit is set on a port that need to send PFC frames,
+ it might violate the stop transmit timing.
+*//***************************************************************************/
+t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit);
+
+/**************************************************************************//**
+ @Function FM_PORT_DeleteRateLimit
+
+ @Description Calling this routine disables and clears rate limit
+ initialization.
+
+ May be used for Tx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetPfcPrioritiesMappingToQmanWQ
+
+ @Description Calling this routine maps each PFC received priority to the transmit WQ.
+ This WQ will be blocked upon receiving a PFC frame with this priority.
+
+ May be used for Tx ports only.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] prio PFC priority (0-7).
+ @Param[in] wq Work Queue (0-7).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, uint8_t wq);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetStatisticsCounters
+
+ @Description Calling this routine enables/disables port's statistics counters.
+ By default, counters are enabled.
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetFrameQueueCounters
+
+ @Description Calling this routine enables/disables port's enqueue/dequeue counters.
+ By default, counters are enabled.
+
+ May be used for all ports
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PORT_AnalyzePerformanceParams
+
+ @Description User may call this routine to so the driver will analyze if the
+ basic performance parameters are correct and also the driver may
+ suggest of improvements; The basic parameters are FIFO sizes, number
+ of DMAs and number of TNUMs for the port.
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort);
+
+
+/**************************************************************************//**
+ @Function FM_PORT_SetAllocBufCounter
+
+ @Description Calling this routine enables/disables BM pool allocate
+ buffer counters.
+ By default, counters are enabled.
+
+ May be used for Rx ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] poolId BM pool id.
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, bool enable);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetBmiCounters
+
+ @Description Read port's BMI stat counters and place them into
+ a designated structure of counters.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[out] p_BmiStats counters structure
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetCounter
+
+ @Description Reads one of the FM PORT counters.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] fmPortCounter The requested counter.
+
+ @Return Counter's current value.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ Note that it is user's responsibility to call this routine only
+ for enabled counters, and there will be no indication if a
+ disabled counter is accessed.
+*//***************************************************************************/
+uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter);
+
+/**************************************************************************//**
+ @Function FM_PORT_ModifyCounter
+
+ @Description Sets a value to an enabled counter. Use "0" to reset the counter.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] fmPortCounter The requested counter.
+ @Param[in] value The requested value to be written into the counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetAllocBufCounter
+
+ @Description Reads one of the FM PORT buffer counters.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] poolId The requested pool.
+
+ @Return Counter's current value.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ Note that it is user's responsibility to call this routine only
+ for enabled counters, and there will be no indication if a
+ disabled counter is accessed.
+*//***************************************************************************/
+uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId);
+
+/**************************************************************************//**
+ @Function FM_PORT_ModifyAllocBufCounter
+
+ @Description Sets a value to an enabled counter. Use "0" to reset the counter.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] poolId The requested pool.
+ @Param[in] value The requested value to be written into the counter.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, uint32_t value);
+
+/**************************************************************************//**
+ @Function FM_PORT_AddCongestionGrps
+
+ @Description This routine effects the corresponding Tx port.
+ It should be called in order to enable pause
+ frame transmission in case of congestion in one or more
+ of the congestion groups relevant to this port.
+ Each call to this routine may add one or more congestion
+ groups to be considered relevant to this port.
+
+ May be used for Rx, or RX+OP ports only (depending on chip)
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_CongestionGrps A pointer to an array of congestion groups
+ id's to consider.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps);
+
+/**************************************************************************//**
+ @Function FM_PORT_RemoveCongestionGrps
+
+ @Description This routine effects the corresponding Tx port. It should be
+ called when congestion groups were
+ defined for this port and are no longer relevant, or pause
+ frames transmitting is not required on their behalf.
+ Each call to this routine may remove one or more congestion
+ groups to be considered relevant to this port.
+
+ May be used for Rx, or RX+OP ports only (depending on chip)
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_CongestionGrps A pointer to an array of congestion groups
+ id's to consider.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps);
+
+/**************************************************************************//**
+ @Function FM_PORT_IsStalled
+
+ @Description A routine for checking whether the specified port is stalled.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return TRUE if port is stalled, FALSE otherwize
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+bool FM_PORT_IsStalled(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_ReleaseStalled
+
+ @Description This routine may be called in case the port was stalled and may
+ now be released.
+ Note that this routine is available only on older FMan revisions
+ (FMan v2, DPAA v1.0 only).
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetRxL4ChecksumVerify
+
+ @Description This routine is relevant for Rx ports (1G and 10G). The routine
+ set/clear the L3/L4 checksum verification (on RX side).
+ Note that this takes affect only if hw-parser is enabled!
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] l4Checksum boolean indicates whether to do L3/L4 checksum
+ on frames or not.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetErrorsRoute
+
+ @Description Errors selected for this routine will cause a frame with that error
+ to be enqueued to error queue.
+ Errors not selected for this routine will cause a frame with that error
+ to be enqueued to the one of the other port queues.
+ By default all errors are defined to be enqueued to error queue.
+ Errors that were configured to be discarded (at initialization)
+ may not be selected here.
+
+ May be used for Rx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] errs A list of errors to enqueue to error queue
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs);
+
+/**************************************************************************//**
+ @Function FM_PORT_SetIMExceptions
+
+ @Description Calling this routine enables/disables FM PORT interrupts.
+
+ @Param[in] h_FmPort FM PORT module descriptor.
+ @Param[in] exception The exception to be selected.
+ @Param[in] enable TRUE to enable interrupt, FALSE to mask it.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ This routine should NOT be called from guest-partition
+ (i.e. guestId != NCSW_MASTER_ID)
+*//***************************************************************************/
+t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable);
+
+/**************************************************************************//*
+ @Function FM_PORT_SetPerformanceCounters
+
+ @Description Calling this routine enables/disables port's performance counters.
+ By default, counters are enabled.
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] enable TRUE to enable, FALSE to disable.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable);
+
+/**************************************************************************//*
+ @Function FM_PORT_SetPerformanceCountersParams
+
+ @Description Calling this routine defines port's performance
+ counters parameters.
+
+ May be used for all port types
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmPortPerformanceCnt A pointer to a structure of performance
+ counters parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetPerformanceCountersParams(t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt);
+
+/**************************************************************************//**
+ @Group FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit
+
+ @Description FM Port PCD Runtime control unit API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description A structure defining the KG scheme after the parser.
+ This is relevant only to change scheme selection mode - from
+ direct to indirect and vice versa, or when the scheme is selected directly,
+ to select the scheme id.
+
+*//***************************************************************************/
+typedef struct t_FmPcdKgSchemeSelect {
+ bool direct; /**< TRUE to use 'h_Scheme' directly, FALSE to use LCV. */
+ t_Handle h_DirectScheme; /**< Scheme handle, selects the scheme after parser;
+ Relevant only when 'direct' is TRUE. */
+} t_FmPcdKgSchemeSelect;
+
+/**************************************************************************//**
+ @Description A structure of scheme parameters
+*//***************************************************************************/
+typedef struct t_FmPcdPortSchemesParams {
+ uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */
+ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; /**< Array of 'numOfSchemes' schemes for the
+ port to be bound to */
+} t_FmPcdPortSchemesParams;
+
+/**************************************************************************//**
+ @Description Union for defining port protocol parameters for parser
+*//***************************************************************************/
+typedef union u_FmPcdHdrPrsOpts {
+ /* MPLS */
+ struct {
+ bool labelInterpretationEnable; /**< When this bit is set, the last MPLS label will be
+ interpreted as described in HW spec table. When the bit
+ is cleared, the parser will advance to MPLS next parse */
+ e_NetHeaderType nextParse; /**< must be equal or higher than IPv4 */
+ } mplsPrsOptions;
+ /* VLAN */
+ struct {
+ uint16_t tagProtocolId1; /**< User defined Tag Protocol Identifier, to be recognized
+ on VLAN TAG on top of 0x8100 and 0x88A8 */
+ uint16_t tagProtocolId2; /**< User defined Tag Protocol Identifier, to be recognized
+ on VLAN TAG on top of 0x8100 and 0x88A8 */
+ } vlanPrsOptions;
+ /* PPP */
+ struct{
+ bool enableMTUCheck; /**< Check validity of MTU according to RFC2516 */
+ } pppoePrsOptions;
+
+ /* IPV6 */
+ struct{
+ bool routingHdrEnable; /**< TRUE to enable routing header, otherwise ignore */
+ } ipv6PrsOptions;
+
+ /* UDP */
+ struct{
+ bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */
+ } udpPrsOptions;
+
+ /* TCP */
+ struct {
+ bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */
+ } tcpPrsOptions;
+} u_FmPcdHdrPrsOpts;
+
+/**************************************************************************//**
+ @Description A structure for defining each header for the parser
+*//***************************************************************************/
+typedef struct t_FmPcdPrsAdditionalHdrParams {
+ e_NetHeaderType hdr; /**< Selected header; use HEADER_TYPE_NONE
+ to indicate that sw parser is to run first
+ (before HW parser, and independent of the
+ existence of any protocol), in this case,
+ swPrsEnable must be set, and all other
+ parameters are irrelevant. */
+ bool errDisable; /**< TRUE to disable error indication */
+ bool swPrsEnable; /**< Enable jump to SW parser when this
+ header is recognized by the HW parser. */
+ uint8_t indexPerHdr; /**< Normally 0, if more than one sw parser
+ attachments exists for the same header,
+ (in the main sw parser code) use this
+ index to distinguish between them. */
+ bool usePrsOpts; /**< TRUE to use parser options. */
+ u_FmPcdHdrPrsOpts prsOpts; /**< A union according to header type,
+ defining the parser options selected.*/
+} t_FmPcdPrsAdditionalHdrParams;
+
+/**************************************************************************//**
+ @Description struct for defining port PCD parameters
+*//***************************************************************************/
+typedef struct t_FmPortPcdPrsParams {
+ uint8_t prsResultPrivateInfo; /**< The private info provides a method of inserting
+ port information into the parser result. This information
+ may be extracted by Keygen and be used for frames
+ distribution when a per-port distinction is required,
+ it may also be used as a port logical id for analyzing
+ incoming frames. */
+ uint8_t parsingOffset; /**< Number of bytes from beginning of packet to start parsing */
+ e_NetHeaderType firstPrsHdr; /**< The type of the first header expected at 'parsingOffset' */
+ bool includeInPrsStatistics; /**< TRUE to include this port in the parser statistics;
+ NOTE: this field is not valid when the FM is in "guest" mode
+ and IPC is not available. */
+ uint8_t numOfHdrsWithAdditionalParams; /**< Normally 0, some headers may get
+ special parameters */
+ t_FmPcdPrsAdditionalHdrParams additionalParams[FM_PCD_PRS_NUM_OF_HDRS];
+ /**< 'numOfHdrsWithAdditionalParams' structures
+ of additional parameters
+ for each header that requires them */
+ bool setVlanTpid1; /**< TRUE to configure user selection of Ethertype to
+ indicate a VLAN tag (in addition to the TPID values
+ 0x8100 and 0x88A8). */
+ uint16_t vlanTpid1; /**< extra tag to use if setVlanTpid1=TRUE. */
+ bool setVlanTpid2; /**< TRUE to configure user selection of Ethertype to
+ indicate a VLAN tag (in addition to the TPID values
+ 0x8100 and 0x88A8). */
+ uint16_t vlanTpid2; /**< extra tag to use if setVlanTpid1=TRUE. */
+} t_FmPortPcdPrsParams;
+
+/**************************************************************************//**
+ @Description struct for defining coarse alassification parameters
+*//***************************************************************************/
+typedef struct t_FmPortPcdCcParams {
+ t_Handle h_CcTree; /**< A handle to a CC tree */
+} t_FmPortPcdCcParams;
+
+/**************************************************************************//**
+ @Description struct for defining keygen parameters
+*//***************************************************************************/
+typedef struct t_FmPortPcdKgParams {
+ uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */
+ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES];
+ /**< Array of 'numOfSchemes' schemes handles for the
+ port to be bound to */
+ bool directScheme; /**< TRUE for going from parser to a specific scheme,
+ regardless of parser result */
+ t_Handle h_DirectScheme; /**< relevant only if direct == TRUE, Scheme handle,
+ as returned by FM_PCD_KgSetScheme */
+} t_FmPortPcdKgParams;
+
+/**************************************************************************//**
+ @Description struct for defining policer parameters
+*//***************************************************************************/
+typedef struct t_FmPortPcdPlcrParams {
+ t_Handle h_Profile; /**< Selected profile handle */
+} t_FmPortPcdPlcrParams;
+
+/**************************************************************************//**
+ @Description struct for defining port PCD parameters
+*//***************************************************************************/
+typedef struct t_FmPortPcdParams {
+ e_FmPortPcdSupport pcdSupport; /**< Relevant for Rx and offline ports only.
+ Describes the active PCD engines for this port. */
+ t_Handle h_NetEnv; /**< HL Unused in PLCR only mode */
+ t_FmPortPcdPrsParams *p_PrsParams; /**< Parser parameters for this port */
+ t_FmPortPcdCcParams *p_CcParams; /**< Coarse classification parameters for this port */
+ t_FmPortPcdKgParams *p_KgParams; /**< Keygen parameters for this port */
+ t_FmPortPcdPlcrParams *p_PlcrParams; /**< Policer parameters for this port; Relevant for one of
+ following cases:
+ e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or
+ e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected,
+ or if any flow uses a KG scheme were policer
+ profile is not generated
+ ('bypassPlcrProfileGeneration selected'). */
+ t_Handle h_IpReassemblyManip; /**< IP Reassembly manipulation */
+#if (DPAA_VERSION >= 11)
+ t_Handle h_CapwapReassemblyManip;/**< CAPWAP Reassembly manipulation */
+#endif /* (DPAA_VERSION >= 11) */
+} t_FmPortPcdParams;
+
+/**************************************************************************//**
+ @Description A structure for defining the Parser starting point
+*//***************************************************************************/
+typedef struct t_FmPcdPrsStart {
+ uint8_t parsingOffset; /**< Number of bytes from beginning of packet to
+ start parsing */
+ e_NetHeaderType firstPrsHdr; /**< The type of the first header axpected at
+ 'parsingOffset' */
+} t_FmPcdPrsStart;
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Description struct for defining external buffer margins
+*//***************************************************************************/
+typedef struct t_FmPortVSPAllocParams {
+ uint8_t numOfProfiles; /**< Number of Virtual Storage Profiles; must be a power of 2 */
+ uint8_t dfltRelativeId; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port
+ The same default Virtual-Storage-Profile-id will be for coupled Tx port
+ if relevant function called for Rx port */
+ t_Handle h_FmTxPort; /**< Handle to coupled Tx Port; not relevant for OP port. */
+} t_FmPortVSPAllocParams;
+#endif /* (DPAA_VERSION >= 11) */
+
+
+/**************************************************************************//**
+ @Function FM_PORT_SetPCD
+
+ @Description Calling this routine defines the port's PCD configuration.
+ It changes it from its default configuration which is PCD
+ disabled (BMI to BMI) and configures it according to the passed
+ parameters.
+
+ May be used for Rx and OP ports only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmPortPcd A Structure of parameters defining the port's PCD
+ configuration.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_FmPortPcd);
+
+/**************************************************************************//**
+ @Function FM_PORT_DeletePCD
+
+ @Description Calling this routine releases the port's PCD configuration.
+ The port returns to its default configuration which is PCD
+ disabled (BMI to BMI) and all PCD configuration is removed.
+
+ May be used for Rx and OP ports which are
+ in PCD mode only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_DeletePCD(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_AttachPCD
+
+ @Description This routine may be called after FM_PORT_DetachPCD was called,
+ to return to the originally configured PCD support flow.
+ The couple of routines are used to allow PCD configuration changes
+ that demand that PCD will not be used while changes take place.
+
+ May be used for Rx and OP ports which are
+ in PCD mode only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+*//***************************************************************************/
+t_Error FM_PORT_AttachPCD(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_DetachPCD
+
+ @Description Calling this routine detaches the port from its PCD functionality.
+ The port returns to its default flow which is BMI to BMI.
+
+ May be used for Rx and OP ports which are
+ in PCD mode only
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_AttachPCD().
+*//***************************************************************************/
+t_Error FM_PORT_DetachPCD(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdPlcrAllocProfiles
+
+ @Description This routine may be called only for ports that use the Policer in
+ order to allocate private policer profiles.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] numOfProfiles The number of required policer profiles
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(),
+ and before FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdPlcrFreeProfiles
+
+ @Description This routine should be called for freeing private policer profiles.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(),
+ and before FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort);
+
+#if (DPAA_VERSION >= 11)
+/**************************************************************************//**
+ @Function FM_PORT_VSPAlloc
+
+ @Description This routine allocated VSPs per port and forces the port to work
+ in VSP mode. Note that the port is initialized by default with the
+ physical-storage-profile only.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_Params A structure of parameters for allocation VSP's per port
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init(), and before FM_PORT_SetPCD()
+ and also before FM_PORT_Enable(); i.e. the port should be disabled.
+*//***************************************************************************/
+t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_Params);
+#endif /* (DPAA_VERSION >= 11) */
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdKgModifyInitialScheme
+
+ @Description This routine may be called only for ports that use the keygen in
+ order to change the initial scheme frame should be routed to.
+ The change may be of a scheme id (in case of direct mode),
+ from direct to indirect, or from indirect to direct - specifying the scheme id.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_FmPcdKgScheme A structure of parameters for defining whether
+ a scheme is direct/indirect, and if direct - scheme id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdKgModifyInitialScheme (t_Handle h_FmPort, t_FmPcdKgSchemeSelect *p_FmPcdKgScheme);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdPlcrModifyInitialProfile
+
+ @Description This routine may be called for ports with flows
+ e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR
+ only, to change the initial Policer profile frame should be
+ routed to. The change may be of a profile and/or absolute/direct
+ mode selection.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] h_Profile Policer profile handle
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdPlcrModifyInitialProfile (t_Handle h_FmPort, t_Handle h_Profile);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdCcModifyTree
+
+ @Description This routine may be called for ports that use coarse classification tree
+ if the user wishes to replace the tree. The routine may not be called while port
+ receives packets using the PCD functionalities, therefor port must be first detached
+ from the PCD, only than the routine may be called, and than port be attached to PCD again.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] h_CcTree A CC tree that was already built. The tree id as returned from
+ the BuildTree routine.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init(), FM_PORT_SetPCD() and FM_PORT_DetachPCD()
+*//***************************************************************************/
+t_Error FM_PORT_PcdCcModifyTree (t_Handle h_FmPort, t_Handle h_CcTree);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdKgBindSchemes
+
+ @Description These routines may be called for adding more schemes for the
+ port to be bound to. The selected schemes are not added,
+ just this specific port starts using them.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_PortScheme A structure defining the list of schemes to be added.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdKgBindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme);
+
+/**************************************************************************//**
+ @Function FM_PORT_PcdKgUnbindSchemes
+
+ @Description These routines may be called for adding more schemes for the
+ port to be bound to. The selected schemes are not removed or invalidated,
+ just this specific port stops using them.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_PortScheme A structure defining the list of schemes to be added.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD().
+*//***************************************************************************/
+t_Error FM_PORT_PcdKgUnbindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme);
+
+/**************************************************************************//**
+ @Function FM_PORT_GetIPv4OptionsCount
+
+ @Description TODO
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[out] p_Ipv4OptionsCount will hold the counter value
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init()
+*//***************************************************************************/
+t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, uint32_t *p_Ipv4OptionsCount);
+
+/** @} */ /* end of FM_PORT_pcd_runtime_control_grp group */
+/** @} */ /* end of FM_PORT_runtime_control_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_PORT_runtime_data_grp FM Port Runtime Data-path Unit
+
+ @Description FM Port Runtime data unit API functions, definitions and enums.
+ This API is valid only if working in Independent-Mode.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_PORT_ImTx
+
+ @Description Tx function, called to transmit a data buffer on the port.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+ @Param[in] p_Data A pointer to an LCP data buffer.
+ @Param[in] length Size of data for transmission.
+ @Param[in] lastBuffer Buffer position - TRUE for the last buffer
+ of a frame, including a single buffer frame
+ @Param[in] h_BufContext A handle of the user acossiated with this buffer
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ NOTE - This routine can be used only when working in
+ Independent-Mode mode.
+*//***************************************************************************/
+t_Error FM_PORT_ImTx( t_Handle h_FmPort,
+ uint8_t *p_Data,
+ uint16_t length,
+ bool lastBuffer,
+ t_Handle h_BufContext);
+
+/**************************************************************************//**
+ @Function FM_PORT_ImTxConf
+
+ @Description Tx port confirmation routine, optional, may be called to verify
+ transmission of all frames. The procedure performed by this
+ routine will be performed automatically on next buffer transmission,
+ but if desired, calling this routine will invoke this action on
+ demand.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ NOTE - This routine can be used only when working in
+ Independent-Mode mode.
+*//***************************************************************************/
+void FM_PORT_ImTxConf(t_Handle h_FmPort);
+
+/**************************************************************************//**
+ @Function FM_PORT_ImRx
+
+ @Description Rx function, may be called to poll for received buffers.
+ Normally, Rx process is invoked by the driver on Rx interrupt.
+ Alternatively, this routine may be called on demand.
+
+ @Param[in] h_FmPort A handle to a FM Port module.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_PORT_Init().
+ NOTE - This routine can be used only when working in
+ Independent-Mode mode.
+*//***************************************************************************/
+t_Error FM_PORT_ImRx(t_Handle h_FmPort);
+
+/** @} */ /* end of FM_PORT_runtime_data_grp group */
+/** @} */ /* end of FM_PORT_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+
+#ifdef NCSW_BACKWARD_COMPATIBLE_API
+#define FM_PORT_ConfigTxFifoDeqPipelineDepth FM_PORT_ConfigFifoDeqPipelineDepth
+#endif /* NCSW_BACKWARD_COMPATIBLE_API */
+
+
+#endif /* __FM_PORT_EXT */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h
new file mode 100644
index 000000000000..72078ac42c10
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_rtc_ext.h
+
+ @Description External definitions and API for FM RTC IEEE1588 Timer Module.
+
+ @Cautions None.
+*//***************************************************************************/
+
+#ifndef __FM_RTC_EXT_H__
+#define __FM_RTC_EXT_H__
+
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "fsl_fman_rtc.h"
+
+/**************************************************************************//**
+
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group fm_rtc_grp FM RTC
+
+ @Description FM RTC functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group fm_rtc_init_grp FM RTC Initialization Unit
+
+ @Description FM RTC initialization API.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description FM RTC Alarm Polarity Options.
+*//***************************************************************************/
+typedef enum e_FmRtcAlarmPolarity
+{
+ e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH, /**< Active-high output polarity */
+ e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW /**< Active-low output polarity */
+} e_FmRtcAlarmPolarity;
+
+/**************************************************************************//**
+ @Description FM RTC Trigger Polarity Options.
+*//***************************************************************************/
+typedef enum e_FmRtcTriggerPolarity
+{
+ e_FM_RTC_TRIGGER_ON_RISING_EDGE = E_FMAN_RTC_TRIGGER_ON_RISING_EDGE, /**< Trigger on rising edge */
+ e_FM_RTC_TRIGGER_ON_FALLING_EDGE = E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE /**< Trigger on falling edge */
+} e_FmRtcTriggerPolarity;
+
+/**************************************************************************//**
+ @Description IEEE1588 Timer Module FM RTC Optional Clock Sources.
+*//***************************************************************************/
+typedef enum e_FmSrcClock
+{
+ e_FM_RTC_SOURCE_CLOCK_EXTERNAL = E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL, /**< external high precision timer reference clock */
+ e_FM_RTC_SOURCE_CLOCK_SYSTEM = E_FMAN_RTC_SOURCE_CLOCK_SYSTEM, /**< MAC system clock */
+ e_FM_RTC_SOURCE_CLOCK_OSCILATOR = E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR /**< RTC clock oscilator */
+}e_FmSrcClk;
+
+/**************************************************************************//**
+ @Description FM RTC configuration parameters structure.
+
+ This structure should be passed to FM_RTC_Config().
+*//***************************************************************************/
+typedef struct t_FmRtcParams
+{
+ t_Handle h_Fm; /**< FM Handle*/
+ uintptr_t baseAddress; /**< Base address of FM RTC registers */
+ t_Handle h_App; /**< A handle to an application layer object; This handle will
+ be passed by the driver upon calling the above callbacks */
+} t_FmRtcParams;
+
+
+/**************************************************************************//**
+ @Function FM_RTC_Config
+
+ @Description Configures the FM RTC module according to user's parameters.
+
+ The driver assigns default values to some FM RTC parameters.
+ These parameters can be overwritten using the advanced
+ configuration routines.
+
+ @Param[in] p_FmRtcParam - FM RTC configuration parameters.
+
+ @Return Handle to the new FM RTC object; NULL pointer on failure.
+
+ @Cautions None
+*//***************************************************************************/
+t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam);
+
+/**************************************************************************//**
+ @Function FM_RTC_Init
+
+ @Description Initializes the FM RTC driver and hardware.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_Init(t_Handle h_FmRtc);
+
+/**************************************************************************//**
+ @Function FM_RTC_Free
+
+ @Description Frees the FM RTC object and all allocated resources.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_Free(t_Handle h_FmRtc);
+
+
+/**************************************************************************//**
+ @Group fm_rtc_adv_config_grp FM RTC Advanced Configuration Unit
+
+ @Description FM RTC advanced configuration functions.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigPeriod
+
+ @Description Configures the period of the timestamp if different than
+ default [DEFAULT_clockPeriod].
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] period - Period in nano-seconds.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigSourceClock
+
+ @Description Configures the source clock of the RTC.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] srcClk - Source clock selection.
+ @Param[in] freqInMhz - the source-clock frequency (in MHz).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc,
+ e_FmSrcClk srcClk,
+ uint32_t freqInMhz);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigPulseRealignment
+
+ @Description Configures the RTC to automatic FIPER pulse realignment in
+ response to timer adjustments [DEFAULT_pulseRealign]
+
+ In this mode, the RTC clock is identical to the source clock.
+ This feature can be useful when the system contains an external
+ RTC with inherent frequency compensation.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] enable - TRUE to enable automatic realignment.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigFrequencyBypass
+
+ @Description Configures the RTC to bypass the frequency compensation
+ mechanism. [DEFAULT_bypass]
+
+ In this mode, the RTC clock is identical to the source clock.
+ This feature can be useful when the system contains an external
+ RTC with inherent frequency compensation.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] enabled - TRUE to bypass frequency compensation;
+ FALSE otherwise.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigInvertedInputClockPhase
+
+ @Description Configures the RTC to invert the source clock phase on input.
+ [DEFAULT_invertInputClkPhase]
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] inverted - TRUE to invert the source clock phase on input.
+ FALSE otherwise.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigInvertedOutputClockPhase
+
+ @Description Configures the RTC to invert the output clock phase.
+ [DEFAULT_invertOutputClkPhase]
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] inverted - TRUE to invert the output clock phase.
+ FALSE otherwise.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigOutputClockDivisor
+
+ @Description Configures the divisor for generating the output clock from
+ the RTC clock. [DEFAULT_outputClockDivisor]
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] divisor - Divisor for generation of the output clock.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigAlarmPolarity
+
+ @Description Configures the polarity (active-high/active-low) of a specific
+ alarm signal. [DEFAULT_alarmPolarity]
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] alarmId - Alarm ID.
+ @Param[in] alarmPolarity - Alarm polarity.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc,
+ uint8_t alarmId,
+ e_FmRtcAlarmPolarity alarmPolarity);
+
+/**************************************************************************//**
+ @Function FM_RTC_ConfigExternalTriggerPolarity
+
+ @Description Configures the polarity (rising/falling edge) of a specific
+ external trigger signal. [DEFAULT_triggerPolarity]
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] triggerId - Trigger ID.
+ @Param[in] triggerPolarity - Trigger polarity.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously created using FM_RTC_Config().
+*//***************************************************************************/
+t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc,
+ uint8_t triggerId,
+ e_FmRtcTriggerPolarity triggerPolarity);
+
+/** @} */ /* end of fm_rtc_adv_config_grp */
+/** @} */ /* end of fm_rtc_init_grp */
+
+
+/**************************************************************************//**
+ @Group fm_rtc_control_grp FM RTC Control Unit
+
+ @Description FM RTC runtime control API.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function t_FmRtcExceptionsCallback
+
+ @Description Exceptions user callback routine, used for RTC different mechanisms.
+
+ @Param[in] h_App - User's application descriptor.
+ @Param[in] id - source id.
+*//***************************************************************************/
+typedef void (t_FmRtcExceptionsCallback) ( t_Handle h_App, uint8_t id);
+
+/**************************************************************************//**
+ @Description FM RTC alarm parameters.
+*//***************************************************************************/
+typedef struct t_FmRtcAlarmParams {
+ uint8_t alarmId; /**< 0 or 1 */
+ uint64_t alarmTime; /**< In nanoseconds, the time when the alarm
+ should go off - must be a multiple of
+ the RTC period */
+ t_FmRtcExceptionsCallback *f_AlarmCallback; /**< This routine will be called when RTC
+ reaches alarmTime */
+ bool clearOnExpiration; /**< TRUE to turn off the alarm once expired. */
+} t_FmRtcAlarmParams;
+
+/**************************************************************************//**
+ @Description FM RTC Periodic Pulse parameters.
+*//***************************************************************************/
+typedef struct t_FmRtcPeriodicPulseParams {
+ uint8_t periodicPulseId; /**< 0 or 1 */
+ uint64_t periodicPulsePeriod; /**< In Nanoseconds. Must be
+ a multiple of the RTC period */
+ t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; /**< This routine will be called every
+ periodicPulsePeriod. */
+} t_FmRtcPeriodicPulseParams;
+
+/**************************************************************************//**
+ @Description FM RTC Periodic Pulse parameters.
+*//***************************************************************************/
+typedef struct t_FmRtcExternalTriggerParams {
+ uint8_t externalTriggerId; /**< 0 or 1 */
+ bool usePulseAsInput; /**< Use the pulse interrupt instead of
+ an external signal */
+ t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; /**< This routine will be called every
+ periodicPulsePeriod. */
+} t_FmRtcExternalTriggerParams;
+
+
+/**************************************************************************//**
+ @Function FM_RTC_Enable
+
+ @Description Enable the RTC (time count is started).
+
+ The user can select to resume the time count from previous
+ point, or to restart the time count.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] resetClock - Restart the time count from zero.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock);
+
+/**************************************************************************//**
+ @Function FM_RTC_Disable
+
+ @Description Disables the RTC (time count is stopped).
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_Disable(t_Handle h_FmRtc);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetClockOffset
+
+ @Description Sets the clock offset (usually relative to another clock).
+
+ The user can pass a negative offset value.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] offset - New clock offset (in nanoseconds).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetAlarm
+
+ @Description Schedules an alarm event to a given RTC time.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] p_FmRtcAlarmParams - Alarm parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+ Must be called only prior to FM_RTC_Enable().
+*//***************************************************************************/
+t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetPeriodicPulse
+
+ @Description Sets a periodic pulse.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] p_FmRtcPeriodicPulseParams - Periodic pulse parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+ Must be called only prior to FM_RTC_Enable().
+*//***************************************************************************/
+t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams);
+
+/**************************************************************************//**
+ @Function FM_RTC_ClearPeriodicPulse
+
+ @Description Clears a periodic pulse.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] periodicPulseId - Periodic pulse id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetExternalTrigger
+
+ @Description Sets an external trigger indication and define a callback
+ routine to be called on such event.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] p_FmRtcExternalTriggerParams - External Trigger parameters.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams);
+
+/**************************************************************************//**
+ @Function FM_RTC_ClearExternalTrigger
+
+ @Description Clears external trigger indication.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] id - External Trigger id.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t id);
+
+/**************************************************************************//**
+ @Function FM_RTC_GetExternalTriggerTimeStamp
+
+ @Description Reads the External Trigger TimeStamp.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] triggerId - External Trigger id.
+ @Param[out] p_TimeStamp - External Trigger timestamp (in nanoseconds).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc,
+ uint8_t triggerId,
+ uint64_t *p_TimeStamp);
+
+/**************************************************************************//**
+ @Function FM_RTC_GetCurrentTime
+
+ @Description Returns the current RTC time.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[out] p_Ts - returned time stamp (in nanoseconds).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetCurrentTime
+
+ @Description Sets the current RTC time.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] ts - The new time stamp (in nanoseconds).
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts);
+
+/**************************************************************************//**
+ @Function FM_RTC_GetFreqCompensation
+
+ @Description Retrieves the frequency compensation value
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[out] p_Compensation - A pointer to the returned value of compensation.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation);
+
+/**************************************************************************//**
+ @Function FM_RTC_SetFreqCompensation
+
+ @Description Sets a new frequency compensation value.
+
+ @Param[in] h_FmRtc - Handle to FM RTC object.
+ @Param[in] freqCompensation - The new frequency compensation value to set.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init().
+*//***************************************************************************/
+t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation);
+
+#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+/**************************************************************************//**
+*@Function FM_RTC_EnableInterrupt
+*
+*@Description Enable interrupt of FM RTC.
+*
+*@Param[in] h_FmRtc - Handle to FM RTC object.
+*@Param[in] events - Interrupt events.
+*
+*@Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events);
+
+/**************************************************************************//**
+*@Function FM_RTC_DisableInterrupt
+*
+*@Description Disable interrupt of FM RTC.
+*
+*@Param[in] h_FmRtc - Handle to FM RTC object.
+*@Param[in] events - Interrupt events.
+*
+*@Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events);
+#endif
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+/**************************************************************************//**
+ @Function FM_RTC_DumpRegs
+
+ @Description Dumps all FM registers
+
+ @Param[in] h_FmRtc A handle to an FM RTC Module.
+
+ @Return E_OK on success;
+
+ @Cautions Allowed only FM_Init().
+*//***************************************************************************/
+t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+/** @} */ /* end of fm_rtc_control_grp */
+/** @} */ /* end of fm_rtc_grp */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_RTC_EXT_H__ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h
new file mode 100644
index 000000000000..f9aed0363d7c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File fm_vsp_ext.h
+
+ @Description FM Virtual Storage-Profile ...
+*//***************************************************************************/
+#ifndef __FM_VSP_EXT_H
+#define __FM_VSP_EXT_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "debug_ext.h"
+
+#include "fm_ext.h"
+
+
+/**************************************************************************//**
+
+ @Group FM_grp Frame Manager API
+
+ @Description FM API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_VSP_grp FM Virtual-Storage-Profile
+
+ @Description FM Virtual-Storage-Profile API
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_VSP_init_grp FM VSP Initialization Unit
+
+ @Description FM VSP initialization API.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Virtual Storage Profile
+*//***************************************************************************/
+typedef struct t_FmVspParams {
+ t_Handle h_Fm; /**< A handle to the FM object this VSP related to */
+ t_FmExtPools extBufPools; /**< Which external buffer pools are used
+ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
+ parameter associated with Rx / OP port */
+ uint16_t liodnOffset; /**< VSP's LIODN offset */
+ struct {
+ e_FmPortType portType; /**< Port type */
+ uint8_t portId; /**< Port Id - relative to type */
+ } portParams;
+ uint8_t relativeProfileId; /**< VSP Id - relative to VSP's range
+ defined in relevant FM object */
+} t_FmVspParams;
+
+
+/**************************************************************************//**
+ @Function FM_VSP_Config
+
+ @Description Creates descriptor for the FM VSP module.
+
+ The routine returns a handle (descriptor) to the FM VSP object.
+ This descriptor must be passed as first parameter to all other
+ FM VSP function calls.
+
+ No actual initialization or configuration of FM hardware is
+ done by this routine.
+
+@Param[in] p_FmVspParams Pointer to data structure of parameters
+
+ @Retval Handle to FM VSP object, or NULL for Failure.
+*//***************************************************************************/
+t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams);
+
+/**************************************************************************//**
+ @Function FM_VSP_Init
+
+ @Description Initializes the FM VSP module
+
+ @Param[in] h_FmVsp - FM VSP module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_VSP_Init(t_Handle h_FmVsp);
+
+/**************************************************************************//**
+ @Function FM_VSP_Free
+
+ @Description Frees all resources that were assigned to FM VSP module.
+
+ Calling this routine invalidates the descriptor.
+
+ @Param[in] h_FmVsp - FM VSP module descriptor
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error FM_VSP_Free(t_Handle h_FmVsp);
+
+
+/**************************************************************************//**
+ @Group FM_VSP_adv_config_grp FM VSP Advanced Configuration Unit
+
+ @Description FM VSP advanced configuration functions.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigBufferPrefixContent
+
+ @Description Defines the structure, size and content of the application buffer.
+
+ The prefix will
+ In VSPs defined for Tx ports, if 'passPrsResult', the application
+ should set a value to their offsets in the prefix of
+ the FM will save the first 'privDataSize', than,
+ depending on 'passPrsResult' and 'passTimeStamp', copy parse result
+ and timeStamp, and the packet itself (in this order), to the
+ application buffer, and to offset.
+
+ Calling this routine changes the buffer margins definitions
+ in the internal driver data base from its default
+ configuration: Data size: [DEFAULT_FM_SP_bufferPrefixContent_privDataSize]
+ Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult].
+ Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp].
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in,out] p_FmBufferPrefixContent A structure of parameters describing the
+ structure of the buffer.
+ Out parameter: Start margin - offset
+ of data from start of external buffer.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp,
+ t_FmBufferPrefixContent *p_FmBufferPrefixContent);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigDmaSwapData
+
+ @Description Calling this routine changes the DMA swap data parameter
+ in the internal driver data base from its default
+ configuration [DEFAULT_FM_SP_dmaSwapData]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] swapData New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigDmaIcCacheAttr
+
+ @Description Calling this routine changes the internal context cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_FM_SP_dmaIntContextCacheAttr]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] intContextCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp,
+ e_FmDmaCacheOption intContextCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigDmaHdrAttr
+
+ @Description Calling this routine changes the header cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_FM_SP_dmaHeaderCacheAttr]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] headerCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigDmaScatterGatherAttr
+
+ @Description Calling this routine changes the scatter gather cache
+ attribute parameter in the internal driver data base
+ from its default configuration [DEFAULT_FM_SP_dmaScatterGatherCacheAttr]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] scatterGatherCacheAttr New selection
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp,
+ e_FmDmaCacheOption scatterGatherCacheAttr);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigDmaWriteOptimize
+
+ @Description Calling this routine changes the write optimization
+ parameter in the internal driver data base
+ from its default configuration: optimize = [DEFAULT_FM_SP_dmaWriteOptimize]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] optimize TRUE to enable optimization, FALSE for normal operation
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigNoScatherGather
+
+ @Description Calling this routine changes the possibility to receive S/G frame
+ in the internal driver data base
+ from its default configuration: optimize = [DEFAULT_FM_SP_noScatherGather]
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] noScatherGather TRUE to operate without scatter/gather capability.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigPoolDepletion
+
+ @Description Calling this routine enables pause frame generation depending on the
+ depletion status of BM pools. It also defines the conditions to activate
+ this functionality. By default, this functionality is disabled.
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] p_BufPoolDepletion A structure of pool depletion parameters
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion);
+
+/**************************************************************************//**
+ @Function FM_VSP_ConfigBackupPools
+
+ @Description Calling this routine allows the configuration of some of the BM pools
+ defined for this port as backup pools.
+ A pool configured to be a backup pool will be used only if all other
+ enabled non-backup pools are depleted.
+
+ @Param[in] h_FmVsp A handle to a FM VSP module.
+ @Param[in] p_BackupBmPools An array of pool id's. All pools specified here will
+ be defined as backup pools.
+
+ @Return E_OK on success; Error code otherwise.
+
+ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init().
+*//***************************************************************************/
+t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools);
+
+/** @} */ /* end of FM_VSP_adv_config_grp group */
+/** @} */ /* end of FM_VSP_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_VSP_control_grp FM VSP Control Unit
+
+ @Description FM VSP runtime control API.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function FM_VSP_GetBufferDataOffset
+
+ @Description Relevant for Rx ports.
+ Returns the data offset from the beginning of the data buffer
+
+ @Param[in] h_FmVsp - FM PORT module descriptor
+
+ @Return data offset.
+
+ @Cautions Allowed only following FM_VSP_Init().
+*//***************************************************************************/
+uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp);
+
+/**************************************************************************//**
+ @Function FM_VSP_GetBufferICInfo
+
+ @Description Returns the Internal Context offset from the beginning of the data buffer
+
+ @Param[in] h_FmVsp - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return Internal context info pointer on success, NULL if 'allOtherInfo' was not
+ configured for this port.
+
+ @Cautions Allowed only following FM_VSP_Init().
+*//***************************************************************************/
+uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_VSP_GetBufferPrsResult
+
+ @Description Returns the pointer to the parse result in the data buffer.
+ In Rx ports this is relevant after reception, if parse
+ result is configured to be part of the data passed to the
+ application. For non Rx ports it may be used to get the pointer
+ of the area in the buffer where parse result should be
+ initialized - if so configured.
+ See FM_VSP_ConfigBufferPrefixContent for data buffer prefix
+ configuration.
+
+ @Param[in] h_FmVsp - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return Parse result pointer on success, NULL if parse result was not
+ configured for this port.
+
+ @Cautions Allowed only following FM_VSP_Init().
+*//***************************************************************************/
+t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_VSP_GetBufferTimeStamp
+
+ @Description Returns the time stamp in the data buffer.
+ Relevant for Rx ports for getting the buffer time stamp.
+ See FM_VSP_ConfigBufferPrefixContent for data buffer prefix
+ configuration.
+
+ @Param[in] h_FmVsp - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return A pointer to the hash result on success, NULL otherwise.
+
+ @Cautions Allowed only following FM_VSP_Init().
+*//***************************************************************************/
+uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data);
+
+/**************************************************************************//**
+ @Function FM_VSP_GetBufferHashResult
+
+ @Description Given a data buffer, on the condition that hash result was defined
+ as a part of the buffer content (see FM_VSP_ConfigBufferPrefixContent)
+ this routine will return the pointer to the hash result location in the
+ buffer prefix.
+
+ @Param[in] h_FmVsp - FM PORT module descriptor
+ @Param[in] p_Data - A pointer to the data buffer.
+
+ @Return A pointer to the hash result on success, NULL otherwise.
+
+ @Cautions Allowed only following FM_VSP_Init().
+*//***************************************************************************/
+uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data);
+
+
+/** @} */ /* end of FM_VSP_control_grp group */
+/** @} */ /* end of FM_VSP_grp group */
+/** @} */ /* end of FM_grp group */
+
+
+#endif /* __FM_VSP_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h
new file mode 100644
index 000000000000..f635d3c24de0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+
+#ifndef __MII_ACC_EXT_H
+#define __MII_ACC_EXT_H
+
+
+/**************************************************************************//**
+ @Function MII_ReadPhyReg
+
+ @Description This routine is called to read a specified PHY
+ register value.
+
+ @Param[in] h_MiiAccess - Handle to MII configuration access registers
+ @Param[in] phyAddr - PHY address (0-31).
+ @Param[in] reg - PHY register to read
+ @Param[out] p_Data - Gets the register value.
+
+ @Return Always zero (success).
+*//***************************************************************************/
+int MII_ReadPhyReg(t_Handle h_MiiAccess,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t *p_Data);
+
+/**************************************************************************//**
+ @Function MII_WritePhyReg
+
+ @Description This routine is called to write data to a specified PHY
+ register.
+
+ @Param[in] h_MiiAccess - Handle to MII configuration access registers
+ @Param[in] phyAddr - PHY address (0-31).
+ @Param[in] reg - PHY register to write
+ @Param[in] data - Data to write in register.
+
+ @Return Always zero (success).
+*//***************************************************************************/
+int MII_WritePhyReg(t_Handle h_MiiAccess,
+ uint8_t phyAddr,
+ uint8_t reg,
+ uint16_t data);
+
+
+#endif /* __MII_ACC_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h
new file mode 100644
index 000000000000..ec89a6dde4cd
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File core_ext.h
+
+ @Description Generic interface to basic core operations.
+
+ The system integrator must ensure that this interface is
+ mapped to a specific core implementation, by including the
+ appropriate header file.
+*//***************************************************************************/
+#ifndef __CORE_EXT_H
+#define __CORE_EXT_H
+
+#ifdef CONFIG_FMAN_ARM
+#include "arm_ext.h"
+#include <linux/smp.h>
+#else
+#ifdef NCSW_PPC_CORE
+#include "ppc_ext.h"
+#elif defined(NCSW_VXWORKS)
+#include "core_vxw_ext.h"
+#else
+#error "Core is not defined!"
+#endif /* NCSW_CORE */
+
+#if (!defined(CORE_IS_LITTLE_ENDIAN) && !defined(CORE_IS_BIG_ENDIAN))
+#error "Must define core as little-endian or big-endian!"
+#endif /* (!defined(CORE_IS_LITTLE_ENDIAN) && ... */
+
+#ifndef CORE_CACHELINE_SIZE
+#error "Must define the core cache-line size!"
+#endif /* !CORE_CACHELINE_SIZE */
+
+#endif /* CONFIG_FMAN_ARM */
+
+
+/**************************************************************************//**
+ @Function CORE_GetId
+
+ @Description Returns the core ID in the system.
+
+ @Return Core ID.
+*//***************************************************************************/
+uint32_t CORE_GetId(void);
+
+/**************************************************************************//**
+ @Function CORE_MemoryBarrier
+
+ @Description This routine will cause the core to stop executing any commands
+ until all previous memory read/write commands are completely out
+ of the core's pipeline.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_MemoryBarrier(void);
+#define fsl_mem_core_barrier() CORE_MemoryBarrier()
+
+#endif /* __CORE_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h
new file mode 100644
index 000000000000..e63444a7d676
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File arm_ext.h
+
+ @Description Core API for ARM cores
+
+ These routines must be implemented by each specific PowerPC
+ core driver.
+*//***************************************************************************/
+#ifndef __ARM_EXT_H
+#define __ARM_EXT_H
+
+#include "part_ext.h"
+
+
+#define CORE_IS_LITTLE_ENDIAN
+
+static __inline__ void CORE_MemoryBarrier(void)
+{
+ mb();
+}
+
+#endif /* __PPC_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h
new file mode 100644
index 000000000000..e79b1ddff121
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File e500v2_ext.h
+
+ @Description E500 external definitions prototypes
+ This file is not included by the E500
+ source file as it is an assembly file. It is used
+ only for prototypes exposure, for inclusion
+ by user and other modules.
+*//***************************************************************************/
+
+#ifndef __E500V2_EXT_H
+#define __E500V2_EXT_H
+
+#include "std_ext.h"
+
+
+/* Layer 1 Cache Manipulations
+ *==============================
+ * Should not be called directly by the user.
+ */
+void L1DCache_Invalidate (void);
+void L1ICache_Invalidate(void);
+void L1DCache_Enable(void);
+void L1ICache_Enable(void);
+void L1DCache_Disable(void);
+void L1ICache_Disable(void);
+void L1DCache_Flush(void);
+void L1ICache_Flush(void);
+uint32_t L1ICache_IsEnabled(void);
+uint32_t L1DCache_IsEnabled(void);
+/*
+ *
+ */
+uint32_t L1DCache_LineLock(uint32_t addr);
+uint32_t L1ICache_LineLock(uint32_t addr);
+void L1Cache_BroadCastEnable(void);
+void L1Cache_BroadCastDisable(void);
+
+
+#define CORE_DCacheEnable E500_DCacheEnable
+#define CORE_ICacheEnable E500_ICacheEnable
+#define CORE_DCacheDisable E500_DCacheDisable
+#define CORE_ICacheDisable E500_ICacheDisable
+#define CORE_GetId E500_GetId
+#define CORE_TestAndSet E500_TestAndSet
+#define CORE_MemoryBarrier E500_MemoryBarrier
+#define CORE_InstructionSync E500_InstructionSync
+
+#define CORE_SetDozeMode E500_SetDozeMode
+#define CORE_SetNapMode E500_SetNapMode
+#define CORE_SetSleepMode E500_SetSleepMode
+#define CORE_SetJogMode E500_SetJogMode
+#define CORE_SetDeepSleepMode E500_SetDeepSleepMode
+
+#define CORE_RecoverDozeMode E500_RecoverDozeMode
+#define CORE_RecoverNapMode E500_RecoverNapMode
+#define CORE_RecoverSleepMode E500_RecoverSleepMode
+#define CORE_RecoverJogMode E500_RecoverJogMode
+
+void E500_SetDozeMode(void);
+void E500_SetNapMode(void);
+void E500_SetSleepMode(void);
+void E500_SetJogMode(void);
+t_Error E500_SetDeepSleepMode(uint32_t bptrAddress);
+
+void E500_RecoverDozeMode(void);
+void E500_RecoverNapMode(void);
+void E500_RecoverSleepMode(void);
+void E500_RecoverJogMode(void);
+
+
+/**************************************************************************//**
+ @Group E500_id E500 Application Programming Interface
+
+ @Description E500 API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group E500_init_grp E500 Initialization Unit
+
+ @Description E500 initialization unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+
+/**************************************************************************//**
+ @Function E500_DCacheEnable
+
+ @Description Enables the data cache for memory pages that are
+ not cache inhibited.
+
+ @Return None.
+*//***************************************************************************/
+void E500_DCacheEnable(void);
+
+/**************************************************************************//**
+ @Function E500_ICacheEnable
+
+ @Description Enables the instruction cache for memory pages that are
+ not cache inhibited.
+
+ @Return None.
+*//***************************************************************************/
+void E500_ICacheEnable(void);
+
+/**************************************************************************//**
+ @Function E500_DCacheDisable
+
+ @Description Disables the data cache.
+
+ @Return None.
+*//***************************************************************************/
+void E500_DCacheDisable(void);
+
+/**************************************************************************//**
+ @Function E500_ICacheDisable
+
+ @Description Disables the instruction cache.
+
+ @Return None.
+*//***************************************************************************/
+void E500_ICacheDisable(void);
+
+/**************************************************************************//**
+ @Function E500_DCacheFlush
+
+ @Description Flushes the data cache
+
+ @Return None.
+*//***************************************************************************/
+void E500_DCacheFlush(void);
+
+/**************************************************************************//**
+ @Function E500_ICacheFlush
+
+ @Description Flushes the instruction cache.
+
+ @Return None.
+*//***************************************************************************/
+void E500_ICacheFlush(void);
+
+/**************************************************************************//**
+ @Function E500_DCacheSetStashId
+
+ @Description Set Stash Id for data cache
+
+ @Param[in] stashId the stash id to be set.
+
+ @Return None.
+*//***************************************************************************/
+void E500_DCacheSetStashId(uint8_t stashId);
+
+/**************************************************************************//**
+ @Description E500mc L2 Cache Operation Mode
+*//***************************************************************************/
+typedef enum e_E500mcL2CacheMode
+{
+ e_L2_CACHE_MODE_DATA_ONLY = 0x00000001, /**< Cache data only */
+ e_L2_CACHE_MODE_INST_ONLY = 0x00000002, /**< Cache instructions only */
+ e_L2_CACHE_MODE_DATA_AND_INST = 0x00000003 /**< Cache data and instructions */
+} e_E500mcL2CacheMode;
+
+#if defined(CORE_E500MC) || defined(CORE_E5500)
+/**************************************************************************//**
+ @Function E500_L2CacheEnable
+
+ @Description Enables the cache for memory pages that are not cache inhibited.
+
+ @param[in] mode - L2 cache mode: data only, instruction only or instruction and data.
+
+ @Return None.
+
+ @Cautions This routine must be call only ONCE for both caches. I.e. it is
+ not possible to call this routine for i-cache and than to call
+ again for d-cache; The second call will override the first one.
+*//***************************************************************************/
+void E500_L2CacheEnable(e_E500mcL2CacheMode mode);
+
+/**************************************************************************//**
+ @Function E500_L2CacheDisable
+
+ @Description Disables the cache (data instruction or both).
+
+ @Return None.
+
+*//***************************************************************************/
+void E500_L2CacheDisable(void);
+
+/**************************************************************************//**
+ @Function E500_L2CacheFlush
+
+ @Description Flushes the cache.
+
+ @Return None.
+*//***************************************************************************/
+void E500_L2CacheFlush(void);
+
+/**************************************************************************//**
+ @Function E500_L2SetStashId
+
+ @Description Set Stash Id
+
+ @Param[in] stashId the stash id to be set.
+
+ @Return None.
+*//***************************************************************************/
+void E500_L2SetStashId(uint8_t stashId);
+#endif /* defined(CORE_E500MC) || defined(CORE_E5500) */
+
+#ifdef CORE_E6500
+/**************************************************************************//**
+ @Function E6500_L2CacheEnable
+
+ @Description Enables the cache for memory pages that are not cache inhibited.
+
+ @param[in] mode - L2 cache mode: support data & instruction only.
+
+ @Return None.
+
+ @Cautions This routine must be call only ONCE for both caches. I.e. it is
+ not possible to call this routine for i-cache and than to call
+ again for d-cache; The second call will override the first one.
+*//***************************************************************************/
+void E6500_L2CacheEnable(uintptr_t clusterBase);
+
+/**************************************************************************//**
+ @Function E6500_L2CacheDisable
+
+ @Description Disables the cache (data instruction or both).
+
+ @Return None.
+
+*//***************************************************************************/
+void E6500_L2CacheDisable(uintptr_t clusterBase);
+
+/**************************************************************************//**
+ @Function E6500_L2CacheFlush
+
+ @Description Flushes the cache.
+
+ @Return None.
+*//***************************************************************************/
+void E6500_L2CacheFlush(uintptr_t clusterBase);
+
+/**************************************************************************//**
+ @Function E6500_L2SetStashId
+
+ @Description Set Stash Id
+
+ @Param[in] stashId the stash id to be set.
+
+ @Return None.
+*//***************************************************************************/
+void E6500_L2SetStashId(uintptr_t clusterBase, uint8_t stashId);
+
+/**************************************************************************//**
+ @Function E6500_GetCcsrBase
+
+ @Description Obtain SoC CCSR base address
+
+ @Param[in] None.
+
+ @Return Physical CCSR base address.
+*//***************************************************************************/
+physAddress_t E6500_GetCcsrBase(void);
+#endif /* CORE_E6500 */
+
+/**************************************************************************//**
+ @Function E500_AddressBusStreamingEnable
+
+ @Description Enables address bus streaming on the CCB.
+
+ This setting, along with the ECM streaming configuration
+ parameters, enables address bus streaming on the CCB.
+
+ @Return None.
+*//***************************************************************************/
+void E500_AddressBusStreamingEnable(void);
+
+/**************************************************************************//**
+ @Function E500_AddressBusStreamingDisable
+
+ @Description Disables address bus streaming on the CCB.
+
+ @Return None.
+*//***************************************************************************/
+void E500_AddressBusStreamingDisable(void);
+
+/**************************************************************************//**
+ @Function E500_AddressBroadcastEnable
+
+ @Description Enables address broadcast.
+
+ The e500 broadcasts cache management instructions (dcbst, dcblc
+ (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi)
+ based on ABE. ABE must be set to allow management of external
+ L2 caches.
+
+ @Return None.
+*//***************************************************************************/
+void E500_AddressBroadcastEnable(void);
+
+/**************************************************************************//**
+ @Function E500_AddressBroadcastDisable
+
+ @Description Disables address broadcast.
+
+ The e500 broadcasts cache management instructions (dcbst, dcblc
+ (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi)
+ based on ABE. ABE must be set to allow management of external
+ L2 caches.
+
+ @Return None.
+*//***************************************************************************/
+void E500_AddressBroadcastDisable(void);
+
+/**************************************************************************//**
+ @Function E500_IsTaskletSupported
+
+ @Description Checks if tasklets are supported by the e500 interrupt handler.
+
+ @Retval TRUE - Tasklets are supported.
+ @Retval FALSE - Tasklets are not supported.
+*//***************************************************************************/
+bool E500_IsTaskletSupported(void);
+
+void E500_EnableTimeBase(void);
+void E500_DisableTimeBase(void);
+
+uint64_t E500_GetTimeBaseTime(void);
+
+void E500_GenericIntrInit(void);
+
+t_Error E500_SetIntr(int ppcIntrSrc,
+ void (* Isr)(t_Handle handle),
+ t_Handle handle);
+
+t_Error E500_ClearIntr(int ppcIntrSrc);
+
+/**************************************************************************//**
+ @Function E500_GenericIntrHandler
+
+ @Description This is the general e500 interrupt handler.
+
+ It is called by the main assembly interrupt handler
+ when an exception occurs and no other function has been
+ assigned to this exception.
+
+ @Param intrEntry - (In) The exception interrupt vector entry.
+*//***************************************************************************/
+void E500_GenericIntrHandler(uint32_t intrEntry);
+
+/**************************************************************************//**
+ @Function CriticalIntr
+
+ @Description This is the specific critical e500 interrupt handler.
+
+ It is called by the main assembly interrupt handler
+ when an critical interrupt.
+
+ @Param intrEntry - (In) The exception interrupt vector entry.
+*//***************************************************************************/
+void CriticalIntr(uint32_t intrEntry);
+
+
+/**************************************************************************//**
+ @Function E500_GetId
+
+ @Description Returns the core ID in the system.
+
+ @Return Core ID.
+*//***************************************************************************/
+uint32_t E500_GetId(void);
+
+/**************************************************************************//**
+ @Function E500_TestAndSet
+
+ @Description This routine tries to atomically test-and-set an integer
+ in memory to a non-zero value.
+
+ The memory will be set only if it is tested as zero, in which
+ case the routine returns the new non-zero value; otherwise the
+ routine returns zero.
+
+ @Param[in] p - pointer to a volatile int in memory, on which test-and-set
+ operation should be made.
+
+ @Retval Zero - Operation failed - memory was already set.
+ @Retval Non-zero - Operation succeeded - memory has been set.
+*//***************************************************************************/
+int E500_TestAndSet(volatile int *p);
+
+/**************************************************************************//**
+ @Function E500_MemoryBarrier
+
+ @Description This routine will cause the core to stop executing any commands
+ until all previous memory read/write commands are completely out
+ of the core's pipeline.
+
+ @Return None.
+*//***************************************************************************/
+static __inline__ void E500_MemoryBarrier(void)
+{
+#ifndef CORE_E500V2
+ __asm__ ("mbar 1");
+#else /* CORE_E500V2 */
+ /**** ERRATA WORK AROUND START ****/
+ /* ERRATA num: CPU1 */
+ /* Description: "mbar MO = 1" instruction fails to order caching-inhibited
+ guarded loads and stores. */
+
+ /* "msync" instruction is used instead */
+
+ __asm__ ("msync");
+
+ /**** ERRATA WORK AROUND END ****/
+#endif /* CORE_E500V2 */
+}
+
+/**************************************************************************//**
+ @Function E500_InstructionSync
+
+ @Description This routine will cause the core to wait for previous instructions
+ (including any interrupts they generate) to complete before the
+ synchronization command executes, which purges all instructions
+ from the processor's pipeline and refetches the next instruction.
+
+ @Return None.
+*//***************************************************************************/
+static __inline__ void E500_InstructionSync(void)
+{
+ __asm__ ("isync");
+}
+
+
+/** @} */ /* end of E500_init_grp group */
+/** @} */ /* end of E500_grp group */
+
+
+#endif /* __E500V2_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h
new file mode 100644
index 000000000000..9344b3a1f472
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File ppc_ext.h
+
+ @Description Core API for PowerPC cores
+
+ These routines must be implemented by each specific PowerPC
+ core driver.
+*//***************************************************************************/
+#ifndef __PPC_EXT_H
+#define __PPC_EXT_H
+
+#include "part_ext.h"
+
+
+#define CORE_IS_BIG_ENDIAN
+
+#if defined(CORE_E300) || defined(CORE_E500V2)
+#define CORE_CACHELINE_SIZE 32
+#elif defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500)
+#define CORE_CACHELINE_SIZE 64
+#else
+#error "Core not defined!"
+#endif /* defined(CORE_E300) || ... */
+
+
+/**************************************************************************//**
+ @Function CORE_TestAndSet
+
+ @Description This routine tries to atomically test-and-set an integer
+ in memory to a non-zero value.
+
+ The memory will be set only if it is tested as zero, in which
+ case the routine returns the new non-zero value; otherwise the
+ routine returns zero.
+
+ @Param[in] p - pointer to a volatile int in memory, on which test-and-set
+ operation should be made.
+
+ @Retval Zero - Operation failed - memory was already set.
+ @Retval Non-zero - Operation succeeded - memory has been set.
+*//***************************************************************************/
+int CORE_TestAndSet(volatile int *p);
+
+/**************************************************************************//**
+ @Function CORE_InstructionSync
+
+ @Description This routine will cause the core to wait for previous instructions
+ (including any interrupts they generate) to complete before the
+ synchronization command executes, which purges all instructions
+ from the processor's pipeline and refetches the next instruction.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_InstructionSync(void);
+
+/**************************************************************************//**
+ @Function CORE_DCacheEnable
+
+ @Description Enables the data cache for memory pages that are
+ not cache inhibited.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_DCacheEnable(void);
+
+/**************************************************************************//**
+ @Function CORE_ICacheEnable
+
+ @Description Enables the instruction cache for memory pages that are
+ not cache inhibited.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_ICacheEnable(void);
+
+/**************************************************************************//**
+ @Function CORE_DCacheDisable
+
+ @Description Disables the data cache.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_DCacheDisable(void);
+
+/**************************************************************************//**
+ @Function CORE_ICacheDisable
+
+ @Description Disables the instruction cache.
+
+ @Return None.
+*//***************************************************************************/
+void CORE_ICacheDisable(void);
+
+
+
+#if defined(CORE_E300)
+#include "e300_ext.h"
+#elif defined(CORE_E500V2) || defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500)
+#include "e500v2_ext.h"
+#if !defined(NCSW_LINUX)
+#include "e500v2_asm_ext.h"
+#endif
+#else
+#error "Core not defined!"
+#endif
+
+
+#endif /* __PPC_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h
new file mode 100644
index 000000000000..8bb343fc2852
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __DDR_SDT_EXT_H
+#define __DDR_SDT_EXT_H
+
+
+/**************************************************************************//**
+ @Group ddr_Generic_Resources
+
+ @Description ddr generic functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+
+/**************************************************************************//**
+ @Description SPD maximum size
+*//***************************************************************************/
+#define SPD_MAX_SIZE 256
+
+/**************************************************************************//**
+ @Description DDR types select
+*//***************************************************************************/
+typedef enum e_DdrType
+{
+ e_DDR_DDR1,
+ e_DDR_DDR2,
+ e_DDR_DDR3,
+ e_DDR_DDR3L,
+ e_DDR_DDR4
+} e_DdrType;
+
+/**************************************************************************//**
+ @Description DDR Mode.
+*//***************************************************************************/
+typedef enum e_DdrMode
+{
+ e_DDR_BUS_WIDTH_32BIT,
+ e_DDR_BUS_WIDTH_64BIT
+} e_DdrMode;
+
+/** @} */ /* end of ddr_Generic_Resources group */
+
+
+
+#endif /* __DDR_SDT_EXT_H */
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h
new file mode 100644
index 000000000000..57db0a1486cd
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File debug_ext.h
+
+ @Description Debug mode definitions.
+*//***************************************************************************/
+
+#ifndef __DEBUG_EXT_H
+#define __DEBUG_EXT_H
+
+#include "std_ext.h"
+#include "xx_ext.h"
+#include "memcpy_ext.h"
+#if (DEBUG_ERRORS > 0)
+#include "sprint_ext.h"
+#include "string_ext.h"
+#endif /* DEBUG_ERRORS > 0 */
+
+
+#if (DEBUG_ERRORS > 0)
+
+/* Internally used macros */
+
+#define DUMP_Print XX_Print
+#define DUMP_MAX_LEVELS 6
+#define DUMP_IDX_LEN 6
+#define DUMP_MAX_STR 64
+
+
+#define _CREATE_DUMP_SUBSTR(phrase) \
+ dumpTmpLevel = 0; dumpSubStr[0] = '\0'; \
+ snprintf(dumpTmpStr, DUMP_MAX_STR, "%s", #phrase); \
+ p_DumpToken = strtok(dumpTmpStr, (dumpIsArr[0] ? "[" : ".")); \
+ while ((p_DumpToken != NULL) && (dumpTmpLevel < DUMP_MAX_LEVELS)) \
+ { \
+ strlcat(dumpSubStr, p_DumpToken, DUMP_MAX_STR); \
+ if (dumpIsArr[dumpTmpLevel]) \
+ { \
+ strlcat(dumpSubStr, dumpIdxStr[dumpTmpLevel], DUMP_MAX_STR); \
+ p_DumpToken = strtok(NULL, "."); \
+ } \
+ if ((p_DumpToken != NULL) && \
+ ((p_DumpToken = strtok(NULL, (dumpIsArr[++dumpTmpLevel] ? "[" : "."))) != NULL)) \
+ strlcat(dumpSubStr, ".", DUMP_MAX_STR); \
+ }
+
+
+/**************************************************************************//**
+ @Group gen_id General Drivers Utilities
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group dump_id Memory and Registers Dump Mechanism
+
+ @Description Macros for dumping memory mapped structures.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Declaration of dump mechanism variables.
+
+ This macro must be declared at the beginning of each routine
+ which uses the dump mechanism macros, before the routine's code
+ starts.
+*//***************************************************************************/
+#define DECLARE_DUMP \
+ char dumpIdxStr[DUMP_MAX_LEVELS + 1][DUMP_IDX_LEN] = { "", }; \
+ char dumpSubStr[DUMP_MAX_STR] = ""; \
+ char dumpTmpStr[DUMP_MAX_STR] = ""; \
+ char *p_DumpToken = NULL; \
+ int dumpArrIdx = 0, dumpArrSize = 0, dumpLevel = 0, dumpTmpLevel = 0; \
+ uint8_t dumpIsArr[DUMP_MAX_LEVELS + 1] = { 0 }; \
+ /* Prevent warnings if not all used */ \
+ UNUSED(dumpIdxStr[0][0]); \
+ UNUSED(dumpSubStr[0]); \
+ UNUSED(dumpTmpStr[0]); \
+ UNUSED(p_DumpToken); \
+ UNUSED(dumpArrIdx); \
+ UNUSED(dumpArrSize); \
+ UNUSED(dumpLevel); \
+ UNUSED(dumpTmpLevel); \
+ UNUSED(dumpIsArr[0]);
+
+
+/**************************************************************************//**
+ @Description Prints a title for a subsequent dumped structure or memory.
+
+ The inputs for this macro are the structure/memory title and
+ its base addresses.
+*//***************************************************************************/
+#define DUMP_TITLE(addr, msg) \
+ DUMP_Print("\r\n"); DUMP_Print msg; \
+ if (addr) \
+ DUMP_Print(" (%p)", (addr)); \
+ DUMP_Print("\r\n---------------------------------------------------------\r\n");
+
+/**************************************************************************//**
+ @Description Prints a subtitle for a subsequent dumped sub-structure (optional).
+
+ The inputs for this macro are the sub-structure subtitle.
+ A separating line with this subtitle will be printed.
+*//***************************************************************************/
+#define DUMP_SUBTITLE(subtitle) \
+ DUMP_Print("----------- "); DUMP_Print subtitle; DUMP_Print("\r\n")
+
+
+/**************************************************************************//**
+ @Description Dumps a memory region in 4-bytes aligned format.
+
+ The inputs for this macro are the base addresses and size
+ (in bytes) of the memory region.
+*//***************************************************************************/
+#define DUMP_MEMORY(addr, size) \
+ MemDisp((uint8_t *)(addr), (int)(size))
+
+
+/**************************************************************************//**
+ @Description Declares a dump loop, for dumping a sub-structure array.
+
+ The inputs for this macro are:
+ - idx: an index variable, for indexing the sub-structure items
+ inside the loop. This variable must be declared separately
+ in the beginning of the routine.
+ - cnt: the number of times to repeat the loop. This number should
+ equal the number of items in the sub-structures array.
+
+ Note, that the body of the loop must be written inside brackets.
+*//***************************************************************************/
+#define DUMP_SUBSTRUCT_ARRAY(idx, cnt) \
+ for (idx=0, dumpIsArr[dumpLevel++] = 1; \
+ (idx < cnt) && (dumpLevel > 0) && snprintf(dumpIdxStr[dumpLevel-1], DUMP_IDX_LEN, "[%d]", idx); \
+ idx++, ((idx < cnt) || (dumpIsArr[--dumpLevel] = 0)))
+
+
+/**************************************************************************//**
+ @Description Dumps a structure's member variable.
+
+ The input for this macro is the full reference for the member
+ variable, where the structure is referenced using a pointer.
+
+ Note, that a members array must be dumped using DUMP_ARR macro,
+ rather than using this macro.
+
+ If the member variable is part of a sub-structure hierarchy,
+ the full hierarchy (including array indexing) must be specified.
+
+ Examples: p_Struct->member
+ p_Struct->sub.member
+ p_Struct->sub[i].member
+*//***************************************************************************/
+#define DUMP_VAR(st, phrase) \
+ do { \
+ void *addr = (void *)&((st)->phrase); \
+ physAddress_t physAddr = XX_VirtToPhys(addr); \
+ _CREATE_DUMP_SUBSTR(phrase); \
+ DUMP_Print("0x%010llX: 0x%08x%8s\t%s\r\n", \
+ physAddr, GET_UINT32(*(uint32_t*)addr), "", dumpSubStr); \
+ } while (0)
+
+
+/**************************************************************************//**
+ @Description Dumps a structure's members array.
+
+ The input for this macro is the full reference for the members
+ array, where the structure is referenced using a pointer.
+
+ If the members array is part of a sub-structure hierarchy,
+ the full hierarchy (including array indexing) must be specified.
+
+ Examples: p_Struct->array
+ p_Struct->sub.array
+ p_Struct->sub[i].array
+*//***************************************************************************/
+#define DUMP_ARR(st, phrase) \
+ do { \
+ physAddress_t physAddr; \
+ _CREATE_DUMP_SUBSTR(phrase); \
+ dumpArrSize = ARRAY_SIZE((st)->phrase); \
+ for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \
+ physAddr = XX_VirtToPhys((void *)&((st)->phrase[dumpArrIdx])); \
+ DUMP_Print("0x%010llX: 0x%08x%8s\t%s[%d]\r\n", \
+ physAddr, GET_UINT32((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \
+ } \
+ } while (0)
+
+
+
+#endif /* DEBUG_ERRORS > 0 */
+
+
+/** @} */ /* end of dump_id group */
+/** @} */ /* end of gen_id group */
+
+
+#endif /* __DEBUG_EXT_H */
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h
new file mode 100644
index 000000000000..5cdec668aedf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File endian_ext.h
+
+ @Description Big/little endian swapping routines.
+*//***************************************************************************/
+
+#ifndef __ENDIAN_EXT_H
+#define __ENDIAN_EXT_H
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group gen_id General Drivers Utilities
+
+ @Description General usage API. This API is intended for usage by both the
+ internal modules and the user's application.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group endian_id Big/Little-Endian Conversion
+
+ @Description Routines and macros for Big/Little-Endian conversion and
+ general byte swapping.
+
+ All routines and macros are expecting unsigned values as
+ parameters, but will generate the correct result also for
+ signed values. Therefore, signed/unsigned casting is allowed.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Collection Byte-Swap Macros
+
+ Macros for swapping byte order.
+
+ @Cautions The parameters of these macros are evaluated multiple times.
+ For calculated expressions or expressions that contain function
+ calls it is recommended to use the byte-swap routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Swaps the byte order of a given 16-bit value.
+
+ @Param[in] val - The 16-bit value to swap.
+
+ @Return The byte-swapped value..
+
+ @Cautions The given value is evaluated multiple times by this macro.
+ For calculated expressions or expressions that contain function
+ calls it is recommended to use the SwapUint16() routine.
+
+ @hideinitializer
+*//***************************************************************************/
+#define SWAP_UINT16(val) \
+ ((uint16_t)((((val) & 0x00FF) << 8) | (((val) & 0xFF00) >> 8)))
+
+/**************************************************************************//**
+ @Description Swaps the byte order of a given 32-bit value.
+
+ @Param[in] val - The 32-bit value to swap.
+
+ @Return The byte-swapped value..
+
+ @Cautions The given value is evaluated multiple times by this macro.
+ For calculated expressions or expressions that contain function
+ calls it is recommended to use the SwapUint32() routine.
+
+ @hideinitializer
+*//***************************************************************************/
+#define SWAP_UINT32(val) \
+ ((uint32_t)((((val) & 0x000000FF) << 24) | \
+ (((val) & 0x0000FF00) << 8) | \
+ (((val) & 0x00FF0000) >> 8) | \
+ (((val) & 0xFF000000) >> 24)))
+
+/**************************************************************************//**
+ @Description Swaps the byte order of a given 64-bit value.
+
+ @Param[in] val - The 64-bit value to swap.
+
+ @Return The byte-swapped value..
+
+ @Cautions The given value is evaluated multiple times by this macro.
+ For calculated expressions or expressions that contain function
+ calls it is recommended to use the SwapUint64() routine.
+
+ @hideinitializer
+*//***************************************************************************/
+#define SWAP_UINT64(val) \
+ ((uint64_t)((((val) & 0x00000000000000FFULL) << 56) | \
+ (((val) & 0x000000000000FF00ULL) << 40) | \
+ (((val) & 0x0000000000FF0000ULL) << 24) | \
+ (((val) & 0x00000000FF000000ULL) << 8) | \
+ (((val) & 0x000000FF00000000ULL) >> 8) | \
+ (((val) & 0x0000FF0000000000ULL) >> 24) | \
+ (((val) & 0x00FF000000000000ULL) >> 40) | \
+ (((val) & 0xFF00000000000000ULL) >> 56)))
+
+/* @} */
+
+/**************************************************************************//**
+ @Collection Byte-Swap Routines
+
+ Routines for swapping the byte order of a given parameter and
+ returning the swapped value.
+
+ These inline routines are safer than the byte-swap macros,
+ because they evaluate the parameter expression only once.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function SwapUint16
+
+ @Description Returns the byte-swapped value of a given 16-bit value.
+
+ @Param[in] val - The 16-bit value.
+
+ @Return The byte-swapped value of the parameter.
+*//***************************************************************************/
+static __inline__ uint16_t SwapUint16(uint16_t val)
+{
+ return (uint16_t)(((val & 0x00FF) << 8) |
+ ((val & 0xFF00) >> 8));
+}
+
+/**************************************************************************//**
+ @Function SwapUint32
+
+ @Description Returns the byte-swapped value of a given 32-bit value.
+
+ @Param[in] val - The 32-bit value.
+
+ @Return The byte-swapped value of the parameter.
+*//***************************************************************************/
+static __inline__ uint32_t SwapUint32(uint32_t val)
+{
+ return (uint32_t)(((val & 0x000000FF) << 24) |
+ ((val & 0x0000FF00) << 8) |
+ ((val & 0x00FF0000) >> 8) |
+ ((val & 0xFF000000) >> 24));
+}
+
+/**************************************************************************//**
+ @Function SwapUint64
+
+ @Description Returns the byte-swapped value of a given 64-bit value.
+
+ @Param[in] val - The 64-bit value.
+
+ @Return The byte-swapped value of the parameter.
+*//***************************************************************************/
+static __inline__ uint64_t SwapUint64(uint64_t val)
+{
+ return (uint64_t)(((val & 0x00000000000000FFULL) << 56) |
+ ((val & 0x000000000000FF00ULL) << 40) |
+ ((val & 0x0000000000FF0000ULL) << 24) |
+ ((val & 0x00000000FF000000ULL) << 8) |
+ ((val & 0x000000FF00000000ULL) >> 8) |
+ ((val & 0x0000FF0000000000ULL) >> 24) |
+ ((val & 0x00FF000000000000ULL) >> 40) |
+ ((val & 0xFF00000000000000ULL) >> 56));
+}
+
+/* @} */
+
+/**************************************************************************//**
+ @Collection In-place Byte-Swap-And-Set Routines
+
+ Routines for swapping the byte order of a given variable and
+ setting the swapped value back to the same variable.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function SwapUint16P
+
+ @Description Swaps the byte order of a given 16-bit variable.
+
+ @Param[in] p_Val - Pointer to the 16-bit variable.
+
+ @Return None.
+*//***************************************************************************/
+static __inline__ void SwapUint16P(uint16_t *p_Val)
+{
+ *p_Val = SwapUint16(*p_Val);
+}
+
+/**************************************************************************//**
+ @Function SwapUint32P
+
+ @Description Swaps the byte order of a given 32-bit variable.
+
+ @Param[in] p_Val - Pointer to the 32-bit variable.
+
+ @Return None.
+*//***************************************************************************/
+static __inline__ void SwapUint32P(uint32_t *p_Val)
+{
+ *p_Val = SwapUint32(*p_Val);
+}
+
+/**************************************************************************//**
+ @Function SwapUint64P
+
+ @Description Swaps the byte order of a given 64-bit variable.
+
+ @Param[in] p_Val - Pointer to the 64-bit variable.
+
+ @Return None.
+*//***************************************************************************/
+static __inline__ void SwapUint64P(uint64_t *p_Val)
+{
+ *p_Val = SwapUint64(*p_Val);
+}
+
+/* @} */
+
+
+/**************************************************************************//**
+ @Collection Little-Endian Conversion Macros
+
+ These macros convert given parameters to or from Little-Endian
+ format. Use these macros when you want to read or write a specific
+ Little-Endian value in memory, without a-priori knowing the CPU
+ byte order.
+
+ These macros use the byte-swap routines. For conversion of
+ constants in initialization structures, you may use the CONST
+ versions of these macros (see below), which are using the
+ byte-swap macros instead.
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Converts a given 16-bit value from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 16-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CPU_TO_LE16(val) SwapUint16(val)
+
+/**************************************************************************//**
+ @Description Converts a given 32-bit value from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 32-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CPU_TO_LE32(val) SwapUint32(val)
+
+/**************************************************************************//**
+ @Description Converts a given 64-bit value from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 64-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CPU_TO_LE64(val) SwapUint64(val)
+
+
+/**************************************************************************//**
+ @Description Converts a given 16-bit value from Little-Endian byte order to
+ CPU byte order.
+
+ @Param[in] val - The 16-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define LE16_TO_CPU(val) CPU_TO_LE16(val)
+
+/**************************************************************************//**
+ @Description Converts a given 32-bit value from Little-Endian byte order to
+ CPU byte order.
+
+ @Param[in] val - The 32-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define LE32_TO_CPU(val) CPU_TO_LE32(val)
+
+/**************************************************************************//**
+ @Description Converts a given 64-bit value from Little-Endian byte order to
+ CPU byte order.
+
+ @Param[in] val - The 64-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define LE64_TO_CPU(val) CPU_TO_LE64(val)
+
+/* @} */
+
+/**************************************************************************//**
+ @Collection Little-Endian Constant Conversion Macros
+
+ These macros convert given constants to or from Little-Endian
+ format. Use these macros when you want to read or write a specific
+ Little-Endian constant in memory, without a-priori knowing the
+ CPU byte order.
+
+ These macros use the byte-swap macros, therefore can be used for
+ conversion of constants in initialization structures.
+
+ @Cautions The parameters of these macros are evaluated multiple times.
+ For non-constant expressions, use the non-CONST macro versions.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Converts a given 16-bit constant from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 16-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_CPU_TO_LE16(val) SWAP_UINT16(val)
+
+/**************************************************************************//**
+ @Description Converts a given 32-bit constant from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 32-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_CPU_TO_LE32(val) SWAP_UINT32(val)
+
+/**************************************************************************//**
+ @Description Converts a given 64-bit constant from CPU byte order to
+ Little-Endian byte order.
+
+ @Param[in] val - The 64-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_CPU_TO_LE64(val) SWAP_UINT64(val)
+
+
+/**************************************************************************//**
+ @Description Converts a given 16-bit constant from Little-Endian byte order
+ to CPU byte order.
+
+ @Param[in] val - The 16-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_LE16_TO_CPU(val) CONST_CPU_TO_LE16(val)
+
+/**************************************************************************//**
+ @Description Converts a given 32-bit constant from Little-Endian byte order
+ to CPU byte order.
+
+ @Param[in] val - The 32-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_LE32_TO_CPU(val) CONST_CPU_TO_LE32(val)
+
+/**************************************************************************//**
+ @Description Converts a given 64-bit constant from Little-Endian byte order
+ to CPU byte order.
+
+ @Param[in] val - The 64-bit value to convert.
+
+ @Return The converted value.
+
+ @hideinitializer
+*//***************************************************************************/
+#define CONST_LE64_TO_CPU(val) CONST_CPU_TO_LE64(val)
+
+/* @} */
+
+
+/** @} */ /* end of endian_id group */
+/** @} */ /* end of gen_id group */
+
+
+#endif /* __ENDIAN_EXT_H */
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h
new file mode 100644
index 000000000000..ef3bee55e897
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h
@@ -0,0 +1,205 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File enet_ext.h
+
+ @Description Ethernet generic definitions and enums.
+*//***************************************************************************/
+
+#ifndef __ENET_EXT_H
+#define __ENET_EXT_H
+
+#include "fsl_enet.h"
+
+#define ENET_NUM_OCTETS_PER_ADDRESS 6 /**< Number of octets (8-bit bytes) in an ethernet address */
+#define ENET_GROUP_ADDR 0x01 /**< Group address mask for ethernet addresses */
+
+
+/**************************************************************************//**
+ @Description Ethernet Address
+*//***************************************************************************/
+typedef uint8_t t_EnetAddr[ENET_NUM_OCTETS_PER_ADDRESS];
+
+/**************************************************************************//**
+ @Description Ethernet Address Type.
+*//***************************************************************************/
+typedef enum e_EnetAddrType
+{
+ e_ENET_ADDR_TYPE_INDIVIDUAL, /**< Individual (unicast) address */
+ e_ENET_ADDR_TYPE_GROUP, /**< Group (multicast) address */
+ e_ENET_ADDR_TYPE_BROADCAST /**< Broadcast address */
+} e_EnetAddrType;
+
+/**************************************************************************//**
+ @Description Ethernet MAC-PHY Interface
+*//***************************************************************************/
+typedef enum e_EnetInterface
+{
+ e_ENET_IF_MII = E_ENET_IF_MII, /**< MII interface */
+ e_ENET_IF_RMII = E_ENET_IF_RMII, /**< RMII interface */
+ e_ENET_IF_SMII = E_ENET_IF_SMII, /**< SMII interface */
+ e_ENET_IF_GMII = E_ENET_IF_GMII, /**< GMII interface */
+ e_ENET_IF_RGMII = E_ENET_IF_RGMII, /**< RGMII interface */
+ e_ENET_IF_TBI = E_ENET_IF_TBI, /**< TBI interface */
+ e_ENET_IF_RTBI = E_ENET_IF_RTBI, /**< RTBI interface */
+ e_ENET_IF_SGMII = E_ENET_IF_SGMII, /**< SGMII interface */
+ e_ENET_IF_XGMII = E_ENET_IF_XGMII, /**< XGMII interface */
+ e_ENET_IF_QSGMII= E_ENET_IF_QSGMII, /**< QSGMII interface */
+ e_ENET_IF_XFI = E_ENET_IF_XFI /**< XFI interface */
+} e_EnetInterface;
+
+#define ENET_IF_SGMII_BASEX 0x80000000 /**< SGMII/QSGII interface with 1000BaseX
+ auto-negotiation between MAC and phy
+ or backplane;
+ Note: 1000BaseX auto-negotiation relates
+ only to interface between MAC and phy/backplane,
+ SGMII phy can still synchronize with far-end phy
+ at 10Mbps, 100Mbps or 1000Mbps */
+
+/**************************************************************************//**
+ @Description Ethernet Duplex Mode
+*//***************************************************************************/
+typedef enum e_EnetDuplexMode
+{
+ e_ENET_HALF_DUPLEX, /**< Half-Duplex mode */
+ e_ENET_FULL_DUPLEX /**< Full-Duplex mode */
+} e_EnetDuplexMode;
+
+/**************************************************************************//**
+ @Description Ethernet Speed (nominal data rate)
+*//***************************************************************************/
+typedef enum e_EnetSpeed
+{
+ e_ENET_SPEED_10 = E_ENET_SPEED_10, /**< 10 Mbps */
+ e_ENET_SPEED_100 = E_ENET_SPEED_100, /**< 100 Mbps */
+ e_ENET_SPEED_1000 = E_ENET_SPEED_1000, /**< 1000 Mbps = 1 Gbps */
+ e_ENET_SPEED_2500 = E_ENET_SPEED_2500, /**< 2500 Mbps = 2.5 Gbps */
+ e_ENET_SPEED_10000 = E_ENET_SPEED_10000 /**< 10000 Mbps = 10 Gbps */
+} e_EnetSpeed;
+
+/**************************************************************************//**
+ @Description Ethernet mode (combination of MAC-PHY interface and speed)
+*//***************************************************************************/
+typedef enum e_EnetMode
+{
+ e_ENET_MODE_INVALID = 0, /**< Invalid Ethernet mode */
+ e_ENET_MODE_MII_10 = (e_ENET_IF_MII | e_ENET_SPEED_10), /**< 10 Mbps MII */
+ e_ENET_MODE_MII_100 = (e_ENET_IF_MII | e_ENET_SPEED_100), /**< 100 Mbps MII */
+ e_ENET_MODE_RMII_10 = (e_ENET_IF_RMII | e_ENET_SPEED_10), /**< 10 Mbps RMII */
+ e_ENET_MODE_RMII_100 = (e_ENET_IF_RMII | e_ENET_SPEED_100), /**< 100 Mbps RMII */
+ e_ENET_MODE_SMII_10 = (e_ENET_IF_SMII | e_ENET_SPEED_10), /**< 10 Mbps SMII */
+ e_ENET_MODE_SMII_100 = (e_ENET_IF_SMII | e_ENET_SPEED_100), /**< 100 Mbps SMII */
+ e_ENET_MODE_GMII_1000 = (e_ENET_IF_GMII | e_ENET_SPEED_1000), /**< 1000 Mbps GMII */
+ e_ENET_MODE_RGMII_10 = (e_ENET_IF_RGMII | e_ENET_SPEED_10), /**< 10 Mbps RGMII */
+ e_ENET_MODE_RGMII_100 = (e_ENET_IF_RGMII | e_ENET_SPEED_100), /**< 100 Mbps RGMII */
+ e_ENET_MODE_RGMII_1000 = (e_ENET_IF_RGMII | e_ENET_SPEED_1000), /**< 1000 Mbps RGMII */
+ e_ENET_MODE_TBI_1000 = (e_ENET_IF_TBI | e_ENET_SPEED_1000), /**< 1000 Mbps TBI */
+ e_ENET_MODE_RTBI_1000 = (e_ENET_IF_RTBI | e_ENET_SPEED_1000), /**< 1000 Mbps RTBI */
+ e_ENET_MODE_SGMII_10 = (e_ENET_IF_SGMII | e_ENET_SPEED_10),
+ /**< 10 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ e_ENET_MODE_SGMII_100 = (e_ENET_IF_SGMII | e_ENET_SPEED_100),
+ /**< 100 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ e_ENET_MODE_SGMII_1000 = (e_ENET_IF_SGMII | e_ENET_SPEED_1000),
+ /**< 1000 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ e_ENET_MODE_SGMII_2500 = (e_ENET_IF_SGMII | e_ENET_SPEED_2500),
+ e_ENET_MODE_SGMII_BASEX_10 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_10),
+ /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ e_ENET_MODE_SGMII_BASEX_100 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_100),
+ /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ e_ENET_MODE_SGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_1000),
+ /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ e_ENET_MODE_QSGMII_1000 = (e_ENET_IF_QSGMII| e_ENET_SPEED_1000),
+ /**< 1000 Mbps QSGMII with auto-negotiation between MAC and
+ QSGMII phy according to Cisco QSGMII specification */
+ e_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | e_ENET_IF_QSGMII| e_ENET_SPEED_1000),
+ /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
+ MAC and QSGMII phy or backplane */
+ e_ENET_MODE_XGMII_10000 = (e_ENET_IF_XGMII | e_ENET_SPEED_10000), /**< 10000 Mbps XGMII */
+ e_ENET_MODE_XFI_10000 = (e_ENET_IF_XFI | e_ENET_SPEED_10000) /**< 10000 Mbps XFI */
+} e_EnetMode;
+
+
+#define IS_ENET_MODE_VALID(mode) \
+ (((mode) == e_ENET_MODE_MII_10 ) || \
+ ((mode) == e_ENET_MODE_MII_100 ) || \
+ ((mode) == e_ENET_MODE_RMII_10 ) || \
+ ((mode) == e_ENET_MODE_RMII_100 ) || \
+ ((mode) == e_ENET_MODE_SMII_10 ) || \
+ ((mode) == e_ENET_MODE_SMII_100 ) || \
+ ((mode) == e_ENET_MODE_GMII_1000 ) || \
+ ((mode) == e_ENET_MODE_RGMII_10 ) || \
+ ((mode) == e_ENET_MODE_RGMII_100 ) || \
+ ((mode) == e_ENET_MODE_RGMII_1000 ) || \
+ ((mode) == e_ENET_MODE_TBI_1000 ) || \
+ ((mode) == e_ENET_MODE_RTBI_1000 ) || \
+ ((mode) == e_ENET_MODE_SGMII_10 ) || \
+ ((mode) == e_ENET_MODE_SGMII_100 ) || \
+ ((mode) == e_ENET_MODE_SGMII_1000 ) || \
+ ((mode) == e_ENET_MODE_SGMII_BASEX_10 ) || \
+ ((mode) == e_ENET_MODE_SGMII_BASEX_100 ) || \
+ ((mode) == e_ENET_MODE_SGMII_BASEX_1000 ) || \
+ ((mode) == e_ENET_MODE_XGMII_10000) || \
+ ((mode) == e_ENET_MODE_QSGMII_1000) || \
+ ((mode) == e_ENET_MODE_QSGMII_BASEX_1000) || \
+ ((mode) == e_ENET_MODE_XFI_10000))
+
+
+#define MAKE_ENET_MODE(_interface, _speed) (e_EnetMode)((_interface) | (_speed))
+
+#define ENET_INTERFACE_FROM_MODE(mode) (e_EnetInterface)((mode) & 0x0FFF0000)
+#define ENET_SPEED_FROM_MODE(mode) (e_EnetSpeed)((mode) & 0x0000FFFF)
+
+#define ENET_ADDR_TO_UINT64(_enetAddr) \
+ (uint64_t)(((uint64_t)(_enetAddr)[0] << 40) | \
+ ((uint64_t)(_enetAddr)[1] << 32) | \
+ ((uint64_t)(_enetAddr)[2] << 24) | \
+ ((uint64_t)(_enetAddr)[3] << 16) | \
+ ((uint64_t)(_enetAddr)[4] << 8) | \
+ ((uint64_t)(_enetAddr)[5]))
+
+#define MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enetAddr) \
+ do { \
+ int i; \
+ for (i=0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) \
+ (_enetAddr)[i] = (uint8_t)((_addr64) >> ((5-i)*8)); \
+ } while (0)
+
+
+#endif /* __ENET_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h
new file mode 100644
index 000000000000..2a5ad67b4729
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h
@@ -0,0 +1,529 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File error_ext.h
+
+ @Description Error definitions.
+*//***************************************************************************/
+
+#ifndef __ERROR_EXT_H
+#define __ERROR_EXT_H
+
+#if !defined(NCSW_LINUX)
+#include <errno.h>
+#endif
+
+#include "std_ext.h"
+#include "xx_ext.h"
+#include "core_ext.h"
+
+
+
+
+/**************************************************************************//**
+ @Group gen_id General Drivers Utilities
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group gen_error_id Errors, Events and Debug
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/******************************************************************************
+The scheme below provides the bits description for error codes:
+
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+| Reserved (should be zero) | Module ID |
+
+ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+| Error Type |
+******************************************************************************/
+
+#define ERROR_CODE(_err) ((((uint32_t)_err) & 0x0000FFFF) | __ERR_MODULE__)
+
+#define GET_ERROR_TYPE(_errcode) ((_errcode) & 0x0000FFFF)
+ /**< Extract module code from error code (#t_Error) */
+
+#define GET_ERROR_MODULE(_errcode) ((_errcode) & 0x00FF0000)
+ /**< Extract error type (#e_ErrorType) from
+ error code (#t_Error) */
+
+
+/**************************************************************************//**
+ @Description Error Type Enumeration
+*//***************************************************************************/
+typedef enum e_ErrorType /* Comments / Associated Message Strings */
+{ /* ------------------------------------------------------------ */
+ E_OK = 0 /* Never use "RETURN_ERROR" with E_OK; Use "return E_OK;" */
+ ,E_WRITE_FAILED = EIO /**< Write access failed on memory/device. */
+ /* String: none, or device name. */
+ ,E_NO_DEVICE = ENXIO /**< The associated device is not initialized. */
+ /* String: none. */
+ ,E_NOT_AVAILABLE = EAGAIN
+ /**< Resource is unavailable. */
+ /* String: none, unless the operation is not the main goal
+ of the function (in this case add resource description). */
+ ,E_NO_MEMORY = ENOMEM /**< External memory allocation failed. */
+ /* String: description of item for which allocation failed. */
+ ,E_INVALID_ADDRESS = EFAULT
+ /**< Invalid address. */
+ /* String: description of the specific violation. */
+ ,E_BUSY = EBUSY /**< Resource or module is busy. */
+ /* String: none, unless the operation is not the main goal
+ of the function (in this case add resource description). */
+ ,E_ALREADY_EXISTS = EEXIST
+ /**< Requested resource or item already exists. */
+ /* Use when resource duplication or sharing are not allowed.
+ String: none, unless the operation is not the main goal
+ of the function (in this case add item description). */
+ ,E_INVALID_OPERATION = ENODEV
+ /**< The operation/command is invalid (unrecognized). */
+ /* String: none. */
+ ,E_INVALID_VALUE = EDOM /**< Invalid value. */
+ /* Use for non-enumeration parameters, and
+ only when other error types are not suitable.
+ String: parameter description + "(should be <attribute>)",
+ e.g: "Maximum Rx buffer length (should be divisible by 8)",
+ "Channel number (should be even)". */
+ ,E_NOT_IN_RANGE = ERANGE/**< Parameter value is out of range. */
+ /* Don't use this error for enumeration parameters.
+ String: parameter description + "(should be %d-%d)",
+ e.g: "Number of pad characters (should be 0-15)". */
+ ,E_NOT_SUPPORTED = ENOSYS
+ /**< The function is not supported or not implemented. */
+ /* String: none. */
+ ,E_INVALID_STATE /**< The operation is not allowed in current module state. */
+ /* String: none. */
+ ,E_INVALID_HANDLE /**< Invalid handle of module or object. */
+ /* String: none, unless the function takes in more than one
+ handle (in this case add the handle description) */
+ ,E_INVALID_ID /**< Invalid module ID (usually enumeration or index). */
+ /* String: none, unless the function takes in more than one
+ ID (in this case add the ID description) */
+ ,E_NULL_POINTER /**< Unexpected NULL pointer. */
+ /* String: pointer description. */
+ ,E_INVALID_SELECTION /**< Invalid selection or mode. */
+ /* Use for enumeration values, only when other error types
+ are not suitable.
+ String: parameter description. */
+ ,E_INVALID_COMM_MODE /**< Invalid communication mode. */
+ /* String: none, unless the function takes in more than one
+ communication mode indications (in this case add
+ parameter description). */
+ ,E_INVALID_MEMORY_TYPE /**< Invalid memory type. */
+ /* String: none, unless the function takes in more than one
+ memory types (in this case add memory description,
+ e.g: "Data memory", "Buffer descriptors memory"). */
+ ,E_INVALID_CLOCK /**< Invalid clock. */
+ /* String: none, unless the function takes in more than one
+ clocks (in this case add clock description,
+ e.g: "Rx clock", "Tx clock"). */
+ ,E_CONFLICT /**< Some setting conflicts with another setting. */
+ /* String: description of the conflicting settings. */
+ ,E_NOT_ALIGNED /**< Non-aligned address. */
+ /* String: parameter description + "(should be %d-bytes aligned)",
+ e.g: "Rx data buffer (should be 32-bytes aligned)". */
+ ,E_NOT_FOUND /**< Requested resource or item was not found. */
+ /* Use only when the resource/item is uniquely identified.
+ String: none, unless the operation is not the main goal
+ of the function (in this case add item description). */
+ ,E_FULL /**< Resource is full. */
+ /* String: none, unless the operation is not the main goal
+ of the function (in this case add resource description). */
+ ,E_EMPTY /**< Resource is empty. */
+ /* String: none, unless the operation is not the main goal
+ of the function (in this case add resource description). */
+ ,E_ALREADY_FREE /**< Specified resource or item is already free or deleted. */
+ /* String: none, unless the operation is not the main goal
+ of the function (in this case add item description). */
+ ,E_READ_FAILED /**< Read access failed on memory/device. */
+ /* String: none, or device name. */
+ ,E_INVALID_FRAME /**< Invalid frame object (NULL handle or missing buffers). */
+ /* String: none. */
+ ,E_SEND_FAILED /**< Send operation failed on device. */
+ /* String: none, or device name. */
+ ,E_RECEIVE_FAILED /**< Receive operation failed on device. */
+ /* String: none, or device name. */
+ ,E_TIMEOUT/* = ETIMEDOUT*/ /**< The operation timed out. */
+ /* String: none. */
+
+ ,E_DUMMY_LAST /* NEVER USED */
+
+} e_ErrorType;
+
+/**************************************************************************//**
+ @Description Event Type Enumeration
+*//***************************************************************************/
+typedef enum e_Event /* Comments / Associated Flags and Message Strings */
+{ /* ------------------------------------------------------------ */
+ EV_NO_EVENT = 0 /**< No event; Never used. */
+
+ ,EV_RX_DISCARD /**< Received packet discarded (by the driver, and only for
+ complete packets);
+ Flags: error flags in case of error, zero otherwise. */
+ /* String: reason for discard, e.g: "Error in frame",
+ "Disordered frame", "Incomplete frame", "No frame object". */
+ ,EV_RX_ERROR /**< Receive error (by hardware/firmware);
+ Flags: usually status flags from the buffer descriptor. */
+ /* String: none. */
+ ,EV_TX_ERROR /**< Transmit error (by hardware/firmware);
+ Flags: usually status flags from the buffer descriptor. */
+ /* String: none. */
+ ,EV_NO_BUFFERS /**< System ran out of buffer objects;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_NO_MB_FRAMES /**< System ran out of multi-buffer frame objects;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_NO_SB_FRAMES /**< System ran out of single-buffer frame objects;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_TX_QUEUE_FULL /**< Transmit queue is full;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_RX_QUEUE_FULL /**< Receive queue is full;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_INTR_QUEUE_FULL /**< Interrupt queue overflow;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_NO_DATA_BUFFER /**< Data buffer allocation (from higher layer) failed;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_OBJ_POOL_EMPTY /**< Objects pool is empty;
+ Flags: zero. */
+ /* String: object description (name). */
+ ,EV_BUS_ERROR /**< Illegal access on bus;
+ Flags: the address (if available) or bus identifier */
+ /* String: bus/address/module description. */
+ ,EV_PTP_TXTS_QUEUE_FULL /**< PTP Tx timestamps queue is full;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_PTP_RXTS_QUEUE_FULL /**< PTP Rx timestamps queue is full;
+ Flags: zero. */
+ /* String: none. */
+ ,EV_DUMMY_LAST
+
+} e_Event;
+
+
+/**************************************************************************//**
+ @Collection Debug Levels for Errors and Events
+
+ The level description refers to errors only.
+ For events, classification is done by the user.
+
+ The TRACE, INFO and WARNING levels are allowed only when using
+ the DBG macro, and are not allowed when using the error macros
+ (RETURN_ERROR or REPORT_ERROR).
+ @{
+*//***************************************************************************/
+#define REPORT_LEVEL_CRITICAL 1 /**< Crasher: Incorrect flow, NULL pointers/handles. */
+#define REPORT_LEVEL_MAJOR 2 /**< Cannot proceed: Invalid operation, parameters or
+ configuration. */
+#define REPORT_LEVEL_MINOR 3 /**< Recoverable problem: a repeating call with the same
+ parameters may be successful. */
+#define REPORT_LEVEL_WARNING 4 /**< Something is not exactly right, yet it is not an error. */
+#define REPORT_LEVEL_INFO 5 /**< Messages which may be of interest to user/programmer. */
+#define REPORT_LEVEL_TRACE 6 /**< Program flow messages. */
+
+#define EVENT_DISABLED 0xFF /**< Disabled event (not reported at all) */
+
+/* @} */
+
+
+
+#define NO_MSG ("")
+
+#ifndef DEBUG_GLOBAL_LEVEL
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* DEBUG_GLOBAL_LEVEL */
+
+#ifndef ERROR_GLOBAL_LEVEL
+#define ERROR_GLOBAL_LEVEL DEBUG_GLOBAL_LEVEL
+#endif /* ERROR_GLOBAL_LEVEL */
+
+#ifndef EVENT_GLOBAL_LEVEL
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+#endif /* EVENT_GLOBAL_LEVEL */
+
+#ifdef EVENT_LOCAL_LEVEL
+#define EVENT_DYNAMIC_LEVEL EVENT_LOCAL_LEVEL
+#else
+#define EVENT_DYNAMIC_LEVEL EVENT_GLOBAL_LEVEL
+#endif /* EVENT_LOCAL_LEVEL */
+
+
+#ifndef DEBUG_DYNAMIC_LEVEL
+#define DEBUG_USING_STATIC_LEVEL
+
+#ifdef DEBUG_STATIC_LEVEL
+#define DEBUG_DYNAMIC_LEVEL DEBUG_STATIC_LEVEL
+#else
+#define DEBUG_DYNAMIC_LEVEL DEBUG_GLOBAL_LEVEL
+#endif /* DEBUG_STATIC_LEVEL */
+
+#else /* DEBUG_DYNAMIC_LEVEL */
+#ifdef DEBUG_STATIC_LEVEL
+#error "Please use either DEBUG_STATIC_LEVEL or DEBUG_DYNAMIC_LEVEL (not both)"
+#else
+int DEBUG_DYNAMIC_LEVEL = DEBUG_GLOBAL_LEVEL;
+#endif /* DEBUG_STATIC_LEVEL */
+#endif /* !DEBUG_DYNAMIC_LEVEL */
+
+
+#ifndef ERROR_DYNAMIC_LEVEL
+
+#ifdef ERROR_STATIC_LEVEL
+#define ERROR_DYNAMIC_LEVEL ERROR_STATIC_LEVEL
+#else
+#define ERROR_DYNAMIC_LEVEL ERROR_GLOBAL_LEVEL
+#endif /* ERROR_STATIC_LEVEL */
+
+#else /* ERROR_DYNAMIC_LEVEL */
+#ifdef ERROR_STATIC_LEVEL
+#error "Please use either ERROR_STATIC_LEVEL or ERROR_DYNAMIC_LEVEL (not both)"
+#else
+int ERROR_DYNAMIC_LEVEL = ERROR_GLOBAL_LEVEL;
+#endif /* ERROR_STATIC_LEVEL */
+#endif /* !ERROR_DYNAMIC_LEVEL */
+
+#define PRINT_FORMAT "[CPU%02d, %s:%d %s]"
+#define PRINT_FMT_PARAMS raw_smp_processor_id(), __FILE__, __LINE__, __FUNCTION__
+
+#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0))
+/* No debug/error/event messages at all */
+#define DBG(_level, _vmsg)
+
+#define REPORT_ERROR(_level, _err, _vmsg)
+
+#define RETURN_ERROR(_level, _err, _vmsg) \
+ return ERROR_CODE(_err)
+
+#if (REPORT_EVENTS > 0)
+
+#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \
+ do { \
+ if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \
+ XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \
+ } \
+ } while (0)
+
+#else
+
+#define REPORT_EVENT(_ev, _appId, _flg, _vmsg)
+
+#endif /* (REPORT_EVENTS > 0) */
+
+
+#else /* DEBUG_ERRORS > 0 */
+
+extern const char *dbgLevelStrings[];
+extern const char *moduleStrings[];
+#if (REPORT_EVENTS > 0)
+extern const char *eventStrings[];
+#endif /* (REPORT_EVENTS > 0) */
+
+char * ErrTypeStrings (e_ErrorType err);
+
+
+#if ((defined(DEBUG_USING_STATIC_LEVEL)) && (DEBUG_DYNAMIC_LEVEL < REPORT_LEVEL_WARNING))
+/* No need for DBG macro - debug level is higher anyway */
+#define DBG(_level, _vmsg)
+#else
+#define DBG(_level, _vmsg) \
+ do { \
+ if (REPORT_LEVEL_##_level <= DEBUG_DYNAMIC_LEVEL) { \
+ XX_Print("> %s (%s) " PRINT_FORMAT ": ", \
+ dbgLevelStrings[REPORT_LEVEL_##_level - 1], \
+ moduleStrings[__ERR_MODULE__ >> 16], \
+ PRINT_FMT_PARAMS); \
+ XX_Print _vmsg; \
+ XX_Print("\r\n"); \
+ } \
+ } while (0)
+#endif /* (defined(DEBUG_USING_STATIC_LEVEL) && (DEBUG_DYNAMIC_LEVEL < WARNING)) */
+
+
+#define REPORT_ERROR(_level, _err, _vmsg) \
+ do { \
+ if (REPORT_LEVEL_##_level <= ERROR_DYNAMIC_LEVEL) { \
+ XX_Print("! %s %s Error " PRINT_FORMAT ": %s; ", \
+ dbgLevelStrings[REPORT_LEVEL_##_level - 1], \
+ moduleStrings[__ERR_MODULE__ >> 16], \
+ PRINT_FMT_PARAMS, \
+ ErrTypeStrings((e_ErrorType)GET_ERROR_TYPE(_err))); \
+ XX_Print _vmsg; \
+ XX_Print("\r\n"); \
+ } \
+ } while (0)
+
+
+#define RETURN_ERROR(_level, _err, _vmsg) \
+ do { \
+ REPORT_ERROR(_level, (_err), _vmsg); \
+ return ERROR_CODE(_err); \
+ } while (0)
+
+
+#if (REPORT_EVENTS > 0)
+
+#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \
+ do { \
+ if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \
+ XX_Print("~ %s %s Event " PRINT_FORMAT ": %s (flags: 0x%04x); ", \
+ dbgLevelStrings[_ev##_LEVEL - 1], \
+ moduleStrings[__ERR_MODULE__ >> 16], \
+ PRINT_FMT_PARAMS, \
+ eventStrings[((_ev) - EV_NO_EVENT - 1)], \
+ (uint16_t)(_flg)); \
+ XX_Print _vmsg; \
+ XX_Print("\r\n"); \
+ XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \
+ } \
+ } while (0)
+
+#else /* not REPORT_EVENTS */
+
+#define REPORT_EVENT(_ev, _appId, _flg, _vmsg)
+
+#endif /* (REPORT_EVENTS > 0) */
+
+#endif /* (DEBUG_ERRORS > 0) */
+
+
+/**************************************************************************//**
+ @Function ASSERT_COND
+
+ @Description Assertion macro.
+
+ @Param[in] _cond - The condition being checked, in positive form;
+ Failure of the condition triggers the assert.
+*//***************************************************************************/
+#ifdef DISABLE_ASSERTIONS
+#define ASSERT_COND(_cond)
+#else
+#define ASSERT_COND(_cond) \
+ do { \
+ if (!(_cond)) { \
+ XX_Print("*** ASSERT_COND failed " PRINT_FORMAT "\r\n", \
+ PRINT_FMT_PARAMS); \
+ XX_Exit(1); \
+ } \
+ } while (0)
+#endif /* DISABLE_ASSERTIONS */
+
+
+#ifdef DISABLE_INIT_PARAMETERS_CHECK
+
+#define CHECK_INIT_PARAMETERS(handle, f_check)
+#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval)
+
+#else
+
+#define CHECK_INIT_PARAMETERS(handle, f_check) \
+ do { \
+ t_Error err = f_check(handle); \
+ if (err != E_OK) { \
+ RETURN_ERROR(MAJOR, err, NO_MSG); \
+ } \
+ } while (0)
+
+#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) \
+ do { \
+ t_Error err = f_check(handle); \
+ if (err != E_OK) { \
+ REPORT_ERROR(MAJOR, err, NO_MSG); \
+ return (retval); \
+ } \
+ } while (0)
+
+#endif /* DISABLE_INIT_PARAMETERS_CHECK */
+
+#ifdef DISABLE_SANITY_CHECKS
+
+#define SANITY_CHECK_RETURN_ERROR(_cond, _err)
+#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval)
+#define SANITY_CHECK_RETURN(_cond, _err)
+#define SANITY_CHECK_EXIT(_cond, _err)
+
+#else /* DISABLE_SANITY_CHECKS */
+
+#define SANITY_CHECK_RETURN_ERROR(_cond, _err) \
+ do { \
+ if (!(_cond)) { \
+ RETURN_ERROR(CRITICAL, (_err), NO_MSG); \
+ } \
+ } while (0)
+
+#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) \
+ do { \
+ if (!(_cond)) { \
+ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
+ return (retval); \
+ } \
+ } while (0)
+
+#define SANITY_CHECK_RETURN(_cond, _err) \
+ do { \
+ if (!(_cond)) { \
+ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
+ return; \
+ } \
+ } while (0)
+
+#define SANITY_CHECK_EXIT(_cond, _err) \
+ do { \
+ if (!(_cond)) { \
+ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \
+ XX_Exit(1); \
+ } \
+ } while (0)
+
+#endif /* DISABLE_SANITY_CHECKS */
+
+/** @} */ /* end of Debug/error Utils group */
+
+/** @} */ /* end of General Utils group */
+
+#endif /* __ERROR_EXT_H */
+
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h
new file mode 100644
index 000000000000..ee6b9f29b4af
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h
@@ -0,0 +1,358 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File list_ext.h
+
+ @Description External prototypes for list.c
+*//***************************************************************************/
+
+#ifndef __LIST_EXT_H
+#define __LIST_EXT_H
+
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group etc_id Utility Library Application Programming Interface
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group list_id List
+
+ @Description List module functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description List structure.
+*//***************************************************************************/
+typedef struct List
+{
+ struct List *p_Next; /**< A pointer to the next list object */
+ struct List *p_Prev; /**< A pointer to the previous list object */
+} t_List;
+
+
+/**************************************************************************//**
+ @Function LIST_FIRST/LIST_LAST/LIST_NEXT/LIST_PREV
+
+ @Description Macro to get first/last/next/previous entry in a list.
+
+ @Param[in] p_List - A pointer to a list.
+*//***************************************************************************/
+#define LIST_FIRST(p_List) (p_List)->p_Next
+#define LIST_LAST(p_List) (p_List)->p_Prev
+#define LIST_NEXT LIST_FIRST
+#define LIST_PREV LIST_LAST
+
+
+/**************************************************************************//**
+ @Function LIST_INIT
+
+ @Description Macro for initialization of a list struct.
+
+ @Param[in] lst - The t_List object to initialize.
+*//***************************************************************************/
+#define LIST_INIT(lst) {&(lst), &(lst)}
+
+
+/**************************************************************************//**
+ @Function LIST
+
+ @Description Macro to declare of a list.
+
+ @Param[in] listName - The list object name.
+*//***************************************************************************/
+#define LIST(listName) t_List listName = LIST_INIT(listName)
+
+
+/**************************************************************************//**
+ @Function INIT_LIST
+
+ @Description Macro to initialize a list pointer.
+
+ @Param[in] p_List - The list pointer.
+*//***************************************************************************/
+#define INIT_LIST(p_List) LIST_FIRST(p_List) = LIST_LAST(p_List) = (p_List)
+
+
+/**************************************************************************//**
+ @Function LIST_OBJECT
+
+ @Description Macro to get the struct (object) for this entry.
+
+ @Param[in] type - The type of the struct (object) this list is embedded in.
+ @Param[in] member - The name of the t_List object within the struct.
+
+ @Return The structure pointer for this entry.
+*//***************************************************************************/
+#define MEMBER_OFFSET(type, member) (PTR_TO_UINT(&((type *)0)->member))
+#define LIST_OBJECT(p_List, type, member) \
+ ((type *)((char *)(p_List)-MEMBER_OFFSET(type, member)))
+
+
+/**************************************************************************//**
+ @Function LIST_FOR_EACH
+
+ @Description Macro to iterate over a list.
+
+ @Param[in] p_Pos - A pointer to a list to use as a loop counter.
+ @Param[in] p_Head - A pointer to the head for your list pointer.
+
+ @Cautions You can't delete items with this routine.
+ For deletion use LIST_FOR_EACH_SAFE().
+*//***************************************************************************/
+#define LIST_FOR_EACH(p_Pos, p_Head) \
+ for (p_Pos = LIST_FIRST(p_Head); p_Pos != (p_Head); p_Pos = LIST_NEXT(p_Pos))
+
+
+/**************************************************************************//**
+ @Function LIST_FOR_EACH_SAFE
+
+ @Description Macro to iterate over a list safe against removal of list entry.
+
+ @Param[in] p_Pos - A pointer to a list to use as a loop counter.
+ @Param[in] p_Tmp - Another pointer to a list to use as temporary storage.
+ @Param[in] p_Head - A pointer to the head for your list pointer.
+*//***************************************************************************/
+#define LIST_FOR_EACH_SAFE(p_Pos, p_Tmp, p_Head) \
+ for (p_Pos = LIST_FIRST(p_Head), p_Tmp = LIST_FIRST(p_Pos); \
+ p_Pos != (p_Head); \
+ p_Pos = p_Tmp, p_Tmp = LIST_NEXT(p_Pos))
+
+
+/**************************************************************************//**
+ @Function LIST_FOR_EACH_OBJECT_SAFE
+
+ @Description Macro to iterate over list of given type safely.
+
+ @Param[in] p_Pos - A pointer to a list to use as a loop counter.
+ @Param[in] p_Tmp - Another pointer to a list to use as temporary storage.
+ @Param[in] type - The type of the struct this is embedded in.
+ @Param[in] p_Head - A pointer to the head for your list pointer.
+ @Param[in] member - The name of the list_struct within the struct.
+
+ @Cautions You can't delete items with this routine.
+ For deletion use LIST_FOR_EACH_SAFE().
+*//***************************************************************************/
+#define LIST_FOR_EACH_OBJECT_SAFE(p_Pos, p_Tmp, p_Head, type, member) \
+ for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member), \
+ p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member); \
+ &p_Pos->member != (p_Head); \
+ p_Pos = p_Tmp, \
+ p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member))
+
+/**************************************************************************//**
+ @Function LIST_FOR_EACH_OBJECT
+
+ @Description Macro to iterate over list of given type.
+
+ @Param[in] p_Pos - A pointer to a list to use as a loop counter.
+ @Param[in] type - The type of the struct this is embedded in.
+ @Param[in] p_Head - A pointer to the head for your list pointer.
+ @Param[in] member - The name of the list_struct within the struct.
+
+ @Cautions You can't delete items with this routine.
+ For deletion use LIST_FOR_EACH_SAFE().
+*//***************************************************************************/
+#define LIST_FOR_EACH_OBJECT(p_Pos, type, p_Head, member) \
+ for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member); \
+ &p_Pos->member != (p_Head); \
+ p_Pos = LIST_OBJECT(LIST_FIRST(&(p_Pos->member)), type, member))
+
+
+/**************************************************************************//**
+ @Function LIST_Add
+
+ @Description Add a new entry to a list.
+
+ Insert a new entry after the specified head.
+ This is good for implementing stacks.
+
+ @Param[in] p_New - A pointer to a new list entry to be added.
+ @Param[in] p_Head - A pointer to a list head to add it after.
+
+ @Return none.
+*//***************************************************************************/
+static __inline__ void LIST_Add(t_List *p_New, t_List *p_Head)
+{
+ LIST_PREV(LIST_NEXT(p_Head)) = p_New;
+ LIST_NEXT(p_New) = LIST_NEXT(p_Head);
+ LIST_PREV(p_New) = p_Head;
+ LIST_NEXT(p_Head) = p_New;
+}
+
+
+/**************************************************************************//**
+ @Function LIST_AddToTail
+
+ @Description Add a new entry to a list.
+
+ Insert a new entry before the specified head.
+ This is useful for implementing queues.
+
+ @Param[in] p_New - A pointer to a new list entry to be added.
+ @Param[in] p_Head - A pointer to a list head to add it before.
+
+ @Return none.
+*//***************************************************************************/
+static __inline__ void LIST_AddToTail(t_List *p_New, t_List *p_Head)
+{
+ LIST_NEXT(LIST_PREV(p_Head)) = p_New;
+ LIST_PREV(p_New) = LIST_PREV(p_Head);
+ LIST_NEXT(p_New) = p_Head;
+ LIST_PREV(p_Head) = p_New;
+}
+
+
+/**************************************************************************//**
+ @Function LIST_Del
+
+ @Description Deletes entry from a list.
+
+ @Param[in] p_Entry - A pointer to the element to delete from the list.
+
+ @Return none.
+
+ @Cautions LIST_IsEmpty() on entry does not return true after this,
+ the entry is in an undefined state.
+*//***************************************************************************/
+static __inline__ void LIST_Del(t_List *p_Entry)
+{
+ LIST_PREV(LIST_NEXT(p_Entry)) = LIST_PREV(p_Entry);
+ LIST_NEXT(LIST_PREV(p_Entry)) = LIST_NEXT(p_Entry);
+}
+
+
+/**************************************************************************//**
+ @Function LIST_DelAndInit
+
+ @Description Deletes entry from list and reinitialize it.
+
+ @Param[in] p_Entry - A pointer to the element to delete from the list.
+
+ @Return none.
+*//***************************************************************************/
+static __inline__ void LIST_DelAndInit(t_List *p_Entry)
+{
+ LIST_Del(p_Entry);
+ INIT_LIST(p_Entry);
+}
+
+
+/**************************************************************************//**
+ @Function LIST_Move
+
+ @Description Delete from one list and add as another's head.
+
+ @Param[in] p_Entry - A pointer to the list entry to move.
+ @Param[in] p_Head - A pointer to the list head that will precede our entry.
+
+ @Return none.
+*//***************************************************************************/
+static __inline__ void LIST_Move(t_List *p_Entry, t_List *p_Head)
+{
+ LIST_Del(p_Entry);
+ LIST_Add(p_Entry, p_Head);
+}
+
+
+/**************************************************************************//**
+ @Function LIST_MoveToTail
+
+ @Description Delete from one list and add as another's tail.
+
+ @Param[in] p_Entry - A pointer to the entry to move.
+ @Param[in] p_Head - A pointer to the list head that will follow our entry.
+
+ @Return none.
+*//***************************************************************************/
+static __inline__ void LIST_MoveToTail(t_List *p_Entry, t_List *p_Head)
+{
+ LIST_Del(p_Entry);
+ LIST_AddToTail(p_Entry, p_Head);
+}
+
+
+/**************************************************************************//**
+ @Function LIST_IsEmpty
+
+ @Description Tests whether a list is empty.
+
+ @Param[in] p_List - A pointer to the list to test.
+
+ @Return 1 if the list is empty, 0 otherwise.
+*//***************************************************************************/
+static __inline__ int LIST_IsEmpty(t_List *p_List)
+{
+ return (LIST_FIRST(p_List) == p_List);
+}
+
+
+/**************************************************************************//**
+ @Function LIST_Append
+
+ @Description Join two lists.
+
+ @Param[in] p_NewList - A pointer to the new list to add.
+ @Param[in] p_Head - A pointer to the place to add it in the first list.
+
+ @Return none.
+*//***************************************************************************/
+void LIST_Append(t_List *p_NewList, t_List *p_Head);
+
+
+/**************************************************************************//**
+ @Function LIST_NumOfObjs
+
+ @Description Counts number of objects in the list
+
+ @Param[in] p_List - A pointer to the list which objects are to be counted.
+
+ @Return Number of objects in the list.
+*//***************************************************************************/
+int LIST_NumOfObjs(t_List *p_List);
+
+/** @} */ /* end of list_id group */
+/** @} */ /* end of etc_id group */
+
+
+#endif /* __LIST_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h
new file mode 100644
index 000000000000..d0565d410ca4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h
@@ -0,0 +1,318 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File mem_ext.h
+
+ @Description External prototypes for the memory manager object
+*//***************************************************************************/
+
+#ifndef __MEM_EXT_H
+#define __MEM_EXT_H
+
+#include "std_ext.h"
+#include "part_ext.h"
+
+
+/**************************************************************************//**
+ @Group etc_id Utility Library Application Programming Interface
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group mem_id Slab Memory Manager
+
+ @Description Slab Memory Manager module functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/* Each block is of the following structure:
+ *
+ *
+ * +-----------+----------+---------------------------+-----------+-----------+
+ * | Alignment | Prefix | Data | Postfix | Alignment |
+ * | field | field | field | field | Padding |
+ * | | | | | |
+ * +-----------+----------+---------------------------+-----------+-----------+
+ * and at the beginning of all bytes, an additional optional padding might reside
+ * to ensure that the first blocks data field is aligned as requested.
+ */
+
+
+#define MEM_MAX_NAME_LENGTH 8
+
+/**************************************************************************//*
+ @Description Memory Segment structure
+*//***************************************************************************/
+
+typedef struct
+{
+ char name[MEM_MAX_NAME_LENGTH];
+ /* The segment's name */
+ uint8_t **p_Bases; /* Base addresses of the segments */
+ uint8_t **p_BlocksStack; /* Array of pointers to blocks */
+ t_Handle h_Spinlock;
+ uint16_t dataSize; /* Size of each data block */
+ uint16_t prefixSize; /* How many bytes to reserve before the data */
+ uint16_t postfixSize; /* How many bytes to reserve after the data */
+ uint16_t alignment; /* Requested alignment for the data field */
+ int allocOwner; /* Memory allocation owner */
+ uint32_t getFailures; /* Number of times get failed */
+ uint32_t num; /* Number of blocks in segment */
+ uint32_t current; /* Current block */
+ bool consecutiveMem; /* Allocate consecutive data blocks memory */
+#ifdef DEBUG_MEM_LEAKS
+ void *p_MemDbg; /* MEM debug database (MEM leaks detection) */
+ uint32_t blockOffset;
+ uint32_t blockSize;
+#endif /* DEBUG_MEM_LEAKS */
+} t_MemorySegment;
+
+
+
+/**************************************************************************//**
+ @Function MEM_Init
+
+ @Description Create a new memory segment.
+
+ @Param[in] name - Name of memory partition.
+ @Param[in] p_Handle - Handle to new segment is returned through here.
+ @Param[in] num - Number of blocks in new segment.
+ @Param[in] dataSize - Size of blocks in segment.
+ @Param[in] prefixSize - How many bytes to allocate before the data.
+ @Param[in] postfixSize - How many bytes to allocate after the data.
+ @Param[in] alignment - Requested alignment for data field (in bytes).
+
+ @Return E_OK - success, E_NO_MEMORY - out of memory.
+*//***************************************************************************/
+t_Error MEM_Init(char name[],
+ t_Handle *p_Handle,
+ uint32_t num,
+ uint16_t dataSize,
+ uint16_t prefixSize,
+ uint16_t postfixSize,
+ uint16_t alignment);
+
+/**************************************************************************//**
+ @Function MEM_InitSmart
+
+ @Description Create a new memory segment.
+
+ @Param[in] name - Name of memory partition.
+ @Param[in] p_Handle - Handle to new segment is returned through here.
+ @Param[in] num - Number of blocks in new segment.
+ @Param[in] dataSize - Size of blocks in segment.
+ @Param[in] prefixSize - How many bytes to allocate before the data.
+ @Param[in] postfixSize - How many bytes to allocate after the data.
+ @Param[in] alignment - Requested alignment for data field (in bytes).
+ @Param[in] memPartitionId - Memory partition ID for allocation.
+ @Param[in] consecutiveMem - Whether to allocate the memory blocks
+ continuously or not.
+
+ @Return E_OK - success, E_NO_MEMORY - out of memory.
+*//***************************************************************************/
+t_Error MEM_InitSmart(char name[],
+ t_Handle *p_Handle,
+ uint32_t num,
+ uint16_t dataSize,
+ uint16_t prefixSize,
+ uint16_t postfixSize,
+ uint16_t alignment,
+ uint8_t memPartitionId,
+ bool consecutiveMem);
+
+/**************************************************************************//**
+ @Function MEM_InitByAddress
+
+ @Description Create a new memory segment with a specified base address.
+
+ @Param[in] name - Name of memory partition.
+ @Param[in] p_Handle - Handle to new segment is returned through here.
+ @Param[in] num - Number of blocks in new segment.
+ @Param[in] dataSize - Size of blocks in segment.
+ @Param[in] prefixSize - How many bytes to allocate before the data.
+ @Param[in] postfixSize - How many bytes to allocate after the data.
+ @Param[in] alignment - Requested alignment for data field (in bytes).
+ @Param[in] address - The required base address.
+
+ @Return E_OK - success, E_NO_MEMORY - out of memory.
+ *//***************************************************************************/
+t_Error MEM_InitByAddress(char name[],
+ t_Handle *p_Handle,
+ uint32_t num,
+ uint16_t dataSize,
+ uint16_t prefixSize,
+ uint16_t postfixSize,
+ uint16_t alignment,
+ uint8_t *address);
+
+/**************************************************************************//**
+ @Function MEM_Free
+
+ @Description Free a specific memory segment.
+
+ @Param[in] h_Mem - Handle to memory segment.
+
+ @Return None.
+*//***************************************************************************/
+void MEM_Free(t_Handle h_Mem);
+
+/**************************************************************************//**
+ @Function MEM_Get
+
+ @Description Get a block of memory from a segment.
+
+ @Param[in] h_Mem - Handle to memory segment.
+
+ @Return Pointer to new memory block on success,0 otherwise.
+*//***************************************************************************/
+void * MEM_Get(t_Handle h_Mem);
+
+/**************************************************************************//**
+ @Function MEM_GetN
+
+ @Description Get up to N blocks of memory from a segment.
+
+ The blocks are assumed to be of a fixed size (one size per segment).
+
+ @Param[in] h_Mem - Handle to memory segment.
+ @Param[in] num - Number of blocks to allocate.
+ @Param[out] array - Array of at least num pointers to which the addresses
+ of the allocated blocks are written.
+
+ @Return The number of blocks actually allocated.
+
+ @Cautions Interrupts are disabled for all of the allocation loop.
+ Although this loop is very short for each block (several machine
+ instructions), you should not allocate a very large number
+ of blocks via this routine.
+*//***************************************************************************/
+uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[]);
+
+/**************************************************************************//**
+ @Function MEM_Put
+
+ @Description Put a block of memory back to a segment.
+
+ @Param[in] h_Mem - Handle to memory segment.
+ @Param[in] p_Block - The block to return.
+
+ @Return Pointer to new memory block on success,0 otherwise.
+*//***************************************************************************/
+t_Error MEM_Put(t_Handle h_Mem, void *p_Block);
+
+/**************************************************************************//**
+ @Function MEM_ComputePartitionSize
+
+ @Description calculate a tight upper boundary of the size of a partition with
+ given attributes.
+
+ The returned value is suitable if one wants to use MEM_InitByAddress().
+
+ @Param[in] num - The number of blocks in the segment.
+ @Param[in] dataSize - Size of block to get.
+ @Param[in] prefixSize - The prefix size
+ @Param postfixSize - The postfix size
+ @Param[in] alignment - The requested alignment value (in bytes)
+
+ @Return The memory block size a segment with the given attributes needs.
+*//***************************************************************************/
+uint32_t MEM_ComputePartitionSize(uint32_t num,
+ uint16_t dataSize,
+ uint16_t prefixSize,
+ uint16_t postfixSize,
+ uint16_t alignment);
+
+#ifdef DEBUG_MEM_LEAKS
+#if !((defined(__MWERKS__) || defined(__GNUC__)) && (__dest_os == __ppc_eabi))
+#error "Memory-Leaks-Debug option is supported only for freescale CodeWarrior"
+#endif /* !(defined(__MWERKS__) && ... */
+
+/**************************************************************************//**
+ @Function MEM_CheckLeaks
+
+ @Description Report MEM object leaks.
+
+ This routine is automatically called by the MEM_Free() routine,
+ but it can also be invoked while the MEM object is alive.
+
+ @Param[in] h_Mem - Handle to memory segment.
+
+ @Return None.
+*//***************************************************************************/
+void MEM_CheckLeaks(t_Handle h_Mem);
+
+#else /* not DEBUG_MEM_LEAKS */
+#define MEM_CheckLeaks(h_Mem)
+#endif /* not DEBUG_MEM_LEAKS */
+
+/**************************************************************************//**
+ @Description Get base of MEM
+*//***************************************************************************/
+#define MEM_GetBase(h_Mem) ((t_MemorySegment *)(h_Mem))->p_Bases[0]
+
+/**************************************************************************//**
+ @Description Get size of MEM block
+*//***************************************************************************/
+#define MEM_GetSize(h_Mem) ((t_MemorySegment *)(h_Mem))->dataSize
+
+/**************************************************************************//**
+ @Description Get prefix size of MEM block
+*//***************************************************************************/
+#define MEM_GetPrefixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->prefixSize
+
+/**************************************************************************//**
+ @Description Get postfix size of MEM block
+*//***************************************************************************/
+#define MEM_GetPostfixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->postfixSize
+
+/**************************************************************************//**
+ @Description Get alignment of MEM block (in bytes)
+*//***************************************************************************/
+#define MEM_GetAlignment(h_Mem) ((t_MemorySegment *)(h_Mem))->alignment
+
+/**************************************************************************//**
+ @Description Get the number of blocks in the segment
+*//***************************************************************************/
+#define MEM_GetNumOfBlocks(h_Mem) ((t_MemorySegment *)(h_Mem))->num
+
+/** @} */ /* end of MEM group */
+/** @} */ /* end of etc_id group */
+
+
+#endif /* __MEM_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h
new file mode 100644
index 000000000000..1b3a2fac5fad
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h
@@ -0,0 +1,208 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File memcpy_ext.h
+
+ @Description Efficient functions for copying and setting blocks of memory.
+*//***************************************************************************/
+
+#ifndef __MEMCPY_EXT_H
+#define __MEMCPY_EXT_H
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group etc_id Utility Library Application Programming Interface
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group mem_cpy Memory Copy
+
+ @Description Memory Copy module functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function MemCpy32
+
+ @Description Copies one memory buffer into another one in 4-byte chunks!
+ Which should be more efficient than byte by byte.
+
+ For large buffers (over 60 bytes) this function is about 4 times
+ more efficient than the trivial memory copy. For short buffers
+ it is reduced to the trivial copy and may be a bit worse.
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] pSrc - The address of the source buffer.
+ @Param[in] size - The number of bytes that will be copied from pSrc to pDst.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non-null parameters as source & destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void * MemCpy32(void* pDst,void* pSrc, uint32_t size);
+void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size);
+void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size);
+void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size);
+
+/**************************************************************************//**
+ @Function MemCpy64
+
+ @Description Copies one memory buffer into another one in 8-byte chunks!
+ Which should be more efficient than byte by byte.
+
+ For large buffers (over 60 bytes) this function is about 8 times
+ more efficient than the trivial memory copy. For short buffers
+ it is reduced to the trivial copy and may be a bit worse.
+
+ Some testing suggests that MemCpy32() preforms better than
+ MemCpy64() over small buffers. On average they break even at
+ 100 byte buffers. For buffers larger than that MemCpy64 is
+ superior.
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] pSrc - The address of the source buffer.
+ @Param[in] size - The number of bytes that will be copied from pSrc to pDst.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non null parameters as source & destination and size
+ that actually fits into their buffer.
+
+ Do not use under Linux.
+*//***************************************************************************/
+void * MemCpy64(void* pDst,void* pSrc, uint32_t size);
+
+/**************************************************************************//**
+ @Function MemSet32
+
+ @Description Sets all bytes of a memory buffer to a specific value, in
+ 4-byte chunks.
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] val - Value to set destination bytes to.
+ @Param[in] size - The number of bytes that will be set to val.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non null parameter as destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void * MemSet32(void* pDst, uint8_t val, uint32_t size);
+void * IOMemSet32(void* pDst, uint8_t val, uint32_t size);
+
+/**************************************************************************//**
+ @Function MemSet64
+
+ @Description Sets all bytes of a memory buffer to a specific value, in
+ 8-byte chunks.
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] val - Value to set destination bytes to.
+ @Param[in] size - The number of bytes that will be set to val.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non null parameter as destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void * MemSet64(void* pDst, uint8_t val, uint32_t size);
+
+/**************************************************************************//**
+ @Function MemDisp
+
+ @Description Displays a block of memory in chunks of 32 bits.
+
+ @Param[in] addr - The address of the memory to display.
+ @Param[in] size - The number of bytes that will be displayed.
+
+ @Return None.
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non null parameter as destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void MemDisp(uint8_t *addr, int size);
+
+/**************************************************************************//**
+ @Function MemCpy8
+
+ @Description Trivial copy one memory buffer into another byte by byte
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] pSrc - The address of the source buffer.
+ @Param[in] size - The number of bytes that will be copied from pSrc to pDst.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non-null parameters as source & destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void * MemCpy8(void* pDst,void* pSrc, uint32_t size);
+
+/**************************************************************************//**
+ @Function MemSet8
+
+ @Description Sets all bytes of a memory buffer to a specific value byte by byte.
+
+ @Param[in] pDst - The address of the destination buffer.
+ @Param[in] c - Value to set destination bytes to.
+ @Param[in] size - The number of bytes that will be set to val.
+
+ @Return pDst (the address of the destination buffer).
+
+ @Cautions There is no parameter or boundary checking! It is up to the user
+ to supply non null parameter as destination and size
+ that actually fits into the destination buffer.
+*//***************************************************************************/
+void * MemSet8(void* pDst, int c, uint32_t size);
+
+/** @} */ /* end of mem_cpy group */
+/** @} */ /* end of etc_id group */
+
+
+#endif /* __MEMCPY_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h
new file mode 100644
index 000000000000..fa7c85e3b2b8
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h
@@ -0,0 +1,310 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File mm_ext.h
+
+ @Description Memory Manager Application Programming Interface
+*//***************************************************************************/
+#ifndef __MM_EXT
+#define __MM_EXT
+
+#include "std_ext.h"
+
+#define MM_MAX_ALIGNMENT 20 /* Alignments from 2 to 128 are available
+ where maximum alignment defined as
+ MM_MAX_ALIGNMENT power of 2 */
+
+#define MM_MAX_NAME_LEN 32
+
+/**************************************************************************//**
+ @Group etc_id Utility Library Application Programming Interface
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group mm_grp Flexible Memory Manager
+
+ @Description Flexible Memory Manager module functions,definitions and enums.
+ (All of the following functions,definitions and enums can be found in mm_ext.h)
+
+ @{
+*//***************************************************************************/
+
+
+/**************************************************************************//**
+ @Function MM_Init
+
+ @Description Initializes a new MM object.
+
+ It initializes a new memory block consisting of base address
+ and size of the available memory by calling to MemBlock_Init
+ routine. It is also initializes a new free block for each
+ by calling FreeBlock_Init routine, which is pointed to
+ the almost all memory started from the required alignment
+ from the base address and to the end of the memory.
+ The handle to the new MM object is returned via "MM"
+ argument (passed by reference).
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] base - Base address of the MM.
+ @Param[in] size - Size of the MM.
+
+ @Return E_OK is returned on success. E_NOMEMORY is returned if the new MM object or a new free block can not be initialized.
+*//***************************************************************************/
+t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size);
+
+/**************************************************************************//**
+ @Function MM_Get
+
+ @Description Allocates a block of memory according to the given size and the alignment.
+
+ The Alignment argument tells from which
+ free list allocate a block of memory. 2^alignment indicates
+ the alignment that the base address of the allocated block
+ should have. So, the only values 1, 2, 4, 8, 16, 32 and 64
+ are available for the alignment argument.
+ The routine passes through the specific free list of free
+ blocks and seeks for a first block that have anough memory
+ that is required (best fit).
+ After the block is found and data is allocated, it calls
+ the internal MM_CutFree routine to update all free lists
+ do not include a just allocated block. Of course, each
+ free list contains a free blocks with the same alignment.
+ It is also creates a busy block that holds
+ information about an allocated block.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] size - Size of the MM.
+ @Param[in] alignment - Index as a power of two defines a required
+ alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64
+ @Param[in] name - The name that specifies an allocated block.
+
+ @Return base address of an allocated block ILLEGAL_BASE if can't allocate a block
+*//***************************************************************************/
+uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char *name);
+
+/**************************************************************************//**
+ @Function MM_GetBase
+
+ @Description Gets the base address of the required MM objects.
+
+ @Param[in] h_MM - Handle to the MM object.
+
+ @Return base address of the block.
+*//***************************************************************************/
+uint64_t MM_GetBase(t_Handle h_MM);
+
+/**************************************************************************//**
+ @Function MM_GetForce
+
+ @Description Force memory allocation.
+
+ It means to allocate a block of memory of the given
+ size from the given base address.
+ The routine checks if the required block can be allocated
+ (that is it is free) and then, calls the internal MM_CutFree
+ routine to update all free lists do not include that block.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] base - Base address of the MM.
+ @Param[in] size - Size of the MM.
+ @Param[in] name - Name that specifies an allocated block.
+
+ @Return base address of an allocated block, ILLEGAL_BASE if can't allocate a block.
+*//***************************************************************************/
+uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char *name);
+
+/**************************************************************************//**
+ @Function MM_GetForceMin
+
+ @Description Allocates a block of memory according to the given size, the alignment and minimum base address.
+
+ The Alignment argument tells from which
+ free list allocate a block of memory. 2^alignment indicates
+ the alignment that the base address of the allocated block
+ should have. So, the only values 1, 2, 4, 8, 16, 32 and 64
+ are available for the alignment argument.
+ The minimum baser address forces the location of the block
+ to be from a given address onward.
+ The routine passes through the specific free list of free
+ blocks and seeks for the first base address equal or smaller
+ than the required minimum address and end address larger than
+ than the required base + its size - i.e. that may contain
+ the required block.
+ After the block is found and data is allocated, it calls
+ the internal MM_CutFree routine to update all free lists
+ do not include a just allocated block. Of course, each
+ free list contains a free blocks with the same alignment.
+ It is also creates a busy block that holds
+ information about an allocated block.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] size - Size of the MM.
+ @Param[in] alignment - Index as a power of two defines a required
+ alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64
+ @Param[in] min - The minimum base address of the block.
+ @Param[in] name - Name that specifies an allocated block.
+
+ @Return base address of an allocated block,ILLEGAL_BASE if can't allocate a block.
+*//***************************************************************************/
+uint64_t MM_GetForceMin(t_Handle h_MM,
+ uint64_t size,
+ uint64_t alignment,
+ uint64_t min,
+ char *name);
+
+/**************************************************************************//**
+ @Function MM_Put
+
+ @Description Puts a block of memory of the given base address back to the memory.
+
+ It checks if there is a busy block with the
+ given base address. If not, it returns 0, that
+ means can't free a block. Otherwise, it gets parameters of
+ the busy block and after it updates lists of free blocks,
+ removes that busy block from the list by calling to MM_CutBusy
+ routine.
+ After that it calls to MM_AddFree routine to add a new free
+ block to the free lists.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] base - Base address of the MM.
+
+ @Return The size of bytes released, 0 if failed.
+*//***************************************************************************/
+uint64_t MM_Put(t_Handle h_MM, uint64_t base);
+
+/**************************************************************************//**
+ @Function MM_PutForce
+
+ @Description Releases a block of memory of the required size from the required base address.
+
+ First, it calls to MM_CutBusy routine
+ to cut a free block from the busy list. And then, calls to
+ MM_AddFree routine to add the free block to the free lists.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] base - Base address of of a block to free.
+ @Param[in] size - Size of a block to free.
+
+ @Return The number of bytes released, 0 on failure.
+*//***************************************************************************/
+uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size);
+
+/**************************************************************************//**
+ @Function MM_Add
+
+ @Description Adds a new memory block for memory allocation.
+
+ When a new memory block is initialized and added to the
+ memory list, it calls to MM_AddFree routine to add the
+ new free block to the free lists.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] base - Base address of the memory block.
+ @Param[in] size - Size of the memory block.
+
+ @Return E_OK on success, otherwise returns an error code.
+*//***************************************************************************/
+t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size);
+
+/**************************************************************************//**
+ @Function MM_Dump
+
+ @Description Prints results of free and busy lists.
+
+ @Param[in] h_MM - Handle to the MM object.
+*//***************************************************************************/
+void MM_Dump(t_Handle h_MM);
+
+/**************************************************************************//**
+ @Function MM_Free
+
+ @Description Releases memory allocated for MM object.
+
+ @Param[in] h_MM - Handle of the MM object.
+*//***************************************************************************/
+void MM_Free(t_Handle h_MM);
+
+/**************************************************************************//**
+ @Function MM_GetMemBlock
+
+ @Description Returns base address of the memory block specified by the index.
+
+ If index is 0, returns base address
+ of the first memory block, 1 - returns base address
+ of the second memory block, etc.
+ Note, those memory blocks are allocated by the
+ application before MM_Init or MM_Add and have to
+ be released by the application before or after invoking
+ the MM_Free routine.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] index - Index of the memory block.
+
+ @Return valid base address or ILLEGAL_BASE if no memory block specified by the index.
+*//***************************************************************************/
+uint64_t MM_GetMemBlock(t_Handle h_MM, int index);
+
+/**************************************************************************//**
+ @Function MM_InRange
+
+ @Description Checks if a specific address is in the memory range of the passed MM object.
+
+ @Param[in] h_MM - Handle to the MM object.
+ @Param[in] addr - The address to be checked.
+
+ @Return TRUE if the address is in the address range of the block, FALSE otherwise.
+*//***************************************************************************/
+bool MM_InRange(t_Handle h_MM, uint64_t addr);
+
+/**************************************************************************//**
+ @Function MM_GetFreeMemSize
+
+ @Description Returns the size (in bytes) of free memory.
+
+ @Param[in] h_MM - Handle to the MM object.
+
+ @Return Free memory size in bytes.
+*//***************************************************************************/
+uint64_t MM_GetFreeMemSize(t_Handle h_MM);
+
+
+/** @} */ /* end of mm_grp group */
+/** @} */ /* end of etc_id group */
+
+#endif /* __MM_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h
new file mode 100644
index 000000000000..52f7a9dc7482
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File sprint_ext.h
+
+ @Description Debug routines (externals).
+
+*//***************************************************************************/
+
+#ifndef __SPRINT_EXT_H
+#define __SPRINT_EXT_H
+
+
+#if defined(NCSW_LINUX) && defined(__KERNEL__)
+#include <linux/kernel.h>
+
+#elif defined(NCSW_VXWORKS)
+#include "private/stdioP.h"
+
+#else
+#include <stdio.h>
+#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group etc_id Utility Library Application Programming Interface
+
+ @Description External routines.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group sprint_id Sprint
+
+ @Description Sprint & Sscan module functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Function Sprint
+
+ @Description Format a string and place it in a buffer.
+
+ @Param[in] buff - The buffer to place the result into.
+ @Param[in] str - The format string to use.
+ @Param[in] ... - Arguments for the format string.
+
+ @Return Number of bytes formatted.
+*//***************************************************************************/
+int Sprint(char *buff, const char *str, ...);
+
+/**************************************************************************//**
+ @Function Snprint
+
+ @Description Format a string and place it in a buffer.
+
+ @Param[in] buf - The buffer to place the result into.
+ @Param[in] size - The size of the buffer, including the trailing null space.
+ @Param[in] fmt - The format string to use.
+ @Param[in] ... - Arguments for the format string.
+
+ @Return Number of bytes formatted.
+*//***************************************************************************/
+int Snprint(char * buf, uint32_t size, const char *fmt, ...);
+
+/**************************************************************************//**
+ @Function Sscan
+
+ @Description Unformat a buffer into a list of arguments.
+
+ @Param[in] buf - input buffer.
+ @Param[in] fmt - formatting of buffer.
+ @Param[out] ... - resulting arguments.
+
+ @Return Number of bytes unformatted.
+*//***************************************************************************/
+int Sscan(const char * buf, const char * fmt, ...);
+
+/** @} */ /* end of sprint_id group */
+/** @} */ /* end of etc_id group */
+
+
+#endif /* __SPRINT_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h
new file mode 100644
index 000000000000..c7b9b46f269b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef FL_E500_MACROS_H
+#define FL_E500_MACROS_H
+
+#endif /* FL_E500_MACROS_H */
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h
new file mode 100644
index 000000000000..b3f516fb10b3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __GENERAL_H
+#define __GENERAL_H
+
+#include "std_ext.h"
+#if !defined(NCSW_LINUX)
+#include "errno.h"
+#endif
+
+
+extern uint32_t get_mac_addr_crc(uint64_t _addr);
+
+#ifndef CONFIG_FMAN_ARM
+#define iowrite32be(val, addr) WRITE_UINT32(*addr, val)
+#define ioread32be(addr) GET_UINT32(*addr)
+#endif
+
+#define ether_crc(len, addr) get_mac_addr_crc(*(uint64_t *)(addr)>>16)
+
+
+#endif /* __GENERAL_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h
new file mode 100755
index 000000000000..8b194e995561
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __FMAN_COMMON_H
+#define __FMAN_COMMON_H
+
+/**************************************************************************//**
+ @Description NIA Description
+*//***************************************************************************/
+#define NIA_ORDER_RESTOR 0x00800000
+#define NIA_ENG_FM_CTL 0x00000000
+#define NIA_ENG_PRS 0x00440000
+#define NIA_ENG_KG 0x00480000
+#define NIA_ENG_PLCR 0x004C0000
+#define NIA_ENG_BMI 0x00500000
+#define NIA_ENG_QMI_ENQ 0x00540000
+#define NIA_ENG_QMI_DEQ 0x00580000
+#define NIA_ENG_MASK 0x007C0000
+
+#define NIA_FM_CTL_AC_CC 0x00000006
+#define NIA_FM_CTL_AC_HC 0x0000000C
+#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008
+#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A
+#define NIA_FM_CTL_AC_FRAG 0x0000000e
+#define NIA_FM_CTL_AC_PRE_FETCH 0x00000010
+#define NIA_FM_CTL_AC_POST_FETCH_PCD 0x00000012
+#define NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN 0x00000018
+#define NIA_FM_CTL_AC_POST_FETCH_NO_PCD 0x00000012
+#define NIA_FM_CTL_AC_FRAG_CHECK 0x00000014
+#define NIA_FM_CTL_AC_PRE_CC 0x00000020
+
+
+#define NIA_BMI_AC_ENQ_FRAME 0x00000002
+#define NIA_BMI_AC_TX_RELEASE 0x000002C0
+#define NIA_BMI_AC_RELEASE 0x000000C0
+#define NIA_BMI_AC_DISCARD 0x000000C1
+#define NIA_BMI_AC_TX 0x00000274
+#define NIA_BMI_AC_FETCH 0x00000208
+#define NIA_BMI_AC_MASK 0x000003FF
+
+#define NIA_KG_DIRECT 0x00000100
+#define NIA_KG_CC_EN 0x00000200
+#define NIA_PLCR_ABSOLUTE 0x00008000
+
+#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202
+#define NIA_BMI_AC_FETCH_ALL_FRAME 0x0000020c
+
+#endif /* __FMAN_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h
new file mode 100644
index 000000000000..caa87fc6b21d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_ENET_H
+#define __FSL_ENET_H
+
+/**
+ @Description Ethernet MAC-PHY Interface
+*/
+
+enum enet_interface {
+ E_ENET_IF_MII = 0x00010000, /**< MII interface */
+ E_ENET_IF_RMII = 0x00020000, /**< RMII interface */
+ E_ENET_IF_SMII = 0x00030000, /**< SMII interface */
+ E_ENET_IF_GMII = 0x00040000, /**< GMII interface */
+ E_ENET_IF_RGMII = 0x00050000, /**< RGMII interface */
+ E_ENET_IF_TBI = 0x00060000, /**< TBI interface */
+ E_ENET_IF_RTBI = 0x00070000, /**< RTBI interface */
+ E_ENET_IF_SGMII = 0x00080000, /**< SGMII interface */
+ E_ENET_IF_XGMII = 0x00090000, /**< XGMII interface */
+ E_ENET_IF_QSGMII = 0x000a0000, /**< QSGMII interface */
+ E_ENET_IF_XFI = 0x000b0000 /**< XFI interface */
+};
+
+/**
+ @Description Ethernet Speed (nominal data rate)
+*/
+enum enet_speed {
+ E_ENET_SPEED_10 = 10, /**< 10 Mbps */
+ E_ENET_SPEED_100 = 100, /**< 100 Mbps */
+ E_ENET_SPEED_1000 = 1000, /**< 1000 Mbps = 1 Gbps */
+ E_ENET_SPEED_2500 = 2500, /**< 2500 Mbps = 2.5 Gbps */
+ E_ENET_SPEED_10000 = 10000 /**< 10000 Mbps = 10 Gbps */
+};
+
+enum mac_type {
+ E_MAC_DTSEC,
+ E_MAC_TGEC,
+ E_MAC_MEMAC
+};
+
+/**************************************************************************//**
+ @Description Enum for inter-module interrupts registration
+*//***************************************************************************/
+enum fman_event_modules {
+ E_FMAN_MOD_PRS, /**< Parser event */
+ E_FMAN_MOD_KG, /**< Keygen event */
+ E_FMAN_MOD_PLCR, /**< Policer event */
+ E_FMAN_MOD_10G_MAC, /**< 10G MAC event */
+ E_FMAN_MOD_1G_MAC, /**< 1G MAC event */
+ E_FMAN_MOD_TMR, /**< Timer event */
+ E_FMAN_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */
+ E_FMAN_MOD_MACSEC,
+ E_FMAN_MOD_DUMMY_LAST
+};
+
+/**************************************************************************//**
+ @Description Enum for interrupts types
+*//***************************************************************************/
+enum fman_intr_type {
+ E_FMAN_INTR_TYPE_ERR,
+ E_FMAN_INTR_TYPE_NORMAL
+};
+
+/**************************************************************************//**
+ @Description enum for defining MAC types
+*//***************************************************************************/
+enum fman_mac_type {
+ E_FMAN_MAC_10G = 0, /**< 10G MAC */
+ E_FMAN_MAC_1G /**< 1G MAC */
+};
+
+enum fman_mac_exceptions {
+ E_FMAN_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0,
+ /**< 10GEC MDIO scan event interrupt */
+ E_FMAN_MAC_EX_10G_MDIO_CMD_CMPL,
+ /**< 10GEC MDIO command completion interrupt */
+ E_FMAN_MAC_EX_10G_REM_FAULT,
+ /**< 10GEC, mEMAC Remote fault interrupt */
+ E_FMAN_MAC_EX_10G_LOC_FAULT,
+ /**< 10GEC, mEMAC Local fault interrupt */
+ E_FMAN_MAC_EX_10G_1TX_ECC_ER,
+ /**< 10GEC, mEMAC Transmit frame ECC error interrupt */
+ E_FMAN_MAC_EX_10G_TX_FIFO_UNFL,
+ /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */
+ E_FMAN_MAC_EX_10G_TX_FIFO_OVFL,
+ /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */
+ E_FMAN_MAC_EX_10G_TX_ER,
+ /**< 10GEC Transmit frame error interrupt */
+ E_FMAN_MAC_EX_10G_RX_FIFO_OVFL,
+ /**< 10GEC, mEMAC Receive FIFO overflow interrupt */
+ E_FMAN_MAC_EX_10G_RX_ECC_ER,
+ /**< 10GEC, mEMAC Receive frame ECC error interrupt */
+ E_FMAN_MAC_EX_10G_RX_JAB_FRM,
+ /**< 10GEC Receive jabber frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_OVRSZ_FRM,
+ /**< 10GEC Receive oversized frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_RUNT_FRM,
+ /**< 10GEC Receive runt frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_FRAG_FRM,
+ /**< 10GEC Receive fragment frame interrupt */
+ E_FMAN_MAC_EX_10G_RX_LEN_ER,
+ /**< 10GEC Receive payload length error interrupt */
+ E_FMAN_MAC_EX_10G_RX_CRC_ER,
+ /**< 10GEC Receive CRC error interrupt */
+ E_FMAN_MAC_EX_10G_RX_ALIGN_ER,
+ /**< 10GEC Receive alignment error interrupt */
+ E_FMAN_MAC_EX_1G_BAB_RX,
+ /**< dTSEC Babbling receive error */
+ E_FMAN_MAC_EX_1G_RX_CTL,
+ /**< dTSEC Receive control (pause frame) interrupt */
+ E_FMAN_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET,
+ /**< dTSEC Graceful transmit stop complete */
+ E_FMAN_MAC_EX_1G_BAB_TX,
+ /**< dTSEC Babbling transmit error */
+ E_FMAN_MAC_EX_1G_TX_CTL,
+ /**< dTSEC Transmit control (pause frame) interrupt */
+ E_FMAN_MAC_EX_1G_TX_ERR,
+ /**< dTSEC Transmit error */
+ E_FMAN_MAC_EX_1G_LATE_COL,
+ /**< dTSEC Late collision */
+ E_FMAN_MAC_EX_1G_COL_RET_LMT,
+ /**< dTSEC Collision retry limit */
+ E_FMAN_MAC_EX_1G_TX_FIFO_UNDRN,
+ /**< dTSEC Transmit FIFO underrun */
+ E_FMAN_MAC_EX_1G_MAG_PCKT,
+ /**< dTSEC Magic Packet detection */
+ E_FMAN_MAC_EX_1G_MII_MNG_RD_COMPLET,
+ /**< dTSEC MII management read completion */
+ E_FMAN_MAC_EX_1G_MII_MNG_WR_COMPLET,
+ /**< dTSEC MII management write completion */
+ E_FMAN_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET,
+ /**< dTSEC Graceful receive stop complete */
+ E_FMAN_MAC_EX_1G_TX_DATA_ERR,
+ /**< dTSEC Internal data error on transmit */
+ E_FMAN_MAC_EX_1G_RX_DATA_ERR,
+ /**< dTSEC Internal data error on receive */
+ E_FMAN_MAC_EX_1G_1588_TS_RX_ERR,
+ /**< dTSEC Time-Stamp Receive Error */
+ E_FMAN_MAC_EX_1G_RX_MIB_CNT_OVFL,
+ /**< dTSEC MIB counter overflow */
+ E_FMAN_MAC_EX_TS_FIFO_ECC_ERR,
+ /**< mEMAC Time-stamp FIFO ECC error interrupt;
+ not supported on T4240/B4860 rev1 chips */
+};
+
+#define ENET_IF_SGMII_BASEX 0x80000000
+ /**< SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC
+ and phy or backplane;
+ Note: 1000BaseX auto-negotiation relates only to interface between MAC
+ and phy/backplane, SGMII phy can still synchronize with far-end phy at
+ 10Mbps, 100Mbps or 1000Mbps */
+
+enum enet_mode {
+ E_ENET_MODE_INVALID = 0,
+ /**< Invalid Ethernet mode */
+ E_ENET_MODE_MII_10 = (E_ENET_IF_MII | E_ENET_SPEED_10),
+ /**< 10 Mbps MII */
+ E_ENET_MODE_MII_100 = (E_ENET_IF_MII | E_ENET_SPEED_100),
+ /**< 100 Mbps MII */
+ E_ENET_MODE_RMII_10 = (E_ENET_IF_RMII | E_ENET_SPEED_10),
+ /**< 10 Mbps RMII */
+ E_ENET_MODE_RMII_100 = (E_ENET_IF_RMII | E_ENET_SPEED_100),
+ /**< 100 Mbps RMII */
+ E_ENET_MODE_SMII_10 = (E_ENET_IF_SMII | E_ENET_SPEED_10),
+ /**< 10 Mbps SMII */
+ E_ENET_MODE_SMII_100 = (E_ENET_IF_SMII | E_ENET_SPEED_100),
+ /**< 100 Mbps SMII */
+ E_ENET_MODE_GMII_1000 = (E_ENET_IF_GMII | E_ENET_SPEED_1000),
+ /**< 1000 Mbps GMII */
+ E_ENET_MODE_RGMII_10 = (E_ENET_IF_RGMII | E_ENET_SPEED_10),
+ /**< 10 Mbps RGMII */
+ E_ENET_MODE_RGMII_100 = (E_ENET_IF_RGMII | E_ENET_SPEED_100),
+ /**< 100 Mbps RGMII */
+ E_ENET_MODE_RGMII_1000 = (E_ENET_IF_RGMII | E_ENET_SPEED_1000),
+ /**< 1000 Mbps RGMII */
+ E_ENET_MODE_TBI_1000 = (E_ENET_IF_TBI | E_ENET_SPEED_1000),
+ /**< 1000 Mbps TBI */
+ E_ENET_MODE_RTBI_1000 = (E_ENET_IF_RTBI | E_ENET_SPEED_1000),
+ /**< 1000 Mbps RTBI */
+ E_ENET_MODE_SGMII_10 = (E_ENET_IF_SGMII | E_ENET_SPEED_10),
+ /**< 10 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ E_ENET_MODE_SGMII_100 = (E_ENET_IF_SGMII | E_ENET_SPEED_100),
+ /**< 100 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ E_ENET_MODE_SGMII_1000 = (E_ENET_IF_SGMII | E_ENET_SPEED_1000),
+ /**< 1000 Mbps SGMII with auto-negotiation between MAC and
+ SGMII phy according to Cisco SGMII specification */
+ E_ENET_MODE_SGMII_BASEX_10 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_10),
+ /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ E_ENET_MODE_SGMII_BASEX_100 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_100),
+ /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ E_ENET_MODE_SGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII
+ | E_ENET_SPEED_1000),
+ /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between
+ MAC and SGMII phy or backplane */
+ E_ENET_MODE_QSGMII_1000 = (E_ENET_IF_QSGMII | E_ENET_SPEED_1000),
+ /**< 1000 Mbps QSGMII with auto-negotiation between MAC and
+ QSGMII phy according to Cisco QSGMII specification */
+ E_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_QSGMII
+ | E_ENET_SPEED_1000),
+ /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between
+ MAC and QSGMII phy or backplane */
+ E_ENET_MODE_XGMII_10000 = (E_ENET_IF_XGMII | E_ENET_SPEED_10000),
+ /**< 10000 Mbps XGMII */
+ E_ENET_MODE_XFI_10000 = (E_ENET_IF_XFI | E_ENET_SPEED_10000)
+ /**< 10000 Mbps XFI */
+};
+
+enum fmam_mac_statistics_level {
+ E_FMAN_MAC_NONE_STATISTICS, /**< No statistics */
+ E_FMAN_MAC_PARTIAL_STATISTICS, /**< Only error counters are available;
+ Optimized for performance */
+ E_FMAN_MAC_FULL_STATISTICS /**< All counters available; Not
+ optimized for performance */
+};
+
+#define _MAKE_ENET_MODE(_interface, _speed) (enum enet_mode)((_interface) \
+ | (_speed))
+
+#define _ENET_INTERFACE_FROM_MODE(mode) (enum enet_interface) \
+ ((mode) & 0x0FFF0000)
+#define _ENET_SPEED_FROM_MODE(mode) (enum enet_speed)((mode) & 0x0000FFFF)
+#define _ENET_ADDR_TO_UINT64(_enet_addr) \
+ (uint64_t)(((uint64_t)(_enet_addr)[0] << 40) | \
+ ((uint64_t)(_enet_addr)[1] << 32) | \
+ ((uint64_t)(_enet_addr)[2] << 24) | \
+ ((uint64_t)(_enet_addr)[3] << 16) | \
+ ((uint64_t)(_enet_addr)[4] << 8) | \
+ ((uint64_t)(_enet_addr)[5]))
+
+#define _MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enet_addr) \
+ do { \
+ int i; \
+ for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) \
+ (_enet_addr)[i] = (uint8_t)((_addr64) >> ((5-i)*8));\
+ } while (0)
+
+#endif /* __FSL_ENET_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h
new file mode 100755
index 000000000000..96a63fa7f283
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h
@@ -0,0 +1,825 @@
+/*
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_H
+#define __FSL_FMAN_H
+
+#include "common/general.h"
+
+struct fman_ext_pool_params {
+ uint8_t id; /**< External buffer pool id */
+ uint16_t size; /**< External buffer pool buffer size */
+};
+
+struct fman_ext_pools {
+ uint8_t num_pools_used; /**< Number of pools use by this port */
+ struct fman_ext_pool_params *ext_buf_pool;
+ /**< Parameters for each port */
+};
+
+struct fman_backup_bm_pools {
+ uint8_t num_backup_pools; /**< Number of BM backup pools -
+ must be smaller than the total number
+ of pools defined for the specified
+ port.*/
+ uint8_t *pool_ids; /**< numOfBackupPools pool id's,
+ specifying which pools should be used
+ only as backup. Pool id's specified
+ here must be a subset of the pools
+ used by the specified port.*/
+};
+
+/**************************************************************************//**
+ @Description A structure for defining BM pool depletion criteria
+*//***************************************************************************/
+struct fman_buf_pool_depletion {
+ bool buf_pool_depletion_enabled;
+ bool pools_grp_mode_enable; /**< select mode in which pause frames
+ will be sent after a number of pools
+ (all together!) are depleted */
+ uint8_t num_pools; /**< the number of depleted pools that
+ will invoke pause frames transmission.
+ */
+ bool *pools_to_consider; /**< For each pool, TRUE if it should be
+ considered for depletion (Note - this
+ pool must be used by this port!). */
+ bool single_pool_mode_enable; /**< select mode in which pause frames
+ will be sent after a single-pool
+ is depleted; */
+ bool *pools_to_consider_for_single_mode;
+ /**< For each pool, TRUE if it should be
+ considered for depletion (Note - this
+ pool must be used by this port!) */
+ bool has_pfc_priorities;
+ bool *pfc_priorities_en; /**< This field is used by the MAC as
+ the Priority Enable Vector in the PFC
+ frame which is transmitted */
+};
+
+/**************************************************************************//**
+ @Description Enum for defining port DMA swap mode
+*//***************************************************************************/
+enum fman_dma_swap_option {
+ FMAN_DMA_NO_SWP, /**< No swap, transfer data as is.*/
+ FMAN_DMA_SWP_PPC_LE, /**< The transferred data should be swapped
+ in PowerPc Little Endian mode. */
+ FMAN_DMA_SWP_BE /**< The transferred data should be swapped
+ in Big Endian mode */
+};
+
+/**************************************************************************//**
+ @Description Enum for defining port DMA cache attributes
+*//***************************************************************************/
+enum fman_dma_cache_option {
+ FMAN_DMA_NO_STASH = 0, /**< Cacheable, no Allocate (No Stashing) */
+ FMAN_DMA_STASH = 1 /**< Cacheable and Allocate (Stashing on) */
+};
+
+typedef struct t_FmPrsResult fm_prs_result_t;
+typedef enum e_EnetMode enet_mode_t;
+typedef t_Handle handle_t;
+
+struct fman_revision_info {
+ uint8_t majorRev; /**< Major revision */
+ uint8_t minorRev; /**< Minor revision */
+};
+
+/* sizes */
+#define CAPWAP_FRAG_EXTRA_SPACE 32
+#define OFFSET_UNITS 16
+#define MAX_INT_OFFSET 240
+#define MAX_IC_SIZE 256
+#define MAX_EXT_OFFSET 496
+#define MAX_EXT_BUFFER_OFFSET 511
+
+/**************************************************************************
+ @Description Memory Mapped Registers
+***************************************************************************/
+#define FMAN_LIODN_TBL 64 /* size of LIODN table */
+
+struct fman_fpm_regs {
+ uint32_t fmfp_tnc; /**< FPM TNUM Control 0x00 */
+ uint32_t fmfp_prc; /**< FPM Port_ID FmCtl Association 0x04 */
+ uint32_t fmfp_brkc; /**< FPM Breakpoint Control 0x08 */
+ uint32_t fmfp_mxd; /**< FPM Flush Control 0x0c */
+ uint32_t fmfp_dist1; /**< FPM Dispatch Thresholds1 0x10 */
+ uint32_t fmfp_dist2; /**< FPM Dispatch Thresholds2 0x14 */
+ uint32_t fm_epi; /**< FM Error Pending Interrupts 0x18 */
+ uint32_t fm_rie; /**< FM Error Interrupt Enable 0x1c */
+ uint32_t fmfp_fcev[4]; /**< FPM FMan-Controller Event 1-4 0x20-0x2f */
+ uint32_t res0030[4]; /**< res 0x30 - 0x3f */
+ uint32_t fmfp_cee[4]; /**< PM FMan-Controller Event 1-4 0x40-0x4f */
+ uint32_t res0050[4]; /**< res 0x50-0x5f */
+ uint32_t fmfp_tsc1; /**< FPM TimeStamp Control1 0x60 */
+ uint32_t fmfp_tsc2; /**< FPM TimeStamp Control2 0x64 */
+ uint32_t fmfp_tsp; /**< FPM Time Stamp 0x68 */
+ uint32_t fmfp_tsf; /**< FPM Time Stamp Fraction 0x6c */
+ uint32_t fm_rcr; /**< FM Rams Control 0x70 */
+ uint32_t fmfp_extc; /**< FPM External Requests Control 0x74 */
+ uint32_t fmfp_ext1; /**< FPM External Requests Config1 0x78 */
+ uint32_t fmfp_ext2; /**< FPM External Requests Config2 0x7c */
+ uint32_t fmfp_drd[16]; /**< FPM Data_Ram Data 0-15 0x80 - 0xbf */
+ uint32_t fmfp_dra; /**< FPM Data Ram Access 0xc0 */
+ uint32_t fm_ip_rev_1; /**< FM IP Block Revision 1 0xc4 */
+ uint32_t fm_ip_rev_2; /**< FM IP Block Revision 2 0xc8 */
+ uint32_t fm_rstc; /**< FM Reset Command 0xcc */
+ uint32_t fm_cld; /**< FM Classifier Debug 0xd0 */
+ uint32_t fm_npi; /**< FM Normal Pending Interrupts 0xd4 */
+ uint32_t fmfp_exte; /**< FPM External Requests Enable 0xd8 */
+ uint32_t fmfp_ee; /**< FPM Event & Mask 0xdc */
+ uint32_t fmfp_cev[4]; /**< FPM CPU Event 1-4 0xe0-0xef */
+ uint32_t res00f0[4]; /**< res 0xf0-0xff */
+ uint32_t fmfp_ps[64]; /**< FPM Port Status 0x100-0x1ff */
+ uint32_t fmfp_clfabc; /**< FPM CLFABC 0x200 */
+ uint32_t fmfp_clfcc; /**< FPM CLFCC 0x204 */
+ uint32_t fmfp_clfaval; /**< FPM CLFAVAL 0x208 */
+ uint32_t fmfp_clfbval; /**< FPM CLFBVAL 0x20c */
+ uint32_t fmfp_clfcval; /**< FPM CLFCVAL 0x210 */
+ uint32_t fmfp_clfamsk; /**< FPM CLFAMSK 0x214 */
+ uint32_t fmfp_clfbmsk; /**< FPM CLFBMSK 0x218 */
+ uint32_t fmfp_clfcmsk; /**< FPM CLFCMSK 0x21c */
+ uint32_t fmfp_clfamc; /**< FPM CLFAMC 0x220 */
+ uint32_t fmfp_clfbmc; /**< FPM CLFBMC 0x224 */
+ uint32_t fmfp_clfcmc; /**< FPM CLFCMC 0x228 */
+ uint32_t fmfp_decceh; /**< FPM DECCEH 0x22c */
+ uint32_t res0230[116]; /**< res 0x230 - 0x3ff */
+ uint32_t fmfp_ts[128]; /**< 0x400: FPM Task Status 0x400 - 0x5ff */
+ uint32_t res0600[0x400 - 384];
+};
+
+struct fman_bmi_regs {
+ uint32_t fmbm_init; /**< BMI Initialization 0x00 */
+ uint32_t fmbm_cfg1; /**< BMI Configuration 1 0x04 */
+ uint32_t fmbm_cfg2; /**< BMI Configuration 2 0x08 */
+ uint32_t res000c[5]; /**< 0x0c - 0x1f */
+ uint32_t fmbm_ievr; /**< Interrupt Event Register 0x20 */
+ uint32_t fmbm_ier; /**< Interrupt Enable Register 0x24 */
+ uint32_t fmbm_ifr; /**< Interrupt Force Register 0x28 */
+ uint32_t res002c[5]; /**< 0x2c - 0x3f */
+ uint32_t fmbm_arb[8]; /**< BMI Arbitration 0x40 - 0x5f */
+ uint32_t res0060[12]; /**<0x60 - 0x8f */
+ uint32_t fmbm_dtc[3]; /**< Debug Trap Counter 0x90 - 0x9b */
+ uint32_t res009c; /**< 0x9c */
+ uint32_t fmbm_dcv[3][4]; /**< Debug Compare val 0xa0-0xcf */
+ uint32_t fmbm_dcm[3][4]; /**< Debug Compare Mask 0xd0-0xff */
+ uint32_t fmbm_gde; /**< BMI Global Debug Enable 0x100 */
+ uint32_t fmbm_pp[63]; /**< BMI Port Parameters 0x104 - 0x1ff */
+ uint32_t res0200; /**< 0x200 */
+ uint32_t fmbm_pfs[63]; /**< BMI Port FIFO Size 0x204 - 0x2ff */
+ uint32_t res0300; /**< 0x300 */
+ uint32_t fmbm_spliodn[63]; /**< Port Partition ID 0x304 - 0x3ff */
+};
+
+struct fman_qmi_regs {
+ uint32_t fmqm_gc; /**< General Configuration Register 0x00 */
+ uint32_t res0004; /**< 0x04 */
+ uint32_t fmqm_eie; /**< Error Interrupt Event Register 0x08 */
+ uint32_t fmqm_eien; /**< Error Interrupt Enable Register 0x0c */
+ uint32_t fmqm_eif; /**< Error Interrupt Force Register 0x10 */
+ uint32_t fmqm_ie; /**< Interrupt Event Register 0x14 */
+ uint32_t fmqm_ien; /**< Interrupt Enable Register 0x18 */
+ uint32_t fmqm_if; /**< Interrupt Force Register 0x1c */
+ uint32_t fmqm_gs; /**< Global Status Register 0x20 */
+ uint32_t fmqm_ts; /**< Task Status Register 0x24 */
+ uint32_t fmqm_etfc; /**< Enqueue Total Frame Counter 0x28 */
+ uint32_t fmqm_dtfc; /**< Dequeue Total Frame Counter 0x2c */
+ uint32_t fmqm_dc0; /**< Dequeue Counter 0 0x30 */
+ uint32_t fmqm_dc1; /**< Dequeue Counter 1 0x34 */
+ uint32_t fmqm_dc2; /**< Dequeue Counter 2 0x38 */
+ uint32_t fmqm_dc3; /**< Dequeue Counter 3 0x3c */
+ uint32_t fmqm_dfdc; /**< Dequeue FQID from Default Counter 0x40 */
+ uint32_t fmqm_dfcc; /**< Dequeue FQID from Context Counter 0x44 */
+ uint32_t fmqm_dffc; /**< Dequeue FQID from FD Counter 0x48 */
+ uint32_t fmqm_dcc; /**< Dequeue Confirm Counter 0x4c */
+ uint32_t res0050[7]; /**< 0x50 - 0x6b */
+ uint32_t fmqm_tapc; /**< Tnum Aging Period Control 0x6c */
+ uint32_t fmqm_dmcvc; /**< Dequeue MAC Command Valid Counter 0x70 */
+ uint32_t fmqm_difdcc; /**< Dequeue Invalid FD Command Counter 0x74 */
+ uint32_t fmqm_da1v; /**< Dequeue A1 Valid Counter 0x78 */
+ uint32_t res007c; /**< 0x7c */
+ uint32_t fmqm_dtc; /**< 0x80 Debug Trap Counter 0x80 */
+ uint32_t fmqm_efddd; /**< 0x84 Enqueue Frame desc Dynamic dbg 0x84 */
+ uint32_t res0088[2]; /**< 0x88 - 0x8f */
+ struct {
+ uint32_t fmqm_dtcfg1; /**< 0x90 dbg trap cfg 1 Register 0x00 */
+ uint32_t fmqm_dtval1; /**< Debug Trap Value 1 Register 0x04 */
+ uint32_t fmqm_dtm1; /**< Debug Trap Mask 1 Register 0x08 */
+ uint32_t fmqm_dtc1; /**< Debug Trap Counter 1 Register 0x0c */
+ uint32_t fmqm_dtcfg2; /**< dbg Trap cfg 2 Register 0x10 */
+ uint32_t fmqm_dtval2; /**< Debug Trap Value 2 Register 0x14 */
+ uint32_t fmqm_dtm2; /**< Debug Trap Mask 2 Register 0x18 */
+ uint32_t res001c; /**< 0x1c */
+ } dbg_traps[3]; /**< 0x90 - 0xef */
+ uint8_t res00f0[0x400 - 0xf0]; /**< 0xf0 - 0x3ff */
+};
+
+struct fman_dma_regs {
+ uint32_t fmdmsr; /**< FM DMA status register 0x00 */
+ uint32_t fmdmmr; /**< FM DMA mode register 0x04 */
+ uint32_t fmdmtr; /**< FM DMA bus threshold register 0x08 */
+ uint32_t fmdmhy; /**< FM DMA bus hysteresis register 0x0c */
+ uint32_t fmdmsetr; /**< FM DMA SOS emergency Threshold Register 0x10 */
+ uint32_t fmdmtah; /**< FM DMA transfer bus address high reg 0x14 */
+ uint32_t fmdmtal; /**< FM DMA transfer bus address low reg 0x18 */
+ uint32_t fmdmtcid; /**< FM DMA transfer bus communication ID reg 0x1c */
+ uint32_t fmdmra; /**< FM DMA bus internal ram address register 0x20 */
+ uint32_t fmdmrd; /**< FM DMA bus internal ram data register 0x24 */
+ uint32_t fmdmwcr; /**< FM DMA CAM watchdog counter value 0x28 */
+ uint32_t fmdmebcr; /**< FM DMA CAM base in MURAM register 0x2c */
+ uint32_t fmdmccqdr; /**< FM DMA CAM and CMD Queue Debug reg 0x30 */
+ uint32_t fmdmccqvr1; /**< FM DMA CAM and CMD Queue Value reg #1 0x34 */
+ uint32_t fmdmccqvr2; /**< FM DMA CAM and CMD Queue Value reg #2 0x38 */
+ uint32_t fmdmcqvr3; /**< FM DMA CMD Queue Value register #3 0x3c */
+ uint32_t fmdmcqvr4; /**< FM DMA CMD Queue Value register #4 0x40 */
+ uint32_t fmdmcqvr5; /**< FM DMA CMD Queue Value register #5 0x44 */
+ uint32_t fmdmsefrc; /**< FM DMA Semaphore Entry Full Reject Cntr 0x48 */
+ uint32_t fmdmsqfrc; /**< FM DMA Semaphore Queue Full Reject Cntr 0x4c */
+ uint32_t fmdmssrc; /**< FM DMA Semaphore SYNC Reject Counter 0x50 */
+ uint32_t fmdmdcr; /**< FM DMA Debug Counter 0x54 */
+ uint32_t fmdmemsr; /**< FM DMA Emergency Smoother Register 0x58 */
+ uint32_t res005c; /**< 0x5c */
+ uint32_t fmdmplr[FMAN_LIODN_TBL / 2]; /**< DMA LIODN regs 0x60-0xdf */
+ uint32_t res00e0[0x400 - 56];
+};
+
+struct fman_rg {
+ struct fman_fpm_regs *fpm_rg;
+ struct fman_dma_regs *dma_rg;
+ struct fman_bmi_regs *bmi_rg;
+ struct fman_qmi_regs *qmi_rg;
+};
+
+enum fman_dma_cache_override {
+ E_FMAN_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */
+ E_FMAN_DMA_NO_STASH_DATA, /**< No data stashing in system level cache */
+ E_FMAN_DMA_MAY_STASH_DATA, /**< Stashing allowed in sys level cache */
+ E_FMAN_DMA_STASH_DATA /**< Stashing performed in system level cache */
+};
+
+enum fman_dma_aid_mode {
+ E_FMAN_DMA_AID_OUT_PORT_ID = 0, /**< 4 LSB of PORT_ID */
+ E_FMAN_DMA_AID_OUT_TNUM /**< 4 LSB of TNUM */
+};
+
+enum fman_dma_dbg_cnt_mode {
+ E_FMAN_DMA_DBG_NO_CNT = 0, /**< No counting */
+ E_FMAN_DMA_DBG_CNT_DONE, /**< Count DONE commands */
+ E_FMAN_DMA_DBG_CNT_COMM_Q_EM, /**< command Q emergency signal */
+ E_FMAN_DMA_DBG_CNT_INT_READ_EM, /**< Read buf emergency signal */
+ E_FMAN_DMA_DBG_CNT_INT_WRITE_EM, /**< Write buf emergency signal */
+ E_FMAN_DMA_DBG_CNT_FPM_WAIT, /**< FPM WAIT signal */
+ E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors */
+ E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT /**< RAW & WAR protection counter */
+};
+
+enum fman_dma_emergency_level {
+ E_FMAN_DMA_EM_EBS = 0, /**< EBS emergency */
+ E_FMAN_DMA_EM_SOS /**< SOS emergency */
+};
+
+enum fman_catastrophic_err {
+ E_FMAN_CATAST_ERR_STALL_PORT = 0, /**< Port_ID stalled reset required */
+ E_FMAN_CATAST_ERR_STALL_TASK /**< Only erroneous task is stalled */
+};
+
+enum fman_dma_err {
+ E_FMAN_DMA_ERR_CATASTROPHIC = 0, /**< Catastrophic DMA error */
+ E_FMAN_DMA_ERR_REPORT /**< Reported DMA error */
+};
+
+struct fman_cfg {
+ uint16_t liodn_bs_pr_port[FMAN_LIODN_TBL];/* base per port */
+ bool en_counters;
+ uint8_t disp_limit_tsh;
+ uint8_t prs_disp_tsh;
+ uint8_t plcr_disp_tsh;
+ uint8_t kg_disp_tsh;
+ uint8_t bmi_disp_tsh;
+ uint8_t qmi_enq_disp_tsh;
+ uint8_t qmi_deq_disp_tsh;
+ uint8_t fm_ctl1_disp_tsh;
+ uint8_t fm_ctl2_disp_tsh;
+ enum fman_dma_cache_override dma_cache_override;
+ enum fman_dma_aid_mode dma_aid_mode;
+ bool dma_aid_override;
+ uint8_t dma_axi_dbg_num_of_beats;
+ uint8_t dma_cam_num_of_entries;
+ uint32_t dma_watchdog;
+ uint8_t dma_comm_qtsh_asrt_emer;
+ uint8_t dma_write_buf_tsh_asrt_emer;
+ uint8_t dma_read_buf_tsh_asrt_emer;
+ uint8_t dma_comm_qtsh_clr_emer;
+ uint8_t dma_write_buf_tsh_clr_emer;
+ uint8_t dma_read_buf_tsh_clr_emer;
+ uint32_t dma_sos_emergency;
+ enum fman_dma_dbg_cnt_mode dma_dbg_cnt_mode;
+ bool dma_stop_on_bus_error;
+ bool dma_en_emergency;
+ uint32_t dma_emergency_bus_select;
+ enum fman_dma_emergency_level dma_emergency_level;
+ bool dma_en_emergency_smoother;
+ uint32_t dma_emergency_switch_counter;
+ bool halt_on_external_activ;
+ bool halt_on_unrecov_ecc_err;
+ enum fman_catastrophic_err catastrophic_err;
+ enum fman_dma_err dma_err;
+ bool en_muram_test_mode;
+ bool en_iram_test_mode;
+ bool external_ecc_rams_enable;
+ uint16_t tnum_aging_period;
+ uint32_t exceptions;
+ uint16_t clk_freq;
+ bool pedantic_dma;
+ uint32_t cam_base_addr;
+ uint32_t fifo_base_addr;
+ uint32_t total_fifo_size;
+ uint8_t total_num_of_tasks;
+ bool qmi_deq_option_support;
+ uint32_t qmi_def_tnums_thresh;
+ bool fman_partition_array;
+ uint8_t num_of_fman_ctrl_evnt_regs;
+};
+
+/**************************************************************************//**
+ @Description Exceptions
+*//***************************************************************************/
+#define FMAN_EX_DMA_BUS_ERROR 0x80000000
+#define FMAN_EX_DMA_READ_ECC 0x40000000
+#define FMAN_EX_DMA_SYSTEM_WRITE_ECC 0x20000000
+#define FMAN_EX_DMA_FM_WRITE_ECC 0x10000000
+#define FMAN_EX_FPM_STALL_ON_TASKS 0x08000000
+#define FMAN_EX_FPM_SINGLE_ECC 0x04000000
+#define FMAN_EX_FPM_DOUBLE_ECC 0x02000000
+#define FMAN_EX_QMI_SINGLE_ECC 0x01000000
+#define FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000
+#define FMAN_EX_QMI_DOUBLE_ECC 0x00400000
+#define FMAN_EX_BMI_LIST_RAM_ECC 0x00200000
+#define FMAN_EX_BMI_PIPELINE_ECC 0x00100000
+#define FMAN_EX_BMI_STATISTICS_RAM_ECC 0x00080000
+#define FMAN_EX_IRAM_ECC 0x00040000
+#define FMAN_EX_NURAM_ECC 0x00020000
+#define FMAN_EX_BMI_DISPATCH_RAM_ECC 0x00010000
+
+enum fman_exceptions {
+ E_FMAN_EX_DMA_BUS_ERROR = 0, /**< DMA bus error. */
+ E_FMAN_EX_DMA_READ_ECC, /**< Read Buffer ECC error */
+ E_FMAN_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC err on sys side */
+ E_FMAN_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side */
+ E_FMAN_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */
+ E_FMAN_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */
+ E_FMAN_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */
+ E_FMAN_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */
+ E_FMAN_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */
+ E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< DeQ from unknown port id */
+ E_FMAN_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */
+ E_FMAN_EX_BMI_STORAGE_PROFILE_ECC, /**< storage profile */
+ E_FMAN_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics RAM ECC Err Enable */
+ E_FMAN_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */
+ E_FMAN_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/
+ E_FMAN_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/
+};
+
+enum fman_counters {
+ E_FMAN_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI tot enQ frames counter */
+ E_FMAN_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI tot deQ frames counter */
+ E_FMAN_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */
+ E_FMAN_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */
+ E_FMAN_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */
+ E_FMAN_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */
+ E_FMAN_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI deQ from dflt queue cntr */
+ E_FMAN_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI deQ from FQ context cntr */
+ E_FMAN_COUNTERS_DEQ_FROM_FD, /**< QMI deQ from FD command field cntr */
+ E_FMAN_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */
+ E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT, /**< DMA full entry cntr */
+ E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT, /**< DMA full CAM Q cntr */
+ E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT /**< DMA sync counter */
+};
+
+#define FPM_PRT_FM_CTL1 0x00000001
+#define FPM_PRT_FM_CTL2 0x00000002
+
+/**************************************************************************//**
+ @Description DMA definitions
+*//***************************************************************************/
+
+/* masks */
+#define DMA_MODE_AID_OR 0x20000000
+#define DMA_MODE_SBER 0x10000000
+#define DMA_MODE_BER 0x00200000
+#define DMA_MODE_EB 0x00100000
+#define DMA_MODE_ECC 0x00000020
+#define DMA_MODE_PRIVILEGE_PROT 0x00001000
+#define DMA_MODE_SECURE_PROT 0x00000800
+#define DMA_MODE_EMER_READ 0x00080000
+#define DMA_MODE_EMER_WRITE 0x00040000
+#define DMA_MODE_CACHE_OR_MASK 0xC0000000
+#define DMA_MODE_CEN_MASK 0x0000E000
+#define DMA_MODE_DBG_MASK 0x00000380
+#define DMA_MODE_AXI_DBG_MASK 0x0F000000
+
+#define DMA_EMSR_EMSTR_MASK 0x0000FFFF
+
+#define DMA_TRANSFER_PORTID_MASK 0xFF000000
+#define DMA_TRANSFER_TNUM_MASK 0x00FF0000
+#define DMA_TRANSFER_LIODN_MASK 0x00000FFF
+
+#define DMA_HIGH_LIODN_MASK 0x0FFF0000
+#define DMA_LOW_LIODN_MASK 0x00000FFF
+
+#define DMA_STATUS_CMD_QUEUE_NOT_EMPTY 0x10000000
+#define DMA_STATUS_BUS_ERR 0x08000000
+#define DMA_STATUS_READ_ECC 0x04000000
+#define DMA_STATUS_SYSTEM_WRITE_ECC 0x02000000
+#define DMA_STATUS_FM_WRITE_ECC 0x01000000
+#define DMA_STATUS_SYSTEM_DPEXT_ECC 0x00800000
+#define DMA_STATUS_FM_DPEXT_ECC 0x00400000
+#define DMA_STATUS_SYSTEM_DPDAT_ECC 0x00200000
+#define DMA_STATUS_FM_DPDAT_ECC 0x00100000
+#define DMA_STATUS_FM_SPDAT_ECC 0x00080000
+
+#define FM_LIODN_BASE_MASK 0x00000FFF
+
+/* shifts */
+#define DMA_MODE_CACHE_OR_SHIFT 30
+#define DMA_MODE_BUS_PRI_SHIFT 16
+#define DMA_MODE_AXI_DBG_SHIFT 24
+#define DMA_MODE_CEN_SHIFT 13
+#define DMA_MODE_BUS_PROT_SHIFT 10
+#define DMA_MODE_DBG_SHIFT 7
+#define DMA_MODE_EMER_LVL_SHIFT 6
+#define DMA_MODE_AID_MODE_SHIFT 4
+#define DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS 16
+#define DMA_MODE_MAX_CAM_NUM_OF_ENTRIES 32
+
+#define DMA_THRESH_COMMQ_SHIFT 24
+#define DMA_THRESH_READ_INT_BUF_SHIFT 16
+
+#define DMA_LIODN_SHIFT 16
+
+#define DMA_TRANSFER_PORTID_SHIFT 24
+#define DMA_TRANSFER_TNUM_SHIFT 16
+
+/* sizes */
+#define DMA_MAX_WATCHDOG 0xffffffff
+
+/* others */
+#define DMA_CAM_SIZEOF_ENTRY 0x40
+#define DMA_CAM_ALIGN 0x1000
+#define DMA_CAM_UNITS 8
+
+/**************************************************************************//**
+ @Description General defines
+*//***************************************************************************/
+
+#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL
+#define FM_UCODE_DEBUG_INSTRUCTION 0x6ffff805UL
+
+/**************************************************************************//**
+ @Description FPM defines
+*//***************************************************************************/
+
+/* masks */
+#define FPM_EV_MASK_DOUBLE_ECC 0x80000000
+#define FPM_EV_MASK_STALL 0x40000000
+#define FPM_EV_MASK_SINGLE_ECC 0x20000000
+#define FPM_EV_MASK_RELEASE_FM 0x00010000
+#define FPM_EV_MASK_DOUBLE_ECC_EN 0x00008000
+#define FPM_EV_MASK_STALL_EN 0x00004000
+#define FPM_EV_MASK_SINGLE_ECC_EN 0x00002000
+#define FPM_EV_MASK_EXTERNAL_HALT 0x00000008
+#define FPM_EV_MASK_ECC_ERR_HALT 0x00000004
+
+#define FPM_RAM_RAMS_ECC_EN 0x80000000
+#define FPM_RAM_IRAM_ECC_EN 0x40000000
+#define FPM_RAM_MURAM_ECC 0x00008000
+#define FPM_RAM_IRAM_ECC 0x00004000
+#define FPM_RAM_MURAM_TEST_ECC 0x20000000
+#define FPM_RAM_IRAM_TEST_ECC 0x10000000
+#define FPM_RAM_RAMS_ECC_EN_SRC_SEL 0x08000000
+
+#define FPM_IRAM_ECC_ERR_EX_EN 0x00020000
+#define FPM_MURAM_ECC_ERR_EX_EN 0x00040000
+
+#define FPM_REV1_MAJOR_MASK 0x0000FF00
+#define FPM_REV1_MINOR_MASK 0x000000FF
+
+#define FPM_REV2_INTEG_MASK 0x00FF0000
+#define FPM_REV2_ERR_MASK 0x0000FF00
+#define FPM_REV2_CFG_MASK 0x000000FF
+
+#define FPM_TS_FRACTION_MASK 0x0000FFFF
+#define FPM_TS_CTL_EN 0x80000000
+
+#define FPM_PRC_REALSE_STALLED 0x00800000
+
+#define FPM_PS_STALLED 0x00800000
+#define FPM_PS_FM_CTL1_SEL 0x80000000
+#define FPM_PS_FM_CTL2_SEL 0x40000000
+#define FPM_PS_FM_CTL_SEL_MASK (FPM_PS_FM_CTL1_SEL | FPM_PS_FM_CTL2_SEL)
+
+#define FPM_RSTC_FM_RESET 0x80000000
+#define FPM_RSTC_10G0_RESET 0x04000000
+#define FPM_RSTC_1G0_RESET 0x40000000
+#define FPM_RSTC_1G1_RESET 0x20000000
+#define FPM_RSTC_1G2_RESET 0x10000000
+#define FPM_RSTC_1G3_RESET 0x08000000
+#define FPM_RSTC_1G4_RESET 0x02000000
+
+
+#define FPM_DISP_LIMIT_MASK 0x1F000000
+#define FPM_THR1_PRS_MASK 0xFF000000
+#define FPM_THR1_KG_MASK 0x00FF0000
+#define FPM_THR1_PLCR_MASK 0x0000FF00
+#define FPM_THR1_BMI_MASK 0x000000FF
+
+#define FPM_THR2_QMI_ENQ_MASK 0xFF000000
+#define FPM_THR2_QMI_DEQ_MASK 0x000000FF
+#define FPM_THR2_FM_CTL1_MASK 0x00FF0000
+#define FPM_THR2_FM_CTL2_MASK 0x0000FF00
+
+/* shifts */
+#define FPM_DISP_LIMIT_SHIFT 24
+
+#define FPM_THR1_PRS_SHIFT 24
+#define FPM_THR1_KG_SHIFT 16
+#define FPM_THR1_PLCR_SHIFT 8
+#define FPM_THR1_BMI_SHIFT 0
+
+#define FPM_THR2_QMI_ENQ_SHIFT 24
+#define FPM_THR2_QMI_DEQ_SHIFT 0
+#define FPM_THR2_FM_CTL1_SHIFT 16
+#define FPM_THR2_FM_CTL2_SHIFT 8
+
+#define FPM_EV_MASK_CAT_ERR_SHIFT 1
+#define FPM_EV_MASK_DMA_ERR_SHIFT 0
+
+#define FPM_REV1_MAJOR_SHIFT 8
+#define FPM_REV1_MINOR_SHIFT 0
+
+#define FPM_REV2_INTEG_SHIFT 16
+#define FPM_REV2_ERR_SHIFT 8
+#define FPM_REV2_CFG_SHIFT 0
+
+#define FPM_TS_INT_SHIFT 16
+
+#define FPM_PORT_FM_CTL_PORTID_SHIFT 24
+
+#define FPM_PS_FM_CTL_SEL_SHIFT 30
+#define FPM_PRC_ORA_FM_CTL_SEL_SHIFT 16
+
+#define FPM_DISP_LIMIT_SHIFT 24
+
+/* Interrupts defines */
+#define FPM_EVENT_FM_CTL_0 0x00008000
+#define FPM_EVENT_FM_CTL 0x0000FF00
+#define FPM_EVENT_FM_CTL_BRK 0x00000080
+
+/* others */
+#define FPM_MAX_DISP_LIMIT 31
+#define FPM_RSTC_FM_RESET 0x80000000
+#define FPM_RSTC_1G0_RESET 0x40000000
+#define FPM_RSTC_1G1_RESET 0x20000000
+#define FPM_RSTC_1G2_RESET 0x10000000
+#define FPM_RSTC_1G3_RESET 0x08000000
+#define FPM_RSTC_10G0_RESET 0x04000000
+#define FPM_RSTC_1G4_RESET 0x02000000
+#define FPM_RSTC_1G5_RESET 0x01000000
+#define FPM_RSTC_1G6_RESET 0x00800000
+#define FPM_RSTC_1G7_RESET 0x00400000
+#define FPM_RSTC_10G1_RESET 0x00200000
+/**************************************************************************//**
+ @Description BMI defines
+*//***************************************************************************/
+/* masks */
+#define BMI_INIT_START 0x80000000
+#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000
+#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000
+#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000
+#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000
+#define BMI_NUM_OF_TASKS_MASK 0x3F000000
+#define BMI_NUM_OF_EXTRA_TASKS_MASK 0x000F0000
+#define BMI_NUM_OF_DMAS_MASK 0x00000F00
+#define BMI_NUM_OF_EXTRA_DMAS_MASK 0x0000000F
+#define BMI_FIFO_SIZE_MASK 0x000003FF
+#define BMI_EXTRA_FIFO_SIZE_MASK 0x03FF0000
+#define BMI_CFG2_DMAS_MASK 0x0000003F
+#define BMI_TOTAL_FIFO_SIZE_MASK 0x07FF0000
+#define BMI_TOTAL_NUM_OF_TASKS_MASK 0x007F0000
+
+/* shifts */
+#define BMI_CFG2_TASKS_SHIFT 16
+#define BMI_CFG2_DMAS_SHIFT 0
+#define BMI_CFG1_FIFO_SIZE_SHIFT 16
+#define BMI_FIFO_SIZE_SHIFT 0
+#define BMI_EXTRA_FIFO_SIZE_SHIFT 16
+#define BMI_NUM_OF_TASKS_SHIFT 24
+#define BMI_EXTRA_NUM_OF_TASKS_SHIFT 16
+#define BMI_NUM_OF_DMAS_SHIFT 8
+#define BMI_EXTRA_NUM_OF_DMAS_SHIFT 0
+
+/* others */
+#define BMI_FIFO_ALIGN 0x100
+#define FMAN_BMI_FIFO_UNITS 0x100
+
+
+/**************************************************************************//**
+ @Description QMI defines
+*//***************************************************************************/
+/* masks */
+#define QMI_CFG_ENQ_EN 0x80000000
+#define QMI_CFG_DEQ_EN 0x40000000
+#define QMI_CFG_EN_COUNTERS 0x10000000
+#define QMI_CFG_SOFT_RESET 0x01000000
+#define QMI_CFG_DEQ_MASK 0x0000003F
+#define QMI_CFG_ENQ_MASK 0x00003F00
+
+#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000
+#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000
+#define QMI_INTR_EN_SINGLE_ECC 0x80000000
+
+/* shifts */
+#define QMI_CFG_ENQ_SHIFT 8
+#define QMI_TAPC_TAP 22
+
+#define QMI_GS_HALT_NOT_BUSY 0x00000002
+
+/**************************************************************************//**
+ @Description IRAM defines
+*//***************************************************************************/
+/* masks */
+#define IRAM_IADD_AIE 0x80000000
+#define IRAM_READY 0x80000000
+
+uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg);
+uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg);
+uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg);
+uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg);
+uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg);
+uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg);
+uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg);
+uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg);
+uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg);
+uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg);
+uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg,
+ uint8_t event_reg_id);
+uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg);
+uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg);
+uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
+uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg);
+uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
+uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id);
+uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id);
+uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id);
+uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg);
+uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg,
+ uint8_t reg_id);
+uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg);
+void fman_get_revision(struct fman_fpm_regs *fpm_rg, uint8_t *major,
+ uint8_t *minor);
+uint32_t fman_get_counter(struct fman_rg *fman_rg,
+ enum fman_counters reg_name);
+uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg);
+
+
+int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg);
+void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id,
+ uint32_t enable_events);
+void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg,
+ uint8_t port_id,
+ uint8_t num_fman_ctrls,
+ uint32_t or_fman_ctrl);
+void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg,
+ uint8_t port_id,
+ bool independent_mode,
+ bool is_rx_port);
+void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val);
+void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val);
+void fman_set_liodn_per_port(struct fman_rg *fman_rg,
+ uint8_t port_id,
+ uint16_t liodn_base,
+ uint16_t liodn_offset);
+void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint32_t size_of_fifo,
+ uint32_t extra_size_of_fifo);
+void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_of_tasks,
+ uint8_t num_of_extra_tasks);
+void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t num_of_open_dmas,
+ uint8_t num_of_extra_open_dmas,
+ uint8_t total_num_of_dmas);
+void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights);
+int fman_set_exception(struct fman_rg *fman_rg,
+ enum fman_exceptions exception,
+ bool enable);
+void fman_set_dma_emergency(struct fman_dma_regs *dma_rg, bool is_write,
+ bool enable);
+void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri);
+void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg,
+ uint32_t congestion_group_id,
+ uint8_t piority_bit_map,
+ uint32_t reg_num);
+
+
+void fman_defconfig(struct fman_cfg *cfg, bool is_master);
+void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg);
+int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg);
+int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg);
+int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg);
+int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg);
+void fman_free_resources(struct fman_rg *fman_rg);
+int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg);
+void fman_reset(struct fman_fpm_regs *fpm_rg);
+void fman_resume(struct fman_fpm_regs *fpm_rg);
+
+
+void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg,
+ uint8_t count1ubit,
+ uint16_t fm_clk_freq);
+void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg);
+void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg);
+void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg);
+void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id);
+int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t macId, bool is_10g);
+bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id);
+bool fman_rams_ecc_is_external_ctl(struct fman_fpm_regs *fpm_rg);
+bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg);
+int fman_modify_counter(struct fman_rg *fman_rg,
+ enum fman_counters reg_name,
+ uint32_t val);
+void fman_force_intr(struct fman_rg *fman_rg,
+ enum fman_exceptions exception);
+void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg,
+ uint8_t port_id,
+ uint8_t base_storage_profile,
+ uint8_t log2_num_of_profiles);
+
+/**************************************************************************//**
+ @Description default values
+*//***************************************************************************/
+#define DEFAULT_CATASTROPHIC_ERR E_FMAN_CATAST_ERR_STALL_PORT
+#define DEFAULT_DMA_ERR E_FMAN_DMA_ERR_CATASTROPHIC
+#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION FALSE /* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR FALSE /* do not change! if changed, must be disabled for rev1 ! */
+#define DEFAULT_EXTERNAL_ECC_RAMS_ENABLE FALSE
+#define DEFAULT_AID_OVERRIDE FALSE
+#define DEFAULT_AID_MODE E_FMAN_DMA_AID_OUT_TNUM
+#define DEFAULT_DMA_COMM_Q_LOW 0x2A
+#define DEFAULT_DMA_COMM_Q_HIGH 0x3F
+#define DEFAULT_CACHE_OVERRIDE E_FMAN_DMA_NO_CACHE_OR
+#define DEFAULT_DMA_CAM_NUM_OF_ENTRIES 64
+#define DEFAULT_DMA_DBG_CNT_MODE E_FMAN_DMA_DBG_NO_CNT
+#define DEFAULT_DMA_EN_EMERGENCY FALSE
+#define DEFAULT_DMA_SOS_EMERGENCY 0
+#define DEFAULT_DMA_WATCHDOG 0 /* disabled */
+#define DEFAULT_DMA_EN_EMERGENCY_SMOOTHER FALSE
+#define DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER 0
+#define DEFAULT_DISP_LIMIT 0
+#define DEFAULT_PRS_DISP_TH 16
+#define DEFAULT_PLCR_DISP_TH 16
+#define DEFAULT_KG_DISP_TH 16
+#define DEFAULT_BMI_DISP_TH 16
+#define DEFAULT_QMI_ENQ_DISP_TH 16
+#define DEFAULT_QMI_DEQ_DISP_TH 16
+#define DEFAULT_FM_CTL1_DISP_TH 16
+#define DEFAULT_FM_CTL2_DISP_TH 16
+#define DEFAULT_TNUM_AGING_PERIOD 4
+
+
+#endif /* __FSL_FMAN_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h
new file mode 100644
index 000000000000..6004e478081a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h
@@ -0,0 +1,1096 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_DTSEC_H
+#define __FSL_FMAN_DTSEC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+
+/**
+ * DOC: dTSEC Init sequence
+ *
+ * To prepare dTSEC block for transfer use the following call sequence:
+ *
+ * - fman_dtsec_defconfig() - This step is optional and yet recommended. Its
+ * use is to obtain the default dTSEC configuration parameters.
+ *
+ * - Change dtsec configuration in &dtsec_cfg. This structure will be used
+ * to customize the dTSEC behavior.
+ *
+ * - fman_dtsec_init() - Applies the configuration on dTSEC hardware. Note that
+ * dTSEC is initialized while both Tx and Rx are disabled.
+ *
+ * - fman_dtsec_set_mac_address() - Set the station address (mac address).
+ * This is used by dTSEC to match against received packets.
+ *
+ * - fman_dtsec_adjust_link() - Set the link speed and duplex parameters
+ * after the PHY establishes the link.
+ *
+ * - dtsec_enable_tx() and dtsec_enable_rx() to enable transmission and
+ * reception.
+ */
+
+/**
+ * DOC: dTSEC Graceful stop
+ *
+ * To temporary stop dTSEC activity use fman_dtsec_stop_tx() and
+ * fman_dtsec_stop_rx(). Note that these functions request dTSEC graceful stop
+ * but return before this stop is complete. To query for graceful stop
+ * completion use fman_dtsec_get_event() and check DTSEC_IEVENT_GTSC and
+ * DTSEC_IEVENT_GRSC bits. Alternatively the dTSEC interrupt mask can be set to
+ * enable graceful stop interrupts.
+ *
+ * To resume operation after graceful stop use fman_dtsec_start_tx() and
+ * fman_dtsec_start_rx().
+ */
+
+/**
+ * DOC: dTSEC interrupt handling
+ *
+ * This code does not provide an interrupt handler for dTSEC. Instead this
+ * handler should be implemented and registered to the operating system by the
+ * caller. Some primitives for accessing the event status and mask registers
+ * are provided.
+ *
+ * See "dTSEC Events" section for a list of events that dTSEC can generate.
+ */
+
+/**
+ * DOC: dTSEC Events
+ *
+ * Interrupt events cause dTSEC event bits to be set. Software may poll the
+ * event register at any time to check for pending interrupts. If an event
+ * occurs and its corresponding enable bit is set in the interrupt mask
+ * register, the event also causes a hardware interrupt at the PIC.
+ *
+ * To poll for event status use the fman_dtsec_get_event() function.
+ * To configure the interrupt mask use fman_dtsec_enable_interrupt() and
+ * fman_dtsec_disable_interrupt() functions.
+ * After servicing a dTSEC interrupt use fman_dtsec_ack_event to reset the
+ * serviced event bit.
+ *
+ * The following events may be signaled by dTSEC hardware:
+ *
+ * %DTSEC_IEVENT_BABR - Babbling receive error. This bit indicates that
+ * a frame was received with length in excess of the MAC's maximum frame length
+ * register.
+ *
+ * %DTSEC_IEVENT_RXC - Receive control (pause frame) interrupt. A pause
+ * control frame was received while Rx pause frame handling is enabled.
+ * Also see fman_dtsec_handle_rx_pause().
+ *
+ * %DTSEC_IEVENT_MSRO - MIB counter overflow. The count for one of the MIB
+ * counters has exceeded the size of its register.
+ *
+ * %DTSEC_IEVENT_GTSC - Graceful transmit stop complete. Graceful stop is now
+ * complete. The transmitter is in a stopped state, in which only pause frames
+ * can be transmitted.
+ * Also see fman_dtsec_stop_tx().
+ *
+ * %DTSEC_IEVENT_BABT - Babbling transmit error. The transmitted frame length
+ * has exceeded the value in the MAC's Maximum Frame Length register.
+ *
+ * %DTSEC_IEVENT_TXC - Transmit control (pause frame) interrupt. his bit
+ * indicates that a control frame was transmitted.
+ *
+ * %DTSEC_IEVENT_TXE - Transmit error. This bit indicates that an error
+ * occurred on the transmitted channel. This bit is set whenever any transmit
+ * error occurs which causes the dTSEC to discard all or part of a frame
+ * (LC, CRL, XFUN).
+ *
+ * %DTSEC_IEVENT_LC - Late collision. This bit indicates that a collision
+ * occurred beyond the collision window (slot time) in half-duplex mode.
+ * The frame is truncated with a bad CRC and the remainder of the frame
+ * is discarded.
+ *
+ * %DTSEC_IEVENT_CRL - Collision retry limit. is bit indicates that the number
+ * of successive transmission collisions has exceeded the MAC's half-duplex
+ * register's retransmission maximum count. The frame is discarded without
+ * being transmitted and transmission of the next frame commences. This only
+ * occurs while in half-duplex mode.
+ * The number of retransmit attempts can be set in
+ * &dtsec_halfdup_cfg.@retransmit before calling fman_dtsec_init().
+ *
+ * %DTSEC_IEVENT_XFUN - Transmit FIFO underrun. This bit indicates that the
+ * transmit FIFO became empty before the complete frame was transmitted.
+ * The frame is truncated with a bad CRC and the remainder of the frame is
+ * discarded.
+ *
+ * %DTSEC_IEVENT_MAG - TBD
+ *
+ * %DTSEC_IEVENT_MMRD - MII management read completion.
+ *
+ * %DTSEC_IEVENT_MMWR - MII management write completion.
+ *
+ * %DTSEC_IEVENT_GRSC - Graceful receive stop complete. It allows the user to
+ * know if the system has completed the stop and it is safe to write to receive
+ * registers (status, control or configuration registers) that are used by the
+ * system during normal operation.
+ *
+ * %DTSEC_IEVENT_TDPE - Internal data error on transmit. This bit indicates
+ * that the dTSEC has detected a parity error on its stored transmit data, which
+ * is likely to compromise the validity of recently transferred frames.
+ *
+ * %DTSEC_IEVENT_RDPE - Internal data error on receive. This bit indicates that
+ * the dTSEC has detected a parity error on its stored receive data, which is
+ * likely to compromise the validity of recently transferred frames.
+ */
+/* Interrupt Mask Register (IMASK) */
+#define DTSEC_IMASK_BREN 0x80000000
+#define DTSEC_IMASK_RXCEN 0x40000000
+#define DTSEC_IMASK_MSROEN 0x04000000
+#define DTSEC_IMASK_GTSCEN 0x02000000
+#define DTSEC_IMASK_BTEN 0x01000000
+#define DTSEC_IMASK_TXCEN 0x00800000
+#define DTSEC_IMASK_TXEEN 0x00400000
+#define DTSEC_IMASK_LCEN 0x00040000
+#define DTSEC_IMASK_CRLEN 0x00020000
+#define DTSEC_IMASK_XFUNEN 0x00010000
+#define DTSEC_IMASK_ABRTEN 0x00008000
+#define DTSEC_IMASK_IFERREN 0x00004000
+#define DTSEC_IMASK_MAGEN 0x00000800
+#define DTSEC_IMASK_MMRDEN 0x00000400
+#define DTSEC_IMASK_MMWREN 0x00000200
+#define DTSEC_IMASK_GRSCEN 0x00000100
+#define DTSEC_IMASK_TDPEEN 0x00000002
+#define DTSEC_IMASK_RDPEEN 0x00000001
+
+#define DTSEC_EVENTS_MASK \
+ ((uint32_t)(DTSEC_IMASK_BREN | \
+ DTSEC_IMASK_RXCEN | \
+ DTSEC_IMASK_BTEN | \
+ DTSEC_IMASK_TXCEN | \
+ DTSEC_IMASK_TXEEN | \
+ DTSEC_IMASK_ABRTEN | \
+ DTSEC_IMASK_LCEN | \
+ DTSEC_IMASK_CRLEN | \
+ DTSEC_IMASK_XFUNEN | \
+ DTSEC_IMASK_IFERREN | \
+ DTSEC_IMASK_MAGEN | \
+ DTSEC_IMASK_TDPEEN | \
+ DTSEC_IMASK_RDPEEN))
+
+/* dtsec timestamp event bits */
+#define TMR_PEMASK_TSREEN 0x00010000
+#define TMR_PEVENT_TSRE 0x00010000
+
+/* Group address bit indication */
+#define MAC_GROUP_ADDRESS 0x0000010000000000ULL
+/* size in bytes of L2 address */
+#define MAC_ADDRLEN 6
+
+#define DEFAULT_HALFDUP_ON FALSE
+#define DEFAULT_HALFDUP_RETRANSMIT 0xf
+#define DEFAULT_HALFDUP_COLL_WINDOW 0x37
+#define DEFAULT_HALFDUP_EXCESS_DEFER TRUE
+#define DEFAULT_HALFDUP_NO_BACKOFF FALSE
+#define DEFAULT_HALFDUP_BP_NO_BACKOFF FALSE
+#define DEFAULT_HALFDUP_ALT_BACKOFF_VAL 0x0A
+#define DEFAULT_HALFDUP_ALT_BACKOFF_EN FALSE
+#define DEFAULT_RX_DROP_BCAST FALSE
+#define DEFAULT_RX_SHORT_FRM TRUE
+#define DEFAULT_RX_LEN_CHECK FALSE
+#define DEFAULT_TX_PAD_CRC TRUE
+#define DEFAULT_TX_CRC FALSE
+#define DEFAULT_RX_CTRL_ACC FALSE
+#define DEFAULT_TX_PAUSE_TIME 0xf000
+#define DEFAULT_TBIPA 5
+#define DEFAULT_RX_PREPEND 0
+#define DEFAULT_PTP_TSU_EN TRUE
+#define DEFAULT_PTP_EXCEPTION_EN TRUE
+#define DEFAULT_PREAMBLE_LEN 7
+#define DEFAULT_RX_PREAMBLE FALSE
+#define DEFAULT_TX_PREAMBLE FALSE
+#define DEFAULT_LOOPBACK FALSE
+#define DEFAULT_RX_TIME_STAMP_EN FALSE
+#define DEFAULT_TX_TIME_STAMP_EN FALSE
+#define DEFAULT_RX_FLOW TRUE
+#define DEFAULT_TX_FLOW TRUE
+#define DEFAULT_RX_GROUP_HASH_EXD FALSE
+#define DEFAULT_TX_PAUSE_TIME_EXTD 0
+#define DEFAULT_RX_PROMISC FALSE
+#define DEFAULT_NON_BACK_TO_BACK_IPG1 0x40
+#define DEFAULT_NON_BACK_TO_BACK_IPG2 0x60
+#define DEFAULT_MIN_IFG_ENFORCEMENT 0x50
+#define DEFAULT_BACK_TO_BACK_IPG 0x60
+#define DEFAULT_MAXIMUM_FRAME 0x600
+#define DEFAULT_TBI_PHY_ADDR 5
+#define DEFAULT_WAKE_ON_LAN FALSE
+
+/* register related defines (bits, field offsets..) */
+#define DTSEC_ID1_ID 0xffff0000
+#define DTSEC_ID1_REV_MJ 0x0000FF00
+#define DTSEC_ID1_REV_MN 0x000000ff
+
+#define DTSEC_ID2_INT_REDUCED_OFF 0x00010000
+#define DTSEC_ID2_INT_NORMAL_OFF 0x00020000
+
+#define DTSEC_ECNTRL_CLRCNT 0x00004000
+#define DTSEC_ECNTRL_AUTOZ 0x00002000
+#define DTSEC_ECNTRL_STEN 0x00001000
+#define DTSEC_ECNTRL_CFG_RO 0x80000000
+#define DTSEC_ECNTRL_GMIIM 0x00000040
+#define DTSEC_ECNTRL_TBIM 0x00000020
+#define DTSEC_ECNTRL_SGMIIM 0x00000002
+#define DTSEC_ECNTRL_RPM 0x00000010
+#define DTSEC_ECNTRL_R100M 0x00000008
+#define DTSEC_ECNTRL_RMM 0x00000004
+#define DTSEC_ECNTRL_QSGMIIM 0x00000001
+
+#define DTSEC_TCTRL_THDF 0x00000800
+#define DTSEC_TCTRL_TTSE 0x00000040
+#define DTSEC_TCTRL_GTS 0x00000020
+#define DTSEC_TCTRL_TFC_PAUSE 0x00000010
+
+/* PTV offsets */
+#define PTV_PTE_OFST 16
+
+#define RCTRL_CFA 0x00008000
+#define RCTRL_GHTX 0x00000400
+#define RCTRL_RTSE 0x00000040
+#define RCTRL_GRS 0x00000020
+#define RCTRL_BC_REJ 0x00000010
+#define RCTRL_MPROM 0x00000008
+#define RCTRL_RSF 0x00000004
+#define RCTRL_UPROM 0x00000001
+#define RCTRL_PROM (RCTRL_UPROM | RCTRL_MPROM)
+
+#define TMR_CTL_ESFDP 0x00000800
+#define TMR_CTL_ESFDE 0x00000400
+
+#define MACCFG1_SOFT_RESET 0x80000000
+#define MACCFG1_LOOPBACK 0x00000100
+#define MACCFG1_RX_FLOW 0x00000020
+#define MACCFG1_TX_FLOW 0x00000010
+#define MACCFG1_TX_EN 0x00000001
+#define MACCFG1_RX_EN 0x00000004
+#define MACCFG1_RESET_RxMC 0x00080000
+#define MACCFG1_RESET_TxMC 0x00040000
+#define MACCFG1_RESET_RxFUN 0x00020000
+#define MACCFG1_RESET_TxFUN 0x00010000
+
+#define MACCFG2_NIBBLE_MODE 0x00000100
+#define MACCFG2_BYTE_MODE 0x00000200
+#define MACCFG2_PRE_AM_Rx_EN 0x00000080
+#define MACCFG2_PRE_AM_Tx_EN 0x00000040
+#define MACCFG2_LENGTH_CHECK 0x00000010
+#define MACCFG2_MAGIC_PACKET_EN 0x00000008
+#define MACCFG2_PAD_CRC_EN 0x00000004
+#define MACCFG2_CRC_EN 0x00000002
+#define MACCFG2_FULL_DUPLEX 0x00000001
+
+#define PREAMBLE_LENGTH_SHIFT 12
+
+#define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT 24
+#define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT 16
+#define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT 8
+
+#define IPGIFG_NON_BACK_TO_BACK_IPG_1 0x7F000000
+#define IPGIFG_NON_BACK_TO_BACK_IPG_2 0x007F0000
+#define IPGIFG_MIN_IFG_ENFORCEMENT 0x0000FF00
+#define IPGIFG_BACK_TO_BACK_IPG 0x0000007F
+
+#define HAFDUP_ALT_BEB 0x00080000
+#define HAFDUP_BP_NO_BACKOFF 0x00040000
+#define HAFDUP_NO_BACKOFF 0x00020000
+#define HAFDUP_EXCESS_DEFER 0x00010000
+#define HAFDUP_COLLISION_WINDOW 0x000003ff
+
+#define HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT 20
+#define HAFDUP_RETRANSMISSION_MAX_SHIFT 12
+#define HAFDUP_RETRANSMISSION_MAX 0x0000f000
+
+#define NUM_OF_HASH_REGS 8 /* Number of hash table registers */
+
+/* CAR1/2 bits */
+#define DTSEC_CAR1_TR64 0x80000000
+#define DTSEC_CAR1_TR127 0x40000000
+#define DTSEC_CAR1_TR255 0x20000000
+#define DTSEC_CAR1_TR511 0x10000000
+#define DTSEC_CAR1_TRK1 0x08000000
+#define DTSEC_CAR1_TRMAX 0x04000000
+#define DTSEC_CAR1_TRMGV 0x02000000
+
+#define DTSEC_CAR1_RBYT 0x00010000
+#define DTSEC_CAR1_RPKT 0x00008000
+#define DTSEC_CAR1_RFCS 0x00004000
+#define DTSEC_CAR1_RMCA 0x00002000
+#define DTSEC_CAR1_RBCA 0x00001000
+#define DTSEC_CAR1_RXCF 0x00000800
+#define DTSEC_CAR1_RXPF 0x00000400
+#define DTSEC_CAR1_RXUO 0x00000200
+#define DTSEC_CAR1_RALN 0x00000100
+#define DTSEC_CAR1_RFLR 0x00000080
+#define DTSEC_CAR1_RCDE 0x00000040
+#define DTSEC_CAR1_RCSE 0x00000020
+#define DTSEC_CAR1_RUND 0x00000010
+#define DTSEC_CAR1_ROVR 0x00000008
+#define DTSEC_CAR1_RFRG 0x00000004
+#define DTSEC_CAR1_RJBR 0x00000002
+#define DTSEC_CAR1_RDRP 0x00000001
+
+#define DTSEC_CAR2_TJBR 0x00080000
+#define DTSEC_CAR2_TFCS 0x00040000
+#define DTSEC_CAR2_TXCF 0x00020000
+#define DTSEC_CAR2_TOVR 0x00010000
+#define DTSEC_CAR2_TUND 0x00008000
+#define DTSEC_CAR2_TFRG 0x00004000
+#define DTSEC_CAR2_TBYT 0x00002000
+#define DTSEC_CAR2_TPKT 0x00001000
+#define DTSEC_CAR2_TMCA 0x00000800
+#define DTSEC_CAR2_TBCA 0x00000400
+#define DTSEC_CAR2_TXPF 0x00000200
+#define DTSEC_CAR2_TDFR 0x00000100
+#define DTSEC_CAR2_TEDF 0x00000080
+#define DTSEC_CAR2_TSCL 0x00000040
+#define DTSEC_CAR2_TMCL 0x00000020
+#define DTSEC_CAR2_TLCL 0x00000010
+#define DTSEC_CAR2_TXCL 0x00000008
+#define DTSEC_CAR2_TNCL 0x00000004
+#define DTSEC_CAR2_TDRP 0x00000001
+
+#define CAM1_ERRORS_ONLY \
+ (DTSEC_CAR1_RXPF | DTSEC_CAR1_RALN | DTSEC_CAR1_RFLR \
+ | DTSEC_CAR1_RCDE | DTSEC_CAR1_RCSE | DTSEC_CAR1_RUND \
+ | DTSEC_CAR1_ROVR | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \
+ | DTSEC_CAR1_RDRP)
+
+#define CAM2_ERRORS_ONLY (DTSEC_CAR2_TFCS | DTSEC_CAR2_TXPF | DTSEC_CAR2_TDRP)
+
+/*
+ * Group of dTSEC specific counters relating to the standard RMON MIB Group 1
+ * (or Ethernet) statistics.
+ */
+#define CAM1_MIB_GRP_1 \
+ (DTSEC_CAR1_RDRP | DTSEC_CAR1_RBYT | DTSEC_CAR1_RPKT | DTSEC_CAR1_RMCA\
+ | DTSEC_CAR1_RBCA | DTSEC_CAR1_RALN | DTSEC_CAR1_RUND | DTSEC_CAR1_ROVR\
+ | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \
+ | DTSEC_CAR1_TR64 | DTSEC_CAR1_TR127 | DTSEC_CAR1_TR255 \
+ | DTSEC_CAR1_TR511 | DTSEC_CAR1_TRMAX)
+
+#define CAM2_MIB_GRP_1 (DTSEC_CAR2_TNCL | DTSEC_CAR2_TDRP)
+
+/* memory map */
+
+struct dtsec_regs {
+ /* dTSEC General Control and Status Registers */
+ uint32_t tsec_id; /* 0x000 ETSEC_ID register */
+ uint32_t tsec_id2; /* 0x004 ETSEC_ID2 register */
+ uint32_t ievent; /* 0x008 Interrupt event register */
+ uint32_t imask; /* 0x00C Interrupt mask register */
+ uint32_t reserved0010[1];
+ uint32_t ecntrl; /* 0x014 E control register */
+ uint32_t ptv; /* 0x018 Pause time value register */
+ uint32_t tbipa; /* 0x01C TBI PHY address register */
+ uint32_t tmr_ctrl; /* 0x020 Time-stamp Control register */
+ uint32_t tmr_pevent; /* 0x024 Time-stamp event register */
+ uint32_t tmr_pemask; /* 0x028 Timer event mask register */
+ uint32_t reserved002c[5];
+ uint32_t tctrl; /* 0x040 Transmit control register */
+ uint32_t reserved0044[3];
+ uint32_t rctrl; /* 0x050 Receive control register */
+ uint32_t reserved0054[11];
+ uint32_t igaddr[8]; /* 0x080-0x09C Individual/group address */
+ uint32_t gaddr[8]; /* 0x0A0-0x0BC Group address registers 0-7 */
+ uint32_t reserved00c0[16];
+ uint32_t maccfg1; /* 0x100 MAC configuration #1 */
+ uint32_t maccfg2; /* 0x104 MAC configuration #2 */
+ uint32_t ipgifg; /* 0x108 IPG/IFG */
+ uint32_t hafdup; /* 0x10C Half-duplex */
+ uint32_t maxfrm; /* 0x110 Maximum frame */
+ uint32_t reserved0114[10];
+ uint32_t ifstat; /* 0x13C Interface status */
+ uint32_t macstnaddr1; /* 0x140 Station Address,part 1 */
+ uint32_t macstnaddr2; /* 0x144 Station Address,part 2 */
+ struct {
+ uint32_t exact_match1; /* octets 1-4 */
+ uint32_t exact_match2; /* octets 5-6 */
+ } macaddr[15]; /* 0x148-0x1BC mac exact match addresses 1-15 */
+ uint32_t reserved01c0[16];
+ uint32_t tr64; /* 0x200 transmit and receive 64 byte frame counter */
+ uint32_t tr127; /* 0x204 transmit and receive 65 to 127 byte frame
+ * counter */
+ uint32_t tr255; /* 0x208 transmit and receive 128 to 255 byte frame
+ * counter */
+ uint32_t tr511; /* 0x20C transmit and receive 256 to 511 byte frame
+ * counter */
+ uint32_t tr1k; /* 0x210 transmit and receive 512 to 1023 byte frame
+ * counter */
+ uint32_t trmax; /* 0x214 transmit and receive 1024 to 1518 byte frame
+ * counter */
+ uint32_t trmgv; /* 0x218 transmit and receive 1519 to 1522 byte good
+ * VLAN frame count */
+ uint32_t rbyt; /* 0x21C receive byte counter */
+ uint32_t rpkt; /* 0x220 receive packet counter */
+ uint32_t rfcs; /* 0x224 receive FCS error counter */
+ uint32_t rmca; /* 0x228 RMCA receive multicast packet counter */
+ uint32_t rbca; /* 0x22C receive broadcast packet counter */
+ uint32_t rxcf; /* 0x230 receive control frame packet counter */
+ uint32_t rxpf; /* 0x234 receive pause frame packet counter */
+ uint32_t rxuo; /* 0x238 receive unknown OP code counter */
+ uint32_t raln; /* 0x23C receive alignment error counter */
+ uint32_t rflr; /* 0x240 receive frame length error counter */
+ uint32_t rcde; /* 0x244 receive code error counter */
+ uint32_t rcse; /* 0x248 receive carrier sense error counter */
+ uint32_t rund; /* 0x24C receive undersize packet counter */
+ uint32_t rovr; /* 0x250 receive oversize packet counter */
+ uint32_t rfrg; /* 0x254 receive fragments counter */
+ uint32_t rjbr; /* 0x258 receive jabber counter */
+ uint32_t rdrp; /* 0x25C receive drop */
+ uint32_t tbyt; /* 0x260 transmit byte counter */
+ uint32_t tpkt; /* 0x264 transmit packet counter */
+ uint32_t tmca; /* 0x268 transmit multicast packet counter */
+ uint32_t tbca; /* 0x26C transmit broadcast packet counter */
+ uint32_t txpf; /* 0x270 transmit pause control frame counter */
+ uint32_t tdfr; /* 0x274 transmit deferral packet counter */
+ uint32_t tedf; /* 0x278 transmit excessive deferral packet counter */
+ uint32_t tscl; /* 0x27C transmit single collision packet counter */
+ uint32_t tmcl; /* 0x280 transmit multiple collision packet counter */
+ uint32_t tlcl; /* 0x284 transmit late collision packet counter */
+ uint32_t txcl; /* 0x288 transmit excessive collision packet counter */
+ uint32_t tncl; /* 0x28C transmit total collision counter */
+ uint32_t reserved0290[1];
+ uint32_t tdrp; /* 0x294 transmit drop frame counter */
+ uint32_t tjbr; /* 0x298 transmit jabber frame counter */
+ uint32_t tfcs; /* 0x29C transmit FCS error counter */
+ uint32_t txcf; /* 0x2A0 transmit control frame counter */
+ uint32_t tovr; /* 0x2A4 transmit oversize frame counter */
+ uint32_t tund; /* 0x2A8 transmit undersize frame counter */
+ uint32_t tfrg; /* 0x2AC transmit fragments frame counter */
+ uint32_t car1; /* 0x2B0 carry register one register* */
+ uint32_t car2; /* 0x2B4 carry register two register* */
+ uint32_t cam1; /* 0x2B8 carry register one mask register */
+ uint32_t cam2; /* 0x2BC carry register two mask register */
+ uint32_t reserved02c0[848];
+};
+
+/**
+ * struct dtsec_mib_grp_1_counters - MIB counter overflows
+ *
+ * @tr64: Transmit and Receive 64 byte frame count. Increment for each
+ * good or bad frame, of any type, transmitted or received, which
+ * is 64 bytes in length.
+ * @tr127: Transmit and Receive 65 to 127 byte frame count. Increments for
+ * each good or bad frame of any type, transmitted or received,
+ * which is 65-127 bytes in length.
+ * @tr255: Transmit and Receive 128 to 255 byte frame count. Increments
+ * for each good or bad frame, of any type, transmitted or
+ * received, which is 128-255 bytes in length.
+ * @tr511: Transmit and Receive 256 to 511 byte frame count. Increments
+ * for each good or bad frame, of any type, transmitted or
+ * received, which is 256-511 bytes in length.
+ * @tr1k: Transmit and Receive 512 to 1023 byte frame count. Increments
+ * for each good or bad frame, of any type, transmitted or
+ * received, which is 512-1023 bytes in length.
+ * @trmax: Transmit and Receive 1024 to 1518 byte frame count. Increments
+ * for each good or bad frame, of any type, transmitted or
+ * received, which is 1024-1518 bytes in length.
+ * @rfrg: Receive fragments count. Increments for each received frame
+ * which is less than 64 bytes in length and contains an invalid
+ * FCS. This includes integral and non-integral lengths.
+ * @rjbr: Receive jabber count. Increments for received frames which
+ * exceed 1518 (non VLAN) or 1522 (VLAN) bytes and contain an
+ * invalid FCS. This includes alignment errors.
+ * @rdrp: Receive dropped packets count. Increments for received frames
+ * which are streamed to system but are later dropped due to lack
+ * of system resources. Does not increment for frames rejected due
+ * to address filtering.
+ * @raln: Receive alignment error count. Increments for each received
+ * frame from 64 to 1518 (non VLAN) or 1522 (VLAN) which contains
+ * an invalid FCS and is not an integral number of bytes.
+ * @rund: Receive undersize packet count. Increments each time a frame is
+ * received which is less than 64 bytes in length and contains a
+ * valid FCS and is otherwise well formed. This count does not
+ * include range length errors.
+ * @rovr: Receive oversize packet count. Increments each time a frame is
+ * received which exceeded 1518 (non VLAN) or 1522 (VLAN) and
+ * contains a valid FCS and is otherwise well formed.
+ * @rbyt: Receive byte count. Increments by the byte count of frames
+ * received, including those in bad packets, excluding preamble and
+ * SFD but including FCS bytes.
+ * @rpkt: Receive packet count. Increments for each received frame
+ * (including bad packets, all unicast, broadcast, and multicast
+ * packets).
+ * @rmca: Receive multicast packet count. Increments for each multicast
+ * frame with valid CRC and of lengths 64 to 1518 (non VLAN) or
+ * 1522 (VLAN), excluding broadcast frames. This count does not
+ * include range/length errors.
+ * @rbca: Receive broadcast packet count. Increments for each broadcast
+ * frame with valid CRC and of lengths 64 to 1518 (non VLAN) or
+ * 1522 (VLAN), excluding multicast frames. Does not include
+ * range/length errors.
+ * @tdrp: Transmit drop frame count. Increments each time a memory error
+ * or an underrun has occurred.
+ * @tncl: Transmit total collision counter. Increments by the number of
+ * collisions experienced during the transmission of a frame. Does
+ * not increment for aborted frames.
+ *
+ * The structure contains a group of dTSEC HW specific counters relating to the
+ * standard RMON MIB Group 1 (or Ethernet statistics) counters. This structure
+ * is counting only the carry events of the corresponding HW counters.
+ *
+ * tr64 to trmax notes: Frame sizes specified are considered excluding preamble
+ * and SFD but including FCS bytes.
+ */
+struct dtsec_mib_grp_1_counters {
+ uint64_t rdrp;
+ uint64_t tdrp;
+ uint64_t rbyt;
+ uint64_t rpkt;
+ uint64_t rbca;
+ uint64_t rmca;
+ uint64_t raln;
+ uint64_t rund;
+ uint64_t rovr;
+ uint64_t rfrg;
+ uint64_t rjbr;
+ uint64_t tncl;
+ uint64_t tr64;
+ uint64_t tr127;
+ uint64_t tr255;
+ uint64_t tr511;
+ uint64_t tr1k;
+ uint64_t trmax;
+};
+
+enum dtsec_stat_counters {
+ E_DTSEC_STAT_TR64,
+ E_DTSEC_STAT_TR127,
+ E_DTSEC_STAT_TR255,
+ E_DTSEC_STAT_TR511,
+ E_DTSEC_STAT_TR1K,
+ E_DTSEC_STAT_TRMAX,
+ E_DTSEC_STAT_TRMGV,
+ E_DTSEC_STAT_RBYT,
+ E_DTSEC_STAT_RPKT,
+ E_DTSEC_STAT_RMCA,
+ E_DTSEC_STAT_RBCA,
+ E_DTSEC_STAT_RXPF,
+ E_DTSEC_STAT_RALN,
+ E_DTSEC_STAT_RFLR,
+ E_DTSEC_STAT_RCDE,
+ E_DTSEC_STAT_RCSE,
+ E_DTSEC_STAT_RUND,
+ E_DTSEC_STAT_ROVR,
+ E_DTSEC_STAT_RFRG,
+ E_DTSEC_STAT_RJBR,
+ E_DTSEC_STAT_RDRP,
+ E_DTSEC_STAT_TFCS,
+ E_DTSEC_STAT_TBYT,
+ E_DTSEC_STAT_TPKT,
+ E_DTSEC_STAT_TMCA,
+ E_DTSEC_STAT_TBCA,
+ E_DTSEC_STAT_TXPF,
+ E_DTSEC_STAT_TNCL,
+ E_DTSEC_STAT_TDRP
+};
+
+enum dtsec_stat_level {
+ /* No statistics */
+ E_MAC_STAT_NONE = 0,
+ /* Only RMON MIB group 1 (ether stats). Optimized for performance */
+ E_MAC_STAT_MIB_GRP1,
+ /* Only error counters are available. Optimized for performance */
+ E_MAC_STAT_PARTIAL,
+ /* All counters available. Not optimized for performance */
+ E_MAC_STAT_FULL
+};
+
+
+/**
+ * struct dtsec_cfg - dTSEC configuration
+ *
+ * @halfdup_on: Transmit half-duplex flow control, under software
+ * control for 10/100-Mbps half-duplex media. If set,
+ * back pressure is applied to media by raising carrier.
+ * @halfdup_retransmit: Number of retransmission attempts following a collision.
+ * If this is exceeded dTSEC aborts transmission due to
+ * excessive collisions. The standard specifies the
+ * attempt limit to be 15.
+ * @halfdup_coll_window:The number of bytes of the frame during which
+ * collisions may occur. The default value of 55
+ * corresponds to the frame byte at the end of the
+ * standard 512-bit slot time window. If collisions are
+ * detected after this byte, the late collision event is
+ * asserted and transmission of current frame is aborted.
+ * @rx_drop_bcast: Discard broadcast frames. If set, all broadcast frames
+ * will be discarded by dTSEC.
+ * @rx_short_frm: Accept short frames. If set, dTSEC will accept frames
+ * of length 14..63 bytes.
+ * @rx_len_check: Length check for received frames. If set, the MAC
+ * checks the frame's length field on receive to ensure it
+ * matches the actual data field length. This only works
+ * for received frames with length field less than 1500.
+ * No check is performed for larger frames.
+ * @tx_pad_crc: Pad and append CRC. If set, the MAC pads all
+ * transmitted short frames and appends a CRC to every
+ * frame regardless of padding requirement.
+ * @tx_crc: Transmission CRC enable. If set, the MAC appends a CRC
+ * to all frames. If frames presented to the MAC have a
+ * valid length and contain a valid CRC, @tx_crc should be
+ * reset.
+ * This field is ignored if @tx_pad_crc is set.
+ * @rx_ctrl_acc: Control frame accept. If set, this overrides 802.3
+ * standard control frame behavior, and all Ethernet frames
+ * that have an ethertype of 0x8808 are treated as normal
+ * Ethernet frames and passed up to the packet interface on
+ * a DA match. Received pause control frames are passed to
+ * the packet interface only if Rx flow control is also
+ * disabled. See fman_dtsec_handle_rx_pause() function.
+ * @tx_pause_time: Transmit pause time value. This pause value is used as
+ * part of the pause frame to be sent when a transmit pause
+ * frame is initiated. If set to 0 this disables
+ * transmission of pause frames.
+ * @rx_preamble: Receive preamble enable. If set, the MAC recovers the
+ * received Ethernet 7-byte preamble and passes it to the
+ * packet interface at the start of each received frame.
+ * This field should be reset for internal MAC loop-back
+ * mode.
+ * @tx_preamble: User defined preamble enable for transmitted frames.
+ * If set, a user-defined preamble must passed to the MAC
+ * and it is transmitted instead of the standard preamble.
+ * @preamble_len: Length, in bytes, of the preamble field preceding each
+ * Ethernet start-of-frame delimiter byte. The default
+ * value of 0x7 should be used in order to guarantee
+ * reliable operation with IEEE 802.3 compliant hardware.
+ * @rx_prepend: Packet alignment padding length. The specified number
+ * of bytes (1-31) of zero padding are inserted before the
+ * start of each received frame. For Ethernet, where
+ * optional preamble extraction is enabled, the padding
+ * appears before the preamble, otherwise the padding
+ * precedes the layer 2 header.
+ *
+ * This structure contains basic dTSEC configuration and must be passed to
+ * fman_dtsec_init() function. A default set of configuration values can be
+ * obtained by calling fman_dtsec_defconfig().
+ */
+struct dtsec_cfg {
+ bool halfdup_on;
+ bool halfdup_alt_backoff_en;
+ bool halfdup_excess_defer;
+ bool halfdup_no_backoff;
+ bool halfdup_bp_no_backoff;
+ uint8_t halfdup_alt_backoff_val;
+ uint16_t halfdup_retransmit;
+ uint16_t halfdup_coll_window;
+ bool rx_drop_bcast;
+ bool rx_short_frm;
+ bool rx_len_check;
+ bool tx_pad_crc;
+ bool tx_crc;
+ bool rx_ctrl_acc;
+ unsigned short tx_pause_time;
+ unsigned short tbipa;
+ bool ptp_tsu_en;
+ bool ptp_exception_en;
+ bool rx_preamble;
+ bool tx_preamble;
+ unsigned char preamble_len;
+ unsigned char rx_prepend;
+ bool loopback;
+ bool rx_time_stamp_en;
+ bool tx_time_stamp_en;
+ bool rx_flow;
+ bool tx_flow;
+ bool rx_group_hash_exd;
+ bool rx_promisc;
+ uint8_t tbi_phy_addr;
+ uint16_t tx_pause_time_extd;
+ uint16_t maximum_frame;
+ uint32_t non_back_to_back_ipg1;
+ uint32_t non_back_to_back_ipg2;
+ uint32_t min_ifg_enforcement;
+ uint32_t back_to_back_ipg;
+ bool wake_on_lan;
+};
+
+
+/**
+ * fman_dtsec_defconfig() - Get default dTSEC configuration
+ * @cfg: pointer to configuration structure.
+ *
+ * Call this function to obtain a default set of configuration values for
+ * initializing dTSEC. The user can overwrite any of the values before calling
+ * fman_dtsec_init(), if specific configuration needs to be applied.
+ */
+void fman_dtsec_defconfig(struct dtsec_cfg *cfg);
+
+/**
+ * fman_dtsec_init() - Init dTSEC hardware block
+ * @regs: Pointer to dTSEC register block
+ * @cfg: dTSEC configuration data
+ * @iface_mode: dTSEC interface mode, the type of MAC - PHY interface.
+ * @iface_speed: 1G or 10G
+ * @macaddr: MAC station address to be assigned to the device
+ * @fm_rev_maj: major rev number
+ * @fm_rev_min: minor rev number
+ * @exceptions_mask: initial exceptions mask
+ *
+ * This function initializes dTSEC and applies basic configuration.
+ *
+ * dTSEC initialization sequence:
+ * Before enabling Rx/Tx call dtsec_set_address() to set MAC address,
+ * fman_dtsec_adjust_link() to configure interface speed and duplex and finally
+ * dtsec_enable_tx()/dtsec_enable_rx() to start transmission and reception.
+ *
+ * Returns: 0 if successful, an error code otherwise.
+ */
+int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg,
+ enum enet_interface iface_mode,
+ enum enet_speed iface_speed,
+ uint8_t *macaddr, uint8_t fm_rev_maj,
+ uint8_t fm_rev_min,
+ uint32_t exception_mask);
+
+/**
+ * fman_dtsec_enable() - Enable dTSEC Tx and Tx
+ * @regs: Pointer to dTSEC register block
+ * @apply_rx: enable rx side
+ * @apply_tx: enable tx side
+ *
+ * This function resets Tx and Rx graceful stop bit and enables dTSEC Tx and Rx.
+ */
+void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx);
+
+/**
+ * fman_dtsec_disable() - Disable dTSEC Tx and Rx
+ * @regs: Pointer to dTSEC register block
+ * @apply_rx: disable rx side
+ * @apply_tx: disable tx side
+ *
+ * This function disables Tx and Rx in dTSEC.
+ */
+void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx);
+
+/**
+ * fman_dtsec_get_revision() - Get dTSEC hardware revision
+ * @regs: Pointer to dTSEC register block
+ *
+ * Returns dtsec_id content
+ *
+ * Call this function to obtain the dTSEC hardware version.
+ */
+uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs);
+
+/**
+ * fman_dtsec_set_mac_address() - Set MAC station address
+ * @regs: Pointer to dTSEC register block
+ * @macaddr: MAC address array
+ *
+ * This function sets MAC station address. To enable unicast reception call
+ * this after fman_dtsec_init(). While promiscuous mode is disabled dTSEC will
+ * match the destination address of received unicast frames against this
+ * address.
+ */
+void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *macaddr);
+
+/**
+ * fman_dtsec_get_mac_address() - Query MAC station address
+ * @regs: Pointer to dTSEC register block
+ * @macaddr: MAC address array
+ */
+void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr);
+
+/**
+ * fman_dtsec_set_uc_promisc() - Sets unicast promiscuous mode
+ * @regs: Pointer to dTSEC register block
+ * @enable: Enable unicast promiscuous mode
+ *
+ * Use this function to enable/disable dTSEC L2 address filtering. If the
+ * address filtering is disabled all unicast packets are accepted.
+ * To set dTSEC in promiscuous mode call both fman_dtsec_set_uc_promisc() and
+ * fman_dtsec_set_mc_promisc() to disable filtering for both unicast and
+ * multicast addresses.
+ */
+void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable);
+
+/**
+ * fman_dtsec_set_wol() - Enable/Disable wake on lan
+ * (magic packet support)
+ * @regs: Pointer to dTSEC register block
+ * @en: Enable Wake On Lan support in dTSEC
+ *
+ */
+void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en);
+
+/**
+ * fman_dtsec_adjust_link() - Adjust dTSEC speed/duplex settings
+ * @regs: Pointer to dTSEC register block
+ * @iface_mode: dTSEC interface mode
+ * @speed: Link speed
+ * @full_dx: True for full-duplex, false for half-duplex.
+ *
+ * This function configures the MAC to function and the desired rates. Use it
+ * to configure dTSEC after fman_dtsec_init() and whenever the link speed
+ * changes (for instance following PHY auto-negociation).
+ *
+ * Returns: 0 if successful, an error code otherwise.
+ */
+int fman_dtsec_adjust_link(struct dtsec_regs *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx);
+
+/**
+ * fman_dtsec_set_tbi_phy_addr() - Updates TBI address field
+ * @regs: Pointer to dTSEC register block
+ * @address: Valid PHY address in the range of 1 to 31. 0 is reserved.
+ *
+ * In SGMII mode, the dTSEC's TBIPA field must contain a valid TBI PHY address
+ * so that the associated TBI PHY (i.e. the link) may be initialized.
+ *
+ * Returns: 0 if successful, an error code otherwise.
+ */
+int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs,
+ uint8_t addr);
+
+/**
+ * fman_dtsec_set_max_frame_len() - Set max frame length
+ * @regs: Pointer to dTSEC register block
+ * @length: Max frame length.
+ *
+ * Sets maximum frame length for received and transmitted frames. Frames that
+ * exceeds this length are truncated.
+ */
+void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length);
+
+/**
+ * fman_dtsec_get_max_frame_len() - Query max frame length
+ * @regs: Pointer to dTSEC register block
+ *
+ * Returns: the current value of the maximum frame length.
+ */
+uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs);
+
+/**
+ * fman_dtsec_handle_rx_pause() - Configure pause frame handling
+ * @regs: Pointer to dTSEC register block
+ * @en: Enable pause frame handling in dTSEC
+ *
+ * If enabled, dTSEC will handle pause frames internally. This must be disabled
+ * if dTSEC is set in half-duplex mode.
+ * If pause frame handling is disabled and &dtsec_cfg.rx_ctrl_acc is set, pause
+ * frames will be transferred to the packet interface just like regular Ethernet
+ * frames.
+ */
+void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en);
+
+/**
+ * fman_dtsec_set_tx_pause_frames() - Configure Tx pause time
+ * @regs: Pointer to dTSEC register block
+ * @time: Time value included in pause frames
+ *
+ * Call this function to set the time value used in transmitted pause frames.
+ * If time is 0, transmission of pause frames is disabled
+ */
+void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time);
+
+/**
+ * fman_dtsec_ack_event() - Acknowledge handled events
+ * @regs: Pointer to dTSEC register block
+ * @ev_mask: Events to acknowledge
+ *
+ * After handling events signaled by dTSEC in either polling or interrupt mode,
+ * call this function to reset the associated status bits in dTSEC event
+ * register.
+ */
+void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask);
+
+/**
+ * fman_dtsec_get_event() - Returns currently asserted events
+ * @regs: Pointer to dTSEC register block
+ * @ev_mask: Mask of relevant events
+ *
+ * Call this function to obtain a bit-mask of events that are currently asserted
+ * in dTSEC, taken from IEVENT register.
+ *
+ * Returns: a bit-mask of events asserted in dTSEC.
+ */
+uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask);
+
+/**
+ * fman_dtsec_get_interrupt_mask() - Returns a bit-mask of enabled interrupts
+ * @regs: Pointer to dTSEC register block
+ *
+ * Call this function to obtain a bit-mask of enabled interrupts
+ * in dTSEC, taken from IMASK register.
+ *
+ * Returns: a bit-mask of enabled interrupts in dTSEC.
+ */
+uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs);
+
+void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs,
+ uint8_t paddr_num);
+
+void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs,
+ uint64_t addr,
+ uint8_t paddr_num);
+
+void fman_dtsec_enable_tmr_interrupt (struct dtsec_regs *regs);
+
+void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs);
+
+/**
+ * fman_dtsec_disable_interrupt() - Disables interrupts for the specified events
+ * @regs: Pointer to dTSEC register block
+ * @ev_mask: Mask of relevant events
+ *
+ * Call this function to disable interrupts in dTSEC for the specified events.
+ * To enable interrupts use fman_dtsec_enable_interrupt().
+ */
+void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask);
+
+/**
+ * fman_dtsec_enable_interrupt() - Enable interrupts for the specified events
+ * @regs: Pointer to dTSEC register block
+ * @ev_mask: Mask of relevant events
+ *
+ * Call this function to enable interrupts in dTSEC for the specified events.
+ * To disable interrupts use fman_dtsec_disable_interrupt().
+ */
+void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask);
+
+/**
+ * fman_dtsec_set_ts() - Enables dTSEC timestamps
+ * @regs: Pointer to dTSEC register block
+ * @en: true to enable timestamps, false to disable them
+ *
+ * Call this function to enable/disable dTSEC timestamps. This affects both
+ * Tx and Rx.
+ */
+void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en);
+
+/**
+ * fman_dtsec_set_bucket() - Enables/disables a filter bucket
+ * @regs: Pointer to dTSEC register block
+ * @bucket: Bucket index
+ * @enable: true/false to enable/disable this bucket
+ *
+ * This function enables or disables the specified bucket. Enabling a bucket
+ * associated with an address configures dTSEC to accept received packets
+ * with that destination address.
+ * Multiple addresses may be associated with the same bucket. Disabling a
+ * bucket will affect all addresses associated with that bucket. A bucket that
+ * is enabled requires further filtering and verification in the upper layers
+ *
+ */
+void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable);
+
+/**
+ * dtsec_set_hash_table() - insert a crc code into thr filter table
+ * @regs: Pointer to dTSEC register block
+ * @crc: crc to insert
+ * @mcast: true is this is a multicast address
+ * @ghtx: true if we are in ghtx mode
+ *
+ * This function inserts a crc code into the filter table.
+ */
+void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc,
+ bool mcast, bool ghtx);
+
+/**
+ * fman_dtsec_reset_filter_table() - Resets the address filtering table
+ * @regs: Pointer to dTSEC register block
+ * @mcast: Reset multicast entries
+ * @ucast: Reset unicast entries
+ *
+ * Resets all entries in L2 address filter table. After calling this function
+ * all buckets enabled using fman_dtsec_set_bucket() will be disabled.
+ * If dtsec_init_filter_table() was called with @unicast_hash set to false,
+ * @ucast argument is ignored.
+ * This does not affect the primary nor the 15 additional addresses configured
+ * using dtsec_set_address() or dtsec_set_match_address().
+ */
+void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast,
+ bool ucast);
+
+/**
+ * fman_dtsec_set_mc_promisc() - Set multicast promiscuous mode
+ * @regs: Pointer to dTSEC register block
+ * @enable: Enable multicast promiscuous mode
+ *
+ * Call this to enable/disable L2 address filtering for multicast packets.
+ */
+void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable);
+
+/* statistics APIs */
+
+/**
+ * fman_dtsec_set_stat_level() - Enable a group of MIB statistics counters
+ * @regs: Pointer to dTSEC register block
+ * @level: Specifies a certain group of dTSEC MIB HW counters or _all_,
+ * to specify all the existing counters.
+ * If set to _none_, it disables all the counters.
+ *
+ * Enables the MIB statistics hw counters and sets up the carry interrupt
+ * masks for the counters corresponding to the @level input parameter.
+ *
+ * Returns: error if invalid @level value given.
+ */
+int fman_dtsec_set_stat_level(struct dtsec_regs *regs,
+ enum dtsec_stat_level level);
+
+/**
+ * fman_dtsec_reset_stat() - Completely resets all dTSEC HW counters
+ * @regs: Pointer to dTSEC register block
+ */
+void fman_dtsec_reset_stat(struct dtsec_regs *regs);
+
+/**
+ * fman_dtsec_get_clear_carry_regs() - Read and clear carry bits (CAR1-2 registers)
+ * @regs: Pointer to dTSEC register block
+ * @car1: car1 register value
+ * @car2: car2 register value
+ *
+ * When set, the carry bits signal that an overflow occurred on the
+ * corresponding counters.
+ * Note that the carry bits (CAR1-2 registers) will assert the
+ * %DTSEC_IEVENT_MSRO interrupt if unmasked (via CAM1-2 regs).
+ *
+ * Returns: true if overflow occurred, otherwise - false
+ */
+bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs,
+ uint32_t *car1, uint32_t *car2);
+
+uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs);
+
+uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs,
+ enum dtsec_stat_counters reg_name);
+
+void fman_dtsec_start_tx(struct dtsec_regs *regs);
+void fman_dtsec_start_rx(struct dtsec_regs *regs);
+void fman_dtsec_stop_tx(struct dtsec_regs *regs);
+void fman_dtsec_stop_rx(struct dtsec_regs *regs);
+uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs);
+
+
+#endif /* __FSL_FMAN_DTSEC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h
new file mode 100644
index 000000000000..0dda09c3c388
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_DTSEC_MII_ACC_H
+#define __FSL_FMAN_DTSEC_MII_ACC_H
+
+#include "common/general.h"
+
+
+/* MII Management Configuration Register */
+#define MIIMCFG_RESET_MGMT 0x80000000
+#define MIIMCFG_MGNTCLK_MASK 0x00000007
+#define MIIMCFG_MGNTCLK_SHIFT 0
+
+/* MII Management Command Register */
+#define MIIMCOM_SCAN_CYCLE 0x00000002
+#define MIIMCOM_READ_CYCLE 0x00000001
+
+/* MII Management Address Register */
+#define MIIMADD_PHY_ADDR_SHIFT 8
+#define MIIMADD_PHY_ADDR_MASK 0x00001f00
+
+#define MIIMADD_REG_ADDR_SHIFT 0
+#define MIIMADD_REG_ADDR_MASK 0x0000001f
+
+/* MII Management Indicator Register */
+#define MIIMIND_BUSY 0x00000001
+
+
+/* PHY Control Register */
+#define PHY_CR_PHY_RESET 0x8000
+#define PHY_CR_LOOPBACK 0x4000
+#define PHY_CR_SPEED0 0x2000
+#define PHY_CR_ANE 0x1000
+#define PHY_CR_RESET_AN 0x0200
+#define PHY_CR_FULLDUPLEX 0x0100
+#define PHY_CR_SPEED1 0x0040
+
+#define PHY_TBICON_SRESET 0x8000
+#define PHY_TBICON_SPEED2 0x0020
+#define PHY_TBICON_CLK_SEL 0x0020
+#define PHY_TBIANA_SGMII 0x4001
+#define PHY_TBIANA_1000X 0x01a0
+/* register map */
+
+/* MII Configuration Control Memory Map Registers */
+struct dtsec_mii_reg {
+ uint32_t reserved1[72];
+ uint32_t miimcfg; /* MII Mgmt:configuration */
+ uint32_t miimcom; /* MII Mgmt:command */
+ uint32_t miimadd; /* MII Mgmt:address */
+ uint32_t miimcon; /* MII Mgmt:control 3 */
+ uint32_t miimstat; /* MII Mgmt:status */
+ uint32_t miimind; /* MII Mgmt:indicators */
+};
+
+/* dTSEC MII API */
+
+/* functions to access the mii registers for phy configuration.
+ * this functionality may not be available for all dtsecs in the system.
+ * consult the reference manual for details */
+void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs);
+/* frequency is in MHz.
+ * note that dtsec clock is 1/2 of fman clock */
+void fman_dtsec_mii_init(struct dtsec_mii_reg *regs, uint16_t dtsec_freq);
+int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs,
+ uint8_t addr,
+ uint8_t reg,
+ uint16_t data,
+ uint16_t dtsec_freq);
+
+int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs,
+ uint8_t addr,
+ uint8_t reg,
+ uint16_t *data,
+ uint16_t dtsec_freq);
+
+#endif /* __FSL_FMAN_DTSEC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h
new file mode 100644
index 000000000000..010e4b709d63
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_KG_H
+#define __FSL_FMAN_KG_H
+
+#include "common/general.h"
+
+#define FM_KG_NUM_OF_GENERIC_REGS 8 /**< Num of generic KeyGen regs */
+#define FMAN_MAX_NUM_OF_HW_PORTS 64
+/**< Total num of masks allowed on KG extractions */
+#define FM_KG_EXTRACT_MASKS_NUM 4
+#define FM_KG_NUM_CLS_PLAN_ENTR 8 /**< Num of class. plan regs */
+#define FM_KG_CLS_PLAN_GRPS_NUM 32 /**< Max num of class. groups */
+
+struct fman_kg_regs {
+ uint32_t fmkg_gcr;
+ uint32_t res004;
+ uint32_t res008;
+ uint32_t fmkg_eer;
+ uint32_t fmkg_eeer;
+ uint32_t res014;
+ uint32_t res018;
+ uint32_t fmkg_seer;
+ uint32_t fmkg_seeer;
+ uint32_t fmkg_gsr;
+ uint32_t fmkg_tpc;
+ uint32_t fmkg_serc;
+ uint32_t res030[4];
+ uint32_t fmkg_fdor;
+ uint32_t fmkg_gdv0r;
+ uint32_t fmkg_gdv1r;
+ uint32_t res04c[6];
+ uint32_t fmkg_feer;
+ uint32_t res068[38];
+ uint32_t fmkg_indirect[63];
+ uint32_t fmkg_ar;
+};
+
+struct fman_kg_scheme_regs {
+ uint32_t kgse_mode; /**< MODE */
+ uint32_t kgse_ekfc; /**< Extract Known Fields Command */
+ uint32_t kgse_ekdv; /**< Extract Known Default Value */
+ uint32_t kgse_bmch; /**< Bit Mask Command High */
+ uint32_t kgse_bmcl; /**< Bit Mask Command Low */
+ uint32_t kgse_fqb; /**< Frame Queue Base */
+ uint32_t kgse_hc; /**< Hash Command */
+ uint32_t kgse_ppc; /**< Policer Profile Command */
+ uint32_t kgse_gec[FM_KG_NUM_OF_GENERIC_REGS];
+ /**< Generic Extract Command */
+ uint32_t kgse_spc; /**< KeyGen Scheme Entry Statistic Packet Counter */
+ uint32_t kgse_dv0; /**< KeyGen Scheme Entry Default Value 0 */
+ uint32_t kgse_dv1; /**< KeyGen Scheme Entry Default Value 1 */
+ uint32_t kgse_ccbs; /**< KeyGen Scheme Entry Coarse Classification Bit*/
+ uint32_t kgse_mv; /**< KeyGen Scheme Entry Match vector */
+ uint32_t kgse_om; /**< KeyGen Scheme Entry Operation Mode bits */
+ uint32_t kgse_vsp; /**< KeyGen Scheme Entry Virtual Storage Profile */
+};
+
+struct fman_kg_pe_regs{
+ uint32_t fmkg_pe_sp;
+ uint32_t fmkg_pe_cpp;
+};
+
+struct fman_kg_cp_regs {
+ uint32_t kgcpe[FM_KG_NUM_CLS_PLAN_ENTR];
+};
+
+
+#define FM_KG_KGAR_GO 0x80000000
+#define FM_KG_KGAR_READ 0x40000000
+#define FM_KG_KGAR_WRITE 0x00000000
+#define FM_KG_KGAR_SEL_SCHEME_ENTRY 0x00000000
+#define FM_KG_KGAR_SCM_WSEL_UPDATE_CNT 0x00008000
+
+#define KG_SCH_PP_SHIFT_HIGH 0x80000000
+#define KG_SCH_PP_NO_GEN 0x10000000
+#define KG_SCH_PP_SHIFT_LOW 0x0000F000
+#define KG_SCH_MODE_NIA_PLCR 0x40000000
+#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000
+#define KG_SCH_BITMASK_MASK 0x000000FF
+#define KG_SCH_GEN_VALID 0x80000000
+#define KG_SCH_GEN_MASK 0x00FF0000
+#define FM_PCD_KG_KGAR_ERR 0x20000000
+#define FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY 0x01000000
+#define FM_PCD_KG_KGAR_SEL_PORT_ENTRY 0x02000000
+#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP 0x00008000
+#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP 0x00004000
+#define FM_PCD_KG_KGAR_WSEL_MASK 0x0000FF00
+#define KG_SCH_HASH_CONFIG_NO_FQID 0x80000000
+#define KG_SCH_HASH_CONFIG_SYM 0x40000000
+
+#define FM_EX_KG_DOUBLE_ECC 0x80000000
+#define FM_EX_KG_KEYSIZE_OVERFLOW 0x40000000
+
+/* ECC capture register */
+#define KG_FMKG_SERC_CAP 0x80000000
+#define KG_FMKG_SERC_CET 0x40000000
+#define KG_FMKG_SERC_CNT_MSK 0x00FF0000
+#define KG_FMKG_SERC_CNT_SHIFT 16
+#define KG_FMKG_SERC_ADDR_MSK 0x000003FF
+
+/* Masks */
+#define FM_KG_KGGCR_EN 0x80000000
+#define KG_SCH_GEN_VALID 0x80000000
+#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000
+#define KG_ERR_TYPE_DOUBLE 0x40000000
+#define KG_ERR_ADDR_MASK 0x00000FFF
+#define KG_SCH_MODE_EN 0x80000000
+
+/* shifts */
+#define FM_KG_KGAR_NUM_SHIFT 16
+#define FM_KG_PE_CPP_MASK_SHIFT 16
+#define FM_KG_KGAR_WSEL_SHIFT 8
+
+#define FM_KG_SCH_GEN_HT_INVALID 0
+
+#define FM_KG_MASK_SEL_GEN_BASE 0x20
+
+#define KG_GET_MASK_SEL_SHIFT(shift, i) \
+switch (i) \
+{ \
+ case 0: (shift) = 26; break; \
+ case 1: (shift) = 20; break; \
+ case 2: (shift) = 10; break; \
+ case 3: (shift) = 4; break; \
+ default: (shift) = 0; \
+}
+
+#define KG_GET_MASK_OFFSET_SHIFT(shift, i) \
+switch (i) \
+{ \
+ case 0: (shift) = 16; break; \
+ case 1: (shift) = 0; break; \
+ case 2: (shift) = 28; break; \
+ case 3: (shift) = 24; break; \
+ default: (shift) = 0; \
+}
+
+#define KG_GET_MASK_SHIFT(shift, i) \
+switch (i) \
+{ \
+ case 0: shift = 24; break; \
+ case 1: shift = 16; break; \
+ case 2: shift = 8; break; \
+ case 3: shift = 0; break; \
+ default: shift = 0; \
+}
+
+/* Port entry CPP register */
+#define FMAN_KG_PE_CPP_MASK_SHIFT 16
+
+/* Scheme registers */
+#define FMAN_KG_SCH_MODE_EN 0x80000000
+#define FMAN_KG_SCH_MODE_NIA_PLCR 0x40000000
+#define FMAN_KG_SCH_MODE_CCOBASE_SHIFT 24
+
+#define FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT 30
+#define FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT 28
+#define FMAN_KG_SCH_DEF_ETYPE_SHIFT 26
+#define FMAN_KG_SCH_DEF_PPP_SID_SHIFT 24
+#define FMAN_KG_SCH_DEF_PPP_PID_SHIFT 22
+#define FMAN_KG_SCH_DEF_MPLS_SHIFT 20
+#define FMAN_KG_SCH_DEF_IP_ADDR_SHIFT 18
+#define FMAN_KG_SCH_DEF_PTYPE_SHIFT 16
+#define FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT 14
+#define FMAN_KG_SCH_DEF_IPv6_FL_SHIFT 12
+#define FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT 10
+#define FMAN_KG_SCH_DEF_L4_PORT_SHIFT 8
+#define FMAN_KG_SCH_DEF_TCP_FLG_SHIFT 6
+
+#define FMAN_KG_SCH_GEN_VALID 0x80000000
+#define FMAN_KG_SCH_GEN_SIZE_MAX 16
+#define FMAN_KG_SCH_GEN_OR 0x00008000
+
+#define FMAN_KG_SCH_GEN_DEF_SHIFT 29
+#define FMAN_KG_SCH_GEN_SIZE_SHIFT 24
+#define FMAN_KG_SCH_GEN_MASK_SHIFT 16
+#define FMAN_KG_SCH_GEN_HT_SHIFT 8
+
+#define FMAN_KG_SCH_HASH_HSHIFT_SHIFT 24
+#define FMAN_KG_SCH_HASH_HSHIFT_MAX 0x28
+#define FMAN_KG_SCH_HASH_SYM 0x40000000
+#define FMAN_KG_SCH_HASH_NO_FQID_GEN 0x80000000
+
+#define FMAN_KG_SCH_PP_SH_SHIFT 27
+#define FMAN_KG_SCH_PP_SL_SHIFT 12
+#define FMAN_KG_SCH_PP_SH_MASK 0x80000000
+#define FMAN_KG_SCH_PP_SL_MASK 0x0000F000
+#define FMAN_KG_SCH_PP_SHIFT_MAX 0x17
+#define FMAN_KG_SCH_PP_MASK_SHIFT 16
+#define FMAN_KG_SCH_PP_NO_GEN 0x10000000
+
+enum fman_kg_gen_extract_src {
+ E_FMAN_KG_GEN_EXTRACT_ETH,
+ E_FMAN_KG_GEN_EXTRACT_ETYPE,
+ E_FMAN_KG_GEN_EXTRACT_SNAP,
+ E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1,
+ E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N,
+ E_FMAN_KG_GEN_EXTRACT_PPPoE,
+ E_FMAN_KG_GEN_EXTRACT_MPLS_1,
+ E_FMAN_KG_GEN_EXTRACT_MPLS_2,
+ E_FMAN_KG_GEN_EXTRACT_MPLS_3,
+ E_FMAN_KG_GEN_EXTRACT_MPLS_N,
+ E_FMAN_KG_GEN_EXTRACT_IPv4_1,
+ E_FMAN_KG_GEN_EXTRACT_IPv6_1,
+ E_FMAN_KG_GEN_EXTRACT_IPv4_2,
+ E_FMAN_KG_GEN_EXTRACT_IPv6_2,
+ E_FMAN_KG_GEN_EXTRACT_MINENCAP,
+ E_FMAN_KG_GEN_EXTRACT_IP_PID,
+ E_FMAN_KG_GEN_EXTRACT_GRE,
+ E_FMAN_KG_GEN_EXTRACT_TCP,
+ E_FMAN_KG_GEN_EXTRACT_UDP,
+ E_FMAN_KG_GEN_EXTRACT_SCTP,
+ E_FMAN_KG_GEN_EXTRACT_DCCP,
+ E_FMAN_KG_GEN_EXTRACT_IPSEC_AH,
+ E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP,
+ E_FMAN_KG_GEN_EXTRACT_SHIM_1,
+ E_FMAN_KG_GEN_EXTRACT_SHIM_2,
+ E_FMAN_KG_GEN_EXTRACT_FROM_DFLT,
+ E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START,
+ E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT,
+ E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE,
+ E_FMAN_KG_GEN_EXTRACT_FROM_FQID
+};
+
+struct fman_kg_ex_ecc_attr
+{
+ bool valid;
+ bool double_ecc;
+ uint16_t addr;
+ uint8_t single_ecc_count;
+};
+
+enum fman_kg_def_select
+{
+ E_FMAN_KG_DEF_GLOBAL_0,
+ E_FMAN_KG_DEF_GLOBAL_1,
+ E_FMAN_KG_DEF_SCHEME_0,
+ E_FMAN_KG_DEF_SCHEME_1
+};
+
+struct fman_kg_extract_def
+{
+ enum fman_kg_def_select mac_addr;
+ enum fman_kg_def_select vlan_tci;
+ enum fman_kg_def_select etype;
+ enum fman_kg_def_select ppp_sid;
+ enum fman_kg_def_select ppp_pid;
+ enum fman_kg_def_select mpls;
+ enum fman_kg_def_select ip_addr;
+ enum fman_kg_def_select ptype;
+ enum fman_kg_def_select ip_tos_tc;
+ enum fman_kg_def_select ipv6_fl;
+ enum fman_kg_def_select ipsec_spi;
+ enum fman_kg_def_select l4_port;
+ enum fman_kg_def_select tcp_flg;
+};
+
+enum fman_kg_gen_extract_type
+{
+ E_FMAN_KG_HASH_EXTRACT,
+ E_FMAN_KG_OR_EXTRACT
+};
+
+struct fman_kg_gen_extract_params
+{
+ /* Hash or Or-ed extract */
+ enum fman_kg_gen_extract_type type;
+ enum fman_kg_gen_extract_src src;
+ bool no_validation;
+ /* Extraction offset from the header location specified above */
+ uint8_t offset;
+ /* Size of extraction for FMAN_KG_HASH_EXTRACT,
+ * hash result shift for FMAN_KG_OR_EXTRACT */
+ uint8_t extract;
+ uint8_t mask;
+ /* Default value to use when header specified
+ * by fman_kg_gen_extract_src doesn't present */
+ enum fman_kg_def_select def_val;
+};
+
+struct fman_kg_extract_mask
+{
+ /**< Indication if mask is on known field extraction or
+ * on general extraction; TRUE for known field */
+ bool is_known;
+ /**< One of FMAN_KG_EXTRACT_xxx defines for known fields mask and
+ * generic register index for generic extracts mask */
+ uint32_t field_or_gen_idx;
+ /**< Byte offset from start of the extracted data specified
+ * by field_or_gen_idx */
+ uint8_t offset;
+ /**< Byte mask (selected bits will be used) */
+ uint8_t mask;
+};
+
+struct fman_kg_extract_params
+{
+ /* Or-ed mask of FMAN_KG_EXTRACT_xxx defines */
+ uint32_t known_fields;
+ struct fman_kg_extract_def known_fields_def;
+ /* Number of entries in gen_extract */
+ uint8_t gen_extract_num;
+ struct fman_kg_gen_extract_params gen_extract[FM_KG_NUM_OF_GENERIC_REGS];
+ /* Number of entries in masks */
+ uint8_t masks_num;
+ struct fman_kg_extract_mask masks[FM_KG_EXTRACT_MASKS_NUM];
+ uint32_t def_scheme_0;
+ uint32_t def_scheme_1;
+};
+
+struct fman_kg_hash_params
+{
+ bool use_hash;
+ uint8_t shift_r;
+ uint32_t mask; /**< 24-bit mask */
+ bool sym; /**< Symmetric hash for src and dest pairs */
+};
+
+struct fman_kg_pp_params
+{
+ uint8_t base;
+ uint8_t shift;
+ uint8_t mask;
+ bool bypass_pp_gen;
+};
+
+struct fman_kg_cc_params
+{
+ uint8_t base_offset;
+ uint32_t qlcv_bits_sel;
+};
+
+enum fman_pcd_engine
+{
+ E_FMAN_PCD_INVALID = 0, /**< Invalid PCD engine indicated*/
+ E_FMAN_PCD_DONE, /**< No PCD Engine indicated */
+ E_FMAN_PCD_KG, /**< Keygen indicated */
+ E_FMAN_PCD_CC, /**< Coarse classification indicated */
+ E_FMAN_PCD_PLCR, /**< Policer indicated */
+ E_FMAN_PCD_PRS /**< Parser indicated */
+};
+
+struct fman_kg_cls_plan_params
+{
+ uint8_t entries_mask;
+ uint32_t mask_vector[FM_KG_NUM_CLS_PLAN_ENTR];
+};
+
+struct fman_kg_scheme_params
+{
+ uint32_t match_vector;
+ struct fman_kg_extract_params extract_params;
+ struct fman_kg_hash_params hash_params;
+ uint32_t base_fqid;
+ /* What we do w/features supported per FM version ?? */
+ bool bypass_fqid_gen;
+ struct fman_kg_pp_params policer_params;
+ struct fman_kg_cc_params cc_params;
+ bool update_counter;
+ /**< counter_value: Set scheme counter to the specified value;
+ * relevant only when update_counter = TRUE. */
+ uint32_t counter_value;
+ enum fman_pcd_engine next_engine;
+ /**< Next engine action code */
+ uint32_t next_engine_action;
+};
+
+
+
+int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar);
+void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add);
+void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp);
+void fman_kg_get_event(struct fman_kg_regs *regs,
+ uint32_t *event,
+ uint32_t *scheme_idx);
+void fman_kg_init(struct fman_kg_regs *regs,
+ uint32_t exceptions,
+ uint32_t dflt_nia);
+void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs);
+void fman_kg_enable(struct fman_kg_regs *regs);
+void fman_kg_disable(struct fman_kg_regs *regs);
+int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs,
+ uint8_t hwport_id,
+ uint32_t bind_cls_plans);
+int fman_kg_build_bind_cls_plans(uint8_t grp_base,
+ uint8_t grp_mask,
+ uint32_t *bind_cls_plans);
+int fman_kg_write_bind_schemes(struct fman_kg_regs *regs,
+ uint8_t hwport_id,
+ uint32_t schemes);
+int fman_kg_write_cls_plan(struct fman_kg_regs *regs,
+ uint8_t grp_id,
+ uint8_t entries_mask,
+ uint8_t hwport_id,
+ struct fman_kg_cp_regs *cls_plan_regs);
+int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params,
+ struct fman_kg_cp_regs *cls_plan_regs);
+uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs);
+int fman_kg_set_scheme_counter(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ uint32_t counter);
+int fman_kg_get_scheme_counter(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ uint32_t *counter);
+int fman_kg_delete_scheme(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id);
+int fman_kg_write_scheme(struct fman_kg_regs *regs,
+ uint8_t scheme_id,
+ uint8_t hwport_id,
+ struct fman_kg_scheme_regs *scheme_regs,
+ bool update_counter);
+int fman_kg_build_scheme(struct fman_kg_scheme_params *params,
+ struct fman_kg_scheme_regs *scheme_regs);
+void fman_kg_get_capture(struct fman_kg_regs *regs,
+ struct fman_kg_ex_ecc_attr *ecc_attr,
+ bool clear);
+void fman_kg_get_exception(struct fman_kg_regs *regs,
+ uint32_t *events,
+ uint32_t *scheme_ids,
+ bool clear);
+void fman_kg_set_exception(struct fman_kg_regs *regs,
+ uint32_t exception,
+ bool enable);
+void fman_kg_set_dflt_val(struct fman_kg_regs *regs,
+ uint8_t def_id,
+ uint32_t val);
+void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset);
+
+
+
+/**************************************************************************//**
+ @Description NIA Description
+*//***************************************************************************/
+#define KG_NIA_ORDER_RESTOR 0x00800000
+#define KG_NIA_ENG_FM_CTL 0x00000000
+#define KG_NIA_ENG_PRS 0x00440000
+#define KG_NIA_ENG_KG 0x00480000
+#define KG_NIA_ENG_PLCR 0x004C0000
+#define KG_NIA_ENG_BMI 0x00500000
+#define KG_NIA_ENG_QMI_ENQ 0x00540000
+#define KG_NIA_ENG_QMI_DEQ 0x00580000
+#define KG_NIA_ENG_MASK 0x007C0000
+
+#define KG_NIA_AC_MASK 0x0003FFFF
+
+#define KG_NIA_INVALID 0xFFFFFFFF
+
+static __inline__ uint32_t fm_kg_build_nia(enum fman_pcd_engine next_engine,
+ uint32_t next_engine_action)
+{
+ uint32_t nia;
+
+ if (next_engine_action & ~KG_NIA_AC_MASK)
+ return KG_NIA_INVALID;
+
+ switch (next_engine) {
+ case E_FMAN_PCD_DONE:
+ nia = KG_NIA_ENG_BMI | next_engine_action;
+ break;
+
+ case E_FMAN_PCD_KG:
+ nia = KG_NIA_ENG_KG | next_engine_action;
+ break;
+
+ case E_FMAN_PCD_CC:
+ nia = KG_NIA_ENG_FM_CTL | next_engine_action;
+ break;
+
+ case E_FMAN_PCD_PLCR:
+ nia = KG_NIA_ENG_PLCR | next_engine_action;
+ break;
+
+ default:
+ nia = KG_NIA_INVALID;
+ }
+
+ return nia;
+}
+
+#endif /* __FSL_FMAN_KG_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
new file mode 100644
index 000000000000..058da1590c8d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __FSL_FMAN_MEMAC_H
+#define __FSL_FMAN_MEMAC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+
+
+#define MEMAC_NUM_OF_PADDRS 7 /* Num of additional exact match MAC adr regs */
+
+/* Control and Configuration Register (COMMAND_CONFIG) */
+#define CMD_CFG_MG 0x80000000 /* 00 Magic Packet detection */
+#define CMD_CFG_REG_LOWP_RXETY 0x01000000 /* 07 Rx low power indication */
+#define CMD_CFG_TX_LOWP_ENA 0x00800000 /* 08 Tx Low Power Idle Enable */
+#define CMD_CFG_SFD_ANY 0x00200000 /* 10 Disable SFD check */
+#define CMD_CFG_PFC_MODE 0x00080000 /* 12 Enable PFC */
+#define CMD_CFG_NO_LEN_CHK 0x00020000 /* 14 Payload length check disable */
+#define CMD_CFG_SEND_IDLE 0x00010000 /* 15 Force idle generation */
+#define CMD_CFG_CNT_FRM_EN 0x00002000 /* 18 Control frame rx enable */
+#define CMD_CFG_SW_RESET 0x00001000 /* 19 S/W Reset, self clearing bit */
+#define CMD_CFG_TX_PAD_EN 0x00000800 /* 20 Enable Tx padding of frames */
+#define CMD_CFG_LOOPBACK_EN 0x00000400 /* 21 XGMII/GMII loopback enable */
+#define CMD_CFG_TX_ADDR_INS 0x00000200 /* 22 Tx source MAC addr insertion */
+#define CMD_CFG_PAUSE_IGNORE 0x00000100 /* 23 Ignore Pause frame quanta */
+#define CMD_CFG_PAUSE_FWD 0x00000080 /* 24 Terminate/frwd Pause frames */
+#define CMD_CFG_CRC_FWD 0x00000040 /* 25 Terminate/frwd CRC of frames */
+#define CMD_CFG_PAD_EN 0x00000020 /* 26 Frame padding removal */
+#define CMD_CFG_PROMIS_EN 0x00000010 /* 27 Promiscuous operation enable */
+#define CMD_CFG_WAN_MODE 0x00000008 /* 28 WAN mode enable */
+#define CMD_CFG_RX_EN 0x00000002 /* 30 MAC receive path enable */
+#define CMD_CFG_TX_EN 0x00000001 /* 31 MAC transmit path enable */
+
+/* Transmit FIFO Sections Register (TX_FIFO_SECTIONS) */
+#define TX_FIFO_SECTIONS_TX_EMPTY_MASK 0xFFFF0000
+#define TX_FIFO_SECTIONS_TX_AVAIL_MASK 0x0000FFFF
+#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G 0x00400000
+#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G 0x00100000
+#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G 0x00360000
+#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G 0x00040000
+#define TX_FIFO_SECTIONS_TX_AVAIL_10G 0x00000019
+#define TX_FIFO_SECTIONS_TX_AVAIL_1G 0x00000020
+#define TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G 0x00000060
+
+#define GET_TX_EMPTY_DEFAULT_VALUE(_val) \
+_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \
+((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G) : \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G));
+
+#define GET_TX_EMPTY_PFC_VALUE(_val) \
+_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \
+((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G) : \
+ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G));
+
+/* Interface Mode Register (IF_MODE) */
+#define IF_MODE_MASK 0x00000003 /* 30-31 Mask on i/f mode bits */
+#define IF_MODE_XGMII 0x00000000 /* 30-31 XGMII (10G) interface */
+#define IF_MODE_GMII 0x00000002 /* 30-31 GMII (1G) interface */
+#define IF_MODE_RGMII 0x00000004
+#define IF_MODE_RGMII_AUTO 0x00008000
+#define IF_MODE_RGMII_1000 0x00004000 /* 10 - 1000Mbps RGMII */
+#define IF_MODE_RGMII_100 0x00000000 /* 00 - 100Mbps RGMII */
+#define IF_MODE_RGMII_10 0x00002000 /* 01 - 10Mbps RGMII */
+#define IF_MODE_RGMII_SP_MASK 0x00006000 /* Setsp mask bits */
+#define IF_MODE_RGMII_FD 0x00001000 /* Full duplex RGMII */
+#define IF_MODE_HD 0x00000040 /* Half duplex operation */
+
+/* Hash table Control Register (HASHTABLE_CTRL) */
+#define HASH_CTRL_MCAST_SHIFT 26
+#define HASH_CTRL_MCAST_EN 0x00000100 /* 23 Mcast frame rx for hash */
+#define HASH_CTRL_ADDR_MASK 0x0000003F /* 26-31 Hash table address code */
+
+#define GROUP_ADDRESS 0x0000010000000000LL /* MAC mcast indication */
+#define HASH_TABLE_SIZE 64 /* Hash tbl size */
+
+/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
+#define MEMAC_TX_IPG_LENGTH_MASK 0x0000003F
+
+/* Statistics Configuration Register (STATN_CONFIG) */
+#define STATS_CFG_CLR 0x00000004 /* 29 Reset all counters */
+#define STATS_CFG_CLR_ON_RD 0x00000002 /* 30 Clear on read */
+#define STATS_CFG_SATURATE 0x00000001 /* 31 Saturate at the maximum val */
+
+/* Interrupt Mask Register (IMASK) */
+#define MEMAC_IMASK_MGI 0x40000000 /* 1 Magic pkt detect indication */
+#define MEMAC_IMASK_TSECC_ER 0x20000000 /* 2 Timestamp FIFO ECC error evnt */
+#define MEMAC_IMASK_TECC_ER 0x02000000 /* 6 Transmit frame ECC error evnt */
+#define MEMAC_IMASK_RECC_ER 0x01000000 /* 7 Receive frame ECC error evnt */
+
+#define MEMAC_ALL_ERRS_IMASK \
+ ((uint32_t)(MEMAC_IMASK_TSECC_ER | \
+ MEMAC_IMASK_TECC_ER | \
+ MEMAC_IMASK_RECC_ER | \
+ MEMAC_IMASK_MGI))
+
+#define MEMAC_IEVNT_PCS 0x80000000 /* PCS (XG). Link sync (G) */
+#define MEMAC_IEVNT_AN 0x40000000 /* Auto-negotiation */
+#define MEMAC_IEVNT_LT 0x20000000 /* Link Training/New page */
+#define MEMAC_IEVNT_MGI 0x00004000 /* Magic pkt detection */
+#define MEMAC_IEVNT_TS_ECC_ER 0x00002000 /* Timestamp FIFO ECC error */
+#define MEMAC_IEVNT_RX_FIFO_OVFL 0x00001000 /* Rx FIFO overflow */
+#define MEMAC_IEVNT_TX_FIFO_UNFL 0x00000800 /* Tx FIFO underflow */
+#define MEMAC_IEVNT_TX_FIFO_OVFL 0x00000400 /* Tx FIFO overflow */
+#define MEMAC_IEVNT_TX_ECC_ER 0x00000200 /* Tx frame ECC error */
+#define MEMAC_IEVNT_RX_ECC_ER 0x00000100 /* Rx frame ECC error */
+#define MEMAC_IEVNT_LI_FAULT 0x00000080 /* Link Interruption flt */
+#define MEMAC_IEVNT_RX_EMPTY 0x00000040 /* Rx FIFO empty */
+#define MEMAC_IEVNT_TX_EMPTY 0x00000020 /* Tx FIFO empty */
+#define MEMAC_IEVNT_RX_LOWP 0x00000010 /* Low Power Idle */
+#define MEMAC_IEVNT_PHY_LOS 0x00000004 /* Phy loss of signal */
+#define MEMAC_IEVNT_REM_FAULT 0x00000002 /* Remote fault (XGMII) */
+#define MEMAC_IEVNT_LOC_FAULT 0x00000001 /* Local fault (XGMII) */
+
+enum memac_counters {
+ E_MEMAC_COUNTER_R64,
+ E_MEMAC_COUNTER_T64,
+ E_MEMAC_COUNTER_R127,
+ E_MEMAC_COUNTER_T127,
+ E_MEMAC_COUNTER_R255,
+ E_MEMAC_COUNTER_T255,
+ E_MEMAC_COUNTER_R511,
+ E_MEMAC_COUNTER_T511,
+ E_MEMAC_COUNTER_R1023,
+ E_MEMAC_COUNTER_T1023,
+ E_MEMAC_COUNTER_R1518,
+ E_MEMAC_COUNTER_T1518,
+ E_MEMAC_COUNTER_R1519X,
+ E_MEMAC_COUNTER_T1519X,
+ E_MEMAC_COUNTER_RFRG,
+ E_MEMAC_COUNTER_RJBR,
+ E_MEMAC_COUNTER_RDRP,
+ E_MEMAC_COUNTER_RALN,
+ E_MEMAC_COUNTER_TUND,
+ E_MEMAC_COUNTER_ROVR,
+ E_MEMAC_COUNTER_RXPF,
+ E_MEMAC_COUNTER_TXPF,
+ E_MEMAC_COUNTER_ROCT,
+ E_MEMAC_COUNTER_RMCA,
+ E_MEMAC_COUNTER_RBCA,
+ E_MEMAC_COUNTER_RPKT,
+ E_MEMAC_COUNTER_RUCA,
+ E_MEMAC_COUNTER_RERR,
+ E_MEMAC_COUNTER_TOCT,
+ E_MEMAC_COUNTER_TMCA,
+ E_MEMAC_COUNTER_TBCA,
+ E_MEMAC_COUNTER_TUCA,
+ E_MEMAC_COUNTER_TERR
+};
+
+#define DEFAULT_PAUSE_QUANTA 0xf000
+#define DEFAULT_FRAME_LENGTH 0x600
+#define DEFAULT_TX_IPG_LENGTH 12
+
+/*
+ * memory map
+ */
+
+struct mac_addr {
+ uint32_t mac_addr_l; /* Lower 32 bits of 48-bit MAC address */
+ uint32_t mac_addr_u; /* Upper 16 bits of 48-bit MAC address */
+};
+
+struct memac_regs {
+ /* General Control and Status */
+ uint32_t res0000[2];
+ uint32_t command_config; /* 0x008 Ctrl and cfg */
+ struct mac_addr mac_addr0; /* 0x00C-0x010 MAC_ADDR_0...1 */
+ uint32_t maxfrm; /* 0x014 Max frame length */
+ uint32_t res0018[1];
+ uint32_t rx_fifo_sections; /* Receive FIFO configuration reg */
+ uint32_t tx_fifo_sections; /* Transmit FIFO configuration reg */
+ uint32_t res0024[2];
+ uint32_t hashtable_ctrl; /* 0x02C Hash table control */
+ uint32_t res0030[4];
+ uint32_t ievent; /* 0x040 Interrupt event */
+ uint32_t tx_ipg_length; /* 0x044 Transmitter inter-packet-gap */
+ uint32_t res0048;
+ uint32_t imask; /* 0x04C Interrupt mask */
+ uint32_t res0050;
+ uint32_t pause_quanta[4]; /* 0x054 Pause quanta */
+ uint32_t pause_thresh[4]; /* 0x064 Pause quanta threshold */
+ uint32_t rx_pause_status; /* 0x074 Receive pause status */
+ uint32_t res0078[2];
+ struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS]; /* 0x80-0x0B4 mac padr */
+ uint32_t lpwake_timer; /* 0x0B8 Low Power Wakeup Timer */
+ uint32_t sleep_timer; /* 0x0BC Transmit EEE Low Power Timer */
+ uint32_t res00c0[8];
+ uint32_t statn_config; /* 0x0E0 Statistics configuration */
+ uint32_t res00e4[7];
+ /* Rx Statistics Counter */
+ uint32_t reoct_l;
+ uint32_t reoct_u;
+ uint32_t roct_l;
+ uint32_t roct_u;
+ uint32_t raln_l;
+ uint32_t raln_u;
+ uint32_t rxpf_l;
+ uint32_t rxpf_u;
+ uint32_t rfrm_l;
+ uint32_t rfrm_u;
+ uint32_t rfcs_l;
+ uint32_t rfcs_u;
+ uint32_t rvlan_l;
+ uint32_t rvlan_u;
+ uint32_t rerr_l;
+ uint32_t rerr_u;
+ uint32_t ruca_l;
+ uint32_t ruca_u;
+ uint32_t rmca_l;
+ uint32_t rmca_u;
+ uint32_t rbca_l;
+ uint32_t rbca_u;
+ uint32_t rdrp_l;
+ uint32_t rdrp_u;
+ uint32_t rpkt_l;
+ uint32_t rpkt_u;
+ uint32_t rund_l;
+ uint32_t rund_u;
+ uint32_t r64_l;
+ uint32_t r64_u;
+ uint32_t r127_l;
+ uint32_t r127_u;
+ uint32_t r255_l;
+ uint32_t r255_u;
+ uint32_t r511_l;
+ uint32_t r511_u;
+ uint32_t r1023_l;
+ uint32_t r1023_u;
+ uint32_t r1518_l;
+ uint32_t r1518_u;
+ uint32_t r1519x_l;
+ uint32_t r1519x_u;
+ uint32_t rovr_l;
+ uint32_t rovr_u;
+ uint32_t rjbr_l;
+ uint32_t rjbr_u;
+ uint32_t rfrg_l;
+ uint32_t rfrg_u;
+ uint32_t rcnp_l;
+ uint32_t rcnp_u;
+ uint32_t rdrntp_l;
+ uint32_t rdrntp_u;
+ uint32_t res01d0[12];
+ /* Tx Statistics Counter */
+ uint32_t teoct_l;
+ uint32_t teoct_u;
+ uint32_t toct_l;
+ uint32_t toct_u;
+ uint32_t res0210[2];
+ uint32_t txpf_l;
+ uint32_t txpf_u;
+ uint32_t tfrm_l;
+ uint32_t tfrm_u;
+ uint32_t tfcs_l;
+ uint32_t tfcs_u;
+ uint32_t tvlan_l;
+ uint32_t tvlan_u;
+ uint32_t terr_l;
+ uint32_t terr_u;
+ uint32_t tuca_l;
+ uint32_t tuca_u;
+ uint32_t tmca_l;
+ uint32_t tmca_u;
+ uint32_t tbca_l;
+ uint32_t tbca_u;
+ uint32_t res0258[2];
+ uint32_t tpkt_l;
+ uint32_t tpkt_u;
+ uint32_t tund_l;
+ uint32_t tund_u;
+ uint32_t t64_l;
+ uint32_t t64_u;
+ uint32_t t127_l;
+ uint32_t t127_u;
+ uint32_t t255_l;
+ uint32_t t255_u;
+ uint32_t t511_l;
+ uint32_t t511_u;
+ uint32_t t1023_l;
+ uint32_t t1023_u;
+ uint32_t t1518_l;
+ uint32_t t1518_u;
+ uint32_t t1519x_l;
+ uint32_t t1519x_u;
+ uint32_t res02a8[6];
+ uint32_t tcnp_l;
+ uint32_t tcnp_u;
+ uint32_t res02c8[14];
+ /* Line Interface Control */
+ uint32_t if_mode; /* 0x300 Interface Mode Control */
+ uint32_t if_status; /* 0x304 Interface Status */
+ uint32_t res0308[14];
+ /* HiGig/2 */
+ uint32_t hg_config; /* 0x340 Control and cfg */
+ uint32_t res0344[3];
+ uint32_t hg_pause_quanta; /* 0x350 Pause quanta */
+ uint32_t res0354[3];
+ uint32_t hg_pause_thresh; /* 0x360 Pause quanta threshold */
+ uint32_t res0364[3];
+ uint32_t hgrx_pause_status; /* 0x370 Receive pause status */
+ uint32_t hg_fifos_status; /* 0x374 fifos status */
+ uint32_t rhm; /* 0x378 rx messages counter */
+ uint32_t thm; /* 0x37C tx messages counter */
+};
+
+struct memac_cfg {
+ bool reset_on_init;
+ bool rx_error_discard;
+ bool pause_ignore;
+ bool pause_forward_enable;
+ bool no_length_check_enable;
+ bool cmd_frame_enable;
+ bool send_idle_enable;
+ bool wan_mode_enable;
+ bool promiscuous_mode_enable;
+ bool tx_addr_ins_enable;
+ bool loopback_enable;
+ bool lgth_check_nostdr;
+ bool time_stamp_enable;
+ bool pad_enable;
+ bool phy_tx_ena_on;
+ bool rx_sfd_any;
+ bool rx_pbl_fwd;
+ bool tx_pbl_fwd;
+ bool debug_mode;
+ bool wake_on_lan;
+ uint16_t max_frame_length;
+ uint16_t pause_quanta;
+ uint32_t tx_ipg_length;
+};
+
+
+/**
+ * fman_memac_defconfig() - Get default MEMAC configuration
+ * @cfg: pointer to configuration structure.
+ *
+ * Call this function to obtain a default set of configuration values for
+ * initializing MEMAC. The user can overwrite any of the values before calling
+ * fman_memac_init(), if specific configuration needs to be applied.
+ */
+void fman_memac_defconfig(struct memac_cfg *cfg);
+
+int fman_memac_init(struct memac_regs *regs,
+ struct memac_cfg *cfg,
+ enum enet_interface enet_interface,
+ enum enet_speed enet_speed,
+ bool slow_10g_if,
+ uint32_t exceptions);
+
+void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx);
+
+void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx);
+
+void fman_memac_set_promiscuous(struct memac_regs *regs, bool val);
+
+void fman_memac_add_addr_in_paddr(struct memac_regs *regs,
+ uint8_t *adr,
+ uint8_t paddr_num);
+
+void fman_memac_clear_addr_in_paddr(struct memac_regs *regs,
+ uint8_t paddr_num);
+
+uint64_t fman_memac_get_counter(struct memac_regs *regs,
+ enum memac_counters reg_name);
+
+void fman_memac_set_tx_pause_frames(struct memac_regs *regs,
+ uint8_t priority, uint16_t pauseTime, uint16_t threshTime);
+
+uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs);
+
+void fman_memac_set_exception(struct memac_regs *regs, uint32_t val,
+ bool enable);
+
+void fman_memac_reset_stat(struct memac_regs *regs);
+
+void fman_memac_reset(struct memac_regs *regs);
+
+void fman_memac_reset_filter_table(struct memac_regs *regs);
+
+void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc);
+
+void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val);
+
+void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs,
+ bool enable);
+
+void fman_memac_set_wol(struct memac_regs *regs, bool enable);
+
+uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask);
+
+void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask);
+
+uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs);
+
+void fman_memac_adjust_link(struct memac_regs *regs,
+ enum enet_interface iface_mode,
+ enum enet_speed speed, bool full_dx);
+
+
+
+#endif /*__FSL_FMAN_MEMAC_H*/
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h
new file mode 100755
index 000000000000..b43044501b80
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_MEMAC_MII_ACC_H
+#define __FSL_FMAN_MEMAC_MII_ACC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+/* MII Management Registers */
+#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80
+#define MDIO_CFG_CLK_DIV_SHIFT 7
+#define MDIO_CFG_HOLD_MASK 0x0000001c
+#define MDIO_CFG_ENC45 0x00000040
+#define MDIO_CFG_READ_ERR 0x00000002
+#define MDIO_CFG_BSY 0x00000001
+
+#define MDIO_CTL_PHY_ADDR_SHIFT 5
+#define MDIO_CTL_READ 0x00008000
+
+#define MDIO_DATA_BSY 0x80000000
+
+/*MEMAC Internal PHY Registers - SGMII */
+#define PHY_SGMII_CR_PHY_RESET 0x8000
+#define PHY_SGMII_CR_RESET_AN 0x0200
+#define PHY_SGMII_CR_DEF_VAL 0x1140
+#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001
+#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0
+#define PHY_SGMII_IF_MODE_AN 0x0002
+#define PHY_SGMII_IF_MODE_SGMII 0x0001
+#define PHY_SGMII_IF_MODE_1000X 0x0000
+
+/*----------------------------------------------------*/
+/* MII Configuration Control Memory Map Registers */
+/*----------------------------------------------------*/
+struct memac_mii_access_mem_map {
+ uint32_t mdio_cfg; /* 0x030 */
+ uint32_t mdio_ctrl; /* 0x034 */
+ uint32_t mdio_data; /* 0x038 */
+ uint32_t mdio_addr; /* 0x03c */
+};
+
+int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t *data,
+ enum enet_speed enet_speed);
+int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs,
+ uint8_t phy_addr, uint8_t reg, uint16_t data,
+ enum enet_speed enet_speed);
+
+#endif /* __MAC_API_MEMAC_MII_ACC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h
new file mode 100755
index 000000000000..080a23e963b9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_PORT_H
+#define __FSL_FMAN_PORT_H
+
+#include "fsl_fman_sp.h"
+
+/** @Collection Registers bit fields */
+
+/** @Description BMI defines */
+#define BMI_EBD_EN 0x80000000
+
+#define BMI_PORT_CFG_EN 0x80000000
+#define BMI_PORT_CFG_FDOVR 0x02000000
+#define BMI_PORT_CFG_IM 0x01000000
+
+#define BMI_PORT_STATUS_BSY 0x80000000
+
+#define BMI_DMA_ATTR_SWP_SHIFT FMAN_SP_DMA_ATTR_SWP_SHIFT
+#define BMI_DMA_ATTR_IC_STASH_ON 0x10000000
+#define BMI_DMA_ATTR_HDR_STASH_ON 0x04000000
+#define BMI_DMA_ATTR_SG_STASH_ON 0x01000000
+#define BMI_DMA_ATTR_WRITE_OPTIMIZE FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE
+
+#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16
+#define BMI_RX_FIFO_THRESHOLD_ETHE 0x80000000
+
+#define BMI_TX_FRAME_END_CS_IGNORE_SHIFT 24
+#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24
+#define BMI_RX_FRAME_END_CUT_SHIFT 16
+
+#define BMI_IC_TO_EXT_SHIFT FMAN_SP_IC_TO_EXT_SHIFT
+#define BMI_IC_FROM_INT_SHIFT FMAN_SP_IC_FROM_INT_SHIFT
+
+#define BMI_INT_BUF_MARG_SHIFT 28
+#define BMI_EXT_BUF_MARG_START_SHIFT FMAN_SP_EXT_BUF_MARG_START_SHIFT
+
+#define BMI_CMD_MR_LEAC 0x00200000
+#define BMI_CMD_MR_SLEAC 0x00100000
+#define BMI_CMD_MR_MA 0x00080000
+#define BMI_CMD_MR_DEAS 0x00040000
+#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \
+ BMI_CMD_MR_SLEAC | \
+ BMI_CMD_MR_MA | \
+ BMI_CMD_MR_DEAS)
+#define BMI_CMD_TX_MR_DEF 0
+#define BMI_CMD_OP_MR_DEF (BMI_CMD_MR_DEAS | \
+ BMI_CMD_MR_MA)
+
+#define BMI_CMD_ATTR_ORDER 0x80000000
+#define BMI_CMD_ATTR_SYNC 0x02000000
+#define BMI_CMD_ATTR_COLOR_SHIFT 26
+
+#define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12
+#define BMI_NEXT_ENG_FD_BITS_SHIFT 24
+#define BMI_FRAME_END_CS_IGNORE_SHIFT 24
+
+#define BMI_COUNTERS_EN 0x80000000
+
+#define BMI_EXT_BUF_POOL_VALID FMAN_SP_EXT_BUF_POOL_VALID
+#define BMI_EXT_BUF_POOL_EN_COUNTER FMAN_SP_EXT_BUF_POOL_EN_COUNTER
+#define BMI_EXT_BUF_POOL_BACKUP FMAN_SP_EXT_BUF_POOL_BACKUP
+#define BMI_EXT_BUF_POOL_ID_SHIFT 16
+#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000
+#define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT 16
+
+#define BMI_TX_FIFO_MIN_FILL_SHIFT 16
+#define BMI_TX_FIFO_PIPELINE_DEPTH_SHIFT 12
+
+#define MAX_PERFORMANCE_TASK_COMP 64
+#define MAX_PERFORMANCE_RX_QUEUE_COMP 64
+#define MAX_PERFORMANCE_TX_QUEUE_COMP 8
+#define MAX_PERFORMANCE_DMA_COMP 16
+#define MAX_PERFORMANCE_FIFO_COMP 1024
+
+#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24
+#define BMI_PERFORMANCE_QUEUE_COMP_SHIFT 16
+#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12
+
+#define BMI_RATE_LIMIT_GRAN_TX 16000 /* In Kbps */
+#define BMI_RATE_LIMIT_GRAN_OP 10000 /* In frames */
+#define BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS 1024
+#define BMI_RATE_LIMIT_MAX_BURST_SIZE 1024 /* In KBytes */
+#define BMI_RATE_LIMIT_MAX_BURST_SHIFT 16
+#define BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN 0x80000000
+#define BMI_RATE_LIMIT_SCALE_TSBS_SHIFT 16
+#define BMI_RATE_LIMIT_SCALE_EN 0x80000000
+#define BMI_SG_DISABLE FMAN_SP_SG_DISABLE
+
+/** @Description QMI defines */
+#define QMI_PORT_CFG_EN 0x80000000
+#define QMI_PORT_CFG_EN_COUNTERS 0x10000000
+
+#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000
+#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000
+
+#define QMI_DEQ_CFG_PRI 0x80000000
+#define QMI_DEQ_CFG_TYPE1 0x10000000
+#define QMI_DEQ_CFG_TYPE2 0x20000000
+#define QMI_DEQ_CFG_TYPE3 0x30000000
+#define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000
+#define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000
+#define QMI_DEQ_CFG_SP_MASK 0xf
+#define QMI_DEQ_CFG_SP_SHIFT 20
+
+
+/** @Description General port defines */
+#define FMAN_PORT_EXT_POOLS_NUM(fm_rev_maj) \
+ (((fm_rev_maj) == 4) ? 4 : 8)
+#define FMAN_PORT_MAX_EXT_POOLS_NUM 8
+#define FMAN_PORT_OBS_EXT_POOLS_NUM 2
+#define FMAN_PORT_CG_MAP_NUM 8
+#define FMAN_PORT_PRS_RESULT_WORDS_NUM 8
+#define FMAN_PORT_BMI_FIFO_UNITS 0x100
+#define FMAN_PORT_IC_OFFSET_UNITS 0x10
+
+
+/** @Collection FM Port Register Map */
+
+/** @Description BMI Rx port register map */
+struct fman_port_rx_bmi_regs {
+ uint32_t fmbm_rcfg; /**< Rx Configuration */
+ uint32_t fmbm_rst; /**< Rx Status */
+ uint32_t fmbm_rda; /**< Rx DMA attributes*/
+ uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/
+ uint32_t fmbm_rfed; /**< Rx Frame End Data*/
+ uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/
+ uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/
+ uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/
+ uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/
+ uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/
+ uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/
+ uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/
+ uint32_t fmbm_rpp; /**< Rx Policer Profile */
+ uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */
+ uint32_t fmbm_reth; /**< Rx Excessive Threshold */
+ uint32_t reserved003c[1]; /**< (0x03C 0x03F) */
+ uint32_t fmbm_rprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
+ /**< Rx Parse Results Array Init*/
+ uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/
+ uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/
+ uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/
+ uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/
+ uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */
+ uint32_t reserved0074[0x2]; /**< (0x074-0x07C) */
+ uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */
+ uint32_t reserved0080[0x20];/**< (0x080 0x0FF) */
+ uint32_t fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM];
+ /**< Buffer Manager pool Information-*/
+ uint32_t fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM];
+ /**< Allocate Counter-*/
+ uint32_t reserved0130[8];
+ /**< 0x130/0x140 - 0x15F reserved -*/
+ uint32_t fmbm_rcgm[FMAN_PORT_CG_MAP_NUM];
+ /**< Congestion Group Map*/
+ uint32_t fmbm_mpd; /**< BM Pool Depletion */
+ uint32_t reserved0184[0x1F]; /**< (0x184 0x1FF) */
+ uint32_t fmbm_rstc; /**< Rx Statistics Counters*/
+ uint32_t fmbm_rfrc; /**< Rx Frame Counter*/
+ uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/
+ uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/
+ uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/
+ uint32_t fmbm_rfdc; /**< Rx Frame Discard Counter*/
+ uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/
+ uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard nntr*/
+ uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter*/
+ uint32_t reserved0224[0x17]; /**< (0x224 0x27F) */
+ uint32_t fmbm_rpc; /**< Rx Performance Counters*/
+ uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/
+ uint32_t fmbm_rccn; /**< Rx Cycle Counter*/
+ uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/
+ uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization cntr*/
+ uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/
+ uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/
+ uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/
+ uint32_t reserved02a0[0x18]; /**< (0x2A0 0x2FF) */
+ uint32_t fmbm_rdbg; /**< Rx Debug-*/
+};
+
+/** @Description BMI Tx port register map */
+struct fman_port_tx_bmi_regs {
+ uint32_t fmbm_tcfg; /**< Tx Configuration */
+ uint32_t fmbm_tst; /**< Tx Status */
+ uint32_t fmbm_tda; /**< Tx DMA attributes */
+ uint32_t fmbm_tfp; /**< Tx FIFO Parameters */
+ uint32_t fmbm_tfed; /**< Tx Frame End Data */
+ uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */
+ uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */
+ uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */
+ uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */
+ uint32_t fmbm_tefqid; /**< Tx Frame Error Queue ID */
+ uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */
+ uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */
+ uint32_t fmbm_trlmt; /**< Tx Rate Limiter */
+ uint32_t reserved0034[0x0e]; /**< (0x034-0x6c) */
+ uint32_t fmbm_tccb; /**< Tx Coarse Classification base */
+ uint32_t fmbm_tfne; /**< Tx Frame Next Engine */
+ uint32_t fmbm_tpfcm[0x02]; /**< Tx Priority based Flow Control (PFC) Mapping */
+ uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */
+ uint32_t reserved0080[0x60]; /**< (0x080-0x200) */
+ uint32_t fmbm_tstc; /**< Tx Statistics Counters */
+ uint32_t fmbm_tfrc; /**< Tx Frame Counter */
+ uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */
+ uint32_t fmbm_tfledc; /**< Tx Frame len error discard cntr */
+ uint32_t fmbm_tfufdc; /**< Tx Frame unsprt frmt discard cntr*/
+ uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */
+ uint32_t reserved0218[0x1A]; /**< (0x218-0x280) */
+ uint32_t fmbm_tpc; /**< Tx Performance Counters*/
+ uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/
+ uint32_t fmbm_tccn; /**< Tx Cycle Counter*/
+ uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/
+ uint32_t fmbm_ttcquc; /**< Tx Transmit conf Q util Counter*/
+ uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/
+ uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/
+};
+
+/** @Description BMI O/H port register map */
+struct fman_port_oh_bmi_regs {
+ uint32_t fmbm_ocfg; /**< O/H Configuration */
+ uint32_t fmbm_ost; /**< O/H Status */
+ uint32_t fmbm_oda; /**< O/H DMA attributes */
+ uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */
+ uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */
+ uint32_t fmbm_ofne; /**< O/H Frame Next Engine */
+ uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */
+ uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */
+ uint32_t fmbm_opso; /**< O/H Parse Start Offset */
+ uint32_t fmbm_opp; /**< O/H Policer Profile */
+ uint32_t fmbm_occb; /**< O/H Coarse Classification base */
+ uint32_t fmbm_oim; /**< O/H Internal margins*/
+ uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/
+ uint32_t fmbm_ofed; /**< O/H Frame End Data*/
+ uint32_t reserved0030[2]; /**< (0x038 - 0x03F) */
+ uint32_t fmbm_oprai[FMAN_PORT_PRS_RESULT_WORDS_NUM];
+ /**< O/H Parse Results Array Initialization */
+ uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */
+ uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */
+ uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */
+ uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */
+ uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */
+ uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */
+ uint32_t fmbm_orlmt; /**< O/H Rate Limiter */
+ uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */
+ uint32_t reserved0080[0x20]; /**< 0x080 - 0x0FF Reserved */
+ uint32_t fmbm_oebmpi[2]; /**< Buf Mngr Observed Pool Info */
+ uint32_t reserved0108[0x16]; /**< 0x108 - 0x15F Reserved */
+ uint32_t fmbm_ocgm[FMAN_PORT_CG_MAP_NUM]; /**< Observed Congestion Group Map */
+ uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */
+ uint32_t reserved0184[0x1F]; /**< 0x184 - 0x1FF Reserved */
+ uint32_t fmbm_ostc; /**< O/H Statistics Counters */
+ uint32_t fmbm_ofrc; /**< O/H Frame Counter */
+ uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */
+ uint32_t fmbm_ofledc; /**< O/H Frames Len Err Discard Cntr */
+ uint32_t fmbm_ofufdc; /**< O/H Frames Unsprtd Discard Cutr */
+ uint32_t fmbm_offc; /**< O/H Filter Frames Counter */
+ uint32_t fmbm_ofwdc; /**< Rx Frames WRED Discard Counter */
+ uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Cntr */
+ uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */
+ uint32_t reserved0218[0x17]; /**< (0x218 - 0x27F) */
+ uint32_t fmbm_opc; /**< O/H Performance Counters */
+ uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */
+ uint32_t fmbm_occn; /**< O/H Cycle Counter */
+ uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */
+ uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */
+ uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */
+};
+
+/** @Description BMI port register map */
+union fman_port_bmi_regs {
+ struct fman_port_rx_bmi_regs rx;
+ struct fman_port_tx_bmi_regs tx;
+ struct fman_port_oh_bmi_regs oh;
+};
+
+/** @Description QMI port register map */
+struct fman_port_qmi_regs {
+ uint32_t fmqm_pnc; /**< PortID n Configuration Register */
+ uint32_t fmqm_pns; /**< PortID n Status Register */
+ uint32_t fmqm_pnts; /**< PortID n Task Status Register */
+ uint32_t reserved00c[4]; /**< 0xn00C - 0xn01B */
+ uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */
+ uint32_t fmqm_pnetfc; /**< PortID n Enq Total Frame Counter */
+ uint32_t reserved024[2]; /**< 0xn024 - 0x02B */
+ uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */
+ uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */
+ uint32_t fmqm_pndtfc; /**< PortID n Dequeue tot Frame cntr */
+ uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID Dflt Cntr */
+ uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */
+};
+
+
+enum fman_port_dma_swap {
+ E_FMAN_PORT_DMA_NO_SWAP, /**< No swap, transfer data as is */
+ E_FMAN_PORT_DMA_SWAP_LE,
+ /**< The transferred data should be swapped in PPC Little Endian mode */
+ E_FMAN_PORT_DMA_SWAP_BE
+ /**< The transferred data should be swapped in Big Endian mode */
+};
+
+/* Default port color */
+enum fman_port_color {
+ E_FMAN_PORT_COLOR_GREEN, /**< Default port color is green */
+ E_FMAN_PORT_COLOR_YELLOW, /**< Default port color is yellow */
+ E_FMAN_PORT_COLOR_RED, /**< Default port color is red */
+ E_FMAN_PORT_COLOR_OVERRIDE /**< Ignore color */
+};
+
+/* QMI dequeue from the SP channel - types */
+enum fman_port_deq_type {
+ E_FMAN_PORT_DEQ_BY_PRI,
+ /**< Priority precedence and Intra-Class scheduling */
+ E_FMAN_PORT_DEQ_ACTIVE_FQ,
+ /**< Active FQ precedence and Intra-Class scheduling */
+ E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS
+ /**< Active FQ precedence and override Intra-Class scheduling */
+};
+
+/* QMI dequeue prefetch modes */
+enum fman_port_deq_prefetch {
+ E_FMAN_PORT_DEQ_NO_PREFETCH, /**< No prefetch mode */
+ E_FMAN_PORT_DEQ_PART_PREFETCH, /**< Partial prefetch mode */
+ E_FMAN_PORT_DEQ_FULL_PREFETCH /**< Full prefetch mode */
+};
+
+/* Parameters for defining performance counters behavior */
+struct fman_port_perf_cnt_params {
+ uint8_t task_val; /**< Task compare value */
+ uint8_t queue_val;
+ /**< Rx or Tx conf queue compare value (unused for O/H ports) */
+ uint8_t dma_val; /**< Dma compare value */
+ uint32_t fifo_val; /**< Fifo compare value (in bytes) */
+};
+
+/** @Description FM Port configuration structure, used at init */
+struct fman_port_cfg {
+ struct fman_port_perf_cnt_params perf_cnt_params;
+ /* BMI parameters */
+ enum fman_port_dma_swap dma_swap_data;
+ bool dma_ic_stash_on;
+ bool dma_header_stash_on;
+ bool dma_sg_stash_on;
+ bool dma_write_optimize;
+ uint16_t ic_ext_offset;
+ uint8_t ic_int_offset;
+ uint16_t ic_size;
+ enum fman_port_color color;
+ bool sync_req;
+ bool discard_override;
+ uint8_t checksum_bytes_ignore;
+ uint8_t rx_cut_end_bytes;
+ uint32_t rx_pri_elevation;
+ uint32_t rx_fifo_thr;
+ uint8_t rx_fd_bits;
+ uint8_t int_buf_start_margin;
+ uint16_t ext_buf_start_margin;
+ uint16_t ext_buf_end_margin;
+ uint32_t tx_fifo_min_level;
+ uint32_t tx_fifo_low_comf_level;
+ uint8_t tx_fifo_deq_pipeline_depth;
+ bool stats_counters_enable;
+ bool perf_counters_enable;
+ /* QMI parameters */
+ bool deq_high_pri;
+ enum fman_port_deq_type deq_type;
+ enum fman_port_deq_prefetch deq_prefetch_opt;
+ uint16_t deq_byte_cnt;
+ bool queue_counters_enable;
+ bool no_scatter_gather;
+ int errata_A006675;
+ int errata_A006320;
+ int excessive_threshold_register;
+ int fmbm_rebm_has_sgd;
+ int fmbm_tfne_has_features;
+ int qmi_deq_options_support;
+};
+
+enum fman_port_type {
+ E_FMAN_PORT_TYPE_OP = 0,
+ /**< Offline parsing port, shares id-s with
+ * host command, so must have exclusive id-s */
+ E_FMAN_PORT_TYPE_RX, /**< 1G Rx port */
+ E_FMAN_PORT_TYPE_RX_10G, /**< 10G Rx port */
+ E_FMAN_PORT_TYPE_TX, /**< 1G Tx port */
+ E_FMAN_PORT_TYPE_TX_10G, /**< 10G Tx port */
+ E_FMAN_PORT_TYPE_DUMMY,
+ E_FMAN_PORT_TYPE_HC = E_FMAN_PORT_TYPE_DUMMY
+ /**< Host command port, shares id-s with
+ * offline parsing ports, so must have exclusive id-s */
+};
+
+struct fman_port_params {
+ uint32_t discard_mask;
+ uint32_t err_mask;
+ uint32_t dflt_fqid;
+ uint32_t err_fqid;
+ uint8_t deq_sp;
+ bool dont_release_buf;
+};
+
+/* Port context - used by most API functions */
+struct fman_port {
+ enum fman_port_type type;
+ uint8_t fm_rev_maj;
+ uint8_t fm_rev_min;
+ union fman_port_bmi_regs *bmi_regs;
+ struct fman_port_qmi_regs *qmi_regs;
+ bool im_en;
+ uint8_t ext_pools_num;
+};
+
+/** @Description External buffer pools configuration */
+struct fman_port_bpools {
+ uint8_t count; /**< Num of pools to set up */
+ bool counters_enable; /**< Enable allocate counters */
+ uint8_t grp_bp_depleted_num;
+ /**< Number of depleted pools - if reached the BMI indicates
+ * the MAC to send a pause frame */
+ struct {
+ uint8_t bpid; /**< BM pool ID */
+ uint16_t size;
+ /**< Pool's size - must be in ascending order */
+ bool is_backup;
+ /**< If this is a backup pool */
+ bool grp_bp_depleted;
+ /**< Consider this buffer in multiple pools depletion criteria*/
+ bool single_bp_depleted;
+ /**< Consider this buffer in single pool depletion criteria */
+ bool pfc_priorities_en;
+ } bpool[FMAN_PORT_MAX_EXT_POOLS_NUM];
+};
+
+enum fman_port_rate_limiter_scale_down {
+ E_FMAN_PORT_RATE_DOWN_NONE,
+ E_FMAN_PORT_RATE_DOWN_BY_2,
+ E_FMAN_PORT_RATE_DOWN_BY_4,
+ E_FMAN_PORT_RATE_DOWN_BY_8
+};
+
+/* Rate limiter configuration */
+struct fman_port_rate_limiter {
+ uint8_t count_1micro_bit;
+ bool high_burst_size_gran;
+ /**< Defines burst_size granularity for OP ports; when TRUE,
+ * burst_size below counts in frames, otherwise in 10^3 frames */
+ uint16_t burst_size;
+ /**< Max burst size, in KBytes for Tx port, according to
+ * high_burst_size_gran definition for OP port */
+ uint32_t rate;
+ /**< In Kbps for Tx port, in frames/sec for OP port */
+ enum fman_port_rate_limiter_scale_down rate_factor;
+};
+
+/* BMI statistics counters */
+enum fman_port_stats_counters {
+ E_FMAN_PORT_STATS_CNT_FRAME,
+ /**< Number of processed frames; valid for all ports */
+ E_FMAN_PORT_STATS_CNT_DISCARD,
+ /**< For Rx ports - frames discarded by QMAN, for Tx or O/H ports -
+ * frames discarded due to DMA error; valid for all ports */
+ E_FMAN_PORT_STATS_CNT_DEALLOC_BUF,
+ /**< Number of buffer deallocate operations; valid for all ports */
+ E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME,
+ /**< Number of bad Rx frames, like CRC error, Rx FIFO overflow etc;
+ * valid for Rx ports only */
+ E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME,
+ /**< Number of Rx oversized frames, that is frames exceeding max frame
+ * size configured for the corresponding ETH controller;
+ * valid for Rx ports only */
+ E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF,
+ /**< Frames discarded due to lack of external buffers; valid for
+ * Rx ports only */
+ E_FMAN_PORT_STATS_CNT_LEN_ERR,
+ /**< Frames discarded due to frame length error; valid for Tx and
+ * O/H ports only */
+ E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT,
+ /**< Frames discarded due to unsupported FD format; valid for Tx
+ * and O/H ports only */
+ E_FMAN_PORT_STATS_CNT_FILTERED_FRAME,
+ /**< Number of frames filtered out by PCD module; valid for
+ * Rx and OP ports only */
+ E_FMAN_PORT_STATS_CNT_DMA_ERR,
+ /**< Frames rejected by QMAN that were not able to release their
+ * buffers due to DMA error; valid for Rx and O/H ports only */
+ E_FMAN_PORT_STATS_CNT_WRED_DISCARD
+ /**< Frames going through O/H port that were not able to to enter the
+ * return queue due to WRED algorithm; valid for O/H ports only */
+};
+
+/* BMI performance counters */
+enum fman_port_perf_counters {
+ E_FMAN_PORT_PERF_CNT_CYCLE, /**< Cycle counter */
+ E_FMAN_PORT_PERF_CNT_TASK_UTIL, /**< Tasks utilization counter */
+ E_FMAN_PORT_PERF_CNT_QUEUE_UTIL,
+ /**< For Rx ports - Rx queue utilization, for Tx ports - Tx conf queue
+ * utilization; not valid for O/H ports */
+ E_FMAN_PORT_PERF_CNT_DMA_UTIL, /**< DMA utilization counter */
+ E_FMAN_PORT_PERF_CNT_FIFO_UTIL, /**< FIFO utilization counter */
+ E_FMAN_PORT_PERF_CNT_RX_PAUSE
+ /**< Number of cycles in which Rx pause activation control is on;
+ * valid for Rx ports only */
+};
+
+/* QMI counters */
+enum fman_port_qmi_counters {
+ E_FMAN_PORT_ENQ_TOTAL, /**< EnQ tot frame cntr */
+ E_FMAN_PORT_DEQ_TOTAL, /**< DeQ tot frame cntr; invalid for Rx ports */
+ E_FMAN_PORT_DEQ_FROM_DFLT,
+ /**< Dequeue from default FQID counter not valid for Rx ports */
+ E_FMAN_PORT_DEQ_CONFIRM /**< DeQ confirm cntr invalid for Rx ports */
+};
+
+
+/** @Collection FM Port API */
+void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type);
+int fman_port_init(struct fman_port *port,
+ struct fman_port_cfg *cfg,
+ struct fman_port_params *params);
+int fman_port_enable(struct fman_port *port);
+int fman_port_disable(const struct fman_port *port);
+int fman_port_set_bpools(const struct fman_port *port,
+ const struct fman_port_bpools *bp);
+int fman_port_set_rate_limiter(struct fman_port *port,
+ struct fman_port_rate_limiter *rate_limiter);
+int fman_port_delete_rate_limiter(struct fman_port *port);
+int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask);
+int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask);
+int fman_port_modify_rx_fd_bits(struct fman_port *port,
+ uint8_t rx_fd_bits,
+ bool add);
+int fman_port_set_perf_cnt_params(struct fman_port *port,
+ struct fman_port_perf_cnt_params *params);
+int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable);
+int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable);
+int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable);
+int fman_port_set_bpool_cnt_mode(struct fman_port *port,
+ uint8_t bpid,
+ bool enable);
+uint32_t fman_port_get_stats_counter(struct fman_port *port,
+ enum fman_port_stats_counters counter);
+void fman_port_set_stats_counter(struct fman_port *port,
+ enum fman_port_stats_counters counter,
+ uint32_t value);
+uint32_t fman_port_get_perf_counter(struct fman_port *port,
+ enum fman_port_perf_counters counter);
+void fman_port_set_perf_counter(struct fman_port *port,
+ enum fman_port_perf_counters counter,
+ uint32_t value);
+uint32_t fman_port_get_qmi_counter(struct fman_port *port,
+ enum fman_port_qmi_counters counter);
+void fman_port_set_qmi_counter(struct fman_port *port,
+ enum fman_port_qmi_counters counter,
+ uint32_t value);
+uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid);
+void fman_port_set_bpool_counter(struct fman_port *port,
+ uint8_t bpid,
+ uint32_t value);
+int fman_port_add_congestion_grps(struct fman_port *port,
+ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]);
+int fman_port_remove_congestion_grps(struct fman_port *port,
+ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]);
+
+
+#endif /* __FSL_FMAN_PORT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h
new file mode 100644
index 000000000000..b18997dc0b8a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_PRS_H
+#define __FSL_FMAN_PRS_H
+
+#include "common/general.h"
+
+#define FM_PCD_EX_PRS_DOUBLE_ECC 0x02000000
+#define FM_PCD_EX_PRS_SINGLE_ECC 0x01000000
+
+#define FM_PCD_PRS_PPSC_ALL_PORTS 0xffff0000
+#define FM_PCD_PRS_RPIMAC_EN 0x00000001
+#define FM_PCD_PRS_PORT_IDLE_STS 0xffff0000
+#define FM_PCD_PRS_SINGLE_ECC 0x00004000
+#define FM_PCD_PRS_DOUBLE_ECC 0x00004000
+#define PRS_MAX_CYCLE_LIMIT 8191
+
+#define DEFAULT_MAX_PRS_CYC_LIM 0
+
+struct fman_prs_regs {
+ uint32_t fmpr_rpclim;
+ uint32_t fmpr_rpimac;
+ uint32_t pmeec;
+ uint32_t res00c[5];
+ uint32_t fmpr_pevr;
+ uint32_t fmpr_pever;
+ uint32_t res028;
+ uint32_t fmpr_perr;
+ uint32_t fmpr_perer;
+ uint32_t res034;
+ uint32_t res038[10];
+ uint32_t fmpr_ppsc;
+ uint32_t res064;
+ uint32_t fmpr_pds;
+ uint32_t fmpr_l2rrs;
+ uint32_t fmpr_l3rrs;
+ uint32_t fmpr_l4rrs;
+ uint32_t fmpr_srrs;
+ uint32_t fmpr_l2rres;
+ uint32_t fmpr_l3rres;
+ uint32_t fmpr_l4rres;
+ uint32_t fmpr_srres;
+ uint32_t fmpr_spcs;
+ uint32_t fmpr_spscs;
+ uint32_t fmpr_hxscs;
+ uint32_t fmpr_mrcs;
+ uint32_t fmpr_mwcs;
+ uint32_t fmpr_mrscs;
+ uint32_t fmpr_mwscs;
+ uint32_t fmpr_fcscs;
+};
+
+struct fman_prs_cfg {
+ uint32_t port_id_stat;
+ uint16_t max_prs_cyc_lim;
+ uint32_t prs_exceptions;
+};
+
+uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask);
+uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs);
+void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event);
+uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask);
+uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs);
+void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event);
+void fman_prs_defconfig(struct fman_prs_cfg *cfg);
+int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg);
+void fman_prs_enable(struct fman_prs_regs *regs);
+void fman_prs_disable(struct fman_prs_regs *regs);
+int fman_prs_is_enabled(struct fman_prs_regs *regs);
+void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk);
+void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable);
+#endif /* __FSL_FMAN_PRS_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h
new file mode 100755
index 000000000000..f6b69a1fbb05
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_RTC_H
+#define __FSL_FMAN_RTC_H
+
+#include "common/general.h"
+
+/* FM RTC Registers definitions */
+#define FMAN_RTC_TMR_CTRL_ALMP1 0x80000000
+#define FMAN_RTC_TMR_CTRL_ALMP2 0x40000000
+#define FMAN_RTC_TMR_CTRL_FS 0x10000000
+#define FMAN_RTC_TMR_CTRL_PP1L 0x08000000
+#define FMAN_RTC_TMR_CTRL_PP2L 0x04000000
+#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK 0x03FF0000
+#define FMAN_RTC_TMR_CTRL_FRD 0x00004000
+#define FMAN_RTC_TMR_CTRL_SLV 0x00002000
+#define FMAN_RTC_TMR_CTRL_ETEP1 0x00000100
+#define FMAN_RTC_TMR_CTRL_COPH 0x00000080
+#define FMAN_RTC_TMR_CTRL_CIPH 0x00000040
+#define FMAN_RTC_TMR_CTRL_TMSR 0x00000020
+#define FMAN_RTC_TMR_CTRL_DBG 0x00000010
+#define FMAN_RTC_TMR_CTRL_BYP 0x00000008
+#define FMAN_RTC_TMR_CTRL_TE 0x00000004
+#define FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK 0x00000003
+#define FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK 0x00000001
+#define FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK 0x00000000
+#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT 16
+
+#define FMAN_RTC_TMR_TEVENT_ETS2 0x02000000
+#define FMAN_RTC_TMR_TEVENT_ETS1 0x01000000
+#define FMAN_RTC_TMR_TEVENT_ALM2 0x00020000
+#define FMAN_RTC_TMR_TEVENT_ALM1 0x00010000
+#define FMAN_RTC_TMR_TEVENT_PP1 0x00000080
+#define FMAN_RTC_TMR_TEVENT_PP2 0x00000040
+#define FMAN_RTC_TMR_TEVENT_PP3 0x00000020
+#define FMAN_RTC_TMR_TEVENT_ALL (FMAN_RTC_TMR_TEVENT_ETS2 |\
+ FMAN_RTC_TMR_TEVENT_ETS1 |\
+ FMAN_RTC_TMR_TEVENT_ALM2 |\
+ FMAN_RTC_TMR_TEVENT_ALM1 |\
+ FMAN_RTC_TMR_TEVENT_PP1 |\
+ FMAN_RTC_TMR_TEVENT_PP2 |\
+ FMAN_RTC_TMR_TEVENT_PP3)
+
+#define FMAN_RTC_TMR_PRSC_OCK_MASK 0x0000FFFF
+
+/**************************************************************************//**
+ @Description FM RTC Alarm Polarity Options.
+*//***************************************************************************/
+enum fman_rtc_alarm_polarity {
+ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH, /**< Active-high output polarity */
+ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW /**< Active-low output polarity */
+};
+
+/**************************************************************************//**
+ @Description FM RTC Trigger Polarity Options.
+*//***************************************************************************/
+enum fman_rtc_trigger_polarity {
+ E_FMAN_RTC_TRIGGER_ON_RISING_EDGE, /**< Trigger on rising edge */
+ E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE /**< Trigger on falling edge */
+};
+
+/**************************************************************************//**
+ @Description IEEE1588 Timer Module FM RTC Optional Clock Sources.
+*//***************************************************************************/
+enum fman_src_clock {
+ E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL, /**< external high precision timer
+ reference clock */
+ E_FMAN_RTC_SOURCE_CLOCK_SYSTEM, /**< MAC system clock */
+ E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR /**< RTC clock oscilator */
+};
+
+/* RTC default values */
+#define DEFAULT_SRC_CLOCK E_FMAN_RTC_SOURCE_CLOCK_SYSTEM
+#define DEFAULT_INVERT_INPUT_CLK_PHASE FALSE
+#define DEFAULT_INVERT_OUTPUT_CLK_PHASE FALSE
+#define DEFAULT_ALARM_POLARITY E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH
+#define DEFAULT_TRIGGER_POLARITY E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE
+#define DEFAULT_PULSE_REALIGN FALSE
+
+#define FMAN_RTC_MAX_NUM_OF_ALARMS 3
+#define FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES 4
+#define FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS 3
+
+/**************************************************************************//**
+ @Description FM RTC timer alarm
+*//***************************************************************************/
+struct t_tmr_alarm{
+ uint32_t tmr_alarm_h; /**< */
+ uint32_t tmr_alarm_l; /**< */
+};
+
+/**************************************************************************//**
+ @Description FM RTC timer Ex trigger
+*//***************************************************************************/
+struct t_tmr_ext_trigger{
+ uint32_t tmr_etts_h; /**< */
+ uint32_t tmr_etts_l; /**< */
+};
+
+struct rtc_regs {
+ uint32_t tmr_id; /* 0x000 Module ID register */
+ uint32_t tmr_id2; /* 0x004 Controller ID register */
+ uint32_t reserved0008[30];
+ uint32_t tmr_ctrl; /* 0x0080 timer control register */
+ uint32_t tmr_tevent; /* 0x0084 timer event register */
+ uint32_t tmr_temask; /* 0x0088 timer event mask register */
+ uint32_t reserved008c[3];
+ uint32_t tmr_cnt_h; /* 0x0098 timer counter high register */
+ uint32_t tmr_cnt_l; /* 0x009c timer counter low register */
+ uint32_t tmr_add; /* 0x00a0 timer drift compensation addend register */
+ uint32_t tmr_acc; /* 0x00a4 timer accumulator register */
+ uint32_t tmr_prsc; /* 0x00a8 timer prescale */
+ uint32_t reserved00ac;
+ uint32_t tmr_off_h; /* 0x00b0 timer offset high */
+ uint32_t tmr_off_l; /* 0x00b4 timer offset low */
+ struct t_tmr_alarm tmr_alarm[FMAN_RTC_MAX_NUM_OF_ALARMS]; /* 0x00b8 timer
+ alarm */
+ uint32_t tmr_fiper[FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES]; /* 0x00d0 timer
+ fixed period interval */
+ struct t_tmr_ext_trigger tmr_etts[FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS];
+ /* 0x00e0 time stamp general purpose external */
+ uint32_t reserved00f0[4];
+};
+
+struct rtc_cfg {
+ enum fman_src_clock src_clk;
+ uint32_t ext_src_clk_freq;
+ uint32_t rtc_freq_hz;
+ bool timer_slave_mode;
+ bool invert_input_clk_phase;
+ bool invert_output_clk_phase;
+ uint32_t events_mask;
+ bool bypass; /**< Indicates if frequency compensation
+ is bypassed */
+ bool pulse_realign;
+ enum fman_rtc_alarm_polarity alarm_polarity[FMAN_RTC_MAX_NUM_OF_ALARMS];
+ enum fman_rtc_trigger_polarity trigger_polarity
+ [FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS];
+};
+
+/**
+ * fman_rtc_defconfig() - Get default RTC configuration
+ * @cfg: pointer to configuration structure.
+ *
+ * Call this function to obtain a default set of configuration values for
+ * initializing RTC. The user can overwrite any of the values before calling
+ * fman_rtc_init(), if specific configuration needs to be applied.
+ */
+void fman_rtc_defconfig(struct rtc_cfg *cfg);
+
+/**
+ * fman_rtc_get_events() - Get the events
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: The events
+ */
+uint32_t fman_rtc_get_events(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_get_interrupt_mask() - Get the events mask
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: The events mask
+ */
+uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs);
+
+
+/**
+ * fman_rtc_set_interrupt_mask() - Set the events mask
+ * @regs: Pointer to RTC register block
+ * @mask: The mask to set
+ */
+void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask);
+
+/**
+ * fman_rtc_get_event() - Check if specific events occurred
+ * @regs: Pointer to RTC register block
+ * @ev_mask: a mask of the events to check
+ *
+ * Returns: 0 if the events did not occur. Non zero if one of the events occurred
+ */
+uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask);
+
+/**
+ * fman_rtc_check_and_clear_event() - Clear events which are on
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: A mask of the events which were cleared
+ */
+uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_ack_event() - Clear events
+ * @regs: Pointer to RTC register block
+ * @events: The events to disable
+ */
+void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events);
+
+/**
+ * fman_rtc_enable_interupt() - Enable events interrupts
+ * @regs: Pointer to RTC register block
+ * @mask: The events to disable
+ */
+void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t mask);
+
+/**
+ * fman_rtc_disable_interupt() - Disable events interrupts
+ * @regs: Pointer to RTC register block
+ * @mask: The events to disable
+ */
+void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t mask);
+
+/**
+ * fman_rtc_get_timer_ctrl() - Get the control register
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: The control register value
+ */
+uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_set_timer_ctrl() - Set timer control register
+ * @regs: Pointer to RTC register block
+ * @val: The value to set
+ */
+void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val);
+
+/**
+ * fman_rtc_get_frequency_compensation() - Get the frequency compensation
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: The timer counter
+ */
+uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_set_frequency_compensation() - Set frequency compensation
+ * @regs: Pointer to RTC register block
+ * @val: The value to set
+ */
+void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val);
+
+/**
+ * fman_rtc_get_trigger_stamp() - Get a trigger stamp
+ * @regs: Pointer to RTC register block
+ * @id: The id of the trigger stamp
+ *
+ * Returns: The time stamp
+ */
+uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id);
+
+/**
+ * fman_rtc_set_timer_alarm_l() - Set timer alarm low register
+ * @regs: Pointer to RTC register block
+ * @index: The index of alarm to set
+ * @val: The value to set
+ */
+void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index,
+ uint32_t val);
+
+/**
+ * fman_rtc_set_timer_alarm() - Set timer alarm
+ * @regs: Pointer to RTC register block
+ * @index: The index of alarm to set
+ * @val: The value to set
+ */
+void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val);
+
+/**
+ * fman_rtc_set_timer_fiper() - Set timer fiper
+ * @regs: Pointer to RTC register block
+ * @index: The index of fiper to set
+ * @val: The value to set
+ */
+void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val);
+
+/**
+ * fman_rtc_set_timer_offset() - Set timer offset
+ * @regs: Pointer to RTC register block
+ * @val: The value to set
+ */
+void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val);
+
+/**
+ * fman_rtc_get_timer() - Get the timer counter
+ * @regs: Pointer to RTC register block
+ *
+ * Returns: The timer counter
+ */
+static inline uint64_t fman_rtc_get_timer(struct rtc_regs *regs)
+{
+ uint64_t time;
+ /* TMR_CNT_L must be read first to get an accurate value */
+ time = (uint64_t)ioread32be(&regs->tmr_cnt_l);
+ time |= ((uint64_t)ioread32be(&regs->tmr_cnt_h) << 32);
+
+ return time;
+}
+
+/**
+ * fman_rtc_set_timer() - Set timer counter
+ * @regs: Pointer to RTC register block
+ * @val: The value to set
+ */
+static inline void fman_rtc_set_timer(struct rtc_regs *regs, int64_t val)
+{
+ iowrite32be((uint32_t)val, &regs->tmr_cnt_l);
+ iowrite32be((uint32_t)(val >> 32), &regs->tmr_cnt_h);
+}
+
+/**
+ * fman_rtc_timers_soft_reset() - Soft reset
+ * @regs: Pointer to RTC register block
+ *
+ * Resets all the timer registers and state machines for the 1588 IP and
+ * the attached client 1588
+ */
+void fman_rtc_timers_soft_reset(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_clear_external_trigger() - Clear an external trigger
+ * @regs: Pointer to RTC register block
+ * @id: The id of the trigger to clear
+ */
+void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id);
+
+/**
+ * fman_rtc_clear_periodic_pulse() - Clear periodic pulse
+ * @regs: Pointer to RTC register block
+ * @id: The id of the fiper to clear
+ */
+void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id);
+
+/**
+ * fman_rtc_enable() - Enable RTC hardware block
+ * @regs: Pointer to RTC register block
+ */
+void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock);
+
+/**
+ * fman_rtc_is_enabled() - Is RTC hardware block enabled
+ * @regs: Pointer to RTC register block
+ *
+ * Return: TRUE if enabled
+ */
+bool fman_rtc_is_enabled(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_disable() - Disable RTC hardware block
+ * @regs: Pointer to RTC register block
+ */
+void fman_rtc_disable(struct rtc_regs *regs);
+
+/**
+ * fman_rtc_init() - Init RTC hardware block
+ * @cfg: RTC configuration data
+ * @regs: Pointer to RTC register block
+ * @num_alarms: Number of alarms in RTC
+ * @num_fipers: Number of fipers in RTC
+ * @num_ext_triggers: Number of external triggers in RTC
+ * @freq_compensation: Frequency compensation
+ * @output_clock_divisor: Output clock divisor
+ *
+ * This function initializes RTC and applies basic configuration.
+ */
+void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,
+ int num_fipers, int num_ext_triggers, bool init_freq_comp,
+ uint32_t freq_compensation, uint32_t output_clock_divisor);
+
+/**
+ * fman_rtc_set_alarm() - Set an alarm
+ * @regs: Pointer to RTC register block
+ * @id: id of alarm
+ * @val: value to write
+ * @enable: should interrupt be enabled
+ */
+void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable);
+
+/**
+ * fman_rtc_set_periodic_pulse() - Set an alarm
+ * @regs: Pointer to RTC register block
+ * @id: id of fiper
+ * @val: value to write
+ * @enable: should interrupt be enabled
+ */
+void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,
+ bool enable);
+
+/**
+ * fman_rtc_set_ext_trigger() - Set an external trigger
+ * @regs: Pointer to RTC register block
+ * @id: id of trigger
+ * @enable: should interrupt be enabled
+ * @use_pulse_as_input: use the pulse as input
+ */
+void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,
+ bool use_pulse_as_input);
+
+struct fm_rtc_alarm_params {
+ uint8_t alarm_id; /**< 0 or 1 */
+ uint64_t alarm_time; /**< In nanoseconds, the time when the
+ alarm should go off - must be a
+ multiple of the RTC period */
+ void (*f_alarm_callback)(void* app, uint8_t id); /**< This routine will
+ be called when RTC reaches alarmTime */
+ bool clear_on_expiration; /**< TRUE to turn off the alarm once
+ expired.*/
+};
+
+struct fm_rtc_periodic_pulse_params {
+ uint8_t periodic_pulse_id; /**< 0 or 1 */
+ uint64_t periodic_pulse_period; /**< In Nanoseconds. Must be a multiple
+ of the RTC period */
+ void (*f_periodic_pulse_callback)(void* app, uint8_t id); /**< This
+ routine will be called every
+ periodicPulsePeriod. */
+};
+
+#endif /* __FSL_FMAN_RTC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h
new file mode 100755
index 000000000000..f8ef7d569e10
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_SP_H
+#define __FSL_FMAN_SP_H
+
+#include "common/general.h"
+#include "fsl_fman.h"
+
+
+struct fm_pcd_storage_profile_regs{
+ uint32_t fm_sp_ebmpi[8];
+ /*offset 0 - 0xc*/
+ /**< Buffer Manager pool Information */
+
+ uint32_t fm_sp_acnt; /*offset 0x20*/
+ uint32_t fm_sp_ebm; /*offset 0x24*/
+ uint32_t fm_sp_da; /*offset 0x28*/
+ uint32_t fm_sp_icp; /*offset 0x2c*/
+ uint32_t fm_sp_mpd; /*offset 0x30*/
+ uint32_t res1[2]; /*offset 0x34 - 0x38*/
+ uint32_t fm_sp_spliodn; /*offset 0x3c*/
+};
+
+/**************************************************************************//**
+ @Description structure for defining internal context copying
+*//***************************************************************************/
+struct fman_sp_int_context_data_copy{
+ uint16_t ext_buf_offset; /**< Offset in External buffer to which
+ internal context is copied to (Rx)
+ or taken from (Tx, Op). */
+ uint8_t int_context_offset; /**< Offset within internal context to copy
+ from (Rx) or to copy to (Tx, Op).*/
+ uint16_t size; /**< Internal offset size to be copied */
+};
+
+/**************************************************************************//**
+ @Description struct for defining external buffer margins
+*//***************************************************************************/
+struct fman_sp_buf_margins{
+ uint16_t start_margins; /**< Number of bytes to be left at the
+ beginning of the external buffer (must be
+ divisible by 16) */
+ uint16_t end_margins; /**< number of bytes to be left at the end of
+ the external buffer(must be divisible by 16)*/
+};
+
+struct fm_storage_profile_params {
+ struct fman_ext_pools fm_ext_pools;
+ struct fman_backup_bm_pools backup_pools;
+ struct fman_sp_int_context_data_copy *int_context;
+ struct fman_sp_buf_margins *buf_margins;
+ enum fman_dma_swap_option dma_swap_data;
+ enum fman_dma_cache_option int_context_cache_attr;
+ enum fman_dma_cache_option header_cache_attr;
+ enum fman_dma_cache_option scatter_gather_cache_attr;
+ bool dma_write_optimize;
+ uint16_t liodn_offset;
+ bool no_scather_gather;
+ struct fman_buf_pool_depletion buf_pool_depletion;
+};
+
+/**************************************************************************//**
+ @Description Registers bit fields
+*//***************************************************************************/
+#define FMAN_SP_EXT_BUF_POOL_EN_COUNTER 0x40000000
+#define FMAN_SP_EXT_BUF_POOL_VALID 0x80000000
+#define FMAN_SP_EXT_BUF_POOL_BACKUP 0x20000000
+#define FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE 0x00100000
+#define FMAN_SP_SG_DISABLE 0x80000000
+
+/* shifts */
+#define FMAN_SP_EXT_BUF_POOL_ID_SHIFT 16
+#define FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT 16
+#define FMAN_SP_EXT_BUF_MARG_START_SHIFT 16
+#define FMAN_SP_EXT_BUF_MARG_END_SHIFT 0
+#define FMAN_SP_DMA_ATTR_SWP_SHIFT 30
+#define FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT 28
+#define FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT 26
+#define FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT 24
+#define FMAN_SP_IC_TO_EXT_SHIFT 16
+#define FMAN_SP_IC_FROM_INT_SHIFT 8
+#define FMAN_SP_IC_SIZE_SHIFT 0
+
+/**************************************************************************//**
+ @Description defaults
+*//***************************************************************************/
+#define DEFAULT_FMAN_SP_DMA_SWAP_DATA FMAN_DMA_NO_SWP
+#define DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR FMAN_DMA_NO_STASH
+#define DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR FMAN_DMA_NO_STASH
+#define DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR FMAN_DMA_NO_STASH
+#define DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE TRUE
+#define DEFAULT_FMAN_SP_NO_SCATTER_GATHER FALSE
+
+void fman_vsp_defconfig(struct fm_storage_profile_params *cfg);
+
+void fman_vsp_init(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index, struct fm_storage_profile_params *fm_vsp_params,
+ int port_max_num_of_ext_pools, int bm_max_num_of_pools,
+ int max_num_of_pfc_priorities);
+
+uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index);
+
+void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs,
+ uint16_t index, uint32_t value);
+
+
+#endif /* __FSL_FMAN_SP_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h
new file mode 100644
index 000000000000..a0373141ac68
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __FSL_FMAN_TGEC_H
+#define __FSL_FMAN_TGEC_H
+
+#include "common/general.h"
+#include "fsl_enet.h"
+
+
+/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
+#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
+
+enum tgec_counters {
+ E_TGEC_COUNTER_R64,
+ E_TGEC_COUNTER_R127,
+ E_TGEC_COUNTER_R255,
+ E_TGEC_COUNTER_R511,
+ E_TGEC_COUNTER_R1023,
+ E_TGEC_COUNTER_R1518,
+ E_TGEC_COUNTER_R1519X,
+ E_TGEC_COUNTER_TRFRG,
+ E_TGEC_COUNTER_TRJBR,
+ E_TGEC_COUNTER_RDRP,
+ E_TGEC_COUNTER_RALN,
+ E_TGEC_COUNTER_TRUND,
+ E_TGEC_COUNTER_TROVR,
+ E_TGEC_COUNTER_RXPF,
+ E_TGEC_COUNTER_TXPF,
+ E_TGEC_COUNTER_ROCT,
+ E_TGEC_COUNTER_RMCA,
+ E_TGEC_COUNTER_RBCA,
+ E_TGEC_COUNTER_RPKT,
+ E_TGEC_COUNTER_RUCA,
+ E_TGEC_COUNTER_RERR,
+ E_TGEC_COUNTER_TOCT,
+ E_TGEC_COUNTER_TMCA,
+ E_TGEC_COUNTER_TBCA,
+ E_TGEC_COUNTER_TUCA,
+ E_TGEC_COUNTER_TERR
+};
+
+/* Command and Configuration Register (COMMAND_CONFIG) */
+#define CMD_CFG_EN_TIMESTAMP 0x00100000
+#define CMD_CFG_TX_ADDR_INS_SEL 0x00080000
+#define CMD_CFG_NO_LEN_CHK 0x00020000
+#define CMD_CFG_SEND_IDLE 0x00010000
+#define CMD_CFG_RX_ER_DISC 0x00004000
+#define CMD_CFG_CMD_FRM_EN 0x00002000
+#define CMD_CFG_STAT_CLR 0x00001000
+#define CMD_CFG_LOOPBACK_EN 0x00000400
+#define CMD_CFG_TX_ADDR_INS 0x00000200
+#define CMD_CFG_PAUSE_IGNORE 0x00000100
+#define CMD_CFG_PAUSE_FWD 0x00000080
+#define CMD_CFG_PROMIS_EN 0x00000010
+#define CMD_CFG_WAN_MODE 0x00000008
+#define CMD_CFG_RX_EN 0x00000002
+#define CMD_CFG_TX_EN 0x00000001
+
+/* Interrupt Mask Register (IMASK) */
+#define TGEC_IMASK_MDIO_SCAN_EVENT 0x00010000
+#define TGEC_IMASK_MDIO_CMD_CMPL 0x00008000
+#define TGEC_IMASK_REM_FAULT 0x00004000
+#define TGEC_IMASK_LOC_FAULT 0x00002000
+#define TGEC_IMASK_TX_ECC_ER 0x00001000
+#define TGEC_IMASK_TX_FIFO_UNFL 0x00000800
+#define TGEC_IMASK_TX_FIFO_OVFL 0x00000400
+#define TGEC_IMASK_TX_ER 0x00000200
+#define TGEC_IMASK_RX_FIFO_OVFL 0x00000100
+#define TGEC_IMASK_RX_ECC_ER 0x00000080
+#define TGEC_IMASK_RX_JAB_FRM 0x00000040
+#define TGEC_IMASK_RX_OVRSZ_FRM 0x00000020
+#define TGEC_IMASK_RX_RUNT_FRM 0x00000010
+#define TGEC_IMASK_RX_FRAG_FRM 0x00000008
+#define TGEC_IMASK_RX_LEN_ER 0x00000004
+#define TGEC_IMASK_RX_CRC_ER 0x00000002
+#define TGEC_IMASK_RX_ALIGN_ER 0x00000001
+
+#define TGEC_EVENTS_MASK \
+ ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \
+ TGEC_IMASK_MDIO_CMD_CMPL | \
+ TGEC_IMASK_REM_FAULT | \
+ TGEC_IMASK_LOC_FAULT | \
+ TGEC_IMASK_TX_ECC_ER | \
+ TGEC_IMASK_TX_FIFO_UNFL | \
+ TGEC_IMASK_TX_FIFO_OVFL | \
+ TGEC_IMASK_TX_ER | \
+ TGEC_IMASK_RX_FIFO_OVFL | \
+ TGEC_IMASK_RX_ECC_ER | \
+ TGEC_IMASK_RX_JAB_FRM | \
+ TGEC_IMASK_RX_OVRSZ_FRM | \
+ TGEC_IMASK_RX_RUNT_FRM | \
+ TGEC_IMASK_RX_FRAG_FRM | \
+ TGEC_IMASK_RX_LEN_ER | \
+ TGEC_IMASK_RX_CRC_ER | \
+ TGEC_IMASK_RX_ALIGN_ER))
+
+/* Hashtable Control Register (HASHTABLE_CTRL) */
+#define TGEC_HASH_MCAST_SHIFT 23
+#define TGEC_HASH_MCAST_EN 0x00000200
+#define TGEC_HASH_ADR_MSK 0x000001ff
+
+#define DEFAULT_WAN_MODE_ENABLE FALSE
+#define DEFAULT_PROMISCUOUS_MODE_ENABLE FALSE
+#define DEFAULT_PAUSE_FORWARD_ENABLE FALSE
+#define DEFAULT_PAUSE_IGNORE FALSE
+#define DEFAULT_TX_ADDR_INS_ENABLE FALSE
+#define DEFAULT_LOOPBACK_ENABLE FALSE
+#define DEFAULT_CMD_FRAME_ENABLE FALSE
+#define DEFAULT_RX_ERROR_DISCARD FALSE
+#define DEFAULT_SEND_IDLE_ENABLE FALSE
+#define DEFAULT_NO_LENGTH_CHECK_ENABLE TRUE
+#define DEFAULT_LGTH_CHECK_NOSTDR FALSE
+#define DEFAULT_TIME_STAMP_ENABLE FALSE
+#define DEFAULT_TX_IPG_LENGTH 12
+#define DEFAULT_MAX_FRAME_LENGTH 0x600
+#define DEFAULT_PAUSE_QUANT 0xf000
+
+/*
+ * 10G memory map
+ */
+struct tgec_regs {
+ uint32_t tgec_id; /* 0x000 Controller ID */
+ uint32_t reserved001[1]; /* 0x004 */
+ uint32_t command_config; /* 0x008 Control and configuration */
+ uint32_t mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */
+ uint32_t mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */
+ uint32_t maxfrm; /* 0x014 Maximum frame length */
+ uint32_t pause_quant; /* 0x018 Pause quanta */
+ uint32_t rx_fifo_sections; /* 0x01c */
+ uint32_t tx_fifo_sections; /* 0x020 */
+ uint32_t rx_fifo_almost_f_e; /* 0x024 */
+ uint32_t tx_fifo_almost_f_e; /* 0x028 */
+ uint32_t hashtable_ctrl; /* 0x02c Hash table control*/
+ uint32_t mdio_cfg_status; /* 0x030 */
+ uint32_t mdio_command; /* 0x034 */
+ uint32_t mdio_data; /* 0x038 */
+ uint32_t mdio_regaddr; /* 0x03c */
+ uint32_t status; /* 0x040 */
+ uint32_t tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */
+ uint32_t mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */
+ uint32_t mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */
+ uint32_t rx_fifo_ptr_rd; /* 0x050 */
+ uint32_t rx_fifo_ptr_wr; /* 0x054 */
+ uint32_t tx_fifo_ptr_rd; /* 0x058 */
+ uint32_t tx_fifo_ptr_wr; /* 0x05c */
+ uint32_t imask; /* 0x060 Interrupt mask */
+ uint32_t ievent; /* 0x064 Interrupt event */
+ uint32_t udp_port; /* 0x068 Defines a UDP Port number */
+ uint32_t type_1588v2; /* 0x06c Type field for 1588v2 */
+ uint32_t reserved070[4]; /* 0x070 */
+ /*10Ge Statistics Counter */
+ uint32_t tfrm_u; /* 80 aFramesTransmittedOK */
+ uint32_t tfrm_l; /* 84 aFramesTransmittedOK */
+ uint32_t rfrm_u; /* 88 aFramesReceivedOK */
+ uint32_t rfrm_l; /* 8c aFramesReceivedOK */
+ uint32_t rfcs_u; /* 90 aFrameCheckSequenceErrors */
+ uint32_t rfcs_l; /* 94 aFrameCheckSequenceErrors */
+ uint32_t raln_u; /* 98 aAlignmentErrors */
+ uint32_t raln_l; /* 9c aAlignmentErrors */
+ uint32_t txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */
+ uint32_t txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */
+ uint32_t rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */
+ uint32_t rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */
+ uint32_t rlong_u; /* B0 aFrameTooLongErrors */
+ uint32_t rlong_l; /* B4 aFrameTooLongErrors */
+ uint32_t rflr_u; /* B8 aInRangeLengthErrors */
+ uint32_t rflr_l; /* Bc aInRangeLengthErrors */
+ uint32_t tvlan_u; /* C0 VLANTransmittedOK */
+ uint32_t tvlan_l; /* C4 VLANTransmittedOK */
+ uint32_t rvlan_u; /* C8 VLANReceivedOK */
+ uint32_t rvlan_l; /* Cc VLANReceivedOK */
+ uint32_t toct_u; /* D0 ifOutOctets */
+ uint32_t toct_l; /* D4 ifOutOctets */
+ uint32_t roct_u; /* D8 ifInOctets */
+ uint32_t roct_l; /* Dc ifInOctets */
+ uint32_t ruca_u; /* E0 ifInUcastPkts */
+ uint32_t ruca_l; /* E4 ifInUcastPkts */
+ uint32_t rmca_u; /* E8 ifInMulticastPkts */
+ uint32_t rmca_l; /* Ec ifInMulticastPkts */
+ uint32_t rbca_u; /* F0 ifInBroadcastPkts */
+ uint32_t rbca_l; /* F4 ifInBroadcastPkts */
+ uint32_t terr_u; /* F8 ifOutErrors */
+ uint32_t terr_l; /* Fc ifOutErrors */
+ uint32_t reserved100[2]; /* 100-108*/
+ uint32_t tuca_u; /* 108 ifOutUcastPkts */
+ uint32_t tuca_l; /* 10c ifOutUcastPkts */
+ uint32_t tmca_u; /* 110 ifOutMulticastPkts */
+ uint32_t tmca_l; /* 114 ifOutMulticastPkts */
+ uint32_t tbca_u; /* 118 ifOutBroadcastPkts */
+ uint32_t tbca_l; /* 11c ifOutBroadcastPkts */
+ uint32_t rdrp_u; /* 120 etherStatsDropEvents */
+ uint32_t rdrp_l; /* 124 etherStatsDropEvents */
+ uint32_t reoct_u; /* 128 etherStatsOctets */
+ uint32_t reoct_l; /* 12c etherStatsOctets */
+ uint32_t rpkt_u; /* 130 etherStatsPkts */
+ uint32_t rpkt_l; /* 134 etherStatsPkts */
+ uint32_t trund_u; /* 138 etherStatsUndersizePkts */
+ uint32_t trund_l; /* 13c etherStatsUndersizePkts */
+ uint32_t r64_u; /* 140 etherStatsPkts64Octets */
+ uint32_t r64_l; /* 144 etherStatsPkts64Octets */
+ uint32_t r127_u; /* 148 etherStatsPkts65to127Octets */
+ uint32_t r127_l; /* 14c etherStatsPkts65to127Octets */
+ uint32_t r255_u; /* 150 etherStatsPkts128to255Octets */
+ uint32_t r255_l; /* 154 etherStatsPkts128to255Octets */
+ uint32_t r511_u; /* 158 etherStatsPkts256to511Octets */
+ uint32_t r511_l; /* 15c etherStatsPkts256to511Octets */
+ uint32_t r1023_u; /* 160 etherStatsPkts512to1023Octets */
+ uint32_t r1023_l; /* 164 etherStatsPkts512to1023Octets */
+ uint32_t r1518_u; /* 168 etherStatsPkts1024to1518Octets */
+ uint32_t r1518_l; /* 16c etherStatsPkts1024to1518Octets */
+ uint32_t r1519x_u; /* 170 etherStatsPkts1519toX */
+ uint32_t r1519x_l; /* 174 etherStatsPkts1519toX */
+ uint32_t trovr_u; /* 178 etherStatsOversizePkts */
+ uint32_t trovr_l; /* 17c etherStatsOversizePkts */
+ uint32_t trjbr_u; /* 180 etherStatsJabbers */
+ uint32_t trjbr_l; /* 184 etherStatsJabbers */
+ uint32_t trfrg_u; /* 188 etherStatsFragments */
+ uint32_t trfrg_l; /* 18C etherStatsFragments */
+ uint32_t rerr_u; /* 190 ifInErrors */
+ uint32_t rerr_l; /* 194 ifInErrors */
+};
+
+/**
+ * struct tgec_cfg - TGEC configuration
+ *
+ * @rx_error_discard: Receive Erroneous Frame Discard Enable. When set to 1
+ * any frame received with an error is discarded in the
+ * Core and not forwarded to the Client interface.
+ * When set to 0 (Reset value), erroneous Frames are
+ * forwarded to the Client interface with ff_rx_err
+ * asserted.
+ * @pause_ignore: Ignore Pause Frame Quanta. If set to 1 received pause
+ * frames are ignored by the MAC. When set to 0
+ * (Reset value) the transmit process is stopped for the
+ * amount of time specified in the pause quanta received
+ * within a pause frame.
+ * @pause_forward_enable:
+ * Terminate / Forward Pause Frames. If set to 1 pause
+ * frames are forwarded to the user application. When set
+ * to 0 (Reset value) pause frames are terminated and
+ * discarded within the MAC.
+ * @no_length_check_enable:
+ * Payload Length Check Disable. When set to 0
+ * (Reset value), the Core checks the frame's payload
+ * length with the Frame Length/Type field, when set to 1
+ * the payload length check is disabled.
+ * @cmd_frame_enable: Enables reception of all command frames. When set to 1
+ * all Command Frames are accepted, when set to 0
+ * (Reset Value) only Pause Frames are accepted and all
+ * other Command Frames are rejected.
+ * @send_idle_enable: Force Idle Generation. When set to 1, the MAC
+ * permanently sends XGMII Idle sequences even when faults
+ * are received.
+ * @wan_mode_enable: WAN Mode Enable. Sets WAN mode (1) or LAN mode
+ * (0, default) of operation.
+ * @promiscuous_mode_enable:
+ * Enables MAC promiscuous operation. When set to 1, all
+ * frames are received without any MAC address filtering,
+ * when set to 0 (Reset value) Unicast Frames with a
+ * destination address not matching the Core MAC Address
+ * (MAC Address programmed in Registers MAC_ADDR_0 and
+ * MAC_ADDR_1 or the MAC address programmed in Registers
+ * MAC_ADDR_2 and MAC_ADDR_3) are rejected.
+ * @tx_addr_ins_enable: Set Source MAC Address on Transmit. If set to 1 the
+ * MAC overwrites the source MAC address received from the
+ * Client Interface with one of the MAC addresses. If set
+ * to 0 (Reset value), the source MAC address from the
+ * Client Interface is transmitted unmodified to the line.
+ * @loopback_enable: PHY Interface Loopback. When set to 1, the signal
+ * loop_ena is set to '1', when set to 0 (Reset value)
+ * the signal loop_ena is set to 0.
+ * @lgth_check_nostdr: The Core interprets the Length/Type field differently
+ * depending on the value of this Bit
+ * @time_stamp_enable: This bit selects between enabling and disabling the
+ * IEEE 1588 functionality. 1: IEEE 1588 is enabled
+ * 0: IEEE 1588 is disabled
+ * @max_frame_length: Maximum supported received frame length.
+ * The 10GEC MAC supports reception of any frame size up
+ * to 16,352 bytes (0x3FE0). Typical settings are
+ * 0x05EE (1,518 bytes) for standard frames.
+ * Default setting is 0x0600 (1,536 bytes).
+ * Received frames that exceed this stated maximum
+ * are truncated.
+ * @pause_quant: Pause quanta value used with transmitted pause frames.
+ * Each quanta represents a 512 bit-times.
+ * @tx_ipg_length: Transmit Inter-Packet-Gap (IPG) value. A 6-bit value:
+ * Depending on LAN or WAN mode of operation the value has
+ * the following meaning: - LAN Mode: Number of octets in
+ * steps of 4. Valid values are 8, 12, 16, ... 100. DIC is
+ * fully supported (see 10.6.1 page 49) for any setting. A
+ * default of 12 (reset value) must be set to conform to
+ * IEEE802.3ae. Warning: When set to 8, PCS layers may not
+ * be able to perform clock rate compensation. - WAN Mode:
+ * Stretch factor. Valid values are 4..15. The stretch
+ * factor is calculated as (value+1)*8. A default of 12
+ * (reset value) must be set to conform to IEEE 802.3ae
+ * (i.e. 13*8=104). A larger value shrinks the IPG
+ * (increasing bandwidth).
+ *
+ * This structure contains basic TGEC configuration and must be passed to
+ * fman_tgec_init() function. A default set of configuration values can be
+ * obtained by calling fman_tgec_defconfig().
+ */
+struct tgec_cfg {
+ bool rx_error_discard;
+ bool pause_ignore;
+ bool pause_forward_enable;
+ bool no_length_check_enable;
+ bool cmd_frame_enable;
+ bool send_idle_enable;
+ bool wan_mode_enable;
+ bool promiscuous_mode_enable;
+ bool tx_addr_ins_enable;
+ bool loopback_enable;
+ bool lgth_check_nostdr;
+ bool time_stamp_enable;
+ uint16_t max_frame_length;
+ uint16_t pause_quant;
+ uint32_t tx_ipg_length;
+ bool skip_fman11_workaround;
+};
+
+
+void fman_tgec_defconfig(struct tgec_cfg *cfg);
+
+/**
+ * fman_tgec_init() - Init tgec hardware block
+ * @regs: Pointer to tgec register block
+ * @cfg: tgec configuration data
+ * @exceptions_mask: initial exceptions mask
+ *
+ * This function initializes the tgec controller and applies its
+ * basic configuration.
+ *
+ * Returns: 0 if successful, an error code otherwise.
+ */
+
+int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg,
+ uint32_t exception_mask);
+
+void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx);
+
+void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx);
+
+uint32_t fman_tgec_get_revision(struct tgec_regs *regs);
+
+void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *macaddr);
+
+void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val);
+
+/**
+ * fman_tgec_reset_stat() - Completely resets all TGEC HW counters
+ * @regs: Pointer to TGEC register block
+ */
+void fman_tgec_reset_stat(struct tgec_regs *regs);
+
+/**
+ * fman_tgec_get_counter() - Reads TGEC HW counters
+ * @regs: Pointer to TGEC register block
+ * @reg_name: Counter name according to the appropriate enum
+ *
+ * Returns: Required counter value
+ */
+uint64_t fman_tgec_get_counter(struct tgec_regs *regs,
+ enum tgec_counters reg_name);
+
+/**
+ * fman_tgec_set_hash_table() - Sets the Hashtable Control Register
+ * @regs: Pointer to TGEC register block
+ * @value: Value to be written in Hashtable Control Register
+ */
+void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value);
+
+/**
+ * fman_tgec_set_tx_pause_frames() - Sets the Pause Quanta Register
+ * @regs: Pointer to TGEC register block
+ * @pause_time: Pause quanta value used with transmitted pause frames.
+ * Each quanta represents a 512 bit-times
+ */
+void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time);
+
+/**
+ * fman_tgec_set_rx_ignore_pause_frames() - Changes the policy WRT pause frames
+ * @regs: Pointer to TGEC register block
+ * @en: Ignore/Respond to pause frame quanta
+ *
+ * Sets the value of PAUSE_IGNORE field in the COMMAND_CONFIG Register
+ * 0 - MAC stops transmit process for the duration specified
+ * in the Pause frame quanta of a received Pause frame.
+ * 1 - MAC ignores received Pause frames.
+ */
+void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en);
+
+/**
+ * fman_tgec_enable_1588_time_stamp() - change timestamp functionality
+ * @regs: Pointer to TGEC register block
+ * @en: enable/disable timestamp functionality
+ *
+ * Sets the value of EN_TIMESTAMP field in the COMMAND_CONFIG Register
+ * IEEE 1588 timestamp functionality control:
+ * 0 disabled, 1 enabled
+ */
+
+void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en);
+
+uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask);
+
+void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask);
+
+uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs);
+
+/**
+ * fman_tgec_add_addr_in_paddr() - Sets additional exact match MAC address
+ * @regs: Pointer to TGEC register block
+ * @addr_ptr: Pointer to 6-byte array containing the MAC address
+ *
+ * Sets the additional station MAC address
+ */
+void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *addr_ptr);
+
+void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs);
+
+void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask);
+
+void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask);
+
+void fman_tgec_reset_filter_table(struct tgec_regs *regs);
+
+void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc);
+
+
+/**
+ * fman_tgec_get_max_frame_len() - Returns the maximum frame length value
+ * @regs: Pointer to TGEC register block
+ */
+uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs);
+
+/**
+ * fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007() - Initialize the
+ * main tgec configuration parameters
+ * @regs: Pointer to TGEC register block
+ *
+ * TODO
+ */
+void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs
+ *regs);
+
+
+#endif /* __FSL_FMAN_TGEC_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h
new file mode 100644
index 000000000000..0346cf608422
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File dpaa_integration_ext.h
+
+ @Description T4240 FM external definitions and structures.
+*//***************************************************************************/
+#ifndef __DPAA_INTEGRATION_EXT_H
+#define __DPAA_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+
+
+#define DPAA_VERSION 11
+
+/**************************************************************************//**
+ @Description DPAA SW Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_SWPORTAL0 = 0,
+ e_DPAA_SWPORTAL1,
+ e_DPAA_SWPORTAL2,
+ e_DPAA_SWPORTAL3,
+ e_DPAA_SWPORTAL4,
+ e_DPAA_SWPORTAL5,
+ e_DPAA_SWPORTAL6,
+ e_DPAA_SWPORTAL7,
+ e_DPAA_SWPORTAL8,
+ e_DPAA_SWPORTAL9,
+ e_DPAA_SWPORTAL10,
+ e_DPAA_SWPORTAL11,
+ e_DPAA_SWPORTAL12,
+ e_DPAA_SWPORTAL13,
+ e_DPAA_SWPORTAL14,
+ e_DPAA_SWPORTAL15,
+ e_DPAA_SWPORTAL16,
+ e_DPAA_SWPORTAL17,
+ e_DPAA_SWPORTAL18,
+ e_DPAA_SWPORTAL19,
+ e_DPAA_SWPORTAL20,
+ e_DPAA_SWPORTAL21,
+ e_DPAA_SWPORTAL22,
+ e_DPAA_SWPORTAL23,
+ e_DPAA_SWPORTAL24,
+ e_DPAA_SWPORTAL_DUMMY_LAST
+} e_DpaaSwPortal;
+
+/**************************************************************************//**
+ @Description DPAA Direct Connect Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_DCPORTAL0 = 0,
+ e_DPAA_DCPORTAL1,
+ e_DPAA_DCPORTAL2,
+ e_DPAA_DCPORTAL_DUMMY_LAST
+} e_DpaaDcPortal;
+
+#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST
+#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST
+
+/*****************************************************************************
+ QMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */
+#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */
+#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */
+#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE)
+ /**< FQIDs range - 24 bits */
+
+/**************************************************************************//**
+ @Description Work Queue Channel assignments in QMan.
+*//***************************************************************************/
+typedef enum
+{
+ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */
+ e_QM_FQ_CHANNEL_SWPORTAL1,
+ e_QM_FQ_CHANNEL_SWPORTAL2,
+ e_QM_FQ_CHANNEL_SWPORTAL3,
+ e_QM_FQ_CHANNEL_SWPORTAL4,
+ e_QM_FQ_CHANNEL_SWPORTAL5,
+ e_QM_FQ_CHANNEL_SWPORTAL6,
+ e_QM_FQ_CHANNEL_SWPORTAL7,
+ e_QM_FQ_CHANNEL_SWPORTAL8,
+ e_QM_FQ_CHANNEL_SWPORTAL9,
+ e_QM_FQ_CHANNEL_SWPORTAL10,
+ e_QM_FQ_CHANNEL_SWPORTAL11,
+ e_QM_FQ_CHANNEL_SWPORTAL12,
+ e_QM_FQ_CHANNEL_SWPORTAL13,
+ e_QM_FQ_CHANNEL_SWPORTAL14,
+ e_QM_FQ_CHANNEL_SWPORTAL15,
+ e_QM_FQ_CHANNEL_SWPORTAL16,
+ e_QM_FQ_CHANNEL_SWPORTAL17,
+ e_QM_FQ_CHANNEL_SWPORTAL18,
+ e_QM_FQ_CHANNEL_SWPORTAL19,
+ e_QM_FQ_CHANNEL_SWPORTAL20,
+ e_QM_FQ_CHANNEL_SWPORTAL21,
+ e_QM_FQ_CHANNEL_SWPORTAL22,
+ e_QM_FQ_CHANNEL_SWPORTAL23,
+ e_QM_FQ_CHANNEL_SWPORTAL24,
+
+ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */
+ e_QM_FQ_CHANNEL_POOL2,
+ e_QM_FQ_CHANNEL_POOL3,
+ e_QM_FQ_CHANNEL_POOL4,
+ e_QM_FQ_CHANNEL_POOL5,
+ e_QM_FQ_CHANNEL_POOL6,
+ e_QM_FQ_CHANNEL_POOL7,
+ e_QM_FQ_CHANNEL_POOL8,
+ e_QM_FQ_CHANNEL_POOL9,
+ e_QM_FQ_CHANNEL_POOL10,
+ e_QM_FQ_CHANNEL_POOL11,
+ e_QM_FQ_CHANNEL_POOL12,
+ e_QM_FQ_CHANNEL_POOL13,
+ e_QM_FQ_CHANNEL_POOL14,
+ e_QM_FQ_CHANNEL_POOL15,
+
+ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0:
+ connected to FMan 0; assigned in incrementing order to
+ each sub-portal (SP) in the portal */
+ e_QM_FQ_CHANNEL_FMAN0_SP1,
+ e_QM_FQ_CHANNEL_FMAN0_SP2,
+ e_QM_FQ_CHANNEL_FMAN0_SP3,
+ e_QM_FQ_CHANNEL_FMAN0_SP4,
+ e_QM_FQ_CHANNEL_FMAN0_SP5,
+ e_QM_FQ_CHANNEL_FMAN0_SP6,
+ e_QM_FQ_CHANNEL_FMAN0_SP7,
+ e_QM_FQ_CHANNEL_FMAN0_SP8,
+ e_QM_FQ_CHANNEL_FMAN0_SP9,
+ e_QM_FQ_CHANNEL_FMAN0_SP10,
+ e_QM_FQ_CHANNEL_FMAN0_SP11,
+ e_QM_FQ_CHANNEL_FMAN0_SP12,
+ e_QM_FQ_CHANNEL_FMAN0_SP13,
+ e_QM_FQ_CHANNEL_FMAN0_SP14,
+ e_QM_FQ_CHANNEL_FMAN0_SP15,
+
+ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
+ e_QM_FQ_CHANNEL_RMAN_SP1,
+
+ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2:
+ connected to SEC */
+} e_QmFQChannel;
+
+/*****************************************************************************
+ BMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */
+
+/*****************************************************************************
+ SEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SEC_NUM_OF_DECOS 3
+#define SEC_ALL_DECOS_MASK 0x00000003
+
+
+/*****************************************************************************
+ FM INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define INTG_MAX_NUM_OF_FM 2
+/* Ports defines */
+#define FM_MAX_NUM_OF_1G_MACS 6
+#define FM_MAX_NUM_OF_10G_MACS 2
+#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
+#define FM_MAX_NUM_OF_OH_PORTS 6
+
+#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
+
+#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */
+#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */
+#define FM_MAX_NUM_OF_SUB_PORTALS 16
+#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0
+
+#define FM_VSP_MAX_NUM_OF_ENTRIES 64
+#define FM_MAX_NUM_OF_PFC_PRIORITIES 8
+
+/* RAMs defines */
+#define FM_MURAM_SIZE (384 * KILOBYTE)
+#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE)
+#define FM_NUM_OF_CTRL 4
+
+/* PCD defines */
+#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */
+#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */
+#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */
+#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */
+#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */
+
+/* RTC defines */
+#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */
+#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */
+#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */
+
+/* QMI defines */
+#define QMI_MAX_NUM_OF_TNUMS 64
+#define QMI_DEF_TNUMS_THRESH 32
+/* FPM defines */
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
+
+/* DMA defines */
+#define DMA_THRESH_MAX_COMMQ 83
+#define DMA_THRESH_MAX_BUF 127
+
+/* BMI defines */
+#define BMI_MAX_NUM_OF_TASKS 128
+#define BMI_MAX_NUM_OF_DMAS 84
+
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define PORT_MAX_WEIGHT 16
+
+#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE
+
+/* Unique T4240 */
+#define FM_OP_OPEN_DMA_MIN_LIMIT
+#define FM_NO_RESTRICT_ON_ACCESS_RSRC
+#define FM_NO_OP_OBSERVED_POOLS
+#define FM_FRAME_END_PARAMS_FOR_OP
+#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
+#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
+
+#define FM_NO_GUARANTEED_RESET_VALUES
+
+/* FM errata */
+#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
+#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
+#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
+#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
+
+#define FM_BCB_ERRATA_BMI_SW001
+#define FM_LEN_CHECK_ERRATA_FMAN_SW002
+#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
+#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
+
+/*****************************************************************************
+ RMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */
+#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */
+
+/* RMan erratas */
+#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
+
+/*****************************************************************************
+ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define NUM_OF_RX_SC 16
+#define NUM_OF_TX_SC 16
+
+#define NUM_OF_SA_PER_RX_SC 2
+#define NUM_OF_SA_PER_TX_SC 2
+
+#endif /* __DPAA_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h
new file mode 100644
index 000000000000..0d62dd151b0e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+
+ @File part_ext.h
+
+ @Description Definitions for the part (integration) module.
+*//***************************************************************************/
+
+#ifndef __PART_EXT_H
+#define __PART_EXT_H
+
+#include "std_ext.h"
+#include "part_integration_ext.h"
+
+#if !(defined(P1023) || \
+ defined(P2041) || \
+ defined(P3041) || \
+ defined(P4080) || \
+ defined(P5020) || \
+ defined(P5040) || \
+ defined(B4860) || \
+ defined(T4240))
+#error "unable to proceed without chip-definition"
+#endif
+
+
+/**************************************************************************//*
+ @Description Part data structure - must be contained in any integration
+ data structure.
+*//***************************************************************************/
+typedef struct t_Part
+{
+ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
+ /**< Returns the address of the module's memory map base. */
+ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
+ /**< Returns the module's ID according to its memory map base. */
+} t_Part;
+
+
+#endif /* __PART_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h
new file mode 100644
index 000000000000..3254c7662cb4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File part_integration_ext.h
+
+ @Description T4240 external definitions and structures.
+*//***************************************************************************/
+#ifndef __PART_INTEGRATION_EXT_H
+#define __PART_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+#include "ddr_std_ext.h"
+#include "enet_ext.h"
+#include "dpaa_integration_ext.h"
+
+
+/**************************************************************************//**
+ @Group T4240_chip_id T4240 Application Programming Interface
+
+ @Description T4240 Chip functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#define CORE_E6500
+
+#define INTG_MAX_NUM_OF_CORES 24
+
+
+/**************************************************************************//**
+ @Description Module types.
+*//***************************************************************************/
+typedef enum e_ModuleId
+{
+ e_MODULE_ID_DUART_1 = 0,
+ e_MODULE_ID_DUART_2,
+ e_MODULE_ID_DUART_3,
+ e_MODULE_ID_DUART_4,
+ e_MODULE_ID_LAW,
+ e_MODULE_ID_IFC,
+ e_MODULE_ID_PAMU,
+ e_MODULE_ID_QM, /**< Queue manager module */
+ e_MODULE_ID_BM, /**< Buffer manager module */
+ e_MODULE_ID_QM_CE_PORTAL_0,
+ e_MODULE_ID_QM_CI_PORTAL_0,
+ e_MODULE_ID_QM_CE_PORTAL_1,
+ e_MODULE_ID_QM_CI_PORTAL_1,
+ e_MODULE_ID_QM_CE_PORTAL_2,
+ e_MODULE_ID_QM_CI_PORTAL_2,
+ e_MODULE_ID_QM_CE_PORTAL_3,
+ e_MODULE_ID_QM_CI_PORTAL_3,
+ e_MODULE_ID_QM_CE_PORTAL_4,
+ e_MODULE_ID_QM_CI_PORTAL_4,
+ e_MODULE_ID_QM_CE_PORTAL_5,
+ e_MODULE_ID_QM_CI_PORTAL_5,
+ e_MODULE_ID_QM_CE_PORTAL_6,
+ e_MODULE_ID_QM_CI_PORTAL_6,
+ e_MODULE_ID_QM_CE_PORTAL_7,
+ e_MODULE_ID_QM_CI_PORTAL_7,
+ e_MODULE_ID_QM_CE_PORTAL_8,
+ e_MODULE_ID_QM_CI_PORTAL_8,
+ e_MODULE_ID_QM_CE_PORTAL_9,
+ e_MODULE_ID_QM_CI_PORTAL_9,
+ e_MODULE_ID_BM_CE_PORTAL_0,
+ e_MODULE_ID_BM_CI_PORTAL_0,
+ e_MODULE_ID_BM_CE_PORTAL_1,
+ e_MODULE_ID_BM_CI_PORTAL_1,
+ e_MODULE_ID_BM_CE_PORTAL_2,
+ e_MODULE_ID_BM_CI_PORTAL_2,
+ e_MODULE_ID_BM_CE_PORTAL_3,
+ e_MODULE_ID_BM_CI_PORTAL_3,
+ e_MODULE_ID_BM_CE_PORTAL_4,
+ e_MODULE_ID_BM_CI_PORTAL_4,
+ e_MODULE_ID_BM_CE_PORTAL_5,
+ e_MODULE_ID_BM_CI_PORTAL_5,
+ e_MODULE_ID_BM_CE_PORTAL_6,
+ e_MODULE_ID_BM_CI_PORTAL_6,
+ e_MODULE_ID_BM_CE_PORTAL_7,
+ e_MODULE_ID_BM_CI_PORTAL_7,
+ e_MODULE_ID_BM_CE_PORTAL_8,
+ e_MODULE_ID_BM_CI_PORTAL_8,
+ e_MODULE_ID_BM_CE_PORTAL_9,
+ e_MODULE_ID_BM_CI_PORTAL_9,
+ e_MODULE_ID_FM, /**< Frame manager module */
+ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM_PARSER, /**< FM parser block */
+ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM_KG, /**< FM Keygen */
+ e_MODULE_ID_FM_DMA, /**< FM DMA */
+ e_MODULE_ID_FM_FPM, /**< FM FPM */
+ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */
+ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */
+ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */
+ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */
+ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */
+ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */
+ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */
+ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */
+ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */
+
+ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */
+ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */
+ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */
+ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */
+ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */
+ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */
+ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */
+ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */
+ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */
+ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */
+ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */
+ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */
+
+ e_MODULE_ID_PIC, /**< PIC */
+ e_MODULE_ID_GPIO, /**< GPIO */
+ e_MODULE_ID_SERDES, /**< SERDES */
+ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */
+ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */
+
+ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */
+
+ e_MODULE_ID_DUMMY_LAST
+} e_ModuleId;
+
+#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST
+
+#if 0 /* using unified values */
+/*****************************************************************************
+ INTEGRATION-SPECIFIC MODULE CODES
+******************************************************************************/
+#define MODULE_UNKNOWN 0x00000000
+#define MODULE_MEM 0x00010000
+#define MODULE_MM 0x00020000
+#define MODULE_CORE 0x00030000
+#define MODULE_T4240 0x00040000
+#define MODULE_T4240_PLATFORM 0x00050000
+#define MODULE_PM 0x00060000
+#define MODULE_MMU 0x00070000
+#define MODULE_PIC 0x00080000
+#define MODULE_CPC 0x00090000
+#define MODULE_DUART 0x000a0000
+#define MODULE_SERDES 0x000b0000
+#define MODULE_PIO 0x000c0000
+#define MODULE_QM 0x000d0000
+#define MODULE_BM 0x000e0000
+#define MODULE_SEC 0x000f0000
+#define MODULE_LAW 0x00100000
+#define MODULE_LBC 0x00110000
+#define MODULE_PAMU 0x00120000
+#define MODULE_FM 0x00130000
+#define MODULE_FM_MURAM 0x00140000
+#define MODULE_FM_PCD 0x00150000
+#define MODULE_FM_RTC 0x00160000
+#define MODULE_FM_MAC 0x00170000
+#define MODULE_FM_PORT 0x00180000
+#define MODULE_FM_SP 0x00190000
+#define MODULE_DPA_PORT 0x001a0000
+#define MODULE_MII 0x001b0000
+#define MODULE_I2C 0x001c0000
+#define MODULE_DMA 0x001d0000
+#define MODULE_DDR 0x001e0000
+#define MODULE_ESPI 0x001f0000
+#define MODULE_DPAA_IPSEC 0x00200000
+#endif /* using unified values */
+
+/*****************************************************************************
+ PAMU INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define PAMU_NUM_OF_PARTITIONS 4
+
+/*****************************************************************************
+ LAW INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define LAW_NUM_OF_WINDOWS 32
+#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4 Kbytes */
+#define LAW_MAX_WINDOW_SIZE 0x0000010000000000LL /**< 1 Tbytes for 40-bit address space */
+
+
+/*****************************************************************************
+ LBC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+/**************************************************************************//**
+ @Group lbc_exception_grp LBC Exception Unit
+
+ @Description LBC Exception unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Anchor lbc_exbm
+
+ @Collection LBC Errors Bit Mask
+
+ These errors are reported through the exceptions callback..
+ The values can be or'ed in any combination in the errors mask
+ parameter of the errors report structure.
+
+ These errors can also be passed as a bit-mask to
+ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
+ for enabling or disabling error checking.
+ @{
+*//***************************************************************************/
+#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */
+#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */
+#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */
+#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */
+
+#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
+ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
+ /**< All possible errors */
+/* @} */
+/** @} */ /* end of lbc_exception_grp group */
+
+#define LBC_INCORRECT_ERROR_REPORT_ERRATA
+
+#define LBC_NUM_OF_BANKS 8
+#define LBC_MAX_CS_SIZE 0x0000000100000000LL /* Up to 4G memory block size */
+#define LBC_PARITY_SUPPORT
+#define LBC_ADDRESS_HOLD_TIME_CTRL
+#define LBC_HIGH_CLK_DIVIDERS
+#define LBC_FCM_AVAILABLE
+
+/*****************************************************************************
+ GPIO INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define GPIO_PORT_OFFSET_0x1000
+
+#define GPIO_NUM_OF_PORTS 3 /**< Number of ports in GPIO module;
+ Each port contains up to 32 I/O pins. */
+
+#define GPIO_VALID_PIN_MASKS \
+ { /* Port A */ 0xFFFFFFFF, \
+ /* Port B */ 0xFFFFFFFF, \
+ /* Port C */ 0xFFFFFFFF }
+
+#define GPIO_VALID_INTR_MASKS \
+ { /* Port A */ 0xFFFFFFFF, \
+ /* Port B */ 0xFFFFFFFF, \
+ /* Port C */ 0xFFFFFFFF }
+
+
+
+#endif /* __PART_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h
new file mode 100644
index 000000000000..f7f8eb07f1af
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File dpaa_integration_ext.h
+
+ @Description T4240 FM external definitions and structures.
+*//***************************************************************************/
+#ifndef __DPAA_INTEGRATION_EXT_H
+#define __DPAA_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+
+
+#define DPAA_VERSION 11
+
+/**************************************************************************//**
+ @Description DPAA SW Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_SWPORTAL0 = 0,
+ e_DPAA_SWPORTAL1,
+ e_DPAA_SWPORTAL2,
+ e_DPAA_SWPORTAL3,
+ e_DPAA_SWPORTAL4,
+ e_DPAA_SWPORTAL5,
+ e_DPAA_SWPORTAL6,
+ e_DPAA_SWPORTAL7,
+ e_DPAA_SWPORTAL8,
+ e_DPAA_SWPORTAL9,
+ e_DPAA_SWPORTAL10,
+ e_DPAA_SWPORTAL11,
+ e_DPAA_SWPORTAL12,
+ e_DPAA_SWPORTAL13,
+ e_DPAA_SWPORTAL14,
+ e_DPAA_SWPORTAL15,
+ e_DPAA_SWPORTAL16,
+ e_DPAA_SWPORTAL17,
+ e_DPAA_SWPORTAL18,
+ e_DPAA_SWPORTAL19,
+ e_DPAA_SWPORTAL20,
+ e_DPAA_SWPORTAL21,
+ e_DPAA_SWPORTAL22,
+ e_DPAA_SWPORTAL23,
+ e_DPAA_SWPORTAL24,
+ e_DPAA_SWPORTAL_DUMMY_LAST
+} e_DpaaSwPortal;
+
+/**************************************************************************//**
+ @Description DPAA Direct Connect Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_DCPORTAL0 = 0,
+ e_DPAA_DCPORTAL1,
+ e_DPAA_DCPORTAL2,
+ e_DPAA_DCPORTAL_DUMMY_LAST
+} e_DpaaDcPortal;
+
+#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST
+#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST
+
+/*****************************************************************************
+ QMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */
+#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */
+#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */
+#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE)
+ /**< FQIDs range - 24 bits */
+
+/**************************************************************************//**
+ @Description Work Queue Channel assignments in QMan.
+*//***************************************************************************/
+typedef enum
+{
+ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */
+ e_QM_FQ_CHANNEL_SWPORTAL1,
+ e_QM_FQ_CHANNEL_SWPORTAL2,
+ e_QM_FQ_CHANNEL_SWPORTAL3,
+ e_QM_FQ_CHANNEL_SWPORTAL4,
+ e_QM_FQ_CHANNEL_SWPORTAL5,
+ e_QM_FQ_CHANNEL_SWPORTAL6,
+ e_QM_FQ_CHANNEL_SWPORTAL7,
+ e_QM_FQ_CHANNEL_SWPORTAL8,
+ e_QM_FQ_CHANNEL_SWPORTAL9,
+ e_QM_FQ_CHANNEL_SWPORTAL10,
+ e_QM_FQ_CHANNEL_SWPORTAL11,
+ e_QM_FQ_CHANNEL_SWPORTAL12,
+ e_QM_FQ_CHANNEL_SWPORTAL13,
+ e_QM_FQ_CHANNEL_SWPORTAL14,
+ e_QM_FQ_CHANNEL_SWPORTAL15,
+ e_QM_FQ_CHANNEL_SWPORTAL16,
+ e_QM_FQ_CHANNEL_SWPORTAL17,
+ e_QM_FQ_CHANNEL_SWPORTAL18,
+ e_QM_FQ_CHANNEL_SWPORTAL19,
+ e_QM_FQ_CHANNEL_SWPORTAL20,
+ e_QM_FQ_CHANNEL_SWPORTAL21,
+ e_QM_FQ_CHANNEL_SWPORTAL22,
+ e_QM_FQ_CHANNEL_SWPORTAL23,
+ e_QM_FQ_CHANNEL_SWPORTAL24,
+
+ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */
+ e_QM_FQ_CHANNEL_POOL2,
+ e_QM_FQ_CHANNEL_POOL3,
+ e_QM_FQ_CHANNEL_POOL4,
+ e_QM_FQ_CHANNEL_POOL5,
+ e_QM_FQ_CHANNEL_POOL6,
+ e_QM_FQ_CHANNEL_POOL7,
+ e_QM_FQ_CHANNEL_POOL8,
+ e_QM_FQ_CHANNEL_POOL9,
+ e_QM_FQ_CHANNEL_POOL10,
+ e_QM_FQ_CHANNEL_POOL11,
+ e_QM_FQ_CHANNEL_POOL12,
+ e_QM_FQ_CHANNEL_POOL13,
+ e_QM_FQ_CHANNEL_POOL14,
+ e_QM_FQ_CHANNEL_POOL15,
+
+ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0:
+ connected to FMan 0; assigned in incrementing order to
+ each sub-portal (SP) in the portal */
+ e_QM_FQ_CHANNEL_FMAN0_SP1,
+ e_QM_FQ_CHANNEL_FMAN0_SP2,
+ e_QM_FQ_CHANNEL_FMAN0_SP3,
+ e_QM_FQ_CHANNEL_FMAN0_SP4,
+ e_QM_FQ_CHANNEL_FMAN0_SP5,
+ e_QM_FQ_CHANNEL_FMAN0_SP6,
+ e_QM_FQ_CHANNEL_FMAN0_SP7,
+ e_QM_FQ_CHANNEL_FMAN0_SP8,
+ e_QM_FQ_CHANNEL_FMAN0_SP9,
+ e_QM_FQ_CHANNEL_FMAN0_SP10,
+ e_QM_FQ_CHANNEL_FMAN0_SP11,
+ e_QM_FQ_CHANNEL_FMAN0_SP12,
+ e_QM_FQ_CHANNEL_FMAN0_SP13,
+ e_QM_FQ_CHANNEL_FMAN0_SP14,
+ e_QM_FQ_CHANNEL_FMAN0_SP15,
+
+ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
+ e_QM_FQ_CHANNEL_RMAN_SP1,
+
+ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2:
+ connected to SEC */
+} e_QmFQChannel;
+
+/*****************************************************************************
+ BMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */
+
+/*****************************************************************************
+ SEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SEC_NUM_OF_DECOS 3
+#define SEC_ALL_DECOS_MASK 0x00000003
+
+
+/*****************************************************************************
+ FM INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define INTG_MAX_NUM_OF_FM 1
+/* Ports defines */
+#define FM_MAX_NUM_OF_1G_MACS 5
+#define FM_MAX_NUM_OF_10G_MACS 1
+#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
+#define FM_MAX_NUM_OF_OH_PORTS 4
+
+#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
+
+#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#define FM_MAX_NUM_OF_MACSECS 1 /* Should be updated */
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */
+#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */
+#define FM_MAX_NUM_OF_SUB_PORTALS 16
+#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0
+
+#define FM_VSP_MAX_NUM_OF_ENTRIES 32
+#define FM_MAX_NUM_OF_PFC_PRIORITIES 8
+
+/* RAMs defines */
+#define FM_MURAM_SIZE (192 * KILOBYTE)
+#define FM_IRAM_SIZE(major, minor) \
+ (((major == 6) && ((minor == 4) )) ? (64 * KILOBYTE) : (32 * KILOBYTE))
+#define FM_NUM_OF_CTRL 2
+
+/* PCD defines */
+#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */
+#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */
+#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */
+#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */
+#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */
+
+/* RTC defines */
+#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */
+#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */
+#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */
+
+/* QMI defines */
+#define QMI_MAX_NUM_OF_TNUMS 64
+#define QMI_DEF_TNUMS_THRESH 32
+/* FPM defines */
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
+
+/* DMA defines */
+#define DMA_THRESH_MAX_COMMQ 83
+#define DMA_THRESH_MAX_BUF 127
+
+/* BMI defines */
+#define BMI_MAX_NUM_OF_TASKS 64
+#define BMI_MAX_NUM_OF_DMAS 32
+
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define PORT_MAX_WEIGHT 16
+
+#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE
+
+/* Unique T4240 */
+#define FM_OP_OPEN_DMA_MIN_LIMIT
+#define FM_NO_RESTRICT_ON_ACCESS_RSRC
+#define FM_NO_OP_OBSERVED_POOLS
+#define FM_FRAME_END_PARAMS_FOR_OP
+#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
+#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
+
+#define FM_NO_GUARANTEED_RESET_VALUES
+
+/* FM errata */
+#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
+#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
+#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
+
+#define FM_BCB_ERRATA_BMI_SW001
+#define FM_LEN_CHECK_ERRATA_FMAN_SW002
+#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
+#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
+
+/*****************************************************************************
+ RMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */
+#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */
+
+/* RMan erratas */
+#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
+
+/*****************************************************************************
+ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define NUM_OF_RX_SC 16
+#define NUM_OF_TX_SC 16
+
+#define NUM_OF_SA_PER_RX_SC 2
+#define NUM_OF_SA_PER_TX_SC 2
+
+#endif /* __DPAA_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h
new file mode 100644
index 000000000000..ba9732ee25bf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+
+ @File part_ext.h
+
+ @Description Definitions for the part (integration) module.
+*//***************************************************************************/
+
+#ifndef __PART_EXT_H
+#define __PART_EXT_H
+
+#include "std_ext.h"
+#include "part_integration_ext.h"
+
+/**************************************************************************//*
+ @Description Part data structure - must be contained in any integration
+ data structure.
+*//***************************************************************************/
+typedef struct t_Part
+{
+ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
+ /**< Returns the address of the module's memory map base. */
+ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
+ /**< Returns the module's ID according to its memory map base. */
+} t_Part;
+
+
+#endif /* __PART_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h
new file mode 100644
index 000000000000..3254c7662cb4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File part_integration_ext.h
+
+ @Description T4240 external definitions and structures.
+*//***************************************************************************/
+#ifndef __PART_INTEGRATION_EXT_H
+#define __PART_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+#include "ddr_std_ext.h"
+#include "enet_ext.h"
+#include "dpaa_integration_ext.h"
+
+
+/**************************************************************************//**
+ @Group T4240_chip_id T4240 Application Programming Interface
+
+ @Description T4240 Chip functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#define CORE_E6500
+
+#define INTG_MAX_NUM_OF_CORES 24
+
+
+/**************************************************************************//**
+ @Description Module types.
+*//***************************************************************************/
+typedef enum e_ModuleId
+{
+ e_MODULE_ID_DUART_1 = 0,
+ e_MODULE_ID_DUART_2,
+ e_MODULE_ID_DUART_3,
+ e_MODULE_ID_DUART_4,
+ e_MODULE_ID_LAW,
+ e_MODULE_ID_IFC,
+ e_MODULE_ID_PAMU,
+ e_MODULE_ID_QM, /**< Queue manager module */
+ e_MODULE_ID_BM, /**< Buffer manager module */
+ e_MODULE_ID_QM_CE_PORTAL_0,
+ e_MODULE_ID_QM_CI_PORTAL_0,
+ e_MODULE_ID_QM_CE_PORTAL_1,
+ e_MODULE_ID_QM_CI_PORTAL_1,
+ e_MODULE_ID_QM_CE_PORTAL_2,
+ e_MODULE_ID_QM_CI_PORTAL_2,
+ e_MODULE_ID_QM_CE_PORTAL_3,
+ e_MODULE_ID_QM_CI_PORTAL_3,
+ e_MODULE_ID_QM_CE_PORTAL_4,
+ e_MODULE_ID_QM_CI_PORTAL_4,
+ e_MODULE_ID_QM_CE_PORTAL_5,
+ e_MODULE_ID_QM_CI_PORTAL_5,
+ e_MODULE_ID_QM_CE_PORTAL_6,
+ e_MODULE_ID_QM_CI_PORTAL_6,
+ e_MODULE_ID_QM_CE_PORTAL_7,
+ e_MODULE_ID_QM_CI_PORTAL_7,
+ e_MODULE_ID_QM_CE_PORTAL_8,
+ e_MODULE_ID_QM_CI_PORTAL_8,
+ e_MODULE_ID_QM_CE_PORTAL_9,
+ e_MODULE_ID_QM_CI_PORTAL_9,
+ e_MODULE_ID_BM_CE_PORTAL_0,
+ e_MODULE_ID_BM_CI_PORTAL_0,
+ e_MODULE_ID_BM_CE_PORTAL_1,
+ e_MODULE_ID_BM_CI_PORTAL_1,
+ e_MODULE_ID_BM_CE_PORTAL_2,
+ e_MODULE_ID_BM_CI_PORTAL_2,
+ e_MODULE_ID_BM_CE_PORTAL_3,
+ e_MODULE_ID_BM_CI_PORTAL_3,
+ e_MODULE_ID_BM_CE_PORTAL_4,
+ e_MODULE_ID_BM_CI_PORTAL_4,
+ e_MODULE_ID_BM_CE_PORTAL_5,
+ e_MODULE_ID_BM_CI_PORTAL_5,
+ e_MODULE_ID_BM_CE_PORTAL_6,
+ e_MODULE_ID_BM_CI_PORTAL_6,
+ e_MODULE_ID_BM_CE_PORTAL_7,
+ e_MODULE_ID_BM_CI_PORTAL_7,
+ e_MODULE_ID_BM_CE_PORTAL_8,
+ e_MODULE_ID_BM_CI_PORTAL_8,
+ e_MODULE_ID_BM_CE_PORTAL_9,
+ e_MODULE_ID_BM_CI_PORTAL_9,
+ e_MODULE_ID_FM, /**< Frame manager module */
+ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM_PARSER, /**< FM parser block */
+ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM_KG, /**< FM Keygen */
+ e_MODULE_ID_FM_DMA, /**< FM DMA */
+ e_MODULE_ID_FM_FPM, /**< FM FPM */
+ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */
+ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */
+ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */
+ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */
+ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */
+ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */
+ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */
+ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */
+ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */
+
+ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */
+ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */
+ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */
+ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */
+ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */
+ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */
+ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */
+ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */
+ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */
+ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */
+ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */
+ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */
+
+ e_MODULE_ID_PIC, /**< PIC */
+ e_MODULE_ID_GPIO, /**< GPIO */
+ e_MODULE_ID_SERDES, /**< SERDES */
+ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */
+ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */
+
+ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */
+
+ e_MODULE_ID_DUMMY_LAST
+} e_ModuleId;
+
+#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST
+
+#if 0 /* using unified values */
+/*****************************************************************************
+ INTEGRATION-SPECIFIC MODULE CODES
+******************************************************************************/
+#define MODULE_UNKNOWN 0x00000000
+#define MODULE_MEM 0x00010000
+#define MODULE_MM 0x00020000
+#define MODULE_CORE 0x00030000
+#define MODULE_T4240 0x00040000
+#define MODULE_T4240_PLATFORM 0x00050000
+#define MODULE_PM 0x00060000
+#define MODULE_MMU 0x00070000
+#define MODULE_PIC 0x00080000
+#define MODULE_CPC 0x00090000
+#define MODULE_DUART 0x000a0000
+#define MODULE_SERDES 0x000b0000
+#define MODULE_PIO 0x000c0000
+#define MODULE_QM 0x000d0000
+#define MODULE_BM 0x000e0000
+#define MODULE_SEC 0x000f0000
+#define MODULE_LAW 0x00100000
+#define MODULE_LBC 0x00110000
+#define MODULE_PAMU 0x00120000
+#define MODULE_FM 0x00130000
+#define MODULE_FM_MURAM 0x00140000
+#define MODULE_FM_PCD 0x00150000
+#define MODULE_FM_RTC 0x00160000
+#define MODULE_FM_MAC 0x00170000
+#define MODULE_FM_PORT 0x00180000
+#define MODULE_FM_SP 0x00190000
+#define MODULE_DPA_PORT 0x001a0000
+#define MODULE_MII 0x001b0000
+#define MODULE_I2C 0x001c0000
+#define MODULE_DMA 0x001d0000
+#define MODULE_DDR 0x001e0000
+#define MODULE_ESPI 0x001f0000
+#define MODULE_DPAA_IPSEC 0x00200000
+#endif /* using unified values */
+
+/*****************************************************************************
+ PAMU INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define PAMU_NUM_OF_PARTITIONS 4
+
+/*****************************************************************************
+ LAW INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define LAW_NUM_OF_WINDOWS 32
+#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4 Kbytes */
+#define LAW_MAX_WINDOW_SIZE 0x0000010000000000LL /**< 1 Tbytes for 40-bit address space */
+
+
+/*****************************************************************************
+ LBC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+/**************************************************************************//**
+ @Group lbc_exception_grp LBC Exception Unit
+
+ @Description LBC Exception unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Anchor lbc_exbm
+
+ @Collection LBC Errors Bit Mask
+
+ These errors are reported through the exceptions callback..
+ The values can be or'ed in any combination in the errors mask
+ parameter of the errors report structure.
+
+ These errors can also be passed as a bit-mask to
+ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
+ for enabling or disabling error checking.
+ @{
+*//***************************************************************************/
+#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */
+#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */
+#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */
+#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */
+
+#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
+ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
+ /**< All possible errors */
+/* @} */
+/** @} */ /* end of lbc_exception_grp group */
+
+#define LBC_INCORRECT_ERROR_REPORT_ERRATA
+
+#define LBC_NUM_OF_BANKS 8
+#define LBC_MAX_CS_SIZE 0x0000000100000000LL /* Up to 4G memory block size */
+#define LBC_PARITY_SUPPORT
+#define LBC_ADDRESS_HOLD_TIME_CTRL
+#define LBC_HIGH_CLK_DIVIDERS
+#define LBC_FCM_AVAILABLE
+
+/*****************************************************************************
+ GPIO INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define GPIO_PORT_OFFSET_0x1000
+
+#define GPIO_NUM_OF_PORTS 3 /**< Number of ports in GPIO module;
+ Each port contains up to 32 I/O pins. */
+
+#define GPIO_VALID_PIN_MASKS \
+ { /* Port A */ 0xFFFFFFFF, \
+ /* Port B */ 0xFFFFFFFF, \
+ /* Port C */ 0xFFFFFFFF }
+
+#define GPIO_VALID_INTR_MASKS \
+ { /* Port A */ 0xFFFFFFFF, \
+ /* Port B */ 0xFFFFFFFF, \
+ /* Port C */ 0xFFFFFFFF }
+
+
+
+#endif /* __PART_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
new file mode 100644
index 000000000000..2ef81d5c7c70
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File dpaa_integration_ext.h
+
+ @Description T4240 FM external definitions and structures.
+*//***************************************************************************/
+#ifndef __DPAA_INTEGRATION_EXT_H
+#define __DPAA_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+
+
+#define DPAA_VERSION 11
+
+/**************************************************************************//**
+ @Description DPAA SW Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_SWPORTAL0 = 0,
+ e_DPAA_SWPORTAL1,
+ e_DPAA_SWPORTAL2,
+ e_DPAA_SWPORTAL3,
+ e_DPAA_SWPORTAL4,
+ e_DPAA_SWPORTAL5,
+ e_DPAA_SWPORTAL6,
+ e_DPAA_SWPORTAL7,
+ e_DPAA_SWPORTAL8,
+ e_DPAA_SWPORTAL9,
+ e_DPAA_SWPORTAL10,
+ e_DPAA_SWPORTAL11,
+ e_DPAA_SWPORTAL12,
+ e_DPAA_SWPORTAL13,
+ e_DPAA_SWPORTAL14,
+ e_DPAA_SWPORTAL15,
+ e_DPAA_SWPORTAL16,
+ e_DPAA_SWPORTAL17,
+ e_DPAA_SWPORTAL18,
+ e_DPAA_SWPORTAL19,
+ e_DPAA_SWPORTAL20,
+ e_DPAA_SWPORTAL21,
+ e_DPAA_SWPORTAL22,
+ e_DPAA_SWPORTAL23,
+ e_DPAA_SWPORTAL24,
+ e_DPAA_SWPORTAL_DUMMY_LAST
+} e_DpaaSwPortal;
+
+/**************************************************************************//**
+ @Description DPAA Direct Connect Portals Enumeration.
+*//***************************************************************************/
+typedef enum
+{
+ e_DPAA_DCPORTAL0 = 0,
+ e_DPAA_DCPORTAL1,
+ e_DPAA_DCPORTAL2,
+ e_DPAA_DCPORTAL_DUMMY_LAST
+} e_DpaaDcPortal;
+
+#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST
+#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST
+
+/*****************************************************************************
+ QMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */
+#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */
+#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */
+#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE)
+ /**< FQIDs range - 24 bits */
+
+/**************************************************************************//**
+ @Description Work Queue Channel assignments in QMan.
+*//***************************************************************************/
+typedef enum
+{
+ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */
+ e_QM_FQ_CHANNEL_SWPORTAL1,
+ e_QM_FQ_CHANNEL_SWPORTAL2,
+ e_QM_FQ_CHANNEL_SWPORTAL3,
+ e_QM_FQ_CHANNEL_SWPORTAL4,
+ e_QM_FQ_CHANNEL_SWPORTAL5,
+ e_QM_FQ_CHANNEL_SWPORTAL6,
+ e_QM_FQ_CHANNEL_SWPORTAL7,
+ e_QM_FQ_CHANNEL_SWPORTAL8,
+ e_QM_FQ_CHANNEL_SWPORTAL9,
+ e_QM_FQ_CHANNEL_SWPORTAL10,
+ e_QM_FQ_CHANNEL_SWPORTAL11,
+ e_QM_FQ_CHANNEL_SWPORTAL12,
+ e_QM_FQ_CHANNEL_SWPORTAL13,
+ e_QM_FQ_CHANNEL_SWPORTAL14,
+ e_QM_FQ_CHANNEL_SWPORTAL15,
+ e_QM_FQ_CHANNEL_SWPORTAL16,
+ e_QM_FQ_CHANNEL_SWPORTAL17,
+ e_QM_FQ_CHANNEL_SWPORTAL18,
+ e_QM_FQ_CHANNEL_SWPORTAL19,
+ e_QM_FQ_CHANNEL_SWPORTAL20,
+ e_QM_FQ_CHANNEL_SWPORTAL21,
+ e_QM_FQ_CHANNEL_SWPORTAL22,
+ e_QM_FQ_CHANNEL_SWPORTAL23,
+ e_QM_FQ_CHANNEL_SWPORTAL24,
+
+ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */
+ e_QM_FQ_CHANNEL_POOL2,
+ e_QM_FQ_CHANNEL_POOL3,
+ e_QM_FQ_CHANNEL_POOL4,
+ e_QM_FQ_CHANNEL_POOL5,
+ e_QM_FQ_CHANNEL_POOL6,
+ e_QM_FQ_CHANNEL_POOL7,
+ e_QM_FQ_CHANNEL_POOL8,
+ e_QM_FQ_CHANNEL_POOL9,
+ e_QM_FQ_CHANNEL_POOL10,
+ e_QM_FQ_CHANNEL_POOL11,
+ e_QM_FQ_CHANNEL_POOL12,
+ e_QM_FQ_CHANNEL_POOL13,
+ e_QM_FQ_CHANNEL_POOL14,
+ e_QM_FQ_CHANNEL_POOL15,
+
+ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0:
+ connected to FMan 0; assigned in incrementing order to
+ each sub-portal (SP) in the portal */
+ e_QM_FQ_CHANNEL_FMAN0_SP1,
+ e_QM_FQ_CHANNEL_FMAN0_SP2,
+ e_QM_FQ_CHANNEL_FMAN0_SP3,
+ e_QM_FQ_CHANNEL_FMAN0_SP4,
+ e_QM_FQ_CHANNEL_FMAN0_SP5,
+ e_QM_FQ_CHANNEL_FMAN0_SP6,
+ e_QM_FQ_CHANNEL_FMAN0_SP7,
+ e_QM_FQ_CHANNEL_FMAN0_SP8,
+ e_QM_FQ_CHANNEL_FMAN0_SP9,
+ e_QM_FQ_CHANNEL_FMAN0_SP10,
+ e_QM_FQ_CHANNEL_FMAN0_SP11,
+ e_QM_FQ_CHANNEL_FMAN0_SP12,
+ e_QM_FQ_CHANNEL_FMAN0_SP13,
+ e_QM_FQ_CHANNEL_FMAN0_SP14,
+ e_QM_FQ_CHANNEL_FMAN0_SP15,
+
+ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */
+ e_QM_FQ_CHANNEL_RMAN_SP1,
+
+ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2:
+ connected to SEC */
+} e_QmFQChannel;
+
+/*****************************************************************************
+ BMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */
+
+/*****************************************************************************
+ SEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SEC_NUM_OF_DECOS 3
+#define SEC_ALL_DECOS_MASK 0x00000003
+
+
+/*****************************************************************************
+ FM INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define INTG_MAX_NUM_OF_FM 2
+
+/* Ports defines */
+#define FM_MAX_NUM_OF_1G_MACS 6
+#define FM_MAX_NUM_OF_10G_MACS 2
+#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
+#define FM_MAX_NUM_OF_OH_PORTS 6
+
+#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
+
+#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */
+#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */
+#define FM_MAX_NUM_OF_SUB_PORTALS 16
+#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0
+
+#define FM_VSP_MAX_NUM_OF_ENTRIES 64
+#define FM_MAX_NUM_OF_PFC_PRIORITIES 8
+
+/* RAMs defines */
+#define FM_MURAM_SIZE (384 * KILOBYTE)
+#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE)
+#define FM_NUM_OF_CTRL 4
+
+/* PCD defines */
+#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */
+#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */
+#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */
+#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */
+#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */
+
+/* RTC defines */
+#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */
+#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */
+#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */
+
+/* QMI defines */
+#define QMI_MAX_NUM_OF_TNUMS 64
+#define QMI_DEF_TNUMS_THRESH 32
+/* FPM defines */
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
+
+/* DMA defines */
+#define DMA_THRESH_MAX_COMMQ 83
+#define DMA_THRESH_MAX_BUF 127
+
+/* BMI defines */
+#define BMI_MAX_NUM_OF_TASKS 128
+#define BMI_MAX_NUM_OF_DMAS 84
+
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define PORT_MAX_WEIGHT 16
+
+#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE
+
+/* Unique T4240 */
+#define FM_OP_OPEN_DMA_MIN_LIMIT
+#define FM_NO_RESTRICT_ON_ACCESS_RSRC
+#define FM_NO_OP_OBSERVED_POOLS
+#define FM_FRAME_END_PARAMS_FOR_OP
+#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
+#define FM_QMI_NO_SINGLE_ECC_EXCEPTION
+
+#define FM_NO_GUARANTEED_RESET_VALUES
+
+/* FM errata */
+#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669
+#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127
+#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320
+#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675
+#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981
+
+#define FM_BCB_ERRATA_BMI_SW001
+#define FM_LEN_CHECK_ERRATA_FMAN_SW002
+#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */
+#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */
+
+#define FM_ERRATUM_A050385
+
+/*****************************************************************************
+ RMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */
+#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */
+
+/* RMan erratas */
+#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756
+
+/*****************************************************************************
+ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define NUM_OF_RX_SC 16
+#define NUM_OF_TX_SC 16
+
+#define NUM_OF_SA_PER_RX_SC 2
+#define NUM_OF_SA_PER_TX_SC 2
+
+#endif /* __DPAA_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h
new file mode 100644
index 000000000000..4787e19c9b9e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+
+ @File part_ext.h
+
+ @Description Definitions for the part (integration) module.
+*//***************************************************************************/
+
+#ifndef __PART_EXT_H
+#define __PART_EXT_H
+
+#include "std_ext.h"
+#include "part_integration_ext.h"
+
+#if !(defined(LS1043))
+#error "unable to proceed without chip-definition"
+#endif
+
+
+/**************************************************************************//*
+ @Description Part data structure - must be contained in any integration
+ data structure.
+*//***************************************************************************/
+typedef struct t_Part
+{
+ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
+ /**< Returns the address of the module's memory map base. */
+ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
+ /**< Returns the module's ID according to its memory map base. */
+} t_Part;
+
+
+#endif /* __PART_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h
new file mode 100644
index 000000000000..85ba2a4745c2
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**
+
+ @File part_integration_ext.h
+
+ @Description T4240 external definitions and structures.
+*//***************************************************************************/
+#ifndef __PART_INTEGRATION_EXT_H
+#define __PART_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+#include "ddr_std_ext.h"
+#include "enet_ext.h"
+#include "dpaa_integration_ext.h"
+
+
+/**************************************************************************//**
+ @Group T4240_chip_id T4240 Application Programming Interface
+
+ @Description T4240 Chip functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#define INTG_MAX_NUM_OF_CORES 4
+
+/**************************************************************************//**
+ @Description Module types.
+*//***************************************************************************/
+typedef enum e_ModuleId
+{
+ e_MODULE_ID_DUART_1 = 0,
+ e_MODULE_ID_DUART_2,
+ e_MODULE_ID_DUART_3,
+ e_MODULE_ID_DUART_4,
+ e_MODULE_ID_LAW,
+ e_MODULE_ID_IFC,
+ e_MODULE_ID_PAMU,
+ e_MODULE_ID_QM, /**< Queue manager module */
+ e_MODULE_ID_BM, /**< Buffer manager module */
+ e_MODULE_ID_QM_CE_PORTAL_0,
+ e_MODULE_ID_QM_CI_PORTAL_0,
+ e_MODULE_ID_QM_CE_PORTAL_1,
+ e_MODULE_ID_QM_CI_PORTAL_1,
+ e_MODULE_ID_QM_CE_PORTAL_2,
+ e_MODULE_ID_QM_CI_PORTAL_2,
+ e_MODULE_ID_QM_CE_PORTAL_3,
+ e_MODULE_ID_QM_CI_PORTAL_3,
+ e_MODULE_ID_QM_CE_PORTAL_4,
+ e_MODULE_ID_QM_CI_PORTAL_4,
+ e_MODULE_ID_QM_CE_PORTAL_5,
+ e_MODULE_ID_QM_CI_PORTAL_5,
+ e_MODULE_ID_QM_CE_PORTAL_6,
+ e_MODULE_ID_QM_CI_PORTAL_6,
+ e_MODULE_ID_QM_CE_PORTAL_7,
+ e_MODULE_ID_QM_CI_PORTAL_7,
+ e_MODULE_ID_QM_CE_PORTAL_8,
+ e_MODULE_ID_QM_CI_PORTAL_8,
+ e_MODULE_ID_QM_CE_PORTAL_9,
+ e_MODULE_ID_QM_CI_PORTAL_9,
+ e_MODULE_ID_BM_CE_PORTAL_0,
+ e_MODULE_ID_BM_CI_PORTAL_0,
+ e_MODULE_ID_BM_CE_PORTAL_1,
+ e_MODULE_ID_BM_CI_PORTAL_1,
+ e_MODULE_ID_BM_CE_PORTAL_2,
+ e_MODULE_ID_BM_CI_PORTAL_2,
+ e_MODULE_ID_BM_CE_PORTAL_3,
+ e_MODULE_ID_BM_CI_PORTAL_3,
+ e_MODULE_ID_BM_CE_PORTAL_4,
+ e_MODULE_ID_BM_CI_PORTAL_4,
+ e_MODULE_ID_BM_CE_PORTAL_5,
+ e_MODULE_ID_BM_CI_PORTAL_5,
+ e_MODULE_ID_BM_CE_PORTAL_6,
+ e_MODULE_ID_BM_CI_PORTAL_6,
+ e_MODULE_ID_BM_CE_PORTAL_7,
+ e_MODULE_ID_BM_CI_PORTAL_7,
+ e_MODULE_ID_BM_CE_PORTAL_8,
+ e_MODULE_ID_BM_CI_PORTAL_8,
+ e_MODULE_ID_BM_CE_PORTAL_9,
+ e_MODULE_ID_BM_CI_PORTAL_9,
+ e_MODULE_ID_FM, /**< Frame manager module */
+ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM_PARSER, /**< FM parser block */
+ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM_KG, /**< FM Keygen */
+ e_MODULE_ID_FM_DMA, /**< FM DMA */
+ e_MODULE_ID_FM_FPM, /**< FM FPM */
+ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */
+ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */
+ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */
+ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */
+ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */
+ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */
+ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */
+ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */
+ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */
+
+ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */
+ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */
+ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */
+ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */
+ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */
+ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */
+ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */
+ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */
+ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */
+ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */
+ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */
+ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */
+
+ e_MODULE_ID_PIC, /**< PIC */
+ e_MODULE_ID_GPIO, /**< GPIO */
+ e_MODULE_ID_SERDES, /**< SERDES */
+ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */
+ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */
+
+ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */
+
+ e_MODULE_ID_DUMMY_LAST
+} e_ModuleId;
+
+#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST
+
+
+#endif /* __PART_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h
new file mode 100644
index 000000000000..7b5390ded393
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**
+
+ @File dpaa_integration_ext.h
+
+ @Description P1023 FM external definitions and structures.
+*//***************************************************************************/
+#ifndef __DPAA_INTEGRATION_EXT_H
+#define __DPAA_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+
+
+#define DPAA_VERSION 10
+
+typedef enum e_DpaaSwPortal {
+ e_DPAA_SWPORTAL0 = 0,
+ e_DPAA_SWPORTAL1,
+ e_DPAA_SWPORTAL2,
+ e_DPAA_SWPORTAL_DUMMY_LAST
+} e_DpaaSwPortal;
+
+typedef enum {
+ e_DPAA_DCPORTAL0 = 0,
+ e_DPAA_DCPORTAL2,
+ e_DPAA_DCPORTAL_DUMMY_LAST
+} e_DpaaDcPortal;
+
+#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST
+#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST
+
+/*****************************************************************************
+ QMAN INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define QM_MAX_NUM_OF_POOL_CHANNELS 3
+#define QM_MAX_NUM_OF_WQ 8
+#define QM_MAX_NUM_OF_SWP_AS 2
+#define QM_MAX_NUM_OF_CGS 64
+#define QM_MAX_NUM_OF_FQIDS (16*MEGABYTE)
+
+typedef enum {
+ e_QM_FQ_CHANNEL_SWPORTAL0 = 0,
+ e_QM_FQ_CHANNEL_SWPORTAL1,
+ e_QM_FQ_CHANNEL_SWPORTAL2,
+
+ e_QM_FQ_CHANNEL_POOL1 = 0x21,
+ e_QM_FQ_CHANNEL_POOL2,
+ e_QM_FQ_CHANNEL_POOL3,
+
+ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40,
+ e_QM_FQ_CHANNEL_FMAN0_SP1,
+ e_QM_FQ_CHANNEL_FMAN0_SP2,
+ e_QM_FQ_CHANNEL_FMAN0_SP3,
+ e_QM_FQ_CHANNEL_FMAN0_SP4,
+ e_QM_FQ_CHANNEL_FMAN0_SP5,
+ e_QM_FQ_CHANNEL_FMAN0_SP6,
+
+
+ e_QM_FQ_CHANNEL_CAAM = 0x80
+} e_QmFQChannel;
+
+/*****************************************************************************
+ BMAN INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define BM_MAX_NUM_OF_POOLS 8
+
+/*****************************************************************************
+ SEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SEC_NUM_OF_DECOS 2
+#define SEC_ALL_DECOS_MASK 0x00000003
+#define SEC_RNGB
+#define SEC_NO_ESP_TRAILER_REMOVAL
+
+/*****************************************************************************
+ FM INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define INTG_MAX_NUM_OF_FM 1
+
+/* Ports defines */
+#define FM_MAX_NUM_OF_1G_MACS 2
+#define FM_MAX_NUM_OF_10G_MACS 0
+#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
+#define FM_MAX_NUM_OF_OH_PORTS 5
+
+#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
+
+#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#define FM_MAX_NUM_OF_MACSECS 1
+
+#define FM_MACSEC_SUPPORT
+
+#define FM_LOW_END_RESTRICTION /* prevents the use of TX port 1 with OP port 0 */
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */
+#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 2 /**< Number of Offline parsing port external BM pools per Rx port */
+#define FM_PORT_NUM_OF_CONGESTION_GRPS 32 /**< Total number of congestion groups in QM */
+#define FM_MAX_NUM_OF_SUB_PORTALS 7
+
+/* Rams defines */
+#define FM_MURAM_SIZE (64*KILOBYTE)
+#define FM_IRAM_SIZE(major, minor) (32 * KILOBYTE)
+#define FM_NUM_OF_CTRL 2
+
+/* PCD defines */
+#define FM_PCD_PLCR_NUM_ENTRIES 32 /**< Total number of policer profiles */
+#define FM_PCD_KG_NUM_OF_SCHEMES 16 /**< Total number of KG schemes */
+#define FM_PCD_MAX_NUM_OF_CLS_PLANS 128 /**< Number of classification plan entries. */
+#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000240 /**< Number of bytes saved for patches */
+#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */
+
+/* RTC defines */
+#define FM_RTC_NUM_OF_ALARMS 2
+#define FM_RTC_NUM_OF_PERIODIC_PULSES 2
+#define FM_RTC_NUM_OF_EXT_TRIGGERS 2
+
+/* QMI defines */
+#define QMI_MAX_NUM_OF_TNUMS 15
+
+/* FPM defines */
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
+
+/* DMA defines */
+#define DMA_THRESH_MAX_COMMQ 15
+#define DMA_THRESH_MAX_BUF 7
+
+/* BMI defines */
+#define BMI_MAX_NUM_OF_TASKS 64
+#define BMI_MAX_NUM_OF_DMAS 16
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define PORT_MAX_WEIGHT 4
+
+/*****************************************************************************
+ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define NUM_OF_RX_SC 16
+#define NUM_OF_TX_SC 16
+
+#define NUM_OF_SA_PER_RX_SC 2
+#define NUM_OF_SA_PER_TX_SC 2
+
+/**************************************************************************//**
+ @Description Enum for inter-module interrupts registration
+*//***************************************************************************/
+
+/* 1023 unique features */
+#define FM_QMI_NO_ECC_EXCEPTIONS
+#define FM_CSI_CFED_LIMIT
+#define FM_PEDANTIC_DMA
+#define FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+#define FM_FIFO_ALLOCATION_ALG
+#define FM_DEQ_PIPELINE_PARAMS_FOR_OP
+#define FM_HAS_TOTAL_DMAS
+#define FM_KG_NO_IPPID_SUPPORT
+#define FM_NO_GUARANTEED_RESET_VALUES
+#define FM_MAC_RESET
+
+/* FM erratas */
+#define FM_RX_PREAM_4_ERRATA_DTSEC_A001
+#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */
+
+#define FM_DEBUG_TRACE_FMAN_A004 /* No implementation, Out of LLD scope */
+#define FM_INT_BUF_LEAK_FMAN_A005 /* No implementation, Out of LLD scope. App must avoid S/G */
+
+#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
+
+/* #define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */
+
+/*
+TKT056919 - axi12axi0 can hang if read request follows the single byte write on the very next cycle
+TKT038900 - FM dma lockup occur due to AXI slave protocol violation
+*/
+#define FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004
+
+
+#endif /* __DPAA_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h
new file mode 100644
index 000000000000..6814d5fb18d6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+
+ @File part_ext.h
+
+ @Description Definitions for the part (integration) module.
+*//***************************************************************************/
+
+#ifndef __PART_EXT_H
+#define __PART_EXT_H
+
+#include "std_ext.h"
+#include "part_integration_ext.h"
+
+
+#if !(defined(MPC8306) || \
+ defined(MPC8309) || \
+ defined(MPC834x) || \
+ defined(MPC836x) || \
+ defined(MPC832x) || \
+ defined(MPC837x) || \
+ defined(MPC8568) || \
+ defined(MPC8569) || \
+ defined(P1020) || \
+ defined(P1021) || \
+ defined(P1022) || \
+ defined(P1023) || \
+ defined(P2020) || \
+ defined(P3041) || \
+ defined(P4080) || \
+ defined(P5020) || \
+ defined(MSC814x))
+#error "unable to proceed without chip-definition"
+#endif
+
+
+/**************************************************************************//*
+ @Description Part data structure - must be contained in any integration
+ data structure.
+*//***************************************************************************/
+typedef struct t_Part
+{
+ uint64_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
+ /**< Returns the address of the module's memory map base. */
+ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uint64_t baseAddress);
+ /**< Returns the module's ID according to its memory map base. */
+} t_Part;
+
+
+#endif /* __PART_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h
new file mode 100644
index 000000000000..e838283d11af
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h
@@ -0,0 +1,635 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File part_integration_ext.h
+
+ @Description P1023 external definitions and structures.
+*//***************************************************************************/
+#ifndef __PART_INTEGRATION_EXT_H
+#define __PART_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+#include "dpaa_integration_ext.h"
+
+
+/**************************************************************************//**
+ @Group 1023_chip_id P1023 Application Programming Interface
+
+ @Description P1023 Chip functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#define INTG_MAX_NUM_OF_CORES 2
+
+
+/**************************************************************************//**
+ @Description Module types.
+*//***************************************************************************/
+typedef enum e_ModuleId
+{
+ e_MODULE_ID_LAW, /**< Local Access module */
+ e_MODULE_ID_ECM, /**< e500 Coherency Module */
+ e_MODULE_ID_DDR, /**< DDR memory controller */
+ e_MODULE_ID_I2C_1, /**< I2C 1 */
+ e_MODULE_ID_I2C_2, /**< I2C 1 */
+ e_MODULE_ID_DUART_1, /**< DUART module 1 */
+ e_MODULE_ID_DUART_2, /**< DUART module 2 */
+ e_MODULE_ID_LBC, /**< Local bus memory controller module */
+ e_MODULE_ID_PCIE_1, /**< PCI Express 1 controller module */
+ e_MODULE_ID_PCIE_ATMU_1, /**< PCI 1 ATMU Window */
+ e_MODULE_ID_PCIE_2, /**< PCI Express 2 controller module */
+ e_MODULE_ID_PCIE_ATMU_2, /**< PCI 2 ATMU Window */
+ e_MODULE_ID_PCIE_3, /**< PCI Express 3 controller module */
+ e_MODULE_ID_PCIE_ATMU_3, /**< PCI 3 ATMU Window */
+ e_MODULE_ID_MSI, /**< MSI registers */
+ e_MODULE_ID_L2_SRAM, /**< L2/SRAM Memory-Mapped controller module */
+ e_MODULE_ID_DMA_1, /**< DMA controller 1 */
+ e_MODULE_ID_DMA_2, /**< DMA controller 2 */
+ e_MODULE_ID_EPIC, /**< Programmable interrupt controller */
+ e_MODULE_ID_ESPI, /**< ESPI module */
+ e_MODULE_ID_GPIO, /**< General Purpose I/O */
+ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */
+ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */
+ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */
+ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */
+ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */
+ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */
+ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */
+ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */
+ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */
+ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */
+ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */
+ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */
+ e_MODULE_ID_USB_DR_1, /**< USB 2.0 module 1 */
+ e_MODULE_ID_USB_DR_2, /**< USB 2.0 module 2 */
+ e_MODULE_ID_ETSEC_MII_MNG, /**< MII MNG registers */
+ e_MODULE_ID_ETSEC_1, /**< ETSEC module 1 */
+ e_MODULE_ID_ETSEC_2, /**< ETSEC module 2 */
+ e_MODULE_ID_GUTS, /**< Serial DMA */
+ e_MODULE_ID_PM, /**< Performance Monitor module */
+ e_MODULE_ID_QM, /**< Queue manager module */
+ e_MODULE_ID_BM, /**< Buffer manager module */
+ e_MODULE_ID_QM_CE_PORTAL,
+ e_MODULE_ID_QM_CI_PORTAL,
+ e_MODULE_ID_BM_CE_PORTAL,
+ e_MODULE_ID_BM_CI_PORTAL,
+ e_MODULE_ID_FM, /**< Frame manager #1 module */
+ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM_PRS, /**< FM parser block */
+ e_MODULE_ID_FM_PORT_HO0, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM_PORT_1GRx0, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx0, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM_KG, /**< FM Keygen */
+ e_MODULE_ID_FM_DMA, /**< FM DMA */
+ e_MODULE_ID_FM_FPM, /**< FM FPM */
+ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM_1GMDIO0, /**< FM 1G MDIO MAC 0*/
+ e_MODULE_ID_FM_1GMDIO1, /**< FM 1G MDIO MAC 1*/
+ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM_RISC0, /**< FM risc #0 */
+ e_MODULE_ID_FM_RISC1, /**< FM risc #1 */
+ e_MODULE_ID_FM_1GMAC0, /**< FM 1G MAC #0 */
+ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM_MACSEC, /**< FM MACSEC */
+
+ e_MODULE_ID_DUMMY_LAST
+} e_ModuleId;
+
+#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST
+
+
+#define P1023_OFFSET_LAW 0x00000C08
+#define P1023_OFFSET_ECM 0x00001000
+#define P1023_OFFSET_DDR 0x00002000
+#define P1023_OFFSET_I2C1 0x00003000
+#define P1023_OFFSET_I2C2 0x00003100
+#define P1023_OFFSET_DUART1 0x00004500
+#define P1023_OFFSET_DUART2 0x00004600
+#define P1023_OFFSET_LBC 0x00005000
+#define P1023_OFFSET_ESPI 0x00007000
+#define P1023_OFFSET_PCIE2 0x00009000
+#define P1023_OFFSET_PCIE2_ATMU 0x00009C00
+#define P1023_OFFSET_PCIE1 0x0000A000
+#define P1023_OFFSET_PCIE1_ATMU 0x0000AC00
+#define P1023_OFFSET_PCIE3 0x0000B000
+#define P1023_OFFSET_PCIE3_ATMU 0x0000BC00
+#define P1023_OFFSET_DMA2 0x0000C100
+#define P1023_OFFSET_GPIO 0x0000F000
+#define P1023_OFFSET_L2_SRAM 0x00020000
+#define P1023_OFFSET_DMA1 0x00021100
+#define P1023_OFFSET_USB1 0x00022000
+#define P1023_OFFSET_SEC_GEN 0x00030000
+#define P1023_OFFSET_SEC_JQ0 0x00031000
+#define P1023_OFFSET_SEC_JQ1 0x00032000
+#define P1023_OFFSET_SEC_JQ2 0x00033000
+#define P1023_OFFSET_SEC_JQ3 0x00034000
+#define P1023_OFFSET_SEC_RTIC 0x00036000
+#define P1023_OFFSET_SEC_QI 0x00037000
+#define P1023_OFFSET_SEC_DECO0_CCB0 0x00038000
+#define P1023_OFFSET_SEC_DECO1_CCB1 0x00039000
+#define P1023_OFFSET_SEC_DECO2_CCB2 0x0003a000
+#define P1023_OFFSET_SEC_DECO3_CCB3 0x0003b000
+#define P1023_OFFSET_SEC_DECO4_CCB4 0x0003c000
+#define P1023_OFFSET_PIC 0x00040000
+#define P1023_OFFSET_MSI 0x00041600
+#define P1023_OFFSET_AXI 0x00081000
+#define P1023_OFFSET_QM 0x00088000
+#define P1023_OFFSET_BM 0x0008A000
+#define P1022_OFFSET_PM 0x000E1000
+
+#define P1023_OFFSET_GUTIL 0x000E0000
+#define P1023_OFFSET_PM 0x000E1000
+#define P1023_OFFSET_DEBUG 0x000E2000
+#define P1023_OFFSET_SERDES 0x000E3000
+#define P1023_OFFSET_ROM 0x000F0000
+#define P1023_OFFSET_FM 0x00100000
+
+#define P1023_OFFSET_FM_MURAM (P1023_OFFSET_FM + 0x00000000)
+#define P1023_OFFSET_FM_BMI (P1023_OFFSET_FM + 0x00080000)
+#define P1023_OFFSET_FM_QMI (P1023_OFFSET_FM + 0x00080400)
+#define P1023_OFFSET_FM_PRS (P1023_OFFSET_FM + 0x00080800)
+#define P1023_OFFSET_FM_PORT_HO0 (P1023_OFFSET_FM + 0x00081000)
+#define P1023_OFFSET_FM_PORT_HO1 (P1023_OFFSET_FM + 0x00082000)
+#define P1023_OFFSET_FM_PORT_HO2 (P1023_OFFSET_FM + 0x00083000)
+#define P1023_OFFSET_FM_PORT_HO3 (P1023_OFFSET_FM + 0x00084000)
+#define P1023_OFFSET_FM_PORT_HO4 (P1023_OFFSET_FM + 0x00085000)
+#define P1023_OFFSET_FM_PORT_1GRX0 (P1023_OFFSET_FM + 0x00088000)
+#define P1023_OFFSET_FM_PORT_1GRX1 (P1023_OFFSET_FM + 0x00089000)
+#define P1023_OFFSET_FM_PORT_1GTX0 (P1023_OFFSET_FM + 0x000A8000)
+#define P1023_OFFSET_FM_PORT_1GTX1 (P1023_OFFSET_FM + 0x000A9000)
+#define P1023_OFFSET_FM_PLCR (P1023_OFFSET_FM + 0x000C0000)
+#define P1023_OFFSET_FM_KG (P1023_OFFSET_FM + 0x000C1000)
+#define P1023_OFFSET_FM_DMA (P1023_OFFSET_FM + 0x000C2000)
+#define P1023_OFFSET_FM_FPM (P1023_OFFSET_FM + 0x000C3000)
+#define P1023_OFFSET_FM_IRAM (P1023_OFFSET_FM + 0x000C4000)
+#define P1023_OFFSET_FM_PRS_IRAM (P1023_OFFSET_FM + 0x000C7000)
+#define P1023_OFFSET_FM_RISC0 (P1023_OFFSET_FM + 0x000D0000)
+#define P1023_OFFSET_FM_RISC1 (P1023_OFFSET_FM + 0x000D0400)
+#define P1023_OFFSET_FM_MACSEC (P1023_OFFSET_FM + 0x000D8000)
+#define P1023_OFFSET_FM_1GMAC0 (P1023_OFFSET_FM + 0x000E0000)
+#define P1023_OFFSET_FM_1GMDIO0 (P1023_OFFSET_FM + 0x000E1120)
+#define P1023_OFFSET_FM_1GMAC1 (P1023_OFFSET_FM + 0x000E2000)
+#define P1023_OFFSET_FM_1GMDIO1 (P1023_OFFSET_FM + 0x000E3000)
+#define P1023_OFFSET_FM_RTC (P1023_OFFSET_FM + 0x000FE000)
+
+/* Offsets relative to QM or BM portals base */
+#define P1023_OFFSET_PORTALS_CE_AREA 0x00000000 /* cache enabled area */
+#define P1023_OFFSET_PORTALS_CI_AREA 0x00100000 /* cache inhibited area */
+
+#define P1023_OFFSET_PORTALS_CE(portal) (P1023_OFFSET_PORTALS_CE_AREA + 0x4000 * (portal))
+#define P1023_OFFSET_PORTALS_CI(portal) (P1023_OFFSET_PORTALS_CI_AREA + 0x1000 * (portal))
+
+/**************************************************************************//**
+ @Description Transaction source ID (for memory controllers error reporting).
+*//***************************************************************************/
+typedef enum e_TransSrc
+{
+ e_TRANS_SRC_PCIE_2 = 0x01, /**< PCIe port 2 */
+ e_TRANS_SRC_PCIE_1 = 0x02, /**< PCIe port 1 */
+ e_TRANS_SRC_PCIE_3 = 0x03, /**< PCIe port 3 */
+ e_TRANS_SRC_LBC = 0x04, /**< Enhanced local bus */
+ e_TRANS_SRC_DPAA_SW_PORTALS = 0x0E, /**< DPAA software portals or SRAM */
+ e_TRANS_SRC_DDR = 0x0F, /**< DDR controller */
+ e_TRANS_SRC_CORE_INS_FETCH = 0x10, /**< Processor (instruction) */
+ e_TRANS_SRC_CORE_DATA = 0x11, /**< Processor (data) */
+ e_TRANS_SRC_DMA = 0x15 /**< DMA */
+} e_TransSrc;
+
+/**************************************************************************//**
+ @Description Local Access Window Target interface ID
+*//***************************************************************************/
+typedef enum e_P1023LawTargetId
+{
+ e_P1023_LAW_TARGET_PCIE_2 = 0x01, /**< PCI Express 2 target interface */
+ e_P1023_LAW_TARGET_PCIE_1 = 0x02, /**< PCI Express 1 target interface */
+ e_P1023_LAW_TARGET_PCIE_3 = 0x03, /**< PCI Express 3 target interface */
+ e_P1023_LAW_TARGET_LBC = 0x04, /**< Local bus target interface */
+ e_P1023_LAW_TARGET_QM_PORTALS = 0x0E, /**< Queue Manager Portals */
+ e_P1023_LAW_TARGET_BM_PORTALS = 0x0E, /**< Buffer Manager Portals */
+ e_P1023_LAW_TARGET_SRAM = 0x0E, /**< SRAM scratchpad */
+ e_P1023_LAW_TARGET_DDR = 0x0F, /**< DDR target interface */
+ e_P1023_LAW_TARGET_NONE = 0xFF /**< Invalid target interface */
+} e_P1023LawTargetId;
+
+
+/**************************************************************************//**
+ @Group 1023_init_grp P1023 Initialization Unit
+
+ @Description P1023 initialization unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Description Part ID and revision number
+*//***************************************************************************/
+typedef enum e_P1023DeviceName
+{
+ e_P1023_REV_INVALID = 0x00000000, /**< Invalid revision */
+ e_SC1023_REV_1_0 = (int)0x80FC0010, /**< SC1023 rev 1.0 */
+ e_SC1023_REV_1_1 = (int)0x80FC0011, /**< SC1023 rev 1.1 */
+ e_P1023_REV_1_0 = (int)0x80FE0010, /**< P1023 rev 1.0 with security */
+ e_P1023_REV_1_1 = (int)0x80FE0011, /**< P1023 rev 1.1 with security */
+ e_P1017_REV_1_1 = (int)0x80FF0011, /**< P1017 rev 1.1 with security */
+ e_P1023_REV_1_0_NO_SEC = (int)0x80F60010, /**< P1023 rev 1.0 without security */
+ e_P1023_REV_1_1_NO_SEC = (int)0x80F60011, /**< P1023 rev 1.1 without security */
+ e_P1017_REV_1_1_NO_SEC = (int)0x80F70011 /**< P1017 rev 1.1 without security */
+} e_P1023DeviceName;
+
+/**************************************************************************//**
+ @Description structure representing P1023 initialization parameters
+*//***************************************************************************/
+typedef struct t_P1023Params
+{
+ uintptr_t ccsrBaseAddress; /**< CCSR base address (virtual) */
+ uintptr_t bmPortalsBaseAddress; /**< Portals base address (virtual) */
+ uintptr_t qmPortalsBaseAddress; /**< Portals base address (virtual) */
+} t_P1023Params;
+
+/**************************************************************************//**
+ @Function P1023_ConfigAndInit
+
+ @Description General initiation of the chip registers.
+
+ @Param[in] p_P1023Params - A pointer to data structure of parameters
+
+ @Return A handle to the P1023 data structure.
+*//***************************************************************************/
+t_Handle P1023_ConfigAndInit(t_P1023Params *p_P1023Params);
+
+/**************************************************************************//**
+ @Function P1023_Free
+
+ @Description Free all resources.
+
+ @Param h_P1023 - (In) The handle of the initialized P1023 object.
+
+ @Return E_OK on success; Other value otherwise.
+*//***************************************************************************/
+t_Error P1023_Free(t_Handle h_P1023);
+
+/**************************************************************************//**
+ @Function P1023_GetRevInfo
+
+ @Description This routine enables access to chip and revision information.
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return Part ID and revision.
+*//***************************************************************************/
+e_P1023DeviceName P1023_GetRevInfo(uintptr_t gutilBase);
+
+/**************************************************************************//**
+ @Function P1023_GetE500Factor
+
+ @Description Returns E500 core clock multiplication factor.
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+ @Param[in] coreId - Id of the requested core.
+ @Param[out] p_E500MulFactor - Returns E500 to CCB multification factor.
+ @Param[out] p_E500DivFactor - Returns E500 to CCB division factor.
+
+ @Return E_OK on success; Other value otherwise.
+*
+*//***************************************************************************/
+t_Error P1023_GetE500Factor(uintptr_t gutilBase,
+ uint32_t coreId,
+ uint32_t *p_E500MulFactor,
+ uint32_t *p_E500DivFactor);
+
+/**************************************************************************//**
+ @Function P1023_GetFmFactor
+
+ @Description returns FM multiplication factors. (This value is returned using
+ two parameters to avoid using float parameter).
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+ @Param[out] p_FmMulFactor - returns E500 to CCB multification factor.
+ @Param[out] p_FmDivFactor - returns E500 to CCB division factor.
+
+ @Return E_OK on success; Other value otherwise.
+*//***************************************************************************/
+t_Error P1023_GetFmFactor(uintptr_t gutilBase, uint32_t *p_FmMulFactor, uint32_t *p_FmDivFactor);
+
+/**************************************************************************//**
+ @Function P1023_GetCcbFactor
+
+ @Description returns system multiplication factor.
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return System multiplication factor.
+*//***************************************************************************/
+uint32_t P1023_GetCcbFactor(uintptr_t gutilBase);
+
+#if 0
+/**************************************************************************//**
+ @Function P1023_GetDdrFactor
+
+ @Description returns the multiplication factor of the clock in for the DDR clock .
+ Note: assumes the ddr_in_clk is identical to the sys_in_clk
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+ @Param p_DdrMulFactor - returns DDR in clk multification factor.
+ @Param p_DdrDivFactor - returns DDR division factor.
+
+ @Return E_OK on success; Other value otherwise..
+*//***************************************************************************/
+t_Error P1023_GetDdrFactor( uintptr_t gutilBase,
+ uint32_t *p_DdrMulFactor,
+ uint32_t *p_DdrDivFactor);
+
+/**************************************************************************//**
+ @Function P1023_GetDdrType
+
+ @Description returns the multiplication factor of the clock in for the DDR clock .
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+ @Param p_DdrType - (Out) returns DDR type DDR1/DDR2/DDR3.
+
+ @Return E_OK on success; Other value otherwise.
+*//***************************************************************************/
+t_Error P1023_GetDdrType(uintptr_t gutilBase, e_DdrType *p_DdrType );
+#endif
+
+/** @} */ /* end of 1023_init_grp group */
+/** @} */ /* end of 1023_grp group */
+
+#define CORE_E500V2
+
+#if 0 /* using unified values */
+/*****************************************************************************
+ INTEGRATION-SPECIFIC MODULE CODES
+******************************************************************************/
+#define MODULE_UNKNOWN 0x00000000
+#define MODULE_MEM 0x00010000
+#define MODULE_MM 0x00020000
+#define MODULE_CORE 0x00030000
+#define MODULE_P1023 0x00040000
+#define MODULE_MII 0x00050000
+#define MODULE_PM 0x00060000
+#define MODULE_MMU 0x00070000
+#define MODULE_PIC 0x00080000
+#define MODULE_L2_CACHE 0x00090000
+#define MODULE_DUART 0x000a0000
+#define MODULE_SERDES 0x000b0000
+#define MODULE_PIO 0x000c0000
+#define MODULE_QM 0x000d0000
+#define MODULE_BM 0x000e0000
+#define MODULE_SEC 0x000f0000
+#define MODULE_FM 0x00100000
+#define MODULE_FM_MURAM 0x00110000
+#define MODULE_FM_PCD 0x00120000
+#define MODULE_FM_RTC 0x00130000
+#define MODULE_FM_MAC 0x00140000
+#define MODULE_FM_PORT 0x00150000
+#define MODULE_FM_MACSEC 0x00160000
+#define MODULE_FM_MACSEC_SECY 0x00170000
+#define MODULE_FM_SP 0x00280000
+#define MODULE_ECM 0x00190000
+#define MODULE_DMA 0x001a0000
+#define MODULE_DDR 0x001b0000
+#define MODULE_LAW 0x001c0000
+#define MODULE_LBC 0x001d0000
+#define MODULE_I2C 0x001e0000
+#define MODULE_ESPI 0x001f0000
+#define MODULE_PCI 0x00200000
+#define MODULE_DPA_PORT 0x00210000
+#define MODULE_USB 0x00220000
+#endif /* using unified values */
+
+/*****************************************************************************
+ LBC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+/**************************************************************************//**
+ @Group lbc_exception_grp LBC Exception Unit
+
+ @Description LBC Exception unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Anchor lbc_exbm
+
+ @Collection LBC Errors Bit Mask
+
+ These errors are reported through the exceptions callback..
+ The values can be or'ed in any combination in the errors mask
+ parameter of the errors report structure.
+
+ These errors can also be passed as a bit-mask to
+ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
+ for enabling or disabling error checking.
+ @{
+*//***************************************************************************/
+#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */
+#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */
+#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */
+#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */
+
+#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
+ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT)
+ /**< All possible errors */
+/* @} */
+/** @} */ /* end of lbc_exception_grp group */
+
+#define LBC_NUM_OF_BANKS 2
+#define LBC_MAX_CS_SIZE 0x0000000100000000LL
+#define LBC_ATOMIC_OPERATION_SUPPORT
+#define LBC_PARITY_SUPPORT
+#define LBC_ADDRESS_SHIFT_SUPPORT
+#define LBC_ADDRESS_HOLD_TIME_CTRL
+#define LBC_HIGH_CLK_DIVIDERS
+#define LBC_FCM_AVAILABLE
+
+
+/*****************************************************************************
+ LAW INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define LAW_ARCH_CCB
+#define LAW_NUM_OF_WINDOWS 12
+#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */
+#define LAW_MAX_WINDOW_SIZE 0x0000001000000000LL /**< 32GB */
+
+
+/*****************************************************************************
+ SPI INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SPI_NUM_OF_CONTROLLERS 1
+
+/*****************************************************************************
+ PCI/PCIe INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+
+#define PCI_MAX_INBOUND_WINDOWS_NUM 4
+#define PCI_MAX_OUTBOUND_WINDOWS_NUM 5
+
+/**************************************************************************//**
+ @Description Target interface of an inbound window
+*//***************************************************************************/
+typedef enum e_PciTargetInterface
+{
+ e_PCI_TARGET_PCIE_2 = 0x1, /**< PCI Express target interface 2 */
+ e_PCI_TARGET_PCIE_1 = 0x2, /**< PCI Express target interface 1 */
+ e_PCI_TARGET_PCIE_3 = 0x3, /**< PCI Express target interface 3 */
+ e_PCI_TARGET_LOCAL_MEMORY = 0xF /**< Local Memory (DDR SDRAM, Local Bus, SRAM) target interface */
+
+} e_PciTargetInterface;
+
+/*****************************************************************************
+ DDR INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define DDR_NUM_OF_VALID_CS 2
+
+/*****************************************************************************
+ SEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define SEC_ERRATA_STAT_REGS_UNUSABLE
+
+/*****************************************************************************
+ DMA INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define DMA_NUM_OF_CONTROLLERS 2
+
+
+
+
+/*****************************************************************************
+ 1588 INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define PTP_V2
+
+/**************************************************************************//**
+ @Function P1023_GetMuxControlReg
+
+ @Description Returns the value of PMUXCR (Alternate Function Signal Multiplex
+ Control Register)
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return Value of PMUXCR
+*//***************************************************************************/
+uint32_t P1023_GetMuxControlReg(uintptr_t gutilBase);
+
+/**************************************************************************//**
+ @Function P1023_SetMuxControlReg
+
+ @Description Sets the value of PMUXCR (Alternate Function Signal Multiplex
+ Control Register)
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+ @Param[in] val - the new value for PMUXCR.
+
+ @Return None
+*//***************************************************************************/
+void P1023_SetMuxControlReg(uintptr_t gutilBase, uint32_t val);
+
+/**************************************************************************//**
+ @Function P1023_GetDeviceDisableStatusRegister
+
+ @Description Returns the value of DEVDISR (Device Disable Register)
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return Value of DEVDISR
+*//***************************************************************************/
+uint32_t P1023_GetDeviceDisableStatusRegister(uintptr_t gutilBase);
+
+/**************************************************************************//**
+ @Function P1023_GetPorDeviceStatusRegister
+
+ @Description Returns the value of POR Device Status Register
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return POR Device Status Register
+*//***************************************************************************/
+uint32_t P1023_GetPorDeviceStatusRegister(uintptr_t gutilBase);
+
+/**************************************************************************//**
+ @Function P1023_GetPorBootModeStatusRegister
+
+ @Description Returns the value of POR Boot Mode Status Register
+
+ @Param[in] gutilBase - Base address of P1023 GUTIL registers.
+
+ @Return POR Boot Mode Status Register value
+*//***************************************************************************/
+uint32_t P1023_GetPorBootModeStatusRegister(uintptr_t gutilBase);
+
+
+#define PORDEVSR_SGMII1_DIS 0x10000000
+#define PORDEVSR_SGMII2_DIS 0x08000000
+#define PORDEVSR_ECP1 0x02000000
+#define PORDEVSR_IO_SEL 0x00780000
+#define PORDEVSR_IO_SEL_SHIFT 19
+#define PORBMSR_HA 0x00070000
+#define PORBMSR_HA_SHIFT 16
+
+#define DEVDISR_QM_BM 0x80000000
+#define DEVDISR_FM 0x40000000
+#define DEVDISR_PCIE1 0x20000000
+#define DEVDISR_MAC_SEC 0x10000000
+#define DEVDISR_ELBC 0x08000000
+#define DEVDISR_PCIE2 0x04000000
+#define DEVDISR_PCIE3 0x02000000
+#define DEVDISR_CAAM 0x01000000
+#define DEVDISR_USB0 0x00800000
+#define DEVDISR_1588 0x00020000
+#define DEVDISR_CORE0 0x00008000
+#define DEVDISR_TB0 0x00004000
+#define DEVDISR_CORE1 0x00002000
+#define DEVDISR_TB1 0x00001000
+#define DEVDISR_DMA1 0x00000400
+#define DEVDISR_DMA2 0x00000200
+#define DEVDISR_DDR 0x00000010
+#define DEVDISR_TSEC1 0x00000080
+#define DEVDISR_TSEC2 0x00000040
+#define DEVDISR_SPI 0x00000008
+#define DEVDISR_I2C 0x00000004
+#define DEVDISR_DUART 0x00000002
+
+
+#endif /* __PART_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h
new file mode 100644
index 000000000000..6e2b925fb178
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h
@@ -0,0 +1,276 @@
+/* Copyright (c) 2009-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File dpaa_integration_ext.h
+
+ @Description P3040/P4080/P5020 FM external definitions and structures.
+*//***************************************************************************/
+#ifndef __DPAA_INTEGRATION_EXT_H
+#define __DPAA_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+
+
+#define DPAA_VERSION 10
+
+typedef enum {
+ e_DPAA_SWPORTAL0 = 0,
+ e_DPAA_SWPORTAL1,
+ e_DPAA_SWPORTAL2,
+ e_DPAA_SWPORTAL3,
+ e_DPAA_SWPORTAL4,
+ e_DPAA_SWPORTAL5,
+ e_DPAA_SWPORTAL6,
+ e_DPAA_SWPORTAL7,
+ e_DPAA_SWPORTAL8,
+ e_DPAA_SWPORTAL9,
+ e_DPAA_SWPORTAL_DUMMY_LAST
+} e_DpaaSwPortal;
+
+typedef enum {
+ e_DPAA_DCPORTAL0 = 0,
+ e_DPAA_DCPORTAL1,
+ e_DPAA_DCPORTAL2,
+ e_DPAA_DCPORTAL3,
+ e_DPAA_DCPORTAL4,
+ e_DPAA_DCPORTAL_DUMMY_LAST
+} e_DpaaDcPortal;
+
+#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST
+#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST
+
+/*****************************************************************************
+ QMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */
+#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */
+#define QM_MAX_NUM_OF_SWP_AS 4
+#define QM_MAX_NUM_OF_CGS 256 /**< Number of congestion groups */
+#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE) /**< FQIDs range - 24 bits */
+
+/**************************************************************************//**
+ @Description Work Queue Channel assignments in QMan.
+*//***************************************************************************/
+typedef enum
+{
+ e_QM_FQ_CHANNEL_SWPORTAL0 = 0, /**< Dedicated channels serviced by software portals 0 to 9 */
+ e_QM_FQ_CHANNEL_SWPORTAL1,
+ e_QM_FQ_CHANNEL_SWPORTAL2,
+ e_QM_FQ_CHANNEL_SWPORTAL3,
+ e_QM_FQ_CHANNEL_SWPORTAL4,
+ e_QM_FQ_CHANNEL_SWPORTAL5,
+ e_QM_FQ_CHANNEL_SWPORTAL6,
+ e_QM_FQ_CHANNEL_SWPORTAL7,
+ e_QM_FQ_CHANNEL_SWPORTAL8,
+ e_QM_FQ_CHANNEL_SWPORTAL9,
+
+ e_QM_FQ_CHANNEL_POOL1 = 0x21, /**< Pool channels that can be serviced by any of the software portals */
+ e_QM_FQ_CHANNEL_POOL2,
+ e_QM_FQ_CHANNEL_POOL3,
+ e_QM_FQ_CHANNEL_POOL4,
+ e_QM_FQ_CHANNEL_POOL5,
+ e_QM_FQ_CHANNEL_POOL6,
+ e_QM_FQ_CHANNEL_POOL7,
+ e_QM_FQ_CHANNEL_POOL8,
+ e_QM_FQ_CHANNEL_POOL9,
+ e_QM_FQ_CHANNEL_POOL10,
+ e_QM_FQ_CHANNEL_POOL11,
+ e_QM_FQ_CHANNEL_POOL12,
+ e_QM_FQ_CHANNEL_POOL13,
+ e_QM_FQ_CHANNEL_POOL14,
+ e_QM_FQ_CHANNEL_POOL15,
+
+ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40, /**< Dedicated channels serviced by Direct Connect Portal 0:
+ connected to FMan 0; assigned in incrementing order to
+ each sub-portal (SP) in the portal */
+ e_QM_FQ_CHANNEL_FMAN0_SP1,
+ e_QM_FQ_CHANNEL_FMAN0_SP2,
+ e_QM_FQ_CHANNEL_FMAN0_SP3,
+ e_QM_FQ_CHANNEL_FMAN0_SP4,
+ e_QM_FQ_CHANNEL_FMAN0_SP5,
+ e_QM_FQ_CHANNEL_FMAN0_SP6,
+ e_QM_FQ_CHANNEL_FMAN0_SP7,
+ e_QM_FQ_CHANNEL_FMAN0_SP8,
+ e_QM_FQ_CHANNEL_FMAN0_SP9,
+ e_QM_FQ_CHANNEL_FMAN0_SP10,
+ e_QM_FQ_CHANNEL_FMAN0_SP11,
+/* difference between 5020 and 4080 :) */
+ e_QM_FQ_CHANNEL_FMAN1_SP0 = 0x60,
+ e_QM_FQ_CHANNEL_FMAN1_SP1,
+ e_QM_FQ_CHANNEL_FMAN1_SP2,
+ e_QM_FQ_CHANNEL_FMAN1_SP3,
+ e_QM_FQ_CHANNEL_FMAN1_SP4,
+ e_QM_FQ_CHANNEL_FMAN1_SP5,
+ e_QM_FQ_CHANNEL_FMAN1_SP6,
+ e_QM_FQ_CHANNEL_FMAN1_SP7,
+ e_QM_FQ_CHANNEL_FMAN1_SP8,
+ e_QM_FQ_CHANNEL_FMAN1_SP9,
+ e_QM_FQ_CHANNEL_FMAN1_SP10,
+ e_QM_FQ_CHANNEL_FMAN1_SP11,
+
+ e_QM_FQ_CHANNEL_CAAM = 0x80, /**< Dedicated channel serviced by Direct Connect Portal 2:
+ connected to SEC 4.x */
+
+ e_QM_FQ_CHANNEL_PME = 0xA0, /**< Dedicated channel serviced by Direct Connect Portal 3:
+ connected to PME */
+ e_QM_FQ_CHANNEL_RAID = 0xC0 /**< Dedicated channel serviced by Direct Connect Portal 4:
+ connected to RAID */
+} e_QmFQChannel;
+
+/*****************************************************************************
+ BMan INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */
+
+
+/*****************************************************************************
+ FM INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define INTG_MAX_NUM_OF_FM 2
+
+/* Ports defines */
+#define FM_MAX_NUM_OF_1G_MACS 5
+#define FM_MAX_NUM_OF_10G_MACS 1
+#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS)
+#define FM_MAX_NUM_OF_OH_PORTS 7
+
+#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS)
+
+#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS
+#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS
+#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS)
+
+#define FM_PORT_MAX_NUM_OF_EXT_POOLS 8 /**< Number of external BM pools per Rx port */
+#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */
+#define FM_MAX_NUM_OF_SUB_PORTALS 12
+#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0
+
+/* Rams defines */
+#define FM_MURAM_SIZE (160*KILOBYTE)
+#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE)
+#define FM_NUM_OF_CTRL 2
+
+/* PCD defines */
+#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */
+#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */
+#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */
+#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000200 /**< Number of bytes saved for patches */
+#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */
+
+/* RTC defines */
+#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */
+#define FM_RTC_NUM_OF_PERIODIC_PULSES 2 /**< RTC number of periodic pulses */
+#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */
+
+/* QMI defines */
+#define QMI_MAX_NUM_OF_TNUMS 64
+#define QMI_DEF_TNUMS_THRESH 48
+
+/* FPM defines */
+#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
+
+/* DMA defines */
+#define DMA_THRESH_MAX_COMMQ 31
+#define DMA_THRESH_MAX_BUF 127
+
+/* BMI defines */
+#define BMI_MAX_NUM_OF_TASKS 128
+#define BMI_MAX_NUM_OF_DMAS 32
+#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE)
+#define PORT_MAX_WEIGHT 16
+
+
+#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE
+
+/* p4080-rev1 unique features */
+#define QM_CGS_NO_FRAME_MODE
+
+/* p4080 unique features */
+#define FM_NO_DISPATCH_RAM_ECC
+#define FM_NO_WATCHDOG
+#define FM_NO_TNUM_AGING
+#define FM_KG_NO_BYPASS_FQID_GEN
+#define FM_KG_NO_BYPASS_PLCR_PROFILE_GEN
+#define FM_NO_BACKUP_POOLS
+#define FM_NO_OP_OBSERVED_POOLS
+#define FM_NO_ADVANCED_RATE_LIMITER
+#define FM_NO_OP_OBSERVED_CGS
+#define FM_HAS_TOTAL_DMAS
+#define FM_KG_NO_IPPID_SUPPORT
+#define FM_NO_GUARANTEED_RESET_VALUES
+#define FM_MAC_RESET
+
+/* FM erratas */
+#define FM_TX_ECC_FRMS_ERRATA_10GMAC_A004
+#define FM_TX_SHORT_FRAME_BAD_TS_ERRATA_10GMAC_A006 /* No implementation, Out of LLD scope */
+#define FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007
+#define FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008
+#define FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 /* Out of LLD scope, user may disable ECC exceptions using FM_DisableRamsEcc */
+#define FM_BAD_VLAN_DETECT_ERRATA_10GMAC_A010
+
+#define FM_RX_PREAM_4_ERRATA_DTSEC_A001
+#define FM_GRS_ERRATA_DTSEC_A002
+#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003
+#define FM_GTS_ERRATA_DTSEC_A004
+#define FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012
+#define FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014
+#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839
+
+#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */
+#define FM_TX_LOCKUP_ERRATA_DTSEC6
+
+#define FM_HC_DEF_FQID_ONLY_ERRATA_FMAN_A003 /* Implemented by ucode */
+#define FM_DEBUG_TRACE_FMAN_A004 /* No implementation, Out of LLD scope */
+
+#define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173
+
+#define FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005
+
+#define FM_LEN_CHECK_ERRATA_FMAN_SW002
+
+#define FM_NO_CTXA_COPY_ERRATA_FMAN_SW001
+#define FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004
+
+/*****************************************************************************
+ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define NUM_OF_RX_SC 16
+#define NUM_OF_TX_SC 16
+
+#define NUM_OF_SA_PER_RX_SC 2
+#define NUM_OF_SA_PER_TX_SC 2
+
+
+#endif /* __DPAA_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h
new file mode 100644
index 000000000000..512f0baff5b9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+
+ @File part_ext.h
+
+ @Description Definitions for the part (integration) module.
+*//***************************************************************************/
+
+#ifndef __PART_EXT_H
+#define __PART_EXT_H
+
+#include "std_ext.h"
+#include "part_integration_ext.h"
+
+
+#if !(defined(MPC8306) || \
+ defined(MPC8309) || \
+ defined(MPC834x) || \
+ defined(MPC836x) || \
+ defined(MPC832x) || \
+ defined(MPC837x) || \
+ defined(MPC8568) || \
+ defined(MPC8569) || \
+ defined(P1020) || \
+ defined(P1021) || \
+ defined(P1022) || \
+ defined(P1023) || \
+ defined(P2020) || \
+ defined(P2040) || \
+ defined(P3041) || \
+ defined(P4080) || \
+ defined(SC4080) || \
+ defined(P5020) || \
+ defined(MSC814x))
+#error "unable to proceed without chip-definition"
+#endif /* !(defined(MPC834x) || ... */
+
+
+/**************************************************************************//*
+ @Description Part data structure - must be contained in any integration
+ data structure.
+*//***************************************************************************/
+typedef struct t_Part
+{
+ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId);
+ /**< Returns the address of the module's memory map base. */
+ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress);
+ /**< Returns the module's ID according to its memory map base. */
+} t_Part;
+
+
+#endif /* __PART_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h
new file mode 100644
index 000000000000..03c59b8b8c08
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h
@@ -0,0 +1,336 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File part_integration_ext.h
+
+ @Description P3040/P4080/P5020 external definitions and structures.
+*//***************************************************************************/
+#ifndef __PART_INTEGRATION_EXT_H
+#define __PART_INTEGRATION_EXT_H
+
+#include "std_ext.h"
+#include "dpaa_integration_ext.h"
+
+
+/**************************************************************************//**
+ @Group P3040/P4080/P5020_chip_id P5020 Application Programming Interface
+
+ @Description P3040/P4080/P5020 Chip functions,definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+#define CORE_E500MC
+
+#define INTG_MAX_NUM_OF_CORES 1
+
+
+/**************************************************************************//**
+ @Description Module types.
+*//***************************************************************************/
+typedef enum e_ModuleId
+{
+ e_MODULE_ID_DUART_1 = 0,
+ e_MODULE_ID_DUART_2,
+ e_MODULE_ID_DUART_3,
+ e_MODULE_ID_DUART_4,
+ e_MODULE_ID_LAW,
+ e_MODULE_ID_LBC,
+ e_MODULE_ID_PAMU,
+ e_MODULE_ID_QM, /**< Queue manager module */
+ e_MODULE_ID_BM, /**< Buffer manager module */
+ e_MODULE_ID_QM_CE_PORTAL_0,
+ e_MODULE_ID_QM_CI_PORTAL_0,
+ e_MODULE_ID_QM_CE_PORTAL_1,
+ e_MODULE_ID_QM_CI_PORTAL_1,
+ e_MODULE_ID_QM_CE_PORTAL_2,
+ e_MODULE_ID_QM_CI_PORTAL_2,
+ e_MODULE_ID_QM_CE_PORTAL_3,
+ e_MODULE_ID_QM_CI_PORTAL_3,
+ e_MODULE_ID_QM_CE_PORTAL_4,
+ e_MODULE_ID_QM_CI_PORTAL_4,
+ e_MODULE_ID_QM_CE_PORTAL_5,
+ e_MODULE_ID_QM_CI_PORTAL_5,
+ e_MODULE_ID_QM_CE_PORTAL_6,
+ e_MODULE_ID_QM_CI_PORTAL_6,
+ e_MODULE_ID_QM_CE_PORTAL_7,
+ e_MODULE_ID_QM_CI_PORTAL_7,
+ e_MODULE_ID_QM_CE_PORTAL_8,
+ e_MODULE_ID_QM_CI_PORTAL_8,
+ e_MODULE_ID_QM_CE_PORTAL_9,
+ e_MODULE_ID_QM_CI_PORTAL_9,
+ e_MODULE_ID_BM_CE_PORTAL_0,
+ e_MODULE_ID_BM_CI_PORTAL_0,
+ e_MODULE_ID_BM_CE_PORTAL_1,
+ e_MODULE_ID_BM_CI_PORTAL_1,
+ e_MODULE_ID_BM_CE_PORTAL_2,
+ e_MODULE_ID_BM_CI_PORTAL_2,
+ e_MODULE_ID_BM_CE_PORTAL_3,
+ e_MODULE_ID_BM_CI_PORTAL_3,
+ e_MODULE_ID_BM_CE_PORTAL_4,
+ e_MODULE_ID_BM_CI_PORTAL_4,
+ e_MODULE_ID_BM_CE_PORTAL_5,
+ e_MODULE_ID_BM_CI_PORTAL_5,
+ e_MODULE_ID_BM_CE_PORTAL_6,
+ e_MODULE_ID_BM_CI_PORTAL_6,
+ e_MODULE_ID_BM_CE_PORTAL_7,
+ e_MODULE_ID_BM_CI_PORTAL_7,
+ e_MODULE_ID_BM_CE_PORTAL_8,
+ e_MODULE_ID_BM_CI_PORTAL_8,
+ e_MODULE_ID_BM_CE_PORTAL_9,
+ e_MODULE_ID_BM_CI_PORTAL_9,
+ e_MODULE_ID_FM1, /**< Frame manager #1 module */
+ e_MODULE_ID_FM1_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM1_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM1_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM1_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM1_PRS, /**< FM parser block */
+ e_MODULE_ID_FM1_PORT_HO0, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO5, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_HO6, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM1_PORT_1GRx0, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GRx2, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GRx3, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GRx4, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_10GRx0, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GTx0, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GTx2, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GTx3, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_1GTx4, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM1_PORT_10GTx0, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM1_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM1_KG, /**< FM Keygen */
+ e_MODULE_ID_FM1_DMA, /**< FM DMA */
+ e_MODULE_ID_FM1_FPM, /**< FM FPM */
+ e_MODULE_ID_FM1_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM1_1GMDIO0, /**< FM 1G MDIO MAC 0*/
+ e_MODULE_ID_FM1_1GMDIO1, /**< FM 1G MDIO MAC 1*/
+ e_MODULE_ID_FM1_1GMDIO2, /**< FM 1G MDIO MAC 2*/
+ e_MODULE_ID_FM1_1GMDIO3, /**< FM 1G MDIO MAC 3*/
+ e_MODULE_ID_FM1_10GMDIO, /**< FM 10G MDIO */
+ e_MODULE_ID_FM1_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM1_1GMAC0, /**< FM 1G MAC #0 */
+ e_MODULE_ID_FM1_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM1_1GMAC2, /**< FM 1G MAC #2 */
+ e_MODULE_ID_FM1_1GMAC3, /**< FM 1G MAC #3 */
+ e_MODULE_ID_FM1_10GMAC0, /**< FM 10G MAC #0 */
+
+ e_MODULE_ID_FM2, /**< Frame manager #2 module */
+ e_MODULE_ID_FM2_RTC, /**< FM Real-Time-Clock */
+ e_MODULE_ID_FM2_MURAM, /**< FM Multi-User-RAM */
+ e_MODULE_ID_FM2_BMI, /**< FM BMI block */
+ e_MODULE_ID_FM2_QMI, /**< FM QMI block */
+ e_MODULE_ID_FM2_PRS, /**< FM parser block */
+ e_MODULE_ID_FM2_PORT_HO0, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO1, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO2, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO3, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO4, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO5, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_HO6, /**< FM Host-command/offline-parsing port block */
+ e_MODULE_ID_FM2_PORT_1GRx0, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GRx1, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GRx2, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GRx3, /**< FM Rx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_10GRx0, /**< FM Rx 10G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GTx0, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GTx1, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GTx2, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_1GTx3, /**< FM Tx 1G MAC port block */
+ e_MODULE_ID_FM2_PORT_10GTx0, /**< FM Tx 10G MAC port block */
+ e_MODULE_ID_FM2_PLCR, /**< FM Policer */
+ e_MODULE_ID_FM2_KG, /**< FM Keygen */
+ e_MODULE_ID_FM2_DMA, /**< FM DMA */
+ e_MODULE_ID_FM2_FPM, /**< FM FPM */
+ e_MODULE_ID_FM2_IRAM, /**< FM Instruction-RAM */
+ e_MODULE_ID_FM2_1GMDIO0, /**< FM 1G MDIO MAC 0*/
+ e_MODULE_ID_FM2_1GMDIO1, /**< FM 1G MDIO MAC 1*/
+ e_MODULE_ID_FM2_1GMDIO2, /**< FM 1G MDIO MAC 2*/
+ e_MODULE_ID_FM2_1GMDIO3, /**< FM 1G MDIO MAC 3*/
+ e_MODULE_ID_FM2_10GMDIO, /**< FM 10G MDIO */
+ e_MODULE_ID_FM2_PRS_IRAM, /**< FM SW-parser Instruction-RAM */
+ e_MODULE_ID_FM2_1GMAC0, /**< FM 1G MAC #0 */
+ e_MODULE_ID_FM2_1GMAC1, /**< FM 1G MAC #1 */
+ e_MODULE_ID_FM2_1GMAC2, /**< FM 1G MAC #2 */
+ e_MODULE_ID_FM2_1GMAC3, /**< FM 1G MAC #3 */
+ e_MODULE_ID_FM2_10GMAC0, /**< FM 10G MAC #0 */
+
+ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */
+ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */
+ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */
+ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */
+ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */
+ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */
+ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */
+ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */
+ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */
+ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */
+ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */
+ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */
+
+ e_MODULE_ID_MPIC, /**< MPIC */
+ e_MODULE_ID_GPIO, /**< GPIO */
+ e_MODULE_ID_SERDES, /**< SERDES */
+ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */
+ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */
+
+ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */
+ e_MODULE_ID_SRIO_MU, /**< RapidIO messaging unit module */
+
+ e_MODULE_ID_DUMMY_LAST
+} e_ModuleId;
+
+#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST
+
+#if 0 /* using unified values */
+/*****************************************************************************
+ INTEGRATION-SPECIFIC MODULE CODES
+******************************************************************************/
+#define MODULE_UNKNOWN 0x00000000
+#define MODULE_MEM 0x00010000
+#define MODULE_MM 0x00020000
+#define MODULE_CORE 0x00030000
+#define MODULE_CHIP 0x00040000
+#define MODULE_PLTFRM 0x00050000
+#define MODULE_PM 0x00060000
+#define MODULE_MMU 0x00070000
+#define MODULE_PIC 0x00080000
+#define MODULE_CPC 0x00090000
+#define MODULE_DUART 0x000a0000
+#define MODULE_SERDES 0x000b0000
+#define MODULE_PIO 0x000c0000
+#define MODULE_QM 0x000d0000
+#define MODULE_BM 0x000e0000
+#define MODULE_SEC 0x000f0000
+#define MODULE_LAW 0x00100000
+#define MODULE_LBC 0x00110000
+#define MODULE_PAMU 0x00120000
+#define MODULE_FM 0x00130000
+#define MODULE_FM_MURAM 0x00140000
+#define MODULE_FM_PCD 0x00150000
+#define MODULE_FM_RTC 0x00160000
+#define MODULE_FM_MAC 0x00170000
+#define MODULE_FM_PORT 0x00180000
+#define MODULE_FM_SP 0x00190000
+#define MODULE_DPA_PORT 0x001a0000
+#define MODULE_MII 0x001b0000
+#define MODULE_I2C 0x001c0000
+#define MODULE_DMA 0x001d0000
+#define MODULE_DDR 0x001e0000
+#define MODULE_ESPI 0x001f0000
+#define MODULE_DPAA_IPSEC 0x00200000
+#endif /* using unified values */
+
+/*****************************************************************************
+ PAMU INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define PAMU_NUM_OF_PARTITIONS 5
+
+#define PAMU_PICS_AVICS_ERRATA_PAMU3
+
+/*****************************************************************************
+ LAW INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define LAW_NUM_OF_WINDOWS 32
+#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */
+#define LAW_MAX_WINDOW_SIZE 0x0000002000000000LL /**< 64GB */
+
+
+/*****************************************************************************
+ LBC INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+/**************************************************************************//**
+ @Group lbc_exception_grp LBC Exception Unit
+
+ @Description LBC Exception unit API functions, definitions and enums
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Anchor lbc_exbm
+
+ @Collection LBC Errors Bit Mask
+
+ These errors are reported through the exceptions callback..
+ The values can be or'ed in any combination in the errors mask
+ parameter of the errors report structure.
+
+ These errors can also be passed as a bit-mask to
+ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(),
+ for enabling or disabling error checking.
+ @{
+*//***************************************************************************/
+#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */
+#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */
+#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */
+#define LBC_ERR_ATOMIC_WRITE 0x00800000 /**< Atomic write error */
+#define LBC_ERR_ATOMIC_READ 0x00400000 /**< Atomic read error */
+#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */
+
+#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \
+ LBC_ERR_WRITE_PROTECT | LBC_ERR_ATOMIC_WRITE | \
+ LBC_ERR_ATOMIC_READ | LBC_ERR_CHIP_SELECT)
+ /**< All possible errors */
+/* @} */
+/** @} */ /* end of lbc_exception_grp group */
+
+#define LBC_INCORRECT_ERROR_REPORT_ERRATA
+
+#define LBC_NUM_OF_BANKS 8
+#define LBC_MAX_CS_SIZE 0x0000000100000000LL
+#define LBC_ATOMIC_OPERATION_SUPPORT
+#define LBC_PARITY_SUPPORT
+#define LBC_ADDRESS_HOLD_TIME_CTRL
+#define LBC_HIGH_CLK_DIVIDERS
+#define LBC_FCM_AVAILABLE
+
+/*****************************************************************************
+ GPIO INTEGRATION-SPECIFIC DEFINITIONS
+******************************************************************************/
+#define GPIO_NUM_OF_PORTS 1 /**< Number of ports in GPIO module;
+ Each port contains up to 32 i/O pins. */
+
+#define GPIO_VALID_PIN_MASKS \
+ { /* Port A */ 0xFFFFFFFF }
+
+#define GPIO_VALID_INTR_MASKS \
+ { /* Port A */ 0xFFFFFFFF }
+
+#endif /* __PART_INTEGRATION_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h
new file mode 100644
index 000000000000..4ecfc6ed1462
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __MATH_EXT_H
+#define __MATH_EXT_H
+
+
+#if defined(NCSW_LINUX) && defined(__KERNEL__)
+#include <linux/math.h>
+#include <linux/math64.h>
+
+#elif defined(__MWERKS__)
+#define LOW(x) ( sizeof(x)==8 ? *(1+(int32_t*)&x) : (*(int32_t*)&x))
+#define HIGH(x) (*(int32_t*)&x)
+#define ULOW(x) ( sizeof(x)==8 ? *(1+(uint32_t*)&x) : (*(uint32_t*)&x))
+#define UHIGH(x) (*(uint32_t*)&x)
+
+static const double big = 1.0e300;
+
+/* Macro for checking if a number is a power of 2 */
+static __inline__ double ceil(double x)
+{
+ int32_t i0,i1,j0; /*- cc 020130 -*/
+ uint32_t i,j; /*- cc 020130 -*/
+ i0 = HIGH(x);
+ i1 = LOW(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(big+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (uint32_t)(0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(big+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((uint32_t)(0xffffffff))>>(j0-20); /*- cc 020130 -*/
+ if((i1&i)==0) return x; /* x is integral */
+ if(big+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = (uint32_t)(i1 + (1<<(52-j0)));
+ if(j<i1) i0+=1; /* got a carry */
+ i1 = (int32_t)j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ HIGH(x) = i0;
+ LOW(x) = i1;
+ return x;
+}
+
+#else
+#include <math.h>
+#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
+
+
+#endif /* __MATH_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h
new file mode 100644
index 000000000000..dc32e24911e9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h
@@ -0,0 +1,435 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File ncsw_ext.h
+
+ @Description General NetCommSw Standard Definitions
+*//***************************************************************************/
+
+#ifndef __NCSW_EXT_H
+#define __NCSW_EXT_H
+
+
+#include "memcpy_ext.h"
+
+#define WRITE_BLOCK IOMemSet32 /* include memcpy_ext.h */
+#define COPY_BLOCK Mem2IOCpy32 /* include memcpy_ext.h */
+
+#define PTR_TO_UINT(_ptr) ((uintptr_t)(_ptr))
+#define UINT_TO_PTR(_val) ((void*)(uintptr_t)(_val))
+
+#define PTR_MOVE(_ptr, _offset) (void*)((uint8_t*)(_ptr) + (_offset))
+
+
+#define WRITE_UINT8_UINT24(arg, data08, data24) \
+ WRITE_UINT32(arg,((uint32_t)(data08)<<24)|((uint32_t)(data24)&0x00FFFFFF))
+#define WRITE_UINT24_UINT8(arg, data24, data08) \
+ WRITE_UINT32(arg,((uint32_t)(data24)<< 8)|((uint32_t)(data08)&0x000000FF))
+
+/* Little-Endian access macros */
+
+#define WRITE_UINT16_LE(arg, data) \
+ WRITE_UINT16((arg), SwapUint16(data))
+
+#define WRITE_UINT32_LE(arg, data) \
+ WRITE_UINT32((arg), SwapUint32(data))
+
+#define WRITE_UINT64_LE(arg, data) \
+ WRITE_UINT64((arg), SwapUint64(data))
+
+#define GET_UINT16_LE(arg) \
+ SwapUint16(GET_UINT16(arg))
+
+#define GET_UINT32_LE(arg) \
+ SwapUint32(GET_UINT32(arg))
+
+#define GET_UINT64_LE(arg) \
+ SwapUint64(GET_UINT64(arg))
+
+/* Write and Read again macros */
+#define WRITE_UINT_SYNC(size, arg, data) \
+ do { \
+ WRITE_UINT##size((arg), (data)); \
+ CORE_MemoryBarrier(); \
+ } while (0)
+
+#define WRITE_UINT8_SYNC(arg, data) WRITE_UINT_SYNC(8, (arg), (data))
+
+#define WRITE_UINT16_SYNC(arg, data) WRITE_UINT_SYNC(16, (arg), (data))
+#define WRITE_UINT32_SYNC(arg, data) WRITE_UINT_SYNC(32, (arg), (data))
+
+#define MAKE_UINT64(high32, low32) (((uint64_t)high32 << 32) | (low32))
+
+
+/*----------------------*/
+/* Miscellaneous macros */
+/*----------------------*/
+
+#define UNUSED(_x) ((void)(_x))
+
+#define KILOBYTE 0x400UL /* 1024 */
+#define MEGABYTE (KILOBYTE * KILOBYTE) /* 1024*1024 */
+#define GIGABYTE ((uint64_t)(KILOBYTE * MEGABYTE)) /* 1024*1024*1024 */
+#define TERABYTE ((uint64_t)(KILOBYTE * GIGABYTE)) /* 1024*1024*1024*1024 */
+
+#ifndef NO_IRQ
+#define NO_IRQ (0)
+#endif
+#define NCSW_MASTER_ID (0)
+
+/* Macro for checking if a number is a power of 2 */
+#define POWER_OF_2(n) (!((n) & ((n)-1)))
+
+/* Macro for calculating log of base 2 */
+#define LOG2(num, log2Num) \
+ do \
+ { \
+ uint64_t tmp = (num); \
+ log2Num = 0; \
+ while (tmp > 1) \
+ { \
+ log2Num++; \
+ tmp >>= 1; \
+ } \
+ } while (0)
+
+#define NEXT_POWER_OF_2(_num, _nextPow) \
+do \
+{ \
+ if (POWER_OF_2(_num)) \
+ _nextPow = (_num); \
+ else \
+ { \
+ uint64_t tmp = (_num); \
+ _nextPow = 1; \
+ while (tmp) \
+ { \
+ _nextPow <<= 1; \
+ tmp >>= 1; \
+ } \
+ } \
+} while (0)
+
+/* Ceiling division - not the fastest way, but safer in terms of overflow */
+#define DIV_CEIL(x,y) (div64_u64((x),(y)) + (((div64_u64((x),(y))*(y)) == (x)) ? 0 : 1))
+
+/* Round up a number to be a multiple of a second number */
+#define ROUND_UP(x,y) ((((x) + (y) - 1) / (y)) * (y))
+
+/* Timing macro for converting usec units to number of ticks. */
+/* (number of usec * clock_Hz) / 1,000,000) - since */
+/* clk is in MHz units, no division needed. */
+#define USEC_TO_CLK(usec,clk) ((usec) * (clk))
+#define CYCLES_TO_USEC(cycles,clk) ((cycles) / (clk))
+
+/* Timing macros for converting between nsec units and number of clocks. */
+#define NSEC_TO_CLK(nsec,clk) DIV_CEIL(((nsec) * (clk)), 1000)
+#define CYCLES_TO_NSEC(cycles,clk) (((cycles) * 1000) / (clk))
+
+/* Timing macros for converting between psec units and number of clocks. */
+#define PSEC_TO_CLK(psec,clk) DIV_CEIL(((psec) * (clk)), 1000000)
+#define CYCLES_TO_PSEC(cycles,clk) (((cycles) * 1000000) / (clk))
+
+/* Min, Max macros */
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define IN_RANGE(min,val,max) ((min)<=(val) && (val)<=(max))
+
+#define ABS(a) ((a<0)?(a*-1):a)
+
+#if !(defined(ARRAY_SIZE))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif /* !defined(ARRAY_SIZE) */
+
+
+/* possible alignments */
+#define HALF_WORD_ALIGNMENT 2
+#define WORD_ALIGNMENT 4
+#define DOUBLE_WORD_ALIGNMENT 8
+#define BURST_ALIGNMENT 32
+
+#define HALF_WORD_ALIGNED 0x00000001
+#define WORD_ALIGNED 0x00000003
+#define DOUBLE_WORD_ALIGNED 0x00000007
+#define BURST_ALIGNED 0x0000001f
+#ifndef IS_ALIGNED
+#define IS_ALIGNED(n,align) (!((uint32_t)(n) & (align - 1)))
+#endif /* IS_ALIGNED */
+
+
+#define LAST_BUF 1
+#define FIRST_BUF 2
+#define SINGLE_BUF (LAST_BUF | FIRST_BUF)
+#define MIDDLE_BUF 4
+
+#define ARRAY_END -1
+
+#define ILLEGAL_BASE (~0)
+
+#define BUF_POSITION(first, last) state[(!!(last))<<1 | !!(first)]
+#define DECLARE_POSITION static uint8_t state[4] = { (uint8_t)MIDDLE_BUF, (uint8_t)FIRST_BUF, (uint8_t)LAST_BUF, (uint8_t)SINGLE_BUF };
+
+
+/**************************************************************************//**
+ @Description Timers operation mode
+*//***************************************************************************/
+typedef enum e_TimerMode
+{
+ e_TIMER_MODE_INVALID = 0,
+ e_TIMER_MODE_FREE_RUN, /**< Free run - counter continues to increase
+ after reaching the reference value. */
+ e_TIMER_MODE_PERIODIC, /**< Periodic - counter restarts counting from 0
+ after reaching the reference value. */
+ e_TIMER_MODE_SINGLE /**< Single (one-shot) - counter stops counting
+ after reaching the reference value. */
+} e_TimerMode;
+
+
+/**************************************************************************//**
+ @Description Enumeration (bit flags) of communication modes (Transmit,
+ receive or both).
+*//***************************************************************************/
+typedef enum e_CommMode
+{
+ e_COMM_MODE_NONE = 0, /**< No transmit/receive communication */
+ e_COMM_MODE_RX = 1, /**< Only receive communication */
+ e_COMM_MODE_TX = 2, /**< Only transmit communication */
+ e_COMM_MODE_RX_AND_TX = 3 /**< Both transmit and receive communication */
+} e_CommMode;
+
+/**************************************************************************//**
+ @Description General Diagnostic Mode
+*//***************************************************************************/
+typedef enum e_DiagMode
+{
+ e_DIAG_MODE_NONE = 0, /**< Normal operation; no diagnostic mode */
+ e_DIAG_MODE_CTRL_LOOPBACK, /**< Loopback in the controller */
+ e_DIAG_MODE_CHIP_LOOPBACK, /**< Loopback in the chip but not in the
+ controller; e.g. IO-pins, SerDes, etc. */
+ e_DIAG_MODE_PHY_LOOPBACK, /**< Loopback in the external PHY */
+ e_DIAG_MODE_EXT_LOOPBACK, /**< Loopback in the external line (beyond the PHY) */
+ e_DIAG_MODE_CTRL_ECHO, /**< Echo incoming data by the controller */
+ e_DIAG_MODE_PHY_ECHO /**< Echo incoming data by the PHY */
+} e_DiagMode;
+
+/**************************************************************************//**
+ @Description Possible RxStore callback responses.
+*//***************************************************************************/
+typedef enum e_RxStoreResponse
+{
+ e_RX_STORE_RESPONSE_PAUSE /**< Pause invoking callback with received data;
+ in polling mode, start again invoking callback
+ only next time user invokes the receive routine;
+ in interrupt mode, start again invoking callback
+ only next time a receive event triggers an interrupt;
+ in all cases, received data that are pending are not
+ lost, rather, their processing is temporarily deferred;
+ in all cases, received data are processed in the order
+ in which they were received. */
+ , e_RX_STORE_RESPONSE_CONTINUE /**< Continue invoking callback with received data. */
+} e_RxStoreResponse;
+
+
+/**************************************************************************//**
+ @Description General Handle
+*//***************************************************************************/
+typedef void * t_Handle; /**< handle, used as object's descriptor */
+
+/**************************************************************************//**
+ @Description MUTEX type
+*//***************************************************************************/
+typedef uint32_t t_Mutex;
+
+/**************************************************************************//**
+ @Description Error Code.
+
+ The high word of the error code is the code of the software
+ module (driver). The low word is the error type (e_ErrorType).
+ To get the values from the error code, use GET_ERROR_TYPE()
+ and GET_ERROR_MODULE().
+*//***************************************************************************/
+typedef uint32_t t_Error;
+
+/**************************************************************************//**
+ @Description General prototype of interrupt service routine (ISR).
+
+ @Param[in] handle - Optional handle of the module handling the interrupt.
+
+ @Return None
+ *//***************************************************************************/
+typedef void (t_Isr)(t_Handle handle);
+
+/**************************************************************************//**
+ @Anchor mem_attr
+
+ @Collection Memory Attributes
+
+ Various attributes of memory partitions. These values may be
+ or'ed together to create a mask of all memory attributes.
+ @{
+*//***************************************************************************/
+#define MEMORY_ATTR_CACHEABLE 0x00000001
+ /**< Memory is cacheable */
+#define MEMORY_ATTR_QE_2ND_BUS_ACCESS 0x00000002
+ /**< Memory can be accessed by QUICC Engine
+ through its secondary bus interface */
+
+/* @} */
+
+
+/**************************************************************************//**
+ @Function t_GetBufFunction
+
+ @Description User callback function called by driver to get data buffer.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_BufferPool - A handle to buffer pool manager
+ @Param[out] p_BufContextHandle - Returns the user's private context that
+ should be associated with the buffer
+
+ @Return Pointer to data buffer, NULL if error
+ *//***************************************************************************/
+typedef uint8_t * (t_GetBufFunction)(t_Handle h_BufferPool,
+ t_Handle *p_BufContextHandle);
+
+/**************************************************************************//**
+ @Function t_PutBufFunction
+
+ @Description User callback function called by driver to return data buffer.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_BufferPool - A handle to buffer pool manager
+ @Param[in] p_Buffer - A pointer to buffer to return
+ @Param[in] h_BufContext - The user's private context associated with
+ the returned buffer
+
+ @Return E_OK on success; Error code otherwise
+ *//***************************************************************************/
+typedef t_Error (t_PutBufFunction)(t_Handle h_BufferPool,
+ uint8_t *p_Buffer,
+ t_Handle h_BufContext);
+
+/**************************************************************************//**
+ @Function t_PhysToVirt
+
+ @Description Translates a physical address to the matching virtual address.
+
+ @Param[in] addr - The physical address to translate.
+
+ @Return Virtual address.
+*//***************************************************************************/
+typedef void * t_PhysToVirt(physAddress_t addr);
+
+/**************************************************************************//**
+ @Function t_VirtToPhys
+
+ @Description Translates a virtual address to the matching physical address.
+
+ @Param[in] addr - The virtual address to translate.
+
+ @Return Physical address.
+*//***************************************************************************/
+typedef physAddress_t t_VirtToPhys(void *addr);
+
+/**************************************************************************//**
+ @Description Buffer Pool Information Structure.
+*//***************************************************************************/
+typedef struct t_BufferPoolInfo
+{
+ t_Handle h_BufferPool; /**< A handle to the buffer pool manager */
+ t_GetBufFunction *f_GetBuf; /**< User callback to get a free buffer */
+ t_PutBufFunction *f_PutBuf; /**< User callback to return a buffer */
+ uint16_t bufferSize; /**< Buffer size (in bytes) */
+
+ t_PhysToVirt *f_PhysToVirt; /**< User callback to translate pool buffers
+ physical addresses to virtual addresses */
+ t_VirtToPhys *f_VirtToPhys; /**< User callback to translate pool buffers
+ virtual addresses to physical addresses */
+} t_BufferPoolInfo;
+
+
+/**************************************************************************//**
+ @Description User callback function called by driver when transmit completed.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_App - Application's handle, as was provided to the
+ driver by the user
+ @Param[in] queueId - Transmit queue ID
+ @Param[in] p_Data - Pointer to the data buffer
+ @Param[in] h_BufContext - The user's private context associated with
+ the given data buffer
+ @Param[in] status - Transmit status and errors
+ @Param[in] flags - Driver-dependent information
+ *//***************************************************************************/
+typedef void (t_TxConfFunction)(t_Handle h_App,
+ uint32_t queueId,
+ uint8_t *p_Data,
+ t_Handle h_BufContext,
+ uint16_t status,
+ uint32_t flags);
+
+/**************************************************************************//**
+ @Description User callback function called by driver with receive data.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_App - Application's handle, as was provided to the
+ driver by the user
+ @Param[in] queueId - Receive queue ID
+ @Param[in] p_Data - Pointer to the buffer with received data
+ @Param[in] h_BufContext - The user's private context associated with
+ the given data buffer
+ @Param[in] length - Length of received data
+ @Param[in] status - Receive status and errors
+ @Param[in] position - Position of buffer in frame
+ @Param[in] flags - Driver-dependent information
+
+ @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx
+ operation for all ready data.
+ @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation.
+ *//***************************************************************************/
+typedef e_RxStoreResponse (t_RxStoreFunction)(t_Handle h_App,
+ uint32_t queueId,
+ uint8_t *p_Data,
+ t_Handle h_BufContext,
+ uint32_t length,
+ uint16_t status,
+ uint8_t position,
+ uint32_t flags);
+
+
+#endif /* __NCSW_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h
new file mode 100644
index 000000000000..8f3bc369247e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File net_ext.h
+
+ @Description This file contains common and general netcomm headers definitions.
+*//***************************************************************************/
+#ifndef __NET_EXT_H
+#define __NET_EXT_H
+
+#include "std_ext.h"
+
+
+typedef uint8_t headerFieldPpp_t;
+
+#define NET_HEADER_FIELD_PPP_PID (1)
+#define NET_HEADER_FIELD_PPP_COMPRESSED (NET_HEADER_FIELD_PPP_PID << 1)
+#define NET_HEADER_FIELD_PPP_ALL_FIELDS ((NET_HEADER_FIELD_PPP_PID << 2) - 1)
+
+
+typedef uint8_t headerFieldPppoe_t;
+
+#define NET_HEADER_FIELD_PPPoE_VER (1)
+#define NET_HEADER_FIELD_PPPoE_TYPE (NET_HEADER_FIELD_PPPoE_VER << 1)
+#define NET_HEADER_FIELD_PPPoE_CODE (NET_HEADER_FIELD_PPPoE_VER << 2)
+#define NET_HEADER_FIELD_PPPoE_SID (NET_HEADER_FIELD_PPPoE_VER << 3)
+#define NET_HEADER_FIELD_PPPoE_LEN (NET_HEADER_FIELD_PPPoE_VER << 4)
+#define NET_HEADER_FIELD_PPPoE_SESSION (NET_HEADER_FIELD_PPPoE_VER << 5)
+#define NET_HEADER_FIELD_PPPoE_PID (NET_HEADER_FIELD_PPPoE_VER << 6)
+#define NET_HEADER_FIELD_PPPoE_ALL_FIELDS ((NET_HEADER_FIELD_PPPoE_VER << 7) - 1)
+
+#define NET_HEADER_FIELD_PPPMUX_PID (1)
+#define NET_HEADER_FIELD_PPPMUX_CKSUM (NET_HEADER_FIELD_PPPMUX_PID << 1)
+#define NET_HEADER_FIELD_PPPMUX_COMPRESSED (NET_HEADER_FIELD_PPPMUX_PID << 2)
+#define NET_HEADER_FIELD_PPPMUX_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_PID << 3) - 1)
+
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4)
+#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1)
+
+
+typedef uint8_t headerFieldEth_t;
+
+#define NET_HEADER_FIELD_ETH_DA (1)
+#define NET_HEADER_FIELD_ETH_SA (NET_HEADER_FIELD_ETH_DA << 1)
+#define NET_HEADER_FIELD_ETH_LENGTH (NET_HEADER_FIELD_ETH_DA << 2)
+#define NET_HEADER_FIELD_ETH_TYPE (NET_HEADER_FIELD_ETH_DA << 3)
+#define NET_HEADER_FIELD_ETH_FINAL_CKSUM (NET_HEADER_FIELD_ETH_DA << 4)
+#define NET_HEADER_FIELD_ETH_PADDING (NET_HEADER_FIELD_ETH_DA << 5)
+#define NET_HEADER_FIELD_ETH_ALL_FIELDS ((NET_HEADER_FIELD_ETH_DA << 6) - 1)
+
+#define NET_HEADER_FIELD_ETH_ADDR_SIZE 6
+
+typedef uint16_t headerFieldIp_t;
+
+#define NET_HEADER_FIELD_IP_VER (1)
+#define NET_HEADER_FIELD_IP_DSCP (NET_HEADER_FIELD_IP_VER << 2)
+#define NET_HEADER_FIELD_IP_ECN (NET_HEADER_FIELD_IP_VER << 3)
+#define NET_HEADER_FIELD_IP_PROTO (NET_HEADER_FIELD_IP_VER << 4)
+
+#define NET_HEADER_FIELD_IP_PROTO_SIZE 1
+
+typedef uint16_t headerFieldIpv4_t;
+
+#define NET_HEADER_FIELD_IPv4_VER (1)
+#define NET_HEADER_FIELD_IPv4_HDR_LEN (NET_HEADER_FIELD_IPv4_VER << 1)
+#define NET_HEADER_FIELD_IPv4_TOS (NET_HEADER_FIELD_IPv4_VER << 2)
+#define NET_HEADER_FIELD_IPv4_TOTAL_LEN (NET_HEADER_FIELD_IPv4_VER << 3)
+#define NET_HEADER_FIELD_IPv4_ID (NET_HEADER_FIELD_IPv4_VER << 4)
+#define NET_HEADER_FIELD_IPv4_FLAG_D (NET_HEADER_FIELD_IPv4_VER << 5)
+#define NET_HEADER_FIELD_IPv4_FLAG_M (NET_HEADER_FIELD_IPv4_VER << 6)
+#define NET_HEADER_FIELD_IPv4_OFFSET (NET_HEADER_FIELD_IPv4_VER << 7)
+#define NET_HEADER_FIELD_IPv4_TTL (NET_HEADER_FIELD_IPv4_VER << 8)
+#define NET_HEADER_FIELD_IPv4_PROTO (NET_HEADER_FIELD_IPv4_VER << 9)
+#define NET_HEADER_FIELD_IPv4_CKSUM (NET_HEADER_FIELD_IPv4_VER << 10)
+#define NET_HEADER_FIELD_IPv4_SRC_IP (NET_HEADER_FIELD_IPv4_VER << 11)
+#define NET_HEADER_FIELD_IPv4_DST_IP (NET_HEADER_FIELD_IPv4_VER << 12)
+#define NET_HEADER_FIELD_IPv4_OPTS (NET_HEADER_FIELD_IPv4_VER << 13)
+#define NET_HEADER_FIELD_IPv4_OPTS_COUNT (NET_HEADER_FIELD_IPv4_VER << 14)
+#define NET_HEADER_FIELD_IPv4_ALL_FIELDS ((NET_HEADER_FIELD_IPv4_VER << 15) - 1)
+
+#define NET_HEADER_FIELD_IPv4_ADDR_SIZE 4
+#define NET_HEADER_FIELD_IPv4_PROTO_SIZE 1
+
+
+typedef uint8_t headerFieldIpv6_t;
+
+#define NET_HEADER_FIELD_IPv6_VER (1)
+#define NET_HEADER_FIELD_IPv6_TC (NET_HEADER_FIELD_IPv6_VER << 1)
+#define NET_HEADER_FIELD_IPv6_SRC_IP (NET_HEADER_FIELD_IPv6_VER << 2)
+#define NET_HEADER_FIELD_IPv6_DST_IP (NET_HEADER_FIELD_IPv6_VER << 3)
+#define NET_HEADER_FIELD_IPv6_NEXT_HDR (NET_HEADER_FIELD_IPv6_VER << 4)
+#define NET_HEADER_FIELD_IPv6_FL (NET_HEADER_FIELD_IPv6_VER << 5)
+#define NET_HEADER_FIELD_IPv6_HOP_LIMIT (NET_HEADER_FIELD_IPv6_VER << 6)
+#define NET_HEADER_FIELD_IPv6_ALL_FIELDS ((NET_HEADER_FIELD_IPv6_VER << 7) - 1)
+
+#define NET_HEADER_FIELD_IPv6_ADDR_SIZE 16
+#define NET_HEADER_FIELD_IPv6_NEXT_HDR_SIZE 1
+
+#define NET_HEADER_FIELD_ICMP_TYPE (1)
+#define NET_HEADER_FIELD_ICMP_CODE (NET_HEADER_FIELD_ICMP_TYPE << 1)
+#define NET_HEADER_FIELD_ICMP_CKSUM (NET_HEADER_FIELD_ICMP_TYPE << 2)
+#define NET_HEADER_FIELD_ICMP_ID (NET_HEADER_FIELD_ICMP_TYPE << 3)
+#define NET_HEADER_FIELD_ICMP_SQ_NUM (NET_HEADER_FIELD_ICMP_TYPE << 4)
+#define NET_HEADER_FIELD_ICMP_ALL_FIELDS ((NET_HEADER_FIELD_ICMP_TYPE << 5) - 1)
+
+#define NET_HEADER_FIELD_ICMP_CODE_SIZE 1
+#define NET_HEADER_FIELD_ICMP_TYPE_SIZE 1
+
+#define NET_HEADER_FIELD_IGMP_VERSION (1)
+#define NET_HEADER_FIELD_IGMP_TYPE (NET_HEADER_FIELD_IGMP_VERSION << 1)
+#define NET_HEADER_FIELD_IGMP_CKSUM (NET_HEADER_FIELD_IGMP_VERSION << 2)
+#define NET_HEADER_FIELD_IGMP_DATA (NET_HEADER_FIELD_IGMP_VERSION << 3)
+#define NET_HEADER_FIELD_IGMP_ALL_FIELDS ((NET_HEADER_FIELD_IGMP_VERSION << 4) - 1)
+
+
+typedef uint16_t headerFieldTcp_t;
+
+#define NET_HEADER_FIELD_TCP_PORT_SRC (1)
+#define NET_HEADER_FIELD_TCP_PORT_DST (NET_HEADER_FIELD_TCP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_TCP_SEQ (NET_HEADER_FIELD_TCP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_TCP_ACK (NET_HEADER_FIELD_TCP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_TCP_OFFSET (NET_HEADER_FIELD_TCP_PORT_SRC << 4)
+#define NET_HEADER_FIELD_TCP_FLAGS (NET_HEADER_FIELD_TCP_PORT_SRC << 5)
+#define NET_HEADER_FIELD_TCP_WINDOW (NET_HEADER_FIELD_TCP_PORT_SRC << 6)
+#define NET_HEADER_FIELD_TCP_CKSUM (NET_HEADER_FIELD_TCP_PORT_SRC << 7)
+#define NET_HEADER_FIELD_TCP_URGPTR (NET_HEADER_FIELD_TCP_PORT_SRC << 8)
+#define NET_HEADER_FIELD_TCP_OPTS (NET_HEADER_FIELD_TCP_PORT_SRC << 9)
+#define NET_HEADER_FIELD_TCP_OPTS_COUNT (NET_HEADER_FIELD_TCP_PORT_SRC << 10)
+#define NET_HEADER_FIELD_TCP_ALL_FIELDS ((NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1)
+
+#define NET_HEADER_FIELD_TCP_PORT_SIZE 2
+
+
+typedef uint8_t headerFieldSctp_t;
+
+#define NET_HEADER_FIELD_SCTP_PORT_SRC (1)
+#define NET_HEADER_FIELD_SCTP_PORT_DST (NET_HEADER_FIELD_SCTP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_SCTP_VER_TAG (NET_HEADER_FIELD_SCTP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_SCTP_CKSUM (NET_HEADER_FIELD_SCTP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_SCTP_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1)
+
+#define NET_HEADER_FIELD_SCTP_PORT_SIZE 2
+
+typedef uint8_t headerFieldDccp_t;
+
+#define NET_HEADER_FIELD_DCCP_PORT_SRC (1)
+#define NET_HEADER_FIELD_DCCP_PORT_DST (NET_HEADER_FIELD_DCCP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_DCCP_ALL_FIELDS ((NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1)
+
+#define NET_HEADER_FIELD_DCCP_PORT_SIZE 2
+
+
+typedef uint8_t headerFieldUdp_t;
+
+#define NET_HEADER_FIELD_UDP_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_PORT_DST (NET_HEADER_FIELD_UDP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_LEN (NET_HEADER_FIELD_UDP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_UDP_CKSUM (NET_HEADER_FIELD_UDP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_UDP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1)
+
+#define NET_HEADER_FIELD_UDP_PORT_SIZE 2
+
+typedef uint8_t headerFieldUdpLite_t;
+
+#define NET_HEADER_FIELD_UDP_LITE_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_LITE_PORT_DST (NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS ((NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1)
+
+#define NET_HEADER_FIELD_UDP_LITE_PORT_SIZE 2
+
+typedef uint8_t headerFieldUdpEncapEsp_t;
+
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5)
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1)
+
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE 2
+#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE 4
+
+#define NET_HEADER_FIELD_IPHC_CID (1)
+#define NET_HEADER_FIELD_IPHC_CID_TYPE (NET_HEADER_FIELD_IPHC_CID << 1)
+#define NET_HEADER_FIELD_IPHC_HCINDEX (NET_HEADER_FIELD_IPHC_CID << 2)
+#define NET_HEADER_FIELD_IPHC_GEN (NET_HEADER_FIELD_IPHC_CID << 3)
+#define NET_HEADER_FIELD_IPHC_D_BIT (NET_HEADER_FIELD_IPHC_CID << 4)
+#define NET_HEADER_FIELD_IPHC_ALL_FIELDS ((NET_HEADER_FIELD_IPHC_CID << 5) - 1)
+
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_END (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9)
+#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1)
+
+#define NET_HEADER_FIELD_L2TPv2_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPv2_LENGTH_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPv2_OFFSET_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4)
+#define NET_HEADER_FIELD_L2TPv2_VERSION (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5)
+#define NET_HEADER_FIELD_L2TPv2_LEN (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6)
+#define NET_HEADER_FIELD_L2TPv2_TUNNEL_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7)
+#define NET_HEADER_FIELD_L2TPv2_SESSION_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8)
+#define NET_HEADER_FIELD_L2TPv2_NS (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9)
+#define NET_HEADER_FIELD_L2TPv2_NR (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10)
+#define NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11)
+#define NET_HEADER_FIELD_L2TPv2_FIRST_BYTE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12)
+#define NET_HEADER_FIELD_L2TPv2_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1)
+
+#define NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_VERSION (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_SENT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_RECV (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8)
+#define NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1)
+
+#define NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT (1)
+#define NET_HEADER_FIELD_L2TPv3_SESS_VERSION (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1)
+#define NET_HEADER_FIELD_L2TPv3_SESS_ID (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2)
+#define NET_HEADER_FIELD_L2TPv3_SESS_COOKIE (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3)
+#define NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1)
+
+
+typedef uint8_t headerFieldVlan_t;
+
+#define NET_HEADER_FIELD_VLAN_VPRI (1)
+#define NET_HEADER_FIELD_VLAN_CFI (NET_HEADER_FIELD_VLAN_VPRI << 1)
+#define NET_HEADER_FIELD_VLAN_VID (NET_HEADER_FIELD_VLAN_VPRI << 2)
+#define NET_HEADER_FIELD_VLAN_LENGTH (NET_HEADER_FIELD_VLAN_VPRI << 3)
+#define NET_HEADER_FIELD_VLAN_TYPE (NET_HEADER_FIELD_VLAN_VPRI << 4)
+#define NET_HEADER_FIELD_VLAN_ALL_FIELDS ((NET_HEADER_FIELD_VLAN_VPRI << 5) - 1)
+
+#define NET_HEADER_FIELD_VLAN_TCI (NET_HEADER_FIELD_VLAN_VPRI | \
+ NET_HEADER_FIELD_VLAN_CFI | \
+ NET_HEADER_FIELD_VLAN_VID)
+
+
+typedef uint8_t headerFieldLlc_t;
+
+#define NET_HEADER_FIELD_LLC_DSAP (1)
+#define NET_HEADER_FIELD_LLC_SSAP (NET_HEADER_FIELD_LLC_DSAP << 1)
+#define NET_HEADER_FIELD_LLC_CTRL (NET_HEADER_FIELD_LLC_DSAP << 2)
+#define NET_HEADER_FIELD_LLC_ALL_FIELDS ((NET_HEADER_FIELD_LLC_DSAP << 3) - 1)
+
+#define NET_HEADER_FIELD_NLPID_NLPID (1)
+#define NET_HEADER_FIELD_NLPID_ALL_FIELDS ((NET_HEADER_FIELD_NLPID_NLPID << 1) - 1)
+
+
+typedef uint8_t headerFieldSnap_t;
+
+#define NET_HEADER_FIELD_SNAP_OUI (1)
+#define NET_HEADER_FIELD_SNAP_PID (NET_HEADER_FIELD_SNAP_OUI << 1)
+#define NET_HEADER_FIELD_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_SNAP_OUI << 2) - 1)
+
+
+typedef uint8_t headerFieldLlcSnap_t;
+
+#define NET_HEADER_FIELD_LLC_SNAP_TYPE (1)
+#define NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1)
+
+#define NET_HEADER_FIELD_ARP_HTYPE (1)
+#define NET_HEADER_FIELD_ARP_PTYPE (NET_HEADER_FIELD_ARP_HTYPE << 1)
+#define NET_HEADER_FIELD_ARP_HLEN (NET_HEADER_FIELD_ARP_HTYPE << 2)
+#define NET_HEADER_FIELD_ARP_PLEN (NET_HEADER_FIELD_ARP_HTYPE << 3)
+#define NET_HEADER_FIELD_ARP_OPER (NET_HEADER_FIELD_ARP_HTYPE << 4)
+#define NET_HEADER_FIELD_ARP_SHA (NET_HEADER_FIELD_ARP_HTYPE << 5)
+#define NET_HEADER_FIELD_ARP_SPA (NET_HEADER_FIELD_ARP_HTYPE << 6)
+#define NET_HEADER_FIELD_ARP_THA (NET_HEADER_FIELD_ARP_HTYPE << 7)
+#define NET_HEADER_FIELD_ARP_TPA (NET_HEADER_FIELD_ARP_HTYPE << 8)
+#define NET_HEADER_FIELD_ARP_ALL_FIELDS ((NET_HEADER_FIELD_ARP_HTYPE << 9) - 1)
+
+#define NET_HEADER_FIELD_RFC2684_LLC (1)
+#define NET_HEADER_FIELD_RFC2684_NLPID (NET_HEADER_FIELD_RFC2684_LLC << 1)
+#define NET_HEADER_FIELD_RFC2684_OUI (NET_HEADER_FIELD_RFC2684_LLC << 2)
+#define NET_HEADER_FIELD_RFC2684_PID (NET_HEADER_FIELD_RFC2684_LLC << 3)
+#define NET_HEADER_FIELD_RFC2684_VPN_OUI (NET_HEADER_FIELD_RFC2684_LLC << 4)
+#define NET_HEADER_FIELD_RFC2684_VPN_IDX (NET_HEADER_FIELD_RFC2684_LLC << 5)
+#define NET_HEADER_FIELD_RFC2684_ALL_FIELDS ((NET_HEADER_FIELD_RFC2684_LLC << 6) - 1)
+
+#define NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1)
+#define NET_HEADER_FIELD_USER_DEFINED_PCDID (NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1)
+#define NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS ((NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1)
+
+#define NET_HEADER_FIELD_PAYLOAD_BUFFER (1)
+#define NET_HEADER_FIELD_PAYLOAD_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 1)
+#define NET_HEADER_FIELD_MAX_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 2)
+#define NET_HEADER_FIELD_MIN_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 3)
+#define NET_HEADER_FIELD_PAYLOAD_TYPE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 4)
+#define NET_HEADER_FIELD_FRAME_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 5)
+#define NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS ((NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1)
+
+
+typedef uint8_t headerFieldGre_t;
+
+#define NET_HEADER_FIELD_GRE_TYPE (1)
+#define NET_HEADER_FIELD_GRE_ALL_FIELDS ((NET_HEADER_FIELD_GRE_TYPE << 1) - 1)
+
+
+typedef uint8_t headerFieldMinencap_t;
+
+#define NET_HEADER_FIELD_MINENCAP_SRC_IP (1)
+#define NET_HEADER_FIELD_MINENCAP_DST_IP (NET_HEADER_FIELD_MINENCAP_SRC_IP << 1)
+#define NET_HEADER_FIELD_MINENCAP_TYPE (NET_HEADER_FIELD_MINENCAP_SRC_IP << 2)
+#define NET_HEADER_FIELD_MINENCAP_ALL_FIELDS ((NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1)
+
+
+typedef uint8_t headerFieldIpsecAh_t;
+
+#define NET_HEADER_FIELD_IPSEC_AH_SPI (1)
+#define NET_HEADER_FIELD_IPSEC_AH_NH (NET_HEADER_FIELD_IPSEC_AH_SPI << 1)
+#define NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1)
+
+
+typedef uint8_t headerFieldIpsecEsp_t;
+
+#define NET_HEADER_FIELD_IPSEC_ESP_SPI (1)
+#define NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_IPSEC_ESP_SPI << 1)
+#define NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1)
+
+#define NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE 4
+
+
+typedef uint8_t headerFieldMpls_t;
+
+#define NET_HEADER_FIELD_MPLS_LABEL_STACK (1)
+#define NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS ((NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1)
+
+
+typedef uint8_t headerFieldMacsec_t;
+
+#define NET_HEADER_FIELD_MACSEC_SECTAG (1)
+#define NET_HEADER_FIELD_MACSEC_ALL_FIELDS ((NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1)
+
+
+typedef enum {
+ HEADER_TYPE_NONE = 0,
+ HEADER_TYPE_PAYLOAD,
+ HEADER_TYPE_ETH,
+ HEADER_TYPE_VLAN,
+ HEADER_TYPE_IPv4,
+ HEADER_TYPE_IPv6,
+ HEADER_TYPE_IP,
+ HEADER_TYPE_TCP,
+ HEADER_TYPE_UDP,
+ HEADER_TYPE_UDP_LITE,
+ HEADER_TYPE_IPHC,
+ HEADER_TYPE_SCTP,
+ HEADER_TYPE_SCTP_CHUNK_DATA,
+ HEADER_TYPE_PPPoE,
+ HEADER_TYPE_PPP,
+ HEADER_TYPE_PPPMUX,
+ HEADER_TYPE_PPPMUX_SUBFRAME,
+ HEADER_TYPE_L2TPv2,
+ HEADER_TYPE_L2TPv3_CTRL,
+ HEADER_TYPE_L2TPv3_SESS,
+ HEADER_TYPE_LLC,
+ HEADER_TYPE_LLC_SNAP,
+ HEADER_TYPE_NLPID,
+ HEADER_TYPE_SNAP,
+ HEADER_TYPE_MPLS,
+ HEADER_TYPE_IPSEC_AH,
+ HEADER_TYPE_IPSEC_ESP,
+ HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */
+ HEADER_TYPE_MACSEC,
+ HEADER_TYPE_GRE,
+ HEADER_TYPE_MINENCAP,
+ HEADER_TYPE_DCCP,
+ HEADER_TYPE_ICMP,
+ HEADER_TYPE_IGMP,
+ HEADER_TYPE_ARP,
+ HEADER_TYPE_CAPWAP,
+ HEADER_TYPE_CAPWAP_DTLS,
+ HEADER_TYPE_RFC2684,
+ HEADER_TYPE_USER_DEFINED_L2,
+ HEADER_TYPE_USER_DEFINED_L3,
+ HEADER_TYPE_USER_DEFINED_L4,
+ HEADER_TYPE_USER_DEFINED_SHIM1,
+ HEADER_TYPE_USER_DEFINED_SHIM2,
+ MAX_HEADER_TYPE_COUNT
+} e_NetHeaderType;
+
+
+#endif /* __NET_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h
new file mode 100644
index 000000000000..d91e6fddf507
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File std_ext.h
+
+ @Description General Standard Definitions
+*//***************************************************************************/
+
+#ifndef __STD_EXT_H
+#define __STD_EXT_H
+
+
+#include "types_ext.h"
+#include "ncsw_ext.h"
+
+
+#endif /* __STD_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h
new file mode 100644
index 000000000000..3c8bb0a05844
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __STDARG_EXT_H
+#define __STDARG_EXT_H
+
+
+#if defined(NCSW_LINUX) && defined(__KERNEL__)
+#include <stdarg.h>
+
+#else
+#include <stdarg.h>
+
+#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
+
+#include "std_ext.h"
+
+
+#endif /* __STDARG_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h
new file mode 100644
index 000000000000..a47860cf12fe
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+
+#ifndef __STDLIB_EXT_H
+#define __STDLIB_EXT_H
+
+
+#if (defined(NCSW_LINUX)) && defined(__KERNEL__)
+#include "stdarg_ext.h"
+#include "std_ext.h"
+
+
+/**
+ * strtoul - convert a string to an uint32_t
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+uint32_t strtoul(const char *cp,char **endp,uint32_t base);
+
+/**
+ * strtol - convert a string to a int32_t
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long strtol(const char *cp,char **endp,uint32_t base);
+
+/**
+ * strtoull - convert a string to an uint64_t
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+uint64_t strtoull(const char *cp,char **endp,uint32_t base);
+
+/**
+ * strtoll - convert a string to a int64 long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long strtoll(const char *cp,char **endp,uint32_t base);
+
+/**
+ * atoi - convert a character to a int
+ * @s: The start of the string
+ */
+int atoi(const char *s);
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count);
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char * s);
+
+/**
+ * strtok - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * WARNING: strtok is deprecated, use strsep instead.
+ */
+char * strtok(char * s,const char * ct);
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char * strncpy(char * dest,const char *src,size_t count);
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char * strcpy(char * dest,const char *src);
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: format of buffer
+ * @args: arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args);
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args);
+
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
+
+#include "std_ext.h"
+
+
+#endif /* __STDLIB_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h
new file mode 100644
index 000000000000..a5c6c7e0e0f0
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef __STRING_EXT_H
+#define __STRING_EXT_H
+
+
+#if defined(NCSW_LINUX) && defined(__KERNEL__)
+#include <linux/kernel.h>
+#include <linux/string.h>
+extern char * strtok ( char * str, const char * delimiters );
+
+#elif defined(__KERNEL__)
+#include "linux/types.h"
+#include "linux/posix_types.h"
+#include "linux/string.h"
+
+#else
+#include <string.h>
+
+#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */
+
+#include "std_ext.h"
+
+
+#endif /* __STRING_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h
new file mode 100644
index 000000000000..8c87edb7aaa7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File types_ext.h
+
+ @Description General types Standard Definitions
+*//***************************************************************************/
+
+#ifndef __TYPES_EXT_H
+#define __TYPES_EXT_H
+
+#if defined(NCSW_LINUX)
+#include "types_linux.h"
+
+#elif defined(NCSW_VXWORKS)
+#include "types_vxworks.h"
+
+#elif defined(__GNUC__) && defined(__cplusplus)
+#include "types_bb_gpp.h"
+
+#elif defined(__GNUC__)
+#include "types_bb_gcc.h"
+
+#elif defined(__ghs__)
+#include "types_ghs.h"
+
+#else
+#include "types_dflt.h"
+#endif /* defined (__ROCOO__) */
+
+#endif /* __TYPES_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h
new file mode 100644
index 000000000000..8e81094b7d44
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File debug_ext.h
+
+ @Description Debug mode definitions.
+*//***************************************************************************/
+
+#ifndef __XX_COMMON_H
+#define __XX_COMMON_H
+
+/*****************************************************************************
+ * UNIFIED MODULE CODES
+ *****************************************************************************/
+#define MODULE_UNKNOWN 0x00000000
+#define MODULE_FM 0x00010000
+#define MODULE_FM_MURAM 0x00020000
+#define MODULE_FM_PCD 0x00030000
+#define MODULE_FM_RTC 0x00040000
+#define MODULE_FM_MAC 0x00050000
+#define MODULE_FM_PORT 0x00060000
+#define MODULE_MM 0x00070000
+#define MODULE_FM_SP 0x00080000
+#define MODULE_FM_MACSEC 0x00090000
+#endif /* __XX_COMMON_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h
new file mode 100644
index 000000000000..21b62d0a2b1b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h
@@ -0,0 +1,791 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+/**************************************************************************//**
+ @File xx_ext.h
+
+ @Description Prototypes, externals and typedefs for system-supplied
+ (external) routines
+*//***************************************************************************/
+
+#ifndef __XX_EXT_H
+#define __XX_EXT_H
+
+#include "std_ext.h"
+#include "xx_common.h"
+#include "part_ext.h"
+
+
+
+/**************************************************************************//**
+ @Group xx_id XX Interface (System call hooks)
+
+ @Description Prototypes, externals and typedefs for system-supplied
+ (external) routines
+
+ @{
+*//***************************************************************************/
+
+#ifdef DEBUG_XX_MALLOC
+void * XX_MallocDebug(uint32_t size, char *fname, int line);
+
+void * XX_MallocSmartDebug(uint32_t size,
+ int memPartitionId,
+ uint32_t alignment,
+ char *fname,
+ int line);
+
+#define XX_Malloc(sz) \
+ XX_MallocDebug((sz), __FILE__, __LINE__)
+
+#define XX_MallocSmart(sz, memt, al) \
+ XX_MallocSmartDebug((sz), (memt), (al), __FILE__, __LINE__)
+
+#else /* not DEBUG_XX_MALLOC */
+/**************************************************************************//**
+ @Function XX_Malloc
+
+ @Description allocates contiguous block of memory.
+
+ @Param[in] size - Number of bytes to allocate.
+
+ @Return The address of the newly allocated block on success, NULL on failure.
+*//***************************************************************************/
+void * XX_Malloc(uint32_t size);
+
+/**************************************************************************//**
+ @Function XX_MallocSmart
+
+ @Description Allocates contiguous block of memory in a specified
+ alignment and from the specified segment.
+
+ @Param[in] size - Number of bytes to allocate.
+ @Param[in] memPartitionId - Memory partition ID; The value zero must
+ be mapped to the default heap partition.
+ @Param[in] alignment - Required memory alignment (in bytes).
+
+ @Return The address of the newly allocated block on success, NULL on failure.
+*//***************************************************************************/
+void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment);
+#endif /* not DEBUG_XX_MALLOC */
+
+/**************************************************************************//**
+ @Function XX_FreeSmart
+
+ @Description Frees the memory block pointed to by "p".
+ Only for memory allocated by XX_MallocSmart
+
+ @Param[in] p_Memory - pointer to the memory block.
+
+ @Return None.
+*//***************************************************************************/
+void XX_FreeSmart(void *p_Memory);
+
+/**************************************************************************//**
+ @Function XX_Free
+
+ @Description frees the memory block pointed to by "p".
+
+ @Param[in] p_Memory - pointer to the memory block.
+
+ @Return None.
+*//***************************************************************************/
+void XX_Free(void *p_Memory);
+
+/**************************************************************************//**
+ @Function XX_Print
+
+ @Description print a string.
+
+ @Param[in] str - string to print.
+
+ @Return None.
+*//***************************************************************************/
+void XX_Print(char *str, ...);
+
+/**************************************************************************//**
+ @Function XX_SetIntr
+
+ @Description Set an interrupt service routine for a specific interrupt source.
+
+ @Param[in] irq - Interrupt ID (system-specific number).
+ @Param[in] f_Isr - Callback routine that will be called when the interrupt occurs.
+ @Param[in] handle - The argument for the user callback routine.
+
+ @Return E_OK on success; error code otherwise..
+*//***************************************************************************/
+t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle);
+
+/**************************************************************************//**
+ @Function XX_FreeIntr
+
+ @Description Free a specific interrupt and a specific callback routine.
+
+ @Param[in] irq - Interrupt ID (system-specific number).
+
+ @Return E_OK on success; error code otherwise..
+*//***************************************************************************/
+t_Error XX_FreeIntr(int irq);
+
+/**************************************************************************//**
+ @Function XX_EnableIntr
+
+ @Description Enable a specific interrupt.
+
+ @Param[in] irq - Interrupt ID (system-specific number).
+
+ @Return E_OK on success; error code otherwise..
+*//***************************************************************************/
+t_Error XX_EnableIntr(int irq);
+
+/**************************************************************************//**
+ @Function XX_DisableIntr
+
+ @Description Disable a specific interrupt.
+
+ @Param[in] irq - Interrupt ID (system-specific number).
+
+ @Return E_OK on success; error code otherwise..
+*//***************************************************************************/
+t_Error XX_DisableIntr(int irq);
+
+/**************************************************************************//**
+ @Function XX_DisableAllIntr
+
+ @Description Disable all interrupts by masking them at the CPU.
+
+ @Return A value that represents the interrupts state before the
+ operation, and should be passed to the matching
+ XX_RestoreAllIntr() call.
+*//***************************************************************************/
+uint32_t XX_DisableAllIntr(void);
+
+/**************************************************************************//**
+ @Function XX_RestoreAllIntr
+
+ @Description Restore previous state of interrupts level at the CPU.
+
+ @Param[in] flags - A value that represents the interrupts state to restore,
+ as returned by the matching call for XX_DisableAllIntr().
+
+ @Return None.
+*//***************************************************************************/
+void XX_RestoreAllIntr(uint32_t flags);
+
+
+/**************************************************************************//**
+ @Function XX_Exit
+
+ @Description Stop execution and report status (where it is applicable)
+
+ @Param[in] status - exit status
+*//***************************************************************************/
+void XX_Exit(int status);
+
+
+/*****************************************************************************/
+/* Tasklet Service Routines */
+/*****************************************************************************/
+typedef t_Handle t_TaskletHandle;
+
+/**************************************************************************//**
+ @Function XX_InitTasklet
+
+ @Description Create and initialize a tasklet object.
+
+ @Param[in] routine - A routine to be ran as a tasklet.
+ @Param[in] data - An argument to pass to the tasklet.
+
+ @Return Tasklet handle is returned on success. NULL is returned otherwise.
+*//***************************************************************************/
+t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data);
+
+/**************************************************************************//**
+ @Function XX_FreeTasklet
+
+ @Description Free a tasklet object.
+
+ @Param[in] h_Tasklet - A handle to a tasklet to be free.
+
+ @Return None.
+*//***************************************************************************/
+void XX_FreeTasklet (t_TaskletHandle h_Tasklet);
+
+/**************************************************************************//**
+ @Function XX_ScheduleTask
+
+ @Description Schedule a tasklet object.
+
+ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled.
+ @Param[in] immediate - Indicate whether to schedule this tasklet on
+ the immediate queue or on the delayed one.
+
+ @Return 0 - on success. Error code - otherwise.
+*//***************************************************************************/
+int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate);
+
+/**************************************************************************//**
+ @Function XX_FlushScheduledTasks
+
+ @Description Flush all tasks there are in the scheduled tasks queue.
+
+ @Return None.
+*//***************************************************************************/
+void XX_FlushScheduledTasks(void);
+
+/**************************************************************************//**
+ @Function XX_TaskletIsQueued
+
+ @Description Check if task is queued.
+
+ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled.
+
+ @Return 1 - task is queued. 0 - otherwise.
+*//***************************************************************************/
+int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet);
+
+/**************************************************************************//**
+ @Function XX_SetTaskletData
+
+ @Description Set data to a scheduled task. Used to change data of already
+ scheduled task.
+
+ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled.
+ @Param[in] data - Data to be set.
+*//***************************************************************************/
+void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data);
+
+/**************************************************************************//**
+ @Function XX_GetTaskletData
+
+ @Description Get the data of scheduled task.
+
+ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled.
+
+ @Return handle to the data of the task.
+*//***************************************************************************/
+t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet);
+
+/**************************************************************************//**
+ @Function XX_BottomHalf
+
+ @Description Bottom half implementation, invoked by the interrupt handler.
+
+ This routine handles all bottom-half tasklets with interrupts
+ enabled.
+
+ @Return None.
+*//***************************************************************************/
+void XX_BottomHalf(void);
+
+
+/*****************************************************************************/
+/* Spinlock Service Routines */
+/*****************************************************************************/
+
+/**************************************************************************//**
+ @Function XX_InitSpinlock
+
+ @Description Creates a spinlock.
+
+ @Return Spinlock handle is returned on success; NULL otherwise.
+*//***************************************************************************/
+t_Handle XX_InitSpinlock(void);
+
+/**************************************************************************//**
+ @Function XX_FreeSpinlock
+
+ @Description Frees the memory allocated for the spinlock creation.
+
+ @Param[in] h_Spinlock - A handle to a spinlock.
+
+ @Return None.
+*//***************************************************************************/
+void XX_FreeSpinlock(t_Handle h_Spinlock);
+
+/**************************************************************************//**
+ @Function XX_LockSpinlock
+
+ @Description Locks a spinlock.
+
+ @Param[in] h_Spinlock - A handle to a spinlock.
+
+ @Return None.
+*//***************************************************************************/
+void XX_LockSpinlock(t_Handle h_Spinlock);
+
+/**************************************************************************//**
+ @Function XX_UnlockSpinlock
+
+ @Description Unlocks a spinlock.
+
+ @Param[in] h_Spinlock - A handle to a spinlock.
+
+ @Return None.
+*//***************************************************************************/
+void XX_UnlockSpinlock(t_Handle h_Spinlock);
+
+/**************************************************************************//**
+ @Function XX_LockIntrSpinlock
+
+ @Description Locks a spinlock (interrupt safe).
+
+ @Param[in] h_Spinlock - A handle to a spinlock.
+
+ @Return A value that represents the interrupts state before the
+ operation, and should be passed to the matching
+ XX_UnlockIntrSpinlock() call.
+*//***************************************************************************/
+uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock);
+
+/**************************************************************************//**
+ @Function XX_UnlockIntrSpinlock
+
+ @Description Unlocks a spinlock (interrupt safe).
+
+ @Param[in] h_Spinlock - A handle to a spinlock.
+ @Param[in] intrFlags - A value that represents the interrupts state to
+ restore, as returned by the matching call for
+ XX_LockIntrSpinlock().
+
+ @Return None.
+*//***************************************************************************/
+void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags);
+
+
+/*****************************************************************************/
+/* Timers Service Routines */
+/*****************************************************************************/
+
+/**************************************************************************//**
+ @Function XX_CurrentTime
+
+ @Description Returns current system time.
+
+ @Return Current system time (in milliseconds).
+*//***************************************************************************/
+uint32_t XX_CurrentTime(void);
+
+/**************************************************************************//**
+ @Function XX_CreateTimer
+
+ @Description Creates a timer.
+
+ @Return Timer handle is returned on success; NULL otherwise.
+*//***************************************************************************/
+t_Handle XX_CreateTimer(void);
+
+/**************************************************************************//**
+ @Function XX_FreeTimer
+
+ @Description Frees the memory allocated for the timer creation.
+
+ @Param[in] h_Timer - A handle to a timer.
+
+ @Return None.
+*//***************************************************************************/
+void XX_FreeTimer(t_Handle h_Timer);
+
+/**************************************************************************//**
+ @Function XX_StartTimer
+
+ @Description Starts a timer.
+
+ The user can select to start the timer as periodic timer or as
+ one-shot timer. The user should provide a callback routine that
+ will be called when the timer expires.
+
+ @Param[in] h_Timer - A handle to a timer.
+ @Param[in] msecs - Timer expiration period (in milliseconds).
+ @Param[in] periodic - TRUE for a periodic timer;
+ FALSE for a one-shot timer..
+ @Param[in] f_TimerExpired - A callback routine to be called when the
+ timer expires.
+ @Param[in] h_Arg - The argument to pass in the timer-expired
+ callback routine.
+
+ @Return None.
+*//***************************************************************************/
+void XX_StartTimer(t_Handle h_Timer,
+ uint32_t msecs,
+ bool periodic,
+ void (*f_TimerExpired)(t_Handle h_Arg),
+ t_Handle h_Arg);
+
+/**************************************************************************//**
+ @Function XX_StopTimer
+
+ @Description Frees the memory allocated for the timer creation.
+
+ @Param[in] h_Timer - A handle to a timer.
+
+ @Return None.
+*//***************************************************************************/
+void XX_StopTimer(t_Handle h_Timer);
+
+/**************************************************************************//**
+ @Function XX_ModTimer
+
+ @Description Updates the expiration time of a timer.
+
+ This routine adds the given time to the current system time,
+ and sets this value as the new expiration time of the timer.
+
+ @Param[in] h_Timer - A handle to a timer.
+ @Param[in] msecs - The new interval until timer expiration
+ (in milliseconds).
+
+ @Return None.
+*//***************************************************************************/
+void XX_ModTimer(t_Handle h_Timer, uint32_t msecs);
+
+/**************************************************************************//**
+ @Function XX_Sleep
+
+ @Description Non-busy wait until the desired time (in milliseconds) has passed.
+
+ @Param[in] msecs - The requested sleep time (in milliseconds).
+
+ @Return Zero if the requested time has elapsed; Otherwise, the value
+ returned will be the unslept amount) in milliseconds.
+
+ @Cautions This routine enables interrupts during its wait time.
+*//***************************************************************************/
+uint32_t XX_Sleep(uint32_t msecs);
+
+/**************************************************************************//**
+ @Function XX_UDelay
+
+ @Description Busy-wait until the desired time (in microseconds) has passed.
+
+ @Param[in] usecs - The requested delay time (in microseconds).
+
+ @Return None.
+
+ @Cautions It is highly unrecommended to call this routine during interrupt
+ time, because the system time may not be updated properly during
+ the delay loop. The behavior of this routine during interrupt
+ time is unexpected.
+*//***************************************************************************/
+void XX_UDelay(uint32_t usecs);
+
+
+/*****************************************************************************/
+/* Other Service Routines */
+/*****************************************************************************/
+
+/**************************************************************************//**
+ @Function XX_PhysToVirt
+
+ @Description Translates a physical address to the matching virtual address.
+
+ @Param[in] addr - The physical address to translate.
+
+ @Return Virtual address.
+*//***************************************************************************/
+void * XX_PhysToVirt(physAddress_t addr);
+
+/**************************************************************************//**
+ @Function XX_VirtToPhys
+
+ @Description Translates a virtual address to the matching physical address.
+
+ @Param[in] addr - The virtual address to translate.
+
+ @Return Physical address.
+*//***************************************************************************/
+physAddress_t XX_VirtToPhys(void *addr);
+
+
+/**************************************************************************//**
+ @Group xx_ipc XX Inter-Partition-Communication API
+
+ @Description The following API is to be used when working with multiple
+ partitions configuration.
+
+ @{
+*//***************************************************************************/
+
+#define XX_IPC_MAX_ADDR_NAME_LENGTH 16 /**< Maximum length of an endpoint name string;
+ The IPC service can use this constant to limit
+ the storage space for IPC endpoint names. */
+
+
+/**************************************************************************//**
+ @Function t_IpcMsgCompletion
+
+ @Description Callback function used upon IPC non-blocking transaction completion
+ to return message buffer to the caller and to forward reply if available.
+
+ This callback function may be attached by the source endpoint to any outgoing
+ IPC message to indicate a non-blocking send (see also XX_IpcSendMessage() routine).
+ Upon completion of an IPC transaction (consisting of a message and an optional reply),
+ the IPC service invokes this callback routine to return the message buffer to the sender
+ and to provide the received reply, if requested.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_Module - Abstract handle to the sending module - the same handle as was passed
+ in the XX_IpcSendMessage() function; This handle is typically used to point
+ to the internal data structure of the source endpoint.
+ @Param[in] p_Msg - Pointer to original (sent) message buffer;
+ The source endpoint can free (or reuse) this buffer when message
+ completion callback is called.
+ @Param[in] p_Reply - Pointer to (received) reply buffer;
+ This pointer is the same as was provided by the source endpoint in
+ XX_IpcSendMessage().
+ @Param[in] replyLength - Length (in bytes) of actual data in the reply buffer.
+ @Param[in] status - Completion status - E_OK or failure indication, e.g. IPC transaction completion
+ timeout.
+
+ @Return None
+ *//***************************************************************************/
+typedef void (t_IpcMsgCompletion)(t_Handle h_Module,
+ uint8_t *p_Msg,
+ uint8_t *p_Reply,
+ uint32_t replyLength,
+ t_Error status);
+
+/**************************************************************************//**
+ @Function t_IpcMsgHandler
+
+ @Description Callback function used as IPC message handler.
+
+ The IPC service invokes message handlers for each IPC message received.
+ The actual function pointer should be registered by each destination endpoint
+ via the XX_IpcRegisterMsgHandler() routine.
+
+ User provides this function. Driver invokes it.
+
+ @Param[in] h_Module - Abstract handle to the message handling module - the same handle as
+ was passed in the XX_IpcRegisterMsgHandler() function; this handle is
+ typically used to point to the internal data structure of the destination
+ endpoint.
+ @Param[in] p_Msg - Pointer to message buffer with data received from peer.
+ @Param[in] msgLength - Length (in bytes) of message data.
+ @Param[in] p_Reply - Pointer to reply buffer, to be filled by the message handler and then sent
+ by the IPC service;
+ The reply buffer is allocated by the IPC service with size equals to the
+ replyLength parameter provided in message handler registration (see
+ XX_IpcRegisterMsgHandler() function);
+ If replyLength was initially specified as zero during message handler registration,
+ the IPC service may set this pointer to NULL and assume that a reply is not needed;
+ The IPC service is also responsible for freeing the reply buffer after the
+ reply has been sent or dismissed.
+ @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function:
+ [In] equals the replyLength parameter provided in message handler
+ registration (see XX_IpcRegisterMsgHandler() function), and
+ [Out] should be updated by message handler to the actual reply length; if
+ this value is set to zero, the IPC service must assume that a reply should
+ not be sent;
+ Note: If p_Reply is not NULL, p_ReplyLength must not be NULL as well.
+
+ @Return E_OK on success; Error code otherwise.
+ *//***************************************************************************/
+typedef t_Error (t_IpcMsgHandler)(t_Handle h_Module,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength);
+
+/**************************************************************************//**
+ @Function XX_IpcRegisterMsgHandler
+
+ @Description IPC mailbox registration.
+
+ This function is used for registering an IPC message handler in the IPC service.
+ This function is called by each destination endpoint to indicate that it is ready
+ to handle incoming messages. The IPC service invokes the message handler upon receiving
+ a message addressed to the specified destination endpoint.
+
+ @Param[in] addr - The address name string associated with the destination endpoint;
+ This address must be unique across the IPC service domain to ensure
+ correct message routing.
+ @Param[in] f_MsgHandler - Pointer to the message handler callback for processing incoming
+ message; invoked by the IPC service upon receiving a message
+ addressed to the destination endpoint specified by the addr
+ parameter.
+ @Param[in] h_Module - Abstract handle to the message handling module, passed unchanged
+ to f_MsgHandler callback function.
+ @Param[in] replyLength - The maximal data length (in bytes) of any reply that the specified message handler
+ may generate; the IPC service provides the message handler with buffer
+ for reply according to the length specified here (refer also to the description
+ of #t_IpcMsgHandler callback function type);
+ This size shall be zero if the message handler never generates replies.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ t_IpcMsgHandler *f_MsgHandler,
+ t_Handle h_Module,
+ uint32_t replyLength);
+
+/**************************************************************************//**
+ @Function XX_IpcUnregisterMsgHandler
+
+ @Description Release IPC mailbox routine.
+
+ This function is used for unregistering an IPC message handler from the IPC service.
+ This function is called by each destination endpoint to indicate that it is no longer
+ capable of handling incoming messages.
+
+ @Param[in] addr - The address name string associated with the destination endpoint;
+ This address is the same as was used when the message handler was
+ registered via XX_IpcRegisterMsgHandler().
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]);
+
+/**************************************************************************//**
+ @Function XX_IpcInitSession
+
+ @Description This function is used for creating an IPC session between the source endpoint
+ and the destination endpoint.
+
+ The actual implementation and representation of a session is left for the IPC service.
+ The function returns an abstract handle to the created session. This handle shall be used
+ by the source endpoint in subsequent calls to XX_IpcSendMessage().
+ The IPC service assumes that before this function is called, no messages are sent from
+ the specified source endpoint to the specified destination endpoint.
+
+ The IPC service may use a connection-oriented approach or a connectionless approach (or both)
+ as described below.
+
+ @par Connection-Oriented Approach
+
+ The IPC service may implement a session in a connection-oriented approach - when this function is called,
+ the IPC service should take the necessary steps to bring up a source-to-destination channel for messages
+ and a destination-to-source channel for replies. The returned handle should represent the internal
+ representation of these channels.
+
+ @par Connectionless Approach
+
+ The IPC service may implement a session in a connectionless approach - when this function is called, the
+ IPC service should not perform any particular steps, but it must store the pair of source and destination
+ addresses in some session representation and return it as a handle. When XX_IpcSendMessage() shall be
+ called, the IPC service may use this handle to provide the necessary identifiers for routing the messages
+ through the connectionless medium.
+
+ @Param[in] destAddr - The address name string associated with the destination endpoint.
+ @Param[in] srcAddr - The address name string associated with the source endpoint.
+
+ @Return Abstract handle to the initialized session, or NULL on error.
+*//***************************************************************************/
+t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]);
+
+/**************************************************************************//**
+ @Function XX_IpcFreeSession
+
+ @Description This function is used for terminating an existing IPC session between a source endpoint
+ and a destination endpoint.
+
+ The IPC service assumes that after this function is called, no messages shall be sent from
+ the associated source endpoint to the associated destination endpoint.
+
+ @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally
+ returned by the XX_IpcInitSession() function.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error XX_IpcFreeSession(t_Handle h_Session);
+
+/**************************************************************************//**
+ @Function XX_IpcSendMessage
+
+ @Description IPC message send routine.
+
+ This function may be used by a source endpoint to send an IPC message to a destination
+ endpoint. The source endpoint cannot send a message to the destination endpoint without
+ first initiating a session with that destination endpoint via XX_IpcInitSession() routine.
+
+ The source endpoint must provide the buffer pointer and length of the outgoing message.
+ Optionally, it may also provide a buffer for an expected reply. In the latter case, the
+ transaction is not considered complete by the IPC service until the reply has been received.
+ If the source endpoint does not provide a reply buffer, the transaction is considered
+ complete after the message has been sent. The source endpoint must keep the message (and
+ optional reply) buffers valid until the transaction is complete.
+
+ @par Non-blocking mode
+
+ The source endpoint may request a non-blocking send by providing a non-NULL pointer to a message
+ completion callback function (f_Completion). Upon completion of the IPC transaction (consisting of a
+ message and an optional reply), the IPC service invokes this callback routine to return the message
+ buffer to the sender and to provide the received reply, if requested.
+
+ @par Blocking mode
+
+ The source endpoint may request a blocking send by setting f_Completion to NULL. The function is
+ expected to block until the IPC transaction is complete - either the reply has been received or (if no reply
+ was requested) the message has been sent.
+
+ @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally
+ returned by the XX_IpcInitSession() function.
+ @Param[in] p_Msg - Pointer to message buffer to send.
+ @Param[in] msgLength - Length (in bytes) of actual data in the message buffer.
+ @Param[in] p_Reply - Pointer to reply buffer - if this buffer is not NULL, the IPC service
+ fills this buffer with the received reply data;
+ In blocking mode, the reply data must be valid when the function returns;
+ In non-blocking mode, the reply data is valid when f_Completion is called;
+ If this pointer is NULL, no reply is expected.
+ @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function:
+ [In] specifies the maximal length (in bytes) of the reply buffer pointed by
+ p_Reply, and
+ [Out] in non-blocking mode this value is updated by the IPC service to the
+ actual reply length (in bytes).
+ @Param[in] f_Completion - Pointer to a completion callback to be used in non-blocking send mode;
+ The completion callback is invoked by the IPC service upon
+ completion of the IPC transaction (consisting of a message and an optional
+ reply);
+ If this pointer is NULL, the function is expected to block until the IPC
+ transaction is complete.
+ @Param[in] h_Arg - Abstract handle to the sending module; passed unchanged to the f_Completion
+ callback function as the first argument.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error XX_IpcSendMessage(t_Handle h_Session,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength,
+ t_IpcMsgCompletion *f_Completion,
+ t_Handle h_Arg);
+
+
+/** @} */ /* end of xx_ipc group */
+/** @} */ /* end of xx_id group */
+
+
+#endif /* __XX_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h
new file mode 100644
index 000000000000..c3a5a623bf23
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __dflags_h
+#define __dflags_h
+
+
+#define NCSW_LINUX
+
+#define LS1043
+
+#define DEBUG_ERRORS 1
+
+#if defined(DEBUG)
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO
+
+#define DEBUG_XX_MALLOC
+#define DEBUG_MEM_LEAKS
+
+#else
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* (DEBUG) */
+
+#define REPORT_EVENTS 1
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+
+#endif /* __dflags_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk b/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
new file mode 100644
index 000000000000..586f9c79eca3
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
@@ -0,0 +1,53 @@
+#
+# Makefile config for the Freescale NetcommSW
+#
+NET_DPA = $(srctree)/drivers/net
+DRV_DPA = $(srctree)/drivers/net/ethernet/freescale/sdk_dpaa
+FMAN = $(srctree)/drivers/net/ethernet/freescale/sdk_fman
+
+ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y")
+ccflags-y +=-include $(FMAN)/p3040_4080_5020_dflags.h
+endif
+ifeq ("$(CONFIG_FMAN_P1023)", "y")
+ccflags-y +=-include $(FMAN)/p1023_dflags.h
+endif
+ifdef CONFIG_FMAN_V3H
+ccflags-y +=-include $(FMAN)/fmanv3h_dflags.h
+endif
+ifdef CONFIG_FMAN_V3L
+ccflags-y +=-include $(FMAN)/fmanv3l_dflags.h
+endif
+ifdef CONFIG_FMAN_ARM
+ccflags-y +=-include $(FMAN)/ls1043_dflags.h
+endif
+
+ccflags-y += -I$(DRV_DPA)/
+ccflags-y += -I$(FMAN)/inc
+ccflags-y += -I$(FMAN)/inc/cores
+ccflags-y += -I$(FMAN)/inc/etc
+ccflags-y += -I$(FMAN)/inc/Peripherals
+ccflags-y += -I$(FMAN)/inc/flib
+
+ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y")
+ccflags-y += -I$(FMAN)/inc/integrations/P3040_P4080_P5020
+endif
+ifeq ("$(CONFIG_FMAN_P1023)", "y")
+ccflags-y += -I$(FMAN)/inc/integrations/P1023
+endif
+ifdef CONFIG_FMAN_V3H
+ccflags-y += -I$(FMAN)/inc/integrations/FMANV3H
+endif
+ifdef CONFIG_FMAN_V3L
+ccflags-y += -I$(FMAN)/inc/integrations/FMANV3L
+endif
+ifdef CONFIG_FMAN_ARM
+ccflags-y += -I$(FMAN)/inc/integrations/LS1043
+endif
+
+ccflags-y += -I$(FMAN)/src/inc
+ccflags-y += -I$(FMAN)/src/inc/system
+ccflags-y += -I$(FMAN)/src/inc/wrapper
+ccflags-y += -I$(FMAN)/src/inc/xx
+ccflags-y += -I$(srctree)/include/uapi/linux/fmd
+ccflags-y += -I$(srctree)/include/uapi/linux/fmd/Peripherals
+ccflags-y += -I$(srctree)/include/uapi/linux/fmd/integrations
diff --git a/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h
new file mode 100644
index 000000000000..b48819d734f4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __dflags_h
+#define __dflags_h
+
+
+#define NCSW_LINUX
+#if 0
+#define DEBUG
+#endif
+
+#define P1023
+#define NCSW_PPC_CORE
+
+#define DEBUG_ERRORS 1
+
+#if defined(DEBUG)
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO
+
+#define DEBUG_XX_MALLOC
+#define DEBUG_MEM_LEAKS
+
+#else
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* (DEBUG) */
+
+#define REPORT_EVENTS 1
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+
+#ifdef CONFIG_P4080_SIM
+#error "Do not define CONFIG_P4080_SIM..."
+#endif
+
+
+#endif /* __dflags_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h
new file mode 100644
index 000000000000..7438974242db
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __dflags_h
+#define __dflags_h
+
+
+#define NCSW_LINUX
+
+#define P4080
+#define NCSW_PPC_CORE
+
+#define DEBUG_ERRORS 1
+
+#if defined(DEBUG)
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO
+
+#define DEBUG_XX_MALLOC
+#define DEBUG_MEM_LEAKS
+
+#else
+#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING
+#endif /* (DEBUG) */
+
+#define REPORT_EVENTS 1
+#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR
+
+#ifdef CONFIG_P4080_SIM
+#define SIMULATOR
+#endif /* CONFIG_P4080_SIM */
+
+
+#endif /* __dflags_h */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/Makefile
new file mode 100644
index 000000000000..49405d0ec925
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+#
+obj-y += system/
+obj-y += wrapper/
+obj-y += xx/
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h
new file mode 100644
index 000000000000..20f27d29d353
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __SYS_EXT_H
+#define __SYS_EXT_H
+
+#include "std_ext.h"
+
+
+/**************************************************************************//**
+ @Group sys_grp System Interfaces
+
+ @Description Linux system programming interfaces.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group sys_gen_grp System General Interface
+
+ @Description General definitions, structures and routines of the linux
+ system programming interface.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Collection Macros for Advanced Configuration Requests
+ @{
+*//***************************************************************************/
+#define SYS_MAX_ADV_CONFIG_ARGS 4
+ /**< Maximum number of arguments in
+ an advanced configuration entry */
+/* @} */
+
+/**************************************************************************//**
+ @Description System Object Advanced Configuration Entry
+
+ This structure represents a single request for an advanced
+ configuration call on the initialized object. An array of such
+ requests may be contained in the settings structure of the
+ corresponding object.
+
+ The maximum number of arguments is limited to #SYS_MAX_ADV_CONFIG_ARGS.
+*//***************************************************************************/
+typedef struct t_SysObjectAdvConfigEntry
+{
+ void *p_Function; /**< Pointer to advanced configuration routine */
+
+ uintptr_t args[SYS_MAX_ADV_CONFIG_ARGS];
+ /**< Array of arguments for the specified routine;
+ All arguments should be casted to uint32_t. */
+} t_SysObjectAdvConfigEntry;
+
+
+/** @} */ /* end of sys_gen_grp */
+/** @} */ /* end of sys_grp */
+
+#define NCSW_PARAMS(_num, _params) ADV_CONFIG_PARAMS_##_num _params
+
+#define ADV_CONFIG_PARAMS_1(_type) \
+ , (_type)p_Entry->args[0]
+
+#define SET_ADV_CONFIG_ARGS_1(_arg0) \
+ p_Entry->args[0] = (uintptr_t )(_arg0); \
+
+#define ARGS(_num, _params) SET_ADV_CONFIG_ARGS_##_num _params
+
+#define ADD_ADV_CONFIG_START(_p_Entries, _maxEntries) \
+ { \
+ t_SysObjectAdvConfigEntry *p_Entry; \
+ t_SysObjectAdvConfigEntry *p_Entrys = (_p_Entries); \
+ int i=0, max = (_maxEntries); \
+
+#define ADD_ADV_CONFIG_END \
+ }
+
+#define ADV_CONFIG_CHECK_START(_p_Entry) \
+ { \
+ t_SysObjectAdvConfigEntry *p_Entry = _p_Entry; \
+ t_Error errCode; \
+
+#define ADV_CONFIG_CHECK(_handle, _func, _params) \
+ if (p_Entry->p_Function == _func) \
+ { \
+ errCode = _func(_handle _params); \
+ } else
+
+#endif /* __SYS_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h
new file mode 100644
index 000000000000..d6aa9d414c0b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __SYS_IO_EXT_H
+#define __SYS_IO_EXT_H
+
+#include "std_ext.h"
+#include "error_ext.h"
+
+
+t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size);
+t_Error SYS_UnregisterIoMap (uint64_t virtAddr);
+uint64_t SYS_PhysToVirt (uint64_t addr);
+uint64_t SYS_VirtToPhys (uint64_t addr);
+
+
+#endif /* __SYS_IO_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h
new file mode 100644
index 000000000000..201ad6999a63
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __TYPES_LINUX_H__
+#define __TYPES_LINUX_H__
+
+#include <linux/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+ #error "This kernel is probably not supported!!!"
+#elif (!((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) || \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)) || \
+ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30))))
+ #warning "This kernel is probably not supported!!! You may need to add some fixes."
+#endif /* LINUX_VERSION_CODE */
+
+
+typedef float float_t; /* Single precision floating point */
+typedef double double_t; /* Double precision floating point */
+
+
+#define _Packed
+#define _PackedType __attribute__ ((packed))
+
+typedef phys_addr_t physAddress_t;
+
+#define UINT8_MAX 0xFF
+#define UINT8_MIN 0
+#define UINT16_MAX 0xFFFF
+#define UINT16_MIN 0
+#define UINT32_MAX 0xFFFFFFFF
+#define UINT32_MIN 0
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFLL
+#define UINT64_MIN 0
+#define INT8_MAX 0x7F
+#define INT8_MIN 0x80
+#define INT16_MAX 0x7FFF
+#define INT16_MIN 0x8000
+#define INT32_MAX 0x7FFFFFFF
+#define INT32_MIN 0x80000000
+#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL
+#define INT64_MIN 0x8000000000000000LL
+
+#define ON 1
+#define OFF 0
+
+#define FALSE false
+#define TRUE true
+
+
+/************************/
+/* memory access macros */
+/************************/
+#ifdef CONFIG_FMAN_ARM
+#define in_be16(a) __be16_to_cpu(__raw_readw(a))
+#define in_be32(a) __be32_to_cpu(__raw_readl(a))
+#define out_be16(a, v) __raw_writew(__cpu_to_be16(v), a)
+#define out_be32(a, v) __raw_writel(__cpu_to_be32(v), a)
+#endif
+
+#define GET_UINT8(arg) *(volatile uint8_t *)(&(arg))
+#define GET_UINT16(arg) in_be16(&(arg))//*(volatile uint16_t*)(&(arg))
+#define GET_UINT32(arg) in_be32(&(arg))//*(volatile uint32_t*)(&(arg))
+#define GET_UINT64(arg) *(volatile uint64_t*)(&(arg))
+
+#ifdef VERBOSE_WRITE
+void XX_Print(char *str, ...);
+#define WRITE_UINT8(arg, data) \
+ do { XX_Print("ADDR: 0x%08x, VAL: 0x%02x\r\n", (uint32_t)&(arg), (data)); *(volatile uint8_t *)(&(arg)) = (data); } while (0)
+#define WRITE_UINT16(arg, data) \
+ do { XX_Print("ADDR: 0x%08x, VAL: 0x%04x\r\n", (uint32_t)&(arg), (data)); out_be16(&(arg), data); /* *(volatile uint16_t*)(&(arg)) = (data);*/ } while (0)
+#define WRITE_UINT32(arg, data) \
+ do { XX_Print("ADDR: 0x%08x, VAL: 0x%08x\r\n", (uint32_t)&(arg), (data)); out_be32(&(arg), data); /* *(volatile uint32_t*)(&(arg)) = (data);*/ } while (0)
+#define WRITE_UINT64(arg, data) \
+ do { XX_Print("ADDR: 0x%08x, VAL: 0x%016llx\r\n", (uint32_t)&(arg), (data)); *(volatile uint64_t*)(&(arg)) = (data); } while (0)
+
+#else /* not VERBOSE_WRITE */
+#define WRITE_UINT8(arg, data) *(volatile uint8_t *)(&(arg)) = (data)
+#define WRITE_UINT16(arg, data) out_be16(&(arg), data)//*(volatile uint16_t*)(&(arg)) = (data)
+#define WRITE_UINT32(arg, data) out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data)
+#define WRITE_UINT64(arg, data) *(volatile uint64_t*)(&(arg)) = (data)
+#endif /* not VERBOSE_WRITE */
+
+
+/*****************************************************************************/
+/* General stuff */
+/*****************************************************************************/
+#ifdef ARRAY_SIZE
+#undef ARRAY_SIZE
+#endif /* ARRAY_SIZE */
+
+#ifdef MAJOR
+#undef MAJOR
+#endif /* MAJOR */
+
+#ifdef MINOR
+#undef MINOR
+#endif /* MINOR */
+
+#ifdef QE_SIZEOF_BD
+#undef QE_SIZEOF_BD
+#endif /* QE_SIZEOF_BD */
+
+#ifdef BD_BUFFER_CLEAR
+#undef BD_BUFFER_CLEAR
+#endif /* BD_BUFFER_CLEAR */
+
+#ifdef BD_BUFFER
+#undef BD_BUFFER
+#endif /* BD_BUFFER */
+
+#ifdef BD_STATUS_AND_LENGTH_SET
+#undef BD_STATUS_AND_LENGTH_SET
+#endif /* BD_STATUS_AND_LENGTH_SET */
+
+#ifdef BD_STATUS_AND_LENGTH
+#undef BD_STATUS_AND_LENGTH
+#endif /* BD_STATUS_AND_LENGTH */
+
+#ifdef BD_BUFFER_ARG
+#undef BD_BUFFER_ARG
+#endif /* BD_BUFFER_ARG */
+
+#ifdef BD_GET_NEXT
+#undef BD_GET_NEXT
+#endif /* BD_GET_NEXT */
+
+#ifdef QE_SDEBCR_BA_MASK
+#undef QE_SDEBCR_BA_MASK
+#endif /* QE_SDEBCR_BA_MASK */
+
+#ifdef BD_BUFFER_SET
+#undef BD_BUFFER_SET
+#endif /* BD_BUFFER_SET */
+
+#ifdef UPGCR_PROTOCOL
+#undef UPGCR_PROTOCOL
+#endif /* UPGCR_PROTOCOL */
+
+#ifdef UPGCR_TMS
+#undef UPGCR_TMS
+#endif /* UPGCR_TMS */
+
+#ifdef UPGCR_RMS
+#undef UPGCR_RMS
+#endif /* UPGCR_RMS */
+
+#ifdef UPGCR_ADDR
+#undef UPGCR_ADDR
+#endif /* UPGCR_ADDR */
+
+#ifdef UPGCR_DIAG
+#undef UPGCR_DIAG
+#endif /* UPGCR_DIAG */
+
+#ifdef NCSW_PARAMS
+#undef NCSW_PARAMS
+#endif /* NCSW_PARAMS */
+
+#ifdef NO_IRQ
+#undef NO_IRQ
+#endif /* NO_IRQ */
+
+#define PRINT_LINE XX_Print("%s:\n %s [%d]\n",__FILE__,__FUNCTION__,__LINE__);
+
+
+#endif /* __TYPES_LINUX_H__ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h
new file mode 100644
index 000000000000..0466a4734aae
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2008-2011 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File fsl_fman_test.h
+
+ @Description
+*//***************************************************************************/
+
+#ifndef __FSL_FMAN_TEST_H
+#define __FSL_FMAN_TEST_H
+
+#include <linux/types.h>
+#include <linux/smp.h> /* raw_smp_processor_id() */
+
+//#define FMT_K_DBG
+//#define FMT_K_DBG_RUNTIME
+
+#define _fmt_prk(stage, format, arg...) \
+ printk(stage "fmt (cpu:%u): " format, raw_smp_processor_id(), ##arg)
+
+#define _fmt_inf(format, arg...) _fmt_prk(KERN_INFO, format, ##arg)
+#define _fmt_wrn(format, arg...) _fmt_prk(KERN_WARNING, format, ##arg)
+#define _fmt_err(format, arg...) _fmt_prk(KERN_ERR, format, ##arg)
+
+/* there are two macros for debugging: for runtime and generic.
+ * Helps when the runtime functions are not targeted for debugging,
+ * thus all the unnecessary information will be skipped.
+ */
+/* used for generic debugging */
+#if defined(FMT_K_DBG)
+ #define _fmt_dbg(format, arg...) \
+ printk("fmt [%s:%u](cpu:%u) - " format, \
+ __func__, __LINE__, raw_smp_processor_id(), ##arg)
+#else
+# define _fmt_dbg(arg...)
+#endif
+
+/* used for debugging runtime functions */
+#if defined(FMT_K_DBG_RUNTIME)
+ #define _fmt_dbgr(format, arg...) \
+ printk("fmt [%s:%u](cpu:%u) - " format, \
+ __func__, __LINE__, raw_smp_processor_id(), ##arg)
+#else
+# define _fmt_dbgr(arg...)
+#endif
+
+#define FMT_RX_ERR_Q 0xffffffff
+#define FMT_RX_DFLT_Q 0xfffffffe
+#define FMT_TX_ERR_Q 0xfffffffd
+#define FMT_TX_CONF_Q 0xfffffffc
+
+#define FMAN_TEST_MAX_TX_FQS 8
+
+#endif /* __FSL_FMAN_TEST_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
new file mode 100644
index 000000000000..dd0f03acfc9c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h
@@ -0,0 +1,130 @@
+/* Copyright (c) 2008-2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_exp_sym.h
+ @Description FMan exported routines
+*/
+
+#ifndef __LNXWRP_EXP_SYM_H
+#define __LNXWRP_EXP_SYM_H
+
+#include "fm_port_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_mac_ext.h"
+
+
+/* FMAN Port exported routines */
+EXPORT_SYMBOL(FM_PORT_Disable);
+EXPORT_SYMBOL(FM_PORT_Enable);
+EXPORT_SYMBOL(FM_PORT_SetPCD);
+EXPORT_SYMBOL(FM_PORT_DeletePCD);
+
+/* Runtime PCD exported routines */
+EXPORT_SYMBOL(FM_PCD_Enable);
+EXPORT_SYMBOL(FM_PCD_Disable);
+EXPORT_SYMBOL(FM_PCD_GetCounter);
+EXPORT_SYMBOL(FM_PCD_PrsLoadSw);
+EXPORT_SYMBOL(FM_PCD_KgSetDfltValue);
+EXPORT_SYMBOL(FM_PCD_KgSetAdditionalDataAfterParsing);
+EXPORT_SYMBOL(FM_PCD_SetException);
+EXPORT_SYMBOL(FM_PCD_ModifyCounter);
+EXPORT_SYMBOL(FM_PCD_SetPlcrStatistics);
+EXPORT_SYMBOL(FM_PCD_SetPrsStatistics);
+EXPORT_SYMBOL(FM_PCD_ForceIntr);
+EXPORT_SYMBOL(FM_PCD_HcTxConf);
+
+EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsSet);
+EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsDelete);
+EXPORT_SYMBOL(FM_PCD_KgSchemeSet);
+EXPORT_SYMBOL(FM_PCD_KgSchemeDelete);
+EXPORT_SYMBOL(FM_PCD_KgSchemeGetCounter);
+EXPORT_SYMBOL(FM_PCD_KgSchemeSetCounter);
+EXPORT_SYMBOL(FM_PCD_CcRootBuild);
+EXPORT_SYMBOL(FM_PCD_CcRootDelete);
+EXPORT_SYMBOL(FM_PCD_MatchTableSet);
+EXPORT_SYMBOL(FM_PCD_MatchTableDelete);
+EXPORT_SYMBOL(FM_PCD_CcRootModifyNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableModifyNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableModifyMissNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableRemoveKey);
+EXPORT_SYMBOL(FM_PCD_MatchTableFindNRemoveKey);
+EXPORT_SYMBOL(FM_PCD_MatchTableAddKey);
+EXPORT_SYMBOL(FM_PCD_MatchTableModifyKeyAndNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKeyAndNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableModifyKey);
+EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKey);
+EXPORT_SYMBOL(FM_PCD_MatchTableGetIndexedHashBucket);
+EXPORT_SYMBOL(FM_PCD_MatchTableGetNextEngine);
+EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyCounter);
+EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyStatistics);
+EXPORT_SYMBOL(FM_PCD_MatchTableFindNGetKeyStatistics);
+EXPORT_SYMBOL(FM_PCD_MatchTableGetMissStatistics);
+EXPORT_SYMBOL(FM_PCD_HashTableGetMissStatistics);
+EXPORT_SYMBOL(FM_PCD_HashTableSet);
+EXPORT_SYMBOL(FM_PCD_HashTableDelete);
+EXPORT_SYMBOL(FM_PCD_HashTableAddKey);
+EXPORT_SYMBOL(FM_PCD_HashTableRemoveKey);
+EXPORT_SYMBOL(FM_PCD_HashTableModifyNextEngine);
+EXPORT_SYMBOL(FM_PCD_HashTableModifyMissNextEngine);
+EXPORT_SYMBOL(FM_PCD_HashTableGetMissNextEngine);
+EXPORT_SYMBOL(FM_PCD_HashTableFindNGetKeyStatistics);
+EXPORT_SYMBOL(FM_PCD_PlcrProfileSet);
+EXPORT_SYMBOL(FM_PCD_PlcrProfileDelete);
+EXPORT_SYMBOL(FM_PCD_PlcrProfileGetCounter);
+EXPORT_SYMBOL(FM_PCD_PlcrProfileSetCounter);
+EXPORT_SYMBOL(FM_PCD_ManipNodeSet);
+EXPORT_SYMBOL(FM_PCD_ManipNodeDelete);
+EXPORT_SYMBOL(FM_PCD_ManipGetStatistics);
+EXPORT_SYMBOL(FM_PCD_ManipNodeReplace);
+#if (DPAA_VERSION >= 11)
+EXPORT_SYMBOL(FM_PCD_FrmReplicSetGroup);
+EXPORT_SYMBOL(FM_PCD_FrmReplicDeleteGroup);
+EXPORT_SYMBOL(FM_PCD_FrmReplicAddMember);
+EXPORT_SYMBOL(FM_PCD_FrmReplicRemoveMember);
+#endif /* DPAA_VERSION >= 11 */
+
+#ifdef FM_CAPWAP_SUPPORT
+EXPORT_SYMBOL(FM_PCD_StatisticsSetNode);
+#endif /* FM_CAPWAP_SUPPORT */
+
+EXPORT_SYMBOL(FM_PCD_SetAdvancedOffloadSupport);
+
+/* FMAN MAC exported routines */
+EXPORT_SYMBOL(FM_MAC_GetStatistics);
+
+EXPORT_SYMBOL(FM_MAC_GetFrameSizeCounters);
+
+EXPORT_SYMBOL(FM_GetSpecialOperationCoding);
+
+#endif /* __LNXWRP_EXP_SYM_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h
new file mode 100644
index 000000000000..a72c86702382
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File lnxwrp_fm_ext.h
+
+ @Description TODO
+*//***************************************************************************/
+
+#ifndef __LNXWRP_FM_EXT_H
+#define __LNXWRP_FM_EXT_H
+
+#include "std_ext.h"
+#include "sys_ext.h"
+#include "fm_ext.h"
+#include "fm_muram_ext.h"
+#include "fm_pcd_ext.h"
+#include "fm_port_ext.h"
+#include "fm_mac_ext.h"
+#include "fm_rtc_ext.h"
+
+
+/**************************************************************************//**
+ @Group FM_LnxKern_grp Frame Manager Linux wrapper API
+
+ @Description FM API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_LnxKern_init_grp Initialization Unit
+
+ @Description Initialization Unit
+
+ Initialization Flow:
+ Initialization of the FM Module will be carried out by the Linux
+ kernel according to the following sequence:
+ a. Calling the initialization routine with no parameters.
+ b. The driver will register to the Device-Tree.
+ c. The Linux Device-Tree will initiate a call to the driver for
+ initialization.
+ d. The driver will read the appropriate information from the Device-Tree
+ e. [Optional] Calling the advance initialization routines to change
+ driver's defaults.
+ f. Initialization of the device will be automatically upon using it.
+
+ @{
+*//***************************************************************************/
+
+typedef struct t_WrpFmDevSettings
+{
+ t_FmParams param;
+ t_SysObjectAdvConfigEntry *advConfig;
+} t_WrpFmDevSettings;
+
+typedef struct t_WrpFmPcdDevSettings
+{
+ t_FmPcdParams param;
+ t_SysObjectAdvConfigEntry *advConfig;
+} t_WrpFmPcdDevSettings;
+
+typedef struct t_WrpFmPortDevSettings
+{
+ bool frag_enabled;
+ t_FmPortParams param;
+ t_SysObjectAdvConfigEntry *advConfig;
+} t_WrpFmPortDevSettings;
+
+typedef struct t_WrpFmMacDevSettings
+{
+ t_FmMacParams param;
+ t_SysObjectAdvConfigEntry *advConfig;
+} t_WrpFmMacDevSettings;
+
+
+/**************************************************************************//**
+ @Function LNXWRP_FM_Init
+
+ @Description Initialize the FM linux wrapper.
+
+ @Return A handle (descriptor) of the newly created FM Linux wrapper
+ structure.
+*//***************************************************************************/
+t_Handle LNXWRP_FM_Init(void);
+
+/**************************************************************************//**
+ @Function LNXWRP_FM_Free
+
+ @Description Free the FM linux wrapper.
+
+ @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper.
+
+ @Return E_OK on success; Error code otherwise.
+*//***************************************************************************/
+t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm);
+
+/**************************************************************************//**
+ @Function LNXWRP_FM_GetMacHandle
+
+ @Description Get the FM-MAC LLD handle from the FM linux wrapper.
+
+ @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper.
+ @Param[in] fmId - Index of the FM device to get the MAC handle from.
+ @Param[in] macId - Index of the mac handle.
+
+ @Return A handle of the LLD compressor.
+*//***************************************************************************/
+t_Handle LNXWRP_FM_GetMacHandle(t_Handle h_LnxWrpFm, uint8_t fmId, uint8_t macId);
+
+#ifdef CONFIG_FSL_SDK_FMAN_TEST
+t_Handle LNXWRP_FM_TEST_Init(void);
+t_Error LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp);
+#endif /* CONFIG_FSL_SDK_FMAN_TEST */
+
+/** @} */ /* end of FM_LnxKern_init_grp group */
+
+
+/**************************************************************************//**
+ @Group FM_LnxKern_ctrl_grp Control Unit
+
+ @Description Control Unit
+
+ TODO
+ @{
+*//***************************************************************************/
+
+#include "lnxwrp_fsl_fman.h"
+
+/** @} */ /* end of FM_LnxKern_ctrl_grp group */
+/** @} */ /* end of FM_LnxKern_grp group */
+
+
+#endif /* __LNXWRP_FM_EXT_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
new file mode 100644
index 000000000000..b0c151ffb628
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h
@@ -0,0 +1,953 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/******************************************************************************
+ @File lnxwrp_fsl_fman.h
+
+ @Description Linux internal kernel API
+*//***************************************************************************/
+
+#ifndef __LNXWRP_FSL_FMAN_H
+#define __LNXWRP_FSL_FMAN_H
+
+#include <linux/types.h>
+#include <linux/device.h> /* struct device */
+#include <linux/fsl_qman.h> /* struct qman_fq */
+#include "dpaa_integration_ext.h"
+#include "fm_port_ext.h"
+#include "fm_mac_ext.h"
+#include "fm_macsec_ext.h"
+#include "fm_rtc_ext.h"
+
+/**************************************************************************//**
+ @Group FM_LnxKern_grp Frame Manager Linux wrapper API
+
+ @Description FM API functions, definitions and enums.
+
+ @{
+*//***************************************************************************/
+
+/**************************************************************************//**
+ @Group FM_LnxKern_ctrl_grp Control Unit
+
+ @Description Control Unit
+
+ Internal Kernel Control Unit API
+ @{
+*//***************************************************************************/
+
+/*****************************************************************************/
+/* Internal Linux kernel routines */
+/*****************************************************************************/
+
+/**************************************************************************//**
+ @Description MACSEC Exceptions wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_exception {
+ SINGLE_BIT_ECC = e_FM_MACSEC_EX_SINGLE_BIT_ECC,
+ MULTI_BIT_ECC = e_FM_MACSEC_EX_MULTI_BIT_ECC
+} fm_macsec_exception;
+
+/**************************************************************************//**
+ @Description Unknown sci frame treatment wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_unknown_sci_frame_treatment {
+ SCI_DISCARD_BOTH = e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH,
+ SCI_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED,
+ SCI_DELIVER_UNCTRL_DISCARD_CTRL = \
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED,
+ SCI_DELIVER_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \
+ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED
+} fm_macsec_unknown_sci_frame_treatment;
+
+/**************************************************************************//**
+ @Description Untag frame treatment wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_untag_frame_treatment {
+ UNTAG_DELIVER_UNCTRL_DISCARD_CTRL = \
+ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED,
+ UNTAG_DISCARD_BOTH = e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH,
+ UNTAG_DISCARD_UNCTRL_DELIVER_CTRL_UNMODIFIED = \
+ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED
+} fm_macsec_untag_frame_treatment;
+
+/**************************************************************************//**
+@Description MACSEC SECY Cipher Suite wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_secy_cipher_suite {
+ SECY_GCM_AES_128 = e_FM_MACSEC_SECY_GCM_AES_128, /**< GCM-AES-128 */
+#if (DPAA_VERSION >= 11)
+ SECY_GCM_AES_256 = e_FM_MACSEC_SECY_GCM_AES_256 /**< GCM-AES-256 */
+#endif /* (DPAA_VERSION >= 11) */
+} fm_macsec_secy_cipher_suite;
+
+/**************************************************************************//**
+ @Description MACSEC SECY Exceptions wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_secy_exception {
+ SECY_EX_FRAME_DISCARDED = e_FM_MACSEC_SECY_EX_FRAME_DISCARDED
+} fm_macsec_secy_exception;
+
+/**************************************************************************//**
+ @Description MACSEC SECY Events wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_secy_event {
+ SECY_EV_NEXT_PN = e_FM_MACSEC_SECY_EV_NEXT_PN
+} fm_macsec_secy_event;
+
+/**************************************************************************//**
+ @Description Valid frame behaviors wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_valid_frame_behavior {
+ VALID_FRAME_BEHAVIOR_DISABLE = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE,
+ VALID_FRAME_BEHAVIOR_CHECK = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK,
+ VALID_FRAME_BEHAVIOR_STRICT = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT
+} fm_macsec_valid_frame_behavior;
+
+/**************************************************************************//**
+ @Description SCI insertion modes wrapper
+*//***************************************************************************/
+typedef enum fm_macsec_sci_insertion_mode {
+ SCI_INSERTION_MODE_EXPLICIT_SECTAG = \
+ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG,
+ SCI_INSERTION_MODE_EXPLICIT_MAC_SA = \
+ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA,
+ SCI_INSERTION_MODE_IMPLICT_PTP = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP
+} fm_macsec_sci_insertion_mode;
+
+typedef macsecSAKey_t macsec_sa_key_t;
+typedef macsecSCI_t macsec_sci_t;
+typedef macsecAN_t macsec_an_t;
+typedef t_Handle handle_t;
+
+/**************************************************************************//**
+ @Function fm_macsec_secy_exception_callback wrapper
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+ @Param[in] app_h A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] exception The exception.
+*//***************************************************************************/
+typedef void (fm_macsec_secy_exception_callback) (handle_t app_h,
+ fm_macsec_secy_exception exception);
+
+/**************************************************************************//**
+ @Function fm_macsec_secy_event_callback wrapper
+ @Description Events user callback routine, will be called upon an
+ event passing the event identification.
+ @Param[in] app_h A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] event The event.
+*//***************************************************************************/
+typedef void (fm_macsec_secy_event_callback) (handle_t app_h,
+ fm_macsec_secy_event event);
+
+/**************************************************************************//**
+ @Function fm_macsec_exception_callback wrapper
+ @Description Exceptions user callback routine, will be called upon an
+ exception passing the exception identification.
+ @Param[in] app_h A handle to an application layer object; This handle
+ will be passed by the driver upon calling this callback.
+ @Param[in] exception The exception.
+*//***************************************************************************/
+typedef void (fm_macsec_exception_callback) (handle_t app_h,
+ fm_macsec_exception exception);
+
+/**************************************************************************//**
+ @Description MACSEC SecY SC Params wrapper
+*//***************************************************************************/
+struct fm_macsec_secy_sc_params {
+ macsec_sci_t sci;
+ fm_macsec_secy_cipher_suite cipher_suite;
+};
+
+/**************************************************************************//**
+ @Description FM MACSEC SecY config input wrapper
+*//***************************************************************************/
+struct fm_macsec_secy_params {
+ handle_t fm_macsec_h;
+ struct fm_macsec_secy_sc_params tx_sc_params;
+ uint32_t num_receive_channels;
+ fm_macsec_secy_exception_callback *exception_f;
+ fm_macsec_secy_event_callback *event_f;
+ handle_t app_h;
+};
+
+/**************************************************************************//**
+ @Description FM MACSEC config input wrapper
+*//***************************************************************************/
+struct fm_macsec_params {
+ handle_t fm_h;
+ bool guest_mode;
+
+ union {
+ struct {
+ uint8_t fm_mac_id;
+ } guest_params;
+
+ struct {
+ uintptr_t base_addr;
+ handle_t fm_mac_h;
+ fm_macsec_exception_callback *exception_f;
+ handle_t app_h;
+ } non_guest_params;
+ };
+
+};
+
+/**************************************************************************//**
+ @Description FM device opaque structure used for type checking
+*//***************************************************************************/
+struct fm;
+
+/**************************************************************************//**
+ @Description FM MAC device opaque structure used for type checking
+*//***************************************************************************/
+struct fm_mac_dev;
+
+/**************************************************************************//**
+ @Description FM MACSEC device opaque structure used for type checking
+*//***************************************************************************/
+struct fm_macsec_dev;
+struct fm_macsec_secy_dev;
+
+/**************************************************************************//**
+ @Description A structure ..,
+*//***************************************************************************/
+struct fm_port;
+
+typedef int (*alloc_pcd_fqids)(struct device *dev, uint32_t num,
+ uint8_t alignment, uint32_t *base_fqid);
+
+typedef int (*free_pcd_fqids)(struct device *dev, uint32_t base_fqid);
+
+struct fm_port_pcd_param {
+ alloc_pcd_fqids cba;
+ free_pcd_fqids cbf;
+ struct device *dev;
+};
+
+/**************************************************************************//**
+ @Description A structure of information about each of the external
+ buffer pools used by the port,
+*//***************************************************************************/
+struct fm_port_pool_param {
+ uint8_t id; /**< External buffer pool id */
+ uint16_t size; /**< External buffer pool buffer size */
+};
+
+/**************************************************************************//**
+ @Description structure for additional port parameters
+*//***************************************************************************/
+struct fm_port_params {
+ uint32_t errq; /**< Error Queue Id. */
+ uint32_t defq; /**< For Tx and HC - Default Confirmation queue,
+ 0 means no Tx conf for processed frames.
+ For Rx and OP - default Rx queue. */
+ uint8_t num_pools; /**< Number of pools use by this port */
+ struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS];
+ /**< Parameters for each pool */
+ uint16_t priv_data_size; /**< Area that user may save for his own
+ need (E.g. save the SKB) */
+ bool parse_results; /**< Put the parser-results in the Rx/Tx buffer */
+ bool hash_results; /**< Put the hash-results in the Rx/Tx buffer */
+ bool time_stamp; /**< Put the time-stamp in the Rx/Tx buffer */
+ bool frag_enable; /**< Fragmentation support, for OP only */
+ uint16_t data_align; /**< value for selecting a data alignment (must be a power of 2);
+ if write optimization is used, must be >= 16. */
+ uint8_t manip_extra_space; /**< Maximum extra size needed (insertion-size minus removal-size);
+ Note that this field impacts the size of the buffer-prefix
+ (i.e. it pushes the data offset); */
+};
+
+/**************************************************************************//**
+ @Function fm_bind
+
+ @Description Bind to a specific FM device.
+
+ @Param[in] fm_dev - the OF handle of the FM device.
+
+ @Return A handle of the FM device.
+
+ @Cautions Allowed only after the port was created.
+*//***************************************************************************/
+struct fm *fm_bind(struct device *fm_dev);
+
+/**************************************************************************//**
+ @Function fm_unbind
+
+ @Description Un-bind from a specific FM device.
+
+ @Param[in] fm - A handle of the FM device.
+
+ @Cautions Allowed only after the port was created.
+*//***************************************************************************/
+void fm_unbind(struct fm *fm);
+
+void *fm_get_handle(struct fm *fm);
+void *fm_get_rtc_handle(struct fm *fm);
+struct resource *fm_get_mem_region(struct fm *fm);
+
+/**************************************************************************//**
+ @Function fm_port_bind
+
+ @Description Bind to a specific FM-port device (may be Rx or Tx port).
+
+ @Param[in] fm_port_dev - the OF handle of the FM port device.
+
+ @Return A handle of the FM port device.
+
+ @Cautions Allowed only after the port was created.
+*//***************************************************************************/
+struct fm_port *fm_port_bind(struct device *fm_port_dev);
+
+/**************************************************************************//**
+ @Function fm_port_unbind
+
+ @Description Un-bind from a specific FM-port device (may be Rx or Tx port).
+
+ @Param[in] port - A handle of the FM port device.
+
+ @Cautions Allowed only after the port was created.
+*//***************************************************************************/
+void fm_port_unbind(struct fm_port *port);
+
+/**************************************************************************//**
+ @Function fm_set_rx_port_params
+
+ @Description Configure parameters for a specific Rx FM-port device.
+
+ @Param[in] port - A handle of the FM port device.
+ @Param[in] params - Rx port parameters
+
+ @Cautions Allowed only after the port is binded.
+*//***************************************************************************/
+void fm_set_rx_port_params(struct fm_port *port,
+ struct fm_port_params *params);
+
+/**************************************************************************//**
+ @Function fm_port_pcd_bind
+
+ @Description Bind as a listener on a port PCD.
+
+ @Param[in] port - A handle of the FM port device.
+ @Param[in] params - PCD port parameters
+
+ @Cautions Allowed only after the port is binded.
+*//***************************************************************************/
+void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params);
+
+/**************************************************************************//**
+ @Function fm_port_get_buff_layout_ext_params
+
+ @Description Get data_align and manip_extra_space from the device tree
+ chosen node if applied.
+ This function will only update these two parameters.
+ When this port has no such parameters in the device tree
+ values will be set to 0.
+
+ @Param[in] port - A handle of the FM port device.
+ @Param[in] params - PCD port parameters
+
+ @Cautions Allowed only after the port is binded.
+*//***************************************************************************/
+void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params);
+
+/**************************************************************************//**
+ @Function fm_get_tx_port_channel
+
+ @Description Get qman-channel number for this Tx port.
+
+ @Param[in] port - A handle of the FM port device.
+
+ @Return qman-channel number for this Tx port.
+
+ @Cautions Allowed only after the port is binded.
+*//***************************************************************************/
+uint16_t fm_get_tx_port_channel(struct fm_port *port);
+
+/**************************************************************************//**
+ @Function fm_set_tx_port_params
+
+ @Description Configure parameters for a specific Tx FM-port device
+
+ @Param[in] port - A handle of the FM port device.
+ @Param[in] params - Tx port parameters
+
+ @Cautions Allowed only after the port is binded.
+*//***************************************************************************/
+void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params);
+
+
+/**************************************************************************//**
+ @Function fm_mac_set_handle
+
+ @Description Set mac handle
+
+ @Param[in] h_lnx_wrp_fm_dev - A handle of the LnxWrp FM device.
+ @Param[in] h_fm_mac - A handle of the LnxWrp FM MAC device.
+ @Param[in] mac_id - MAC id.
+*//***************************************************************************/
+void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, t_Handle h_fm_mac,
+ int mac_id);
+
+/**************************************************************************//**
+ @Function fm_port_enable
+
+ @Description Enable specific FM-port device (may be Rx or Tx port).
+
+ @Param[in] port - A handle of the FM port device.
+
+ @Cautions Allowed only after the port is initialized.
+*//***************************************************************************/
+int fm_port_enable(struct fm_port *port);
+
+/**************************************************************************//**
+ @Function fm_port_disable
+
+ @Description Disable specific FM-port device (may be Rx or Tx port).
+
+ @Param[in] port - A handle of the FM port device.
+
+ @Cautions Allowed only after the port is initialized.
+*//***************************************************************************/
+int fm_port_disable(struct fm_port *port);
+
+void *fm_port_get_handle(const struct fm_port *port);
+
+u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port,
+ const void *data);
+
+/**************************************************************************//**
+ @Function fm_port_get_base_address
+
+ @Description Get base address of this port. Useful for accessing
+ port-specific registers (i.e., not common ones).
+
+ @Param[in] port - A handle of the FM port device.
+
+ @Param[out] base_addr - The port's base addr (virtual address).
+*//***************************************************************************/
+void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr);
+
+/**************************************************************************//**
+ @Function fm_mutex_lock
+
+ @Description Lock function required before any FMD/LLD call.
+*//***************************************************************************/
+void fm_mutex_lock(void);
+
+/**************************************************************************//**
+ @Function fm_mutex_unlock
+
+ @Description Unlock function required after any FMD/LLD call.
+*//***************************************************************************/
+void fm_mutex_unlock(void);
+
+/**************************************************************************//**
+ @Function fm_get_max_frm
+
+ @Description Get the maximum frame size
+*//***************************************************************************/
+int fm_get_max_frm(void);
+
+/**************************************************************************//**
+ @Function fm_get_rx_extra_headroom
+
+ @Description Get the extra headroom size
+*//***************************************************************************/
+int fm_get_rx_extra_headroom(void);
+
+/**************************************************************************//**
+ @Function fm_has_errata_a050385
+
+ @Description Detect if the SoC is vulnerable to the A050385 errata
+*//***************************************************************************/
+#ifdef FM_ERRATUM_A050385
+bool fm_has_errata_a050385(void);
+#endif
+
+/**************************************************************************//**
+@Function fm_port_set_rate_limit
+
+@Description Configure Shaper parameter on FM-port device (Tx port).
+
+@Param[in] port - A handle of the FM port device.
+@Param[in] max_burst_size - Value of maximum burst size allowed.
+@Param[in] rate_limit - The required rate value.
+
+@Cautions Allowed only after the port is initialized.
+*//***************************************************************************/
+int fm_port_set_rate_limit(struct fm_port *port,
+ uint16_t max_burst_size,
+ uint32_t rate_limit);
+/**************************************************************************//**
+@Function fm_port_set_rate_limit
+
+@Description Delete Shaper configuration on FM-port device (Tx port).
+
+@Param[in] port - A handle of the FM port device.
+
+@Cautions Allowed only after the port is initialized.
+*//***************************************************************************/
+int fm_port_del_rate_limit(struct fm_port *port);
+
+struct auto_res_tables_sizes
+{
+ uint16_t max_num_of_arp_entries;
+ uint16_t max_num_of_echo_ipv4_entries;
+ uint16_t max_num_of_ndp_entries;
+ uint16_t max_num_of_echo_ipv6_entries;
+ uint16_t max_num_of_snmp_ipv4_entries;
+ uint16_t max_num_of_snmp_ipv6_entries;
+ uint16_t max_num_of_snmp_oid_entries;
+ uint16_t max_num_of_snmp_char; /* total amount of character needed
+ for the snmp table */
+ uint16_t max_num_of_ip_prot_filtering;
+ uint16_t max_num_of_tcp_port_filtering;
+ uint16_t max_num_of_udp_port_filtering;
+};
+/* ARP */
+struct auto_res_arp_entry
+{
+ uint32_t ip_address;
+ uint8_t mac[6];
+ bool is_vlan;
+ uint16_t vid;
+};
+struct auto_res_arp_info
+{
+ uint8_t table_size;
+ struct auto_res_arp_entry *auto_res_table;
+ bool enable_conflict_detection; /* when TRUE
+ Conflict Detection will be checked and wake the host if
+ needed */
+};
+
+/* NDP */
+struct auto_res_ndp_entry
+{
+ uint32_t ip_address[4];
+ uint8_t mac[6];
+ bool is_vlan;
+ uint16_t vid;
+};
+struct auto_res_ndp_info
+{
+ uint32_t multicast_group;
+ uint8_t table_size_assigned;
+ struct auto_res_ndp_entry *auto_res_table_assigned; /* This list
+ refer to solicitation IP addresses. Note that all IP adresses
+ must be from the same multicast group. This will be checked and
+ if not operation will fail. */
+ uint8_t table_size_tmp;
+ struct auto_res_ndp_entry *auto_res_table_tmp; /* This list
+ refer to temp IP addresses. Note that all temp IP adresses must
+ be from the same multicast group. This will be checked and if
+ not operation will fail. */
+
+ bool enable_conflict_detection; /* when TRUE
+ Conflict Detection will be checked and wake the host if
+ needed */
+};
+
+/* ICMP ECHO */
+struct auto_res_echo_ipv4_info
+{
+ uint8_t table_size;
+ struct auto_res_arp_entry *auto_res_table;
+};
+
+struct auto_res_echo_ipv6_info
+{
+ uint8_t table_size;
+ struct auto_res_ndp_entry *auto_res_table;
+};
+
+/* SNMP */
+struct auto_res_snmp_entry
+{
+ uint16_t oidSize;
+ uint8_t *oidVal; /* only the oid string */
+ uint16_t resSize;
+ uint8_t *resVal; /* resVal will be the entire reply,
+ i.e. "Type|Length|Value" */
+};
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+struct auto_res_snmp_ipv4addr_tbl_entry
+{
+ uint32_t ipv4addr; /*!< 32 bit IPv4 Address. */
+ bool is_vlan;
+ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+};
+
+/**************************************************************************//**
+ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry
+ Refer to the FMan Controller spec for more details.
+*//***************************************************************************/
+struct auto_res_snmp_ipv6addr_tbl_entry
+{
+ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */
+ bool isVlan;
+ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */
+ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */
+};
+
+struct auto_res_snmp_info
+{
+ uint16_t control; /**< Control bits [0-15]. */
+ uint16_t max_snmp_msg_length; /**< Maximal allowed SNMP message length. */
+ uint16_t num_ipv4_addresses; /**< Number of entries in IPv4 addresses table. */
+ uint16_t num_ipv6_addresses; /**< Number of entries in IPv6 addresses table. */
+ struct auto_res_snmp_ipv4addr_tbl_entry *ipv4addr_tbl; /**< Pointer to IPv4 addresses table. */
+ struct auto_res_snmp_ipv6addr_tbl_entry *ipv6addr_tbl; /**< Pointer to IPv6 addresses table. */
+ char *community_read_write_string;
+ char *community_read_only_string;
+ struct auto_res_snmp_entry *oid_table;
+ uint32_t oid_table_size;
+ uint32_t *statistics;
+};
+
+/* Filtering */
+struct auto_res_port_filtering_entry
+{
+ uint16_t src_port;
+ uint16_t dst_port;
+ uint16_t src_port_mask;
+ uint16_t dst_port_mask;
+};
+struct auto_res_filtering_info
+{
+ /* IP protocol filtering parameters */
+ uint8_t ip_prot_table_size;
+ uint8_t *ip_prot_table_ptr;
+ bool ip_prot_pass_on_hit; /* when TRUE, miss in the table will
+ cause the packet to be droped, hit will pass the packet to
+ UDP/TCP filters if needed and if not to the classification
+ tree. If the classification tree will pass the packet to a
+ queue it will cause a wake interupt. When FALSE it the other
+ way around. */
+ /* UDP port filtering parameters */
+ uint8_t udp_ports_table_size;
+ struct auto_res_port_filtering_entry *udp_ports_table_ptr;
+ bool udp_port_pass_on_hit; /* when TRUE, miss in the table will
+ cause the packet to be droped, hit will pass the packet to
+ classification tree. If the classification tree will pass the
+ packet to a queue it will cause a wake interupt. When FALSE it
+ the other way around. */
+ /* TCP port filtering parameters */
+ uint16_t tcp_flags_mask;
+ uint8_t tcp_ports_table_size;
+ struct auto_res_port_filtering_entry *tcp_ports_table_ptr;
+ bool tcp_port_pass_on_hit; /* when TRUE, miss in the table will
+ cause the packet to be droped, hit will pass the packet to
+ classification tree. If the classification tree will pass the
+ packet to a queue it will cause a wake interupt. When FALSE it
+ the other way around. */
+};
+
+struct auto_res_port_params
+{
+ t_Handle h_FmPortTx;
+ struct auto_res_arp_info *p_auto_res_arp_info;
+ struct auto_res_echo_ipv4_info *p_auto_res_echo_ipv4_info;
+ struct auto_res_ndp_info *p_auto_res_ndp_info;
+ struct auto_res_echo_ipv6_info *p_auto_res_echo_ipv6_info;
+ struct auto_res_snmp_info *p_auto_res_snmp_info;
+ struct auto_res_filtering_info *p_auto_res_filtering_info;
+};
+
+struct auto_res_port_stats
+{
+ uint32_t arp_ar_cnt;
+ uint32_t echo_icmpv4_ar_cnt;
+ uint32_t ndp_ar_cnt;
+ uint32_t echo_icmpv6_ar_cnt;
+};
+
+int fm_port_config_autores_for_deepsleep_support(struct fm_port *port,
+ struct auto_res_tables_sizes *params);
+
+int fm_port_enter_autores_for_deepsleep(struct fm_port *port,
+ struct auto_res_port_params *params);
+
+void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx,
+ struct fm_port *port_tx);
+
+bool fm_port_is_in_auto_res_mode(struct fm_port *port);
+
+struct auto_res_tables_sizes *fm_port_get_autores_maxsize(
+ struct fm_port *port);
+
+int fm_port_get_autores_stats(struct fm_port *port, struct auto_res_port_stats
+ *stats);
+
+int fm_port_resume(struct fm_port *port);
+
+int fm_port_suspend(struct fm_port *port);
+
+#ifdef CONFIG_FMAN_PFC
+/**************************************************************************//**
+@Function fm_port_set_pfc_priorities_mapping_to_qman_wq
+
+@Description Associate a QMan Work Queue with a PFC priority on this
+ FM-port device (Tx port).
+
+@Param[in] port - A handle of the FM port device.
+
+@Param[in] prio - The PFC priority.
+
+@Param[in] wq - The Work Queue associated with the PFC priority.
+
+@Cautions Allowed only after the port is initialized.
+*//***************************************************************************/
+int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port,
+ uint8_t prio, uint8_t wq);
+#endif
+
+/**************************************************************************//**
+@Function fm_mac_set_exception
+
+@Description Set MAC exception state.
+
+@Param[in] fm_mac_dev - A handle of the FM MAC device.
+@Param[in] exception - FM MAC exception type.
+@Param[in] enable - new state.
+
+*//***************************************************************************/
+int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev,
+ e_FmMacExceptions exception, bool enable);
+
+int fm_mac_free(struct fm_mac_dev *fm_mac_dev);
+
+struct fm_mac_dev *fm_mac_config(t_FmMacParams *params);
+
+int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev,
+ int len);
+
+int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable);
+
+int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable);
+
+int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable);
+
+int fm_mac_init(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version);
+
+int fm_mac_enable(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_disable(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_resume(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev,
+ bool enable);
+
+int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ t_EnetAddr *mac_addr);
+
+int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ t_EnetAddr *mac_addr);
+
+int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ uint8_t *addr);
+
+int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev,
+ bool link, int speed, bool duplex);
+
+int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev);
+
+int fm_mac_set_rx_pause_frames(
+ struct fm_mac_dev *fm_mac_dev, bool en);
+
+int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ bool en);
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+int fm_rtc_enable(struct fm *fm_dev);
+
+int fm_rtc_disable(struct fm *fm_dev);
+
+int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts);
+
+int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts);
+
+int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift);
+
+int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift);
+
+int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
+ uint64_t time);
+
+int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
+ uint64_t fiper);
+#else
+static inline int fm_rtc_enable(struct fm *fm_dev) { return 0; }
+
+static inline int fm_rtc_disable(struct fm *fm_dev) { return 0; }
+
+static inline int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts) { return 0; }
+
+static inline int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts) { return 0; }
+
+static inline int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift)
+{ return 0; }
+
+static inline int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift)
+{ return 0; }
+
+static inline int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
+ uint64_t time) { return 0; }
+
+static inline int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
+ uint64_t fiper) { return 0; }
+#endif
+
+int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev,
+ bool en);
+
+/**************************************************************************//**
+@Function fm_macsec_set_exception
+
+@Description Set MACSEC exception state.
+
+@Param[in] fm_macsec_dev - A handle of the FM MACSEC device.
+@Param[in] exception - FM MACSEC exception type.
+@Param[in] enable - new state.
+
+*//***************************************************************************/
+
+int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_exception exception, bool enable);
+int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev);
+struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params);
+int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev);
+int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev
+ *fm_macsec_dev,
+ fm_macsec_unknown_sci_frame_treatment treat_mode);
+int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ bool deliver_uncontrolled);
+int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ bool discard_uncontrolled);
+int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_untag_frame_treatment treat_mode);
+int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev,
+ uint32_t pnExhThr);
+int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev);
+int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev);
+int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_exception exception, bool enable);
+int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev,
+ int *macsec_revision);
+int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev);
+int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev);
+
+
+int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_secy_exception exception,
+ bool enable);
+int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
+struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params);
+int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
+int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_sci_insertion_mode sci_insertion_mode);
+int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool protect_frames);
+int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool replay_protect, uint32_t replay_window);
+int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_valid_frame_behavior validate_frames);
+int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool confidentiality_enable,
+ uint32_t confidentiality_offset);
+int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev);
+int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_secy_event event,
+ bool enable);
+struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct fm_macsec_secy_sc_params *params);
+int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc);
+int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, macsec_an_t an,
+ uint32_t lowest_pn, macsec_sa_key_t key);
+int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, macsec_an_t an);
+int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an);
+int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an);
+int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, uint32_t updt_next_pn);
+int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, uint32_t updt_lowest_pn);
+int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, macsec_sa_key_t key);
+int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an, macsec_sa_key_t key);
+int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an);
+int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t next_active_an,
+ macsec_sa_key_t key);
+int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an);
+int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t *p_an);
+int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, uint32_t *sc_phys_id);
+int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ uint32_t *sc_phys_id);
+
+/** @} */ /* end of FM_LnxKern_ctrl_grp group */
+/** @} */ /* end of FM_LnxKern_grp group */
+
+/* default values for initializing PTP 1588 timer clock */
+#define DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT 2 /* power of 2 for better performance */
+#define DPA_PTP_NOMINAL_FREQ_PERIOD_NS (1 << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT) /* 4ns,250MHz */
+
+#endif /* __LNXWRP_FSL_FMAN_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h
new file mode 100644
index 000000000000..b183c86ddd86
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef __XX_H
+#define __XX_H
+
+#include "xx_ext.h"
+
+void * xx_Malloc(uint32_t n);
+void xx_Free(void *p);
+
+void *xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t align);
+void xx_FreeSmart(void *p);
+
+/* never used: */
+#define GetDeviceName(irq) ((char *)NULL)
+
+int GetDeviceIrqNum(int irq);
+
+
+#endif /* __XX_H */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile
new file mode 100644
index 000000000000..667cd859931f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+#
+
+obj-y += sys_io.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c b/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c
new file mode 100644
index 000000000000..c106a8b7b208
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/modversions.h>
+#else
+#include <config/modversions.h>
+#endif /* LINUX_VERSION_CODE */
+#endif /* MODVERSIONS */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "string_ext.h"
+#include "list_ext.h"
+#include "sys_io_ext.h"
+
+
+#define __ERR_MODULE__ MODULE_UNKNOWN
+
+
+typedef struct {
+ uint64_t virtAddr;
+ uint64_t physAddr;
+ uint32_t size;
+ t_List node;
+} t_IoMap;
+#define IOMAP_OBJECT(ptr) LIST_OBJECT(ptr, t_IoMap, node)
+
+LIST(mapsList);
+
+
+static void EnqueueIoMap(t_IoMap *p_IoMap)
+{
+ uint32_t intFlags;
+
+ intFlags = XX_DisableAllIntr();
+ LIST_AddToTail(&p_IoMap->node, &mapsList);
+ XX_RestoreAllIntr(intFlags);
+}
+
+static t_IoMap * FindIoMapByVirtAddr(uint64_t addr)
+{
+ t_IoMap *p_IoMap;
+ t_List *p_Pos;
+
+ LIST_FOR_EACH(p_Pos, &mapsList)
+ {
+ p_IoMap = IOMAP_OBJECT(p_Pos);
+ if ((addr >= p_IoMap->virtAddr) && (addr < p_IoMap->virtAddr+p_IoMap->size))
+ return p_IoMap;
+ }
+
+ return NULL;
+}
+
+static t_IoMap * FindIoMapByPhysAddr(uint64_t addr)
+{
+ t_IoMap *p_IoMap;
+ t_List *p_Pos;
+
+ LIST_FOR_EACH(p_Pos, &mapsList)
+ {
+ p_IoMap = IOMAP_OBJECT(p_Pos);
+ if ((addr >= p_IoMap->physAddr) && (addr < p_IoMap->physAddr+p_IoMap->size))
+ return p_IoMap;
+ }
+
+ return NULL;
+}
+
+t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size)
+{
+ t_IoMap *p_IoMap;
+
+ p_IoMap = (t_IoMap*)XX_Malloc(sizeof(t_IoMap));
+ if (!p_IoMap)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
+ memset(p_IoMap, 0, sizeof(t_IoMap));
+
+ p_IoMap->virtAddr = virtAddr;
+ p_IoMap->physAddr = physAddr;
+ p_IoMap->size = size;
+
+ INIT_LIST(&p_IoMap->node);
+ EnqueueIoMap(p_IoMap);
+
+ return E_OK;
+}
+
+t_Error SYS_UnregisterIoMap (uint64_t virtAddr)
+{
+ t_IoMap *p_IoMap = FindIoMapByVirtAddr(virtAddr);
+ if (!p_IoMap)
+ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
+
+ LIST_Del(&p_IoMap->node);
+ XX_Free(p_IoMap);
+
+ return E_OK;
+}
+
+uint64_t SYS_PhysToVirt(uint64_t addr)
+{
+ t_IoMap *p_IoMap = FindIoMapByPhysAddr(addr);
+ if (p_IoMap)
+ {
+ /* This is optimization - put the latest in the list-head - like a cache */
+ if (mapsList.p_Next != &p_IoMap->node)
+ {
+ uint32_t intFlags = XX_DisableAllIntr();
+ LIST_DelAndInit(&p_IoMap->node);
+ LIST_Add(&p_IoMap->node, &mapsList);
+ XX_RestoreAllIntr(intFlags);
+ }
+ return (uint64_t)(addr - p_IoMap->physAddr + p_IoMap->virtAddr);
+ }
+ return PTR_TO_UINT(phys_to_virt((unsigned long)addr));
+}
+
+uint64_t SYS_VirtToPhys(uint64_t addr)
+{
+ t_IoMap *p_IoMap;
+
+ if (addr == 0)
+ return 0;
+
+ p_IoMap = FindIoMapByVirtAddr(addr);
+ if (p_IoMap)
+ return (uint64_t)(addr - p_IoMap->virtAddr + p_IoMap->physAddr);
+ return (uint64_t)virt_to_phys(UINT_TO_PTR(addr));
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile
new file mode 100644
index 000000000000..62713d626dfa
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile
@@ -0,0 +1,19 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc
+
+ccflags-y += -I$(NCSW_FM_INC)
+ccflags-y += -I$(NET_DPA)
+
+obj-y += fsl-ncsw-PFM.o
+obj-$(CONFIG_FSL_SDK_FMAN_TEST) += fman_test.o
+
+fsl-ncsw-PFM-objs := lnxwrp_fm.o lnxwrp_fm_port.o lnxwrp_ioctls_fm.o \
+ lnxwrp_sysfs.o lnxwrp_sysfs_fm.o lnxwrp_sysfs_fm_port.o
+obj-$(CONFIG_COMPAT) += lnxwrp_ioctls_fm_compat.o
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c
new file mode 100644
index 000000000000..270d07b8829d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c
@@ -0,0 +1,1665 @@
+/* Copyright (c) 2008-2011 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File fman_test.c
+ @Authors Pistirica Sorin Andrei
+ @Description FM Linux test environment
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/ip.h>
+#include <linux/compat.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/fsl_qman.h>
+#include <linux/fsl_bman.h>
+
+/* private headers */
+#include "fm_ext.h"
+#include "lnxwrp_fsl_fman.h"
+#include "fm_port_ext.h"
+#if (DPAA_VERSION == 11)
+#include "../../Peripherals/FM/MAC/memac.h"
+#endif
+#include "fm_test_ioctls.h"
+#include "fsl_fman_test.h"
+
+#include "dpaa_eth.h"
+#include "dpaa_eth_common.h"
+
+#define FMT_FRM_WATERMARK 0xdeadbeefdeadbeeaLL
+
+struct fmt_frame_s {
+ ioc_fmt_buff_desc_t buff;
+ struct list_head list;
+};
+
+struct fmt_fqs_s {
+ struct qman_fq fq_base;
+ bool init;
+ struct fmt_port_s *fmt_port_priv;
+};
+
+struct fmt_port_pcd_s {
+ int num_queues;
+ struct fmt_fqs_s *fmt_pcd_fqs;
+ uint32_t fqid_base;
+};
+
+/* char dev structure: fm test port */
+struct fmt_port_s {
+ bool valid;
+ uint8_t id;
+ ioc_fmt_port_type port_type;
+ ioc_diag_mode diag;
+ bool compat_test_type;
+
+ /* fm ports */
+ /* ! for oh ports p_tx_fm_port_dev == p_rx_fm_port_dev &&
+ * p_tx_port == p_rx_port */
+ /* t_LnxWrpFmPortDev */
+ struct fm_port *p_tx_port;
+ /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */
+ void *p_tx_fm_port_dev;
+ /* t_LnxWrpFmPortDev */
+ struct fm_port *p_rx_port;
+ /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */
+ void *p_rx_fm_port_dev;
+
+ void *p_mac_dev;
+ uint64_t fm_phys_base_addr;
+
+ /* read/write queue manipulation */
+ spinlock_t rx_q_lock;
+ struct list_head rx_q;
+
+ /* tx queuee for injecting traffic */
+ int num_of_tx_fqs;
+ struct fmt_fqs_s p_tx_fqs[FMAN_TEST_MAX_TX_FQS];
+
+ /* pcd private queues manipulation */
+ struct fmt_port_pcd_s fmt_port_pcd;
+
+ /* debugging stuff */
+
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_t enqueue_to_qman_frm;
+ atomic_t enqueue_to_rxq;
+ atomic_t dequeue_from_rxq;
+ atomic_t not_enqueue_to_rxq_wrong_frm;
+#endif
+
+};
+
+/* The devices. */
+struct fmt_s {
+ int major;
+ struct fmt_port_s ports[IOC_FMT_MAX_NUM_OF_PORTS];
+ struct class *fmt_class;
+};
+
+/* fm test structure */
+static struct fmt_s fm_test;
+
+#if (DPAA_VERSION == 11)
+struct mac_priv_s {
+ t_Handle mac;
+};
+#endif
+
+#define DTSEC_BASE_ADDR 0x000e0000
+#define DTSEC_MEM_RANGE 0x00002000
+#define MAC_1G_MACCFG1 0x00000100
+#define MAC_1G_LOOP_MASK 0x00000100
+static int set_1gmac_loopback(
+ struct fmt_port_s *fmt_port,
+ bool en)
+{
+#if (DPAA_VERSION <= 10)
+ uint32_t dtsec_idx = fmt_port->id; /* dtsec for which port */
+ uint32_t dtsec_idx_off = dtsec_idx * DTSEC_MEM_RANGE;
+ phys_addr_t maccfg1_hw;
+ void *maccfg1_map;
+ uint32_t maccfg1_val;
+
+ /* compute the maccfg1 register address */
+ maccfg1_hw = fmt_port->fm_phys_base_addr +
+ (phys_addr_t)(DTSEC_BASE_ADDR +
+ dtsec_idx_off +
+ MAC_1G_MACCFG1);
+
+ /* map register */
+ maccfg1_map = ioremap(maccfg1_hw, sizeof(u32));
+
+ /* set register */
+ maccfg1_val = in_be32(maccfg1_map);
+ if (en)
+ maccfg1_val |= MAC_1G_LOOP_MASK;
+ else
+ maccfg1_val &= ~MAC_1G_LOOP_MASK;
+ out_be32(maccfg1_map, maccfg1_val);
+
+ /* unmap register */
+ iounmap(maccfg1_map);
+#else
+ struct mac_device *mac_dev;
+ struct mac_priv_s *priv;
+ t_Memac *p_memac;
+
+ if (!fmt_port)
+ return -EINVAL;
+
+ mac_dev = (struct mac_device *)fmt_port->p_mac_dev;
+
+ if (!mac_dev)
+ return -EINVAL;
+
+ priv = macdev_priv(mac_dev);
+
+ if (!priv)
+ return -EINVAL;
+
+ p_memac = priv->mac;
+
+ if (!p_memac)
+ return -EINVAL;
+
+ memac_set_loopback(p_memac->p_MemMap, en);
+#endif
+ return 0;
+}
+
+/* TODO: re-write this function */
+static int set_10gmac_int_loopback(
+ struct fmt_port_s *fmt_port,
+ bool en)
+{
+#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK
+#define FM_10GMAC0_OFFSET 0x000f0000
+#define FM_10GMAC_CMD_CONF_CTRL_OFFSET 0x8
+#define CMD_CFG_LOOPBACK_EN 0x00000400
+
+ uint64_t base_addr, reg_addr;
+ uint32_t tmp_val;
+
+ base_addr = fmt_port->fm_phys_base_addr + (FM_10GMAC0_OFFSET +
+ ((fmt_port->id-FM_MAX_NUM_OF_1G_RX_PORTS)*0x2000));
+
+ base_addr = PTR_TO_UINT(ioremap(base_addr, 0x1000));
+
+ reg_addr = base_addr + FM_10GMAC_CMD_CONF_CTRL_OFFSET;
+ tmp_val = GET_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr)));
+ if (en)
+ tmp_val |= CMD_CFG_LOOPBACK_EN;
+ else
+ tmp_val &= ~CMD_CFG_LOOPBACK_EN;
+ WRITE_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr)), tmp_val);
+
+ iounmap(UINT_TO_PTR(base_addr));
+
+ return 0;
+#else
+ _fmt_err("TGEC don't have internal-loopback.\n");
+ return -EPERM;
+#endif
+}
+
+static int set_mac_int_loopback(struct fmt_port_s *fmt_port, bool en)
+{
+ int _err = 0;
+
+ switch (fmt_port->port_type) {
+
+ case e_IOC_FMT_PORT_T_RXTX:
+ /* 1G port */
+ if (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS)
+ _err = set_1gmac_loopback(fmt_port, en);
+ /* 10g port */
+ else if ((fmt_port->id >= FM_MAX_NUM_OF_1G_RX_PORTS) &&
+ (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS +
+ FM_MAX_NUM_OF_10G_RX_PORTS)) {
+
+ _err = set_10gmac_int_loopback(fmt_port, en);
+ } else
+ _err = -EINVAL;
+ break;
+ /* op port does not have MAC (loopback mode) */
+ case e_IOC_FMT_PORT_T_OP:
+
+ _err = 0;
+ break;
+ default:
+
+ _err = -EPERM;
+ break;
+ }
+
+ return _err;
+}
+
+static void enqueue_fmt_frame(
+ struct fmt_port_s *fmt_port,
+ struct fmt_frame_s *p_fmt_frame)
+{
+ spinlock_t *rx_q_lock = NULL;
+
+ rx_q_lock = &fmt_port->rx_q_lock;
+
+ spin_lock(rx_q_lock);
+ list_add_tail(&p_fmt_frame->list, &fmt_port->rx_q);
+ spin_unlock(rx_q_lock);
+
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_inc(&fmt_port->enqueue_to_rxq);
+#endif
+}
+
+static struct fmt_frame_s *dequeue_fmt_frame(
+ struct fmt_port_s *fmt_port)
+{
+ struct fmt_frame_s *p_fmt_frame = NULL;
+ spinlock_t *rx_q_lock = NULL;
+
+ rx_q_lock = &fmt_port->rx_q_lock;
+
+ spin_lock(rx_q_lock);
+
+#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member)
+
+ if (!list_empty(&fmt_port->rx_q)) {
+ p_fmt_frame = list_last_entry(&fmt_port->rx_q,
+ struct fmt_frame_s,
+ list);
+ list_del(&p_fmt_frame->list);
+
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_inc(&fmt_port->dequeue_from_rxq);
+#endif
+ }
+
+ spin_unlock(rx_q_lock);
+
+ return p_fmt_frame;
+}
+
+/* eth-dev -to- fmt port association */
+struct fmt_port_s *match_dpa_to_fmt_port(
+ struct dpa_priv_s *dpa_priv) {
+ struct mac_device *mac_dev = dpa_priv->mac_dev;
+ struct fm_port *fm_port = (struct fm_port *) mac_dev;
+ struct fmt_port_s *fmt_port = NULL;
+ int i;
+
+ _fmt_dbgr("calling...\n");
+
+ /* find the FM-test-port object */
+ for (i = 0; i < IOC_FMT_MAX_NUM_OF_PORTS; i++)
+ if ((fm_test.ports[i].p_mac_dev &&
+ mac_dev == fm_test.ports[i].p_mac_dev) ||
+ fm_port == fm_test.ports[i].p_tx_port) {
+
+ fmt_port = &fm_test.ports[i];
+ break;
+ }
+
+ _fmt_dbgr("called\n");
+ return fmt_port;
+}
+
+void dump_frame(
+ uint8_t *buffer,
+ uint32_t size)
+{
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (i%16 == 0)
+ printk(KERN_DEBUG "\n");
+ printk(KERN_DEBUG "%2x ", *(buffer+i));
+ }
+#endif
+ return;
+}
+
+bool test_and_steal_frame(struct fmt_port_s *fmt_port,
+ uint32_t fqid,
+ uint8_t *buffer,
+ uint32_t size)
+{
+ struct fmt_frame_s *p_fmt_frame = NULL;
+ bool test_and_steal_frame_frame;
+ uint32_t data_offset;
+ uint32_t i;
+
+ _fmt_dbgr("calling...\n");
+
+ if (!fmt_port || !fmt_port->p_rx_fm_port_dev)
+ return false;
+
+ /* check watermark */
+ test_and_steal_frame_frame = false;
+ for (i = 0; i < size; i++) {
+ uint64_t temp = *((uint64_t *)(buffer + i));
+
+ if (temp == (uint64_t) FMT_FRM_WATERMARK) {
+ _fmt_dbgr("watermark found!\n");
+ test_and_steal_frame_frame = true;
+ break;
+ }
+ }
+
+ if (!test_and_steal_frame_frame) {
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm);
+#endif
+ _fmt_dbgr("NOT watermark found!\n");
+ return false;
+ }
+
+ /* do not enqueue the tx conf/err frames */
+ if ((fqid == FMT_TX_CONF_Q) || (fqid == FMT_TX_ERR_Q))
+ goto _test_and_steal_frame_return_true;
+
+ _fmt_dbgr("on port %d got FMUC frame\n", fmt_port->id);
+ data_offset = FM_PORT_GetBufferDataOffset(
+ fmt_port->p_rx_fm_port_dev);
+
+ p_fmt_frame = kmalloc(sizeof(struct fmt_frame_s), GFP_KERNEL);
+
+ /* dump frame... no more space left on device */
+ if (p_fmt_frame == NULL) {
+ _fmt_err("no space left on device!\n");
+ goto _test_and_steal_frame_return_true;
+ }
+
+ memset(p_fmt_frame, 0, sizeof(struct fmt_frame_s));
+ p_fmt_frame->buff.p_data = kmalloc(size * sizeof(uint8_t), GFP_KERNEL);
+
+ /* No more space left on device*/
+ if (p_fmt_frame->buff.p_data == NULL) {
+ _fmt_err("no space left on device!\n");
+ kfree(p_fmt_frame);
+ goto _test_and_steal_frame_return_true;
+ }
+
+ p_fmt_frame->buff.size = size-data_offset;
+ p_fmt_frame->buff.qid = fqid;
+
+ memcpy(p_fmt_frame->buff.p_data,
+ (uint8_t *)PTR_MOVE(buffer, data_offset),
+ p_fmt_frame->buff.size);
+
+ memcpy(p_fmt_frame->buff.buff_context.fm_prs_res,
+ FM_PORT_GetBufferPrsResult(fmt_port->p_rx_fm_port_dev,
+ (char *)buffer),
+ 32);
+
+ /* enqueue frame - this frame will go to us */
+ enqueue_fmt_frame(fmt_port, p_fmt_frame);
+
+_test_and_steal_frame_return_true:
+ return true;
+}
+
+static int fmt_fq_release(const struct qm_fd *fd)
+{
+ struct dpa_bp *_dpa_bp;
+ struct bm_buffer _bmb;
+
+ if (fd->format == qm_fd_contig) {
+ _dpa_bp = dpa_bpid2pool(fd->bpid);
+ BUG_ON(IS_ERR(_dpa_bp));
+
+ _bmb.hi = fd->addr_hi;
+ _bmb.lo = fd->addr_lo;
+
+ while (bman_release(_dpa_bp->pool, &_bmb, 1, 0))
+ cpu_relax();
+
+ } else {
+ _fmt_err("frame not supported !\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* sync it w/ dpaa_eth.c: DPA_BP_HEAD */
+#define DPA_BP_HEADROOM (DPA_TX_PRIV_DATA_SIZE + \
+ fm_get_rx_extra_headroom() + \
+ DPA_PARSE_RESULTS_SIZE + \
+ DPA_HASH_RESULTS_SIZE)
+#define MAC_HEADER_LENGTH 14
+#define L2_AND_HEADROOM_OFF ((DPA_BP_HEADROOM) + (MAC_HEADER_LENGTH))
+
+/* dpa ingress hooks definition */
+enum dpaa_eth_hook_result fmt_rx_default_hook(
+ struct sk_buff *skb,
+ struct net_device *net_dev,
+ u32 fqid)
+{
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ uint8_t *buffer;
+ uint32_t buffer_len;
+
+ _fmt_dbgr("calling...\n");
+
+ dpa_priv = netdev_priv(net_dev);
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+
+ /* conversion from skb to fd:
+ * skb cames processed for L3, so we need to go back for
+ * layer 2 offset */
+ buffer = (uint8_t *)(skb->data - ((int)L2_AND_HEADROOM_OFF));
+ buffer_len = skb->len + ((int)L2_AND_HEADROOM_OFF);
+
+ /* if is not out frame let dpa to handle it */
+ if (test_and_steal_frame(fmt_port,
+ FMT_RX_DFLT_Q,
+ buffer,
+ buffer_len))
+ goto _fmt_rx_default_hook_stolen;
+
+ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
+ return DPAA_ETH_CONTINUE;
+
+_fmt_rx_default_hook_stolen:
+ dev_kfree_skb(skb);
+
+ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
+ return DPAA_ETH_STOLEN;
+}
+
+enum dpaa_eth_hook_result fmt_rx_error_hook(
+ struct net_device *net_dev,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct dpa_bp *dpa_bp = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ void *fd_virt_addr = NULL;
+ dma_addr_t addr = qm_fd_addr(fd);
+
+ _fmt_dbgr("calling...\n");
+
+ dpa_priv = netdev_priv(net_dev);
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+
+ /* dpaa doesn't do this... we have to do it here */
+ dpa_bp = dpa_bpid2pool(fd->bpid);
+ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
+
+ fd_virt_addr = phys_to_virt(addr);
+ /* if is not out frame let dpa to handle it */
+ if (test_and_steal_frame(fmt_port,
+ FMT_RX_ERR_Q,
+ fd_virt_addr,
+ fd->length20 + fd->offset)) {
+ goto _fmt_rx_error_hook_stolen;
+ }
+
+ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
+ return DPAA_ETH_CONTINUE;
+
+_fmt_rx_error_hook_stolen:
+ /* the frame data doesn't matter,
+ * so, no mapping is needed */
+ fmt_fq_release(fd);
+
+ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
+ return DPAA_ETH_STOLEN;
+}
+
+enum dpaa_eth_hook_result fmt_tx_confirm_hook(
+ struct net_device *net_dev,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ dma_addr_t addr = qm_fd_addr(fd);
+ void *fd_virt_addr = NULL;
+ uint32_t fd_len = 0;
+
+ _fmt_dbgr("calling...\n");
+
+ dpa_priv = netdev_priv(net_dev);
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+
+ fd_virt_addr = phys_to_virt(addr);
+ fd_len = fd->length20 + fd->offset;
+
+ if (fd_len > fm_get_max_frm()) {
+ _fmt_err("tx confirm bad frame size: %u!\n", fd_len);
+ goto _fmt_tx_confirm_hook_continue;
+ }
+
+ if (test_and_steal_frame(fmt_port,
+ FMT_TX_CONF_Q,
+ fd_virt_addr,
+ fd_len))
+ goto _fmt_tx_confirm_hook_stolen;
+
+_fmt_tx_confirm_hook_continue:
+ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
+ return DPAA_ETH_CONTINUE;
+
+_fmt_tx_confirm_hook_stolen:
+ kfree(fd_virt_addr);
+
+ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
+ return DPAA_ETH_STOLEN;
+}
+
+enum dpaa_eth_hook_result fmt_tx_confirm_error_hook(
+ struct net_device *net_dev,
+ const struct qm_fd *fd,
+ u32 fqid)
+{
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ dma_addr_t addr = qm_fd_addr(fd);
+ void *fd_virt_addr = NULL;
+ uint32_t fd_len = 0;
+
+ _fmt_dbgr("calling...\n");
+
+ dpa_priv = netdev_priv(net_dev);
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+
+ fd_virt_addr = phys_to_virt(addr);
+ fd_len = fd->length20 + fd->offset;
+
+ if (fd_len > fm_get_max_frm()) {
+ _fmt_err("tx confirm err bad frame size: %u !\n", fd_len);
+ goto _priv_ingress_tx_err_continue;
+ }
+
+ if (test_and_steal_frame(fmt_port, FMT_TX_ERR_Q, fd_virt_addr, fd_len))
+ goto _priv_ingress_tx_err_stolen;
+
+_priv_ingress_tx_err_continue:
+ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n");
+ return DPAA_ETH_CONTINUE;
+
+_priv_ingress_tx_err_stolen:
+ kfree(fd_virt_addr);
+
+ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n");
+ return DPAA_ETH_STOLEN;
+}
+
+/* egress callbacks definition */
+enum qman_cb_dqrr_result fmt_egress_dqrr(
+ struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dqrr)
+{
+ /* this callback should never be called */
+ BUG();
+ return qman_cb_dqrr_consume;
+}
+
+static void fmt_egress_error_dqrr(
+ struct qman_portal *p,
+ struct qman_fq *fq,
+ const struct qm_mr_entry *msg)
+{
+ uint8_t *fd_virt_addr = NULL;
+
+ /* tx failure, on the ern callback - release buffer */
+ fd_virt_addr = (uint8_t *)phys_to_virt(qm_fd_addr(&msg->ern.fd));
+ kfree(fd_virt_addr);
+
+ return;
+}
+
+static const struct qman_fq fmt_egress_fq = {
+ .cb = { .dqrr = fmt_egress_dqrr,
+ .ern = fmt_egress_error_dqrr,
+ .fqs = NULL}
+};
+
+int fmt_fq_alloc(
+ struct fmt_fqs_s *fmt_fqs,
+ const struct qman_fq *qman_fq,
+ uint32_t fqid, uint32_t flags,
+ uint16_t channel, uint8_t wq)
+{
+ int _errno = 0;
+
+ _fmt_dbg("calling...\n");
+
+ fmt_fqs->fq_base = *qman_fq;
+
+ if (fqid == 0) {
+ flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
+ flags &= ~QMAN_FQ_FLAG_NO_MODIFY;
+ } else
+ flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID;
+
+ fmt_fqs->init = !(flags & QMAN_FQ_FLAG_NO_MODIFY);
+
+ _errno = qman_create_fq(fqid, flags, &fmt_fqs->fq_base);
+ if (_errno < 0) {
+ _fmt_err("frame queues create failed.\n");
+ return -EINVAL;
+ }
+
+ if (fmt_fqs->init) {
+ struct qm_mcc_initfq initfq;
+
+ initfq.we_mask = QM_INITFQ_WE_DESTWQ;
+ initfq.fqd.dest.channel = channel;
+ initfq.fqd.dest.wq = wq;
+
+ _errno = qman_init_fq(&fmt_fqs->fq_base,
+ QMAN_INITFQ_FLAG_SCHED,
+ &initfq);
+ if (_errno < 0) {
+ _fmt_err("frame queues init erorr.\n");
+ qman_destroy_fq(&fmt_fqs->fq_base, 0);
+ return -EINVAL;
+ }
+ }
+
+ _fmt_dbg("called.\n");
+ return 0;
+}
+
+static int fmt_fq_free(struct fmt_fqs_s *fmt_fq)
+{
+ int _err = 0;
+
+ _fmt_dbg("calling...\n");
+
+ if (fmt_fq->init) {
+ _err = qman_retire_fq(&fmt_fq->fq_base, NULL);
+ if (unlikely(_err < 0))
+ _fmt_err("qman_retire_fq(%u) = %d\n",
+ qman_fq_fqid(&fmt_fq->fq_base), _err);
+
+ _err = qman_oos_fq(&fmt_fq->fq_base);
+ if (unlikely(_err < 0))
+ _fmt_err("qman_oos_fq(%u) = %d\n",
+ qman_fq_fqid(&fmt_fq->fq_base), _err);
+ }
+
+ qman_destroy_fq(&fmt_fq->fq_base, 0);
+
+ _fmt_dbg("called.\n");
+ return _err;
+}
+
+/* private pcd dqrr calbacks */
+static enum qman_cb_dqrr_result fmt_pcd_dqrr(
+ struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ struct dpa_bp *dpa_bp = NULL;
+ dma_addr_t addr = qm_fd_addr(&dq->fd);
+ uint8_t *fd_virt_addr = NULL;
+ struct fmt_port_s *fmt_port;
+ struct fmt_port_pcd_s *fmt_port_pcd;
+ uint32_t relative_fqid = 0;
+ uint32_t fd_len = 0;
+
+ _fmt_dbgr("calling...\n");
+
+ /* upcast - from pcd_alloc_fq */
+ fmt_port = ((struct fmt_fqs_s *)fq)->fmt_port_priv;
+ if (!fmt_port) {
+ _fmt_err(" wrong fmt port -to- fq match.\n");
+ goto _fmt_pcd_dqrr_return;
+ }
+ fmt_port_pcd = &fmt_port->fmt_port_pcd;
+
+ relative_fqid = dq->fqid - fmt_port_pcd->fqid_base;
+ _fmt_dbgr("pcd dqrr got frame on relative fq:%u@base:%u\n",
+ relative_fqid, fmt_port_pcd->fqid_base);
+
+ fd_len = dq->fd.length20 + dq->fd.offset;
+
+ if (fd_len > fm_get_max_frm()) {
+ _fmt_err("pcd dqrr wrong frame size: %u (%u:%u)!\n",
+ fd_len, dq->fd.length20, dq->fd.offset);
+ goto _fmt_pcd_dqrr_return;
+ }
+
+ dpa_bp = dpa_bpid2pool(dq->fd.bpid);
+ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL);
+
+ fd_virt_addr = phys_to_virt(addr);
+ if (!test_and_steal_frame(fmt_port, relative_fqid, fd_virt_addr,
+ fd_len)) {
+
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm);
+#endif
+ _fmt_wrn("pcd dqrr unrecognized frame@fqid: %u,"
+ " frame len: %u (dropped).\n",
+ dq->fqid, dq->fd.length20);
+ dump_frame(fd_virt_addr, fd_len);
+ }
+
+_fmt_pcd_dqrr_return:
+ /* no need to map again here */
+ fmt_fq_release(&dq->fd);
+
+ _fmt_dbgr("calle.\n");
+ return qman_cb_dqrr_consume;
+}
+
+static void fmt_pcd_err_dqrr(
+ struct qman_portal *qm,
+ struct qman_fq *fq,
+ const struct qm_mr_entry *msg)
+{
+ _fmt_err("this callback should never be called.\n");
+ BUG();
+ return;
+}
+
+static void fmt_pcd_fqs_dqrr(
+ struct qman_portal *qm,
+ struct qman_fq *fq,
+ const struct qm_mr_entry *msg)
+{
+ _fmt_dbg(" fq state(0x%x)@fqid(%u.\n", msg->fq.fqs, msg->fq.fqid);
+ return;
+}
+
+/* private pcd queue template */
+static const struct qman_fq pcd_fq = {
+ .cb = { .dqrr = fmt_pcd_dqrr,
+ .ern = fmt_pcd_err_dqrr,
+ .fqs = fmt_pcd_fqs_dqrr}
+};
+
+/* defined as weak in dpaa driver. */
+/* ! parameters come from IOCTL call - US */
+int dpa_alloc_pcd_fqids(
+ struct device *dev,
+ uint32_t num, uint8_t alignment,
+ uint32_t *base_fqid)
+{
+ int _err = 0, i;
+ struct net_device *net_dev = NULL;
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct fmt_port_pcd_s *fmt_port_pcd = NULL;
+ struct fmt_fqs_s *fmt_fqs = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ int num_allocated = 0;
+
+ _fmt_dbg("calling...\n");
+
+ net_dev = (typeof(net_dev))dev_get_drvdata(dev);
+ dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev);
+
+ if (!netif_msg_probe(dpa_priv)) {
+ _fmt_err("dpa not probe.\n");
+ _err = -ENODEV;
+ goto _pcd_alloc_fqs_err;
+ }
+
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+ if (!fmt_port) {
+ _fmt_err("fmt port not found.");
+ _err = -EINVAL;
+ goto _pcd_alloc_fqs_err;
+ }
+
+ fmt_port_pcd = &fmt_port->fmt_port_pcd;
+
+ num_allocated = qman_alloc_fqid_range(base_fqid, num, alignment, 0);
+
+ if ((num_allocated <= 0) ||
+ (num_allocated < num) ||
+ (alignment && (*base_fqid) % alignment)) {
+ *base_fqid = 0;
+ _fmt_err("Failed to alloc pcd fqs rang.\n");
+ _err = -EINVAL;
+ goto _pcd_alloc_fqs_err;
+ }
+
+ _fmt_dbg("wanted %d fqs(align %d), got %d fqids@%u.\n",
+ num, alignment, num_allocated, *base_fqid);
+
+ /* alloc pcd queues */
+ fmt_port_pcd->fmt_pcd_fqs = kmalloc(num_allocated *
+ sizeof(struct fmt_fqs_s),
+ GFP_KERNEL);
+ fmt_port_pcd->num_queues = num_allocated;
+ fmt_port_pcd->fqid_base = *base_fqid;
+ fmt_fqs = fmt_port_pcd->fmt_pcd_fqs;
+
+ /* alloc the pcd queues */
+ for (i = 0; i < num_allocated; i++, fmt_fqs++) {
+ _err = fmt_fq_alloc(
+ fmt_fqs,
+ &pcd_fq,
+ (*base_fqid) + i, QMAN_FQ_FLAG_NO_ENQUEUE,
+ dpa_priv->channel, 7);
+
+ if (_err < 0)
+ goto _pcd_alloc_fqs_err;
+
+ /* upcast to identify from where the frames came from */
+ fmt_fqs->fmt_port_priv = fmt_port;
+ }
+
+ _fmt_dbg("called.\n");
+ return _err;
+_pcd_alloc_fqs_err:
+ if (num_allocated > 0)
+ qman_release_fqid_range(*base_fqid, num_allocated);
+ /*TODO: free fmt_pcd_fqs if are any */
+
+ _fmt_dbg("called(_err:%d).\n", _err);
+ return _err;
+}
+
+/* defined as weak in dpaa driver. */
+int dpa_free_pcd_fqids(
+ struct device *dev,
+ uint32_t base_fqid)
+{
+
+ int _err = 0, i;
+ struct net_device *net_dev = NULL;
+ struct dpa_priv_s *dpa_priv = NULL;
+ struct fmt_port_pcd_s *fmt_port_pcd = NULL;
+ struct fmt_fqs_s *fmt_fqs = NULL;
+ struct fmt_port_s *fmt_port = NULL;
+ int num_allocated = 0;
+
+ _fmt_dbg("calling...\n");
+
+ net_dev = (typeof(net_dev))dev_get_drvdata(dev);
+ dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev);
+
+ if (!netif_msg_probe(dpa_priv)) {
+ _fmt_err("dpa not probe.\n");
+ _err = -ENODEV;
+ goto _pcd_free_fqs_err;
+ }
+
+ fmt_port = match_dpa_to_fmt_port(dpa_priv);
+ if (!fmt_port) {
+ _fmt_err("fmt port not found.");
+ _err = -EINVAL;
+ goto _pcd_free_fqs_err;
+ }
+
+ fmt_port_pcd = &fmt_port->fmt_port_pcd;
+ num_allocated = fmt_port_pcd->num_queues;
+ fmt_fqs = fmt_port_pcd->fmt_pcd_fqs;
+
+ for (i = 0; i < num_allocated; i++, fmt_fqs++)
+ fmt_fq_free(fmt_fqs);
+
+ qman_release_fqid_range(base_fqid,num_allocated);
+
+ kfree(fmt_port_pcd->fmt_pcd_fqs);
+ memset(fmt_port_pcd, 0, sizeof(*fmt_port_pcd));
+
+ /* debugging stuff */
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ _fmt_dbg(" portid: %u.\n", fmt_port->id);
+ _fmt_dbg(" frames enqueue to qman: %u.\n",
+ atomic_read(&fmt_port->enqueue_to_qman_frm));
+ _fmt_dbg(" frames enqueue to rxq: %u.\n",
+ atomic_read(&fmt_port->enqueue_to_rxq));
+ _fmt_dbg(" frames dequeue from rxq: %u.\n",
+ atomic_read(&fmt_port->dequeue_from_rxq));
+ _fmt_dbg(" frames not enqueue to rxq - wrong frm: %u.\n",
+ atomic_read(&fmt_port->not_enqueue_to_rxq_wrong_frm));
+ atomic_set(&fmt_port->enqueue_to_qman_frm, 0);
+ atomic_set(&fmt_port->enqueue_to_rxq, 0);
+ atomic_set(&fmt_port->dequeue_from_rxq, 0);
+ atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0);
+#endif
+ return 0;
+
+_pcd_free_fqs_err:
+ return _err;
+}
+
+static int fmt_port_init(
+ struct fmt_port_s *fmt_port,
+ ioc_fmt_port_param_t *p_Params)
+{
+ struct device_node *fm_node, *fm_port_node;
+ const uint32_t *uint32_prop;
+ int _errno = 0, lenp = 0, i;
+ static struct of_device_id fm_node_of_match[] = {
+ { .compatible = "fsl,fman", },
+ { /* end of list */ },
+ };
+
+ _fmt_dbg("calling...\n");
+
+ /* init send/receive tu US list */
+ INIT_LIST_HEAD(&fmt_port->rx_q);
+
+ /* check parameters */
+ if (p_Params->num_tx_queues > FMAN_TEST_MAX_TX_FQS ||
+ p_Params->fm_port_id > IOC_FMT_MAX_NUM_OF_PORTS) {
+ _fmt_dbg("wrong test parameters.\n");
+ return -EINVAL;
+ }
+
+ /* set port parameters */
+ fmt_port->num_of_tx_fqs = p_Params->num_tx_queues;
+ fmt_port->id = p_Params->fm_port_id;
+ fmt_port->port_type = p_Params->fm_port_type;
+ fmt_port->diag = e_IOC_DIAG_MODE_NONE;
+
+ /* init debugging stuff */
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_set(&fmt_port->enqueue_to_qman_frm, 0);
+ atomic_set(&fmt_port->enqueue_to_rxq, 0);
+ atomic_set(&fmt_port->dequeue_from_rxq, 0);
+ atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0);
+#endif
+
+ /* TODO: This should be done at probe time not at runtime
+ * very ugly function */
+ /* fill fmt port properties from dts */
+ for_each_matching_node(fm_node, fm_node_of_match) {
+
+ uint32_prop = (uint32_t *)of_get_property(fm_node,
+ "cell-index", &lenp);
+ if (unlikely(uint32_prop == NULL)) {
+ _fmt_wrn("of_get_property(%s, cell-index) invalid",
+ fm_node->full_name);
+ return -EINVAL;
+ }
+ if (WARN_ON(lenp != sizeof(uint32_t))) {
+ _fmt_wrn("of_get_property(%s, cell-index) invalid",
+ fm_node->full_name);
+ return -EINVAL;
+ }
+
+ if (*uint32_prop == p_Params->fm_id) {
+ struct resource res;
+
+ /* Get the FM address */
+ _errno = of_address_to_resource(fm_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ _fmt_wrn("of_address_to_resource() = %u.\n", _errno);
+ return -EINVAL;
+ }
+
+ fmt_port->fm_phys_base_addr = res.start;
+
+ for_each_child_of_node(fm_node, fm_port_node) {
+ struct platform_device *of_dev;
+
+ if (!of_device_is_available(fm_port_node))
+ continue;
+
+ uint32_prop = (uint32_t *)of_get_property(
+ fm_port_node,
+ "cell-index",
+ &lenp);
+ if (uint32_prop == NULL)
+ continue;
+
+ if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-port-oh") &&
+ (fmt_port->port_type == e_IOC_FMT_PORT_T_OP)) {
+
+ if (*uint32_prop == fmt_port->id) {
+ of_dev = of_find_device_by_node(fm_port_node);
+ if (unlikely(of_dev == NULL)) {
+ _fmt_wrn("fm id invalid\n");
+ return -EINVAL;
+ }
+
+ fmt_port->p_tx_port =
+ fm_port_bind(&of_dev->dev);
+ fmt_port->p_tx_fm_port_dev =
+ (void *)fm_port_get_handle(
+ fmt_port->p_tx_port);
+ fmt_port->p_rx_port =
+ fmt_port->p_tx_port;
+ fmt_port->p_rx_fm_port_dev =
+ fmt_port->p_tx_fm_port_dev;
+ fmt_port->p_mac_dev = NULL;
+ break;
+ }
+ } else if ((*uint32_prop == fmt_port->id) &&
+ fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) {
+
+ of_dev = of_find_device_by_node(fm_port_node);
+ if (unlikely(of_dev == NULL)) {
+ _fmt_wrn("dtb fm id invalid value");
+ return -EINVAL;
+ }
+
+ if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-port-1g-tx")) {
+ fmt_port->p_tx_port =
+ fm_port_bind(&of_dev->dev);
+ fmt_port->p_tx_fm_port_dev = (void *)
+ fm_port_get_handle(
+ fmt_port->p_tx_port);
+ } else if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-port-1g-rx")) {
+ fmt_port->p_rx_port =
+ fm_port_bind(&of_dev->dev);
+ fmt_port->p_rx_fm_port_dev = (void *)
+ fm_port_get_handle(
+ fmt_port->p_rx_port);
+ } else if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-1g-mac") ||
+ of_device_is_compatible(fm_port_node,
+ "fsl,fman-memac"))
+ fmt_port->p_mac_dev =
+ (typeof(fmt_port->p_mac_dev))
+ dev_get_drvdata(&of_dev->dev);
+ else
+ continue;
+
+ if (fmt_port->p_tx_fm_port_dev &&
+ fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev)
+ break;
+ } else if (((*uint32_prop + FM_MAX_NUM_OF_1G_RX_PORTS) ==
+ fmt_port->id) &&
+ fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) {
+
+ of_dev = of_find_device_by_node(fm_port_node);
+ if (unlikely(of_dev == NULL)) {
+ _fmt_wrn("dtb fm id invalid value\n");
+ return -EINVAL;
+ }
+
+ if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-port-10g-tx")) {
+ fmt_port->p_tx_port =
+ fm_port_bind(&of_dev->dev);
+ fmt_port->p_tx_fm_port_dev = (void *)
+ fm_port_get_handle(
+ fmt_port->p_tx_port);
+ } else if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-port-10g-rx")) {
+ fmt_port->p_rx_port =
+ fm_port_bind(&of_dev->dev);
+ fmt_port->p_rx_fm_port_dev = (void *)
+ fm_port_get_handle(
+ fmt_port->p_rx_port);
+ } else if (of_device_is_compatible(fm_port_node,
+ "fsl,fman-10g-mac") ||
+ of_device_is_compatible(fm_port_node,
+ "fsl,fman-memac"))
+ fmt_port->p_mac_dev =
+ (typeof(fmt_port->p_mac_dev))
+ dev_get_drvdata(&of_dev->dev);
+ else
+ continue;
+
+ if (fmt_port->p_tx_fm_port_dev &&
+ fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev)
+ break;
+ }
+ } /* for_each_child */
+ }
+ } /* for each matching node */
+
+ if (fmt_port->p_tx_fm_port_dev == 0 ||
+ fmt_port->p_rx_fm_port_dev == 0) {
+
+ _fmt_err("bad fm port pointers.\n");
+ return -EINVAL;
+ }
+
+ _fmt_dbg("alloc %u tx queues.\n", fmt_port->num_of_tx_fqs);
+
+ /* init fman test egress dynamic frame queues */
+ for (i = 0; i < fmt_port->num_of_tx_fqs; i++) {
+ int _errno;
+ _errno = fmt_fq_alloc(
+ &fmt_port->p_tx_fqs[i],
+ &fmt_egress_fq,
+ 0,
+ QMAN_FQ_FLAG_TO_DCPORTAL,
+ fm_get_tx_port_channel(fmt_port->p_tx_port),
+ i);
+
+ if (_errno < 0) {
+ _fmt_err("tx queues allocation failed.\n");
+ /* TODO: memory leak here if 1 queue is allocated and
+ * next queues are failing ... */
+ return -EINVAL;
+ }
+ }
+
+ /* port is valid and ready to use. */
+ fmt_port->valid = TRUE;
+
+ _fmt_dbg("called.\n");
+ return 0;
+}
+
+/* fm test chardev functions */
+static int fmt_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = iminor(inode);
+
+ _fmt_dbg("calling...\n");
+
+ if (file->private_data != NULL)
+ return 0;
+
+ /* The minor represent the port number.
+ * Set the port structure accordingly, thus all the operations
+ * will be done on this port. */
+ if ((minor >= DEV_FM_TEST_PORTS_MINOR_BASE) &&
+ (minor < DEV_FM_TEST_MAX_MINORS))
+ file->private_data = &fm_test.ports[minor];
+ else
+ return -ENXIO;
+
+ _fmt_dbg("called.\n");
+ return 0;
+}
+
+static int fmt_close(struct inode *inode, struct file *file)
+{
+ struct fmt_port_s *fmt_port = NULL;
+ struct fmt_frame_s *fmt_frame = NULL;
+
+ int err = 0;
+
+ _fmt_dbg("calling...\n");
+
+ fmt_port = file->private_data;
+ if (!fmt_port)
+ return -ENODEV;
+
+ /* Close the current test port by invalidating it. */
+ fmt_port->valid = FALSE;
+
+ /* clean the fmt port queue */
+ while ((fmt_frame = dequeue_fmt_frame(fmt_port)) != NULL) {
+ if (fmt_frame && fmt_frame->buff.p_data){
+ kfree(fmt_frame->buff.p_data);
+ kfree(fmt_frame);
+ }
+ }
+
+ /* !!! the qman queues are cleaning from fm_ioctl...
+ * - very ugly */
+
+ _fmt_dbg("called.\n");
+ return err;
+}
+
+static int fmt_ioctls(unsigned int minor,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg,
+ bool compat)
+{
+ struct fmt_port_s *fmt_port = NULL;
+
+ _fmt_dbg("IOCTL minor:%u "
+ " arg:0x%08lx ioctl cmd (0x%08x):(0x%02x:0x%02x.\n",
+ minor, arg, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
+
+ fmt_port = file->private_data;
+ if (!fmt_port) {
+ _fmt_err("invalid fmt port.\n");
+ return -ENODEV;
+ }
+
+ /* set test type properly */
+ if (compat)
+ fmt_port->compat_test_type = true;
+ else
+ fmt_port->compat_test_type = false;
+
+ switch (cmd) {
+ case FMT_PORT_IOC_INIT:
+ {
+ ioc_fmt_port_param_t param;
+
+ if (fmt_port->valid) {
+ _fmt_wrn("port is already initialized.\n");
+ return -EFAULT;
+ }
+#if defined(CONFIG_COMPAT)
+ if (compat) {
+ if (copy_from_user(&param,
+ (ioc_fmt_port_param_t *)compat_ptr(arg),
+ sizeof(ioc_fmt_port_param_t)))
+
+ return -EFAULT;
+ } else
+#endif
+ {
+ if (copy_from_user(&param,
+ (ioc_fmt_port_param_t *) arg,
+ sizeof(ioc_fmt_port_param_t)))
+
+ return -EFAULT;
+ }
+
+ return fmt_port_init(fmt_port, &param);
+ }
+
+ case FMT_PORT_IOC_SET_DIAG_MODE:
+ if (get_user(fmt_port->diag, (ioc_diag_mode *)arg))
+ return -EFAULT;
+
+ if (fmt_port->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK)
+ return set_mac_int_loopback(fmt_port, TRUE);
+ else
+ return set_mac_int_loopback(fmt_port, FALSE);
+ break;
+
+ case FMT_PORT_IOC_SET_DPAECHO_MODE:
+ case FMT_PORT_IOC_SET_IP_HEADER_MANIP:
+ default:
+ _fmt_wrn("ioctl unimplemented minor:%u@ioctl"
+ " cmd:0x%08x(type:0x%02x, nr:0x%02x.\n",
+ minor, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long fmt_compat_ioctl(
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+
+ _fmt_dbg("calling...\n");
+ return fmt_ioctls(minor, file, cmd, arg, true);
+}
+#endif
+
+static long fmt_ioctl(
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ unsigned int res;
+
+ _fmt_dbg("calling...\n");
+
+ fm_mutex_lock();
+ res = fmt_ioctls(minor, file, cmd, arg, false);
+ fm_mutex_unlock();
+
+ _fmt_dbg("called.\n");
+
+ return res;
+}
+
+#ifdef CONFIG_COMPAT
+void copy_compat_test_frame_buffer(
+ ioc_fmt_buff_desc_t *buff,
+ ioc_fmt_compat_buff_desc_t *compat_buff)
+{
+ compat_buff->qid = buff->qid;
+ compat_buff->p_data = ptr_to_compat(buff->p_data);
+ compat_buff->size = buff->size;
+ compat_buff->status = buff->status;
+
+ compat_buff->buff_context.p_user_priv =
+ ptr_to_compat(buff->buff_context.p_user_priv);
+ memcpy(compat_buff->buff_context.fm_prs_res,
+ buff->buff_context.fm_prs_res,
+ FM_PRS_MAX * sizeof(uint8_t));
+ memcpy(compat_buff->buff_context.fm_time_stamp,
+ buff->buff_context.fm_time_stamp,
+ FM_TIME_STAMP_MAX * sizeof(uint8_t));
+}
+#endif
+
+ssize_t fmt_read(
+ struct file *file,
+ char __user *buf,
+ size_t size,
+ loff_t *ppos)
+{
+ struct fmt_port_s *fmt_port = NULL;
+ struct fmt_frame_s *p_fmt_frame = NULL;
+ ssize_t cnt = 0;
+
+ fmt_port = file->private_data;
+ if (!fmt_port || !fmt_port->valid) {
+ _fmt_err("fmt port not valid!\n");
+ return -ENODEV;
+ }
+
+ p_fmt_frame = dequeue_fmt_frame(fmt_port);
+ if (p_fmt_frame == NULL)
+ return 0;
+
+ _fmt_dbgr("calling...\n");
+
+#ifdef CONFIG_COMPAT
+ if (fmt_port->compat_test_type){
+ cnt = sizeof(ioc_fmt_compat_buff_desc_t);
+ }
+ else
+#endif
+ {
+ cnt = sizeof(ioc_fmt_buff_desc_t);
+ }
+
+ if (size < cnt) {
+ _fmt_err("illegal buffer-size!\n");
+ cnt = 0;
+ goto _fmt_read_return;
+ }
+
+ /* Copy structure */
+#ifdef CONFIG_COMPAT
+ if (fmt_port->compat_test_type) {
+ {
+ ioc_fmt_compat_buff_desc_t compat_buff;
+ copy_compat_test_frame_buffer(&p_fmt_frame->buff,
+ &compat_buff);
+
+ if (copy_to_user(buf, &compat_buff, cnt)) {
+ _fmt_err("copy_to_user failed!\n");
+ goto _fmt_read_return;
+ }
+ }
+
+ ((ioc_fmt_compat_buff_desc_t *)buf)->p_data =
+ ptr_to_compat(buf+sizeof(ioc_fmt_compat_buff_desc_t));
+ cnt += MIN(p_fmt_frame->buff.size, size-cnt);
+ } else
+#endif
+ {
+ if (copy_to_user(buf, &p_fmt_frame->buff, cnt)) {
+ _fmt_err("copy_to_user failed!\n");
+ goto _fmt_read_return;
+ }
+
+ ((ioc_fmt_buff_desc_t *)buf)->p_data =
+ buf + sizeof(ioc_fmt_buff_desc_t);
+ cnt += MIN(p_fmt_frame->buff.size, size-cnt);
+ }
+
+ if (size < cnt) {
+ _fmt_err("illegal buffer-size!\n");
+ goto _fmt_read_return;
+ }
+
+ /* copy frame */
+#ifdef CONFIG_COMPAT
+ if (fmt_port->compat_test_type) {
+ if (copy_to_user(buf+sizeof(ioc_fmt_compat_buff_desc_t),
+ p_fmt_frame->buff.p_data, cnt)) {
+ _fmt_err("copy_to_user failed!\n");
+ goto _fmt_read_return;
+ }
+ } else
+#endif
+ {
+ if (copy_to_user(buf+sizeof(ioc_fmt_buff_desc_t),
+ p_fmt_frame->buff.p_data, cnt)) {
+ _fmt_err("copy_to_user failed!\n");
+ goto _fmt_read_return;
+ }
+ }
+
+_fmt_read_return:
+ kfree(p_fmt_frame->buff.p_data);
+ kfree(p_fmt_frame);
+
+ _fmt_dbgr("called.\n");
+ return cnt;
+}
+
+ssize_t fmt_write(
+ struct file *file,
+ const char __user *buf,
+ size_t size,
+ loff_t *ppos)
+{
+ struct fmt_port_s *fmt_port = NULL;
+ ioc_fmt_buff_desc_t buff_desc;
+#ifdef CONFIG_COMPAT
+ ioc_fmt_compat_buff_desc_t buff_desc_compat;
+#endif
+ uint8_t *p_data = NULL;
+ uint32_t data_offset;
+ int _errno;
+ t_DpaaFD fd;
+
+ _fmt_dbgr("calling...\n");
+
+ fmt_port = file->private_data;
+ if (!fmt_port || !fmt_port->valid) {
+ _fmt_err("fmt port not valid.\n");
+ return -EINVAL;
+ }
+
+ /* If Compat (32B UserSpace - 64B KernelSpace) */
+#ifdef CONFIG_COMPAT
+ if (fmt_port->compat_test_type) {
+ if (size < sizeof(ioc_fmt_compat_buff_desc_t)) {
+ _fmt_err("invalid buff_desc size.\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&buff_desc_compat, buf,
+ sizeof(ioc_fmt_compat_buff_desc_t)))
+ return -EFAULT;
+
+ buff_desc.qid = buff_desc_compat.qid;
+ buff_desc.p_data = compat_ptr(buff_desc_compat.p_data);
+ buff_desc.size = buff_desc_compat.size;
+ buff_desc.status = buff_desc_compat.status;
+
+ buff_desc.buff_context.p_user_priv =
+ compat_ptr(buff_desc_compat.buff_context.p_user_priv);
+ memcpy(buff_desc.buff_context.fm_prs_res,
+ buff_desc_compat.buff_context.fm_prs_res,
+ FM_PRS_MAX * sizeof(uint8_t));
+ memcpy(buff_desc.buff_context.fm_time_stamp,
+ buff_desc_compat.buff_context.fm_time_stamp,
+ FM_TIME_STAMP_MAX * sizeof(uint8_t));
+ } else
+#endif
+ {
+ if (size < sizeof(ioc_fmt_buff_desc_t)) {
+ _fmt_err("invalid buff_desc size.\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&buff_desc, (ioc_fmt_buff_desc_t *)buf,
+ sizeof(ioc_fmt_buff_desc_t)))
+ return -EFAULT;
+ }
+
+ data_offset = FM_PORT_GetBufferDataOffset(fmt_port->p_tx_fm_port_dev);
+ p_data = kmalloc(buff_desc.size+data_offset, GFP_KERNEL);
+ if (!p_data)
+ return -ENOMEM;
+
+ /* If Compat (32UserSpace - 64KernelSpace) the buff_desc.p_data is ok */
+ if (copy_from_user((uint8_t *)PTR_MOVE(p_data, data_offset),
+ buff_desc.p_data,
+ buff_desc.size)) {
+ kfree(p_data);
+ return -EFAULT;
+ }
+
+ /* TODO: dma_map_single here (cannot access the bpool struct) */
+
+ /* prepare fd */
+ memset(&fd, 0, sizeof(fd));
+ DPAA_FD_SET_ADDR(&fd, p_data);
+ DPAA_FD_SET_OFFSET(&fd, data_offset);
+ DPAA_FD_SET_LENGTH(&fd, buff_desc.size);
+
+ _errno = qman_enqueue(&fmt_port->p_tx_fqs[buff_desc.qid].fq_base,
+ (struct qm_fd *)&fd, 0);
+ if (_errno) {
+ buff_desc.status = (uint32_t)_errno;
+ if (copy_to_user((ioc_fmt_buff_desc_t *)buf, &buff_desc,
+ sizeof(ioc_fmt_buff_desc_t))) {
+ kfree(p_data);
+ return -EFAULT;
+ }
+ }
+
+ /* for debugging */
+#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME)
+ atomic_inc(&fmt_port->enqueue_to_qman_frm);
+#endif
+ _fmt_dbgr("called.\n");
+ return buff_desc.size;
+}
+
+/* fm test character device definition */
+static const struct file_operations fmt_fops =
+{
+ .owner = THIS_MODULE,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fmt_compat_ioctl,
+#endif
+ .unlocked_ioctl = fmt_ioctl,
+ .open = fmt_open,
+ .release = fmt_close,
+ .read = fmt_read,
+ .write = fmt_write,
+};
+
+static int fmt_init(void)
+{
+ int id;
+
+ _fmt_dbg("calling...\n");
+
+ /* Register to the /dev for IOCTL API */
+ /* Register dynamically a new major number for the character device: */
+ fm_test.major = register_chrdev(0, DEV_FM_TEST_NAME, &fmt_fops);
+ if (fm_test.major <= 0) {
+ _fmt_wrn("Failed to allocate major number for device %s.\n",
+ DEV_FM_TEST_NAME);
+ return -ENODEV;
+ }
+
+ /* Creating class for FMan_test */
+ fm_test.fmt_class = class_create(THIS_MODULE, DEV_FM_TEST_NAME);
+ if (IS_ERR(fm_test.fmt_class)) {
+ unregister_chrdev(fm_test.major, DEV_FM_TEST_NAME);
+ _fmt_wrn("Error creating %s class.\n", DEV_FM_TEST_NAME);
+ return -ENODEV;
+ }
+
+ for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++)
+ if (NULL == device_create(fm_test.fmt_class, NULL,
+ MKDEV(fm_test.major,
+ DEV_FM_TEST_PORTS_MINOR_BASE + id), NULL,
+ DEV_FM_TEST_NAME "%d", id)) {
+
+ _fmt_err("Error creating %s device.\n",
+ DEV_FM_TEST_NAME);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void fmt_free(void)
+{
+ int id;
+
+ for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++)
+ device_destroy(fm_test.fmt_class, MKDEV(fm_test.major,
+ DEV_FM_TEST_PORTS_MINOR_BASE + id));
+ class_destroy(fm_test.fmt_class);
+}
+
+static int __init __cold fmt_load(void)
+{
+ struct dpaa_eth_hooks_s priv_dpaa_eth_hooks;
+
+ /* set dpaa hooks for default queues */
+ memset(&priv_dpaa_eth_hooks, 0, sizeof(priv_dpaa_eth_hooks));
+ priv_dpaa_eth_hooks.rx_default = fmt_rx_default_hook;
+ priv_dpaa_eth_hooks.rx_error = fmt_rx_error_hook;
+ priv_dpaa_eth_hooks.tx_confirm = fmt_tx_confirm_hook;
+ priv_dpaa_eth_hooks.tx_error = fmt_tx_confirm_error_hook;
+
+ fsl_dpaa_eth_set_hooks(&priv_dpaa_eth_hooks);
+
+ /* initialize the fman test environment */
+ if (fmt_init() < 0) {
+ _fmt_err("Failed to init FM-test modul.\n");
+ fmt_free();
+ return -ENODEV;
+ }
+
+ _fmt_inf("FSL FM test module loaded.\n");
+
+ return 0;
+}
+
+static void __exit __cold fmt_unload(void)
+{
+ fmt_free();
+ _fmt_inf("FSL FM test module unloaded.\n");
+}
+
+module_init(fmt_load);
+module_exit(fmt_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
new file mode 100755
index 000000000000..c48884e34c08
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c
@@ -0,0 +1,2939 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ * Copyright 2019 NXP
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_fm.c
+ @Author Shlomi Gridish
+ @Description FM Linux wrapper functions.
+*/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/errno.h>
+#ifndef CONFIG_FMAN_ARM
+#include <sysdev/fsl_soc.h>
+#include <linux/fsl/guts.h>
+#include <linux/fsl/svr.h>
+#endif
+#include <linux/stat.h> /* For file access mask */
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+
+/* NetCommSw Headers --------------- */
+#include "std_ext.h"
+#include "error_ext.h"
+#include "sprint_ext.h"
+#include "debug_ext.h"
+#include "sys_io_ext.h"
+
+#include "fm_ioctls.h"
+
+#include "lnxwrp_fm.h"
+#include "lnxwrp_resources.h"
+#include "lnxwrp_sysfs_fm.h"
+#include "lnxwrp_sysfs_fm_port.h"
+#include "lnxwrp_exp_sym.h"
+#include "fm_common.h"
+#include "../../sdk_fman/Peripherals/FM/fm.h"
+#define __ERR_MODULE__ MODULE_FM
+
+extern struct device_node *GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node,
+ e_FmPortType portType,
+ uint8_t portId);
+
+#define PROC_PRINT(args...) offset += sprintf(buf+offset,args)
+
+#define ADD_ADV_CONFIG_NO_RET(_func, _param) \
+ do { \
+ if (i<max){ \
+ p_Entry = &p_Entrys[i]; \
+ p_Entry->p_Function = _func; \
+ _param \
+ i++; \
+ } \
+ else \
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,\
+ ("Number of advanced-configuration entries exceeded"));\
+ } while (0)
+
+/* Bootarg used to override the Kconfig FSL_FM_MAX_FRAME_SIZE value */
+#define FSL_FM_MAX_FRM_BOOTARG "fsl_fm_max_frm"
+
+/* Bootarg used to override FSL_FM_RX_EXTRA_HEADROOM Kconfig value */
+#define FSL_FM_RX_EXTRA_HEADROOM_BOOTARG "fsl_fm_rx_extra_headroom"
+
+/* Minimum and maximum value for the fsl_fm_rx_extra_headroom bootarg */
+#define FSL_FM_RX_EXTRA_HEADROOM_MIN 16
+#define FSL_FM_RX_EXTRA_HEADROOM_MAX 384
+
+#define FSL_FM_PAUSE_TIME_ENABLE 0xf000
+#define FSL_FM_PAUSE_TIME_DISABLE 0
+#define FSL_FM_PAUSE_THRESH_DEFAULT 0
+
+/*
+ * Max frame size, across all interfaces.
+ * Configurable from Kconfig or bootargs, to avoid allocating
+ * oversized (socket) buffers when not using jumbo frames.
+ * Must be large enough to accommodate the network MTU, but small enough
+ * to avoid wasting skb memory.
+ *
+ * Could be overridden once, at boot-time, via the
+ * fm_set_max_frm() callback.
+ */
+int fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
+
+/*
+ * Extra headroom for Rx buffers.
+ * FMan is instructed to allocate, on the Rx path, this amount of
+ * space at the beginning of a data buffer, beside the DPA private
+ * data area and the IC fields.
+ * Does not impact Tx buffer layout.
+ *
+ * Configurable from Kconfig or bootargs. Zero by default, it's needed
+ * on particular forwarding scenarios that add extra headers to the
+ * forwarded frame.
+ */
+int fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
+
+#ifdef CONFIG_FMAN_PFC
+static int fsl_fm_pfc_quanta[] = {
+ CONFIG_FMAN_PFC_QUANTA_0,
+ CONFIG_FMAN_PFC_QUANTA_1,
+ CONFIG_FMAN_PFC_QUANTA_2,
+ CONFIG_FMAN_PFC_QUANTA_3
+};
+#endif
+
+static t_LnxWrpFm lnxWrpFm;
+
+#ifdef FM_ERRATUM_A050385
+static bool fm_has_err_a050385;
+#endif
+
+int fm_get_max_frm()
+{
+ return fsl_fm_max_frm;
+}
+EXPORT_SYMBOL(fm_get_max_frm);
+
+int fm_get_rx_extra_headroom()
+{
+ return ALIGN(fsl_fm_rx_extra_headroom, 16);
+}
+EXPORT_SYMBOL(fm_get_rx_extra_headroom);
+
+#ifdef FM_ERRATUM_A050385
+bool fm_has_errata_a050385(void)
+{
+ return fm_has_err_a050385;
+}
+EXPORT_SYMBOL(fm_has_errata_a050385);
+#endif
+
+static int __init fm_set_max_frm(char *str)
+{
+ int ret = 0;
+
+ ret = get_option(&str, &fsl_fm_max_frm);
+ if (ret != 1) {
+ /*
+ * This will only work if CONFIG_EARLY_PRINTK is compiled in,
+ * and something like "earlyprintk=serial,uart0,115200" is
+ * specified in the bootargs
+ */
+ printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; "
+ "will use the default FSL_FM_MAX_FRAME_SIZE (%d) "
+ "from Kconfig.\n", FSL_FM_MAX_FRM_BOOTARG,
+ CONFIG_FSL_FM_MAX_FRAME_SIZE);
+
+ fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
+ return 1;
+ }
+
+ /* Don't allow invalid bootargs; fallback to the Kconfig value */
+ if (fsl_fm_max_frm < 64 || fsl_fm_max_frm > 9600) {
+ printk(KERN_WARNING "Invalid %s=%d in bootargs, valid range is "
+ "64-9600. Falling back to the FSL_FM_MAX_FRAME_SIZE (%d) "
+ "from Kconfig.\n",
+ FSL_FM_MAX_FRM_BOOTARG, fsl_fm_max_frm,
+ CONFIG_FSL_FM_MAX_FRAME_SIZE);
+
+ fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE;
+ return 1;
+ }
+
+ printk(KERN_INFO "Using fsl_fm_max_frm=%d from bootargs\n",
+ fsl_fm_max_frm);
+ return 0;
+}
+early_param(FSL_FM_MAX_FRM_BOOTARG, fm_set_max_frm);
+
+static int __init fm_set_rx_extra_headroom(char *str)
+{
+ int ret;
+
+ ret = get_option(&str, &fsl_fm_rx_extra_headroom);
+
+ if (ret != 1) {
+ printk(KERN_WARNING "No suitable %s=<int> prop in bootargs; "
+ "will use the default FSL_FM_RX_EXTRA_HEADROOM (%d) "
+ "from Kconfig.\n", FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
+ CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
+ fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
+
+ return 1;
+ }
+
+ if (fsl_fm_rx_extra_headroom < FSL_FM_RX_EXTRA_HEADROOM_MIN ||
+ fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) {
+ printk(KERN_WARNING "Invalid value for %s=%d prop in "
+ "bootargs; will use the default "
+ "FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n",
+ FSL_FM_RX_EXTRA_HEADROOM_BOOTARG,
+ fsl_fm_rx_extra_headroom,
+ CONFIG_FSL_FM_RX_EXTRA_HEADROOM);
+ fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM;
+ }
+
+ printk(KERN_INFO "Using fsl_fm_rx_extra_headroom=%d from bootargs\n",
+ fsl_fm_rx_extra_headroom);
+
+ return 0;
+}
+early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, fm_set_rx_extra_headroom);
+
+static irqreturn_t fm_irq(int irq, void *_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev;
+#ifdef CONFIG_PM_SLEEP
+ t_Fm *p_Fm = (t_Fm*)p_LnxWrpFmDev->h_Dev;
+#endif
+ if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev)
+ return IRQ_NONE;
+
+#ifdef CONFIG_PM_SLEEP
+ if (fman_get_normal_pending(p_Fm->p_FmFpmRegs) & INTR_EN_WAKEUP)
+ {
+ pm_wakeup_event(p_LnxWrpFmDev->dev, 200);
+ }
+#endif
+ FM_EventIsr(p_LnxWrpFmDev->h_Dev);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fm_err_irq(int irq, void *_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev;
+
+ if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev)
+ return IRQ_NONE;
+
+ if (FM_ErrorIsr(p_LnxWrpFmDev->h_Dev) == E_OK)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+/* used to protect FMD/LLD from concurrent calls in functions fm_mutex_lock / fm_mutex_unlock */
+static struct mutex lnxwrp_mutex;
+
+static t_LnxWrpFmDev * CreateFmDev(uint8_t id)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ int j;
+
+ p_LnxWrpFmDev = (t_LnxWrpFmDev *)XX_Malloc(sizeof(t_LnxWrpFmDev));
+ if (!p_LnxWrpFmDev)
+ {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ return NULL;
+ }
+
+ memset(p_LnxWrpFmDev, 0, sizeof(t_LnxWrpFmDev));
+ p_LnxWrpFmDev->fmDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->fmDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ p_LnxWrpFmDev->fmPcdDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->fmPcdDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ p_LnxWrpFmDev->hcPort.settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->hcPort.settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++)
+ {
+ p_LnxWrpFmDev->rxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->rxPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ }
+ for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++)
+ {
+ p_LnxWrpFmDev->txPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->txPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ }
+ for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++)
+ {
+ p_LnxWrpFmDev->opPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry));
+ memset(p_LnxWrpFmDev->opPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)));
+ }
+
+ return p_LnxWrpFmDev;
+}
+
+static void DestroyFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ int j;
+
+ for (j=0; j<FM_MAX_NUM_OF_OH_PORTS-1; j++)
+ if (p_LnxWrpFmDev->opPorts[j].settings.advConfig)
+ XX_Free(p_LnxWrpFmDev->opPorts[j].settings.advConfig);
+ for (j=0; j<FM_MAX_NUM_OF_TX_PORTS; j++)
+ if (p_LnxWrpFmDev->txPorts[j].settings.advConfig)
+ XX_Free(p_LnxWrpFmDev->txPorts[j].settings.advConfig);
+ for (j=0; j<FM_MAX_NUM_OF_RX_PORTS; j++)
+ if (p_LnxWrpFmDev->rxPorts[j].settings.advConfig)
+ XX_Free(p_LnxWrpFmDev->rxPorts[j].settings.advConfig);
+ if (p_LnxWrpFmDev->hcPort.settings.advConfig)
+ XX_Free(p_LnxWrpFmDev->hcPort.settings.advConfig);
+ if (p_LnxWrpFmDev->fmPcdDevSettings.advConfig)
+ XX_Free(p_LnxWrpFmDev->fmPcdDevSettings.advConfig);
+ if (p_LnxWrpFmDev->fmDevSettings.advConfig)
+ XX_Free(p_LnxWrpFmDev->fmDevSettings.advConfig);
+
+ XX_Free(p_LnxWrpFmDev);
+}
+
+static t_Error FillRestFmInfo(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+#define FM_BMI_PPIDS_OFFSET 0x00080304
+#define FM_DMA_PLR_OFFSET 0x000c2060
+#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4
+#define DMA_HIGH_LIODN_MASK 0x0FFF0000
+#define DMA_LOW_LIODN_MASK 0x00000FFF
+#define DMA_LIODN_SHIFT 16
+
+typedef _Packed struct {
+ uint32_t plr[32];
+} _PackedType t_Plr;
+
+typedef _Packed struct {
+ volatile uint32_t fmbm_ppid[63];
+} _PackedType t_Ppids;
+
+ t_Plr *p_Plr;
+ t_Ppids *p_Ppids;
+ int i,j;
+ uint32_t fmRev;
+
+ static const uint8_t phys1GRxPortId[] = {0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
+ static const uint8_t phys10GRxPortId[] = {0x10,0x11};
+#if (DPAA_VERSION >= 11)
+ static const uint8_t physOhPortId[] = {/* 0x1, */0x2,0x3,0x4,0x5,0x6,0x7};
+#else
+ static const uint8_t physOhPortId[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7};
+#endif
+ static const uint8_t phys1GTxPortId[] = {0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f};
+ static const uint8_t phys10GTxPortId[] = {0x30,0x31};
+
+ fmRev = (uint32_t)(*((volatile uint32_t *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_FPM_IP_REV_1_OFFSET)));
+ fmRev &= 0xffff;
+
+ p_Plr = (t_Plr *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_DMA_PLR_OFFSET);
+#ifdef MODULE
+ for (i=0;i<FM_MAX_NUM_OF_PARTITIONS/2;i++)
+ p_Plr->plr[i] = 0;
+#endif /* MODULE */
+
+ for (i=0; i<FM_MAX_NUM_OF_PARTITIONS; i++)
+ {
+ uint16_t liodnBase = (uint16_t)((i%2) ?
+ (p_Plr->plr[i/2] & DMA_LOW_LIODN_MASK) :
+ ((p_Plr->plr[i/2] & DMA_HIGH_LIODN_MASK) >> DMA_LIODN_SHIFT));
+#ifdef FM_PARTITION_ARRAY
+ /* TODO: this was .liodnPerPartition[i] = liodnBase; is the index meaning the same? */
+ p_LnxWrpFmDev->fmDevSettings.param.liodnBasePerPort[i] = liodnBase;
+#endif /* FM_PARTITION_ARRAY */
+
+ if ((i >= phys1GRxPortId[0]) &&
+ (i <= phys1GRxPortId[FM_MAX_NUM_OF_1G_RX_PORTS-1]))
+ {
+ for (j=0; j<ARRAY_SIZE(phys1GRxPortId); j++)
+ if (phys1GRxPortId[j] == i)
+ break;
+ ASSERT_COND(j<ARRAY_SIZE(phys1GRxPortId));
+ p_LnxWrpFmDev->rxPorts[j].settings.param.liodnBase = liodnBase;
+ }
+ else if (FM_MAX_NUM_OF_10G_RX_PORTS &&
+ (i >= phys10GRxPortId[0]) &&
+ (i <= phys10GRxPortId[FM_MAX_NUM_OF_10G_RX_PORTS-1]))
+ {
+ for (j=0; j<ARRAY_SIZE(phys10GRxPortId); j++)
+ if (phys10GRxPortId[j] == i)
+ break;
+ ASSERT_COND(j<ARRAY_SIZE(phys10GRxPortId));
+ p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+j].settings.param.liodnBase = liodnBase;
+ }
+ else if ((i >= physOhPortId[0]) &&
+ (i <= physOhPortId[FM_MAX_NUM_OF_OH_PORTS-1]))
+ {
+ for (j=0; j<ARRAY_SIZE(physOhPortId); j++)
+ if (physOhPortId[j] == i)
+ break;
+ ASSERT_COND(j<ARRAY_SIZE(physOhPortId));
+ if (j == 0)
+ p_LnxWrpFmDev->hcPort.settings.param.liodnBase = liodnBase;
+ else
+ p_LnxWrpFmDev->opPorts[j - 1].settings.param.liodnBase = liodnBase;
+ }
+ else if ((i >= phys1GTxPortId[0]) &&
+ (i <= phys1GTxPortId[FM_MAX_NUM_OF_1G_TX_PORTS-1]))
+ {
+ for (j=0; j<ARRAY_SIZE(phys1GTxPortId); j++)
+ if (phys1GTxPortId[j] == i)
+ break;
+ ASSERT_COND(j<ARRAY_SIZE(phys1GTxPortId));
+ p_LnxWrpFmDev->txPorts[j].settings.param.liodnBase = liodnBase;
+ }
+ else if (FM_MAX_NUM_OF_10G_TX_PORTS &&
+ (i >= phys10GTxPortId[0]) &&
+ (i <= phys10GTxPortId[FM_MAX_NUM_OF_10G_TX_PORTS-1]))
+ {
+ for (j=0; j<ARRAY_SIZE(phys10GTxPortId); j++)
+ if (phys10GTxPortId[j] == i)
+ break;
+ ASSERT_COND(j<ARRAY_SIZE(phys10GTxPortId));
+ p_LnxWrpFmDev->txPorts[FM_MAX_NUM_OF_1G_TX_PORTS+j].settings.param.liodnBase = liodnBase;
+ }
+ }
+
+ p_Ppids = (t_Ppids *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_BMI_PPIDS_OFFSET);
+
+ for (i=0; i<FM_MAX_NUM_OF_1G_RX_PORTS; i++)
+ p_LnxWrpFmDev->rxPorts[i].settings.param.specificParams.rxParams.liodnOffset =
+ p_Ppids->fmbm_ppid[phys1GRxPortId[i]-1];
+
+ for (i=0; i<FM_MAX_NUM_OF_10G_RX_PORTS; i++)
+ p_LnxWrpFmDev->rxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+i].settings.param.specificParams.rxParams.liodnOffset =
+ p_Ppids->fmbm_ppid[phys10GRxPortId[i]-1];
+
+ return E_OK;
+}
+
+/* Structure that defines QE firmware binary files.
+ *
+ * See Documentation/powerpc/qe_firmware.txt for a description of these
+ * fields.
+ */
+struct qe_firmware {
+ struct qe_header {
+ __be32 length; /* Length of the entire structure, in bytes */
+ u8 magic[3]; /* Set to { 'Q', 'E', 'F' } */
+ u8 version; /* Version of this layout. First ver is '1' */
+ } header;
+ u8 id[62]; /* Null-terminated identifier string */
+ u8 split; /* 0 = shared I-RAM, 1 = split I-RAM */
+ u8 count; /* Number of microcode[] structures */
+ struct {
+ __be16 model; /* The SOC model */
+ u8 major; /* The SOC revision major */
+ u8 minor; /* The SOC revision minor */
+ } __attribute__ ((packed)) soc;
+ u8 padding[4]; /* Reserved, for alignment */
+ __be64 extended_modes; /* Extended modes */
+ __be32 vtraps[8]; /* Virtual trap addresses */
+ u8 reserved[4]; /* Reserved, for future expansion */
+ struct qe_microcode {
+ u8 id[32]; /* Null-terminated identifier */
+ __be32 traps[16]; /* Trap addresses, 0 == ignore */
+ __be32 eccr; /* The value for the ECCR register */
+ __be32 iram_offset; /* Offset into I-RAM for the code */
+ __be32 count; /* Number of 32-bit words of the code */
+ __be32 code_offset; /* Offset of the actual microcode */
+ u8 major; /* The microcode version major */
+ u8 minor; /* The microcode version minor */
+ u8 revision; /* The microcode version revision */
+ u8 padding; /* Reserved, for alignment */
+ u8 reserved[4]; /* Reserved, for future expansion */
+ } __attribute__ ((packed)) microcode[1];
+ /* All microcode binaries should be located here */
+ /* CRC32 should be located here, after the microcode binaries */
+} __attribute__ ((packed));
+
+
+/**
+ * FindFmanMicrocode - find the Fman microcode
+ *
+ * This function returns a pointer to the QE Firmware blob that holds
+ * the Fman microcode. We use the QE Firmware structure because Fman microcode
+ * is similar to QE microcode, so there's no point in defining a new layout.
+ *
+ * Current versions of U-Boot embed the Fman firmware into the device tree,
+ * so we check for that first. Each Fman node in the device tree contains a
+ * node or a pointer to node that holds the firmware. Technically, we should
+ * be fetching the firmware node for the current Fman, but we don't have that
+ * information any more, so we assume that there is only one firmware node in
+ * the device tree, and that all Fmen use the same firmware.
+ */
+static const struct qe_firmware *FindFmanMicrocode(void)
+{
+ static const struct qe_firmware *P4080_UCPatch;
+ struct device_node *np;
+
+ if (P4080_UCPatch)
+ return P4080_UCPatch;
+
+ /* The firmware should be inside the device tree. */
+ np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware");
+ if (np) {
+ P4080_UCPatch = of_get_property(np, "fsl,firmware", NULL);
+ of_node_put(np);
+ if (P4080_UCPatch)
+ return P4080_UCPatch;
+ else
+ REPORT_ERROR(WARNING, E_NOT_FOUND, ("firmware node is incomplete"));
+ }
+
+ /* Returning NULL here forces the reuse of the IRAM content */
+ return NULL;
+}
+#define SVR_SECURITY_MASK 0x00080000
+#define SVR_PERSONALITY_MASK 0x0000FF00
+#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
+#define SVR_B4860_REV1_VALUE 0x86800010
+#define SVR_B4860_REV2_VALUE 0x86800020
+#define SVR_T4240_VALUE 0x82400000
+#define SVR_T4120_VALUE 0x82400100
+#define SVR_T4160_VALUE 0x82410000
+#define SVR_T4080_VALUE 0x82410200
+#define SVR_T4_DEVICE_ID 0x82400000
+#define SVR_DEVICE_ID_MASK 0xFFF00000
+
+#define OF_DEV_ID_NUM 2 /* one used, another one zeroed */
+
+/* searches for a subnode with the given name/compatible */
+static bool HasFmPcdOfNode(struct device_node *fm_node,
+ struct of_device_id *ids,
+ const char *name,
+ const char *compatible)
+{
+ struct device_node *dev_node;
+ bool ret = false;
+
+ memset(ids, 0, OF_DEV_ID_NUM*sizeof(struct of_device_id));
+ if (WARN_ON(strlen(name) >= sizeof(ids[0].name)))
+ return false;
+ strcpy(ids[0].name, name);
+ if (WARN_ON(strlen(compatible) >= sizeof(ids[0].compatible)))
+ return false;
+ strcpy(ids[0].compatible, compatible);
+ for_each_child_of_node(fm_node, dev_node)
+ if (of_match_node(ids, dev_node) != NULL)
+ ret = true;
+ return ret;
+}
+
+static t_LnxWrpFmDev * ReadFmDevTreeNode (struct platform_device *of_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ struct device_node *fm_node, *dev_node;
+ struct of_device_id ids[OF_DEV_ID_NUM];
+ struct resource res;
+ struct clk *clk;
+ u32 clk_rate;
+ const uint32_t *uint32_prop;
+ int _errno=0, lenp;
+ uint32_t tmp_prop;
+
+ fm_node = of_node_get(of_dev->dev.of_node);
+
+ uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp);
+ if (unlikely(uint32_prop == NULL)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+
+ if (tmp_prop > INTG_MAX_NUM_OF_FM) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
+ return NULL;
+ }
+ p_LnxWrpFmDev = CreateFmDev(tmp_prop);
+ if (!p_LnxWrpFmDev) {
+ REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG);
+ return NULL;
+ }
+ p_LnxWrpFmDev->dev = &of_dev->dev;
+ p_LnxWrpFmDev->id = tmp_prop;
+
+ /* Get the FM interrupt */
+ p_LnxWrpFmDev->irq = of_irq_to_resource(fm_node, 0, NULL);
+ if (unlikely(p_LnxWrpFmDev->irq == /*NO_IRQ*/0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ /* Get the FM error interrupt */
+ p_LnxWrpFmDev->err_irq = of_irq_to_resource(fm_node, 1, NULL);
+
+ if (unlikely(p_LnxWrpFmDev->err_irq == /*NO_IRQ*/0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ /* Get the FM address */
+ _errno = of_address_to_resource(fm_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+
+ p_LnxWrpFmDev->fmBaseAddr = 0;
+ p_LnxWrpFmDev->fmPhysBaseAddr = res.start;
+ p_LnxWrpFmDev->fmMemSize = res.end + 1 - res.start;
+
+ clk = of_clk_get(fm_node, 0);
+ if (IS_ERR(clk)) {
+ dev_err(&of_dev->dev, "%s: Failed to get FM clock structure\n",
+ __func__);
+ of_node_put(fm_node);
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ clk_rate = clk_get_rate(clk);
+ if (!clk_rate) {
+ dev_err(&of_dev->dev, "%s: Failed to determine FM clock rate\n",
+ __func__);
+ of_node_put(fm_node);
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ p_LnxWrpFmDev->fmDevSettings.param.fmClkFreq = DIV_ROUND_UP(clk_rate, 1000000); /* In MHz, rounded */
+ /* Get the MURAM base address and size */
+ memset(ids, 0, sizeof(ids));
+ if (WARN_ON(strlen("muram") >= sizeof(ids[0].name)))
+ return NULL;
+ strcpy(ids[0].name, "muram");
+ if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(ids[0].compatible)))
+ return NULL;
+ strcpy(ids[0].compatible, "fsl,fman-muram");
+ for_each_child_of_node(fm_node, dev_node) {
+ if (likely(of_match_node(ids, dev_node) != NULL)) {
+ _errno = of_address_to_resource(dev_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ p_LnxWrpFmDev->fmMuramBaseAddr = 0;
+ p_LnxWrpFmDev->fmMuramPhysBaseAddr = res.start;
+ p_LnxWrpFmDev->fmMuramMemSize = res.end + 1 - res.start;
+
+#ifndef CONFIG_FMAN_ARM
+ {
+ uint32_t svr;
+ svr = mfspr(SPRN_SVR);
+
+ if ((svr & ~SVR_VER_IGNORE_MASK) >= SVR_B4860_REV2_VALUE)
+ p_LnxWrpFmDev->fmMuramMemSize = 0x80000;
+ }
+#endif
+ }
+ }
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ /* Get the RTC base address and size */
+ memset(ids, 0, sizeof(ids));
+ if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name)))
+ return NULL;
+ strcpy(ids[0].name, "ptp-timer");
+ if (WARN_ON(strlen("fsl,fman-ptp-timer") >= sizeof(ids[0].compatible)))
+ return NULL;
+ strcpy(ids[0].compatible, "fsl,fman-ptp-timer");
+ for_each_child_of_node(fm_node, dev_node) {
+ if (likely(of_match_node(ids, dev_node) != NULL)) {
+ _errno = of_address_to_resource(dev_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+
+ p_LnxWrpFmDev->fmRtcBaseAddr = 0;
+ p_LnxWrpFmDev->fmRtcPhysBaseAddr = res.start;
+ p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start;
+ }
+ }
+#endif
+
+#if (DPAA_VERSION >= 11)
+ /* Get the VSP base address */
+ for_each_child_of_node(fm_node, dev_node) {
+ if (of_device_is_compatible(dev_node, "fsl,fman-vsps")) {
+ _errno = of_address_to_resource(dev_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno));
+ DestroyFmDev(p_LnxWrpFmDev);
+ return NULL;
+ }
+ p_LnxWrpFmDev->fmVspBaseAddr = 0;
+ p_LnxWrpFmDev->fmVspPhysBaseAddr = res.start;
+ p_LnxWrpFmDev->fmVspMemSize = res.end + 1 - res.start;
+ }
+ }
+#endif
+
+ /* Get all PCD nodes */
+ p_LnxWrpFmDev->prsActive = HasFmPcdOfNode(fm_node, ids, "parser", "fsl,fman-parser");
+ p_LnxWrpFmDev->kgActive = HasFmPcdOfNode(fm_node, ids, "keygen", "fsl,fman-keygen");
+ p_LnxWrpFmDev->ccActive = HasFmPcdOfNode(fm_node, ids, "cc", "fsl,fman-cc");
+ p_LnxWrpFmDev->plcrActive = HasFmPcdOfNode(fm_node, ids, "policer", "fsl,fman-policer");
+
+ if (p_LnxWrpFmDev->prsActive || p_LnxWrpFmDev->kgActive ||
+ p_LnxWrpFmDev->ccActive || p_LnxWrpFmDev->plcrActive)
+ p_LnxWrpFmDev->pcdActive = TRUE;
+
+ if (p_LnxWrpFmDev->pcdActive)
+ {
+ const char *str_prop = (char *)of_get_property(fm_node, "fsl,default-pcd", &lenp);
+ if (str_prop) {
+ if (strncmp(str_prop, "3-tuple", strlen("3-tuple")) == 0)
+ p_LnxWrpFmDev->defPcd = e_FM_PCD_3_TUPLE;
+ }
+ else
+ p_LnxWrpFmDev->defPcd = e_NO_PCD;
+ }
+
+#ifdef FM_ERRATUM_A050385
+ fm_has_err_a050385 = of_property_read_bool(fm_node, "fsl,erratum-a050385");
+#endif
+
+ of_node_put(fm_node);
+
+ p_LnxWrpFmDev->hcCh =
+ qman_affine_channel(cpumask_first(qman_affine_cpus()));
+
+ p_LnxWrpFmDev->active = TRUE;
+
+ return p_LnxWrpFmDev;
+}
+
+struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx)
+{
+ struct device_node *dev_node;
+ const uint32_t *uint32_prop;
+ int lenp;
+ uint32_t tmp_prop;
+
+ for_each_compatible_node(dev_node, NULL, "fsl,fman-extended-args") {
+ uint32_prop = (uint32_t *)of_get_property(dev_node, "cell-index", &lenp);
+ if (unlikely(uint32_prop == NULL)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ dev_node->full_name));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ if (tmp_prop > INTG_MAX_NUM_OF_FM) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
+ return NULL;
+ }
+ if (fmIndx == tmp_prop)
+ return dev_node;
+ }
+
+ return NULL;
+}
+
+static t_Error CheckNConfigFmAdvArgs (t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ struct device_node *dev_node;
+ t_Error err = E_INVALID_VALUE;
+ const uint32_t *uint32_prop;
+ const char *str_prop;
+ int lenp;
+ uint32_t tmp_prop;
+
+ dev_node = GetFmAdvArgsDevTreeNode(p_LnxWrpFmDev->id);
+ if (!dev_node) /* no advance parameters for FMan */
+ return E_OK;
+
+ str_prop = (char *)of_get_property(dev_node, "dma-aid-mode", &lenp);
+ if (str_prop) {
+ if (strcmp(str_prop, "port") == 0)
+ err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_PORT_ID);
+ else if (strcmp(str_prop, "tnum") == 0)
+ err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_TNUM);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(dev_node,
+ "total-fifo-size", &lenp);
+ if (uint32_prop) {
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ if (FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev,
+ tmp_prop) != E_OK)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(dev_node, "tnum-aging-period",
+ &lenp);
+ if (uint32_prop) {
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ err = FM_ConfigTnumAgingPeriod(p_LnxWrpFmDev->h_Dev,
+ (uint16_t)tmp_prop/*tnumAgingPeriod*/);
+
+ if (err != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ of_node_put(dev_node);
+
+ return E_OK;
+}
+
+static void LnxwrpFmDevExceptionsCb(t_Handle h_App, e_FmExceptions exception)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App;
+
+ ASSERT_COND(p_LnxWrpFmDev);
+
+ DBG(INFO, ("got fm exception %d", exception));
+
+ /* do nothing */
+ UNUSED(exception);
+}
+
+static void LnxwrpFmDevBusErrorCb(t_Handle h_App,
+ e_FmPortType portType,
+ uint8_t portId,
+ uint64_t addr,
+ uint8_t tnum,
+ uint16_t liodn)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App;
+
+ ASSERT_COND(p_LnxWrpFmDev);
+
+ /* do nothing */
+ UNUSED(portType);UNUSED(portId);UNUSED(addr);UNUSED(tnum);UNUSED(liodn);
+}
+
+static t_Error ConfigureFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ struct resource *dev_res;
+ int _errno;
+
+ if (!p_LnxWrpFmDev->active)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!"));
+
+#ifndef MODULE
+ _errno = can_request_irq(p_LnxWrpFmDev->irq, 0);
+ if (unlikely(_errno < 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno));
+#endif
+ _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, IRQF_SHARED, "fman", p_LnxWrpFmDev);
+ if (unlikely(_errno < 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno));
+
+ enable_irq_wake(p_LnxWrpFmDev->irq);
+
+ if (p_LnxWrpFmDev->err_irq != 0) {
+#ifndef MODULE
+ _errno = can_request_irq(p_LnxWrpFmDev->err_irq, 0);
+ if (unlikely(_errno < 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno));
+#endif
+ _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, fm_err_irq, IRQF_SHARED, "fman-err", p_LnxWrpFmDev);
+ if (unlikely(_errno < 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->err_irq, _errno));
+
+ enable_irq_wake(p_LnxWrpFmDev->err_irq);
+ }
+
+ p_LnxWrpFmDev->res = devm_request_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize, "fman");
+ if (unlikely(p_LnxWrpFmDev->res == NULL))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_mem_region() failed"));
+
+ p_LnxWrpFmDev->fmBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize));
+ if (unlikely(p_LnxWrpFmDev->fmBaseAddr == 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
+
+ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmBaseAddr, (uint64_t)p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM memory map"));
+
+ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize, "fman-muram");
+ if (unlikely(dev_res == NULL))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
+
+ p_LnxWrpFmDev->fmMuramBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize));
+ if (unlikely(p_LnxWrpFmDev->fmMuramBaseAddr == 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
+
+ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map"));
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (p_LnxWrpFmDev->fmRtcPhysBaseAddr)
+ {
+ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-ptp-timer");
+ if (unlikely(dev_res == NULL))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
+
+ p_LnxWrpFmDev->fmRtcBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize));
+ if (unlikely(p_LnxWrpFmDev->fmRtcBaseAddr == 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
+
+ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map"));
+ }
+#endif
+
+#if (DPAA_VERSION >= 11)
+ if (p_LnxWrpFmDev->fmVspPhysBaseAddr) {
+ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize, "fman-vsp");
+ if (unlikely(dev_res == NULL))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed"));
+
+ p_LnxWrpFmDev->fmVspBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize));
+ if (unlikely(p_LnxWrpFmDev->fmVspBaseAddr == 0))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed"));
+ }
+#endif
+
+ p_LnxWrpFmDev->fmDevSettings.param.baseAddr = p_LnxWrpFmDev->fmBaseAddr;
+ p_LnxWrpFmDev->fmDevSettings.param.fmId = p_LnxWrpFmDev->id;
+ p_LnxWrpFmDev->fmDevSettings.param.irq = NO_IRQ;
+ p_LnxWrpFmDev->fmDevSettings.param.errIrq = NO_IRQ;
+ p_LnxWrpFmDev->fmDevSettings.param.f_Exception = LnxwrpFmDevExceptionsCb;
+ p_LnxWrpFmDev->fmDevSettings.param.f_BusError = LnxwrpFmDevBusErrorCb;
+ p_LnxWrpFmDev->fmDevSettings.param.h_App = p_LnxWrpFmDev;
+
+ return FillRestFmInfo(p_LnxWrpFmDev);
+}
+
+#ifndef CONFIG_FMAN_ARM
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for QorIQ SOCs.
+ * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4
+ * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0"
+ * string would be used.
+*/
+static const struct of_device_id guts_device_ids[] = {
+ { .compatible = "fsl,qoriq-device-config-1.0", },
+ { .compatible = "fsl,qoriq-device-config-2.0", },
+ {}
+};
+
+static unsigned int get_rcwsr(int regnum)
+{
+ struct ccsr_guts __iomem *guts_regs = NULL;
+ struct device_node *guts_node;
+
+ guts_node = of_find_matching_node(NULL, guts_device_ids);
+ if (!guts_node) {
+ pr_err("could not find GUTS node\n");
+ return 0;
+ }
+ guts_regs = of_iomap(guts_node, 0);
+ of_node_put(guts_node);
+ if (!guts_regs) {
+ pr_err("ioremap of GUTS node failed\n");
+ return 0;
+ }
+
+ return ioread32be(&guts_regs->rcwsr[regnum]);
+}
+
+#define FMAN1_ALL_MACS_MASK 0xFCC00000
+#define FMAN2_ALL_MACS_MASK 0x000FCC00
+
+/**
+ * @Function ResetOnInitErrata_A007273
+ *
+ * @Description Workaround for Errata A-007273
+ * This workaround is required to avoid a FMan hang during reset on initialization.
+ * Enable all MACs in guts.devdisr2 register,
+ * then perform a regular FMan reset and then restore MACs to their original state.
+ *
+ * @Param[in] h_Fm - FM module descriptor
+ *
+ * @Return None.
+ */
+void ResetOnInitErrata_A007273(t_Handle h_Fm)
+{
+ struct ccsr_guts __iomem *guts_regs = NULL;
+ struct device_node *guts_node;
+ u32 devdisr2, enableMacs;
+
+ /* Get guts registers */
+ guts_node = of_find_matching_node(NULL, guts_device_ids);
+ if (!guts_node) {
+ pr_err("could not find GUTS node\n");
+ return;
+ }
+ guts_regs = of_iomap(guts_node, 0);
+ of_node_put(guts_node);
+ if (!guts_regs) {
+ pr_err("ioremap of GUTS node failed\n");
+ return;
+ }
+
+ /* Read current state */
+ devdisr2 = ioread32be(&guts_regs->devdisr2);
+
+ if (FmGetId(h_Fm) == 0)
+ enableMacs = devdisr2 & ~FMAN1_ALL_MACS_MASK;
+ else
+ enableMacs = devdisr2 & ~FMAN2_ALL_MACS_MASK;
+
+ /* Enable all MACs */
+ iowrite32be(enableMacs, &guts_regs->devdisr2);
+
+ /* Perform standard FMan reset */
+ FmReset(h_Fm);
+
+ /* Restore devdisr2 value */
+ iowrite32be(devdisr2, &guts_regs->devdisr2);
+
+ iounmap(guts_regs);
+}
+#endif
+
+static t_Error InitFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ const struct qe_firmware *fw;
+
+ if (!p_LnxWrpFmDev->active)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!"));
+
+ if ((p_LnxWrpFmDev->h_MuramDev = FM_MURAM_ConfigAndInit(p_LnxWrpFmDev->fmMuramBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)) == NULL)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM!"));
+
+ /* Loading the fman-controller code */
+ fw = FindFmanMicrocode();
+
+ if (!fw) {
+ /* this forces the reuse of the current IRAM content */
+ p_LnxWrpFmDev->fmDevSettings.param.firmware.size = 0;
+ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = NULL;
+ } else {
+ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code =
+ (void *) fw + be32_to_cpu(fw->microcode[0].code_offset);
+ p_LnxWrpFmDev->fmDevSettings.param.firmware.size =
+ sizeof(u32) * be32_to_cpu(fw->microcode[0].count);
+ DBG(INFO, ("Loading fman-controller code version %d.%d.%d",
+ fw->microcode[0].major,
+ fw->microcode[0].minor,
+ fw->microcode[0].revision));
+ }
+
+#ifdef CONFIG_FMAN_ARM
+ { /* endianness adjustments: byteswap the ucode retrieved from the f/w blob */
+ int i;
+ int usz = p_LnxWrpFmDev->fmDevSettings.param.firmware.size;
+ void * p_Code = p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code;
+ u32 *dest = kzalloc(usz, GFP_KERNEL);
+
+ if (p_Code && dest)
+ for(i=0; i < usz / 4; ++i)
+ dest[i] = be32_to_cpu(((u32 *)p_Code)[i]);
+
+ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = dest;
+ }
+#endif
+
+ p_LnxWrpFmDev->fmDevSettings.param.h_FmMuram = p_LnxWrpFmDev->h_MuramDev;
+
+#if (DPAA_VERSION >= 11)
+ if (p_LnxWrpFmDev->fmVspBaseAddr) {
+ p_LnxWrpFmDev->fmDevSettings.param.vspBaseAddr = p_LnxWrpFmDev->fmVspBaseAddr;
+ p_LnxWrpFmDev->fmDevSettings.param.partVSPBase = 0;
+ p_LnxWrpFmDev->fmDevSettings.param.partNumOfVSPs = FM_VSP_MAX_NUM_OF_ENTRIES;
+ }
+#endif
+
+#ifdef CONFIG_FMAN_ARM
+ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1;
+#else
+ if(p_LnxWrpFmDev->fmDevSettings.param.fmId == 0)
+ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio =
+ !!(get_rcwsr(4) & 0x2); /* RCW[FM_MAC_RAT0] */
+ else
+ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio =
+ !!(get_rcwsr(4) & 0x1); /* RCW[FM_MAC_RAT1] */
+
+ {
+ /* T4 Devices ClkRatio is always 1 regardless of RCW[FM_MAC_RAT1] */
+ uint32_t svr;
+ svr = mfspr(SPRN_SVR);
+
+ if ((svr & SVR_DEVICE_ID_MASK) == SVR_T4_DEVICE_ID)
+ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1;
+ }
+#endif /* CONFIG_FMAN_ARM */
+
+ if ((p_LnxWrpFmDev->h_Dev = FM_Config(&p_LnxWrpFmDev->fmDevSettings.param)) == NULL)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM"));
+
+
+ if (FM_ConfigResetOnInit(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
+
+#ifndef CONFIG_FMAN_ARM
+#ifdef FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273
+ if (FM_ConfigResetOnInitOverrideCallback(p_LnxWrpFmDev->h_Dev, ResetOnInitErrata_A007273) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
+#endif /* FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 */
+#endif /* CONFIG_FMAN_ARM */
+
+#ifdef CONFIG_FMAN_P1023
+ if (FM_ConfigDmaAidOverride(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
+#endif
+
+
+ CheckNConfigFmAdvArgs(p_LnxWrpFmDev);
+
+ if (FM_Init(p_LnxWrpFmDev->h_Dev) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM"));
+
+ /* TODO: Why we mask these interrupts? */
+ if (p_LnxWrpFmDev->err_irq == 0) {
+ FM_SetException(p_LnxWrpFmDev->h_Dev, e_FM_EX_DMA_BUS_ERROR,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_READ_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SYSTEM_WRITE_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_FM_WRITE_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SINGLE_PORT_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_STALL_ON_TASKS , FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_SINGLE_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_DOUBLE_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_SINGLE_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DOUBLE_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_LIST_RAM_ECC,FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STORAGE_PROFILE_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STATISTICS_RAM_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_DISPATCH_RAM_ECC, FALSE);
+ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_IRAM_ECC,FALSE);
+ /* TODO: FmDisableRamsEcc assert for ramsEccOwners.
+ * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/
+ }
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (p_LnxWrpFmDev->fmRtcBaseAddr)
+ {
+ t_FmRtcParams fmRtcParam;
+
+ memset(&fmRtcParam, 0, sizeof(fmRtcParam));
+ fmRtcParam.h_App = p_LnxWrpFmDev;
+ fmRtcParam.h_Fm = p_LnxWrpFmDev->h_Dev;
+ fmRtcParam.baseAddress = p_LnxWrpFmDev->fmRtcBaseAddr;
+
+ if(!(p_LnxWrpFmDev->h_RtcDev = FM_RTC_Config(&fmRtcParam)))
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-RTC"));
+
+ if (FM_RTC_ConfigPeriod(p_LnxWrpFmDev->h_RtcDev, DPA_PTP_NOMINAL_FREQ_PERIOD_NS) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC"));
+
+ if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC"));
+ }
+#endif
+
+ return E_OK;
+}
+
+/* TODO: to be moved back here */
+extern void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev);
+
+static void FreeFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ if (!p_LnxWrpFmDev->active)
+ return;
+
+ FreeFmPcdDev(p_LnxWrpFmDev);
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (p_LnxWrpFmDev->h_RtcDev)
+ FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev);
+#endif
+
+ if (p_LnxWrpFmDev->h_Dev)
+ FM_Free(p_LnxWrpFmDev->h_Dev);
+
+ if (p_LnxWrpFmDev->h_MuramDev)
+ FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev);
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+ if (p_LnxWrpFmDev->fmRtcBaseAddr)
+ {
+ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr);
+ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr));
+ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize);
+ }
+#endif
+ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr);
+ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr));
+ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize);
+ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmBaseAddr);
+ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr));
+ devm_release_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize);
+ if (p_LnxWrpFmDev->err_irq != 0) {
+ devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, p_LnxWrpFmDev);
+ }
+
+ devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, p_LnxWrpFmDev);
+}
+
+/* FMan character device file operations */
+extern struct file_operations fm_fops;
+
+static int /*__devinit*/ fm_probe(struct platform_device *of_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+
+ if ((p_LnxWrpFmDev = ReadFmDevTreeNode(of_dev)) == NULL)
+ return -EIO;
+ if (ConfigureFmDev(p_LnxWrpFmDev) != E_OK)
+ return -EIO;
+ if (InitFmDev(p_LnxWrpFmDev) != E_OK)
+ return -EIO;
+
+ /* IOCTL ABI checking */
+ LnxWrpPCDIOCTLEnumChecking();
+ LnxWrpPCDIOCTLTypeChecking();
+
+ Sprint (p_LnxWrpFmDev->name, "%s%d", DEV_FM_NAME, p_LnxWrpFmDev->id);
+
+ /* Register to the /dev for IOCTL API */
+ /* Register dynamically a new major number for the character device: */
+ if ((p_LnxWrpFmDev->major = register_chrdev(0, p_LnxWrpFmDev->name, &fm_fops)) <= 0) {
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", p_LnxWrpFmDev->name));
+ return -EIO;
+ }
+
+ /* Creating classes for FM */
+ DBG(TRACE ,("class_create fm_class"));
+ p_LnxWrpFmDev->fm_class = class_create(THIS_MODULE, p_LnxWrpFmDev->name);
+ if (IS_ERR(p_LnxWrpFmDev->fm_class)) {
+ unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_class"));
+ return -EIO;
+ }
+
+ device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE), NULL,
+ "fm%d", p_LnxWrpFmDev->id);
+ device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE), NULL,
+ "fm%d-pcd", p_LnxWrpFmDev->id);
+ dev_set_drvdata(p_LnxWrpFmDev->dev, p_LnxWrpFmDev);
+
+ /* create sysfs entries for stats and regs */
+ if ( fm_sysfs_create(p_LnxWrpFmDev->dev) !=0 )
+ {
+ FreeFmDev(p_LnxWrpFmDev);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unable to create sysfs entry - fm!!!"));
+ return -EIO;
+ }
+
+#ifdef CONFIG_PM
+ device_set_wakeup_capable(p_LnxWrpFmDev->dev, true);
+#endif
+
+ DBG(TRACE, ("FM%d probed", p_LnxWrpFmDev->id));
+
+ return 0;
+}
+
+static int fm_remove(struct platform_device *of_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+ p_LnxWrpFmDev = dev_get_drvdata(dev);
+
+ fm_sysfs_destroy(dev);
+
+ DBG(TRACE, ("destroy fm_class"));
+ device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE));
+ device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE));
+ class_destroy(p_LnxWrpFmDev->fm_class);
+
+ /* Destroy chardev */
+ unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name);
+
+ FreeFmDev(p_LnxWrpFmDev);
+
+ DestroyFmDev(p_LnxWrpFmDev);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id fm_match[] = {
+ {
+ .compatible = "fsl,fman"
+ },
+ {}
+};
+#ifndef MODULE
+MODULE_DEVICE_TABLE(of, fm_match);
+#endif /* !MODULE */
+
+#if defined CONFIG_PM && (defined CONFIG_PPC || defined CONFIG_PPC64)
+
+#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C
+#define SCFG_FMCLKDPSLPCR_DS_VAL 0x48402000
+#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000
+
+struct device *g_fm_dev;
+
+static int fm_soc_suspend(struct device *dev)
+{
+ int err = 0;
+ uint32_t *fmclk;
+ t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev));
+ g_fm_dev = dev;
+ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
+ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL);
+ if (p_LnxWrpFmDev->h_DsarRxPort)
+ {
+#ifdef CONFIG_FSL_QORIQ_PM
+ device_set_wakeup_enable(p_LnxWrpFmDev->dev, 1);
+#endif
+ err = FM_PORT_EnterDsarFinal(p_LnxWrpFmDev->h_DsarRxPort,
+ p_LnxWrpFmDev->h_DsarTxPort);
+ }
+ return err;
+}
+
+static int fm_soc_resume(struct device *dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev));
+ uint32_t *fmclk;
+ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4);
+ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_NORMAL_VAL);
+ if (p_LnxWrpFmDev->h_DsarRxPort)
+ {
+#ifdef CONFIG_FSL_QORIQ_PM
+ device_set_wakeup_enable(p_LnxWrpFmDev->dev, 0);
+#endif
+ FM_PORT_ExitDsar(p_LnxWrpFmDev->h_DsarRxPort,
+ p_LnxWrpFmDev->h_DsarTxPort);
+ p_LnxWrpFmDev->h_DsarRxPort = 0;
+ p_LnxWrpFmDev->h_DsarTxPort = 0;
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops fm_pm_ops = {
+ .suspend = fm_soc_suspend,
+ .resume = fm_soc_resume,
+};
+
+#define FM_PM_OPS (&fm_pm_ops)
+
+#else /* CONFIG_PM && (CONFIG_PPC || CONFIG_PPC64) */
+
+#define FM_PM_OPS NULL
+
+#endif /* CONFIG_PM && (CONFIG_PPC || CONFIG_PPC64) */
+
+static struct platform_driver fm_driver = {
+ .driver = {
+ .name = "fsl-fman",
+ .of_match_table = fm_match,
+ .owner = THIS_MODULE,
+ .pm = FM_PM_OPS,
+ },
+ .probe = fm_probe,
+ .remove = fm_remove
+};
+
+t_Handle LNXWRP_FM_Init(void)
+{
+ memset(&lnxWrpFm, 0, sizeof(lnxWrpFm));
+ mutex_init(&lnxwrp_mutex);
+
+ /* Register to the DTB for basic FM API */
+ platform_driver_register(&fm_driver);
+
+ return &lnxWrpFm;
+}
+
+t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm)
+{
+ platform_driver_unregister(&fm_driver);
+ mutex_destroy(&lnxwrp_mutex);
+
+ return E_OK;
+}
+
+
+struct fm * fm_bind(struct device *fm_dev)
+{
+ return (struct fm *)(dev_get_drvdata(get_device(fm_dev)));
+}
+EXPORT_SYMBOL(fm_bind);
+
+void fm_unbind(struct fm *fm)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
+
+ put_device(p_LnxWrpFmDev->dev);
+}
+EXPORT_SYMBOL(fm_unbind);
+
+struct resource * fm_get_mem_region(struct fm *fm)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
+
+ return p_LnxWrpFmDev->res;
+}
+EXPORT_SYMBOL(fm_get_mem_region);
+
+void * fm_get_handle(struct fm *fm)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
+
+ return (void *)p_LnxWrpFmDev->h_Dev;
+}
+EXPORT_SYMBOL(fm_get_handle);
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+void * fm_get_rtc_handle(struct fm *fm)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm;
+
+ return (void *)p_LnxWrpFmDev->h_RtcDev;
+}
+EXPORT_SYMBOL(fm_get_rtc_handle);
+#endif
+
+struct fm_port * fm_port_bind (struct device *fm_port_dev)
+{
+ return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev)));
+}
+EXPORT_SYMBOL(fm_port_bind);
+
+void fm_port_unbind(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+
+ put_device(p_LnxWrpFmPortDev->dev);
+}
+EXPORT_SYMBOL(fm_port_unbind);
+
+void *fm_port_get_handle(const struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+
+ return (void *)p_LnxWrpFmPortDev->h_Dev;
+}
+EXPORT_SYMBOL(fm_port_get_handle);
+
+u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port,
+ const void *data)
+{
+ return FM_PORT_GetBufferTimeStamp(fm_port_get_handle(port),
+ (void *)data);
+}
+EXPORT_SYMBOL(fm_port_get_buffer_time_stamp);
+
+void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+
+ *base_addr = p_LnxWrpFmPortDev->settings.param.baseAddr;
+}
+EXPORT_SYMBOL(fm_port_get_base_addr);
+
+void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+
+ p_LnxWrpFmPortDev->pcd_owner_params.cba = params->cba;
+ p_LnxWrpFmPortDev->pcd_owner_params.cbf = params->cbf;
+ p_LnxWrpFmPortDev->pcd_owner_params.dev = params->dev;
+}
+EXPORT_SYMBOL(fm_port_pcd_bind);
+
+void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ struct device_node *fm_node, *port_node;
+ const uint32_t *uint32_prop;
+ int lenp;
+
+ params->data_align = 0;
+ params->manip_extra_space = 0;
+
+ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
+ if (!fm_node) /* no advance parameters for FMan */
+ return;
+
+ port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
+ p_LnxWrpFmPortDev->settings.param.portType,
+ p_LnxWrpFmPortDev->settings.param.portId);
+ if (!port_node) /* no advance parameters for FMan-Port */
+ return;
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "buffer-layout", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)*2))
+ return;
+
+ params->manip_extra_space = (uint8_t)be32_to_cpu(uint32_prop[0]);
+ params->data_align = (uint16_t)be32_to_cpu(uint32_prop[1]);
+ }
+
+ of_node_put(port_node);
+ of_node_put(fm_node);
+}
+EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params);
+
+uint16_t fm_get_tx_port_channel(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+
+ return p_LnxWrpFmPortDev->txCh;
+}
+EXPORT_SYMBOL(fm_get_tx_port_channel);
+
+int fm_port_enable (struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+ t_Error err = FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
+
+ return GET_ERROR_TYPE(err);
+}
+EXPORT_SYMBOL(fm_port_enable);
+
+int fm_port_disable(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port;
+ t_Error err = FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
+
+ return GET_ERROR_TYPE(err);
+}
+EXPORT_SYMBOL(fm_port_disable);
+
+int fm_port_set_rate_limit(struct fm_port *port,
+ uint16_t max_burst_size,
+ uint32_t rate_limit)
+{
+ t_FmPortRateLimit param;
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ int err = 0;
+
+ param.maxBurstSize = max_burst_size;
+ param.rateLimit = rate_limit;
+ param.rateLimitDivider = 0;
+
+ err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, &param);
+ return err;
+}
+EXPORT_SYMBOL(fm_port_set_rate_limit);
+
+int fm_port_del_rate_limit(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+
+ FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev);
+ return 0;
+}
+EXPORT_SYMBOL(fm_port_del_rate_limit);
+
+void FM_PORT_Dsar_DumpRegs(void);
+int ar_showmem(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ FM_PORT_Dsar_DumpRegs();
+ return 2;
+}
+
+struct auto_res_tables_sizes *fm_port_get_autores_maxsize(
+ struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ return &p_LnxWrpFmPortDev->dsar_table_sizes;
+}
+EXPORT_SYMBOL(fm_port_get_autores_maxsize);
+
+int fm_port_enter_autores_for_deepsleep(struct fm_port *port,
+ struct auto_res_port_params *params)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ t_LnxWrpFmDev* p_LnxWrpFmDev = (t_LnxWrpFmDev*)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ p_LnxWrpFmDev->h_DsarRxPort = p_LnxWrpFmPortDev->h_Dev;
+ p_LnxWrpFmDev->h_DsarTxPort = params->h_FmPortTx;
+
+ /*Register other under /proc/autoresponse */
+ if (WARN_ON(sizeof(t_FmPortDsarParams) != sizeof(struct auto_res_port_params)))
+ return -EFAULT;
+
+ FM_PORT_EnterDsar(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarParams*)params);
+ return 0;
+}
+EXPORT_SYMBOL(fm_port_enter_autores_for_deepsleep);
+
+void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx,
+ struct fm_port *port_tx)
+{
+}
+EXPORT_SYMBOL(fm_port_exit_auto_res_for_deep_sleep);
+
+int fm_port_get_autores_stats(struct fm_port *port,
+ struct auto_res_port_stats *stats)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ if (WARN_ON(sizeof(t_FmPortDsarStats) != sizeof(struct auto_res_port_stats)))
+ return -EFAULT;
+ return FM_PORT_GetDsarStats(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarStats*)stats);
+}
+EXPORT_SYMBOL(fm_port_get_autores_stats);
+
+int fm_port_suspend(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev))
+ return FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
+ else
+ return 0;
+}
+EXPORT_SYMBOL(fm_port_suspend);
+
+int fm_port_resume(struct fm_port *port)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev))
+ return FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
+ else
+ return 0;
+}
+EXPORT_SYMBOL(fm_port_resume);
+
+bool fm_port_is_in_auto_res_mode(struct fm_port *port)
+{
+ return FM_PORT_IsInDsar(port);
+}
+EXPORT_SYMBOL(fm_port_is_in_auto_res_mode);
+
+#ifdef CONFIG_FMAN_PFC
+int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port,
+ uint8_t prio, uint8_t wq)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+ int err;
+ int _errno;
+
+ err = FM_PORT_SetPfcPrioritiesMappingToQmanWQ(p_LnxWrpFmPortDev->h_Dev,
+ prio, wq);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_PORT_SetPfcPrioritiesMappingToQmanWQ() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_port_set_pfc_priorities_mapping_to_qman_wq);
+#endif
+
+int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev,
+ e_FmMacExceptions exception, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_SetException(fm_mac_dev, exception, enable);
+
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_SetException() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_set_exception);
+
+int fm_mac_free(struct fm_mac_dev *fm_mac_dev)
+{
+ int err;
+ int _error;
+
+ err = FM_MAC_Free(fm_mac_dev);
+ _error = -GET_ERROR_TYPE(err);
+
+ if (unlikely(_error < 0))
+ pr_err("FM_MAC_Free() = 0x%08x\n", err);
+
+ return _error;
+}
+EXPORT_SYMBOL(fm_mac_free);
+
+struct fm_mac_dev *fm_mac_config(t_FmMacParams *params)
+{
+ struct fm_mac_dev *fm_mac_dev;
+
+ fm_mac_dev = FM_MAC_Config(params);
+ if (unlikely(fm_mac_dev == NULL))
+ pr_err("FM_MAC_Config() failed\n");
+
+ return fm_mac_dev;
+}
+EXPORT_SYMBOL(fm_mac_config);
+
+int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev,
+ int len)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_ConfigMaxFrameLength(fm_mac_dev, len);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_config_max_frame_length);
+
+int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_ConfigPadAndCrc(fm_mac_dev, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_ConfigPadAndCrc() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_config_pad_and_crc);
+
+int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_ConfigHalfDuplex(fm_mac_dev, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_ConfigHalfDuplex() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_config_half_duplex);
+
+int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_ConfigResetOnInit(fm_mac_dev, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_ConfigResetOnInit() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_config_reset_on_init);
+
+int fm_mac_init(struct fm_mac_dev *fm_mac_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_Init(fm_mac_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Init() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_init);
+
+int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version)
+{
+ int err;
+ int _errno;
+
+ err = FM_MAC_GetVesrion(fm_mac_dev, version);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_GetVesrion() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_get_version);
+
+int fm_mac_enable(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_Enable(fm_mac_dev, e_COMM_MODE_RX_AND_TX);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Enable() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_enable);
+
+int fm_mac_disable(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_Disable(fm_mac_dev, e_COMM_MODE_RX_AND_TX);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Disable() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_disable);
+
+int fm_mac_resume(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_Resume(fm_mac_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Resume() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_resume);
+
+int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev,
+ bool enable)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_SetPromiscuous(fm_mac_dev, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_SetPromiscuous() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_set_promiscuous);
+
+int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ t_EnetAddr *mac_addr)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_RemoveHashMacAddr(fm_mac_dev, mac_addr);
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0) {
+ pr_err("FM_MAC_RemoveHashMacAddr() = 0x%08x\n", err);
+ return _errno;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fm_mac_remove_hash_mac_addr);
+
+int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ t_EnetAddr *mac_addr)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_AddHashMacAddr(fm_mac_dev, mac_addr);
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0) {
+ pr_err("FM_MAC_AddHashMacAddr() = 0x%08x\n", err);
+ return _errno;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fm_mac_add_hash_mac_addr);
+
+int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev,
+ uint8_t *addr)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_ModifyMacAddr(fm_mac_dev, (t_EnetAddr *)addr);
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0)
+ pr_err("FM_MAC_ModifyMacAddr() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_modify_mac_addr);
+
+int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev,
+ bool link, int speed, bool duplex)
+{
+ int _errno;
+ t_Error err;
+
+ if (!link) {
+#if (DPAA_VERSION < 11)
+ FM_MAC_RestartAutoneg(fm_mac_dev);
+#endif
+ return 0;
+ }
+
+ err = FM_MAC_AdjustLink(fm_mac_dev, speed, duplex);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_AdjustLink() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_adjust_link);
+
+int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_Enable1588TimeStamp(fm_mac_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Enable1588TimeStamp() = 0x%08x\n", err);
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_enable_1588_time_stamp);
+
+int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_MAC_Disable1588TimeStamp(fm_mac_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_Disable1588TimeStamp() = 0x%08x\n", err);
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_disable_1588_time_stamp);
+
+int fm_mac_set_rx_pause_frames(
+ struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ int _errno;
+ t_Error err;
+
+ /* if rx pause is enabled, do NOT ignore pause frames */
+ err = FM_MAC_SetRxIgnorePauseFrames(fm_mac_dev, !en);
+
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0)
+ pr_err("FM_MAC_SetRxIgnorePauseFrames() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_set_rx_pause_frames);
+
+#ifdef CONFIG_FMAN_PFC
+int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ bool en)
+{
+ int _errno, i;
+ t_Error err;
+
+ if (en)
+ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
+ err = FM_MAC_SetTxPauseFrames(fm_mac_dev,
+ i, fsl_fm_pfc_quanta[i],
+ FSL_FM_PAUSE_THRESH_DEFAULT);
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0) {
+ pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err);
+ return _errno;
+ }
+ }
+ else
+ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
+ err = FM_MAC_SetTxPauseFrames(fm_mac_dev,
+ i, FSL_FM_PAUSE_TIME_DISABLE,
+ FSL_FM_PAUSE_THRESH_DEFAULT);
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0) {
+ pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err);
+ return _errno;
+ }
+ }
+
+ return _errno;
+}
+#else
+int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev,
+ bool en)
+{
+ int _errno;
+ t_Error err;
+
+ if (en)
+ err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev,
+ FSL_FM_PAUSE_TIME_ENABLE);
+ else
+ err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev,
+ FSL_FM_PAUSE_TIME_DISABLE);
+
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0)
+ pr_err("FM_MAC_SetTxAutoPauseFrames() = 0x%08x\n", err);
+
+ return _errno;
+}
+#endif
+EXPORT_SYMBOL(fm_mac_set_tx_pause_frames);
+
+#ifdef CONFIG_FSL_SDK_FMAN_RTC_API
+int fm_rtc_enable(struct fm *fm_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_Enable(fm_get_rtc_handle(fm_dev), 0);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_Enable = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_enable);
+
+int fm_rtc_disable(struct fm *fm_dev)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_Disable(fm_get_rtc_handle(fm_dev));
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_Disable = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_disable);
+
+int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_GetCurrentTime(fm_get_rtc_handle(fm_dev), ts);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_GetCurrentTime = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_get_cnt);
+
+int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_SetCurrentTime(fm_get_rtc_handle(fm_dev), ts);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_SetCurrentTime = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_set_cnt);
+
+int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_GetFreqCompensation(fm_get_rtc_handle(fm_dev),
+ drift);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_GetFreqCompensation = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_get_drift);
+
+int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_SetFreqCompensation(fm_get_rtc_handle(fm_dev),
+ drift);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_SetFreqCompensation = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_set_drift);
+
+int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id,
+ uint64_t time)
+{
+ t_FmRtcAlarmParams alarm;
+ int _errno;
+ t_Error err;
+
+ alarm.alarmId = id;
+ alarm.alarmTime = time;
+ alarm.f_AlarmCallback = NULL;
+ err = FM_RTC_SetAlarm(fm_get_rtc_handle(fm_dev),
+ &alarm);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_SetAlarm = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_set_alarm);
+
+int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id,
+ uint64_t fiper)
+{
+ t_FmRtcPeriodicPulseParams pp;
+ int _errno;
+ t_Error err;
+
+ pp.periodicPulseId = id;
+ pp.periodicPulsePeriod = fiper;
+ pp.f_PeriodicPulseCallback = NULL;
+ err = FM_RTC_SetPeriodicPulse(fm_get_rtc_handle(fm_dev), &pp);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_SetPeriodicPulse = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_set_fiper);
+
+#ifdef CONFIG_PTP_1588_CLOCK_DPAA
+int fm_rtc_enable_interrupt(struct fm *fm_dev, uint32_t events)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_EnableInterrupt(fm_get_rtc_handle(fm_dev),
+ events);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_EnableInterrupt = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_enable_interrupt);
+
+int fm_rtc_disable_interrupt(struct fm *fm_dev, uint32_t events)
+{
+ int _errno;
+ t_Error err;
+
+ err = FM_RTC_DisableInterrupt(fm_get_rtc_handle(fm_dev),
+ events);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_RTC_DisableInterrupt = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_rtc_disable_interrupt);
+#endif
+#endif /* CONFIG_FSL_SDK_FMAN_RTC_API */
+
+int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, bool en)
+{
+ int _errno;
+ t_Error err;
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port;
+
+ /* Do not set WoL on AR ports */
+ if (FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev)) {
+ printk(KERN_WARNING "Port is AutoResponse enabled! WoL will not be set on this port!\n");
+ return 0;
+ }
+
+ err = FM_MAC_SetWakeOnLan(fm_mac_dev, en);
+
+ _errno = -GET_ERROR_TYPE(err);
+ if (_errno < 0)
+ pr_err("FM_MAC_SetWakeOnLan() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_mac_set_wol);
+
+void fm_mutex_lock(void)
+{
+ mutex_lock(&lnxwrp_mutex);
+}
+EXPORT_SYMBOL(fm_mutex_lock);
+
+void fm_mutex_unlock(void)
+{
+ mutex_unlock(&lnxwrp_mutex);
+}
+EXPORT_SYMBOL(fm_mutex_unlock);
+
+/*Macsec wrapper functions*/
+struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params)
+{
+ struct fm_macsec_dev *fm_macsec_dev;
+
+ fm_macsec_dev = FM_MACSEC_Config((t_FmMacsecParams *)fm_params);
+ if (unlikely(fm_macsec_dev == NULL))
+ pr_err("FM_MACSEC_Config() failed\n");
+
+ return fm_macsec_dev;
+}
+EXPORT_SYMBOL(fm_macsec_config);
+
+int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_Init(fm_macsec_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_Init() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_init);
+
+int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _error;
+
+ err = FM_MACSEC_Free(fm_macsec_dev);
+ _error = -GET_ERROR_TYPE(err);
+
+ if (unlikely(_error < 0))
+ pr_err("FM_MACSEC_Free() = 0x%08x\n", err);
+
+ return _error;
+}
+EXPORT_SYMBOL(fm_macsec_free);
+
+int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev
+ *fm_macsec_dev,
+ fm_macsec_unknown_sci_frame_treatment treat_mode)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigUnknownSciFrameTreatment(fm_macsec_dev,
+ treat_mode);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigUnknownSciFrameTreatmen() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_unknown_sci_frame_treatment);
+
+int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ bool deliver_uncontrolled)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigInvalidTagsFrameTreatment(fm_macsec_dev,
+ deliver_uncontrolled);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_invalid_tags_frame_treatment);
+
+int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ bool discard_uncontrolled)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(fm_macsec_dev,
+ discard_uncontrolled);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatmen() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_kay_frame_treatment);
+
+int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_untag_frame_treatment treat_mode)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigUntagFrameTreatment(fm_macsec_dev, treat_mode);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigUntagFrameTreatment() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_untag_frame_treatment);
+
+int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev,
+ uint32_t pn_exh_thr)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigPnExhaustionThreshold(fm_macsec_dev, pn_exh_thr);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigPnExhaustionThreshold() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_pn_exhaustion_threshold);
+
+int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigKeysUnreadable(fm_macsec_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigKeysUnreadable() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_keys_unreadable);
+
+int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigSectagWithoutSCI(fm_macsec_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigSectagWithoutSCI() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_sectag_without_sci);
+
+int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_exception exception, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_ConfigException(fm_macsec_dev, exception, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_ConfigException() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_config_exception);
+
+int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev,
+ int *macsec_revision)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_GetRevision(fm_macsec_dev, macsec_revision);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_GetRevision() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_get_revision);
+
+int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_Enable(fm_macsec_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_Enable() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_enable);
+
+int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_Disable(fm_macsec_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_Disable() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_disable);
+
+int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev,
+ fm_macsec_exception exception, bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SetException(fm_macsec_dev, exception, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SetException() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_set_exception);
+
+/* Macsec SECY wrapper API */
+struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params)
+{
+ struct fm_macsec_secy_dev *fm_macsec_secy;
+
+ fm_macsec_secy = FM_MACSEC_SECY_Config((t_FmMacsecSecYParams *)secy_params);
+ if (unlikely(fm_macsec_secy < 0))
+ pr_err("FM_MACSEC_SECY_Config() failed\n");
+
+ return fm_macsec_secy;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config);
+
+int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_Init(fm_macsec_secy_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_Init() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_init);
+
+int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_Free(fm_macsec_secy_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_Free() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_free);
+
+int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_sci_insertion_mode sci_insertion_mode)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigSciInsertionMode(fm_macsec_secy_dev,
+ sci_insertion_mode);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigSciInsertionMode() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_sci_insertion_mode);
+
+int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool protect_frames)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigProtectFrames(fm_macsec_secy_dev,
+ protect_frames);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigProtectFrames() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_protect_frames);
+
+int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool replay_protect, uint32_t replay_window)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigReplayWindow(fm_macsec_secy_dev,
+ replay_protect, replay_window);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigReplayWindow() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_replay_window);
+
+int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_valid_frame_behavior validate_frames)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigValidationMode(fm_macsec_secy_dev,
+ validate_frames);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigValidationMode() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_validation_mode);
+
+int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ bool confidentiality_enable,
+ uint32_t confidentiality_offset)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigConfidentiality(fm_macsec_secy_dev,
+ confidentiality_enable,
+ confidentiality_offset);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigConfidentiality() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_confidentiality);
+
+int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigPointToPoint(fm_macsec_secy_dev);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigPointToPoint() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_point_to_point);
+
+int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_secy_exception exception,
+ bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigException(fm_macsec_secy_dev, exception,
+ enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigException() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_exception);
+
+int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ fm_macsec_secy_event event,
+ bool enable)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_ConfigEvent(fm_macsec_secy_dev, event, enable);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_ConfigEvent() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_config_event);
+
+struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct fm_macsec_secy_sc_params *params)
+{
+ struct rx_sc_dev *rx_sc_dev;
+
+ rx_sc_dev = FM_MACSEC_SECY_CreateRxSc(fm_macsec_secy_dev, (t_FmMacsecSecYSCParams *)params);
+ if (unlikely(rx_sc_dev == NULL))
+ pr_err("FM_MACSEC_SECY_CreateRxSc() failed\n");
+
+ return rx_sc_dev;
+}
+EXPORT_SYMBOL(fm_macsec_secy_create_rxsc);
+
+int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_DeleteRxSc(fm_macsec_secy_dev, sc);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_DeleteRxSc() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_delete_rxsc);
+
+int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, macsec_an_t an,
+ uint32_t lowest_pn, macsec_sa_key_t key)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_CreateRxSa(fm_macsec_secy_dev, sc, an,
+ lowest_pn, key);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_CreateRxSa() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_create_rx_sa);
+
+int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, macsec_an_t an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_DeleteRxSa(fm_macsec_secy_dev, sc, an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_DeleteRxSa() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_delete_rx_sa);
+
+int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_RxSaEnableReceive(fm_macsec_secy_dev, sc, an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_RxSaEnableReceive() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_rxsa_enable_receive);
+
+int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_RxSaDisableReceive(fm_macsec_secy_dev, sc, an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_RxSaDisableReceive() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_rxsa_disable_receive);
+
+int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, uint32_t updt_next_pn)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_RxSaUpdateNextPn(fm_macsec_secy_dev, sc, an,
+ updt_next_pn);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_RxSaUpdateNextPn() = 0x%08x\n", err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_next_pn);
+
+int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, uint32_t updt_lowest_pn)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_RxSaUpdateLowestPn(fm_macsec_secy_dev, sc, an,
+ updt_lowest_pn);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_RxSaUpdateLowestPn() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_lowest_pn);
+
+int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc,
+ macsec_an_t an, macsec_sa_key_t key)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_RxSaModifyKey(fm_macsec_secy_dev, sc, an, key);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_RxSaModifyKey() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_rxsa_modify_key);
+
+int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an, macsec_sa_key_t key)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_CreateTxSa(fm_macsec_secy_dev, an, key);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_CreateTxSa() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_create_tx_sa);
+
+int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_DeleteTxSa(fm_macsec_secy_dev, an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_DeleteTxSa() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_delete_tx_sa);
+
+int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t next_active_an,
+ macsec_sa_key_t key)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_TxSaModifyKey(fm_macsec_secy_dev, next_active_an,
+ key);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_TxSaModifyKey() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_txsa_modify_key);
+
+int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_TxSaSetActive(fm_macsec_secy_dev, an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_TxSaSetActive() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_txsa_set_active);
+
+int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ macsec_an_t *p_an)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_TxSaGetActive(fm_macsec_secy_dev, p_an);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_TxSaGetActive() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_txsa_get_active);
+
+int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ struct rx_sc_dev *sc, uint32_t *sc_phys_id)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_GetRxScPhysId(fm_macsec_secy_dev, sc, sc_phys_id);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_GetRxScPhysId() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_get_rxsc_phys_id);
+
+int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev,
+ uint32_t *sc_phys_id)
+{
+ int err;
+ int _errno;
+
+ err = FM_MACSEC_SECY_GetTxScPhysId(fm_macsec_secy_dev, sc_phys_id);
+ _errno = -GET_ERROR_TYPE(err);
+ if (unlikely(_errno < 0))
+ pr_err("FM_MACSEC_SECY_GetTxScPhysId() = 0x%08x\n",
+ err);
+
+ return _errno;
+}
+EXPORT_SYMBOL(fm_macsec_secy_get_txsc_phys_id);
+
+static t_Handle h_FmLnxWrp;
+
+static int __init __cold fm_load (void)
+{
+ if ((h_FmLnxWrp = LNXWRP_FM_Init()) == NULL)
+ {
+ printk("Failed to init FM wrapper!\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "Freescale FM module," \
+ " FMD API version %d.%d.%d\n",
+ FMD_API_VERSION_MAJOR,
+ FMD_API_VERSION_MINOR,
+ FMD_API_VERSION_RESPIN);
+ return 0;
+}
+
+static void __exit __cold fm_unload (void)
+{
+ if (h_FmLnxWrp)
+ LNXWRP_FM_Free(h_FmLnxWrp);
+}
+
+module_init (fm_load);
+module_exit (fm_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h
new file mode 100644
index 000000000000..098325635d23
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_fm.h
+
+ @Author Shlomi Gridish
+
+ @Description FM Linux wrapper functions.
+
+*/
+
+#ifndef __LNXWRP_FM_H__
+#define __LNXWRP_FM_H__
+
+#include <linux/fsl_qman.h> /* struct qman_fq */
+
+#include "std_ext.h"
+#include "error_ext.h"
+#include "list_ext.h"
+
+#include "lnxwrp_fm_ext.h"
+
+#define FM_MAX_NUM_OF_ADV_SETTINGS 10
+
+#define LNXWRP_FM_NUM_OF_SHARED_PROFILES 16
+
+#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES)
+#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */
+#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */
+#else
+#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */
+#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */
+#endif
+#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */
+#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */
+
+#define FRAG_MANIP_SPACE 128
+#define FRAG_DATA_ALIGN 64
+
+#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE
+#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0
+#endif
+
+#ifndef CONFIG_FSL_FM_RX_EXTRA_HEADROOM
+#define CONFIG_FSL_FM_RX_EXTRA_HEADROOM 16
+#endif
+
+typedef enum {
+ e_NO_PCD = 0,
+ e_FM_PCD_3_TUPLE
+} e_LnxWrpFmPortPcdDefUseCase;
+
+
+typedef struct t_FmTestFq {
+ struct qman_fq fq_base;
+ t_Handle h_Arg;
+} t_FmTestFq;
+
+typedef struct {
+ uint8_t id; /* sw port id, see SW_PORT_ID_TO_HW_PORT_ID() in fm_common.h */
+ int minor;
+ char name[20];
+ bool active;
+ uint64_t phys_baseAddr;
+ uint64_t baseAddr; /* Port's *virtual* address */
+ uint32_t memSize;
+ t_WrpFmPortDevSettings settings;
+ t_FmExtPools opExtPools;
+ uint8_t totalNumOfSchemes;
+ uint8_t schemesBase;
+ uint8_t numOfSchemesUsed;
+ uint32_t pcdBaseQ;
+ uint16_t pcdNumOfQs;
+ struct fm_port_pcd_param pcd_owner_params;
+ e_LnxWrpFmPortPcdDefUseCase defPcd;
+ t_Handle h_DefNetEnv;
+ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES];
+ t_FmBufferPrefixContent buffPrefixContent;
+ t_Handle h_Dev;
+ t_Handle h_DfltVsp;
+ t_Handle h_LnxWrpFmDev;
+ uint16_t txCh;
+ struct device *dev;
+ struct device_attribute *dev_attr_stats;
+ struct device_attribute *dev_attr_regs;
+ struct device_attribute *dev_attr_bmi_regs;
+ struct device_attribute *dev_attr_qmi_regs;
+#if (DPAA_VERSION >= 11)
+ struct device_attribute *dev_attr_ipv4_opt;
+#endif
+ struct device_attribute *dev_attr_dsar_regs;
+ struct device_attribute *dev_attr_dsar_mem;
+ struct auto_res_tables_sizes dsar_table_sizes;
+} t_LnxWrpFmPortDev;
+
+typedef struct {
+ uint8_t id;
+ bool active;
+ uint64_t baseAddr;
+ uint32_t memSize;
+ t_WrpFmMacDevSettings settings;
+ t_Handle h_Dev;
+ t_Handle h_LnxWrpFmDev;
+} t_LnxWrpFmMacDev;
+
+/* information about all active ports for an FMan.
+ * !Some ports may be disabled by u-boot, thus will not be available */
+struct fm_active_ports {
+ uint32_t num_oh_ports;
+ uint32_t num_tx_ports;
+ uint32_t num_rx_ports;
+ uint32_t num_tx25_ports;
+ uint32_t num_rx25_ports;
+ uint32_t num_tx10_ports;
+ uint32_t num_rx10_ports;
+};
+
+/* FMan resources precalculated at fm probe based
+ * on available FMan port. */
+struct fm_resource_settings {
+ /* buffers - fifo sizes */
+ uint32_t tx1g_num_buffers;
+ uint32_t rx1g_num_buffers;
+ uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */
+ uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */
+ uint32_t tx10g_num_buffers;
+ uint32_t rx10g_num_buffers;
+ uint32_t oh_num_buffers;
+ uint32_t shared_ext_buffers;
+
+ /* open DMAs */
+ uint32_t tx_1g_dmas;
+ uint32_t rx_1g_dmas;
+ uint32_t tx_2g5_dmas; /* Not supported yet by LLD */
+ uint32_t rx_2g5_dmas; /* Not supported yet by LLD */
+ uint32_t tx_10g_dmas;
+ uint32_t rx_10g_dmas;
+ uint32_t oh_dmas;
+ uint32_t shared_ext_open_dma;
+
+ /* Tnums */
+ uint32_t tx_1g_tnums;
+ uint32_t rx_1g_tnums;
+ uint32_t tx_2g5_tnums; /* Not supported yet by LLD */
+ uint32_t rx_2g5_tnums; /* Not supported yet by LLD */
+ uint32_t tx_10g_tnums;
+ uint32_t rx_10g_tnums;
+ uint32_t oh_tnums;
+ uint32_t shared_ext_tnums;
+};
+
+typedef struct {
+ uint8_t id;
+ char name[10];
+ bool active;
+ bool pcdActive;
+ bool prsActive;
+ bool kgActive;
+ bool ccActive;
+ bool plcrActive;
+ e_LnxWrpFmPortPcdDefUseCase defPcd;
+ uint32_t usedSchemes;
+ uint8_t totalNumOfSharedSchemes;
+ uint8_t sharedSchemesBase;
+ uint8_t numOfSchemesUsed;
+ uint8_t defNetEnvId;
+ uint64_t fmPhysBaseAddr;
+ uint64_t fmBaseAddr;
+ uint32_t fmMemSize;
+ uint64_t fmMuramPhysBaseAddr;
+ uint64_t fmMuramBaseAddr;
+ uint32_t fmMuramMemSize;
+ uint64_t fmRtcPhysBaseAddr;
+ uint64_t fmRtcBaseAddr;
+ uint32_t fmRtcMemSize;
+ uint64_t fmVspPhysBaseAddr;
+ uint64_t fmVspBaseAddr;
+ uint32_t fmVspMemSize;
+ int irq;
+ int err_irq;
+ t_WrpFmDevSettings fmDevSettings;
+ t_WrpFmPcdDevSettings fmPcdDevSettings;
+ t_Handle h_Dev;
+ uint16_t hcCh;
+
+ t_Handle h_MuramDev;
+ t_Handle h_PcdDev;
+ t_Handle h_RtcDev;
+
+ t_Handle h_DsarRxPort;
+ t_Handle h_DsarTxPort;
+
+ t_LnxWrpFmPortDev hcPort;
+ t_LnxWrpFmPortDev opPorts[FM_MAX_NUM_OF_OH_PORTS-1];
+ t_LnxWrpFmPortDev rxPorts[FM_MAX_NUM_OF_RX_PORTS];
+ t_LnxWrpFmPortDev txPorts[FM_MAX_NUM_OF_TX_PORTS];
+ t_LnxWrpFmMacDev macs[FM_MAX_NUM_OF_MACS];
+ struct fm_active_ports fm_active_ports_info;
+ struct fm_resource_settings fm_resource_settings_info;
+
+ struct device *dev;
+ struct resource *res;
+ int major;
+ struct class *fm_class;
+ struct device_attribute *dev_attr_stats;
+ struct device_attribute *dev_attr_regs;
+ struct device_attribute *dev_attr_risc_load;
+
+ struct device_attribute *dev_pcd_attr_stats;
+ struct device_attribute *dev_plcr_attr_regs;
+ struct device_attribute *dev_prs_attr_regs;
+ struct device_attribute *dev_fm_fpm_attr_regs;
+ struct device_attribute *dev_fm_kg_attr_regs;
+ struct device_attribute *dev_fm_kg_pe_attr_regs;
+ struct device_attribute *dev_attr_muram_free_size;
+ struct device_attribute *dev_attr_fm_ctrl_code_ver;
+
+
+ struct qman_fq *hc_tx_conf_fq, *hc_tx_err_fq, *hc_tx_fq;
+} t_LnxWrpFmDev;
+
+typedef struct {
+ t_LnxWrpFmDev *p_FmDevs[INTG_MAX_NUM_OF_FM];
+} t_LnxWrpFm;
+#define LNXWRP_FM_OBJECT(ptr) LIST_OBJECT(ptr, t_LnxWrpFm, fms[((t_LnxWrpFmDev *)ptr)->id])
+
+
+t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat);
+t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat);
+
+
+#if 0
+static __inline__ t_Error AllocSchemesForPort(t_LnxWrpFmDev *p_LnxWrpFmDev, uint8_t numSchemes, uint8_t *p_BaseSchemeNum)
+{
+ uint32_t schemeMask;
+ uint8_t i;
+
+ if (!numSchemes)
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ schemeMask = 0x80000000;
+ *p_BaseSchemeNum = 0xff;
+
+ for (i=0; schemeMask && numSchemes; schemeMask>>=1, i++)
+ if ((p_LnxWrpFmDev->usedSchemes & schemeMask) == 0)
+ {
+ p_LnxWrpFmDev->usedSchemes |= schemeMask;
+ numSchemes--;
+ if (*p_BaseSchemeNum==0xff)
+ *p_BaseSchemeNum = i;
+ }
+ else if (*p_BaseSchemeNum!=0xff)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Fragmentation on schemes array!!!"));
+
+ if (numSchemes)
+ RETURN_ERROR(MINOR, E_FULL, ("schemes!!!"));
+ return E_OK;
+}
+#endif
+
+void LnxWrpPCDIOCTLTypeChecking(void);
+void LnxWrpPCDIOCTLEnumChecking(void);
+
+#endif /* __LNXWRP_FM_H__ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
new file mode 100644
index 000000000000..b22ac3c85bee
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c
@@ -0,0 +1,1512 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_fm_port.c
+
+ @Description FMD wrapper - FMan port functions.
+
+*/
+
+#include <linux/version.h>
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#ifndef CONFIG_FMAN_ARM
+#include <linux/fsl/svr.h>
+#endif
+#include <linux/io.h>
+
+#include "sprint_ext.h"
+#include "fm_common.h"
+#include "lnxwrp_fsl_fman.h"
+#include "fm_port_ext.h"
+#if (DPAA_VERSION >= 11)
+#include "fm_vsp_ext.h"
+#endif /* DPAA_VERSION >= 11 */
+#include "fm_ioctls.h"
+#include "lnxwrp_resources.h"
+#include "lnxwrp_sysfs_fm_port.h"
+
+#define __ERR_MODULE__ MODULE_FM
+
+extern struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx);
+
+/* TODO: duplicated, see lnxwrp_fm.c */
+#define ADD_ADV_CONFIG_NO_RET(_func, _param)\
+do {\
+ if (i < max) {\
+ p_Entry = &p_Entrys[i];\
+ p_Entry->p_Function = _func;\
+ _param\
+ i++;\
+ } else {\
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,\
+ ("Number of advanced-configuration entries exceeded"));\
+ } \
+} while (0)
+
+#ifndef CONFIG_FMAN_ARM
+#define IS_T1023_T1024 (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \
+ SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023)
+#endif
+
+static volatile int hcFrmRcv/* = 0 */;
+static spinlock_t lock;
+
+static enum qman_cb_dqrr_result qm_tx_conf_dqrr_cb(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry
+ *dq)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_FmTestFq *) fq)->h_Arg;
+ unsigned long flags;
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+{
+ /* extract the HC frame address */
+ uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *)&dq->fd));
+ int hcf_l = ((struct qm_fd *)&dq->fd)->length20;
+ int i;
+
+ /* 32b byteswap of all data in the HC Frame */
+ for(i = 0; i < hcf_l / 4; ++i)
+ hcf_va[i] =
+ ___constant_swab32(hcf_va[i]);
+}
+#endif
+ FM_PCD_HcTxConf(p_LnxWrpFmDev->h_PcdDev, (t_DpaaFD *)&dq->fd);
+ spin_lock_irqsave(&lock, flags);
+ hcFrmRcv--;
+ spin_unlock_irqrestore(&lock, flags);
+
+ return qman_cb_dqrr_consume;
+}
+
+static enum qman_cb_dqrr_result qm_tx_dqrr_cb(struct qman_portal *portal,
+ struct qman_fq *fq,
+ const struct qm_dqrr_entry *dq)
+{
+ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+ __func__);
+ return qman_cb_dqrr_consume;
+}
+
+static void qm_err_cb(struct qman_portal *portal,
+ struct qman_fq *fq, const struct qm_mr_entry *msg)
+{
+ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+ __func__);
+}
+
+static struct qman_fq *FqAlloc(t_LnxWrpFmDev * p_LnxWrpFmDev,
+ uint32_t fqid,
+ uint32_t flags, uint16_t channel, uint8_t wq)
+{
+ int _errno;
+ struct qman_fq *fq = NULL;
+ t_FmTestFq *p_FmtFq;
+ struct qm_mcc_initfq initfq;
+
+ p_FmtFq = (t_FmTestFq *) XX_Malloc(sizeof(t_FmTestFq));
+ if (!p_FmtFq) {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!"));
+ return NULL;
+ }
+
+ p_FmtFq->fq_base.cb.dqrr = ((flags & QMAN_FQ_FLAG_NO_ENQUEUE)
+ ? qm_tx_conf_dqrr_cb
+ : qm_tx_dqrr_cb);
+ p_FmtFq->fq_base.cb.ern = qm_err_cb;
+ /* p_FmtFq->fq_base.cb.fqs = qm_err_cb; */
+ /* qm_err_cb wrongly called when the FQ is parked */
+ p_FmtFq->fq_base.cb.fqs = NULL;
+ p_FmtFq->h_Arg = (t_Handle) p_LnxWrpFmDev;
+ if (fqid == 0) {
+ flags |= QMAN_FQ_FLAG_DYNAMIC_FQID;
+ flags &= ~QMAN_FQ_FLAG_NO_MODIFY;
+ } else {
+ flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID;
+ }
+
+ if (qman_create_fq(fqid, flags, &p_FmtFq->fq_base)) {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!"));
+ XX_Free(p_FmtFq);
+ return NULL;
+ }
+ fq = &p_FmtFq->fq_base;
+
+ if (!(flags & QMAN_FQ_FLAG_NO_MODIFY)) {
+ initfq.we_mask = QM_INITFQ_WE_DESTWQ;
+ initfq.fqd.dest.channel = channel;
+ initfq.fqd.dest.wq = wq;
+
+ _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_NO_MEMORY,
+ ("FQ obj - qman_init_fq!!!"));
+ qman_destroy_fq(fq, 0);
+ XX_Free(p_FmtFq);
+ return NULL;
+ }
+ }
+
+ DBG(TRACE,
+ ("fqid %d, flags 0x%08x, channel %d, wq %d", qman_fq_fqid(fq),
+ flags, channel, wq));
+
+ return fq;
+}
+
+static void FqFree(struct qman_fq *fq)
+{
+ int _errno;
+
+ _errno = qman_retire_fq(fq, NULL);
+ if (unlikely(_errno < 0))
+ printk(KERN_WARNING "qman_retire_fq(%u) = %d\n", qman_fq_fqid(fq), _errno);
+
+ _errno = qman_oos_fq(fq);
+ if (unlikely(_errno < 0))
+ printk(KERN_WARNING "qman_oos_fq(%u) = %d\n", qman_fq_fqid(fq), _errno);
+
+ qman_destroy_fq(fq, 0);
+ XX_Free((t_FmTestFq *) fq);
+}
+
+static t_Error QmEnqueueCB(t_Handle h_Arg, void *p_Fd)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_Arg;
+ int _errno, timeout = 1000000;
+ unsigned long flags;
+
+ ASSERT_COND(p_LnxWrpFmDev);
+
+ spin_lock_irqsave(&lock, flags);
+ hcFrmRcv++;
+ spin_unlock_irqrestore(&lock, flags);
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+{
+ /* extract the HC frame address */
+ uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *) p_Fd));
+ int hcf_l = ((struct qm_fd *)p_Fd)->length20;
+ int i;
+
+ /* 32b byteswap of all data in the HC Frame */
+ for(i = 0; i < hcf_l / 4; ++i)
+ hcf_va[i] =
+ ___constant_swab32(hcf_va[i]);
+}
+#endif
+
+ _errno = qman_enqueue(p_LnxWrpFmDev->hc_tx_fq, (struct qm_fd *) p_Fd,
+ 0);
+ if (_errno)
+ RETURN_ERROR(MINOR, E_INVALID_STATE,
+ ("qman_enqueue() failed"));
+
+ while (hcFrmRcv && --timeout) {
+ udelay(1);
+ cpu_relax();
+ }
+ if (timeout == 0) {
+ dump_stack();
+ RETURN_ERROR(MINOR, E_WRITE_FAILED,
+ ("timeout waiting for Tx confirmation"));
+ return E_WRITE_FAILED;
+ }
+
+ return E_OK;
+}
+
+static t_LnxWrpFmPortDev *ReadFmPortDevTreeNode(struct platform_device
+ *of_dev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+ struct device_node *fm_node, *port_node;
+ struct resource res;
+ const uint32_t *uint32_prop;
+ int _errno = 0, lenp;
+ uint32_t tmp_prop;
+
+#ifdef CONFIG_FMAN_P1023
+ static unsigned char have_oh_port/* = 0 */;
+#endif
+
+ port_node = of_node_get(of_dev->dev.of_node);
+
+ /* Get the FM node */
+ fm_node = of_get_parent(port_node);
+ if (unlikely(fm_node == NULL)) {
+ REPORT_ERROR(MAJOR, E_NO_DEVICE,
+ ("of_get_parent() = %d", _errno));
+ return NULL;
+ }
+
+ p_LnxWrpFmDev =
+ dev_get_drvdata(&of_find_device_by_node(fm_node)->dev);
+ of_node_put(fm_node);
+
+ /* if fm_probe() failed, no point in going further with port probing */
+ if (p_LnxWrpFmDev == NULL)
+ return NULL;
+
+ uint32_prop =
+ (uint32_t *) of_get_property(port_node, "cell-index", &lenp);
+ if (unlikely(uint32_prop == NULL)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ if (of_device_is_compatible(port_node, "fsl,fman-port-oh") ||
+ of_device_is_compatible(port_node, "fsl,fman-v2-port-oh") ||
+ of_device_is_compatible(port_node, "fsl,fman-v3-port-oh")) {
+#ifndef CONFIG_FMAN_ARM
+#ifdef CONFIG_FMAN_P3040_P4080_P5020
+ /* On PPC FMan v2, OH ports start from cell-index 0x1 */
+ tmp_prop -= 0x1;
+#else
+ /* On PPC FMan v3 (Low and High), OH ports start from
+ * cell-index 0x2
+ */
+ tmp_prop -= 0x2;
+#endif // CONFIG_FMAN_P3040_P4080_P5020
+#endif // CONFIG_FMAN_ARM
+
+ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_OH_PORTS)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+
+#ifdef CONFIG_FMAN_P1023
+ /* Beware, this can be done when there is only
+ one FMan to be initialized */
+ if (!have_oh_port) {
+ have_oh_port = 1; /* first OP/HC port
+ is used for host command */
+#else
+ /* Here it is hardcoded the use of the OH port 1
+ (with cell-index 0) */
+ if (tmp_prop == 0) {
+#endif
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
+ p_LnxWrpFmPortDev->id = 0;
+ /*
+ p_LnxWrpFmPortDev->id = *uint32_prop-1;
+ p_LnxWrpFmPortDev->id = *uint32_prop;
+ */
+ p_LnxWrpFmPortDev->settings.param.portType =
+ e_FM_PORT_TYPE_OH_HOST_COMMAND;
+ } else {
+ p_LnxWrpFmPortDev =
+ &p_LnxWrpFmDev->opPorts[tmp_prop - 1];
+ p_LnxWrpFmPortDev->id = tmp_prop- 1;
+ p_LnxWrpFmPortDev->settings.param.portType =
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING;
+ }
+ p_LnxWrpFmPortDev->settings.param.portId = tmp_prop;
+
+ uint32_prop =
+ (uint32_t *) of_get_property(port_node,
+ "fsl,qman-channel-id",
+ &lenp);
+ if (uint32_prop == NULL) {
+ /*
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("missing fsl,qman-channel-id"));
+ */
+ XX_Print("FM warning: missing fsl,qman-channel-id"
+ " for OH port.\n");
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ p_LnxWrpFmPortDev->txCh = tmp_prop;
+
+ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
+ qmChannel = p_LnxWrpFmPortDev->txCh;
+ } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-tx")) {
+ tmp_prop -= 0x28;
+ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_TX_PORTS)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop];
+
+ p_LnxWrpFmPortDev->id = tmp_prop;
+ p_LnxWrpFmPortDev->settings.param.portId =
+ p_LnxWrpFmPortDev->id;
+ p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_TX;
+
+ uint32_prop = (uint32_t *) of_get_property(port_node,
+ "fsl,qman-channel-id", &lenp);
+ if (uint32_prop == NULL) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("missing fsl,qman-channel-id"));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ p_LnxWrpFmPortDev->txCh = tmp_prop;
+ p_LnxWrpFmPortDev->
+ settings.param.specificParams.nonRxParams.qmChannel =
+ p_LnxWrpFmPortDev->txCh;
+ } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) {
+#ifndef CONFIG_FMAN_ARM
+ /* On T102x, the 10G TX port IDs start from 0x28 */
+ if (IS_T1023_T1024)
+ tmp_prop -= 0x28;
+ else
+#endif
+ tmp_prop -= 0x30;
+
+ if (unlikely(tmp_prop>= FM_MAX_NUM_OF_10G_TX_PORTS)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop +
+ FM_MAX_NUM_OF_1G_TX_PORTS];
+#ifndef CONFIG_FMAN_ARM
+ if (IS_T1023_T1024)
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop];
+#endif
+
+ p_LnxWrpFmPortDev->id = tmp_prop;
+ p_LnxWrpFmPortDev->settings.param.portId =
+ p_LnxWrpFmPortDev->id;
+ p_LnxWrpFmPortDev->settings.param.portType =
+ e_FM_PORT_TYPE_TX_10G;
+ uint32_prop = (uint32_t *) of_get_property(port_node,
+ "fsl,qman-channel-id", &lenp);
+ if (uint32_prop == NULL) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("missing fsl,qman-channel-id"));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ p_LnxWrpFmPortDev->txCh = tmp_prop;
+ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
+ qmChannel = p_LnxWrpFmPortDev->txCh;
+ } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-rx")) {
+ tmp_prop -= 0x08;
+ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_RX_PORTS)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop];
+
+ p_LnxWrpFmPortDev->id = tmp_prop;
+ p_LnxWrpFmPortDev->settings.param.portId =
+ p_LnxWrpFmPortDev->id;
+ p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_RX;
+ if (p_LnxWrpFmDev->pcdActive)
+ p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd;
+ } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) {
+#ifndef CONFIG_FMAN_ARM
+ /* On T102x, the 10G RX port IDs start from 0x08 */
+ if (IS_T1023_T1024)
+ tmp_prop -= 0x8;
+ else
+#endif
+ tmp_prop -= 0x10;
+
+ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_10G_RX_PORTS)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop +
+ FM_MAX_NUM_OF_1G_RX_PORTS];
+
+#ifndef CONFIG_FMAN_ARM
+ if (IS_T1023_T1024)
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop];
+#endif
+
+ p_LnxWrpFmPortDev->id = tmp_prop;
+ p_LnxWrpFmPortDev->settings.param.portId =
+ p_LnxWrpFmPortDev->id;
+ p_LnxWrpFmPortDev->settings.param.portType =
+ e_FM_PORT_TYPE_RX_10G;
+ if (p_LnxWrpFmDev->pcdActive)
+ p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd;
+ } else {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type"));
+ return NULL;
+ }
+
+ _errno = of_address_to_resource(port_node, 0, &res);
+ if (unlikely(_errno < 0)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_address_to_resource() = %d", _errno));
+ return NULL;
+ }
+
+ p_LnxWrpFmPortDev->dev = &of_dev->dev;
+ p_LnxWrpFmPortDev->baseAddr = 0;
+ p_LnxWrpFmPortDev->phys_baseAddr = res.start;
+ p_LnxWrpFmPortDev->memSize = res.end + 1 - res.start;
+ p_LnxWrpFmPortDev->settings.param.h_Fm = p_LnxWrpFmDev->h_Dev;
+ p_LnxWrpFmPortDev->h_LnxWrpFmDev = (t_Handle) p_LnxWrpFmDev;
+
+ of_node_put(port_node);
+
+ p_LnxWrpFmPortDev->active = TRUE;
+
+#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES)
+ /* for performance mode no OH port available. */
+ if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ p_LnxWrpFmPortDev->active = FALSE;
+#endif
+
+ return p_LnxWrpFmPortDev;
+}
+
+struct device_node * GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node,
+ e_FmPortType portType,
+ uint8_t portId)
+{
+ struct device_node *port_node;
+ const uint32_t *uint32_prop;
+ int lenp;
+ char *portTypeString;
+ uint32_t tmp_prop;
+
+ switch(portType) {
+ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
+ portTypeString = "fsl,fman-port-op-extended-args";
+ break;
+ case e_FM_PORT_TYPE_TX:
+ portTypeString = "fsl,fman-port-1g-tx-extended-args";
+ break;
+ case e_FM_PORT_TYPE_TX_10G:
+ portTypeString = "fsl,fman-port-10g-tx-extended-args";
+ break;
+ case e_FM_PORT_TYPE_RX:
+ portTypeString = "fsl,fman-port-1g-rx-extended-args";
+ break;
+ case e_FM_PORT_TYPE_RX_10G:
+ portTypeString = "fsl,fman-port-10g-rx-extended-args";
+ break;
+ default:
+ return NULL;
+ }
+
+ for_each_child_of_node(fm_node, port_node) {
+ uint32_prop = (uint32_t *)of_get_property(port_node, "cell-index", &lenp);
+ if (unlikely(uint32_prop == NULL)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE,
+ ("of_get_property(%s, cell-index) failed",
+ port_node->full_name));
+ return NULL;
+ }
+ tmp_prop = be32_to_cpu(*uint32_prop);
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ return NULL;
+ if ((portId == tmp_prop) &&
+ (of_device_is_compatible(port_node, portTypeString))) {
+ return port_node;
+ }
+ }
+
+ return NULL;
+}
+
+static t_Error CheckNConfigFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
+{
+ struct device_node *fm_node, *port_node;
+ t_Error err;
+ t_FmPortRsrc portRsrc;
+ const uint32_t *uint32_prop;
+ /*const char *str_prop;*/
+ int lenp;
+#ifdef CONFIG_FMAN_PFC
+ uint8_t i, id, num_pools;
+ t_FmBufPoolDepletion poolDepletion;
+
+ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX ||
+ p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) {
+ memset(&poolDepletion, 0, sizeof(t_FmBufPoolDepletion));
+ poolDepletion.singlePoolModeEnable = true;
+ num_pools = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
+ extBufPools.numOfPoolsUsed;
+ for (i = 0; i < num_pools; i++) {
+ id = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
+ extBufPools.extBufPool[i].id;
+ poolDepletion.poolsToConsiderForSingleMode[id] = true;
+ }
+
+ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++)
+ poolDepletion.pfcPrioritiesEn[i] = true;
+
+ err = FM_PORT_ConfigPoolDepletion(p_LnxWrpFmPortDev->h_Dev,
+ &poolDepletion);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, ("FM_PORT_ConfigPoolDepletion() failed"));
+ }
+#endif
+
+ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
+ if (!fm_node) /* no advance parameters for FMan */
+ return E_OK;
+
+ port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
+ p_LnxWrpFmPortDev->settings.param.portType,
+ p_LnxWrpFmPortDev->settings.param.portId);
+ if (!port_node) /* no advance parameters for FMan-Port */
+ return E_OK;
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "num-tnums", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)*2))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ portRsrc.num = be32_to_cpu(uint32_prop[0]);
+ portRsrc.extra = be32_to_cpu(uint32_prop[1]);
+
+ if ((err = FM_PORT_ConfigNumOfTasks(p_LnxWrpFmPortDev->h_Dev,
+ &portRsrc)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "num-dmas", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)*2))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ portRsrc.num = be32_to_cpu(uint32_prop[0]);
+ portRsrc.extra = be32_to_cpu(uint32_prop[1]);
+
+ if ((err = FM_PORT_ConfigNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev,
+ &portRsrc)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "fifo-size", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)*2))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ portRsrc.num = be32_to_cpu(uint32_prop[0]);
+ portRsrc.extra = be32_to_cpu(uint32_prop[1]);
+
+ if ((err = FM_PORT_ConfigSizeOfFifo(p_LnxWrpFmPortDev->h_Dev,
+ &portRsrc)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "errors-to-discard", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+ if ((err = FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev,
+ be32_to_cpu(uint32_prop[0]))) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ uint32_prop = (uint32_t *)of_get_property(port_node, "ar-tables-sizes",
+ &lenp);
+ if (uint32_prop) {
+
+ if (WARN_ON(lenp != sizeof(uint32_t)*8))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+ if (WARN_ON(p_LnxWrpFmPortDev->settings.param.portType !=
+ e_FM_PORT_TYPE_RX) &&
+ (p_LnxWrpFmPortDev->settings.param.portType !=
+ e_FM_PORT_TYPE_RX_10G))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE,
+ ("Auto Response is an Rx port atribute."));
+
+ memset(&p_LnxWrpFmPortDev->dsar_table_sizes, 0, sizeof(struct auto_res_tables_sizes));
+
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_arp_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[0]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv4_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[1]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ndp_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[2]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv6_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[3]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv4_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[4]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv6_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[5]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_oid_entries =
+ (uint16_t)be32_to_cpu(uint32_prop[6]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_char =
+ (uint16_t)be32_to_cpu(uint32_prop[7]);
+
+ uint32_prop = (uint32_t *)of_get_property(port_node,
+ "ar-filters-sizes", &lenp);
+ if (uint32_prop) {
+ if (WARN_ON(lenp != sizeof(uint32_t)*3))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ip_prot_filtering =
+ (uint16_t)be32_to_cpu(uint32_prop[0]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_tcp_port_filtering =
+ (uint16_t)be32_to_cpu(uint32_prop[1]);
+ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_udp_port_filtering =
+ (uint16_t)be32_to_cpu(uint32_prop[2]);
+ }
+
+ if ((err = FM_PORT_ConfigDsarSupport(p_LnxWrpFmPortDev->h_Dev,
+ (t_FmPortDsarTablesSizes*)&p_LnxWrpFmPortDev->dsar_table_sizes)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+
+ of_node_put(port_node);
+ of_node_put(fm_node);
+
+ return E_OK;
+}
+
+static t_Error CheckNSetFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
+{
+ struct device_node *fm_node, *port_node;
+ t_Error err;
+ const uint32_t *uint32_prop;
+ /*const char *str_prop;*/
+ int lenp;
+
+ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id);
+ if (!fm_node) /* no advance parameters for FMan */
+ return E_OK;
+
+ port_node = GetFmPortAdvArgsDevTreeNode(fm_node,
+ p_LnxWrpFmPortDev->settings.param.portType,
+ p_LnxWrpFmPortDev->settings.param.portId);
+ if (!port_node) /* no advance parameters for FMan-Port */
+ return E_OK;
+
+#if (DPAA_VERSION >= 11)
+ uint32_prop = (uint32_t *)of_get_property(port_node, "vsp-window", &lenp);
+ if (uint32_prop) {
+ t_FmPortVSPAllocParams portVSPAllocParams;
+ t_FmVspParams fmVspParams;
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ uint8_t portId;
+
+ p_LnxWrpFmDev = ((t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev);
+
+ if (WARN_ON(lenp != sizeof(uint32_t)*2))
+ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG);
+
+ if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) ||
+ (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX_10G) ||
+ ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
+ p_LnxWrpFmPortDev->settings.frag_enabled))
+ return E_OK;
+
+ memset(&portVSPAllocParams, 0, sizeof(portVSPAllocParams));
+ memset(&fmVspParams, 0, sizeof(fmVspParams));
+
+ portVSPAllocParams.numOfProfiles = (uint8_t)be32_to_cpu(uint32_prop[0]);
+ portVSPAllocParams.dfltRelativeId = (uint8_t)be32_to_cpu(uint32_prop[1]);
+ fmVspParams.h_Fm = p_LnxWrpFmDev->h_Dev;
+
+ fmVspParams.portParams.portType = p_LnxWrpFmPortDev->settings.param.portType;
+ fmVspParams.portParams.portId = p_LnxWrpFmPortDev->settings.param.portId;
+ fmVspParams.relativeProfileId = portVSPAllocParams.dfltRelativeId;
+
+ if (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)
+ {
+ portId = fmVspParams.portParams.portId;
+ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G){
+#ifndef CONFIG_FMAN_ARM
+ if (!(IS_T1023_T1024))
+#endif
+ portId += FM_MAX_NUM_OF_1G_RX_PORTS;
+ }
+ portVSPAllocParams.h_FmTxPort =
+ p_LnxWrpFmDev->txPorts[portId].h_Dev;
+ fmVspParams.liodnOffset =
+ p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset;
+ memcpy(&fmVspParams.extBufPools,
+ &p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools,
+ sizeof(t_FmExtPools));
+ }
+ else
+ {
+ memcpy(&fmVspParams.extBufPools,
+ &p_LnxWrpFmPortDev->opExtPools,
+ sizeof(t_FmExtPools));
+ }
+
+ if ((err = FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev,
+ &portVSPAllocParams)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ /* We're initializing only the default VSP that are being used by the Linux-Ethernet-driver */
+ if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
+ !p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed)
+ return E_OK;
+
+ p_LnxWrpFmPortDev->h_DfltVsp = FM_VSP_Config(&fmVspParams);
+ if (!p_LnxWrpFmPortDev->h_DfltVsp)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("default-VSP for port!"));
+
+ if ((err = FM_VSP_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_DfltVsp,
+ &p_LnxWrpFmPortDev->buffPrefixContent)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+
+ if ((err = FM_VSP_Init(p_LnxWrpFmPortDev->h_DfltVsp)) != E_OK)
+ RETURN_ERROR(MINOR, err, NO_MSG);
+ }
+#else
+UNUSED(err); UNUSED(uint32_prop); UNUSED(lenp);
+#endif /* (DPAA_VERSION >= 11) */
+
+ of_node_put(port_node);
+ of_node_put(fm_node);
+
+ return E_OK;
+}
+
+static t_Error ConfigureFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ struct resource *dev_res;
+
+ if (!p_LnxWrpFmPortDev->active)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("FM port not configured!!!"));
+
+ dev_res =
+ __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res,
+ p_LnxWrpFmPortDev->phys_baseAddr,
+ p_LnxWrpFmPortDev->memSize,
+ "fman-port-hc");
+ if (unlikely(dev_res == NULL))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE,
+ ("__devm_request_region() failed"));
+ p_LnxWrpFmPortDev->baseAddr =
+ PTR_TO_UINT(devm_ioremap
+ (p_LnxWrpFmDev->dev,
+ p_LnxWrpFmPortDev->phys_baseAddr,
+ p_LnxWrpFmPortDev->memSize));
+ if (unlikely(p_LnxWrpFmPortDev->baseAddr == 0))
+ REPORT_ERROR(MAJOR, E_INVALID_STATE,
+ ("devm_ioremap() failed"));
+
+ p_LnxWrpFmPortDev->settings.param.baseAddr =
+ p_LnxWrpFmPortDev->baseAddr;
+
+ return E_OK;
+}
+
+static t_Error InitFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
+{
+#define MY_ADV_CONFIG_CHECK_END \
+ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,\
+ ("Advanced configuration routine"));\
+ if (errCode != E_OK)\
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);\
+ }
+
+ int i = 0;
+
+ if (!p_LnxWrpFmPortDev->active || p_LnxWrpFmPortDev->h_Dev)
+ return E_INVALID_STATE;
+
+ p_LnxWrpFmPortDev->h_Dev =
+ FM_PORT_Config(&p_LnxWrpFmPortDev->settings.param);
+ if (p_LnxWrpFmPortDev->h_Dev == NULL)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-port"));
+
+#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT
+ if ((p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_TX_10G)
+ || (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_TX)) {
+ t_Error errCode = E_OK;
+ errCode =
+ FM_PORT_ConfigDeqHighPriority(p_LnxWrpFmPortDev->h_Dev,
+ TRUE);
+ if (errCode != E_OK)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+ errCode =
+ FM_PORT_ConfigDeqPrefetchOption(p_LnxWrpFmPortDev->h_Dev,
+ e_FM_PORT_DEQ_FULL_PREFETCH);
+ if (errCode
+ != E_OK)
+ RETURN_ERROR(MAJOR, errCode, NO_MSG);
+ }
+#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */
+
+#ifndef CONFIG_FMAN_ARM
+#ifdef FM_BCB_ERRATA_BMI_SW001
+/* Configure BCB workaround on Rx ports, only for B4860 rev1 */
+#define SVR_SECURITY_MASK 0x00080000
+#define SVR_PERSONALITY_MASK 0x0000FF00
+#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK)
+#define SVR_B4860_REV1_VALUE 0x86800010
+
+ if ((p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_RX_10G) ||
+ (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_RX)) {
+ unsigned int svr;
+
+ svr = mfspr(SPRN_SVR);
+
+ if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE)
+ FM_PORT_ConfigBCBWorkaround(p_LnxWrpFmPortDev->h_Dev);
+ }
+#endif /* FM_BCB_ERRATA_BMI_SW001 */
+#endif /* CONFIG_FMAN_ARM */
+/* Call the driver's advanced configuration routines, if requested:
+ Compare the function pointer of each entry to the available routines,
+ and invoke the matching routine with proper casting of arguments. */
+ while (p_LnxWrpFmPortDev->settings.advConfig[i].p_Function
+ && (i < FM_MAX_NUM_OF_ADV_SETTINGS)) {
+
+/* TODO: Change this MACRO */
+ ADV_CONFIG_CHECK_START(
+ &(p_LnxWrpFmPortDev->settings.advConfig[i]))
+
+ ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev,
+ FM_PORT_ConfigBufferPrefixContent,
+ NCSW_PARAMS(1,
+ (t_FmBufferPrefixContent *)))
+
+ if ((p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
+ (p_LnxWrpFmPortDev->settings.frag_enabled == TRUE)) {
+
+ ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev,
+ FM_PORT_ConfigExtBufPools,
+ NCSW_PARAMS(1, (t_FmExtPools *)))
+
+ /* this define contains an else */
+ MY_ADV_CONFIG_CHECK_END
+ }
+
+ /* Advance to next advanced configuration entry */
+ i++;
+ }
+
+
+ if ((p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX) &&
+ (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX_10G)) {
+ if (FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev, (FM_PORT_FRM_ERR_IPRE |
+ FM_PORT_FRM_ERR_IPR_NCSP |
+ FM_PORT_FRM_ERR_CLS_DISCARD)) !=E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+ }
+
+ if (CheckNConfigFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (FM_PORT_Init(p_LnxWrpFmPortDev->h_Dev) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+ if (CheckNSetFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK)
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+
+/* FMan Fifo sizes behind the scene":
+ * Using the following formulae (*), under a set of simplifying assumptions (.):
+ * . all ports are configured in Normal Mode (rather than Independent Mode)
+ * . the DPAA Eth driver allocates buffers of size:
+ * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE
+ * + DPA_HASH_RESULTS_SIZE, i.e.:
+ * MAXFRM + 2 + 16 + sizeof(t_FmPrsResult) + 16, i.e.:
+ * MAXFRM + 66
+ * . excessive buffer pools not accounted for
+ *
+ * * for Rx ports on P4080:
+ * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256) * 256 + 7 * 256
+ * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise,
+ * add up to 256 to the above
+ *
+ * * for Rx ports on P1023:
+ * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256)) * 256 + 7 * 256,
+ * if at least 2 bpools are configured
+ * . IFSZ = 8 * 256, if only a single bpool is configured
+ *
+ * * for Tx ports:
+ * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256
+ * + FMBM_TFP[DPDE] * 256, i.e.:
+ * IFSZ = ceil(MAXFRM / 256) * 256 + 3 x 256 + FMBM_TFP[DPDE] * 256
+ *
+ * * for OH ports on P4080:
+ * . IFSZ = ceil(frame_size / 256) * 256 + 1 * 256 + FMBM_PP[MXT] * 256
+ * * for OH ports on P1023:
+ * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + FMBM_TFP[DPDE] * 256
+ * * for both P4080 and P1023:
+ * . (conservative decisions, assuming that BMI must bring the entire
+ * frame, not only the frame header)
+ * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise,
+ * add up to 256 to the above
+ *
+ * . for P4080/P5020/P3041/P2040, DPDE is:
+ * > 0 or 1, for 1Gb ports, HW default: 0
+ * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3
+ * . for P1023, DPDE should be 1
+ *
+ * . for P1023, MXT is in range (0..31)
+ * . for P4080, MXT is in range (0..63)
+ *
+ */
+#if 0
+ if ((p_LnxWrpFmPortDev->defPcd != e_NO_PCD) &&
+ (InitFmPort3TupleDefPcd(p_LnxWrpFmPortDev) != E_OK))
+ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
+#endif
+ return E_OK;
+}
+
+void fm_set_rx_port_params(struct fm_port *port,
+ struct fm_port_params *params)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port;
+ int i;
+
+ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.errFqid =
+ params->errq;
+ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.dfltFqid =
+ params->defq;
+ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools.
+ numOfPoolsUsed = params->num_pools;
+ for (i = 0; i < params->num_pools; i++) {
+ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
+ extBufPools.extBufPool[i].id =
+ params->pool_param[i].id;
+ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.
+ extBufPools.extBufPool[i].size =
+ params->pool_param[i].size;
+ }
+
+ p_LnxWrpFmPortDev->buffPrefixContent.privDataSize =
+ params->priv_data_size;
+ p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult =
+ params->parse_results;
+ p_LnxWrpFmPortDev->buffPrefixContent.passHashResult =
+ params->hash_results;
+ p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp =
+ params->time_stamp;
+ p_LnxWrpFmPortDev->buffPrefixContent.dataAlign =
+ params->data_align;
+ p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace =
+ params->manip_extra_space;
+
+ ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig,
+ FM_MAX_NUM_OF_ADV_SETTINGS)
+
+ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent,
+ ARGS(1,
+ (&p_LnxWrpFmPortDev->
+ buffPrefixContent)));
+
+ ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev);
+}
+EXPORT_SYMBOL(fm_set_rx_port_params);
+
+/* this function is called from oh_probe as well, thus it contains oh port
+ * specific parameters (make sure everything is checked) */
+void fm_set_tx_port_params(struct fm_port *port,
+ struct fm_port_params *params)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port;
+
+ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.errFqid =
+ params->errq;
+ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.
+ dfltFqid = params->defq;
+
+ p_LnxWrpFmPortDev->buffPrefixContent.privDataSize =
+ params->priv_data_size;
+ p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult =
+ params->parse_results;
+ p_LnxWrpFmPortDev->buffPrefixContent.passHashResult =
+ params->hash_results;
+ p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp =
+ params->time_stamp;
+ p_LnxWrpFmPortDev->settings.frag_enabled =
+ params->frag_enable;
+ p_LnxWrpFmPortDev->buffPrefixContent.dataAlign =
+ params->data_align;
+ p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace =
+ params->manip_extra_space;
+
+ ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig,
+ FM_MAX_NUM_OF_ADV_SETTINGS)
+
+ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent,
+ ARGS(1,
+ (&p_LnxWrpFmPortDev->
+ buffPrefixContent)));
+
+ /* oh port specific parameter (for fragmentation only) */
+ if ((p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) &&
+ params->num_pools) {
+ int i;
+
+ p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed = params->num_pools;
+ for (i = 0; i < params->num_pools; i++) {
+ p_LnxWrpFmPortDev->opExtPools.extBufPool[i].id = params->pool_param[i].id;
+ p_LnxWrpFmPortDev->opExtPools.extBufPool[i].size = params->pool_param[i].size;
+ }
+
+ if (p_LnxWrpFmPortDev->settings.frag_enabled)
+ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigExtBufPools,
+ ARGS(1, (&p_LnxWrpFmPortDev->opExtPools)));
+ }
+
+ ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev);
+}
+EXPORT_SYMBOL(fm_set_tx_port_params);
+
+void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev,
+ t_Handle h_fm_mac,
+ int mac_id)
+{
+ t_LnxWrpFmDev *p_lnx_wrp_fm_dev = (t_LnxWrpFmDev *)h_lnx_wrp_fm_dev;
+
+ p_lnx_wrp_fm_dev->macs[mac_id].h_Dev = h_fm_mac;
+ p_lnx_wrp_fm_dev->macs[mac_id].h_LnxWrpFmDev = h_lnx_wrp_fm_dev;
+}
+EXPORT_SYMBOL(fm_mac_set_handle);
+
+static void LnxwrpFmPcdDevExceptionsCb(t_Handle h_App,
+ e_FmPcdExceptions exception)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App;
+
+ ASSERT_COND(p_LnxWrpFmDev);
+
+ DBG(INFO, ("got fm-pcd exception %d", exception));
+
+ /* do nothing */
+ UNUSED(exception);
+}
+
+static void LnxwrpFmPcdDevIndexedExceptionsCb(t_Handle h_App,
+ e_FmPcdExceptions exception,
+ uint16_t index)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App;
+
+ ASSERT_COND(p_LnxWrpFmDev);
+
+ DBG(INFO,
+ ("got fm-pcd-indexed exception %d, indx %d", exception, index));
+
+ /* do nothing */
+ UNUSED(exception);
+ UNUSED(index);
+}
+
+static t_Error InitFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+ spin_lock_init(&lock);
+
+ if (p_LnxWrpFmDev->pcdActive) {
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
+ t_FmPcdParams fmPcdParams;
+ t_Error err;
+
+ memset(&fmPcdParams, 0, sizeof(fmPcdParams));
+ fmPcdParams.h_Fm = p_LnxWrpFmDev->h_Dev;
+ fmPcdParams.prsSupport = p_LnxWrpFmDev->prsActive;
+ fmPcdParams.kgSupport = p_LnxWrpFmDev->kgActive;
+ fmPcdParams.plcrSupport = p_LnxWrpFmDev->plcrActive;
+ fmPcdParams.ccSupport = p_LnxWrpFmDev->ccActive;
+ fmPcdParams.numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES;
+
+#ifndef CONFIG_GUEST_PARTITION
+ fmPcdParams.f_Exception = LnxwrpFmPcdDevExceptionsCb;
+ if (fmPcdParams.kgSupport)
+ fmPcdParams.f_ExceptionId =
+ LnxwrpFmPcdDevIndexedExceptionsCb;
+ fmPcdParams.h_App = p_LnxWrpFmDev;
+#endif /* !CONFIG_GUEST_PARTITION */
+
+#ifdef CONFIG_MULTI_PARTITION_SUPPORT
+ fmPcdParams.numOfSchemes = 0;
+ fmPcdParams.numOfClsPlanEntries = 0;
+ fmPcdParams.partitionId = 0;
+#endif /* CONFIG_MULTI_PARTITION_SUPPORT */
+ fmPcdParams.useHostCommand = TRUE;
+
+ p_LnxWrpFmDev->hc_tx_fq =
+ FqAlloc(p_LnxWrpFmDev,
+ 0,
+ QMAN_FQ_FLAG_TO_DCPORTAL,
+ p_LnxWrpFmPortDev->txCh, 0);
+ if (!p_LnxWrpFmDev->hc_tx_fq)
+ RETURN_ERROR(MAJOR, E_NULL_POINTER,
+ ("Frame queue allocation failed..."));
+
+ p_LnxWrpFmDev->hc_tx_conf_fq =
+ FqAlloc(p_LnxWrpFmDev,
+ 0,
+ QMAN_FQ_FLAG_NO_ENQUEUE,
+ p_LnxWrpFmDev->hcCh, 1);
+ if (!p_LnxWrpFmDev->hc_tx_conf_fq)
+ RETURN_ERROR(MAJOR, E_NULL_POINTER,
+ ("Frame queue allocation failed..."));
+
+ p_LnxWrpFmDev->hc_tx_err_fq =
+ FqAlloc(p_LnxWrpFmDev,
+ 0,
+ QMAN_FQ_FLAG_NO_ENQUEUE,
+ p_LnxWrpFmDev->hcCh, 2);
+ if (!p_LnxWrpFmDev->hc_tx_err_fq)
+ RETURN_ERROR(MAJOR, E_NULL_POINTER,
+ ("Frame queue allocation failed..."));
+
+ fmPcdParams.hc.portBaseAddr = p_LnxWrpFmPortDev->baseAddr;
+ fmPcdParams.hc.portId =
+ p_LnxWrpFmPortDev->settings.param.portId;
+ fmPcdParams.hc.liodnBase =
+ p_LnxWrpFmPortDev->settings.param.liodnBase;
+ fmPcdParams.hc.errFqid =
+ qman_fq_fqid(p_LnxWrpFmDev->hc_tx_err_fq);
+ fmPcdParams.hc.confFqid =
+ qman_fq_fqid(p_LnxWrpFmDev->hc_tx_conf_fq);
+ fmPcdParams.hc.qmChannel = p_LnxWrpFmPortDev->txCh;
+ fmPcdParams.hc.f_QmEnqueue = QmEnqueueCB;
+ fmPcdParams.hc.h_QmArg = (t_Handle) p_LnxWrpFmDev;
+
+ p_LnxWrpFmDev->h_PcdDev = FM_PCD_Config(&fmPcdParams);
+ if (!p_LnxWrpFmDev->h_PcdDev)
+ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!"));
+
+ err =
+ FM_PCD_ConfigPlcrNumOfSharedProfiles(p_LnxWrpFmDev->h_PcdDev,
+ LNXWRP_FM_NUM_OF_SHARED_PROFILES);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ err = FM_PCD_Init(p_LnxWrpFmDev->h_PcdDev);
+ if (err != E_OK)
+ RETURN_ERROR(MAJOR, err, NO_MSG);
+
+ if (p_LnxWrpFmDev->err_irq == 0) {
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE,
+ FALSE);
+ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev,
+ e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC,
+ FALSE);
+ }
+ }
+
+ return E_OK;
+}
+
+void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev)
+{
+
+ if (p_LnxWrpFmDev->h_PcdDev)
+ FM_PCD_Free(p_LnxWrpFmDev->h_PcdDev);
+
+ if (p_LnxWrpFmDev->hc_tx_err_fq)
+ FqFree(p_LnxWrpFmDev->hc_tx_err_fq);
+
+ if (p_LnxWrpFmDev->hc_tx_conf_fq)
+ FqFree(p_LnxWrpFmDev->hc_tx_conf_fq);
+
+ if (p_LnxWrpFmDev->hc_tx_fq)
+ FqFree(p_LnxWrpFmDev->hc_tx_fq);
+}
+
+static void FreeFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+
+ if (!p_LnxWrpFmPortDev->active)
+ return;
+
+ if (p_LnxWrpFmPortDev->h_Dev)
+ FM_PORT_Free(p_LnxWrpFmPortDev->h_Dev);
+
+ devm_iounmap(p_LnxWrpFmDev->dev,
+ UINT_TO_PTR(p_LnxWrpFmPortDev->baseAddr));
+ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res,
+ p_LnxWrpFmPortDev->phys_baseAddr,
+ p_LnxWrpFmPortDev->memSize);
+}
+
+static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+
+ p_LnxWrpFmPortDev = ReadFmPortDevTreeNode(of_dev);
+ if (p_LnxWrpFmPortDev == NULL)
+ return -EIO;
+ /* Port can be inactive, thus will not be probed:
+ - in performance mode, OH ports are disabled
+ ...
+ */
+ if (!p_LnxWrpFmPortDev->active)
+ return 0;
+
+ if (ConfigureFmPortDev(p_LnxWrpFmPortDev) != E_OK)
+ return -EIO;
+
+ dev_set_drvdata(dev, p_LnxWrpFmPortDev);
+
+ if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_HOST_COMMAND)
+ InitFmPcdDev((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev);
+
+ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+
+ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
+ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + DEV_FM_RX_PORTS_MINOR_BASE;
+ } else if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_RX_10G) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
+ p_LnxWrpFmDev->name,
+ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS +
+ DEV_FM_RX_PORTS_MINOR_BASE;
+#ifndef CONFIG_FMAN_ARM
+ if (IS_T1023_T1024) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d",
+ p_LnxWrpFmDev->name,
+ p_LnxWrpFmPortDev->id);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id +
+ DEV_FM_RX_PORTS_MINOR_BASE;
+ }
+#endif
+ } else if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_TX) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
+ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + DEV_FM_TX_PORTS_MINOR_BASE;
+ } else if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_TX_10G) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
+ p_LnxWrpFmDev->name,
+ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS +
+ DEV_FM_TX_PORTS_MINOR_BASE;
+#ifndef CONFIG_FMAN_ARM
+ if (IS_T1023_T1024) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d",
+ p_LnxWrpFmDev->name,
+ p_LnxWrpFmPortDev->id);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id +
+ DEV_FM_TX_PORTS_MINOR_BASE;
+ }
+#endif
+ } else if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_HOST_COMMAND) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d",
+ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + DEV_FM_OH_PORTS_MINOR_BASE;
+ } else if (p_LnxWrpFmPortDev->settings.param.portType ==
+ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) {
+ Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d",
+ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id + 1);
+ p_LnxWrpFmPortDev->minor =
+ p_LnxWrpFmPortDev->id + 1 +
+ DEV_FM_OH_PORTS_MINOR_BASE;
+ }
+
+ device_create(p_LnxWrpFmDev->fm_class, NULL,
+ MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor),
+ NULL, p_LnxWrpFmPortDev->name);
+
+ /* create sysfs entries for stats and regs */
+
+ if (fm_port_sysfs_create(dev) != 0) {
+ FreeFmPortDev(p_LnxWrpFmPortDev);
+ REPORT_ERROR(MAJOR, E_INVALID_STATE,
+ ("Unable to create sys entry - fm port!!!"));
+ return -EIO;
+ }
+
+#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009
+ FM_DisableRamsEcc(p_LnxWrpFmDev->h_Dev);
+#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */
+
+ DBG(TRACE, ("%s probed", p_LnxWrpFmPortDev->name));
+
+ return 0;
+}
+
+static int fm_port_remove(struct platform_device *of_dev)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ struct device *dev;
+
+ dev = &of_dev->dev;
+ p_LnxWrpFmPortDev = dev_get_drvdata(dev);
+
+ fm_port_sysfs_destroy(dev);
+
+ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ device_destroy(p_LnxWrpFmDev->fm_class,
+ MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor));
+
+ FreeFmPortDev(p_LnxWrpFmPortDev);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id fm_port_match[] = {
+ {
+ .compatible = "fsl,fman-port-oh"},
+ {
+ .compatible = "fsl,fman-v2-port-oh"},
+ {
+ .compatible = "fsl,fman-v3-port-oh"},
+ {
+ .compatible = "fsl,fman-port-1g-rx"},
+ {
+ .compatible = "fsl,fman-port-10g-rx"},
+ {
+ .compatible = "fsl,fman-port-1g-tx"},
+ {
+ .compatible = "fsl,fman-port-10g-tx"},
+ {}
+};
+
+#ifndef MODULE
+MODULE_DEVICE_TABLE(of, fm_port_match);
+#endif /* !MODULE */
+
+static struct platform_driver fm_port_driver = {
+
+ .driver = {
+ .name = "fsl-fman-port",
+ .of_match_table = fm_port_match,
+ .owner = THIS_MODULE,
+ },
+ .probe = fm_port_probe,
+ .remove = fm_port_remove
+};
+
+
+t_Error LNXWRP_FM_Port_Init(void)
+{
+ /* Register to the DTB for basic FM port API */
+ if (platform_driver_register(&fm_port_driver))
+ return E_NO_DEVICE;
+
+ return E_OK;
+}
+
+void LNXWRP_FM_Port_Free(void)
+{
+ platform_driver_unregister(&fm_port_driver);
+}
+
+static int __init __cold fm_port_load(void)
+{
+ if (LNXWRP_FM_Port_Init() != E_OK) {
+ printk(KERN_ERR "Failed to init FM Ports wrapper!\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "Freescale FM Ports module\n");
+
+ return 0;
+}
+
+static void __exit __cold fm_port_unload(void)
+{
+ LNXWRP_FM_Port_Free();
+}
+
+module_init(fm_port_load);
+module_exit(fm_port_unload);
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
new file mode 100644
index 000000000000..06833ba89e05
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c
@@ -0,0 +1,4854 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_ioctls_fm.c
+ @Author Shlomi Gridish
+ @Description FM Linux wrapper functions.
+*/
+
+/* Linux Headers ------------------- */
+#include <linux/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+#ifndef CONFIG_FMAN_ARM
+#include <sysdev/fsl_soc.h>
+#include <linux/fsl/svr.h>
+#endif
+
+#if defined(CONFIG_COMPAT)
+#include <linux/compat.h>
+#endif
+
+#include "part_ext.h"
+#include "fm_ioctls.h"
+#include "fm_pcd_ioctls.h"
+#include "fm_port_ioctls.h"
+#include "fm_vsp_ext.h"
+
+#ifndef CONFIG_FMAN_ARM
+#define IS_T1023_T1024 (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \
+ SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023)
+#endif
+
+#define __ERR_MODULE__ MODULE_FM
+
+#if defined(CONFIG_COMPAT)
+#include "lnxwrp_ioctls_fm_compat.h"
+#endif
+
+#include "lnxwrp_fm.h"
+
+#define CMP_IOC_DEFINE(def) (IOC_##def != def)
+
+/* fm_pcd_ioctls.h === fm_pcd_ext.h assertions */
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_PRIVATE_HDRS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_HDRS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_GENERIC_REGS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_EXTRACT_MASKS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_DEFAULT_GROUPS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_LABELS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_SW_PRS_SIZE)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if DPAA_VERSION >= 11
+#if CMP_IOC_DEFINE(FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)
+#error Error: please synchronize IOC_ defines!
+#endif
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_TREES)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_GROUPS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_UNITS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_KEYS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_SIZE_OF_KEY)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(FM_PCD_LAST_KEY_INDEX)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+/* net_ioctls.h === net_ext.h assertions */
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_PID)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_COMPRESSED)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPoE_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ETH_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv4_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv6_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ICMP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IGMP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_TCP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_DCCP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPHC_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv2_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_VLAN_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_NLPID_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SNAP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS)
+#warning Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ARP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_RFC2684_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_GRE_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MINENCAP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MACSEC_ALL_FIELDS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+/* fm_ioctls.h === fm_ext.h assertions */
+#if CMP_IOC_DEFINE(FM_MAX_NUM_OF_VALID_PORTS)
+#error Error: please synchronize IOC_ defines!
+#endif
+
+void LnxWrpPCDIOCTLTypeChecking(void)
+{
+ /* fm_ext.h == fm_ioctls.h */
+ ASSERT_COND(sizeof(ioc_fm_port_bandwidth_params) == sizeof(t_FmPortsBandwidthParams));
+ ASSERT_COND(sizeof(ioc_fm_revision_info_t) == sizeof(t_FmRevisionInfo));
+
+ /* fm_pcd_ext.h == fm_pcd_ioctls.h */
+ /*ioc_fm_pcd_counters_params_t : NOT USED */
+ /*ioc_fm_pcd_exception_params_t : private */
+#if (DPAA_VERSION >= 11)
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_params_t) == sizeof(t_FmPcdManipFragCapwapParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_params_t) == sizeof(t_FmPcdManipReassemCapwapParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t) == sizeof(t_FmPcdManipHdrInsrtByHdrParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_ip_params_t) == sizeof(t_FmPcdManipHdrInsrtIpParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_t) == sizeof(t_FmPcdManipHdrInsrt));
+ ASSERT_COND(sizeof(ioc_fm_manip_hdr_info_t) == sizeof(t_FmManipHdrInfo));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t) == sizeof(t_FmPcdManipHdrRmvByHdrParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_capwap_params_t) == sizeof(t_FmPcdManipSpecialOffloadCapwapParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_stats_t) == sizeof(t_FmPcdManipFragCapwapStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_stats_t) == sizeof(t_FmPcdManipReassemCapwapStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams));
+#endif /* (DPAA_VERSION >= 11) */
+
+ ASSERT_COND(sizeof(ioc_fm_pcd_prs_label_params_t) == sizeof(t_FmPcdPrsLabelParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_prs_sw_params_t) == sizeof(t_FmPcdPrsSwParams));
+ /*ioc_fm_pcd_kg_dflt_value_params_t : private */
+ ASSERT_COND(sizeof(ioc_fm_pcd_hdr_protocol_opt_u) == sizeof(u_FmPcdHdrProtocolOpt));
+ ASSERT_COND(sizeof(ioc_fm_pcd_fields_u) == sizeof(t_FmPcdFields));
+ ASSERT_COND(sizeof(ioc_fm_pcd_from_hdr_t) == sizeof(t_FmPcdFromHdr));
+ ASSERT_COND(sizeof(ioc_fm_pcd_from_field_t) == sizeof(t_FmPcdFromField));
+ ASSERT_COND(sizeof(ioc_fm_pcd_distinction_unit_t) == sizeof(t_FmPcdDistinctionUnit));
+
+#if defined(CONFIG_ARM64)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *) + 4);
+#else
+#if !defined(CONFIG_COMPAT)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *));
+#endif
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_extract_entry_t) == sizeof(t_FmPcdExtractEntry));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_mask_t) == sizeof(t_FmPcdKgExtractMask));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_dflt_t) == sizeof(t_FmPcdKgExtractDflt));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t) == sizeof(t_FmPcdKgKeyExtractAndHashParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extracted_or_params_t) == sizeof(t_FmPcdKgExtractedOrParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_counter_t) == sizeof(t_FmPcdKgSchemeCounter));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_plcr_profile_t) == sizeof(t_FmPcdKgPlcrProfile));
+#if (DPAA_VERSION >= 11)
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_storage_profile_t) == sizeof(t_FmPcdKgStorageProfile));
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_cc_t) == sizeof(t_FmPcdKgCc));
+#if !defined(CONFIG_COMPAT)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_params_t) == sizeof(t_FmPcdKgSchemeParams) + sizeof(void *));
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_cc_params_t) == sizeof(t_FmPcdCcNextCcParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_plcr_params_t) == sizeof(t_FmPcdCcNextPlcrParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_enqueue_params_t) == sizeof(t_FmPcdCcNextEnqueueParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_kg_params_t) == sizeof(t_FmPcdCcNextKgParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams));
+ ASSERT_COND(sizeof(ioc_keys_params_t) == sizeof(t_KeysParams));
+#if !defined(CONFIG_COMPAT)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_node_params_t) == sizeof(t_FmPcdCcNodeParams) + sizeof(void *));
+ ASSERT_COND(sizeof(ioc_fm_pcd_hash_table_params_t) == sizeof(t_FmPcdHashTableParams) + sizeof(void *));
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_grp_params_t) == sizeof(t_FmPcdCcGrpParams));
+#if !defined(CONFIG_COMPAT)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_cc_tree_params_t) == sizeof(t_FmPcdCcTreeParams) + sizeof(void *));
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_byte_rate_mode_param_t) == sizeof(t_FmPcdPlcrByteRateModeParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t) == sizeof(t_FmPcdPlcrNonPassthroughAlgParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_next_engine_params_u) == sizeof(u_FmPcdPlcrNextEngineParams));
+ /*ioc_fm_pcd_port_params_t : private */
+ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_profile_params_t) == sizeof(t_FmPcdPlcrProfileParams) + sizeof(void *));
+ /*ioc_fm_pcd_cc_tree_modify_next_engine_params_t : private */
+
+#ifdef FM_CAPWAP_SUPPORT
+#error TODO: unsupported feature
+/*
+ ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipHdrInsrtByTemplateParams));
+ ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapFragmentationParams));
+ ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapReassemblyParams));
+*/
+#endif
+
+ /*ioc_fm_pcd_cc_node_modify_next_engine_params_t : private */
+ /*ioc_fm_pcd_cc_node_remove_key_params_t : private */
+ /*ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t : private */
+ /*ioc_fm_pcd_cc_node_modify_key_params_t : private */
+ /*ioc_fm_manip_hdr_info_t : private */
+ /*ioc_fm_pcd_hash_table_set_t : private */
+
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_params_t) == sizeof(t_FmPcdManipFragIpParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_params_t) == sizeof(t_FmPcdManipReassemIpParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_ipsec_params_t) == sizeof(t_FmPcdManipSpecialOffloadIPSecParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_params_t) == sizeof(t_FmPcdManipSpecialOffloadParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_generic_params_t) == sizeof(t_FmPcdManipHdrRmvGenericParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_generic_params_t) == sizeof(t_FmPcdManipHdrInsrtGenericParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_params_t) == sizeof(t_FmPcdManipHdrInsrtParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_params_t) == sizeof(t_FmPcdManipHdrRmvParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_params_t) == sizeof(t_FmPcdManipHdrParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_params_t) == sizeof(t_FmPcdManipReassemParams));
+#if !defined(CONFIG_COMPAT)
+ /* different alignment */
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_params_t) == sizeof(t_FmPcdManipParams) + sizeof(void *));
+#endif
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_stats_t) == sizeof(t_FmPcdManipReassemIpStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_stats_t) == sizeof(t_FmPcdManipFragIpStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_stats_t) == sizeof(t_FmPcdManipReassemStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_stats_t) == sizeof(t_FmPcdManipFragStats));
+ ASSERT_COND(sizeof(ioc_fm_pcd_manip_stats_t) == sizeof(t_FmPcdManipStats));
+#if DPAA_VERSION >= 11
+ ASSERT_COND(sizeof(ioc_fm_pcd_frm_replic_group_params_t) == sizeof(t_FmPcdFrmReplicGroupParams) + sizeof(void *));
+#endif
+
+ /* fm_port_ext.h == fm_port_ioctls.h */
+ ASSERT_COND(sizeof(ioc_fm_port_rate_limit_t) == sizeof(t_FmPortRateLimit));
+ ASSERT_COND(sizeof(ioc_fm_port_pcd_params_t) == sizeof(t_FmPortPcdParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_select_t) == sizeof(t_FmPcdKgSchemeSelect));
+ ASSERT_COND(sizeof(ioc_fm_pcd_port_schemes_params_t) == sizeof(t_FmPcdPortSchemesParams));
+ ASSERT_COND(sizeof(ioc_fm_pcd_prs_start_t) == sizeof(t_FmPcdPrsStart));
+
+ return;
+}
+
+#define ASSERT_IOC_NET_ENUM(def) ASSERT_COND((unsigned long)e_IOC_NET_##def == (unsigned long)def)
+
+void LnxWrpPCDIOCTLEnumChecking(void)
+{
+ /* net_ext.h == net_ioctls.h : sampling checks */
+ ASSERT_IOC_NET_ENUM(HEADER_TYPE_MACSEC);
+ ASSERT_IOC_NET_ENUM(HEADER_TYPE_PPP);
+ ASSERT_IOC_NET_ENUM(MAX_HEADER_TYPE_COUNT);
+
+ /* fm_ext.h == fm_ioctls.h */
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_TYPE_DUMMY == (unsigned long)e_FM_PORT_TYPE_DUMMY);
+ ASSERT_COND((unsigned long)e_IOC_EX_MURAM_ECC == (unsigned long)e_FM_EX_MURAM_ECC);
+ ASSERT_COND((unsigned long)e_IOC_FM_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_COUNTERS_DEQ_CONFIRM);
+
+ /* fm_pcd_ext.h == fm_pcd_ioctls.h */
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES == (unsigned long)e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC == (unsigned long)e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS == (unsigned long)e_FM_PCD_PRS);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FULL_FIELD == (unsigned long)e_FM_PCD_EXTRACT_FULL_FIELD);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID == (unsigned long)e_FM_PCD_EXTRACT_FROM_FLOW_ID);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO == (unsigned long)e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_DFLT_ILLEGAL == (unsigned long)e_FM_PCD_KG_DFLT_ILLEGAL);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA == (unsigned long)e_FM_PCD_KG_GENERIC_NOT_FROM_DATA);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_HDR_INDEX_LAST == (unsigned long)e_FM_PCD_HDR_INDEX_LAST);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_SHARED == (unsigned long)e_FM_PCD_PLCR_SHARED);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_RFC_4115 == (unsigned long)e_FM_PCD_PLCR_RFC_4115);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_COLOR_AWARE == (unsigned long)e_FM_PCD_PLCR_COLOR_AWARE);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_OVERRIDE == (unsigned long)e_FM_PCD_PLCR_OVERRIDE);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_FULL_FRM_LEN);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PACKET_MODE == (unsigned long)e_FM_PCD_PLCR_PACKET_MODE);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_DROP_FRAME == (unsigned long)e_FM_PCD_DROP_FRAME);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER == (unsigned long)e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP == (unsigned long)e_FM_PCD_ACTION_INDEXED_LOOKUP);
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR);
+#if !defined(FM_CAPWAP_SUPPORT)
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_GENERIC == (unsigned long)e_FM_PCD_MANIP_INSRT_GENERIC);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_GENERIC == (unsigned long)e_FM_PCD_MANIP_RMV_GENERIC);
+#else
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE == (unsigned long)e_FM_PCD_MANIP_INSRT_BY_TEMPLATE);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START);
+#endif
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG == (unsigned long)e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH == (unsigned long)e_FM_PCD_MANIP_EIGHT_WAYS_HASH);
+
+#ifdef FM_CAPWAP_SUPPORT
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_STATS_PER_FLOWID == (unsigned long)e_FM_PCD_STATS_PER_FLOWID);
+#endif
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_CC_STATS_MODE_FRAME == (unsigned long)e_FM_PCD_CC_STATS_MODE_FRAME);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG == (unsigned long)e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG);
+ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC);
+
+ /* fm_port_ext.h == fm_port_ioctls.h */
+#if !defined(FM_CAPWAP_SUPPORT)
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR);
+#else
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR);
+#endif
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_PORT_COUNTERS_DEQ_CONFIRM);
+ ASSERT_COND((unsigned long)e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 == (unsigned long)e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8);
+
+ return;
+}
+
+static t_Error LnxwrpFmPcdIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat)
+{
+ t_Error err = E_OK;
+
+/*
+Status: PCD API to fmlib (file: drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h):
+
+ FM_PCD_PrsLoadSw
+ FM_PCD_SetAdvancedOffloadSupport
+ FM_PCD_Enable
+ FM_PCD_Disable
+ FM_PCD_ForceIntr
+ FM_PCD_SetException
+ FM_PCD_KgSetAdditionalDataAfterParsing
+ FM_PCD_KgSetDfltValue
+ FM_PCD_NetEnvCharacteristicsSet
+ FM_PCD_NetEnvCharacteristicsDelete
+ FM_PCD_KgSchemeSet
+ FM_PCD_KgSchemeDelete
+ FM_PCD_MatchTableSet
+ FM_PCD_MatchTableDelete
+ FM_PCD_CcRootBuild
+ FM_PCD_CcRootDelete
+ FM_PCD_PlcrProfileSet
+ FM_PCD_PlcrProfileDelete
+ FM_PCD_CcRootModifyNextEngine
+ FM_PCD_MatchTableModifyNextEngine
+ FM_PCD_MatchTableModifyMissNextEngine
+ FM_PCD_MatchTableRemoveKey
+ FM_PCD_MatchTableAddKey
+ FM_PCD_MatchTableModifyKeyAndNextEngine
+ FM_PCD_HashTableSet
+ FM_PCD_HashTableDelete
+ FM_PCD_HashTableAddKey
+ FM_PCD_HashTableRemoveKey
+ FM_PCD_MatchTableModifyKey
+ FM_PCD_ManipNodeReplace
+ FM_PCD_ManipNodeSet
+ FM_PCD_ManipNodeDelete
+
+Status: not exported, should be thru sysfs
+ FM_PCD_KgSchemeGetCounter
+ FM_PCD_KgSchemeSetCounter
+ FM_PCD_PlcrProfileGetCounter
+ FM_PCD_PlcrProfileSetCounter
+
+Status: not exported
+ FM_PCD_MatchTableFindNRemoveKey
+ FM_PCD_MatchTableFindNModifyNextEngine
+ FM_PCD_MatchTableFindNModifyKeyAndNextEngine
+ FM_PCD_MatchTableFindNModifyKey
+ FM_PCD_MatchTableGetIndexedHashBucket
+ FM_PCD_MatchTableGetNextEngine
+ FM_PCD_MatchTableGetKeyCounter
+
+Status: not exported, would be nice to have
+ FM_PCD_HashTableModifyNextEngine
+ FM_PCD_HashTableModifyMissNextEngine
+ FM_PCD_HashTableGetMissNextEngine
+ FM_PCD_ManipGetStatistics
+
+Status: not exported
+#if DPAA_VERSION >= 11
+
+ FM_VSP_GetStatistics -- it's not available yet
+#endif
+
+Status: feature not supported
+#ifdef FM_CAPWAP_SUPPORT
+#error unsupported feature
+ FM_PCD_StatisticsSetNode
+#endif
+
+ */
+ _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n",
+ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 20);
+
+ switch (cmd)
+ {
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_PRS_LOAD_SW_COMPAT:
+#endif
+ case FM_PCD_IOC_PRS_LOAD_SW:
+ {
+ ioc_fm_pcd_prs_sw_params_t *param;
+ uint8_t *p_code;
+
+ param = (ioc_fm_pcd_prs_sw_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_sw_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_prs_sw_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_prs_sw_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_prs_sw_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_prs_sw_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_prs_sw_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_prs_sw_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_prs_sw_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_fm_pcd_prs_sw(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_prs_sw_params_t *)arg,
+ sizeof(ioc_fm_pcd_prs_sw_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (!param->p_code || !param->size)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ p_code = (uint8_t *) XX_Malloc(param->size);
+ if (!p_code)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(p_code, 0, param->size);
+ if (copy_from_user(p_code, param->p_code, param->size))
+ {
+ XX_Free(p_code);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->p_code = p_code;
+
+ err = FM_PCD_PrsLoadSw(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPrsSwParams*)param);
+
+ XX_Free(p_code);
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT:
+ err = FM_PCD_SetAdvancedOffloadSupport(p_LnxWrpFmDev->h_PcdDev);
+ break;
+
+ case FM_PCD_IOC_ENABLE:
+ err = FM_PCD_Enable(p_LnxWrpFmDev->h_PcdDev);
+ break;
+
+ case FM_PCD_IOC_DISABLE:
+ err = FM_PCD_Disable(p_LnxWrpFmDev->h_PcdDev);
+ break;
+
+ case FM_PCD_IOC_FORCE_INTR:
+ {
+ int exception;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (get_user(exception, (int *) compat_ptr(arg)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ {
+ if (get_user(exception, (int *)arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_ForceIntr(p_LnxWrpFmDev->h_PcdDev, (e_FmPcdExceptions)exception);
+ break;
+ }
+
+ case FM_PCD_IOC_SET_EXCEPTION:
+ {
+ ioc_fm_pcd_exception_params_t *param;
+
+ param = (ioc_fm_pcd_exception_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_exception_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_exception_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)compat_ptr(arg),
+ sizeof(ioc_fm_pcd_exception_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)arg,
+ sizeof(ioc_fm_pcd_exception_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, param->exception, param->enable);
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING:
+ {
+ uint8_t payloadOffset;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (get_user(payloadOffset, (uint8_t*) compat_ptr(arg)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ {
+ if (get_user(payloadOffset, (uint8_t*) arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_KgSetAdditionalDataAfterParsing(p_LnxWrpFmDev->h_PcdDev, payloadOffset);
+ break;
+ }
+
+ case FM_PCD_IOC_KG_SET_DFLT_VALUE:
+ {
+ ioc_fm_pcd_kg_dflt_value_params_t *param;
+
+ param = (ioc_fm_pcd_kg_dflt_value_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_kg_dflt_value_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_kg_dflt_value_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)compat_ptr(arg),
+ sizeof(ioc_fm_pcd_kg_dflt_value_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)arg,
+ sizeof(ioc_fm_pcd_kg_dflt_value_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_KgSetDfltValue(p_LnxWrpFmDev->h_PcdDev, param->valueId, param->value);
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET:
+ {
+ ioc_fm_pcd_net_env_params_t *param;
+
+ param = (ioc_fm_pcd_net_env_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_net_env_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_net_env_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_net_env_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_net_env_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t));
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_net_env_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_US_TO_K);
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_net_env_params_t *) arg,
+ sizeof(ioc_fm_pcd_net_env_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->id = FM_PCD_NetEnvCharacteristicsSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdNetEnvParams*)param);
+
+ if (!param->id)
+ {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_net_env_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_net_env_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t));
+ compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_K_TO_US);
+
+ if (copy_to_user((ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_net_env_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_net_env_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_net_env_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_NetEnvCharacteristicsDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_KG_SCHEME_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_KG_SCHEME_SET:
+ {
+ ioc_fm_pcd_kg_scheme_params_t *param;
+
+ param = (ioc_fm_pcd_kg_scheme_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL;
+
+ compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
+
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_params_t *)arg,
+ sizeof(ioc_fm_pcd_kg_scheme_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->id = FM_PCD_KgSchemeSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdKgSchemeParams*)param);
+
+ if (!param->id)
+ {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t));
+ compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_params_t *)compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_kg_scheme_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_kg_scheme_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_KG_SCHEME_GET_CNTR_COMPAT:
+#endif
+ case FM_PCD_IOC_KG_SCHEME_GET_CNTR:
+ {
+ ioc_fm_pcd_kg_scheme_spc_t *param;
+
+ param = (ioc_fm_pcd_kg_scheme_spc_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_spc_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_spc_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param = NULL;
+
+ compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
+
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_spc_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_spc_t *)arg,
+ sizeof(ioc_fm_pcd_kg_scheme_spc_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->val = FM_PCD_KgSchemeGetCounter((t_Handle)param->id);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t));
+ compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_spc_t *)compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_kg_scheme_spc_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_kg_scheme_spc_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_KG_SCHEME_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_KgSchemeDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_SET:
+ {
+ ioc_fm_pcd_cc_node_params_t *param;
+ uint8_t *keys;
+ uint8_t *masks;
+ int i,k;
+
+ param = (ioc_fm_pcd_cc_node_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+
+ keys = (uint8_t *) (param + 1);
+ masks = keys + IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_params_t *)arg, sizeof(ioc_fm_pcd_cc_node_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ ASSERT_COND(param->keys_params.num_of_keys <= IOC_FM_PCD_MAX_NUM_OF_KEYS);
+ ASSERT_COND(param->keys_params.key_size <= IOC_FM_PCD_MAX_SIZE_OF_KEY);
+
+ /* support for indexed lookup */
+ if( !(param->extract_cc_params.type == e_IOC_FM_PCD_EXTRACT_NON_HDR &&
+ param->extract_cc_params.extract_params.extract_non_hdr.src == e_IOC_FM_PCD_EXTRACT_FROM_HASH &&
+ param->extract_cc_params.extract_params.extract_non_hdr.action == e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP))
+ {
+ for (i=0, k=0;
+ i < param->keys_params.num_of_keys;
+ i++, k += IOC_FM_PCD_MAX_SIZE_OF_KEY)
+ {
+ if (param->keys_params.key_params[i].p_key &&
+ param->keys_params.key_size)
+ {
+ if (copy_from_user(&keys[k],
+ param->keys_params.key_params[i].p_key,
+ param->keys_params.key_size))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->keys_params.key_params[i].p_key = &keys[k];
+ }
+
+ if (param->keys_params.key_params[i].p_mask)
+ {
+ if (copy_from_user(&masks[k],
+ param->keys_params.key_params[i].p_mask,
+ param->keys_params.key_size))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->keys_params.key_params[i].p_mask = &masks[k];
+ }
+ }
+ }
+
+ param->id = FM_PCD_MatchTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcNodeParams*)param);
+
+ if (!param->id) {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_params_t *compat_param;
+ compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) +
+ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY);
+ compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_K_TO_US);
+
+ if (copy_to_user((ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_cc_node_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_cc_node_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_cc_node_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_MatchTableDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_CC_ROOT_BUILD_COMPAT:
+#endif
+ case FM_PCD_IOC_CC_ROOT_BUILD:
+ {
+ ioc_fm_pcd_cc_tree_params_t *param;
+
+ param = (ioc_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_cc_tree_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tree_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_tree_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_tree_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_tree_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->id = FM_PCD_CcRootBuild(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcTreeParams*)param);
+
+ if (!param->id) {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tree_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t));
+
+ compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_K_TO_US);
+
+ if (copy_to_user((ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_cc_tree_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_cc_tree_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_cc_tree_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_CC_ROOT_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_CC_ROOT_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_CcRootDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_PLCR_PROFILE_SET:
+ {
+ ioc_fm_pcd_plcr_profile_params_t *param;
+
+ param = (ioc_fm_pcd_plcr_profile_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_plcr_profile_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
+ if (copy_from_user(compat_param, (
+ ioc_compat_fm_pcd_plcr_profile_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_plcr_profile_params_t *)arg,
+ sizeof(ioc_fm_pcd_plcr_profile_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (!param->modify &&
+ (((t_FmPcdPlcrProfileParams*)param)->id.newParams.profileType != e_FM_PCD_PLCR_SHARED))
+ {
+ t_Handle h_Port;
+ ioc_fm_pcd_port_params_t *port_params;
+
+ port_params = (ioc_fm_pcd_port_params_t*) XX_Malloc(sizeof(ioc_fm_pcd_port_params_t));
+ if (!port_params)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(port_params, 0, sizeof(ioc_fm_pcd_port_params_t));
+ if (copy_from_user(port_params, (ioc_fm_pcd_port_params_t*)((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort,
+ sizeof(ioc_fm_pcd_port_params_t)))
+ {
+ XX_Free(port_params);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ switch(port_params->port_type)
+ {
+ case (e_IOC_FM_PORT_TYPE_RX):
+ if (port_params->port_id < FM_MAX_NUM_OF_1G_RX_PORTS) {
+ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev;
+ break;
+ }
+ goto invalid_port_id;
+
+ case (e_IOC_FM_PORT_TYPE_RX_10G):
+ if (port_params->port_id < FM_MAX_NUM_OF_10G_RX_PORTS) {
+#ifndef CONFIG_FMAN_ARM
+ if (IS_T1023_T1024) {
+ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev;
+ } else {
+#else
+ {
+#endif
+ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id + FM_MAX_NUM_OF_1G_RX_PORTS].h_Dev;
+ }
+ break;
+ }
+ goto invalid_port_id;
+
+ case (e_IOC_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ if (port_params->port_id && port_params->port_id < FM_MAX_NUM_OF_OH_PORTS) {
+ h_Port = p_LnxWrpFmDev->opPorts[port_params->port_id - 1].h_Dev;
+ break;
+ }
+ goto invalid_port_id;
+
+ default:
+invalid_port_id:
+ XX_Free(port_params);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG);
+ }
+
+ ((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort = h_Port;
+ XX_Free(port_params);
+ }
+
+ param->id = FM_PCD_PlcrProfileSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPlcrProfileParams*)param);
+
+ if (!param->id) {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t));
+ compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_plcr_profile_params_t *) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_plcr_profile_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_plcr_profile_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_PLCR_PROFILE_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_PlcrProfileDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT:
+#endif
+ case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE:
+ {
+ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param;
+
+ param = (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t));
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_fm_pcd_cc_tree_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_CcRootModifyNextEngine(param->id,
+ param->grp_indx,
+ param->indx,
+ (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE:
+ {
+ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_MatchTableModifyNextEngine(param->id,
+ param->key_indx,
+ (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE:
+ {
+ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t));
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) arg,
+ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_MatchTableModifyMissNextEngine(param->id,
+ (t_FmPcdCcNextEngineParams*)(&param->cc_next_engine_params));
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY:
+ {
+ ioc_fm_pcd_cc_node_remove_key_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_remove_key_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_remove_key_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_remove_key_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_node_remove_key_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->id = compat_ptr(compat_param->id);
+ param->key_indx = compat_param->key_indx;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_remove_key_params_t *) arg,
+ sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_MatchTableRemoveKey(param->id, param->key_indx);
+
+ XX_Free(param);
+ break;
+ }
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_ADD_KEY:
+ {
+ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (param->key_size)
+ {
+ int size = 0;
+
+ if (param->key_params.p_key) size += param->key_size;
+ if (param->key_params.p_mask) size += param->key_size;
+
+ if (size)
+ {
+ uint8_t *p_tmp;
+
+ p_tmp = (uint8_t*) XX_Malloc(size);
+ if (!p_tmp)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
+ }
+
+ if (param->key_params.p_key)
+ {
+ if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size))
+ {
+ XX_Free(p_tmp);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->key_params.p_key = p_tmp;
+ }
+
+ if (param->key_params.p_mask)
+ {
+ p_tmp += param->key_size;
+ if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size))
+ {
+ XX_Free(p_tmp - param->key_size);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->key_params.p_mask = p_tmp;
+ }
+ }
+ }
+
+ err = FM_PCD_MatchTableAddKey(
+ param->id,
+ param->key_indx,
+ param->key_size,
+ (t_FmPcdCcKeyParams*)&param->key_params);
+
+ if (param->key_params.p_key)
+ XX_Free(param->key_params.p_key);
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE:
+ {
+ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PCD_MatchTableModifyKeyAndNextEngine(param->id,
+ param->key_indx,
+ param->key_size,
+ (t_FmPcdCcKeyParams*)(&param->key_params));
+
+ XX_Free(param);
+ break;
+ }
+
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT:
+ {
+ ioc_fm_pcd_cc_tbl_get_stats_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
+ {
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+
+ err = FM_PCD_MatchTableGetKeyStatistics((t_Handle) param.id,
+ param.key_index,
+ (t_FmPcdCcKeyStatistics *) &param.statistics);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ &param,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+
+ break;
+ }
+
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT:
+ {
+ ioc_fm_pcd_cc_tbl_get_stats_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
+ {
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+
+ err = FM_PCD_MatchTableGetMissStatistics((t_Handle) param.id,
+ (t_FmPcdCcKeyStatistics *) &param.statistics);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ &param,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+
+ break;
+ }
+
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT_COMPAT:
+#endif
+ case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT:
+ {
+ ioc_fm_pcd_cc_tbl_get_stats_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)))
+ {
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&param, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+
+ err = FM_PCD_HashTableGetMissStatistics((t_Handle) param.id,
+ (t_FmPcdCcKeyStatistics *) &param.statistics);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t));
+ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, &param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg,
+ &param,
+ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t)))
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_HASH_TABLE_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_HASH_TABLE_SET:
+ {
+ ioc_fm_pcd_hash_table_params_t *param;
+
+ param = (ioc_fm_pcd_hash_table_params_t*) XX_Malloc(
+ sizeof(ioc_fm_pcd_hash_table_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_hash_table_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_hash_table_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_hash_table_params_t*)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_hash_table_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_hash_table_params_t *)arg,
+ sizeof(ioc_fm_pcd_hash_table_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->id = FM_PCD_HashTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdHashTableParams *) param);
+
+ if (!param->id)
+ {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_hash_table_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_hash_table_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t));
+ compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_hash_table_params_t*) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_hash_table_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_hash_table_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_hash_table_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_HASH_TABLE_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0, sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ id.obj = compat_pcd_id2ptr(compat_id.obj);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_HashTableDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT:
+#endif
+ case FM_PCD_IOC_HASH_TABLE_ADD_KEY:
+ {
+ ioc_fm_pcd_hash_table_add_key_params_t *param = NULL;
+
+ param = (ioc_fm_pcd_hash_table_add_key_params_t*) XX_Malloc(
+ sizeof(ioc_fm_pcd_hash_table_add_key_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_add_key_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_hash_table_add_key_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_hash_table_add_key_params_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_hash_table_add_key_params_t*) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ if (compat_param->key_size)
+ {
+ param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl);
+ param->key_size = compat_param->key_size;
+
+ compat_copy_fm_pcd_cc_key(&compat_param->key_params, &param->key_params, COMPAT_US_TO_K);
+ }
+ else
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ break;
+ }
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_hash_table_add_key_params_t*) arg,
+ sizeof(ioc_fm_pcd_hash_table_add_key_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (param->key_size)
+ {
+ int size = 0;
+
+ if (param->key_params.p_key) size += param->key_size;
+ if (param->key_params.p_mask) size += param->key_size;
+
+ if (size)
+ {
+ uint8_t *p_tmp;
+
+ p_tmp = (uint8_t*) XX_Malloc(size);
+ if (!p_tmp)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
+ }
+
+ if (param->key_params.p_key)
+ {
+ if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size))
+ {
+ XX_Free(p_tmp);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->key_params.p_key = p_tmp;
+ }
+
+ if (param->key_params.p_mask)
+ {
+ p_tmp += param->key_size;
+ if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size))
+ {
+ XX_Free(p_tmp - param->key_size);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->key_params.p_mask = p_tmp;
+ }
+ }
+ }
+
+ err = FM_PCD_HashTableAddKey(
+ param->p_hash_tbl,
+ param->key_size,
+ (t_FmPcdCcKeyParams*)&param->key_params);
+
+ if (param->key_params.p_key)
+ XX_Free(param->key_params.p_key);
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT:
+#endif
+ case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY:
+ {
+ ioc_fm_pcd_hash_table_remove_key_params_t *param = NULL;
+
+ param = (ioc_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc(
+ sizeof(ioc_fm_pcd_hash_table_remove_key_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_remove_key_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_hash_table_remove_key_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl);
+ param->key_size = compat_param->key_size;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_hash_table_remove_key_params_t*)arg,
+ sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (param->key_size)
+ {
+ uint8_t *p_key;
+
+ p_key = (uint8_t*) XX_Malloc(param->key_size);
+ if (!p_key)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ if (param->p_key && copy_from_user(p_key, param->p_key, param->key_size))
+ {
+ XX_Free(p_key);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ param->p_key = p_key;
+ }
+
+ err = FM_PCD_HashTableRemoveKey(
+ param->p_hash_tbl,
+ param->key_size,
+ param->p_key);
+
+ if (param->p_key)
+ XX_Free(param->p_key);
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT:
+#endif
+ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY:
+ {
+ ioc_fm_pcd_cc_node_modify_key_params_t *param;
+
+ param = (ioc_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_cc_node_modify_key_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t));
+ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_key_params_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_cc_node_modify_key(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_params_t *)arg,
+ sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (param->key_size)
+ {
+ int size = 0;
+
+ if (param->p_key) size += param->key_size;
+ if (param->p_mask) size += param->key_size;
+
+ if (size)
+ {
+ uint8_t *p_tmp;
+
+ p_tmp = (uint8_t*) XX_Malloc(size);
+ if (!p_tmp)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask"));
+ }
+
+ if (param->p_key)
+ {
+ if (copy_from_user(p_tmp, param->p_key, param->key_size))
+ {
+ XX_Free(p_tmp);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->p_key = p_tmp;
+ }
+
+ if (param->p_mask)
+ {
+ p_tmp += param->key_size;
+ if (copy_from_user(p_tmp, param->p_mask, param->key_size))
+ {
+ XX_Free(p_tmp - param->key_size);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->p_mask = p_tmp;
+ }
+ }
+ }
+
+ err = FM_PCD_MatchTableModifyKey(param->id,
+ param->key_indx,
+ param->key_size,
+ param->p_key,
+ param->p_mask);
+
+ if (param->p_key)
+ XX_Free(param->p_key);
+ else if (param->p_mask)
+ XX_Free(param->p_mask);
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MANIP_NODE_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_MANIP_NODE_SET:
+ {
+ ioc_fm_pcd_manip_params_t *param;
+ uint8_t *p_data = NULL;
+ uint8_t size;
+
+ param = (ioc_fm_pcd_manip_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_manip_params_t));
+
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_manip_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_manip_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_manip_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_manip_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_manip_params_t *)arg,
+ sizeof(ioc_fm_pcd_manip_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (param->type == e_IOC_FM_PCD_MANIP_HDR)
+ {
+ size = param->u.hdr.insrt_params.u.generic.size;
+ p_data = (uint8_t *) XX_Malloc(size);
+ if (!p_data )
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, NO_MSG);
+ }
+
+ if (param->u.hdr.insrt_params.u.generic.p_data &&
+ copy_from_user(p_data,
+ param->u.hdr.insrt_params.u.generic.p_data, size))
+ {
+ XX_Free(p_data);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ param->u.hdr.insrt_params.u.generic.p_data = p_data;
+ }
+
+ if (param->id)
+ {
+ /* Security Hole: the user can pass any piece of garbage
+ in 'param->id', and that will go straight through to the LLD,
+ no checks being done by the wrapper! */
+ err = FM_PCD_ManipNodeReplace(
+ (t_Handle) param->id,
+ (t_FmPcdManipParams*) param);
+ if (err)
+ {
+ if (p_data)
+ XX_Free(p_data);
+ XX_Free(param);
+ break;
+ }
+ }
+ else
+ {
+ param->id = FM_PCD_ManipNodeSet(
+ p_LnxWrpFmDev->h_PcdDev,
+ (t_FmPcdManipParams*) param);
+ if (!param->id)
+ {
+ if (p_data)
+ XX_Free(p_data);
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /* Since the LLD has no errno-style error reporting,
+ we're left here with no other option than to report
+ a generic E_INVALID_VALUE */
+ break;
+ }
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_manip_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_manip_params_t));
+ if (!compat_param)
+ {
+ if (p_data)
+ XX_Free(p_data);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t));
+
+ compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_K_TO_US);
+
+ if (copy_to_user((ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_manip_params_t)))
+ err = E_READ_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_pcd_manip_params_t *)arg,
+ param, sizeof(ioc_fm_pcd_manip_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ if (p_data)
+ XX_Free(p_data);
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_MANIP_NODE_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0, sizeof(ioc_fm_obj_t));
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_ManipNodeDelete(id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_MANIP_GET_STATS_COMPAT:
+#endif
+ case FM_PCD_IOC_MANIP_GET_STATS:
+ {
+ ioc_fm_pcd_manip_get_stats_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_manip_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_manip_get_stats_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_manip_get_stats_t *)compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_manip_get_stats_t)))
+ {
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_manip_get_stats(compat_param, &param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&param, (ioc_fm_pcd_manip_get_stats_t *)arg,
+ sizeof(ioc_fm_pcd_manip_get_stats_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PCD_ManipGetStatistics((t_Handle) param.id,
+ (t_FmPcdManipStats*) &param.stats);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_manip_get_stats_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_manip_get_stats_t*) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
+ if (!compat_param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t));
+ compat_copy_fm_pcd_manip_get_stats(compat_param, &param, COMPAT_K_TO_US);
+ if (copy_to_user((ioc_compat_fm_pcd_manip_get_stats_t*) compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_manip_get_stats_t))){
+ XX_Free(compat_param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ if (copy_to_user((ioc_fm_pcd_manip_get_stats_t *)arg,
+ &param,
+ sizeof(ioc_fm_pcd_manip_get_stats_t)))
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+
+ break;
+ }
+
+#if (DPAA_VERSION >= 11)
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT:
+#endif
+ case FM_PCD_IOC_FRM_REPLIC_GROUP_SET:
+ {
+ ioc_fm_pcd_frm_replic_group_params_t *param;
+
+ param = (ioc_fm_pcd_frm_replic_group_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_frm_replic_group_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_frm_replic_group_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_frm_replic_group_params_t
+ *compat_param;
+
+ compat_param =
+ (ioc_compat_fm_pcd_frm_replic_group_params_t *)
+ XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY,
+ ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_frm_replic_group_params_t *)
+ compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t))) {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_frm_replic_group_params(compat_param,
+ param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param,
+ (ioc_fm_pcd_frm_replic_group_params_t *)arg,
+ sizeof(ioc_fm_pcd_frm_replic_group_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ }
+
+ param->id = FM_PCD_FrmReplicSetGroup(p_LnxWrpFmDev->h_PcdDev,
+ (t_FmPcdFrmReplicGroupParams*)param);
+
+ if (!param->id) {
+ XX_Free(param);
+ err = E_INVALID_VALUE;
+ /*
+ * Since the LLD has no errno-style error reporting,
+ * we're left here with no other option than to report
+ * a generic E_INVALID_VALUE
+ */
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_frm_replic_group_params_t
+ *compat_param;
+
+ compat_param =
+ (ioc_compat_fm_pcd_frm_replic_group_params_t *)
+ XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY,
+ ("IOCTL FM PCD"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t));
+ compat_copy_fm_pcd_frm_replic_group_params(compat_param,
+ param, COMPAT_K_TO_US);
+ if (copy_to_user(
+ (ioc_compat_fm_pcd_frm_replic_group_params_t *)
+ compat_ptr(arg),
+ compat_param,
+ sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)))
+ err = E_WRITE_FAILED;
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_to_user(
+ (ioc_fm_pcd_frm_replic_group_params_t *)arg,
+ param,
+ sizeof(ioc_fm_pcd_frm_replic_group_params_t)))
+ err = E_WRITE_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT:
+#endif
+ case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0, sizeof(ioc_fm_obj_t));
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id,
+ (ioc_compat_fm_obj_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_obj_t)))
+ break;
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
+ sizeof(ioc_fm_obj_t)))
+ break;
+ }
+
+ return FM_PCD_FrmReplicDeleteGroup(id.obj);
+ }
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT:
+#endif
+ case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD:
+ {
+ ioc_fm_pcd_frm_replic_member_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_frm_replic_member_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_pcd_frm_replic_member_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ return FM_PCD_FrmReplicAddMember(param.member.h_replic_group,
+ param.member.member_index,
+ (t_FmPcdCcNextEngineParams*)&param.next_engine_params);
+ }
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT:
+#endif
+ case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE:
+ {
+ ioc_fm_pcd_frm_replic_member_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_frm_replic_member_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_pcd_frm_replic_member(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ return FM_PCD_FrmReplicRemoveMember(param.h_replic_group, param.member_index);
+ }
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_CONFIG_COMPAT:
+#endif
+ case FM_IOC_VSP_CONFIG:
+ {
+ ioc_fm_vsp_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_vsp_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_vsp_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ {
+ uint8_t portId = param.port_params.port_id;
+ param.liodn_offset =
+ p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset;
+ }
+ param.p_fm = p_LnxWrpFmDev->h_Dev;
+ param.id = FM_VSP_Config((t_FmVspParams *)&param);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_vsp_params_t compat_param;
+
+ memset(&compat_param, 0, sizeof(compat_param));
+ compat_copy_fm_vsp_params(&compat_param, &param, COMPAT_K_TO_US);
+
+ if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ if (copy_to_user((void *)arg, &param, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_INIT_COMPAT:
+#endif
+ case FM_IOC_VSP_INIT:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0, sizeof(ioc_fm_obj_t));
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id,
+ (ioc_compat_fm_obj_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_obj_t)))
+ break;
+ id.obj = compat_pcd_id2ptr(compat_id.obj);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
+ sizeof(ioc_fm_obj_t)))
+ break;
+ }
+
+ return FM_VSP_Init(id.obj);
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_FREE_COMPAT:
+#endif
+ case FM_IOC_VSP_FREE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0, sizeof(ioc_fm_obj_t));
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id,
+ (ioc_compat_fm_obj_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_obj_t)))
+ break;
+ compat_obj_delete(&compat_id, &id);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg,
+ sizeof(ioc_fm_obj_t)))
+ break;
+ }
+
+ return FM_VSP_Free(id.obj);
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT:
+#endif
+ case FM_IOC_VSP_CONFIG_POOL_DEPLETION:
+ {
+ ioc_fm_buf_pool_depletion_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_buf_pool_depletion_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_buf_pool_depletion_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (FM_VSP_ConfigPoolDepletion(param.p_fm_vsp,
+ (t_FmBufPoolDepletion *)&param.fm_buf_pool_depletion))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT:
+#endif
+ case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT:
+ {
+ ioc_fm_buffer_prefix_content_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_buffer_prefix_content_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_buffer_prefix_content_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (FM_VSP_ConfigBufferPrefixContent(param.p_fm_vsp,
+ (t_FmBufferPrefixContent *)&param.fm_buffer_prefix_content))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_CONFIG_NO_SG_COMPAT:
+#endif
+ case FM_IOC_VSP_CONFIG_NO_SG:
+ {
+ ioc_fm_vsp_config_no_sg_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_vsp_config_no_sg_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_vsp_config_no_sg_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (FM_VSP_ConfigNoScatherGather(param.p_fm_vsp, param.no_sg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT:
+#endif
+ case FM_IOC_VSP_GET_BUFFER_PRS_RESULT:
+ {
+ ioc_fm_vsp_prs_result_params_t param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_vsp_prs_result_params_t compat_param;
+
+ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_vsp_prs_result_params(&compat_param, &param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ if (copy_from_user(&param, (void *)arg, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ /* this call just adds the parse results offset to p_data */
+ param.p_data = FM_VSP_GetBufferPrsResult(param.p_fm_vsp, param.p_data);
+
+ if (!param.p_data)
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_vsp_prs_result_params_t compat_param;
+
+ memset(&compat_param, 0, sizeof(compat_param));
+ compat_copy_fm_vsp_prs_result_params(&compat_param, &param, COMPAT_K_TO_US);
+
+ if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ if (copy_to_user((void *)arg, &param, sizeof(param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+#ifdef FM_CAPWAP_SUPPORT
+#warning "feature not supported!"
+#if defined(CONFIG_COMPAT)
+ case FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT:
+#endif
+ case FM_PCD_IOC_STATISTICS_SET_NODE:
+ {
+/* ioc_fm_pcd_stats_params_t param;
+ ...
+ param->id = FM_PCD_StatisticsSetNode(p_LnxWrpFmDev->h_PcdDev,
+ (t_FmPcdStatsParams *)&param);
+*/
+ err = E_NOT_SUPPORTED;
+ break;
+ }
+#endif /* FM_CAPWAP_SUPPORT */
+
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr: %d.\n",
+ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)));
+ }
+
+ if (err)
+ RETURN_ERROR(MINOR, err, ("IOCTL FM PCD"));
+
+ return E_OK;
+}
+
+void FM_Get_Api_Version(ioc_fm_api_version_t *p_version)
+{
+ p_version->version.major = FMD_API_VERSION_MAJOR;
+ p_version->version.minor = FMD_API_VERSION_MINOR;
+ p_version->version.respin = FMD_API_VERSION_RESPIN;
+ p_version->version.reserved = 0;
+}
+
+t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat)
+{
+ t_Error err = E_OK;
+
+ switch (cmd)
+ {
+ case FM_IOC_SET_PORTS_BANDWIDTH:
+ {
+ ioc_fm_port_bandwidth_params *param;
+
+ param = (ioc_fm_port_bandwidth_params*) XX_Malloc(sizeof(ioc_fm_port_bandwidth_params));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_port_bandwidth_params));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)compat_ptr(arg), sizeof(ioc_fm_port_bandwidth_params)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)arg, sizeof(ioc_fm_port_bandwidth_params)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_SetPortsBandwidth(p_LnxWrpFmDev->h_Dev, (t_FmPortsBandwidthParams*) param);
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_IOC_GET_REVISION:
+ {
+ ioc_fm_revision_info_t *param;
+
+ param = (ioc_fm_revision_info_t *) XX_Malloc(sizeof(ioc_fm_revision_info_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ FM_GetRevision(p_LnxWrpFmDev->h_Dev, (t_FmRevisionInfo*)param);
+ /* This one never returns anything other than E_OK */
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_to_user((ioc_fm_revision_info_t *)compat_ptr(arg),
+ param,
+ sizeof(ioc_fm_revision_info_t))){
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_revision_info_t *)arg,
+ param,
+ sizeof(ioc_fm_revision_info_t))){
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG);
+ }
+ }
+ XX_Free(param);
+ break;
+ }
+
+ case FM_IOC_SET_COUNTER:
+ {
+ ioc_fm_counters_params_t *param;
+
+ param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_counters_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_ModifyCounter(p_LnxWrpFmDev->h_Dev, param->cnt, param->val);
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_IOC_GET_COUNTER:
+ {
+ ioc_fm_counters_params_t *param;
+
+ param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD"));
+
+ memset(param, 0, sizeof(ioc_fm_counters_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ param->val = FM_GetCounter(p_LnxWrpFmDev->h_Dev, param->cnt);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_to_user((ioc_fm_counters_params_t *)compat_ptr(arg), param, sizeof(ioc_fm_counters_params_t)))
+ err = E_READ_FAILED;
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_counters_params_t *)arg, param, sizeof(ioc_fm_counters_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_IOC_FORCE_INTR:
+ {
+ ioc_fm_exceptions param;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (get_user(param, (ioc_fm_exceptions*) compat_ptr(arg)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ {
+ if (get_user(param, (ioc_fm_exceptions*)arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_ForceIntr(p_LnxWrpFmDev->h_Dev, (e_FmExceptions)param);
+ break;
+ }
+
+ case FM_IOC_GET_API_VERSION:
+ {
+ ioc_fm_api_version_t version;
+
+ FM_Get_Api_Version(&version);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_to_user(
+ (ioc_fm_api_version_t *)compat_ptr(arg),
+ &version, sizeof(version)))
+ err = E_READ_FAILED;
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_api_version_t *)arg,
+ &version, sizeof(version)))
+ err = E_READ_FAILED;
+ }
+ }
+ break;
+
+ case FM_IOC_CTRL_MON_START:
+ {
+ FM_CtrlMonStart(p_LnxWrpFmDev->h_Dev);
+ }
+ break;
+
+ case FM_IOC_CTRL_MON_STOP:
+ {
+ FM_CtrlMonStop(p_LnxWrpFmDev->h_Dev);
+ }
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT:
+#endif
+ case FM_IOC_CTRL_MON_GET_COUNTERS:
+ {
+ ioc_fm_ctrl_mon_counters_params_t param;
+ t_FmCtrlMon mon;
+
+#if defined(CONFIG_COMPAT)
+ ioc_compat_fm_ctrl_mon_counters_params_t compat_param;
+
+ if (compat)
+ {
+ if (copy_from_user(&compat_param, (void *)compat_ptr(arg),
+ sizeof(compat_param)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ param.fm_ctrl_index = compat_param.fm_ctrl_index;
+ param.p_mon = (fm_ctrl_mon_t *)compat_ptr(compat_param.p_mon);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&param, (void *)arg, sizeof(ioc_fm_ctrl_mon_counters_params_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ if (FM_CtrlMonGetCounters(p_LnxWrpFmDev->h_Dev, param.fm_ctrl_index, &mon))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (copy_to_user(param.p_mon, &mon, sizeof(t_FmCtrlMon)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ break;
+
+ default:
+ return LnxwrpFmPcdIOCTL(p_LnxWrpFmDev, cmd, arg, compat);
+ }
+
+ if (err)
+ RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM"));
+
+ return E_OK;
+}
+
+t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat)
+{
+ t_Error err = E_OK;
+
+ _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n",
+ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 70);
+
+ switch (cmd)
+ {
+ case FM_PORT_IOC_DISABLE:
+ FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev);
+ /* deliberately ignoring error codes here */
+ return E_OK;
+
+ case FM_PORT_IOC_ENABLE:
+ FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev);
+ /* deliberately ignoring error codes here */
+ return E_OK;
+
+ case FM_PORT_IOC_SET_ERRORS_ROUTE:
+ {
+ ioc_fm_port_frame_err_select_t errs;
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (get_user(errs, (ioc_fm_port_frame_err_select_t*)compat_ptr(arg)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ {
+ if (get_user(errs, (ioc_fm_port_frame_err_select_t*)arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PORT_SetErrorsRoute(p_LnxWrpFmPortDev->h_Dev, (fmPortFrameErrSelect_t)errs);
+ break;
+ }
+
+ case FM_PORT_IOC_SET_RATE_LIMIT:
+ {
+ ioc_fm_port_rate_limit_t *param;
+
+ param = (ioc_fm_port_rate_limit_t *) XX_Malloc(sizeof(ioc_fm_port_rate_limit_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_port_rate_limit_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)compat_ptr(arg), sizeof(ioc_fm_port_rate_limit_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)arg, sizeof(ioc_fm_port_rate_limit_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, (t_FmPortRateLimit *)param);
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PORT_IOC_REMOVE_RATE_LIMIT:
+ FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev);
+ /* deliberately ignoring error codes here */
+ return E_OK;
+
+ case FM_PORT_IOC_ALLOC_PCD_FQIDS:
+ {
+ ioc_fm_port_pcd_fqids_params_t *param;
+
+ if (!p_LnxWrpFmPortDev->pcd_owner_params.cba)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!"));
+
+ param = (ioc_fm_port_pcd_fqids_params_t *) XX_Malloc(sizeof(ioc_fm_port_pcd_fqids_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_port_pcd_fqids_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg),
+ sizeof(ioc_fm_port_pcd_fqids_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)arg,
+ sizeof(ioc_fm_port_pcd_fqids_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (p_LnxWrpFmPortDev->pcd_owner_params.cba(p_LnxWrpFmPortDev->pcd_owner_params.dev,
+ param->num_fqids,
+ param->alignment,
+ &param->base_fqid))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("can't allocate fqids for PCD!!!"));
+ }
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg),
+ param, sizeof(ioc_fm_port_pcd_fqids_params_t)))
+ err = E_READ_FAILED;
+ }
+ else
+#endif
+ {
+ if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)arg,
+ param, sizeof(ioc_fm_port_pcd_fqids_params_t)))
+ err = E_READ_FAILED;
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PORT_IOC_FREE_PCD_FQIDS:
+ {
+ uint32_t base_fqid;
+
+ if (!p_LnxWrpFmPortDev->pcd_owner_params.cbf)
+ RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!"));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (get_user(base_fqid, (uint32_t*) compat_ptr(arg)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ else
+#endif
+ {
+ if (get_user(base_fqid, (uint32_t*)arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ if (p_LnxWrpFmPortDev->pcd_owner_params.cbf(p_LnxWrpFmPortDev->pcd_owner_params.dev, base_fqid))
+ err = E_WRITE_FAILED;
+
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_SET_PCD_COMPAT:
+#endif
+ case FM_PORT_IOC_SET_PCD:
+ {
+ ioc_fm_port_pcd_params_t *port_pcd_params;
+ ioc_fm_port_pcd_prs_params_t *port_pcd_prs_params;
+ ioc_fm_port_pcd_cc_params_t *port_pcd_cc_params;
+ ioc_fm_port_pcd_kg_params_t *port_pcd_kg_params;
+ ioc_fm_port_pcd_plcr_params_t *port_pcd_plcr_params;
+
+ port_pcd_params = (ioc_fm_port_pcd_params_t *) XX_Malloc(
+ sizeof(ioc_fm_port_pcd_params_t) +
+ sizeof(ioc_fm_port_pcd_prs_params_t) +
+ sizeof(ioc_fm_port_pcd_cc_params_t) +
+ sizeof(ioc_fm_port_pcd_kg_params_t) +
+ sizeof(ioc_fm_port_pcd_plcr_params_t));
+ if (!port_pcd_params)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(port_pcd_params, 0,
+ sizeof(ioc_fm_port_pcd_params_t) +
+ sizeof(ioc_fm_port_pcd_prs_params_t) +
+ sizeof(ioc_fm_port_pcd_cc_params_t) +
+ sizeof(ioc_fm_port_pcd_kg_params_t) +
+ sizeof(ioc_fm_port_pcd_plcr_params_t));
+
+ port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (port_pcd_params + 1);
+ port_pcd_cc_params = (ioc_fm_port_pcd_cc_params_t *) (port_pcd_prs_params + 1);
+ port_pcd_kg_params = (ioc_fm_port_pcd_kg_params_t *) (port_pcd_cc_params + 1);
+ port_pcd_plcr_params = (ioc_fm_port_pcd_plcr_params_t *) (port_pcd_kg_params + 1);
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_port_pcd_params_t *compat_port_pcd_params;
+ ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params;
+ ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params;
+ ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params;
+ ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params;
+
+ compat_port_pcd_params = (ioc_compat_fm_port_pcd_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_port_pcd_params_t) +
+ sizeof(ioc_fm_port_pcd_prs_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_cc_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_kg_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_plcr_params_t));
+ if (!compat_port_pcd_params)
+ {
+ XX_Free(port_pcd_params);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+ }
+
+ memset(compat_port_pcd_params, 0,
+ sizeof(ioc_compat_fm_port_pcd_params_t) +
+ sizeof(ioc_fm_port_pcd_prs_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_cc_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_kg_params_t) +
+ sizeof(ioc_compat_fm_port_pcd_plcr_params_t));
+ same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_port_pcd_params + 1);
+ compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1);
+ compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1);
+ compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1);
+
+ if (copy_from_user(compat_port_pcd_params,
+ (ioc_compat_fm_port_pcd_params_t*) compat_ptr(arg),
+ sizeof(ioc_compat_fm_port_pcd_params_t)))
+ err = E_WRITE_FAILED;
+
+ while (!err) /* pseudo-while */
+ {
+ /* set pointers from where to copy from: */
+ port_pcd_params->p_prs_params = compat_ptr(compat_port_pcd_params->p_prs_params); /* same structure */
+ port_pcd_params->p_cc_params = compat_ptr(compat_port_pcd_params->p_cc_params);
+ port_pcd_params->p_kg_params = compat_ptr(compat_port_pcd_params->p_kg_params);
+ port_pcd_params->p_plcr_params = compat_ptr(compat_port_pcd_params->p_plcr_params);
+ port_pcd_params->p_ip_reassembly_manip = compat_ptr(compat_port_pcd_params->p_ip_reassembly_manip);
+#if (DPAA_VERSION >= 11)
+ port_pcd_params->p_capwap_reassembly_manip = compat_ptr(compat_port_pcd_params->p_capwap_reassembly_manip);
+#endif
+ /* the prs member is the same, no compat structure...memcpy only */
+ if (port_pcd_params->p_prs_params)
+ {
+ if (copy_from_user(same_port_pcd_prs_params,
+ port_pcd_params->p_prs_params,
+ sizeof(ioc_fm_port_pcd_prs_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ memcpy(port_pcd_prs_params, same_port_pcd_prs_params, sizeof(ioc_fm_port_pcd_prs_params_t));
+ port_pcd_params->p_prs_params = port_pcd_prs_params;
+ }
+
+ if (port_pcd_params->p_cc_params)
+ {
+ if (copy_from_user(compat_port_pcd_cc_params,
+ port_pcd_params->p_cc_params,
+ sizeof(ioc_compat_fm_port_pcd_cc_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_cc_params = port_pcd_cc_params;
+ }
+
+ if (port_pcd_params->p_kg_params)
+ {
+ if (copy_from_user(compat_port_pcd_kg_params,
+ port_pcd_params->p_kg_params,
+ sizeof(ioc_compat_fm_port_pcd_kg_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_kg_params = port_pcd_kg_params;
+ }
+
+ if (port_pcd_params->p_plcr_params)
+ {
+ if (copy_from_user(compat_port_pcd_plcr_params,
+ port_pcd_params->p_plcr_params,
+ sizeof(ioc_compat_fm_port_pcd_plcr_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_plcr_params = port_pcd_plcr_params;
+ }
+
+ break; /* pseudo-while: always run once! */
+ }
+
+ if (!err)
+ compat_copy_fm_port_pcd(compat_port_pcd_params, port_pcd_params, COMPAT_US_TO_K);
+
+ XX_Free(compat_port_pcd_params);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(port_pcd_params,
+ (ioc_fm_port_pcd_params_t*) arg,
+ sizeof(ioc_fm_port_pcd_params_t)))
+ err = E_WRITE_FAILED;
+
+ while (!err) /* pseudo-while */
+ {
+ if (port_pcd_params->p_prs_params)
+ {
+ if (copy_from_user(port_pcd_prs_params,
+ port_pcd_params->p_prs_params,
+ sizeof(ioc_fm_port_pcd_prs_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_prs_params = port_pcd_prs_params;
+ }
+
+ if (port_pcd_params->p_cc_params)
+ {
+ if (copy_from_user(port_pcd_cc_params,
+ port_pcd_params->p_cc_params,
+ sizeof(ioc_fm_port_pcd_cc_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_cc_params = port_pcd_cc_params;
+ }
+
+ if (port_pcd_params->p_kg_params)
+ {
+ if (copy_from_user(port_pcd_kg_params,
+ port_pcd_params->p_kg_params,
+ sizeof(ioc_fm_port_pcd_kg_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_kg_params = port_pcd_kg_params;
+ }
+
+ if (port_pcd_params->p_plcr_params)
+ {
+ if (copy_from_user(port_pcd_plcr_params,
+ port_pcd_params->p_plcr_params,
+ sizeof(ioc_fm_port_pcd_plcr_params_t)))
+ {
+ err = E_WRITE_FAILED;
+ break; /* from pseudo-while */
+ }
+
+ port_pcd_params->p_plcr_params = port_pcd_plcr_params;
+ }
+
+ break; /* pseudo-while: always run once! */
+ }
+ }
+
+ if (!err)
+ err = FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, (t_FmPortPcdParams*) port_pcd_params);
+
+ XX_Free(port_pcd_params);
+ break;
+ }
+
+ case FM_PORT_IOC_DELETE_PCD:
+ err = FM_PORT_DeletePCD(p_LnxWrpFmPortDev->h_Dev);
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT:
+#endif
+ case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME:
+ {
+ ioc_fm_pcd_kg_scheme_select_t *param;
+
+ param = (ioc_fm_pcd_kg_scheme_select_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_kg_scheme_select_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_select_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param;
+
+ compat_param = (ioc_compat_fm_pcd_kg_scheme_select_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_pcd_kg_scheme_select_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_select_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_pcd_kg_scheme_select_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_kg_scheme_select(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_select_t *)arg,
+ sizeof(ioc_fm_pcd_kg_scheme_select_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PORT_PcdKgModifyInitialScheme(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdKgSchemeSelect *)param);
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT:
+#endif
+ case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ id.obj = compat_ptr(compat_id.obj);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PORT_PcdPlcrModifyInitialProfile(p_LnxWrpFmPortDev->h_Dev, id.obj);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT:
+#endif
+ case FM_PORT_IOC_PCD_KG_BIND_SCHEMES:
+ {
+ ioc_fm_pcd_port_schemes_params_t *param;
+
+ param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_port_schemes_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_port_schemes_params_t compat_param;
+
+ if (copy_from_user(&compat_param,
+ (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_port_schemes_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg,
+ sizeof(ioc_fm_pcd_port_schemes_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PORT_PcdKgBindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param);
+
+ XX_Free(param);
+ break;
+ }
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT:
+#endif
+ case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES:
+ {
+ ioc_fm_pcd_port_schemes_params_t *param;
+
+ param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc(
+ sizeof(ioc_fm_pcd_port_schemes_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_pcd_port_schemes_params_t compat_param;
+
+ if (copy_from_user(&compat_param,
+ (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_pcd_port_schemes_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg,
+ sizeof(ioc_fm_pcd_port_schemes_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = FM_PORT_PcdKgUnbindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param);
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES:
+ {
+ uint16_t num;
+ if (get_user(num, (uint16_t*) arg))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ err = FM_PORT_PcdPlcrAllocProfiles(p_LnxWrpFmPortDev->h_Dev, num);
+ break;
+ }
+
+ case FM_PORT_IOC_PCD_PLCR_FREE_PROFILES:
+ err = FM_PORT_PcdPlcrFreeProfiles(p_LnxWrpFmPortDev->h_Dev);
+ break;
+
+ case FM_PORT_IOC_DETACH_PCD:
+ err = FM_PORT_DetachPCD(p_LnxWrpFmPortDev->h_Dev);
+ break;
+
+ case FM_PORT_IOC_ATTACH_PCD:
+ err = FM_PORT_AttachPCD(p_LnxWrpFmPortDev->h_Dev);
+ break;
+
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT:
+#endif
+ case FM_PORT_IOC_PCD_CC_MODIFY_TREE:
+ {
+ ioc_fm_obj_t id;
+
+ memset(&id, 0 , sizeof(ioc_fm_obj_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_obj_t compat_id;
+
+ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ compat_copy_fm_port_pcd_modify_tree(&compat_id, &id, COMPAT_US_TO_K);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ err = FM_PORT_PcdCcModifyTree(p_LnxWrpFmPortDev->h_Dev, id.obj);
+ break;
+ }
+
+ case FM_PORT_IOC_ADD_CONGESTION_GRPS:
+ case FM_PORT_IOC_REMOVE_CONGESTION_GRPS:
+ {
+ ioc_fm_port_congestion_groups_t *param;
+
+ param = (ioc_fm_port_congestion_groups_t*) XX_Malloc(sizeof(ioc_fm_port_congestion_groups_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_port_congestion_groups_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (t_FmPortCongestionGrps*) compat_ptr(arg),
+ sizeof(t_FmPortCongestionGrps)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif /* CONFIG_COMPAT */
+ {
+ if (copy_from_user(param, (t_FmPortCongestionGrps*) arg,
+ sizeof(t_FmPortCongestionGrps)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ err = (cmd == FM_PORT_IOC_ADD_CONGESTION_GRPS)
+ ? FM_PORT_AddCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param)
+ : FM_PORT_RemoveCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param)
+ ;
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR:
+ case FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR:
+ {
+ ioc_fm_port_mac_addr_params_t *param;
+
+ param = (ioc_fm_port_mac_addr_params_t*) XX_Malloc(
+ sizeof(ioc_fm_port_mac_addr_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_port_mac_addr_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) compat_ptr(arg),
+ sizeof(ioc_fm_port_mac_addr_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+ else
+#endif /* CONFIG_COMPAT */
+ {
+ if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) arg,
+ sizeof(ioc_fm_port_mac_addr_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ if (p_LnxWrpFmPortDev->pcd_owner_params.dev)
+ {
+ int id = -1;
+
+ switch(p_LnxWrpFmPortDev->settings.param.portType)
+ {
+ case e_FM_PORT_TYPE_RX:
+ case e_FM_PORT_TYPE_TX:
+ id = p_LnxWrpFmPortDev->id;
+ break;
+ case e_FM_PORT_TYPE_RX_10G:
+ case e_FM_PORT_TYPE_TX_10G:
+ id = p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_MACS;
+ break;
+ default:
+ err = E_NOT_AVAILABLE;
+ REPORT_ERROR(MINOR, err, ("Attempt to add/remove hash MAC addr. to/from MAC-less port!"));
+ }
+ if (id >= 0)
+ {
+ t_LnxWrpFmDev *fm = (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ t_Handle mac_handle = fm->macs[id].h_Dev;
+
+ err = (cmd == FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR)
+ ? FM_MAC_AddHashMacAddr(mac_handle, (t_EnetAddr*) param)
+ : FM_MAC_RemoveHashMacAddr(mac_handle, (t_EnetAddr*) param);
+ }
+ }
+ else
+ {
+ err = E_NOT_AVAILABLE;
+ REPORT_ERROR(MINOR, err, ("Port not initialized or other error!?!?"));
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+ case FM_PORT_IOC_SET_TX_PAUSE_FRAMES:
+ {
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ ioc_fm_port_tx_pause_frames_params_t param;
+ int mac_id = p_LnxWrpFmPortDev->id;
+
+ if(&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev)
+ mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
+
+ if (copy_from_user(&param, (ioc_fm_port_tx_pause_frames_params_t *)arg,
+ sizeof(ioc_fm_port_tx_pause_frames_params_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (p_LnxWrpFmDev && p_LnxWrpFmDev->macs[mac_id].h_Dev)
+ {
+ FM_MAC_SetTxPauseFrames(p_LnxWrpFmDev->macs[mac_id].h_Dev,
+ param.priority,
+ param.pause_time,
+ param.thresh_time);
+ }
+ else
+ {
+ err = E_NOT_AVAILABLE;
+ REPORT_ERROR(MINOR, err, ("Port not initialized or other error!"));
+ }
+
+ break;
+ }
+
+ case FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT:
+ {
+ ioc_fm_buffer_prefix_content_t *param;
+
+ param = (ioc_fm_buffer_prefix_content_t*) XX_Malloc(sizeof(ioc_fm_buffer_prefix_content_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_buffer_prefix_content_t));
+
+ if (copy_from_user(param, (ioc_fm_buffer_prefix_content_t*) arg,
+ sizeof(ioc_fm_buffer_prefix_content_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ if (FM_PORT_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_Dev,
+ (t_FmBufferPrefixContent *)param))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ XX_Free(param);
+ break;
+ }
+
+#if (DPAA_VERSION >= 11)
+#if defined(CONFIG_COMPAT)
+ case FM_PORT_IOC_VSP_ALLOC_COMPAT:
+#endif
+ case FM_PORT_IOC_VSP_ALLOC:
+ {
+ ioc_fm_port_vsp_alloc_params_t *param;
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ t_LnxWrpFmPortDev *p_LnxWrpFmTxPortDev;
+
+ param = (ioc_fm_port_vsp_alloc_params_t *) XX_Malloc(
+ sizeof(ioc_fm_port_vsp_alloc_params_t));
+ if (!param)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+
+ memset(param, 0, sizeof(ioc_fm_port_vsp_alloc_params_t));
+
+#if defined(CONFIG_COMPAT)
+ if (compat)
+ {
+ ioc_compat_fm_port_vsp_alloc_params_t *compat_param;
+
+ compat_param = (ioc_compat_fm_port_vsp_alloc_params_t *) XX_Malloc(
+ sizeof(ioc_compat_fm_port_vsp_alloc_params_t));
+ if (!compat_param)
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT"));
+ }
+
+ memset(compat_param, 0, sizeof(ioc_compat_fm_port_vsp_alloc_params_t));
+ if (copy_from_user(compat_param,
+ (ioc_compat_fm_port_vsp_alloc_params_t *) compat_ptr(arg),
+ sizeof(ioc_compat_fm_port_vsp_alloc_params_t)))
+ {
+ XX_Free(compat_param);
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ compat_copy_fm_port_vsp_alloc_params(compat_param, param, COMPAT_US_TO_K);
+
+ XX_Free(compat_param);
+ }
+ else
+#endif
+ {
+ if (copy_from_user(param, (ioc_fm_port_vsp_alloc_params_t *)arg,
+ sizeof(ioc_fm_port_vsp_alloc_params_t)))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+ }
+
+ /* Userspace may not have the Tx port t_handle when issuing the IOCTL */
+ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX ||
+ p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G)
+ {
+ /* Determine the Tx port t_Handle from the Rx port id */
+ p_LnxWrpFmDev = p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ p_LnxWrpFmTxPortDev = &p_LnxWrpFmDev->txPorts[p_LnxWrpFmPortDev->id];
+ param->p_fm_tx_port = p_LnxWrpFmTxPortDev->h_Dev;
+ }
+
+ if (FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, (t_FmPortVSPAllocParams *)param))
+ {
+ XX_Free(param);
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+ }
+
+ XX_Free(param);
+ break;
+ }
+#endif /* (DPAA_VERSION >= 11) */
+
+ case FM_PORT_IOC_GET_MAC_STATISTICS:
+ {
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ ioc_fm_port_mac_statistics_t param;
+ int mac_id = p_LnxWrpFmPortDev->id;
+
+ if (!p_LnxWrpFmDev)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
+
+ if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev &&
+ &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev)
+ mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
+
+ if (!p_LnxWrpFmDev->macs[mac_id].h_Dev)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
+
+ if (FM_MAC_GetStatistics(p_LnxWrpFmDev->macs[mac_id].h_Dev,
+ (t_FmMacStatistics *)&param))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (copy_to_user((ioc_fm_port_mac_statistics_t *)arg, &param,
+ sizeof(ioc_fm_port_mac_statistics_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+ case FM_PORT_IOC_GET_MAC_FRAME_SIZE_COUNTERS:
+ {
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ ioc_fm_port_mac_frame_size_counters_t param;
+ t_FmMacFrameSizeCounters frameSizeCounters;
+ int mac_id = p_LnxWrpFmPortDev->id;
+
+ if (!p_LnxWrpFmDev)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
+
+ if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev &&
+ &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev)
+ mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */
+
+ if (!p_LnxWrpFmDev->macs[mac_id].h_Dev)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
+
+ if (copy_from_user(&param, (ioc_fm_port_mac_frame_size_counters_t *)arg,
+ sizeof(ioc_fm_port_mac_frame_size_counters_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (FM_MAC_GetFrameSizeCounters(p_LnxWrpFmDev->macs[mac_id].h_Dev,
+ &frameSizeCounters, param.type))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ param.count_pkts_64 = frameSizeCounters.count_pkts_64;
+ param.count_pkts_65_to_127 = frameSizeCounters.count_pkts_65_to_127;
+ param.count_pkts_128_to_255 = frameSizeCounters.count_pkts_128_to_255;
+ param.count_pkts_256_to_511 = frameSizeCounters.count_pkts_256_to_511;
+ param.count_pkts_512_to_1023 = frameSizeCounters.count_pkts_512_to_1023;
+ param.count_pkts_1024_to_1518 = frameSizeCounters.count_pkts_1024_to_1518;
+ param.count_pkts_1519_to_1522 = frameSizeCounters.count_pkts_1519_to_1522;
+
+ if (copy_to_user((ioc_fm_port_mac_frame_size_counters_t *)arg, &param,
+ sizeof(ioc_fm_port_mac_frame_size_counters_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+ case FM_PORT_IOC_GET_BMI_COUNTERS:
+ {
+ t_LnxWrpFmDev *p_LnxWrpFmDev =
+ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ ioc_fm_port_bmi_stats_t param;
+
+ if (!p_LnxWrpFmDev)
+ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!"));
+
+ if (FM_PORT_GetBmiCounters(p_LnxWrpFmPortDev->h_Dev,
+ (t_FmPortBmiStats *)&param))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ if (copy_to_user((ioc_fm_port_bmi_stats_t *)arg, &param,
+ sizeof(ioc_fm_port_bmi_stats_t)))
+ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG);
+
+ break;
+ }
+
+ default:
+ RETURN_ERROR(MINOR, E_INVALID_SELECTION,
+ ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr:0x%02x.\n",
+ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)));
+ }
+
+ if (err)
+ RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM PORT"));
+
+ return E_OK;
+}
+
+/*****************************************************************************/
+/* API routines for the FM Linux Device */
+/*****************************************************************************/
+
+static int fm_open(struct inode *inode, struct file *file)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev = NULL;
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL;
+ unsigned int major = imajor(inode);
+ unsigned int minor = iminor(inode);
+ struct device_node *fm_node;
+ static struct of_device_id fm_node_of_match[] = {
+ { .compatible = "fsl,fman", },
+ { /* end of list */ },
+ };
+
+ DBG(TRACE, ("Opening minor - %d - ", minor));
+
+ if (file->private_data != NULL)
+ return 0;
+
+ /* Get all the FM nodes */
+ for_each_matching_node(fm_node, fm_node_of_match) {
+ struct platform_device *of_dev;
+
+ of_dev = of_find_device_by_node(fm_node);
+ if (unlikely(of_dev == NULL)) {
+ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!"));
+ return -ENXIO;
+ }
+
+ p_LnxWrpFmDev = (t_LnxWrpFmDev *)fm_bind(&of_dev->dev);
+ if (p_LnxWrpFmDev->major == major)
+ break;
+ fm_unbind((struct fm *)p_LnxWrpFmDev);
+ p_LnxWrpFmDev = NULL;
+ }
+
+ if (!p_LnxWrpFmDev)
+ return -ENODEV;
+
+ if (minor == DEV_FM_MINOR_BASE)
+ file->private_data = p_LnxWrpFmDev;
+ else if (minor == DEV_FM_PCD_MINOR_BASE)
+ file->private_data = p_LnxWrpFmDev;
+ else {
+ if (minor == DEV_FM_OH_PORTS_MINOR_BASE)
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort;
+ else if ((minor > DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE))
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->opPorts[minor-DEV_FM_OH_PORTS_MINOR_BASE-1];
+ else if ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE))
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[minor-DEV_FM_RX_PORTS_MINOR_BASE];
+ else if ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))
+ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[minor-DEV_FM_TX_PORTS_MINOR_BASE];
+ else
+ return -EINVAL;
+
+ /* if trying to open port, check if it initialized */
+ if (!p_LnxWrpFmPortDev->h_Dev)
+ return -ENODEV;
+
+ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)fm_port_bind(p_LnxWrpFmPortDev->dev);
+ file->private_data = p_LnxWrpFmPortDev;
+ fm_unbind((struct fm *)p_LnxWrpFmDev);
+ }
+
+ if (file->private_data == NULL)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int fm_close(struct inode *inode, struct file *file)
+{
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+ unsigned int minor = iminor(inode);
+ int err = 0;
+
+ DBG(TRACE, ("Closing minor - %d - ", minor));
+
+ if ((minor == DEV_FM_MINOR_BASE) ||
+ (minor == DEV_FM_PCD_MINOR_BASE))
+ {
+ p_LnxWrpFmDev = (t_LnxWrpFmDev*)file->private_data;
+ if (!p_LnxWrpFmDev)
+ return -ENODEV;
+ fm_unbind((struct fm *)p_LnxWrpFmDev);
+ }
+ else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) ||
+ ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) ||
+ ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)))
+ {
+ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)file->private_data;
+ if (!p_LnxWrpFmPortDev)
+ return -ENODEV;
+ fm_port_unbind((struct fm_port *)p_LnxWrpFmPortDev);
+ }
+
+ return err;
+}
+
+static int fm_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat)
+{
+ DBG(TRACE, ("IOCTL minor - %u, cmd - 0x%08x, arg - 0x%08lx \n", minor, cmd, arg));
+
+ if ((minor == DEV_FM_MINOR_BASE) ||
+ (minor == DEV_FM_PCD_MINOR_BASE))
+ {
+ t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_LnxWrpFmDev*)file->private_data);
+ if (!p_LnxWrpFmDev)
+ return -ENODEV;
+ if (LnxwrpFmIOCTL(p_LnxWrpFmDev, cmd, arg, compat))
+ return -EFAULT;
+ }
+ else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) ||
+ ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) ||
+ ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)))
+ {
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = ((t_LnxWrpFmPortDev*)file->private_data);
+ if (!p_LnxWrpFmPortDev)
+ return -ENODEV;
+ if (LnxwrpFmPortIOCTL(p_LnxWrpFmPortDev, cmd, arg, compat))
+ return -EFAULT;
+ }
+ else
+ {
+ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("minor"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long fm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ long res;
+
+ fm_mutex_lock();
+ res = fm_ioctls(minor, file, cmd, arg, true);
+ fm_mutex_unlock();
+
+ return res;
+}
+#endif
+
+static long fm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ long res;
+
+ fm_mutex_lock();
+ res = fm_ioctls(minor, file, cmd, arg, false);
+ fm_mutex_unlock();
+
+ return res;
+}
+
+/* Globals for FM character device */
+struct file_operations fm_fops =
+{
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = fm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fm_compat_ioctl,
+#endif
+ .open = fm_open,
+ .release = fm_close,
+};
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
new file mode 100644
index 000000000000..d8f4e88a3c7d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c
@@ -0,0 +1,1299 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_fm_compat_ioctls.c
+
+ @Description FM PCD compat functions
+
+*/
+
+#if !defined(CONFIG_COMPAT)
+#error "missing COMPAT layer..."
+#endif
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/errno.h>
+#ifndef CONFIG_FMAN_ARM
+#include <sysdev/fsl_soc.h>
+#endif
+
+#include "part_ext.h"
+#include "fm_ioctls.h"
+#include "fm_pcd_ioctls.h"
+#include "fm_port_ioctls.h"
+#include "lnxwrp_ioctls_fm_compat.h"
+
+#if defined(FM_COMPAT_DBG)
+static void hex_dump(void * p_addr, unsigned int size)
+{
+ int i;
+
+ for(i=0; i<size; i+=16)
+ {
+ printk("%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", p_addr + i,
+ *(unsigned int *)(p_addr + i),
+ *(unsigned int *)(p_addr + i + 4),
+ *(unsigned int *)(p_addr + i + 8),
+ *(unsigned int *)(p_addr + i +12)
+ );
+ }
+}
+#endif
+
+/* maping kernel pointers w/ UserSpace id's { */
+struct map_node {
+ void *ptr;
+ u8 node_type;
+};
+
+static struct map_node compat_ptr2id_array[COMPAT_PTR2ID_ARRAY_MAX] = {{NULL},{FM_MAP_TYPE_UNSPEC}};
+
+void compat_del_ptr2id(void *p, enum fm_map_node_type node_type)
+{
+ compat_uptr_t k;
+
+ _fm_cpt_dbg(COMPAT_GENERIC, "delete (%p)\n", p);
+
+ for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
+ if(compat_ptr2id_array[k].ptr == p){
+ compat_ptr2id_array[k].ptr = NULL;
+ compat_ptr2id_array[k].node_type = FM_MAP_TYPE_UNSPEC;
+ }
+}
+EXPORT_SYMBOL(compat_del_ptr2id);
+
+compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type node_type)
+{
+ compat_uptr_t k;
+
+ _fm_cpt_dbg(COMPAT_GENERIC, " (%p) do ->\n", p);
+
+ if(!p)
+ return 0;
+
+ for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
+ if(compat_ptr2id_array[k].ptr == NULL)
+ {
+ compat_ptr2id_array[k].ptr = p;
+ compat_ptr2id_array[k].node_type = node_type;
+ _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x \n", k | COMPAT_PTR2ID_WATERMARK);
+ return k | COMPAT_PTR2ID_WATERMARK;
+ }
+
+ printk(KERN_WARNING "FMan map list full! No more PCD space on kernel!\n");
+ return 0;
+}
+EXPORT_SYMBOL(compat_add_ptr2id);
+
+compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type node_type)
+{
+ compat_uptr_t k;
+
+ _fm_cpt_dbg(COMPAT_GENERIC, " (%p) get -> \n", p);
+
+ for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++)
+ if(compat_ptr2id_array[k].ptr == p &&
+ compat_ptr2id_array[k].node_type == node_type) {
+
+ _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x\n", k | COMPAT_PTR2ID_WATERMARK);
+ return k | COMPAT_PTR2ID_WATERMARK;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(compat_get_ptr2id);
+
+void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type node_type)
+{
+
+ _fm_cpt_dbg(COMPAT_GENERIC, " (0x%08x) get -> \n", comp);
+
+ if((COMPAT_PTR2ID_WM_MASK & comp) != COMPAT_PTR2ID_WATERMARK) {
+ _fm_cpt_dbg(COMPAT_GENERIC, "Error, invalid watermark (0x%08x)!\n\n", comp);
+ dump_stack();
+ return compat_ptr(comp);
+ }
+
+ comp &= ~COMPAT_PTR2ID_WM_MASK;
+
+ if(((0 < comp) && (comp < COMPAT_PTR2ID_ARRAY_MAX) && (compat_ptr2id_array[comp].ptr != NULL)
+ && compat_ptr2id_array[comp].node_type == node_type)) {
+ _fm_cpt_dbg(COMPAT_GENERIC, "%p\n", compat_ptr2id_array[comp].ptr);
+ return compat_ptr2id_array[comp].ptr;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(compat_get_id2ptr);
+/* } maping kernel pointers w/ UserSpace id's */
+
+void compat_obj_delete(
+ ioc_compat_fm_obj_t *compat_id,
+ ioc_fm_obj_t *id)
+{
+ id->obj = compat_pcd_id2ptr(compat_id->obj);
+ compat_del_ptr2id(id->obj, FM_MAP_TYPE_PCD_NODE);
+}
+
+static inline void compat_copy_fm_pcd_plcr_next_engine(
+ ioc_compat_fm_pcd_plcr_next_engine_params_u *compat_param,
+ ioc_fm_pcd_plcr_next_engine_params_u *param,
+ ioc_fm_pcd_engine next_engine,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ switch (next_engine)
+ {
+ case e_IOC_FM_PCD_PLCR:
+ if (compat == COMPAT_US_TO_K)
+ param->p_profile = compat_pcd_id2ptr(compat_param->p_profile);
+ else
+ compat_param->p_profile = compat_pcd_ptr2id(param->p_profile);
+ break;
+ case e_IOC_FM_PCD_KG:
+ if (compat == COMPAT_US_TO_K)
+ param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme);
+ else
+ compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme);
+ break;
+ default:
+ if (compat == COMPAT_US_TO_K)
+ param->action = compat_param->action;
+ else
+ compat_param->action = param->action;
+ break;
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_pcd_plcr_profile(
+ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param,
+ ioc_fm_pcd_plcr_profile_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->modify = compat_param->modify;
+
+ /* profile_select */
+ if (!compat_param->modify)
+ {
+ param->profile_select.new_params.profile_type =
+ compat_param->profile_select.new_params.profile_type;
+ param->profile_select.new_params.p_fm_port =
+ compat_ptr(compat_param->profile_select.new_params.p_fm_port);
+ param->profile_select.new_params.relative_profile_id =
+ compat_param->profile_select.new_params.relative_profile_id;
+ }
+ else
+ param->profile_select.p_profile =
+ compat_pcd_id2ptr(compat_param->profile_select.p_profile);
+
+ param->alg_selection = compat_param->alg_selection;
+ param->color_mode = compat_param->color_mode;
+
+ /* both parameters in the union has the same size, so memcpy works */
+ memcpy(&param->color, &compat_param->color, sizeof(param->color));
+
+ memcpy(&param->non_passthrough_alg_param,
+ &compat_param->non_passthrough_alg_param,
+ sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t));
+
+ param->next_engine_on_green = compat_param->next_engine_on_green;
+ param->next_engine_on_yellow = compat_param->next_engine_on_yellow;
+ param->next_engine_on_red = compat_param->next_engine_on_red;
+
+ param->trap_profile_on_flow_A = compat_param->trap_profile_on_flow_A;
+ param->trap_profile_on_flow_B = compat_param->trap_profile_on_flow_B;
+ param->trap_profile_on_flow_C = compat_param->trap_profile_on_flow_C;
+ }
+ else
+ {
+ compat_param->modify = param->modify;
+
+ /* profile_select */
+ if (!param->modify)
+ {
+ compat_param->profile_select.new_params.profile_type =
+ param->profile_select.new_params.profile_type;
+ compat_param->profile_select.new_params.p_fm_port =
+ ptr_to_compat(param->profile_select.new_params.p_fm_port);
+ compat_param->profile_select.new_params.relative_profile_id =
+ param->profile_select.new_params.relative_profile_id;
+ }
+ else
+ compat_param->profile_select.p_profile =
+ compat_pcd_ptr2id(param->profile_select.p_profile);
+
+ compat_param->alg_selection = param->alg_selection;
+ compat_param->color_mode = param->color_mode;
+
+ /* both parameters in the union has the same size, so memcpy works */
+ memcpy(&compat_param->color, &param->color, sizeof(compat_param->color));
+
+ memcpy(&compat_param->non_passthrough_alg_param,
+ &param->non_passthrough_alg_param,
+ sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t));
+
+ compat_param->next_engine_on_green = param->next_engine_on_green;
+ compat_param->next_engine_on_yellow = param->next_engine_on_yellow;
+ compat_param->next_engine_on_red = param->next_engine_on_red;
+
+ compat_param->trap_profile_on_flow_A = param->trap_profile_on_flow_A;
+ compat_param->trap_profile_on_flow_B = param->trap_profile_on_flow_B;
+ compat_param->trap_profile_on_flow_C = param->trap_profile_on_flow_C;
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+
+ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_green,
+ &param->params_on_green, param->next_engine_on_green, compat);
+
+ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_yellow,
+ &param->params_on_yellow, param->next_engine_on_yellow, compat);
+
+ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_red,
+ &param->params_on_red, param->next_engine_on_red, compat);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+static inline void compat_copy_fm_pcd_cc_next_kg(
+ ioc_compat_fm_pcd_cc_next_kg_params_t *compat_param,
+ ioc_fm_pcd_cc_next_kg_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->new_fqid = compat_param->new_fqid;
+ param->override_fqid = compat_param->override_fqid;
+#if DPAA_VERSION >= 11
+ param->new_relative_storage_profile_id = compat_param->new_relative_storage_profile_id;
+#endif
+ param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme);
+ }
+ else
+ {
+ compat_param->new_fqid = param->new_fqid;
+ compat_param->override_fqid = param->override_fqid;
+#if DPAA_VERSION >= 11
+ compat_param->new_relative_storage_profile_id = param->new_relative_storage_profile_id;
+#endif
+ compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme);
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+static inline void compat_copy_fm_pcd_cc_next_cc(
+ ioc_compat_fm_pcd_cc_next_cc_params_t *compat_param,
+ ioc_fm_pcd_cc_next_cc_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ param->cc_node_id = compat_pcd_id2ptr(compat_param->cc_node_id);
+ else
+ compat_param->cc_node_id = compat_pcd_ptr2id(param->cc_node_id);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+static inline void compat_copy_fm_pcd_cc_next_engine(
+ ioc_compat_fm_pcd_cc_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_next_engine_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->next_engine = compat_param->next_engine;
+ if (param->next_engine != e_IOC_FM_PCD_INVALID )
+ _fm_cpt_dbg(compat, " param->next_engine = %i \n", param->next_engine);
+
+ switch (param->next_engine)
+ {
+#if DPAA_VERSION >= 11
+ case e_IOC_FM_PCD_FR:
+ param->params.fr_params.frm_replic_id = compat_pcd_id2ptr(compat_param->params.fr_params.frm_replic_id);
+ break;
+#endif /* DPAA_VERSION >= 11 */
+ case e_IOC_FM_PCD_CC:
+ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
+ compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, &param->params.cc_params, compat);
+ break;
+ case e_IOC_FM_PCD_KG:
+ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
+ compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, &param->params.kg_params, compat);
+ break;
+ case e_IOC_FM_PCD_DONE:
+ case e_IOC_FM_PCD_PLCR:
+ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id);
+ /* fall through */
+ default:
+ memcpy(&param->params, &compat_param->params, sizeof(param->params));
+ }
+ param->statistics_en = compat_param->statistics_en;
+ }
+ else
+ {
+ compat_param->next_engine = param->next_engine;
+
+ switch (compat_param->next_engine)
+ {
+#if DPAA_VERSION >= 11
+ case e_IOC_FM_PCD_FR:
+ compat_param->params.fr_params.frm_replic_id = compat_pcd_ptr2id(param->params.fr_params.frm_replic_id);
+ break;
+#endif /* DPAA_VERSION >= 11 */
+ case e_IOC_FM_PCD_CC:
+ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
+ compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, &param->params.cc_params, compat);
+ break;
+ case e_IOC_FM_PCD_KG:
+ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
+ compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, &param->params.kg_params, compat);
+ break;
+ case e_IOC_FM_PCD_DONE:
+ case e_IOC_FM_PCD_PLCR:
+ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id);
+ /* fall through */
+ default:
+ memcpy(&compat_param->params, &param->params, sizeof(compat_param->params));
+ }
+ compat_param->statistics_en = param->statistics_en;
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_pcd_cc_key(
+ ioc_compat_fm_pcd_cc_key_params_t *compat_param,
+ ioc_fm_pcd_cc_key_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->p_key = compat_ptr(compat_param->p_key);
+ param->p_mask = compat_ptr(compat_param->p_mask);
+ }
+ else
+ {
+ compat_param->p_key = ptr_to_compat(param->p_key);
+ compat_param->p_mask = ptr_to_compat(param->p_mask);
+ }
+
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->cc_next_engine_params,
+ &param->cc_next_engine_params,
+ compat);
+}
+
+void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(
+ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ param->key_indx = compat_param->key_indx;
+ param->key_size = compat_param->key_size;
+ compat_copy_fm_pcd_cc_key(
+ &compat_param->key_params,
+ &param->key_params,
+ compat);
+ }
+ else
+ {
+ compat_param->id = compat_pcd_ptr2id(param->id);
+ compat_param->key_indx = param->key_indx;
+ compat_param->key_size = param->key_size;
+ compat_copy_fm_pcd_cc_key(
+ &compat_param->key_params,
+ &param->key_params,
+ compat);
+ }
+}
+
+void compat_copy_fm_pcd_cc_node_modify_next_engine(
+ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ param->key_indx = compat_param->key_indx;
+ param->key_size = compat_param->key_size;
+ }
+ else
+ {
+ compat_param->id = compat_pcd_ptr2id(param->id);
+ compat_param->key_indx = param->key_indx;
+ compat_param->key_size = param->key_size;
+ }
+
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->cc_next_engine_params,
+ &param->cc_next_engine_params,
+ compat);
+}
+
+void compat_fm_pcd_cc_tree_modify_next_engine(
+ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ param->grp_indx = compat_param->grp_indx;
+ param->indx = compat_param->indx;
+ }
+ else
+ {
+ compat_param->id = compat_pcd_ptr2id(param->id);
+ compat_param->grp_indx = param->grp_indx;
+ compat_param->indx = param->indx;
+ }
+
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->cc_next_engine_params,
+ &param->cc_next_engine_params,
+ compat);
+}
+
+void compat_copy_fm_pcd_hash_table(
+ ioc_compat_fm_pcd_hash_table_params_t *compat_param,
+ ioc_fm_pcd_hash_table_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->max_num_of_keys = compat_param->max_num_of_keys;
+ param->statistics_mode = compat_param->statistics_mode;
+ param->kg_hash_shift = compat_param->kg_hash_shift;
+ param->hash_res_mask = compat_param->hash_res_mask;
+ param->hash_shift = compat_param->hash_shift;
+ param->match_key_size = compat_param->match_key_size;
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ }
+ else
+ {
+ compat_param->max_num_of_keys = param->max_num_of_keys;
+ compat_param->statistics_mode = param->statistics_mode;
+ compat_param->kg_hash_shift = param->kg_hash_shift;
+ compat_param->hash_res_mask = param->hash_res_mask;
+ compat_param->hash_shift = param->hash_shift;
+ compat_param->match_key_size = param->match_key_size;
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->cc_next_engine_params_for_miss,
+ &param->cc_next_engine_params_for_miss,
+ compat);
+}
+
+void compat_copy_fm_pcd_cc_grp(
+ ioc_compat_fm_pcd_cc_grp_params_t *compat_param,
+ ioc_fm_pcd_cc_grp_params_t *param,
+ uint8_t compat)
+{
+ int k;
+
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->num_of_distinction_units = compat_param->num_of_distinction_units;
+ memcpy(param->unit_ids, compat_param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS);
+ }
+ else
+ {
+ compat_param->num_of_distinction_units = param->num_of_distinction_units;
+ memcpy(compat_param->unit_ids, param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS);
+ }
+
+ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP; k++)
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->next_engine_per_entries_in_grp[k],
+ &param->next_engine_per_entries_in_grp[k],
+ compat);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_pcd_cc_tree(
+ ioc_compat_fm_pcd_cc_tree_params_t *compat_param,
+ ioc_fm_pcd_cc_tree_params_t *param,
+ uint8_t compat)
+{
+ int k;
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id);
+ param->num_of_groups = compat_param->num_of_groups;
+ }
+ else
+ {
+ compat_param->net_env_id = compat_pcd_ptr2id(param->net_env_id);
+ compat_param->num_of_groups = param->num_of_groups;
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+
+ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++)
+ compat_copy_fm_pcd_cc_grp(
+ &compat_param->fm_pcd_cc_group_params[k],
+ &param->fm_pcd_cc_group_params[k],
+ compat);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_fm_pcd_prs_sw(
+ ioc_compat_fm_pcd_prs_sw_params_t *compat_param,
+ ioc_fm_pcd_prs_sw_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->override = compat_param->override;
+ param->size = compat_param->size;
+ param->base = compat_param->base;
+ param->p_code = compat_ptr(compat_param->p_code);
+ memcpy(param->sw_prs_data_params,compat_param->sw_prs_data_params,IOC_FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t));
+ param->num_of_labels = compat_param->num_of_labels;
+ memcpy(param->labels_table,compat_param->labels_table,IOC_FM_PCD_PRS_NUM_OF_LABELS*sizeof(ioc_fm_pcd_prs_label_params_t));
+ }
+}
+
+void compat_copy_fm_pcd_kg_scheme(
+ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param,
+ ioc_fm_pcd_kg_scheme_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg(compat," {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->modify = compat_param->modify;
+
+ /* scm_id */
+ if (compat_param->modify)
+ {
+ param->scm_id.scheme_id = compat_pcd_id2ptr(compat_param->scm_id.scheme_id);
+ _fm_cpt_dbg(compat," param->scm_id.scheme_id = %p \n", param->scm_id.scheme_id);
+ }
+ else
+ param->scm_id.relative_scheme_id = compat_param->scm_id.relative_scheme_id;
+
+ param->always_direct = compat_param->always_direct;
+ /* net_env_params */
+ param->net_env_params.net_env_id = compat_pcd_id2ptr(compat_param->net_env_params.net_env_id);
+ param->net_env_params.num_of_distinction_units = compat_param->net_env_params.num_of_distinction_units;
+ memcpy(param->net_env_params.unit_ids,
+ compat_param->net_env_params.unit_ids,
+ IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+
+ param->use_hash = compat_param->use_hash;
+ memcpy(&param->key_extract_and_hash_params,
+ &compat_param->key_extract_and_hash_params,
+ sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t));
+ param->bypass_fqid_generation = compat_param->bypass_fqid_generation;
+ param->base_fqid = compat_param->base_fqid;
+#if DPAA_VERSION >= 11
+ param->override_storage_profile =
+ compat_param->override_storage_profile;
+ param->storage_profile = compat_param->storage_profile;
+#endif
+ param->num_of_used_extracted_ors = compat_param->num_of_used_extracted_ors;
+ memcpy(param->extracted_ors,
+ compat_param->extracted_ors,
+ IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t));
+ param->next_engine = compat_param->next_engine;
+
+ /* kg_next_engine_params */
+ if (param->next_engine == e_IOC_FM_PCD_CC)
+ {
+ param->kg_next_engine_params.cc.tree_id = compat_pcd_id2ptr(compat_param->kg_next_engine_params.cc.tree_id);
+ param->kg_next_engine_params.cc.grp_id = compat_param->kg_next_engine_params.cc.grp_id;
+ param->kg_next_engine_params.cc.plcr_next = compat_param->kg_next_engine_params.cc.plcr_next;
+ param->kg_next_engine_params.cc.bypass_plcr_profile_generation
+ = compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation;
+ memcpy(&param->kg_next_engine_params.cc.plcr_profile,
+ &compat_param->kg_next_engine_params.cc.plcr_profile,
+ sizeof(ioc_fm_pcd_kg_plcr_profile_t));
+ }
+ else
+ memcpy(&param->kg_next_engine_params,
+ &compat_param->kg_next_engine_params,
+ sizeof(param->kg_next_engine_params));
+
+ memcpy(&param->scheme_counter,
+ &compat_param->scheme_counter,
+ sizeof(ioc_fm_pcd_kg_scheme_counter_t));
+ }
+ else
+ {
+ compat_param->modify = param->modify;
+
+ /* scm_id */
+ if (param->modify)
+ compat_param->scm_id.scheme_id = compat_pcd_ptr2id(param->scm_id.scheme_id);
+ else
+ compat_param->scm_id.relative_scheme_id = param->scm_id.relative_scheme_id;
+
+ compat_param->always_direct = param->always_direct;
+
+ /* net_env_params */
+ compat_param->net_env_params.net_env_id = compat_pcd_ptr2id(param->net_env_params.net_env_id);
+ compat_param->net_env_params.num_of_distinction_units = param->net_env_params.num_of_distinction_units;
+ memcpy(compat_param->net_env_params.unit_ids, param->net_env_params.unit_ids, IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+
+ compat_param->use_hash = param->use_hash;
+ memcpy(&compat_param->key_extract_and_hash_params, &param->key_extract_and_hash_params, sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t));
+ compat_param->bypass_fqid_generation = param->bypass_fqid_generation;
+ compat_param->base_fqid = param->base_fqid;
+#if DPAA_VERSION >= 11
+ compat_param->override_storage_profile =
+ param->override_storage_profile;
+ compat_param->storage_profile = param->storage_profile;
+#endif
+ compat_param->num_of_used_extracted_ors = param->num_of_used_extracted_ors;
+ memcpy(compat_param->extracted_ors, param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t));
+ compat_param->next_engine = param->next_engine;
+
+ /* kg_next_engine_params */
+ if (compat_param->next_engine == e_IOC_FM_PCD_CC)
+ {
+ compat_param->kg_next_engine_params.cc.tree_id = compat_pcd_ptr2id(param->kg_next_engine_params.cc.tree_id);
+ compat_param->kg_next_engine_params.cc.grp_id = param->kg_next_engine_params.cc.grp_id;
+ compat_param->kg_next_engine_params.cc.plcr_next = param->kg_next_engine_params.cc.plcr_next;
+ compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation
+ = param->kg_next_engine_params.cc.bypass_plcr_profile_generation;
+ memcpy(&compat_param->kg_next_engine_params.cc.plcr_profile,
+ &param->kg_next_engine_params.cc.plcr_profile,
+ sizeof(ioc_fm_pcd_kg_plcr_profile_t));
+ }
+ else
+ memcpy(&param->kg_next_engine_params, &compat_param->kg_next_engine_params, sizeof(compat_param->kg_next_engine_params));
+
+ memcpy(&compat_param->scheme_counter, &param->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t));
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+
+ _fm_cpt_dbg(compat," ...->}\n");
+}
+
+void compat_copy_fm_pcd_kg_scheme_spc(
+ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param,
+ ioc_fm_pcd_kg_scheme_spc_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ param->val = compat_param->val;
+ } else {
+ compat_param->id = compat_pcd_ptr2id(param->id);
+ compat_param->val = param->val;
+ }
+}
+
+
+void compat_copy_fm_pcd_kg_scheme_select(
+ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param,
+ ioc_fm_pcd_kg_scheme_select_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->direct = compat_param->direct;
+ if (param->direct)
+ param->scheme_id = compat_pcd_id2ptr(compat_param->scheme_id);
+ }
+}
+
+void compat_copy_fm_pcd_kg_schemes_params(
+ ioc_compat_fm_pcd_port_schemes_params_t *compat_param,
+ ioc_fm_pcd_port_schemes_params_t *param,
+ uint8_t compat)
+{
+ int k;
+
+ if (compat == COMPAT_US_TO_K) {
+ param->num_of_schemes = compat_param->num_of_schemes;
+ for(k=0; k < compat_param->num_of_schemes; k++)
+ param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]);
+ }
+}
+
+void compat_copy_fm_port_pcd_cc(
+ ioc_compat_fm_port_pcd_cc_params_t *compat_cc_params ,
+ ioc_fm_port_pcd_cc_params_t *p_cc_params,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K){
+ p_cc_params->cc_tree_id = compat_pcd_id2ptr(compat_cc_params->cc_tree_id);
+ }
+}
+
+void compat_copy_fm_port_pcd_kg(
+ ioc_compat_fm_port_pcd_kg_params_t *compat_param,
+ ioc_fm_port_pcd_kg_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K){
+ uint8_t k;
+
+ param->num_of_schemes = compat_param->num_of_schemes;
+ for(k=0; k<compat_param->num_of_schemes; k++)
+ param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]);
+
+ param->direct_scheme = compat_param->direct_scheme;
+ if (param->direct_scheme)
+ param->direct_scheme_id = compat_pcd_id2ptr(compat_param->direct_scheme_id);
+ }
+}
+
+void compat_copy_fm_port_pcd(
+ ioc_compat_fm_port_pcd_params_t *compat_param,
+ ioc_fm_port_pcd_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params;
+ ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params;
+ ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params;
+ ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params;
+
+ same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_param + 1);
+ compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1);
+ compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1);
+ compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1);
+
+ _fm_cpt_dbg(compat,"\n param->p_prs_params=%p \n", param->p_prs_params);
+ _fm_cpt_dbg(compat," param->p_cc_params=%p \n", param->p_cc_params);
+ _fm_cpt_dbg(compat," param->p_kg_params=%p \n", param->p_kg_params);
+ _fm_cpt_dbg(compat," param->p_plcr_params=%p \n", param->p_plcr_params);
+ _fm_cpt_dbg(compat," param->p_ip_reassembly_manip=%p \n", param->p_ip_reassembly_manip);
+#if (DPAA_VERSION >= 11)
+ _fm_cpt_dbg(compat," param->p_capwap_reassembly_manip=%p \n", param->p_capwap_reassembly_manip);
+#endif
+ param->pcd_support = compat_param->pcd_support;
+ param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id);
+
+ if (param->p_cc_params)
+ compat_copy_fm_port_pcd_cc(compat_port_pcd_cc_params, param->p_cc_params, COMPAT_US_TO_K);
+ if (param->p_kg_params)
+ compat_copy_fm_port_pcd_kg(compat_port_pcd_kg_params, param->p_kg_params, COMPAT_US_TO_K);
+ if (param->p_plcr_params)
+ param->p_plcr_params->plcr_profile_id = compat_pcd_id2ptr(compat_port_pcd_plcr_params->plcr_profile_id);
+ param->p_ip_reassembly_manip = compat_pcd_id2ptr(compat_param->p_ip_reassembly_manip);
+#if (DPAA_VERSION >= 11)
+ param->p_capwap_reassembly_manip = compat_pcd_id2ptr(compat_param->p_capwap_reassembly_manip);
+#endif
+ }
+}
+
+void compat_copy_fm_port_pcd_modify_tree(
+ ioc_compat_fm_obj_t *compat_id,
+ ioc_fm_obj_t *id,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ id->obj = compat_pcd_id2ptr(compat_id->obj);
+}
+
+#if (DPAA_VERSION >= 11)
+void compat_copy_fm_port_vsp_alloc_params(
+ ioc_compat_fm_port_vsp_alloc_params_t *compat_param,
+ ioc_fm_port_vsp_alloc_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ _fm_cpt_dbg(compat," param->p_fm_tx_port=%p \n", param->p_fm_tx_port);
+
+ param->dflt_relative_id = compat_param->dflt_relative_id;
+ param->num_of_profiles = compat_param->num_of_profiles;
+ param->p_fm_tx_port = compat_pcd_id2ptr(compat_param->p_fm_tx_port);
+ }
+}
+#endif /* (DPAA_VERSION >= 11) */
+
+void compat_copy_fm_pcd_cc_tbl_get_stats(
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param,
+ ioc_fm_pcd_cc_tbl_get_stats_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ param->key_index = compat_param->key_index;
+ memcpy(&param->statistics, &compat_param->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t));
+ } else {
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ compat_param->key_index = param->key_index;
+ memcpy(&compat_param->statistics, &param->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t));
+ }
+}
+
+
+void compat_copy_fm_pcd_net_env(
+ ioc_compat_fm_pcd_net_env_params_t *compat_param,
+ ioc_fm_pcd_net_env_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->num_of_distinction_units = compat_param->num_of_distinction_units;
+ memcpy(param->units, compat_param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+ param->id = NULL; /* to avoid passing garbage to the kernel */
+ }
+ else
+ {
+ compat_param->num_of_distinction_units = param->num_of_distinction_units;
+ memcpy(compat_param->units, param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS);
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+}
+
+void compat_copy_fm_pcd_cc_node_modify_key(
+ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_key_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->key_indx = compat_param->key_indx;
+ param->key_size = compat_param->key_size;
+ param->p_key = (uint8_t *)compat_ptr(compat_param->p_key);
+ _fm_cpt_dbg(compat," param->p_key = %p \n", param->p_key);
+ param->p_mask = (uint8_t *)compat_ptr(compat_param->p_mask);
+ _fm_cpt_dbg(compat," param->p_mask = %p\n", param->p_mask);
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ _fm_cpt_dbg(compat," param->id = %p \n", param->id);
+ }
+ else
+ {
+ compat_param->key_indx = param->key_indx;
+ compat_param->key_size = param->key_size;
+ compat_param->p_key = ptr_to_compat((void *)param->p_key);
+ compat_param->p_mask = ptr_to_compat((void *)param->p_mask);
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+}
+
+void compat_copy_keys(
+ ioc_compat_keys_params_t *compat_param,
+ ioc_keys_params_t *param,
+ uint8_t compat)
+{
+ int k = 0;
+
+ _fm_cpt_dbg(compat," {->...\n");
+
+ if (compat == COMPAT_US_TO_K) {
+ param->max_num_of_keys = compat_param->max_num_of_keys;
+ param->mask_support = compat_param->mask_support;
+ param->statistics_mode = compat_param->statistics_mode;
+ param->num_of_keys = compat_param->num_of_keys;
+ param->key_size = compat_param->key_size;
+#if (DPAA_VERSION >= 11)
+ memcpy(&param->frame_length_ranges,
+ &compat_param->frame_length_ranges,
+ sizeof(param->frame_length_ranges[0]) *
+ IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR);
+#endif /* (DPAA_VERSION >= 11) */
+ }
+ else {
+ compat_param->max_num_of_keys = param->max_num_of_keys;
+ compat_param->mask_support = param->mask_support;
+ compat_param->statistics_mode = param->statistics_mode;
+ compat_param->num_of_keys = param->num_of_keys;
+ compat_param->key_size = param->key_size;
+#if (DPAA_VERSION >= 11)
+ memcpy(&compat_param->frame_length_ranges,
+ &param->frame_length_ranges,
+ sizeof(compat_param->frame_length_ranges[0]) *
+ IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR);
+#endif /* (DPAA_VERSION >= 11) */
+ }
+
+ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_KEYS; k++)
+ compat_copy_fm_pcd_cc_key(
+ &compat_param->key_params[k],
+ &param->key_params[k],
+ compat);
+
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->cc_next_engine_params_for_miss,
+ &param->cc_next_engine_params_for_miss,
+ compat);
+
+ _fm_cpt_dbg(compat," ...->}\n");
+}
+
+void compat_copy_fm_pcd_cc_node(
+ ioc_compat_fm_pcd_cc_node_params_t *compat_param,
+ ioc_fm_pcd_cc_node_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg(compat," {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ memcpy(&param->extract_cc_params, &compat_param->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t));
+
+ else
+ {
+ compat_copy_keys(&compat_param->keys_params, &param->keys_params, compat);
+
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ _fm_cpt_dbg(compat," param->id = %p \n", param->id);
+ }
+
+ compat_copy_keys(&compat_param->keys_params, &param->keys_params, compat);
+
+ _fm_cpt_dbg(compat," ...->}\n");
+}
+
+void compat_fm_pcd_manip_set_node(
+ ioc_compat_fm_pcd_manip_params_t *compat_param,
+ ioc_fm_pcd_manip_params_t *param,
+ uint8_t compat)
+{
+ if (compat == COMPAT_US_TO_K) {
+ param->type = compat_param->type;
+ switch (param->type) {
+ case e_IOC_FM_PCD_MANIP_HDR:
+ param->u.hdr.rmv = compat_param->u.hdr.rmv;
+ memcpy(&param->u.hdr.rmv_params,
+ &compat_param->u.hdr.rmv_params,
+ sizeof(param->u.hdr.rmv_params));
+
+ param->u.hdr.insrt = compat_param->u.hdr.insrt;
+ param->u.hdr.insrt_params.type =
+ compat_param->u.hdr.insrt_params.type;
+ switch (compat_param->u.hdr.insrt_params.type)
+ {
+ case e_IOC_FM_PCD_MANIP_INSRT_GENERIC:
+ param->u.hdr.insrt_params.u.generic.offset =
+ compat_param->u.hdr.insrt_params.u.generic.offset;
+ param->u.hdr.insrt_params.u.generic.size =
+ compat_param->u.hdr.insrt_params.u.generic.size;
+ param->u.hdr.insrt_params.u.generic.replace =
+ compat_param->u.hdr.insrt_params.u.generic.replace;
+ param->u.hdr.insrt_params.u.generic.p_data =
+ compat_ptr(compat_param->u.hdr.insrt_params.u.generic.p_data);
+ break;
+ case e_IOC_FM_PCD_MANIP_INSRT_BY_HDR:
+ param->u.hdr.insrt_params.u.by_hdr.type =
+ compat_param->u.hdr.insrt_params.u.by_hdr.type;
+ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2 =
+ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2;
+ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update =
+ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update;
+ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size =
+ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size;
+ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data =
+ compat_ptr(compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data);
+ break;
+ default:
+ _fm_cpt_err("Unsupported type: %d", compat_param->u.hdr.insrt_params.type);
+ }
+
+ param->u.hdr.field_update = compat_param->u.hdr.field_update;
+ memcpy(&param->u.hdr.field_update_params,
+ &compat_param->u.hdr.field_update_params,
+ sizeof(param->u.hdr.field_update_params));
+
+ param->u.hdr.custom = compat_param->u.hdr.custom;
+ memcpy(&param->u.hdr.custom_params,
+ &compat_param->u.hdr.custom_params,
+ sizeof(param->u.hdr.custom_params));
+
+ param->u.hdr.dont_parse_after_manip =
+ compat_param->u.hdr.dont_parse_after_manip;
+ break;
+ case e_IOC_FM_PCD_MANIP_REASSEM:
+ memcpy(&param->u.reassem, &compat_param->u.reassem, sizeof(param->u.reassem));
+ break;
+ case e_IOC_FM_PCD_MANIP_FRAG:
+ memcpy(&param->u.frag, &compat_param->u.frag, sizeof(param->u.frag));
+ break;
+ case e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD:
+ memcpy(&param->u.special_offload,
+ &compat_param->u.special_offload,
+ sizeof(param->u.special_offload));
+ break;
+ }
+
+ param->p_next_manip = compat_pcd_id2ptr(compat_param->p_next_manip);
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ }
+ else {
+ compat_param->type = param->type;
+ memcpy(&compat_param->u, &param->u, sizeof(compat_param->u));
+
+ if (param->type == e_IOC_FM_PCD_MANIP_HDR &&
+ param->u.hdr.insrt_params.type == e_IOC_FM_PCD_MANIP_INSRT_GENERIC)
+ compat_param->u.hdr.insrt_params.u.generic.p_data =
+ ptr_to_compat(param->u.hdr.insrt_params.u.generic.p_data);
+
+ compat_param->p_next_manip = compat_pcd_ptr2id(param->id);
+ /* ... should be one that was added previously by the very call to
+ compat_add_ptr2id() below: */
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+}
+
+void compat_copy_fm_pcd_manip_get_stats(
+ ioc_compat_fm_pcd_manip_get_stats_t *compat_param,
+ ioc_fm_pcd_manip_get_stats_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ memcpy(&param->stats, &compat_param->stats,
+ sizeof(ioc_fm_pcd_manip_stats_t));
+ }
+ else
+ {
+ compat_param->id = compat_add_ptr2id(param->id,
+ FM_MAP_TYPE_PCD_NODE);
+ memcpy(&compat_param->stats, &param->stats,
+ sizeof(ioc_fm_pcd_manip_stats_t));
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+#if (DPAA_VERSION >= 11)
+void compat_copy_fm_pcd_frm_replic_group_params(
+ ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param,
+ ioc_fm_pcd_frm_replic_group_params_t *param,
+ uint8_t compat)
+{
+ int k;
+
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->max_num_of_entries = compat_param->max_num_of_entries;
+ param->num_of_entries = compat_param->num_of_entries;
+ param->id = compat_pcd_id2ptr(compat_param->id);
+ }
+ else
+ {
+ compat_param->max_num_of_entries = param->max_num_of_entries;
+ compat_param->num_of_entries = param->num_of_entries;
+ compat_param->id = compat_add_ptr2id(param->id,
+ FM_MAP_TYPE_PCD_NODE);
+ }
+
+ for (k=0; k < IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES; k++)
+ compat_copy_fm_pcd_cc_next_engine(
+ &compat_param->next_engine_params[k],
+ &param->next_engine_params[k],
+ compat);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_pcd_frm_replic_member(
+ ioc_compat_fm_pcd_frm_replic_member_t *compat_param,
+ ioc_fm_pcd_frm_replic_member_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->h_replic_group = compat_pcd_id2ptr(compat_param->h_replic_group);
+ param->member_index = compat_param->member_index;
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_pcd_frm_replic_member_params(
+ ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param,
+ ioc_fm_pcd_frm_replic_member_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ compat_copy_fm_pcd_frm_replic_member(&compat_param->member,
+ &param->member, compat);
+
+ compat_copy_fm_pcd_cc_next_engine(&compat_param->next_engine_params,
+ &param->next_engine_params, compat);
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_vsp_params(
+ ioc_compat_fm_vsp_params_t *compat_param,
+ ioc_fm_vsp_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ memcpy(&param->ext_buf_pools, &compat_param->ext_buf_pools, sizeof(ioc_fm_ext_pools));
+ param->liodn_offset = compat_param->liodn_offset;
+ param->port_params.port_id = compat_param->port_params.port_id;
+ param->port_params.port_type = compat_param->port_params.port_type;
+ param->relative_profile_id = compat_param->relative_profile_id;
+ }
+ else
+ {
+ memcpy(&compat_param->ext_buf_pools, &param->ext_buf_pools, sizeof(ioc_fm_ext_pools));
+ compat_param->liodn_offset = param->liodn_offset;
+ compat_param->port_params.port_id = param->port_params.port_id;
+ compat_param->port_params.port_type = param->port_params.port_type;
+ compat_param->relative_profile_id = param->relative_profile_id;
+ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE);
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_buf_pool_depletion_params(
+ ioc_compat_fm_buf_pool_depletion_params_t *compat_param,
+ ioc_fm_buf_pool_depletion_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
+ memcpy(&param->fm_buf_pool_depletion,
+ &compat_param->fm_buf_pool_depletion,
+ sizeof(ioc_fm_buf_pool_depletion_t));
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_buffer_prefix_content_params(
+ ioc_compat_fm_buffer_prefix_content_params_t *compat_param,
+ ioc_fm_buffer_prefix_content_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
+ memcpy(&param->fm_buffer_prefix_content,
+ &compat_param->fm_buffer_prefix_content,
+ sizeof(ioc_fm_buffer_prefix_content_t));
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_vsp_config_no_sg_params(
+ ioc_compat_fm_vsp_config_no_sg_params_t *compat_param,
+ ioc_fm_vsp_config_no_sg_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
+ param->no_sg = compat_param->no_sg;
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+
+void compat_copy_fm_vsp_prs_result_params(
+ ioc_compat_fm_vsp_prs_result_params_t *compat_param,
+ ioc_fm_vsp_prs_result_params_t *param,
+ uint8_t compat)
+{
+ _fm_cpt_dbg (compat, " {->...\n");
+
+ if (compat == COMPAT_US_TO_K)
+ {
+ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp);
+ /* p_data is an user-space pointer that needs to remain unmodified */
+ param->p_data = (void *)(unsigned long long)compat_param->p_data;
+ }
+ else
+ {
+ compat_param->p_fm_vsp = compat_pcd_ptr2id(param->p_fm_vsp);
+ /* p_data is an user-space pointer that needs to remain unmodified */
+ compat_param->p_data = (compat_uptr_t)((unsigned long long)param->p_data & 0xFFFFFFFF);
+ }
+
+ _fm_cpt_dbg (compat, " ...->}\n");
+}
+#endif /* (DPAA_VERSION >= 11) */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h
new file mode 100644
index 000000000000..187011f7ee5a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h
@@ -0,0 +1,755 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_ioctls_fm_compat.h
+
+ @Description FM PCD compat structures definition.
+
+*/
+
+#ifndef __FM_COMPAT_IOCTLS_H
+#define __FM_COMPAT_IOCTLS_H
+
+#include <linux/compat.h>
+
+#define COMPAT_K_TO_US 0 /* copy from Kernel to User */
+#define COMPAT_US_TO_K 1 /* copy from User to Kernel */
+#define COMPAT_GENERIC 2
+
+#define COMPAT_COPY_K2US(dest, src, type) compat_copy_##type(src, dest, 0)
+#define COMPAT_COPY_US2K(dest, src, type) compat_copy_##type(dest, src, 1)
+
+/* mapping kernel pointers w/ UserSpace id's { */
+/* Because compat_ptr(ptr_to_compat(X)) != X, this way we cannot exchange pointers
+ back and forth (US - KS). compat_ptr is a cast and pointers are broken. */
+#define COMPAT_PTR2ID_ARRAY_MAX (512+1) /* first location is not used */
+#define COMPAT_PTR2ID_WATERMARK 0xface0000
+#define COMPAT_PTR2ID_WM_MASK 0xffff0000
+
+/* define it for debug trace */
+/*#define FM_COMPAT_DBG*/
+
+#define _fm_cpt_prk(stage, format, arg...) \
+ printk(stage "fm_cpt (cpu:%u): " format, raw_smp_processor_id(), ##arg)
+
+#define _fm_cpt_inf(format, arg...) _fm_cpt_prk(KERN_INFO, format, ##arg)
+#define _fm_cpt_wrn(format, arg...) _fm_cpt_prk(KERN_WARNING, format, ##arg)
+#define _fm_cpt_err(format, arg...) _fm_cpt_prk(KERN_ERR, format, ##arg)
+
+/* used for compat IOCTL debugging */
+#if defined(FM_COMPAT_DBG)
+ #define _fm_cpt_dbg(from, format, arg...) \
+ do{ \
+ if (from == COMPAT_US_TO_K) \
+ printk("fm_cpt to KS [%s:%u](cpu:%u) - " format, \
+ __func__, __LINE__, raw_smp_processor_id(), ##arg); \
+ else if (from == COMPAT_K_TO_US) \
+ printk("fm_cpt to US [%s:%u](cpu:%u) - " format, \
+ __func__, __LINE__, raw_smp_processor_id(), ##arg); \
+ else \
+ printk("fm_cpt [%s:%u](cpu:%u) - " format, \
+ __func__, __LINE__, raw_smp_processor_id(), ##arg); \
+ }while(0)
+#else
+# define _fm_cpt_dbg(arg...)
+#endif
+
+/*TODO: per FMan module:
+ *
+ * Parser: FM_MAP_TYPE_PARSER_NODE,
+ * Kg: FM_MAP_TYPE_KG_NODE,
+ * Policer: FM_MAP_TYPE_POLICER_NODE
+ * Manip: FM_MAP_TYPE_MANIP_NODE
+ **/
+enum fm_map_node_type {
+ FM_MAP_TYPE_UNSPEC = 0,
+ FM_MAP_TYPE_PCD_NODE,
+
+ /* add types here, update the policy */
+
+ __FM_MAP_TYPE_AFTER_LAST,
+ FM_MAP_TYPE_MAX = __FM_MAP_TYPE_AFTER_LAST - 1
+};
+
+void compat_del_ptr2id(void *p, enum fm_map_node_type);
+compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type);
+compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type);
+void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type);
+
+static inline compat_uptr_t compat_pcd_ptr2id(void *ptr) {
+ return (ptr)? compat_get_ptr2id(ptr, FM_MAP_TYPE_PCD_NODE)
+ : (compat_uptr_t) 0;
+}
+
+static inline void *compat_pcd_id2ptr(compat_uptr_t id) {
+ return (id) ? compat_get_id2ptr(id, FM_MAP_TYPE_PCD_NODE)
+ : NULL;
+}
+
+/* other similar inlines may be added as new nodes are added
+ to enum fm_map_node_type above... */
+/* } mapping kernel pointers w/ UserSpace id's */
+
+/* pcd compat structures { */
+typedef struct ioc_compat_fm_pcd_cc_node_remove_key_params_t {
+ compat_uptr_t id;
+ uint16_t key_indx;
+} ioc_compat_fm_pcd_cc_node_remove_key_params_t;
+
+typedef union ioc_compat_fm_pcd_plcr_next_engine_params_u {
+ ioc_fm_pcd_done_action action;
+ compat_uptr_t p_profile;
+ compat_uptr_t p_direct_scheme;
+} ioc_compat_fm_pcd_plcr_next_engine_params_u;
+
+typedef struct ioc_compat_fm_pcd_plcr_profile_params_t {
+ bool modify;
+ union {
+ struct {
+ ioc_fm_pcd_profile_type_selection profile_type;
+ compat_uptr_t p_fm_port;
+ uint16_t relative_profile_id;
+ } new_params;
+ compat_uptr_t p_profile;
+ } profile_select;
+ ioc_fm_pcd_plcr_algorithm_selection alg_selection;
+ ioc_fm_pcd_plcr_color_mode color_mode;
+
+ union {
+ ioc_fm_pcd_plcr_color dflt_color;
+ ioc_fm_pcd_plcr_color override;
+ } color;
+
+ ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param;
+
+ ioc_fm_pcd_engine next_engine_on_green;
+ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_green;
+
+ ioc_fm_pcd_engine next_engine_on_yellow;
+ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_yellow;
+
+ ioc_fm_pcd_engine next_engine_on_red;
+ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_red;
+
+ bool trap_profile_on_flow_A;
+ bool trap_profile_on_flow_B;
+ bool trap_profile_on_flow_C;
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_plcr_profile_params_t;
+
+typedef struct ioc_compat_fm_obj_t {
+ compat_uptr_t obj;
+} ioc_compat_fm_obj_t;
+
+typedef struct ioc_compat_fm_pcd_kg_scheme_select_t {
+ bool direct;
+ compat_uptr_t scheme_id;
+} ioc_compat_fm_pcd_kg_scheme_select_t;
+
+typedef struct ioc_compat_fm_pcd_port_schemes_params_t {
+ uint8_t num_of_schemes;
+ compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];
+} ioc_compat_fm_pcd_port_schemes_params_t;
+
+#if (DPAA_VERSION >= 11)
+typedef struct ioc_compat_fm_port_vsp_alloc_params_t {
+ uint8_t num_of_profiles; /**< Number of Virtual Storage Profiles */
+ uint8_t dflt_relative_id; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port
+ The same default Virtual-Storage-Profile-id will be for coupled Tx port
+ if relevant function called for Rx port */
+ compat_uptr_t p_fm_tx_port; /**< Handle to coupled Tx Port; not relevant for OP port. */
+}ioc_compat_fm_port_vsp_alloc_params_t;
+#endif /* (DPAA_VERSION >= 11) */
+
+typedef struct ioc_compat_fm_pcd_net_env_params_t {
+ uint8_t num_of_distinction_units;
+ ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* same structure*/
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_net_env_params_t;
+
+typedef struct ioc_compat_fm_pcd_prs_sw_params_t {
+ bool override;
+ uint32_t size;
+ uint16_t base;
+ compat_uptr_t p_code;
+ uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS];
+ uint8_t num_of_labels;
+ ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS];
+} ioc_compat_fm_pcd_prs_sw_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_next_kg_params_t {
+ bool override_fqid;
+ uint32_t new_fqid;
+#if DPAA_VERSION >= 11
+ uint8_t new_relative_storage_profile_id;
+#endif
+ compat_uptr_t p_direct_scheme;
+} ioc_compat_fm_pcd_cc_next_kg_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_next_cc_params_t {
+ compat_uptr_t cc_node_id;
+} ioc_compat_fm_pcd_cc_next_cc_params_t;
+
+#if DPAA_VERSION >= 11
+typedef struct ioc_compat_fm_pcd_cc_next_fr_params_t {
+ compat_uptr_t frm_replic_id;
+} ioc_compat_fm_pcd_cc_next_fr_params_t;
+#endif /* DPAA_VERSION >= 11 */
+
+typedef struct ioc_compat_fm_pcd_cc_next_engine_params_t {
+ ioc_fm_pcd_engine next_engine;
+ union {
+ ioc_compat_fm_pcd_cc_next_cc_params_t cc_params; /**< compat structure*/
+ ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< same structure*/
+ ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< same structure*/
+ ioc_compat_fm_pcd_cc_next_kg_params_t kg_params; /**< compat structure*/
+#if DPAA_VERSION >= 11
+ ioc_compat_fm_pcd_cc_next_fr_params_t fr_params; /**< compat structure*/
+#endif /* DPAA_VERSION >= 11 */
+ } params;
+ compat_uptr_t manip_id;
+ bool statistics_en;
+} ioc_compat_fm_pcd_cc_next_engine_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_grp_params_t {
+ uint8_t num_of_distinction_units;
+ uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS];
+ ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP];
+} ioc_compat_fm_pcd_cc_grp_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_tree_params_t {
+ compat_uptr_t net_env_id;
+ uint8_t num_of_groups;
+ ioc_compat_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS];
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_cc_tree_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t {
+ compat_uptr_t id;
+ uint8_t grp_indx;
+ uint8_t indx;
+ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params;
+} ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_key_params_t {
+ compat_uptr_t p_key;
+ compat_uptr_t p_mask;
+ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; /**< compat structure*/
+} ioc_compat_fm_pcd_cc_key_params_t;
+
+typedef struct ioc_compat_keys_params_t {
+ uint16_t max_num_of_keys;
+ bool mask_support;
+ ioc_fm_pcd_cc_stats_mode statistics_mode;
+#if (DPAA_VERSION >= 11)
+ uint16_t frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR];
+#endif /* (DPAA_VERSION >= 11) */
+ uint16_t num_of_keys;
+ uint8_t key_size;
+ ioc_compat_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; /**< compat structure*/
+ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; /**< compat structure*/
+} ioc_compat_keys_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_node_params_t {
+ ioc_fm_pcd_extract_entry_t extract_cc_params; /**< same structure*/
+ ioc_compat_keys_params_t keys_params; /**< compat structure*/
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_cc_node_params_t;
+
+/**************************************************************************//**
+ @Description Parameters for defining a hash table
+*//***************************************************************************/
+typedef struct ioc_compat_fm_pcd_hash_table_params_t {
+ uint16_t max_num_of_keys;
+ ioc_fm_pcd_cc_stats_mode statistics_mode;
+ uint8_t kg_hash_shift;
+ uint16_t hash_res_mask;
+ uint8_t hash_shift;
+ uint8_t match_key_size;
+ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss;
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_hash_table_params_t;
+
+typedef struct ioc_compat_fm_pcd_hash_table_add_key_params_t {
+ compat_uptr_t p_hash_tbl;
+ uint8_t key_size;
+ ioc_compat_fm_pcd_cc_key_params_t key_params;
+} ioc_compat_fm_pcd_hash_table_add_key_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_node_modify_key_params_t {
+ compat_uptr_t id;
+ uint16_t key_indx;
+ uint8_t key_size;
+ compat_uptr_t p_key;
+ compat_uptr_t p_mask;
+} ioc_compat_fm_pcd_cc_node_modify_key_params_t;
+
+typedef struct ioc_compat_fm_pcd_hash_table_remove_key_params_t {
+ compat_uptr_t p_hash_tbl;
+ uint8_t key_size;
+ compat_uptr_t p_key;
+} ioc_compat_fm_pcd_hash_table_remove_key_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t {
+ compat_uptr_t id;
+ uint16_t key_indx;
+ uint8_t key_size;
+ ioc_compat_fm_pcd_cc_key_params_t key_params;
+} ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t;
+
+typedef struct ioc_compat_fm_port_pcd_plcr_params_t {
+ compat_uptr_t plcr_profile_id;
+} ioc_compat_fm_port_pcd_plcr_params_t;
+
+typedef struct ioc_compat_fm_port_pcd_cc_params_t {
+ compat_uptr_t cc_tree_id;
+} ioc_compat_fm_port_pcd_cc_params_t;
+
+typedef struct ioc_compat_fm_port_pcd_kg_params_t {
+ uint8_t num_of_schemes;
+ compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES];
+ bool direct_scheme;
+ compat_uptr_t direct_scheme_id;
+} ioc_compat_fm_port_pcd_kg_params_t;
+
+typedef struct ioc_compat_fm_port_pcd_params_t {
+ ioc_fm_port_pcd_support pcd_support;
+ compat_uptr_t net_env_id;
+ compat_uptr_t p_prs_params;
+ compat_uptr_t p_cc_params;
+ compat_uptr_t p_kg_params;
+ compat_uptr_t p_plcr_params;
+ compat_uptr_t p_ip_reassembly_manip;
+#if DPAA_VERSION >= 11
+ compat_uptr_t p_capwap_reassembly_manip;
+#endif
+} ioc_compat_fm_port_pcd_params_t;
+
+typedef struct ioc_compat_fm_pcd_kg_cc_t {
+ compat_uptr_t tree_id;
+ uint8_t grp_id;
+ bool plcr_next;
+ bool bypass_plcr_profile_generation;
+ ioc_fm_pcd_kg_plcr_profile_t plcr_profile;
+} ioc_compat_fm_pcd_kg_cc_t;
+
+typedef struct ioc_compat_fm_pcd_kg_scheme_params_t {
+ bool modify;
+ union {
+ uint8_t relative_scheme_id;
+ compat_uptr_t scheme_id;
+ } scm_id;
+ bool always_direct;
+ struct {
+ compat_uptr_t net_env_id;
+ uint8_t num_of_distinction_units;
+ uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS];
+ } net_env_params;
+ bool use_hash;
+ ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params;
+ bool bypass_fqid_generation;
+ uint32_t base_fqid;
+ uint8_t num_of_used_extracted_ors;
+ ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS];
+#if DPAA_VERSION >= 11
+ bool override_storage_profile;
+ ioc_fm_pcd_kg_storage_profile_t storage_profile;
+#endif /* DPAA_VERSION >= 11 */
+ ioc_fm_pcd_engine next_engine;
+ union{
+ ioc_fm_pcd_done_action done_action;
+ ioc_fm_pcd_kg_plcr_profile_t plcr_profile;
+ ioc_compat_fm_pcd_kg_cc_t cc;
+ } kg_next_engine_params;
+ ioc_fm_pcd_kg_scheme_counter_t scheme_counter;
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_kg_scheme_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t {
+ compat_uptr_t id;
+ uint16_t key_indx;
+ uint8_t key_size;
+ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params;
+} ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t {
+ uint8_t offset;
+ uint8_t size;
+ bool replace;
+ compat_uptr_t p_data;
+} ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t {
+ ioc_fm_pcd_manip_hdr_insrt_specific_l2 specific_l2;
+ bool update;
+ uint8_t size;
+ compat_uptr_t p_data;
+} ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_t {
+ uint8_t size; /**< size of inserted section */
+ compat_uptr_t p_data; /**< data to be inserted */
+} ioc_compat_fm_pcd_manip_hdr_insrt_t;
+
+#if (DPAA_VERSION >= 11)
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t {
+ bool calc_l4_checksum; /**< Calculate L4 checksum. */
+ ioc_fm_pcd_manip_hdr_qos_mapping_mode mapping_mode; /**< TODO */
+ uint8_t last_pid_offset; /**< the offset of the last Protocol within
+ the inserted header */
+ uint16_t id; /**< 16 bit New IP ID */
+ bool dont_frag_overwrite;
+ /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte.
+ * This byte is configured to be overwritten when RPD is set. */
+ uint8_t last_dst_offset;
+ /**< IPv6 only. if routing extension exist, user should set the offset of the destination address
+ * in order to calculate UDP checksum pseudo header;
+ * Otherwise set it to '0'. */
+ ioc_compat_fm_pcd_manip_hdr_insrt_t insrt; /**< size and data to be inserted. */
+} ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t;
+#endif /* (DPAA_VERSION >= 11) */
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t {
+ ioc_fm_pcd_manip_hdr_insrt_by_hdr_type type;
+ union {
+ ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t specific_l2_params;
+#if (DPAA_VERSION >= 11)
+ ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t ip_params;
+ ioc_compat_fm_pcd_manip_hdr_insrt_t insrt;
+#endif /* (DPAA_VERSION >= 11) */
+ } u;
+} ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_params_t {
+ ioc_fm_pcd_manip_hdr_insrt_type type;
+ union {
+ ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t by_hdr;
+ ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t generic;
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+#error "FM_CAPWAP_SUPPORT feature not supported!"
+ ioc_fm_pcd_manip_hdr_insrt_by_template_params_t by_template;
+#endif /* FM_CAPWAP_SUPPORT */
+ } u;
+} ioc_compat_fm_pcd_manip_hdr_insrt_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_hdr_params_t {
+ bool rmv;
+ ioc_fm_pcd_manip_hdr_rmv_params_t rmv_params;
+ bool insrt;
+ ioc_compat_fm_pcd_manip_hdr_insrt_params_t insrt_params;
+ bool field_update;
+ ioc_fm_pcd_manip_hdr_field_update_params_t field_update_params;
+ bool custom;
+ ioc_fm_pcd_manip_hdr_custom_params_t custom_params;
+ bool dont_parse_after_manip;
+} ioc_compat_fm_pcd_manip_hdr_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_special_offload_params_t {
+ bool decryption;
+ bool ecn_copy;
+ bool dscp_copy;
+ bool variable_ip_hdr_len;
+ bool variable_ip_version;
+ uint8_t outer_ip_hdr_len;
+ uint16_t arw_size;
+ compat_uptr_t arw_addr;
+} ioc_compat_fm_pcd_manip_special_offload_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_params_t {
+ ioc_fm_pcd_manip_type type;
+ union {
+ ioc_compat_fm_pcd_manip_hdr_params_t hdr;
+ ioc_fm_pcd_manip_reassem_params_t reassem;
+ ioc_fm_pcd_manip_frag_params_t frag;
+ ioc_compat_fm_pcd_manip_special_offload_params_t special_offload;
+ } u;
+ compat_uptr_t p_next_manip;
+#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))
+#error "FM_CAPWAP_SUPPORT feature not supported!"
+ bool frag_or_reasm;
+ ioc_fm_pcd_manip_frag_or_reasm_params_t frag_or_reasm_params;
+#endif /* FM_CAPWAP_SUPPORT */
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_manip_params_t;
+
+typedef struct ioc_compat_fm_pcd_manip_get_stats_t {
+ compat_uptr_t id;
+ ioc_fm_pcd_manip_stats_t stats;
+} ioc_compat_fm_pcd_manip_get_stats_t;
+
+#if (DPAA_VERSION >= 11)
+typedef struct ioc_compat_fm_pcd_frm_replic_group_params_t {
+ uint8_t max_num_of_entries;
+ uint8_t num_of_entries;
+ ioc_compat_fm_pcd_cc_next_engine_params_t
+ next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES];
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_frm_replic_group_params_t;
+
+typedef struct ioc_compat_fm_pcd_frm_replic_member_t {
+ compat_uptr_t h_replic_group;
+ uint16_t member_index;
+} ioc_compat_fm_pcd_frm_replic_member_t;
+
+typedef struct ioc_compat_fm_pcd_frm_replic_member_params_t {
+ ioc_compat_fm_pcd_frm_replic_member_t member;
+ ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_params;
+} ioc_compat_fm_pcd_frm_replic_member_params_t;
+
+typedef struct ioc_compat_fm_vsp_params_t {
+ compat_uptr_t p_fm; /**< A handle to the FM object this VSP related to */
+ ioc_fm_ext_pools ext_buf_pools; /**< Which external buffer pools are used
+ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes.
+ parameter associated with Rx / OP port */
+ uint16_t liodn_offset; /**< VSP's LIODN offset */
+ struct {
+ ioc_fm_port_type port_type; /**< Port type */
+ uint8_t port_id; /**< Port Id - relative to type */
+ } port_params;
+ uint8_t relative_profile_id; /**< VSP Id - relative to VSP's range
+ defined in relevant FM object */
+ compat_uptr_t id; /**< return value */
+} ioc_compat_fm_vsp_params_t;
+
+typedef struct ioc_compat_fm_buf_pool_depletion_params_t {
+ compat_uptr_t p_fm_vsp;
+ ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion;
+} ioc_compat_fm_buf_pool_depletion_params_t;
+
+typedef struct ioc_compat_fm_buffer_prefix_content_params_t {
+ compat_uptr_t p_fm_vsp;
+ ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content;
+} ioc_compat_fm_buffer_prefix_content_params_t;
+
+typedef struct ioc_compat_fm_vsp_config_no_sg_params_t {
+ compat_uptr_t p_fm_vsp;
+ bool no_sg;
+} ioc_compat_fm_vsp_config_no_sg_params_t;
+
+typedef struct ioc_compat_fm_vsp_prs_result_params_t {
+ compat_uptr_t p_fm_vsp;
+ compat_uptr_t p_data;
+} ioc_compat_fm_vsp_prs_result_params_t;
+
+#endif /* (DPAA_VERSION >= 11) */
+typedef struct ioc_compat_fm_pcd_kg_scheme_spc_t {
+ uint32_t val;
+ compat_uptr_t id;
+} ioc_compat_fm_pcd_kg_scheme_spc_t;
+
+typedef struct ioc_compat_fm_ctrl_mon_counters_params_t {
+ uint8_t fm_ctrl_index;
+ compat_uptr_t p_mon;
+} ioc_compat_fm_ctrl_mon_counters_params_t;
+
+typedef struct ioc_compat_fm_pcd_cc_tbl_get_stats_t {
+ compat_uptr_t id;
+ uint16_t key_index;
+ ioc_fm_pcd_cc_key_statistics_t statistics;
+} ioc_compat_fm_pcd_cc_tbl_get_stats_t;
+
+
+/* } pcd compat structures */
+
+void compat_obj_delete(
+ ioc_compat_fm_obj_t *compat_id,
+ ioc_fm_obj_t *id);
+
+/* pcd compat functions { */
+void compat_copy_fm_pcd_plcr_profile(
+ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param,
+ ioc_fm_pcd_plcr_profile_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_key(
+ ioc_compat_fm_pcd_cc_key_params_t *compat_param,
+ ioc_fm_pcd_cc_key_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(
+ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_node_modify_next_engine(
+ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param,
+ uint8_t compat);
+
+void compat_fm_pcd_cc_tree_modify_next_engine(
+ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param,
+ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_hash_table(
+ ioc_compat_fm_pcd_hash_table_params_t *compat_param,
+ ioc_fm_pcd_hash_table_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_grp(
+ ioc_compat_fm_pcd_cc_grp_params_t *compat_param,
+ ioc_fm_pcd_cc_grp_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_tree(
+ ioc_compat_fm_pcd_cc_tree_params_t *compat_param,
+ ioc_fm_pcd_cc_tree_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_tbl_get_stats(
+ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param,
+ ioc_fm_pcd_cc_tbl_get_stats_t *param,
+ uint8_t compat);
+
+void compat_fm_pcd_prs_sw(
+ ioc_compat_fm_pcd_prs_sw_params_t *compat_param,
+ ioc_fm_pcd_prs_sw_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_kg_scheme(
+ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param,
+ ioc_fm_pcd_kg_scheme_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_kg_scheme_select(
+ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param,
+ ioc_fm_pcd_kg_scheme_select_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_kg_schemes_params(
+ ioc_compat_fm_pcd_port_schemes_params_t *compat_param,
+ ioc_fm_pcd_port_schemes_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_port_pcd_kg(
+ ioc_compat_fm_port_pcd_kg_params_t *compat_param,
+ ioc_fm_port_pcd_kg_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_port_pcd(
+ ioc_compat_fm_port_pcd_params_t *compat_param,
+ ioc_fm_port_pcd_params_t *param,
+ uint8_t compat);
+
+#if (DPAA_VERSION >= 11)
+void compat_copy_fm_port_vsp_alloc_params(
+ ioc_compat_fm_port_vsp_alloc_params_t *compat_param,
+ ioc_fm_port_vsp_alloc_params_t *param,
+ uint8_t compat);
+#endif /* (DPAA_VERSION >= 11) */
+
+void compat_copy_fm_pcd_net_env(
+ ioc_compat_fm_pcd_net_env_params_t *compat_param,
+ ioc_fm_pcd_net_env_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_node_modify_key(
+ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param,
+ ioc_fm_pcd_cc_node_modify_key_params_t *param,
+ uint8_t compat);
+
+void compat_copy_keys(
+ ioc_compat_keys_params_t *compat_param,
+ ioc_keys_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_cc_node(
+ ioc_compat_fm_pcd_cc_node_params_t *compat_param,
+ ioc_fm_pcd_cc_node_params_t *param,
+ uint8_t compat);
+
+void compat_fm_pcd_manip_set_node(
+ ioc_compat_fm_pcd_manip_params_t *compat_param,
+ ioc_fm_pcd_manip_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_manip_get_stats(
+ ioc_compat_fm_pcd_manip_get_stats_t *compat_param,
+ ioc_fm_pcd_manip_get_stats_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_port_pcd_modify_tree(
+ ioc_compat_fm_obj_t *compat_id,
+ ioc_fm_obj_t *id,
+ uint8_t compat);
+
+#if (DPAA_VERSION >= 11)
+void compat_copy_fm_pcd_frm_replic_group_params(
+ ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param,
+ ioc_fm_pcd_frm_replic_group_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_frm_replic_member(
+ ioc_compat_fm_pcd_frm_replic_member_t *compat_param,
+ ioc_fm_pcd_frm_replic_member_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_pcd_frm_replic_member_params(
+ ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param,
+ ioc_fm_pcd_frm_replic_member_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_vsp_params(
+ ioc_compat_fm_vsp_params_t *compat_param,
+ ioc_fm_vsp_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_buf_pool_depletion_params(
+ ioc_compat_fm_buf_pool_depletion_params_t *compat_param,
+ ioc_fm_buf_pool_depletion_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_buffer_prefix_content_params(
+ ioc_compat_fm_buffer_prefix_content_params_t *compat_param,
+ ioc_fm_buffer_prefix_content_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_vsp_config_no_sg_params(
+ ioc_compat_fm_vsp_config_no_sg_params_t *compat_param,
+ ioc_fm_vsp_config_no_sg_params_t *param,
+ uint8_t compat);
+
+void compat_copy_fm_vsp_prs_result_params(
+ ioc_compat_fm_vsp_prs_result_params_t *compat_param,
+ ioc_fm_vsp_prs_result_params_t *param,
+ uint8_t compat);
+
+#endif /* (DPAA_VERSION >= 11) */
+
+void compat_copy_fm_pcd_kg_scheme_spc(
+ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param,
+ ioc_fm_pcd_kg_scheme_spc_t *param,
+ uint8_t compat);
+
+/* } pcd compat functions */
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h
new file mode 100644
index 000000000000..1b72e1d5bca6
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_resources.h
+
+ @Description FMD wrapper resource allocation functions.
+
+*/
+
+#ifndef LNXWRP_RESOURCES_H_
+#define LNXWRP_RESOURCES_H_
+
+#if !defined(FMAN_RESOURCES_UNIT_TEST)
+#include "lnxwrp_fm.h"
+#else
+#include "lnxwrp_resources_ut.h"
+#endif
+
+#define ROUND(X) ((2*(X)+1)/2)
+#define CEIL(X) ((X)+1)
+/* #define ROUND_DIV(X, Y) (((X)+(Y)/2)/(Y)) */
+#define ROUND_DIV(X, Y) ((2*(X)+(Y))/(2*(Y)))
+#define CEIL_DIV(X, Y) (((X)+(Y)-1)/(Y))
+
+/* used for resource calculus */
+#define DPDE_1G 2 /* DQDP 1g - from LLD:
+ DEFAULT_PORT_txFifoDeqPipelineDepth_1G */
+#define DPDE_10G 8 /* DQDP 10g - from LLD:
+ DEFAULT_PORT_txFifoDeqPipelineDepth_10G */
+
+int fm_set_active_fman_ports(struct platform_device *of_dev,
+ t_LnxWrpFmDev *p_LnxWrpFmDev);
+
+/* Calculate the fifosize based on MURAM allocation, number of ports, dpde
+ * value and s/g software support (! Kernel does not suport s/g).
+ *
+ * Algorithm summary:
+ * - Calculate the the minimum fifosize required for every type of port
+ * (TX,RX for 1G, 2.5G and 10G).
+ * - Set TX the minimum fifosize required.
+ * - Distribute the remaining buffers (after all TX were set) to RX ports
+ * based on:
+ * 1G RX = Remaining_buffers * 1/(1+2.5+10)
+ * 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10)
+ * 10G RX = Remaining_buffers * 10/(1+2.5+10)
+ * - if the RX is smaller than the minimum required, then set the minimum
+ * required
+ * - In the end distribuite the leftovers if there are any (due to
+ * unprecise calculus) or if over allocation cat some buffers from all RX
+ * ports w/o pass over minimum required treshold, but if there must be
+ * pass the treshold in order to cat the over allocation ,then this
+ * configuration can not be set - KERN_ALERT.
+*/
+int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev,
+ int muram_fifo_size);
+
+#if !defined(FMAN_RESOURCES_UNIT_TEST)
+int fm_config_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
+#endif
+
+/* Compute FMan open DMA based on total number of open DMAs and
+ * number of available fman ports.
+ *
+ * By default 10g ports are set to input parameters. The other ports
+ * tries to keep the proportion rx=2tx open dmas or tresholds.
+ *
+ * If leftovers, then those will be set as shared.
+ *
+ * If after computing overflow appears, then it decrements open dma
+ * for all ports w/o cross the tresholds. If the tresholds are meet
+ * and is still overflow, then it returns error.
+*/
+int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev,
+ int max_fm_open_dma,
+ int default_tx_10g_dmas,
+ int default_rx_10g_dmas,
+ int min_tx_10g_treshold, int min_rx_10g_treshold);
+
+#if !defined(FMAN_RESOURCES_UNIT_TEST)
+int fm_config_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
+#endif
+
+/* Compute FMan tnums based on available tnums and number of ports.
+ * Set defaults (minim tresholds) and then distribute leftovers.*/
+int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums);
+
+#if !defined(FMAN_RESOURCES_UNIT_TEST)
+int fm_config_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev);
+#endif
+
+#endif /* LNXWRP_RESOURCES_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c
new file mode 100644
index 000000000000..6c06a5a677f1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "lnxwrp_resources.h"
+#include "lnxwrp_resources_ut.h"
+
+#define KILOBYTE 0x400 /* 1024 */
+
+typedef enum e_board_type {
+ e_p3041,
+ e_p4080,
+ e_p5020,
+ e_p1023
+} e_board_type;
+
+uint8_t board_type;
+uint32_t muram_size = 0;
+uint32_t dmas_num = 0;
+uint32_t task_num = 0;
+uint32_t frame_size = 0;
+uint32_t oh_num = 0;
+uint32_t num_ports_1g = 0;
+uint32_t num_ports_10g = 0;
+uint32_t num_ports_2g5 = 0;
+uint32_t fsl_fman_phy_maxfrm = 0;
+uint32_t dpa_rx_extra_headroom = 0;
+
+void show_help(void){
+ printf(" help: \n");
+ printf(" -b <board_type> -f <max_fram_size(mtu)> -o <num_oh_ports> -g1"
+ " <num_1g_ports> -g10 <num_10g_ports> -g25 <num_2g5_ports>\n");
+ printf(" Maxim num of DMAS availbale: P3/P4/P5:32 , P1023:16 \n");
+ printf(" Maxim num of TNUMs availbale: P3/P4/P5:128, P1023:32 \n");
+ printf(" Muram size: P3/P4/P5:160K, P1023:64K \n");
+ printf(" Number of ports:\n");
+ printf(" P3/P5: 5p 1g, 1p 10g, 7p oh \n");
+ printf(" P4 : 4p 1g, 1p 10g, 7p oh \n");
+ printf(" P1 : 2p 1g, 0p 10g, 4p oh \n");
+ printf(" MTU: Default:1522, Jumbo:9600 \n");
+}
+
+int fm_set_param(t_LnxWrpFmDev *p_LnxWrpFmDev) {
+ struct fm_active_ports *fm_active_ports_info = NULL;
+ fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info;
+
+ switch(board_type){
+ case e_p3041:
+ case e_p5020:
+ muram_size = 160*KILOBYTE;
+ dmas_num = 32;
+ task_num = 128;
+ if ((num_ports_1g+num_ports_2g5) > 5 || num_ports_10g > 1 || oh_num > 7)
+ goto err_fm_set_param;
+ break;
+ case e_p4080:
+ muram_size = 160*KILOBYTE;
+ dmas_num = 32;
+ task_num = 128;
+ if ((num_ports_1g+num_ports_2g5) > 4 || num_ports_10g > 1 || oh_num > 7)
+ goto err_fm_set_param;
+ break;
+ case e_p1023:
+ muram_size = 64*KILOBYTE;
+ dmas_num = 16;
+ task_num = 128;
+ if ((num_ports_1g+num_ports_2g5) > 2 || oh_num > 4)
+ goto err_fm_set_param;
+ break;
+ default:
+ goto err_fm_set_param;
+ break;
+ }
+
+ p_LnxWrpFmDev->id = 0;
+ fsl_fman_phy_maxfrm = frame_size;
+ dpa_rx_extra_headroom = 0; /* ATTENTION: can be != 0 */
+ fm_active_ports_info->num_oh_ports = oh_num;
+ fm_active_ports_info->num_tx_ports = num_ports_1g;
+ fm_active_ports_info->num_rx_ports = num_ports_1g;
+ fm_active_ports_info->num_tx25_ports = num_ports_2g5;
+ fm_active_ports_info->num_rx25_ports = num_ports_2g5;
+ fm_active_ports_info->num_tx10_ports = num_ports_10g;
+ fm_active_ports_info->num_rx10_ports = num_ports_10g;
+
+ return 0;
+
+err_fm_set_param:
+ printf(" ERR: To many ports!!! \n");
+ return -1;
+}
+
+int main (int argc, char *argv[]){
+ t_LnxWrpFmDev LnxWrpFmDev;
+ t_LnxWrpFmDev *p_LnxWrpFmDev = &LnxWrpFmDev;
+ int tokens_cnt = 1;
+
+ char *token = NULL;
+
+ while(tokens_cnt < argc)
+ {
+ token = argv[tokens_cnt++];
+ if (strcmp(token, "-b") == 0){
+ if(strcmp(argv[tokens_cnt],"p3") == 0)
+ board_type = e_p3041;
+ else if(strcmp(argv[tokens_cnt],"p4") == 0)
+ board_type = e_p4080;
+ else if(strcmp(argv[tokens_cnt],"p5") == 0)
+ board_type = e_p5020;
+ else if(strcmp(argv[tokens_cnt],"p1") == 0)
+ board_type = e_p1023;
+ else
+ show_help();
+ tokens_cnt++;
+ }
+ else if(strcmp(token, "-d") == 0){
+ dmas_num = atoi(argv[tokens_cnt++]);
+ }
+ else if(strcmp(token, "-t") == 0)
+ task_num = atoi(argv[tokens_cnt++]);
+ else if(strcmp(token, "-f") == 0)
+ frame_size = atoi(argv[tokens_cnt++]);
+ else if(strcmp(token, "-o") == 0)
+ oh_num = atoi(argv[tokens_cnt++]);
+ else if(strcmp(token, "-g1") == 0)
+ num_ports_1g = atoi(argv[tokens_cnt++]);
+ else if(strcmp(token, "-g10") == 0)
+ num_ports_10g = atoi(argv[tokens_cnt++]);
+ else if(strcmp(token, "-g25") == 0)
+ num_ports_2g5 = atoi(argv[tokens_cnt++]);
+ else {
+ show_help();
+ return -1;
+ }
+ }
+
+ if(fm_set_param(p_LnxWrpFmDev) < 0){
+ show_help();
+ return -1;
+ }
+
+ if(fm_precalculate_fifosizes(
+ p_LnxWrpFmDev,
+ 128*KILOBYTE)
+ != 0)
+ return -1;
+ if(fm_precalculate_open_dma(
+ p_LnxWrpFmDev,
+ dmas_num, /* max open dmas:dpaa_integration_ext.h */
+ FM_DEFAULT_TX10G_OPENDMA, /* default TX 10g open dmas */
+ FM_DEFAULT_RX10G_OPENDMA, /* default RX 10g open dmas */
+ FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */
+ FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */
+ != 0)
+ return -1;
+ if(fm_precalculate_tnums(
+ p_LnxWrpFmDev,
+ task_num) /* max TNUMS: dpa integration file. */
+ != 0)
+ return -1;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h
new file mode 100644
index 000000000000..063946eb9ef8
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h
@@ -0,0 +1,144 @@
+/* Copyright (c) 2012 Freescale Semiconductor, 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef FM_RESS_TEST_H_
+#define FM_RESS_TEST_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define _Packed
+#define _PackedType __attribute__ ((packed))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define KERN_ALERT ""
+#define KERN_INFO ""
+#define ASSERT_COND assert
+#define printk printf
+#define NET_IP_ALIGN 0
+#define FM_FIFO_ALLOCATION_OLD_ALG
+
+#if defined(CONFIG_FMAN_DISABLE_OH_AND_DISTRIBUTE_RESOURCES)
+#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */
+#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */
+#else
+#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */
+#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */
+#endif
+#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */
+#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */
+
+/* information about all active ports for an FMan.
+ * !Some ports may be disabled by u-boot, thus will not be available */
+struct fm_active_ports {
+ uint32_t num_oh_ports;
+ uint32_t num_tx_ports;
+ uint32_t num_rx_ports;
+ uint32_t num_tx25_ports;
+ uint32_t num_rx25_ports;
+ uint32_t num_tx10_ports;
+ uint32_t num_rx10_ports;
+};
+
+/* FMan resources precalculated at fm probe based
+ * on available FMan port. */
+struct fm_resource_settings {
+ /* buffers - fifo sizes */
+ uint32_t tx1g_num_buffers;
+ uint32_t rx1g_num_buffers;
+ uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */
+ uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */
+ uint32_t tx10g_num_buffers;
+ uint32_t rx10g_num_buffers;
+ uint32_t oh_num_buffers;
+ uint32_t shared_ext_buffers;
+
+
+ /* open DMAs */
+ uint32_t tx_1g_dmas;
+ uint32_t rx_1g_dmas;
+ uint32_t tx_2g5_dmas; /* Not supported yet by LLD */
+ uint32_t rx_2g5_dmas; /* Not supported yet by LLD */
+ uint32_t tx_10g_dmas;
+ uint32_t rx_10g_dmas;
+ uint32_t oh_dmas;
+ uint32_t shared_ext_open_dma;
+
+ /* Tnums */
+ uint32_t tx_1g_tnums;
+ uint32_t rx_1g_tnums;
+ uint32_t tx_2g5_tnums; /* Not supported yet by LLD */
+ uint32_t rx_2g5_tnums; /* Not supported yet by LLD */
+ uint32_t tx_10g_tnums;
+ uint32_t rx_10g_tnums;
+ uint32_t oh_tnums;
+ uint32_t shared_ext_tnums;
+};
+
+typedef struct {
+ uint8_t id;
+ struct fm_active_ports fm_active_ports_info;
+ struct fm_resource_settings fm_resource_settings_info;
+} t_LnxWrpFmDev;
+
+typedef struct {
+ uint8_t id;
+} t_LnxWrpFmPortDev;
+
+typedef _Packed struct t_FmPrsResult {
+ volatile uint8_t lpid; /**< Logical port id */
+ volatile uint8_t shimr; /**< Shim header result */
+ volatile uint16_t l2r; /**< Layer 2 result */
+ volatile uint16_t l3r; /**< Layer 3 result */
+ volatile uint8_t l4r; /**< Layer 4 result */
+ volatile uint8_t cplan; /**< Classification plan id */
+ volatile uint16_t nxthdr; /**< Next Header */
+ volatile uint16_t cksum; /**< Checksum */
+ volatile uint32_t lcv; /**< LCV */
+ volatile uint8_t shim_off[3]; /**< Shim offset */
+ volatile uint8_t eth_off; /**< ETH offset */
+ volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */
+ volatile uint8_t vlan_off[2]; /**< VLAN offset */
+ volatile uint8_t etype_off; /**< ETYPE offset */
+ volatile uint8_t pppoe_off; /**< PPP offset */
+ volatile uint8_t mpls_off[2]; /**< MPLS offset */
+ volatile uint8_t ip_off[2]; /**< IP offset */
+ volatile uint8_t gre_off; /**< GRE offset */
+ volatile uint8_t l4_off; /**< Layer 4 offset */
+ volatile uint8_t nxthdr_off; /**< Parser end point */
+} _PackedType t_FmPrsResult;
+
+#endif
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make
new file mode 100644
index 000000000000..58009cd8a91e
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make
@@ -0,0 +1,28 @@
+CC=gcc
+
+LNXWRP_RESS_UT=lnxwrp_resources_ut
+OBJ=lnxwrp_resources
+
+INC_PATH=
+LIB_PATH=
+
+INC=$(addprefix -I,$(INC_PATH))
+LIB=$(addprefix -L,$(LIB_PATH))
+
+CFLAGS= -gdwarf-2 -g -O0 -Wall
+XFLAGS= -DFMAN_RESOURCES_UNIT_TEST
+
+all: $(LNXWRP_RESS_UT)
+
+$(LNXWRP_RESS_UT):$(addsuffix .o,$(OBJ)) $(LNXWRP_RESS_UT).o
+ $(CC) -o $(LNXWRP_RESS_UT) $(LNXWRP_RESS_UT).o $(addsuffix .o,$(OBJ))
+
+%.o: %.c
+ @(echo " (CC) $@")
+ @($(CC) $(INC) $(CFLAGS) $(XFLAGS) -o $(@) -c $<)
+
+.PHONY: clean
+
+clean:
+ rm -f *.o
+ rm -f $(LNXWRP_RESS_UT)
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c
new file mode 100644
index 000000000000..813771bfdac7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_sysfs.c
+
+ @Description FM wrapper sysfs related functions.
+
+*/
+
+#include <linux/types.h>
+#include "lnxwrp_sysfs.h"
+
+uint8_t fm_find_statistic_counter_by_name(const char *attr_name,
+ const struct sysfs_stats_t *sysfs_stats,
+ uint8_t *offset)
+{
+ int i = 0;
+
+ while (sysfs_stats[i].stat_name != NULL) {
+ if (strcmp(sysfs_stats[i].stat_name, attr_name) == 0) {
+ if (offset != NULL)
+ *offset = i;
+ return sysfs_stats[i].stat_counter;
+ }
+
+ i++;
+ }
+ WARN(1, "FMD: Should never get here!");
+ return 0;
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h
new file mode 100644
index 000000000000..2098b2441ad5
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+#ifndef LNXWRP_SYSFS_H_
+#define LNXWRP_SYSFS_H_
+
+/* Linux Headers ------------------- */
+#include <linux/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+
+struct sysfs_stats_t {
+ const char *stat_name;
+ uint8_t stat_counter;
+};
+
+uint8_t fm_find_statistic_counter_by_name(const char *attr_name,
+ const struct sysfs_stats_t *sysfs_stats,
+ uint8_t *offset);
+
+#endif /* LNXWRP_SYSFS_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
new file mode 100644
index 000000000000..2647076dc2c4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c
@@ -0,0 +1,1858 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "lnxwrp_sysfs.h"
+#include "lnxwrp_sysfs_fm.h"
+#include "lnxwrp_fm.h"
+
+#include "../../sdk_fman/Peripherals/FM/inc/fm_common.h"
+#include "../../sdk_fman/Peripherals/FM/Pcd/fm_pcd.h"
+#include "../../sdk_fman/Peripherals/FM/Pcd/fm_kg.h"
+#include "../../sdk_fman/Peripherals/FM/Pcd/fm_plcr.h"
+
+#if defined(__ERR_MODULE__)
+#undef __ERR_MODULE__
+#endif
+
+#include "../../sdk_fman/Peripherals/FM/fm.h"
+#include <linux/delay.h>
+
+
+static int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val);
+
+enum fm_dma_match_stats {
+ FM_DMA_COUNTERS_CMQ_NOT_EMPTY,
+ FM_DMA_COUNTERS_BUS_ERROR,
+ FM_DMA_COUNTERS_READ_BUF_ECC_ERROR,
+ FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR,
+ FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR
+};
+
+static const struct sysfs_stats_t fm_sysfs_stats[] = {
+ /* FM statistics */
+ {
+ .stat_name = "enq_total_frame",
+ .stat_counter = e_FM_COUNTERS_ENQ_TOTAL_FRAME,
+ },
+ {
+ .stat_name = "deq_total_frame",
+ .stat_counter = e_FM_COUNTERS_DEQ_TOTAL_FRAME,
+ },
+ {
+ .stat_name = "deq_0",
+ .stat_counter = e_FM_COUNTERS_DEQ_0,
+ },
+ {
+ .stat_name = "deq_1",
+ .stat_counter = e_FM_COUNTERS_DEQ_1,
+ },
+ {
+ .stat_name = "deq_2",
+ .stat_counter = e_FM_COUNTERS_DEQ_2,
+ },
+ {
+ .stat_name = "deq_3",
+ .stat_counter = e_FM_COUNTERS_DEQ_3,
+ },
+ {
+ .stat_name = "deq_from_default",
+ .stat_counter = e_FM_COUNTERS_DEQ_FROM_DEFAULT,
+ },
+ {
+ .stat_name = "deq_from_context",
+ .stat_counter = e_FM_COUNTERS_DEQ_FROM_CONTEXT,
+ },
+ {
+ .stat_name = "deq_from_fd",
+ .stat_counter = e_FM_COUNTERS_DEQ_FROM_FD,
+ },
+ {
+ .stat_name = "deq_confirm",
+ .stat_counter = e_FM_COUNTERS_DEQ_CONFIRM,
+ },
+ /* FM:DMA statistics */
+ {
+ .stat_name = "cmq_not_empty",
+ .stat_counter = FM_DMA_COUNTERS_CMQ_NOT_EMPTY,
+ },
+ {
+ .stat_name = "bus_error",
+ .stat_counter = FM_DMA_COUNTERS_BUS_ERROR,
+ },
+ {
+ .stat_name = "read_buf_ecc_error",
+ .stat_counter = FM_DMA_COUNTERS_READ_BUF_ECC_ERROR,
+ },
+ {
+ .stat_name = "write_buf_ecc_sys_error",
+ .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR,
+ },
+ {
+ .stat_name = "write_buf_ecc_fm_error",
+ .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR,
+ },
+ /* FM:PCD statistics */
+ {
+ .stat_name = "pcd_kg_total",
+ .stat_counter = e_FM_PCD_KG_COUNTERS_TOTAL,
+ },
+ {
+ .stat_name = "pcd_plcr_yellow",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_YELLOW,
+ },
+ {
+ .stat_name = "pcd_plcr_red",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RED,
+ },
+ {
+ .stat_name = "pcd_plcr_recolored_to_red",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED,
+ },
+ {
+ .stat_name = "pcd_plcr_recolored_to_yellow",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW,
+ },
+ {
+ .stat_name = "pcd_plcr_total",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_TOTAL,
+ },
+ {
+ .stat_name = "pcd_plcr_length_mismatch",
+ .stat_counter = e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH,
+ },
+ {
+ .stat_name = "pcd_prs_parse_dispatch",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH,
+ },
+ {
+ .stat_name = "pcd_prs_l2_parse_result_returned",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED,
+ },
+ {
+ .stat_name = "pcd_prs_l3_parse_result_returned",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED,
+ },
+ {
+ .stat_name = "pcd_prs_l4_parse_result_returned",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED,
+ },
+ {
+ .stat_name = "pcd_prs_shim_parse_result_returned",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED,
+ },
+ {
+ .stat_name = "pcd_prs_l2_parse_result_returned_with_err",
+ .stat_counter =
+ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR,
+ },
+ {
+ .stat_name = "pcd_prs_l3_parse_result_returned_with_err",
+ .stat_counter =
+ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR,
+ },
+ {
+ .stat_name = "pcd_prs_l4_parse_result_returned_with_err",
+ .stat_counter =
+ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR,
+ },
+ {
+ .stat_name = "pcd_prs_shim_parse_result_returned_with_err",
+ .stat_counter =
+ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR,
+ },
+ {
+ .stat_name = "pcd_prs_soft_prs_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_soft_prs_stall_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_hard_prs_cycle_incl_stall_cycles",
+ .stat_counter =
+ e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_muram_read_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_muram_read_stall_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_muram_write_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_muram_write_stall_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES,
+ },
+ {
+ .stat_name = "pcd_prs_fpm_command_stall_cycles",
+ .stat_counter = e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES,
+ },
+ {}
+};
+
+
+static ssize_t show_fm_risc_load(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ unsigned long flags;
+ int m =0;
+ int err =0;
+ unsigned n = 0;
+ t_FmCtrlMon util;
+ uint8_t i =0 ;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+
+ local_irq_save(flags);
+
+ /* Calculate risc load */
+ FM_CtrlMonStart(p_wrp_fm_dev->h_Dev);
+ msleep(1000);
+ FM_CtrlMonStop(p_wrp_fm_dev->h_Dev);
+
+ for (i = 0; i < FM_NUM_OF_CTRL; i++) {
+ err |= FM_CtrlMonGetCounters(p_wrp_fm_dev->h_Dev, i, &util);
+ m = snprintf(&buf[n],PAGE_SIZE,"\tRisc%u: util-%u%%, efficiency-%u%%\n",
+ i, util.percentCnt[0], util.percentCnt[1]);
+ n=m+n;
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+/* Fm stats and regs dumps via sysfs */
+static ssize_t show_fm_dma_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ t_FmDmaStatus dma_status;
+ unsigned long flags = 0;
+ unsigned n = 0;
+ uint8_t counter_value = 0, counter = 0;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+
+ counter = fm_find_statistic_counter_by_name(
+ attr->attr.name,
+ fm_sysfs_stats, NULL);
+
+ local_irq_save(flags);
+
+ memset(&dma_status, 0, sizeof(dma_status));
+ FM_GetDmaStatus(p_wrp_fm_dev->h_Dev, &dma_status);
+
+ switch (counter) {
+ case FM_DMA_COUNTERS_CMQ_NOT_EMPTY:
+ counter_value = dma_status.cmqNotEmpty;
+ break;
+ case FM_DMA_COUNTERS_BUS_ERROR:
+ counter_value = dma_status.busError;
+ break;
+ case FM_DMA_COUNTERS_READ_BUF_ECC_ERROR:
+ counter_value = dma_status.readBufEccError;
+ break;
+ case FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR:
+ counter_value = dma_status.writeBufEccSysError;
+ break;
+ case FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR:
+ counter_value = dma_status.writeBufEccFmError;
+ break;
+ default:
+ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+ __func__);
+ break;
+ };
+
+ n = snprintf(buf, PAGE_SIZE, "\tFM %u counter: %c\n",
+ p_wrp_fm_dev->id, counter_value ? 'T' : 'F');
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+static ssize_t show_fm_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ unsigned long flags = 0;
+ unsigned n = 0, cnt_e = 0;
+ uint32_t cnt_val;
+ int err;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+
+ cnt_e = fm_find_statistic_counter_by_name(
+ attr->attr.name,
+ fm_sysfs_stats, NULL);
+
+ err = fm_get_counter(p_wrp_fm_dev->h_Dev,
+ (e_FmCounters) cnt_e, &cnt_val);
+
+ if (err)
+ return err;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n",
+ p_wrp_fm_dev->id, cnt_val);
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+static ssize_t show_fm_muram_free_sz(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ unsigned long flags = 0;
+ unsigned n = 0;
+ uint64_t muram_free_size = 0;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+
+ muram_free_size = FM_MURAM_GetFreeMemSize(p_wrp_fm_dev->h_MuramDev);
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "\tFM %d muram_free_size: %lld\n",
+ p_wrp_fm_dev->id, muram_free_size);
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+static ssize_t show_fm_ctrl_code_ver(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ unsigned long flags = 0;
+ unsigned n = 0;
+ t_FmCtrlCodeRevisionInfo rv_info;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+
+ FM_GetFmanCtrlCodeRevision((t_Fm *)p_wrp_fm_dev->h_Dev, &rv_info);
+
+ local_irq_save(flags);
+
+ FM_DMP_LN(buf, n, "- FM %d ctrl code pkg info:\n", p_wrp_fm_dev->id);
+ FM_DMP_LN(buf, n, "Package rev: %d\n", rv_info.packageRev);
+ FM_DMP_LN(buf, n, "major rev: %d\n", rv_info.majorRev);
+ FM_DMP_LN(buf, n, "minor rev: %d\n", rv_info.minorRev);
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+static ssize_t show_fm_pcd_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+ unsigned long flags = 0;
+ unsigned n = 0, counter = 0;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev ||
+ !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+
+ counter = fm_find_statistic_counter_by_name(
+ attr->attr.name,
+ fm_sysfs_stats, NULL);
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n",
+ p_wrp_fm_dev->id,
+ FM_PCD_GetCounter(p_wrp_fm_dev->h_PcdDev,
+ (e_FmPcdCounters) counter));
+
+ local_irq_restore(flags);
+
+ return n;
+}
+
+static ssize_t show_fm_tnum_dbg(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (!p_wrp_fm_dev->active)
+ return -EIO;
+ else {
+ int tn_s;
+
+ if (!sscanf(attr->attr.name, "tnum_dbg_%d", &tn_s))
+ return -EINVAL;
+
+ n = fm_dump_tnum_dbg(p_wrp_fm_dev->h_Dev,
+ tn_s, tn_s + 15, buf, n);
+ }
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_fm_cls_plan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "\n FM-KG classification plan dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else {
+ int cpn;
+
+ if (!sscanf(attr->attr.name, "cls_plan_%d", &cpn))
+ return -EINVAL;
+
+ n = fm_dump_cls_plan(p_wrp_fm_dev->h_PcdDev, cpn, buf, n);
+ }
+ local_irq_restore(flags);
+#else
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_fm_profiles(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "FM policer profile dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else {
+ int pn;
+
+ if (!sscanf(attr->attr.name, "profile_%d", &pn))
+ return -EINVAL;
+
+ n = fm_profile_dump_regs(p_wrp_fm_dev->h_PcdDev, pn, buf, n);
+ }
+ local_irq_restore(flags);
+#else
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_fm_schemes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "FM-KG driver schemes dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else {
+ int sn;
+
+ if (!sscanf(attr->attr.name, "scheme_%d", &sn))
+ return -EINVAL;
+
+ n = fm_dump_scheme(p_wrp_fm_dev->h_PcdDev, sn, buf, n);
+ }
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+/* FM */
+static DEVICE_ATTR(enq_total_frame, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_total_frame, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(fm_risc_load_val, S_IRUGO, show_fm_risc_load, NULL);
+static DEVICE_ATTR(deq_0, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_1, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_2, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_3, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_from_default, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_from_context, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_from_fd, S_IRUGO, show_fm_stats, NULL);
+static DEVICE_ATTR(deq_confirm, S_IRUGO, show_fm_stats, NULL);
+/* FM:DMA */
+static DEVICE_ATTR(cmq_not_empty, S_IRUGO, show_fm_dma_stats, NULL);
+static DEVICE_ATTR(bus_error, S_IRUGO, show_fm_dma_stats, NULL);
+static DEVICE_ATTR(read_buf_ecc_error, S_IRUGO, show_fm_dma_stats, NULL);
+static DEVICE_ATTR(write_buf_ecc_sys_error, S_IRUGO, show_fm_dma_stats, NULL);
+static DEVICE_ATTR(write_buf_ecc_fm_error, S_IRUGO, show_fm_dma_stats, NULL);
+/* FM:PCD */
+static DEVICE_ATTR(pcd_kg_total, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_plcr_yellow, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_plcr_red, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_plcr_recolored_to_red, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_plcr_recolored_to_yellow, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_plcr_total, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_plcr_length_mismatch, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_prs_parse_dispatch, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l2_parse_result_returned, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l3_parse_result_returned, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l4_parse_result_returned, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_shim_parse_result_returned, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l2_parse_result_returned_with_err, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l3_parse_result_returned_with_err, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_l4_parse_result_returned_with_err, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_shim_parse_result_returned_with_err, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_soft_prs_cycles, S_IRUGO, show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_soft_prs_stall_cycles, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_prs_hard_prs_cycle_incl_stall_cycles, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_muram_read_cycles, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_prs_muram_read_stall_cycles, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_muram_write_cycles, S_IRUGO, show_fm_pcd_stats,
+ NULL);
+static DEVICE_ATTR(pcd_prs_muram_write_stall_cycles, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+static DEVICE_ATTR(pcd_prs_fpm_command_stall_cycles, S_IRUGO,
+ show_fm_pcd_stats, NULL);
+
+static DEVICE_ATTR(tnum_dbg_0, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_16, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_32, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_48, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_64, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_80, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_96, S_IRUGO, show_fm_tnum_dbg, NULL);
+static DEVICE_ATTR(tnum_dbg_112, S_IRUGO, show_fm_tnum_dbg, NULL);
+
+static DEVICE_ATTR(cls_plan_0, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_1, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_2, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_3, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_4, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_5, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_6, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_7, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_8, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_9, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_10, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_11, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_12, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_13, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_14, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_15, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_16, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_17, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_18, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_19, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_20, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_21, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_22, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_23, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_24, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_25, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_26, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_27, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_28, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_29, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_30, S_IRUGO, show_fm_cls_plan, NULL);
+static DEVICE_ATTR(cls_plan_31, S_IRUGO, show_fm_cls_plan, NULL);
+
+static DEVICE_ATTR(profile_0, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_1, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_2, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_3, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_4, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_5, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_6, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_7, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_8, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_9, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_10, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_11, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_12, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_13, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_14, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_15, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_16, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_17, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_18, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_19, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_20, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_21, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_22, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_23, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_24, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_25, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_26, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_27, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_28, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_29, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_30, S_IRUGO, show_fm_profiles, NULL);
+static DEVICE_ATTR(profile_31, S_IRUGO, show_fm_profiles, NULL);
+
+static DEVICE_ATTR(scheme_0, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_1, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_2, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_3, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_4, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_5, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_6, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_7, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_8, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_9, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_10, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_11, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_12, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_13, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_14, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_15, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_16, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_17, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_18, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_19, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_20, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_21, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_22, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_23, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_24, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_25, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_26, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_27, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_28, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_29, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_30, S_IRUGO, show_fm_schemes, NULL);
+static DEVICE_ATTR(scheme_31, S_IRUGO, show_fm_schemes, NULL);
+
+
+static struct attribute *fm_dev_stats_attributes[] = {
+ &dev_attr_enq_total_frame.attr,
+ &dev_attr_deq_total_frame.attr,
+ &dev_attr_deq_0.attr,
+ &dev_attr_deq_1.attr,
+ &dev_attr_deq_2.attr,
+ &dev_attr_deq_3.attr,
+ &dev_attr_deq_from_default.attr,
+ &dev_attr_deq_from_context.attr,
+ &dev_attr_deq_from_fd.attr,
+ &dev_attr_deq_confirm.attr,
+ &dev_attr_cmq_not_empty.attr,
+ &dev_attr_bus_error.attr,
+ &dev_attr_read_buf_ecc_error.attr,
+ &dev_attr_write_buf_ecc_sys_error.attr,
+ &dev_attr_write_buf_ecc_fm_error.attr,
+ &dev_attr_pcd_kg_total.attr,
+ &dev_attr_pcd_plcr_yellow.attr,
+ &dev_attr_pcd_plcr_red.attr,
+ &dev_attr_pcd_plcr_recolored_to_red.attr,
+ &dev_attr_pcd_plcr_recolored_to_yellow.attr,
+ &dev_attr_pcd_plcr_total.attr,
+ &dev_attr_pcd_plcr_length_mismatch.attr,
+ &dev_attr_pcd_prs_parse_dispatch.attr,
+ &dev_attr_pcd_prs_l2_parse_result_returned.attr,
+ &dev_attr_pcd_prs_l3_parse_result_returned.attr,
+ &dev_attr_pcd_prs_l4_parse_result_returned.attr,
+ &dev_attr_pcd_prs_shim_parse_result_returned.attr,
+ &dev_attr_pcd_prs_l2_parse_result_returned_with_err.attr,
+ &dev_attr_pcd_prs_l3_parse_result_returned_with_err.attr,
+ &dev_attr_pcd_prs_l4_parse_result_returned_with_err.attr,
+ &dev_attr_pcd_prs_shim_parse_result_returned_with_err.attr,
+ &dev_attr_pcd_prs_soft_prs_cycles.attr,
+ &dev_attr_pcd_prs_soft_prs_stall_cycles.attr,
+ &dev_attr_pcd_prs_hard_prs_cycle_incl_stall_cycles.attr,
+ &dev_attr_pcd_prs_muram_read_cycles.attr,
+ &dev_attr_pcd_prs_muram_read_stall_cycles.attr,
+ &dev_attr_pcd_prs_muram_write_cycles.attr,
+ &dev_attr_pcd_prs_muram_write_stall_cycles.attr,
+ &dev_attr_pcd_prs_fpm_command_stall_cycles.attr,
+ NULL
+};
+
+static struct attribute *fm_dev_tnums_dbg_attributes[] = {
+ &dev_attr_tnum_dbg_0.attr,
+ &dev_attr_tnum_dbg_16.attr,
+ &dev_attr_tnum_dbg_32.attr,
+ &dev_attr_tnum_dbg_48.attr,
+ &dev_attr_tnum_dbg_64.attr,
+ &dev_attr_tnum_dbg_80.attr,
+ &dev_attr_tnum_dbg_96.attr,
+ &dev_attr_tnum_dbg_112.attr,
+ NULL
+};
+
+static struct attribute *fm_dev_cls_plans_attributes[] = {
+ &dev_attr_cls_plan_0.attr,
+ &dev_attr_cls_plan_1.attr,
+ &dev_attr_cls_plan_2.attr,
+ &dev_attr_cls_plan_3.attr,
+ &dev_attr_cls_plan_4.attr,
+ &dev_attr_cls_plan_5.attr,
+ &dev_attr_cls_plan_6.attr,
+ &dev_attr_cls_plan_7.attr,
+ &dev_attr_cls_plan_8.attr,
+ &dev_attr_cls_plan_9.attr,
+ &dev_attr_cls_plan_10.attr,
+ &dev_attr_cls_plan_11.attr,
+ &dev_attr_cls_plan_12.attr,
+ &dev_attr_cls_plan_13.attr,
+ &dev_attr_cls_plan_14.attr,
+ &dev_attr_cls_plan_15.attr,
+ &dev_attr_cls_plan_16.attr,
+ &dev_attr_cls_plan_17.attr,
+ &dev_attr_cls_plan_18.attr,
+ &dev_attr_cls_plan_19.attr,
+ &dev_attr_cls_plan_20.attr,
+ &dev_attr_cls_plan_21.attr,
+ &dev_attr_cls_plan_22.attr,
+ &dev_attr_cls_plan_23.attr,
+ &dev_attr_cls_plan_24.attr,
+ &dev_attr_cls_plan_25.attr,
+ &dev_attr_cls_plan_26.attr,
+ &dev_attr_cls_plan_27.attr,
+ &dev_attr_cls_plan_28.attr,
+ &dev_attr_cls_plan_29.attr,
+ &dev_attr_cls_plan_30.attr,
+ &dev_attr_cls_plan_31.attr,
+ NULL
+};
+
+static struct attribute *fm_dev_profiles_attributes[] = {
+ &dev_attr_profile_0.attr,
+ &dev_attr_profile_1.attr,
+ &dev_attr_profile_2.attr,
+ &dev_attr_profile_3.attr,
+ &dev_attr_profile_4.attr,
+ &dev_attr_profile_5.attr,
+ &dev_attr_profile_6.attr,
+ &dev_attr_profile_7.attr,
+ &dev_attr_profile_8.attr,
+ &dev_attr_profile_9.attr,
+ &dev_attr_profile_10.attr,
+ &dev_attr_profile_11.attr,
+ &dev_attr_profile_12.attr,
+ &dev_attr_profile_13.attr,
+ &dev_attr_profile_14.attr,
+ &dev_attr_profile_15.attr,
+ &dev_attr_profile_16.attr,
+ &dev_attr_profile_17.attr,
+ &dev_attr_profile_18.attr,
+ &dev_attr_profile_19.attr,
+ &dev_attr_profile_20.attr,
+ &dev_attr_profile_21.attr,
+ &dev_attr_profile_22.attr,
+ &dev_attr_profile_23.attr,
+ &dev_attr_profile_24.attr,
+ &dev_attr_profile_25.attr,
+ &dev_attr_profile_26.attr,
+ &dev_attr_profile_27.attr,
+ &dev_attr_profile_28.attr,
+ &dev_attr_profile_29.attr,
+ &dev_attr_profile_30.attr,
+ &dev_attr_profile_31.attr,
+ NULL
+};
+
+static struct attribute *fm_dev_schemes_attributes[] = {
+ &dev_attr_scheme_0.attr,
+ &dev_attr_scheme_1.attr,
+ &dev_attr_scheme_2.attr,
+ &dev_attr_scheme_3.attr,
+ &dev_attr_scheme_4.attr,
+ &dev_attr_scheme_5.attr,
+ &dev_attr_scheme_6.attr,
+ &dev_attr_scheme_7.attr,
+ &dev_attr_scheme_8.attr,
+ &dev_attr_scheme_9.attr,
+ &dev_attr_scheme_10.attr,
+ &dev_attr_scheme_11.attr,
+ &dev_attr_scheme_12.attr,
+ &dev_attr_scheme_13.attr,
+ &dev_attr_scheme_14.attr,
+ &dev_attr_scheme_15.attr,
+ &dev_attr_scheme_16.attr,
+ &dev_attr_scheme_17.attr,
+ &dev_attr_scheme_18.attr,
+ &dev_attr_scheme_19.attr,
+ &dev_attr_scheme_20.attr,
+ &dev_attr_scheme_21.attr,
+ &dev_attr_scheme_22.attr,
+ &dev_attr_scheme_23.attr,
+ &dev_attr_scheme_24.attr,
+ &dev_attr_scheme_25.attr,
+ &dev_attr_scheme_26.attr,
+ &dev_attr_scheme_27.attr,
+ &dev_attr_scheme_28.attr,
+ &dev_attr_scheme_29.attr,
+ &dev_attr_scheme_30.attr,
+ &dev_attr_scheme_31.attr,
+ NULL
+};
+
+static const struct attribute_group fm_dev_stats_attr_grp = {
+ .name = "statistics",
+ .attrs = fm_dev_stats_attributes
+};
+
+static const struct attribute_group fm_dev_tnums_dbg_attr_grp = {
+ .name = "tnums_dbg",
+ .attrs = fm_dev_tnums_dbg_attributes
+};
+
+static const struct attribute_group fm_dev_cls_plans_attr_grp = {
+ .name = "cls_plans",
+ .attrs = fm_dev_cls_plans_attributes
+};
+
+static const struct attribute_group fm_dev_schemes_attr_grp = {
+ .name = "schemes",
+ .attrs = fm_dev_schemes_attributes
+};
+
+static const struct attribute_group fm_dev_profiles_attr_grp = {
+ .name = "profiles",
+ .attrs = fm_dev_profiles_attributes
+};
+
+static ssize_t show_fm_regs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+ else
+ n = fm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_fm_kg_pe_regs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE,
+ "\n FM-KG Port Partition Config registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else
+ n = fm_kg_pe_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_fm_kg_regs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "FM-KG registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else
+ n = fm_kg_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+
+static ssize_t show_fm_fpm_regs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ n = snprintf(buf, PAGE_SIZE, "FM-FPM registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev)
+ return -EIO;
+ else
+ n = fm_fpm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_prs_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else
+ n = fm_prs_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static ssize_t show_plcr_regs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return -EINVAL;
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n");
+
+ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev)
+ return -EIO;
+ else
+ n = fm_plcr_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n);
+
+ local_irq_restore(flags);
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+#endif /* (defined(DEBUG_ERRORS) && ... */
+
+ return n;
+}
+
+static DEVICE_ATTR(fm_regs, S_IRUGO, show_fm_regs, NULL);
+static DEVICE_ATTR(fm_fpm_regs, S_IRUGO, show_fm_fpm_regs, NULL);
+static DEVICE_ATTR(fm_kg_regs, S_IRUGO, show_fm_kg_regs, NULL);
+static DEVICE_ATTR(fm_kg_pe_regs, S_IRUGO, show_fm_kg_pe_regs, NULL);
+static DEVICE_ATTR(fm_plcr_regs, S_IRUGO, show_plcr_regs, NULL);
+static DEVICE_ATTR(fm_prs_regs, S_IRUGO, show_prs_regs, NULL);
+static DEVICE_ATTR(fm_muram_free_size, S_IRUGO, show_fm_muram_free_sz, NULL);
+static DEVICE_ATTR(fm_ctrl_code_ver, S_IRUGO, show_fm_ctrl_code_ver, NULL);
+
+int fm_sysfs_create(struct device *dev)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+
+ if (dev == NULL)
+ return -EIO;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+
+ /* store to remove them when module is disabled */
+ p_wrp_fm_dev->dev_attr_regs = &dev_attr_fm_regs;
+ p_wrp_fm_dev->dev_attr_risc_load = &dev_attr_fm_risc_load_val;
+ p_wrp_fm_dev->dev_fm_fpm_attr_regs = &dev_attr_fm_fpm_regs;
+ p_wrp_fm_dev->dev_fm_kg_attr_regs = &dev_attr_fm_kg_regs;
+ p_wrp_fm_dev->dev_fm_kg_pe_attr_regs = &dev_attr_fm_kg_pe_regs;
+ p_wrp_fm_dev->dev_plcr_attr_regs = &dev_attr_fm_plcr_regs;
+ p_wrp_fm_dev->dev_prs_attr_regs = &dev_attr_fm_prs_regs;
+ p_wrp_fm_dev->dev_attr_muram_free_size = &dev_attr_fm_muram_free_size;
+ p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver = &dev_attr_fm_ctrl_code_ver;
+
+ /* Create sysfs statistics group for FM module */
+ if (sysfs_create_group(&dev->kobj, &fm_dev_stats_attr_grp) != 0)
+ return -EIO;
+
+ if (sysfs_create_group(&dev->kobj, &fm_dev_schemes_attr_grp) != 0)
+ return -EIO;
+
+ if (sysfs_create_group(&dev->kobj, &fm_dev_profiles_attr_grp) != 0)
+ return -EIO;
+
+ if (sysfs_create_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp) != 0)
+ return -EIO;
+
+ if (sysfs_create_group(&dev->kobj, &fm_dev_cls_plans_attr_grp) != 0)
+ return -EIO;
+
+ /* Registers dump entry - in future will be moved to debugfs */
+ if (device_create_file(dev, &dev_attr_fm_regs) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_risc_load_val) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_fpm_regs) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_kg_regs) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_kg_pe_regs) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_plcr_regs) != 0)
+ return -EIO;
+
+ if (device_create_file(dev, &dev_attr_fm_prs_regs) != 0)
+ return -EIO;
+
+ /* muram free size */
+ if (device_create_file(dev, &dev_attr_fm_muram_free_size) != 0)
+ return -EIO;
+
+ /* fm ctrl code version */
+ if (device_create_file(dev, &dev_attr_fm_ctrl_code_ver) != 0)
+ return -EIO;
+
+ return 0;
+}
+
+void fm_sysfs_destroy(struct device *dev)
+{
+ t_LnxWrpFmDev *p_wrp_fm_dev = NULL;
+
+ if (WARN_ON(dev == NULL))
+ return;
+
+ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_wrp_fm_dev == NULL))
+ return;
+
+ sysfs_remove_group(&dev->kobj, &fm_dev_stats_attr_grp);
+ sysfs_remove_group(&dev->kobj, &fm_dev_schemes_attr_grp);
+ sysfs_remove_group(&dev->kobj, &fm_dev_profiles_attr_grp);
+ sysfs_remove_group(&dev->kobj, &fm_dev_cls_plans_attr_grp);
+ sysfs_remove_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp);
+ device_remove_file(dev, p_wrp_fm_dev->dev_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_fm_fpm_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_pe_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_plcr_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_prs_attr_regs);
+ device_remove_file(dev, p_wrp_fm_dev->dev_attr_muram_free_size);
+ device_remove_file(dev, p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver);
+}
+
+int fm_dump_regs(void *h_fm, char *buf, int nn)
+{
+ t_Fm *p_Fm = (t_Fm *)h_fm;
+ uint8_t i = 0;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_TITLE(buf, n, p_Fm->p_FmDmaRegs, "FM-DMA Regs");
+
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmemsr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmmr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmhy);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsetr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtah);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtal);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtcid);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmra);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmrd);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmwcr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmebcr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmdcr);
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr, "fmdmplr");
+
+ for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS / 2 ; ++i)
+ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[i]);
+
+ FM_DMP_TITLE(buf, n, p_Fm->p_FmBmiRegs, "FM-BMI COMMON Regs");
+ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_init);
+ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg1);
+ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg2);
+ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ievr);
+ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ier);
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb, "fmbm_arb");
+ for (i = 0; i < 8 ; ++i)
+ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb[i]);
+
+ FM_DMP_TITLE(buf, n, p_Fm->p_FmQmiRegs, "FM-QMI COMMON Regs");
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gc);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eie);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eien);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eif);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ie);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ien);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_if);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gs);
+ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_etfc);
+
+ return n;
+}
+
+int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn)
+{
+ t_Fm *p_Fm = (t_Fm *)h_fm;
+ uint8_t i, j = 0;
+ int n = nn;
+
+ FM_DMP_TITLE(buf, n, NULL, "Tnums and Tnum dbg regs %d - %d",
+ tn_s, tn_e);
+
+ iowrite32be(tn_s << 24, &p_Fm->p_FmFpmRegs->fmfp_dra);
+
+ mb();
+
+ for (j = tn_s; j <= tn_e; j++) {
+ FM_DMP_LN(buf, n, "> fmfp_ts[%d]\n", j);
+ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ts[j]);
+ FM_DMP_V32(buf, n, p_Fm->p_FmFpmRegs, fmfp_dra);
+ FM_DMP_LN(buf, n, "> fmfp_drd[0-3]\n");
+
+ for (i = 0; i < 4 ; ++i)
+ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_drd[i]);
+
+ FM_DMP_LN(buf, n, "\n");
+
+ }
+
+ return n;
+}
+
+int fm_dump_cls_plan(void *h_fm_pcd, int cpn, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ int i = 0;
+ uint32_t tmp;
+ unsigned long i_flg;
+ int n = nn;
+ u_FmPcdKgIndirectAccessRegs *idac;
+ spinlock_t *p_lk;
+
+ p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock;
+ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
+
+ spin_lock_irqsave(p_lk, i_flg);
+
+ /* Read ClsPlan Block Action Regs */
+ tmp = (uint32_t)(FM_KG_KGAR_GO |
+ FM_KG_KGAR_READ |
+ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
+ DUMMY_PORT_ID |
+ ((uint32_t)cpn << FM_PCD_KG_KGAR_NUM_SHIFT) |
+ FM_PCD_KG_KGAR_WSEL_MASK);
+
+ if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp)) {
+ FM_DMP_LN(buf, nn, "Keygen scheme access violation");
+ spin_unlock_irqrestore(p_lk, i_flg);
+ return nn;
+ }
+ FM_DMP_TITLE(buf, n, &idac->clsPlanRegs,
+ "ClsPlan %d Indirect Access Regs", cpn);
+
+ for (i = 0; i < 8; i++)
+ FM_DMP_MEM_32(buf, n, &idac->clsPlanRegs.kgcpe[i]);
+
+ spin_unlock_irqrestore(p_lk, i_flg);
+
+ return n;
+}
+
+int fm_profile_dump_regs(void *h_fm_pcd, int ppn, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ t_FmPcdPlcrProfileRegs *p_prof_regs;
+ t_FmPcdPlcrRegs *p_plcr_regs;
+ t_FmPcdPlcr *p_plcr;
+ uint32_t tmp;
+ unsigned long i_flg;
+ int n = nn;
+ int toc = 10;
+ spinlock_t *p_lk;
+
+ p_plcr = p_pcd->p_FmPcdPlcr;
+ p_prof_regs = &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs;
+ p_plcr_regs = p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
+
+ p_lk = (spinlock_t *)((t_FmPcdPlcr *)p_plcr)->h_HwSpinlock;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_plcr_regs, "FM-PCD policer-profile regs");
+
+ tmp = (uint32_t)(FM_PCD_PLCR_PAR_GO |
+ FM_PCD_PLCR_PAR_R |
+ ((uint32_t)ppn << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
+ FM_PCD_PLCR_PAR_PWSEL_MASK);
+
+ spin_lock_irqsave(p_lk, i_flg);
+
+ iowrite32be(tmp, &p_plcr_regs->fmpl_par);
+
+ mb();
+
+ /* wait for the porfile regs to be present */
+ do {
+ --toc;
+ udelay(10);
+ if (!toc) {
+ /* looks like PLCR_PAR_GO refuses to clear */
+ spin_unlock_irqrestore(p_lk, i_flg);
+ FM_DMP_LN(buf, n, "Profile regs not accessible -");
+ FM_DMP_LN(buf, n, " check profile init process\n");
+ return n;
+ }
+ } while ((ioread32be(&p_plcr_regs->fmpl_par) & FM_PCD_PLCR_PAR_GO));
+
+ FM_DMP_TITLE(buf, n, p_prof_regs, "Profile %d regs", ppn);
+
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pemode);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegnia);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_peynia);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pernia);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecir);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecbs);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepepir_eir);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepbs_ebs);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pelts);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pects);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepts_ets);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegpc);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_peypc);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perpc);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perypc);
+ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perrpc);
+
+ spin_unlock_irqrestore(p_lk, i_flg);
+
+ return n;
+}
+
+int fm_dump_scheme(void *h_fm_pcd, int scnum, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ uint32_t tmp_ar;
+ unsigned long i_flg;
+ int i, n = nn;
+ spinlock_t *p_lk;
+ u_FmPcdKgIndirectAccessRegs *idac;
+
+ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
+ p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock;
+
+ spin_lock_irqsave(p_lk, i_flg);
+
+ tmp_ar = FmPcdKgBuildReadSchemeActionReg((uint8_t)scnum);
+ if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp_ar)) {
+ FM_DMP_LN(buf, nn,
+ "Keygen scheme access violation or no such scheme");
+ spin_unlock_irqrestore(p_lk, i_flg);
+ return nn;
+ }
+
+ FM_DMP_TITLE(buf, n, &idac->schemeRegs,
+ "Scheme %d Indirect Access Regs", scnum);
+
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mode);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekfc);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekdv);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmch);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmcl);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_fqb);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_hc);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ppc);
+
+ FM_DMP_TITLE(buf, n, &idac->schemeRegs.kgse_gec, "kgse_gec");
+
+ for (i = 0; i < FM_KG_NUM_OF_GENERIC_REGS; i++)
+ FM_DMP_MEM_32(buf, n, &idac->schemeRegs.kgse_gec[i]);
+
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_spc);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv0);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv1);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ccbs);
+ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mv);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ spin_unlock_irqrestore(p_lk, i_flg);
+
+ return n;
+}
+
+int fm_kg_pe_dump_regs(void *h_fm_pcd, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ int i = 0;
+ uint8_t prt_id = 0;
+ uint32_t tmp_ar;
+ unsigned long i_flg;
+ int n = nn;
+ u_FmPcdKgIndirectAccessRegs *idac;
+ t_FmPcdKg *p_kg;
+ spinlock_t *p_lk;
+
+ p_kg = p_pcd->p_FmPcdKg;
+ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs;
+ p_lk = (spinlock_t *)p_kg->h_HwSpinlock;
+
+ spin_lock_irqsave(p_lk, i_flg);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) {
+ SW_PORT_INDX_TO_HW_PORT_ID(prt_id, i);
+
+ tmp_ar = FmPcdKgBuildReadPortSchemeBindActionReg(prt_id);
+
+ if (fman_kg_write_ar_wait(p_kg->p_FmPcdKgRegs, tmp_ar)) {
+ FM_DMP_LN(buf, nn, "Keygen scheme access violation");
+ spin_unlock_irqrestore(p_lk, i_flg);
+ return nn;
+ }
+ FM_DMP_TITLE(buf, n, &idac->portRegs, "Port %d regs", prt_id);
+ FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_sp);
+ FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_cpp);
+ }
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ spin_unlock_irqrestore(p_lk, i_flg);
+
+ return n;
+}
+
+int fm_kg_dump_regs(void *h_fm_pcd, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs,
+ "FmPcdKgRegs Regs");
+
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gcr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eeer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seeer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gsr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_tpc);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_serc);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_fdor);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv0r);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv1r);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_feer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_ar);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ return n;
+}
+
+
+int fm_fpm_dump_regs(void *h_fm, char *buf, int nn)
+{
+ t_Fm *p_fm = (t_Fm *)h_fm;
+ uint8_t i;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_TITLE(buf, n, p_fm->p_FmFpmRegs, "FM-FPM Regs");
+
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tnc);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_prc);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_brkc);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_mxd);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist1);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist2);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_epi);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rie);
+
+ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev, "fmfp_fcev");
+ for (i = 0; i < 4; ++i)
+ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev[i]);
+
+ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee, "fmfp_cee");
+ for (i = 0; i < 4; ++i)
+ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee[i]);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc1);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc2);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsp);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsf);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rcr);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_extc);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext1);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext2);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_1);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_2);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rstc);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_cld);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_npi);
+ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ee);
+
+ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev, "fmfp_cev");
+ for (i = 0; i < 4; ++i)
+ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev[i]);
+
+ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps, "fmfp_ps");
+ for (i = 0; i < 64; ++i)
+ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps[i]);
+
+ return n;
+}
+
+int fm_prs_dump_regs(void *h_fm_pcd, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs,
+ "FM-PCD parser regs");
+
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpclim);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpimac);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, pmeec);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pevr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pever);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perer);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_ppsc);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pds);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rrs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rrs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rrs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srrs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rres);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rres);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rres);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srres);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spcs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spscs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_hxscs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrcs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwcs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrscs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwscs);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_fcscs);
+
+ return n;
+}
+
+int fm_plcr_dump_regs(void *h_fm_pcd, char *buf, int nn)
+{
+ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd;
+ int i = 0;
+ int n = nn;
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_TITLE(buf, n,
+ p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,
+ "FM policer regs");
+
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gcr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gsr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_evr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ier);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ifr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eevr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eier);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eifr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rpcnt);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ypcnt);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rrpcnt);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rypcnt);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_tpcnt);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_flmcnt);
+
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_serc);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_upcr);
+ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_dpmr);
+
+ FM_DMP_TITLE(buf, n,
+ &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr,
+ "fmpl_pmr");
+
+ for (i = 0; i < 63; ++i)
+ FM_DMP_MEM_32(buf, n,
+ &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr[i]);
+
+ return n;
+}
+
+int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val)
+{
+ t_Fm *p_fm = (t_Fm *)h_fm;
+
+ /* When applicable (when there is an "enable counters" bit),
+ check that counters are enabled */
+
+ switch (cnt_e) {
+ case (e_FM_COUNTERS_DEQ_1):
+ case (e_FM_COUNTERS_DEQ_2):
+ /* fall through */
+ case (e_FM_COUNTERS_DEQ_3):
+ if (p_fm->p_FmStateStruct->revInfo.majorRev >= 6)
+ return -EINVAL; /* counter not available */
+
+ /* Else fall through */
+ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
+ case (e_FM_COUNTERS_DEQ_0):
+ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
+ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
+ case (e_FM_COUNTERS_DEQ_FROM_FD):
+ /* fall through */
+ case (e_FM_COUNTERS_DEQ_CONFIRM):
+ if (!(ioread32be(&p_fm->p_FmQmiRegs->fmqm_gc) &
+ QMI_CFG_EN_COUNTERS))
+ return -EINVAL; /* Requested counter not available */
+ break;
+ default:
+ break;
+ }
+
+ switch (cnt_e) {
+ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_etfc);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dtfc);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_0):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc0);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_1):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc1);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_2):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc2);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_3):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc3);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfdc);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfcc);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_FROM_FD):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dffc);
+ return 0;
+ case (e_FM_COUNTERS_DEQ_CONFIRM):
+ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dcc);
+ return 0;
+ }
+ /* should never get here */
+ return -EINVAL; /* counter not available */
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h
new file mode 100644
index 000000000000..137653e91ec7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+
+#ifndef LNXWRP_SYSFS_FM_H_
+#define LNXWRP_SYSFS_FM_H_
+
+#include "lnxwrp_sysfs.h"
+
+int fm_sysfs_create(struct device *dev);
+void fm_sysfs_destroy(struct device *dev);
+int fm_dump_regs(void *h_dev, char *buf, int nn);
+int fm_fpm_dump_regs(void *h_dev, char *buf, int nn);
+int fm_kg_dump_regs(void *h_pcd, char *buf, int nn);
+int fm_kg_pe_dump_regs(void *h_pcd, char *buf, int nn);
+int fm_dump_scheme(void *h_pcd, int scnum, char *buf, int nn);
+int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn);
+int fm_dump_cls_plan(void *h_pcd, int cpn, char *buf, int nn);
+int fm_plcr_dump_regs(void *h_pcd, char *buf, int nn);
+int fm_prs_dump_regs(void *h_pcd, char *buf, int nn);
+int fm_profile_dump_regs(void *h_pcd, int ppnum, char *buf, int nn);
+
+#define FM_DMP_PGSZ_ERR { \
+ snprintf(&buf[PAGE_SIZE - 80], 70, \
+ "\n Err: current sysfs buffer reached PAGE_SIZE\n");\
+ n = PAGE_SIZE - 2; \
+ }
+
+#define FM_DMP_LN(buf, n, ...) \
+ do { \
+ int k, m = n; \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ n = m; \
+ } while (0)
+
+#define FM_DMP_TITLE(buf, n, addr, ...) \
+ do { \
+ int k, m = n; \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ if (addr) { \
+ phys_addr_t pa; \
+ pa = virt_to_phys(addr); \
+ m += k = \
+ snprintf(&buf[m], PAGE_SIZE - m, " (0x%lX)", \
+ (long unsigned int)(pa)); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ } \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, \
+ "\n----------------------------------------\n\n"); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ n = m; \
+ } while (0)
+
+#define FM_DMP_SUBTITLE(buf, n, ...) \
+ do { \
+ int k, m = n; \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, "------- "); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ n = m; \
+ } while (0)
+
+#define FM_DMP_MEM_32(buf, n, addr) \
+ { \
+ uint32_t val; \
+ phys_addr_t pa; \
+ int k, m = n; \
+ pa = virt_to_phys(addr); \
+ val = ioread32be((addr)); \
+ do { \
+ m += k = snprintf(&buf[m], \
+ PAGE_SIZE - m, "0x%010llX: 0x%08x\n", \
+ pa, val); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ n += k; \
+ } while (0) ;\
+ }
+
+#define FM_DMP_V32(buf, n, st, phrase) \
+ do { \
+ int k, m = n; \
+ phys_addr_t pa = virt_to_phys(&((st)->phrase)); \
+ k = snprintf(&buf[m], PAGE_SIZE - m, \
+ "0x%010llX: 0x%08x%8s\t%s\n", (unsigned long long) pa, \
+ ioread32be((uint32_t *)&((st)->phrase)), "", #phrase); \
+ if (k < 0 || m > PAGE_SIZE - 90) \
+ FM_DMP_PGSZ_ERR \
+ n += k; \
+ } while (0)
+
+#endif /* LNXWRP_SYSFS_FM_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c
new file mode 100644
index 000000000000..db8e824c71e7
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c
@@ -0,0 +1,1268 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "lnxwrp_sysfs.h"
+#include "lnxwrp_fm.h"
+#include "debug_ext.h"
+#include "lnxwrp_sysfs_fm_port.h"
+#include "lnxwrp_sysfs_fm.h"
+
+#include "../../sdk_fman/Peripherals/FM/Port/fm_port.h"
+#include "../../sdk_fman/Peripherals/FM/Port/fm_port_dsar.h"
+
+#if defined(__ERR_MODULE__)
+#undef __ERR_MODULE__
+#endif
+
+#include "../../sdk_fman/Peripherals/FM/fm.h"
+
+static const struct sysfs_stats_t portSysfsStats[] = {
+ /* RX/TX/OH common statistics */
+ {
+ .stat_name = "port_frame",
+ .stat_counter = e_FM_PORT_COUNTERS_FRAME,
+ },
+ {
+ .stat_name = "port_discard_frame",
+ .stat_counter = e_FM_PORT_COUNTERS_DISCARD_FRAME,
+ },
+ {
+ .stat_name = "port_dealloc_buf",
+ .stat_counter = e_FM_PORT_COUNTERS_DEALLOC_BUF,
+ },
+ {
+ .stat_name = "port_enq_total",
+ .stat_counter = e_FM_PORT_COUNTERS_ENQ_TOTAL,
+ },
+ /* TX/OH */
+ {
+ .stat_name = "port_length_err",
+ .stat_counter = e_FM_PORT_COUNTERS_LENGTH_ERR,
+ },
+ {
+ .stat_name = "port_unsupprted_format",
+ .stat_counter = e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT,
+ },
+ {
+ .stat_name = "port_deq_total",
+ .stat_counter = e_FM_PORT_COUNTERS_DEQ_TOTAL,
+ },
+ {
+ .stat_name = "port_deq_from_default",
+ .stat_counter = e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT,
+ },
+ {
+ .stat_name = "port_deq_confirm",
+ .stat_counter = e_FM_PORT_COUNTERS_DEQ_CONFIRM,
+ },
+ /* RX/OH */
+ {
+ .stat_name = "port_rx_bad_frame",
+ .stat_counter = e_FM_PORT_COUNTERS_RX_BAD_FRAME,
+ },
+ {
+ .stat_name = "port_rx_large_frame",
+ .stat_counter = e_FM_PORT_COUNTERS_RX_LARGE_FRAME,
+ },
+ {
+ .stat_name = "port_rx_out_of_buffers_discard",
+ .stat_counter = e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD,
+ },
+ {
+ .stat_name = "port_rx_filter_frame",
+ .stat_counter = e_FM_PORT_COUNTERS_RX_FILTER_FRAME,
+ },
+ /* TODO: Particular statistics for OH ports */
+ {}
+};
+
+static ssize_t show_fm_port_stats(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+ t_LnxWrpFmDev *p_LnxWrpFmDev;
+ unsigned long flags;
+ int n = 0;
+ uint8_t counter = 0;
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_LnxWrpFmPortDev == NULL))
+ return -EINVAL;
+
+ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev;
+ if (WARN_ON(p_LnxWrpFmDev == NULL))
+ return -EINVAL;
+
+ if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev)
+ return -EIO;
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ }
+
+ counter = fm_find_statistic_counter_by_name(
+ attr->attr.name,
+ portSysfsStats, NULL);
+
+ if (counter == e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR) {
+ uint32_t fmRev = 0;
+ fmRev = 0xffff &
+ ioread32(UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr +
+ 0x000c30c4));
+
+ if (fmRev == 0x0100) {
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "counter not available for revision 1\n");
+ local_irq_restore(flags);
+ }
+ return n;
+ }
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE, "\t%s counter: %u\n",
+ p_LnxWrpFmPortDev->name,
+ FM_PORT_GetCounter(p_LnxWrpFmPortDev->h_Dev,
+ (e_FmPortCounters) counter));
+ local_irq_restore(flags);
+
+ return n;
+}
+
+/* FM PORT RX/TX/OH statistics */
+static DEVICE_ATTR(port_frame, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_discard_frame, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_dealloc_buf, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_enq_total, S_IRUGO, show_fm_port_stats, NULL);
+/* FM PORT TX/OH statistics */
+static DEVICE_ATTR(port_length_err, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_unsupprted_format, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_deq_total, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_deq_from_default, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_deq_confirm, S_IRUGO, show_fm_port_stats, NULL);
+/* FM PORT RX/OH statistics */
+static DEVICE_ATTR(port_rx_bad_frame, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_rx_large_frame, S_IRUGO, show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_rx_out_of_buffers_discard, S_IRUGO,
+ show_fm_port_stats, NULL);
+static DEVICE_ATTR(port_rx_filter_frame, S_IRUGO, show_fm_port_stats, NULL);
+
+/* FM PORT TX statistics */
+static struct attribute *fm_tx_port_dev_stats_attributes[] = {
+ &dev_attr_port_frame.attr,
+ &dev_attr_port_discard_frame.attr,
+ &dev_attr_port_dealloc_buf.attr,
+ &dev_attr_port_enq_total.attr,
+ &dev_attr_port_length_err.attr,
+ &dev_attr_port_unsupprted_format.attr,
+ &dev_attr_port_deq_total.attr,
+ &dev_attr_port_deq_from_default.attr,
+ &dev_attr_port_deq_confirm.attr,
+ NULL
+};
+
+static const struct attribute_group fm_tx_port_dev_stats_attr_grp = {
+ .name = "statistics",
+ .attrs = fm_tx_port_dev_stats_attributes
+};
+
+/* FM PORT RX statistics */
+static struct attribute *fm_rx_port_dev_stats_attributes[] = {
+ &dev_attr_port_frame.attr,
+ &dev_attr_port_discard_frame.attr,
+ &dev_attr_port_dealloc_buf.attr,
+ &dev_attr_port_enq_total.attr,
+ &dev_attr_port_rx_bad_frame.attr,
+ &dev_attr_port_rx_large_frame.attr,
+ &dev_attr_port_rx_out_of_buffers_discard.attr,
+ &dev_attr_port_rx_filter_frame.attr,
+ NULL
+};
+
+static const struct attribute_group fm_rx_port_dev_stats_attr_grp = {
+ .name = "statistics",
+ .attrs = fm_rx_port_dev_stats_attributes
+};
+
+/* TODO: add particular OH ports statistics */
+static struct attribute *fm_oh_port_dev_stats_attributes[] = {
+ &dev_attr_port_frame.attr,
+ &dev_attr_port_discard_frame.attr,
+ &dev_attr_port_dealloc_buf.attr,
+ &dev_attr_port_enq_total.attr,
+ /*TX*/ &dev_attr_port_length_err.attr,
+ &dev_attr_port_unsupprted_format.attr,
+ &dev_attr_port_deq_total.attr,
+ &dev_attr_port_deq_from_default.attr,
+ &dev_attr_port_deq_confirm.attr,
+ /* &dev_attr_port_rx_bad_frame.attr, */
+ /* &dev_attr_port_rx_large_frame.attr, */
+ &dev_attr_port_rx_out_of_buffers_discard.attr,
+ /*&dev_attr_port_rx_filter_frame.attr, */
+ NULL
+};
+
+static const struct attribute_group fm_oh_port_dev_stats_attr_grp = {
+ .name = "statistics",
+ .attrs = fm_oh_port_dev_stats_attributes
+};
+
+static ssize_t show_fm_port_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "FM port driver registers dump.\n");
+ n = fm_port_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+static int fm_port_dsar_dump_mem(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ t_Fm *p_Fm;
+ uint8_t hardwarePortId;
+ uint32_t *param_page;
+ t_ArCommonDesc *ArCommonDescPtr;
+ uint32_t *mem;
+ int i, n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+ hardwarePortId = p_FmPort->hardwarePortId;
+ p_Fm = (t_Fm *)p_FmPort->h_Fm;
+
+ if (!FM_PORT_IsInDsar(p_FmPort))
+ {
+ FM_DMP_LN(buf, n, "port %u is not a DSAR port\n",
+ hardwarePortId);
+ return n;
+ }
+ FM_DMP_LN(buf, n, "port %u DSAR mem\n", hardwarePortId);
+ FM_DMP_LN(buf, n, "========================\n");
+
+ /* do I need request_mem_region here? */
+ param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4);
+ ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), 300*4)); /* this should be changed*/
+ mem = (uint32_t*)ArCommonDescPtr;
+ for (i = 0; i < 300; i+=4)
+ FM_DMP_LN(buf, n, "%08x: %08x %08x %08x %08x\n", i*4, mem[i], mem[i + 1], mem[i + 2], mem[i + 3]);
+ iounmap(ArCommonDescPtr);
+ iounmap(param_page);
+ return n;
+}
+
+static int fm_port_dsar_dump_regs(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ t_Fm *p_Fm;
+ uint8_t hardwarePortId;
+ uint32_t *param_page;
+ t_ArCommonDesc *ArCommonDescPtr;
+ int i, n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+ hardwarePortId = p_FmPort->hardwarePortId;
+ p_Fm = (t_Fm *)p_FmPort->h_Fm;
+
+ if (!FM_PORT_IsInDsar(p_FmPort))
+ {
+ FM_DMP_LN(buf, n, "port %u is not a DSAR port\n",
+ hardwarePortId);
+ return n;
+ }
+ FM_DMP_LN(buf, n, "port %u DSAR information\n", hardwarePortId);
+ FM_DMP_LN(buf, n, "========================\n");
+
+ /* do I need request_mem_region here? */
+ param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4);
+ ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), sizeof(t_ArCommonDesc))); /* this should be changed*/
+ FM_DMP_LN(buf, n, "Tx port: 0x%x\n", ArCommonDescPtr->arTxPort);
+ FM_DMP_LN(buf, n, "Active HPNIA: 0x%08x\n", ArCommonDescPtr->activeHPNIA);
+ FM_DMP_LN(buf, n, "Snmp port: 0x%x\n", ArCommonDescPtr->snmpPort);
+ FM_DMP_LN(buf, n, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", ArCommonDescPtr->macStationAddr[0],
+ ArCommonDescPtr->macStationAddr[1], ArCommonDescPtr->macStationAddr[2],
+ ArCommonDescPtr->macStationAddr[3], ArCommonDescPtr->macStationAddr[4],
+ ArCommonDescPtr->macStationAddr[5]);
+ FM_DMP_LN(buf, n, "filterControl: 0x%02x\n", ArCommonDescPtr->filterControl);
+ FM_DMP_LN(buf, n, "tcpControlPass: 0x%04x\n", ArCommonDescPtr->tcpControlPass);
+ FM_DMP_LN(buf, n, "ipProtocolTblSize: 0x%x\n", ArCommonDescPtr->ipProtocolTblSize);
+ FM_DMP_LN(buf, n, "udpPortTblSize: 0x%x\n", ArCommonDescPtr->udpPortTblSize);
+ FM_DMP_LN(buf, n, "tcpPortTblSize: 0x%x\n", ArCommonDescPtr->tcpPortTblSize);
+ if (ArCommonDescPtr->p_ArStats)
+ {
+ t_ArStatistics *arStatistics = (t_ArStatistics*)
+ ioremap(ioread32be(&ArCommonDescPtr->p_ArStats) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof (t_ArStatistics));
+ FM_DMP_LN(buf, n, "\nDSAR statistics\n");
+ FM_DMP_LN(buf, n, "DSAR_Discarded: 0x%x\n", arStatistics->dsarDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_Err_Discarded: 0x%x\n", arStatistics->dsarErrDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_Frag_Discarded: 0x%x\n", arStatistics->dsarFragDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_Tunnel_Discarded: 0x%x\n", arStatistics->dsarTunnelDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_ARP_Discarded: 0x%x\n", arStatistics->dsarArpDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_IP_Discarded: 0x%x\n", arStatistics->dsarIpDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_TCP_Discarded: 0x%x\n", arStatistics->dsarTcpDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_UDP_Discarded: 0x%x\n", arStatistics->dsarUdpDiscarded);
+ FM_DMP_LN(buf, n, "DSAR_ICMPv6_Checksum_Err: 0x%x\n", arStatistics->dsarIcmpV6ChecksumErr);
+ FM_DMP_LN(buf, n, "DSAR_ICMPv6_Other_Type: 0x%x\n", arStatistics->dsarIcmpV6OtherType);
+ FM_DMP_LN(buf, n, "DSAR_ICMPv4_Other_Type: 0x%x\n", arStatistics->dsarIcmpV4OtherType);
+
+ iounmap(arStatistics);
+ }
+ if (ArCommonDescPtr->p_ArpDescriptor)
+ {
+ t_DsarArpDescriptor* ArpDescriptor = (t_DsarArpDescriptor*)
+ ioremap(ioread32be(&ArCommonDescPtr->p_ArpDescriptor) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof (t_DsarArpDescriptor));
+ FM_DMP_LN(buf, n, "\nARP\n");
+ FM_DMP_LN(buf, n, "===\n");
+ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ArpDescriptor->control);
+ if (ArpDescriptor->numOfBindings)
+ {
+ char ip_str[100];
+ t_DsarArpBindingEntry* bindings = ioremap(
+ ioread32be(&ArpDescriptor->p_Bindings) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ ArpDescriptor->numOfBindings *
+ sizeof(t_DsarArpBindingEntry));
+ uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr;
+ FM_DMP_LN(buf, n, " ip vlan id\n");
+ for (i = 0; i < ArpDescriptor->numOfBindings; i++)
+ {
+ n += snprintf(ip_str, 100, "%d.%d.%d.%d",
+ ip_addr[0], ip_addr[1],
+ ip_addr[2], ip_addr[3]);
+ FM_DMP_LN(buf, n, "%-15s 0x%x\n",
+ ip_str, bindings->vlanId);
+ }
+ iounmap(bindings);
+ }
+ if (ArpDescriptor->p_Statistics)
+ {
+ t_DsarArpStatistics* arpStats = ioremap(
+ ioread32be(&ArpDescriptor->p_Statistics) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof(t_DsarArpStatistics));
+ FM_DMP_LN(buf, n, "statistics\n");
+ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", arpStats->invalCnt);
+ FM_DMP_LN(buf, n, "ECHO_CNT: 0x%x\n", arpStats->echoCnt);
+ FM_DMP_LN(buf, n, "CD_CNT: 0x%x\n", arpStats->cdCnt);
+ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", arpStats->arCnt);
+ FM_DMP_LN(buf, n, "RATM_CNT: 0x%x\n", arpStats->ratmCnt);
+ FM_DMP_LN(buf, n, "UKOP_CNT: 0x%x\n", arpStats->ukopCnt);
+ FM_DMP_LN(buf, n, "NMTP_CNT: 0x%x\n", arpStats->nmtpCnt);
+ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", arpStats->nmVlanCnt);
+ iounmap(arpStats);
+ }
+
+ iounmap(ArpDescriptor);
+ }
+ if (ArCommonDescPtr->p_IcmpV4Descriptor)
+ {
+ t_DsarIcmpV4Descriptor* ICMPV4Descriptor =
+ (t_DsarIcmpV4Descriptor*)ioremap(ioread32be(
+ &ArCommonDescPtr->p_IcmpV4Descriptor) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof (t_DsarIcmpV4Descriptor));
+ FM_DMP_LN(buf, n, "\nEcho ICMPv4\n");
+ FM_DMP_LN(buf, n, "===========\n");
+ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV4Descriptor->control);
+ if (ICMPV4Descriptor->numOfBindings)
+ {
+ char ip_str[100];
+ t_DsarArpBindingEntry* bindings = ioremap(
+ ioread32be(&ICMPV4Descriptor->p_Bindings) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ ICMPV4Descriptor->numOfBindings *
+ sizeof(t_DsarArpBindingEntry));
+ uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr;
+ FM_DMP_LN(buf, n, " ip vlan id\n");
+ for (i = 0; i < ICMPV4Descriptor->numOfBindings; i++)
+ {
+ n += snprintf(ip_str, 100, "%d.%d.%d.%d",
+ ip_addr[0], ip_addr[1],
+ ip_addr[2], ip_addr[3]);
+ FM_DMP_LN(buf, n, "%-15s 0x%x\n",
+ ip_str, bindings->vlanId);
+ }
+ iounmap(bindings);
+ }
+ if (ICMPV4Descriptor->p_Statistics)
+ {
+ t_DsarIcmpV4Statistics* icmpv4Stats = ioremap(
+ ioread32be(&ICMPV4Descriptor->p_Statistics) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof(t_DsarIcmpV4Statistics));
+ FM_DMP_LN(buf, n, "statistics\n");
+ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", icmpv4Stats->invalCnt);
+ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", icmpv4Stats->nmVlanCnt);
+ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", icmpv4Stats->nmIpCnt);
+ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", icmpv4Stats->arCnt);
+ FM_DMP_LN(buf, n, "CSERR_CNT: 0x%x\n", icmpv4Stats->cserrCnt);
+ iounmap(icmpv4Stats);
+ }
+ iounmap(ICMPV4Descriptor);
+ }
+ if (ArCommonDescPtr->p_NdDescriptor)
+ {
+ t_DsarNdDescriptor *NDDescriptor =
+ (t_DsarNdDescriptor*)ioremap(ioread32be(
+ &ArCommonDescPtr->p_NdDescriptor) + p_FmPort->
+ fmMuramPhysBaseAddr, sizeof (t_DsarNdDescriptor));
+ FM_DMP_LN(buf, n, "\nNDP\n");
+ FM_DMP_LN(buf, n, "===\n");
+ FM_DMP_LN(buf, n, "control bits 0x%04x\n", NDDescriptor->control);
+ FM_DMP_LN(buf, n, "solicited address 0x%08x\n", NDDescriptor->solicitedAddr);
+ if (NDDescriptor->numOfBindings)
+ {
+ char ip_str[100];
+ t_DsarIcmpV6BindingEntry* bindings = ioremap(
+ ioread32be(&NDDescriptor->p_Bindings) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ NDDescriptor->numOfBindings *
+ sizeof(t_DsarIcmpV6BindingEntry));
+ uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr;
+ FM_DMP_LN(buf, n, " ip vlan id\n");
+ for (i = 0; i < NDDescriptor->numOfBindings; i++)
+ {
+ n += snprintf(ip_str, 100,
+ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+ ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3],
+ ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]);
+ FM_DMP_LN(buf, n, "%s 0x%x\n", ip_str, bindings->vlanId);
+ }
+ iounmap(bindings);
+ }
+ if (NDDescriptor->p_Statistics)
+ {
+ t_NdStatistics* ndStats = ioremap(
+ ioread32be(&NDDescriptor->p_Statistics) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof(t_NdStatistics));
+ FM_DMP_LN(buf, n, "statistics\n");
+ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", ndStats->invalCnt);
+ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", ndStats->nmVlanCnt);
+ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", ndStats->nmIpCnt);
+ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", ndStats->arCnt);
+ FM_DMP_LN(buf, n, "USADVERT_CNT: 0x%x\n", ndStats->usadvertCnt);
+ FM_DMP_LN(buf, n, "NMMCAST_CNT: 0x%x\n", ndStats->nmmcastCnt);
+ FM_DMP_LN(buf, n, "NSLLA_CNT: 0x%x\n", ndStats->nsllaCnt);
+ iounmap(ndStats);
+ }
+ iounmap(NDDescriptor);
+ }
+ if (ArCommonDescPtr->p_IcmpV6Descriptor)
+ {
+ t_DsarIcmpV6Descriptor *ICMPV6Descriptor =
+ (t_DsarIcmpV6Descriptor*)ioremap(ioread32be(
+ &ArCommonDescPtr->p_IcmpV6Descriptor) + p_FmPort->
+ fmMuramPhysBaseAddr, sizeof (t_DsarIcmpV6Descriptor));
+ FM_DMP_LN(buf, n, "\nEcho ICMPv6\n");
+ FM_DMP_LN(buf, n, "===========\n");
+ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV6Descriptor->control);
+ if (ICMPV6Descriptor->numOfBindings)
+ {
+ char ip_str[100];
+ t_DsarIcmpV6BindingEntry* bindings = ioremap(
+ ioread32be(&ICMPV6Descriptor->p_Bindings) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ ICMPV6Descriptor->numOfBindings *
+ sizeof(t_DsarIcmpV6BindingEntry));
+ uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr;
+ FM_DMP_LN(buf, n, " ip vlan id\n");
+ for (i = 0; i < ICMPV6Descriptor->numOfBindings; i++)
+ {
+ n += snprintf(ip_str, 100,
+ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+ ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3],
+ ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]);
+ FM_DMP_LN(buf, n, "%s 0x%x\n", ip_str, bindings->vlanId);
+ }
+ iounmap(bindings);
+ }
+ if (ICMPV6Descriptor->p_Statistics)
+ {
+ t_DsarIcmpV6Statistics* icmpv6Stats = ioremap(
+ ioread32be(&ICMPV6Descriptor->p_Statistics) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof(t_DsarIcmpV6Statistics));
+ FM_DMP_LN(buf, n, "statistics\n");
+ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", icmpv6Stats->invalCnt);
+ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", icmpv6Stats->nmVlanCnt);
+ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", icmpv6Stats->nmIpCnt);
+ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", icmpv6Stats->arCnt);
+ iounmap(icmpv6Stats);
+ }
+ iounmap(ICMPV6Descriptor);
+ }
+ if (ArCommonDescPtr->p_SnmpDescriptor)
+ {
+ t_DsarSnmpDescriptor *SnmpDescriptor =
+ (t_DsarSnmpDescriptor*)ioremap(ioread32be(
+ &ArCommonDescPtr->p_SnmpDescriptor) + p_FmPort->
+ fmMuramPhysBaseAddr, sizeof (t_DsarSnmpDescriptor));
+ FM_DMP_LN(buf, n, "\nSNMP\n");
+ FM_DMP_LN(buf, n, "===========\n");
+ FM_DMP_LN(buf, n, "control bits 0x%04x\n", SnmpDescriptor->control);
+ FM_DMP_LN(buf, n, "max message length 0x%04x\n", SnmpDescriptor->maxSnmpMsgLength);
+ if (SnmpDescriptor->numOfIpv4Addresses)
+ {
+ char ip_str[100];
+ t_DsarSnmpIpv4AddrTblEntry* addrs = ioremap(
+ ioread32be(&SnmpDescriptor->p_Ipv4AddrTbl) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ SnmpDescriptor->numOfIpv4Addresses *
+ sizeof(t_DsarSnmpIpv4AddrTblEntry));
+ uint8_t* ip_addr = (uint8_t*)&addrs->ipv4Addr;
+ FM_DMP_LN(buf, n, " ip vlan id\n");
+ for (i = 0; i < SnmpDescriptor->numOfIpv4Addresses; i++)
+ {
+ n += snprintf(ip_str, 100, "%d.%d.%d.%d",
+ ip_addr[0], ip_addr[1],
+ ip_addr[2], ip_addr[3]);
+ FM_DMP_LN(buf, n, "%-15s 0x%x\n", ip_str, addrs->vlanId);
+ }
+ iounmap(addrs);
+ }
+ if (SnmpDescriptor->p_Statistics)
+ {
+ t_DsarSnmpStatistics* snmpStats = ioremap(
+ ioread32be(&SnmpDescriptor->p_Statistics) +
+ p_FmPort->fmMuramPhysBaseAddr,
+ sizeof(t_DsarSnmpStatistics));
+ FM_DMP_LN(buf, n, "statistics\n");
+ FM_DMP_LN(buf, n, "snmpErrCnt: 0x%x\n", snmpStats->snmpErrCnt);
+ FM_DMP_LN(buf, n, "snmpCommunityErrCnt: 0x%x\n", snmpStats->snmpCommunityErrCnt);
+ FM_DMP_LN(buf, n, "snmpTotalDiscardCnt: 0x%x\n", snmpStats->snmpTotalDiscardCnt);
+ FM_DMP_LN(buf, n, "snmpGetReqCnt: 0x%x\n", snmpStats->snmpGetReqCnt);
+ FM_DMP_LN(buf, n, "snmpGetNextReqCnt: 0x%x\n", snmpStats->snmpGetNextReqCnt);
+ iounmap(snmpStats);
+ }
+ iounmap(SnmpDescriptor);
+ }
+ iounmap(ArCommonDescPtr);
+ iounmap(param_page);
+ return n;
+}
+
+static ssize_t show_fm_port_dsar_mem(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "FM port driver registers dump.\n");
+ n = fm_port_dsar_dump_mem(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+static ssize_t show_fm_port_dsar_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "FM port driver registers dump.\n");
+ n = fm_port_dsar_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+#if (DPAA_VERSION >= 11)
+static ssize_t show_fm_port_ipv4_options(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else if (((t_FmPort *)p_LnxWrpFmPortDev->h_Dev)->p_ParamsPage
+ == NULL) {
+ n = snprintf(buf, PAGE_SIZE,
+ "\tPort: FMan-controller params page not set\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "Counter for fragmented pkt with IP header options\n");
+ n = fm_port_dump_ipv4_opt(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+#endif
+
+static ssize_t show_fm_port_bmi_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "FM port driver registers dump.\n");
+ n = fm_port_dump_regs_bmi(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+static ssize_t show_fm_port_qmi_regs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ unsigned n = 0;
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+#endif
+
+ if (attr == NULL || buf == NULL || dev == NULL)
+ return -EINVAL;
+
+#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
+ p_LnxWrpFmPortDev =
+ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+
+ local_irq_save(flags);
+
+ if (!p_LnxWrpFmPortDev->h_Dev) {
+ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n");
+ return n;
+ } else {
+ n = snprintf(buf, PAGE_SIZE,
+ "FM port driver registers dump.\n");
+ n = fm_port_dump_regs_qmi(p_LnxWrpFmPortDev->h_Dev, buf, n);
+ }
+
+ local_irq_restore(flags);
+
+ return n;
+#else
+
+ local_irq_save(flags);
+ n = snprintf(buf, PAGE_SIZE,
+ "Debug level is too low to dump registers!!!\n");
+ local_irq_restore(flags);
+
+ return n;
+#endif
+}
+
+static DEVICE_ATTR(fm_port_regs, S_IRUGO | S_IRUSR, show_fm_port_regs, NULL);
+static DEVICE_ATTR(fm_port_qmi_regs, S_IRUGO | S_IRUSR, show_fm_port_qmi_regs, NULL);
+static DEVICE_ATTR(fm_port_bmi_regs, S_IRUGO | S_IRUSR, show_fm_port_bmi_regs, NULL);
+#if (DPAA_VERSION >= 11)
+static DEVICE_ATTR(fm_port_ipv4_opt, S_IRUGO | S_IRUSR, show_fm_port_ipv4_options, NULL);
+#endif
+static DEVICE_ATTR(fm_port_dsar_regs, S_IRUGO | S_IRUSR, show_fm_port_dsar_regs, NULL);
+static DEVICE_ATTR(fm_port_dsar_mem, S_IRUGO | S_IRUSR, show_fm_port_dsar_mem, NULL);
+
+int fm_port_sysfs_create(struct device *dev)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev;
+
+ if (dev == NULL)
+ return -EINVAL;
+
+ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_LnxWrpFmPortDev == NULL))
+ return -EINVAL;
+
+ /* store to remove them when module is disabled */
+ p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs;
+ p_LnxWrpFmPortDev->dev_attr_qmi_regs = &dev_attr_fm_port_qmi_regs;
+ p_LnxWrpFmPortDev->dev_attr_bmi_regs = &dev_attr_fm_port_bmi_regs;
+#if (DPAA_VERSION >= 11)
+ p_LnxWrpFmPortDev->dev_attr_ipv4_opt = &dev_attr_fm_port_ipv4_opt;
+#endif
+ p_LnxWrpFmPortDev->dev_attr_dsar_regs = &dev_attr_fm_port_dsar_regs;
+ p_LnxWrpFmPortDev->dev_attr_dsar_mem = &dev_attr_fm_port_dsar_mem;
+ /* Registers dump entry - in future will be moved to debugfs */
+ if (device_create_file(dev, &dev_attr_fm_port_regs) != 0)
+ return -EIO;
+ if (device_create_file(dev, &dev_attr_fm_port_qmi_regs) != 0)
+ return -EIO;
+ if (device_create_file(dev, &dev_attr_fm_port_bmi_regs) != 0)
+ return -EIO;
+#if (DPAA_VERSION >= 11)
+ if (device_create_file(dev, &dev_attr_fm_port_ipv4_opt) != 0)
+ return -EIO;
+#endif
+ if (device_create_file(dev, &dev_attr_fm_port_dsar_regs) != 0)
+ return -EIO;
+ if (device_create_file(dev, &dev_attr_fm_port_dsar_mem) != 0)
+ return -EIO;
+
+ /* FM Ports statistics */
+ switch (p_LnxWrpFmPortDev->settings.param.portType) {
+ case e_FM_PORT_TYPE_TX:
+ case e_FM_PORT_TYPE_TX_10G:
+ if (sysfs_create_group
+ (&dev->kobj, &fm_tx_port_dev_stats_attr_grp) != 0)
+ return -EIO;
+ break;
+ case e_FM_PORT_TYPE_RX:
+ case e_FM_PORT_TYPE_RX_10G:
+ if (sysfs_create_group
+ (&dev->kobj, &fm_rx_port_dev_stats_attr_grp) != 0)
+ return -EIO;
+ break;
+ case e_FM_PORT_TYPE_DUMMY:
+ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
+ if (sysfs_create_group
+ (&dev->kobj, &fm_oh_port_dev_stats_attr_grp) != 0)
+ return -EIO;
+ break;
+ default:
+ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+ __func__);
+ return -EINVAL;
+ break;
+ };
+
+ return 0;
+}
+
+void fm_port_sysfs_destroy(struct device *dev)
+{
+ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL;
+
+ /* this function has never been tested !!! */
+
+ if (WARN_ON(dev == NULL))
+ return;
+
+ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev);
+ if (WARN_ON(p_LnxWrpFmPortDev == NULL))
+ return;
+
+ /* The name attribute will be freed also by these 2 functions? */
+ switch (p_LnxWrpFmPortDev->settings.param.portType) {
+ case e_FM_PORT_TYPE_TX:
+ case e_FM_PORT_TYPE_TX_10G:
+ sysfs_remove_group(&dev->kobj, &fm_tx_port_dev_stats_attr_grp);
+ break;
+ case e_FM_PORT_TYPE_RX:
+ case e_FM_PORT_TYPE_RX_10G:
+ sysfs_remove_group(&dev->kobj, &fm_rx_port_dev_stats_attr_grp);
+ break;
+ case e_FM_PORT_TYPE_DUMMY:
+ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING:
+ sysfs_remove_group(&dev->kobj, &fm_oh_port_dev_stats_attr_grp);
+ break;
+ default:
+ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__,
+ __func__);
+ break;
+ };
+
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs);
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_qmi_regs);
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_bmi_regs);
+#if (DPAA_VERSION >= 11)
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_ipv4_opt);
+#endif
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_regs);
+ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_mem);
+}
+
+
+int fm_port_dump_regs(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ t_Fm *p_Fm;
+ uint8_t hardwarePortId;
+ int n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+ hardwarePortId = p_FmPort->hardwarePortId;
+ p_Fm = (t_Fm *)p_FmPort->h_Fm;
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1],
+ "fmbm_pp for port %u", hardwarePortId);
+ FM_DMP_MEM_32(buf, n,
+ &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1]);
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1],
+ "fmbm_pfs for port %u", hardwarePortId);
+ FM_DMP_MEM_32(buf, n,
+ &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1]);
+
+ FM_DMP_TITLE(buf, n,
+ &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1],
+ "fmbm_spliodn for port %u", hardwarePortId);
+ FM_DMP_MEM_32(buf, n,
+ &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1]);
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId],
+ "fmfp_psfor port %u", hardwarePortId);
+ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId]);
+
+ FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2],
+ "fmdmplrfor port %u", hardwarePortId);
+ FM_DMP_MEM_32(buf, n,
+ &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2]);
+ return n;
+}
+
+#if (DPAA_VERSION >= 11)
+
+int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ int n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+
+ FM_DMP_V32(buf, n, p_FmPort->p_ParamsPage, ipfOptionsCounter);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ return n;
+}
+#endif
+
+int fm_port_dump_regs_bmi(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ u_FmPortBmiRegs *p_bmi;
+
+ char arr[20];
+ uint8_t flag;
+ int i = 0;
+ int n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+ p_bmi = p_FmPort->p_FmPortBmiRegs;
+
+ memset(arr, 0, sizeof(arr));
+ switch (p_FmPort->portType) {
+ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING):
+ strcpy(arr, "OFFLINE-PARSING");
+ flag = 0;
+ break;
+ case (e_FM_PORT_TYPE_OH_HOST_COMMAND):
+ strcpy(arr, "HOST-COMMAND");
+ flag = 0;
+ break;
+ case (e_FM_PORT_TYPE_RX):
+ strcpy(arr, "RX");
+ flag = 1;
+ break;
+ case (e_FM_PORT_TYPE_RX_10G):
+ strcpy(arr, "RX-10G");
+ flag = 1;
+ break;
+ case (e_FM_PORT_TYPE_TX):
+ strcpy(arr, "TX");
+ flag = 2;
+ break;
+ case (e_FM_PORT_TYPE_TX_10G):
+ strcpy(arr, "TX-10G");
+ flag = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ FM_DMP_TITLE(buf, n, NULL,
+ "FMan-Port (%s #%d) registers:",
+ arr, p_FmPort->portId);
+
+ FM_DMP_TITLE(buf, n, p_bmi, "Bmi Port Regs");
+
+ switch (flag) {
+ case (0):
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocfg);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ost);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oda);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oicp);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdne);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofne);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofca);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofpne);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opso);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opp);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occb);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oim);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofp);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofed);
+
+ FM_DMP_TITLE(buf, n,
+ &(p_bmi->ohPortBmiRegs.fmbm_oprai), "fmbm_oprai");
+ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->ohPortBmiRegs.fmbm_oprai[i]));
+ }
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofqid);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oefqid);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsdm);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsem);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofene);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmts);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmt);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocmne);
+ {
+#ifndef FM_NO_OP_OBSERVED_POOLS
+ if (p_FmPort->fmRevInfo.majorRev == 4) {
+ FM_DMP_TITLE(buf, n,
+ &p_bmi->ohPortBmiRegs.fmbm_oebmpi,
+ "fmbm_oebmpi");
+
+ for (i = 0; i < FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->ohPortBmiRegs.fmbm_oebmpi[i]));
+ }
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocgm);
+ }
+#endif /* !FM_NO_OP_OBSERVED_POOLS */
+ }
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ostc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofrc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofledc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofufdc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_offc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofwdc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofldec);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opcp);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occn);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_otuc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oduc);
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofuc);
+ FM_DMP_TITLE(buf, n, &(p_bmi->ohPortBmiRegs.fmbm_odcfg),
+ "fmbm_odcfg");
+ for (i = 0; i < 3; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->ohPortBmiRegs.fmbm_odcfg[i]));
+ }
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ogpr);
+ break;
+ case (1):
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcfg);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rst);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rda);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfp);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_reth);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfed);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_ricp);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rebm);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfne);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfca);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfpne);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpso);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpp);
+ FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rprai),
+ "fmbm_rprai");
+ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->rxPortBmiRegs.fmbm_rprai[i]));
+ }
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfqid);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_refqid);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsdm);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsem);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfene);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcmne);
+ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_ebmpi,
+ "fmbm_ebmpi");
+ for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->rxPortBmiRegs.fmbm_ebmpi[i]));
+ }
+ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_acnt,
+ "fmbm_acnt");
+ for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->rxPortBmiRegs.fmbm_acnt[i]));
+ }
+ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_rcgm,
+ "fmbm_rcgm");
+ for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS / 32; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->rxPortBmiRegs.fmbm_rcgm[i]));
+ }
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rmpd);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rstc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfrc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfbc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rlfc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rffc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfcd);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfldec);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rodc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpcp);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rccn);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rtuc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rrquc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rduc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfuc);
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpac);
+ FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rdcfg),
+ "fmbm_rdcfg");
+ for (i = 0; i < 3; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->rxPortBmiRegs.fmbm_rdcfg[i]));
+ }
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rgpr);
+ break;
+ case (2):
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfg);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tst);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tda);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfp);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfed);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ticp);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdne);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfca);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfqid);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfeqid);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfene);
+#if (DPAA_VERSION >= 11)
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfne);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcmne);
+#endif /* (DPAA_VERSION >= 11) */
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmts);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmt);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tstc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfrc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfledc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfufdc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpcp);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tccn);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttuc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttcquc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tduc);
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfuc);
+ FM_DMP_TITLE(buf, n, &(p_bmi->txPortBmiRegs.fmbm_tdcfg),
+ "fmbm_tdcfg");
+ for (i = 0; i < 3 ; ++i) {
+ FM_DMP_MEM_32(buf, n,
+ &(p_bmi->txPortBmiRegs.fmbm_tdcfg[i]));
+ }
+ FM_DMP_SUBTITLE(buf, n, "\n");
+ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tgpr);
+ break;
+ }
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ return n;
+}
+
+int fm_port_dump_regs_qmi(void *h_dev, char *buf, int nn)
+{
+ t_FmPort *p_FmPort;
+ int n = nn;
+
+ p_FmPort = (t_FmPort *)h_dev;
+
+ FM_DMP_TITLE(buf, n, p_FmPort->p_FmPortQmiRegs, "Qmi Port Regs");
+
+ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnc);
+ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pns);
+ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnts);
+ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnen);
+ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnetfc);
+ FM_DMP_V32(buf, n,
+ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndn);
+ FM_DMP_V32(buf, n,
+ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndc);
+ FM_DMP_V32(buf, n,
+ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndtfc);
+ FM_DMP_V32(buf, n,
+ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndfdc);
+ FM_DMP_V32(buf, n,
+ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndcc);
+
+ FM_DMP_SUBTITLE(buf, n, "\n");
+
+ return n;
+}
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h
new file mode 100644
index 000000000000..1e7636f47fc4
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/*
+ @File lnxwrp_sysfs_fm_port.h
+
+ @Description FM port sysfs functions.
+
+*/
+
+#ifndef LNXWRP_SYSFS_FM_PORT_H_
+#define LNXWRP_SYSFS_FM_PORT_H_
+
+#include "lnxwrp_sysfs.h"
+
+int fm_port_sysfs_create(struct device *dev);
+void fm_port_sysfs_destroy(struct device *dev);
+
+int fm_port_dump_regs(void *h_dev, char *buf, int n);
+int fm_port_dump_regs_bmi(void *h_dev, char *buf, int n);
+int fm_port_dump_regs_qmi(void *h_dev, char *buf, int n);
+
+#if (DPAA_VERSION >= 11)
+int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int n);
+#endif
+
+#endif /* LNXWRP_SYSFS_FM_PORT_H_ */
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile
new file mode 100644
index 000000000000..1071c22a4289
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Freescale Ethernet controllers
+#
+ccflags-y += -DVERSION=\"\"
+#
+#Include netcomm SW specific definitions
+include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
+
+obj-y += fsl-ncsw-xx.o
+
+ifneq ($(CONFIG_FMAN_ARM),y)
+fsl-ncsw-xx-objs := xx_linux.o \
+ module_strings.o
+else
+fsl-ncsw-xx-objs := xx_arm_linux.o \
+ module_strings.o
+endif
+
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c
new file mode 100644
index 000000000000..d7fed170d713
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/* Module names for debug messages */
+const char *moduleStrings[] =
+{
+ "", /* MODULE_UNKNOWN */
+ "FM", /* MODULE_FM */
+ "FM-MURAM", /* MODULE_FM_MURAM */
+ "FM-PCD", /* MODULE_FM_PCD */
+ "FM-RTC", /* MODULE_FM_RTC */
+ "FM-MAC", /* MODULE_FM_MAC */
+ "FM-Port", /* MODULE_FM_PORT */
+ "MM", /* MODULE_MM */
+ "FM-SP", /* MODULE_FM_SP */
+ "FM-MACSEC" /* MODULE_FM_MACSEC */
+};
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
new file mode 100644
index 000000000000..ea59e413ce80
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File xx_arm_linux.c
+
+ @Description XX routines implementation for Linux.
+*//***************************************************************************/
+#include <linux/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/smp.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
+
+#include <linux/workqueue.h>
+
+#ifdef BIGPHYSAREA_ENABLE
+#include <linux/bigphysarea.h>
+#endif /* BIGPHYSAREA_ENABLE */
+
+//#include <sysdev/fsl_soc.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/string.h>
+#include <asm/byteorder.h>
+#include <asm/page.h>
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "list_ext.h"
+#include "mm_ext.h"
+#include "sys_io_ext.h"
+#include "xx.h"
+
+
+#define __ERR_MODULE__ MODULE_UNKNOWN
+
+#ifdef BIGPHYSAREA_ENABLE
+#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */
+
+
+/* TODO: large allocations => use big phys area */
+/******************************************************************************
+ * routine: get_nr_pages
+ *
+ * description:
+ * calculates the number of memory pages for a given size (in bytes)
+ *
+ * arguments:
+ * size - the number of bytes
+ *
+ * return code:
+ * The number of pages
+ *
+ *****************************************************************************/
+static __inline__ uint32_t get_nr_pages (uint32_t size)
+{
+ return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0));
+}
+
+static bool in_big_phys_area (uint32_t addr)
+{
+ uint32_t base, size;
+
+ bigphysarea_get_details (&base, &size);
+ return ((addr >= base) && (addr < base + size));
+}
+#endif /* BIGPHYSAREA_ENABLE */
+
+void * xx_Malloc(uint32_t n)
+{
+ void *a;
+ uint32_t flags;
+
+ flags = XX_DisableAllIntr();
+#ifdef BIGPHYSAREA_ENABLE
+ if (n >= MAX_ALLOCATION_SIZE)
+ a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC);
+ else
+#endif /* BIGPHYSAREA_ENABLE */
+ a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC);
+ if (!a)
+ XX_Print("No memory for XX_Malloc\n");
+ XX_RestoreAllIntr(flags);
+
+ return a;
+}
+
+void xx_Free(void *p)
+{
+#ifdef BIGPHYSAREA_ENABLE
+ if (in_big_phys_area ((uint32_t)p))
+ bigphysarea_free_pages(p);
+ else
+#endif /* BIGPHYSAREA_ENABLE */
+ kfree(p);
+}
+
+void XX_Exit(int status)
+{
+ WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n");
+}
+
+#define BUF_SIZE 512
+void XX_Print(char *str, ...)
+{
+ va_list args;
+#ifdef CONFIG_SMP
+ char buf[BUF_SIZE];
+#endif /* CONFIG_SMP */
+
+ va_start(args, str);
+#ifdef CONFIG_SMP
+ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
+ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
+ printk(KERN_CRIT "cpu %d: %s", raw_smp_processor_id(), buf);
+#else
+ vprintk(str, args);
+#endif /* CONFIG_SMP */
+ va_end(args);
+}
+
+void XX_Fprint(void *file, char *str, ...)
+{
+ va_list args;
+#ifdef CONFIG_SMP
+ char buf[BUF_SIZE];
+#endif /* CONFIG_SMP */
+
+ va_start(args, str);
+#ifdef CONFIG_SMP
+ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
+ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
+ printk (KERN_CRIT "cpu %d: %s", smp_processor_id(), buf);
+
+#else
+ vprintk(str, args);
+#endif /* CONFIG_SMP */
+ va_end(args);
+}
+
+#ifdef DEBUG_XX_MALLOC
+typedef void (*t_ffn)(void *);
+typedef struct {
+ t_ffn f_free;
+ void *mem;
+ char *fname;
+ int fline;
+ uint32_t size;
+ t_List node;
+} t_MemDebug;
+#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node)
+
+LIST(memDbgLst);
+
+
+void * XX_MallocDebug(uint32_t size, char *fname, int line)
+{
+ void *mem;
+ t_MemDebug *p_MemDbg;
+
+ p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug));
+ if (p_MemDbg == NULL)
+ return NULL;
+
+ mem = xx_Malloc(size);
+ if (mem == NULL)
+ {
+ XX_Free(p_MemDbg);
+ return NULL;
+ }
+
+ INIT_LIST(&p_MemDbg->node);
+ p_MemDbg->f_free = xx_Free;
+ p_MemDbg->mem = mem;
+ p_MemDbg->fname = fname;
+ p_MemDbg->fline = line;
+ p_MemDbg->size = size+sizeof(t_MemDebug);
+ LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
+
+ return mem;
+}
+
+void * XX_MallocSmartDebug(uint32_t size,
+ int memPartitionId,
+ uint32_t align,
+ char *fname,
+ int line)
+{
+ void *mem;
+ t_MemDebug *p_MemDbg;
+
+ p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug));
+ if (p_MemDbg == NULL)
+ return NULL;
+
+ mem = xx_MallocSmart((uint32_t)size, memPartitionId, align);
+ if (mem == NULL)
+ {
+ XX_Free(p_MemDbg);
+ return NULL;
+ }
+
+ INIT_LIST(&p_MemDbg->node);
+ p_MemDbg->f_free = xx_FreeSmart;
+ p_MemDbg->mem = mem;
+ p_MemDbg->fname = fname;
+ p_MemDbg->fline = line;
+ p_MemDbg->size = size+sizeof(t_MemDebug);
+ LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
+
+ return mem;
+}
+
+static void debug_free(void *mem)
+{
+ t_List *p_MemDbgLh = NULL;
+ t_MemDebug *p_MemDbg;
+ bool found = FALSE;
+
+ if (LIST_IsEmpty(&memDbgLst))
+ {
+ REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem));
+ return;
+ }
+
+ LIST_FOR_EACH(p_MemDbgLh, &memDbgLst)
+ {
+ p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh);
+ if (p_MemDbg->mem == mem)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_FOUND,
+ ("Attempt to free unallocated address (0x%08x)",mem));
+ dump_stack();
+ return;
+ }
+
+ LIST_Del(p_MemDbgLh);
+ p_MemDbg->f_free(mem);
+ p_MemDbg->f_free(p_MemDbg);
+}
+
+void XX_FreeSmart(void *p)
+{
+ debug_free(p);
+}
+
+
+void XX_Free(void *p)
+{
+ debug_free(p);
+}
+
+#else /* not DEBUG_XX_MALLOC */
+void * XX_Malloc(uint32_t size)
+{
+ return xx_Malloc(size);
+}
+
+void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
+{
+ return xx_MallocSmart(size,memPartitionId, alignment);
+}
+
+void XX_FreeSmart(void *p)
+{
+ xx_FreeSmart(p);
+}
+
+
+void XX_Free(void *p)
+{
+ xx_Free(p);
+}
+#endif /* not DEBUG_XX_MALLOC */
+
+
+#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0))
+void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg)
+{
+ e_Event eventCode = (e_Event)event;
+
+ UNUSED(eventCode);
+ UNUSED(appId);
+ UNUSED(flags);
+ UNUSED(msg);
+}
+#endif /* (defined(REPORT_EVENTS) && ... */
+
+
+uint32_t XX_DisableAllIntr(void)
+{
+ unsigned long flags;
+
+#ifdef local_irq_save_nort
+ local_irq_save_nort(flags);
+#else
+ local_irq_save(flags);
+#endif
+
+ return (uint32_t)flags;
+}
+
+void XX_RestoreAllIntr(uint32_t flags)
+{
+#ifdef local_irq_restore_nort
+ local_irq_restore_nort((unsigned long)flags);
+#else
+ local_irq_restore((unsigned long)flags);
+#endif
+}
+
+t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags )
+{
+ UNUSED(qid);
+ UNUSED(appId);
+ UNUSED(flags);
+
+ return f(id);
+}
+
+int XX_IsICacheEnable(void)
+{
+ return TRUE;
+}
+
+int XX_IsDCacheEnable(void)
+{
+ return TRUE;
+}
+
+
+typedef struct {
+ t_Isr *f_Isr;
+ t_Handle handle;
+} t_InterruptHandler;
+
+
+t_Handle interruptHandlers[0x00010000];
+
+static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id)
+{
+ t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id;
+ p_IntrHndl->f_Isr(p_IntrHndl->handle);
+ return IRQ_HANDLED;
+}
+
+t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle)
+{
+ const char *device;
+ t_InterruptHandler *p_IntrHndl;
+
+ device = GetDeviceName(irq);
+ if (device == NULL)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq));
+
+ p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler));
+ if (p_IntrHndl == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ p_IntrHndl->f_Isr = f_Isr;
+ p_IntrHndl->handle = handle;
+ interruptHandlers[irq] = p_IntrHndl;
+
+ if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0)
+ RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device));
+ disable_irq(GetDeviceIrqNum(irq));
+
+ return E_OK;
+}
+
+t_Error XX_FreeIntr(int irq)
+{
+ t_InterruptHandler *p_IntrHndl = interruptHandlers[irq];
+ free_irq(GetDeviceIrqNum(irq), p_IntrHndl);
+ XX_Free(p_IntrHndl);
+ interruptHandlers[irq] = 0;
+ return E_OK;
+}
+
+t_Error XX_EnableIntr(int irq)
+{
+ enable_irq(GetDeviceIrqNum(irq));
+ return E_OK;
+}
+
+t_Error XX_DisableIntr(int irq)
+{
+ disable_irq(GetDeviceIrqNum(irq));
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Tasklet Service Routines */
+/*****************************************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+typedef struct
+{
+ t_Handle h_Data;
+ void (*f_Callback) (void *);
+ struct delayed_work dwork;
+} t_Tasklet;
+
+static void GenericTaskletCallback(struct work_struct *p_Work)
+{
+ t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work);
+
+ p_Task->f_Callback(p_Task->h_Data);
+}
+#endif /* LINUX_VERSION_CODE */
+
+
+t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ struct work_struct *p_Task;
+ p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct));
+ INIT_WORK(p_Task, routine, data);
+#else
+ t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet));
+ p_Task->h_Data = data;
+ p_Task->f_Callback = routine;
+ INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback);
+#endif /* LINUX_VERSION_CODE */
+
+ return (t_TaskletHandle)p_Task;
+}
+
+
+void XX_FreeTasklet (t_TaskletHandle h_Tasklet)
+{
+ if (h_Tasklet)
+ XX_Free(h_Tasklet);
+}
+
+int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate)
+{
+ int ans;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ if (immediate)
+ ans = schedule_work(h_Tasklet);
+ else
+ ans = schedule_delayed_work(h_Tasklet, 1);
+#else
+ if (immediate)
+ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0);
+ else
+ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ);
+#endif /* LINUX_VERSION_CODE */
+
+ return ans;
+}
+
+void XX_FlushScheduledTasks(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ flush_scheduled_tasks();
+#else
+ flush_scheduled_work();
+#endif /* LINUX_VERSION_CODE */
+}
+
+int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ return (int)(((struct work_struct *)h_Tasklet)->pending);
+#else
+ return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork);
+#endif /* LINUX_VERSION_CODE */
+}
+
+void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ ((struct tq_struct *)h_Tasklet)->data = data;
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ ((struct work_struct *)h_Tasklet)->data = data;
+#else
+ ((t_Tasklet *)h_Tasklet)->h_Data = data;
+#endif /* LINUX_VERSION_CODE */
+}
+
+t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ return (t_Handle)(((struct work_struct *)h_Tasklet)->data);
+#else
+ return ((t_Tasklet *)h_Tasklet)->h_Data;
+#endif /* LINUX_VERSION_CODE */
+}
+
+
+/*****************************************************************************/
+/* Spinlock Service Routines */
+/*****************************************************************************/
+
+t_Handle XX_InitSpinlock(void)
+{
+ spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t));
+ if (!p_Spinlock)
+ return NULL;
+
+ spin_lock_init(p_Spinlock);
+
+ return (t_Handle)p_Spinlock;
+}
+
+void XX_FreeSpinlock(t_Handle h_Spinlock)
+{
+ if (h_Spinlock)
+ XX_Free(h_Spinlock);
+}
+
+void XX_LockSpinlock(t_Handle h_Spinlock)
+{
+ spin_lock((spinlock_t *)h_Spinlock);
+}
+
+void XX_UnlockSpinlock(t_Handle h_Spinlock)
+{
+ spin_unlock((spinlock_t *)h_Spinlock);
+}
+
+uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock)
+{
+ unsigned long intrFlags;
+ spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags);
+ return intrFlags;
+}
+
+void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags)
+{
+ spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags);
+}
+
+
+/*****************************************************************************/
+/* Timers Service Routines */
+/*****************************************************************************/
+/* The time now is in mili sec. resolution */
+uint32_t XX_CurrentTime(void)
+{
+ return (jiffies*1000)/HZ;
+}
+
+#if 0
+t_Handle XX_CreateTimer(void)
+{
+ struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
+ if (p_Timer)
+ {
+ memset(p_Timer, 0, sizeof(struct timer_list));
+ init_timer(p_Timer);
+ }
+ return (t_Handle)p_Timer;
+}
+
+void XX_FreeTimer(t_Handle h_Timer)
+{
+ if (h_Timer)
+ XX_Free(h_Timer);
+}
+
+void XX_StartTimer(t_Handle h_Timer,
+ uint32_t msecs,
+ bool periodic,
+ void (*f_TimerExpired)(t_Handle),
+ t_Handle h_Arg)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED);
+
+ p_Timer->function = (void (*)(unsigned long))f_TimerExpired;
+ p_Timer->data = (unsigned long)h_Arg;
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ p_Timer->expires = (jiffies + tmp_jiffies);
+
+ add_timer((struct timer_list *)h_Timer);
+}
+
+void XX_SetTimerData(t_Handle h_Timer, t_Handle data)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ p_Timer->data = (unsigned long)data;
+}
+
+t_Handle XX_GetTimerData(t_Handle h_Timer)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ return (t_Handle)p_Timer->data;
+}
+
+uint32_t XX_GetExpirationTime(t_Handle h_Timer)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ return (uint32_t)p_Timer->expires;
+}
+
+void XX_StopTimer(t_Handle h_Timer)
+{
+ del_timer((struct timer_list *)h_Timer);
+}
+
+void XX_ModTimer(t_Handle h_Timer, uint32_t msecs)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies);
+}
+
+int XX_TimerIsActive(t_Handle h_Timer)
+{
+ return timer_pending((struct timer_list *)h_Timer);
+}
+#endif
+
+uint32_t XX_Sleep(uint32_t msecs)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ return schedule_timeout(tmp_jiffies);
+}
+
+/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/
+void XX_UDelay(uint32_t usecs)
+{
+ udelay(usecs);
+}
+
+/* TODO: verify that these are correct */
+#define MSG_BODY_SIZE 512
+typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]);
+typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]);
+t_Error XX_SendMessage(char *p_DestAddr,
+ uint32_t msgId,
+ uint8_t msgBody[MSG_BODY_SIZE],
+ t_MsgCompletionCB *f_CompletionCB,
+ t_Handle h_CBArg);
+
+typedef struct {
+ char *p_Addr;
+ t_MsgHandler *f_MsgHandlerCB;
+ t_Handle h_Mod;
+ t_List node;
+} t_MsgHndlr;
+#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node)
+
+LIST(msgHndlrList);
+
+static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr)
+{
+ uint32_t intFlags;
+
+ intFlags = XX_DisableAllIntr();
+ LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList);
+ XX_RestoreAllIntr(intFlags);
+}
+/* TODO: add this for multi-platform support
+static t_MsgHndlr * DequeueMsgHndlr(void)
+{
+ t_MsgHndlr *p_MsgHndlr = NULL;
+ uint32_t intFlags;
+
+ intFlags = XX_DisableAllIntr();
+ if (!LIST_IsEmpty(&msgHndlrList))
+ {
+ p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next);
+ LIST_DelAndInit(&p_MsgHndlr->node);
+ }
+ XX_RestoreAllIntr(intFlags);
+
+ return p_MsgHndlr;
+}
+*/
+static t_MsgHndlr * FindMsgHndlr(char *p_Addr)
+{
+ t_MsgHndlr *p_MsgHndlr;
+ t_List *p_Pos;
+
+ LIST_FOR_EACH(p_Pos, &msgHndlrList)
+ {
+ p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos);
+ if (strstr(p_MsgHndlr->p_Addr, p_Addr))
+ return p_MsgHndlr;
+ }
+
+ return NULL;
+}
+
+t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod)
+{
+ t_MsgHndlr *p_MsgHndlr;
+ uint32_t len;
+
+ p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr));
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
+ memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr));
+
+ len = strlen(p_Addr);
+ p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1);
+ strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1));
+
+ p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB;
+ p_MsgHndlr->h_Mod = h_Mod;
+ INIT_LIST(&p_MsgHndlr->node);
+ EnqueueMsgHndlr(p_MsgHndlr);
+
+ return E_OK;
+}
+
+t_Error XX_UnregisterMessageHandler (char *p_Addr)
+{
+ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr);
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
+
+ LIST_Del(&p_MsgHndlr->node);
+ XX_Free(p_MsgHndlr->p_Addr);
+ XX_Free(p_MsgHndlr);
+
+ return E_OK;
+}
+
+t_Error XX_SendMessage(char *p_DestAddr,
+ uint32_t msgId,
+ uint8_t msgBody[MSG_BODY_SIZE],
+ t_MsgCompletionCB *f_CompletionCB,
+ t_Handle h_CBArg)
+{
+ t_Error ans;
+ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr);
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
+
+ ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody);
+
+ if (f_CompletionCB)
+ f_CompletionCB(h_CBArg, msgBody);
+
+ return ans;
+}
+
+t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ t_IpcMsgHandler *f_MsgHandler,
+ t_Handle h_Module,
+ uint32_t replyLength)
+{
+ UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength);
+ return E_OK;
+}
+
+t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH])
+{
+ UNUSED(addr);
+ return E_OK;
+}
+
+
+t_Error XX_IpcSendMessage(t_Handle h_Session,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength,
+ t_IpcMsgCompletion *f_Completion,
+ t_Handle h_Arg)
+{
+ UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply);
+ UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg);
+ return E_OK;
+}
+
+t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH])
+{
+ UNUSED(destAddr); UNUSED(srcAddr);
+ return E_OK;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+int GetDeviceIrqNum(int irq)
+{
+ struct device_node *iPar;
+ struct irq_domain *irqHost;
+ uint32_t hwIrq;
+
+ /* Get the interrupt controller */
+ iPar = of_find_node_by_name(NULL, "mpic");
+ hwIrq = 0;
+
+ ASSERT_COND(iPar != NULL);
+ /* Get the irq host */
+ irqHost = irq_find_host(iPar);
+ of_node_put(iPar);
+
+ /* Create irq mapping */
+ return irq_create_mapping(irqHost, hwIrq);
+}
+#else
+#error "kernel not supported!!!"
+#endif /* LINUX_VERSION_CODE */
+
+void * XX_PhysToVirt(physAddress_t addr)
+{
+ return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr));
+}
+
+physAddress_t XX_VirtToPhys(void * addr)
+{
+ return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr));
+}
+
+void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
+{
+ uintptr_t *returnCode, tmp;
+
+ if (alignment < sizeof(uintptr_t))
+ alignment = sizeof(uintptr_t);
+ size += alignment + sizeof(returnCode);
+ tmp = (uintptr_t)xx_Malloc(size);
+ if (tmp == 0)
+ return NULL;
+ returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1));
+ *(returnCode - 1) = tmp;
+
+ return (void*)returnCode;
+}
+
+void xx_FreeSmart(void *p)
+{
+ xx_Free((void*)(*((uintptr_t *)(p) - 1)));
+}
diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
new file mode 100644
index 000000000000..076eccfe06fb
--- /dev/null
+++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c
@@ -0,0 +1,919 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+/**************************************************************************//**
+ @File xx_linux.c
+
+ @Description XX routines implementation for Linux.
+*//***************************************************************************/
+#include <linux/version.h>
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+#ifdef MODVERSIONS
+#include <config/modversions.h>
+#endif /* MODVERSIONS */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/smp.h>
+#include <linux/of.h>
+#ifdef CONFIG_FMAN_ARM
+#include <linux/irqdomain.h>
+#endif
+
+#include <linux/workqueue.h>
+
+#ifdef BIGPHYSAREA_ENABLE
+#include <linux/bigphysarea.h>
+#endif /* BIGPHYSAREA_ENABLE */
+
+#ifndef CONFIG_FMAN_ARM
+#include <sysdev/fsl_soc.h>
+#endif
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/string.h>
+#include <asm/byteorder.h>
+#include <asm/page.h>
+
+#include "error_ext.h"
+#include "std_ext.h"
+#include "list_ext.h"
+#include "mm_ext.h"
+#include "sys_io_ext.h"
+#include "xx.h"
+
+
+#define __ERR_MODULE__ MODULE_UNKNOWN
+
+#ifdef BIGPHYSAREA_ENABLE
+#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */
+
+
+/* TODO: large allocations => use big phys area */
+/******************************************************************************
+ * routine: get_nr_pages
+ *
+ * description:
+ * calculates the number of memory pages for a given size (in bytes)
+ *
+ * arguments:
+ * size - the number of bytes
+ *
+ * return code:
+ * The number of pages
+ *
+ *****************************************************************************/
+static __inline__ uint32_t get_nr_pages (uint32_t size)
+{
+ return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0));
+}
+
+static bool in_big_phys_area (uint32_t addr)
+{
+ uint32_t base, size;
+
+ bigphysarea_get_details (&base, &size);
+ return ((addr >= base) && (addr < base + size));
+}
+#endif /* BIGPHYSAREA_ENABLE */
+
+void * xx_Malloc(uint32_t n)
+{
+ void *a;
+ uint32_t flags;
+
+ flags = XX_DisableAllIntr();
+#ifdef BIGPHYSAREA_ENABLE
+ if (n >= MAX_ALLOCATION_SIZE)
+ a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC);
+ else
+#endif /* BIGPHYSAREA_ENABLE */
+ a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC);
+ if (!a)
+ XX_Print("No memory for XX_Malloc\n");
+ XX_RestoreAllIntr(flags);
+
+ return a;
+}
+
+void xx_Free(void *p)
+{
+#ifdef BIGPHYSAREA_ENABLE
+ if (in_big_phys_area ((uint32_t)p))
+ bigphysarea_free_pages(p);
+ else
+#endif /* BIGPHYSAREA_ENABLE */
+ kfree(p);
+}
+
+void XX_Exit(int status)
+{
+ WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n");
+}
+
+#define BUF_SIZE 512
+void XX_Print(char *str, ...)
+{
+ va_list args;
+#ifdef CONFIG_SMP
+ char buf[BUF_SIZE];
+#endif /* CONFIG_SMP */
+
+ va_start(args, str);
+#ifdef CONFIG_SMP
+ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
+ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
+ printk(KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf);
+#else
+ vprintk(str, args);
+#endif /* CONFIG_SMP */
+ va_end(args);
+}
+
+void XX_Fprint(void *file, char *str, ...)
+{
+ va_list args;
+#ifdef CONFIG_SMP
+ char buf[BUF_SIZE];
+#endif /* CONFIG_SMP */
+
+ va_start(args, str);
+#ifdef CONFIG_SMP
+ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE)
+ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE);
+ printk (KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf);
+
+#else
+ vprintk(str, args);
+#endif /* CONFIG_SMP */
+ va_end(args);
+}
+
+#ifdef DEBUG_XX_MALLOC
+typedef void (*t_ffn)(void *);
+typedef struct {
+ t_ffn f_free;
+ void *mem;
+ char *fname;
+ int fline;
+ uint32_t size;
+ t_List node;
+} t_MemDebug;
+#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node)
+
+LIST(memDbgLst);
+
+
+void * XX_MallocDebug(uint32_t size, char *fname, int line)
+{
+ void *mem;
+ t_MemDebug *p_MemDbg;
+
+ p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug));
+ if (p_MemDbg == NULL)
+ return NULL;
+
+ mem = xx_Malloc(size);
+ if (mem == NULL)
+ {
+ XX_Free(p_MemDbg);
+ return NULL;
+ }
+
+ INIT_LIST(&p_MemDbg->node);
+ p_MemDbg->f_free = xx_Free;
+ p_MemDbg->mem = mem;
+ p_MemDbg->fname = fname;
+ p_MemDbg->fline = line;
+ p_MemDbg->size = size+sizeof(t_MemDebug);
+ LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
+
+ return mem;
+}
+
+void * XX_MallocSmartDebug(uint32_t size,
+ int memPartitionId,
+ uint32_t align,
+ char *fname,
+ int line)
+{
+ void *mem;
+ t_MemDebug *p_MemDbg;
+
+ p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug));
+ if (p_MemDbg == NULL)
+ return NULL;
+
+ mem = xx_MallocSmart((uint32_t)size, memPartitionId, align);
+ if (mem == NULL)
+ {
+ XX_Free(p_MemDbg);
+ return NULL;
+ }
+
+ INIT_LIST(&p_MemDbg->node);
+ p_MemDbg->f_free = xx_FreeSmart;
+ p_MemDbg->mem = mem;
+ p_MemDbg->fname = fname;
+ p_MemDbg->fline = line;
+ p_MemDbg->size = size+sizeof(t_MemDebug);
+ LIST_AddToTail(&p_MemDbg->node, &memDbgLst);
+
+ return mem;
+}
+
+static void debug_free(void *mem)
+{
+ t_List *p_MemDbgLh = NULL;
+ t_MemDebug *p_MemDbg;
+ bool found = FALSE;
+
+ if (LIST_IsEmpty(&memDbgLst))
+ {
+ REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem));
+ return;
+ }
+
+ LIST_FOR_EACH(p_MemDbgLh, &memDbgLst)
+ {
+ p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh);
+ if (p_MemDbg->mem == mem)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ REPORT_ERROR(MAJOR, E_NOT_FOUND,
+ ("Attempt to free unallocated address (0x%08x)",mem));
+ dump_stack();
+ return;
+ }
+
+ LIST_Del(p_MemDbgLh);
+ p_MemDbg->f_free(mem);
+ p_MemDbg->f_free(p_MemDbg);
+}
+
+void XX_FreeSmart(void *p)
+{
+ debug_free(p);
+}
+
+
+void XX_Free(void *p)
+{
+ debug_free(p);
+}
+
+#else /* not DEBUG_XX_MALLOC */
+void * XX_Malloc(uint32_t size)
+{
+ return xx_Malloc(size);
+}
+
+void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
+{
+ return xx_MallocSmart(size,memPartitionId, alignment);
+}
+
+void XX_FreeSmart(void *p)
+{
+ xx_FreeSmart(p);
+}
+
+
+void XX_Free(void *p)
+{
+ xx_Free(p);
+}
+#endif /* not DEBUG_XX_MALLOC */
+
+
+#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0))
+void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg)
+{
+ e_Event eventCode = (e_Event)event;
+
+ UNUSED(eventCode);
+ UNUSED(appId);
+ UNUSED(flags);
+ UNUSED(msg);
+}
+#endif /* (defined(REPORT_EVENTS) && ... */
+
+
+uint32_t XX_DisableAllIntr(void)
+{
+ unsigned long flags;
+
+#ifdef local_irq_save_nort
+ local_irq_save_nort(flags);
+#else
+ local_irq_save(flags);
+#endif
+
+ return (uint32_t)flags;
+}
+
+void XX_RestoreAllIntr(uint32_t flags)
+{
+#ifdef local_irq_restore_nort
+ local_irq_restore_nort((unsigned long)flags);
+#else
+ local_irq_restore((unsigned long)flags);
+#endif
+}
+
+t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags )
+{
+ UNUSED(qid);
+ UNUSED(appId);
+ UNUSED(flags);
+
+ return f(id);
+}
+
+int XX_IsICacheEnable(void)
+{
+ return TRUE;
+}
+
+int XX_IsDCacheEnable(void)
+{
+ return TRUE;
+}
+
+
+typedef struct {
+ t_Isr *f_Isr;
+ t_Handle handle;
+} t_InterruptHandler;
+
+
+t_Handle interruptHandlers[0x00010000];
+
+#ifdef CONFIG_FMAN_ARM
+static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id)
+{
+ t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id;
+ p_IntrHndl->f_Isr(p_IntrHndl->handle);
+ return IRQ_HANDLED;
+}
+#endif
+
+t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle)
+{
+#ifdef CONFIG_FMAN_ARM
+ const char *device;
+ t_InterruptHandler *p_IntrHndl;
+
+ device = GetDeviceName(irq);
+ if (device == NULL)
+ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq));
+
+ p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler));
+ if (p_IntrHndl == NULL)
+ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
+ p_IntrHndl->f_Isr = f_Isr;
+ p_IntrHndl->handle = handle;
+ interruptHandlers[irq] = p_IntrHndl;
+
+ if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0)
+ RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device));
+ disable_irq(GetDeviceIrqNum(irq));
+#endif
+ return E_OK;
+}
+
+t_Error XX_FreeIntr(int irq)
+{
+ t_InterruptHandler *p_IntrHndl = interruptHandlers[irq];
+ free_irq(GetDeviceIrqNum(irq), p_IntrHndl);
+ XX_Free(p_IntrHndl);
+ interruptHandlers[irq] = 0;
+ return E_OK;
+}
+
+t_Error XX_EnableIntr(int irq)
+{
+ enable_irq(GetDeviceIrqNum(irq));
+ return E_OK;
+}
+
+t_Error XX_DisableIntr(int irq)
+{
+ disable_irq(GetDeviceIrqNum(irq));
+ return E_OK;
+}
+
+
+/*****************************************************************************/
+/* Tasklet Service Routines */
+/*****************************************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+typedef struct
+{
+ t_Handle h_Data;
+ void (*f_Callback) (void *);
+ struct delayed_work dwork;
+} t_Tasklet;
+
+static void GenericTaskletCallback(struct work_struct *p_Work)
+{
+ t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work);
+
+ p_Task->f_Callback(p_Task->h_Data);
+}
+#endif /* LINUX_VERSION_CODE */
+
+
+t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ struct work_struct *p_Task;
+ p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct));
+ INIT_WORK(p_Task, routine, data);
+#else
+ t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet));
+ p_Task->h_Data = data;
+ p_Task->f_Callback = routine;
+ INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback);
+#endif /* LINUX_VERSION_CODE */
+
+ return (t_TaskletHandle)p_Task;
+}
+
+
+void XX_FreeTasklet (t_TaskletHandle h_Tasklet)
+{
+ if (h_Tasklet)
+ XX_Free(h_Tasklet);
+}
+
+int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate)
+{
+ int ans;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ if (immediate)
+ ans = schedule_work(h_Tasklet);
+ else
+ ans = schedule_delayed_work(h_Tasklet, 1);
+#else
+ if (immediate)
+ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0);
+ else
+ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ);
+#endif /* LINUX_VERSION_CODE */
+
+ return ans;
+}
+
+void XX_FlushScheduledTasks(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ flush_scheduled_tasks();
+#else
+ flush_scheduled_work();
+#endif /* LINUX_VERSION_CODE */
+}
+
+int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ return (int)(((struct work_struct *)h_Tasklet)->pending);
+#else
+ return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork);
+#endif /* LINUX_VERSION_CODE */
+}
+
+void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ ((struct tq_struct *)h_Tasklet)->data = data;
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ ((struct work_struct *)h_Tasklet)->data = data;
+#else
+ ((t_Tasklet *)h_Tasklet)->h_Data = data;
+#endif /* LINUX_VERSION_CODE */
+}
+
+t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ return (t_Handle)(((struct work_struct *)h_Tasklet)->data);
+#else
+ return ((t_Tasklet *)h_Tasklet)->h_Data;
+#endif /* LINUX_VERSION_CODE */
+}
+
+
+/*****************************************************************************/
+/* Spinlock Service Routines */
+/*****************************************************************************/
+
+t_Handle XX_InitSpinlock(void)
+{
+ spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t));
+ if (!p_Spinlock)
+ return NULL;
+
+ spin_lock_init(p_Spinlock);
+
+ return (t_Handle)p_Spinlock;
+}
+
+void XX_FreeSpinlock(t_Handle h_Spinlock)
+{
+ if (h_Spinlock)
+ XX_Free(h_Spinlock);
+}
+
+void XX_LockSpinlock(t_Handle h_Spinlock)
+{
+ spin_lock((spinlock_t *)h_Spinlock);
+}
+
+void XX_UnlockSpinlock(t_Handle h_Spinlock)
+{
+ spin_unlock((spinlock_t *)h_Spinlock);
+}
+
+uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock)
+{
+ unsigned long intrFlags;
+ spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags);
+ return intrFlags;
+}
+
+void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags)
+{
+ spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags);
+}
+
+
+/*****************************************************************************/
+/* Timers Service Routines */
+/*****************************************************************************/
+/* The time now is in mili sec. resolution */
+uint32_t XX_CurrentTime(void)
+{
+ return (jiffies*1000)/HZ;
+}
+
+#if 0
+t_Handle XX_CreateTimer(void)
+{
+ struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list));
+ if (p_Timer)
+ {
+ memset(p_Timer, 0, sizeof(struct timer_list));
+ init_timer(p_Timer);
+ }
+ return (t_Handle)p_Timer;
+}
+
+void XX_FreeTimer(t_Handle h_Timer)
+{
+ if (h_Timer)
+ XX_Free(h_Timer);
+}
+
+void XX_StartTimer(t_Handle h_Timer,
+ uint32_t msecs,
+ bool periodic,
+ void (*f_TimerExpired)(t_Handle),
+ t_Handle h_Arg)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED);
+
+ p_Timer->function = (void (*)(unsigned long))f_TimerExpired;
+ p_Timer->data = (unsigned long)h_Arg;
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ p_Timer->expires = (jiffies + tmp_jiffies);
+
+ add_timer((struct timer_list *)h_Timer);
+}
+
+void XX_SetTimerData(t_Handle h_Timer, t_Handle data)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ p_Timer->data = (unsigned long)data;
+}
+
+t_Handle XX_GetTimerData(t_Handle h_Timer)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ return (t_Handle)p_Timer->data;
+}
+
+uint32_t XX_GetExpirationTime(t_Handle h_Timer)
+{
+ struct timer_list *p_Timer = (struct timer_list *)h_Timer;
+
+ return (uint32_t)p_Timer->expires;
+}
+
+void XX_StopTimer(t_Handle h_Timer)
+{
+ del_timer((struct timer_list *)h_Timer);
+}
+
+void XX_ModTimer(t_Handle h_Timer, uint32_t msecs)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies);
+}
+
+int XX_TimerIsActive(t_Handle h_Timer)
+{
+ return timer_pending((struct timer_list *)h_Timer);
+}
+#endif
+
+uint32_t XX_Sleep(uint32_t msecs)
+{
+ int tmp_jiffies = (msecs*HZ)/1000;
+
+ if ((msecs*HZ)%1000)
+ tmp_jiffies++;
+ return schedule_timeout(tmp_jiffies);
+}
+
+/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/
+void XX_UDelay(uint32_t usecs)
+{
+ udelay(usecs);
+}
+
+/* TODO: verify that these are correct */
+#define MSG_BODY_SIZE 512
+typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]);
+typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]);
+t_Error XX_SendMessage(char *p_DestAddr,
+ uint32_t msgId,
+ uint8_t msgBody[MSG_BODY_SIZE],
+ t_MsgCompletionCB *f_CompletionCB,
+ t_Handle h_CBArg);
+
+typedef struct {
+ char *p_Addr;
+ t_MsgHandler *f_MsgHandlerCB;
+ t_Handle h_Mod;
+ t_List node;
+} t_MsgHndlr;
+#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node)
+
+LIST(msgHndlrList);
+
+static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr)
+{
+ uint32_t intFlags;
+
+ intFlags = XX_DisableAllIntr();
+ LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList);
+ XX_RestoreAllIntr(intFlags);
+}
+/* TODO: add this for multi-platform support
+static t_MsgHndlr * DequeueMsgHndlr(void)
+{
+ t_MsgHndlr *p_MsgHndlr = NULL;
+ uint32_t intFlags;
+
+ intFlags = XX_DisableAllIntr();
+ if (!LIST_IsEmpty(&msgHndlrList))
+ {
+ p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next);
+ LIST_DelAndInit(&p_MsgHndlr->node);
+ }
+ XX_RestoreAllIntr(intFlags);
+
+ return p_MsgHndlr;
+}
+*/
+static t_MsgHndlr * FindMsgHndlr(char *p_Addr)
+{
+ t_MsgHndlr *p_MsgHndlr;
+ t_List *p_Pos;
+
+ LIST_FOR_EACH(p_Pos, &msgHndlrList)
+ {
+ p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos);
+ if (strstr(p_MsgHndlr->p_Addr, p_Addr))
+ return p_MsgHndlr;
+ }
+
+ return NULL;
+}
+
+t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod)
+{
+ t_MsgHndlr *p_MsgHndlr;
+ uint32_t len;
+
+ p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr));
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!"));
+ memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr));
+
+ len = strlen(p_Addr);
+ p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1);
+ strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1));
+
+ p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB;
+ p_MsgHndlr->h_Mod = h_Mod;
+ INIT_LIST(&p_MsgHndlr->node);
+ EnqueueMsgHndlr(p_MsgHndlr);
+
+ return E_OK;
+}
+
+t_Error XX_UnregisterMessageHandler (char *p_Addr)
+{
+ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr);
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
+
+ LIST_Del(&p_MsgHndlr->node);
+ XX_Free(p_MsgHndlr->p_Addr);
+ XX_Free(p_MsgHndlr);
+
+ return E_OK;
+}
+
+t_Error XX_SendMessage(char *p_DestAddr,
+ uint32_t msgId,
+ uint8_t msgBody[MSG_BODY_SIZE],
+ t_MsgCompletionCB *f_CompletionCB,
+ t_Handle h_CBArg)
+{
+ t_Error ans;
+ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr);
+ if (!p_MsgHndlr)
+ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!"));
+
+ ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody);
+
+ if (f_CompletionCB)
+ f_CompletionCB(h_CBArg, msgBody);
+
+ return ans;
+}
+
+t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ t_IpcMsgHandler *f_MsgHandler,
+ t_Handle h_Module,
+ uint32_t replyLength)
+{
+ UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength);
+ return E_OK;
+}
+
+t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH])
+{
+ UNUSED(addr);
+ return E_OK;
+}
+
+
+t_Error XX_IpcSendMessage(t_Handle h_Session,
+ uint8_t *p_Msg,
+ uint32_t msgLength,
+ uint8_t *p_Reply,
+ uint32_t *p_ReplyLength,
+ t_IpcMsgCompletion *f_Completion,
+ t_Handle h_Arg)
+{
+ UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply);
+ UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg);
+ return E_OK;
+}
+
+t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH],
+ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH])
+{
+ UNUSED(destAddr); UNUSED(srcAddr);
+ return E_OK;
+}
+
+/*Forced to introduce due to PRINT_FMT_PARAMS define*/
+uint32_t E500_GetId(void)
+{
+ return raw_smp_processor_id();
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+int GetDeviceIrqNum(int irq)
+{
+ struct device_node *iPar;
+ struct irq_domain *irqHost;
+ uint32_t hwIrq;
+
+ /* Get the interrupt controller */
+ iPar = of_find_node_by_name(NULL, "mpic");
+ hwIrq = 0;
+
+ ASSERT_COND(iPar != NULL);
+ /* Get the irq host */
+ irqHost = irq_find_host(iPar);
+ of_node_put(iPar);
+
+ /* Create irq mapping */
+ return irq_create_mapping(irqHost, hwIrq);
+}
+#else
+#error "kernel not supported!!!"
+#endif /* LINUX_VERSION_CODE */
+
+void * XX_PhysToVirt(physAddress_t addr)
+{
+ return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr));
+}
+
+physAddress_t XX_VirtToPhys(void * addr)
+{
+ return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr));
+}
+
+void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment)
+{
+ uintptr_t *returnCode, tmp;
+
+ if (alignment < sizeof(uintptr_t))
+ alignment = sizeof(uintptr_t);
+ size += alignment + sizeof(returnCode);
+ tmp = (uintptr_t)xx_Malloc(size);
+ if (tmp == 0)
+ return NULL;
+ returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1));
+ *(returnCode - 1) = tmp;
+
+ return (void*)returnCode;
+}
+
+void xx_FreeSmart(void *p)
+{
+ xx_Free((void*)(*((uintptr_t *)(p) - 1)));
+}
diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index 9a36c26095c8..a23ca4f0c051 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
mscc_ocelot_common-y := ocelot.o ocelot_io.o
mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o
+mscc_ocelot_common-y += ocelot_tsn.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 6030c90d50cc..fb65cd3f9be1 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -132,11 +132,11 @@ static void ocelot_mact_init(struct ocelot *ocelot)
ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS);
}
-static void ocelot_vcap_enable(struct ocelot *ocelot, struct ocelot_port *port)
+static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
{
ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
- ANA_PORT_VCAP_S2_CFG, port->chip_port);
+ ANA_PORT_VCAP_S2_CFG, port);
}
static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)
@@ -169,117 +169,178 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
return ocelot_vlant_wait_for_completion(ocelot);
}
-static void ocelot_vlan_mode(struct ocelot_port *port,
+static void ocelot_vlan_mode(struct ocelot *ocelot, int port,
netdev_features_t features)
{
- struct ocelot *ocelot = port->ocelot;
- u8 p = port->chip_port;
u32 val;
/* Filtering */
val = ocelot_read(ocelot, ANA_VLANMASK);
if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
- val |= BIT(p);
+ val |= BIT(port);
else
- val &= ~BIT(p);
+ val &= ~BIT(port);
ocelot_write(ocelot, val, ANA_VLANMASK);
}
-static void ocelot_vlan_port_apply(struct ocelot *ocelot,
- struct ocelot_port *port)
+void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
+ bool vlan_aware)
{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
u32 val;
- /* Ingress clasification (ANA_PORT_VLAN_CFG) */
- /* Default vlan to clasify for untagged frames (may be zero) */
- val = ANA_PORT_VLAN_CFG_VLAN_VID(port->pvid);
- if (port->vlan_aware)
- val |= ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
- ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
-
+ if (vlan_aware)
+ val = ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
+ else
+ val = 0;
ocelot_rmw_gix(ocelot, val,
- ANA_PORT_VLAN_CFG_VLAN_VID_M |
ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
- ANA_PORT_VLAN_CFG, port->chip_port);
+ ANA_PORT_VLAN_CFG, port);
- /* Drop frames with multicast source address */
- val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA;
- if (port->vlan_aware && !port->vid)
+ if (vlan_aware && !ocelot_port->vid)
/* If port is vlan-aware and tagged, drop untagged and priority
* tagged frames.
*/
- val |= ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
+ val = ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
+ ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
+ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
+ else
+ val = 0;
+ ocelot_rmw_gix(ocelot, val,
+ ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA |
ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
- ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
- ocelot_write_gix(ocelot, val, ANA_PORT_DROP_CFG, port->chip_port);
-
- /* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q. */
- val = REW_TAG_CFG_TAG_TPID_CFG(0);
+ ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
+ ANA_PORT_DROP_CFG, port);
- if (port->vlan_aware) {
- if (port->vid)
+ if (vlan_aware) {
+ if (ocelot_port->vid)
/* Tag all frames except when VID == DEFAULT_VLAN */
val |= REW_TAG_CFG_TAG_CFG(1);
else
/* Tag all frames */
val |= REW_TAG_CFG_TAG_CFG(3);
+ } else {
+ /* Port tagging disabled. */
+ val = REW_TAG_CFG_TAG_CFG(0);
}
ocelot_rmw_gix(ocelot, val,
- REW_TAG_CFG_TAG_TPID_CFG_M |
REW_TAG_CFG_TAG_CFG_M,
- REW_TAG_CFG, port->chip_port);
+ REW_TAG_CFG, port);
+}
+EXPORT_SYMBOL(ocelot_port_vlan_filtering);
- /* Set default VLAN and tag type to 8021Q. */
- val = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q) |
- REW_PORT_VLAN_CFG_PORT_VID(port->vid);
- ocelot_rmw_gix(ocelot, val,
- REW_PORT_VLAN_CFG_PORT_TPID_M |
+static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
+ u16 vid)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ if (ocelot_port->vid != vid) {
+ /* Always permit deleting the native VLAN (vid = 0) */
+ if (ocelot_port->vid && vid) {
+ dev_err(ocelot->dev,
+ "Port already has a native VLAN: %d\n",
+ ocelot_port->vid);
+ return -EBUSY;
+ }
+ ocelot_port->vid = vid;
+ }
+
+ ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid),
REW_PORT_VLAN_CFG_PORT_VID_M,
- REW_PORT_VLAN_CFG, port->chip_port);
+ REW_PORT_VLAN_CFG, port);
+
+ return 0;
}
-static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
- bool untagged)
+/* Default vlan to clasify for untagged frames (may be zero) */
+static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- int ret;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
- /* Add the port MAC address to with the right VLAN information */
- ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid,
- ENTRYTYPE_LOCKED);
+ ocelot_rmw_gix(ocelot,
+ ANA_PORT_VLAN_CFG_VLAN_VID(pvid),
+ ANA_PORT_VLAN_CFG_VLAN_VID_M,
+ ANA_PORT_VLAN_CFG, port);
+
+ ocelot_port->pvid = pvid;
+}
+
+int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
+ bool untagged)
+{
+ int ret;
/* Make the port a member of the VLAN */
- ocelot->vlan_mask[vid] |= BIT(port->chip_port);
+ ocelot->vlan_mask[vid] |= BIT(port);
ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
if (ret)
return ret;
/* Default ingress vlan classification */
if (pvid)
- port->pvid = vid;
+ ocelot_port_set_pvid(ocelot, port, vid);
/* Untagged egress vlan clasification */
- if (untagged && port->vid != vid) {
- if (port->vid) {
- dev_err(ocelot->dev,
- "Port already has a native VLAN: %d\n",
- port->vid);
- return -EBUSY;
- }
- port->vid = vid;
+ if (untagged) {
+ ret = ocelot_port_set_native_vlan(ocelot, port, vid);
+ if (ret)
+ return ret;
}
- ocelot_vlan_port_apply(ocelot, port);
+ return 0;
+}
+EXPORT_SYMBOL(ocelot_vlan_add);
+
+static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
+ bool untagged)
+{
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
+ int port = priv->chip_port;
+ int ret;
+
+ ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged);
+ if (ret)
+ return ret;
+
+ /* Add the port MAC address to with the right VLAN information */
+ ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid,
+ ENTRYTYPE_LOCKED);
+
+ return 0;
+}
+
+int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ int ret;
+
+ /* Stop the port from being a member of the vlan */
+ ocelot->vlan_mask[vid] &= ~BIT(port);
+ ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
+ if (ret)
+ return ret;
+
+ /* Ingress */
+ if (ocelot_port->pvid == vid)
+ ocelot_port_set_pvid(ocelot, port, 0);
+
+ /* Egress */
+ if (ocelot_port->vid == vid)
+ ocelot_port_set_native_vlan(ocelot, port, 0);
return 0;
}
+EXPORT_SYMBOL(ocelot_vlan_del);
static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
int ret;
/* 8021q removes VID 0 on module unload for all interfaces
@@ -289,24 +350,12 @@ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
if (vid == 0)
return 0;
- /* Del the port MAC address to with the right VLAN information */
- ocelot_mact_forget(ocelot, dev->dev_addr, vid);
-
- /* Stop the port from being a member of the vlan */
- ocelot->vlan_mask[vid] &= ~BIT(port->chip_port);
- ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
+ ret = ocelot_vlan_del(ocelot, port, vid);
if (ret)
return ret;
- /* Ingress */
- if (port->pvid == vid)
- port->pvid = 0;
-
- /* Egress */
- if (port->vid == vid)
- port->vid = 0;
-
- ocelot_vlan_port_apply(ocelot, port);
+ /* Del the port MAC address to with the right VLAN information */
+ ocelot_mact_forget(ocelot, dev->dev_addr, vid);
return 0;
}
@@ -333,16 +382,11 @@ static void ocelot_vlan_init(struct ocelot *ocelot)
ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0);
ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]);
- /* Configure the CPU port to be VLAN aware */
- ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
- ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
- ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
- ANA_PORT_VLAN_CFG, ocelot->num_phys_ports);
-
/* Set vlan ingress filter mask to all ports but the CPU port by
* default.
*/
- ocelot_write(ocelot, GENMASK(9, 0), ANA_VLANMASK);
+ ocelot_write(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0),
+ ANA_VLANMASK);
for (port = 0; port < ocelot->num_phys_ports; port++) {
ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port);
@@ -362,14 +406,13 @@ static u16 ocelot_wm_enc(u16 value)
return value;
}
-static void ocelot_port_adjust_link(struct net_device *dev)
+void ocelot_adjust_link(struct ocelot *ocelot, int port,
+ struct phy_device *phydev)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- u8 p = port->chip_port;
- int speed, atop_wm, mode = 0;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ int speed, mode = 0;
- switch (dev->phydev->speed) {
+ switch (phydev->speed) {
case SPEED_10:
speed = OCELOT_SPEED_10;
break;
@@ -385,87 +428,41 @@ static void ocelot_port_adjust_link(struct net_device *dev)
mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA;
break;
default:
- netdev_err(dev, "Unsupported PHY speed: %d\n",
- dev->phydev->speed);
+ dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n",
+ port, phydev->speed);
return;
}
- phy_print_status(dev->phydev);
+ phy_print_status(phydev);
- if (!dev->phydev->link)
+ if (!phydev->link)
return;
/* Only full duplex supported for now */
- ocelot_port_writel(port, DEV_MAC_MODE_CFG_FDX_ENA |
+ ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA |
mode, DEV_MAC_MODE_CFG);
- /* Set MAC IFG Gaps
- * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0
- * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5
- */
- ocelot_port_writel(port, DEV_MAC_IFG_CFG_TX_IFG(5), DEV_MAC_IFG_CFG);
-
- /* Load seed (0) and set MAC HDX late collision */
- ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
- DEV_MAC_HDX_CFG_SEED_LOAD,
- DEV_MAC_HDX_CFG);
- mdelay(1);
- ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
- DEV_MAC_HDX_CFG);
-
- /* Disable HDX fast control */
- ocelot_port_writel(port, DEV_PORT_MISC_HDX_FAST_DIS, DEV_PORT_MISC);
-
- /* SGMII only for now */
- ocelot_port_writel(port, PCS1G_MODE_CFG_SGMII_MODE_ENA, PCS1G_MODE_CFG);
- ocelot_port_writel(port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
-
- /* Enable PCS */
- ocelot_port_writel(port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
-
- /* No aneg on SGMII */
- ocelot_port_writel(port, 0, PCS1G_ANEG_CFG);
-
- /* No loopback */
- ocelot_port_writel(port, 0, PCS1G_LB_CFG);
-
- /* Set Max Length and maximum tags allowed */
- ocelot_port_writel(port, VLAN_ETH_FRAME_LEN, DEV_MAC_MAXLEN_CFG);
- ocelot_port_writel(port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
- DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
- DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
- DEV_MAC_TAGS_CFG);
+ if (ocelot->ops->pcs_init)
+ ocelot->ops->pcs_init(ocelot, port);
/* Enable MAC module */
- ocelot_port_writel(port, DEV_MAC_ENA_CFG_RX_ENA |
+ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
/* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of
* reset */
- ocelot_port_writel(port, DEV_CLOCK_CFG_LINK_SPEED(speed),
+ ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed),
DEV_CLOCK_CFG);
- /* Set SMAC of Pause frame (00:00:00:00:00:00) */
- ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
- ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_LOW_CFG);
-
/* No PFC */
ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed),
- ANA_PFC_PFC_CFG, p);
-
- /* Set Pause WM hysteresis
- * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
- * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ
- */
- ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
- SYS_PAUSE_CFG_PAUSE_STOP(101) |
- SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, p);
+ ANA_PFC_PFC_CFG, port);
/* Core: Enable port for frame transfer */
ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
QSYS_SWITCH_PORT_MODE_PORT_ENA,
- QSYS_SWITCH_PORT_MODE, p);
+ QSYS_SWITCH_PORT_MODE, port);
/* Flow control */
ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
@@ -473,64 +470,89 @@ static void ocelot_port_adjust_link(struct net_device *dev)
SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
SYS_MAC_FC_CFG_FC_LINK_SPEED(speed),
- SYS_MAC_FC_CFG, p);
- ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, p);
-
- /* Tail dropping watermark */
- atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ;
- ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN),
- SYS_ATOP, p);
- ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+ SYS_MAC_FC_CFG, port);
+ ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
}
+EXPORT_SYMBOL(ocelot_adjust_link);
-static int ocelot_port_open(struct net_device *dev)
+static void ocelot_port_adjust_link(struct net_device *dev)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- int err;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+
+ ocelot_adjust_link(ocelot, port, dev->phydev);
+}
+void ocelot_port_enable(struct ocelot *ocelot, int port,
+ struct phy_device *phy)
+{
/* Enable receiving frames on the port, and activate auto-learning of
* MAC addresses.
*/
ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
ANA_PORT_PORT_CFG_RECV_ENA |
- ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port),
- ANA_PORT_PORT_CFG, port->chip_port);
+ ANA_PORT_PORT_CFG_PORTID_VAL(port),
+ ANA_PORT_PORT_CFG, port);
+}
+EXPORT_SYMBOL(ocelot_port_enable);
- if (port->serdes) {
- err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET,
- port->phy_mode);
+static int ocelot_port_open(struct net_device *dev)
+{
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
+ int port = priv->chip_port;
+ int err;
+
+ if (priv->serdes) {
+ err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
+ ocelot_port->phy_mode);
if (err) {
netdev_err(dev, "Could not set mode of SerDes\n");
return err;
}
}
- err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link,
- port->phy_mode);
+ err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
+ ocelot_port->phy_mode);
if (err) {
netdev_err(dev, "Could not attach to PHY\n");
return err;
}
- dev->phydev = port->phy;
+ dev->phydev = priv->phy;
+
+ phy_attached_info(priv->phy);
+ phy_start(priv->phy);
+
+ ocelot_port_enable(ocelot, port, priv->phy);
- phy_attached_info(port->phy);
- phy_start(port->phy);
return 0;
}
+void ocelot_port_disable(struct ocelot *ocelot, int port)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
+ ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
+ QSYS_SWITCH_PORT_MODE, port);
+}
+EXPORT_SYMBOL(ocelot_port_disable);
+
static int ocelot_port_stop(struct net_device *dev)
{
- struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
- phy_disconnect(port->phy);
+ phy_disconnect(priv->phy);
dev->phydev = NULL;
- ocelot_port_writel(port, 0, DEV_MAC_ENA_CFG);
- ocelot_rmw_rix(port->ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
- QSYS_SWITCH_PORT_MODE, port->chip_port);
+ ocelot_port_disable(ocelot, port);
+
return 0;
}
@@ -554,15 +576,35 @@ static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info)
return 0;
}
+int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
+ struct sk_buff *skb)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ struct ocelot *ocelot = ocelot_port->ocelot;
+
+ if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
+ ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+ shinfo->tx_flags |= SKBTX_IN_PROGRESS;
+ /* Store timestamp ID in cb[0] of sk_buff */
+ skb->cb[0] = ocelot_port->ts_id % 4;
+ skb_queue_tail(&ocelot_port->tx_skbs, skb);
+ return 0;
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb);
+
static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ struct ocelot_port_private *priv = netdev_priv(dev);
struct skb_shared_info *shinfo = skb_shinfo(skb);
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- u32 val, ifh[IFH_LEN];
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
+ u32 val, ifh[OCELOT_TAG_LEN / 4];
struct frame_info info = {};
u8 grp = 0; /* Send everything on CPU group 0 */
unsigned int i, count, last;
+ int port = priv->chip_port;
val = ocelot_read(ocelot, QS_INJ_STATUS);
if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) ||
@@ -572,20 +614,20 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);
- info.port = BIT(port->chip_port);
+ info.port = BIT(port);
info.tag_type = IFH_TAG_TYPE_C;
info.vid = skb_vlan_tag_get(skb);
/* Check if timestamping is needed */
if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {
- info.rew_op = port->ptp_cmd;
- if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
- info.rew_op |= (port->ts_id % 4) << 3;
+ info.rew_op = ocelot_port->ptp_cmd;
+ if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
+ info.rew_op |= (ocelot_port->ts_id % 4) << 3;
}
ocelot_gen_ifh(ifh, &info);
- for (i = 0; i < IFH_LEN; i++)
+ for (i = 0; i < OCELOT_TAG_LEN / 4; i++)
ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]),
QS_INJ_WR, grp);
@@ -614,31 +656,17 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
- port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
- struct ocelot_skb *oskb =
- kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC);
-
- if (unlikely(!oskb))
- goto out;
-
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-
- oskb->skb = skb;
- oskb->id = port->ts_id % 4;
- port->ts_id++;
-
- list_add_tail(&oskb->head, &port->skbs);
-
+ if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) {
+ ocelot_port->ts_id++;
return NETDEV_TX_OK;
}
-out:
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
-void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts)
+static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
+ struct timespec64 *ts)
{
unsigned long flags;
u32 val;
@@ -663,36 +691,97 @@ void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts)
spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
}
-EXPORT_SYMBOL(ocelot_get_hwtimestamp);
+
+void ocelot_get_txtstamp(struct ocelot *ocelot)
+{
+ int budget = OCELOT_PTP_QUEUE_SZ;
+
+ while (budget--) {
+ struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct ocelot_port *port;
+ struct timespec64 ts;
+ unsigned long flags;
+ u32 val, id, txport;
+
+ val = ocelot_read(ocelot, SYS_PTP_STATUS);
+
+ /* Check if a timestamp can be retrieved */
+ if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
+ break;
+
+ WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
+
+ /* Retrieve the ts ID and Tx port */
+ id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
+ txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
+
+ /* Retrieve its associated skb */
+ port = ocelot->ports[txport];
+
+ spin_lock_irqsave(&port->tx_skbs.lock, flags);
+
+ skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
+ if (skb->cb[0] != id)
+ continue;
+ __skb_unlink(skb, &port->tx_skbs);
+ skb_match = skb;
+ break;
+ }
+
+ spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
+
+ /* Next ts */
+ ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
+
+ if (unlikely(!skb_match))
+ continue;
+
+ /* Get the h/w timestamp */
+ ocelot_get_hwtimestamp(ocelot, &ts);
+
+ /* Set the timestamp into the skb */
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+ skb_tstamp_tx(skb_match, &shhwtstamps);
+
+ dev_kfree_skb_any(skb_match);
+ }
+}
+EXPORT_SYMBOL(ocelot_get_txtstamp);
static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
{
- struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
- return ocelot_mact_forget(port->ocelot, addr, port->pvid);
+ return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid);
}
static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
{
- struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
- return ocelot_mact_learn(port->ocelot, PGID_CPU, addr, port->pvid,
+ return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid,
ENTRYTYPE_LOCKED);
}
static void ocelot_set_rx_mode(struct net_device *dev)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- int i;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
u32 val;
+ int i;
/* This doesn't handle promiscuous mode because the bridge core is
* setting IFF_PROMISC on all slave interfaces and all frames would be
* forwarded to the CPU port.
*/
val = GENMASK(ocelot->num_phys_ports - 1, 0);
- for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++)
+ for (i = ocelot->num_phys_ports + 1; i < PGID_MCRED; i++)
ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i);
__dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
@@ -701,10 +790,11 @@ static void ocelot_set_rx_mode(struct net_device *dev)
static int ocelot_port_get_phys_port_name(struct net_device *dev,
char *buf, size_t len)
{
- struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ int port = priv->chip_port;
int ret;
- ret = snprintf(buf, len, "p%d", port->chip_port);
+ ret = snprintf(buf, len, "p%d", port);
if (ret >= len)
return -EINVAL;
@@ -713,15 +803,16 @@ static int ocelot_port_get_phys_port_name(struct net_device *dev,
static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
const struct sockaddr *addr = p;
/* Learn the new net device MAC address in the mac table. */
- ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, port->pvid,
+ ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid,
ENTRYTYPE_LOCKED);
/* Then forget the previous one. */
- ocelot_mact_forget(ocelot, dev->dev_addr, port->pvid);
+ ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid);
ether_addr_copy(dev->dev_addr, addr->sa_data);
return 0;
@@ -730,11 +821,12 @@ static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
static void ocelot_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
/* Configure the port to read the stats from */
- ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port->chip_port),
+ ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port),
SYS_STAT_CFG);
/* Get Rx stats */
@@ -765,21 +857,18 @@ static void ocelot_get_stats64(struct net_device *dev,
stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION);
}
-static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev, const unsigned char *addr,
- u16 vid, u16 flags,
- struct netlink_ext_ack *extack)
+int ocelot_fdb_add(struct ocelot *ocelot, int port,
+ const unsigned char *addr, u16 vid, bool vlan_aware)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
if (!vid) {
- if (!port->vlan_aware)
+ if (!vlan_aware)
/* If the bridge is not VLAN aware and no VID was
* provided, set it to pvid to ensure the MAC entry
* matches incoming untagged packets
*/
- vid = port->pvid;
+ vid = ocelot_port->pvid;
else
/* If the bridge is VLAN aware a VID must be provided as
* otherwise the learnt entry wouldn't match any frame.
@@ -787,19 +876,40 @@ static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return -EINVAL;
}
- return ocelot_mact_learn(ocelot, port->chip_port, addr, vid,
- ENTRYTYPE_LOCKED);
+ return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED);
}
+EXPORT_SYMBOL(ocelot_fdb_add);
-static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr, u16 vid)
+static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr,
+ u16 vid, u16 flags,
+ struct netlink_ext_ack *extack)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+
+ return ocelot_fdb_add(ocelot, port, addr, vid, priv->vlan_aware);
+}
+int ocelot_fdb_del(struct ocelot *ocelot, int port,
+ const unsigned char *addr, u16 vid)
+{
return ocelot_mact_forget(ocelot, addr, vid);
}
+EXPORT_SYMBOL(ocelot_fdb_del);
+
+static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr, u16 vid)
+{
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+
+ return ocelot_fdb_del(ocelot, port, addr, vid);
+}
struct ocelot_dump_ctx {
struct net_device *dev;
@@ -808,9 +918,10 @@ struct ocelot_dump_ctx {
int idx;
};
-static int ocelot_fdb_do_dump(struct ocelot_mact_entry *entry,
- struct ocelot_dump_ctx *dump)
+static int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
+ bool is_static, void *data)
{
+ struct ocelot_dump_ctx *dump = data;
u32 portid = NETLINK_CB(dump->cb->skb).portid;
u32 seq = dump->cb->nlh->nlmsg_seq;
struct nlmsghdr *nlh;
@@ -831,12 +942,12 @@ static int ocelot_fdb_do_dump(struct ocelot_mact_entry *entry,
ndm->ndm_flags = NTF_SELF;
ndm->ndm_type = 0;
ndm->ndm_ifindex = dump->dev->ifindex;
- ndm->ndm_state = NUD_REACHABLE;
+ ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
- if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac))
+ if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
goto nla_put_failure;
- if (entry->vid && nla_put_u16(dump->skb, NDA_VLAN, entry->vid))
+ if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
goto nla_put_failure;
nlmsg_end(dump->skb, nlh);
@@ -850,12 +961,11 @@ nla_put_failure:
return -EMSGSIZE;
}
-static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col,
- struct ocelot_mact_entry *entry)
+static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
+ struct ocelot_mact_entry *entry)
{
- struct ocelot *ocelot = port->ocelot;
- char mac[ETH_ALEN];
u32 val, dst, macl, mach;
+ char mac[ETH_ALEN];
/* Set row and column to read from */
ocelot_field_write(ocelot, ANA_TABLES_MACTINDX_M_INDEX, row);
@@ -878,7 +988,7 @@ static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col,
* do not report it.
*/
dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3;
- if (dst != port->chip_port)
+ if (dst != port)
return -EINVAL;
/* Get the entry's MAC address and VLAN id */
@@ -898,43 +1008,61 @@ static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col,
return 0;
}
-static int ocelot_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
- struct net_device *dev,
- struct net_device *filter_dev, int *idx)
+int ocelot_fdb_dump(struct ocelot *ocelot, int port,
+ dsa_fdb_dump_cb_t *cb, void *data)
{
- struct ocelot_port *port = netdev_priv(dev);
- int i, j, ret = 0;
- struct ocelot_dump_ctx dump = {
- .dev = dev,
- .skb = skb,
- .cb = cb,
- .idx = *idx,
- };
-
- struct ocelot_mact_entry entry;
+ int i, j;
/* Loop through all the mac tables entries. There are 1024 rows of 4
* entries.
*/
for (i = 0; i < 1024; i++) {
for (j = 0; j < 4; j++) {
- ret = ocelot_mact_read(port, i, j, &entry);
+ struct ocelot_mact_entry entry;
+ bool is_static;
+ int ret;
+
+ ret = ocelot_mact_read(ocelot, port, i, j, &entry);
/* If the entry is invalid (wrong port, invalid...),
* skip it.
*/
if (ret == -EINVAL)
continue;
else if (ret)
- goto end;
+ return ret;
- ret = ocelot_fdb_do_dump(&entry, &dump);
+ is_static = (entry.type == ENTRYTYPE_LOCKED);
+
+ ret = cb(entry.mac, entry.vid, is_static, data);
if (ret)
- goto end;
+ return ret;
}
}
-end:
+ return 0;
+}
+EXPORT_SYMBOL(ocelot_fdb_dump);
+
+static int ocelot_port_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ struct net_device *filter_dev, int *idx)
+{
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ struct ocelot_dump_ctx dump = {
+ .dev = dev,
+ .skb = skb,
+ .cb = cb,
+ .idx = *idx,
+ };
+ int port = priv->chip_port;
+ int ret;
+
+ ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump);
+
*idx = dump.idx;
+
return ret;
}
@@ -953,18 +1081,20 @@ static int ocelot_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
static int ocelot_set_features(struct net_device *dev,
netdev_features_t features)
{
- struct ocelot_port *port = netdev_priv(dev);
netdev_features_t changed = dev->features ^ features;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
- port->tc.offload_cnt) {
+ priv->tc.offload_cnt) {
netdev_err(dev,
"Cannot disable HW TC offload while offloads active\n");
return -EBUSY;
}
if (changed & NETIF_F_HW_VLAN_CTAG_FILTER)
- ocelot_vlan_mode(port, features);
+ ocelot_vlan_mode(ocelot, port, features);
return 0;
}
@@ -972,8 +1102,8 @@ static int ocelot_set_features(struct net_device *dev,
static int ocelot_get_port_parent_id(struct net_device *dev,
struct netdev_phys_item_id *ppid)
{
- struct ocelot_port *ocelot_port = netdev_priv(dev);
- struct ocelot *ocelot = ocelot_port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
ppid->id_len = sizeof(ocelot->base_mac);
memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
@@ -981,17 +1111,16 @@ static int ocelot_get_port_parent_id(struct net_device *dev,
return 0;
}
-static int ocelot_hwstamp_get(struct ocelot_port *port, struct ifreq *ifr)
+int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
{
- struct ocelot *ocelot = port->ocelot;
-
return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
}
+EXPORT_SYMBOL(ocelot_hwstamp_get);
-static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr)
+int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
{
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
struct hwtstamp_config cfg;
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
@@ -1004,16 +1133,16 @@ static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr)
/* Tx type sanity check */
switch (cfg.tx_type) {
case HWTSTAMP_TX_ON:
- port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
+ ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
break;
case HWTSTAMP_TX_ONESTEP_SYNC:
/* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
* need to update the origin time.
*/
- port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
+ ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
break;
case HWTSTAMP_TX_OFF:
- port->ptp_cmd = 0;
+ ocelot_port->ptp_cmd = 0;
break;
default:
return -ERANGE;
@@ -1052,11 +1181,13 @@ static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr)
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
+EXPORT_SYMBOL(ocelot_hwstamp_set);
static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
/* The function is only used for PTP operations for now */
if (!ocelot->ptp)
@@ -1064,9 +1195,9 @@ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCSHWTSTAMP:
- return ocelot_hwstamp_set(port, ifr);
+ return ocelot_hwstamp_set(ocelot, port, ifr);
case SIOCGHWTSTAMP:
- return ocelot_hwstamp_get(port, ifr);
+ return ocelot_hwstamp_get(ocelot, port, ifr);
default:
return -EOPNOTSUPP;
}
@@ -1080,9 +1211,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_get_phys_port_name = ocelot_port_get_phys_port_name,
.ndo_set_mac_address = ocelot_port_set_mac_address,
.ndo_get_stats64 = ocelot_get_stats64,
- .ndo_fdb_add = ocelot_fdb_add,
- .ndo_fdb_del = ocelot_fdb_del,
- .ndo_fdb_dump = ocelot_fdb_dump,
+ .ndo_fdb_add = ocelot_port_fdb_add,
+ .ndo_fdb_del = ocelot_port_fdb_del,
+ .ndo_fdb_dump = ocelot_port_fdb_dump,
.ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
.ndo_set_features = ocelot_set_features,
@@ -1091,10 +1222,8 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_do_ioctl = ocelot_ioctl,
};
-static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
{
- struct ocelot_port *port = netdev_priv(netdev);
- struct ocelot *ocelot = port->ocelot;
int i;
if (sset != ETH_SS_STATS)
@@ -1104,6 +1233,17 @@ static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name,
ETH_GSTRING_LEN);
}
+EXPORT_SYMBOL(ocelot_get_strings);
+
+static void ocelot_port_get_strings(struct net_device *netdev, u32 sset,
+ u8 *data)
+{
+ struct ocelot_port_private *priv = netdev_priv(netdev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+
+ ocelot_get_strings(ocelot, port, sset, data);
+}
static void ocelot_update_stats(struct ocelot *ocelot)
{
@@ -1145,11 +1285,8 @@ static void ocelot_check_stats_work(struct work_struct *work)
OCELOT_STATS_CHECK_DELAY);
}
-static void ocelot_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
+void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
int i;
/* check and update now */
@@ -1157,28 +1294,42 @@ static void ocelot_get_ethtool_stats(struct net_device *dev,
/* Copy all counters */
for (i = 0; i < ocelot->num_stats; i++)
- *data++ = ocelot->stats[port->chip_port * ocelot->num_stats + i];
+ *data++ = ocelot->stats[port * ocelot->num_stats + i];
}
+EXPORT_SYMBOL(ocelot_get_ethtool_stats);
-static int ocelot_get_sset_count(struct net_device *dev, int sset)
+static void ocelot_port_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+ ocelot_get_ethtool_stats(ocelot, port, data);
+}
+
+int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
+{
if (sset != ETH_SS_STATS)
return -EOPNOTSUPP;
+
return ocelot->num_stats;
}
+EXPORT_SYMBOL(ocelot_get_sset_count);
-static int ocelot_get_ts_info(struct net_device *dev,
- struct ethtool_ts_info *info)
+static int ocelot_port_get_sset_count(struct net_device *dev, int sset)
{
- struct ocelot_port *ocelot_port = netdev_priv(dev);
- struct ocelot *ocelot = ocelot_port->ocelot;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
- if (!ocelot->ptp)
- return ethtool_op_get_ts_info(dev, info);
+ return ocelot_get_sset_count(ocelot, port, sset);
+}
+int ocelot_get_ts_info(struct ocelot *ocelot, int port,
+ struct ethtool_ts_info *info)
+{
info->phc_index = ocelot->ptp_clock ?
ptp_clock_index(ocelot->ptp_clock) : -1;
info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
@@ -1193,36 +1344,43 @@ static int ocelot_get_ts_info(struct net_device *dev,
return 0;
}
+EXPORT_SYMBOL(ocelot_get_ts_info);
+
+static int ocelot_port_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
+
+ if (!ocelot->ptp)
+ return ethtool_op_get_ts_info(dev, info);
+
+ return ocelot_get_ts_info(ocelot, port, info);
+}
static const struct ethtool_ops ocelot_ethtool_ops = {
- .get_strings = ocelot_get_strings,
- .get_ethtool_stats = ocelot_get_ethtool_stats,
- .get_sset_count = ocelot_get_sset_count,
+ .get_strings = ocelot_port_get_strings,
+ .get_ethtool_stats = ocelot_port_get_ethtool_stats,
+ .get_sset_count = ocelot_port_get_sset_count,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
- .get_ts_info = ocelot_get_ts_info,
+ .get_ts_info = ocelot_port_get_ts_info,
};
-static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port,
- struct switchdev_trans *trans,
- u8 state)
+void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
u32 port_cfg;
- int port, i;
-
- if (switchdev_trans_ph_prepare(trans))
- return 0;
+ int p, i;
- if (!(BIT(ocelot_port->chip_port) & ocelot->bridge_mask))
- return 0;
+ if (!(BIT(port) & ocelot->bridge_mask))
+ return;
- port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG,
- ocelot_port->chip_port);
+ port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
switch (state) {
case BR_STATE_FORWARDING:
- ocelot->bridge_fwd_mask |= BIT(ocelot_port->chip_port);
+ ocelot->bridge_fwd_mask |= BIT(port);
/* Fallthrough */
case BR_STATE_LEARNING:
port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
@@ -1230,19 +1388,18 @@ static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port,
default:
port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA;
- ocelot->bridge_fwd_mask &= ~BIT(ocelot_port->chip_port);
+ ocelot->bridge_fwd_mask &= ~BIT(port);
break;
}
- ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG,
- ocelot_port->chip_port);
+ ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port);
/* Apply FWD mask. The loop is needed to add/remove the current port as
* a source for the other ports.
*/
- for (port = 0; port < ocelot->num_phys_ports; port++) {
- if (ocelot->bridge_fwd_mask & BIT(port)) {
- unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(port);
+ for (p = 0; p < ocelot->num_phys_ports; p++) {
+ if (p == ocelot->cpu || (ocelot->bridge_fwd_mask & BIT(p))) {
+ unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p);
for (i = 0; i < ocelot->num_phys_ports; i++) {
unsigned long bond_mask = ocelot->lags[i];
@@ -1250,78 +1407,93 @@ static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port,
if (!bond_mask)
continue;
- if (bond_mask & BIT(port)) {
+ if (bond_mask & BIT(p)) {
mask &= ~bond_mask;
break;
}
}
- ocelot_write_rix(ocelot,
- BIT(ocelot->num_phys_ports) | mask,
- ANA_PGID_PGID, PGID_SRC + port);
+ /* Avoid the NPI port from looping back to itself */
+ if (p != ocelot->cpu)
+ mask |= BIT(ocelot->cpu);
+
+ ocelot_write_rix(ocelot, mask,
+ ANA_PGID_PGID, PGID_SRC + p);
} else {
/* Only the CPU port, this is compatible with link
* aggregation.
*/
ocelot_write_rix(ocelot,
- BIT(ocelot->num_phys_ports),
- ANA_PGID_PGID, PGID_SRC + port);
+ BIT(ocelot->cpu),
+ ANA_PGID_PGID, PGID_SRC + p);
}
}
+}
+EXPORT_SYMBOL(ocelot_bridge_stp_state_set);
- return 0;
+static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,
+ struct switchdev_trans *trans,
+ u8 state)
+{
+ if (switchdev_trans_ph_prepare(trans))
+ return;
+
+ ocelot_bridge_stp_state_set(ocelot, port, state);
+}
+
+void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
+{
+ ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(msecs / 2),
+ ANA_AUTOAGE);
}
+EXPORT_SYMBOL(ocelot_set_ageing_time);
-static void ocelot_port_attr_ageing_set(struct ocelot_port *ocelot_port,
+static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port,
unsigned long ageing_clock_t)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
- ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(ageing_time / 2),
- ANA_AUTOAGE);
+ ocelot_set_ageing_time(ocelot, ageing_time);
}
-static void ocelot_port_attr_mc_set(struct ocelot_port *port, bool mc)
+static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc)
{
- struct ocelot *ocelot = port->ocelot;
- u32 val = ocelot_read_gix(ocelot, ANA_PORT_CPU_FWD_CFG,
- port->chip_port);
+ u32 cpu_fwd_mcast = ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
+ ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
+ ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA;
+ u32 val = 0;
if (mc)
- val |= ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA;
- else
- val &= ~(ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA);
+ val = cpu_fwd_mcast;
- ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port);
+ ocelot_rmw_gix(ocelot, val, cpu_fwd_mcast,
+ ANA_PORT_CPU_FWD_CFG, port);
}
static int ocelot_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr,
struct switchdev_trans *trans)
{
- struct ocelot_port *ocelot_port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot *ocelot = priv->port.ocelot;
+ int port = priv->chip_port;
int err = 0;
switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
- ocelot_port_attr_stp_state_set(ocelot_port, trans,
+ ocelot_port_attr_stp_state_set(ocelot, port, trans,
attr->u.stp_state);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
- ocelot_port_attr_ageing_set(ocelot_port, attr->u.ageing_time);
+ ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
- ocelot_port->vlan_aware = attr->u.vlan_filtering;
- ocelot_vlan_port_apply(ocelot_port->ocelot, ocelot_port);
+ priv->vlan_aware = attr->u.vlan_filtering;
+ ocelot_port_vlan_filtering(ocelot, port, priv->vlan_aware);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
- ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled);
+ ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
break;
default:
err = -EOPNOTSUPP;
@@ -1383,15 +1555,17 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev,
const struct switchdev_obj_port_mdb *mdb,
struct switchdev_trans *trans)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- struct ocelot_multicast *mc;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
unsigned char addr[ETH_ALEN];
+ struct ocelot_multicast *mc;
+ int port = priv->chip_port;
u16 vid = mdb->vid;
bool new = false;
if (!vid)
- vid = port->pvid;
+ vid = ocelot_port->pvid;
mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
if (!mc) {
@@ -1415,7 +1589,7 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev,
ocelot_mact_forget(ocelot, addr, vid);
}
- mc->ports |= BIT(port->chip_port);
+ mc->ports |= BIT(port);
addr[2] = mc->ports << 0;
addr[1] = mc->ports << 8;
@@ -1425,14 +1599,16 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev,
static int ocelot_port_obj_del_mdb(struct net_device *dev,
const struct switchdev_obj_port_mdb *mdb)
{
- struct ocelot_port *port = netdev_priv(dev);
- struct ocelot *ocelot = port->ocelot;
- struct ocelot_multicast *mc;
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
unsigned char addr[ETH_ALEN];
+ struct ocelot_multicast *mc;
+ int port = priv->chip_port;
u16 vid = mdb->vid;
if (!vid)
- vid = port->pvid;
+ vid = ocelot_port->pvid;
mc = ocelot_multicast_get(ocelot, mdb->addr, vid);
if (!mc)
@@ -1444,7 +1620,7 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev,
addr[0] = 0;
ocelot_mact_forget(ocelot, addr, vid);
- mc->ports &= ~BIT(port->chip_port);
+ mc->ports &= ~BIT(port);
if (!mc->ports) {
list_del(&mc->list);
devm_kfree(ocelot->dev, mc);
@@ -1501,10 +1677,10 @@ static int ocelot_port_obj_del(struct net_device *dev,
return ret;
}
-static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port,
- struct net_device *bridge)
+int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
+ struct net_device *bridge)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
if (!ocelot->bridge_mask) {
ocelot->hw_bridge_dev = bridge;
@@ -1515,26 +1691,31 @@ static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port,
return -ENODEV;
}
- ocelot->bridge_mask |= BIT(ocelot_port->chip_port);
+ ocelot->bridge_mask |= BIT(port);
+
+ /* Direct CPU traffic to PCU port, this should override any existing
+ * entries
+ */
+ ocelot_mact_learn(ocelot, PGID_CPU, bridge->dev_addr, ocelot_port->pvid,
+ ENTRYTYPE_LOCKED);
return 0;
}
+EXPORT_SYMBOL(ocelot_port_bridge_join);
-static void ocelot_port_bridge_leave(struct ocelot_port *ocelot_port,
- struct net_device *bridge)
+int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
+ struct net_device *bridge)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
-
- ocelot->bridge_mask &= ~BIT(ocelot_port->chip_port);
+ ocelot->bridge_mask &= ~BIT(port);
if (!ocelot->bridge_mask)
ocelot->hw_bridge_dev = NULL;
- /* Clear bridge vlan settings before calling ocelot_vlan_port_apply */
- ocelot_port->vlan_aware = 0;
- ocelot_port->pvid = 0;
- ocelot_port->vid = 0;
+ ocelot_port_vlan_filtering(ocelot, port, 0);
+ ocelot_port_set_pvid(ocelot, port, 0);
+ return ocelot_port_set_native_vlan(ocelot, port, 0);
}
+EXPORT_SYMBOL(ocelot_port_bridge_leave);
static void ocelot_set_aggr_pgids(struct ocelot *ocelot)
{
@@ -1594,20 +1775,18 @@ static void ocelot_setup_lag(struct ocelot *ocelot, int lag)
}
}
-static int ocelot_port_lag_join(struct ocelot_port *ocelot_port,
+static int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
- int p = ocelot_port->chip_port;
- int lag, lp;
struct net_device *ndev;
u32 bond_mask = 0;
+ int lag, lp;
rcu_read_lock();
for_each_netdev_in_bond_rcu(bond, ndev) {
- struct ocelot_port *port = netdev_priv(ndev);
+ struct ocelot_port_private *priv = netdev_priv(ndev);
- bond_mask |= BIT(port->chip_port);
+ bond_mask |= BIT(priv->chip_port);
}
rcu_read_unlock();
@@ -1616,17 +1795,17 @@ static int ocelot_port_lag_join(struct ocelot_port *ocelot_port,
/* If the new port is the lowest one, use it as the logical port from
* now on
*/
- if (p == lp) {
- lag = p;
- ocelot->lags[p] = bond_mask;
- bond_mask &= ~BIT(p);
+ if (port == lp) {
+ lag = port;
+ ocelot->lags[port] = bond_mask;
+ bond_mask &= ~BIT(port);
if (bond_mask) {
lp = __ffs(bond_mask);
ocelot->lags[lp] = 0;
}
} else {
lag = lp;
- ocelot->lags[lp] |= BIT(p);
+ ocelot->lags[lp] |= BIT(port);
}
ocelot_setup_lag(ocelot, lag);
@@ -1635,34 +1814,32 @@ static int ocelot_port_lag_join(struct ocelot_port *ocelot_port,
return 0;
}
-static void ocelot_port_lag_leave(struct ocelot_port *ocelot_port,
+static void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
struct net_device *bond)
{
- struct ocelot *ocelot = ocelot_port->ocelot;
- int p = ocelot_port->chip_port;
u32 port_cfg;
int i;
/* Remove port from any lag */
for (i = 0; i < ocelot->num_phys_ports; i++)
- ocelot->lags[i] &= ~BIT(ocelot_port->chip_port);
+ ocelot->lags[i] &= ~BIT(port);
/* if it was the logical port of the lag, move the lag config to the
* next port
*/
- if (ocelot->lags[p]) {
- int n = __ffs(ocelot->lags[p]);
+ if (ocelot->lags[port]) {
+ int n = __ffs(ocelot->lags[port]);
- ocelot->lags[n] = ocelot->lags[p];
- ocelot->lags[p] = 0;
+ ocelot->lags[n] = ocelot->lags[port];
+ ocelot->lags[port] = 0;
ocelot_setup_lag(ocelot, n);
}
- port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, p);
+ port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M;
- ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(p),
- ANA_PORT_PORT_CFG, p);
+ ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(port),
+ ANA_PORT_PORT_CFG, port);
ocelot_set_aggr_pgids(ocelot);
}
@@ -1677,28 +1854,30 @@ static int ocelot_netdevice_port_event(struct net_device *dev,
unsigned long event,
struct netdev_notifier_changeupper_info *info)
{
- struct ocelot_port *ocelot_port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
+ struct ocelot_port *ocelot_port = &priv->port;
+ struct ocelot *ocelot = ocelot_port->ocelot;
+ int port = priv->chip_port;
int err = 0;
switch (event) {
case NETDEV_CHANGEUPPER:
if (netif_is_bridge_master(info->upper_dev)) {
- if (info->linking)
- err = ocelot_port_bridge_join(ocelot_port,
+ if (info->linking) {
+ err = ocelot_port_bridge_join(ocelot, port,
info->upper_dev);
- else
- ocelot_port_bridge_leave(ocelot_port,
- info->upper_dev);
-
- ocelot_vlan_port_apply(ocelot_port->ocelot,
- ocelot_port);
+ } else {
+ err = ocelot_port_bridge_leave(ocelot, port,
+ info->upper_dev);
+ priv->vlan_aware = false;
+ }
}
if (netif_is_lag_master(info->upper_dev)) {
if (info->linking)
- err = ocelot_port_lag_join(ocelot_port,
+ err = ocelot_port_lag_join(ocelot, port,
info->upper_dev);
else
- ocelot_port_lag_leave(ocelot_port,
+ ocelot_port_lag_leave(ocelot, port,
info->upper_dev);
}
break;
@@ -1975,6 +2154,12 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
.adjfine = ocelot_ptp_adjfine,
};
+static void ocelot_deinit_timestamp(struct ocelot *ocelot)
+{
+ if (ocelot->ptp_clock)
+ ptp_clock_unregister(ocelot->ptp_clock);
+}
+
static int ocelot_init_timestamp(struct ocelot *ocelot)
{
struct ptp_clock *ptp_clock;
@@ -2003,24 +2188,97 @@ static int ocelot_init_timestamp(struct ocelot *ocelot)
return 0;
}
+static void ocelot_port_set_mtu(struct ocelot *ocelot, int port, size_t mtu)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ int atop_wm;
+
+ ocelot_port_writel(ocelot_port, mtu, DEV_MAC_MAXLEN_CFG);
+
+ /* Set Pause WM hysteresis
+ * 152 = 6 * mtu / OCELOT_BUFFER_CELL_SZ
+ * 101 = 4 * mtu / OCELOT_BUFFER_CELL_SZ
+ */
+ ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
+ SYS_PAUSE_CFG_PAUSE_STOP(101) |
+ SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
+
+ /* Tail dropping watermark */
+ atop_wm = (ocelot->shared_queue_sz - 9 * mtu) / OCELOT_BUFFER_CELL_SZ;
+ ocelot_write_rix(ocelot, ocelot_wm_enc(9 * mtu),
+ SYS_ATOP, port);
+ ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+}
+
+void ocelot_init_port(struct ocelot *ocelot, int port)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ skb_queue_head_init(&ocelot_port->tx_skbs);
+
+ /* Basic L2 initialization */
+
+ /* Set MAC IFG Gaps
+ * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0
+ * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5
+ */
+ ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5),
+ DEV_MAC_IFG_CFG);
+
+ /* Load seed (0) and set MAC HDX late collision */
+ ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) |
+ DEV_MAC_HDX_CFG_SEED_LOAD,
+ DEV_MAC_HDX_CFG);
+ mdelay(1);
+ ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67),
+ DEV_MAC_HDX_CFG);
+
+ /* Set Max Length and maximum tags allowed */
+ ocelot_port_set_mtu(ocelot, port, VLAN_ETH_FRAME_LEN);
+ ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
+ DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+ DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
+ DEV_MAC_TAGS_CFG);
+
+ /* Set SMAC of Pause frame (00:00:00:00:00:00) */
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG);
+ ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG);
+
+ /* Drop frames with multicast source address */
+ ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+ ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA,
+ ANA_PORT_DROP_CFG, port);
+
+ /* Set default VLAN and tag type to 8021Q. */
+ ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q),
+ REW_PORT_VLAN_CFG_PORT_TPID_M,
+ REW_PORT_VLAN_CFG, port);
+
+ /* Enable vcap lookups */
+ ocelot_vcap_enable(ocelot, port);
+}
+EXPORT_SYMBOL(ocelot_init_port);
+
int ocelot_probe_port(struct ocelot *ocelot, u8 port,
void __iomem *regs,
struct phy_device *phy)
{
+ struct ocelot_port_private *priv;
struct ocelot_port *ocelot_port;
struct net_device *dev;
int err;
- dev = alloc_etherdev(sizeof(struct ocelot_port));
+ dev = alloc_etherdev(sizeof(struct ocelot_port_private));
if (!dev)
return -ENOMEM;
SET_NETDEV_DEV(dev, ocelot->dev);
- ocelot_port = netdev_priv(dev);
- ocelot_port->dev = dev;
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->phy = phy;
+ priv->chip_port = port;
+ ocelot_port = &priv->port;
ocelot_port->ocelot = ocelot;
ocelot_port->regs = regs;
- ocelot_port->chip_port = port;
- ocelot_port->phy = phy;
ocelot->ports[port] = ocelot_port;
dev->netdev_ops = &ocelot_port_netdev_ops;
@@ -2035,33 +2293,107 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid,
ENTRYTYPE_LOCKED);
- INIT_LIST_HEAD(&ocelot_port->skbs);
+ ocelot_init_port(ocelot, port);
err = register_netdev(dev);
if (err) {
dev_err(ocelot->dev, "register_netdev failed\n");
- goto err_register_netdev;
+ free_netdev(dev);
}
- /* Basic L2 initialization */
- ocelot_vlan_port_apply(ocelot, ocelot_port);
+ return err;
+}
+EXPORT_SYMBOL(ocelot_probe_port);
- /* Enable vcap lookups */
- ocelot_vcap_enable(ocelot, ocelot_port);
+void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
+ enum ocelot_tag_prefix injection,
+ enum ocelot_tag_prefix extraction)
+{
+ int port;
- return 0;
+ for (port = 0; port < ocelot->num_phys_ports; port++) {
+ /* Disable old CPU port and enable new one */
+ ocelot_rmw_rix(ocelot, 0, BIT(ocelot->cpu),
+ ANA_PGID_PGID, PGID_SRC + port);
+ if (port == cpu)
+ continue;
+ ocelot_rmw_rix(ocelot, BIT(cpu), BIT(cpu),
+ ANA_PGID_PGID, PGID_SRC + port);
+ }
-err_register_netdev:
- free_netdev(dev);
- return err;
+ /* Configure and enable the CPU port. */
+ ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
+ ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU);
+ ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA |
+ ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
+ ANA_PORT_PORT_CFG, cpu);
+
+ /* If the CPU port is a physical port, set up the port in Node
+ * Processor Interface (NPI) mode. This is the mode through which
+ * frames can be injected from and extracted to an external CPU.
+ * Only one port can be an NPI at the same time.
+ */
+ if (cpu < ocelot->num_phys_ports) {
+ int mtu = VLAN_ETH_FRAME_LEN + OCELOT_TAG_LEN;
+
+ ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
+ QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu),
+ QSYS_EXT_CPU_CFG);
+
+ if (injection == OCELOT_TAG_PREFIX_SHORT)
+ mtu += OCELOT_SHORT_PREFIX_LEN;
+ else if (injection == OCELOT_TAG_PREFIX_LONG)
+ mtu += OCELOT_LONG_PREFIX_LEN;
+
+ ocelot_port_set_mtu(ocelot, cpu, mtu);
+ }
+
+ /* CPU port Injection/Extraction configuration */
+ ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
+ QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
+ QSYS_SWITCH_PORT_MODE_PORT_ENA,
+ QSYS_SWITCH_PORT_MODE, cpu);
+ ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) |
+ SYS_PORT_MODE_INCL_INJ_HDR(injection),
+ SYS_PORT_MODE, cpu);
+
+ /* Configure the CPU port to be VLAN aware */
+ ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) |
+ ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
+ ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1),
+ ANA_PORT_VLAN_CFG, cpu);
+
+ ocelot->cpu = cpu;
}
-EXPORT_SYMBOL(ocelot_probe_port);
+EXPORT_SYMBOL(ocelot_set_cpu_port);
+
+/* Entry for PTP over Ethernet (etype 0x88f7)
+ * Action: trap to CPU port
+ */
+static struct ocelot_ace_rule ptp_rule = {
+ .prio = 1,
+ .type = OCELOT_ACE_TYPE_ETYPE,
+ .dmac_mc = OCELOT_VCAP_BIT_1,
+ .action = OCELOT_ACL_ACTION_TRAP,
+ .frame.etype.etype.value[0] = 0x88,
+ .frame.etype.etype.value[1] = 0xf7,
+ .frame.etype.etype.mask[0] = 0xff,
+ .frame.etype.etype.mask[1] = 0xff,
+};
int ocelot_init(struct ocelot *ocelot)
{
- u32 port;
- int i, ret, cpu = ocelot->num_phys_ports;
char queue_name[32];
+ int i, ret;
+ u32 port;
+
+ if (ocelot->ops->reset) {
+ ret = ocelot->ops->reset(ocelot);
+ if (ret) {
+ dev_err(ocelot->dev, "Switch reset failed\n");
+ return ret;
+ }
+ }
ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
sizeof(u32), GFP_KERNEL);
@@ -2083,6 +2415,7 @@ int ocelot_init(struct ocelot *ocelot)
if (!ocelot->stats_queue)
return -ENOMEM;
+ INIT_LIST_HEAD(&ocelot->multicast);
ocelot_mact_init(ocelot);
ocelot_vlan_init(ocelot);
ocelot_ace_init(ocelot);
@@ -2118,10 +2451,11 @@ int ocelot_init(struct ocelot *ocelot)
SYS_FRM_AGING_MAX_AGE(307692), SYS_FRM_AGING);
/* Setup flooding PGIDs */
- ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
- ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
- ANA_FLOODING_FLD_UNICAST(PGID_UC),
- ANA_FLOODING, 0);
+ for (i = 0; i < 8; i++)
+ ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
+ ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
+ ANA_FLOODING_FLD_UNICAST(PGID_UC),
+ ANA_FLOODING, i);
ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) |
ANA_FLOODING_IPMC_FLD_MC6_CTRL(PGID_MC) |
ANA_FLOODING_IPMC_FLD_MC4_DATA(PGID_MCIPV4) |
@@ -2140,13 +2474,6 @@ int ocelot_init(struct ocelot *ocelot)
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port);
}
- /* Configure and enable the CPU port. */
- ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
- ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU);
- ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA |
- ANA_PORT_PORT_CFG_PORTID_VAL(cpu),
- ANA_PORT_PORT_CFG, cpu);
-
/* Allow broadcast MAC frames. */
for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) {
u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0));
@@ -2159,13 +2486,6 @@ int ocelot_init(struct ocelot *ocelot)
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4);
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6);
- /* CPU port Injection/Extraction configuration */
- ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
- QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
- QSYS_SWITCH_PORT_MODE_PORT_ENA,
- QSYS_SWITCH_PORT_MODE, cpu);
- ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(1) |
- SYS_PORT_MODE_INCL_INJ_HDR(1), SYS_PORT_MODE, cpu);
/* Allow manual injection via DEVCPU_QS registers, and byte swap these
* registers endianness.
*/
@@ -2198,6 +2518,13 @@ int ocelot_init(struct ocelot *ocelot)
"Timestamp initialization failed\n");
return ret;
}
+
+ /* Available on all ingress port except CPU port */
+ ptp_rule.ocelot = ocelot;
+ ptp_rule.ingress_port_mask =
+ GENMASK(ocelot->num_phys_ports - 1, 0);
+ ptp_rule.ingress_port_mask &= ~BIT(ocelot->cpu);
+ ocelot_ace_rule_offload_add(&ptp_rule);
}
return 0;
@@ -2206,28 +2533,22 @@ EXPORT_SYMBOL(ocelot_init);
void ocelot_deinit(struct ocelot *ocelot)
{
- struct list_head *pos, *tmp;
struct ocelot_port *port;
- struct ocelot_skb *entry;
int i;
cancel_delayed_work(&ocelot->stats_work);
destroy_workqueue(ocelot->stats_queue);
mutex_destroy(&ocelot->stats_lock);
+ if (ocelot->ptp)
+ ocelot_ace_rule_offload_del(&ptp_rule);
ocelot_ace_deinit();
+ ocelot_deinit_timestamp(ocelot);
if (ocelot->ptp_clock)
ptp_clock_unregister(ocelot->ptp_clock);
for (i = 0; i < ocelot->num_phys_ports; i++) {
port = ocelot->ports[i];
-
- list_for_each_safe(pos, tmp, &port->skbs) {
- entry = list_entry(pos, struct ocelot_skb, head);
-
- list_del(pos);
- dev_kfree_skb_any(entry->skb);
- kfree(entry);
- }
+ skb_queue_purge(&port->tx_skbs);
}
}
EXPORT_SYMBOL(ocelot_deinit);
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 06ac806052bc..90b7601408c1 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -18,19 +18,22 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/regmap.h>
-#include "ocelot_ana.h"
-#include "ocelot_dev.h"
-#include "ocelot_qsys.h"
+#include <soc/mscc/ocelot_qsys.h>
+#include <soc/mscc/ocelot_sys.h>
+#include <soc/mscc/ocelot_dev.h>
+#include <soc/mscc/ocelot_ana.h>
+#include <soc/mscc/ocelot.h>
#include "ocelot_rew.h"
-#include "ocelot_sys.h"
#include "ocelot_qs.h"
#include "ocelot_tc.h"
#include "ocelot_ptp.h"
+#include "ocelot_dev_gmii.h"
#define PGID_AGGR 64
#define PGID_SRC 80
/* Reserved PGIDs */
+#define PGID_MCRED (PGID_AGGR - 25)
#define PGID_CPU (PGID_AGGR - 5)
#define PGID_UC (PGID_AGGR - 4)
#define PGID_MC (PGID_AGGR - 3)
@@ -43,8 +46,6 @@
#define OCELOT_PTP_QUEUE_SZ 128
-#define IFH_LEN 4
-
struct frame_info {
u32 len;
u16 port;
@@ -54,372 +55,6 @@ struct frame_info {
u32 timestamp; /* rew_val */
};
-#define IFH_INJ_BYPASS BIT(31)
-#define IFH_INJ_POP_CNT_DISABLE (3 << 28)
-
-#define IFH_TAG_TYPE_C 0
-#define IFH_TAG_TYPE_S 1
-
-#define IFH_REW_OP_NOOP 0x0
-#define IFH_REW_OP_DSCP 0x1
-#define IFH_REW_OP_ONE_STEP_PTP 0x2
-#define IFH_REW_OP_TWO_STEP_PTP 0x3
-#define IFH_REW_OP_ORIGIN_PTP 0x5
-
-#define OCELOT_SPEED_2500 0
-#define OCELOT_SPEED_1000 1
-#define OCELOT_SPEED_100 2
-#define OCELOT_SPEED_10 3
-
-#define TARGET_OFFSET 24
-#define REG_MASK GENMASK(TARGET_OFFSET - 1, 0)
-#define REG(reg, offset) [reg & REG_MASK] = offset
-
-enum ocelot_target {
- ANA = 1,
- QS,
- QSYS,
- REW,
- SYS,
- S2,
- HSIO,
- PTP,
- TARGET_MAX,
-};
-
-enum ocelot_reg {
- ANA_ADVLEARN = ANA << TARGET_OFFSET,
- ANA_VLANMASK,
- ANA_PORT_B_DOMAIN,
- ANA_ANAGEFIL,
- ANA_ANEVENTS,
- ANA_STORMLIMIT_BURST,
- ANA_STORMLIMIT_CFG,
- ANA_ISOLATED_PORTS,
- ANA_COMMUNITY_PORTS,
- ANA_AUTOAGE,
- ANA_MACTOPTIONS,
- ANA_LEARNDISC,
- ANA_AGENCTRL,
- ANA_MIRRORPORTS,
- ANA_EMIRRORPORTS,
- ANA_FLOODING,
- ANA_FLOODING_IPMC,
- ANA_SFLOW_CFG,
- ANA_PORT_MODE,
- ANA_CUT_THRU_CFG,
- ANA_PGID_PGID,
- ANA_TABLES_ANMOVED,
- ANA_TABLES_MACHDATA,
- ANA_TABLES_MACLDATA,
- ANA_TABLES_STREAMDATA,
- ANA_TABLES_MACACCESS,
- ANA_TABLES_MACTINDX,
- ANA_TABLES_VLANACCESS,
- ANA_TABLES_VLANTIDX,
- ANA_TABLES_ISDXACCESS,
- ANA_TABLES_ISDXTIDX,
- ANA_TABLES_ENTRYLIM,
- ANA_TABLES_PTP_ID_HIGH,
- ANA_TABLES_PTP_ID_LOW,
- ANA_TABLES_STREAMACCESS,
- ANA_TABLES_STREAMTIDX,
- ANA_TABLES_SEQ_HISTORY,
- ANA_TABLES_SEQ_MASK,
- ANA_TABLES_SFID_MASK,
- ANA_TABLES_SFIDACCESS,
- ANA_TABLES_SFIDTIDX,
- ANA_MSTI_STATE,
- ANA_OAM_UPM_LM_CNT,
- ANA_SG_ACCESS_CTRL,
- ANA_SG_CONFIG_REG_1,
- ANA_SG_CONFIG_REG_2,
- ANA_SG_CONFIG_REG_3,
- ANA_SG_CONFIG_REG_4,
- ANA_SG_CONFIG_REG_5,
- ANA_SG_GCL_GS_CONFIG,
- ANA_SG_GCL_TI_CONFIG,
- ANA_SG_STATUS_REG_1,
- ANA_SG_STATUS_REG_2,
- ANA_SG_STATUS_REG_3,
- ANA_PORT_VLAN_CFG,
- ANA_PORT_DROP_CFG,
- ANA_PORT_QOS_CFG,
- ANA_PORT_VCAP_CFG,
- ANA_PORT_VCAP_S1_KEY_CFG,
- ANA_PORT_VCAP_S2_CFG,
- ANA_PORT_PCP_DEI_MAP,
- ANA_PORT_CPU_FWD_CFG,
- ANA_PORT_CPU_FWD_BPDU_CFG,
- ANA_PORT_CPU_FWD_GARP_CFG,
- ANA_PORT_CPU_FWD_CCM_CFG,
- ANA_PORT_PORT_CFG,
- ANA_PORT_POL_CFG,
- ANA_PORT_PTP_CFG,
- ANA_PORT_PTP_DLY1_CFG,
- ANA_PORT_PTP_DLY2_CFG,
- ANA_PORT_SFID_CFG,
- ANA_PFC_PFC_CFG,
- ANA_PFC_PFC_TIMER,
- ANA_IPT_OAM_MEP_CFG,
- ANA_IPT_IPT,
- ANA_PPT_PPT,
- ANA_FID_MAP_FID_MAP,
- ANA_AGGR_CFG,
- ANA_CPUQ_CFG,
- ANA_CPUQ_CFG2,
- ANA_CPUQ_8021_CFG,
- ANA_DSCP_CFG,
- ANA_DSCP_REWR_CFG,
- ANA_VCAP_RNG_TYPE_CFG,
- ANA_VCAP_RNG_VAL_CFG,
- ANA_VRAP_CFG,
- ANA_VRAP_HDR_DATA,
- ANA_VRAP_HDR_MASK,
- ANA_DISCARD_CFG,
- ANA_FID_CFG,
- ANA_POL_PIR_CFG,
- ANA_POL_CIR_CFG,
- ANA_POL_MODE_CFG,
- ANA_POL_PIR_STATE,
- ANA_POL_CIR_STATE,
- ANA_POL_STATE,
- ANA_POL_FLOWC,
- ANA_POL_HYST,
- ANA_POL_MISC_CFG,
- QS_XTR_GRP_CFG = QS << TARGET_OFFSET,
- QS_XTR_RD,
- QS_XTR_FRM_PRUNING,
- QS_XTR_FLUSH,
- QS_XTR_DATA_PRESENT,
- QS_XTR_CFG,
- QS_INJ_GRP_CFG,
- QS_INJ_WR,
- QS_INJ_CTRL,
- QS_INJ_STATUS,
- QS_INJ_ERR,
- QS_INH_DBG,
- QSYS_PORT_MODE = QSYS << TARGET_OFFSET,
- QSYS_SWITCH_PORT_MODE,
- QSYS_STAT_CNT_CFG,
- QSYS_EEE_CFG,
- QSYS_EEE_THRES,
- QSYS_IGR_NO_SHARING,
- QSYS_EGR_NO_SHARING,
- QSYS_SW_STATUS,
- QSYS_EXT_CPU_CFG,
- QSYS_PAD_CFG,
- QSYS_CPU_GROUP_MAP,
- QSYS_QMAP,
- QSYS_ISDX_SGRP,
- QSYS_TIMED_FRAME_ENTRY,
- QSYS_TFRM_MISC,
- QSYS_TFRM_PORT_DLY,
- QSYS_TFRM_TIMER_CFG_1,
- QSYS_TFRM_TIMER_CFG_2,
- QSYS_TFRM_TIMER_CFG_3,
- QSYS_TFRM_TIMER_CFG_4,
- QSYS_TFRM_TIMER_CFG_5,
- QSYS_TFRM_TIMER_CFG_6,
- QSYS_TFRM_TIMER_CFG_7,
- QSYS_TFRM_TIMER_CFG_8,
- QSYS_RED_PROFILE,
- QSYS_RES_QOS_MODE,
- QSYS_RES_CFG,
- QSYS_RES_STAT,
- QSYS_EGR_DROP_MODE,
- QSYS_EQ_CTRL,
- QSYS_EVENTS_CORE,
- QSYS_QMAXSDU_CFG_0,
- QSYS_QMAXSDU_CFG_1,
- QSYS_QMAXSDU_CFG_2,
- QSYS_QMAXSDU_CFG_3,
- QSYS_QMAXSDU_CFG_4,
- QSYS_QMAXSDU_CFG_5,
- QSYS_QMAXSDU_CFG_6,
- QSYS_QMAXSDU_CFG_7,
- QSYS_PREEMPTION_CFG,
- QSYS_CIR_CFG,
- QSYS_EIR_CFG,
- QSYS_SE_CFG,
- QSYS_SE_DWRR_CFG,
- QSYS_SE_CONNECT,
- QSYS_SE_DLB_SENSE,
- QSYS_CIR_STATE,
- QSYS_EIR_STATE,
- QSYS_SE_STATE,
- QSYS_HSCH_MISC_CFG,
- QSYS_TAG_CONFIG,
- QSYS_TAS_PARAM_CFG_CTRL,
- QSYS_PORT_MAX_SDU,
- QSYS_PARAM_CFG_REG_1,
- QSYS_PARAM_CFG_REG_2,
- QSYS_PARAM_CFG_REG_3,
- QSYS_PARAM_CFG_REG_4,
- QSYS_PARAM_CFG_REG_5,
- QSYS_GCL_CFG_REG_1,
- QSYS_GCL_CFG_REG_2,
- QSYS_PARAM_STATUS_REG_1,
- QSYS_PARAM_STATUS_REG_2,
- QSYS_PARAM_STATUS_REG_3,
- QSYS_PARAM_STATUS_REG_4,
- QSYS_PARAM_STATUS_REG_5,
- QSYS_PARAM_STATUS_REG_6,
- QSYS_PARAM_STATUS_REG_7,
- QSYS_PARAM_STATUS_REG_8,
- QSYS_PARAM_STATUS_REG_9,
- QSYS_GCL_STATUS_REG_1,
- QSYS_GCL_STATUS_REG_2,
- REW_PORT_VLAN_CFG = REW << TARGET_OFFSET,
- REW_TAG_CFG,
- REW_PORT_CFG,
- REW_DSCP_CFG,
- REW_PCP_DEI_QOS_MAP_CFG,
- REW_PTP_CFG,
- REW_PTP_DLY1_CFG,
- REW_RED_TAG_CFG,
- REW_DSCP_REMAP_DP1_CFG,
- REW_DSCP_REMAP_CFG,
- REW_STAT_CFG,
- REW_REW_STICKY,
- REW_PPT,
- SYS_COUNT_RX_OCTETS = SYS << TARGET_OFFSET,
- SYS_COUNT_RX_UNICAST,
- SYS_COUNT_RX_MULTICAST,
- SYS_COUNT_RX_BROADCAST,
- SYS_COUNT_RX_SHORTS,
- SYS_COUNT_RX_FRAGMENTS,
- SYS_COUNT_RX_JABBERS,
- SYS_COUNT_RX_CRC_ALIGN_ERRS,
- SYS_COUNT_RX_SYM_ERRS,
- SYS_COUNT_RX_64,
- SYS_COUNT_RX_65_127,
- SYS_COUNT_RX_128_255,
- SYS_COUNT_RX_256_1023,
- SYS_COUNT_RX_1024_1526,
- SYS_COUNT_RX_1527_MAX,
- SYS_COUNT_RX_PAUSE,
- SYS_COUNT_RX_CONTROL,
- SYS_COUNT_RX_LONGS,
- SYS_COUNT_RX_CLASSIFIED_DROPS,
- SYS_COUNT_TX_OCTETS,
- SYS_COUNT_TX_UNICAST,
- SYS_COUNT_TX_MULTICAST,
- SYS_COUNT_TX_BROADCAST,
- SYS_COUNT_TX_COLLISION,
- SYS_COUNT_TX_DROPS,
- SYS_COUNT_TX_PAUSE,
- SYS_COUNT_TX_64,
- SYS_COUNT_TX_65_127,
- SYS_COUNT_TX_128_511,
- SYS_COUNT_TX_512_1023,
- SYS_COUNT_TX_1024_1526,
- SYS_COUNT_TX_1527_MAX,
- SYS_COUNT_TX_AGING,
- SYS_RESET_CFG,
- SYS_SR_ETYPE_CFG,
- SYS_VLAN_ETYPE_CFG,
- SYS_PORT_MODE,
- SYS_FRONT_PORT_MODE,
- SYS_FRM_AGING,
- SYS_STAT_CFG,
- SYS_SW_STATUS,
- SYS_MISC_CFG,
- SYS_REW_MAC_HIGH_CFG,
- SYS_REW_MAC_LOW_CFG,
- SYS_TIMESTAMP_OFFSET,
- SYS_CMID,
- SYS_PAUSE_CFG,
- SYS_PAUSE_TOT_CFG,
- SYS_ATOP,
- SYS_ATOP_TOT_CFG,
- SYS_MAC_FC_CFG,
- SYS_MMGT,
- SYS_MMGT_FAST,
- SYS_EVENTS_DIF,
- SYS_EVENTS_CORE,
- SYS_CNT,
- SYS_PTP_STATUS,
- SYS_PTP_TXSTAMP,
- SYS_PTP_NXT,
- SYS_PTP_CFG,
- SYS_RAM_INIT,
- SYS_CM_ADDR,
- SYS_CM_DATA_WR,
- SYS_CM_DATA_RD,
- SYS_CM_OP,
- SYS_CM_DATA,
- S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
- S2_CORE_MV_CFG,
- S2_CACHE_ENTRY_DAT,
- S2_CACHE_MASK_DAT,
- S2_CACHE_ACTION_DAT,
- S2_CACHE_CNT_DAT,
- S2_CACHE_TG_DAT,
- PTP_PIN_CFG = PTP << TARGET_OFFSET,
- PTP_PIN_TOD_SEC_MSB,
- PTP_PIN_TOD_SEC_LSB,
- PTP_PIN_TOD_NSEC,
- PTP_CFG_MISC,
- PTP_CLK_CFG_ADJ_CFG,
- PTP_CLK_CFG_ADJ_FREQ,
-};
-
-enum ocelot_regfield {
- ANA_ADVLEARN_VLAN_CHK,
- ANA_ADVLEARN_LEARN_MIRROR,
- ANA_ANEVENTS_FLOOD_DISCARD,
- ANA_ANEVENTS_MSTI_DROP,
- ANA_ANEVENTS_ACLKILL,
- ANA_ANEVENTS_ACLUSED,
- ANA_ANEVENTS_AUTOAGE,
- ANA_ANEVENTS_VS2TTL1,
- ANA_ANEVENTS_STORM_DROP,
- ANA_ANEVENTS_LEARN_DROP,
- ANA_ANEVENTS_AGED_ENTRY,
- ANA_ANEVENTS_CPU_LEARN_FAILED,
- ANA_ANEVENTS_AUTO_LEARN_FAILED,
- ANA_ANEVENTS_LEARN_REMOVE,
- ANA_ANEVENTS_AUTO_LEARNED,
- ANA_ANEVENTS_AUTO_MOVED,
- ANA_ANEVENTS_DROPPED,
- ANA_ANEVENTS_CLASSIFIED_DROP,
- ANA_ANEVENTS_CLASSIFIED_COPY,
- ANA_ANEVENTS_VLAN_DISCARD,
- ANA_ANEVENTS_FWD_DISCARD,
- ANA_ANEVENTS_MULTICAST_FLOOD,
- ANA_ANEVENTS_UNICAST_FLOOD,
- ANA_ANEVENTS_DEST_KNOWN,
- ANA_ANEVENTS_BUCKET3_MATCH,
- ANA_ANEVENTS_BUCKET2_MATCH,
- ANA_ANEVENTS_BUCKET1_MATCH,
- ANA_ANEVENTS_BUCKET0_MATCH,
- ANA_ANEVENTS_CPU_OPERATION,
- ANA_ANEVENTS_DMAC_LOOKUP,
- ANA_ANEVENTS_SMAC_LOOKUP,
- ANA_ANEVENTS_SEQ_GEN_ERR_0,
- ANA_ANEVENTS_SEQ_GEN_ERR_1,
- ANA_TABLES_MACACCESS_B_DOM,
- ANA_TABLES_MACTINDX_BUCKET,
- ANA_TABLES_MACTINDX_M_INDEX,
- QSYS_TIMED_FRAME_ENTRY_TFRM_VLD,
- QSYS_TIMED_FRAME_ENTRY_TFRM_FP,
- QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO,
- QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL,
- QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T,
- SYS_RESET_CFG_CORE_ENA,
- SYS_RESET_CFG_MEM_ENA,
- SYS_RESET_CFG_MEM_INIT,
- REGFIELD_MAX
-};
-
-enum ocelot_clk_pins {
- ALT_PPS_PIN = 1,
- EXT_CLK_PIN,
- ALT_LDST_PIN,
- TOD_ACC_PIN
-};
-
struct ocelot_multicast {
struct list_head list;
unsigned char addr[ETH_ALEN];
@@ -427,133 +62,39 @@ struct ocelot_multicast {
u16 ports;
};
-struct ocelot_port;
-
-struct ocelot_stat_layout {
- u32 offset;
- char name[ETH_GSTRING_LEN];
-};
-
-struct ocelot {
- struct device *dev;
-
- struct regmap *targets[TARGET_MAX];
- struct regmap_field *regfields[REGFIELD_MAX];
- const u32 *const *map;
- const struct ocelot_stat_layout *stats_layout;
- unsigned int num_stats;
-
- u8 base_mac[ETH_ALEN];
-
- struct net_device *hw_bridge_dev;
- u16 bridge_mask;
- u16 bridge_fwd_mask;
-
- struct workqueue_struct *ocelot_owq;
-
- int shared_queue_sz;
-
- u8 num_phys_ports;
- u8 num_cpu_ports;
- struct ocelot_port **ports;
-
- u32 *lags;
-
- /* Keep track of the vlan port masks */
- u32 vlan_mask[VLAN_N_VID];
-
- struct list_head multicast;
-
- /* Workqueue to check statistics for overflow with its lock */
- struct mutex stats_lock;
- u64 *stats;
- struct delayed_work stats_work;
- struct workqueue_struct *stats_queue;
-
- u8 ptp:1;
- struct ptp_clock *ptp_clock;
- struct ptp_clock_info ptp_info;
- struct hwtstamp_config hwtstamp_config;
- struct mutex ptp_lock; /* Protects the PTP interface state */
- spinlock_t ptp_clock_lock; /* Protects the PTP clock */
-};
-
-struct ocelot_port {
+struct ocelot_port_private {
+ struct ocelot_port port;
struct net_device *dev;
- struct ocelot *ocelot;
struct phy_device *phy;
- void __iomem *regs;
u8 chip_port;
- /* Ingress default VLAN (pvid) */
- u16 pvid;
-
- /* Egress default VLAN (vid) */
- u16 vid;
-
u8 vlan_aware;
- u64 *stats;
-
- phy_interface_t phy_mode;
struct phy *serdes;
struct ocelot_port_tc tc;
-
- u8 ptp_cmd;
- struct list_head skbs;
- u8 ts_id;
-};
-
-struct ocelot_skb {
- struct list_head head;
- struct sk_buff *skb;
- u8 id;
};
-u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
-#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
-#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi))
-#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri))
-#define ocelot_read(ocelot, reg) __ocelot_read_ix(ocelot, reg, 0)
-
-void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset);
-#define ocelot_write_ix(ocelot, val, reg, gi, ri) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
-#define ocelot_write_gix(ocelot, val, reg, gi) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi))
-#define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri))
-#define ocelot_write(ocelot, val, reg) __ocelot_write_ix(ocelot, val, reg, 0)
-
-void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
- u32 offset);
-#define ocelot_rmw_ix(ocelot, val, m, reg, gi, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
-#define ocelot_rmw_gix(ocelot, val, m, reg, gi) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi))
-#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri))
-#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0)
-
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
-int ocelot_regfields_init(struct ocelot *ocelot,
- const struct reg_field *const regfields);
-struct regmap *ocelot_io_platform_init(struct ocelot *ocelot,
- struct platform_device *pdev,
- const char *name);
-
#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
-int ocelot_init(struct ocelot *ocelot);
-void ocelot_deinit(struct ocelot *ocelot);
-int ocelot_chip_init(struct ocelot *ocelot);
+int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops);
int ocelot_probe_port(struct ocelot *ocelot, u8 port,
void __iomem *regs,
struct phy_device *phy);
+void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
+ enum ocelot_tag_prefix injection,
+ enum ocelot_tag_prefix extraction);
+
extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb;
-int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
-void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
+#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val))
+#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val))
#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index 86fc6e6b46dd..18670645d47f 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -352,7 +352,7 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
data.type = IS2_ACTION_TYPE_NORMAL;
VCAP_KEY_ANY_SET(PAG);
- VCAP_KEY_SET(IGR_PORT_MASK, 0, ~BIT(ace->chip_port));
+ VCAP_KEY_SET(IGR_PORT_MASK, 0, ~ace->ingress_port_mask);
VCAP_KEY_BIT_SET(FIRST, OCELOT_VCAP_BIT_1);
VCAP_KEY_BIT_SET(HOST_MATCH, OCELOT_VCAP_BIT_ANY);
VCAP_KEY_BIT_SET(L2_MC, ace->dmac_mc);
@@ -576,7 +576,7 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
static void is2_entry_get(struct ocelot_ace_rule *rule, int ix)
{
- struct ocelot *op = rule->port->ocelot;
+ struct ocelot *op = rule->ocelot;
struct vcap_data data;
int row = (ix / 2);
u32 cnt;
@@ -655,11 +655,11 @@ int ocelot_ace_rule_offload_add(struct ocelot_ace_rule *rule)
/* Move down the rules to make place for the new rule */
for (i = acl_block->count - 1; i > index; i--) {
ace = ocelot_ace_rule_get_rule_index(acl_block, i);
- is2_entry_set(rule->port->ocelot, i, ace);
+ is2_entry_set(rule->ocelot, i, ace);
}
/* Now insert the new rule */
- is2_entry_set(rule->port->ocelot, index, rule);
+ is2_entry_set(rule->ocelot, index, rule);
return 0;
}
@@ -697,11 +697,11 @@ int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule)
/* Move up all the blocks over the deleted rule */
for (i = index; i < acl_block->count; i++) {
ace = ocelot_ace_rule_get_rule_index(acl_block, i);
- is2_entry_set(rule->port->ocelot, i, ace);
+ is2_entry_set(rule->ocelot, i, ace);
}
/* Now delete the last rule, because it is duplicated */
- is2_entry_set(rule->port->ocelot, acl_block->count, &del_ace);
+ is2_entry_set(rule->ocelot, acl_block->count, &del_ace);
return 0;
}
@@ -717,7 +717,7 @@ int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule)
/* After we get the result we need to clear the counters */
tmp = ocelot_ace_rule_get_rule_index(acl_block, index);
tmp->stats.pkts = 0;
- is2_entry_set(rule->port->ocelot, index, tmp);
+ is2_entry_set(rule->ocelot, index, tmp);
return 0;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index e98944c87259..2927ac83741b 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -186,14 +186,14 @@ struct ocelot_ace_stats {
struct ocelot_ace_rule {
struct list_head list;
- struct ocelot_port *port;
+ struct ocelot *ocelot;
u16 prio;
u32 id;
enum ocelot_ace_action action;
struct ocelot_ace_stats stats;
- int chip_port;
+ u16 ingress_port_mask;
enum ocelot_vcap_bit dmac_mc;
enum ocelot_vcap_bit dmac_bc;
@@ -224,9 +224,9 @@ int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule);
int ocelot_ace_init(struct ocelot *ocelot);
void ocelot_ace_deinit(void);
-int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
+int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
struct flow_block_offload *f);
-void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
+void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
struct flow_block_offload *f);
#endif /* _MSCC_OCELOT_ACE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_ana.h b/drivers/net/ethernet/mscc/ocelot_ana.h
deleted file mode 100644
index 841c6ec22b64..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_ana.h
+++ /dev/null
@@ -1,625 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_ANA_H_
-#define _MSCC_OCELOT_ANA_H_
-
-#define ANA_ANAGEFIL_B_DOM_EN BIT(22)
-#define ANA_ANAGEFIL_B_DOM_VAL BIT(21)
-#define ANA_ANAGEFIL_AGE_LOCKED BIT(20)
-#define ANA_ANAGEFIL_PID_EN BIT(19)
-#define ANA_ANAGEFIL_PID_VAL(x) (((x) << 14) & GENMASK(18, 14))
-#define ANA_ANAGEFIL_PID_VAL_M GENMASK(18, 14)
-#define ANA_ANAGEFIL_PID_VAL_X(x) (((x) & GENMASK(18, 14)) >> 14)
-#define ANA_ANAGEFIL_VID_EN BIT(13)
-#define ANA_ANAGEFIL_VID_VAL(x) ((x) & GENMASK(12, 0))
-#define ANA_ANAGEFIL_VID_VAL_M GENMASK(12, 0)
-
-#define ANA_STORMLIMIT_CFG_RSZ 0x4
-
-#define ANA_STORMLIMIT_CFG_STORM_RATE(x) (((x) << 3) & GENMASK(6, 3))
-#define ANA_STORMLIMIT_CFG_STORM_RATE_M GENMASK(6, 3)
-#define ANA_STORMLIMIT_CFG_STORM_RATE_X(x) (((x) & GENMASK(6, 3)) >> 3)
-#define ANA_STORMLIMIT_CFG_STORM_UNIT BIT(2)
-#define ANA_STORMLIMIT_CFG_STORM_MODE(x) ((x) & GENMASK(1, 0))
-#define ANA_STORMLIMIT_CFG_STORM_MODE_M GENMASK(1, 0)
-
-#define ANA_AUTOAGE_AGE_FAST BIT(21)
-#define ANA_AUTOAGE_AGE_PERIOD(x) (((x) << 1) & GENMASK(20, 1))
-#define ANA_AUTOAGE_AGE_PERIOD_M GENMASK(20, 1)
-#define ANA_AUTOAGE_AGE_PERIOD_X(x) (((x) & GENMASK(20, 1)) >> 1)
-#define ANA_AUTOAGE_AUTOAGE_LOCKED BIT(0)
-
-#define ANA_MACTOPTIONS_REDUCED_TABLE BIT(1)
-#define ANA_MACTOPTIONS_SHADOW BIT(0)
-
-#define ANA_AGENCTRL_FID_MASK(x) (((x) << 12) & GENMASK(23, 12))
-#define ANA_AGENCTRL_FID_MASK_M GENMASK(23, 12)
-#define ANA_AGENCTRL_FID_MASK_X(x) (((x) & GENMASK(23, 12)) >> 12)
-#define ANA_AGENCTRL_IGNORE_DMAC_FLAGS BIT(11)
-#define ANA_AGENCTRL_IGNORE_SMAC_FLAGS BIT(10)
-#define ANA_AGENCTRL_FLOOD_SPECIAL BIT(9)
-#define ANA_AGENCTRL_FLOOD_IGNORE_VLAN BIT(8)
-#define ANA_AGENCTRL_MIRROR_CPU BIT(7)
-#define ANA_AGENCTRL_LEARN_CPU_COPY BIT(6)
-#define ANA_AGENCTRL_LEARN_FWD_KILL BIT(5)
-#define ANA_AGENCTRL_LEARN_IGNORE_VLAN BIT(4)
-#define ANA_AGENCTRL_CPU_CPU_KILL_ENA BIT(3)
-#define ANA_AGENCTRL_GREEN_COUNT_MODE BIT(2)
-#define ANA_AGENCTRL_YELLOW_COUNT_MODE BIT(1)
-#define ANA_AGENCTRL_RED_COUNT_MODE BIT(0)
-
-#define ANA_FLOODING_RSZ 0x4
-
-#define ANA_FLOODING_FLD_UNICAST(x) (((x) << 12) & GENMASK(17, 12))
-#define ANA_FLOODING_FLD_UNICAST_M GENMASK(17, 12)
-#define ANA_FLOODING_FLD_UNICAST_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define ANA_FLOODING_FLD_BROADCAST(x) (((x) << 6) & GENMASK(11, 6))
-#define ANA_FLOODING_FLD_BROADCAST_M GENMASK(11, 6)
-#define ANA_FLOODING_FLD_BROADCAST_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define ANA_FLOODING_FLD_MULTICAST(x) ((x) & GENMASK(5, 0))
-#define ANA_FLOODING_FLD_MULTICAST_M GENMASK(5, 0)
-
-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL(x) (((x) << 18) & GENMASK(23, 18))
-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_M GENMASK(23, 18)
-#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_X(x) (((x) & GENMASK(23, 18)) >> 18)
-#define ANA_FLOODING_IPMC_FLD_MC4_DATA(x) (((x) << 12) & GENMASK(17, 12))
-#define ANA_FLOODING_IPMC_FLD_MC4_DATA_M GENMASK(17, 12)
-#define ANA_FLOODING_IPMC_FLD_MC4_DATA_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL(x) (((x) << 6) & GENMASK(11, 6))
-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_M GENMASK(11, 6)
-#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define ANA_FLOODING_IPMC_FLD_MC6_DATA(x) ((x) & GENMASK(5, 0))
-#define ANA_FLOODING_IPMC_FLD_MC6_DATA_M GENMASK(5, 0)
-
-#define ANA_SFLOW_CFG_RSZ 0x4
-
-#define ANA_SFLOW_CFG_SF_RATE(x) (((x) << 2) & GENMASK(13, 2))
-#define ANA_SFLOW_CFG_SF_RATE_M GENMASK(13, 2)
-#define ANA_SFLOW_CFG_SF_RATE_X(x) (((x) & GENMASK(13, 2)) >> 2)
-#define ANA_SFLOW_CFG_SF_SAMPLE_RX BIT(1)
-#define ANA_SFLOW_CFG_SF_SAMPLE_TX BIT(0)
-
-#define ANA_PORT_MODE_RSZ 0x4
-
-#define ANA_PORT_MODE_REDTAG_PARSE_CFG BIT(3)
-#define ANA_PORT_MODE_VLAN_PARSE_CFG(x) (((x) << 1) & GENMASK(2, 1))
-#define ANA_PORT_MODE_VLAN_PARSE_CFG_M GENMASK(2, 1)
-#define ANA_PORT_MODE_VLAN_PARSE_CFG_X(x) (((x) & GENMASK(2, 1)) >> 1)
-#define ANA_PORT_MODE_L3_PARSE_CFG BIT(0)
-
-#define ANA_CUT_THRU_CFG_RSZ 0x4
-
-#define ANA_PGID_PGID_RSZ 0x4
-
-#define ANA_PGID_PGID_PGID(x) ((x) & GENMASK(11, 0))
-#define ANA_PGID_PGID_PGID_M GENMASK(11, 0)
-#define ANA_PGID_PGID_CPUQ_DST_PGID(x) (((x) << 27) & GENMASK(29, 27))
-#define ANA_PGID_PGID_CPUQ_DST_PGID_M GENMASK(29, 27)
-#define ANA_PGID_PGID_CPUQ_DST_PGID_X(x) (((x) & GENMASK(29, 27)) >> 27)
-
-#define ANA_TABLES_MACHDATA_VID(x) (((x) << 16) & GENMASK(28, 16))
-#define ANA_TABLES_MACHDATA_VID_M GENMASK(28, 16)
-#define ANA_TABLES_MACHDATA_VID_X(x) (((x) & GENMASK(28, 16)) >> 16)
-#define ANA_TABLES_MACHDATA_MACHDATA(x) ((x) & GENMASK(15, 0))
-#define ANA_TABLES_MACHDATA_MACHDATA_M GENMASK(15, 0)
-
-#define ANA_TABLES_STREAMDATA_SSID_VALID BIT(16)
-#define ANA_TABLES_STREAMDATA_SSID(x) (((x) << 9) & GENMASK(15, 9))
-#define ANA_TABLES_STREAMDATA_SSID_M GENMASK(15, 9)
-#define ANA_TABLES_STREAMDATA_SSID_X(x) (((x) & GENMASK(15, 9)) >> 9)
-#define ANA_TABLES_STREAMDATA_SFID_VALID BIT(8)
-#define ANA_TABLES_STREAMDATA_SFID(x) ((x) & GENMASK(7, 0))
-#define ANA_TABLES_STREAMDATA_SFID_M GENMASK(7, 0)
-
-#define ANA_TABLES_MACACCESS_MAC_CPU_COPY BIT(15)
-#define ANA_TABLES_MACACCESS_SRC_KILL BIT(14)
-#define ANA_TABLES_MACACCESS_IGNORE_VLAN BIT(13)
-#define ANA_TABLES_MACACCESS_AGED_FLAG BIT(12)
-#define ANA_TABLES_MACACCESS_VALID BIT(11)
-#define ANA_TABLES_MACACCESS_ENTRYTYPE(x) (((x) << 9) & GENMASK(10, 9))
-#define ANA_TABLES_MACACCESS_ENTRYTYPE_M GENMASK(10, 9)
-#define ANA_TABLES_MACACCESS_ENTRYTYPE_X(x) (((x) & GENMASK(10, 9)) >> 9)
-#define ANA_TABLES_MACACCESS_DEST_IDX(x) (((x) << 3) & GENMASK(8, 3))
-#define ANA_TABLES_MACACCESS_DEST_IDX_M GENMASK(8, 3)
-#define ANA_TABLES_MACACCESS_DEST_IDX_X(x) (((x) & GENMASK(8, 3)) >> 3)
-#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) ((x) & GENMASK(2, 0))
-#define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0)
-#define MACACCESS_CMD_IDLE 0
-#define MACACCESS_CMD_LEARN 1
-#define MACACCESS_CMD_FORGET 2
-#define MACACCESS_CMD_AGE 3
-#define MACACCESS_CMD_GET_NEXT 4
-#define MACACCESS_CMD_INIT 5
-#define MACACCESS_CMD_READ 6
-#define MACACCESS_CMD_WRITE 7
-
-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK(x) (((x) << 2) & GENMASK(13, 2))
-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_M GENMASK(13, 2)
-#define ANA_TABLES_VLANACCESS_VLAN_PORT_MASK_X(x) (((x) & GENMASK(13, 2)) >> 2)
-#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD(x) ((x) & GENMASK(1, 0))
-#define ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M GENMASK(1, 0)
-#define ANA_TABLES_VLANACCESS_CMD_IDLE 0x0
-#define ANA_TABLES_VLANACCESS_CMD_WRITE 0x2
-#define ANA_TABLES_VLANACCESS_CMD_INIT 0x3
-
-#define ANA_TABLES_VLANTIDX_VLAN_SEC_FWD_ENA BIT(17)
-#define ANA_TABLES_VLANTIDX_VLAN_FLOOD_DIS BIT(16)
-#define ANA_TABLES_VLANTIDX_VLAN_PRIV_VLAN BIT(15)
-#define ANA_TABLES_VLANTIDX_VLAN_LEARN_DISABLED BIT(14)
-#define ANA_TABLES_VLANTIDX_VLAN_MIRROR BIT(13)
-#define ANA_TABLES_VLANTIDX_VLAN_SRC_CHK BIT(12)
-#define ANA_TABLES_VLANTIDX_V_INDEX(x) ((x) & GENMASK(11, 0))
-#define ANA_TABLES_VLANTIDX_V_INDEX_M GENMASK(11, 0)
-
-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK(x) (((x) << 2) & GENMASK(8, 2))
-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_M GENMASK(8, 2)
-#define ANA_TABLES_ISDXACCESS_ISDX_PORT_MASK_X(x) (((x) & GENMASK(8, 2)) >> 2)
-#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD(x) ((x) & GENMASK(1, 0))
-#define ANA_TABLES_ISDXACCESS_ISDX_TBL_CMD_M GENMASK(1, 0)
-
-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI(x) (((x) << 21) & GENMASK(28, 21))
-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_M GENMASK(28, 21)
-#define ANA_TABLES_ISDXTIDX_ISDX_SDLBI_X(x) (((x) & GENMASK(28, 21)) >> 21)
-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI(x) (((x) << 15) & GENMASK(20, 15))
-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_M GENMASK(20, 15)
-#define ANA_TABLES_ISDXTIDX_ISDX_MSTI_X(x) (((x) & GENMASK(20, 15)) >> 15)
-#define ANA_TABLES_ISDXTIDX_ISDX_ES0_KEY_ENA BIT(14)
-#define ANA_TABLES_ISDXTIDX_ISDX_FORCE_ENA BIT(10)
-#define ANA_TABLES_ISDXTIDX_ISDX_INDEX(x) ((x) & GENMASK(7, 0))
-#define ANA_TABLES_ISDXTIDX_ISDX_INDEX_M GENMASK(7, 0)
-
-#define ANA_TABLES_ENTRYLIM_RSZ 0x4
-
-#define ANA_TABLES_ENTRYLIM_ENTRYLIM(x) (((x) << 14) & GENMASK(17, 14))
-#define ANA_TABLES_ENTRYLIM_ENTRYLIM_M GENMASK(17, 14)
-#define ANA_TABLES_ENTRYLIM_ENTRYLIM_X(x) (((x) & GENMASK(17, 14)) >> 14)
-#define ANA_TABLES_ENTRYLIM_ENTRYSTAT(x) ((x) & GENMASK(13, 0))
-#define ANA_TABLES_ENTRYLIM_ENTRYSTAT_M GENMASK(13, 0)
-
-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(x) (((x) << 4) & GENMASK(31, 4))
-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_M GENMASK(31, 4)
-#define ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(x) (((x) & GENMASK(31, 4)) >> 4)
-#define ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA BIT(3)
-#define ANA_TABLES_STREAMACCESS_GEN_REC_TYPE BIT(2)
-#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(x) ((x) & GENMASK(1, 0))
-#define ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD_M GENMASK(1, 0)
-
-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS(x) (((x) << 30) & GENMASK(31, 30))
-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_M GENMASK(31, 30)
-#define ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(x) (((x) & GENMASK(31, 30)) >> 30)
-#define ANA_TABLES_STREAMTIDX_S_INDEX(x) (((x) << 16) & GENMASK(22, 16))
-#define ANA_TABLES_STREAMTIDX_S_INDEX_M GENMASK(22, 16)
-#define ANA_TABLES_STREAMTIDX_S_INDEX_X(x) (((x) & GENMASK(22, 16)) >> 16)
-#define ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR BIT(14)
-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(x) (((x) << 8) & GENMASK(13, 8))
-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_M GENMASK(13, 8)
-#define ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(x) (((x) & GENMASK(13, 8)) >> 8)
-#define ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE BIT(7)
-#define ANA_TABLES_STREAMTIDX_REDTAG_POP BIT(6)
-#define ANA_TABLES_STREAMTIDX_STREAM_SPLIT BIT(5)
-#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(x) ((x) & GENMASK(4, 0))
-#define ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2_M GENMASK(4, 0)
-
-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK(x) (((x) << 16) & GENMASK(22, 16))
-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_M GENMASK(22, 16)
-#define ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(x) (((x) & GENMASK(22, 16)) >> 16)
-#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(x) ((x) & GENMASK(6, 0))
-#define ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK_M GENMASK(6, 0)
-
-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK(x) (((x) << 1) & GENMASK(7, 1))
-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_M GENMASK(7, 1)
-#define ANA_TABLES_SFID_MASK_IGR_PORT_MASK_X(x) (((x) & GENMASK(7, 1)) >> 1)
-#define ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA BIT(0)
-
-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA BIT(22)
-#define ANA_TABLES_SFIDACCESS_IGR_PRIO(x) (((x) << 19) & GENMASK(21, 19))
-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_M GENMASK(21, 19)
-#define ANA_TABLES_SFIDACCESS_IGR_PRIO_X(x) (((x) & GENMASK(21, 19)) >> 19)
-#define ANA_TABLES_SFIDACCESS_FORCE_BLOCK BIT(18)
-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(x) (((x) << 2) & GENMASK(17, 2))
-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_M GENMASK(17, 2)
-#define ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(x) (((x) & GENMASK(17, 2)) >> 2)
-#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x) ((x) & GENMASK(1, 0))
-#define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M GENMASK(1, 0)
-
-#define ANA_TABLES_SFIDTIDX_SGID_VALID BIT(26)
-#define ANA_TABLES_SFIDTIDX_SGID(x) (((x) << 18) & GENMASK(25, 18))
-#define ANA_TABLES_SFIDTIDX_SGID_M GENMASK(25, 18)
-#define ANA_TABLES_SFIDTIDX_SGID_X(x) (((x) & GENMASK(25, 18)) >> 18)
-#define ANA_TABLES_SFIDTIDX_POL_ENA BIT(17)
-#define ANA_TABLES_SFIDTIDX_POL_IDX(x) (((x) << 8) & GENMASK(16, 8))
-#define ANA_TABLES_SFIDTIDX_POL_IDX_M GENMASK(16, 8)
-#define ANA_TABLES_SFIDTIDX_POL_IDX_X(x) (((x) & GENMASK(16, 8)) >> 8)
-#define ANA_TABLES_SFIDTIDX_SFID_INDEX(x) ((x) & GENMASK(7, 0))
-#define ANA_TABLES_SFIDTIDX_SFID_INDEX_M GENMASK(7, 0)
-
-#define ANA_MSTI_STATE_RSZ 0x4
-
-#define ANA_OAM_UPM_LM_CNT_RSZ 0x4
-
-#define ANA_SG_ACCESS_CTRL_SGID(x) ((x) & GENMASK(7, 0))
-#define ANA_SG_ACCESS_CTRL_SGID_M GENMASK(7, 0)
-#define ANA_SG_ACCESS_CTRL_CONFIG_CHANGE BIT(28)
-
-#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(x) ((x) & GENMASK(15, 0))
-#define ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_M GENMASK(15, 0)
-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH(x) (((x) << 16) & GENMASK(18, 16))
-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M GENMASK(18, 16)
-#define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x) (((x) & GENMASK(18, 16)) >> 16)
-#define ANA_SG_CONFIG_REG_3_GATE_ENABLE BIT(20)
-#define ANA_SG_CONFIG_REG_3_INIT_IPS(x) (((x) << 24) & GENMASK(27, 24))
-#define ANA_SG_CONFIG_REG_3_INIT_IPS_M GENMASK(27, 24)
-#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x) (((x) & GENMASK(27, 24)) >> 24)
-#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE BIT(28)
-
-#define ANA_SG_GCL_GS_CONFIG_RSZ 0x4
-
-#define ANA_SG_GCL_GS_CONFIG_IPS(x) ((x) & GENMASK(3, 0))
-#define ANA_SG_GCL_GS_CONFIG_IPS_M GENMASK(3, 0)
-#define ANA_SG_GCL_GS_CONFIG_GATE_STATE BIT(4)
-
-#define ANA_SG_GCL_TI_CONFIG_RSZ 0x4
-
-#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(x) ((x) & GENMASK(15, 0))
-#define ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB_M GENMASK(15, 0)
-#define ANA_SG_STATUS_REG_3_GATE_STATE BIT(16)
-#define ANA_SG_STATUS_REG_3_IPS(x) (((x) << 20) & GENMASK(23, 20))
-#define ANA_SG_STATUS_REG_3_IPS_M GENMASK(23, 20)
-#define ANA_SG_STATUS_REG_3_IPS_X(x) (((x) & GENMASK(23, 20)) >> 20)
-#define ANA_SG_STATUS_REG_3_CONFIG_PENDING BIT(24)
-
-#define ANA_PORT_VLAN_CFG_GSZ 0x100
-
-#define ANA_PORT_VLAN_CFG_VLAN_VID_AS_ISDX BIT(21)
-#define ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA BIT(20)
-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT(x) (((x) << 18) & GENMASK(19, 18))
-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M GENMASK(19, 18)
-#define ANA_PORT_VLAN_CFG_VLAN_POP_CNT_X(x) (((x) & GENMASK(19, 18)) >> 18)
-#define ANA_PORT_VLAN_CFG_VLAN_INNER_TAG_ENA BIT(17)
-#define ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE BIT(16)
-#define ANA_PORT_VLAN_CFG_VLAN_DEI BIT(15)
-#define ANA_PORT_VLAN_CFG_VLAN_PCP(x) (((x) << 12) & GENMASK(14, 12))
-#define ANA_PORT_VLAN_CFG_VLAN_PCP_M GENMASK(14, 12)
-#define ANA_PORT_VLAN_CFG_VLAN_PCP_X(x) (((x) & GENMASK(14, 12)) >> 12)
-#define ANA_PORT_VLAN_CFG_VLAN_VID(x) ((x) & GENMASK(11, 0))
-#define ANA_PORT_VLAN_CFG_VLAN_VID_M GENMASK(11, 0)
-
-#define ANA_PORT_DROP_CFG_GSZ 0x100
-
-#define ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA BIT(6)
-#define ANA_PORT_DROP_CFG_DROP_S_TAGGED_ENA BIT(5)
-#define ANA_PORT_DROP_CFG_DROP_C_TAGGED_ENA BIT(4)
-#define ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA BIT(3)
-#define ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA BIT(2)
-#define ANA_PORT_DROP_CFG_DROP_NULL_MAC_ENA BIT(1)
-#define ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA BIT(0)
-
-#define ANA_PORT_QOS_CFG_GSZ 0x100
-
-#define ANA_PORT_QOS_CFG_DP_DEFAULT_VAL BIT(8)
-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL(x) (((x) << 5) & GENMASK(7, 5))
-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_M GENMASK(7, 5)
-#define ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(x) (((x) & GENMASK(7, 5)) >> 5)
-#define ANA_PORT_QOS_CFG_QOS_DSCP_ENA BIT(4)
-#define ANA_PORT_QOS_CFG_QOS_PCP_ENA BIT(3)
-#define ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA BIT(2)
-#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG(x) ((x) & GENMASK(1, 0))
-#define ANA_PORT_QOS_CFG_DSCP_REWR_CFG_M GENMASK(1, 0)
-
-#define ANA_PORT_VCAP_CFG_GSZ 0x100
-
-#define ANA_PORT_VCAP_CFG_S1_ENA BIT(14)
-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA(x) (((x) << 11) & GENMASK(13, 11))
-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_M GENMASK(13, 11)
-#define ANA_PORT_VCAP_CFG_S1_DMAC_DIP_ENA_X(x) (((x) & GENMASK(13, 11)) >> 11)
-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA(x) (((x) << 8) & GENMASK(10, 8))
-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_M GENMASK(10, 8)
-#define ANA_PORT_VCAP_CFG_S1_VLAN_INNER_TAG_ENA_X(x) (((x) & GENMASK(10, 8)) >> 8)
-#define ANA_PORT_VCAP_CFG_PAG_VAL(x) ((x) & GENMASK(7, 0))
-#define ANA_PORT_VCAP_CFG_PAG_VAL_M GENMASK(7, 0)
-
-#define ANA_PORT_VCAP_S1_KEY_CFG_GSZ 0x100
-#define ANA_PORT_VCAP_S1_KEY_CFG_RSZ 0x4
-
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(x) (((x) << 4) & GENMASK(6, 4))
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_M GENMASK(6, 4)
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG_X(x) (((x) & GENMASK(6, 4)) >> 4)
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(x) (((x) << 2) & GENMASK(3, 2))
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_M GENMASK(3, 2)
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG_X(x) (((x) & GENMASK(3, 2)) >> 2)
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG(x) ((x) & GENMASK(1, 0))
-#define ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_OTHER_CFG_M GENMASK(1, 0)
-
-#define ANA_PORT_VCAP_S2_CFG_GSZ 0x100
-
-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA(x) (((x) << 17) & GENMASK(18, 17))
-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_M GENMASK(18, 17)
-#define ANA_PORT_VCAP_S2_CFG_S2_UDP_PAYLOAD_ENA_X(x) (((x) & GENMASK(18, 17)) >> 17)
-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA(x) (((x) << 15) & GENMASK(16, 15))
-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_M GENMASK(16, 15)
-#define ANA_PORT_VCAP_S2_CFG_S2_ETYPE_PAYLOAD_ENA_X(x) (((x) & GENMASK(16, 15)) >> 15)
-#define ANA_PORT_VCAP_S2_CFG_S2_ENA BIT(14)
-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(x) (((x) << 12) & GENMASK(13, 12))
-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_M GENMASK(13, 12)
-#define ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS_X(x) (((x) & GENMASK(13, 12)) >> 12)
-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(x) (((x) << 10) & GENMASK(11, 10))
-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_M GENMASK(11, 10)
-#define ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS_X(x) (((x) & GENMASK(11, 10)) >> 10)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(x) (((x) << 8) & GENMASK(9, 8))
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_M GENMASK(9, 8)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS_X(x) (((x) & GENMASK(9, 8)) >> 8)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(x) (((x) << 6) & GENMASK(7, 6))
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_M GENMASK(7, 6)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS_X(x) (((x) & GENMASK(7, 6)) >> 6)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(x) (((x) << 2) & GENMASK(5, 2))
-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_M GENMASK(5, 2)
-#define ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG_X(x) (((x) & GENMASK(5, 2)) >> 2)
-#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(x) ((x) & GENMASK(1, 0))
-#define ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS_M GENMASK(1, 0)
-
-#define ANA_PORT_PCP_DEI_MAP_GSZ 0x100
-#define ANA_PORT_PCP_DEI_MAP_RSZ 0x4
-
-#define ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL BIT(3)
-#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(x) ((x) & GENMASK(2, 0))
-#define ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M GENMASK(2, 0)
-
-#define ANA_PORT_CPU_FWD_CFG_GSZ 0x100
-
-#define ANA_PORT_CPU_FWD_CFG_CPU_VRAP_REDIR_ENA BIT(7)
-#define ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA BIT(6)
-#define ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA BIT(5)
-#define ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA BIT(4)
-#define ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA BIT(3)
-#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_DROP_ENA BIT(2)
-#define ANA_PORT_CPU_FWD_CFG_CPU_ALLBRIDGE_REDIR_ENA BIT(1)
-#define ANA_PORT_CPU_FWD_CFG_CPU_OAM_ENA BIT(0)
-
-#define ANA_PORT_CPU_FWD_BPDU_CFG_GSZ 0x100
-
-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA(x) (((x) << 16) & GENMASK(31, 16))
-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_M GENMASK(31, 16)
-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(x) ((x) & GENMASK(15, 0))
-#define ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_M GENMASK(15, 0)
-
-#define ANA_PORT_CPU_FWD_GARP_CFG_GSZ 0x100
-
-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA(x) (((x) << 16) & GENMASK(31, 16))
-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_M GENMASK(31, 16)
-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_DROP_ENA_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA(x) ((x) & GENMASK(15, 0))
-#define ANA_PORT_CPU_FWD_GARP_CFG_GARP_REDIR_ENA_M GENMASK(15, 0)
-
-#define ANA_PORT_CPU_FWD_CCM_CFG_GSZ 0x100
-
-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA(x) (((x) << 16) & GENMASK(31, 16))
-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_M GENMASK(31, 16)
-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_DROP_ENA_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA(x) ((x) & GENMASK(15, 0))
-#define ANA_PORT_CPU_FWD_CCM_CFG_CCM_REDIR_ENA_M GENMASK(15, 0)
-
-#define ANA_PORT_PORT_CFG_GSZ 0x100
-
-#define ANA_PORT_PORT_CFG_SRC_MIRROR_ENA BIT(15)
-#define ANA_PORT_PORT_CFG_LIMIT_DROP BIT(14)
-#define ANA_PORT_PORT_CFG_LIMIT_CPU BIT(13)
-#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_DROP BIT(12)
-#define ANA_PORT_PORT_CFG_LOCKED_PORTMOVE_CPU BIT(11)
-#define ANA_PORT_PORT_CFG_LEARNDROP BIT(10)
-#define ANA_PORT_PORT_CFG_LEARNCPU BIT(9)
-#define ANA_PORT_PORT_CFG_LEARNAUTO BIT(8)
-#define ANA_PORT_PORT_CFG_LEARN_ENA BIT(7)
-#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
-#define ANA_PORT_PORT_CFG_PORTID_VAL(x) (((x) << 2) & GENMASK(5, 2))
-#define ANA_PORT_PORT_CFG_PORTID_VAL_M GENMASK(5, 2)
-#define ANA_PORT_PORT_CFG_PORTID_VAL_X(x) (((x) & GENMASK(5, 2)) >> 2)
-#define ANA_PORT_PORT_CFG_USE_B_DOM_TBL BIT(1)
-#define ANA_PORT_PORT_CFG_LSR_MODE BIT(0)
-
-#define ANA_PORT_POL_CFG_GSZ 0x100
-
-#define ANA_PORT_POL_CFG_POL_CPU_REDIR_8021 BIT(19)
-#define ANA_PORT_POL_CFG_POL_CPU_REDIR_IP BIT(18)
-#define ANA_PORT_POL_CFG_PORT_POL_ENA BIT(17)
-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA(x) (((x) << 9) & GENMASK(16, 9))
-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_M GENMASK(16, 9)
-#define ANA_PORT_POL_CFG_QUEUE_POL_ENA_X(x) (((x) & GENMASK(16, 9)) >> 9)
-#define ANA_PORT_POL_CFG_POL_ORDER(x) ((x) & GENMASK(8, 0))
-#define ANA_PORT_POL_CFG_POL_ORDER_M GENMASK(8, 0)
-
-#define ANA_PORT_PTP_CFG_GSZ 0x100
-
-#define ANA_PORT_PTP_CFG_PTP_BACKPLANE_MODE BIT(0)
-
-#define ANA_PORT_PTP_DLY1_CFG_GSZ 0x100
-
-#define ANA_PORT_PTP_DLY2_CFG_GSZ 0x100
-
-#define ANA_PORT_SFID_CFG_GSZ 0x100
-#define ANA_PORT_SFID_CFG_RSZ 0x4
-
-#define ANA_PORT_SFID_CFG_SFID_VALID BIT(8)
-#define ANA_PORT_SFID_CFG_SFID(x) ((x) & GENMASK(7, 0))
-#define ANA_PORT_SFID_CFG_SFID_M GENMASK(7, 0)
-
-#define ANA_PFC_PFC_CFG_GSZ 0x40
-
-#define ANA_PFC_PFC_CFG_RX_PFC_ENA(x) (((x) << 2) & GENMASK(9, 2))
-#define ANA_PFC_PFC_CFG_RX_PFC_ENA_M GENMASK(9, 2)
-#define ANA_PFC_PFC_CFG_RX_PFC_ENA_X(x) (((x) & GENMASK(9, 2)) >> 2)
-#define ANA_PFC_PFC_CFG_FC_LINK_SPEED(x) ((x) & GENMASK(1, 0))
-#define ANA_PFC_PFC_CFG_FC_LINK_SPEED_M GENMASK(1, 0)
-
-#define ANA_PFC_PFC_TIMER_GSZ 0x40
-#define ANA_PFC_PFC_TIMER_RSZ 0x4
-
-#define ANA_IPT_OAM_MEP_CFG_GSZ 0x8
-
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P(x) (((x) << 6) & GENMASK(10, 6))
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_M GENMASK(10, 6)
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_P_X(x) (((x) & GENMASK(10, 6)) >> 6)
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX(x) (((x) << 1) & GENMASK(5, 1))
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_M GENMASK(5, 1)
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_X(x) (((x) & GENMASK(5, 1)) >> 1)
-#define ANA_IPT_OAM_MEP_CFG_MEP_IDX_ENA BIT(0)
-
-#define ANA_IPT_IPT_GSZ 0x8
-
-#define ANA_IPT_IPT_IPT_CFG(x) (((x) << 15) & GENMASK(16, 15))
-#define ANA_IPT_IPT_IPT_CFG_M GENMASK(16, 15)
-#define ANA_IPT_IPT_IPT_CFG_X(x) (((x) & GENMASK(16, 15)) >> 15)
-#define ANA_IPT_IPT_ISDX_P(x) (((x) << 7) & GENMASK(14, 7))
-#define ANA_IPT_IPT_ISDX_P_M GENMASK(14, 7)
-#define ANA_IPT_IPT_ISDX_P_X(x) (((x) & GENMASK(14, 7)) >> 7)
-#define ANA_IPT_IPT_PPT_IDX(x) ((x) & GENMASK(6, 0))
-#define ANA_IPT_IPT_PPT_IDX_M GENMASK(6, 0)
-
-#define ANA_PPT_PPT_RSZ 0x4
-
-#define ANA_FID_MAP_FID_MAP_RSZ 0x4
-
-#define ANA_FID_MAP_FID_MAP_FID_C_VAL(x) (((x) << 6) & GENMASK(11, 6))
-#define ANA_FID_MAP_FID_MAP_FID_C_VAL_M GENMASK(11, 6)
-#define ANA_FID_MAP_FID_MAP_FID_C_VAL_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define ANA_FID_MAP_FID_MAP_FID_B_VAL(x) ((x) & GENMASK(5, 0))
-#define ANA_FID_MAP_FID_MAP_FID_B_VAL_M GENMASK(5, 0)
-
-#define ANA_AGGR_CFG_AC_RND_ENA BIT(7)
-#define ANA_AGGR_CFG_AC_DMAC_ENA BIT(6)
-#define ANA_AGGR_CFG_AC_SMAC_ENA BIT(5)
-#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA BIT(4)
-#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA BIT(3)
-#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA BIT(2)
-#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA BIT(1)
-#define ANA_AGGR_CFG_AC_ISDX_ENA BIT(0)
-
-#define ANA_CPUQ_CFG_CPUQ_MLD(x) (((x) << 27) & GENMASK(29, 27))
-#define ANA_CPUQ_CFG_CPUQ_MLD_M GENMASK(29, 27)
-#define ANA_CPUQ_CFG_CPUQ_MLD_X(x) (((x) & GENMASK(29, 27)) >> 27)
-#define ANA_CPUQ_CFG_CPUQ_IGMP(x) (((x) << 24) & GENMASK(26, 24))
-#define ANA_CPUQ_CFG_CPUQ_IGMP_M GENMASK(26, 24)
-#define ANA_CPUQ_CFG_CPUQ_IGMP_X(x) (((x) & GENMASK(26, 24)) >> 24)
-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL(x) (((x) << 21) & GENMASK(23, 21))
-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_M GENMASK(23, 21)
-#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_X(x) (((x) & GENMASK(23, 21)) >> 21)
-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE(x) (((x) << 18) & GENMASK(20, 18))
-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_M GENMASK(20, 18)
-#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_X(x) (((x) & GENMASK(20, 18)) >> 18)
-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE(x) (((x) << 15) & GENMASK(17, 15))
-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_M GENMASK(17, 15)
-#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_X(x) (((x) & GENMASK(17, 15)) >> 15)
-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY(x) (((x) << 12) & GENMASK(14, 12))
-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_M GENMASK(14, 12)
-#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_X(x) (((x) & GENMASK(14, 12)) >> 12)
-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY(x) (((x) << 9) & GENMASK(11, 9))
-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_M GENMASK(11, 9)
-#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_X(x) (((x) & GENMASK(11, 9)) >> 9)
-#define ANA_CPUQ_CFG_CPUQ_LRN(x) (((x) << 6) & GENMASK(8, 6))
-#define ANA_CPUQ_CFG_CPUQ_LRN_M GENMASK(8, 6)
-#define ANA_CPUQ_CFG_CPUQ_LRN_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define ANA_CPUQ_CFG_CPUQ_MIRROR(x) (((x) << 3) & GENMASK(5, 3))
-#define ANA_CPUQ_CFG_CPUQ_MIRROR_M GENMASK(5, 3)
-#define ANA_CPUQ_CFG_CPUQ_MIRROR_X(x) (((x) & GENMASK(5, 3)) >> 3)
-#define ANA_CPUQ_CFG_CPUQ_SFLOW(x) ((x) & GENMASK(2, 0))
-#define ANA_CPUQ_CFG_CPUQ_SFLOW_M GENMASK(2, 0)
-
-#define ANA_CPUQ_8021_CFG_RSZ 0x4
-
-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL(x) (((x) << 6) & GENMASK(8, 6))
-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_M GENMASK(8, 6)
-#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL(x) (((x) << 3) & GENMASK(5, 3))
-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_M GENMASK(5, 3)
-#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_X(x) (((x) & GENMASK(5, 3)) >> 3)
-#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL(x) ((x) & GENMASK(2, 0))
-#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_M GENMASK(2, 0)
-
-#define ANA_DSCP_CFG_RSZ 0x4
-
-#define ANA_DSCP_CFG_DP_DSCP_VAL BIT(11)
-#define ANA_DSCP_CFG_QOS_DSCP_VAL(x) (((x) << 8) & GENMASK(10, 8))
-#define ANA_DSCP_CFG_QOS_DSCP_VAL_M GENMASK(10, 8)
-#define ANA_DSCP_CFG_QOS_DSCP_VAL_X(x) (((x) & GENMASK(10, 8)) >> 8)
-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(x) (((x) << 2) & GENMASK(7, 2))
-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_M GENMASK(7, 2)
-#define ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_X(x) (((x) & GENMASK(7, 2)) >> 2)
-#define ANA_DSCP_CFG_DSCP_TRUST_ENA BIT(1)
-#define ANA_DSCP_CFG_DSCP_REWR_ENA BIT(0)
-
-#define ANA_DSCP_REWR_CFG_RSZ 0x4
-
-#define ANA_VCAP_RNG_TYPE_CFG_RSZ 0x4
-
-#define ANA_VCAP_RNG_VAL_CFG_RSZ 0x4
-
-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL(x) (((x) << 16) & GENMASK(31, 16))
-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_M GENMASK(31, 16)
-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MIN_VAL_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL(x) ((x) & GENMASK(15, 0))
-#define ANA_VCAP_RNG_VAL_CFG_VCAP_RNG_MAX_VAL_M GENMASK(15, 0)
-
-#define ANA_VRAP_CFG_VRAP_VLAN_AWARE_ENA BIT(12)
-#define ANA_VRAP_CFG_VRAP_VID(x) ((x) & GENMASK(11, 0))
-#define ANA_VRAP_CFG_VRAP_VID_M GENMASK(11, 0)
-
-#define ANA_DISCARD_CFG_DROP_TAGGING_ISDX0 BIT(3)
-#define ANA_DISCARD_CFG_DROP_CTRLPROT_ISDX0 BIT(2)
-#define ANA_DISCARD_CFG_DROP_TAGGING_S2_ENA BIT(1)
-#define ANA_DISCARD_CFG_DROP_CTRLPROT_S2_ENA BIT(0)
-
-#define ANA_FID_CFG_VID_MC_ENA BIT(0)
-
-#define ANA_POL_PIR_CFG_GSZ 0x20
-
-#define ANA_POL_PIR_CFG_PIR_RATE(x) (((x) << 6) & GENMASK(20, 6))
-#define ANA_POL_PIR_CFG_PIR_RATE_M GENMASK(20, 6)
-#define ANA_POL_PIR_CFG_PIR_RATE_X(x) (((x) & GENMASK(20, 6)) >> 6)
-#define ANA_POL_PIR_CFG_PIR_BURST(x) ((x) & GENMASK(5, 0))
-#define ANA_POL_PIR_CFG_PIR_BURST_M GENMASK(5, 0)
-
-#define ANA_POL_CIR_CFG_GSZ 0x20
-
-#define ANA_POL_CIR_CFG_CIR_RATE(x) (((x) << 6) & GENMASK(20, 6))
-#define ANA_POL_CIR_CFG_CIR_RATE_M GENMASK(20, 6)
-#define ANA_POL_CIR_CFG_CIR_RATE_X(x) (((x) & GENMASK(20, 6)) >> 6)
-#define ANA_POL_CIR_CFG_CIR_BURST(x) ((x) & GENMASK(5, 0))
-#define ANA_POL_CIR_CFG_CIR_BURST_M GENMASK(5, 0)
-
-#define ANA_POL_MODE_CFG_GSZ 0x20
-
-#define ANA_POL_MODE_CFG_IPG_SIZE(x) (((x) << 5) & GENMASK(9, 5))
-#define ANA_POL_MODE_CFG_IPG_SIZE_M GENMASK(9, 5)
-#define ANA_POL_MODE_CFG_IPG_SIZE_X(x) (((x) & GENMASK(9, 5)) >> 5)
-#define ANA_POL_MODE_CFG_FRM_MODE(x) (((x) << 3) & GENMASK(4, 3))
-#define ANA_POL_MODE_CFG_FRM_MODE_M GENMASK(4, 3)
-#define ANA_POL_MODE_CFG_FRM_MODE_X(x) (((x) & GENMASK(4, 3)) >> 3)
-#define ANA_POL_MODE_CFG_DLB_COUPLED BIT(2)
-#define ANA_POL_MODE_CFG_CIR_ENA BIT(1)
-#define ANA_POL_MODE_CFG_OVERSHOOT_ENA BIT(0)
-
-#define ANA_POL_PIR_STATE_GSZ 0x20
-
-#define ANA_POL_CIR_STATE_GSZ 0x20
-
-#define ANA_POL_STATE_GSZ 0x20
-
-#define ANA_POL_FLOWC_RSZ 0x4
-
-#define ANA_POL_FLOWC_POL_FLOWC BIT(0)
-
-#define ANA_POL_HYST_POL_FC_HYST(x) (((x) << 4) & GENMASK(9, 4))
-#define ANA_POL_HYST_POL_FC_HYST_M GENMASK(9, 4)
-#define ANA_POL_HYST_POL_FC_HYST_X(x) (((x) & GENMASK(9, 4)) >> 4)
-#define ANA_POL_HYST_POL_STOP_HYST(x) ((x) & GENMASK(3, 0))
-#define ANA_POL_HYST_POL_STOP_HYST_M GENMASK(3, 0)
-
-#define ANA_POL_MISC_CFG_POL_CLOSE_ALL BIT(1)
-#define ANA_POL_MISC_CFG_POL_LEAK_DIS BIT(0)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index 337156232501..9b10e697e4e2 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -95,6 +95,8 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
do {
struct skb_shared_hwtstamps *shhwtstamps;
+ struct ocelot_port_private *priv;
+ struct ocelot_port *ocelot_port;
u64 tod_in_ns, full_ts_in_ns;
struct frame_info info = {};
struct net_device *dev;
@@ -103,7 +105,7 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
int sz, len, buf_len;
struct sk_buff *skb;
- for (i = 0; i < IFH_LEN; i++) {
+ for (i = 0; i < OCELOT_TAG_LEN / 4; i++) {
err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
if (err != 4)
break;
@@ -122,7 +124,10 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
ocelot_parse_ifh(ifh, &info);
- dev = ocelot->ports[info.port]->dev;
+ ocelot_port = ocelot->ports[info.port];
+ priv = container_of(ocelot_port, struct ocelot_port_private,
+ port);
+ dev = priv->dev;
skb = netdev_alloc_skb(dev, info.len);
@@ -193,69 +198,69 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
{
- int budget = OCELOT_PTP_QUEUE_SZ;
struct ocelot *ocelot = arg;
- while (budget--) {
- struct skb_shared_hwtstamps shhwtstamps;
- struct list_head *pos, *tmp;
- struct sk_buff *skb = NULL;
- struct ocelot_skb *entry;
- struct ocelot_port *port;
- struct timespec64 ts;
- u32 val, id, txport;
+ ocelot_get_txtstamp(ocelot);
- val = ocelot_read(ocelot, SYS_PTP_STATUS);
+ return IRQ_HANDLED;
+}
- /* Check if a timestamp can be retrieved */
- if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
- break;
+static const struct of_device_id mscc_ocelot_match[] = {
+ { .compatible = "mscc,vsc7514-switch" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
- WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
+static void ocelot_port_pcs_init(struct ocelot *ocelot, int port)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
- /* Retrieve the ts ID and Tx port */
- id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
- txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
+ /* Disable HDX fast control */
+ ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS,
+ DEV_PORT_MISC);
- /* Retrieve its associated skb */
- port = ocelot->ports[txport];
+ /* SGMII only for now */
+ ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
+ PCS1G_MODE_CFG);
+ ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
- list_for_each_safe(pos, tmp, &port->skbs) {
- entry = list_entry(pos, struct ocelot_skb, head);
- if (entry->id != id)
- continue;
+ /* Enable PCS */
+ ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
- skb = entry->skb;
+ /* No aneg on SGMII */
+ ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG);
- list_del(pos);
- kfree(entry);
- }
+ /* No loopback */
+ ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG);
+}
- /* Next ts */
- ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
+static int ocelot_reset(struct ocelot *ocelot)
+{
+ int retries = 100;
+ u32 val;
- if (unlikely(!skb))
- continue;
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
- /* Get the h/w timestamp */
- ocelot_get_hwtimestamp(ocelot, &ts);
+ do {
+ msleep(1);
+ regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
+ &val);
+ } while (val && --retries);
- /* Set the timestamp into the skb */
- memset(&shhwtstamps, 0, sizeof(shhwtstamps));
- shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
- skb_tstamp_tx(skb, &shhwtstamps);
+ if (!retries)
+ return -ETIMEDOUT;
- dev_kfree_skb_any(skb);
- }
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
- return IRQ_HANDLED;
+ return 0;
}
-static const struct of_device_id mscc_ocelot_match[] = {
- { .compatible = "mscc,vsc7514-switch" },
- { }
+static const struct ocelot_ops ocelot_ops = {
+ .pcs_init = ocelot_port_pcs_init,
+ .reset = ocelot_reset,
};
-MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
static int mscc_ocelot_probe(struct platform_device *pdev)
{
@@ -265,13 +270,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct ocelot *ocelot;
struct regmap *hsio;
unsigned int i;
- u32 val;
struct {
enum ocelot_target id;
char *name;
u8 optional:1;
- } res[] = {
+ } io_target[] = {
{ SYS, "sys" },
{ REW, "rew" },
{ QSYS, "qsys" },
@@ -291,20 +295,23 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ocelot);
ocelot->dev = &pdev->dev;
- for (i = 0; i < ARRAY_SIZE(res); i++) {
+ for (i = 0; i < ARRAY_SIZE(io_target); i++) {
struct regmap *target;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ io_target[i].name);
- target = ocelot_io_platform_init(ocelot, pdev, res[i].name);
+ target = ocelot_regmap_init(ocelot, res);
if (IS_ERR(target)) {
- if (res[i].optional) {
- ocelot->targets[res[i].id] = NULL;
+ if (io_target[i].optional) {
+ ocelot->targets[io_target[i].id] = NULL;
continue;
}
-
return PTR_ERR(target);
}
- ocelot->targets[res[i].id] = target;
+ ocelot->targets[io_target[i].id] = target;
}
hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
@@ -315,7 +322,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->targets[HSIO] = hsio;
- err = ocelot_chip_init(ocelot);
+ err = ocelot_chip_init(ocelot, &ocelot_ops);
if (err)
return err;
@@ -342,18 +349,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->ptp = 1;
}
- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
-
- do {
- msleep(1);
- regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
- &val);
- } while (val);
-
- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
- regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
-
ocelot->num_cpu_ports = 1; /* 1 port on the switch, two groups */
ports = of_get_child_by_name(np, "ethernet-ports");
@@ -367,10 +362,13 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
sizeof(struct ocelot_port *), GFP_KERNEL);
- INIT_LIST_HEAD(&ocelot->multicast);
ocelot_init(ocelot);
+ ocelot_set_cpu_port(ocelot, ocelot->num_phys_ports,
+ OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE);
for_each_available_child_of_node(ports, portnp) {
+ struct ocelot_port_private *priv;
+ struct ocelot_port *ocelot_port;
struct device_node *phy_node;
struct phy_device *phy;
struct resource *res;
@@ -406,13 +404,17 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
goto out_put_ports;
}
+ ocelot_port = ocelot->ports[port];
+ priv = container_of(ocelot_port, struct ocelot_port_private,
+ port);
+
phy_mode = of_get_phy_mode(portnp);
if (phy_mode < 0)
- ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
- else
- ocelot->ports[port]->phy_mode = phy_mode;
+ phy_mode = PHY_INTERFACE_MODE_NA;
+
+ ocelot_port->phy_mode = phy_mode;
- switch (ocelot->ports[port]->phy_mode) {
+ switch (ocelot_port->phy_mode) {
case PHY_INTERFACE_MODE_NA:
continue;
case PHY_INTERFACE_MODE_SGMII:
@@ -421,7 +423,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
/* Ensure clock signals and speed is set on all
* QSGMII links
*/
- ocelot_port_writel(ocelot->ports[port],
+ ocelot_port_writel(ocelot_port,
DEV_CLOCK_CFG_LINK_SPEED
(OCELOT_SPEED_1000),
DEV_CLOCK_CFG);
@@ -449,7 +451,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
goto out_put_ports;
}
- ocelot->ports[port]->serdes = serdes;
+ priv->serdes = serdes;
}
register_netdevice_notifier(&ocelot_netdevice_nb);
diff --git a/drivers/net/ethernet/mscc/ocelot_dev.h b/drivers/net/ethernet/mscc/ocelot_dev.h
deleted file mode 100644
index 0a50d53bbd3f..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_dev.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_DEV_H_
-#define _MSCC_OCELOT_DEV_H_
-
-#define DEV_CLOCK_CFG 0x0
-
-#define DEV_CLOCK_CFG_MAC_TX_RST BIT(7)
-#define DEV_CLOCK_CFG_MAC_RX_RST BIT(6)
-#define DEV_CLOCK_CFG_PCS_TX_RST BIT(5)
-#define DEV_CLOCK_CFG_PCS_RX_RST BIT(4)
-#define DEV_CLOCK_CFG_PORT_RST BIT(3)
-#define DEV_CLOCK_CFG_PHY_RST BIT(2)
-#define DEV_CLOCK_CFG_LINK_SPEED(x) ((x) & GENMASK(1, 0))
-#define DEV_CLOCK_CFG_LINK_SPEED_M GENMASK(1, 0)
-
-#define DEV_PORT_MISC 0x4
-
-#define DEV_PORT_MISC_FWD_ERROR_ENA BIT(4)
-#define DEV_PORT_MISC_FWD_PAUSE_ENA BIT(3)
-#define DEV_PORT_MISC_FWD_CTRL_ENA BIT(2)
-#define DEV_PORT_MISC_DEV_LOOP_ENA BIT(1)
-#define DEV_PORT_MISC_HDX_FAST_DIS BIT(0)
-
-#define DEV_EVENTS 0x8
-
-#define DEV_EEE_CFG 0xc
-
-#define DEV_EEE_CFG_EEE_ENA BIT(22)
-#define DEV_EEE_CFG_EEE_TIMER_AGE(x) (((x) << 15) & GENMASK(21, 15))
-#define DEV_EEE_CFG_EEE_TIMER_AGE_M GENMASK(21, 15)
-#define DEV_EEE_CFG_EEE_TIMER_AGE_X(x) (((x) & GENMASK(21, 15)) >> 15)
-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP(x) (((x) << 8) & GENMASK(14, 8))
-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_M GENMASK(14, 8)
-#define DEV_EEE_CFG_EEE_TIMER_WAKEUP_X(x) (((x) & GENMASK(14, 8)) >> 8)
-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF(x) (((x) << 1) & GENMASK(7, 1))
-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_M GENMASK(7, 1)
-#define DEV_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1)
-#define DEV_EEE_CFG_PORT_LPI BIT(0)
-
-#define DEV_RX_PATH_DELAY 0x10
-
-#define DEV_TX_PATH_DELAY 0x14
-
-#define DEV_PTP_PREDICT_CFG 0x18
-
-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG(x) (((x) << 4) & GENMASK(11, 4))
-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_M GENMASK(11, 4)
-#define DEV_PTP_PREDICT_CFG_PTP_PHY_PREDICT_CFG_X(x) (((x) & GENMASK(11, 4)) >> 4)
-#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG(x) ((x) & GENMASK(3, 0))
-#define DEV_PTP_PREDICT_CFG_PTP_PHASE_PREDICT_CFG_M GENMASK(3, 0)
-
-#define DEV_MAC_ENA_CFG 0x1c
-
-#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
-#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
-
-#define DEV_MAC_MODE_CFG 0x20
-
-#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
-#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
-#define DEV_MAC_MODE_CFG_FDX_ENA BIT(0)
-
-#define DEV_MAC_MAXLEN_CFG 0x24
-
-#define DEV_MAC_TAGS_CFG 0x28
-
-#define DEV_MAC_TAGS_CFG_TAG_ID(x) (((x) << 16) & GENMASK(31, 16))
-#define DEV_MAC_TAGS_CFG_TAG_ID_M GENMASK(31, 16)
-#define DEV_MAC_TAGS_CFG_TAG_ID_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2)
-#define DEV_MAC_TAGS_CFG_PB_ENA BIT(1)
-#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
-
-#define DEV_MAC_ADV_CHK_CFG 0x2c
-
-#define DEV_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
-
-#define DEV_MAC_IFG_CFG 0x30
-
-#define DEV_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
-#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16)
-#define DEV_MAC_IFG_CFG_TX_IFG(x) (((x) << 8) & GENMASK(12, 8))
-#define DEV_MAC_IFG_CFG_TX_IFG_M GENMASK(12, 8)
-#define DEV_MAC_IFG_CFG_TX_IFG_X(x) (((x) & GENMASK(12, 8)) >> 8)
-#define DEV_MAC_IFG_CFG_RX_IFG2(x) (((x) << 4) & GENMASK(7, 4))
-#define DEV_MAC_IFG_CFG_RX_IFG2_M GENMASK(7, 4)
-#define DEV_MAC_IFG_CFG_RX_IFG2_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define DEV_MAC_IFG_CFG_RX_IFG1(x) ((x) & GENMASK(3, 0))
-#define DEV_MAC_IFG_CFG_RX_IFG1_M GENMASK(3, 0)
-
-#define DEV_MAC_HDX_CFG 0x34
-
-#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
-#define DEV_MAC_HDX_CFG_OB_ENA BIT(25)
-#define DEV_MAC_HDX_CFG_WEXC_DIS BIT(24)
-#define DEV_MAC_HDX_CFG_SEED(x) (((x) << 16) & GENMASK(23, 16))
-#define DEV_MAC_HDX_CFG_SEED_M GENMASK(23, 16)
-#define DEV_MAC_HDX_CFG_SEED_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define DEV_MAC_HDX_CFG_SEED_LOAD BIT(12)
-#define DEV_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
-#define DEV_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0))
-#define DEV_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0)
-
-#define DEV_MAC_DBG_CFG 0x38
-
-#define DEV_MAC_DBG_CFG_TBI_MODE BIT(4)
-#define DEV_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0)
-
-#define DEV_MAC_FC_MAC_LOW_CFG 0x3c
-
-#define DEV_MAC_FC_MAC_HIGH_CFG 0x40
-
-#define DEV_MAC_STICKY 0x44
-
-#define DEV_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9)
-#define DEV_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8)
-#define DEV_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7)
-#define DEV_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6)
-#define DEV_MAC_STICKY_RX_JUNK_STICKY BIT(5)
-#define DEV_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4)
-#define DEV_MAC_STICKY_TX_JAM_STICKY BIT(3)
-#define DEV_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2)
-#define DEV_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
-#define DEV_MAC_STICKY_TX_ABORT_STICKY BIT(0)
-
-#define PCS1G_CFG 0x48
-
-#define PCS1G_CFG_LINK_STATUS_TYPE BIT(4)
-#define PCS1G_CFG_AN_LINK_CTRL_ENA BIT(1)
-#define PCS1G_CFG_PCS_ENA BIT(0)
-
-#define PCS1G_MODE_CFG 0x4c
-
-#define PCS1G_MODE_CFG_UNIDIR_MODE_ENA BIT(4)
-#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
-
-#define PCS1G_SD_CFG 0x50
-
-#define PCS1G_SD_CFG_SD_SEL BIT(8)
-#define PCS1G_SD_CFG_SD_POL BIT(4)
-#define PCS1G_SD_CFG_SD_ENA BIT(0)
-
-#define PCS1G_ANEG_CFG 0x54
-
-#define PCS1G_ANEG_CFG_ADV_ABILITY(x) (((x) << 16) & GENMASK(31, 16))
-#define PCS1G_ANEG_CFG_ADV_ABILITY_M GENMASK(31, 16)
-#define PCS1G_ANEG_CFG_ADV_ABILITY_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define PCS1G_ANEG_CFG_SW_RESOLVE_ENA BIT(8)
-#define PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT BIT(1)
-#define PCS1G_ANEG_CFG_ANEG_ENA BIT(0)
-
-#define PCS1G_ANEG_NP_CFG 0x58
-
-#define PCS1G_ANEG_NP_CFG_NP_TX(x) (((x) << 16) & GENMASK(31, 16))
-#define PCS1G_ANEG_NP_CFG_NP_TX_M GENMASK(31, 16)
-#define PCS1G_ANEG_NP_CFG_NP_TX_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define PCS1G_ANEG_NP_CFG_NP_LOADED_ONE_SHOT BIT(0)
-
-#define PCS1G_LB_CFG 0x5c
-
-#define PCS1G_LB_CFG_RA_ENA BIT(4)
-#define PCS1G_LB_CFG_GMII_PHY_LB_ENA BIT(1)
-#define PCS1G_LB_CFG_TBI_HOST_LB_ENA BIT(0)
-
-#define PCS1G_DBG_CFG 0x60
-
-#define PCS1G_DBG_CFG_UDLT BIT(0)
-
-#define PCS1G_CDET_CFG 0x64
-
-#define PCS1G_CDET_CFG_CDET_ENA BIT(0)
-
-#define PCS1G_ANEG_STATUS 0x68
-
-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY(x) (((x) << 16) & GENMASK(31, 16))
-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_M GENMASK(31, 16)
-#define PCS1G_ANEG_STATUS_LP_ADV_ABILITY_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define PCS1G_ANEG_STATUS_PR BIT(4)
-#define PCS1G_ANEG_STATUS_PAGE_RX_STICKY BIT(3)
-#define PCS1G_ANEG_STATUS_ANEG_COMPLETE BIT(0)
-
-#define PCS1G_ANEG_NP_STATUS 0x6c
-
-#define PCS1G_LINK_STATUS 0x70
-
-#define PCS1G_LINK_STATUS_DELAY_VAR(x) (((x) << 12) & GENMASK(15, 12))
-#define PCS1G_LINK_STATUS_DELAY_VAR_M GENMASK(15, 12)
-#define PCS1G_LINK_STATUS_DELAY_VAR_X(x) (((x) & GENMASK(15, 12)) >> 12)
-#define PCS1G_LINK_STATUS_SIGNAL_DETECT BIT(8)
-#define PCS1G_LINK_STATUS_LINK_STATUS BIT(4)
-#define PCS1G_LINK_STATUS_SYNC_STATUS BIT(0)
-
-#define PCS1G_LINK_DOWN_CNT 0x74
-
-#define PCS1G_STICKY 0x78
-
-#define PCS1G_STICKY_LINK_DOWN_STICKY BIT(4)
-#define PCS1G_STICKY_OUT_OF_SYNC_STICKY BIT(0)
-
-#define PCS1G_DEBUG_STATUS 0x7c
-
-#define PCS1G_LPI_CFG 0x80
-
-#define PCS1G_LPI_CFG_QSGMII_MS_SEL BIT(20)
-#define PCS1G_LPI_CFG_RX_LPI_OUT_DIS BIT(17)
-#define PCS1G_LPI_CFG_LPI_TESTMODE BIT(16)
-#define PCS1G_LPI_CFG_LPI_RX_WTIM(x) (((x) << 4) & GENMASK(5, 4))
-#define PCS1G_LPI_CFG_LPI_RX_WTIM_M GENMASK(5, 4)
-#define PCS1G_LPI_CFG_LPI_RX_WTIM_X(x) (((x) & GENMASK(5, 4)) >> 4)
-#define PCS1G_LPI_CFG_TX_ASSERT_LPIDLE BIT(0)
-
-#define PCS1G_LPI_WAKE_ERROR_CNT 0x84
-
-#define PCS1G_LPI_STATUS 0x88
-
-#define PCS1G_LPI_STATUS_RX_LPI_FAIL BIT(16)
-#define PCS1G_LPI_STATUS_RX_LPI_EVENT_STICKY BIT(12)
-#define PCS1G_LPI_STATUS_RX_QUIET BIT(9)
-#define PCS1G_LPI_STATUS_RX_LPI_MODE BIT(8)
-#define PCS1G_LPI_STATUS_TX_LPI_EVENT_STICKY BIT(4)
-#define PCS1G_LPI_STATUS_TX_QUIET BIT(1)
-#define PCS1G_LPI_STATUS_TX_LPI_MODE BIT(0)
-
-#define PCS1G_TSTPAT_MODE_CFG 0x8c
-
-#define PCS1G_TSTPAT_STATUS 0x90
-
-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT(x) (((x) << 8) & GENMASK(15, 8))
-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_M GENMASK(15, 8)
-#define PCS1G_TSTPAT_STATUS_JTP_ERR_CNT_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define PCS1G_TSTPAT_STATUS_JTP_ERR BIT(4)
-#define PCS1G_TSTPAT_STATUS_JTP_LOCK BIT(0)
-
-#define DEV_PCS_FX100_CFG 0x94
-
-#define DEV_PCS_FX100_CFG_SD_SEL BIT(26)
-#define DEV_PCS_FX100_CFG_SD_POL BIT(25)
-#define DEV_PCS_FX100_CFG_SD_ENA BIT(24)
-#define DEV_PCS_FX100_CFG_LOOPBACK_ENA BIT(20)
-#define DEV_PCS_FX100_CFG_SWAP_MII_ENA BIT(16)
-#define DEV_PCS_FX100_CFG_RXBITSEL(x) (((x) << 12) & GENMASK(15, 12))
-#define DEV_PCS_FX100_CFG_RXBITSEL_M GENMASK(15, 12)
-#define DEV_PCS_FX100_CFG_RXBITSEL_X(x) (((x) & GENMASK(15, 12)) >> 12)
-#define DEV_PCS_FX100_CFG_SIGDET_CFG(x) (((x) << 9) & GENMASK(10, 9))
-#define DEV_PCS_FX100_CFG_SIGDET_CFG_M GENMASK(10, 9)
-#define DEV_PCS_FX100_CFG_SIGDET_CFG_X(x) (((x) & GENMASK(10, 9)) >> 9)
-#define DEV_PCS_FX100_CFG_LINKHYST_TM_ENA BIT(8)
-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER(x) (((x) << 4) & GENMASK(7, 4))
-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_M GENMASK(7, 4)
-#define DEV_PCS_FX100_CFG_LINKHYSTTIMER_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define DEV_PCS_FX100_CFG_UNIDIR_MODE_ENA BIT(3)
-#define DEV_PCS_FX100_CFG_FEFCHK_ENA BIT(2)
-#define DEV_PCS_FX100_CFG_FEFGEN_ENA BIT(1)
-#define DEV_PCS_FX100_CFG_PCS_ENA BIT(0)
-
-#define DEV_PCS_FX100_STATUS 0x98
-
-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP(x) (((x) << 8) & GENMASK(11, 8))
-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_M GENMASK(11, 8)
-#define DEV_PCS_FX100_STATUS_EDGE_POS_PTP_X(x) (((x) & GENMASK(11, 8)) >> 8)
-#define DEV_PCS_FX100_STATUS_PCS_ERROR_STICKY BIT(7)
-#define DEV_PCS_FX100_STATUS_FEF_FOUND_STICKY BIT(6)
-#define DEV_PCS_FX100_STATUS_SSD_ERROR_STICKY BIT(5)
-#define DEV_PCS_FX100_STATUS_SYNC_LOST_STICKY BIT(4)
-#define DEV_PCS_FX100_STATUS_FEF_STATUS BIT(2)
-#define DEV_PCS_FX100_STATUS_SIGNAL_DETECT BIT(1)
-#define DEV_PCS_FX100_STATUS_SYNC_STATUS BIT(0)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_dev_gmii.h b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
new file mode 100644
index 000000000000..07c195029545
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_DEV_GMII_H_
+#define _MSCC_OCELOT_DEV_GMII_H_
+
+#define DEV_GMII_PORT_MODE_CLOCK_CFG 0x0
+
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_TX_RST BIT(5)
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_RX_RST BIT(4)
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_PORT_RST BIT(3)
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_PHY_RST BIT(2)
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED(x) ((x) & GENMASK(1, 0))
+#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED_M GENMASK(1, 0)
+
+#define DEV_GMII_PORT_MODE_PORT_MISC 0x4
+
+#define DEV_GMII_PORT_MODE_PORT_MISC_MPLS_RX_ENA BIT(5)
+#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_ERROR_ENA BIT(4)
+#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_PAUSE_ENA BIT(3)
+#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_CTRL_ENA BIT(2)
+#define DEV_GMII_PORT_MODE_PORT_MISC_GMII_LOOP_ENA BIT(1)
+#define DEV_GMII_PORT_MODE_PORT_MISC_DEV_LOOP_ENA BIT(0)
+
+#define DEV_GMII_PORT_MODE_EVENTS 0x8
+
+#define DEV_GMII_PORT_MODE_EEE_CFG 0xc
+
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_ENA BIT(22)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE(x) (((x) << 15) & GENMASK(21, 15))
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_M GENMASK(21, 15)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_X(x) (((x) & GENMASK(21, 15)) >> 15)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP(x) (((x) << 8) & GENMASK(14, 8))
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_M GENMASK(14, 8)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_X(x) (((x) & GENMASK(14, 8)) >> 8)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF(x) (((x) << 1) & GENMASK(7, 1))
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_M GENMASK(7, 1)
+#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1)
+#define DEV_GMII_PORT_MODE_EEE_CFG_PORT_LPI BIT(0)
+
+#define DEV_GMII_PORT_MODE_RX_PATH_DELAY 0x10
+
+#define DEV_GMII_PORT_MODE_TX_PATH_DELAY 0x14
+
+#define DEV_GMII_PORT_MODE_PTP_PREDICT_CFG 0x18
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG 0x1c
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_TX_ENA BIT(0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG 0x20
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FDX_ENA BIT(0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_MAXLEN_CFG 0x24
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG 0x28
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID(x) (((x) << 16) & GENMASK(31, 16))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_M GENMASK(31, 16)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_X(x) (((x) & GENMASK(31, 16)) >> 16)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_PB_ENA BIT(1)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG 0x2c
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG 0x30
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG(x) (((x) << 8) & GENMASK(12, 8))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_M GENMASK(12, 8)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_X(x) (((x) & GENMASK(12, 8)) >> 8)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2(x) (((x) << 4) & GENMASK(7, 4))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_M GENMASK(7, 4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_X(x) (((x) & GENMASK(7, 4)) >> 4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1(x) ((x) & GENMASK(3, 0))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1_M GENMASK(3, 0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG 0x34
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_OB_ENA BIT(25)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_WEXC_DIS BIT(24)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED(x) (((x) << 16) & GENMASK(23, 16))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_M GENMASK(23, 16)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_X(x) (((x) & GENMASK(23, 16)) >> 16)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_LOAD BIT(12)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0))
+#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG 0x38
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_TBI_MODE BIT(4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0)
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_LOW_CFG 0x3c
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_HIGH_CFG 0x40
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY 0x44
+
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_JUNK_STICKY BIT(5)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_JAM_STICKY BIT(3)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
+#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_ABORT_STICKY BIT(0)
+
+#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG 0x48
+
+#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA BIT(0)
+#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA BIT(4)
+#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D BIT(8)
+
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG 0x4c
+
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS BIT(0)
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4))
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4)
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4)
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12))
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12)
+#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12)
+
+#define DEV_GMII_MM_STATISTICS_MM_STATUS 0x50
+
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8))
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24)
+#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28)
+
+#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index b894bc0c9c16..ffd2bb50cfc3 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -10,7 +10,7 @@
struct ocelot_port_block {
struct ocelot_acl_block *block;
- struct ocelot_port *port;
+ struct ocelot_port_private *priv;
};
static int ocelot_flower_parse_action(struct flow_cls_offload *f,
@@ -177,8 +177,8 @@ struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
if (!rule)
return NULL;
- rule->port = block->port;
- rule->chip_port = block->port->chip_port;
+ rule->ocelot = block->priv->port.ocelot;
+ rule->ingress_port_mask = BIT(block->priv->chip_port);
return rule;
}
@@ -202,7 +202,7 @@ static int ocelot_flower_replace(struct flow_cls_offload *f,
if (ret)
return ret;
- port_block->port->tc.offload_cnt++;
+ port_block->priv->tc.offload_cnt++;
return 0;
}
@@ -213,14 +213,14 @@ static int ocelot_flower_destroy(struct flow_cls_offload *f,
int ret;
rule.prio = f->common.prio;
- rule.port = port_block->port;
+ rule.ocelot = port_block->priv->port.ocelot;
rule.id = f->cookie;
ret = ocelot_ace_rule_offload_del(&rule);
if (ret)
return ret;
- port_block->port->tc.offload_cnt--;
+ port_block->priv->tc.offload_cnt--;
return 0;
}
@@ -231,7 +231,7 @@ static int ocelot_flower_stats_update(struct flow_cls_offload *f,
int ret;
rule.prio = f->common.prio;
- rule.port = port_block->port;
+ rule.ocelot = port_block->priv->port.ocelot;
rule.id = f->cookie;
ret = ocelot_ace_rule_stats_update(&rule);
if (ret)
@@ -261,7 +261,7 @@ static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
{
struct ocelot_port_block *port_block = cb_priv;
- if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
+ if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
@@ -275,7 +275,7 @@ static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
}
static struct ocelot_port_block*
-ocelot_port_block_create(struct ocelot_port *port)
+ocelot_port_block_create(struct ocelot_port_private *priv)
{
struct ocelot_port_block *port_block;
@@ -283,7 +283,7 @@ ocelot_port_block_create(struct ocelot_port *port)
if (!port_block)
return NULL;
- port_block->port = port;
+ port_block->priv = priv;
return port_block;
}
@@ -300,7 +300,7 @@ static void ocelot_tc_block_unbind(void *cb_priv)
ocelot_port_block_destroy(port_block);
}
-int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
+int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct ocelot_port_block *port_block;
@@ -311,14 +311,14 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
return -EOPNOTSUPP;
block_cb = flow_block_cb_lookup(f->block,
- ocelot_setup_tc_block_cb_flower, port);
+ ocelot_setup_tc_block_cb_flower, priv);
if (!block_cb) {
- port_block = ocelot_port_block_create(port);
+ port_block = ocelot_port_block_create(priv);
if (!port_block)
return -ENOMEM;
block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
- port, port_block,
+ priv, port_block,
ocelot_tc_block_unbind);
if (IS_ERR(block_cb)) {
ret = PTR_ERR(block_cb);
@@ -339,13 +339,13 @@ err_cb_register:
return ret;
}
-void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
+void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct flow_block_cb *block_cb;
block_cb = flow_block_cb_lookup(f->block,
- ocelot_setup_tc_block_cb_flower, port);
+ ocelot_setup_tc_block_cb_flower, priv);
if (!block_cb)
return;
diff --git a/drivers/net/ethernet/mscc/ocelot_io.c b/drivers/net/ethernet/mscc/ocelot_io.c
index c6db8ad31fdf..b229b1cb68ef 100644
--- a/drivers/net/ethernet/mscc/ocelot_io.c
+++ b/drivers/net/ethernet/mscc/ocelot_io.c
@@ -97,20 +97,16 @@ static struct regmap_config ocelot_regmap_config = {
.reg_stride = 4,
};
-struct regmap *ocelot_io_platform_init(struct ocelot *ocelot,
- struct platform_device *pdev,
- const char *name)
+struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res)
{
- struct resource *res;
void __iomem *regs;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
regs = devm_ioremap_resource(ocelot->dev, res);
if (IS_ERR(regs))
return ERR_CAST(regs);
- ocelot_regmap_config.name = name;
- return devm_regmap_init_mmio(ocelot->dev, regs,
- &ocelot_regmap_config);
+ ocelot_regmap_config.name = res->name;
+
+ return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config);
}
-EXPORT_SYMBOL(ocelot_io_platform_init);
+EXPORT_SYMBOL(ocelot_regmap_init);
diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
index 701e82dd749a..faddce43f2e3 100644
--- a/drivers/net/ethernet/mscc/ocelot_police.c
+++ b/drivers/net/ethernet/mscc/ocelot_police.c
@@ -40,13 +40,12 @@ struct qos_policer_conf {
u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
};
-static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
+static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
struct qos_policer_conf *conf)
{
u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
bool cir_discard = 0, pir_discard = 0;
- struct ocelot *ocelot = port->ocelot;
u32 pbs_max = 0, cbs_max = 0;
u8 ipg = 20;
u32 value;
@@ -123,22 +122,26 @@ static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
/* Check limits */
if (pir > GENMASK(15, 0)) {
- netdev_err(port->dev, "Invalid pir\n");
+ dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
+ port, pir, GENMASK(15, 0));
return -EINVAL;
}
if (cir > GENMASK(15, 0)) {
- netdev_err(port->dev, "Invalid cir\n");
+ dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
+ port, cir, GENMASK(15, 0));
return -EINVAL;
}
if (pbs > pbs_max) {
- netdev_err(port->dev, "Invalid pbs\n");
+ dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
+ port, pbs, pbs_max);
return -EINVAL;
}
if (cbs > cbs_max) {
- netdev_err(port->dev, "Invalid cbs\n");
+ dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
+ port, cbs, cbs_max);
return -EINVAL;
}
@@ -171,10 +174,9 @@ static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
return 0;
}
-int ocelot_port_policer_add(struct ocelot_port *port,
+int ocelot_port_policer_add(struct ocelot *ocelot, int port,
struct ocelot_policer *pol)
{
- struct ocelot *ocelot = port->ocelot;
struct qos_policer_conf pp = { 0 };
int err;
@@ -185,11 +187,10 @@ int ocelot_port_policer_add(struct ocelot_port *port,
pp.pir = pol->rate;
pp.pbs = pol->burst;
- netdev_dbg(port->dev,
- "%s: port %u pir %u kbps, pbs %u bytes\n",
- __func__, port->chip_port, pp.pir, pp.pbs);
+ dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
+ __func__, port, pp.pir, pp.pbs);
- err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
+ err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
if (err)
return err;
@@ -198,22 +199,21 @@ int ocelot_port_policer_add(struct ocelot_port *port,
ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
ANA_PORT_POL_CFG_PORT_POL_ENA |
ANA_PORT_POL_CFG_POL_ORDER_M,
- ANA_PORT_POL_CFG, port->chip_port);
+ ANA_PORT_POL_CFG, port);
return 0;
}
-int ocelot_port_policer_del(struct ocelot_port *port)
+int ocelot_port_policer_del(struct ocelot *ocelot, int port)
{
- struct ocelot *ocelot = port->ocelot;
struct qos_policer_conf pp = { 0 };
int err;
- netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
+ dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
- err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
+ err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
if (err)
return err;
@@ -221,7 +221,7 @@ int ocelot_port_policer_del(struct ocelot_port *port)
ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
ANA_PORT_POL_CFG_PORT_POL_ENA |
ANA_PORT_POL_CFG_POL_ORDER_M,
- ANA_PORT_POL_CFG, port->chip_port);
+ ANA_PORT_POL_CFG, port);
return 0;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h
index d1137f79efda..ae9509229463 100644
--- a/drivers/net/ethernet/mscc/ocelot_police.h
+++ b/drivers/net/ethernet/mscc/ocelot_police.h
@@ -14,9 +14,9 @@ struct ocelot_policer {
u32 burst; /* bytes */
};
-int ocelot_port_policer_add(struct ocelot_port *port,
+int ocelot_port_policer_add(struct ocelot *ocelot, int port,
struct ocelot_policer *pol);
-int ocelot_port_policer_del(struct ocelot_port *port);
+int ocelot_port_policer_del(struct ocelot *ocelot, int port);
#endif /* _MSCC_OCELOT_POLICE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_qsys.h b/drivers/net/ethernet/mscc/ocelot_qsys.h
deleted file mode 100644
index d8c63aa761be..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_qsys.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_QSYS_H_
-#define _MSCC_OCELOT_QSYS_H_
-
-#define QSYS_PORT_MODE_RSZ 0x4
-
-#define QSYS_PORT_MODE_DEQUEUE_DIS BIT(1)
-#define QSYS_PORT_MODE_DEQUEUE_LATE BIT(0)
-
-#define QSYS_SWITCH_PORT_MODE_RSZ 0x4
-
-#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(14)
-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(x) (((x) << 11) & GENMASK(13, 11))
-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_M GENMASK(13, 11)
-#define QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG_X(x) (((x) & GENMASK(13, 11)) >> 11)
-#define QSYS_SWITCH_PORT_MODE_YEL_RSRVD BIT(10)
-#define QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE BIT(9)
-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA(x) (((x) << 1) & GENMASK(8, 1))
-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_M GENMASK(8, 1)
-#define QSYS_SWITCH_PORT_MODE_TX_PFC_ENA_X(x) (((x) & GENMASK(8, 1)) >> 1)
-#define QSYS_SWITCH_PORT_MODE_TX_PFC_MODE BIT(0)
-
-#define QSYS_STAT_CNT_CFG_TX_GREEN_CNT_MODE BIT(5)
-#define QSYS_STAT_CNT_CFG_TX_YELLOW_CNT_MODE BIT(4)
-#define QSYS_STAT_CNT_CFG_DROP_GREEN_CNT_MODE BIT(3)
-#define QSYS_STAT_CNT_CFG_DROP_YELLOW_CNT_MODE BIT(2)
-#define QSYS_STAT_CNT_CFG_DROP_COUNT_ONCE BIT(1)
-#define QSYS_STAT_CNT_CFG_DROP_COUNT_EGRESS BIT(0)
-
-#define QSYS_EEE_CFG_RSZ 0x4
-
-#define QSYS_EEE_THRES_EEE_HIGH_BYTES(x) (((x) << 8) & GENMASK(15, 8))
-#define QSYS_EEE_THRES_EEE_HIGH_BYTES_M GENMASK(15, 8)
-#define QSYS_EEE_THRES_EEE_HIGH_BYTES_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define QSYS_EEE_THRES_EEE_HIGH_FRAMES(x) ((x) & GENMASK(7, 0))
-#define QSYS_EEE_THRES_EEE_HIGH_FRAMES_M GENMASK(7, 0)
-
-#define QSYS_SW_STATUS_RSZ 0x4
-
-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT(x) (((x) << 8) & GENMASK(12, 8))
-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_M GENMASK(12, 8)
-#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_X(x) (((x) & GENMASK(12, 8)) >> 8)
-#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK(x) ((x) & GENMASK(7, 0))
-#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M GENMASK(7, 0)
-
-#define QSYS_QMAP_GSZ 0x4
-
-#define QSYS_QMAP_SE_BASE(x) (((x) << 5) & GENMASK(12, 5))
-#define QSYS_QMAP_SE_BASE_M GENMASK(12, 5)
-#define QSYS_QMAP_SE_BASE_X(x) (((x) & GENMASK(12, 5)) >> 5)
-#define QSYS_QMAP_SE_IDX_SEL(x) (((x) << 2) & GENMASK(4, 2))
-#define QSYS_QMAP_SE_IDX_SEL_M GENMASK(4, 2)
-#define QSYS_QMAP_SE_IDX_SEL_X(x) (((x) & GENMASK(4, 2)) >> 2)
-#define QSYS_QMAP_SE_INP_SEL(x) ((x) & GENMASK(1, 0))
-#define QSYS_QMAP_SE_INP_SEL_M GENMASK(1, 0)
-
-#define QSYS_ISDX_SGRP_GSZ 0x4
-
-#define QSYS_TIMED_FRAME_ENTRY_GSZ 0x4
-
-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT(x) (((x) << 9) & GENMASK(18, 9))
-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_M GENMASK(18, 9)
-#define QSYS_TFRM_MISC_TIMED_CANCEL_SLOT_X(x) (((x) & GENMASK(18, 9)) >> 9)
-#define QSYS_TFRM_MISC_TIMED_CANCEL_1SHOT BIT(8)
-#define QSYS_TFRM_MISC_TIMED_SLOT_MODE_MC BIT(7)
-#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT(x) ((x) & GENMASK(6, 0))
-#define QSYS_TFRM_MISC_TIMED_ENTRY_FAST_CNT_M GENMASK(6, 0)
-
-#define QSYS_RED_PROFILE_RSZ 0x4
-
-#define QSYS_RED_PROFILE_WM_RED_LOW(x) (((x) << 8) & GENMASK(15, 8))
-#define QSYS_RED_PROFILE_WM_RED_LOW_M GENMASK(15, 8)
-#define QSYS_RED_PROFILE_WM_RED_LOW_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define QSYS_RED_PROFILE_WM_RED_HIGH(x) ((x) & GENMASK(7, 0))
-#define QSYS_RED_PROFILE_WM_RED_HIGH_M GENMASK(7, 0)
-
-#define QSYS_RES_CFG_GSZ 0x8
-
-#define QSYS_RES_STAT_GSZ 0x8
-
-#define QSYS_RES_STAT_INUSE(x) (((x) << 12) & GENMASK(23, 12))
-#define QSYS_RES_STAT_INUSE_M GENMASK(23, 12)
-#define QSYS_RES_STAT_INUSE_X(x) (((x) & GENMASK(23, 12)) >> 12)
-#define QSYS_RES_STAT_MAXUSE(x) ((x) & GENMASK(11, 0))
-#define QSYS_RES_STAT_MAXUSE_M GENMASK(11, 0)
-
-#define QSYS_EVENTS_CORE_EV_FDC(x) (((x) << 2) & GENMASK(4, 2))
-#define QSYS_EVENTS_CORE_EV_FDC_M GENMASK(4, 2)
-#define QSYS_EVENTS_CORE_EV_FDC_X(x) (((x) & GENMASK(4, 2)) >> 2)
-#define QSYS_EVENTS_CORE_EV_FRD(x) ((x) & GENMASK(1, 0))
-#define QSYS_EVENTS_CORE_EV_FRD_M GENMASK(1, 0)
-
-#define QSYS_QMAXSDU_CFG_0_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_1_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_2_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_3_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_4_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_5_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_6_RSZ 0x4
-
-#define QSYS_QMAXSDU_CFG_7_RSZ 0x4
-
-#define QSYS_PREEMPTION_CFG_RSZ 0x4
-
-#define QSYS_PREEMPTION_CFG_P_QUEUES(x) ((x) & GENMASK(7, 0))
-#define QSYS_PREEMPTION_CFG_P_QUEUES_M GENMASK(7, 0)
-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE(x) (((x) << 8) & GENMASK(9, 8))
-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_M GENMASK(9, 8)
-#define QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(x) (((x) & GENMASK(9, 8)) >> 8)
-#define QSYS_PREEMPTION_CFG_STRICT_IPG(x) (((x) << 12) & GENMASK(13, 12))
-#define QSYS_PREEMPTION_CFG_STRICT_IPG_M GENMASK(13, 12)
-#define QSYS_PREEMPTION_CFG_STRICT_IPG_X(x) (((x) & GENMASK(13, 12)) >> 12)
-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE(x) (((x) << 16) & GENMASK(31, 16))
-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_M GENMASK(31, 16)
-#define QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(x) (((x) & GENMASK(31, 16)) >> 16)
-
-#define QSYS_CIR_CFG_GSZ 0x80
-
-#define QSYS_CIR_CFG_CIR_RATE(x) (((x) << 6) & GENMASK(20, 6))
-#define QSYS_CIR_CFG_CIR_RATE_M GENMASK(20, 6)
-#define QSYS_CIR_CFG_CIR_RATE_X(x) (((x) & GENMASK(20, 6)) >> 6)
-#define QSYS_CIR_CFG_CIR_BURST(x) ((x) & GENMASK(5, 0))
-#define QSYS_CIR_CFG_CIR_BURST_M GENMASK(5, 0)
-
-#define QSYS_EIR_CFG_GSZ 0x80
-
-#define QSYS_EIR_CFG_EIR_RATE(x) (((x) << 7) & GENMASK(21, 7))
-#define QSYS_EIR_CFG_EIR_RATE_M GENMASK(21, 7)
-#define QSYS_EIR_CFG_EIR_RATE_X(x) (((x) & GENMASK(21, 7)) >> 7)
-#define QSYS_EIR_CFG_EIR_BURST(x) (((x) << 1) & GENMASK(6, 1))
-#define QSYS_EIR_CFG_EIR_BURST_M GENMASK(6, 1)
-#define QSYS_EIR_CFG_EIR_BURST_X(x) (((x) & GENMASK(6, 1)) >> 1)
-#define QSYS_EIR_CFG_EIR_MARK_ENA BIT(0)
-
-#define QSYS_SE_CFG_GSZ 0x80
-
-#define QSYS_SE_CFG_SE_DWRR_CNT(x) (((x) << 6) & GENMASK(9, 6))
-#define QSYS_SE_CFG_SE_DWRR_CNT_M GENMASK(9, 6)
-#define QSYS_SE_CFG_SE_DWRR_CNT_X(x) (((x) & GENMASK(9, 6)) >> 6)
-#define QSYS_SE_CFG_SE_RR_ENA BIT(5)
-#define QSYS_SE_CFG_SE_AVB_ENA BIT(4)
-#define QSYS_SE_CFG_SE_FRM_MODE(x) (((x) << 2) & GENMASK(3, 2))
-#define QSYS_SE_CFG_SE_FRM_MODE_M GENMASK(3, 2)
-#define QSYS_SE_CFG_SE_FRM_MODE_X(x) (((x) & GENMASK(3, 2)) >> 2)
-#define QSYS_SE_CFG_SE_EXC_ENA BIT(1)
-#define QSYS_SE_CFG_SE_EXC_FWD BIT(0)
-
-#define QSYS_SE_DWRR_CFG_GSZ 0x80
-#define QSYS_SE_DWRR_CFG_RSZ 0x4
-
-#define QSYS_SE_CONNECT_GSZ 0x80
-
-#define QSYS_SE_CONNECT_SE_OUTP_IDX(x) (((x) << 17) & GENMASK(24, 17))
-#define QSYS_SE_CONNECT_SE_OUTP_IDX_M GENMASK(24, 17)
-#define QSYS_SE_CONNECT_SE_OUTP_IDX_X(x) (((x) & GENMASK(24, 17)) >> 17)
-#define QSYS_SE_CONNECT_SE_INP_IDX(x) (((x) << 9) & GENMASK(16, 9))
-#define QSYS_SE_CONNECT_SE_INP_IDX_M GENMASK(16, 9)
-#define QSYS_SE_CONNECT_SE_INP_IDX_X(x) (((x) & GENMASK(16, 9)) >> 9)
-#define QSYS_SE_CONNECT_SE_OUTP_CON(x) (((x) << 5) & GENMASK(8, 5))
-#define QSYS_SE_CONNECT_SE_OUTP_CON_M GENMASK(8, 5)
-#define QSYS_SE_CONNECT_SE_OUTP_CON_X(x) (((x) & GENMASK(8, 5)) >> 5)
-#define QSYS_SE_CONNECT_SE_INP_CNT(x) (((x) << 1) & GENMASK(4, 1))
-#define QSYS_SE_CONNECT_SE_INP_CNT_M GENMASK(4, 1)
-#define QSYS_SE_CONNECT_SE_INP_CNT_X(x) (((x) & GENMASK(4, 1)) >> 1)
-#define QSYS_SE_CONNECT_SE_TERMINAL BIT(0)
-
-#define QSYS_SE_DLB_SENSE_GSZ 0x80
-
-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO(x) (((x) << 11) & GENMASK(13, 11))
-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_M GENMASK(13, 11)
-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_X(x) (((x) & GENMASK(13, 11)) >> 11)
-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT(x) (((x) << 7) & GENMASK(10, 7))
-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_M GENMASK(10, 7)
-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_X(x) (((x) & GENMASK(10, 7)) >> 7)
-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT(x) (((x) << 3) & GENMASK(6, 3))
-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_M GENMASK(6, 3)
-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_X(x) (((x) & GENMASK(6, 3)) >> 3)
-#define QSYS_SE_DLB_SENSE_SE_DLB_PRIO_ENA BIT(2)
-#define QSYS_SE_DLB_SENSE_SE_DLB_SPORT_ENA BIT(1)
-#define QSYS_SE_DLB_SENSE_SE_DLB_DPORT_ENA BIT(0)
-
-#define QSYS_CIR_STATE_GSZ 0x80
-
-#define QSYS_CIR_STATE_CIR_LVL(x) (((x) << 4) & GENMASK(25, 4))
-#define QSYS_CIR_STATE_CIR_LVL_M GENMASK(25, 4)
-#define QSYS_CIR_STATE_CIR_LVL_X(x) (((x) & GENMASK(25, 4)) >> 4)
-#define QSYS_CIR_STATE_SHP_TIME(x) ((x) & GENMASK(3, 0))
-#define QSYS_CIR_STATE_SHP_TIME_M GENMASK(3, 0)
-
-#define QSYS_EIR_STATE_GSZ 0x80
-
-#define QSYS_SE_STATE_GSZ 0x80
-
-#define QSYS_SE_STATE_SE_OUTP_LVL(x) (((x) << 1) & GENMASK(2, 1))
-#define QSYS_SE_STATE_SE_OUTP_LVL_M GENMASK(2, 1)
-#define QSYS_SE_STATE_SE_OUTP_LVL_X(x) (((x) & GENMASK(2, 1)) >> 1)
-#define QSYS_SE_STATE_SE_WAS_YEL BIT(0)
-
-#define QSYS_HSCH_MISC_CFG_SE_CONNECT_VLD BIT(8)
-#define QSYS_HSCH_MISC_CFG_FRM_ADJ(x) (((x) << 3) & GENMASK(7, 3))
-#define QSYS_HSCH_MISC_CFG_FRM_ADJ_M GENMASK(7, 3)
-#define QSYS_HSCH_MISC_CFG_FRM_ADJ_X(x) (((x) & GENMASK(7, 3)) >> 3)
-#define QSYS_HSCH_MISC_CFG_LEAK_DIS BIT(2)
-#define QSYS_HSCH_MISC_CFG_QSHP_EXC_ENA BIT(1)
-#define QSYS_HSCH_MISC_CFG_PFC_BYP_UPD BIT(0)
-
-#define QSYS_TAG_CONFIG_RSZ 0x4
-
-#define QSYS_TAG_CONFIG_ENABLE BIT(0)
-#define QSYS_TAG_CONFIG_LINK_SPEED(x) (((x) << 4) & GENMASK(5, 4))
-#define QSYS_TAG_CONFIG_LINK_SPEED_M GENMASK(5, 4)
-#define QSYS_TAG_CONFIG_LINK_SPEED_X(x) (((x) & GENMASK(5, 4)) >> 4)
-#define QSYS_TAG_CONFIG_INIT_GATE_STATE(x) (((x) << 8) & GENMASK(15, 8))
-#define QSYS_TAG_CONFIG_INIT_GATE_STATE_M GENMASK(15, 8)
-#define QSYS_TAG_CONFIG_INIT_GATE_STATE_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(x) (((x) << 16) & GENMASK(23, 16))
-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M GENMASK(23, 16)
-#define QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_X(x) (((x) & GENMASK(23, 16)) >> 16)
-
-#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(x) ((x) & GENMASK(7, 0))
-#define QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M GENMASK(7, 0)
-#define QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q BIT(8)
-#define QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE BIT(16)
-
-#define QSYS_PORT_MAX_SDU_RSZ 0x4
-
-#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(x) ((x) & GENMASK(15, 0))
-#define QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M GENMASK(15, 0)
-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH(x) (((x) << 16) & GENMASK(31, 16))
-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_M GENMASK(31, 16)
-#define QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(x) (((x) & GENMASK(31, 16)) >> 16)
-
-#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(x) ((x) & GENMASK(5, 0))
-#define QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M GENMASK(5, 0)
-#define QSYS_GCL_CFG_REG_1_GATE_STATE(x) (((x) << 8) & GENMASK(15, 8))
-#define QSYS_GCL_CFG_REG_1_GATE_STATE_M GENMASK(15, 8)
-#define QSYS_GCL_CFG_REG_1_GATE_STATE_X(x) (((x) & GENMASK(15, 8)) >> 8)
-
-#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(x) ((x) & GENMASK(15, 0))
-#define QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB_M GENMASK(15, 0)
-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH(x) (((x) << 16) & GENMASK(31, 16))
-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_M GENMASK(31, 16)
-#define QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(x) (((x) & GENMASK(31, 16)) >> 16)
-
-#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(x) ((x) & GENMASK(15, 0))
-#define QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB_M GENMASK(15, 0)
-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE(x) (((x) << 16) & GENMASK(23, 16))
-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_M GENMASK(23, 16)
-#define QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING BIT(24)
-
-#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(x) ((x) & GENMASK(5, 0))
-#define QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M GENMASK(5, 0)
-#define QSYS_GCL_STATUS_REG_1_GATE_STATE(x) (((x) << 8) & GENMASK(15, 8))
-#define QSYS_GCL_STATUS_REG_1_GATE_STATE_M GENMASK(15, 8)
-#define QSYS_GCL_STATUS_REG_1_GATE_STATE_X(x) (((x) & GENMASK(15, 8)) >> 8)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index e59977d20400..b88b5899b227 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -423,7 +423,7 @@ static void ocelot_pll5_init(struct ocelot *ocelot)
HSIO_PLL5G_CFG2_AMPC_SEL(0x10));
}
-int ocelot_chip_init(struct ocelot *ocelot)
+int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
{
int ret;
@@ -431,6 +431,7 @@ int ocelot_chip_init(struct ocelot *ocelot)
ocelot->stats_layout = ocelot_stats_layout;
ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout);
ocelot->shared_queue_sz = 224 * 1024;
+ ocelot->ops = ops;
ret = ocelot_regfields_init(ocelot, ocelot_regfields);
if (ret)
diff --git a/drivers/net/ethernet/mscc/ocelot_sys.h b/drivers/net/ethernet/mscc/ocelot_sys.h
deleted file mode 100644
index 16f91e172bcb..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_sys.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_SYS_H_
-#define _MSCC_OCELOT_SYS_H_
-
-#define SYS_COUNT_RX_OCTETS_RSZ 0x4
-
-#define SYS_COUNT_TX_OCTETS_RSZ 0x4
-
-#define SYS_PORT_MODE_RSZ 0x4
-
-#define SYS_PORT_MODE_DATA_WO_TS(x) (((x) << 5) & GENMASK(6, 5))
-#define SYS_PORT_MODE_DATA_WO_TS_M GENMASK(6, 5)
-#define SYS_PORT_MODE_DATA_WO_TS_X(x) (((x) & GENMASK(6, 5)) >> 5)
-#define SYS_PORT_MODE_INCL_INJ_HDR(x) (((x) << 3) & GENMASK(4, 3))
-#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3)
-#define SYS_PORT_MODE_INCL_INJ_HDR_X(x) (((x) & GENMASK(4, 3)) >> 3)
-#define SYS_PORT_MODE_INCL_XTR_HDR(x) (((x) << 1) & GENMASK(2, 1))
-#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1)
-#define SYS_PORT_MODE_INCL_XTR_HDR_X(x) (((x) & GENMASK(2, 1)) >> 1)
-#define SYS_PORT_MODE_INJ_HDR_ERR BIT(0)
-
-#define SYS_FRONT_PORT_MODE_RSZ 0x4
-
-#define SYS_FRONT_PORT_MODE_HDX_MODE BIT(0)
-
-#define SYS_FRM_AGING_AGE_TX_ENA BIT(20)
-#define SYS_FRM_AGING_MAX_AGE(x) ((x) & GENMASK(19, 0))
-#define SYS_FRM_AGING_MAX_AGE_M GENMASK(19, 0)
-
-#define SYS_STAT_CFG_STAT_CLEAR_SHOT(x) (((x) << 10) & GENMASK(16, 10))
-#define SYS_STAT_CFG_STAT_CLEAR_SHOT_M GENMASK(16, 10)
-#define SYS_STAT_CFG_STAT_CLEAR_SHOT_X(x) (((x) & GENMASK(16, 10)) >> 10)
-#define SYS_STAT_CFG_STAT_VIEW(x) ((x) & GENMASK(9, 0))
-#define SYS_STAT_CFG_STAT_VIEW_M GENMASK(9, 0)
-
-#define SYS_SW_STATUS_RSZ 0x4
-
-#define SYS_SW_STATUS_PORT_RX_PAUSED BIT(0)
-
-#define SYS_MISC_CFG_PTP_RSRV_CLR BIT(1)
-#define SYS_MISC_CFG_PTP_DIS_NEG_RO BIT(0)
-
-#define SYS_REW_MAC_HIGH_CFG_RSZ 0x4
-
-#define SYS_REW_MAC_LOW_CFG_RSZ 0x4
-
-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG(x) (((x) << 6) & GENMASK(21, 6))
-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_M GENMASK(21, 6)
-#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_X(x) (((x) & GENMASK(21, 6)) >> 6)
-#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x) ((x) & GENMASK(5, 0))
-#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M GENMASK(5, 0)
-
-#define SYS_PAUSE_CFG_RSZ 0x4
-
-#define SYS_PAUSE_CFG_PAUSE_START(x) (((x) << 10) & GENMASK(18, 10))
-#define SYS_PAUSE_CFG_PAUSE_START_M GENMASK(18, 10)
-#define SYS_PAUSE_CFG_PAUSE_START_X(x) (((x) & GENMASK(18, 10)) >> 10)
-#define SYS_PAUSE_CFG_PAUSE_STOP(x) (((x) << 1) & GENMASK(9, 1))
-#define SYS_PAUSE_CFG_PAUSE_STOP_M GENMASK(9, 1)
-#define SYS_PAUSE_CFG_PAUSE_STOP_X(x) (((x) & GENMASK(9, 1)) >> 1)
-#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
-
-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x) (((x) << 9) & GENMASK(17, 9))
-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M GENMASK(17, 9)
-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x) (((x) & GENMASK(17, 9)) >> 9)
-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP(x) ((x) & GENMASK(8, 0))
-#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP_M GENMASK(8, 0)
-
-#define SYS_ATOP_RSZ 0x4
-
-#define SYS_MAC_FC_CFG_RSZ 0x4
-
-#define SYS_MAC_FC_CFG_FC_LINK_SPEED(x) (((x) << 26) & GENMASK(27, 26))
-#define SYS_MAC_FC_CFG_FC_LINK_SPEED_M GENMASK(27, 26)
-#define SYS_MAC_FC_CFG_FC_LINK_SPEED_X(x) (((x) & GENMASK(27, 26)) >> 26)
-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG(x) (((x) << 20) & GENMASK(25, 20))
-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_M GENMASK(25, 20)
-#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_X(x) (((x) & GENMASK(25, 20)) >> 20)
-#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA BIT(18)
-#define SYS_MAC_FC_CFG_TX_FC_ENA BIT(17)
-#define SYS_MAC_FC_CFG_RX_FC_ENA BIT(16)
-#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG(x) ((x) & GENMASK(15, 0))
-#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_M GENMASK(15, 0)
-
-#define SYS_MMGT_RELCNT(x) (((x) << 16) & GENMASK(31, 16))
-#define SYS_MMGT_RELCNT_M GENMASK(31, 16)
-#define SYS_MMGT_RELCNT_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define SYS_MMGT_FREECNT(x) ((x) & GENMASK(15, 0))
-#define SYS_MMGT_FREECNT_M GENMASK(15, 0)
-
-#define SYS_MMGT_FAST_FREEVLD(x) (((x) << 4) & GENMASK(7, 4))
-#define SYS_MMGT_FAST_FREEVLD_M GENMASK(7, 4)
-#define SYS_MMGT_FAST_FREEVLD_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define SYS_MMGT_FAST_RELVLD(x) ((x) & GENMASK(3, 0))
-#define SYS_MMGT_FAST_RELVLD_M GENMASK(3, 0)
-
-#define SYS_EVENTS_DIF_RSZ 0x4
-
-#define SYS_EVENTS_DIF_EV_DRX(x) (((x) << 6) & GENMASK(8, 6))
-#define SYS_EVENTS_DIF_EV_DRX_M GENMASK(8, 6)
-#define SYS_EVENTS_DIF_EV_DRX_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define SYS_EVENTS_DIF_EV_DTX(x) ((x) & GENMASK(5, 0))
-#define SYS_EVENTS_DIF_EV_DTX_M GENMASK(5, 0)
-
-#define SYS_EVENTS_CORE_EV_FWR BIT(2)
-#define SYS_EVENTS_CORE_EV_ANA(x) ((x) & GENMASK(1, 0))
-#define SYS_EVENTS_CORE_EV_ANA_M GENMASK(1, 0)
-
-#define SYS_CNT_GSZ 0x4
-
-#define SYS_PTP_STATUS_PTP_TXSTAMP_OAM BIT(29)
-#define SYS_PTP_STATUS_PTP_OVFL BIT(28)
-#define SYS_PTP_STATUS_PTP_MESS_VLD BIT(27)
-#define SYS_PTP_STATUS_PTP_MESS_ID(x) (((x) << 21) & GENMASK(26, 21))
-#define SYS_PTP_STATUS_PTP_MESS_ID_M GENMASK(26, 21)
-#define SYS_PTP_STATUS_PTP_MESS_ID_X(x) (((x) & GENMASK(26, 21)) >> 21)
-#define SYS_PTP_STATUS_PTP_MESS_TXPORT(x) (((x) << 16) & GENMASK(20, 16))
-#define SYS_PTP_STATUS_PTP_MESS_TXPORT_M GENMASK(20, 16)
-#define SYS_PTP_STATUS_PTP_MESS_TXPORT_X(x) (((x) & GENMASK(20, 16)) >> 16)
-#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID(x) ((x) & GENMASK(15, 0))
-#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID_M GENMASK(15, 0)
-
-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP(x) ((x) & GENMASK(29, 0))
-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_M GENMASK(29, 0)
-#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC BIT(31)
-
-#define SYS_PTP_NXT_PTP_NXT BIT(0)
-
-#define SYS_PTP_CFG_PTP_STAMP_WID(x) (((x) << 2) & GENMASK(7, 2))
-#define SYS_PTP_CFG_PTP_STAMP_WID_M GENMASK(7, 2)
-#define SYS_PTP_CFG_PTP_STAMP_WID_X(x) (((x) & GENMASK(7, 2)) >> 2)
-#define SYS_PTP_CFG_PTP_CF_ROLL_MODE(x) ((x) & GENMASK(1, 0))
-#define SYS_PTP_CFG_PTP_CF_ROLL_MODE_M GENMASK(1, 0)
-
-#define SYS_RAM_INIT_RAM_INIT BIT(1)
-#define SYS_RAM_INIT_RAM_CFG_HOOK BIT(0)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index 16a6db71ca5e..a4f7fbd76507 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -9,17 +9,19 @@
#include "ocelot_ace.h"
#include <net/pkt_cls.h>
-static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
+static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
struct tc_cls_matchall_offload *f,
bool ingress)
{
struct netlink_ext_ack *extack = f->common.extack;
+ struct ocelot *ocelot = priv->port.ocelot;
struct ocelot_policer pol = { 0 };
struct flow_action_entry *action;
+ int port = priv->chip_port;
int err;
- netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n",
- __func__, port->chip_port, f->command, f->cookie);
+ netdev_dbg(priv->dev, "%s: port %u command %d cookie %lu\n",
+ __func__, port, f->command, f->cookie);
if (!ingress) {
NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
@@ -34,7 +36,7 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
return -EOPNOTSUPP;
}
- if (port->tc.block_shared) {
+ if (priv->tc.block_shared) {
NL_SET_ERR_MSG_MOD(extack,
"Rate limit is not supported on shared blocks");
return -EOPNOTSUPP;
@@ -47,7 +49,7 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
return -EOPNOTSUPP;
}
- if (port->tc.police_id && port->tc.police_id != f->cookie) {
+ if (priv->tc.police_id && priv->tc.police_id != f->cookie) {
NL_SET_ERR_MSG_MOD(extack,
"Only one policer per port is supported\n");
return -EEXIST;
@@ -58,27 +60,27 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
PSCHED_NS2TICKS(action->police.burst),
PSCHED_TICKS_PER_SEC);
- err = ocelot_port_policer_add(port, &pol);
+ err = ocelot_port_policer_add(ocelot, port, &pol);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
return err;
}
- port->tc.police_id = f->cookie;
- port->tc.offload_cnt++;
+ priv->tc.police_id = f->cookie;
+ priv->tc.offload_cnt++;
return 0;
case TC_CLSMATCHALL_DESTROY:
- if (port->tc.police_id != f->cookie)
+ if (priv->tc.police_id != f->cookie)
return -ENOENT;
- err = ocelot_port_policer_del(port);
+ err = ocelot_port_policer_del(ocelot, port);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Could not delete policer\n");
return err;
}
- port->tc.police_id = 0;
- port->tc.offload_cnt--;
+ priv->tc.police_id = 0;
+ priv->tc.offload_cnt--;
return 0;
case TC_CLSMATCHALL_STATS: /* fall through */
default:
@@ -90,21 +92,21 @@ static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
void *type_data,
void *cb_priv, bool ingress)
{
- struct ocelot_port *port = cb_priv;
+ struct ocelot_port_private *priv = cb_priv;
- if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
+ if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSMATCHALL:
- netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
+ netdev_dbg(priv->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
ingress ? "ingress" : "egress");
- return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
+ return ocelot_setup_tc_cls_matchall(priv, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return 0;
default:
- netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
+ netdev_dbg(priv->dev, "tc_block_cb: type %d %s\n",
type,
ingress ? "ingress" : "egress");
@@ -130,19 +132,19 @@ static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
static LIST_HEAD(ocelot_block_cb_list);
-static int ocelot_setup_tc_block(struct ocelot_port *port,
+static int ocelot_setup_tc_block(struct ocelot_port_private *priv,
struct flow_block_offload *f)
{
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
int err;
- netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
+ netdev_dbg(priv->dev, "tc_block command %d, binder_type %d\n",
f->command, f->binder_type);
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = ocelot_setup_tc_block_cb_ig;
- port->tc.block_shared = f->block_shared;
+ priv->tc.block_shared = f->block_shared;
} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = ocelot_setup_tc_block_cb_eg;
} else {
@@ -153,14 +155,14 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
switch (f->command) {
case FLOW_BLOCK_BIND:
- if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list))
+ if (flow_block_cb_is_busy(cb, priv, &ocelot_block_cb_list))
return -EBUSY;
- block_cb = flow_block_cb_alloc(cb, port, port, NULL);
+ block_cb = flow_block_cb_alloc(cb, priv, priv, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
- err = ocelot_setup_tc_block_flower_bind(port, f);
+ err = ocelot_setup_tc_block_flower_bind(priv, f);
if (err < 0) {
flow_block_cb_free(block_cb);
return err;
@@ -169,11 +171,11 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
list_add_tail(&block_cb->driver_list, f->driver_block_list);
return 0;
case FLOW_BLOCK_UNBIND:
- block_cb = flow_block_cb_lookup(f->block, cb, port);
+ block_cb = flow_block_cb_lookup(f->block, cb, priv);
if (!block_cb)
return -ENOENT;
- ocelot_setup_tc_block_flower_unbind(port, f);
+ ocelot_setup_tc_block_flower_unbind(priv, f);
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
return 0;
@@ -185,11 +187,11 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
- struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot_port_private *priv = netdev_priv(dev);
switch (type) {
case TC_SETUP_BLOCK:
- return ocelot_setup_tc_block(port, type_data);
+ return ocelot_setup_tc_block(priv, type_data);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_tsn.c b/drivers/net/ethernet/mscc/ocelot_tsn.c
new file mode 100644
index 000000000000..b8fcbfd810ce
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tsn.c
@@ -0,0 +1,1586 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Felix Switch TSN driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/iopoll.h>
+#include "ocelot.h"
+#include <soc/mscc/ocelot_sys.h>
+#include <soc/mscc/ocelot_ana.h>
+#include <soc/mscc/ocelot_qsys.h>
+#include "ocelot_rew.h"
+#include "ocelot_dev_gmii.h"
+#include "ocelot_tsn.h"
+
+#define MSCC_NUM_OUT_PORT 4 /* Number of physical output ports */
+#define SE_IX_PORT 64
+
+/* MSCC TSN parameters limited */
+#define NUM_MSCC_QOS_PRIO 8
+#define MSCC_PSFP_SFID_NUM 176
+#define MSCC_FRER_SSID_NUM 128
+
+/* Using the max number of MSCC_PSFP_SFID_NUM and MSCC_FRER_SSID_NUM */
+#define MSCC_STREAM_HANDLE_NUM MSCC_PSFP_SFID_NUM
+
+int streamhandle_map[MSCC_STREAM_HANDLE_NUM] = {0};
+static struct mscc_switch_capa capa __ro_after_init = {
+ .num_tas_gcl = 64,
+ .tas_ct_min = 100,
+ .tas_ct_max = 1000000000,
+ .tas_cte_max = 999999999,
+ .tas_it_max = 999999999,
+ .tas_it_min = 1000,
+ .num_hsch = 72,
+ .num_psfp_sfid = MSCC_PSFP_SFID_NUM,
+ .num_psfp_sgid = 184,
+ .psfp_fmi_max = 246,
+ .psfp_fmi_min = 63,
+ .num_sgi_gcl = 4,
+ .sgi_ct_min = 5000,
+ .sgi_ct_max = 1000000000,
+ .sgi_cte_max = 999999999,
+ .qos_pol_max = 383,
+ /* Maximum allowed value of committed burst size(CBS) is 240 KB */
+ .pol_cbs_max = 60,
+ /* Maximum allowed value of excess burst size(EBS) is 240 KB */
+ .pol_pbs_max = 60,
+ .num_frer_ssid = MSCC_FRER_SSID_NUM,
+ .frer_seq_len_min = 1,
+ .frer_seq_len_max = 28,
+ .frer_his_len_min = 1,
+ .frer_his_len_max = 32,
+ .qos_dscp_max = 63,
+ .qos_cos_max = NUM_MSCC_QOS_PRIO - 1,
+ .qos_dp_max = 1,
+};
+
+static int qos_port_tas_gcl_set(struct ocelot *ocelot, const u8 gcl_ix,
+ struct tsn_qbv_entry *control_list)
+{
+ if (gcl_ix >= capa.num_tas_gcl) {
+ dev_err(ocelot->dev, "Invalid gcl ix %u\n", gcl_ix);
+ return -EINVAL;
+ }
+ if (control_list->time_interval < capa.tas_it_min ||
+ control_list->time_interval > capa.tas_it_max) {
+ dev_err(ocelot->dev, "Invalid time_interval %u\n",
+ control_list->time_interval);
+
+ return -EINVAL;
+ }
+
+ ocelot_write(ocelot,
+ QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
+ QSYS_GCL_CFG_REG_1_GATE_STATE(control_list->gate_state),
+ QSYS_GCL_CFG_REG_1);
+
+ ocelot_write(ocelot,
+ control_list->time_interval,
+ QSYS_GCL_CFG_REG_2);
+
+ return 0;
+}
+
+static u32 tas_read_status(struct ocelot *ocelot)
+{
+ u32 val;
+
+ val = ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
+
+ return val;
+}
+
+int ocelot_qbv_set(struct ocelot *ocelot, int port_id,
+ struct tsn_qbv_conf *shaper_config)
+{
+ struct tsn_qbv_basic *admin_basic = &shaper_config->admin;
+ struct tsn_qbv_entry *control_list = admin_basic->control_list;
+ u32 base_time_nsec = admin_basic->base_time % 1000000000;
+ u64 base_time_sec = admin_basic->base_time / 1000000000;
+ u64 cur_time;
+ u32 val;
+ u8 speed;
+ int i;
+ int ret;
+
+ if (admin_basic->control_list_length > capa.num_tas_gcl) {
+ dev_err(ocelot->dev,
+ "Invalid admin_control_list_length %u\n",
+ admin_basic->control_list_length);
+ return -EINVAL;
+ }
+
+ if ((admin_basic->cycle_time < capa.tas_ct_min ||
+ admin_basic->cycle_time > capa.tas_ct_max) &&
+ shaper_config->gate_enabled) {
+ dev_err(ocelot->dev, "Invalid admin_cycle_time %u ns\n",
+ admin_basic->cycle_time);
+ return -EINVAL;
+ }
+ if (admin_basic->cycle_time_extension > capa.tas_cte_max) {
+ dev_err(ocelot->dev,
+ "Invalid admin_cycle_time_extension %u\n",
+ admin_basic->cycle_time_extension);
+ return -EINVAL;
+ }
+
+ cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
+ cur_time = cur_time << 32;
+ cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
+
+ if (base_time_sec < cur_time) {
+ base_time_sec = cur_time;
+ base_time_nsec = ocelot_read(ocelot, PTP_CUR_NSEC);
+ }
+
+ /* Select port */
+ ocelot_rmw(ocelot,
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
+ QSYS_TAS_PARAM_CFG_CTRL);
+
+ val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
+ if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) {
+ ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
+ QSYS_TAG_CONFIG, port_id);
+ }
+
+ if (!shaper_config->gate_enabled)
+ admin_basic->gate_states = 0xff;
+
+ val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port_id);
+ speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
+
+ ocelot_rmw_rix(ocelot,
+ (shaper_config->gate_enabled ?
+ QSYS_TAG_CONFIG_ENABLE : 0) |
+ QSYS_TAG_CONFIG_INIT_GATE_STATE(admin_basic->gate_states) |
+ QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xff) |
+ QSYS_TAG_CONFIG_LINK_SPEED(speed),
+ QSYS_TAG_CONFIG_ENABLE |
+ QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
+ QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M |
+ QSYS_TAG_CONFIG_LINK_SPEED_M,
+ QSYS_TAG_CONFIG,
+ port_id);
+
+ ocelot_write_rix(ocelot, shaper_config->maxsdu,
+ QSYS_PORT_MAX_SDU, port_id);
+ /* TODO: add queue max SDU set */
+
+ if (shaper_config->gate_enabled) {
+ ocelot_write(ocelot, base_time_nsec,
+ QSYS_PARAM_CFG_REG_1);
+
+ ocelot_write(ocelot, base_time_sec & GENMASK(31, 0),
+ QSYS_PARAM_CFG_REG_2);
+
+ ocelot_write(ocelot,
+ QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(base_time_sec >> 32) |
+ QSYS_PARAM_CFG_REG_3_LIST_LENGTH(admin_basic->control_list_length),
+ QSYS_PARAM_CFG_REG_3);
+
+ ocelot_write(ocelot, admin_basic->cycle_time,
+ QSYS_PARAM_CFG_REG_4);
+
+ ocelot_write(ocelot, admin_basic->cycle_time_extension,
+ QSYS_PARAM_CFG_REG_5);
+
+ for (i = 0; i < admin_basic->control_list_length; i++) {
+ qos_port_tas_gcl_set(ocelot, i, control_list);
+ control_list++;
+ }
+
+ /* Start configuration change */
+ ocelot_rmw(ocelot,
+ QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+ QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+ QSYS_TAS_PARAM_CFG_CTRL);
+
+ ret = readx_poll_timeout(tas_read_status, ocelot, val,
+ !(QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE
+ & val), 10, 100000);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ocelot_qbv_get(struct ocelot *ocelot, int port_id,
+ struct tsn_qbv_conf *shaper_config)
+{
+ u32 val, reg;
+ int i;
+ u32 base_timel;
+ u32 base_timeh;
+ struct tsn_qbv_basic *admin = &shaper_config->admin;
+ struct tsn_qbv_entry *list;
+
+ ocelot_rmw(ocelot,
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
+ QSYS_TAS_PARAM_CFG_CTRL);
+
+ val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port_id);
+ shaper_config->gate_enabled = (val & QSYS_TAG_CONFIG_ENABLE);
+ admin->gate_states = QSYS_TAG_CONFIG_INIT_GATE_STATE_X(val);
+
+ base_timel = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_1);
+ base_timeh = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_2);
+ reg = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_3);
+ admin->base_time = base_timeh |
+ (((u64)QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(reg)) << 32);
+
+ admin->base_time = (admin->base_time * 1000000000) + base_timel;
+
+ admin->control_list_length =
+ QSYS_PARAM_CFG_REG_3_LIST_LENGTH_X(reg);
+
+ admin->cycle_time = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_4);
+ admin->cycle_time_extension =
+ ocelot_read(ocelot, QSYS_PARAM_CFG_REG_5);
+
+ list = kmalloc_array(admin->control_list_length,
+ sizeof(struct tsn_qbv_entry), GFP_KERNEL);
+ admin->control_list = list;
+
+ for (i = 0; i < admin->control_list_length; i++) {
+ ocelot_rmw(ocelot,
+ QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(i),
+ QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM_M,
+ QSYS_GCL_CFG_REG_1);
+
+ list->time_interval =
+ ocelot_read(ocelot, QSYS_GCL_CFG_REG_2);
+
+ reg = ocelot_read(ocelot, QSYS_GCL_CFG_REG_1);
+ list->gate_state = QSYS_GCL_CFG_REG_1_GATE_STATE_X(reg);
+
+ list++;
+ }
+
+ return 0;
+}
+
+static int qbv_get_gatelist(struct ocelot *ocelot,
+ struct tsn_qbv_basic *oper)
+{
+ u32 base_timel;
+ u32 base_timeh;
+ u32 val;
+ struct tsn_qbv_entry *glist;
+ int i;
+
+ base_timel = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_1);
+ base_timeh = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_2);
+ val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_3);
+ oper->base_time = base_timeh;
+ oper->base_time +=
+ ((u64)QSYS_PARAM_STATUS_REG_3_BASE_TIME_SEC_MSB(val)) <<
+ 32;
+ oper->base_time = (oper->base_time * 1000000000) + base_timel;
+
+ oper->control_list_length =
+ QSYS_PARAM_STATUS_REG_3_LIST_LENGTH_X(val);
+
+ oper->cycle_time = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_4);
+ oper->cycle_time_extension = ocelot_read(ocelot,
+ QSYS_PARAM_STATUS_REG_5);
+
+ val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
+ oper->gate_states = QSYS_PARAM_STATUS_REG_8_OPER_GATE_STATE_X(val);
+
+ glist = kmalloc_array(oper->control_list_length,
+ sizeof(struct tsn_qbv_entry), GFP_KERNEL);
+
+ oper->control_list = glist;
+
+ for (i = 0; i < oper->control_list_length; i++) {
+ ocelot_rmw(ocelot,
+ QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM(i),
+ QSYS_GCL_STATUS_REG_1_GCL_ENTRY_NUM_M,
+ QSYS_GCL_STATUS_REG_1);
+
+ val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_2);
+ glist->time_interval = val;
+ val = ocelot_read(ocelot, QSYS_GCL_STATUS_REG_1);
+ glist->gate_state =
+ QSYS_GCL_STATUS_REG_1_GATE_STATE_X(val);
+
+ glist++;
+ }
+
+ return 0;
+}
+
+int ocelot_qbv_get_status(struct ocelot *ocelot, int port_id,
+ struct tsn_qbv_status *qbvstatus)
+{
+ struct tsn_qbv_basic *oper = &qbvstatus->oper;
+ u32 val;
+ ptptime_t cur_time;
+
+ ocelot_rmw(ocelot,
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port_id),
+ QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
+ QSYS_TAS_PARAM_CFG_CTRL);
+
+ qbvstatus->supported_list_max = capa.num_tas_gcl;
+
+ val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
+ qbvstatus->config_pending =
+ (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) ? 1 : 0;
+
+ qbvstatus->config_change_time =
+ ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_7);
+
+ qbvstatus->config_change_time +=
+ ((u64)QSYS_PARAM_STATUS_REG_8_CFG_CHG_TIME_SEC_MSB(val)) <<
+ 32;
+
+ qbvstatus->config_change_time =
+ (qbvstatus->config_change_time * 1000000000) +
+ ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_6);
+
+ qbvstatus->config_change_error =
+ ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_9);
+
+ cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
+ cur_time = cur_time << 32;
+ cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
+ cur_time = (cur_time * 1000000000) +
+ ocelot_read(ocelot, PTP_CUR_NSEC);
+
+ qbvstatus->current_time = cur_time;
+ qbv_get_gatelist(ocelot, oper);
+
+ return 0;
+}
+
+int ocelot_cut_thru_set(struct ocelot *ocelot, int port_id, u8 cut_thru)
+{
+ ocelot_write_rix(ocelot, cut_thru, ANA_CUT_THRU_CFG, port_id);
+
+ return 0;
+}
+
+static int qos_shaper_conf_set(struct ocelot *ocelot, int port,
+ u32 port_ix, u8 percent)
+{
+ u32 val;
+ int speed;
+ u32 cbs = 0;
+ u32 cir = 0;
+
+ if (percent > 100) {
+ dev_err(ocelot->dev, "percentage %d larger than 100\n",
+ percent);
+ return -EINVAL;
+ }
+ if (port_ix >= capa.num_hsch) {
+ dev_err(ocelot->dev,
+ "CIR_CFG: id %d is exceed num of HSCH instance\n",
+ port_ix);
+ return -EINVAL;
+ }
+
+ val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
+ speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
+ switch (speed) {
+ case OCELOT_SPEED_10:
+ cir = 10000;
+ break;
+ case OCELOT_SPEED_100:
+ cir = 100000;
+ break;
+ case OCELOT_SPEED_1000:
+ cir = 1000000;
+ break;
+ case OCELOT_SPEED_2500:
+ cir = 2500000;
+ break;
+ }
+
+ cir = cir * percent / 100;
+ cir = DIV_ROUND_UP(cir, 100); /* Rate unit is 100 kbps */
+ cir = (cir ? cir : 1); /* Avoid using zero rate */
+ cbs = DIV_ROUND_UP(cbs, 4096); /* Burst unit is 4kB */
+ cbs = (cbs ? cbs : 1); /* Avoid using zero burst size */
+ cir = min_t(u32, GENMASK(15, 0), cir);
+ cbs = min_t(u32, GENMASK(6, 0), cbs);
+ ocelot_write_gix(ocelot,
+ QSYS_CIR_CFG_CIR_RATE(cir) |
+ QSYS_CIR_CFG_CIR_BURST(cbs),
+ QSYS_CIR_CFG,
+ port_ix);
+
+ return 0;
+}
+
+static int qos_shaper_conf_get(struct ocelot *ocelot, int port,
+ u32 port_ix)
+{
+ u32 val;
+ u32 bandwidth = 0;
+ u32 cir = 0;
+ int percentage;
+ int speed;
+
+ if (port_ix >= capa.num_hsch) {
+ dev_err(ocelot->dev,
+ "CIR_CFG: id %d is exceed num of HSCH instance\n",
+ port_ix);
+ return -EINVAL;
+ }
+
+ val = ocelot_read_gix(ocelot, ANA_PFC_PFC_CFG, port);
+ speed = ANA_PFC_PFC_CFG_FC_LINK_SPEED(val);
+ switch (speed) {
+ case OCELOT_SPEED_10:
+ bandwidth = 10000;
+ break;
+ case OCELOT_SPEED_100:
+ bandwidth = 100000;
+ break;
+ case OCELOT_SPEED_1000:
+ bandwidth = 1000000;
+ break;
+ case OCELOT_SPEED_2500:
+ bandwidth = 2500000;
+ break;
+ }
+
+ val = ocelot_read_gix(ocelot, QSYS_CIR_CFG, port_ix);
+
+ cir = QSYS_CIR_CFG_CIR_RATE_X(val);
+ cir *= 100;
+ percentage = cir * 100 / bandwidth;
+
+ return percentage;
+}
+
+int ocelot_cbs_set(struct ocelot *ocelot, int port, u8 tc, u8 bw)
+{
+ if (tc > capa.qos_cos_max) {
+ dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
+ return -EINVAL;
+ }
+
+ qos_shaper_conf_set(ocelot, port, port * 8 + tc, bw);
+
+ ocelot_rmw_gix(ocelot,
+ QSYS_SE_CFG_SE_AVB_ENA,
+ QSYS_SE_CFG_SE_AVB_ENA,
+ QSYS_SE_CFG,
+ port * 8 + tc);
+
+ return 0;
+}
+
+int ocelot_cbs_get(struct ocelot *ocelot, int port, u8 tc)
+{
+ int ret;
+
+ if (tc > capa.qos_cos_max) {
+ dev_err(ocelot->dev, "Invalid tc: %u\n", tc);
+ return -EINVAL;
+ }
+
+ ret = qos_shaper_conf_get(ocelot, port, port * 8 + tc);
+
+ return ret;
+}
+
+int ocelot_qbu_set(struct ocelot *ocelot, int port, u8 preemptible)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ ocelot_port_rmwl(ocelot_port,
+ DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
+ DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
+ DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
+ DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
+ DEV_GMII_MM_CONFIG_ENABLE_CONFIG);
+
+ ocelot_rmw_rix(ocelot,
+ QSYS_PREEMPTION_CFG_P_QUEUES(preemptible),
+ QSYS_PREEMPTION_CFG_P_QUEUES_M,
+ QSYS_PREEMPTION_CFG,
+ port);
+
+ return 0;
+}
+
+int ocelot_qbu_get(struct ocelot *ocelot, int port,
+ struct tsn_preempt_status *c)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ u32 val;
+
+ val = ocelot_read_rix(ocelot,
+ QSYS_PREEMPTION_CFG,
+ port);
+
+ c->admin_state = QSYS_PREEMPTION_CFG_P_QUEUES(val);
+ c->hold_advance = QSYS_PREEMPTION_CFG_HOLD_ADVANCE_X(val);
+
+ val = ocelot_port_readl(ocelot_port,
+ DEV_GMII_MM_STATISTICS_MM_STATUS);
+ c->preemption_active =
+ DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS & val;
+
+ return 0;
+}
+
+int ocelot_cb_streamid_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_cb_streamid *streamid)
+{
+ u32 m_index;
+ u32 bucket;
+ u32 val, dst, reg;
+ u64 dmac;
+ u32 ldmac, hdmac;
+
+ if (index >= MSCC_STREAM_HANDLE_NUM) {
+ dev_err(ocelot->dev,
+ "Invalid stream handle %u, maximum:%u\n",
+ index, MSCC_STREAM_HANDLE_NUM - 1);
+ return -EINVAL;
+ }
+
+ index = streamhandle_map[index];
+ m_index = index / 4;
+ bucket = index % 4;
+ streamid->type = 1;
+ regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
+ bucket);
+ regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
+ m_index);
+
+ /*READ command MACACCESS.VALID(11 bit) must be 0 */
+ ocelot_write(ocelot,
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
+ ANA_TABLES_MACACCESS);
+
+ val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
+ dst = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
+ reg = ocelot_read_rix(ocelot, ANA_PGID_PGID, dst);
+ streamid->ofac_oport = ANA_PGID_PGID_PGID(reg);
+
+ /*Get the entry's MAC address and VLAN id*/
+ ldmac = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
+ val = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
+ val &= 0x1fffffff;
+ hdmac = val & 0xffff;
+ dmac = hdmac;
+ dmac = (dmac << 32) | ldmac;
+ streamid->para.nid.dmac = dmac;
+
+ streamid->para.nid.vid = ANA_TABLES_MACHDATA_VID_X(val);
+
+ val = ocelot_read(ocelot, ANA_TABLES_STREAMDATA);
+ if (!(val & ANA_TABLES_STREAMDATA_SFID_VALID))
+ return -EINVAL;
+
+ streamid->handle = ANA_TABLES_STREAMDATA_SFID(val);
+
+ return 0;
+}
+
+static int lookup_mactable(struct ocelot *ocelot, u16 vid, u64 mac)
+{
+ u32 mach, macl;
+ u32 reg1, reg2;
+ u32 index, bucket;
+
+ macl = mac & 0xffffffff;
+ mach = (mac >> 32) & 0xffff;
+ ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
+ ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
+ ANA_TABLES_MACHDATA_MACHDATA(mach),
+ ANA_TABLES_MACHDATA);
+
+ ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
+ ANA_TABLES_MACACCESS);
+
+ reg1 = ocelot_read(ocelot, ANA_TABLES_MACLDATA);
+ reg2 = ocelot_read(ocelot, ANA_TABLES_MACHDATA);
+ if (reg1 == 0 && reg2 == 0)
+ return -1;
+
+ regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
+ &bucket);
+ regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
+ &index);
+
+ index = index * 4 + bucket;
+
+ return index;
+}
+
+int ocelot_cb_streamid_set(struct ocelot *ocelot, int port,
+ u32 index, bool enable,
+ struct tsn_cb_streamid *streamid)
+{
+ struct regmap_field *rf;
+ u16 vid;
+ u64 mac;
+ u32 macl, mach;
+ u32 dst_idx;
+ int idx;
+ u32 reg;
+ int sfid, ssid;
+ u32 m_index, bucket;
+
+ if (!enable) {
+ if (index >= MSCC_STREAM_HANDLE_NUM) {
+ dev_err(ocelot->dev,
+ "Invalid index %u, maximum:%u\n",
+ index, MSCC_STREAM_HANDLE_NUM - 1);
+ return -EINVAL;
+ }
+ m_index = streamhandle_map[index] / 4;
+ bucket = streamhandle_map[index] % 4;
+ rf = ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET];
+ regmap_field_write(rf, bucket);
+ rf = ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX];
+ regmap_field_write(rf, m_index);
+
+ /*READ command MACACCESS.VALID(11 bit) must be 0 */
+ ocelot_write(ocelot,
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
+ ANA_TABLES_MACACCESS);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_FORGET),
+ ANA_TABLES_MACACCESS);
+
+ streamhandle_map[index] = 0;
+
+ return 0;
+ }
+
+ if (streamid->type != 1) {
+ dev_err(ocelot->dev, "Invalid stream type\n");
+ return -EINVAL;
+ }
+
+ if (streamid->handle >= MSCC_STREAM_HANDLE_NUM) {
+ dev_err(ocelot->dev,
+ "Invalid stream handle %u, maximum:%u\n",
+ streamid->handle, MSCC_STREAM_HANDLE_NUM - 1);
+ return -EINVAL;
+ }
+
+ sfid = streamid->handle;
+ ssid = (streamid->handle < MSCC_FRER_SSID_NUM ?
+ streamid->handle : (MSCC_FRER_SSID_NUM - 1));
+
+ mac = streamid->para.nid.dmac;
+ macl = mac & 0xffffffff;
+ mach = (mac >> 32) & 0xffff;
+ vid = streamid->para.nid.vid;
+
+ idx = lookup_mactable(ocelot, vid, mac);
+
+ if (idx < 0) {
+ ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA);
+ ocelot_write(ocelot, ANA_TABLES_MACHDATA_VID(vid) |
+ ANA_TABLES_MACHDATA_MACHDATA(mach),
+ ANA_TABLES_MACHDATA);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMDATA_SFID_VALID |
+ ANA_TABLES_STREAMDATA_SFID(sfid) |
+ ANA_TABLES_STREAMDATA_SSID_VALID |
+ ANA_TABLES_STREAMDATA_SSID(ssid),
+ ANA_TABLES_STREAMDATA);
+
+ dst_idx = port;
+ ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
+ ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
+ ANA_TABLES_MACACCESS);
+
+ ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
+ ANA_TABLES_MACACCESS);
+
+ regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
+ &bucket);
+ regmap_field_read(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
+ &m_index);
+
+ m_index = m_index * 4 + bucket;
+ streamhandle_map[streamid->handle] = m_index;
+
+ return 0;
+ }
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMDATA_SFID_VALID |
+ ANA_TABLES_STREAMDATA_SFID(sfid) |
+ ANA_TABLES_STREAMDATA_SSID_VALID |
+ ANA_TABLES_STREAMDATA_SSID(ssid),
+ ANA_TABLES_STREAMDATA);
+
+ reg = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
+ dst_idx = ANA_TABLES_MACACCESS_DEST_IDX_X(reg);
+ ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
+ ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
+ ANA_TABLES_MACACCESS);
+
+ streamhandle_map[streamid->handle] = idx;
+
+ return 0;
+}
+
+static int streamid_multi_forward_set(struct ocelot *ocelot, u32 index,
+ u8 fwdmask)
+{
+ u32 m_index;
+ u32 bucket;
+ u32 val;
+ int m, n, i;
+ u8 pgid_val = 0, fwdport;
+ u32 dst_idx;
+
+ m_index = index / 4;
+ bucket = index % 4;
+
+ regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_BUCKET],
+ bucket);
+ regmap_field_write(ocelot->regfields[ANA_TABLES_MACTINDX_M_INDEX],
+ m_index);
+
+ /*READ command MACACCESS.VALID(11 bit) must be 0 */
+ ocelot_write(ocelot,
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ),
+ ANA_TABLES_MACACCESS);
+
+ val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
+ fwdport = ANA_TABLES_MACACCESS_DEST_IDX_X(val);
+
+ if (fwdport >= MSCC_NUM_OUT_PORT) {
+ dst_idx = fwdport;
+ return 0;
+ }
+
+ fwdmask |= (1 << fwdport);
+
+ m = ocelot->num_phys_ports - 1;
+ for (i = m; i >= MSCC_NUM_OUT_PORT; i--) {
+ if (fwdmask & (1 << i)) {
+ dst_idx = PGID_MCRED +
+ (m - i) * MSCC_NUM_OUT_PORT +
+ fwdport;
+
+ pgid_val = (1 << i) | (1 << fwdport);
+ break;
+ }
+ }
+
+ if (i < MSCC_NUM_OUT_PORT) {
+ m = PGID_MCRED +
+ (ocelot->num_phys_ports - MSCC_NUM_OUT_PORT) *
+ MSCC_NUM_OUT_PORT;
+
+ for (; i > 0; i--) {
+ if (fwdmask & (1 << i))
+ break;
+
+ m = m + (1 << i) - 1;
+ }
+ n = fwdmask & ((1 << i) - 1);
+ if (n) {
+ dst_idx = m + n;
+ pgid_val = fwdmask & ((1 << MSCC_NUM_OUT_PORT) - 1);
+ } else {
+ dst_idx = fwdport;
+ }
+ }
+
+ if (dst_idx < PGID_MCRED)
+ return 0;
+
+ ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID |
+ ANA_TABLES_MACACCESS_ENTRYTYPE(1) |
+ ANA_TABLES_MACACCESS_DEST_IDX(dst_idx) |
+ ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_WRITE),
+ ANA_TABLES_MACACCESS);
+
+ ocelot_write_rix(ocelot, pgid_val, ANA_PGID_PGID, dst_idx);
+
+ return 0;
+}
+
+int ocelot_qci_sfi_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_qci_psfp_sfi_conf *sfi)
+{
+ u32 val, reg, fmeter_id, max_sdu;
+ u32 sfid = index;
+
+ if (sfid >= capa.num_psfp_sfid) {
+ dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
+ sfid, capa.num_psfp_sfid);
+ return -EINVAL;
+ }
+
+ ocelot_rmw(ocelot,
+ ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
+ ANA_TABLES_SFIDTIDX_SFID_INDEX_M,
+ ANA_TABLES_SFIDTIDX);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_READ),
+ ANA_TABLES_SFIDACCESS);
+
+ val = ocelot_read(ocelot, ANA_TABLES_SFIDTIDX);
+ if (!(val & ANA_TABLES_SFIDTIDX_SGID_VALID))
+ return -EINVAL;
+
+ sfi->stream_gate_instance_id = ANA_TABLES_SFIDTIDX_SGID_X(val);
+ fmeter_id = ANA_TABLES_SFIDTIDX_POL_IDX_X(val);
+ sfi->stream_filter.flow_meter_instance_id = fmeter_id;
+
+ reg = ocelot_read(ocelot, ANA_TABLES_SFIDACCESS);
+ max_sdu = ANA_TABLES_SFIDACCESS_MAX_SDU_LEN_X(reg);
+ sfi->stream_filter.maximum_sdu_size = max_sdu;
+
+ if (reg & ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA)
+ sfi->priority_spec = ANA_TABLES_SFIDACCESS_IGR_PRIO_X(reg);
+ else
+ dev_err(ocelot->dev, "priority not enable\n");
+
+ return 0;
+}
+
+int ocelot_qci_sfi_set(struct ocelot *ocelot, int port,
+ u32 index, bool enable,
+ struct tsn_qci_psfp_sfi_conf *sfi)
+{
+ int igr_prio = sfi->priority_spec;
+ u16 sgid = sfi->stream_gate_instance_id;
+ u16 pol_idx;
+ int fmid = sfi->stream_filter.flow_meter_instance_id;
+ u16 max_sdu_len = sfi->stream_filter.maximum_sdu_size;
+ int sfid = index;
+ u32 val;
+
+ if (fmid == -1)
+ pol_idx = capa.psfp_fmi_max;
+ else
+ pol_idx = (u16)fmid;
+
+ if (sfid >= capa.num_psfp_sfid) {
+ dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
+ sfid, capa.num_psfp_sfid);
+ return -EINVAL;
+ }
+
+ if (!enable) {
+ val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE);
+ ocelot_write(ocelot,
+ ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
+ ANA_TABLES_SFIDTIDX);
+ ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS);
+ return 0;
+ }
+
+ if (sgid >= capa.num_psfp_sgid) {
+ dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
+ sgid, capa.num_psfp_sgid);
+ return -EINVAL;
+ }
+ if (pol_idx > capa.psfp_fmi_max || pol_idx < capa.psfp_fmi_min) {
+ dev_err(ocelot->dev, "Invalid pol_idx %u, range:%d~%d\n",
+ pol_idx, capa.psfp_fmi_min, capa.psfp_fmi_max);
+ return -EINVAL;
+ }
+
+ ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SGID_VALID |
+ ANA_TABLES_SFIDTIDX_SGID(sgid) |
+ ((fmid != -1) ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) |
+ ANA_TABLES_SFIDTIDX_POL_IDX(pol_idx) |
+ ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
+ ANA_TABLES_SFIDTIDX);
+
+ ocelot_write(ocelot,
+ ((igr_prio >= 0) ?
+ ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) |
+ ANA_TABLES_SFIDACCESS_IGR_PRIO(igr_prio) |
+ ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(max_sdu_len) |
+ ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
+ ANA_TABLES_SFIDACCESS);
+
+ return 0;
+}
+
+int ocelot_qci_sfi_counters_get(struct ocelot *ocelot, int port,
+ u32 index,
+ struct tsn_qci_psfp_sfi_counters *sfi_cnt)
+{
+ u32 sfid = index;
+ u32 match, not_pass, not_pass_sdu, red;
+
+ if (sfid >= capa.num_psfp_sfid) {
+ dev_err(ocelot->dev, "Invalid index %u, maximum:%u\n",
+ sfid, capa.num_psfp_sfid);
+ return -EINVAL;
+ }
+
+ ocelot_rmw(ocelot,
+ SYS_STAT_CFG_STAT_VIEW(sfid),
+ SYS_STAT_CFG_STAT_VIEW_M,
+ SYS_STAT_CFG);
+
+ match = ocelot_read_gix(ocelot, SYS_CNT, 0x200);
+ not_pass = ocelot_read_gix(ocelot, SYS_CNT, 0x201);
+ not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202);
+ red = ocelot_read_gix(ocelot, SYS_CNT, 0x203);
+
+ sfi_cnt->matching_frames_count = match;
+ sfi_cnt->not_passing_frames_count = not_pass;
+ sfi_cnt->not_passing_sdu_count = not_pass_sdu;
+ sfi_cnt->red_frames_count = red;
+
+ sfi_cnt->passing_frames_count = match - not_pass;
+ sfi_cnt->passing_sdu_count = match - not_pass - not_pass_sdu;
+
+ return 0;
+}
+
+int ocelot_qci_max_cap_get(struct ocelot *ocelot,
+ struct tsn_qci_psfp_stream_param *stream_para)
+{
+ /* MaxStreamFilterInstances */
+ stream_para->max_sf_instance = capa.num_psfp_sfid;
+ /* MaxStreamGateInstances */
+ stream_para->max_sg_instance = capa.num_psfp_sgid;
+ /* MaxFlowMeterInstances */
+ stream_para->max_fm_instance = capa.psfp_fmi_max -
+ capa.psfp_fmi_min + 1;
+ /* SupportedListMax */
+ stream_para->supported_list_max = capa.num_sgi_gcl;
+
+ return 0;
+}
+
+static int sgi_set_glist(struct ocelot *ocelot,
+ struct tsn_qci_psfp_gcl *gcl, uint32_t num)
+{
+ u32 time_sum = 0;
+ int i;
+
+ if (num > capa.num_sgi_gcl)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ u32 val = ANA_SG_GCL_GS_CONFIG_IPS((gcl->ipv < 0) ?
+ 0 : gcl->ipv + 8);
+ val |= (gcl->gate_state ? ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0);
+ ocelot_write_rix(ocelot, val, ANA_SG_GCL_GS_CONFIG, i);
+
+ time_sum += gcl->time_interval;
+ ocelot_write_rix(ocelot, time_sum, ANA_SG_GCL_TI_CONFIG, i);
+
+ gcl++;
+ }
+
+ return 0;
+}
+
+static u32 sgi_read_status(struct ocelot *ocelot)
+{
+ u32 val;
+
+ val = ocelot_read(ocelot, ANA_SG_ACCESS_CTRL);
+
+ return val;
+}
+
+int ocelot_qci_sgi_set(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf)
+{
+ struct tsn_qci_sg_control *admin_list = &sgi_conf->admin;
+ u32 sgid = index;
+ u32 list_length = sgi_conf->admin.control_list_length;
+ u32 cycle_time = sgi_conf->admin.cycle_time;
+ u32 cycle_time_ex = sgi_conf->admin.cycle_time_extension;
+ u32 l_basetime = sgi_conf->admin.base_time % 1000000000;
+ u64 h_basetime = sgi_conf->admin.base_time / 1000000000;
+ u64 cur_time;
+ u32 val;
+ int ret;
+
+ if (sgid >= capa.num_psfp_sgid) {
+ dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
+ sgid, capa.num_psfp_sgid);
+ return -EINVAL;
+ }
+ if ((cycle_time < capa.sgi_ct_min ||
+ cycle_time > capa.sgi_ct_max) &&
+ sgi_conf->gate_enabled) {
+ dev_err(ocelot->dev, "Invalid cycle_time %u ns\n",
+ cycle_time);
+ return -EINVAL;
+ }
+ if (cycle_time_ex > capa.sgi_cte_max) {
+ dev_err(ocelot->dev,
+ "Invalid cycle_time_extension %u\n",
+ cycle_time_ex);
+ return -EINVAL;
+ }
+ if (list_length > capa.num_sgi_gcl) {
+ dev_err(ocelot->dev,
+ "Invalid sgi_gcl len %u, maximum:%u\n",
+ list_length, capa.num_sgi_gcl);
+ return -EINVAL;
+ }
+
+ /*configure SGID*/
+ ocelot_rmw(ocelot,
+ ANA_SG_ACCESS_CTRL_SGID(sgid),
+ ANA_SG_ACCESS_CTRL_SGID_M,
+ ANA_SG_ACCESS_CTRL);
+
+ /*Disable SG*/
+ if (!sgi_conf->gate_enabled) {
+ ocelot_rmw(ocelot,
+ ANA_SG_CONFIG_REG_3_INIT_GATE_STATE,
+ ANA_SG_CONFIG_REG_3_INIT_GATE_STATE |
+ ANA_SG_CONFIG_REG_3_GATE_ENABLE,
+ ANA_SG_CONFIG_REG_3);
+ return 0;
+ }
+
+ /*admin parameters*/
+ cur_time = ocelot_read(ocelot, PTP_CUR_SEC_MSB);
+ cur_time = cur_time << 32;
+ cur_time += ocelot_read(ocelot, PTP_CUR_SEC_LSB);
+ if (h_basetime < cur_time) {
+ h_basetime = cur_time;
+ l_basetime = ocelot_read(ocelot, PTP_CUR_NSEC);
+ }
+
+ ocelot_write(ocelot, l_basetime, ANA_SG_CONFIG_REG_1);
+ ocelot_write(ocelot, h_basetime, ANA_SG_CONFIG_REG_2);
+
+ ocelot_write(ocelot,
+ (sgi_conf->admin.init_ipv < 0 ?
+ 0 : ANA_SG_CONFIG_REG_3_IPV_VALID) |
+ ANA_SG_CONFIG_REG_3_INIT_IPV(sgi_conf->admin.init_ipv) |
+ ANA_SG_CONFIG_REG_3_GATE_ENABLE |
+ ANA_SG_CONFIG_REG_3_LIST_LENGTH(list_length) |
+ (sgi_conf->admin.gate_states > 0 ?
+ ANA_SG_CONFIG_REG_3_INIT_GATE_STATE : 0) |
+ ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(h_basetime >> 32),
+ ANA_SG_CONFIG_REG_3);
+
+ ocelot_write(ocelot, cycle_time, ANA_SG_CONFIG_REG_4);
+ ocelot_write(ocelot, cycle_time_ex, ANA_SG_CONFIG_REG_5);
+
+ ret = sgi_set_glist(ocelot, admin_list->gcl, list_length);
+ if (ret < 0)
+ return ret;
+
+ /* Start configuration change */
+ ocelot_rmw(ocelot,
+ ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
+ ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
+ ANA_SG_ACCESS_CTRL);
+
+ ret = readx_poll_timeout(sgi_read_status, ocelot, val,
+ (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)),
+ 10, 100000);
+
+ return ret;
+}
+
+static int sgi_get_glist(struct ocelot *ocelot,
+ struct tsn_qci_psfp_gcl *gcl,
+ uint32_t num)
+{
+ int i;
+ u16 val;
+ u32 time = 0;
+ u32 reg;
+
+ if (num > capa.num_sgi_gcl)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ val = ocelot_read_rix(ocelot, ANA_SG_GCL_GS_CONFIG, i);
+ gcl->gate_state = (val & ANA_SG_GCL_GS_CONFIG_GATE_STATE);
+
+ if (val & ANA_SG_GCL_GS_CONFIG_IPV_VALID)
+ gcl->ipv = ANA_SG_GCL_GS_CONFIG_IPV(val);
+ else
+ gcl->ipv = -1;
+
+ reg = ocelot_read_rix(ocelot, ANA_SG_GCL_TI_CONFIG, i);
+ gcl->time_interval = (reg - time);
+ time = reg;
+
+ gcl++;
+ }
+
+ return 0;
+}
+
+int ocelot_qci_sgi_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_qci_psfp_sgi_conf *sgi_conf)
+{
+ struct tsn_qci_sg_control *admin = &sgi_conf->admin;
+ struct tsn_qci_psfp_gcl *glist;
+ u32 val, reg;
+ u32 list_num;
+ int ret;
+
+ if (index >= capa.num_psfp_sgid) {
+ dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
+ index, capa.num_psfp_sgid);
+ return -EINVAL;
+ }
+
+ ocelot_rmw(ocelot,
+ ANA_SG_ACCESS_CTRL_SGID(index),
+ ANA_SG_ACCESS_CTRL_SGID_M,
+ ANA_SG_ACCESS_CTRL);
+
+ admin->cycle_time = ocelot_read(ocelot, ANA_SG_CONFIG_REG_4);
+ admin->cycle_time_extension =
+ ocelot_read(ocelot, ANA_SG_CONFIG_REG_5);
+
+ val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_2);
+ admin->base_time = val;
+
+ reg = ocelot_read(ocelot, ANA_SG_CONFIG_REG_1);
+ val = ocelot_read(ocelot, ANA_SG_CONFIG_REG_3);
+
+ admin->base_time +=
+ ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val) << 32;
+
+ admin->base_time = admin->base_time * 1000000000 + reg;
+
+ if (val & ANA_SG_CONFIG_REG_3_IPV_VALID)
+ admin->init_ipv = ANA_SG_CONFIG_REG_3_INIT_IPV_X(val);
+ else
+ admin->init_ipv = -1;
+
+ if (val & ANA_SG_CONFIG_REG_3_GATE_ENABLE)
+ sgi_conf->gate_enabled = TRUE;
+
+ admin->control_list_length = ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(val);
+
+ list_num = admin->control_list_length;
+
+ glist = kmalloc_array(list_num, sizeof(struct tsn_qci_psfp_gcl),
+ GFP_KERNEL);
+ admin->gcl = glist;
+
+ ret = sgi_get_glist(ocelot, glist, list_num);
+
+ return ret;
+}
+
+int ocelot_qci_sgi_status_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_psfp_sgi_status *sgi_status)
+{
+ u32 val, reg;
+
+ if (index >= capa.num_psfp_sgid) {
+ dev_err(ocelot->dev, "Invalid sgid %u, maximum:%u\n",
+ index, capa.num_psfp_sgid);
+ return -EINVAL;
+ }
+
+ ocelot_rmw(ocelot,
+ ANA_SG_ACCESS_CTRL_SGID(index),
+ ANA_SG_ACCESS_CTRL_SGID_M,
+ ANA_SG_ACCESS_CTRL);
+
+ val = ocelot_read(ocelot, ANA_SG_STATUS_REG_2);
+ sgi_status->config_change_time = val;
+
+ reg = ocelot_read(ocelot, ANA_SG_STATUS_REG_1);
+ val = ocelot_read(ocelot, ANA_SG_STATUS_REG_3);
+ sgi_status->config_change_time +=
+ ANA_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB(val) << 32;
+ sgi_status->config_change_time =
+ sgi_status->config_change_time * 1000000000 + reg;
+
+ if (val & ANA_SG_STATUS_REG_3_CONFIG_PENDING)
+ sgi_status->config_pending = TRUE;
+ else
+ sgi_status->config_pending = FALSE;
+
+ if (val & ANA_SG_STATUS_REG_3_GATE_STATE)
+ sgi_status->oper.gate_states = TRUE;
+ else
+ sgi_status->oper.gate_states = FALSE;
+ /*bit 3 encoding 0:IPV [0:2]is invalid . 1:IPV[0:2] is valid*/
+ if (val & ANA_SG_STATUS_REG_3_IPV_VALID)
+ sgi_status->oper.init_ipv = ANA_SG_STATUS_REG_3_IPV_X(val);
+ else
+ sgi_status->oper.init_ipv = -1;
+
+ return 0;
+}
+
+int ocelot_qci_fmi_set(struct ocelot *ocelot, int port, u32 index,
+ bool enable, struct tsn_qci_psfp_fmi *fmi)
+{
+ u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
+ u32 cir_ena = 0;
+ u32 pbs_max = 0, cbs_max = 0;
+ bool cir_discard = 0, pir_discard = 0;
+
+ if (index > capa.qos_pol_max) {
+ dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
+ index, capa.qos_pol_max);
+ return -EINVAL;
+ }
+
+ if (fmi->mark_red_enable && fmi->mark_red) {
+ fmi->eir = 0;
+ fmi->ebs = 0;
+ fmi->cir = 0;
+ fmi->cbs = 0;
+ }
+
+ pir = fmi->eir;
+ pbs = fmi->ebs;
+
+ if (!fmi->drop_on_yellow)
+ cir_ena = 1;
+
+ if (cir_ena) {
+ cir = fmi->cir;
+ cbs = fmi->cbs;
+ if (cir == 0 && cbs == 0) {
+ cir_discard = 1;
+ } else {
+ cir = DIV_ROUND_UP(cir, 100);
+ cir *= 3; /* Rate unit is 33 1/3 kbps */
+ cbs = DIV_ROUND_UP(cbs, 4096);
+ cbs = (cbs ? cbs : 1);
+ cbs_max = capa.pol_cbs_max;
+ if (fmi->cf)
+ pir += fmi->cir;
+ }
+ }
+
+ if (pir == 0 && pbs == 0) {
+ pir_discard = 1;
+ } else {
+ pir = DIV_ROUND_UP(pir, 100);
+ pir *= 3; /* Rate unit is 33 1/3 kbps */
+ pbs = DIV_ROUND_UP(pbs, 4096);
+ pbs = (pbs ? pbs : 1);
+ pbs_max = capa.pol_pbs_max;
+ }
+ pir = min_t(u32, GENMASK(15, 0), pir);
+ cir = min_t(u32, GENMASK(15, 0), cir);
+ pbs = min(pbs_max, pbs);
+ cbs = min(cbs_max, cbs);
+
+ ocelot_write_gix(ocelot, (ANA_POL_MODE_CFG_IPG_SIZE(20) |
+ ANA_POL_MODE_CFG_FRM_MODE(1) |
+ (fmi->cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
+ (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
+ ANA_POL_MODE_CFG_OVERSHOOT_ENA),
+ ANA_POL_MODE_CFG, index);
+
+ ocelot_write_gix(ocelot, ANA_POL_PIR_CFG_PIR_RATE(pir) |
+ ANA_POL_PIR_CFG_PIR_BURST(pbs),
+ ANA_POL_PIR_CFG, index);
+
+ ocelot_write_gix(ocelot,
+ (pir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_PIR_STATE, index);
+
+ ocelot_write_gix(ocelot, ANA_POL_CIR_CFG_CIR_RATE(cir) |
+ ANA_POL_CIR_CFG_CIR_BURST(cbs),
+ ANA_POL_CIR_CFG, index);
+
+ ocelot_write_gix(ocelot,
+ (cir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_CIR_STATE, index);
+
+ return 0;
+}
+
+int ocelot_qci_fmi_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_qci_psfp_fmi *fmi,
+ struct tsn_qci_psfp_fmi_counters *counters)
+{
+ u32 val, reg;
+
+ if (index > capa.qos_pol_max) {
+ dev_err(ocelot->dev, "Invalid pol_idx %u, maximum: %u\n",
+ index, capa.qos_pol_max);
+ return -EINVAL;
+ }
+
+ val = ocelot_read_gix(ocelot, ANA_POL_PIR_CFG, index);
+ reg = ocelot_read_gix(ocelot, ANA_POL_CIR_CFG, index);
+
+ fmi->eir = ANA_POL_PIR_CFG_PIR_RATE_X(val);
+ fmi->eir = fmi->eir * 100 / 3;
+ fmi->ebs = ANA_POL_PIR_CFG_PIR_BURST(val);
+ fmi->ebs *= 4096;
+ fmi->cir = ANA_POL_CIR_CFG_CIR_RATE_X(reg);
+ fmi->cir = fmi->cir * 100 / 3;
+ fmi->cbs = ANA_POL_CIR_CFG_CIR_BURST(reg);
+ fmi->cbs *= 4096;
+ if (!(fmi->eir | fmi->ebs | fmi->cir | fmi->cbs))
+ fmi->mark_red = TRUE;
+ else
+ fmi->mark_red = FALSE;
+
+ val = ocelot_read_gix(ocelot, ANA_POL_MODE_CFG, index);
+ if (val & ANA_POL_MODE_CFG_DLB_COUPLED)
+ fmi->cf = TRUE;
+ else
+ fmi->cf = FALSE;
+ if (val & ANA_POL_MODE_CFG_CIR_ENA)
+ fmi->drop_on_yellow = FALSE;
+ else
+ fmi->drop_on_yellow = TRUE;
+
+ return 0;
+}
+
+int ocelot_seq_gen_set(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_seq_gen_conf *sg_conf)
+{
+ u8 iport_mask = sg_conf->iport_mask;
+ u8 split_mask = sg_conf->split_mask;
+ u8 seq_len = sg_conf->seq_len;
+ u32 seq_num = sg_conf->seq_num;
+
+ if (index >= capa.num_frer_ssid) {
+ dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
+ index, capa.num_frer_ssid - 1);
+ return -EINVAL;
+ }
+ if (seq_len < capa.frer_seq_len_min ||
+ seq_len > capa.frer_seq_len_max) {
+ dev_err(ocelot->dev,
+ "Invalid seq_space_bits num %u,range:%d~%d\n",
+ seq_len,
+ capa.frer_seq_len_min,
+ capa.frer_seq_len_max);
+ return -EINVAL;
+ }
+
+ streamid_multi_forward_set(ocelot,
+ streamhandle_map[index],
+ split_mask);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_SEQ_MASK_SPLIT_MASK(split_mask) |
+ ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(iport_mask),
+ ANA_TABLES_SEQ_MASK);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMTIDX_S_INDEX(index) |
+ ANA_TABLES_STREAMTIDX_STREAM_SPLIT |
+ ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
+ ANA_TABLES_STREAMTIDX);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM(seq_num) |
+ ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
+ ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
+ ANA_TABLES_STREAMACCESS);
+
+ return 0;
+}
+
+int ocelot_seq_rec_set(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_seq_rec_conf *sr_conf)
+{
+ u8 seq_len = sr_conf->seq_len;
+ u8 hislen = sr_conf->his_len;
+
+ if (index >= capa.num_frer_ssid) {
+ dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
+ index, capa.num_frer_ssid - 1);
+ return -EINVAL;
+ }
+ if (seq_len < capa.frer_seq_len_min ||
+ seq_len > capa.frer_seq_len_max) {
+ dev_err(ocelot->dev,
+ "Invalid seq_space_bits num %u,range:%d~%d\n",
+ seq_len,
+ capa.frer_seq_len_min,
+ capa.frer_seq_len_max);
+ return -EINVAL;
+ }
+ if (hislen < capa.frer_his_len_min ||
+ hislen > capa.frer_his_len_max) {
+ dev_err(ocelot->dev,
+ "Invalid history_bits num %u,range:%d~%d\n",
+ hislen,
+ capa.frer_his_len_min,
+ capa.frer_his_len_max);
+ return -EINVAL;
+ }
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMTIDX_S_INDEX(index) |
+ ANA_TABLES_STREAMTIDX_FORCE_SF_BEHAVIOUR |
+ ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN(hislen) |
+ ANA_TABLES_STREAMTIDX_RESET_ON_ROGUE |
+ (sr_conf->rtag_pop_en ?
+ ANA_TABLES_STREAMTIDX_REDTAG_POP : 0) |
+ ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(seq_len),
+ ANA_TABLES_STREAMTIDX);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMACCESS_SEQ_GEN_REC_ENA |
+ ANA_TABLES_STREAMACCESS_GEN_REC_TYPE |
+ ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_WRITE),
+ ANA_TABLES_STREAMACCESS);
+
+ return 0;
+}
+
+int ocelot_cb_get(struct ocelot *ocelot, int port, u32 index,
+ struct tsn_cb_status *c)
+{
+ u32 val;
+
+ if (index >= capa.num_frer_ssid) {
+ dev_err(ocelot->dev, "Invalid SSID %u, maximum:%u\n",
+ index, capa.num_frer_ssid - 1);
+ return -EINVAL;
+ }
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMTIDX_S_INDEX(index),
+ ANA_TABLES_STREAMTIDX);
+
+ ocelot_write(ocelot,
+ ANA_TABLES_STREAMACCESS_STREAM_TBL_CMD(SFIDACCESS_CMD_READ),
+ ANA_TABLES_STREAMACCESS);
+
+ val = ocelot_read(ocelot, ANA_TABLES_STREAMACCESS);
+ c->gen_rec = (ANA_TABLES_STREAMACCESS_GEN_REC_TYPE & val) >> 2;
+ c->seq_num = ANA_TABLES_STREAMACCESS_GEN_REC_SEQ_NUM_X(val);
+
+ val = ocelot_read(ocelot, ANA_TABLES_STREAMTIDX);
+ c->err = ANA_TABLES_STREAMTIDX_SEQ_GEN_ERR_STATUS_X(val);
+ c->his_len = ANA_TABLES_STREAMTIDX_SEQ_HISTORY_LEN_X(val);
+ c->seq_len = ANA_TABLES_STREAMTIDX_SEQ_SPACE_LOG2(val);
+
+ val = ocelot_read(ocelot, ANA_TABLES_SEQ_MASK);
+ c->split_mask = ANA_TABLES_SEQ_MASK_SPLIT_MASK_X(val);
+ c->iport_mask = ANA_TABLES_SEQ_MASK_INPUT_PORT_MASK(val);
+
+ c->seq_his = ocelot_read(ocelot, ANA_TABLES_SEQ_HISTORY);
+
+ return 0;
+}
+
+int ocelot_pcp_map_enable(struct ocelot *ocelot, u8 port)
+{
+ int i;
+
+ ocelot_rmw_gix(ocelot,
+ ANA_PORT_QOS_CFG_QOS_PCP_ENA,
+ ANA_PORT_QOS_CFG_QOS_PCP_ENA,
+ ANA_PORT_QOS_CFG,
+ port);
+
+ for (i = 0; i < NUM_MSCC_QOS_PRIO * 2; i++) {
+ ocelot_rmw_ix(ocelot,
+ (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
+ ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
+ ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL |
+ ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M,
+ ANA_PORT_PCP_DEI_MAP,
+ port, i);
+ }
+
+ return 0;
+}
+
+int ocelot_rtag_parse_enable(struct ocelot *ocelot, u8 port)
+{
+ ocelot_rmw_rix(ocelot,
+ ANA_PORT_MODE_REDTAG_PARSE_CFG,
+ ANA_PORT_MODE_REDTAG_PARSE_CFG,
+ ANA_PORT_MODE,
+ port);
+
+ return 0;
+}
+
+int ocelot_dscp_set(struct ocelot *ocelot, int port,
+ bool enable, const u8 dscp_ix,
+ struct tsn_qos_switch_dscp_conf *c)
+{
+ u32 val, ri = dscp_ix;
+
+ c->dscp = 0;
+ c->trust = 1;
+ c->remark = 0;
+
+ if (dscp_ix > capa.qos_dscp_max) {
+ dev_err(ocelot->dev, "Invalid dscp_ix %u\n", dscp_ix);
+ return -EINVAL;
+ }
+ if (c->cos > capa.qos_cos_max) {
+ dev_err(ocelot->dev, "Invalid cos %d\n", c->cos);
+ return -EINVAL;
+ }
+ if (c->dpl > capa.qos_dp_max) {
+ dev_err(ocelot->dev, "Invalid dpl %d\n", c->dpl);
+ return -EINVAL;
+ }
+
+ ocelot_rmw_gix(ocelot,
+ (enable ? ANA_PORT_QOS_CFG_QOS_DSCP_ENA : 0) |
+ (c->dscp ? ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA : 0),
+ ANA_PORT_QOS_CFG_QOS_DSCP_ENA |
+ ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA,
+ ANA_PORT_QOS_CFG,
+ port);
+
+ val = (c->dpl ? ANA_DSCP_CFG_DP_DSCP_VAL : 0) |
+ ANA_DSCP_CFG_QOS_DSCP_VAL(c->cos) |
+ ANA_DSCP_CFG_DSCP_TRANSLATE_VAL(c->dscp) |
+ (c->trust ? ANA_DSCP_CFG_DSCP_TRUST_ENA : 0) |
+ (c->remark ? ANA_DSCP_CFG_DSCP_REWR_ENA : 0);
+
+ ocelot_write_rix(ocelot, val, ANA_DSCP_CFG, ri);
+
+ return 0;
+}
+
+void ocelot_preempt_irq_clean(struct ocelot *ocelot)
+{
+ struct ocelot_port *ocelot_port;
+ int port;
+ u32 val;
+
+ val = DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY;
+ for (port = 0; port < ocelot->num_phys_ports; port++) {
+ ocelot_port = ocelot->ports[port];
+ ocelot_port_rmwl(ocelot_port, val, val,
+ DEV_GMII_MM_STATISTICS_MM_STATUS);
+ }
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_tsn.h b/drivers/net/ethernet/mscc/ocelot_tsn.h
new file mode 100644
index 000000000000..218acde8a5f7
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tsn.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * TSN_SWITCH driver
+ *
+ * Copyright 2018-2019 NXP
+ */
+
+#ifndef _MSCC_OCELOT_SWITCH_TSN_H_
+#define _MSCC_OCELOT_SWITCH_TSN_H_
+
+#define TRUE 1
+#define FALSE 0
+
+struct mscc_switch_capa {
+ u8 num_tas_gcl; /* Number of TAS Gate Control Lists */
+ u32 tas_ct_min; /* Minimum supported TAS CycleTime in nS */
+ u32 tas_ct_max; /* Maximum supported TAS CycleTime in nS */
+ u32 tas_cte_max; /* Maximum supported TAS CycleTimeExtension in nS
+ */
+ u32 tas_it_max;
+ u32 tas_it_min;
+ u8 num_hsch;
+ u8 num_psfp_sfid;
+ u8 num_frer_ssid;
+ u8 num_psfp_sgid;
+ u16 psfp_fmi_max;
+ u16 psfp_fmi_min;
+ u8 num_sgi_gcl;
+ u32 sgi_ct_min;
+ u32 sgi_ct_max;
+ u32 sgi_cte_max;
+ u16 qos_pol_max;
+ u8 pol_cbs_max;
+ u8 pol_pbs_max;
+ u8 frer_seq_len_min;
+ u8 frer_seq_len_max;
+ u8 frer_his_len_min;
+ u8 frer_his_len_max;
+ u8 qos_dscp_max;
+ u8 qos_cos_max;
+ u8 qos_dp_max;
+};
+
+static inline void ocelot_port_rmwl(struct ocelot_port *port, u32 val,
+ u32 mask, u32 reg)
+{
+ u32 cur = ocelot_port_readl(port, reg);
+
+ ocelot_port_writel(port, (cur & (~mask)) | val, reg);
+}
+#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.h b/drivers/net/ethernet/mscc/ocelot_vcap.h
index e22eac1da783..895a61442fa8 100644
--- a/drivers/net/ethernet/mscc/ocelot_vcap.h
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.h
@@ -25,7 +25,7 @@
#define VCAP_IS2_CNT 64
#define VCAP_IS2_ENTRY_WIDTH 376
#define VCAP_IS2_ACTION_WIDTH 99
-#define VCAP_PORT_CNT 11
+#define VCAP_PORT_CNT 6
/* IS2 half key types */
#define IS2_TYPE_ETYPE 0
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 338e25a6374e..7a88a434b0dc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -195,6 +195,19 @@ config DWMAC_SUN8I
This selects Allwinner SoC glue layer support for the
stmmac device driver. This driver is used for H3/A83T/A64
EMAC ethernet controller.
+
+config DWMAC_IMX8
+ tristate "NXP IMX8 DWMAC support"
+ default ARCH_MXC
+ depends on OF && (ARCH_MXC || COMPILE_TEST)
+ select MFD_SYSCON
+ ---help---
+ Support for ethernet controller on NXP i.MX8 SOCs.
+
+ This selects NXP SoC glue layer support for the stmmac
+ device driver. This driver is used on for the i.MX8 series
+ SOCs GMAC ethernet controller.
+
endif
config STMMAC_PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c59926d96bcc..ae223ec1b754 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o
obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
+obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o
obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
stmmac-platform-objs:= stmmac_platform.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index bc82cdf36cc3..31003b67d24f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -248,12 +248,13 @@ struct stmmac_safety_stats {
/* Max/Min RI Watchdog Timer count value */
#define MAX_DMA_RIWT 0xff
#define MIN_DMA_RIWT 0x10
+#define DEF_DMA_RIWT 0xa0
/* Tx coalesce parameters */
#define STMMAC_COAL_TX_TIMER 1000
#define STMMAC_MAX_COAL_TX_TICK 100000
#define STMMAC_TX_MAX_FRAMES 256
-#define STMMAC_TX_FRAMES 1
-#define STMMAC_RX_FRAMES 25
+#define STMMAC_TX_FRAMES 25
+#define STMMAC_RX_FRAMES 0
/* Packets types */
enum packets_types {
@@ -362,6 +363,11 @@ struct dma_features {
unsigned int dvlan;
unsigned int l3l4fnum;
unsigned int arpoffsel;
+ /* TSN Features */
+ unsigned int estwid;
+ unsigned int estdep;
+ unsigned int estsel;
+ unsigned int fpesel;
};
/* RX Buffer size must be multiple of 4/8/16 bytes */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
index dd9967aeda22..781762255b58 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
@@ -270,6 +270,7 @@ static void *tegra_eqos_probe(struct platform_device *pdev,
struct plat_stmmacenet_data *data,
struct stmmac_resources *res)
{
+ struct device *dev = &pdev->dev;
struct tegra_eqos *eqos;
int err;
@@ -282,6 +283,9 @@ static void *tegra_eqos_probe(struct platform_device *pdev,
eqos->dev = &pdev->dev;
eqos->regs = res->addr;
+ if (!is_of_node(dev->fwnode))
+ goto bypass_clk_reset_gpio;
+
eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
if (IS_ERR(eqos->clk_master)) {
err = PTR_ERR(eqos->clk_master);
@@ -354,6 +358,7 @@ static void *tegra_eqos_probe(struct platform_device *pdev,
usleep_range(2000, 4000);
+bypass_clk_reset_gpio:
data->fix_mac_speed = tegra_eqos_fix_speed;
data->init = tegra_eqos_init;
data->bsp_priv = eqos;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
new file mode 100644
index 000000000000..f86d24af34c4
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx8
+ *
+ * Copyright 2020 NXP
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#ifdef CONFIG_IMX_SCU_SOC
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/sci.h>
+#endif
+
+#define GPR_ENET_QOS_INTF_MODE_MASK GENMASK(21, 16)
+#define GPR_ENET_QOS_INTF_SEL_MII (0x0 << 16)
+#define GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 16)
+#define GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 16)
+#define GPR_ENET_QOS_CLK_GEN_EN (0x1 << 19)
+#define GPR_ENET_QOS_CLK_TX_CLK_SEL (0x1 << 20)
+#define GPR_ENET_QOS_RGMII_EN (0x1 << 21)
+
+struct imx_dwmac_ops {
+ u32 addr_width;
+ bool mac_txclk_auto_adj;
+
+ int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);
+ int (*set_stop_mode)(struct plat_stmmacenet_data *plat_dat, bool is_en);
+};
+
+struct imx_priv_data {
+ struct device *dev;
+ struct clk *clk_tx;
+ struct clk *clk_mem;
+ struct regmap *intf_regmap;
+ u32 intf_reg_off;
+ bool rmii_refclk_ext;
+
+ const struct imx_dwmac_ops *ops;
+ struct plat_stmmacenet_data *plat_dat;
+};
+
+static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct imx_priv_data *dwmac = plat_dat->bsp_priv;
+ int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ val = GPR_ENET_QOS_INTF_SEL_MII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ val = GPR_ENET_QOS_INTF_SEL_RMII;
+ val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL);
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val = GPR_ENET_QOS_INTF_SEL_RGMII |
+ GPR_ENET_QOS_RGMII_EN;
+ break;
+ default:
+ pr_debug("imx dwmac doesn't support %d interface\n",
+ plat_dat->interface);
+ return -EINVAL;
+ }
+
+ val |= GPR_ENET_QOS_CLK_GEN_EN;
+ return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
+ GPR_ENET_QOS_INTF_MODE_MASK, val);
+};
+
+static int
+imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ int ret = 0;
+#ifdef CONFIG_IMX_SCU_SOC
+ struct imx_sc_ipc *ipc_handle;
+ int val;
+
+ ret = imx_scu_get_handle(&ipc_handle);
+ if (ret)
+ return ret;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ val = GPR_ENET_QOS_INTF_SEL_MII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ val = GPR_ENET_QOS_INTF_SEL_RMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val = GPR_ENET_QOS_INTF_SEL_RGMII;
+ break;
+ default:
+ pr_debug("imx dwmac doesn't support %d interface\n",
+ plat_dat->interface);
+ return -EINVAL;
+ }
+
+ ret = imx_sc_misc_set_control(ipc_handle, IMX_SC_R_ENET_1,
+ IMX_SC_C_INTF_SEL, val >> 16);
+ ret |= imx_sc_misc_set_control(ipc_handle, IMX_SC_R_ENET_1,
+ IMX_SC_C_CLK_GEN_EN, 0x1);
+#endif
+
+ return ret;
+}
+
+static int
+imx8mp_set_stop_mode(struct plat_stmmacenet_data *plat_dat, bool is_en)
+{
+ /* TBD */
+ return 0;
+};
+
+static int
+imx8dxl_set_stop_mode(struct plat_stmmacenet_data *plat_dat, bool is_en)
+{
+ /* TBD */
+ return 0;
+};
+
+static int imx_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct imx_priv_data *dwmac = priv;
+ struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat;
+ int ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(dwmac->clk_mem);
+ if (ret) {
+ dev_err(&pdev->dev, "mem clock enable failed\n");
+ goto clk_mem_failed;
+ }
+
+ ret = clk_prepare_enable(dwmac->clk_tx);
+ if (ret) {
+ dev_err(&pdev->dev, "tx clock enable failed\n");
+ goto clk_tx_en_failed;
+ }
+
+ if (dwmac->ops->set_stop_mode) {
+ ret = dwmac->ops->set_stop_mode(plat_dat, false);
+ if (ret)
+ goto stop_mode_failed;
+ }
+
+ if (dwmac->ops->set_intf_mode) {
+ ret = dwmac->ops->set_intf_mode(plat_dat);
+ if (ret)
+ goto intf_mode_failed;
+ }
+
+ return 0;
+
+intf_mode_failed:
+stop_mode_failed:
+ clk_disable_unprepare(dwmac->clk_tx);
+clk_tx_en_failed:
+ clk_disable_unprepare(dwmac->clk_mem);
+clk_mem_failed:
+ pm_runtime_put_noidle(&pdev->dev);
+ return ret;
+}
+
+static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct imx_priv_data *dwmac = priv;
+ struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat;
+ int ret;
+
+ if (dwmac->ops->set_stop_mode) {
+ ret = dwmac->ops->set_stop_mode(plat_dat, true);
+ if (ret) {
+ dev_err(dwmac->dev, "enter stop mode failed %d\n", ret);
+ return;
+ }
+ }
+
+ if (dwmac->clk_tx)
+ clk_disable_unprepare(dwmac->clk_tx);
+ clk_disable_unprepare(dwmac->clk_mem);
+ pm_runtime_put(&pdev->dev);
+}
+
+static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
+{
+ struct imx_priv_data *dwmac = priv;
+ struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat;
+ unsigned long rate;
+ int err;
+
+ if (dwmac->ops->mac_txclk_auto_adj ||
+ (plat_dat->interface == PHY_INTERFACE_MODE_RMII) ||
+ (plat_dat->interface == PHY_INTERFACE_MODE_MII))
+ return;
+
+ switch (speed) {
+ case SPEED_1000:
+ rate = 125000000;
+ break;
+ case SPEED_100:
+ rate = 25000000;
+ break;
+ case SPEED_10:
+ rate = 2500000;
+ break;
+ default:
+ dev_err(dwmac->dev, "invalid speed %u\n", speed);
+ return;
+ }
+
+ err = clk_set_rate(dwmac->clk_tx, rate);
+ if (err < 0)
+ dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
+}
+
+static int
+imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ int err = 0;
+
+ if (of_get_property(np, "snps,rmii_refclk_ext", NULL))
+ dwmac->rmii_refclk_ext = true;
+
+ dwmac->clk_tx = devm_clk_get(dev, "tx");
+ if (IS_ERR(dwmac->clk_tx)) {
+ dev_err(dev, "failed to get tx clock\n");
+ return PTR_ERR(dwmac->clk_tx);
+ }
+
+ dwmac->clk_mem = NULL;
+ if (of_machine_is_compatible("fsl,imx8dxl")) {
+ dwmac->clk_mem = devm_clk_get(dev, "mem");
+ if (IS_ERR(dwmac->clk_mem)) {
+ dev_err(dev, "failed to get mem clock\n");
+ return PTR_ERR(dwmac->clk_mem);
+ }
+ }
+
+ if (of_machine_is_compatible("fsl,imx8mp")) {
+ /* Binding doc describes the propety:
+ is required by i.MX8MP.
+ is optinoal for i.MX8DXL.
+ */
+ dwmac->intf_regmap = syscon_regmap_lookup_by_phandle(np, "intf_mode");
+ if (IS_ERR(dwmac->intf_regmap))
+ return PTR_ERR(dwmac->intf_regmap);
+
+ err = of_property_read_u32_index(np, "intf_mode", 1, &dwmac->intf_reg_off);
+ if (err) {
+ dev_err(dev, "Can't get intf mode reg offset (%d)\n", err);
+ return err;
+ }
+ }
+
+ return err;
+}
+
+static int imx_dwmac_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct imx_priv_data *dwmac;
+ const struct imx_dwmac_ops *data;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return PTR_ERR(dwmac);
+
+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+ if (IS_ERR(plat_dat))
+ return PTR_ERR(plat_dat);
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to get match data\n");
+ ret = -EINVAL;
+ goto err_match_data;
+ }
+
+ dwmac->ops = data;
+ dwmac->dev = &pdev->dev;
+
+ ret = imx_dwmac_parse_dt(dwmac, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse OF data\n");
+ goto err_parse_dt;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev,
+ DMA_BIT_MASK(dwmac->ops->addr_width));
+ if (ret) {
+ dev_err(&pdev->dev, "DMA mask set failed\n");
+ goto err_dma_mask;
+ }
+
+ plat_dat->init = imx_dwmac_init;
+ plat_dat->exit = imx_dwmac_exit;
+ plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
+ plat_dat->bsp_priv = dwmac;
+ dwmac->plat_dat = plat_dat;
+
+ /* enable runtime pm to turn off power domain when netif down */
+ pm_runtime_enable(&pdev->dev);
+
+ ret = imx_dwmac_init(pdev, dwmac);
+ if (ret)
+ goto err_dwmac_init;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_drv_probe;
+
+ return 0;
+
+err_drv_probe:
+ imx_dwmac_exit(pdev, plat_dat->bsp_priv);
+err_dwmac_init:
+ pm_runtime_disable(&pdev->dev);
+err_dma_mask:
+err_parse_dt:
+err_match_data:
+ stmmac_remove_config_dt(pdev, plat_dat);
+ return ret;
+}
+
+int imx_dwmac_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ return stmmac_pltfr_remove(pdev);
+}
+
+static struct imx_dwmac_ops imx8mp_dwmac_data = {
+ .addr_width = 34,
+ .mac_txclk_auto_adj = false,
+ .set_intf_mode = imx8mp_set_intf_mode,
+ .set_stop_mode = imx8mp_set_stop_mode,
+};
+
+static struct imx_dwmac_ops imx8dxl_dwmac_data = {
+ .addr_width = 32, /* for bringup */
+ .mac_txclk_auto_adj = true,
+ .set_intf_mode = imx8dxl_set_intf_mode,
+ .set_stop_mode = imx8dxl_set_stop_mode,
+};
+
+static const struct of_device_id imx_dwmac_match[] = {
+ { .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data },
+ { .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, imx_dwmac_match);
+
+static struct platform_driver imx_dwmac_driver = {
+ .probe = imx_dwmac_probe,
+ .remove = imx_dwmac_remove,
+ .driver = {
+ .name = "imx-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = imx_dwmac_match,
+ },
+};
+module_platform_driver(imx_dwmac_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 2f6258ca9515..a656920e0aac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -337,14 +337,30 @@ static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw,
}
}
-static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx)
{
- writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN);
+ u32 value = readl(ioaddr + EMAC_INT_EN);
+
+ if (rx)
+ value |= EMAC_RX_INT;
+ if (tx)
+ value |= EMAC_TX_INT;
+
+ writel(value, ioaddr + EMAC_INT_EN);
}
-static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx)
{
- writel(0, ioaddr + EMAC_INT_EN);
+ u32 value = readl(ioaddr + EMAC_INT_EN);
+
+ if (rx)
+ value &= ~EMAC_RX_INT;
+ if (tx)
+ value &= ~EMAC_TX_INT;
+
+ writel(value, ioaddr + EMAC_INT_EN);
}
static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 89a3420eba42..18789fec7ffd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -14,6 +14,7 @@
/* MAC registers */
#define GMAC_CONFIG 0x00000000
+#define GMAC_EXT_CONFIG 0x00000004
#define GMAC_PACKET_FILTER 0x00000008
#define GMAC_HASH_TAB(x) (0x10 + (x) * 4)
#define GMAC_VLAN_TAG 0x00000050
@@ -43,6 +44,10 @@
#define GMAC_ARP_ADDR 0x00000210
#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8)
#define GMAC_ADDR_LOW(reg) (0x304 + reg * 8)
+#define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30)
+#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30)
+#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30)
+#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30)
/* RX Queues Routing */
#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
@@ -59,6 +64,8 @@
#define GMAC_RXQCTRL_MCBCQEN_SHIFT 20
#define GMAC_RXQCTRL_TACPQE BIT(21)
#define GMAC_RXQCTRL_TACPQE_SHIFT 21
+#define GMAC_RXQCTRL_FPRQ GENMASK(26, 24)
+#define GMAC_RXQCTRL_FPRQ_SHIFT 24
/* MAC Packet Filtering */
#define GMAC_PACKET_FILTER_PR BIT(0)
@@ -67,6 +74,7 @@
#define GMAC_PACKET_FILTER_PCF BIT(7)
#define GMAC_PACKET_FILTER_HPF BIT(10)
#define GMAC_PACKET_FILTER_VTFE BIT(16)
+#define GMAC_PACKET_FILTER_IPFE BIT(20)
#define GMAC_MAX_PERFECT_ADDRESSES 128
@@ -170,6 +178,8 @@ enum power_event {
#define GMAC_CONFIG_SARC GENMASK(30, 28)
#define GMAC_CONFIG_SARC_SHIFT 28
#define GMAC_CONFIG_IPC BIT(27)
+#define GMAC_CONFIG_IPG GENMASK(26, 24)
+#define GMAC_CONFIG_IPG_SHIFT 24
#define GMAC_CONFIG_2K BIT(22)
#define GMAC_CONFIG_ACS BIT(20)
#define GMAC_CONFIG_BE BIT(18)
@@ -177,12 +187,21 @@ enum power_event {
#define GMAC_CONFIG_JE BIT(16)
#define GMAC_CONFIG_PS BIT(15)
#define GMAC_CONFIG_FES BIT(14)
+#define GMAC_CONFIG_FES_SHIFT 14
#define GMAC_CONFIG_DM BIT(13)
#define GMAC_CONFIG_LM BIT(12)
#define GMAC_CONFIG_DCRS BIT(9)
#define GMAC_CONFIG_TE BIT(1)
#define GMAC_CONFIG_RE BIT(0)
+/* MAC extended config */
+#define GMAC_CONFIG_EIPG GENMASK(29, 25)
+#define GMAC_CONFIG_EIPG_SHIFT 25
+#define GMAC_CONFIG_EIPG_EN BIT(24)
+#define GMAC_CONFIG_HDSMS GENMASK(22, 20)
+#define GMAC_CONFIG_HDSMS_SHIFT 20
+#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT)
+
/* MAC HW features0 bitmap */
#define GMAC_HW_FEAT_SAVLANINS BIT(27)
#define GMAC_HW_FEAT_ADDMAC BIT(18)
@@ -202,9 +221,11 @@ enum power_event {
#define GMAC_HW_FEAT_MIISEL BIT(0)
/* MAC HW features1 bitmap */
+#define GMAC_HW_FEAT_L3L4FNUM GENMASK(30, 27)
#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24)
#define GMAC_HW_FEAT_AVSEL BIT(20)
#define GMAC_HW_TSOEN BIT(18)
+#define GMAC_HW_FEAT_SPHEN BIT(17)
#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6)
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
@@ -217,6 +238,10 @@ enum power_event {
/* MAC HW features3 bitmap */
#define GMAC_HW_FEAT_ASP GENMASK(29, 28)
+#define GMAC_HW_FEAT_FPESEL BIT(26)
+#define GMAC_HW_FEAT_ESTWID GENMASK(21, 20)
+#define GMAC_HW_FEAT_ESTDEP GENMASK(19, 17)
+#define GMAC_HW_FEAT_ESTSEL BIT(16)
#define GMAC_HW_FEAT_FRPES GENMASK(14, 13)
#define GMAC_HW_FEAT_FRPBS GENMASK(12, 11)
#define GMAC_HW_FEAT_FRPSEL BIT(10)
@@ -227,6 +252,21 @@ enum power_event {
#define GMAC_HI_DCS_SHIFT 16
#define GMAC_HI_REG_AE BIT(31)
+/* L3/L4 Filters regs */
+#define GMAC_L4DPIM0 BIT(21)
+#define GMAC_L4DPM0 BIT(20)
+#define GMAC_L4SPIM0 BIT(19)
+#define GMAC_L4SPM0 BIT(18)
+#define GMAC_L4PEN0 BIT(16)
+#define GMAC_L3DAIM0 BIT(5)
+#define GMAC_L3DAM0 BIT(4)
+#define GMAC_L3SAIM0 BIT(3)
+#define GMAC_L3SAM0 BIT(2)
+#define GMAC_L3PEN0 BIT(0)
+#define GMAC_L4DP0 GENMASK(31, 16)
+#define GMAC_L4DP0_SHIFT 16
+#define GMAC_L4SP0 GENMASK(15, 0)
+
/* MTL registers */
#define MTL_OPERATION_MODE 0x00000c00
#define MTL_FRPE BIT(15)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 66e60c7e9850..16d94e2d284a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -799,6 +799,106 @@ static void dwmac4_set_arp_offload(struct mac_device_info *hw, bool en,
writel(value, ioaddr + GMAC_CONFIG);
}
+static int dwmac4_config_l3_filter(struct mac_device_info *hw, u32 filter_no,
+ bool en, bool ipv6, bool sa, bool inv,
+ u32 match)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value;
+
+ value = readl(ioaddr + GMAC_PACKET_FILTER);
+ value |= GMAC_PACKET_FILTER_IPFE;
+ writel(value, ioaddr + GMAC_PACKET_FILTER);
+
+ value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no));
+
+ /* For IPv6 not both SA/DA filters can be active */
+ if (ipv6) {
+ value |= GMAC_L3PEN0;
+ value &= ~(GMAC_L3SAM0 | GMAC_L3SAIM0);
+ value &= ~(GMAC_L3DAM0 | GMAC_L3DAIM0);
+ if (sa) {
+ value |= GMAC_L3SAM0;
+ if (inv)
+ value |= GMAC_L3SAIM0;
+ } else {
+ value |= GMAC_L3DAM0;
+ if (inv)
+ value |= GMAC_L3DAIM0;
+ }
+ } else {
+ value &= ~GMAC_L3PEN0;
+ if (sa) {
+ value |= GMAC_L3SAM0;
+ if (inv)
+ value |= GMAC_L3SAIM0;
+ } else {
+ value |= GMAC_L3DAM0;
+ if (inv)
+ value |= GMAC_L3DAIM0;
+ }
+ }
+
+ writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no));
+
+ if (sa) {
+ writel(match, ioaddr + GMAC_L3_ADDR0(filter_no));
+ } else {
+ writel(match, ioaddr + GMAC_L3_ADDR1(filter_no));
+ }
+
+ if (!en)
+ writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no));
+
+ return 0;
+}
+
+static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
+ bool en, bool udp, bool sa, bool inv,
+ u32 match)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value;
+
+ value = readl(ioaddr + GMAC_PACKET_FILTER);
+ value |= GMAC_PACKET_FILTER_IPFE;
+ writel(value, ioaddr + GMAC_PACKET_FILTER);
+
+ value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no));
+ if (udp) {
+ value |= GMAC_L4PEN0;
+ } else {
+ value &= ~GMAC_L4PEN0;
+ }
+
+ value &= ~(GMAC_L4SPM0 | GMAC_L4SPIM0);
+ value &= ~(GMAC_L4DPM0 | GMAC_L4DPIM0);
+ if (sa) {
+ value |= GMAC_L4SPM0;
+ if (inv)
+ value |= GMAC_L4SPIM0;
+ } else {
+ value |= GMAC_L4DPM0;
+ if (inv)
+ value |= GMAC_L4DPIM0;
+ }
+
+ writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no));
+
+ if (sa) {
+ value = match & GMAC_L4SP0;
+ } else {
+ value = (match << GMAC_L4DP0_SHIFT) & GMAC_L4DP0;
+ }
+
+ writel(value, ioaddr + GMAC_L4_ADDR(filter_no));
+
+ if (!en)
+ writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no));
+
+ return 0;
+}
+
const struct stmmac_ops dwmac4_ops = {
.core_init = dwmac4_core_init,
.set_mac = stmmac_set_mac,
@@ -828,11 +928,14 @@ const struct stmmac_ops dwmac4_ops = {
.pcs_get_adv_lp = dwmac4_get_adv_lp,
.debug = dwmac4_debug,
.set_filter = dwmac4_set_filter,
+ .flex_pps_config = dwmac5_flex_pps_config,
.set_mac_loopback = dwmac4_set_mac_loopback,
.update_vlan_hash = dwmac4_update_vlan_hash,
.sarc_configure = dwmac4_sarc_configure,
.enable_vlan = dwmac4_enable_vlan,
.set_arp_offload = dwmac4_set_arp_offload,
+ .config_l3_filter = dwmac4_config_l3_filter,
+ .config_l4_filter = dwmac4_config_l4_filter,
};
const struct stmmac_ops dwmac410_ops = {
@@ -869,6 +972,10 @@ const struct stmmac_ops dwmac410_ops = {
.sarc_configure = dwmac4_sarc_configure,
.enable_vlan = dwmac4_enable_vlan,
.set_arp_offload = dwmac4_set_arp_offload,
+ .config_l3_filter = dwmac4_config_l3_filter,
+ .config_l4_filter = dwmac4_config_l4_filter,
+ .est_configure = dwmac5_est_configure,
+ .fpe_configure = dwmac5_fpe_configure,
};
const struct stmmac_ops dwmac510_ops = {
@@ -910,6 +1017,10 @@ const struct stmmac_ops dwmac510_ops = {
.sarc_configure = dwmac4_sarc_configure,
.enable_vlan = dwmac4_enable_vlan,
.set_arp_offload = dwmac4_set_arp_offload,
+ .config_l3_filter = dwmac4_config_l3_filter,
+ .config_l4_filter = dwmac4_config_l4_filter,
+ .est_configure = dwmac5_est_configure,
+ .fpe_configure = dwmac5_fpe_configure,
};
int dwmac4_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 15eb1abba91d..3e14da69f378 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -83,9 +83,10 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(rdes3 & RDES3_OWN))
return dma_own;
- /* Verify rx error by looking at the last segment. */
- if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR)))
+ if (unlikely(rdes3 & RDES3_CONTEXT_DESCRIPTOR))
return discard_frame;
+ if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR)))
+ return rx_not_ls;
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
if (unlikely(rdes3 & RDES3_GIANT_PACKET))
@@ -188,7 +189,7 @@ static void dwmac4_set_tx_owner(struct dma_desc *p)
static void dwmac4_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
{
- p->des3 = cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
+ p->des3 |= cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
if (!disable_rx_ic)
p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN);
@@ -431,8 +432,8 @@ static void dwmac4_get_addr(struct dma_desc *p, unsigned int *addr)
static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
{
- p->des0 = cpu_to_le32(addr);
- p->des1 = 0;
+ p->des0 = cpu_to_le32(lower_32_bits(addr));
+ p->des1 = cpu_to_le32(upper_32_bits(addr));
}
static void dwmac4_clear(struct dma_desc *p)
@@ -492,6 +493,18 @@ static void dwmac4_set_vlan(struct dma_desc *p, u32 type)
p->des2 |= cpu_to_le32(type & TDES2_VLAN_TAG_MASK);
}
+static int dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len)
+{
+ *len = le32_to_cpu(p->des2) & RDES2_HL;
+ return 0;
+}
+
+static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr)
+{
+ p->des2 = cpu_to_le32(lower_32_bits(addr));
+ p->des3 = cpu_to_le32(upper_32_bits(addr) | RDES3_BUFFER2_VALID_ADDR);
+}
+
const struct stmmac_desc_ops dwmac4_desc_ops = {
.tx_status = dwmac4_wrback_get_tx_status,
.rx_status = dwmac4_wrback_get_rx_status,
@@ -519,6 +532,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
.set_sarc = dwmac4_set_sarc,
.set_vlan_tag = dwmac4_set_vlan_tag,
.set_vlan = dwmac4_set_vlan,
+ .get_rx_header_len = dwmac4_get_rx_header_len,
+ .set_sec_addr = dwmac4_set_sec_addr,
};
const struct stmmac_mode_ops dwmac4_ring_mode_ops = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
index 0d7b3bbcd5a7..6d92109dc9aa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
@@ -109,6 +109,7 @@
#define RDES2_L4_FILTER_MATCH BIT(28)
#define RDES2_L3_L4_FILT_NB_MATCH_MASK GENMASK(27, 26)
#define RDES2_L3_L4_FILT_NB_MATCH_SHIFT 26
+#define RDES2_HL GENMASK(9, 0)
/* RDES3 (write back format) */
#define RDES3_PACKET_SIZE_MASK GENMASK(14, 0)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 0d993f4b701c..47b1204cf6a3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -80,6 +80,7 @@ static void dwmac4_dma_init_rx_chan(void __iomem *ioaddr,
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
+ writel(upper_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_HADDR(chan));
}
static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
@@ -98,6 +99,7 @@ static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
+ writel(upper_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_HADDR(chan));
}
static void dwmac4_dma_init_channel(void __iomem *ioaddr,
@@ -149,7 +151,7 @@ static void dwmac4_dma_init(void __iomem *ioaddr,
if (dma_cfg->aal)
value |= DMA_SYS_BUS_AAL;
- writel(value, ioaddr + DMA_SYS_BUS_MODE);
+ writel(value | DMA_SYS_EAME, ioaddr + DMA_SYS_BUS_MODE);
}
static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
@@ -258,19 +260,9 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
rfa = 0x01; /* Full-1.5K */
break;
- case 8192:
- rfd = 0x06; /* Full-4K */
- rfa = 0x0a; /* Full-6K */
- break;
-
- case 16384:
- rfd = 0x06; /* Full-4K */
- rfa = 0x12; /* Full-10K */
- break;
-
default:
- rfd = 0x06; /* Full-4K */
- rfa = 0x1e; /* Full-16K */
+ rfd = 0x07; /* Full-4.5K */
+ rfa = 0x04; /* Full-3K */
break;
}
@@ -365,9 +357,11 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature1 */
hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
+ dma_cap->l3l4fnum = (hw_cap & GMAC_HW_FEAT_L3L4FNUM) >> 27;
dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24;
dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
+ dma_cap->sphen = (hw_cap & GMAC_HW_FEAT_SPHEN) >> 17;
/* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
* shifting and store the sizes in bytes.
*/
@@ -396,6 +390,10 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
/* 5.10 Features */
dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
+ dma_cap->fpesel = (hw_cap & GMAC_HW_FEAT_FPESEL) >> 26;
+ dma_cap->estwid = (hw_cap & GMAC_HW_FEAT_ESTWID) >> 20;
+ dma_cap->estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP) >> 17;
+ dma_cap->estsel = (hw_cap & GMAC_HW_FEAT_ESTSEL) >> 16;
dma_cap->frpes = (hw_cap & GMAC_HW_FEAT_FRPES) >> 13;
dma_cap->frpbs = (hw_cap & GMAC_HW_FEAT_FRPBS) >> 11;
dma_cap->frpsel = (hw_cap & GMAC_HW_FEAT_FRPSEL) >> 10;
@@ -443,6 +441,22 @@ static void dwmac4_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
}
+static void dwmac4_enable_sph(void __iomem *ioaddr, bool en, u32 chan)
+{
+ u32 value = readl(ioaddr + GMAC_EXT_CONFIG);
+
+ value &= ~GMAC_CONFIG_HDSMS;
+ value |= GMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
+ writel(value, ioaddr + GMAC_EXT_CONFIG);
+
+ value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+ if (en)
+ value |= DMA_CONTROL_SPH;
+ else
+ value &= ~DMA_CONTROL_SPH;
+ writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+}
+
const struct stmmac_dma_ops dwmac4_dma_ops = {
.reset = dwmac4_dma_reset,
.init = dwmac4_dma_init,
@@ -469,6 +483,7 @@ const struct stmmac_dma_ops dwmac4_dma_ops = {
.enable_tso = dwmac4_enable_tso,
.qmode = dwmac4_qmode,
.set_bfsize = dwmac4_set_bfsize,
+ .enable_sph = dwmac4_enable_sph,
};
const struct stmmac_dma_ops dwmac410_dma_ops = {
@@ -497,4 +512,5 @@ const struct stmmac_dma_ops dwmac410_dma_ops = {
.enable_tso = dwmac4_enable_tso,
.qmode = dwmac4_qmode,
.set_bfsize = dwmac4_set_bfsize,
+ .enable_sph = dwmac4_enable_sph,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index b66da0237d2a..7e387ceda958 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -65,6 +65,7 @@
#define DMA_SYS_BUS_MB BIT(14)
#define DMA_AXI_1KBBE BIT(13)
#define DMA_SYS_BUS_AAL BIT(12)
+#define DMA_SYS_EAME BIT(11)
#define DMA_AXI_BLEN256 BIT(7)
#define DMA_AXI_BLEN128 BIT(6)
#define DMA_AXI_BLEN64 BIT(5)
@@ -91,7 +92,9 @@
#define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x)
#define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4)
#define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8)
+#define DMA_CHAN_TX_BASE_HADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x10)
#define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14)
+#define DMA_CHAN_RX_BASE_HADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x18)
#define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c)
#define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20)
#define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28)
@@ -107,6 +110,7 @@
#define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x60)
/* DMA Control X */
+#define DMA_CONTROL_SPH BIT(24)
#define DMA_CONTROL_MSS_MASK GENMASK(13, 0)
/* DMA Tx Channel X Control register defines */
@@ -164,6 +168,8 @@
/* DMA default interrupt mask for 4.00 */
#define DMA_CHAN_INTR_DEFAULT_MASK (DMA_CHAN_INTR_NORMAL | \
DMA_CHAN_INTR_ABNORMAL)
+#define DMA_CHAN_INTR_DEFAULT_RX (DMA_CHAN_INTR_ENA_RIE)
+#define DMA_CHAN_INTR_DEFAULT_TX (DMA_CHAN_INTR_ENA_TIE)
#define DMA_CHAN_INTR_NORMAL_4_10 (DMA_CHAN_INTR_ENA_NIE_4_10 | \
DMA_CHAN_INTR_ENA_RIE | \
@@ -174,6 +180,8 @@
/* DMA default interrupt mask for 4.10a */
#define DMA_CHAN_INTR_DEFAULT_MASK_4_10 (DMA_CHAN_INTR_NORMAL_4_10 | \
DMA_CHAN_INTR_ABNORMAL_4_10)
+#define DMA_CHAN_INTR_DEFAULT_RX_4_10 (DMA_CHAN_INTR_ENA_RIE)
+#define DMA_CHAN_INTR_DEFAULT_TX_4_10 (DMA_CHAN_INTR_ENA_TIE)
/* channel 0 specific fields */
#define DMA_CHAN0_DBG_STAT_TPS GENMASK(15, 12)
@@ -182,9 +190,10 @@
#define DMA_CHAN0_DBG_STAT_RPS_SHIFT 8
int dwmac4_dma_reset(void __iomem *ioaddr);
-void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan);
+void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index afdea015f4b4..9610d4444a68 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -19,7 +19,7 @@ int dwmac4_dma_reset(void __iomem *ioaddr)
/* DMA SW reset */
value |= DMA_BUS_MODE_SFT_RESET;
writel(value, ioaddr + DMA_BUS_MODE);
- limit = 10;
+ limit = 100;
while (limit--) {
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
break;
@@ -93,21 +93,52 @@ void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
}
-void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
- writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr +
- DMA_CHAN_INTR_ENA(chan));
+ u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+ if (rx)
+ value |= DMA_CHAN_INTR_DEFAULT_RX;
+ if (tx)
+ value |= DMA_CHAN_INTR_DEFAULT_TX;
+
+ writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
-void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
- writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
- ioaddr + DMA_CHAN_INTR_ENA(chan));
+ u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+ if (rx)
+ value |= DMA_CHAN_INTR_DEFAULT_RX_4_10;
+ if (tx)
+ value |= DMA_CHAN_INTR_DEFAULT_TX_4_10;
+
+ writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
-void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
- writel(0, ioaddr + DMA_CHAN_INTR_ENA(chan));
+ u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+ if (rx)
+ value &= ~DMA_CHAN_INTR_DEFAULT_RX;
+ if (tx)
+ value &= ~DMA_CHAN_INTR_DEFAULT_TX;
+
+ writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
+void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
+{
+ u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+ if (rx)
+ value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10;
+ if (tx)
+ value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10;
+
+ writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
int dwmac4_dma_interrupt(void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index e436fa160c7d..e3c9f39d0e58 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -550,3 +550,123 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
writel(val, ioaddr + MAC_PPS_CONTROL);
return 0;
}
+
+static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+ u32 ctrl;
+
+ writel(val, ioaddr + MTL_EST_GCL_DATA);
+
+ ctrl = (reg << ADDR_SHIFT);
+ ctrl |= gcl ? 0 : GCRR;
+
+ writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+ ctrl |= SRWO;
+ writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
+
+ return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
+ ctrl, !(ctrl & SRWO), 100, 5000);
+}
+
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+ unsigned int ptp_rate)
+{
+ u32 speed, total_offset, offset, ctrl, ctr_low;
+ u32 extcfg = readl(ioaddr + GMAC_EXT_CONFIG);
+ u32 mac_cfg = readl(ioaddr + GMAC_CONFIG);
+ int i, ret = 0x0;
+ u64 total_ctr;
+
+ if (extcfg & GMAC_CONFIG_EIPG_EN) {
+ offset = (extcfg & GMAC_CONFIG_EIPG) >> GMAC_CONFIG_EIPG_SHIFT;
+ offset = 104 + (offset * 8);
+ } else {
+ offset = (mac_cfg & GMAC_CONFIG_IPG) >> GMAC_CONFIG_IPG_SHIFT;
+ offset = 96 - (offset * 8);
+ }
+
+ speed = mac_cfg & (GMAC_CONFIG_PS | GMAC_CONFIG_FES);
+ speed = speed >> GMAC_CONFIG_FES_SHIFT;
+
+ switch (speed) {
+ case 0x0:
+ offset = offset * 1000; /* 1G */
+ break;
+ case 0x1:
+ offset = offset * 400; /* 2.5G */
+ break;
+ case 0x2:
+ offset = offset * 100000; /* 10M */
+ break;
+ case 0x3:
+ offset = offset * 10000; /* 100M */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ offset = offset / 1000;
+
+ ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
+ ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
+ ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
+ ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
+ if (ret)
+ return ret;
+
+ total_offset = 0;
+ for (i = 0; i < cfg->gcl_size; i++) {
+ ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i] + offset, true);
+ if (ret)
+ return ret;
+
+ total_offset += offset;
+ }
+
+ total_ctr = cfg->ctr[0] + cfg->ctr[1] * 1000000000;
+ total_ctr += total_offset;
+
+ ctr_low = do_div(total_ctr, 1000000000);
+
+ ret |= dwmac5_est_write(ioaddr, CTR_LOW, ctr_low, false);
+ ret |= dwmac5_est_write(ioaddr, CTR_HIGH, total_ctr, false);
+ if (ret)
+ return ret;
+
+ ctrl = readl(ioaddr + MTL_EST_CONTROL);
+ ctrl &= ~PTOV;
+ ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
+ if (cfg->enable)
+ ctrl |= EEST | SSWL;
+ else
+ ctrl &= ~EEST;
+
+ writel(ctrl, ioaddr + MTL_EST_CONTROL);
+ return 0;
+}
+
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+ bool enable)
+{
+ u32 value;
+
+ if (!enable) {
+ value = readl(ioaddr + MAC_FPE_CTRL_STS);
+
+ value &= ~EFPE;
+
+ writel(value, ioaddr + MAC_FPE_CTRL_STS);
+
+ return;
+ }
+
+ value = readl(ioaddr + GMAC_RXQ_CTRL1);
+ value &= ~GMAC_RXQCTRL_FPRQ;
+ value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
+ writel(value, ioaddr + GMAC_RXQ_CTRL1);
+
+ value = readl(ioaddr + MAC_FPE_CTRL_STS);
+ value |= EFPE;
+ writel(value, ioaddr + MAC_FPE_CTRL_STS);
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 23fecf68f781..3e8faa96b4d4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -11,6 +11,9 @@
#define PRTYEN BIT(1)
#define TMOUTEN BIT(0)
+#define MAC_FPE_CTRL_STS 0x00000234
+#define EFPE BIT(0)
+
#define MAC_PPS_CONTROL 0x00000b70
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
#define PPS_MINIDX(x) ((x) * 8)
@@ -30,6 +33,23 @@
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
+#define MTL_EST_CONTROL 0x00000c50
+#define PTOV GENMASK(31, 24)
+#define PTOV_SHIFT 24
+#define SSWL BIT(1)
+#define EEST BIT(0)
+#define MTL_EST_GCL_CONTROL 0x00000c80
+#define BTR_LOW 0x0
+#define BTR_HIGH 0x1
+#define CTR_LOW 0x2
+#define CTR_HIGH 0x3
+#define TER 0x4
+#define LLR 0x5
+#define ADDR_SHIFT 8
+#define GCRR BIT(2)
+#define SRWO BIT(0)
+#define MTL_EST_GCL_DATA 0x00000c84
+
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
#define RXPI BIT(31)
#define NPE GENMASK(23, 16)
@@ -83,5 +103,9 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags);
+int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+ unsigned int ptp_rate);
+void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+ bool enable);
#endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 292b880f3f9f..e5dbd0bc257e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -96,6 +96,8 @@
/* DMA default interrupt mask */
#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+#define DMA_INTR_DEFAULT_RX (DMA_INTR_ENA_RIE)
+#define DMA_INTR_DEFAULT_TX (DMA_INTR_ENA_TIE)
/* DMA Status register defines */
#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
@@ -130,8 +132,8 @@
#define NUM_DWMAC1000_DMA_REGS 23
void dwmac_enable_dma_transmission(void __iomem *ioaddr);
-void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan);
-void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan);
+void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
+void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 1bc25aa86dbd..688d36095333 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -37,14 +37,28 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr)
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
}
-void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
- writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+ u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+ if (rx)
+ value |= DMA_INTR_DEFAULT_RX;
+ if (tx)
+ value |= DMA_INTR_DEFAULT_TX;
+
+ writel(value, ioaddr + DMA_INTR_ENA);
}
-void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
- writel(0, ioaddr + DMA_INTR_ENA);
+ u32 value = readl(ioaddr + DMA_INTR_ENA);
+
+ if (rx)
+ value &= ~DMA_INTR_DEFAULT_RX;
+ if (tx)
+ value &= ~DMA_INTR_DEFAULT_TX;
+
+ writel(value, ioaddr + DMA_INTR_ENA);
}
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index ff751ab3d765..64d13e50e403 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -73,6 +73,9 @@
#define XGMAC_RXQ_CTRL0 0x000000a0
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
+#define XGMAC_RXQ_CTRL1 0x000000a4
+#define XGMAC_RQ GENMASK(7, 4)
+#define XGMAC_RQ_SHIFT 4
#define XGMAC_RXQ_CTRL2 0x000000a8
#define XGMAC_RXQ_CTRL3 0x000000ac
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
@@ -136,6 +139,10 @@
#define XGMAC_HWFEAT_TXQCNT GENMASK(9, 6)
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
#define XGMAC_HW_FEATURE3 0x00000128
+#define XGMAC_HWFEAT_FPESEL BIT(26)
+#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
+#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
+#define XGMAC_HWFEAT_ESTSEL BIT(19)
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
#define XGMAC_HWFEAT_DVLAN BIT(13)
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
@@ -148,6 +155,8 @@
#define XGMAC_MDIO_ADDR 0x00000200
#define XGMAC_MDIO_DATA 0x00000204
#define XGMAC_MDIO_C22P 0x00000220
+#define XGMAC_FPE_CTRL_STS 0x00000280
+#define XGMAC_EFPE BIT(0)
#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8)
#define XGMAC_ADDR_MAX 32
#define XGMAC_AE BIT(31)
@@ -237,6 +246,22 @@
#define XGMAC_TC_PRTY_MAP1 0x00001044
#define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8)
#define XGMAC_PSTC_SHIFT(x) ((x) * 8)
+#define XGMAC_MTL_EST_CONTROL 0x00001050
+#define XGMAC_PTOV GENMASK(31, 23)
+#define XGMAC_PTOV_SHIFT 23
+#define XGMAC_SSWL BIT(1)
+#define XGMAC_EEST BIT(0)
+#define XGMAC_MTL_EST_GCL_CONTROL 0x00001080
+#define XGMAC_BTR_LOW 0x0
+#define XGMAC_BTR_HIGH 0x1
+#define XGMAC_CTR_LOW 0x2
+#define XGMAC_CTR_HIGH 0x3
+#define XGMAC_TER 0x4
+#define XGMAC_LLR 0x5
+#define XGMAC_ADDR_SHIFT 8
+#define XGMAC_GCRR BIT(2)
+#define XGMAC_SRWO BIT(0)
+#define XGMAC_MTL_EST_GCL_DATA 0x00001084
#define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0
#define XGMAC_RXPI BIT(31)
#define XGMAC_NPE GENMASK(23, 16)
@@ -362,7 +387,9 @@
#define XGMAC_TBUE BIT(2)
#define XGMAC_TIE BIT(0)
#define XGMAC_DMA_INT_DEFAULT_EN (XGMAC_NIE | XGMAC_AIE | XGMAC_RBUE | \
- XGMAC_RIE | XGMAC_TBUE | XGMAC_TIE)
+ XGMAC_RIE | XGMAC_TIE)
+#define XGMAC_DMA_INT_DEFAULT_RX (XGMAC_RBUE | XGMAC_RIE)
+#define XGMAC_DMA_INT_DEFAULT_TX (XGMAC_TIE)
#define XGMAC_DMA_CH_Rx_WATCHDOG(x) (0x0000313c + (0x80 * (x)))
#define XGMAC_RWT GENMASK(7, 0)
#define XGMAC_DMA_CH_STATUS(x) (0x00003160 + (0x80 * (x)))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 070bd7d1ae4c..988a68731160 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -1344,6 +1344,80 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
writel(value, ioaddr + XGMAC_RX_CONFIG);
}
+static int dwxgmac3_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
+{
+ u32 ctrl;
+
+ writel(val, ioaddr + XGMAC_MTL_EST_GCL_DATA);
+
+ ctrl = (reg << XGMAC_ADDR_SHIFT);
+ ctrl |= gcl ? 0 : XGMAC_GCRR;
+
+ writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+ ctrl |= XGMAC_SRWO;
+ writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
+
+ return readl_poll_timeout_atomic(ioaddr + XGMAC_MTL_EST_GCL_CONTROL,
+ ctrl, !(ctrl & XGMAC_SRWO), 100, 5000);
+}
+
+static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
+ unsigned int ptp_rate)
+{
+ int i, ret = 0x0;
+ u32 ctrl;
+
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_LOW, cfg->btr[0], false);
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_HIGH, cfg->btr[1], false);
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_TER, cfg->ter, false);
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_LLR, cfg->gcl_size, false);
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_LOW, cfg->ctr[0], false);
+ ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_HIGH, cfg->ctr[1], false);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < cfg->gcl_size; i++) {
+ ret = dwxgmac3_est_write(ioaddr, i, cfg->gcl[i], true);
+ if (ret)
+ return ret;
+ }
+
+ ctrl = readl(ioaddr + XGMAC_MTL_EST_CONTROL);
+ ctrl &= ~XGMAC_PTOV;
+ ctrl |= ((1000000000 / ptp_rate) * 9) << XGMAC_PTOV_SHIFT;
+ if (cfg->enable)
+ ctrl |= XGMAC_EEST | XGMAC_SSWL;
+ else
+ ctrl &= ~XGMAC_EEST;
+
+ writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL);
+ return 0;
+}
+
+static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq,
+ u32 num_rxq, bool enable)
+{
+ u32 value;
+
+ if (!enable) {
+ value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+
+ value &= ~XGMAC_EFPE;
+
+ writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+ }
+
+ value = readl(ioaddr + XGMAC_RXQ_CTRL1);
+ value &= ~XGMAC_RQ;
+ value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
+ writel(value, ioaddr + XGMAC_RXQ_CTRL1);
+
+ value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
+ value |= XGMAC_EFPE;
+ writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
+}
+
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,
@@ -1387,6 +1461,8 @@ const struct stmmac_ops dwxgmac210_ops = {
.config_l3_filter = dwxgmac2_config_l3_filter,
.config_l4_filter = dwxgmac2_config_l4_filter,
.set_arp_offload = dwxgmac2_set_arp_offload,
+ .est_configure = dwxgmac3_est_configure,
+ .fpe_configure = dwxgmac3_fpe_configure,
};
int dwxgmac2_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 4af7271cea56..ccbb029eab12 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -180,19 +180,9 @@ static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode,
rfa = 0x01; /* Full-1.5K */
break;
- case 8192:
- rfd = 0x06; /* Full-4K */
- rfa = 0x0a; /* Full-6K */
- break;
-
- case 16384:
- rfd = 0x06; /* Full-4K */
- rfa = 0x12; /* Full-10K */
- break;
-
default:
- rfd = 0x06; /* Full-4K */
- rfa = 0x1e; /* Full-16K */
+ rfd = 0x07; /* Full-4.5K */
+ rfa = 0x04; /* Full-3K */
break;
}
@@ -255,14 +245,30 @@ static void dwxgmac2_dma_tx_mode(void __iomem *ioaddr, int mode,
writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
}
-static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void dwxgmac2_enable_dma_irq(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx)
{
- writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+ u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+
+ if (rx)
+ value |= XGMAC_DMA_INT_DEFAULT_RX;
+ if (tx)
+ value |= XGMAC_DMA_INT_DEFAULT_TX;
+
+ writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
}
-static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+static void dwxgmac2_disable_dma_irq(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx)
{
- writel(0, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+ u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+
+ if (rx)
+ value &= ~XGMAC_DMA_INT_DEFAULT_RX;
+ if (tx)
+ value &= ~XGMAC_DMA_INT_DEFAULT_TX;
+
+ writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
}
static void dwxgmac2_dma_start_tx(void __iomem *ioaddr, u32 chan)
@@ -420,6 +426,10 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 3 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
+ dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
+ dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
+ dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
+ dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 9010d881b12e..eecb90d17970 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -187,8 +187,10 @@ struct stmmac_dma_ops {
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr);
void (*enable_dma_transmission) (void __iomem *ioaddr);
- void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan);
- void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan);
+ void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx);
+ void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan,
+ bool rx, bool tx);
void (*start_tx)(void __iomem *ioaddr, u32 chan);
void (*stop_tx)(void __iomem *ioaddr, u32 chan);
void (*start_rx)(void __iomem *ioaddr, u32 chan);
@@ -274,6 +276,7 @@ struct stmmac_safety_stats;
struct stmmac_tc_entry;
struct stmmac_pps_cfg;
struct stmmac_rss;
+struct stmmac_est;
/* Helpers to program the MAC core */
struct stmmac_ops {
@@ -371,6 +374,10 @@ struct stmmac_ops {
bool en, bool udp, bool sa, bool inv,
u32 match);
void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
+ int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
+ unsigned int ptp_rate);
+ void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
+ bool enable);
};
#define stmmac_core_init(__priv, __args...) \
@@ -457,6 +464,10 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, config_l4_filter, __args)
#define stmmac_set_arp_offload(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
+#define stmmac_est_configure(__priv, __args...) \
+ stmmac_do_callback(__priv, mac, est_configure, __args)
+#define stmmac_fpe_configure(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
@@ -514,6 +525,7 @@ struct stmmac_priv;
struct tc_cls_u32_offload;
struct tc_cbs_qopt_offload;
struct flow_cls_offload;
+struct tc_taprio_qopt_offload;
struct stmmac_tc_ops {
int (*init)(struct stmmac_priv *priv);
@@ -523,6 +535,8 @@ struct stmmac_tc_ops {
struct tc_cbs_qopt_offload *qopt);
int (*setup_cls)(struct stmmac_priv *priv,
struct flow_cls_offload *cls);
+ int (*setup_taprio)(struct stmmac_priv *priv,
+ struct tc_taprio_qopt_offload *qopt);
};
#define stmmac_tc_init(__priv, __args...) \
@@ -533,6 +547,8 @@ struct stmmac_tc_ops {
stmmac_do_callback(__priv, tc, setup_cbs, __args)
#define stmmac_tc_setup_cls(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_cls, __args)
+#define stmmac_tc_setup_taprio(__priv, __args...) \
+ stmmac_do_callback(__priv, tc, setup_taprio, __args)
struct stmmac_counters;
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
index 252cf48c5816..a57b0fa815ab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -119,6 +119,13 @@
#define MMC_RX_ICMP_GD_OCTETS 0x180
#define MMC_RX_ICMP_ERR_OCTETS 0x184
+#define MMC_TX_FPE_FRAG 0x1a8
+#define MMC_TX_HOLD_REQ 0x1ac
+#define MMC_RX_PKT_ASSEMBLY_ERR 0x1c8
+#define MMC_RX_PKT_SMD_ERR 0x1cc
+#define MMC_RX_PKT_ASSEMBLY_OK 0x1d0
+#define MMC_RX_FPE_FRAG 0x1d4
+
/* XGMAC MMC Registers */
#define MMC_XGMAC_TX_OCTET_GB 0x14
#define MMC_XGMAC_TX_PKT_GB 0x1c
@@ -315,6 +322,15 @@ static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
mmc->mmc_rx_tcp_err_octets += readl(mmcaddr + MMC_RX_TCP_ERR_OCTETS);
mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
+
+ mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_TX_FPE_FRAG);
+ mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_TX_HOLD_REQ);
+ mmc->mmc_rx_packet_assembly_err_cntr +=
+ readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_ERR);
+ mmc->mmc_rx_packet_smd_err_cntr += readl(mmcaddr + MMC_RX_PKT_SMD_ERR);
+ mmc->mmc_rx_packet_assembly_ok_cntr +=
+ readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_OK);
+ mmc->mmc_rx_fpe_fragment_cntr += readl(mmcaddr + MMC_RX_FPE_FRAG);
}
const struct stmmac_mmc_ops dwmac_mmc_ops = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index d993fc7e82c3..ee4c4a821808 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -88,6 +88,7 @@ struct stmmac_channel {
struct napi_struct rx_napi ____cacheline_aligned_in_smp;
struct napi_struct tx_napi ____cacheline_aligned_in_smp;
struct stmmac_priv *priv_data;
+ spinlock_t lock;
u32 index;
};
@@ -173,6 +174,7 @@ struct stmmac_priv {
struct stmmac_channel channel[STMMAC_CH_MAX];
int speed;
+ bool mdio_rst_after_resume;
unsigned int flow_ctrl;
unsigned int pause;
struct mii_bus *mii;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 10d28be73f45..5e42c07ae99c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -36,6 +36,7 @@
#endif /* CONFIG_DEBUG_FS */
#include <linux/net_tstamp.h>
#include <linux/phylink.h>
+#include <linux/udp.h>
#include <net/pkt_cls.h>
#include "stmmac_ptp.h"
#include "stmmac.h"
@@ -112,6 +113,27 @@ static void stmmac_exit_fs(struct net_device *dev);
#define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+static int stmmac_bus_clks_enable(struct stmmac_priv *priv, bool enabled)
+{
+ int ret = 0;
+
+ if (enabled) {
+ ret = clk_prepare_enable(priv->plat->stmmac_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(priv->plat->pclk);
+ if (ret) {
+ clk_disable_unprepare(priv->plat->stmmac_clk);
+ return ret;
+ }
+ } else {
+ clk_disable_unprepare(priv->plat->stmmac_clk);
+ clk_disable_unprepare(priv->plat->pclk);
+ }
+
+ return ret;
+}
+
/**
* stmmac_verify_args - verify the driver parameters.
* Description: it checks the driver parameters and set a default in case of
@@ -1953,7 +1975,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
/* We still have pending packets, let's call for a new scheduling */
if (tx_q->dirty_tx != tx_q->cur_tx)
- mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(10));
+ mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer));
__netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
@@ -1987,6 +2009,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
tx_q->cur_tx = 0;
tx_q->mss = 0;
netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, chan));
+ stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+ tx_q->dma_tx_phy, chan);
stmmac_start_tx_dma(priv, chan);
priv->dev->stats.tx_errors++;
@@ -2045,17 +2069,25 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan)
int status = stmmac_dma_interrupt_status(priv, priv->ioaddr,
&priv->xstats, chan);
struct stmmac_channel *ch = &priv->channel[chan];
+ unsigned long flags;
if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) {
if (napi_schedule_prep(&ch->rx_napi)) {
- stmmac_disable_dma_irq(priv, priv->ioaddr, chan);
+ spin_lock_irqsave(&ch->lock, flags);
+ stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+ spin_unlock_irqrestore(&ch->lock, flags);
__napi_schedule_irqoff(&ch->rx_napi);
- status |= handle_tx;
}
}
- if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use))
- napi_schedule_irqoff(&ch->tx_napi);
+ if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) {
+ if (napi_schedule_prep(&ch->tx_napi)) {
+ spin_lock_irqsave(&ch->lock, flags);
+ stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+ spin_unlock_irqrestore(&ch->lock, flags);
+ __napi_schedule_irqoff(&ch->tx_napi);
+ }
+ }
return status;
}
@@ -2250,14 +2282,14 @@ static void stmmac_tx_timer(struct timer_list *t)
ch = &priv->channel[tx_q->queue_index];
- /*
- * If NAPI is already running we can miss some events. Let's rearm
- * the timer and try again.
- */
- if (likely(napi_schedule_prep(&ch->tx_napi)))
+ if (likely(napi_schedule_prep(&ch->tx_napi))) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ch->lock, flags);
+ stmmac_disable_dma_irq(priv, priv->ioaddr, ch->index, 0, 1);
+ spin_unlock_irqrestore(&ch->lock, flags);
__napi_schedule(&ch->tx_napi);
- else
- mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(10));
+ }
}
/**
@@ -2581,9 +2613,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
if (priv->use_riwt) {
- ret = stmmac_rx_watchdog(priv, priv->ioaddr, MIN_DMA_RIWT, rx_cnt);
- if (!ret)
- priv->rx_riwt = MIN_DMA_RIWT;
+ if (!priv->rx_riwt)
+ priv->rx_riwt = DEF_DMA_RIWT;
+
+ ret = stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt);
}
if (priv->hw->pcs)
@@ -2633,10 +2666,17 @@ static void stmmac_hw_teardown(struct net_device *dev)
static int stmmac_open(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ struct platform_device *pdev = to_platform_device(priv->device);
int bfsize = 0;
u32 chan;
int ret;
+ ret = stmmac_bus_clks_enable(priv, true);
+ if (ret)
+ return ret;
+ if (priv->plat->init)
+ priv->plat->init(pdev, priv->plat->bsp_priv);
+
if (priv->hw->pcs != STMMAC_PCS_RGMII &&
priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI) {
@@ -2756,6 +2796,8 @@ dma_desc_error:
static int stmmac_release(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ struct platform_device *pdev = to_platform_device(priv->device);
+
u32 chan;
/* Stop and disconnect the PHY */
@@ -2792,6 +2834,10 @@ static int stmmac_release(struct net_device *dev)
stmmac_release_ptp(priv);
+ if (priv->plat->exit)
+ priv->plat->exit(pdev, priv->plat->bsp_priv);
+ stmmac_bus_clks_enable(priv, false);
+
return 0;
}
@@ -2901,19 +2947,26 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
int nfrags = skb_shinfo(skb)->nr_frags;
u32 queue = skb_get_queue_mapping(skb);
+ unsigned int first_entry, tx_packets;
+ int tmp_pay_len = 0, first_tx;
struct stmmac_tx_queue *tx_q;
- unsigned int first_entry;
- int tmp_pay_len = 0;
+ u8 proto_hdr_len, hdr;
+ bool has_vlan, set_ic;
u32 pay_len, mss;
- u8 proto_hdr_len;
dma_addr_t des;
- bool has_vlan;
int i;
tx_q = &priv->tx_queue[queue];
+ first_tx = tx_q->cur_tx;
/* Compute header lengths */
- proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
+ proto_hdr_len = skb_transport_offset(skb) + sizeof(struct udphdr);
+ hdr = sizeof(struct udphdr);
+ } else {
+ proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ hdr = tcp_hdrlen(skb);
+ }
/* Desc availability based on threshold should be enough safe */
if (unlikely(stmmac_tx_avail(priv, queue) <
@@ -2943,8 +2996,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (netif_msg_tx_queued(priv)) {
- pr_info("%s: tcphdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
- __func__, tcp_hdrlen(skb), proto_hdr_len, pay_len, mss);
+ pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
+ __func__, hdr, proto_hdr_len, pay_len, mss);
pr_info("\tskb->len %d, skb->data_len %d\n", skb->len,
skb->data_len);
}
@@ -3012,12 +3065,21 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_skbuff[tx_q->cur_tx] = skb;
/* Manage tx mitigation */
- tx_q->tx_count_frames += nfrags + 1;
- if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
- !((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
- priv->hwts_tx_en)) {
- stmmac_tx_timer_arm(priv, queue);
- } else {
+ tx_packets = (tx_q->cur_tx + 1) - first_tx;
+ tx_q->tx_count_frames += tx_packets;
+
+ if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)
+ set_ic = true;
+ else if (!priv->tx_coal_frames)
+ set_ic = false;
+ else if (tx_packets > priv->tx_coal_frames)
+ set_ic = true;
+ else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets)
+ set_ic = true;
+ else
+ set_ic = false;
+
+ if (set_ic) {
desc = &tx_q->dma_tx[tx_q->cur_tx];
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
@@ -3058,7 +3120,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
proto_hdr_len,
pay_len,
1, tx_q->tx_skbuff_dma[first_entry].last_segment,
- tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len));
+ hdr / 4, (skb->len - proto_hdr_len));
/* If context desc is used to change MSS */
if (mss_desc) {
@@ -3113,27 +3175,30 @@ dma_map_err:
*/
static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ unsigned int first_entry, tx_packets, enh_desc;
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int nopaged_len = skb_headlen(skb);
int i, csum_insertion = 0, is_jumbo = 0;
u32 queue = skb_get_queue_mapping(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
+ int gso = skb_shinfo(skb)->gso_type;
struct dma_desc *desc, *first;
struct stmmac_tx_queue *tx_q;
- unsigned int first_entry;
- unsigned int enh_desc;
+ bool has_vlan, set_ic;
+ int entry, first_tx;
dma_addr_t des;
- bool has_vlan;
- int entry;
tx_q = &priv->tx_queue[queue];
+ first_tx = tx_q->cur_tx;
if (priv->tx_path_in_lpi_mode)
stmmac_disable_eee_mode(priv);
/* Manage oversized TCP frames for GMAC4 device */
if (skb_is_gso(skb) && priv->tso) {
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))
+ if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))
+ return stmmac_tso_xmit(skb, dev);
+ if (priv->plat->has_gmac4 && (gso & SKB_GSO_UDP_L4))
return stmmac_tso_xmit(skb, dev);
}
@@ -3218,12 +3283,21 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
* This approach takes care about the fragments: desc is the first
* element in case of no SG.
*/
- tx_q->tx_count_frames += nfrags + 1;
- if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
- !((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
- priv->hwts_tx_en)) {
- stmmac_tx_timer_arm(priv, queue);
- } else {
+ tx_packets = (entry + 1) - first_tx;
+ tx_q->tx_count_frames += tx_packets;
+
+ if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)
+ set_ic = true;
+ else if (!priv->tx_coal_frames)
+ set_ic = false;
+ else if (tx_packets > priv->tx_coal_frames)
+ set_ic = true;
+ else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets)
+ set_ic = true;
+ else
+ set_ic = false;
+
+ if (set_ic) {
if (likely(priv->extend_desc))
desc = &tx_q->dma_etx[entry].basic;
else
@@ -3419,7 +3493,11 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
rx_q->rx_count_frames += priv->rx_coal_frames;
if (rx_q->rx_count_frames > priv->rx_coal_frames)
rx_q->rx_count_frames = 0;
- use_rx_wd = priv->use_riwt && rx_q->rx_count_frames;
+
+ use_rx_wd = !priv->rx_coal_frames;
+ use_rx_wd |= rx_q->rx_count_frames > 0;
+ if (!priv->use_riwt)
+ use_rx_wd = false;
dma_wmb();
stmmac_set_rx_owner(priv, p, use_rx_wd);
@@ -3432,6 +3510,55 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue);
}
+static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv,
+ struct dma_desc *p,
+ int status, unsigned int len)
+{
+ int ret, coe = priv->hw->rx_csum;
+ unsigned int plen = 0, hlen = 0;
+
+ /* Not first descriptor, buffer is always zero */
+ if (priv->sph && len)
+ return 0;
+
+ /* First descriptor, get split header length */
+ ret = stmmac_get_rx_header_len(priv, p, &hlen);
+ if (priv->sph && hlen) {
+ priv->xstats.rx_split_hdr_pkt_n++;
+ return hlen;
+ }
+
+ /* First descriptor, not last descriptor and not split header */
+ if (status & rx_not_ls)
+ return priv->dma_buf_sz;
+
+ plen = stmmac_get_rx_frame_len(priv, p, coe);
+
+ /* First descriptor and last descriptor and not split header */
+ return min_t(unsigned int, priv->dma_buf_sz, plen);
+}
+
+static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
+ struct dma_desc *p,
+ int status, unsigned int len)
+{
+ int coe = priv->hw->rx_csum;
+ unsigned int plen = 0;
+
+ /* Not split header, buffer is not available */
+ if (!priv->sph)
+ return 0;
+
+ /* Not last descriptor */
+ if (status & rx_not_ls)
+ return priv->dma_buf_sz;
+
+ plen = stmmac_get_rx_frame_len(priv, p, coe);
+
+ /* Last descriptor */
+ return plen - len;
+}
+
/**
* stmmac_rx - manage the receive process
* @priv: driver private structure
@@ -3461,11 +3588,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
}
while (count < limit) {
- unsigned int hlen = 0, prev_len = 0;
+ unsigned int buf1_len = 0, buf2_len = 0;
enum pkt_hash_types hash_type;
struct stmmac_rx_buffer *buf;
struct dma_desc *np, *p;
- unsigned int sec_len;
int entry;
u32 hash;
@@ -3484,7 +3610,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
break;
read_again:
- sec_len = 0;
+ buf1_len = 0;
+ buf2_len = 0;
entry = next_entry;
buf = &rx_q->buf_pool[entry];
@@ -3509,7 +3636,6 @@ read_again:
np = rx_q->dma_rx + next_entry;
prefetch(np);
- prefetch(page_address(buf->page));
if (priv->extend_desc)
stmmac_rx_extended_status(priv, &priv->dev->stats,
@@ -3526,69 +3652,62 @@ read_again:
goto read_again;
if (unlikely(error)) {
dev_kfree_skb(skb);
+ skb = NULL;
count++;
continue;
}
/* Buffer is good. Go on. */
- if (likely(status & rx_not_ls)) {
- len += priv->dma_buf_sz;
- } else {
- prev_len = len;
- len = stmmac_get_rx_frame_len(priv, p, coe);
-
- /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
- * Type frames (LLC/LLC-SNAP)
- *
- * llc_snap is never checked in GMAC >= 4, so this ACS
- * feature is always disabled and packets need to be
- * stripped manually.
- */
- if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
- unlikely(status != llc_snap))
- len -= ETH_FCS_LEN;
+ prefetch(page_address(buf->page));
+ if (buf->sec_page)
+ prefetch(page_address(buf->sec_page));
+
+ buf1_len = stmmac_rx_buf1_len(priv, p, status, len);
+ len += buf1_len;
+ buf2_len = stmmac_rx_buf2_len(priv, p, status, len);
+ len += buf2_len;
+
+ /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+ * Type frames (LLC/LLC-SNAP)
+ *
+ * llc_snap is never checked in GMAC >= 4, so this ACS
+ * feature is always disabled and packets need to be
+ * stripped manually.
+ */
+ if (likely(!(status & rx_not_ls)) &&
+ (likely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
+ unlikely(status != llc_snap))) {
+ if (buf2_len)
+ buf2_len -= ETH_FCS_LEN;
+ else
+ buf1_len -= ETH_FCS_LEN;
+
+ len -= ETH_FCS_LEN;
}
if (!skb) {
- int ret = stmmac_get_rx_header_len(priv, p, &hlen);
-
- if (priv->sph && !ret && (hlen > 0)) {
- sec_len = len;
- if (!(status & rx_not_ls))
- sec_len = sec_len - hlen;
- len = hlen;
-
- prefetch(page_address(buf->sec_page));
- priv->xstats.rx_split_hdr_pkt_n++;
- }
-
- skb = napi_alloc_skb(&ch->rx_napi, len);
+ skb = napi_alloc_skb(&ch->rx_napi, buf1_len);
if (!skb) {
priv->dev->stats.rx_dropped++;
count++;
- continue;
+ goto drain_data;
}
- dma_sync_single_for_cpu(priv->device, buf->addr, len,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(priv->device, buf->addr,
+ buf1_len, DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb, page_address(buf->page),
- len);
- skb_put(skb, len);
+ buf1_len);
+ skb_put(skb, buf1_len);
/* Data payload copied into SKB, page ready for recycle */
page_pool_recycle_direct(rx_q->page_pool, buf->page);
buf->page = NULL;
- } else {
- unsigned int buf_len = len - prev_len;
-
- if (likely(status & rx_not_ls))
- buf_len = priv->dma_buf_sz;
-
+ } else if (buf1_len) {
dma_sync_single_for_cpu(priv->device, buf->addr,
- buf_len, DMA_FROM_DEVICE);
+ buf1_len, DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
- buf->page, 0, buf_len,
+ buf->page, 0, buf1_len,
priv->dma_buf_sz);
/* Data payload appended into SKB */
@@ -3596,22 +3715,23 @@ read_again:
buf->page = NULL;
}
- if (sec_len > 0) {
+ if (buf2_len) {
dma_sync_single_for_cpu(priv->device, buf->sec_addr,
- sec_len, DMA_FROM_DEVICE);
+ buf2_len, DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
- buf->sec_page, 0, sec_len,
+ buf->sec_page, 0, buf2_len,
priv->dma_buf_sz);
- len += sec_len;
-
/* Data payload appended into SKB */
page_pool_release_page(rx_q->page_pool, buf->sec_page);
buf->sec_page = NULL;
}
+drain_data:
if (likely(status & rx_not_ls))
goto read_again;
+ if (!skb)
+ continue;
/* Got entire packet into SKB. Finish it. */
@@ -3629,13 +3749,14 @@ read_again:
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rx_napi, skb);
+ skb = NULL;
priv->dev->stats.rx_packets++;
priv->dev->stats.rx_bytes += len;
count++;
}
- if (status & rx_not_ls) {
+ if (status & rx_not_ls || skb) {
rx_q->state_saved = true;
rx_q->state.skb = skb;
rx_q->state.error = error;
@@ -3660,8 +3781,14 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget)
priv->xstats.napi_poll++;
work_done = stmmac_rx(priv, budget, chan);
- if (work_done < budget && napi_complete_done(napi, work_done))
- stmmac_enable_dma_irq(priv, priv->ioaddr, chan);
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ch->lock, flags);
+ stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 0);
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+
return work_done;
}
@@ -3670,7 +3797,6 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
struct stmmac_channel *ch =
container_of(napi, struct stmmac_channel, tx_napi);
struct stmmac_priv *priv = ch->priv_data;
- struct stmmac_tx_queue *tx_q;
u32 chan = ch->index;
int work_done;
@@ -3679,15 +3805,12 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
work_done = stmmac_tx_clean(priv, DMA_TX_SIZE, chan);
work_done = min(work_done, budget);
- if (work_done < budget)
- napi_complete_done(napi, work_done);
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ unsigned long flags;
- /* Force transmission restart */
- tx_q = &priv->tx_queue[chan];
- if (tx_q->cur_tx != tx_q->dirty_tx) {
- stmmac_enable_dma_transmission(priv, priv->ioaddr);
- stmmac_set_tx_tail_ptr(priv, priv->ioaddr, tx_q->tx_tail_addr,
- chan);
+ spin_lock_irqsave(&ch->lock, flags);
+ stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 0, 1);
+ spin_unlock_irqrestore(&ch->lock, flags);
}
return work_done;
@@ -3960,6 +4083,21 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
static LIST_HEAD(stmmac_block_cb_list);
+int stmmactc_setup_mqprio(struct net_device *ndev, void *type_data)
+{
+ struct tc_mqprio_qopt *mqprio = type_data;
+ u8 num_tc;
+ int i;
+
+ num_tc = mqprio->num_tc;
+ netif_set_real_num_tx_queues(ndev, num_tc);
+ netdev_set_num_tc(ndev, num_tc);
+ for (i = 0; i < num_tc; i++)
+ netdev_set_tc_queue(ndev, i, 1, i);
+
+ return 0;
+}
+
static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
{
@@ -3973,6 +4111,10 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
priv, priv, true);
case TC_SETUP_QDISC_CBS:
return stmmac_tc_setup_cbs(priv, priv, type_data);
+ case TC_SETUP_QDISC_TAPRIO:
+ return stmmac_tc_setup_taprio(priv, priv, type_data);
+ case TC_SETUP_QDISC_MQPRIO:
+ return stmmactc_setup_mqprio(ndev, type_data);
default:
return -EOPNOTSUPP;
}
@@ -3981,11 +4123,13 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev)
{
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+ int gso = skb_shinfo(skb)->gso_type;
+
+ if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6 | SKB_GSO_UDP_L4)) {
/*
- * There is no way to determine the number of TSO
+ * There is no way to determine the number of TSO/USO
* capable Queues. Let's use always the Queue 0
- * because if TSO is supported then at least this
+ * because if TSO/USO is supported then at least this
* one will be capable.
*/
return 0;
@@ -4143,9 +4287,38 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
priv->dma_cap.number_rx_channel);
seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
priv->dma_cap.number_tx_channel);
+ seq_printf(seq, "\tNumber of Additional RX queues: %d\n",
+ priv->dma_cap.number_rx_queues);
+ seq_printf(seq, "\tNumber of Additional TX queues: %d\n",
+ priv->dma_cap.number_tx_queues);
seq_printf(seq, "\tEnhanced descriptors: %s\n",
(priv->dma_cap.enh_desc) ? "Y" : "N");
-
+ seq_printf(seq, "\tTX Fifo Size: %d\n", priv->dma_cap.tx_fifo_size);
+ seq_printf(seq, "\tRX Fifo Size: %d\n", priv->dma_cap.rx_fifo_size);
+ seq_printf(seq, "\tHash Table Size: %d\n", priv->dma_cap.hash_tb_sz);
+ seq_printf(seq, "\tTSO: %s\n", priv->dma_cap.tsoen ? "Y" : "N");
+ seq_printf(seq, "\tNumber of PPS Outputs: %d\n",
+ priv->dma_cap.pps_out_num);
+ seq_printf(seq, "\tSafety Features: %s\n",
+ priv->dma_cap.asp ? "Y" : "N");
+ seq_printf(seq, "\tFlexible RX Parser: %s\n",
+ priv->dma_cap.frpsel ? "Y" : "N");
+ seq_printf(seq, "\tEnhanced Addressing: %d\n",
+ priv->dma_cap.addr64);
+ seq_printf(seq, "\tReceive Side Scaling: %s\n",
+ priv->dma_cap.rssen ? "Y" : "N");
+ seq_printf(seq, "\tVLAN Hash Filtering: %s\n",
+ priv->dma_cap.vlhash ? "Y" : "N");
+ seq_printf(seq, "\tSplit Header: %s\n",
+ priv->dma_cap.sphen ? "Y" : "N");
+ seq_printf(seq, "\tVLAN TX Insertion: %s\n",
+ priv->dma_cap.vlins ? "Y" : "N");
+ seq_printf(seq, "\tDouble VLAN: %s\n",
+ priv->dma_cap.dvlan ? "Y" : "N");
+ seq_printf(seq, "\tNumber of L3/L4 Filters: %d\n",
+ priv->dma_cap.l3l4fnum);
+ seq_printf(seq, "\tARP Offloading: %s\n",
+ priv->dma_cap.arpoffsel ? "Y" : "N");
return 0;
}
DEFINE_SHOW_ATTRIBUTE(stmmac_dma_cap);
@@ -4269,6 +4442,11 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
{
struct stmmac_priv *priv = netdev_priv(ndev);
bool is_double = false;
+ int ret;
+
+ ret = stmmac_bus_clks_enable(priv, true);
+ if (ret)
+ return ret;
if (!priv->dma_cap.vlhash)
return -EOPNOTSUPP;
@@ -4276,7 +4454,10 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
is_double = true;
clear_bit(vid, priv->active_vlans);
- return stmmac_vlan_update(priv, is_double);
+ ret = stmmac_vlan_update(priv, is_double);
+
+ stmmac_bus_clks_enable(priv, false);
+ return ret;
}
static const struct net_device_ops stmmac_netdev_ops = {
@@ -4443,6 +4624,7 @@ int stmmac_dvr_probe(struct device *device,
struct plat_stmmacenet_data *plat_dat,
struct stmmac_resources *res)
{
+ struct platform_device *pdev = to_platform_device(device);
struct net_device *ndev = NULL;
struct stmmac_priv *priv;
u32 queue, rxq, maxq;
@@ -4525,6 +4707,8 @@ int stmmac_dvr_probe(struct device *device,
if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
+ if (priv->plat->has_gmac4)
+ ndev->hw_features |= NETIF_F_GSO_UDP_L4;
priv->tso = true;
dev_info(priv->device, "TSO feature enabled\n");
}
@@ -4606,6 +4790,7 @@ int stmmac_dvr_probe(struct device *device,
for (queue = 0; queue < maxq; queue++) {
struct stmmac_channel *ch = &priv->channel[queue];
+ spin_lock_init(&ch->lock);
ch->priv_data = priv;
ch->index = queue;
@@ -4665,6 +4850,10 @@ int stmmac_dvr_probe(struct device *device,
stmmac_init_fs(ndev);
#endif
+ if (priv->plat->exit)
+ priv->plat->exit(pdev, priv->plat->bsp_priv);
+ stmmac_bus_clks_enable(priv, false);
+
return ret;
error_netdev_register:
@@ -4685,6 +4874,7 @@ error_mdio_register:
}
error_hw_init:
destroy_workqueue(priv->wq);
+ stmmac_bus_clks_enable(priv, false);
return ret;
}
@@ -4700,6 +4890,7 @@ int stmmac_dvr_remove(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ bool netif_status = netif_running(ndev);
netdev_info(priv->dev, "%s: removing driver", __func__);
@@ -4714,8 +4905,8 @@ int stmmac_dvr_remove(struct device *dev)
phylink_destroy(priv->phylink);
if (priv->plat->stmmac_rst)
reset_control_assert(priv->plat->stmmac_rst);
- clk_disable_unprepare(priv->plat->pclk);
- clk_disable_unprepare(priv->plat->stmmac_clk);
+ if (netif_status)
+ stmmac_bus_clks_enable(priv, false);
if (priv->hw->pcs != STMMAC_PCS_RGMII &&
priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI)
@@ -4778,8 +4969,7 @@ int stmmac_suspend(struct device *dev)
/* Disable clock in case of PWM is off */
if (priv->plat->clk_ptp_ref)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
- clk_disable_unprepare(priv->plat->pclk);
- clk_disable_unprepare(priv->plat->stmmac_clk);
+ stmmac_bus_clks_enable(priv, false);
}
mutex_unlock(&priv->lock);
@@ -4826,6 +5016,7 @@ int stmmac_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ int ret = 0;
if (!netif_running(ndev))
return 0;
@@ -4844,16 +5035,21 @@ int stmmac_resume(struct device *dev)
} else {
pinctrl_pm_select_default_state(priv->device);
/* enable the clk previously disabled */
- clk_prepare_enable(priv->plat->stmmac_clk);
- clk_prepare_enable(priv->plat->pclk);
+ ret = stmmac_bus_clks_enable(priv, true);
+ if (ret)
+ return ret;
if (priv->plat->clk_ptp_ref)
clk_prepare_enable(priv->plat->clk_ptp_ref);
/* reset the phy so that it's ready */
- if (priv->mii)
+ if (priv->mii && priv->mdio_rst_after_resume)
stmmac_mdio_reset(priv->mii);
}
- netif_device_attach(ndev);
+ if (!device_may_wakeup(priv->device)) {
+ rtnl_lock();
+ phylink_start(priv->phylink);
+ rtnl_unlock();
+ }
mutex_lock(&priv->lock);
@@ -4870,14 +5066,10 @@ int stmmac_resume(struct device *dev)
mutex_unlock(&priv->lock);
- if (!device_may_wakeup(priv->device)) {
- rtnl_lock();
- phylink_start(priv->phylink);
- rtnl_unlock();
- }
-
phylink_mac_change(priv->phylink, true);
+ netif_device_attach(ndev);
+
return 0;
}
EXPORT_SYMBOL_GPL(stmmac_resume);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 40c42637ad75..226e5a4bf21c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -41,20 +41,32 @@
#define MII_XGMAC_BUSY BIT(22)
#define MII_XGMAC_MAX_C22ADDR 3
#define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
+#define MII_XGMAC_PA_SHIFT 16
+#define MII_XGMAC_DA_SHIFT 21
+
+static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
+ int phyreg, u32 *hw_addr)
+{
+ u32 tmp;
+
+ /* Set port as Clause 45 */
+ tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
+ tmp &= ~BIT(phyaddr);
+ writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
+
+ *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
+ *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT;
+ return 0;
+}
static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr)
{
- unsigned int mii_data = priv->hw->mii.data;
u32 tmp;
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
- /* Wait until any existing MII operation is complete */
- if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
- !(tmp & MII_XGMAC_BUSY), 100, 10000))
- return -EBUSY;
/* Set port as Clause 22 */
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
@@ -62,7 +74,7 @@ static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
tmp |= BIT(phyaddr);
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
- *hw_addr = (phyaddr << 16) | (phyreg & 0x1f);
+ *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
return 0;
}
@@ -75,17 +87,28 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
u32 tmp, addr, value = MII_XGMAC_BUSY;
int ret;
+ /* Wait until any existing MII operation is complete */
+ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+ !(tmp & MII_XGMAC_BUSY), 100, 10000))
+ return -EBUSY;
+
if (phyreg & MII_ADDR_C45) {
- return -EOPNOTSUPP;
+ phyreg &= ~MII_ADDR_C45;
+
+ ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
+ if (ret)
+ return ret;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
return ret;
+
+ value |= MII_XGMAC_SADDR;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
- value |= MII_XGMAC_SADDR | MII_XGMAC_READ;
+ value |= MII_XGMAC_READ;
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
@@ -115,17 +138,28 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
u32 addr, tmp, value = MII_XGMAC_BUSY;
int ret;
+ /* Wait until any existing MII operation is complete */
+ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
+ !(tmp & MII_XGMAC_BUSY), 100, 10000))
+ return -EBUSY;
+
if (phyreg & MII_ADDR_C45) {
- return -EOPNOTSUPP;
+ phyreg &= ~MII_ADDR_C45;
+
+ ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
+ if (ret)
+ return ret;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
return ret;
+
+ value |= MII_XGMAC_SADDR;
}
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
- value |= phydata | MII_XGMAC_SADDR;
+ value |= phydata;
value |= MII_XGMAC_WRITE;
/* Wait until any existing MII operation is complete */
@@ -260,6 +294,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
*/
int stmmac_mdio_reset(struct mii_bus *bus)
{
+ int ret = 0;
#if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
@@ -273,12 +308,16 @@ int stmmac_mdio_reset(struct mii_bus *bus)
reset_gpio = devm_gpiod_get_optional(priv->device,
"snps,reset",
GPIOD_OUT_LOW);
- if (IS_ERR(reset_gpio))
- return PTR_ERR(reset_gpio);
+ if (IS_ERR_OR_NULL(reset_gpio)) {
+ ret = PTR_ERR_OR_ZERO(reset_gpio);
+ goto mdio_gpio_reset_end;
+ }
device_property_read_u32_array(priv->device,
"snps,reset-delays-us",
delays, ARRAY_SIZE(delays));
+ priv->mdio_rst_after_resume = of_property_read_bool(priv->device->of_node,
+ "mdio_rst_after_resume");
if (delays[0])
msleep(DIV_ROUND_UP(delays[0], 1000));
@@ -290,7 +329,11 @@ int stmmac_mdio_reset(struct mii_bus *bus)
gpiod_set_value_cansleep(reset_gpio, 0);
if (delays[2])
msleep(DIV_ROUND_UP(delays[2], 1000));
+
+ devm_gpiod_put(priv->device, reset_gpio);
}
+
+mdio_gpio_reset_end:
#endif
/* This is a workaround for problems with the STE101P PHY.
@@ -301,7 +344,7 @@ int stmmac_mdio_reset(struct mii_bus *bus)
if (!priv->plat->has_gmac4)
writel(0, priv->ioaddr + mii_address);
#endif
- return 0;
+ return ret;
}
/**
@@ -363,6 +406,10 @@ int stmmac_mdio_register(struct net_device *ndev)
goto bus_register_fail;
}
+ /* Looks like we need a dummy read for XGMAC only and C45 PHYs */
+ if (priv->plat->has_xgmac)
+ stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45);
+
if (priv->plat->phy_node || mdio_node)
goto bus_register_done;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 678aa2b001e0..c776d521d646 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -507,7 +507,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
of_device_is_compatible(np, "snps,dwmac-4.10a") ||
- of_device_is_compatible(np, "snps,dwmac-4.20a")) {
+ of_device_is_compatible(np, "snps,dwmac-4.20a") ||
+ of_device_is_compatible(np, "snps,dwmac-5.10a")) {
plat->has_gmac4 = 1;
plat->has_gmac = 0;
plat->pmt = 1;
@@ -702,7 +703,7 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
struct plat_stmmacenet_data *plat = priv->plat;
int ret = stmmac_dvr_remove(&pdev->dev);
- if (plat->exit)
+ if (plat->exit && ndev && netif_running(ndev))
plat->exit(pdev, plat->bsp_priv);
stmmac_remove_config_dt(pdev, plat);
@@ -727,7 +728,7 @@ static int stmmac_pltfr_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
ret = stmmac_suspend(dev);
- if (priv->plat->exit)
+ if (priv->plat->exit && ndev && netif_running(ndev))
priv->plat->exit(pdev, priv->plat->bsp_priv);
return ret;
@@ -746,7 +747,7 @@ static int stmmac_pltfr_resume(struct device *dev)
struct stmmac_priv *priv = netdev_priv(ndev);
struct platform_device *pdev = to_platform_device(dev);
- if (priv->plat->init)
+ if (priv->plat->init && ndev && netif_running(ndev))
priv->plat->init(pdev, priv->plat->bsp_priv);
return stmmac_resume(dev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 52b453b60597..13334aff1070 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -321,8 +321,6 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
return -EINVAL;
if (!priv->dma_cap.av)
return -EOPNOTSUPP;
- if (priv->speed != SPEED_100 && priv->speed != SPEED_1000)
- return -EOPNOTSUPP;
mode_to_use = priv->plat->tx_queues_cfg[queue].mode_to_use;
if (mode_to_use == MTL_QUEUE_DCB && qopt->enable) {
@@ -602,9 +600,146 @@ static int tc_setup_cls(struct stmmac_priv *priv,
return ret;
}
+static int tc_setup_taprio(struct stmmac_priv *priv,
+ struct tc_taprio_qopt_offload *qopt)
+{
+ u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
+ struct plat_stmmacenet_data *plat = priv->plat;
+ struct timespec64 time;
+ bool fpe = false;
+ int i, ret = 0;
+ u64 ctr;
+
+ if (!priv->dma_cap.estsel)
+ return -EOPNOTSUPP;
+
+ switch (wid) {
+ case 0x1:
+ wid = 16;
+ break;
+ case 0x2:
+ wid = 20;
+ break;
+ case 0x3:
+ wid = 24;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (dep) {
+ case 0x1:
+ dep = 64;
+ break;
+ case 0x2:
+ dep = 128;
+ break;
+ case 0x3:
+ dep = 256;
+ break;
+ case 0x4:
+ dep = 512;
+ break;
+ case 0x5:
+ dep = 1024;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (!qopt->enable)
+ goto disable;
+ if (qopt->num_entries >= dep)
+ return -EINVAL;
+ if (!qopt->base_time)
+ return -ERANGE;
+ if (!qopt->cycle_time)
+ return -ERANGE;
+
+ if (!plat->est) {
+ plat->est = devm_kzalloc(priv->device, sizeof(*plat->est),
+ GFP_KERNEL);
+ if (!plat->est)
+ return -ENOMEM;
+ } else {
+ memset(plat->est, 0, sizeof(*plat->est));
+ }
+
+ size = qopt->num_entries;
+
+ priv->plat->est->gcl_size = size;
+ priv->plat->est->enable = qopt->enable;
+
+ for (i = 0; i < size; i++) {
+ s64 delta_ns = qopt->entries[i].interval;
+ u32 gates = qopt->entries[i].gate_mask;
+
+ if (delta_ns > GENMASK(wid, 0))
+ return -ERANGE;
+ if (gates > GENMASK(31 - wid, 0))
+ return -ERANGE;
+
+ switch (qopt->entries[i].command) {
+ case TC_TAPRIO_CMD_SET_GATES:
+ if (fpe)
+ return -EINVAL;
+ break;
+ case TC_TAPRIO_CMD_SET_AND_HOLD:
+ gates |= BIT(0);
+ fpe = true;
+ break;
+ case TC_TAPRIO_CMD_SET_AND_RELEASE:
+ gates &= ~BIT(0);
+ fpe = true;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ priv->plat->est->gcl[i] = delta_ns | (gates << wid);
+ }
+
+ /* Adjust for real system time */
+ time = ktime_to_timespec64(qopt->base_time);
+ priv->plat->est->btr[0] = (u32)time.tv_nsec;
+ priv->plat->est->btr[1] = (u32)time.tv_sec;
+
+ ctr = qopt->cycle_time;
+ priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
+ priv->plat->est->ctr[1] = (u32)ctr;
+
+ if (fpe && !priv->dma_cap.fpesel)
+ return -EOPNOTSUPP;
+
+ ret = stmmac_fpe_configure(priv, priv->ioaddr,
+ priv->plat->tx_queues_to_use,
+ priv->plat->rx_queues_to_use, fpe);
+ if (ret && fpe) {
+ netdev_err(priv->dev, "failed to enable Frame Preemption\n");
+ return ret;
+ }
+
+ ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ priv->plat->clk_ptp_rate);
+ if (ret) {
+ netdev_err(priv->dev, "failed to configure EST\n");
+ goto disable;
+ }
+
+ netdev_info(priv->dev, "configured EST\n");
+ return 0;
+
+disable:
+ priv->plat->est->enable = false;
+ stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ priv->plat->clk_ptp_rate);
+ return ret;
+}
+
const struct stmmac_tc_ops dwmac510_tc_ops = {
.init = tc_init,
.setup_cls_u32 = tc_setup_cls_u32,
.setup_cbs = tc_setup_cbs,
.setup_cls = tc_setup_cls,
+ .setup_taprio = tc_setup_taprio,
};
diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
new file mode 100644
index 000000000000..c4821b80aec8
--- /dev/null
+++ b/drivers/net/ivshmem-net.c
@@ -0,0 +1,1077 @@
+/*
+ * Copyright 2016 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) Siemens AG, 2016-2020
+ *
+ * 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/ivshmem.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/virtio_ring.h>
+
+#define DRV_NAME "ivshmem-net"
+
+#define IVSHM_NET_STATE_RESET 0
+#define IVSHM_NET_STATE_INIT 1
+#define IVSHM_NET_STATE_READY 2
+#define IVSHM_NET_STATE_RUN 3
+
+#define IVSHM_NET_FLAG_RUN 0
+
+#define IVSHM_NET_MTU_DEF 16384
+
+#define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES)
+
+#define IVSHM_NET_VQ_ALIGN 64
+
+#define IVSHM_NET_SECTION_TX 0
+#define IVSHM_NET_SECTION_RX 1
+
+#define IVSHM_NET_MSIX_STATE 0
+#define IVSHM_NET_MSIX_TX_RX 1
+
+#define IVSHM_NET_NUM_VECTORS 2
+
+struct ivshm_net_queue {
+ struct vring vr;
+ u32 free_head;
+ u32 num_free;
+ u32 num_added;
+ u16 last_avail_idx;
+ u16 last_used_idx;
+
+ void *data;
+ void *end;
+ u32 size;
+ u32 head;
+ u32 tail;
+};
+
+struct ivshm_net_stats {
+ u32 tx_rx_interrupts;
+ u32 tx_packets;
+ u32 tx_notify;
+ u32 tx_pause;
+ u32 rx_packets;
+ u32 rx_notify;
+ u32 napi_poll;
+ u32 napi_complete;
+ u32 napi_poll_n[10];
+};
+
+struct ivshm_net {
+ struct ivshm_net_queue rx;
+ struct ivshm_net_queue tx;
+
+ u32 vrsize;
+ u32 qlen;
+ u32 qsize;
+
+ struct napi_struct napi;
+
+ u32 state;
+ u32 last_peer_state;
+ u32 *state_table;
+
+ unsigned long flags;
+
+ struct workqueue_struct *state_wq;
+ struct work_struct state_work;
+
+ struct ivshm_net_stats stats;
+
+ struct ivshm_regs __iomem *ivshm_regs;
+ void *shm[2];
+ resource_size_t shmlen;
+ u32 peer_id;
+
+ u32 tx_rx_vector;
+
+ struct pci_dev *pdev;
+};
+
+static void *ivshm_net_desc_data(struct ivshm_net *in,
+ struct ivshm_net_queue *q,
+ unsigned int region,
+ struct vring_desc *desc,
+ u32 *len)
+{
+ u64 offs = READ_ONCE(desc->addr);
+ u32 dlen = READ_ONCE(desc->len);
+ u16 flags = READ_ONCE(desc->flags);
+ void *data;
+
+ if (flags)
+ return NULL;
+
+ if (offs >= in->shmlen)
+ return NULL;
+
+ data = in->shm[region] + offs;
+
+ if (data < q->data || data >= q->end)
+ return NULL;
+
+ if (dlen > q->end - data)
+ return NULL;
+
+ *len = dlen;
+
+ return data;
+}
+
+static void ivshm_net_init_queue(struct ivshm_net *in,
+ struct ivshm_net_queue *q,
+ void *mem, unsigned int len)
+{
+ memset(q, 0, sizeof(*q));
+
+ vring_init(&q->vr, len, mem, IVSHM_NET_VQ_ALIGN);
+ q->data = mem + in->vrsize;
+ q->end = q->data + in->qsize;
+ q->size = in->qsize;
+}
+
+static void ivshm_net_init_queues(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ void *tx;
+ void *rx;
+ int i;
+
+ tx = in->shm[IVSHM_NET_SECTION_TX];
+ rx = in->shm[IVSHM_NET_SECTION_RX];
+
+ memset(tx, 0, in->shmlen);
+
+ ivshm_net_init_queue(in, &in->tx, tx, in->qlen);
+ ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
+
+ swap(in->rx.vr.used, in->tx.vr.used);
+
+ in->tx.num_free = in->tx.vr.num;
+
+ for (i = 0; i < in->tx.vr.num - 1; i++)
+ in->tx.vr.desc[i].next = i + 1;
+}
+
+static int ivshm_net_calc_qsize(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ unsigned int vrsize;
+ unsigned int qsize;
+ unsigned int qlen;
+
+ for (qlen = 4096; qlen > 32; qlen >>= 1) {
+ vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN);
+ vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN);
+ if (vrsize < in->shmlen / 8)
+ break;
+ }
+
+ if (vrsize > in->shmlen)
+ return -EINVAL;
+
+ qsize = in->shmlen - vrsize;
+
+ if (qsize < 4 * ETH_MIN_MTU)
+ return -EINVAL;
+
+ in->vrsize = vrsize;
+ in->qlen = qlen;
+ in->qsize = qsize;
+
+ return 0;
+}
+
+static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num)
+{
+ u16 evt, old, new;
+
+ virt_mb();
+
+ evt = READ_ONCE(vring_avail_event(&in->tx.vr));
+ old = in->tx.last_avail_idx - num;
+ new = in->tx.last_avail_idx;
+
+ if (vring_need_event(evt, new, old)) {
+ writel(in->tx_rx_vector | (in->peer_id << 16),
+ &in->ivshm_regs->doorbell);
+ in->stats.tx_notify++;
+ }
+}
+
+static void ivshm_net_enable_rx_irq(struct ivshm_net *in)
+{
+ vring_avail_event(&in->rx.vr) = in->rx.last_avail_idx;
+ virt_wmb();
+}
+
+static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num)
+{
+ u16 evt, old, new;
+
+ virt_mb();
+
+ evt = READ_ONCE(vring_used_event(&in->rx.vr));
+ old = in->rx.last_used_idx - num;
+ new = in->rx.last_used_idx;
+
+ if (vring_need_event(evt, new, old)) {
+ writel(in->tx_rx_vector | (in->peer_id << 16),
+ &in->ivshm_regs->doorbell);
+ in->stats.rx_notify++;
+ }
+}
+
+static void ivshm_net_enable_tx_irq(struct ivshm_net *in)
+{
+ vring_used_event(&in->tx.vr) = in->tx.last_used_idx;
+ virt_wmb();
+}
+
+static bool ivshm_net_rx_avail(struct ivshm_net *in)
+{
+ virt_mb();
+ return READ_ONCE(in->rx.vr.avail->idx) != in->rx.last_avail_idx;
+}
+
+static size_t ivshm_net_tx_space(struct ivshm_net *in)
+{
+ struct ivshm_net_queue *tx = &in->tx;
+ u32 tail = tx->tail;
+ u32 head = tx->head;
+ u32 space;
+
+ if (head < tail)
+ space = tail - head;
+ else
+ space = max(tx->size - head, tail);
+
+ return space;
+}
+
+static bool ivshm_net_tx_ok(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ return in->tx.num_free >= 2 &&
+ ivshm_net_tx_space(in) >= 2 * IVSHM_NET_FRAME_SIZE(ndev->mtu);
+}
+
+static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len)
+{
+ u32 p = *pos;
+
+ len = IVSHM_NET_FRAME_SIZE(len);
+
+ if (q->size - p < len)
+ p = 0;
+ *pos = p + len;
+
+ return p;
+}
+
+static bool ivshm_net_tx_clean(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+ struct vring_used_elem *used;
+ struct vring *vr = &tx->vr;
+ struct vring_desc *desc;
+ struct vring_desc *fdesc;
+ u16 last = tx->last_used_idx;
+ unsigned int num;
+ bool tx_ok;
+ u32 fhead;
+
+ fdesc = NULL;
+ fhead = 0;
+ num = 0;
+
+ while (last != virt_load_acquire(&vr->used->idx)) {
+ void *data;
+ u32 len;
+ u32 tail;
+
+ used = vr->used->ring + (last % vr->num);
+ if (used->id >= vr->num || used->len != 1) {
+ netdev_err(ndev, "invalid tx used->id %d ->len %d\n",
+ used->id, used->len);
+ break;
+ }
+
+ desc = &vr->desc[used->id];
+
+ data = ivshm_net_desc_data(in, &in->tx, IVSHM_NET_SECTION_TX,
+ desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad tx descriptor, data == NULL\n");
+ break;
+ }
+
+ tail = ivshm_net_tx_advance(tx, &tx->tail, len);
+ if (data != tx->data + tail) {
+ netdev_err(ndev, "bad tx descriptor\n");
+ break;
+ }
+
+ if (!num)
+ fdesc = desc;
+ else
+ desc->next = fhead;
+
+ fhead = used->id;
+
+ tx->last_used_idx = ++last;
+ num++;
+ tx->num_free++;
+ BUG_ON(tx->num_free > vr->num);
+
+ tx_ok = ivshm_net_tx_ok(ndev);
+ if (!tx_ok)
+ ivshm_net_enable_tx_irq(in);
+ }
+
+ if (num) {
+ fdesc->next = tx->free_head;
+ tx->free_head = fhead;
+ } else {
+ tx_ok = ivshm_net_tx_ok(ndev);
+ }
+
+ return tx_ok;
+}
+
+static void ivshm_net_tx_poll(struct net_device *ndev)
+{
+ struct netdev_queue *txq = netdev_get_tx_queue(ndev, 0);
+
+ if (!__netif_tx_trylock(txq))
+ return;
+
+ if (ivshm_net_tx_clean(ndev) && netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
+
+ __netif_tx_unlock(txq);
+}
+
+static struct vring_desc *ivshm_net_rx_desc(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *rx = &in->rx;
+ struct vring *vr = &rx->vr;
+ unsigned int avail;
+ u16 avail_idx;
+
+ avail_idx = virt_load_acquire(&vr->avail->idx);
+
+ if (avail_idx == rx->last_avail_idx)
+ return NULL;
+
+ avail = vr->avail->ring[rx->last_avail_idx++ & (vr->num - 1)];
+ if (avail >= vr->num) {
+ netdev_err(ndev, "invalid rx avail %d\n", avail);
+ return NULL;
+ }
+
+ return &vr->desc[avail];
+}
+
+static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc)
+{
+ struct ivshm_net_queue *rx = &in->rx;
+ struct vring *vr = &rx->vr;
+ unsigned int desc_id = desc - vr->desc;
+ unsigned int used;
+
+ used = rx->last_used_idx++ & (vr->num - 1);
+ vr->used->ring[used].id = desc_id;
+ vr->used->ring[used].len = 1;
+
+ virt_store_release(&vr->used->idx, rx->last_used_idx);
+}
+
+static int ivshm_net_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ struct ivshm_net *in = container_of(napi, struct ivshm_net, napi);
+ int received = 0;
+
+ in->stats.napi_poll++;
+
+ ivshm_net_tx_poll(ndev);
+
+ while (received < budget) {
+ struct vring_desc *desc;
+ struct sk_buff *skb;
+ void *data;
+ u32 len;
+
+ desc = ivshm_net_rx_desc(ndev);
+ if (!desc)
+ break;
+
+ data = ivshm_net_desc_data(in, &in->rx, IVSHM_NET_SECTION_RX,
+ desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad rx descriptor\n");
+ break;
+ }
+
+ skb = napi_alloc_skb(napi, len);
+
+ if (skb) {
+ memcpy(skb_put(skb, len), data, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(napi, skb);
+ }
+
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
+
+ ivshm_net_rx_finish(in, desc);
+ received++;
+ }
+
+ if (received < budget) {
+ in->stats.napi_complete++;
+ napi_complete_done(napi, received);
+ ivshm_net_enable_rx_irq(in);
+ if (ivshm_net_rx_avail(in))
+ napi_schedule(napi);
+ }
+
+ if (received)
+ ivshm_net_notify_rx(in, received);
+
+ in->stats.rx_packets += received;
+ in->stats.napi_poll_n[received ? 1 + min(ilog2(received), 8) : 0]++;
+
+ return received;
+}
+
+static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+ bool xmit_more = netdev_xmit_more();
+ struct vring *vr = &tx->vr;
+ struct vring_desc *desc;
+ unsigned int desc_idx;
+ unsigned int avail;
+ u32 head;
+ void *buf;
+
+ if (!ivshm_net_tx_clean(ndev)) {
+ netif_stop_queue(ndev);
+
+ netdev_err(ndev, "BUG: tx ring full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ desc_idx = tx->free_head;
+ desc = &vr->desc[desc_idx];
+ tx->free_head = desc->next;
+ tx->num_free--;
+
+ head = ivshm_net_tx_advance(tx, &tx->head, skb->len);
+
+ if (!ivshm_net_tx_ok(ndev)) {
+ ivshm_net_enable_tx_irq(in);
+ netif_stop_queue(ndev);
+ xmit_more = false;
+ in->stats.tx_pause++;
+ }
+
+ buf = tx->data + head;
+ skb_copy_and_csum_dev(skb, buf);
+
+ desc->addr = buf - in->shm[IVSHM_NET_SECTION_TX];
+ desc->len = skb->len;
+ desc->flags = 0;
+
+ avail = tx->last_avail_idx++ & (vr->num - 1);
+ vr->avail->ring[avail] = desc_idx;
+ tx->num_added++;
+
+ virt_store_release(&vr->avail->idx, tx->last_avail_idx);
+
+ if (!xmit_more) {
+ ivshm_net_notify_tx(in, tx->num_added);
+ tx->num_added = 0;
+ }
+
+ in->stats.tx_packets++;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+
+ dev_consume_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static void ivshm_net_set_state(struct ivshm_net *in, u32 state)
+{
+ virt_wmb();
+ WRITE_ONCE(in->state, state);
+ writel(state, &in->ivshm_regs->state);
+}
+
+static void ivshm_net_run(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ if (in->state < IVSHM_NET_STATE_READY)
+ return;
+
+ if (!netif_running(ndev))
+ return;
+
+ if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ return;
+
+ netif_start_queue(ndev);
+ napi_enable(&in->napi);
+ napi_schedule(&in->napi);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
+}
+
+static void ivshm_net_do_stop(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+
+ if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ return;
+
+ netif_stop_queue(ndev);
+ napi_disable(&in->napi);
+}
+
+static void ivshm_net_state_change(struct work_struct *work)
+{
+ struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
+ struct net_device *ndev = in->napi.dev;
+ u32 peer_state = READ_ONCE(in->state_table[in->peer_id]);
+
+ switch (in->state) {
+ case IVSHM_NET_STATE_RESET:
+ /*
+ * Wait for the remote to leave READY/RUN before transitioning
+ * to INIT.
+ */
+ if (peer_state < IVSHM_NET_STATE_READY)
+ ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
+ break;
+
+ case IVSHM_NET_STATE_INIT:
+ /*
+ * Wait for the remote to leave RESET before performing the
+ * initialization and moving to READY.
+ */
+ if (peer_state > IVSHM_NET_STATE_RESET) {
+ ivshm_net_init_queues(ndev);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+
+ rtnl_lock();
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, ndev);
+ rtnl_unlock();
+ }
+ break;
+
+ case IVSHM_NET_STATE_READY:
+ /*
+ * Link is up and we are running once the remote is in READY or
+ * RUN.
+ */
+ if (peer_state >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+ ivshm_net_run(ndev);
+ break;
+ }
+ /* fall through */
+ case IVSHM_NET_STATE_RUN:
+ /*
+ * If the remote goes to RESET, we need to follow immediately.
+ */
+ if (peer_state == IVSHM_NET_STATE_RESET) {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+ }
+ break;
+ }
+
+ virt_wmb();
+ WRITE_ONCE(in->last_peer_state, peer_state);
+}
+
+static void ivshm_net_check_state(struct ivshm_net *in)
+{
+ if (in->state_table[in->peer_id] != in->last_peer_state ||
+ !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ queue_work(in->state_wq, &in->state_work);
+}
+
+static irqreturn_t ivshm_net_int_state(int irq, void *data)
+{
+ struct ivshm_net *in = data;
+
+ ivshm_net_check_state(in);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ivshm_net_int_tx_rx(int irq, void *data)
+{
+ struct ivshm_net *in = data;
+
+ in->stats.tx_rx_interrupts++;
+
+ napi_schedule_irqoff(&in->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ivshm_net_intx(int irq, void *data)
+{
+ ivshm_net_int_state(irq, data);
+ ivshm_net_int_tx_rx(irq, data);
+
+ return IRQ_HANDLED;
+}
+
+static int ivshm_net_open(struct net_device *ndev)
+{
+ netdev_reset_queue(ndev);
+ ndev->operstate = IF_OPER_UP;
+ ivshm_net_run(ndev);
+
+ return 0;
+}
+
+static int ivshm_net_stop(struct net_device *ndev)
+{
+ ndev->operstate = IF_OPER_DOWN;
+ ivshm_net_do_stop(ndev);
+
+ return 0;
+}
+
+static int ivshm_net_change_mtu(struct net_device *ndev, int mtu)
+{
+ if (netif_running(ndev)) {
+ netdev_err(ndev, "must be stopped to change its MTU\n");
+ return -EBUSY;
+ }
+
+ ndev->mtu = mtu;
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ivshm_net_poll_controller(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ napi_schedule(&in->napi);
+}
+#endif
+
+static const struct net_device_ops ivshm_net_ops = {
+ .ndo_open = ivshm_net_open,
+ .ndo_stop = ivshm_net_stop,
+ .ndo_start_xmit = ivshm_net_xmit,
+ .ndo_change_mtu = ivshm_net_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ivshm_net_poll_controller,
+#endif
+};
+
+static const char ivshm_net_stats[][ETH_GSTRING_LEN] = {
+ "tx_rx_interrupts",
+ "tx_packets",
+ "tx_notify",
+ "tx_pause",
+ "rx_packets",
+ "rx_notify",
+ "napi_poll",
+ "napi_complete",
+ "napi_poll_0",
+ "napi_poll_1",
+ "napi_poll_2",
+ "napi_poll_4",
+ "napi_poll_8",
+ "napi_poll_16",
+ "napi_poll_32",
+ "napi_poll_64",
+ "napi_poll_128",
+ "napi_poll_256",
+};
+
+#define NUM_STATS ARRAY_SIZE(ivshm_net_stats)
+
+static int ivshm_net_get_sset_count(struct net_device *ndev, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return NUM_STATS;
+
+ return -EOPNOTSUPP;
+}
+
+static void ivshm_net_get_strings(struct net_device *ndev, u32 sset, u8 *buf)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(buf, &ivshm_net_stats, sizeof(ivshm_net_stats));
+}
+
+static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *estats, u64 *st)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ unsigned int n = 0;
+ unsigned int i;
+
+ st[n++] = in->stats.tx_rx_interrupts;
+ st[n++] = in->stats.tx_packets;
+ st[n++] = in->stats.tx_notify;
+ st[n++] = in->stats.tx_pause;
+ st[n++] = in->stats.rx_packets;
+ st[n++] = in->stats.rx_notify;
+ st[n++] = in->stats.napi_poll;
+ st[n++] = in->stats.napi_complete;
+
+ for (i = 0; i < ARRAY_SIZE(in->stats.napi_poll_n); i++)
+ st[n++] = in->stats.napi_poll_n[i];
+
+ memset(&in->stats, 0, sizeof(in->stats));
+}
+
+#define IVSHM_NET_REGS_LEN (3 * sizeof(u32) + 6 * sizeof(u16))
+
+static int ivshm_net_get_regs_len(struct net_device *ndev)
+{
+ return IVSHM_NET_REGS_LEN;
+}
+
+static void ivshm_net_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ u32 *reg32 = p;
+ u16 *reg16;
+
+ *reg32++ = in->state;
+ *reg32++ = in->last_peer_state;
+ *reg32++ = in->qlen;
+
+ reg16 = (u16 *)reg32;
+
+ *reg16++ = in->tx.vr.avail ? in->tx.vr.avail->idx : 0;
+ *reg16++ = in->tx.vr.used ? in->tx.vr.used->idx : 0;
+ *reg16++ = in->tx.vr.avail ? vring_avail_event(&in->tx.vr) : 0;
+
+ *reg16++ = in->rx.vr.avail ? in->rx.vr.avail->idx : 0;
+ *reg16++ = in->rx.vr.used ? in->rx.vr.used->idx : 0;
+ *reg16++ = in->rx.vr.avail ? vring_avail_event(&in->rx.vr) : 0;
+}
+
+static const struct ethtool_ops ivshm_net_ethtool_ops = {
+ .get_sset_count = ivshm_net_get_sset_count,
+ .get_strings = ivshm_net_get_strings,
+ .get_ethtool_stats = ivshm_net_get_ethtool_stats,
+ .get_regs_len = ivshm_net_get_regs_len,
+ .get_regs = ivshm_net_get_regs,
+};
+
+static u64 get_config_qword(struct pci_dev *pdev, unsigned int pos)
+{
+ u32 lo, hi;
+
+ pci_read_config_dword(pdev, pos, &lo);
+ pci_read_config_dword(pdev, pos + 4, &hi);
+ return lo | ((u64)hi << 32);
+}
+
+static int ivshm_net_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ phys_addr_t output_sections_addr, section_addr;
+ resource_size_t section_sz, output_section_sz;
+ void *state_table, *output_sections;
+ struct ivshm_regs __iomem *regs;
+ struct net_device *ndev;
+ struct ivshm_net *in;
+ unsigned int cap_pos;
+ char *device_name;
+ int vendor_cap;
+ u32 id, dword;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device: %d\n", ret);
+ return ret;
+ }
+
+ ret = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", ret);
+ return ret;
+ }
+
+ regs = pcim_iomap_table(pdev)[0];
+
+ id = readl(&regs->id);
+ if (id > 1) {
+ dev_err(&pdev->dev, "invalid ID %d\n", id);
+ return -EINVAL;
+ }
+ if (readl(&regs->max_peers) > 2) {
+ dev_err(&pdev->dev, "only 2 peers supported\n");
+ return -EINVAL;
+ }
+
+ vendor_cap = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
+ if (vendor_cap < 0) {
+ dev_err(&pdev->dev, "missing vendor capability\n");
+ return -EINVAL;
+ }
+
+ if (pci_resource_len(pdev, 2) > 0) {
+ section_addr = pci_resource_start(pdev, 2);
+ } else {
+ cap_pos = vendor_cap + IVSHM_CFG_ADDRESS;
+ section_addr = get_config_qword(pdev, cap_pos);
+ }
+
+ cap_pos = vendor_cap + IVSHM_CFG_STATE_TAB_SZ;
+ pci_read_config_dword(pdev, cap_pos, &dword);
+ section_sz = dword;
+
+ if (!devm_request_mem_region(&pdev->dev, section_addr, section_sz,
+ DRV_NAME))
+ return -EBUSY;
+
+ state_table = devm_memremap(&pdev->dev, section_addr, section_sz,
+ MEMREMAP_WB);
+ if (!state_table)
+ return -ENOMEM;
+
+ output_sections_addr = section_addr + section_sz;
+
+ cap_pos = vendor_cap + IVSHM_CFG_RW_SECTION_SZ;
+ section_sz = get_config_qword(pdev, cap_pos);
+ if (section_sz > 0) {
+ dev_info(&pdev->dev, "R/W section detected - "
+ "unused by this driver version\n");
+ output_sections_addr += section_sz;
+ }
+
+ cap_pos = vendor_cap + IVSHM_CFG_OUTPUT_SECTION_SZ;
+ output_section_sz = get_config_qword(pdev, cap_pos);
+ if (output_section_sz == 0) {
+ dev_err(&pdev->dev, "Missing input/output sections\n");
+ return -EINVAL;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, output_sections_addr,
+ output_section_sz * 2, DRV_NAME))
+ return -EBUSY;
+
+ output_sections = devm_memremap(&pdev->dev, output_sections_addr,
+ output_section_sz * 2, MEMREMAP_WB);
+ if (!output_sections)
+ return -ENOMEM;
+
+ section_addr = output_sections_addr + output_section_sz * id;
+ dev_info(&pdev->dev, "TX memory at %pa, size %pa\n",
+ &section_addr, &output_section_sz);
+ section_addr = output_sections_addr + output_section_sz * !id;
+ dev_info(&pdev->dev, "RX memory at %pa, size %pa\n",
+ &section_addr, &output_section_sz);
+
+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME,
+ dev_name(&pdev->dev));
+ if (!device_name)
+ return -ENOMEM;
+
+ ndev = alloc_etherdev(sizeof(*in));
+ if (!ndev)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ in = netdev_priv(ndev);
+ in->ivshm_regs = regs;
+ in->state_table = state_table;
+
+ in->shm[IVSHM_NET_SECTION_TX] =
+ output_sections + output_section_sz * id;
+ in->shm[IVSHM_NET_SECTION_RX] =
+ output_sections + output_section_sz * !id;
+
+ in->shmlen = output_section_sz;
+
+ in->peer_id = !id;
+ in->pdev = pdev;
+
+ ret = ivshm_net_calc_qsize(ndev);
+ if (ret)
+ goto err_free;
+
+ in->state_wq = alloc_ordered_workqueue(device_name, 0);
+ if (!in->state_wq)
+ goto err_free;
+
+ INIT_WORK(&in->state_work, ivshm_net_state_change);
+
+ eth_random_addr(ndev->dev_addr);
+ ndev->netdev_ops = &ivshm_net_ops;
+ ndev->ethtool_ops = &ivshm_net_ethtool_ops;
+ ndev->mtu = min_t(u32, IVSHM_NET_MTU_DEF, in->qsize / 16);
+ ndev->min_mtu = ETH_MIN_MTU;
+ ndev->max_mtu = min_t(u32, ETH_MAX_MTU, in->qsize / 4);
+ ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG;
+ ndev->features = ndev->hw_features;
+
+ netif_carrier_off(ndev);
+ netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto err_wq;
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 2, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
+ if (ret < 0)
+ goto err_alloc_irq;
+
+ if (pdev->msix_enabled) {
+ if (ret != 2) {
+ ret = -EBUSY;
+ goto err_request_irq;
+ }
+
+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s-state[%s]", DRV_NAME,
+ dev_name(&pdev->dev));
+ if (!device_name) {
+ ret = -ENOMEM;
+ goto err_request_irq;
+ }
+
+ ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE),
+ ivshm_net_int_state, 0, device_name, in);
+ if (ret)
+ goto err_request_irq;
+
+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s-tx-rx[%s]", DRV_NAME,
+ dev_name(&pdev->dev));
+ if (!device_name) {
+ ret = -ENOMEM;
+ goto err_request_irq2;
+ }
+
+ ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX),
+ ivshm_net_int_tx_rx, 0, device_name, in);
+ if (ret)
+ goto err_request_irq2;
+
+ in->tx_rx_vector = IVSHM_NET_MSIX_TX_RX;
+ } else {
+ ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_intx, 0,
+ device_name, in);
+ if (ret)
+ goto err_request_irq;
+
+ in->tx_rx_vector = 0;
+ }
+
+ pci_set_master(pdev);
+
+ pci_write_config_byte(pdev, vendor_cap + IVSHM_CFG_PRIV_CNTL, 0);
+ writel(IVSHM_INT_ENABLE, &in->ivshm_regs->int_control);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state);
+ ivshm_net_check_state(in);
+
+ return 0;
+
+err_request_irq2:
+ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in);
+err_request_irq:
+ pci_free_irq_vectors(pdev);
+err_alloc_irq:
+ unregister_netdev(ndev);
+err_wq:
+ destroy_workqueue(in->state_wq);
+err_free:
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static void ivshm_net_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state);
+ writel(0, &in->ivshm_regs->int_control);
+
+ if (pdev->msix_enabled) {
+ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in);
+ free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX), in);
+ } else {
+ free_irq(pci_irq_vector(pdev, 0), in);
+ }
+ pci_free_irq_vectors(pdev);
+
+ unregister_netdev(ndev);
+ cancel_work_sync(&in->state_work);
+ destroy_workqueue(in->state_wq);
+ free_netdev(ndev);
+}
+
+static const struct pci_device_id ivshm_net_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_IVSHMEM),
+ (PCI_CLASS_OTHERS << 16) | IVSHM_PROTO_NET, 0xffffff },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ivshm_net_id_table);
+
+static struct pci_driver ivshm_net_driver = {
+ .name = DRV_NAME,
+ .id_table = ivshm_net_id_table,
+ .probe = ivshm_net_probe,
+ .remove = ivshm_net_remove,
+};
+module_pci_driver(ivshm_net_driver);
+
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dcf2051ef2c0..24b2581b8e1e 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -288,6 +288,16 @@ config AT803X_PHY
---help---
Currently supports the AT8030 and AT8035 model
+config AT803X_PHY_SMART_EEE
+ depends on AT803X_PHY
+ default n
+ tristate "SmartEEE feature for AT803X PHYs"
+ ---help---
+ Enables the Atheros SmartEEE feature (not IEEE 802.3az). When 2 PHYs
+ which support this feature are connected back-to-back, they may
+ negotiate a low-power sleep mode autonomously, without the Ethernet
+ controller's knowledge. May cause packet loss.
+
config BCM63XX_PHY
tristate "Broadcom 63xx SOCs internal PHY"
depends on BCM63XX || COMPILE_TEST
@@ -380,6 +390,11 @@ config ICPLUS_PHY
---help---
Currently supports the IP175C and IP1001 PHYs.
+config INPHI_PHY
+ tristate "Inphi CDR 10G/25G Ethernet PHY"
+ ---help---
+ Currently supports the IN112525_S03 part @ 25G
+
config INTEL_XWAY_PHY
tristate "Intel XWAY PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a03437e091f3..c0bc15a8c177 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o
obj-$(CONFIG_DP83867_PHY) += dp83867.o
obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_INPHI_PHY) += inphi.o
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_LXT_PHY) += lxt.o
diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index 975789d9349d..846c60c2cb80 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -22,6 +22,14 @@
#define PHY_ID_AQR107 0x03a1b4e0
#define PHY_ID_AQCS109 0x03a1b5c2
#define PHY_ID_AQR405 0x03a1b4b0
+#define PHY_ID_AQR112 0x03a1b662
+#define PHY_ID_AQR412 0x03a1b712
+
+/* PCS counters */
+#define MDIO_C45_PCS_STAT_XFI_TX_GOOD_FRAMES 0xc860
+#define MDIO_C45_PCS_STAT_XFI_TX_BAD_FRAMES 0xc862
+#define MDIO_C45_PCS_STAT_XFI_RX_GOOD_FRAMES 0xe860
+#define MDIO_C45_PCS_STAT_XFI_RX_BAD_FRAMES 0xe862
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
@@ -31,6 +39,9 @@
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10
+#define MDIO_PHYXS_VEND_PROV2 0xC441
+#define MDIO_PHYXS_VEND_PROV2_USX_AN BIT(3)
+
#define MDIO_AN_VEND_PROV 0xc400
#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15)
#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14)
@@ -121,13 +132,39 @@
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
+/* registers in MDIO_MMD_VEND1 region */
+#define AQUANTIA_VND1_GLOBAL_SC 0x000
+#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb)
+
+/* global start rate, the protocol associated with this speed is used by default
+ * on SI.
+ */
+#define AQUANTIA_VND1_GSTART_RATE 0x31a
+#define AQUANTIA_VND1_GSTART_RATE_OFF 0
+#define AQUANTIA_VND1_GSTART_RATE_100M 1
+#define AQUANTIA_VND1_GSTART_RATE_1G 2
+#define AQUANTIA_VND1_GSTART_RATE_10G 3
+#define AQUANTIA_VND1_GSTART_RATE_2_5G 4
+#define AQUANTIA_VND1_GSTART_RATE_5G 5
+
+/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
+#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b
+#define AQUANTIA_VND1_GSYSCFG_100M 0
+#define AQUANTIA_VND1_GSYSCFG_1G 1
+#define AQUANTIA_VND1_GSYSCFG_2_5G 2
+#define AQUANTIA_VND1_GSYSCFG_5G 3
+#define AQUANTIA_VND1_GSYSCFG_10G 4
+
struct aqr107_hw_stat {
const char *name;
int reg;
int size;
+ int devad;
};
-#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
+#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s, \
+ MDIO_MMD_C22EXT}
+#define C45_PCS_STAT(n, r, s) { n, MDIO_C45_PCS_STAT_ ## r, s, MDIO_MMD_PCS }
static const struct aqr107_hw_stat aqr107_hw_stats[] = {
SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
@@ -139,6 +176,10 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = {
SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
+ C45_PCS_STAT("xfi_rx_good_frames", XFI_RX_GOOD_FRAMES, 26),
+ C45_PCS_STAT("xfi_rx_bad_frames", XFI_RX_BAD_FRAMES, 26),
+ C45_PCS_STAT("xfi_tx_good_frames", XFI_TX_GOOD_FRAMES, 26),
+ C45_PCS_STAT("xfi_tx_bad_frames", XFI_TX_BAD_FRAMES, 26),
};
#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
@@ -168,13 +209,13 @@ static u64 aqr107_get_stat(struct phy_device *phydev, int index)
u64 ret;
int val;
- val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg);
+ val = phy_read_mmd(phydev, stat->devad, stat->reg);
if (val < 0)
return U64_MAX;
ret = val & GENMASK(len_l - 1, 0);
if (len_h) {
- val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1);
+ val = phy_read_mmd(phydev, stat->devad, stat->reg + 1);
if (val < 0)
return U64_MAX;
@@ -241,6 +282,61 @@ static int aqr_config_aneg(struct phy_device *phydev)
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
+static struct {
+ u16 syscfg;
+ int cnt;
+ u16 start_rate;
+} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
+ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
+ AQUANTIA_VND1_GSTART_RATE_1G},
+ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
+ AQUANTIA_VND1_GSTART_RATE_2_5G},
+ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+};
+
+/* Sets up protocol on system side before calling aqr_config_aneg */
+static int aqr_config_aneg_set_prot(struct phy_device *phydev)
+{
+ int if_type = phydev->interface;
+ int i;
+
+ if (!aquantia_syscfg[if_type].cnt)
+ return 0;
+
+ /* set PHY in low power mode so we can configure protocols */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
+ AQUANTIA_VND1_GLOBAL_SC_LP);
+ mdelay(10);
+
+ /* set the default rate to enable the SI link */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
+ aquantia_syscfg[if_type].start_rate);
+
+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
+ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ AQUANTIA_VND1_GSYSCFG_BASE + i);
+ if (!reg)
+ continue;
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ AQUANTIA_VND1_GSYSCFG_BASE + i,
+ aquantia_syscfg[if_type].syscfg);
+ }
+
+ if (if_type == PHY_INTERFACE_MODE_USXGMII)
+ phy_write_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_PROV2,
+ MDIO_PHYXS_VEND_PROV2_USX_AN);
+
+ /* wake PHY back up */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
+ mdelay(10);
+
+ return aqr_config_aneg(phydev);
+}
+
static int aqr_config_intr(struct phy_device *phydev)
{
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
@@ -682,6 +778,30 @@ static struct phy_driver aqr_driver[] = {
.ack_interrupt = aqr_ack_interrupt,
.read_status = aqr_read_status,
},
+{
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
+ .name = "Aquantia AQR112",
+ .probe = aqr107_probe,
+ .config_aneg = aqr_config_aneg_set_prot,
+ .config_intr = aqr_config_intr,
+ .ack_interrupt = aqr_ack_interrupt,
+ .read_status = aqr_read_status,
+ .get_sset_count = aqr107_get_sset_count,
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+},
+{
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
+ .name = "Aquantia AQR412",
+ .probe = aqr107_probe,
+ .config_aneg = aqr_config_aneg_set_prot,
+ .config_intr = aqr_config_intr,
+ .ack_interrupt = aqr_ack_interrupt,
+ .read_status = aqr_read_status,
+ .get_sset_count = aqr107_get_sset_count,
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+},
};
module_phy_driver(aqr_driver);
@@ -694,6 +814,8 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
{ }
};
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 1eb5d4fb8925..6808009f9512 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -44,8 +44,13 @@
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
+#define AT803X_SMARTEEE_CTL3_OFFSET 0x805D
+#define AT803X_MMD_ACCESS_CONTROL 0x0D
+#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
+#define AT803X_FUNC_DATA 0x4003
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
+#define AT803X_SMARTEEE_DISABLED_VAL 0x1000
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
@@ -62,17 +67,26 @@
#define AT803X_DEBUG_REG_5 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
+#define AT803X_LPI_EN BIT(8)
+
+#define AT803X_DEBUG_REG_31 0x1f
+#define AT803X_VDDIO_1P8V_EN 0x8
+
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
#define ATH8035_PHY_ID 0x004dd072
#define AT803X_PHY_ID_MASK 0xffffffef
+#define AT803X_EEE_FEATURE_DISABLE (1 << 1)
+#define AT803X_VDDIO_1P8V (1 << 2)
+
MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
struct at803x_priv {
bool phy_reset:1;
+ u32 quirks;
};
struct at803x_context {
@@ -136,6 +150,39 @@ static int at803x_disable_tx_delay(struct phy_device *phydev)
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
}
+static inline int at803x_set_vddio_1p8v(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_31, 0,
+ AT803X_VDDIO_1P8V_EN);
+}
+
+static int at803x_disable_eee(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_DEVICE_ADDR);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ AT803X_SMARTEEE_CTL3_OFFSET);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_FUNC_DATA);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ AT803X_SMARTEEE_DISABLED_VAL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
/* save relevant PHY registers to private copy */
static void at803x_context_save(struct phy_device *phydev,
struct at803x_context *context)
@@ -249,14 +296,41 @@ static int at803x_probe(struct phy_device *phydev)
if (!priv)
return -ENOMEM;
+ if (of_property_read_bool(dev->of_node, "at803x,eee-disabled"))
+ priv->quirks |= AT803X_EEE_FEATURE_DISABLE;
+
+ if (of_property_read_bool(dev->of_node, "at803x,vddio-1p8v"))
+ priv->quirks |= AT803X_VDDIO_1P8V;
+
phydev->priv = priv;
return 0;
}
+static void at803x_enable_smart_eee(struct phy_device *phydev, int on)
+{
+ int value;
+
+ /* 5.1.11 Smart_eee control3 */
+ value = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x805D);
+ if (on)
+ value |= AT803X_LPI_EN;
+ else
+ value &= ~AT803X_LPI_EN;
+ phy_write_mmd(phydev, MDIO_MMD_PCS, 0x805D, value);
+}
+
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
+ struct at803x_priv *priv = phydev->priv;
+
+
+#ifdef CONFIG_AT803X_PHY_SMART_EEE
+ at803x_enable_smart_eee(phydev, 1);
+#else
+ at803x_enable_smart_eee(phydev, 0);
+#endif
/* The RX and TX delay default is:
* after HW reset: RX delay enabled and TX delay disabled
@@ -277,6 +351,18 @@ static int at803x_config_init(struct phy_device *phydev)
else
ret = at803x_disable_tx_delay(phydev);
+ if (priv->quirks & AT803X_VDDIO_1P8V) {
+ ret = at803x_set_vddio_1p8v(phydev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->quirks & AT803X_EEE_FEATURE_DISABLE) {
+ ret = at803x_disable_eee(phydev);
+ if (ret < 0)
+ return ret;
+ }
+
return ret;
}
diff --git a/drivers/net/phy/inphi.c b/drivers/net/phy/inphi.c
new file mode 100644
index 000000000000..65d3059ceae4
--- /dev/null
+++ b/drivers/net/phy/inphi.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright 2018 NXP
+ * Copyright 2018 INPHI
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * 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 HOLDER 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.
+ *
+ * Inphi is a registered trademark of Inphi Corporation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/mdio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#define PHY_ID_IN112525 0x02107440
+
+#define INPHI_S03_DEVICE_ID_MSB 0x2
+#define INPHI_S03_DEVICE_ID_LSB 0x3
+
+#define ALL_LANES 4
+#define INPHI_POLL_DELAY 2500
+
+#define PHYCTRL_REG1 0x0012
+#define PHYCTRL_REG2 0x0014
+#define PHYCTRL_REG3 0x0120
+#define PHYCTRL_REG4 0x0121
+#define PHYCTRL_REG5 0x0180
+#define PHYCTRL_REG6 0x0580
+#define PHYCTRL_REG7 0x05C4
+#define PHYCTRL_REG8 0x01C8
+#define PHYCTRL_REG9 0x0521
+
+#define PHYSTAT_REG1 0x0021
+#define PHYSTAT_REG2 0x0022
+#define PHYSTAT_REG3 0x0123
+
+#define PHYMISC_REG1 0x0025
+#define PHYMISC_REG2 0x002c
+#define PHYMISC_REG3 0x00b3
+#define PHYMISC_REG4 0x0181
+#define PHYMISC_REG5 0x019D
+#define PHYMISC_REG6 0x0198
+#define PHYMISC_REG7 0x0199
+#define PHYMISC_REG8 0x0581
+#define PHYMISC_REG9 0x0598
+#define PHYMISC_REG10 0x059c
+#define PHYMISC_REG20 0x01B0
+#define PHYMISC_REG21 0x01BC
+#define PHYMISC_REG22 0x01C0
+
+#define RX_VCO_CODE_OFFSET 5
+#define VCO_CODE 390
+
+int vco_codes[ALL_LANES] = {
+ VCO_CODE,
+ VCO_CODE,
+ VCO_CODE,
+ VCO_CODE
+};
+
+static void mykmod_work_handler(struct work_struct *w);
+
+static struct workqueue_struct *wq;
+static DECLARE_DELAYED_WORK(mykmod_work, mykmod_work_handler);
+static unsigned long onesec;
+struct phy_device *inphi_phydev;
+
+static int mdio_wr(u32 regnum, u16 val)
+{
+ regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
+
+ return mdiobus_write(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
+ regnum, val);
+}
+
+static int mdio_rd(u32 regnum)
+{
+ regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
+
+ return mdiobus_read(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
+ regnum);
+}
+
+
+int bit_test(int value, int bit_field)
+{
+ int result;
+ int bit_mask = (1 << bit_field);
+
+ result = ((value & bit_mask) == bit_mask);
+ return result;
+}
+
+int tx_pll_lock_test(int lane)
+{
+ int i, val, locked = 1;
+
+ if (lane == ALL_LANES) {
+ for (i = 0; i < ALL_LANES; i++) {
+ val = mdio_rd(i * 0x100 + PHYSTAT_REG3);
+ locked = locked & bit_test(val, 15);
+ }
+ } else {
+ val = mdio_rd(lane * 0x100 + PHYSTAT_REG3);
+ locked = locked & bit_test(val, 15);
+ }
+
+ return locked;
+}
+
+void rx_reset_assert(int lane)
+{
+ int mask, val;
+
+ if (lane == ALL_LANES) {
+ val = mdio_rd(PHYMISC_REG2);
+ mask = (1 << 15);
+ mdio_wr(PHYMISC_REG2, val + mask);
+ } else {
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
+ mask = (1 << 6);
+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
+ }
+}
+
+void rx_reset_de_assert(int lane)
+{
+ int mask, val;
+
+ if (lane == ALL_LANES) {
+ val = mdio_rd(PHYMISC_REG2);
+ mask = 0xffff - (1 << 15);
+ mdio_wr(PHYMISC_REG2, val & mask);
+ } else {
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
+ mask = 0xffff - (1 << 6);
+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
+ }
+}
+
+void rx_powerdown_assert(int lane)
+{
+ int mask, val;
+
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
+ mask = (1 << 5);
+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
+}
+
+void rx_powerdown_de_assert(int lane)
+{
+ int mask, val;
+
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
+ mask = 0xffff - (1 << 5);
+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
+}
+
+void tx_pll_assert(int lane)
+{
+ int val, recal;
+
+ if (lane == ALL_LANES) {
+ val = mdio_rd(PHYMISC_REG2);
+ recal = (1 << 12);
+ mdio_wr(PHYMISC_REG2, val | recal);
+ } else {
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
+ recal = (1 << 15);
+ mdio_wr(lane * 0x100 + PHYCTRL_REG4, val | recal);
+ }
+}
+
+void tx_pll_de_assert(int lane)
+{
+ int recal, val;
+
+ if (lane == ALL_LANES) {
+ val = mdio_rd(PHYMISC_REG2);
+ recal = 0xefff;
+ mdio_wr(PHYMISC_REG2, val & recal);
+ } else {
+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
+ recal = 0x7fff;
+ mdio_wr(lane * 0x100 + PHYCTRL_REG4, val & recal);
+ }
+}
+
+void tx_core_assert(int lane)
+{
+ int recal, val, val2, core_reset;
+
+ if (lane == 4) {
+ val = mdio_rd(PHYMISC_REG2);
+ recal = 1 << 10;
+ mdio_wr(PHYMISC_REG2, val | recal);
+ } else {
+ val2 = mdio_rd(PHYMISC_REG3);
+ core_reset = (1 << (lane + 8));
+ mdio_wr(PHYMISC_REG3, val2 | core_reset);
+ }
+}
+
+void lol_disable(int lane)
+{
+ int val, mask;
+
+ val = mdio_rd(PHYMISC_REG3);
+ mask = 1 << (lane + 4);
+ mdio_wr(PHYMISC_REG3, val | mask);
+}
+
+void tx_core_de_assert(int lane)
+{
+ int val, recal, val2, core_reset;
+
+ if (lane == ALL_LANES) {
+ val = mdio_rd(PHYMISC_REG2);
+ recal = 0xffff - (1 << 10);
+ mdio_wr(PHYMISC_REG2, val & recal);
+ } else {
+ val2 = mdio_rd(PHYMISC_REG3);
+ core_reset = 0xffff - (1 << (lane + 8));
+ mdio_wr(PHYMISC_REG3, val2 & core_reset);
+ }
+}
+
+void tx_restart(int lane)
+{
+ tx_core_assert(lane);
+ tx_pll_assert(lane);
+ tx_pll_de_assert(lane);
+ usleep_range(1500, 1600);
+ tx_core_de_assert(lane);
+}
+
+void disable_lane(int lane)
+{
+ rx_reset_assert(lane);
+ rx_powerdown_assert(lane);
+ tx_core_assert(lane);
+ lol_disable(lane);
+}
+
+void toggle_reset(int lane)
+{
+ int reg, val, orig;
+
+ if (lane == ALL_LANES) {
+ mdio_wr(PHYMISC_REG2, 0x8000);
+ udelay(100);
+ mdio_wr(PHYMISC_REG2, 0x0000);
+ } else {
+ reg = lane * 0x100 + PHYCTRL_REG8;
+ val = (1 << 6);
+ orig = mdio_rd(reg);
+ mdio_wr(reg, orig + val);
+ udelay(100);
+ mdio_wr(reg, orig);
+ }
+}
+
+int az_complete_test(int lane)
+{
+ int success = 1, value;
+
+ if (lane == 0 || lane == ALL_LANES) {
+ value = mdio_rd(PHYCTRL_REG5);
+ success = success & bit_test(value, 2);
+ }
+ if (lane == 1 || lane == ALL_LANES) {
+ value = mdio_rd(PHYCTRL_REG5 + 0x100);
+ success = success & bit_test(value, 2);
+ }
+ if (lane == 2 || lane == ALL_LANES) {
+ value = mdio_rd(PHYCTRL_REG5 + 0x200);
+ success = success & bit_test(value, 2);
+ }
+ if (lane == 3 || lane == ALL_LANES) {
+ value = mdio_rd(PHYCTRL_REG5 + 0x300);
+ success = success & bit_test(value, 2);
+ }
+
+ return success;
+}
+
+void save_az_offsets(int lane)
+{
+ int i;
+
+#define AZ_OFFSET_LANE_UPDATE(reg, lane) \
+ mdio_wr((reg) + (lane) * 0x100, \
+ (mdio_rd((reg) + (lane) * 0x100) >> 8))
+
+ if (lane == ALL_LANES) {
+ for (i = 0; i < ALL_LANES; i++) {
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, i);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, i);
+ }
+ } else {
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, lane);
+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, lane);
+ }
+
+ mdio_wr(PHYCTRL_REG7, 0x0001);
+}
+
+void save_vco_codes(int lane)
+{
+ int i;
+
+ if (lane == ALL_LANES) {
+ for (i = 0; i < ALL_LANES; i++) {
+ vco_codes[i] = mdio_rd(PHYMISC_REG5 + i * 0x100);
+ mdio_wr(PHYMISC_REG5 + i * 0x100,
+ vco_codes[i] + RX_VCO_CODE_OFFSET);
+ }
+ } else {
+ vco_codes[lane] = mdio_rd(PHYMISC_REG5 + lane * 0x100);
+ mdio_wr(PHYMISC_REG5 + lane * 0x100,
+ vco_codes[lane] + RX_VCO_CODE_OFFSET);
+ }
+}
+
+int inphi_lane_recovery(int lane)
+{
+ int i, value, az_pass;
+
+ switch (lane) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ rx_reset_assert(lane);
+ mdelay(20);
+ break;
+ case ALL_LANES:
+ mdio_wr(PHYMISC_REG2, 0x9C00);
+ mdelay(20);
+ do {
+ value = mdio_rd(PHYMISC_REG2);
+ udelay(10);
+ } while (!bit_test(value, 4));
+ break;
+ default:
+ dev_err(&inphi_phydev->mdio.dev,
+ "Incorrect usage of APIs in %s driver\n",
+ inphi_phydev->drv->name);
+ break;
+ }
+
+ if (lane == ALL_LANES) {
+ for (i = 0; i < ALL_LANES; i++)
+ mdio_wr(PHYMISC_REG7 + i * 0x100, VCO_CODE);
+ } else {
+ mdio_wr(PHYMISC_REG7 + lane * 0x100, VCO_CODE);
+ }
+
+ if (lane == ALL_LANES)
+ for (i = 0; i < ALL_LANES; i++)
+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0418);
+ else
+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0418);
+
+ mdio_wr(PHYCTRL_REG7, 0x0000);
+
+ rx_reset_de_assert(lane);
+
+ if (lane == ALL_LANES) {
+ for (i = 0; i < ALL_LANES; i++) {
+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0410);
+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0412);
+ }
+ } else {
+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0410);
+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0412);
+ }
+
+ for (i = 0; i < 64; i++) {
+ mdelay(100);
+ az_pass = az_complete_test(lane);
+ if (az_pass) {
+ save_az_offsets(lane);
+ break;
+ }
+ }
+
+ if (!az_pass) {
+ pr_info("in112525: AZ calibration fail @ lane=%d\n", lane);
+ return -1;
+ }
+
+ if (lane == ALL_LANES) {
+ mdio_wr(PHYMISC_REG8, 0x0002);
+ mdio_wr(PHYMISC_REG9, 0x2028);
+ mdio_wr(PHYCTRL_REG6, 0x0010);
+ usleep_range(1000, 1200);
+ mdio_wr(PHYCTRL_REG6, 0x0110);
+ mdelay(30);
+ mdio_wr(PHYMISC_REG9, 0x3020);
+ } else {
+ mdio_wr(PHYMISC_REG4 + lane * 0x100, 0x0002);
+ mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x2028);
+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0010);
+ usleep_range(1000, 1200);
+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0110);
+ mdelay(30);
+ mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x3020);
+ }
+
+ if (lane == ALL_LANES) {
+ mdio_wr(PHYMISC_REG2, 0x1C00);
+ mdio_wr(PHYMISC_REG2, 0x0C00);
+ } else {
+ tx_restart(lane);
+ mdelay(11);
+ }
+
+ if (lane == ALL_LANES) {
+ if (bit_test(mdio_rd(PHYMISC_REG2), 6) == 0)
+ return -1;
+ } else {
+ if (tx_pll_lock_test(lane) == 0)
+ return -1;
+ }
+
+ save_vco_codes(lane);
+
+ if (lane == ALL_LANES) {
+ mdio_wr(PHYMISC_REG2, 0x0400);
+ mdio_wr(PHYMISC_REG2, 0x0000);
+ value = mdio_rd(PHYCTRL_REG1);
+ value = value & 0xffbf;
+ mdio_wr(PHYCTRL_REG2, value);
+ } else {
+ tx_core_de_assert(lane);
+ }
+
+ if (lane == ALL_LANES) {
+ mdio_wr(PHYMISC_REG1, 0x8000);
+ mdio_wr(PHYMISC_REG1, 0x0000);
+ }
+ mdio_rd(PHYMISC_REG1);
+ mdio_rd(PHYMISC_REG1);
+ usleep_range(1000, 1200);
+ mdio_rd(PHYSTAT_REG1);
+ mdio_rd(PHYSTAT_REG2);
+
+ return 0;
+}
+
+static void mykmod_work_handler(struct work_struct *w)
+{
+ int all_lanes_lock, lane0_lock, lane1_lock, lane2_lock, lane3_lock;
+
+ lane0_lock = bit_test(mdio_rd(0x123), 15);
+ lane1_lock = bit_test(mdio_rd(0x223), 15);
+ lane2_lock = bit_test(mdio_rd(0x323), 15);
+ lane3_lock = bit_test(mdio_rd(0x423), 15);
+
+ /* check if the chip had any successful lane lock from the previous
+ * stage (e.g. u-boot)
+ */
+ all_lanes_lock = lane0_lock | lane1_lock | lane2_lock | lane3_lock;
+
+ if (!all_lanes_lock) {
+ /* start fresh */
+ inphi_lane_recovery(ALL_LANES);
+ } else {
+ if (!lane0_lock)
+ inphi_lane_recovery(0);
+ if (!lane1_lock)
+ inphi_lane_recovery(1);
+ if (!lane2_lock)
+ inphi_lane_recovery(2);
+ if (!lane3_lock)
+ inphi_lane_recovery(3);
+ }
+
+ queue_delayed_work(wq, &mykmod_work, onesec);
+}
+
+int inphi_probe(struct phy_device *phydev)
+{
+ int phy_id = 0, id_lsb = 0, id_msb = 0;
+
+ /* setup the inphi_phydev ptr for mdio_rd/mdio_wr APIs */
+ inphi_phydev = phydev;
+
+ /* Read device id from phy registers */
+ id_lsb = mdio_rd(INPHI_S03_DEVICE_ID_MSB);
+ if (id_lsb < 0)
+ return -ENXIO;
+
+ phy_id = id_lsb << 16;
+
+ id_msb = mdio_rd(INPHI_S03_DEVICE_ID_LSB);
+ if (id_msb < 0)
+ return -ENXIO;
+
+ phy_id |= id_msb;
+
+ /* Make sure the device tree binding matched the driver with the
+ * right device.
+ */
+ if (phy_id != phydev->drv->phy_id) {
+ dev_err(&phydev->mdio.dev,
+ "Error matching phy with %s driver\n",
+ phydev->drv->name);
+ return -ENODEV;
+ }
+
+ /* update the local phydev pointer, used inside all APIs */
+ inphi_phydev = phydev;
+ onesec = msecs_to_jiffies(INPHI_POLL_DELAY);
+
+ wq = create_singlethread_workqueue("inphi_kmod");
+ if (wq) {
+ queue_delayed_work(wq, &mykmod_work, onesec);
+ } else {
+ dev_err(&phydev->mdio.dev,
+ "Error creating kernel workqueue for %s driver\n",
+ phydev->drv->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static struct phy_driver inphi_driver[] = {
+{
+ .phy_id = PHY_ID_IN112525,
+ .phy_id_mask = 0x0ff0fff0,
+ .name = "Inphi 112525_S03",
+ .features = PHY_GBIT_FEATURES,
+ .probe = &inphi_probe,
+},
+};
+
+module_phy_driver(inphi_driver);
+
+static struct mdio_device_id __maybe_unused inphi_tbl[] = {
+ { PHY_ID_IN112525, 0x0ff0fff0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(mdio, inphi_tbl);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 5bf06eac04ba..e023def8a07c 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -408,8 +408,11 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
gpiod_set_value_cansleep(gpiod, 0);
}
- if (bus->reset)
- bus->reset(bus);
+ if (bus->reset) {
+ err = bus->reset(bus);
+ if (err)
+ goto reset_err;
+ }
for (i = 0; i < PHY_MAX_ADDR; i++) {
if ((bus->phy_mask & (1 << i)) == 0) {
@@ -439,6 +442,7 @@ error:
mdiodev->device_free(mdiodev);
}
+reset_err:
/* Put PHYs in RESET to save power */
if (bus->reset_gpiod)
gpiod_set_value_cansleep(bus->reset_gpiod, 1);
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 2339b9381d21..9186a24a4405 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -176,6 +176,8 @@ enum rgmii_rx_clock_delay {
#define SECURE_ON_PASSWD_LEN_4 0x4000
/* Extended Page 3 Registers */
+#define MSCC_PHY_SERDES_CON 16
+#define MSCC_PHY_SERDES_ANEG BIT(7)
#define MSCC_PHY_SERDES_TX_VALID_CNT 21
#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22
#define MSCC_PHY_SERDES_RX_VALID_CNT 28
@@ -2131,6 +2133,14 @@ static int vsc8514_config_init(struct phy_device *phydev)
mutex_unlock(&phydev->mdio.bus->mdio_lock);
+ ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
+ if (ret)
+ return ret;
+
+ ret = phy_set_bits(phydev, MSCC_PHY_SERDES_CON, MSCC_PHY_SERDES_ANEG);
+ if (ret)
+ return ret;
+
ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
if (ret)
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index b705d0bd798b..90eeff3986df 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/hwmon.h>
#include <linux/bitfield.h>
@@ -26,11 +27,15 @@
#define MII_ECTRL_WAKE_REQUEST BIT(0)
#define MII_CFG1 18
+#define MII_CFG1_MASTER_SLAVE BIT(15)
#define MII_CFG1_AUTO_OP BIT(14)
+#define MII_CFG1_MII_MODE GENMASK(9, 8)
#define MII_CFG1_SLEEP_CONFIRM BIT(6)
#define MII_CFG1_LED_MODE_MASK GENMASK(5, 4)
#define MII_CFG1_LED_MODE_LINKUP 0
#define MII_CFG1_LED_ENABLE BIT(3)
+#define MII_CFG1_MODE_REFCLK_IN 0x100
+#define MII_CFG1_MODE_REFCLK_OUT 0x200
#define MII_CFG2 19
#define MII_CFG2_SLEEP_REQUEST_TO GENMASK(1, 0)
@@ -49,9 +54,13 @@
#define MII_COMMCFG 27
#define MII_COMMCFG_AUTO_OP BIT(15)
+#define TJA110X_REFCLK_IN (0x1 << 0)
+
struct tja11xx_priv {
char *hwmon_name;
struct device *hwmon_dev;
+
+ u32 quirks;
};
struct tja11xx_phy_stats {
@@ -110,6 +119,11 @@ static int tja11xx_enable_link_control(struct phy_device *phydev)
return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
}
+static int tja11xx_disable_link_control(struct phy_device *phydev)
+{
+ return phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
+}
+
static int tja11xx_wakeup(struct phy_device *phydev)
{
int ret;
@@ -169,6 +183,8 @@ static int tja11xx_soft_reset(struct phy_device *phydev)
static int tja11xx_config_init(struct phy_device *phydev)
{
+ struct tja11xx_priv *priv = phydev->priv;
+ int reg_mask, reg_val = 0;
int ret;
ret = tja11xx_enable_reg_write(phydev);
@@ -181,15 +197,35 @@ static int tja11xx_config_init(struct phy_device *phydev)
switch (phydev->phy_id & PHY_ID_MASK) {
case PHY_ID_TJA1100:
- ret = phy_modify(phydev, MII_CFG1,
- MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
- MII_CFG1_LED_ENABLE,
- MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
- MII_CFG1_LED_ENABLE);
+ reg_mask = MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
+ MII_CFG1_LED_ENABLE;
+ reg_val = MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
+ MII_CFG1_LED_ENABLE;
+
+ reg_mask |= MII_CFG1_MII_MODE;
+ if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+ if (priv->quirks & TJA110X_REFCLK_IN)
+ reg_val |= MII_CFG1_MODE_REFCLK_IN;
+ else
+ reg_val |= MII_CFG1_MODE_REFCLK_OUT;
+ }
+
+ ret = phy_modify(phydev, MII_CFG1, reg_mask, reg_val);
if (ret)
return ret;
break;
case PHY_ID_TJA1101:
+ reg_mask = MII_CFG1_MII_MODE;
+ if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+ if (priv->quirks & TJA110X_REFCLK_IN)
+ reg_val = MII_CFG1_MODE_REFCLK_IN;
+ else
+ reg_val = MII_CFG1_MODE_REFCLK_OUT;
+ }
+ ret = phy_modify(phydev, MII_CFG1, reg_mask, reg_val);
+ if (ret)
+ return ret;
+
ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
if (ret)
return ret;
@@ -327,11 +363,128 @@ static const struct hwmon_chip_info tja11xx_hwmon_chip_info = {
.info = tja11xx_hwmon_info,
};
+/* Helper function, configures phy as master or slave
+ * @param phydev the phy to be configured
+ * @param setmaster ==0: set to slave
+ * !=0: set to master
+ * @return 0 on success, error code on failure
+ */
+static int set_master_cfg(struct phy_device *phydev, int setmaster)
+{
+ int err;
+
+ /* disable link control prior to master/slave cfg */
+ tja11xx_disable_link_control(phydev);
+
+ err = phy_modify(phydev, MII_CFG1, MII_CFG1_MASTER_SLAVE,
+ setmaster ? MII_CFG1_MASTER_SLAVE : 0);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* enable link control after master/slave cfg was set */
+ tja11xx_enable_link_control(phydev);
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error\n");
+ return err;
+}
+
+/* Helper function, reads master/slave configuration of phy
+ * @param phydev the phy to be read
+ *
+ * @return ==0: is slave
+ * !=0: is master
+ */
+static int get_master_cfg(struct phy_device *phydev)
+{
+ int reg_val;
+
+ /* read the current configuration */
+ reg_val = phy_read(phydev, MII_CFG1);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ return reg_val & MII_CFG1_MASTER_SLAVE;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error\n");
+ return reg_val;
+}
+
+/* This function handles read accesses to the node 'master_cfg' in
+ * sysfs.
+ * Depending on current configuration of the phy, the node reads
+ * 'master' or 'slave'
+ */
+static ssize_t master_cfg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int is_master;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ is_master = get_master_cfg(phydev);
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ is_master ? "master" : "slave");
+}
+
+/* This function handles write accesses to the node 'master_cfg' in sysfs.
+ * Depending on the value written to it, the phy is configured as
+ * master or slave
+ */
+static ssize_t master_cfg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int setmaster;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &setmaster);
+ if (err < 0)
+ goto phy_parse_error;
+
+ /* write configuration to the phy */
+ err = set_master_cfg(phydev, setmaster);
+ if (err < 0)
+ goto phy_cfg_error;
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse failed\n");
+ return err;
+
+phy_cfg_error:
+ dev_err(&phydev->mdio.dev, "phy cfg error\n");
+ return err;
+}
+
+static DEVICE_ATTR_RW(master_cfg);
+
+static struct attribute *nxp_sysfs_entries[] = {
+ &dev_attr_master_cfg.attr,
+ NULL
+};
+
+static struct attribute_group nxp_attribute_group = {
+ .name = "configuration",
+ .attrs = nxp_sysfs_entries,
+};
+
static int tja11xx_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct tja11xx_priv *priv;
int i;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -345,6 +498,16 @@ static int tja11xx_probe(struct phy_device *phydev)
if (hwmon_is_bad_char(priv->hwmon_name[i]))
priv->hwmon_name[i] = '_';
+ if (dev->of_node &&
+ of_property_read_bool(dev->of_node, "tja110x,refclk_in"))
+ priv->quirks |= TJA110X_REFCLK_IN;
+
+ /* register sysfs files */
+ phydev->priv = priv;
+ ret = sysfs_create_group(&phydev->mdio.dev.kobj, &nxp_attribute_group);
+ if (ret)
+ return ret;
+
priv->hwmon_dev =
devm_hwmon_device_register_with_info(dev, priv->hwmon_name,
phydev,
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 9412669b579c..790a5c81e533 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -379,7 +379,7 @@ int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv->read_mmd) {
+ if (phydev->drv && phydev->drv->read_mmd) {
val = phydev->drv->read_mmd(phydev, devad, regnum);
} else if (phydev->is_c45) {
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
@@ -436,7 +436,7 @@ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv->write_mmd) {
+ if (phydev->drv && phydev->drv->write_mmd) {
ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
} else if (phydev->is_c45) {
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9d0a306f0562..c02612787bfd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -240,13 +240,23 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!drv || !phydrv->suspend)
return false;
- /* PHY not attached? May suspend if the PHY has not already been
- * suspended as part of a prior call to phy_disconnect() ->
- * phy_detach() -> phy_suspend() because the parent netdev might be the
- * MDIO bus driver and clock gated at this point.
- */
+ /* netdev is NULL has three cases:
+ * - phy is not found
+ * - phy is found, match to general phy driver
+ * - phy is found, match to specifical phy driver
+ *
+ * Case 1: phy is not found, cannot communicate by MDIO bus.
+ * Case 2: phy is found:
+ * if phy dev driver probe/bind err, netdev is not __open__
+ * status, mdio bus is unregistered.
+ * if phy is detached, phy had entered suspended status.
+ * Case 3: phy is found, phy is detached, phy had entered suspended
+ * status.
+ *
+ * So, in here, it shouldn't set phy to suspend by calling mdio bus.
+ */
if (!netdev)
- goto out;
+ return false;
if (netdev->wol_enabled)
return false;
@@ -266,8 +276,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (device_may_wakeup(&netdev->dev))
return false;
-out:
- return !phydev->suspended;
+ return true;
}
static int mdio_bus_phy_suspend(struct device *dev)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index bf5bbb565cf5..6f9802d7415f 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -279,6 +279,7 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
switch (pl->link_config.interface) {
case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
phylink_set(pl->supported, 10baseT_Half);
phylink_set(pl->supported, 10baseT_Full);
phylink_set(pl->supported, 100baseT_Half);
@@ -295,6 +296,16 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
phylink_set(pl->supported, 2500baseX_Full);
break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ phylink_set(pl->supported, 10baseT_Half);
+ phylink_set(pl->supported, 10baseT_Full);
+ phylink_set(pl->supported, 100baseT_Half);
+ phylink_set(pl->supported, 100baseT_Full);
+ phylink_set(pl->supported, 1000baseT_Half);
+ phylink_set(pl->supported, 1000baseT_Full);
+ phylink_set(pl->supported, 2500baseX_Full);
+ break;
+
case PHY_INTERFACE_MODE_10GKR:
phylink_set(pl->supported, 10baseT_Half);
phylink_set(pl->supported, 10baseT_Full);
@@ -1009,7 +1020,8 @@ void phylink_start(struct phylink *pl)
if (irq <= 0)
mod_timer(&pl->link_poll, jiffies + HZ);
}
- if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
+ if ((pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
+ pl->config->pcs_poll)
mod_timer(&pl->link_poll, jiffies + HZ);
if (pl->phydev)
phy_start(pl->phydev);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 879ca37c8508..248ae3bb1e1f 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -9,6 +9,7 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*/
#include <linux/bitops.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/module.h>
@@ -28,6 +29,7 @@
#define RTL8211F_INSR 0x1d
+#define RTL8211F_RX_DELAY BIT(3)
#define RTL8211F_TX_DELAY BIT(8)
#define RTL8211E_TX_DELAY BIT(1)
#define RTL8211E_RX_DELAY BIT(2)
@@ -49,10 +51,20 @@
#define RTL_GENERIC_PHYID 0x001cc800
+/* page 0xa43, register 0x19 */
+#define RTL8211F_PHYCR2 0x19
+#define RTL8211F_CLKOUT_EN BIT(0)
+
+#define RTL821X_CLKOUT_EN_FEATURE (1 << 0)
+
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
+struct rtl821x_priv {
+ u32 quirks;
+};
+
static int rtl821x_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -63,6 +75,23 @@ static int rtl821x_write_page(struct phy_device *phydev, int page)
return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
}
+static int rtl821x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl821x_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (of_property_read_bool(dev->of_node, "rtl821x,clkout_en"))
+ priv->quirks |= RTL821X_CLKOUT_EN_FEATURE;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
static int rtl8201_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -171,42 +200,58 @@ static int rtl8211c_config_init(struct phy_device *phydev)
static int rtl8211f_config_init(struct phy_device *phydev)
{
- struct device *dev = &phydev->mdio.dev;
- u16 val;
+ u16 txdly = 0;
+ u16 rxdly = 0;
int ret;
+ struct rtl821x_priv *priv = phydev->priv;
/* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and
* rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin.
*/
switch (phydev->interface) {
- case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ rxdly = RTL8211F_RX_DELAY;
+ txdly = RTL8211F_TX_DELAY;
+ break;
case PHY_INTERFACE_MODE_RGMII_RXID:
- val = 0;
+ rxdly = RTL8211F_RX_DELAY;
break;
- case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_TXID:
- val = RTL8211F_TX_DELAY;
+ txdly = RTL8211F_TX_DELAY;
break;
default: /* the rest of the modes imply leaving delay as is. */
return 0;
}
- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
- val);
+ ret = phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, txdly);
if (ret < 0) {
- dev_err(dev, "Failed to update the TX delay register\n");
+ dev_err(&phydev->mdio.dev, "tx delay set failed\n");
return ret;
- } else if (ret) {
- dev_dbg(dev,
- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
- val ? "Enabling" : "Disabling");
+ }
+
+ ret = phy_modify_paged(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, rxdly);
+ if (ret < 0) {
+ dev_err(&phydev->mdio.dev, "rx delay set failed\n");
+ return ret;
+ }
+
+ if (priv->quirks & RTL821X_CLKOUT_EN_FEATURE) {
+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
+ RTL8211F_CLKOUT_EN, RTL8211F_CLKOUT_EN);
+ if (ret < 0) {
+ dev_err(&phydev->mdio.dev, "clkout enable failed\n");
+ return ret;
+ }
} else {
- dev_dbg(dev,
- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
- val ? "enabled" : "disabled");
+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
+ RTL8211F_CLKOUT_EN, 0);
+ if (ret < 0) {
+ dev_err(&phydev->mdio.dev, "clkout disable failed\n");
+ return ret;
+ }
}
- return 0;
+ return ret;
}
static int rtl8211e_config_init(struct phy_device *phydev)
@@ -514,6 +559,7 @@ static struct phy_driver realtek_drvs[] = {
}, {
PHY_ID_MATCH_EXACT(0x001cc916),
.name = "RTL8211F Gigabit Ethernet",
+ .probe = rtl821x_probe,
.config_init = &rtl8211f_config_init,
.ack_interrupt = &rtl8211f_ack_interrupt,
.config_intr = &rtl8211f_config_intr,
diff --git a/drivers/net/phy/swphy.c b/drivers/net/phy/swphy.c
index 53c214a22b95..17a6a0d28d5d 100644
--- a/drivers/net/phy/swphy.c
+++ b/drivers/net/phy/swphy.c
@@ -71,6 +71,7 @@ static const struct swmii_regs duplex[] = {
static int swphy_decode_speed(int speed)
{
switch (speed) {
+ case 10000:
case 1000:
return SWMII_SPEED_1000;
case 100:
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 1c98d781ae49..877568136fa2 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -40,6 +40,7 @@ source "drivers/net/wireless/intel/Kconfig"
source "drivers/net/wireless/intersil/Kconfig"
source "drivers/net/wireless/marvell/Kconfig"
source "drivers/net/wireless/mediatek/Kconfig"
+source "drivers/net/wireless/nxp/Kconfig"
source "drivers/net/wireless/ralink/Kconfig"
source "drivers/net/wireless/realtek/Kconfig"
source "drivers/net/wireless/rsi/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 6cfe74515c95..be1751c4c916 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/
obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/
obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/
obj-$(CONFIG_WLAN_VENDOR_MEDIATEK) += mediatek/
+obj-$(CONFIG_WLAN_VENDOR_NXP) += nxp/
obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/
obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/
obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index c492d2d2db1d..b34696bad5d7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/of.h>
#include <net/cfg80211.h>
#include <defs.h>
@@ -36,6 +37,7 @@
#include "sdio.h"
#include "core.h"
#include "common.h"
+#include "cfg80211.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
@@ -43,6 +45,7 @@
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
+#define SDIO_4373_FUNC2_BLOCKSIZE 256
/* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000
@@ -903,6 +906,7 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host)
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
+ unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
sdio_claim_host(sdiodev->func1);
@@ -912,11 +916,18 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
sdio_release_host(sdiodev->func1);
goto out;
}
- ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE);
+
+ if (sdiodev->func1->device == SDIO_DEVICE_ID_CYPRESS_4373) {
+ f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
+ }
+
+ ret = sdio_set_block_size(sdiodev->func2, f2_blksz);
if (ret) {
brcmf_err("Failed to set F2 blocksize\n");
sdio_release_host(sdiodev->func1);
goto out;
+ } else {
+ brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz);
}
/* increase F2 timeout */
@@ -964,6 +975,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43428),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
@@ -995,6 +1007,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
struct device *dev;
+ struct device *func_dev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
@@ -1010,6 +1023,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
/* prohibit ACPI power management for this device */
brcmf_sdiod_acpi_set_power_manageable(dev, 0);
+ func_dev = &func->card->sdio_func[0]->dev;
+ if (!func_dev->of_node ||
+ !of_device_is_compatible(func_dev->of_node, "brcm,bcm4329-fmac"))
+ return -ENODEV;
+
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
@@ -1039,6 +1057,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func1->dev, bus_if);
sdiodev->dev = &sdiodev->func1->dev;
+ dev_set_drvdata(&sdiodev->func2->dev, bus_if);
brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
@@ -1055,6 +1074,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
fail:
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func1->dev, NULL);
+ dev_set_drvdata(&sdiodev->func2->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
return err;
@@ -1093,6 +1113,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
brcmf_dbg(SDIO, "Exit\n");
}
+static void brcmf_ops_sdio_shutdown(struct device *dev)
+{
+ struct sdio_func *func = container_of(dev, struct sdio_func, dev);
+
+ brcmf_ops_sdio_remove(func);
+ return;
+}
+
void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -1109,14 +1137,26 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
mmc_pm_flag_t sdio_flags;
+ struct brcmf_cfg80211_info *config;
+ int retry = BRCMF_PM_WAIT_MAXRETRY;
func = container_of(dev, struct sdio_func, dev);
+ bus_if = dev_get_drvdata(dev);
+ config = bus_if->drvr->config;
+
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
+
if (func->num != 1)
return 0;
+ while (retry &&
+ config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
+ usleep_range(10000, 20000);
+ retry--;
+ }
+ if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
+ brcmf_err("timed out wait for cfg80211 suspended\n");
- bus_if = dev_get_drvdata(dev);
sdiodev = bus_if->bus_priv.sdio;
brcmf_sdiod_freezer_on(sdiodev);
@@ -1164,6 +1204,7 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#ifdef CONFIG_PM_SLEEP
.pm = &brcmf_sdio_pm_ops,
#endif /* CONFIG_PM_SLEEP */
+ .shutdown = brcmf_ops_sdio_shutdown,
.coredump = brcmf_dev_coredump,
},
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index cd813c69a178..803fcd520ca2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -3583,7 +3583,7 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
sizeof(wake_ind_le));
if (err) {
- bphy_err(drvr, "Get wowl_wakeind failed, err = %d\n", err);
+ brcmf_dbg(INFO, "cannet get wowl_wakeind, err = %d\n", err);
return;
}
@@ -3651,10 +3651,24 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_bus *bus_if = drvr->bus_if;
+ struct brcmf_cfg80211_info *config = drvr->config;
+ int retry = BRCMF_PM_WAIT_MAXRETRY;
brcmf_dbg(TRACE, "Enter\n");
+ config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMING;
+
if (cfg->wowl.active) {
+ /* wait for bus resumed */
+ while (retry && bus_if->state != BRCMF_BUS_UP) {
+ usleep_range(10000, 20000);
+ retry--;
+ }
+ if (!retry && bus_if->state != BRCMF_BUS_UP)
+ brcmf_err("timed out wait for bus resume\n");
+
brcmf_report_wowl_wakeind(wiphy, ifp);
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
@@ -3670,7 +3684,12 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
brcmf_notify_sched_scan_results);
cfg->wowl.nd_enabled = false;
}
+
+ /* disable packet filters */
+ brcmf_pktfilter_enable(ifp->ndev, false);
+
}
+ config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
return 0;
}
@@ -3728,6 +3747,9 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
cfg->wowl.active = true;
+
+ /* enable packet filters */
+ brcmf_pktfilter_enable(ifp->ndev, true);
}
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
@@ -3737,9 +3759,12 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif;
+ struct brcmf_cfg80211_info *config = ifp->drvr->config;
brcmf_dbg(TRACE, "Enter\n");
+ config->pm_state = BRCMF_CFG80211_PM_STATE_SUSPENDING;
+
/* if the primary net_device is not READY there is nothing
* we can do but pray resume goes smoothly.
*/
@@ -3754,7 +3779,8 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_abort_scanning(cfg);
- if (wowl == NULL) {
+ if (!wowl || !test_bit(BRCMF_VIF_STATUS_CONNECTED,
+ &ifp->vif->sme_state)) {
brcmf_bus_wowl_config(cfg->pub->bus_if, false);
list_for_each_entry(vif, &cfg->vif_list, list) {
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
@@ -3774,14 +3800,19 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
brcmf_set_mpc(ifp, 1);
} else {
- /* Configure WOWL paramaters */
- brcmf_configure_wowl(cfg, ifp, wowl);
+ /* Configure WOWL parameters */
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
+ brcmf_configure_wowl(cfg, ifp, wowl);
}
exit:
- brcmf_dbg(TRACE, "Exit\n");
+ /* set cfg80211 pm state to cfg80211 suspended state */
+ config->pm_state = BRCMF_CFG80211_PM_STATE_SUSPENDED;
+
/* clear any scanning activity */
cfg->scan_status = 0;
+
+ brcmf_dbg(TRACE, "Exit\n");
return 0;
}
@@ -4592,9 +4623,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
}
}
- if ((dev_role == NL80211_IFTYPE_AP) &&
- ((ifp->ifidx == 0) ||
- !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
+ if ((dev_role == NL80211_IFTYPE_AP) && (ifp->ifidx == 0)) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
bphy_err(drvr, "BRCMF_C_DOWN error %d\n",
@@ -5014,7 +5043,7 @@ static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
err = brcmf_fil_iovar_int_get(netdev_priv(ndev), "chanspec", &chanspec);
if (err) {
- bphy_err(drvr, "chanspec failed (%d)\n", err);
+ brcmf_dbg(TRACE, "chanspec failed (%d)\n", err);
return err;
}
@@ -5243,6 +5272,26 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
return brcmf_set_pmk(ifp, NULL, 0);
}
+static int
+brcmf_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
+ struct bss_parameters *params)
+{
+ struct brcmf_if *ifp;
+ int ret = 0;
+ u32 ap_isolate;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ ifp = netdev_priv(dev);
+ if (params->ap_isolate >= 0) {
+ ap_isolate = (u32)params->ap_isolate;
+ ret = brcmf_fil_iovar_int_set(ifp, "ap_isolate", ap_isolate);
+ if (ret < 0)
+ brcmf_err("ap_isolate iovar failed: ret=%d\n", ret);
+ }
+
+ return ret;
+}
+
static struct cfg80211_ops brcmf_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -5288,6 +5337,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.update_connect_params = brcmf_cfg80211_update_conn_params,
.set_pmk = brcmf_cfg80211_set_pmk,
.del_pmk = brcmf_cfg80211_del_pmk,
+ .change_bss = brcmf_cfg80211_change_bss,
};
struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings)
@@ -5438,12 +5488,125 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
conn_info->resp_ie_len = 0;
}
+u8 brcmf_map_prio_to_prec(void *config, u8 prio)
+{
+ struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
+
+ if (!cfg)
+ return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
+ (prio ^ 2) : prio;
+
+ /* For those AC(s) with ACM flag set to 1, convert its 4-level priority
+ * to an 8-level precedence which is the same as BE's */
+ if (prio > PRIO_8021D_EE &&
+ cfg->ac_priority[prio] == cfg->ac_priority[PRIO_8021D_BE])
+ return cfg->ac_priority[prio] * 2;
+
+ /* Conversion of 4-level priority to 8-level precedence */
+ if (prio == PRIO_8021D_BE || prio == PRIO_8021D_BK ||
+ prio == PRIO_8021D_CL || prio == PRIO_8021D_VO)
+ return cfg->ac_priority[prio] * 2;
+ else
+ return cfg->ac_priority[prio] * 2 + 1;
+}
+
+u8 brcmf_map_prio_to_aci(void *config, u8 prio)
+{
+ /* Prio here refers to the 802.1d priority in range of 0 to 7.
+ * ACI here refers to the WLAN AC Index in range of 0 to 3.
+ * This function will return ACI corresponding to input prio.
+ */
+ struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
+
+ if (cfg)
+ return cfg->ac_priority[prio];
+
+ return prio;
+}
+
+static void brcmf_wifi_prioritize_acparams(const
+ struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority)
+{
+ u8 aci;
+ u8 aifsn;
+ u8 ecwmin;
+ u8 ecwmax;
+ u8 acm;
+ u8 ranking_basis[EDCF_AC_COUNT];
+ u8 aci_prio[EDCF_AC_COUNT]; /* AC_BE, AC_BK, AC_VI, AC_VO */
+ u8 index;
+
+ for (aci = 0; aci < EDCF_AC_COUNT; aci++, acp++) {
+ aifsn = acp->ACI & EDCF_AIFSN_MASK;
+ acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0;
+ ecwmin = acp->ECW & EDCF_ECWMIN_MASK;
+ ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT;
+ brcmf_dbg(CONN, "ACI %d aifsn %d acm %d ecwmin %d ecwmax %d\n",
+ aci, aifsn, acm, ecwmin, ecwmax);
+ /* Default AC_VO will be the lowest ranking value */
+ ranking_basis[aci] = aifsn + ecwmin + ecwmax;
+ /* Initialise priority starting at 0 (AC_BE) */
+ aci_prio[aci] = 0;
+
+ /* If ACM is set, STA can't use this AC as per 802.11.
+ * Change the ranking to BE
+ */
+ if (aci != AC_BE && aci != AC_BK && acm == 1)
+ ranking_basis[aci] = ranking_basis[AC_BE];
+ }
+
+ /* Ranking method which works for AC priority
+ * swapping when values for cwmin, cwmax and aifsn are varied
+ * Compare each aci_prio against each other aci_prio
+ */
+ for (aci = 0; aci < EDCF_AC_COUNT; aci++) {
+ for (index = 0; index < EDCF_AC_COUNT; index++) {
+ if (index != aci) {
+ /* Smaller ranking value has higher priority,
+ * so increment priority for each ACI which has
+ * a higher ranking value
+ */
+ if (ranking_basis[aci] < ranking_basis[index])
+ aci_prio[aci]++;
+ }
+ }
+ }
+
+ /* By now, aci_prio[] will be in range of 0 to 3.
+ * Use ACI prio to get the new priority value for
+ * each 802.1d traffic type, in this range.
+ */
+
+ /* 802.1d 0,3 maps to BE */
+ priority[0] = aci_prio[AC_BE];
+ priority[3] = aci_prio[AC_BE];
+
+ /* 802.1d 1,2 maps to BK */
+ priority[1] = aci_prio[AC_BK];
+ priority[2] = aci_prio[AC_BK];
+
+ /* 802.1d 4,5 maps to VO */
+ priority[4] = aci_prio[AC_VI];
+ priority[5] = aci_prio[AC_VI];
+
+ /* 802.1d 6,7 maps to VO */
+ priority[6] = aci_prio[AC_VO];
+ priority[7] = aci_prio[AC_VO];
+
+ brcmf_dbg(CONN, "Adj prio BE 0->%d, BK 1->%d, BK 2->%d, BE 3->%d\n",
+ priority[0], priority[1], priority[2], priority[3]);
+
+ brcmf_dbg(CONN, "Adj prio VI 4->%d, VI 5->%d, VO 6->%d, VO 7->%d\n",
+ priority[4], priority[5], priority[6], priority[7]);
+}
+
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = cfg->pub;
struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+ struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT];
u32 req_len;
u32 resp_len;
s32 err = 0;
@@ -5492,6 +5655,17 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
GFP_KERNEL);
if (!conn_info->resp_ie)
conn_info->resp_ie_len = 0;
+
+ err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta",
+ edcf_acparam_info,
+ sizeof(edcf_acparam_info));
+ if (err) {
+ brcmf_err("could not get wme_ac_sta (%d)\n", err);
+ return err;
+ }
+
+ brcmf_wifi_prioritize_acparams(edcf_acparam_info,
+ cfg->ac_priority);
} else {
conn_info->resp_ie_len = 0;
conn_info->resp_ie = NULL;
@@ -5809,6 +5983,25 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
conf->retry_long = (u32)-1;
}
+static void brcmf_init_wmm_prio(u8 *priority)
+{
+ /* Initialize AC priority array to default
+ * 802.1d priority as per following table:
+ * 802.1d prio 0,3 maps to BE
+ * 802.1d prio 1,2 maps to BK
+ * 802.1d prio 4,5 maps to VI
+ * 802.1d prio 6,7 maps to VO
+ */
+ priority[0] = AC_BE;
+ priority[3] = AC_BE;
+ priority[1] = AC_BK;
+ priority[2] = AC_BK;
+ priority[4] = AC_VI;
+ priority[5] = AC_VI;
+ priority[6] = AC_VO;
+ priority[7] = AC_VO;
+}
+
static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
{
brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
@@ -5903,6 +6096,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg);
brcmf_init_conf(cfg->conf);
+ brcmf_init_wmm_prio(cfg->ac_priority);
init_completion(&cfg->vif_disabled);
return err;
}
@@ -6590,6 +6784,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_pub *drvr = cfg->pub;
struct wiphy_wowlan_support *wowl;
+ struct cfg80211_wowlan *brcmf_wowlan_config = NULL;
wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
GFP_KERNEL);
@@ -6612,6 +6807,27 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
}
wiphy->wowlan = wowl;
+
+ /* wowlan_config structure report for kernels */
+ brcmf_wowlan_config = kzalloc(sizeof(*brcmf_wowlan_config),
+ GFP_KERNEL);
+ if (brcmf_wowlan_config) {
+ brcmf_wowlan_config->any = false;
+ brcmf_wowlan_config->disconnect = true;
+ brcmf_wowlan_config->eap_identity_req = true;
+ brcmf_wowlan_config->four_way_handshake = true;
+ brcmf_wowlan_config->rfkill_release = false;
+ brcmf_wowlan_config->patterns = NULL;
+ brcmf_wowlan_config->n_patterns = 0;
+ brcmf_wowlan_config->tcp = NULL;
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
+ brcmf_wowlan_config->gtk_rekey_failure = true;
+ else
+ brcmf_wowlan_config->gtk_rekey_failure = false;
+ } else {
+ brcmf_err("Can not allocate memory for brcm_wowlan_config\n");
+ }
+ wiphy->wowlan_config = brcmf_wowlan_config;
#endif
}
@@ -6750,6 +6966,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
struct wireless_dev *wdev;
struct brcmf_if *ifp;
s32 power_mode;
+ s32 eap_restrict;
s32 err = 0;
if (cfg->dongle_up)
@@ -6774,6 +6991,14 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
err = brcmf_dongle_roam(ifp);
if (err)
goto default_conf_out;
+
+ eap_restrict = ifp->drvr->settings->eap_restrict;
+ if (eap_restrict) {
+ err = brcmf_fil_iovar_int_set(ifp, "eap_restrict",
+ eap_restrict);
+ if (err)
+ brcmf_info("eap_restrict error (%d)\n", err);
+ }
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
NULL);
if (err)
@@ -7054,6 +7279,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cfg->wiphy = wiphy;
cfg->pub = drvr;
+ cfg->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 14d5bbad1db1..fc3e49bcff70 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -23,6 +23,23 @@
#define WL_ROAM_TRIGGER_LEVEL -75
#define WL_ROAM_DELTA 20
+/* WME Access Category Indices (ACIs) */
+#define AC_BE 0 /* Best Effort */
+#define AC_BK 1 /* Background */
+#define AC_VI 2 /* Video */
+#define AC_VO 3 /* Voice */
+#define EDCF_AC_COUNT 4
+#define MAX_8021D_PRIO 8
+
+#define EDCF_ACI_MASK 0x60
+#define EDCF_ACI_SHIFT 5
+#define EDCF_ACM_MASK 0x10
+#define EDCF_ECWMIN_MASK 0x0f
+#define EDCF_ECWMAX_SHIFT 4
+#define EDCF_AIFSN_MASK 0x0f
+#define EDCF_AIFSN_MAX 15
+#define EDCF_ECWMAX_MASK 0xf0
+
/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
* problematic on some systems and should be avoided.
*/
@@ -75,6 +92,15 @@
#define BRCMF_VIF_EVENT_TIMEOUT msecs_to_jiffies(1500)
+#define BRCMF_PM_WAIT_MAXRETRY 100
+
+/* cfg80211 wowlan definitions */
+#define WL_WOWLAN_MAX_PATTERNS 8
+#define WL_WOWLAN_MIN_PATTERN_LEN 1
+#define WL_WOWLAN_MAX_PATTERN_LEN 255
+#define WL_WOWLAN_PKT_FILTER_ID_FIRST 201
+#define WL_WOWLAN_PKT_FILTER_ID_LAST (WL_WOWLAN_PKT_FILTER_ID_FIRST + \
+ WL_WOWLAN_MAX_PATTERNS - 1)
/**
* enum brcmf_scan_status - scan engine status
*
@@ -145,6 +171,13 @@ enum brcmf_vif_status {
BRCMF_VIF_STATUS_ASSOC_SUCCESS,
};
+enum brcmf_cfg80211_pm_state {
+ BRCMF_CFG80211_PM_STATE_RESUMED,
+ BRCMF_CFG80211_PM_STATE_RESUMING,
+ BRCMF_CFG80211_PM_STATE_SUSPENDED,
+ BRCMF_CFG80211_PM_STATE_SUSPENDING,
+};
+
/**
* struct vif_saved_ie - holds saved IEs for a virtual interface.
*
@@ -203,6 +236,12 @@ struct brcmf_cfg80211_assoc_ielen_le {
__le32 resp_len;
};
+struct brcmf_cfg80211_edcf_acparam {
+ u8 ACI;
+ u8 ECW;
+ u16 TXOP; /* stored in network order (ls octet first) */
+};
+
/* dongle escan state */
enum wl_escan_state {
WL_ESCAN_STATE_IDLE,
@@ -321,6 +360,8 @@ struct brcmf_cfg80211_info {
struct brcmf_assoclist_le assoclist;
struct brcmf_cfg80211_wowl wowl;
struct brcmf_pno_info *pno;
+ u8 ac_priority[MAX_8021D_PRIO];
+ u8 pm_state;
};
/**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index dd586a96b57a..0ad43feb748b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -433,11 +433,25 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
{
struct brcmf_chip_priv *ci;
int count;
+ struct brcmf_core *d11core2 = NULL;
+ struct brcmf_core_priv *d11priv2 = NULL;
ci = core->chip;
+ /* special handle two D11 cores reset */
+ if (core->pub.id == BCMA_CORE_80211) {
+ d11core2 = brcmf_chip_get_d11core(&ci->pub, 1);
+ if (d11core2) {
+ brcmf_dbg(INFO, "found two d11 cores, reset both\n");
+ d11priv2 = container_of(d11core2, struct brcmf_core_priv,
+ pub);
+ }
+ }
+
/* must disable first to work for arbitrary current core state */
brcmf_chip_ai_coredisable(core, prereset, reset);
+ if (d11priv2)
+ brcmf_chip_ai_coredisable(d11priv2, prereset, reset);
count = 0;
while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
@@ -449,9 +463,30 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
usleep_range(40, 60);
}
+ if (d11priv2) {
+ count = 0;
+ while (ci->ops->read32(ci->ctx,
+ d11priv2->wrapbase + BCMA_RESET_CTL) &
+ BCMA_RESET_CTL_RESET) {
+ ci->ops->write32(ci->ctx,
+ d11priv2->wrapbase + BCMA_RESET_CTL,
+ 0);
+ count++;
+ if (count > 50)
+ break;
+ usleep_range(40, 60);
+ }
+ }
+
ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
postreset | BCMA_IOCTL_CLK);
ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+
+ if (d11priv2) {
+ ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL,
+ postreset | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL);
+ }
}
char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
@@ -463,6 +498,16 @@ char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
return buf;
}
+bool brcmf_chip_has_clm_blob(u32 id)
+{
+ bool ret = true;
+
+ if (id == BRCM_CC_4339_CHIP_ID)
+ return false;
+
+ return ret;
+}
+
static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci,
u16 coreid, u32 base,
u32 wrapbase)
@@ -1113,6 +1158,21 @@ void brcmf_chip_detach(struct brcmf_chip *pub)
kfree(chip);
}
+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core_priv *core;
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ list_for_each_entry(core, &chip->cores, list) {
+ if (core->pub.id == BCMA_CORE_80211) {
+ if (unit-- == 0)
+ return &core->pub;
+ }
+ }
+ return NULL;
+}
+
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
{
struct brcmf_chip_priv *chip;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
index 7b00f6a59e89..6693614e207e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
@@ -76,6 +76,7 @@ void brcmf_chip_detach(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit);
bool brcmf_chip_iscoreup(struct brcmf_core *core);
void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
@@ -84,5 +85,6 @@ void brcmf_chip_set_passive(struct brcmf_chip *ci);
bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec);
bool brcmf_chip_sr_capable(struct brcmf_chip *pub);
char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len);
+bool brcmf_chip_has_clm_blob(u32 id);
#endif /* BRCMF_AXIDMP_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index dec25e415619..f1b9faafdda1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/firmware.h>
+#include <linux/pinctrl/consumer.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
@@ -67,6 +68,14 @@ static int brcmf_iapp_enable;
module_param_named(iapp, brcmf_iapp_enable, int, 0);
MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
+static int brcmf_eap_restrict;
+module_param_named(eap_restrict, brcmf_eap_restrict, int, 0400);
+MODULE_PARM_DESC(eap_restrict, "Block non-802.1X frames until auth finished");
+
+static int brcmf_sdio_wq_highpri;
+module_param_named(sdio_wq_highpri, brcmf_sdio_wq_highpri, int, 0);
+MODULE_PARM_DESC(sdio_wq_highpri, "SDIO workqueue is set to high priority");
+
#ifdef DEBUG
/* always succeed brcmf_bus_started() */
static int brcmf_ignore_probe_fail;
@@ -202,7 +211,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
char *ptr;
s32 err;
- /* retreive mac address */
+ /* retrieve mac addresses */
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
@@ -250,10 +259,12 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
ri->chipname, sizeof(ri->chipname));
/* Do any CLM downloading */
- err = brcmf_c_process_clm_blob(ifp);
- if (err < 0) {
- bphy_err(drvr, "download CLM blob file failed, %d\n", err);
- goto done;
+ if (brcmf_chip_has_clm_blob(bus->chip)) {
+ err = brcmf_c_process_clm_blob(ifp);
+ if (err < 0) {
+ bphy_err(drvr, "download CLM blob file failed, %d\n", err);
+ goto done;
+ }
}
/* query for 'ver' to get version info from firmware */
@@ -336,6 +347,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* Enable tx beamforming, errors can be ignored (not supported) */
(void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
+
+ /* add unicast packet filter */
+ err = brcmf_pktfilter_add_remove(ifp->ndev,
+ BRCMF_UNICAST_FILTER_NUM, true);
+ if (err)
+ brcmf_info("Add unicast filter error (%d)\n", err);
+
done:
return err;
}
@@ -407,12 +425,14 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
if (!settings)
return NULL;
- /* start by using the module paramaters */
+ /* start by using the module parameters */
settings->p2p_enable = !!brcmf_p2p_enable;
settings->feature_disable = brcmf_feature_disable;
settings->fcmode = brcmf_fcmode;
settings->roamoff = !!brcmf_roamoff;
settings->iapp = !!brcmf_iapp_enable;
+ settings->eap_restrict = !!brcmf_eap_restrict;
+ settings->sdio_wq_highpri = !!brcmf_sdio_wq_highpri;
#ifdef DEBUG
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif
@@ -423,6 +443,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
/* See if there is any device specific platform data configured */
found = false;
if (brcmfmac_pdata) {
+ pinctrl_pm_select_default_state(brcmfmac_pdata->dev);
for (i = 0; i < brcmfmac_pdata->device_count; i++) {
device_pd = &brcmfmac_pdata->devices[i];
if ((device_pd->bus_type == bus_type) &&
@@ -456,10 +477,30 @@ void brcmf_release_module_param(struct brcmf_mp_device *module_param)
static int __init brcmf_common_pd_probe(struct platform_device *pdev)
{
+ int err;
+ struct brcmfmac_platform_data pdata = {
+ .power_on = NULL,
+ .power_off = NULL,
+ .fw_alternative_path = NULL,
+ .device_count = 0,
+ };
+
brcmf_dbg(INFO, "Enter\n");
brcmfmac_pdata = dev_get_platdata(&pdev->dev);
+ if (!brcmfmac_pdata) {
+ err = platform_device_add_data(pdev, &pdata,
+ sizeof(pdata));
+ if (err)
+ brcmf_err("platform data allocation failed\n");
+ brcmfmac_pdata = dev_get_platdata(&pdev->dev);
+ pinctrl_pm_select_idle_state(&pdev->dev);
+ }
+
+ if (!brcmfmac_pdata)
+ return 0;
+ brcmfmac_pdata->dev = &pdev->dev;
if (brcmfmac_pdata->power_on)
brcmfmac_pdata->power_on();
@@ -470,7 +511,7 @@ static int brcmf_common_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(INFO, "Enter\n");
- if (brcmfmac_pdata->power_off)
+ if (brcmfmac_pdata && brcmfmac_pdata->power_off)
brcmfmac_pdata->power_off();
return 0;
@@ -492,7 +533,7 @@ static int __init brcmfmac_module_init(void)
if (err == -ENODEV)
brcmf_dbg(INFO, "No platform data available.\n");
- /* Initialize global module paramaters */
+ /* Initialize global module parameters */
brcmf_mp_attach();
/* Continue the initialization by registering the different busses */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index 144cf4570bc3..6184ca09e29e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -37,6 +37,8 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
* @feature_disable: Feature_disable bitmask.
* @fcmode: FWS flow control.
* @roamoff: Firmware roaming off?
+ * @eap_restrict: Not allow data tx/rx until 802.1X auth succeeds
+ * @sdio_wq_highpri: Tasks submitted to SDIO workqueue will run immediately.
* @ignore_probe_fail: Ignore probe failure.
* @country_codes: If available, pointer to struct for translating country codes
* @bus: Bus specific platform data. Only SDIO at the mmoment.
@@ -47,6 +49,9 @@ struct brcmf_mp_device {
int fcmode;
bool roamoff;
bool iapp;
+ bool eap_restrict;
+ int sdio_dpc_prio;
+ bool sdio_wq_highpri;
bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes;
const char *board_type;
@@ -71,5 +76,8 @@ void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev);
static inline void
brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
#endif
+u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);
+
+u8 brcmf_map_prio_to_aci(void *cfg, u8 prio);
#endif /* BRCMFMAC_COMMON_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index edb79e9665dc..83b23dffae38 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -536,6 +536,11 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
struct ethhdr *eh;
u16 type;
+ if (!ifp) {
+ brcmu_pkt_buf_free_skb(txp);
+ return;
+ }
+
eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto);
@@ -1469,3 +1474,177 @@ void __exit brcmf_core_exit(void)
brcmf_pcie_exit();
}
+int
+brcmf_pktfilter_add_remove(struct net_device *ndev, int filter_num, bool add)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_pkt_filter_le *pkt_filter;
+ int filter_fixed_len = offsetof(struct brcmf_pkt_filter_le, u);
+ int pattern_fixed_len = offsetof(struct brcmf_pkt_filter_pattern_le,
+ mask_and_pattern);
+ u16 mask_and_pattern[MAX_PKTFILTER_PATTERN_SIZE];
+ int buflen = 0;
+ int ret = 0;
+
+ brcmf_dbg(INFO, "%s packet filter number %d\n",
+ (add ? "add" : "remove"), filter_num);
+
+ pkt_filter = kzalloc(sizeof(*pkt_filter) +
+ (MAX_PKTFILTER_PATTERN_SIZE * 2), GFP_ATOMIC);
+ if (!pkt_filter)
+ return -ENOMEM;
+
+ switch (filter_num) {
+ case BRCMF_UNICAST_FILTER_NUM:
+ pkt_filter->id = 100;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 1;
+ mask_and_pattern[0] = 0x0001;
+ break;
+ case BRCMF_BROADCAST_FILTER_NUM:
+ //filter_pattern = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
+ pkt_filter->id = 101;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 6;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0xFFFF;
+ mask_and_pattern[2] = 0xFFFF;
+ mask_and_pattern[3] = 0xFFFF;
+ mask_and_pattern[4] = 0xFFFF;
+ mask_and_pattern[5] = 0xFFFF;
+ break;
+ case BRCMF_MULTICAST4_FILTER_NUM:
+ //filter_pattern = "102 0 0 0 0xFFFFFF 0x01005E";
+ pkt_filter->id = 102;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 3;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0x01FF;
+ mask_and_pattern[2] = 0x5E00;
+ break;
+ case BRCMF_MULTICAST6_FILTER_NUM:
+ //filter_pattern = "103 0 0 0 0xFFFF 0x3333";
+ pkt_filter->id = 103;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 2;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0x3333;
+ break;
+ case BRCMF_MDNS_FILTER_NUM:
+ //filter_pattern = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
+ pkt_filter->id = 104;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 6;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0xFFFF;
+ mask_and_pattern[2] = 0xFFFF;
+ mask_and_pattern[3] = 0x0001;
+ mask_and_pattern[4] = 0x005E;
+ mask_and_pattern[5] = 0xFB00;
+ break;
+ case BRCMF_ARP_FILTER_NUM:
+ //filter_pattern = "105 0 0 12 0xFFFF 0x0806";
+ pkt_filter->id = 105;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 12;
+ pkt_filter->u.pattern.size_bytes = 2;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0x0608;
+ break;
+ case BRCMF_BROADCAST_ARP_FILTER_NUM:
+ //filter_pattern = "106 0 0 0
+ //0xFFFFFFFFFFFF0000000000000806
+ //0xFFFFFFFFFFFF0000000000000806";
+ pkt_filter->id = 106;
+ pkt_filter->type = 0;
+ pkt_filter->negate_match = 0;
+ pkt_filter->u.pattern.offset = 0;
+ pkt_filter->u.pattern.size_bytes = 14;
+ mask_and_pattern[0] = 0xFFFF;
+ mask_and_pattern[1] = 0xFFFF;
+ mask_and_pattern[2] = 0xFFFF;
+ mask_and_pattern[3] = 0x0000;
+ mask_and_pattern[4] = 0x0000;
+ mask_and_pattern[5] = 0x0000;
+ mask_and_pattern[6] = 0x0608;
+ mask_and_pattern[7] = 0xFFFF;
+ mask_and_pattern[8] = 0xFFFF;
+ mask_and_pattern[9] = 0xFFFF;
+ mask_and_pattern[10] = 0x0000;
+ mask_and_pattern[11] = 0x0000;
+ mask_and_pattern[12] = 0x0000;
+ mask_and_pattern[13] = 0x0608;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+ memcpy(pkt_filter->u.pattern.mask_and_pattern, mask_and_pattern,
+ pkt_filter->u.pattern.size_bytes * 2);
+ buflen = filter_fixed_len + pattern_fixed_len +
+ pkt_filter->u.pattern.size_bytes * 2;
+
+ if (add) {
+ /* Add filter */
+ ret = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add",
+ pkt_filter, buflen);
+ if (ret)
+ goto failed;
+ drvr->pkt_filter[filter_num].id = pkt_filter->id;
+ drvr->pkt_filter[filter_num].enable = 0;
+
+ } else {
+ /* Delete filter */
+ ret = brcmf_fil_iovar_int_set(ifp, "pkt_filter_delete",
+ pkt_filter->id);
+ if (ret == -ENOENT)
+ ret = 0;
+ if (ret)
+ goto failed;
+
+ drvr->pkt_filter[filter_num].id = 0;
+ drvr->pkt_filter[filter_num].enable = 0;
+ }
+failed:
+ if (ret)
+ brcmf_err("%s packet filter failed, ret=%d\n",
+ (add ? "add" : "remove"), ret);
+
+ kfree(pkt_filter);
+ return ret;
+}
+
+int brcmf_pktfilter_enable(struct net_device *ndev, bool enable)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ int ret = 0;
+ int idx = 0;
+
+ for (idx = 0; idx < MAX_PKT_FILTER_COUNT; ++idx) {
+ if (drvr->pkt_filter[idx].id != 0) {
+ drvr->pkt_filter[idx].enable = enable;
+ ret = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable",
+ &drvr->pkt_filter[idx],
+ sizeof(struct brcmf_pkt_filter_enable_le));
+ if (ret) {
+ brcmf_err("%s packet filter id(%d) failed, ret=%d\n",
+ (enable ? "enable" : "disable"),
+ drvr->pkt_filter[idx].id, ret);
+ }
+ }
+ }
+ return ret;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 6699637d3bf8..6def862f6008 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -12,6 +12,7 @@
#include <net/cfg80211.h>
#include "fweh.h"
+#include "fwil_types.h"
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
@@ -136,6 +137,8 @@ struct brcmf_pub {
struct work_struct bus_reset;
u8 clmver[BRCMF_DCMD_SMLEN];
+ struct brcmf_pkt_filter_enable_le pkt_filter[MAX_PKT_FILTER_COUNT];
+
};
/* forward declarations */
@@ -213,5 +216,7 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
int __init brcmf_core_init(void);
void __exit brcmf_core_exit(void);
-
+int brcmf_pktfilter_add_remove(struct net_device *ndev, int filter_num,
+ bool add);
+int brcmf_pktfilter_enable(struct net_device *ndev, bool enable);
#endif /* BRCMFMAC_CORE_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
index 9ed85420f3ca..164735f613f2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
@@ -99,7 +99,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
s32 err, fwerr;
if (drvr->bus_if->state != BRCMF_BUS_UP) {
- bphy_err(drvr, "bus is down. we have nothing to do.\n");
+ brcmf_dbg(FIL, "bus is down. we have nothing to do.\n");
return -EIO;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index ce18433aaefb..ee728d6af2a3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -136,6 +136,19 @@
#define BRCMF_WOWL_MAXPATTERNS 8
#define BRCMF_WOWL_MAXPATTERNSIZE 128
+enum {
+ BRCMF_UNICAST_FILTER_NUM = 0,
+ BRCMF_BROADCAST_FILTER_NUM,
+ BRCMF_MULTICAST4_FILTER_NUM,
+ BRCMF_MULTICAST6_FILTER_NUM,
+ BRCMF_MDNS_FILTER_NUM,
+ BRCMF_ARP_FILTER_NUM,
+ BRCMF_BROADCAST_ARP_FILTER_NUM,
+ MAX_PKT_FILTER_COUNT
+};
+
+#define MAX_PKTFILTER_PATTERN_SIZE 16
+
#define BRCMF_COUNTRY_BUF_SZ 4
#define BRCMF_ANT_MAX 4
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index 3d36b6ee158b..46dd302b569f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -404,7 +404,7 @@ struct brcmf_fws_mac_descriptor {
u8 traffic_lastreported_bmp;
};
-#define BRCMF_FWS_HANGER_MAXITEMS 1024
+#define BRCMF_FWS_HANGER_MAXITEMS 3072
/**
* enum brcmf_fws_hanger_item_state - state of hanger item.
@@ -1869,6 +1869,9 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
WARN_ON(siglen > skb->len);
+ if (siglen > skb->len)
+ siglen = skb->len;
+
if (!siglen)
return;
/* if flow control disabled, skip to packet data and leave */
@@ -2134,8 +2137,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
skcb->if_flags = 0;
skcb->state = BRCMF_FWS_SKBSTATE_NEW;
brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
+
+ /* mapping from 802.1d priority to firmware fifo index */
if (!multicast)
- fifo = brcmf_fws_prio2fifo[skb->priority];
+ fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority);
brcmf_fws_lock(fws);
if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
@@ -2346,7 +2351,7 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
struct brcmf_if *ifp;
u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
int rc;
- u32 mode;
+ u32 mode = 0;
fws = kzalloc(sizeof(*fws), GFP_KERNEL);
if (!fws) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index b886b56a5e5a..625471007b6c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -18,15 +18,17 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *root, *np = dev->of_node;
struct property *prop;
+ const char *cp = NULL;
int irq;
u32 irqf;
- u32 val;
+ u32 val32;
+ u16 val16;
/* Set board-type to the first string of the machine compatible prop */
root = of_find_node_by_path("/");
if (root) {
prop = of_find_property(root, "compatible", NULL);
- settings->board_type = of_prop_next_string(prop, NULL);
+ cp = of_prop_next_string(prop, NULL);
of_node_put(root);
}
@@ -34,8 +36,18 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
!of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
- sdio->drive_strength = val;
+ if (of_property_read_u32(np, "brcm,drive-strength", &val32) == 0)
+ sdio->drive_strength = val32;
+
+ if (of_property_read_bool(np, "brcm,use_board_type"))
+ settings->board_type = cp;
+
+ sdio->broken_sg_support = of_property_read_bool(np,
+ "brcm,broken_sg_support");
+ if (of_property_read_u16(np, "brcm,sd_head_align", &val16) == 0)
+ sdio->sd_head_align = val16;
+ if (of_property_read_u16(np, "brcm,sd_sgentry_align", &val16) == 0)
+ sdio->sd_sgentry_align = val16;
/* make sure there are interrupts defined in the node */
if (!of_find_property(np, "interrupts", NULL))
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 1f5deea5a288..49bf3aed510f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -457,10 +457,21 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
*/
static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
{
+ struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
bool random_addr = false;
+ bool local_admin = false;
- if (!dev_addr || is_zero_ether_addr(dev_addr))
- random_addr = true;
+ if (!dev_addr || is_zero_ether_addr(dev_addr)) {
+ /* If the primary interface address is already locally
+ * administered, create a new random address.
+ */
+ if (pri_ifp->mac_addr[0] & 0x02) {
+ random_addr = true;
+ } else {
+ dev_addr = pri_ifp->mac_addr;
+ local_admin = true;
+ }
+ }
/* Generate the P2P Device Address obtaining a random ethernet
* address with the locally administered bit set.
@@ -470,6 +481,9 @@ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
else
memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
+ if (local_admin)
+ p2p->dev_addr[0] |= 0x02;
+
/* Generate the P2P Interface Address. If the discovery and connection
* BSSCFGs need to simultaneously co-exist, then this address must be
* different from the P2P Device Address, but also locally administered.
@@ -1491,6 +1505,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
{
struct brcmf_pub *drvr = p2p->cfg->pub;
struct brcmf_cfg80211_vif *vif;
+ struct brcmf_p2p_action_frame *p2p_act_frame;
s32 err = 0;
s32 timeout = 0;
@@ -1500,7 +1515,13 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
- vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ /* check if it is a p2p_presence response */
+ p2p_act_frame = (struct brcmf_p2p_action_frame *) af_params->action_frame.data;
+ if (p2p_act_frame->subtype == P2P_AF_PRESENCE_RSP)
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+ else
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+
err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
sizeof(*af_params));
if (err) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index bda042138e96..fce90713aad0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -38,6 +38,7 @@
#include "chip.h"
#include "core.h"
#include "common.h"
+#include "cfg80211.h"
enum brcmf_pcie_state {
@@ -78,7 +79,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
};
-#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
+#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
#define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)
@@ -188,7 +189,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_H2D_HOST_D0_INFORM_IN_USE 0x00000008
#define BRCMF_H2D_HOST_D0_INFORM 0x00000010
-#define BRCMF_PCIE_MBDATA_TIMEOUT msecs_to_jiffies(2000)
+#define BRCMF_PCIE_MBDATA_TIMEOUT msecs_to_jiffies(5000)
#define BRCMF_PCIE_CFGREG_STATUS_CMD 0x4
#define BRCMF_PCIE_CFGREG_PM_CSR 0x4C
@@ -692,7 +693,7 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
/* Send mailbox interrupt twice as a hardware workaround */
core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2);
- if (core->rev <= 13)
+ if (core && (core->rev <= 0xd && core->rev != 0xb))
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
return 0;
@@ -1836,6 +1837,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
return;
fail:
+ brcmf_free(dev);
device_release_driver(dev);
}
@@ -2005,6 +2007,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
dev_set_drvdata(&pdev->dev, NULL);
}
+static void brcmf_pcie_shutdown(struct pci_dev *pdev)
+{
+ brcmf_pcie_remove(pdev);
+ return;
+}
#ifdef CONFIG_PM
@@ -2013,11 +2020,22 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
{
struct brcmf_pciedev_info *devinfo;
struct brcmf_bus *bus;
+ struct brcmf_cfg80211_info *config;
+ int retry = BRCMF_PM_WAIT_MAXRETRY;
brcmf_dbg(PCIE, "Enter\n");
bus = dev_get_drvdata(dev);
devinfo = bus->bus_priv.pcie->devinfo;
+ config = bus->drvr->config;
+
+ while (retry &&
+ config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
+ usleep_range(10000, 20000);
+ retry--;
+ }
+ if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
+ brcmf_err(bus, "timed out wait for cfg80211 suspended\n");
brcmf_bus_change_state(bus, BRCMF_BUS_DOWN);
@@ -2027,9 +2045,21 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed,
BRCMF_PCIE_MBDATA_TIMEOUT);
if (!devinfo->mbdata_completed) {
- brcmf_err(bus, "Timeout on response for entering D3 substate\n");
- brcmf_bus_change_state(bus, BRCMF_BUS_UP);
- return -EIO;
+ struct brcmf_pcie_shared_info *shared;
+ u32 addr;
+ u32 dtoh_mb_data;
+
+ shared = &devinfo->shared;
+ addr = shared->dtoh_mb_data_addr;
+ dtoh_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
+
+ if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) {
+ brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n");
+ devinfo->mbdata_completed = true;
+ }
+
+ if (!devinfo->mbdata_completed)
+ brcmf_err(bus, "Timeout on response for entering D3 substate\n");
}
devinfo->state = BRCMFMAC_PCIE_STATE_DOWN;
@@ -2037,7 +2067,6 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
return 0;
}
-
static int brcmf_pcie_pm_leave_D3(struct device *dev)
{
struct brcmf_pciedev_info *devinfo;
@@ -2057,6 +2086,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
goto cleanup;
brcmf_dbg(PCIE, "Hot resume, continue....\n");
+ msleep(10);
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
brcmf_bus_change_state(bus, BRCMF_BUS_UP);
@@ -2130,6 +2160,7 @@ static struct pci_driver brcmf_pciedrvr = {
.id_table = brcmf_pcie_devid_table,
.probe = brcmf_pcie_probe,
.remove = brcmf_pcie_remove,
+ .shutdown = brcmf_pcie_shutdown,
#ifdef CONFIG_PM
.driver.pm = &brcmf_pciedrvr_pm,
#endif
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index ef5521b9b357..f46d59c66c3d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -34,15 +34,23 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
+#include "fwil.h"
#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
+#define ULP_HUDI_PROC_DONE_TIME msecs_to_jiffies(2500)
/* watermark expressed in number of words */
#define DEFAULT_F2_WATERMARK 0x8
#define CY_4373_F2_WATERMARK 0x40
#define CY_43012_F2_WATERMARK 0x60
-
+#define CY_43455_F2_WATERMARK 0x60
+#define CY_43455_MES_WATERMARK 0x50
+#define CY_43455_MESBUSYCTRL (CY_43455_MES_WATERMARK | \
+ SBSDIO_MESBUSYCTRL_ENAB)
+#define CY_4339_F2_WATERMARK 48
+#define CY_4339_MES_WATERMARK 80
+#define CY_4339_MESBUSYCTRL (CY_4339_MES_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
#ifdef DEBUG
#define BRCMF_TRAP_INFO_SIZE 80
@@ -313,14 +321,8 @@ struct rte_console {
#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5
-/*
- * Conversion of 802.1D priority to precedence level
- */
-static uint prio2prec(u32 prio)
-{
- return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
- (prio^2) : prio;
-}
+static void brcmf_sdio_firmware_callback(struct device *dev, int err,
+ struct brcmf_fw_request *fwreq);
#ifdef DEBUG
/* Device console log buffer state */
@@ -2320,6 +2322,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
&prec_out);
if (pkt == NULL)
break;
+ skb_orphan(pkt);
__skb_queue_tail(&pktq, pkt);
}
spin_unlock_bh(&bus->txq_lock);
@@ -2543,6 +2546,166 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
return ret;
}
+/* This Function is used to retrieve important
+ * details from dongle related to ULP mode Mostly
+ * values/SHM details that will be vary depending
+ * on the firmware branches
+ */
+static void
+brcmf_sdio_ulp_preinit(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_if *ifp = bus_if->drvr->iflist[0];
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Query ulp_sdioctrl iovar to get the ULP related SHM offsets */
+ err = brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl", &sdiodev->shm_ulp,
+ sizeof(sdiodev->shm_ulp));
+ if (err)
+ brcmf_dbg(TRACE, "ulp_sdioctrl iovar returned err = %d\n", err);
+
+ sdiodev->ulp = false;
+
+ brcmf_dbg(TRACE, "m_ulp_ctrl_sdio[%x] m_ulp_wakeevt_ind [%x]\n",
+ M_DS1_CTRL_SDIO(sdiodev->shm_ulp),
+ M_WAKEEVENT_IND(sdiodev->shm_ulp));
+ brcmf_dbg(TRACE, "m_ulp_wakeind [%x]\n",
+ M_ULP_WAKE_IND(sdiodev->shm_ulp));
+}
+
+#define BRCMF_SDIO_FW_CODE 0
+#define BRCMF_SDIO_FW_NVRAM 1
+
+/* Reinitialize ARM because In DS1 mode ARM got off */
+static int
+brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus)
+{
+ struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
+ struct brcmf_fw_request *fwreq;
+ int err = 0;
+
+ /* After firmware redownload tx/rx seq are reset accordingly
+ * these values are reset on FMAC side tx_max is initially set to 4,
+ * which later is updated by FW.
+ */
+ bus->tx_seq = 0;
+ bus->rx_seq = 0;
+ bus->tx_max = 4;
+
+ fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item),
+ GFP_KERNEL);
+ if (!fwreq)
+ return -ENOMEM;
+
+ fwreq->items[BRCMF_SDIO_FW_CODE].path = sdiodev->fw_name;
+ fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+ fwreq->items[BRCMF_SDIO_FW_NVRAM].path = sdiodev->nvram_name;
+ fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+ fwreq->n_items = 2;
+
+ err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
+ brcmf_sdio_firmware_callback);
+ if (err != 0) {
+ brcmf_err("async firmware request failed: %d\n", err);
+ kfree(fwreq);
+ }
+
+ return err;
+}
+
+/* Check if device is in DS1 mode and handshake with ULP UCODE */
+static bool
+brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus)
+{
+ int err = 0;
+ u32 value = 0;
+ u32 val32, ulp_wake_ind, wowl_wake_ind;
+ int reg_addr;
+ unsigned long timeout;
+
+ value = brcmf_sdiod_readb(bus->sdiodev, SDIO_CCCR_IOEx, &err);
+
+ if (value == SDIO_FUNC_ENABLE_1) {
+ brcmf_dbg(SDIO, "GOT THE INTERRUPT FROM UCODE\n");
+ bus->sdiodev->ulp = true;
+ ulp_wake_ind = D11SHM_RD(bus->sdiodev, M_ULP_WAKE_IND(
+ bus->sdiodev->shm_ulp), &err) >> 16;
+ wowl_wake_ind = D11SHM_RD(bus->sdiodev, M_WAKEEVENT_IND(
+ bus->sdiodev->shm_ulp), &err) >> 16;
+
+ brcmf_dbg(SDIO, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
+ wowl_wake_ind, ulp_wake_ind);
+
+ if (wowl_wake_ind || ulp_wake_ind) {
+ /* TX wake Don't do anything.
+ * Just bail out and re-download firmware.
+ */
+ } else {
+ /* RX wake negotiate with MAC */
+ brcmf_dbg(SDIO, "M_DS1_CTRL_SDIO: 0x%08x\n",
+ (u32)D11SHM_RD(bus->sdiodev,
+ M_DS1_CTRL_SDIO(bus->sdiodev->shm_ulp),
+ &err));
+ D11SHM_WR(bus->sdiodev, M_DS1_CTRL_SDIO(
+ bus->sdiodev->shm_ulp),
+ C_DS1_CTRL_SDIO_DS1_EXIT |
+ C_DS1_CTRL_REQ_VALID,
+ &err);
+ val32 = D11REG_RD(bus->sdiodev,
+ D11_MACCONTROL_REG, &err);
+ val32 = val32 | D11_MACCONTROL_REG_WAKE;
+ D11REG_WR(bus->sdiodev,
+ D11_MACCONTROL_REG, val32, &err);
+
+ /* Poll for PROC_DONE to be set by ucode */
+ value = D11SHM_RD(bus->sdiodev,
+ M_DS1_CTRL_SDIO(
+ bus->sdiodev->shm_ulp), &err);
+ /* Wait here (polling) for C_DS1_CTRL_PROC_DONE */
+ timeout = jiffies + ULP_HUDI_PROC_DONE_TIME;
+ while (!(value & C_DS1_CTRL_PROC_DONE)) {
+ value = D11SHM_RD(bus->sdiodev,
+ M_DS1_CTRL_SDIO(
+ bus->sdiodev->shm_ulp), &err);
+ if (time_after(jiffies, timeout))
+ break;
+ usleep_range(1000, 2000);
+ }
+ brcmf_dbg(SDIO, "M_DS1_CTRL_SDIO: 0x%08x\n",
+ (u32)D11SHM_RD(bus->sdiodev,
+ M_DS1_CTRL_SDIO(
+ bus->sdiodev->shm_ulp), &err));
+ value = D11SHM_RD(bus->sdiodev,
+ M_DS1_CTRL_SDIO(
+ bus->sdiodev->shm_ulp), &err);
+ if (!(value & C_DS1_CTRL_PROC_DONE)) {
+ brcmf_err("%s: timeout Failed to enter DS1 Exit state!\n",
+ __func__);
+ return false;
+ }
+ }
+ ulp_wake_ind = D11SHM_RD(bus->sdiodev, M_ULP_WAKE_IND(
+ bus->sdiodev->shm_ulp), &err) >> 16;
+ wowl_wake_ind = D11SHM_RD(bus->sdiodev, M_WAKEEVENT_IND(
+ bus->sdiodev->shm_ulp), &err) >> 16;
+ brcmf_dbg(SDIO, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
+ wowl_wake_ind, ulp_wake_ind);
+ reg_addr = CORE_CC_REG(
+ brcmf_chip_get_pmu(bus->ci)->base, min_res_mask);
+ brcmf_sdiod_writel(bus->sdiodev, reg_addr,
+ DEFAULT_43012_MIN_RES_MASK, &err);
+ if (err)
+ brcmf_err("min_res_mask failed\n");
+
+ return true;
+ }
+
+ return false;
+}
+
static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiod = bus->sdiodev;
@@ -2616,6 +2779,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
if (intstatus & I_HMB_HOST_INT) {
intstatus &= ~I_HMB_HOST_INT;
intstatus |= brcmf_sdio_hostmail(bus);
+ if ((sdiod->func1->device != SDIO_DEVICE_ID_BROADCOM_4339) &&
+ brcmf_sdio_ulp_pre_redownload_check(bus))
+ brcmf_sdio_ulp_reinit_fw(bus);
}
sdio_release_host(bus->sdiodev->func1);
@@ -2770,7 +2936,13 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
skb_push(pkt, bus->tx_hdrlen);
/* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
- prec = prio2prec((pkt->priority & PRIOMASK));
+ /* In WLAN, priority is always set by the AP using WMM parameters
+ * and this need not always follow the standard 802.1d priority.
+ * Based on AP WMM config, map from 802.1d priority to corresponding
+ * precedence level.
+ */
+ prec = brcmf_map_prio_to_prec(bus_if->drvr->config,
+ (pkt->priority & PRIOMASK));
/* Check for existing queue, current flow-control,
pending event, or pending clock */
@@ -3518,6 +3690,11 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
if (err < 0)
goto done;
+ /* initialize SHM address from firmware for DS1 */
+ if ((sdiodev->func1->device != SDIO_DEVICE_ID_BROADCOM_4339) &&
+ !bus->sdiodev->ulp)
+ brcmf_sdio_ulp_preinit(dev);
+
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
if (sdiodev->sg_support) {
bus->txglom = false;
@@ -4113,9 +4290,6 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.debugfs_create = brcmf_sdio_debugfs_create
};
-#define BRCMF_SDIO_FW_CODE 0
-#define BRCMF_SDIO_FW_NVRAM 1
-
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq)
{
@@ -4212,6 +4386,31 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
&err);
break;
+ case SDIO_DEVICE_ID_BROADCOM_43455:
+ brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes for 43455\n",
+ CY_43455_F2_WATERMARK);
+ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
+ CY_43455_F2_WATERMARK, &err);
+ devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL,
+ &err);
+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
+ brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
+ &err);
+ brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL,
+ CY_43455_MESBUSYCTRL, &err);
+ break;
+ case SDIO_DEVICE_ID_BROADCOM_4339:
+ brcmf_sdiod_writeb(sdiod,
+ SBSDIO_WATERMARK,
+ CY_4339_F2_WATERMARK, &err);
+ devctl = brcmf_sdiod_readb(sdiod,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
+ brcmf_sdiod_writeb(sdiod,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_sdiod_writeb(sdiod,
+ SBSDIO_FUNC1_MESBUSYCTRL, CY_4339_MESBUSYCTRL, &err);
+ break;
default:
brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
DEFAULT_F2_WATERMARK, &err);
@@ -4329,9 +4528,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->txminmax = BRCMF_TXMINMAX;
bus->tx_seq = SDPCM_SEQ_WRAP - 1;
+ /* attempt to attach to the dongle */
+ if (!(brcmf_sdio_probe_attach(bus))) {
+ brcmf_err("brcmf_sdio_probe_attach failed\n");
+ goto fail;
+ }
+
/* single-threaded workqueue */
- wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
- dev_name(&sdiodev->func1->dev));
+ if (sdiodev->settings->sdio_wq_highpri) {
+ wq = alloc_workqueue("brcmf_wq/%s",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND,
+ 1, dev_name(&sdiodev->func1->dev));
+ } else {
+ wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
+ dev_name(&sdiodev->func1->dev));
+ }
if (!wq) {
brcmf_err("insufficient memory to create txworkqueue\n");
goto fail;
@@ -4340,12 +4551,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->brcmf_wq = wq;
- /* attempt to attach to the dongle */
- if (!(brcmf_sdio_probe_attach(bus))) {
- brcmf_err("brcmf_sdio_probe_attach failed\n");
- goto fail;
- }
-
spin_lock_init(&bus->rxctl_lock);
spin_lock_init(&bus->txq_lock);
init_waitqueue_head(&bus->ctrl_wait);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 0bd47c119dae..88acfd2e034c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -165,6 +165,17 @@ struct brcmf_sdreg {
struct brcmf_sdio;
struct brcmf_sdiod_freezer;
+/* ULP SHM Offsets info */
+struct ulp_shm_info {
+ u32 m_ulp_ctrl_sdio;
+ u32 m_ulp_wakeevt_ind;
+ u32 m_ulp_wakeind;
+};
+
+struct fmac_ulp {
+ struct ulp_shm_info ulp_shm_offset;
+};
+
struct brcmf_sdio_dev {
struct sdio_func *func1;
struct sdio_func *func2;
@@ -190,6 +201,8 @@ struct brcmf_sdio_dev {
bool wowl_enabled;
enum brcmf_sdiod_state state;
struct brcmf_sdiod_freezer *freezer;
+ struct fmac_ulp shm_ulp;
+ bool ulp;
};
/* sdio core registers */
@@ -377,4 +390,51 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
+/* SHM offsets */
+#define M_DS1_CTRL_SDIO(ptr) ((ptr).ulp_shm_offset.m_ulp_ctrl_sdio)
+#define M_WAKEEVENT_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeevt_ind)
+#define M_ULP_WAKE_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeind)
+
+#define D11_BASE_ADDR 0x18001000
+#define D11_AXI_BASE_ADDR 0xE8000000
+#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000)
+
+#define D11REG_ADDR(offset) (D11_BASE_ADDR + (offset))
+#define D11IHR_ADDR(offset) (D11_AXI_BASE_ADDR + 0x400 + (2 * (offset)))
+#define D11SHM_ADDR(offset) (D11_SHM_BASE_ADDR + (offset))
+
+/* MacControl register */
+#define D11_MACCONTROL_REG D11REG_ADDR(0x120)
+#define D11_MACCONTROL_REG_WAKE 0x4000000
+
+/* Following are the offsets in M_DRVR_UCODE_IF_PTR block. Start address of
+ * M_DRVR_UCODE_IF_PTR block is present in M_DRVR_UCODE_IF_PTR.
+ */
+
+/* M_ULP_WAKE_IND bits */
+#define ULP_WAKE_IND_WATCHDOG_EXP 0x1
+#define ULP_WAKE_IND_FCBS_ERROR 0x2
+#define ULP_WAKE_IND_RE_TRANSMIT_ERR 0x4
+#define ULP_WAKE_IND_HOST_WKUP 0x8
+#define ULP_WAKE_IND_INVALID_FCBS_BLK 0x10
+
+#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1
+#define C_DS1_CTRL_SDIO_MAC_ON 0x2
+#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4
+#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8
+#define C_DS1_CTRL_PROC_DONE 0x100
+#define C_DS1_CTRL_REQ_VALID 0x200
+
+#define D11SHM_WR(sdh, offset, val, ret) \
+ brcmf_sdiod_writel(sdh, D11SHM_ADDR(offset), val, ret)
+
+#define D11SHM_RD(sdh, offset, ret) \
+ brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret)
+
+#define D11REG_WR(sdh, addr, val, ret) \
+ brcmf_sdiod_writel(sdh, addr, val, ret)
+
+#define D11REG_RD(sdh, addr, ret) \
+ brcmf_sdiod_readl(sdh, addr, ret)
+
#endif /* BRCMFMAC_SDIO_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 3b897f040371..3d0c5c87e7a8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -19,6 +19,7 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
+#include "cfg80211.h"
#define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
@@ -1442,8 +1443,22 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
{
struct usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+ struct brcmf_bus *bus;
+ struct brcmf_cfg80211_info *config;
+ int retry = BRCMF_PM_WAIT_MAXRETRY;
brcmf_dbg(USB, "Enter\n");
+
+ bus = devinfo->bus_pub.bus;
+ config = bus->drvr->config;
+ while (retry &&
+ config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
+ usleep_range(10000, 20000);
+ retry--;
+ }
+ if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
+ brcmf_err("timed out wait for cfg80211 suspended\n");
+
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
if (devinfo->wowl_enabled) {
brcmf_cancel_all_urbs(devinfo);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
index d07e7c7355d9..8bd84482b846 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
@@ -70,8 +70,12 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
else
ret = brcmf_fil_cmd_data_get(ifp, cmdhdr->cmd, dcmd_buf,
ret_len);
- if (ret != 0)
+
+ if (ret != 0) {
+ brcmf_dbg(INFO, "error(%d), return -EPERM\n", ret);
+ ret = -EPERM;
goto exit;
+ }
wr_pointer = dcmd_buf;
while (ret_len > 0) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
index 0340bba96868..1f6fcd4aff5c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
@@ -306,6 +306,8 @@ struct chipcregs {
* Maximum delay for the PMU state transition in us.
* This is an upper bound intended for spinwaits etc.
*/
-#define PMU_MAX_TRANSITION_DLY 15000
+#define PMU_MAX_TRANSITION_DLY 15000
+
+#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77
#endif /* _SBCHIPC_H */
diff --git a/drivers/net/wireless/nxp/Kconfig b/drivers/net/wireless/nxp/Kconfig
new file mode 100644
index 000000000000..f19fc2244856
--- /dev/null
+++ b/drivers/net/wireless/nxp/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config WLAN_VENDOR_NXP
+ bool "NXP devices"
+ default y
+ ---help---
+ If you have a nxp 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 these cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if WLAN_VENDOR_NXP
+
+source "drivers/net/wireless/nxp/mxm_wifiex/Kconfig"
+
+endif # WLAN_VENDOR_NXP
diff --git a/drivers/net/wireless/nxp/Makefile b/drivers/net/wireless/nxp/Makefile
new file mode 100644
index 000000000000..58efe568ab46
--- /dev/null
+++ b/drivers/net/wireless/nxp/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Linux Wireless network device drivers.
+#
+obj-$(CONFIG_MXMWIFIEX) += mxm_wifiex/
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/Kconfig b/drivers/net/wireless/nxp/mxm_wifiex/Kconfig
new file mode 100644
index 000000000000..f7298b36e8eb
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# NXP Wireless device configuration
+#
+config MXMWIFIEX
+ tristate "NXP MxM WiFi Driver"
+ depends on CFG80211
+ ---help---
+ This driver is multi-chip-multi-interface driver
+ (indicating Multi-Chip x Multi-Interface support) based on
+ NXP 802.11n/ac chipsets. If you choose to build it as a module,
+ it will be build 2 modules moal.ko and mlan.ko.
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/Makefile b/drivers/net/wireless/nxp/mxm_wifiex/Makefile
new file mode 100644
index 000000000000..212f83ca092c
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_MXMWIFIEX) += wlan_src/
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/Makefile b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/Makefile
new file mode 100644
index 000000000000..7892b3e6e288
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/Makefile
@@ -0,0 +1,503 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# File: Makefile
+#
+# Copyright 2014-2020 NXP
+#
+# This software file (the File) is distributed by NXP
+# under the terms of the GNU General Public License Version 2, June 1991
+# (the License). You may use, redistribute and/or modify the File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+#
+
+#############################################################################
+# Configuration Options
+#############################################################################
+# Multi-chipsets
+CONFIG_SD8887=n
+CONFIG_SD8897=n
+CONFIG_USB8897=n
+CONFIG_PCIE8897=n
+CONFIG_SD8977=n
+CONFIG_SD8978=n
+CONFIG_USB8978=n
+CONFIG_SD8997=n
+CONFIG_USB8997=n
+CONFIG_PCIE8997=y
+CONFIG_SD8987=y
+CONFIG_SD9097=n
+CONFIG_USB9097=n
+CONFIG_PCIE9097=n
+CONFIG_SD9098=n
+CONFIG_USB9098=n
+CONFIG_PCIE9098=n
+
+# Debug Option
+# DEBUG LEVEL n/1/2:
+# n: NO DEBUG
+# 1: Only PRINTM(MMSG,...), PRINTM(MFATAL,...), ...
+# 2: All PRINTM()
+CONFIG_DEBUG=1
+
+# Enable STA mode support
+CONFIG_STA_SUPPORT=y
+
+# Enable uAP mode support
+CONFIG_UAP_SUPPORT=y
+
+# Enable WIFIDIRECT support
+CONFIG_WIFI_DIRECT_SUPPORT=y
+
+# Re-association in driver
+CONFIG_REASSOCIATION=y
+
+# Manufacturing firmware support
+CONFIG_MFG_CMD_SUPPORT=y
+
+# OpenWrt support
+CONFIG_OPENWRT_SUPPORT=n
+
+# Big-endian platform
+CONFIG_BIG_ENDIAN=n
+
+ifeq ($(CONFIG_DRV_EMBEDDED_SUPPLICANT), y)
+CONFIG_EMBEDDED_SUPP_AUTH=y
+else
+ifeq ($(CONFIG_DRV_EMBEDDED_AUTHENTICATOR), y)
+CONFIG_EMBEDDED_SUPP_AUTH=y
+endif
+endif
+
+#ifdef SDIO_MMC
+# SDIO suspend/resume
+CONFIG_SDIO_SUSPEND_RESUME=y
+#endif
+
+# DFS testing support
+CONFIG_DFS_TESTING_SUPPORT=y
+
+CONFIG_ANDROID_KERNEL=n
+
+#32bit app over 64bit kernel support
+CONFIG_USERSPACE_32BIT_OVER_KERNEL_64BIT=n
+
+#############################################################################
+# Select Platform Tools
+#############################################################################
+
+MODEXT = ko
+ccflags-y += -I$(M)/mlan
+ccflags-y += -DLINUX
+
+CONFIG_IMX_SUPPORT=y
+ifeq ($(CONFIG_IMX_SUPPORT),y)
+ccflags-y += -DIMX_SUPPORT
+endif
+
+LD += -S
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+ ccflags-y += -DFPNUM='"92"'
+
+ifeq ($(CONFIG_DEBUG),1)
+ ccflags-y += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_DEBUG),2)
+ ccflags-y += -DDEBUG_LEVEL1
+ ccflags-y += -DDEBUG_LEVEL2
+ DBG= -dbg
+endif
+
+ifeq ($(CONFIG_64BIT), y)
+ ccflags-y += -DMLAN_64BIT
+endif
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ ccflags-y += -DSTA_SUPPORT
+ifeq ($(CONFIG_REASSOCIATION),y)
+ ccflags-y += -DREASSOCIATION
+endif
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_STA_WEXT=n
+CONFIG_STA_CFG80211=n
+endif
+
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ ccflags-y += -DUAP_SUPPORT
+else
+CONFIG_WIFI_DIRECT_SUPPORT=n
+CONFIG_UAP_WEXT=n
+CONFIG_UAP_CFG80211=n
+endif
+
+ifeq ($(CONFIG_WIFI_DIRECT_SUPPORT),y)
+ ccflags-y += -DWIFI_DIRECT_SUPPORT
+endif
+
+ifeq ($(CONFIG_MFG_CMD_SUPPORT),y)
+ ccflags-y += -DMFG_CMD_SUPPORT
+endif
+
+ifeq ($(CONFIG_BIG_ENDIAN),y)
+ ccflags-y += -DBIG_ENDIAN_SUPPORT
+endif
+
+ifeq ($(CONFIG_USERSPACE_32BIT_OVER_KERNEL_64BIT),y)
+ ccflags-y += -DUSERSPACE_32BIT_OVER_KERNEL_64BIT
+endif
+
+#ifdef SDIO_MMC
+ifeq ($(CONFIG_SDIO_SUSPEND_RESUME),y)
+ ccflags-y += -DSDIO_SUSPEND_RESUME
+endif
+#endif
+
+
+ifeq ($(CONFIG_DFS_TESTING_SUPPORT),y)
+ ccflags-y += -DDFS_TESTING_SUPPORT
+endif
+
+
+ifeq ($(CONFIG_ANDROID_KERNEL), y)
+ ccflags-y += -DANDROID_KERNEL
+endif
+
+ifeq ($(CONFIG_OPENWRT_SUPPORT), y)
+ ccflags-y += -DOPENWRT
+endif
+
+ifeq ($(CONFIG_T50), y)
+ ccflags-y += -DT50
+ ccflags-y += -DT40
+ ccflags-y += -DT3T
+endif
+
+ifeq ($(CONFIG_SD8887),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8887
+endif
+ifeq ($(CONFIG_SD8897),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8897
+endif
+ifeq ($(CONFIG_SD8977),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8977
+endif
+ifeq ($(CONFIG_SD8978),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8978
+endif
+ifeq ($(CONFIG_SD8997),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8997
+endif
+ifeq ($(CONFIG_SD8987),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD8987
+endif
+ifeq ($(CONFIG_SD9097),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD9097
+endif
+ifeq ($(CONFIG_SD9098),y)
+ CONFIG_SDIO=y
+ ccflags-y += -DSD9098
+endif
+ifeq ($(CONFIG_USB8897),y)
+ CONFIG_MUSB=y
+ ccflags-y += -DUSB8897
+endif
+ifeq ($(CONFIG_USB8997),y)
+ CONFIG_MUSB=y
+ ccflags-y += -DUSB8997
+endif
+ifeq ($(CONFIG_USB8978),y)
+ CONFIG_MUSB=y
+ ccflags-y += -DUSB8978
+endif
+ifeq ($(CONFIG_USB9097),y)
+ CONFIG_MUSB=y
+ ccflags-y += -DUSB9097
+endif
+ifeq ($(CONFIG_USB9098),y)
+ CONFIG_MUSB=y
+ ccflags-y += -DUSB9098
+endif
+ifeq ($(CONFIG_PCIE8897),y)
+ CONFIG_PCIE=y
+ ccflags-y += -DPCIE8897
+endif
+ifeq ($(CONFIG_PCIE8997),y)
+ CONFIG_PCIE=y
+ ccflags-y += -DPCIE8997
+endif
+ifeq ($(CONFIG_PCIE9097),y)
+ CONFIG_PCIE=y
+ ccflags-y += -DPCIE9097
+endif
+ifeq ($(CONFIG_PCIE9098),y)
+ CONFIG_PCIE=y
+ ccflags-y += -DPCIE9098
+endif
+ifeq ($(CONFIG_SDIO),y)
+ ccflags-y += -DSDIO
+ ccflags-y += -DSDIO_MMC
+endif
+ifeq ($(CONFIG_MUSB),y)
+ ccflags-y += -DUSB
+endif
+ifeq ($(CONFIG_PCIE),y)
+ ccflags-y += -DPCIE
+endif
+
+# add -Wno-packed-bitfield-compat when GCC version greater than 4.4
+GCC_VERSION := $(shell echo `gcc -dumpversion | cut -f1-2 -d.` \>= 4.4 | sed -e 's/\./*100+/g' | bc )
+ifeq ($(GCC_VERSION),1)
+ ccflags-y += -Wno-packed-bitfield-compat
+endif
+ ccflags-y += -Wno-stringop-overflow
+ ccflags-y += -Wno-tautological-compare
+ ccflags-y += -Wno-packed-bitfield-compat
+ ccflags-y += -Wno-stringop-truncation
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifeq ($(CONFIG_WIRELESS_EXT),y)
+ifeq ($(CONFIG_WEXT_PRIV),y)
+ # Enable WEXT for STA
+ CONFIG_STA_WEXT=y
+ # Enable WEXT for uAP
+ CONFIG_UAP_WEXT=y
+else
+# Disable WEXT for STA
+ CONFIG_STA_WEXT=n
+# Disable WEXT for uAP
+ CONFIG_UAP_WEXT=n
+endif
+endif
+
+# Enable CFG80211 for STA
+ifeq ($(CONFIG_CFG80211),y)
+ CONFIG_STA_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+ CONFIG_STA_CFG80211=y
+else
+ CONFIG_STA_CFG80211=n
+endif
+endif
+
+# OpenWrt
+ifeq ($(CONFIG_OPENWRT_SUPPORT), y)
+ifeq ($(CPTCFG_CFG80211),y)
+ CONFIG_STA_CFG80211=y
+else
+ifeq ($(CPTCFG_CFG80211),m)
+ CONFIG_STA_CFG80211=y
+else
+ CONFIG_STA_CFG80211=n
+endif
+endif
+endif
+
+# Enable CFG80211 for uAP
+ifeq ($(CONFIG_CFG80211),y)
+ CONFIG_UAP_CFG80211=y
+else
+ifeq ($(CONFIG_CFG80211),m)
+ CONFIG_UAP_CFG80211=y
+else
+ CONFIG_UAP_CFG80211=n
+endif
+endif
+
+# OpenWrt
+ifeq ($(CONFIG_OPENWRT_SUPPORT), y)
+ifeq ($(CPTCFG_CFG80211),y)
+ CONFIG_STA_CFG80211=y
+else
+ifeq ($(CPTCFG_CFG80211),m)
+ CONFIG_STA_CFG80211=y
+else
+ CONFIG_STA_CFG80211=n
+endif
+endif
+endif
+
+ifneq ($(CONFIG_STA_SUPPORT),y)
+ CONFIG_WIFI_DIRECT_SUPPORT=n
+ CONFIG_STA_WEXT=n
+ CONFIG_STA_CFG80211=n
+endif
+
+ifneq ($(CONFIG_UAP_SUPPORT),y)
+ CONFIG_WIFI_DIRECT_SUPPORT=n
+ CONFIG_UAP_WEXT=n
+ CONFIG_UAP_CFG80211=n
+endif
+
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ifeq ($(CONFIG_STA_WEXT),y)
+ ccflags-y += -DSTA_WEXT
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+ ccflags-y += -DSTA_CFG80211
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ifeq ($(CONFIG_UAP_WEXT),y)
+ ccflags-y += -DUAP_WEXT
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+ ccflags-y += -DUAP_CFG80211
+endif
+endif
+
+print:
+ifeq ($(CONFIG_STA_SUPPORT),y)
+ifeq ($(CONFIG_STA_WEXT),n)
+ifeq ($(CONFIG_STA_CFG80211),n)
+ @echo "Can not build STA without WEXT or CFG80211"
+ exit 2
+endif
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+ifeq ($(CONFIG_UAP_WEXT),n)
+ifeq ($(CONFIG_UAP_CFG80211),n)
+ @echo "Can not build UAP without WEXT or CFG80211"
+ exit 2
+endif
+endif
+endif
+
+MOALOBJS = mlinux/moal_main.o \
+ mlinux/moal_ioctl.o \
+ mlinux/moal_shim.o \
+ mlinux/moal_eth_ioctl.o \
+ mlinux/moal_init.o
+
+MLANOBJS = mlan/mlan_shim.o mlan/mlan_init.o \
+ mlan/mlan_txrx.o \
+ mlan/mlan_cmdevt.o mlan/mlan_misc.o \
+ mlan/mlan_cfp.o \
+ mlan/mlan_module.o
+
+MLANOBJS += mlan/mlan_wmm.o
+ifeq ($(CONFIG_MUSB),y)
+MLANOBJS += mlan/mlan_usb.o
+endif
+ifeq ($(CONFIG_SDIO),y)
+MLANOBJS += mlan/mlan_sdio.o
+endif
+ifeq ($(CONFIG_PCIE),y)
+MLANOBJS += mlan/mlan_pcie.o
+endif
+MLANOBJS += mlan/mlan_11n_aggr.o
+MLANOBJS += mlan/mlan_11n_rxreorder.o
+MLANOBJS += mlan/mlan_11n.o
+MLANOBJS += mlan/mlan_11ac.o
+MLANOBJS += mlan/mlan_11ax.o
+MLANOBJS += mlan/mlan_11d.o
+MLANOBJS += mlan/mlan_11h.o
+ifeq ($(CONFIG_STA_SUPPORT),y)
+MLANOBJS += mlan/mlan_meas.o
+MLANOBJS += mlan/mlan_scan.o \
+ mlan/mlan_sta_ioctl.o \
+ mlan/mlan_sta_rx.o \
+ mlan/mlan_sta_tx.o \
+ mlan/mlan_sta_event.o \
+ mlan/mlan_sta_cmd.o \
+ mlan/mlan_sta_cmdresp.o \
+ mlan/mlan_join.o
+ifeq ($(CONFIG_STA_WEXT),y)
+MOALOBJS += mlinux/moal_priv.o \
+ mlinux/moal_wext.o
+endif
+endif
+ifeq ($(CONFIG_UAP_SUPPORT),y)
+MLANOBJS += mlan/mlan_uap_ioctl.o
+MLANOBJS += mlan/mlan_uap_cmdevent.o
+MLANOBJS += mlan/mlan_uap_txrx.o
+MOALOBJS += mlinux/moal_uap.o
+ifeq ($(CONFIG_UAP_WEXT),y)
+MOALOBJS += mlinux/moal_uap_priv.o
+MOALOBJS += mlinux/moal_uap_wext.o
+endif
+endif
+ifeq ($(CONFIG_STA_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_cfg80211_util.o
+MOALOBJS += mlinux/moal_sta_cfg80211.o
+endif
+ifeq ($(CONFIG_UAP_CFG80211),y)
+MOALOBJS += mlinux/moal_cfg80211.o
+MOALOBJS += mlinux/moal_cfg80211_util.o
+MOALOBJS += mlinux/moal_uap_cfg80211.o
+endif
+
+ifdef CONFIG_PROC_FS
+MOALOBJS += mlinux/moal_proc.o
+MOALOBJS += mlinux/moal_debug.o
+endif
+
+obj-$(CONFIG_MXMWIFIEX) := mlan.o
+mlan-objs := $(MLANOBJS)
+
+ifeq ($(CONFIG_MUSB),y)
+MOALOBJS += mlinux/moal_usb.o
+endif
+ifeq ($(CONFIG_SDIO),y)
+MOALOBJS += mlinux/moal_sdio_mmc.o
+endif
+ifeq ($(CONFIG_PCIE),y)
+MOALOBJS += mlinux/moal_pcie.o
+endif
+
+obj-$(CONFIG_MXMWIFIEX) += moal.o
+moal-objs := $(MOALOBJS)
+
+clean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -find . -name "*.mod" -exec rm {} \;
+ -find . -name "Module.symvers" -exec rm {} \;
+ -find . -name "Module.markers" -exec rm {} \;
+ -find . -name "modules.order" -exec rm {} \;
+ -find . -name ".*.dwo" -exec rm {} \;
+ -find . -name "*dwo" -exec rm {} \;
+ -rm -rf .tmp_versions
+
+distclean:
+ -find . -name "*.o" -exec rm {} \;
+ -find . -name "*.orig" -exec rm {} \;
+ -find . -name "*.swp" -exec rm {} \;
+ -find . -name "*.*~" -exec rm {} \;
+ -find . -name "*~" -exec rm {} \;
+ -find . -name "*.d" -exec rm {} \;
+ -find . -name "*.a" -exec rm {} \;
+ -find . -name "tags" -exec rm {} \;
+ -find . -name ".*" -exec rm -rf 2> /dev/null \;
+ -find . -name "*.ko" -exec rm {} \;
+ -find . -name ".*.cmd" -exec rm {} \;
+ -find . -name "*.mod.c" -exec rm {} \;
+ -find . -name ".*.dwo" -exec rm {} \;
+ -find . -name "*dwo" -exec rm {} \;
+ -rm -rf .tmp_versions
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan.h
new file mode 100644
index 000000000000..d2cd022e02d7
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan.h
@@ -0,0 +1,37 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.c
new file mode 100644
index 000000000000..04aee8d4e019
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.c
@@ -0,0 +1,1309 @@
+/** @file mlan_11ac.c
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+
+#define NO_NSS_SUPPORT 0x3
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+t_u16 wlan_convert_mcsmap_to_maxrate(mlan_private *priv, t_u16 bands,
+ t_u16 mcs_map);
+/**
+ * @brief determine the center frquency center index for bandwidth
+ * of 80 MHz and 160 MHz
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band band
+ * @param pri_chan primary channel
+ * @param chan_bw channel bandwidth
+ *
+ * @return channel center frequency center, if found; O, otherwise
+ */
+
+t_u8 wlan_get_center_freq_idx(mlan_private *pmpriv, t_u16 band, t_u32 pri_chan,
+ t_u8 chan_bw)
+{
+ t_u8 center_freq_idx = 0;
+
+ if (band & BAND_AAC) {
+ switch (pri_chan) {
+ case 36:
+ case 40:
+ case 44:
+ case 48:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 42;
+ break;
+ }
+ /* fall through */
+ case 52:
+ case 56:
+ case 60:
+ case 64:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 58;
+ break;
+ } else if (chan_bw == CHANNEL_BW_160MHZ) {
+ center_freq_idx = 50;
+ break;
+ }
+ /* fall through */
+ case 100:
+ case 104:
+ case 108:
+ case 112:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 106;
+ break;
+ }
+ /* fall through */
+ case 116:
+ case 120:
+ case 124:
+ case 128:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 122;
+ break;
+ } else if (chan_bw == CHANNEL_BW_160MHZ) {
+ center_freq_idx = 114;
+ break;
+ }
+ /* fall through */
+ case 132:
+ case 136:
+ case 140:
+ case 144:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 138;
+ break;
+ }
+ /* fall through */
+ case 149:
+ case 153:
+ case 157:
+ case 161:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 155;
+ break;
+ }
+ /* fall through */
+ case 165:
+ case 169:
+ case 173:
+ case 177:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 171;
+ break;
+ }
+ /* fall through */
+ case 184:
+ case 188:
+ case 192:
+ case 196:
+ if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 190;
+ break;
+ }
+ /* fall through */
+ default: /* error. go to the default */
+ center_freq_idx = 42;
+ }
+ }
+ return center_freq_idx;
+}
+
+/**
+ * @brief This function gets the bitmap of nss which supports VHT mcs
+ *
+ * @param mcs_map_set VHT mcs map
+ *
+ * @return The bitmap of supported nss
+ */
+static t_u8 wlan_get_nss_vht_mcs(t_u16 mcs_map_set)
+{
+ t_u8 nss, nss_map = 0;
+ for (nss = 1; nss <= 8; nss++) {
+ if (GET_VHTNSSMCS(mcs_map_set, nss) != NO_NSS_SUPPORT)
+ nss_map |= 1 << (nss - 1);
+ }
+ PRINTM(MCMND, "Supported nss bit map:0x%02x\n", nss_map);
+ return nss_map;
+}
+
+/**
+ * @brief This function gets the bitmap of nss which supports VHT mcs
+ *
+ * @param mcs_map_set VHT mcs map
+ *
+ * @return The bitmap of supported nss
+ */
+static t_u8 wlan_get_nss_num_vht_mcs(t_u16 mcs_map_set)
+{
+ t_u8 nss, nss_num = 0;
+ for (nss = 1; nss <= 8; nss++) {
+ if (GET_VHTNSSMCS(mcs_map_set, nss) != NO_NSS_SUPPORT)
+ nss_num++;
+ }
+ PRINTM(MCMND, "Supported nss:%d\n", nss_num);
+ return nss_num;
+}
+
+/**
+ * @brief This function fills the cap info
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+static void wlan_fill_cap_info(mlan_private *priv, VHT_capa_t *vht_cap,
+ t_u8 bands)
+{
+ t_u32 usr_dot_11ac_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11ac_dev_cap = priv->usr_dot_11ac_dev_cap_a;
+ else
+ usr_dot_11ac_dev_cap = priv->usr_dot_11ac_dev_cap_bg;
+
+ vht_cap->vht_cap_info = usr_dot_11ac_dev_cap;
+
+ LEAVE();
+}
+
+/**
+ * @brief Set/get 11ac configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11ac_ioctl_vhtcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11ac_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u32 usr_vht_cap_info = 0;
+ t_u32 cfg_value = 0;
+ t_u32 hw_value = 0;
+ t_u8 nss = 0;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ t_u16 rx_nss = 0;
+ t_u16 tx_nss = 0;
+#endif
+
+ ENTER();
+
+#define VHT_CAP_INFO_BIT_FIELDS \
+ (MBIT(4) | MBIT(5) | MBIT(6) | MBIT(7) | MBIT(11) | MBIT(12) | \
+ MBIT(19) | MBIT(20) | MBIT(21) | MBIT(22) | MBIT(28) | MBIT(29))
+
+ cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /** SET operation */
+ /** validate the user input and correct it if necessary */
+ if (pmpriv->bss_role == MLAN_BSS_ROLE_STA) {
+ if (cfg->param.vht_cfg.txrx == 3) {
+ PRINTM(MERROR,
+ "Configuration of VHT capabilities for TX/RX 3 is not supported in STA mode!\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ if (pmpriv->bss_role == MLAN_BSS_ROLE_UAP) {
+ if (cfg->param.vht_cfg.txrx != 3) {
+ PRINTM(MERROR,
+ "Configuration of VHT capabilities for TX/RX %d is not supported in UAP mode!\n",
+ cfg->param.vht_cfg.txrx);
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ /** set bit fileds */
+ usr_vht_cap_info = VHT_CAP_INFO_BIT_FIELDS &
+ cfg->param.vht_cfg.vht_cap_info &
+ pmadapter->hw_dot_11ac_dev_cap;
+ /** set MAX MPDU LEN field (bit 0 - bit 1) */
+ cfg_value =
+ GET_VHTCAP_MAXMPDULEN(cfg->param.vht_cfg.vht_cap_info);
+ hw_value =
+ GET_VHTCAP_MAXMPDULEN(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_MAXMPDULEN(usr_vht_cap_info,
+ MIN(cfg_value, hw_value));
+ /** set CHAN Width Set field (bit 2 - bit 3) */
+ cfg_value = GET_VHTCAP_CHWDSET(cfg->param.vht_cfg.vht_cap_info);
+ hw_value = GET_VHTCAP_CHWDSET(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_CHWDSET(usr_vht_cap_info, MIN(cfg_value, hw_value));
+ /** set Rx STBC field (bit 8 - bit 10) */
+ cfg_value = GET_VHTCAP_RXSTBC(cfg->param.vht_cfg.vht_cap_info);
+ hw_value = GET_VHTCAP_RXSTBC(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_RXSTBC(usr_vht_cap_info, MIN(cfg_value, hw_value));
+ /** set Steering Number of BFer Ant (bit 13 - bit 15) */
+ cfg_value =
+ GET_VHTCAP_SNBFERANT(cfg->param.vht_cfg.vht_cap_info);
+ hw_value = GET_VHTCAP_SNBFERANT(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_SNBFERANT(usr_vht_cap_info,
+ MIN(cfg_value, hw_value));
+ /** set Number of Sounding Dimension (bit 16 - bit 18) */
+ cfg_value =
+ GET_VHTCAP_NUMSNDDM(cfg->param.vht_cfg.vht_cap_info);
+ hw_value = GET_VHTCAP_NUMSNDDM(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_NUMSNDDM(usr_vht_cap_info, MIN(cfg_value, hw_value));
+ /** set Number of Max AMPDU Length Exponent (bit 23 - bit 25) */
+ cfg_value = GET_VHTCAP_MAXAMPDULENEXP(
+ cfg->param.vht_cfg.vht_cap_info);
+ hw_value = GET_VHTCAP_MAXAMPDULENEXP(
+ pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_MAXAMPDULENEXP(usr_vht_cap_info,
+ MIN(cfg_value, hw_value));
+ /** set VHT Link Adaptation Capable (bit 26 - bit 27) */
+ cfg_value =
+ GET_VHTCAP_LINKADPCAP(cfg->param.vht_cfg.vht_cap_info);
+ hw_value =
+ GET_VHTCAP_LINKADPCAP(pmadapter->hw_dot_11ac_dev_cap);
+ SET_VHTCAP_LINKADPCAP(usr_vht_cap_info,
+ MIN(cfg_value, hw_value));
+ /** update the user setting if it is beyond the hw capabiliteis
+ */
+ cfg->param.vht_cfg.vht_cap_info = usr_vht_cap_info;
+ PRINTM(MINFO, "Set: vht cap info 0x%x\n", usr_vht_cap_info);
+
+ /** update the RX MCS map */
+ if (cfg->param.vht_cfg.txrx & MLAN_RADIO_RX) {
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ if (cfg->param.vht_cfg.band == BAND_SELECT_A) {
+ rx_nss = GET_RXMCSSUPP(
+ pmadapter->user_htstream >> 8);
+ tx_nss =
+ GET_TXMCSSUPP(
+ pmadapter->user_htstream >>
+ 8) &
+ 0x0f;
+ } else {
+ rx_nss = GET_RXMCSSUPP(
+ pmadapter->user_htstream);
+ tx_nss =
+ GET_TXMCSSUPP(
+ pmadapter->user_htstream) &
+ 0x0f;
+ }
+ }
+#endif
+ /* use the previous user value */
+ if (cfg->param.vht_cfg.vht_rx_mcs == 0xffffffff)
+ cfg->param.vht_cfg.vht_rx_mcs = GET_VHTMCS(
+ pmpriv->usr_dot_11ac_mcs_support);
+ for (nss = 1; nss <= 8; nss++) {
+ cfg_value = GET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_rx_mcs, nss);
+ hw_value = GET_DEVNSSRXMCS(
+ pmadapter->hw_dot_11ac_mcs_support,
+ nss);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if ((rx_nss != 0) && (nss > rx_nss))
+ cfg_value = NO_NSS_SUPPORT;
+#endif
+ if ((hw_value == NO_NSS_SUPPORT) ||
+ (cfg_value == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_rx_mcs,
+ nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_rx_mcs,
+ nss, MIN(cfg_value, hw_value));
+ }
+ PRINTM(MINFO, "Set: vht rx mcs set 0x%08x\n",
+ cfg->param.vht_cfg.vht_rx_mcs);
+ /* use the previous user value */
+ if (cfg->param.vht_cfg.vht_tx_mcs == 0xffffffff)
+ cfg->param.vht_cfg.vht_tx_mcs = GET_VHTMCS(
+ pmpriv->usr_dot_11ac_mcs_support >> 16);
+ for (nss = 1; nss <= 8; nss++) {
+ cfg_value = GET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_tx_mcs, nss);
+ hw_value = GET_DEVNSSTXMCS(
+ pmadapter->hw_dot_11ac_mcs_support,
+ nss);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if ((rx_nss != 0) && (nss > rx_nss))
+ cfg_value = NO_NSS_SUPPORT;
+#endif
+ if ((hw_value == NO_NSS_SUPPORT) ||
+ (cfg_value == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_tx_mcs,
+ nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(
+ cfg->param.vht_cfg.vht_tx_mcs,
+ nss, MIN(cfg_value, hw_value));
+ }
+ PRINTM(MINFO, "Set: vht tx mcs set 0x%08x\n",
+ cfg->param.vht_cfg.vht_tx_mcs);
+ if (!cfg->param.vht_cfg.skip_usr_11ac_mcs_cfg) {
+ RESET_DEVRXMCSMAP(
+ pmpriv->usr_dot_11ac_mcs_support);
+ pmpriv->usr_dot_11ac_mcs_support |= GET_VHTMCS(
+ cfg->param.vht_cfg.vht_rx_mcs);
+ RESET_DEVTXMCSMAP(
+ pmpriv->usr_dot_11ac_mcs_support);
+ pmpriv->usr_dot_11ac_mcs_support |=
+ (GET_VHTMCS(
+ cfg->param.vht_cfg.vht_tx_mcs)
+ << 16);
+ PRINTM(MINFO, "Set: vht mcs set 0x%08x\n",
+ pmpriv->usr_dot_11ac_mcs_support);
+ } else {
+ PRINTM(MINFO,
+ "Skipped user 11ac mcs configuration\n");
+ cfg->param.vht_cfg.skip_usr_11ac_mcs_cfg =
+ MFALSE;
+ }
+ }
+ }
+
+ if (pmpriv->bss_role == MLAN_BSS_ROLE_STA) {
+ if (cfg->param.vht_cfg.txrx & MLAN_RADIO_RX) {
+ /* maximum VHT configuration used in association */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (cfg->param.vht_cfg.band == BAND_SELECT_BG)
+ pmpriv->usr_dot_11ac_dev_cap_bg =
+ usr_vht_cap_info;
+ else if (cfg->param.vht_cfg.band ==
+ BAND_SELECT_A)
+ pmpriv->usr_dot_11ac_dev_cap_a =
+ usr_vht_cap_info;
+ else {
+ pmpriv->usr_dot_11ac_dev_cap_bg =
+ usr_vht_cap_info;
+ pmpriv->usr_dot_11ac_dev_cap_a =
+ usr_vht_cap_info;
+ }
+ pmpriv->usr_dot_11ac_bw =
+ cfg->param.vht_cfg.bwcfg;
+
+ } else {
+ /** GET operation */
+ if (cfg->param.vht_cfg.band == BAND_SELECT_BG) {
+ cfg->param.vht_cfg.vht_cap_info =
+ pmpriv->usr_dot_11ac_dev_cap_bg;
+ PRINTM(MINFO,
+ "Get: vht cap info for 2.4GHz 0x%x\n",
+ pmpriv->usr_dot_11ac_dev_cap_bg);
+ } else if (cfg->param.vht_cfg.band ==
+ BAND_SELECT_A) {
+ cfg->param.vht_cfg.vht_cap_info =
+ pmpriv->usr_dot_11ac_dev_cap_a;
+ PRINTM(MINFO,
+ "Get: vht cap info for 5GHz 0x%x\n",
+ pmpriv->usr_dot_11ac_dev_cap_a);
+ } else {
+ PRINTM(MINFO,
+ "Get: invalid band selection for vht cap info\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ cfg->param.vht_cfg.bwcfg =
+ pmpriv->usr_dot_11ac_bw;
+ cfg->param.vht_cfg.vht_rx_mcs = GET_DEVRXMCSMAP(
+ pmpriv->usr_dot_11ac_mcs_support);
+ cfg->param.vht_cfg.vht_tx_mcs = GET_DEVTXMCSMAP(
+ pmpriv->usr_dot_11ac_mcs_support);
+ cfg->param.vht_cfg.vht_rx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(
+ pmpriv, cfg->param.vht_cfg.band,
+ cfg->param.vht_cfg.vht_rx_mcs);
+ cfg->param.vht_cfg.vht_tx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(
+ pmpriv, cfg->param.vht_cfg.band,
+ cfg->param.vht_cfg.vht_tx_mcs);
+ }
+ LEAVE();
+ return ret;
+ }
+ }
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AC_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.vht_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set Operating Mode Notification cfg
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11ac_ioctl_opermodecfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11ac_cfg *cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u8 hw_bw_160or8080 = 0;
+ t_u8 hw_rx_nss = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.opermode_cfg.bw = pmpriv->usr_dot_11ac_opermode_bw;
+ cfg->param.opermode_cfg.nss = pmpriv->usr_dot_11ac_opermode_nss;
+ } else if (pioctl_req->action == MLAN_ACT_SET) {
+ hw_bw_160or8080 =
+ GET_VHTCAP_CHWDSET(pmadapter->hw_dot_11ac_dev_cap);
+ hw_rx_nss = wlan_get_nss_num_vht_mcs(
+ GET_DEVRXMCSMAP(pmadapter->hw_dot_11ac_mcs_support));
+ if ((((cfg->param.opermode_cfg.bw - 1) > BW_80MHZ) &&
+ !hw_bw_160or8080) ||
+ (cfg->param.opermode_cfg.nss > hw_rx_nss)) {
+ PRINTM(MERROR,
+ "bw or nss NOT supported. HW support bw_160or8080=%d rx_nss=%d.\n",
+ hw_bw_160or8080, hw_rx_nss);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->usr_dot_11ac_opermode_bw = cfg->param.opermode_cfg.bw;
+ pmpriv->usr_dot_11ac_opermode_nss = cfg->param.opermode_cfg.nss;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get supported MCS set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11ac_ioctl_supported_mcs_set(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ /*mlan_ds_11ac_cfg *cfg= MNULL;*/
+ /*int rx_mcs_supp;*/
+ /*t_u8 mcs_set[NUM_MCS_SUPP];*/
+
+ ENTER();
+#if 0
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Set operation is not supported\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rx_mcs_supp = GET_11ACRXMCSSUPP(pmadapter->usr_dot_11ac_mcs_support);
+ /* Set MCS */
+ memset(pmadapter, (t_u8 *) mcs_set, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *) &mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if (ISSUPP_CHANWIDTH80(pmadapter->usr_dot_11ac_dev_cap_bg)
+ || ISSUPP_CHANWIDTH80(pmadapter->usr_dot_11ac_dev_cap_a)
+ )
+ SETHT_MCS32(mcs_set);
+
+ cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
+ memcpy_ext(pmadapter, cfg->param.supported_mcs_set, mcs_set,
+ NUM_MCS_SUPP, sizeof(cfg->param.supported_mcs_set));
+
+#endif
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prints the 802.11ac device capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void wlan_show_dot11acdevcap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ switch (GET_VHTCAP_MAXMPDULEN(cap)) {
+ case 0x0:
+ PRINTM(MINFO,
+ "GET_HW_SPEC: Maximum MSDU length = 3895 octets\n");
+ break;
+ case 0x1:
+ PRINTM(MINFO,
+ "GET_HW_SPEC: Maximum MSDU length = 7991 octets\n");
+ break;
+ case 0x2:
+ PRINTM(MINFO,
+ "GET_HW_SPEC: Maximum MSDU length = 11454 octets\n");
+ break;
+ default:
+ PRINTM(MINFO, "Unsupport value\n");
+ break;
+ }
+
+ PRINTM(MINFO, "GET_HW_SPEC: HTC-VHT %s\n",
+ (ISSUPP_11ACVHTHTCVHT(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: VHT TXOP PS %s\n",
+ (ISSUPP_11ACVHTTXOPPS(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MU RX beamformee %s\n",
+ (ISSUPP_11ACMURXBEAMFORMEE(cap) ? "supported" :
+ "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MU TX beamformee %s\n",
+ (ISSUPP_11ACMUTXBEAMFORMEE(cap) ? "supported" :
+ "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: SU RX Beamformee %s\n",
+ (ISSUPP_11ACSUBEAMFORMEE(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: SU TX Beamformer %s\n",
+ (ISSUPP_11ACSUBEAMFORMER(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
+ (ISSUPP_11ACRXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
+ (ISSUPP_11ACTXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI %s for 160MHz BW\n",
+ (ISSUPP_11ACSGI160(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI %s for 80MHz BW\n",
+ (ISSUPP_11ACSGI80(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: LDPC coding %s\n",
+ (ISSUPP_11ACLDPC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Channel BW 20/40/80/160/80+80 MHz %s\n",
+ (ISSUPP_11ACBW8080(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Channel BW 20/40/80/160 MHz %s\n",
+ (ISSUPP_11ACBW160(cap) ? "supported" : "not supported"));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prints the 802.11ac device MCS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void wlan_show_dot11acmcssupport(pmlan_adapter pmadapter, t_u32 support)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: MCSs for %2dx%2d MIMO\n",
+ GET_DEVRXMCSMAP(support), GET_DEVTXMCSMAP(support));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function converts the 2-bit MCS map to the highest long GI
+ * VHT PPDU data rate
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param bands Supported bands
+ * @param mcs_map 2-bit MCS map
+ *
+ * @return the max data rate for long GI
+ */
+t_u16 wlan_convert_mcsmap_to_maxrate(mlan_private *priv, t_u16 bands,
+ t_u16 mcs_map)
+{
+ t_u8 i;
+ t_u8 nss;
+ t_u8 max_mcs;
+ t_u16 max_rate = 0;
+ t_u32 usr_vht_cap_info = 0;
+ t_u32 usr_dot_11n_dev_cap;
+
+ /* tables of the MCS map to the highest data rate (in Mbps)
+ * supported for long GI */
+ t_u16 max_rate_lgi_20MHZ[8][3] = {
+ {0x41, 0x4E, 0x0}, /* NSS = 1 */
+ {0x82, 0x9C, 0x0}, /* NSS = 2 */
+ {0xC3, 0xEA, 0x104}, /* NSS = 3 */
+ {0x104, 0x138, 0x0}, /* NSS = 4 */
+ {0x145, 0x186, 0x0}, /* NSS = 5 */
+ {0x186, 0x1D4, 0x208}, /* NSS = 6 */
+ {0x1C7, 0x222, 0x0}, /* NSS = 7 */
+ {0x208, 0x270, 0x0} /* NSS = 8 */
+ };
+
+ t_u16 max_rate_lgi_40MHZ[8][3] = {
+ {0x87, 0xA2, 0xB4}, /* NSS = 1 */
+ {0x10E, 0x144, 0x168}, /* NSS = 2 */
+ {0x195, 0x1E6, 0x21C}, /* NSS = 3 */
+ {0x21C, 0x288, 0x2D0}, /* NSS = 4 */
+ {0x2A3, 0x32A, 0x384}, /* NSS = 5 */
+ {0x32A, 0x3CC, 0x438}, /* NSS = 6 */
+ {0x3B1, 0x46E, 0x4EC}, /* NSS = 7 */
+ {0x438, 0x510, 0x5A0} /* NSS = 8 */
+ };
+
+ t_u16 max_rate_lgi_80MHZ[8][3] = {
+ {0x124, 0x15F, 0x186}, /* NSS = 1 */
+ {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
+ {0x36D, 0x41D, 0x492}, /* NSS = 3 */
+ {0x492, 0x57C, 0x618}, /* NSS = 4 */
+ {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
+ {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
+ {0x924, 0xAF8, 0xC30} /* NSS = 8 */
+ };
+ t_u16 max_rate_lgi_160MHZ[8][3] = {
+ {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
+ {0x492, 0x57C, 0x618}, /* NSS = 2 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
+ {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
+ {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
+ {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
+ {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
+ {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
+ };
+
+ if (bands & BAND_AAC) {
+ usr_vht_cap_info = priv->usr_dot_11ac_dev_cap_a;
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
+ } else {
+ usr_vht_cap_info = priv->usr_dot_11ac_dev_cap_bg;
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
+ }
+
+ /* find the max NSS supported */
+ nss = 0;
+ for (i = 0; i < 8; i++) {
+ max_mcs = (mcs_map >> (2 * i)) & 0x3;
+ if (max_mcs < 3)
+ nss = i;
+ }
+
+ max_mcs = (mcs_map >> (2 * nss)) & 0x3;
+ /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9*/
+ if (max_mcs >= 3)
+ max_mcs = 2;
+
+ if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
+ /* support 160 MHz */
+ max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
+ if (max_mcs >= 1 && max_rate == 0)
+ /* MCS9 is not supported in NSS6 */
+ max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
+
+ } else {
+ if (priv->usr_dot_11ac_bw == BW_FOLLOW_VHTCAP) {
+ max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
+ if (max_mcs >= 1 && max_rate == 0)
+ /* MCS9 is not supported in NSS3 */
+ max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
+ } else {
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap)) {
+ max_rate = max_rate_lgi_40MHZ[nss][max_mcs];
+ } else {
+ max_rate = max_rate_lgi_20MHZ[nss][max_mcs];
+ /* MCS9 is not supported in NSS1/2/4/5/7/8 */
+ if (max_mcs >= 1 && max_rate == 0)
+ max_rate =
+ max_rate_lgi_20MHZ[nss]
+ [max_mcs - 1];
+ }
+ }
+ }
+ PRINTM(MCMND, "max_rate=%dM\n", max_rate);
+ return max_rate;
+}
+
+/**
+ * @brief This function fills the VHT cap tlv out put format is LE, not CPU
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pvht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ * @param flag TREU--pvht_cap has the setting for resp
+ * MFALSE -- pvht_cap is clean
+ * @param bw_80p80 TRUE -- enable 80p80
+ * @return N/A
+ */
+void wlan_fill_vht_cap_tlv(mlan_private *priv, MrvlIETypes_VHTCap_t *pvht_cap,
+ t_u16 bands, t_u8 flag, t_u8 bw_80p80)
+{
+ t_u16 mcs_map_user = 0;
+ t_u16 mcs_map_resp = 0;
+ t_u16 mcs_map_result = 0;
+ t_u16 mcs_user = 0;
+ t_u16 mcs_resp = 0;
+ t_u16 nss;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ t_u16 rx_nss = 0, tx_nss = 0;
+#endif
+ ENTER();
+
+ /* Fill VHT cap info */
+ wlan_fill_cap_info(priv, &pvht_cap->vht_cap, bands);
+ /* clear 80p80 in vht_cap_info */
+ if (!bw_80p80)
+ pvht_cap->vht_cap.vht_cap_info &= ~(MBIT(2) | MBIT(3));
+ pvht_cap->vht_cap.vht_cap_info =
+ wlan_cpu_to_le32(pvht_cap->vht_cap.vht_cap_info);
+
+ /* Fill VHT MCS Set */
+ /* rx MCS Set, find the minimum of the user rx mcs and ap rx mcs*/
+ mcs_map_resp = mcs_map_user =
+ GET_DEVRXMCSMAP(priv->usr_dot_11ac_mcs_support);
+ if (flag)
+ mcs_map_resp =
+ wlan_le16_to_cpu(pvht_cap->vht_cap.mcs_sets.rx_mcs_map);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(priv->adapter->card_type) ||
+ IS_CARD9097(priv->adapter->card_type)) {
+ if (bands & BAND_A) {
+ rx_nss = GET_RXMCSSUPP(priv->adapter->user_htstream >>
+ 8);
+ tx_nss = GET_TXMCSSUPP(priv->adapter->user_htstream >>
+ 8) &
+ 0x0f;
+ } else {
+ rx_nss = GET_RXMCSSUPP(priv->adapter->user_htstream);
+ tx_nss = GET_TXMCSSUPP(priv->adapter->user_htstream) &
+ 0x0f;
+ }
+ /** force 1x1 when enable 80P80 */
+ if (bw_80p80)
+ rx_nss = tx_nss = 1;
+ }
+#endif
+ mcs_map_result = 0;
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if ((rx_nss != 0) && (nss > rx_nss))
+ mcs_user = NO_NSS_SUPPORT;
+#endif
+ if ((mcs_user == NO_NSS_SUPPORT) ||
+ (mcs_resp == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ MIN(mcs_user, mcs_resp));
+ }
+ /* rx MCS map */
+ pvht_cap->vht_cap.mcs_sets.rx_mcs_map =
+ wlan_cpu_to_le16(mcs_map_result);
+
+ /* rx highest rate */
+ pvht_cap->vht_cap.mcs_sets.rx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ pvht_cap->vht_cap.mcs_sets.rx_max_rate =
+ wlan_cpu_to_le16(pvht_cap->vht_cap.mcs_sets.rx_max_rate);
+
+ /* tx MCS Set find the minimum of the user tx mcs and ap tx mcs */
+ mcs_map_resp = mcs_map_user =
+ GET_DEVTXMCSMAP(priv->usr_dot_11ac_mcs_support);
+ if (flag)
+ mcs_map_resp =
+ wlan_le16_to_cpu(pvht_cap->vht_cap.mcs_sets.tx_mcs_map);
+ mcs_map_result = 0;
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if ((tx_nss != 0) && (nss > tx_nss))
+ mcs_user = NO_NSS_SUPPORT;
+#endif
+ if ((mcs_user == NO_NSS_SUPPORT) ||
+ (mcs_resp == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ MIN(mcs_user, mcs_resp));
+ }
+
+ /* tx MCS map */
+ pvht_cap->vht_cap.mcs_sets.tx_mcs_map =
+ wlan_cpu_to_le16(mcs_map_result);
+ /* tx highest rate */
+ pvht_cap->vht_cap.mcs_sets.tx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ pvht_cap->vht_cap.mcs_sets.tx_max_rate =
+ wlan_cpu_to_le16(pvht_cap->vht_cap.mcs_sets.tx_max_rate);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function fills the VHT cap tlv out put format is CPU
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pvht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+void wlan_fill_vht_cap_ie(mlan_private *priv, IEEEtypes_VHTCap_t *pvht_cap,
+ t_u16 bands)
+{
+ ENTER();
+
+ pvht_cap->ieee_hdr.element_id = VHT_CAPABILITY;
+ pvht_cap->ieee_hdr.len = sizeof(VHT_capa_t);
+
+ /* Fill VHT cap info */
+ wlan_fill_cap_info(priv, &pvht_cap->vht_cap, bands);
+
+ /* rx MCS map */
+ pvht_cap->vht_cap.mcs_sets.rx_mcs_map =
+ GET_DEVRXMCSMAP(priv->usr_dot_11ac_mcs_support);
+
+ /* rx highest rate */
+ pvht_cap->vht_cap.mcs_sets.rx_max_rate = wlan_convert_mcsmap_to_maxrate(
+ priv, bands, pvht_cap->vht_cap.mcs_sets.rx_mcs_map);
+
+ /* tx MCS map */
+ pvht_cap->vht_cap.mcs_sets.tx_mcs_map =
+ GET_DEVTXMCSMAP(priv->usr_dot_11ac_mcs_support);
+ /* tx highest rate */
+ pvht_cap->vht_cap.mcs_sets.tx_max_rate = wlan_convert_mcsmap_to_maxrate(
+ priv, bands, pvht_cap->vht_cap.mcs_sets.tx_mcs_map);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function would check whether support 80+80Mhz
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ *
+ * @return ret suport 80+80Mhz or not
+ */
+t_u8 wlan_is_80_80_support(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
+{
+ t_u8 ret = MFALSE;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ t_u16 rx_nss = 0, tx_nss = 0;
+ IEEEtypes_VHTCap_t *pvht_cap = pbss_desc->pvht_cap;
+ MrvlIEtypes_He_cap_t *phecap = MNULL;
+ IEEEtypes_HECap_t *pBsshecap = MNULL;
+#endif
+
+ ENTER();
+
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (!IS_CARD9098(pmpriv->adapter->card_type) &&
+ !IS_CARD9097(pmpriv->adapter->card_type))
+ return ret;
+ /** check band A */
+ if (!(pbss_desc->bss_band & BAND_A))
+ return ret;
+
+ /** check band A antenna setting */
+ rx_nss = GET_RXMCSSUPP(pmpriv->adapter->user_htstream >> 8);
+ tx_nss = GET_TXMCSSUPP(pmpriv->adapter->user_htstream >> 8) & 0x0f;
+ /** check if support 2*2 */
+ if (rx_nss != 2 || tx_nss != 2)
+ return ret;
+ /** check if AP support AC 80P80 */
+ if (ISSUPP_11ACBW8080(pmpriv->usr_dot_11ac_dev_cap_a) && pvht_cap &&
+ ISSUPP_11ACBW8080(pvht_cap->vht_cap.vht_cap_info))
+ ret = MTRUE;
+ /** check if AP support AX 80P80 */
+ if (pbss_desc->phe_cap) {
+ pBsshecap = (IEEEtypes_HECap_t *)pbss_desc->phe_cap;
+ phecap = (MrvlIEtypes_He_cap_t *)pmpriv->user_he_cap;
+ if (ret && (phecap->he_phy_cap[0] & MBIT(4)) &&
+ (pBsshecap->he_phy_cap[0] & MBIT(4)))
+ ret = MTRUE;
+ else
+ ret = MFALSE;
+ }
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function append the 802_11N tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int wlan_cmd_append_11ac_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIETypes_VHTCap_t *pvht_cap;
+ MrvlIETypes_OperModeNtf_t *pmrvl_oper_mode;
+ t_u16 mcs_map_user = 0;
+ t_u16 nss;
+ int ret_len = 0;
+ t_u8 bw_80p80 = MFALSE;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ t_u16 rx_nss = 0;
+#endif
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /* VHT Capabilities IE */
+ if (pbss_desc->pvht_cap &&
+ wlan_get_nss_vht_mcs(
+ pbss_desc->pvht_cap->vht_cap.mcs_sets.rx_mcs_map)) {
+ pvht_cap = (MrvlIETypes_VHTCap_t *)*ppbuffer;
+ memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
+ pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
+ pvht_cap->header.len = sizeof(VHT_capa_t);
+ memcpy_ext(pmadapter,
+ (t_u8 *)pvht_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *)pbss_desc->pvht_cap +
+ sizeof(IEEEtypes_Header_t),
+ pvht_cap->header.len, sizeof(VHT_capa_t));
+ bw_80p80 = wlan_is_80_80_support(pmpriv, pbss_desc);
+ wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pbss_desc->bss_band,
+ MTRUE, bw_80p80);
+
+ HEXDUMP("VHT_CAPABILITIES IE", (t_u8 *)pvht_cap,
+ sizeof(MrvlIETypes_VHTCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_VHTCap_t);
+ ret_len += sizeof(MrvlIETypes_VHTCap_t);
+ pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
+ } else {
+ LEAVE();
+ return 0;
+ }
+
+ /* Operating Mode Notification IE */
+ pmrvl_oper_mode = (MrvlIETypes_OperModeNtf_t *)*ppbuffer;
+ memset(pmadapter, pmrvl_oper_mode, 0,
+ sizeof(MrvlIETypes_OperModeNtf_t));
+ pmrvl_oper_mode->header.type = wlan_cpu_to_le16(OPER_MODE_NTF);
+ pmrvl_oper_mode->header.len = sizeof(t_u8);
+
+ if (pmpriv->usr_dot_11ac_opermode_bw ||
+ pmpriv->usr_dot_11ac_opermode_nss) {
+ pmrvl_oper_mode->oper_mode |=
+ (pmpriv->usr_dot_11ac_opermode_nss - 1) << 4;
+ pmrvl_oper_mode->oper_mode |=
+ pmpriv->usr_dot_11ac_opermode_bw - 1;
+ if (pbss_desc->bss_band & BAND_G) {
+ if (!(IS_OPER_MODE_20M(pmrvl_oper_mode->oper_mode))) {
+ if (pbss_desc->pht_cap->ht_cap.ht_cap_info &
+ MBIT(1))
+ SET_OPER_MODE_40M(
+ pmrvl_oper_mode->oper_mode);
+ else
+ SET_OPER_MODE_20M(
+ pmrvl_oper_mode->oper_mode);
+ }
+ }
+ } else {
+ /** set default bandwidth:80M*/
+ SET_OPER_MODE_80M(pmrvl_oper_mode->oper_mode);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ if (pbss_desc->bss_band & BAND_A)
+ rx_nss = GET_RXMCSSUPP(
+ pmadapter->user_htstream >> 8);
+ else
+ rx_nss =
+ GET_RXMCSSUPP(pmadapter->user_htstream);
+ }
+#endif
+ mcs_map_user =
+ GET_DEVRXMCSMAP(pmpriv->usr_dot_11ac_mcs_support);
+ nss = wlan_get_nss_num_vht_mcs(mcs_map_user);
+
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ PRINTM(MCMND, "rx_nss=%d nss=%d\n", rx_nss, nss);
+ nss = MIN(rx_nss, nss);
+ }
+#endif
+
+ pmrvl_oper_mode->oper_mode |= (nss - 1) << 4;
+
+ switch (pbss_desc->curr_bandwidth) {
+ case BW_20MHZ:
+ SET_OPER_MODE_20M(pmrvl_oper_mode->oper_mode);
+ break;
+ case BW_40MHZ:
+ SET_OPER_MODE_40M(pmrvl_oper_mode->oper_mode);
+ break;
+ case BW_80MHZ:
+ default:
+ break;
+ }
+ }
+ HEXDUMP("OPER MODE NTF IE", (t_u8 *)pmrvl_oper_mode,
+ sizeof(MrvlIETypes_OperModeNtf_t));
+ *ppbuffer += sizeof(MrvlIETypes_OperModeNtf_t);
+ ret_len += sizeof(MrvlIETypes_OperModeNtf_t);
+ pmrvl_oper_mode->header.len =
+ wlan_cpu_to_le16(pmrvl_oper_mode->header.len);
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief 11ac configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11ac_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11ac_cfg *cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11ac_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11ac_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11AC_VHT_CFG:
+ status = wlan_11ac_ioctl_vhtcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11AC_CFG_SUPPORTED_MCS_SET:
+ status = wlan_11ac_ioctl_supported_mcs_set(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_11AC_OPERMODE_CFG:
+ status = wlan_11ac_ioctl_opermodecfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares 11ac cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11ac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_11AC_CFG *vhtcfg = &cmd->params.vhtcfg;
+ mlan_ds_11ac_vht_cfg *vht_cfg = (mlan_ds_11ac_vht_cfg *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AC_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11AC_CFG) + S_DS_GEN);
+ vhtcfg->action = wlan_cpu_to_le16(cmd_action);
+ vhtcfg->band_config = vht_cfg->band & 0xFF;
+ // block user enable 80MHZ
+ if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
+ vht_cfg->bwcfg = 0;
+
+ vhtcfg->misc_config = vht_cfg->txrx & 0x3;
+ if (vhtcfg->misc_config != 2)
+ vhtcfg->misc_config |= (vht_cfg->bwcfg << 2);
+
+ vhtcfg->vht_cap_info = wlan_cpu_to_le32(vht_cfg->vht_cap_info);
+ vht_cfg->vht_rx_mcs = wlan_cpu_to_le32(vht_cfg->vht_rx_mcs);
+ memcpy_ext(pmadapter, &vhtcfg->vht_supp_mcs_set[0],
+ &vht_cfg->vht_rx_mcs, sizeof(t_u32), sizeof(t_u32));
+ vht_cfg->vht_tx_mcs = wlan_cpu_to_le32(vht_cfg->vht_tx_mcs);
+ memcpy_ext(pmadapter, &vhtcfg->vht_supp_mcs_set[4],
+ &vht_cfg->vht_tx_mcs, sizeof(t_u32), sizeof(t_u32));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11accfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11ac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_ds_11ac_cfg *cfg = MNULL;
+ HostCmd_DS_11AC_CFG *vhtcfg = &resp->params.vhtcfg;
+
+ ENTER();
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(vhtcfg->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_11ac_cfg *)pioctl_buf->pbuf;
+ cfg->param.vht_cfg.band = vhtcfg->band_config;
+ cfg->param.vht_cfg.txrx = vhtcfg->misc_config & 0x03;
+ if (cfg->param.vht_cfg.txrx & 0x1)
+ cfg->param.vht_cfg.bwcfg =
+ (vhtcfg->misc_config & 0x04) >> 2;
+ else
+ cfg->param.vht_cfg.bwcfg = 0;
+
+ cfg->param.vht_cfg.vht_cap_info =
+ wlan_le32_to_cpu(vhtcfg->vht_cap_info);
+ memcpy_ext(pmadapter, &cfg->param.vht_cfg.vht_rx_mcs,
+ &vhtcfg->vht_supp_mcs_set[0], sizeof(t_u32),
+ sizeof(t_u32));
+ cfg->param.vht_cfg.vht_rx_mcs =
+ wlan_le32_to_cpu(cfg->param.vht_cfg.vht_rx_mcs);
+ memcpy_ext(pmadapter, &cfg->param.vht_cfg.vht_tx_mcs,
+ &vhtcfg->vht_supp_mcs_set[4], sizeof(t_u32),
+ sizeof(t_u32));
+ cfg->param.vht_cfg.vht_tx_mcs =
+ wlan_le32_to_cpu(cfg->param.vht_cfg.vht_tx_mcs);
+ cfg->param.vht_cfg.vht_rx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(
+ pmpriv, cfg->param.vht_cfg.band,
+ cfg->param.vht_cfg.vht_rx_mcs);
+ cfg->param.vht_cfg.vht_tx_max_rate =
+ wlan_convert_mcsmap_to_maxrate(
+ pmpriv, cfg->param.vht_cfg.band,
+ cfg->param.vht_cfg.vht_tx_mcs);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+void wlan_update_11ac_cap(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ pmpriv->usr_dot_11ac_mcs_support = pmadapter->hw_dot_11ac_mcs_support;
+ pmpriv->usr_dot_11ac_dev_cap_bg =
+ pmadapter->hw_dot_11ac_dev_cap &
+ ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
+ pmpriv->usr_dot_11ac_dev_cap_a =
+ pmadapter->hw_dot_11ac_dev_cap &
+ ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
+ pmpriv->usr_dot_11ac_bw = BW_FOLLOW_VHTCAP;
+}
+
+/**
+ * @brief This function check if 11AC is allowed in bandcfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_band bss band
+ *
+ * @return 0--not allowed, other value allowed
+ */
+t_u8 wlan_11ac_bandconfig_allowed(mlan_private *pmpriv, t_u16 bss_band)
+{
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ if (bss_band & BAND_G)
+ return (pmpriv->adapter->adhoc_start_band & BAND_GAC);
+ else if (bss_band & BAND_A)
+ return (pmpriv->adapter->adhoc_start_band & BAND_AAC);
+ } else {
+ if (bss_band & BAND_G)
+ return (pmpriv->config_bands & BAND_GAC);
+ else if (bss_band & BAND_A)
+ return (pmpriv->config_bands & BAND_AAC);
+ }
+ return 0;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.h
new file mode 100644
index 000000000000..81661065bbaf
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ac.h
@@ -0,0 +1,52 @@
+/** @file mlan_11ac.h
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MLAN_11AC_H_
+#define _MLAN_11AC_H_
+
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#include "mlan_wmm.h"
+
+void wlan_show_dot11acdevcap(pmlan_adapter pmadapter, t_u32 cap);
+void wlan_show_dot11acmcssupport(pmlan_adapter pmadapter, t_u32 support);
+t_u16 wlan_convert_mcsmap_to_maxrate(mlan_private *priv, t_u16 bands,
+ t_u16 mcs_map);
+void wlan_fill_vht_cap_tlv(mlan_private *priv, MrvlIETypes_VHTCap_t *pvht_cap,
+ t_u16 bands, t_u8 flag, t_u8 bw_80p80);
+void wlan_fill_vht_cap_ie(mlan_private *priv, IEEEtypes_VHTCap_t *pvht_cap,
+ t_u16 bands);
+int wlan_cmd_append_11ac_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer);
+mlan_status wlan_11ac_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+void wlan_update_11ac_cap(mlan_private *pmpriv);
+t_u8 wlan_11ac_bandconfig_allowed(mlan_private *pmpriv, t_u8 bss_band);
+t_u8 wlan_is_80_80_support(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc);
+
+mlan_status wlan_cmd_11ac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+
+mlan_status wlan_ret_11ac_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#endif /* _MLAN_11AC_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.c
new file mode 100644
index 000000000000..628e430dfe4e
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.c
@@ -0,0 +1,904 @@
+/** @file mlan_11ax.c
+ *
+ * @brief This file contains the functions for 11ax related features.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_ioctl.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ax.h"
+#include "mlan_11ac.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prints the 802.11ax HE mac capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void wlan_show_dot11axmaccap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function check if AP support TWT Response.
+ *
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 wlan_check_ap_11ax_twt_supported(BSSDescriptor_t *pbss_desc)
+{
+ if (!pbss_desc->phe_cap)
+ return MFALSE;
+ if (!(pbss_desc->phe_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT))
+ return MFALSE;
+ if (!pbss_desc->pext_cap)
+ return MFALSE;
+ if (!ISSUPP_EXTCAP_EXT_TWT_RESP(pbss_desc->pext_cap->ext_cap))
+ return MFALSE;
+ return MTRUE;
+}
+
+/**
+ * @brief This function check if we should enable TWT support
+ *
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 wlan_check_11ax_twt_supported(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc)
+{
+ MrvlIEtypes_He_cap_t *phecap =
+ (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
+ MrvlIEtypes_He_cap_t *hw_he_cap =
+ (MrvlIEtypes_He_cap_t *)&pmpriv->adapter->hw_he_cap;
+ if (pbss_desc && !wlan_check_ap_11ax_twt_supported(pbss_desc)) {
+ PRINTM(MINFO, "AP don't support twt feature\n");
+ return MFALSE;
+ }
+ if (pbss_desc) {
+ if (pbss_desc->bss_band & BAND_A) {
+ hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
+ ->hw_he_cap;
+ phecap = (MrvlIEtypes_He_cap_t *)&pmpriv->user_he_cap;
+ } else {
+ hw_he_cap = (MrvlIEtypes_He_cap_t *)&pmpriv->adapter
+ ->hw_2g_he_cap;
+ phecap =
+ (MrvlIEtypes_He_cap_t *)&pmpriv->user_2g_he_cap;
+ }
+ }
+ if (!(hw_he_cap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)) {
+ PRINTM(MINFO, "FW don't support TWT\n");
+ return MFALSE;
+ }
+ if (phecap->he_mac_cap[0] & HE_MAC_CAP_TWT_REQ_SUPPORT)
+ return MTRUE;
+ PRINTM(MINFO, "USER HE_MAC_CAP don't support TWT\n");
+ return MFALSE;
+}
+
+/**
+ * @brief This function prints the 802.11ax HE PHY cap
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void wlan_show_dot11axphycap(pmlan_adapter pmadapter, t_u32 support)
+{
+ ENTER();
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function fills the HE cap tlv out put format is LE, not CPU
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param band 5G or 2.4 G
+ * @param phe_cap A pointer to MrvlIEtypes_Data_t structure
+ * @param flag TREU--pvht_cap has the setting for resp
+ * MFALSE -- pvht_cap is clean
+ *
+ * @return bytes added to the phe_cap
+ */
+t_u16 wlan_fill_he_cap_tlv(mlan_private *pmpriv, t_u8 band,
+ MrvlIEtypes_Extension_t *phe_cap, t_u8 flag)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u16 len = 0;
+
+ if (!phe_cap) {
+ LEAVE();
+ return 0;
+ }
+ if (band & BAND_A) {
+ memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_he_cap,
+ pmpriv->user_hecap_len,
+ sizeof(MrvlIEtypes_He_cap_t));
+ len = pmpriv->user_hecap_len;
+ } else {
+ memcpy_ext(pmadapter, (t_u8 *)phe_cap, pmpriv->user_2g_he_cap,
+ pmpriv->user_2g_hecap_len,
+ sizeof(MrvlIEtypes_He_cap_t));
+ len = pmpriv->user_2g_hecap_len;
+ }
+ phe_cap->type = wlan_cpu_to_le16(phe_cap->type);
+ phe_cap->len = wlan_cpu_to_le16(phe_cap->len);
+
+ LEAVE();
+ return len;
+}
+
+/**
+ * @brief This function append the 802_11ax HE capability tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int wlan_cmd_append_11ax_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypes_He_cap_t *phecap = MNULL;
+ int len = 0;
+ t_u8 bw_80p80 = MFALSE;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ /** check if AP support HE, if not return right away */
+ if (!pbss_desc->phe_cap) {
+ LEAVE();
+ return 0;
+ }
+ bw_80p80 = wlan_is_80_80_support(pmpriv, pbss_desc);
+ phecap = (MrvlIEtypes_He_cap_t *)*ppbuffer;
+ if (pbss_desc->bss_band & BAND_A) {
+ memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_he_cap,
+ pmpriv->user_hecap_len, pmpriv->user_hecap_len);
+ *ppbuffer += pmpriv->user_hecap_len;
+ len = pmpriv->user_hecap_len;
+ } else {
+ memcpy_ext(pmadapter, *ppbuffer, pmpriv->user_2g_he_cap,
+ pmpriv->user_2g_hecap_len,
+ pmpriv->user_2g_hecap_len);
+ *ppbuffer += pmpriv->user_2g_hecap_len;
+ len = pmpriv->user_2g_hecap_len;
+ }
+ phecap->type = wlan_cpu_to_le16(phecap->type);
+ phecap->len = wlan_cpu_to_le16(phecap->len);
+
+ if (bw_80p80) {
+ /** configure 2*2 to 1*1 to support 80+80Mhz*/
+ /** set 1*1 mcs rate for 80Mhz rx*/
+ phecap->he_txrx_mcs_support[0] &= ~(MBIT(0) | MBIT(1));
+ /** set 1*1 mcs rate for 80Mhz tx*/
+ phecap->he_txrx_mcs_support[3] &= ~(MBIT(0) | MBIT(1));
+ /** set 1*1 mcs rate for 160Mhz rx*/
+ phecap->he160_txrx_mcs_support[0] &= ~(MBIT(0) | MBIT(1));
+ /** set 1*1 mcs rate for 160Mhz tx*/
+ phecap->he160_txrx_mcs_support[3] &= ~(MBIT(0) | MBIT(1));
+ /** set 1*1 mcs rate for 80+80Mhz rx*/
+ phecap->he8080_txrx_mcs_support[0] &= ~(MBIT(0) | MBIT(1));
+ /** set 1*1 mcs rate for 80+80Mhz tx*/
+ phecap->he8080_txrx_mcs_support[3] &= ~(MBIT(0) | MBIT(1));
+ } else {
+ /** reset BIT3 and BIT4 channel width ,not support 80 + 80*/
+ /** not support 160Mhz now, if support,not reset bit3 */
+ phecap->he_phy_cap[0] &= ~(MBIT(3) | MBIT(4));
+ }
+
+ LEAVE();
+ return len;
+}
+
+/**
+ * @brief This function save the 11ax cap from FW.
+ *
+ * @param pmadapater A pointer to mlan_adapter
+ * @param hw_he_cap A pointer to MrvlIEtypes_Extension_t
+ *
+ * @return N/A
+ */
+void wlan_update_11ax_cap(mlan_adapter *pmadapter,
+ MrvlIEtypes_Extension_t *hw_he_cap)
+{
+ MrvlIEtypes_He_cap_t *phe_cap = MNULL;
+ t_u8 i = 0;
+ t_u8 he_cap_2g = 0;
+
+ ENTER();
+ if ((hw_he_cap->len + sizeof(MrvlIEtypesHeader_t)) >
+ sizeof(pmadapter->hw_he_cap)) {
+ PRINTM(MERROR, "hw_he_cap too big, len=%d\n", hw_he_cap->len);
+ LEAVE();
+ return;
+ }
+ phe_cap = (MrvlIEtypes_He_cap_t *)hw_he_cap;
+ if (phe_cap->he_phy_cap[0] &
+ (AX_2G_40MHZ_SUPPORT | AX_2G_20MHZ_SUPPORT)) {
+ pmadapter->hw_2g_hecap_len =
+ hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
+ memcpy_ext(pmadapter, pmadapter->hw_2g_he_cap,
+ (t_u8 *)hw_he_cap,
+ hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmadapter->hw_2g_he_cap));
+ pmadapter->fw_bands |= BAND_GAX;
+ pmadapter->config_bands |= BAND_GAX;
+ he_cap_2g = MTRUE;
+ DBG_HEXDUMP(MCMD_D, "2.4G HE capability IE ",
+ (t_u8 *)pmadapter->hw_2g_he_cap,
+ pmadapter->hw_2g_hecap_len);
+ } else {
+ pmadapter->fw_bands |= BAND_AAX;
+ pmadapter->config_bands |= BAND_AAX;
+ pmadapter->hw_hecap_len =
+ hw_he_cap->len + sizeof(MrvlIEtypesHeader_t);
+ memcpy_ext(pmadapter, pmadapter->hw_he_cap, (t_u8 *)hw_he_cap,
+ hw_he_cap->len + sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmadapter->hw_he_cap));
+ DBG_HEXDUMP(MCMD_D, "5G HE capability IE ",
+ (t_u8 *)pmadapter->hw_he_cap,
+ pmadapter->hw_hecap_len);
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ pmadapter->priv[i]->config_bands =
+ pmadapter->config_bands;
+ if (he_cap_2g) {
+ pmadapter->priv[i]->user_2g_hecap_len =
+ pmadapter->hw_2g_hecap_len;
+ memcpy_ext(pmadapter,
+ pmadapter->priv[i]->user_2g_he_cap,
+ pmadapter->hw_2g_he_cap,
+ pmadapter->hw_2g_hecap_len,
+ sizeof(pmadapter->priv[i]
+ ->user_2g_he_cap));
+ } else {
+ pmadapter->priv[i]->user_hecap_len =
+ pmadapter->hw_hecap_len;
+ memcpy_ext(
+ pmadapter,
+ pmadapter->priv[i]->user_he_cap,
+ pmadapter->hw_he_cap,
+ pmadapter->hw_hecap_len,
+ sizeof(pmadapter->priv[i]->user_he_cap));
+ }
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function check if 11AX is allowed in bandcfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_band bss band
+ *
+ * @return 0--not allowed, other value allowed
+ */
+t_u16 wlan_11ax_bandconfig_allowed(mlan_private *pmpriv, t_u16 bss_band)
+{
+ if (!IS_FW_SUPPORT_11AX(pmpriv->adapter))
+ return MFALSE;
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ if (bss_band & BAND_G)
+ return (pmpriv->adapter->adhoc_start_band & BAND_GAX);
+ else if (bss_band & BAND_A)
+ return (pmpriv->adapter->adhoc_start_band & BAND_AAX);
+ } else {
+ if (bss_band & BAND_G)
+ return (pmpriv->config_bands & BAND_GAX);
+ else if (bss_band & BAND_A)
+ return (pmpriv->config_bands & BAND_AAX);
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief Set 11ax configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11ax_ioctl_hecfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11ax_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11ax_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11ax_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
+
+ if ((cfg->param.he_cfg.band & MBIT(0)) &&
+ !(pmadapter->fw_bands & BAND_GAX)) {
+ PRINTM(MERROR, "FW don't support 2.4G AX\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((cfg->param.he_cfg.band & MBIT(1)) &&
+ !(pmadapter->fw_bands & BAND_AAX)) {
+ PRINTM(MERROR, "FW don't support 5G AX\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.he_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 11ax configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11ax_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11ax_cfg *)pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11AX_HE_CFG:
+ status = wlan_11ax_ioctl_hecfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11AX_CMD_CFG:
+ status = wlan_11ax_ioctl_cmd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11AX_TWT_CFG:
+ status = wlan_11ax_ioctl_twtcfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares 11ax cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_11AX_CFG *axcfg = &cmd->params.axcfg;
+ mlan_ds_11ax_he_cfg *hecfg = (mlan_ds_11ax_he_cfg *)pdata_buf;
+ MrvlIEtypes_Extension_t *tlv = MNULL;
+ t_u8 *pos = MNULL;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CFG);
+ cmd->size = sizeof(HostCmd_DS_11AX_CFG) + S_DS_GEN;
+
+ axcfg->action = wlan_cpu_to_le16(cmd_action);
+ axcfg->band_config = hecfg->band & 0xFF;
+
+ pos = (t_u8 *)axcfg->val;
+ /**HE Capability */
+ if (hecfg->he_cap.len && (hecfg->he_cap.ext_id == HE_CAPABILITY)) {
+ tlv = (MrvlIEtypes_Extension_t *)pos;
+ tlv->type = wlan_cpu_to_le16(hecfg->he_cap.id);
+ tlv->len = wlan_cpu_to_le16(hecfg->he_cap.len);
+ memcpy_ext(pmadapter, &tlv->ext_id, &hecfg->he_cap.ext_id,
+ hecfg->he_cap.len,
+ MRVDRV_SIZE_OF_CMD_BUFFER - cmd->size);
+ cmd->size += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
+ pos += hecfg->he_cap.len + sizeof(MrvlIEtypesHeader_t);
+ }
+
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+/**
+ * @brief This function handles the command response of 11axcfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_ds_11ax_cfg *cfg = MNULL;
+ mlan_ds_11ax_he_capa *hecap = MNULL;
+ HostCmd_DS_11AX_CFG *axcfg = &resp->params.axcfg;
+ MrvlIEtypes_Extension_t *tlv = MNULL;
+ t_u16 left_len = 0, tlv_type = 0, tlv_len = 0;
+
+ ENTER();
+
+ if (pioctl_buf == MNULL)
+ goto done;
+
+ cfg = (mlan_ds_11ax_cfg *)pioctl_buf->pbuf;
+ cfg->param.he_cfg.band = axcfg->band_config;
+ hecap = (mlan_ds_11ax_he_capa *)&cfg->param.he_cfg.he_cap;
+
+ /* TLV parse */
+ left_len = resp->size - sizeof(HostCmd_DS_11AX_CFG) - S_DS_GEN;
+ tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
+
+ while (left_len > sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if (tlv_type == EXTENSION) {
+ switch (tlv->ext_id) {
+ case HE_CAPABILITY:
+ hecap->id = tlv_type;
+ hecap->len = tlv_len;
+ memcpy_ext(pmadapter, (t_u8 *)&hecap->ext_id,
+ (t_u8 *)&tlv->ext_id, tlv_len,
+ sizeof(mlan_ds_11ax_he_capa) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (cfg->param.he_cfg.band & MBIT(1)) {
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)&pmpriv->user_he_cap,
+ (t_u8 *)tlv,
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmpriv->user_he_cap));
+ pmpriv->user_hecap_len = MIN(
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmpriv->user_he_cap));
+ PRINTM(MCMND, "user_hecap_len=%d\n",
+ pmpriv->user_hecap_len);
+ } else {
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)&pmpriv->user_2g_he_cap,
+ (t_u8 *)tlv,
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmpriv->user_2g_he_cap));
+ pmpriv->user_2g_hecap_len = MIN(
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(pmpriv->user_2g_he_cap));
+ PRINTM(MCMND, "user_2g_hecap_len=%d\n",
+ pmpriv->user_2g_hecap_len);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypes_Extension_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief 11ax command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11ax_cmd_cfg *cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11ax_cmd_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11ax_cmd_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ status = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AX_CMD, cmd_action, 0,
+ (t_void *)pioctl_req, (t_void *)cfg);
+ if (status == MLAN_STATUS_SUCCESS)
+ status = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares 11ax command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_11AX_CMD_CFG *axcmd = &cmd->params.axcmd;
+ mlan_ds_11ax_cmd_cfg *ds_11ax_cmd = (mlan_ds_11ax_cmd_cfg *)pdata_buf;
+ mlan_ds_11ax_sr_cmd *sr_cmd =
+ (mlan_ds_11ax_sr_cmd *)&ds_11ax_cmd->param;
+ mlan_ds_11ax_beam_cmd *beam_cmd =
+ (mlan_ds_11ax_beam_cmd *)&ds_11ax_cmd->param;
+ mlan_ds_11ax_htc_cmd *htc_cmd =
+ (mlan_ds_11ax_htc_cmd *)&ds_11ax_cmd->param;
+ mlan_ds_11ax_txop_cmd *txop_cmd =
+ (mlan_ds_11ax_txop_cmd *)&ds_11ax_cmd->param;
+ mlan_ds_11ax_txomi_cmd *txomi_cmd =
+ (mlan_ds_11ax_txomi_cmd *)&ds_11ax_cmd->param;
+ mlan_ds_11ax_toltime_cmd *toltime_cmd =
+ (mlan_ds_11ax_toltime_cmd *)&ds_11ax_cmd->param;
+ MrvlIEtypes_Data_t *tlv = MNULL;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AX_CMD);
+ cmd->size = sizeof(HostCmd_DS_11AX_CMD_CFG) + S_DS_GEN;
+
+ axcmd->action = wlan_cpu_to_le16(cmd_action);
+ axcmd->sub_id = wlan_cpu_to_le16(ds_11ax_cmd->sub_id);
+ switch (ds_11ax_cmd->sub_id) {
+ case MLAN_11AXCMD_SR_SUBID:
+ tlv = (MrvlIEtypes_Data_t *)axcmd->val;
+ tlv->header.type = wlan_cpu_to_le16(sr_cmd->type);
+ tlv->header.len = wlan_cpu_to_le16(sr_cmd->len);
+ memcpy_ext(pmadapter, tlv->data,
+ &sr_cmd->param.obss_pd_offset.offset, sr_cmd->len,
+ sr_cmd->len);
+ cmd->size += sizeof(MrvlIEtypesHeader_t) + sr_cmd->len;
+ break;
+ case MLAN_11AXCMD_BEAM_SUBID:
+ axcmd->val[0] = beam_cmd->value;
+ cmd->size += sizeof(t_u8);
+ break;
+ case MLAN_11AXCMD_HTC_SUBID:
+ axcmd->val[0] = htc_cmd->value;
+ cmd->size += sizeof(t_u8);
+ break;
+ case MLAN_11AXCMD_TXOPRTS_SUBID:
+ memcpy_ext(pmadapter, axcmd->val, &txop_cmd->rts_thres,
+ sizeof(t_u16), sizeof(t_u16));
+ cmd->size += sizeof(t_u16);
+ break;
+ case MLAN_11AXCMD_TXOMI_SUBID:
+ memcpy_ext(pmadapter, axcmd->val, &txomi_cmd->omi,
+ sizeof(t_u16), sizeof(t_u16));
+ cmd->size += sizeof(t_u16);
+ break;
+ case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
+ memcpy_ext(pmadapter, axcmd->val, &toltime_cmd->tol_time,
+ sizeof(t_u32), sizeof(t_u32));
+ cmd->size += sizeof(t_u32);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown subcmd %x\n", ds_11ax_cmd->sub_id);
+ break;
+ }
+
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11axcmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_ds_11ax_cmd_cfg *cfg = MNULL;
+ HostCmd_DS_11AX_CMD_CFG *axcmd = &resp->params.axcmd;
+ MrvlIEtypes_Data_t *tlv = MNULL;
+ t_s16 left_len = 0;
+ t_u16 tlv_type = 0, tlv_len = 0;
+
+ ENTER();
+
+ if (pioctl_buf == MNULL)
+ goto done;
+
+ cfg = (mlan_ds_11ax_cmd_cfg *)pioctl_buf->pbuf;
+ cfg->sub_id = wlan_le16_to_cpu(axcmd->sub_id);
+
+ switch (axcmd->sub_id) {
+ case MLAN_11AXCMD_SR_SUBID:
+ /* TLV parse */
+ left_len =
+ resp->size - sizeof(HostCmd_DS_11AX_CMD_CFG) - S_DS_GEN;
+ // tlv = (MrvlIEtypes_Extension_t *)axcfg->val;
+ tlv = (MrvlIEtypes_Data_t *)axcmd->val;
+ while (left_len > sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(tlv->header.len);
+ memcpy_ext(
+ pmadapter,
+ cfg->param.sr_cfg.param.obss_pd_offset.offset,
+ tlv->data, tlv_len, tlv_len);
+ left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypes_Data_t
+ *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ break;
+ case MLAN_11AXCMD_BEAM_SUBID:
+ cfg->param.beam_cfg.value = *axcmd->val;
+ break;
+ case MLAN_11AXCMD_HTC_SUBID:
+ cfg->param.htc_cfg.value = *axcmd->val;
+ break;
+ case MLAN_11AXCMD_TXOPRTS_SUBID:
+ memcpy_ext(pmadapter, &cfg->param.txop_cfg.rts_thres,
+ axcmd->val, sizeof(t_u16), sizeof(t_u16));
+ break;
+ case MLAN_11AXCMD_TXOMI_SUBID:
+ memcpy_ext(pmadapter, &cfg->param.txomi_cfg.omi, axcmd->val,
+ sizeof(t_u16), sizeof(t_u16));
+ break;
+ case MLAN_11AXCMD_OBSS_TOLTIME_SUBID:
+ memcpy_ext(pmadapter, &cfg->param.toltime_cfg.tol_time,
+ axcmd->val, sizeof(t_u32), sizeof(t_u32));
+ break;
+ default:
+ PRINTM(MERROR, "Unknown subcmd %x\n", axcmd->sub_id);
+ break;
+ }
+
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares TWT cfg command to configure
+ * setup/teardown
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return Status returned
+ */
+mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TWT_CFG *hostcmd_twtcfg =
+ (HostCmd_DS_TWT_CFG *)&cmd->params.twtcfg;
+ mlan_ds_twtcfg *ds_twtcfg = (mlan_ds_twtcfg *)pdata_buf;
+ hostcmd_twt_setup *twt_setup_params = MNULL;
+ hostcmd_twt_teardown *twt_teardown_params = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TWT_CFG);
+
+ hostcmd_twtcfg->action = wlan_cpu_to_le16(cmd_action);
+ hostcmd_twtcfg->sub_id = wlan_cpu_to_le16(ds_twtcfg->sub_id);
+
+ cmd->size = S_DS_GEN + sizeof(hostcmd_twtcfg->action) +
+ sizeof(hostcmd_twtcfg->sub_id);
+
+ switch (hostcmd_twtcfg->sub_id) {
+ case MLAN_11AX_TWT_SETUP_SUBID:
+ twt_setup_params = &hostcmd_twtcfg->param.twt_setup;
+ memset(pmadapter, twt_setup_params, 0x00,
+ sizeof(hostcmd_twtcfg->param.twt_setup));
+ twt_setup_params->implicit =
+ ds_twtcfg->param.twt_setup.implicit;
+ twt_setup_params->announced =
+ ds_twtcfg->param.twt_setup.announced;
+ twt_setup_params->trigger_enabled =
+ ds_twtcfg->param.twt_setup.trigger_enabled;
+ twt_setup_params->twt_info_disabled =
+ ds_twtcfg->param.twt_setup.twt_info_disabled;
+ twt_setup_params->negotiation_type =
+ ds_twtcfg->param.twt_setup.negotiation_type;
+ twt_setup_params->twt_wakeup_duration =
+ ds_twtcfg->param.twt_setup.twt_wakeup_duration;
+ twt_setup_params->flow_identifier =
+ ds_twtcfg->param.twt_setup.flow_identifier;
+ twt_setup_params->hard_constraint =
+ ds_twtcfg->param.twt_setup.hard_constraint;
+ twt_setup_params->twt_exponent =
+ ds_twtcfg->param.twt_setup.twt_exponent;
+ twt_setup_params->twt_mantissa = wlan_cpu_to_le16(
+ ds_twtcfg->param.twt_setup.twt_mantissa);
+ twt_setup_params->twt_request =
+ ds_twtcfg->param.twt_setup.twt_request;
+ cmd->size += sizeof(hostcmd_twtcfg->param.twt_setup);
+ break;
+ case MLAN_11AX_TWT_TEARDOWN_SUBID:
+ twt_teardown_params = &hostcmd_twtcfg->param.twt_teardown;
+ memset(pmadapter, twt_teardown_params, 0x00,
+ sizeof(hostcmd_twtcfg->param.twt_teardown));
+ twt_teardown_params->flow_identifier =
+ ds_twtcfg->param.twt_teardown.flow_identifier;
+ twt_teardown_params->negotiation_type =
+ ds_twtcfg->param.twt_teardown.negotiation_type;
+ twt_teardown_params->teardown_all_twt =
+ ds_twtcfg->param.twt_teardown.teardown_all_twt;
+ cmd->size += sizeof(hostcmd_twtcfg->param.twt_teardown);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown subcmd %x\n", ds_twtcfg->sub_id);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief TWT config command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_twtcfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_twtcfg)) {
+ PRINTM(MERROR, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_twtcfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ cfg = (mlan_ds_twtcfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TWT_CFG, cmd_action, 0,
+ (t_void *)pioctl_req, (t_void *)cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.h
new file mode 100644
index 000000000000..4e64772adfa4
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11ax.h
@@ -0,0 +1,58 @@
+/** @file mlan_11ax.h
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MLAN_11AX_H_
+#define _MLAN_11AX_H_
+
+/** device support 2.4G 40MHZ*/
+#define AX_2G_40MHZ_SUPPORT MBIT(1)
+/** device support 2.4G 242 tone RUs */
+#define AX_2G_20MHZ_SUPPORT MBIT(5)
+
+t_u8 wlan_check_11ax_twt_supported(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc);
+mlan_status wlan_11ax_ioctl_twtcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_twt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+t_u16 wlan_fill_he_cap_tlv(mlan_private *pmpriv, t_u8 band,
+ MrvlIEtypes_Extension_t *phe_cap, t_u8 flag);
+void wlan_update_11ax_cap(mlan_adapter *pmadapter,
+ MrvlIEtypes_Extension_t *hw_he_cap);
+int wlan_cmd_append_11ax_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer);
+t_u16 wlan_11ax_bandconfig_allowed(mlan_private *pmpriv, t_u16 bss_band);
+mlan_status wlan_11ax_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_11ax_ioctl_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_11ax_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_11ax_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#endif /* _MLAN_11AX_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11d.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11d.c
new file mode 100644
index 000000000000..a9ac930eb2dd
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11d.c
@@ -0,0 +1,1590 @@
+/** @file mlan_11d.c
+ *
+ * @brief This file contains functions for 802.11D.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11h.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+#ifdef STA_SUPPORT
+/** Region code mapping */
+typedef struct _region_code_mapping {
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ {"JP ", 0x41}, /* Japan */
+ {"CN ", 0x50}, /* China */
+ {"JP ", 0xFE}, /* Japan */
+ {"JP ", 0xFF}, /* Japan special */
+ {"NE ", 0x30}, /* New Zeland */
+};
+
+/** Universal region code */
+#define UNIVERSAL_REGION_CODE 0xff
+#endif
+
+/** Default Tx power */
+#define TX_PWR_DEFAULT 10
+
+/* Following two structures define the supported channels */
+/** Channels for 802.11b/g */
+static chan_freq_power_t channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT}, {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT}, {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT}, {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT}, {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT}, {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT}, {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT}, {14, 2484, TX_PWR_DEFAULT}};
+
+/** Channels for 802.11a/j */
+static chan_freq_power_t channel_freq_power_UN_AJ[] = {
+ {8, 5040, TX_PWR_DEFAULT}, {12, 5060, TX_PWR_DEFAULT},
+ {16, 5080, TX_PWR_DEFAULT}, {34, 5170, TX_PWR_DEFAULT},
+ {38, 5190, TX_PWR_DEFAULT}, {42, 5210, TX_PWR_DEFAULT},
+ {46, 5230, TX_PWR_DEFAULT}, {36, 5180, TX_PWR_DEFAULT},
+ {40, 5200, TX_PWR_DEFAULT}, {44, 5220, TX_PWR_DEFAULT},
+ {48, 5240, TX_PWR_DEFAULT}, {52, 5260, TX_PWR_DEFAULT},
+ {56, 5280, TX_PWR_DEFAULT}, {60, 5300, TX_PWR_DEFAULT},
+ {64, 5320, TX_PWR_DEFAULT}, {100, 5500, TX_PWR_DEFAULT},
+ {104, 5520, TX_PWR_DEFAULT}, {108, 5540, TX_PWR_DEFAULT},
+ {112, 5560, TX_PWR_DEFAULT}, {116, 5580, TX_PWR_DEFAULT},
+ {120, 5600, TX_PWR_DEFAULT}, {124, 5620, TX_PWR_DEFAULT},
+ {128, 5640, TX_PWR_DEFAULT}, {132, 5660, TX_PWR_DEFAULT},
+ {136, 5680, TX_PWR_DEFAULT}, {140, 5700, TX_PWR_DEFAULT},
+ {149, 5745, TX_PWR_DEFAULT}, {153, 5765, TX_PWR_DEFAULT},
+ {157, 5785, TX_PWR_DEFAULT}, {161, 5805, TX_PWR_DEFAULT},
+ {165, 5825, TX_PWR_DEFAULT},
+ /* {240, 4920, TX_PWR_DEFAULT},
+ {244, 4940, TX_PWR_DEFAULT},
+ {248, 4960, TX_PWR_DEFAULT},
+ {252, 4980, TX_PWR_DEFAULT},
+ channels for 11J JP 10M channel gap */
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef STA_SUPPORT
+/**
+ * @brief This function converts integer code to region string
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param code Region code
+ *
+ * @return Region string
+ */
+static t_u8 *wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code)
+{
+ t_u8 i;
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < NELEMENTS(region_code_mapping); i++) {
+ if (region_code_mapping[i].code == code) {
+ LEAVE();
+ return region_code_mapping[i].region;
+ }
+ }
+
+ LEAVE();
+ /* Default is US */
+ return region_code_mapping[0].region;
+}
+
+/**
+ * @brief This function Checks if channel txpwr is learned from AP/IBSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Channel number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8 wlan_11d_channel_known(pmlan_adapter pmadapter, t_u8 band,
+ t_u8 chan,
+ parsed_region_chan_11d_t *parsed_region_chan)
+{
+ chan_power_11d_t *pchan_pwr = parsed_region_chan->chan_pwr;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 i = 0;
+ t_u8 ret = MFALSE;
+ mlan_private *pmpriv;
+
+ ENTER();
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *)pchan_pwr,
+ sizeof(chan_power_11d_t) * no_of_chan);
+
+ /* Search channel */
+ for (i = 0; i < no_of_chan; i++) {
+ if (chan == pchan_pwr[i].chan && band == pchan_pwr[i].band) {
+ PRINTM(MINFO, "11D: Found channel:%d (band:%d)\n", chan,
+ band);
+ ret = MTRUE;
+
+ if (band & BAND_A) {
+ /* If chan is a DFS channel, we need to see an
+ * AP on it */
+ pmpriv = wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_STA);
+ if (pmpriv && wlan_11h_radar_detect_required(
+ pmpriv, chan)) {
+ PRINTM(MINFO,
+ "11H: DFS channel %d, and ap_seen=%d\n",
+ chan, pchan_pwr[i].ap_seen);
+ ret = pchan_pwr[i].ap_seen;
+ }
+ }
+
+ LEAVE();
+ return ret;
+ }
+ }
+
+ PRINTM(MINFO, "11D: Could not find channel:%d (band:%d)\n", chan, band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info
+ * learned from AP/IBSS
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param region_chan Pointer to region_chan_t
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void wlan_11d_generate_parsed_region_chan(
+ pmlan_adapter pmadapter, region_chan_t *region_chan,
+ parsed_region_chan_11d_t *parsed_region_chan)
+{
+ chan_freq_power_t *cfp;
+ t_u8 i;
+
+ ENTER();
+
+ /* Region channel must be provided */
+ if (!region_chan) {
+ PRINTM(MWARN, "11D: region_chan is MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Get channel-frequency-power trio */
+ cfp = region_chan->pcfp;
+ if (!cfp) {
+ PRINTM(MWARN, "11D: cfp equal MNULL\n");
+ LEAVE();
+ return;
+ }
+
+ /* Set channel, band and power */
+ for (i = 0; i < region_chan->num_cfp; i++, cfp++) {
+ parsed_region_chan->chan_pwr[i].chan = (t_u8)cfp->channel;
+ parsed_region_chan->chan_pwr[i].band = region_chan->band;
+ parsed_region_chan->chan_pwr[i].pwr = (t_u8)cfp->max_tx_power;
+ PRINTM(MINFO, "11D: Chan[%d] Band[%d] Pwr[%d]\n",
+ parsed_region_chan->chan_pwr[i].chan,
+ parsed_region_chan->chan_pwr[i].band,
+ parsed_region_chan->chan_pwr[i].pwr);
+ }
+ parsed_region_chan->no_of_chan = region_chan->num_cfp;
+
+ PRINTM(MINFO, "11D: no_of_chan[%d]\n", parsed_region_chan->no_of_chan);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function generates domain_info from parsed_region_chan
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_generate_domain_info(pmlan_adapter pmadapter,
+ parsed_region_chan_11d_t *parsed_region_chan)
+{
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_chan = parsed_region_chan->no_of_chan;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = MFALSE;
+ wlan_802_11d_domain_reg_t *domain_info = &pmadapter->domain_reg;
+
+ ENTER();
+
+ /* Should be only place that clear domain_reg (besides init) */
+ memset(pmadapter, domain_info, 0, sizeof(wlan_802_11d_domain_reg_t));
+
+ /* Set country code */
+ memcpy_ext(pmadapter, domain_info->country_code,
+ wlan_11d_code_2_region(pmadapter,
+ (t_u8)pmadapter->region_code),
+ COUNTRY_CODE_LEN, COUNTRY_CODE_LEN);
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n", no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ /* Set channel and power */
+ for (i = 0; i < no_of_chan; i++) {
+ if (!flag) {
+ flag = MTRUE;
+ next_chan = first_chan =
+ parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1 &&
+ parsed_region_chan->chan_pwr[i].pwr == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ domain_info->sub_band[no_of_sub_band].first_chan =
+ first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr =
+ max_pwr;
+ no_of_sub_band++;
+ no_of_parsed_chan = 1;
+ next_chan = first_chan =
+ parsed_region_chan->chan_pwr[i].chan;
+ max_pwr = parsed_region_chan->chan_pwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
+ domain_info->sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ }
+ domain_info->no_of_sub_band = no_of_sub_band;
+
+ PRINTM(MINFO, "11D: Number of sub-band =0x%x\n",
+ domain_info->no_of_sub_band);
+ HEXDUMP("11D: domain_info", (t_u8 *)domain_info,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates the channel power table with the channel
+ * present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_11d_update_chan_pwr_table(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i;
+ t_u8 tx_power = 0;
+ t_u8 chan;
+
+ ENTER();
+
+ chan = pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ tx_power = wlan_get_txpwr_of_chan_from_cfp(pmpriv, chan);
+
+ if (!tx_power) {
+ PRINTM(MMSG, "11D: Invalid channel\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Check whether the channel already exists in channel power table of
+ parsed region */
+ for (i = 0;
+ ((i < parsed_region_chan->no_of_chan) && (i < MAX_NO_OF_CHAN));
+ i++) {
+ if (parsed_region_chan->chan_pwr[i].chan == chan &&
+ parsed_region_chan->chan_pwr[i].band ==
+ pbss_desc->bss_band) {
+ /* Channel already exists, use minimum of existing and
+ tx_power */
+ parsed_region_chan->chan_pwr[i].pwr = MIN(
+ parsed_region_chan->chan_pwr[i].pwr, tx_power);
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ break;
+ }
+ }
+
+ if (i == parsed_region_chan->no_of_chan && i < MAX_NO_OF_CHAN) {
+ /* Channel not found. Update the channel in the channel-power
+ table */
+ parsed_region_chan->chan_pwr[i].chan = chan;
+ parsed_region_chan->chan_pwr[i].band =
+ (t_u8)pbss_desc->bss_band;
+ parsed_region_chan->chan_pwr[i].pwr = tx_power;
+ parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
+ parsed_region_chan->no_of_chan++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds the no_of_chan-th chan after the first_chan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band
+ * @param first_chan First channel number
+ * @param no_of_chan Number of channels
+ * @param chan Pointer to the returned no_of_chan-th chan number
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_u8 wlan_11d_get_chan(pmlan_adapter pmadapter, t_u8 band,
+ t_u8 first_chan, t_u8 no_of_chan, t_u8 *chan)
+{
+ chan_freq_power_t *cfp = MNULL;
+ t_u8 i;
+ t_u8 cfp_no = 0;
+
+ ENTER();
+ if (band & (BAND_B | BAND_G | BAND_GN | BAND_GAC)) {
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = NELEMENTS(channel_freq_power_UN_BG);
+ } else if (band & (BAND_A | BAND_AN | BAND_AAC)) {
+ cfp = channel_freq_power_UN_AJ;
+ cfp_no = NELEMENTS(channel_freq_power_UN_AJ);
+ } else {
+ PRINTM(MERROR, "11D: Wrong Band[%d]\n", band);
+ LEAVE();
+ return MFALSE;
+ }
+ /* Locate the first_chan */
+ for (i = 0; i < cfp_no; i++) {
+ if (cfp && ((cfp + i)->channel == first_chan)) {
+ PRINTM(MINFO, "11D: first_chan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /* Check if beyond the boundary */
+ if (i + no_of_chan < cfp_no) {
+ /* Get first_chan + no_of_chan */
+ *chan = (t_u8)(cfp + i + no_of_chan)->channel;
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function processes the country info present in BSSDescriptor.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_11d_process_country_info(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t *parsed_region_chan =
+ &pmadapter->parsed_region_chan;
+ t_u16 i, j, num_chan_added = 0;
+
+ ENTER();
+
+ memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
+
+ /* Parse 11D country info */
+ if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info,
+ (t_u8)pbss_desc->bss_band,
+ &region_chan) != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (parsed_region_chan->no_of_chan != 0) {
+ /*
+ * Check if the channel number already exists in the
+ * chan-power table of parsed_region_chan
+ */
+ for (i = 0; (i < region_chan.no_of_chan && i < MAX_NO_OF_CHAN);
+ i++) {
+ for (j = 0; (j < parsed_region_chan->no_of_chan &&
+ j < MAX_NO_OF_CHAN);
+ j++) {
+ /*
+ * Channel already exists, update the tx power
+ * with new tx power, since country IE is valid
+ * here.
+ */
+ if (region_chan.chan_pwr[i].chan ==
+ parsed_region_chan->chan_pwr[j]
+ .chan &&
+ region_chan.chan_pwr[i].band ==
+ parsed_region_chan->chan_pwr[j]
+ .band) {
+ parsed_region_chan->chan_pwr[j].pwr =
+ region_chan.chan_pwr[i].pwr;
+ break;
+ }
+ }
+
+ if (j == parsed_region_chan->no_of_chan &&
+ (j + num_chan_added) < MAX_NO_OF_CHAN) {
+ /*
+ * Channel does not exist in the channel power
+ * table, update this new chan and tx_power
+ * to the channel power table
+ */
+ parsed_region_chan
+ ->chan_pwr[parsed_region_chan
+ ->no_of_chan +
+ num_chan_added]
+ .chan = region_chan.chan_pwr[i].chan;
+ parsed_region_chan
+ ->chan_pwr[parsed_region_chan
+ ->no_of_chan +
+ num_chan_added]
+ .band = region_chan.chan_pwr[i].band;
+ parsed_region_chan
+ ->chan_pwr[parsed_region_chan
+ ->no_of_chan +
+ num_chan_added]
+ .pwr = region_chan.chan_pwr[i].pwr;
+ parsed_region_chan
+ ->chan_pwr[parsed_region_chan
+ ->no_of_chan +
+ num_chan_added]
+ .ap_seen = MFALSE;
+ num_chan_added++;
+ }
+ }
+ parsed_region_chan->no_of_chan += num_chan_added;
+ } else {
+ /* Parsed region is empty, copy the first one */
+ memcpy_ext(pmadapter, parsed_region_chan, &region_chan,
+ sizeof(parsed_region_chan_11d_t),
+ sizeof(parsed_region_chan_11d_t));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This helper function copies chan_power_11d_t element
+ *
+ * @param chan_dst Pointer to destination of chan_power
+ * @param chan_src Pointer to source of chan_power
+ *
+ * @return N/A
+ */
+static t_void wlan_11d_copy_chan_power(chan_power_11d_t *chan_dst,
+ chan_power_11d_t *chan_src)
+{
+ ENTER();
+
+ chan_dst->chan = chan_src->chan;
+ chan_dst->band = chan_src->band;
+ chan_dst->pwr = chan_src->pwr;
+ chan_dst->ap_seen = chan_src->ap_seen;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sorts parsed_region_chan in ascending
+ * channel number.
+ *
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return N/A
+ */
+static t_void
+wlan_11d_sort_parsed_region_chan(parsed_region_chan_11d_t *parsed_region_chan)
+{
+ int i, j;
+ chan_power_11d_t temp;
+ chan_power_11d_t *pchan_power = parsed_region_chan->chan_pwr;
+
+ ENTER();
+
+ PRINTM(MINFO, "11D: Number of channel = %d\n",
+ parsed_region_chan->no_of_chan);
+
+ /* Use insertion sort method */
+ for (i = 1; i < parsed_region_chan->no_of_chan; i++) {
+ wlan_11d_copy_chan_power(&temp, pchan_power + i);
+ for (j = i; j > 0 && (pchan_power + j - 1)->chan > temp.chan;
+ j--)
+ wlan_11d_copy_chan_power(pchan_power + j,
+ pchan_power + j - 1);
+ wlan_11d_copy_chan_power(pchan_power + j, &temp);
+ }
+
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t));
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function sends domain info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_11d_send_domain_info(mlan_private *pmpriv,
+ t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send cmd to FW to set domain info */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_buf,
+ MNULL);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to download domain Info\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function overwrites domain_info
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param band Intended operating band
+ * @param country_code Intended country code
+ * @param num_sub_band Count of tuples in list below
+ * @param sub_band_list List of sub_band tuples
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11d_set_domain_info(mlan_private *pmpriv, t_u8 band,
+ t_u8 country_code[COUNTRY_CODE_LEN], t_u8 num_sub_band,
+ IEEEtypes_SubbandSet_t *sub_band_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ wlan_802_11d_domain_reg_t *pdomain = &pmadapter->domain_reg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmadapter, pdomain, 0, sizeof(wlan_802_11d_domain_reg_t));
+ memcpy_ext(pmadapter, pdomain->country_code, country_code,
+ COUNTRY_CODE_LEN, COUNTRY_CODE_LEN);
+ pdomain->band = band;
+ pdomain->no_of_sub_band = num_sub_band;
+ memcpy_ext(pmadapter, pdomain->sub_band, sub_band_list,
+ num_sub_band * sizeof(IEEEtypes_SubbandSet_t),
+ MRVDRV_MAX_SUBBAND_802_11D * sizeof(IEEEtypes_SubbandSet_t));
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function gets if priv is a station (STA)
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_is_station(mlan_private *pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief This function gets if 11D is enabled
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_11d_is_enabled(mlan_private *pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (pmpriv->state_11d.enable_11d == ENABLE_11D &&
+ pmpriv->state_11d.user_enable_11d == ENABLE_11D) ?
+ MTRUE :
+ MFALSE;
+}
+
+/**
+ * @brief This function gets if 11D is enabled in FW
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_fw_11d_is_enabled(mlan_private *pmpriv)
+{
+ ENTER();
+ LEAVE();
+ return (pmpriv->state_11d.enable_11d == ENABLE_11D) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief Initialize interface variable for 11D
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_11d_priv_init(mlan_private *pmpriv)
+{
+ wlan_802_11d_state_t *state = &pmpriv->state_11d;
+
+ ENTER();
+
+ /* Start in disabled mode */
+ state->enable_11d = DISABLE_11D;
+ if (!pmpriv->adapter->init_para.cfg_11d)
+ state->user_enable_11d = DEFAULT_11D_STATE;
+ else
+ state->user_enable_11d = (pmpriv->adapter->init_para.cfg_11d ==
+ MLAN_INIT_PARA_DISABLED) ?
+ DISABLE_11D :
+ ENABLE_11D;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Initialize device variable for 11D
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_11d_init(mlan_adapter *pmadapter)
+{
+ ENTER();
+
+#ifdef STA_SUPPORT
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &(pmadapter->universal_channel), 0,
+ sizeof(region_chan_t));
+#endif
+ memset(pmadapter, &(pmadapter->domain_reg), 0,
+ sizeof(wlan_802_11d_domain_reg_t));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function enable/disable 11D
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag 11D status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_enable(mlan_private *pmpriv, t_void *pioctl_buf,
+ state_11d_t flag)
+{
+#ifdef STA_SUPPORT
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#endif
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable = flag;
+
+ ENTER();
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i,
+ (t_void *)pioctl_buf, &enable);
+
+ if (ret) {
+ PRINTM(MERROR, "11D: Failed to %s 11D\n",
+ (flag) ? "enable" : "disable");
+ }
+#ifdef STA_SUPPORT
+ else {
+ /* clear parsed table regardless of flag */
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ }
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure of
+ * command buffer
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11d_domain_info(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info =
+ &pcmd->params.domain_info;
+ MrvlIEtypes_DomainParamSet_t *domain = &pdomain_info->domain;
+ t_u8 no_of_sub_band = pmadapter->domain_reg.no_of_sub_band;
+ t_u8 i;
+
+ ENTER();
+ PRINTM(MCMND, "11D:Country=%c%c band=%d sub-band=5d\n",
+ pmadapter->domain_reg.country_code[0],
+ pmadapter->domain_reg.country_code[1],
+ pmadapter->domain_reg.band, no_of_sub_band);
+ for (i = 0; i < no_of_sub_band; i++) {
+ PRINTM(MCMND,
+ "11D: first chan=%d no_of_chan=%d, max_tx_pwr=%d\n",
+ pmadapter->domain_reg.sub_band[i].first_chan,
+ pmadapter->domain_reg.sub_band[i].no_of_chan,
+ pmadapter->domain_reg.sub_band[i].max_tx_pwr);
+ }
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+ pdomain_info->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ /* Dump domain info */
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) +
+ S_DS_GEN);
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* Set domain info fields */
+ domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy_ext(pmadapter, domain->country_code,
+ pmadapter->domain_reg.country_code,
+ sizeof(domain->country_code), sizeof(domain->country_code));
+
+ domain->header.len =
+ ((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) +
+ sizeof(domain->country_code));
+
+ if (no_of_sub_band) {
+ memcpy_ext(pmadapter, domain->sub_band,
+ pmadapter->domain_reg.sub_band,
+ no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t),
+ MRVDRV_MAX_SUBBAND_802_11D *
+ sizeof(IEEEtypes_SubbandSet_t));
+
+ pcmd->size = wlan_cpu_to_le16(
+ sizeof(pdomain_info->action) + domain->header.len +
+ sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+ } else {
+ pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) +
+ S_DS_GEN);
+ }
+ domain->header.len = wlan_cpu_to_le16(domain->header.len);
+
+ HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd,
+ wlan_le16_to_cpu(pcmd->size));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of CMD_802_11D_DOMAIN_INFO
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11d_domain_info(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP *domain_info =
+ &resp->params.domain_info_resp;
+ MrvlIEtypes_DomainParamSet_t *domain = &domain_info->domain;
+ t_u16 action = wlan_le16_to_cpu(domain_info->action);
+ t_u8 no_of_sub_band = 0;
+
+ ENTER();
+
+ /* Dump domain info response data */
+ HEXDUMP("11D: DOMAIN Info Rsp Data", (t_u8 *)resp, resp->size);
+
+ no_of_sub_band = (t_u8)(
+ (wlan_le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t));
+
+ PRINTM(MINFO, "11D Domain Info Resp: number of sub-band=%d\n",
+ no_of_sub_band);
+
+ if (no_of_sub_band > MRVDRV_MAX_SUBBAND_802_11D) {
+ PRINTM(MWARN, "11D: Invalid number of subbands %d returned!!\n",
+ no_of_sub_band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET: /* Proc Set Action */
+ break;
+ case HostCmd_ACT_GEN_GET:
+ break;
+ default:
+ PRINTM(MERROR, "11D: Invalid Action:%d\n", domain_info->action);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function converts channel to frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param chan Channel number
+ * @param band Band
+ *
+ * @return Channel frequency
+ */
+t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band)
+{
+ chan_freq_power_t *cf;
+ t_u16 cnt;
+ t_u16 i;
+ t_u32 freq = 0;
+
+ ENTER();
+
+ /* Get channel-frequency-power trios */
+ if (band & (BAND_A | BAND_AN | BAND_AAC)) {
+ cf = channel_freq_power_UN_AJ;
+ cnt = NELEMENTS(channel_freq_power_UN_AJ);
+ } else {
+ cf = channel_freq_power_UN_BG;
+ cnt = NELEMENTS(channel_freq_power_UN_BG);
+ }
+
+ /* Locate channel and return corresponding frequency */
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ LEAVE();
+ return freq;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function parses country information for region channel
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param country_info Country information
+ * @param band Chan band
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_parse_domain_info(
+ pmlan_adapter pmadapter, IEEEtypes_CountryInfoFullSet_t *country_info,
+ t_u8 band, parsed_region_chan_11d_t *parsed_region_chan)
+{
+ t_u8 no_of_sub_band, no_of_chan;
+ t_u8 last_chan, first_chan, cur_chan = 0;
+ t_u8 idx = 0;
+ t_u8 j, i;
+
+ ENTER();
+
+ /*
+ * Validation Rules:
+ * 1. Valid Region Code
+ * 2. First Chan increment
+ * 3. Channel range no overlap
+ * 4. Channel is valid?
+ * 5. Channel is supported by Region?
+ * 6. Others
+ */
+
+ HEXDUMP("country_info", (t_u8 *)country_info, 30);
+
+ /* Step 1: Check region_code */
+ if (!(*(country_info->country_code)) ||
+ (country_info->len <= COUNTRY_CODE_LEN)) {
+ /* No region info or wrong region info: treat as no 11D info */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ no_of_sub_band = (country_info->len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t);
+
+ for (j = 0, last_chan = 0; j < no_of_sub_band; j++) {
+ if (country_info->sub_band[j].first_chan <= last_chan) {
+ /* Step2&3: Check First Chan Num increment and no
+ * overlap */
+ PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n",
+ country_info->sub_band[j].first_chan, last_chan);
+ continue;
+ }
+
+ first_chan = country_info->sub_band[j].first_chan;
+ no_of_chan = country_info->sub_band[j].no_of_chan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < no_of_chan; i++) {
+ /* Step 4 : Channel is supported? */
+ if (wlan_11d_get_chan(pmadapter, band, first_chan, i,
+ &cur_chan) == MFALSE) {
+ /* Chan is not found in UN table */
+ PRINTM(MWARN,
+ "11D: channel is not supported: %d\n",
+ i);
+ break;
+ }
+
+ last_chan = cur_chan;
+
+ /* Step 5: We don't need to check if cur_chan is
+ supported by mrvl in region */
+ parsed_region_chan->chan_pwr[idx].chan = cur_chan;
+ parsed_region_chan->chan_pwr[idx].band = band;
+ parsed_region_chan->chan_pwr[idx].pwr =
+ country_info->sub_band[j].max_tx_pwr;
+ idx++;
+ }
+
+ /* Step 6: Add other checking if any */
+ }
+
+ parsed_region_chan->no_of_chan = idx;
+
+ PRINTM(MINFO, "11D: number of channel=0x%x\n",
+ parsed_region_chan->no_of_chan);
+ HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan->chan_pwr,
+ sizeof(chan_power_11d_t) * idx);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function setups scan channels
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ * @param band Band
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_11d_set_universaltable(mlan_private *pmpriv, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 i = 0;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->universal_channel, 0,
+ sizeof(pmadapter->universal_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN))
+ /* If band B, G or N */
+ {
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ NELEMENTS(channel_freq_power_UN_BG);
+ PRINTM(MINFO, "11D: BG-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_BG;
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ if (band & BAND_GN)
+ pmadapter->universal_channel[i].band = BAND_G;
+ else
+ pmadapter->universal_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+ i++;
+ }
+
+ if (band & (BAND_A | BAND_AN | BAND_AAC)) {
+ /* If band A */
+
+ /* Set channel-frequency-power */
+ pmadapter->universal_channel[i].num_cfp =
+ NELEMENTS(channel_freq_power_UN_AJ);
+ PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n",
+ pmadapter->universal_channel[i].num_cfp);
+
+ pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
+
+ pmadapter->universal_channel[i].valid = MTRUE;
+
+ /* Set region code */
+ pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+
+ /* Set band */
+ pmadapter->universal_channel[i].band = BAND_A;
+ i++;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band Band number
+ * @param chan Chan number
+ * @param parsed_region_chan Pointer to parsed_region_chan_11d_t
+ *
+ * @return PASSIVE if chan is unknown; ACTIVE
+ * if chan is known
+ */
+t_u8 wlan_11d_get_scan_type(pmlan_adapter pmadapter, t_u8 band, t_u8 chan,
+ parsed_region_chan_11d_t *parsed_region_chan)
+{
+ t_u8 scan_type = MLAN_SCAN_TYPE_PASSIVE;
+
+ ENTER();
+
+ if (wlan_11d_channel_known(pmadapter, band, chan, parsed_region_chan)) {
+ /* Channel found */
+ PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ } else
+ PRINTM(MINFO,
+ "11D: Channel not found and doing Passive Scan\n");
+
+ LEAVE();
+ return scan_type;
+}
+
+/**
+ * @brief This function clears the parsed region table, if 11D is enabled
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_clear_parsedtable(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11d_is_enabled(pmpriv))
+ memset(pmadapter, &(pmadapter->parsed_region_chan), 0,
+ sizeof(parsed_region_chan_11d_t));
+ else
+ ret = MLAN_STATUS_FAILURE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode
+ * and download to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band to create
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_create_dnld_countryinfo(mlan_private *pmpriv, t_u8 band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *region_chan;
+ parsed_region_chan_11d_t parsed_region_chan;
+ t_u8 j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+ PRINTM(MINFO, "11D: Band[%d]\n", band);
+
+ /* Update parsed_region_chan; download domain info to FW */
+
+ /* Find region channel */
+ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) {
+ region_chan = &pmadapter->region_channel[j];
+
+ PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid ||
+ !region_chan->pcfp)
+ continue;
+ switch (region_chan->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_B:
+ case BAND_G:
+ case BAND_G | BAND_B:
+ case BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ /* Check if region channel found */
+ if (j >= MAX_REGION_CHANNEL_NUM) {
+ PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n",
+ band);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Generate parsed region channel info from region channel */
+ memset(pmadapter, &parsed_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+ wlan_11d_generate_parsed_region_chan(pmadapter, region_chan,
+ &parsed_region_chan);
+
+ /* Generate domain info from parsed region channel info */
+ wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR,
+ "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses country info from AP and
+ * download country info to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSS descriptor
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ parsed_region_chan_11d_t region_chan;
+ parsed_region_chan_11d_t bssdesc_region_chan;
+ t_u32 i, j;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv)) {
+ memset(pmadapter, &region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+ memset(pmadapter, &bssdesc_region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+
+ memcpy_ext(pmadapter, &region_chan,
+ &pmadapter->parsed_region_chan,
+ sizeof(parsed_region_chan_11d_t),
+ sizeof(parsed_region_chan_11d_t));
+
+ if (pbss_desc) {
+ /* Parse domain info if available */
+ ret = wlan_11d_parse_domain_info(
+ pmadapter, &pbss_desc->country_info,
+ (t_u8)pbss_desc->bss_band,
+ &bssdesc_region_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ /* Update the channel-power table */
+ for (i = 0;
+ ((i < bssdesc_region_chan.no_of_chan) &&
+ (i < MAX_NO_OF_CHAN));
+ i++) {
+ for (j = 0;
+ ((j < region_chan.no_of_chan) &&
+ (j < MAX_NO_OF_CHAN));
+ j++) {
+ /*
+ * Channel already exists, use
+ * minimum of existing tx power
+ * and tx_power received from
+ * country info of the current
+ * AP
+ */
+ if (region_chan.chan_pwr[i]
+ .chan ==
+ bssdesc_region_chan
+ .chan_pwr[j]
+ .chan &&
+ region_chan.chan_pwr[i]
+ .band ==
+ bssdesc_region_chan
+ .chan_pwr[j]
+ .band) {
+ region_chan.chan_pwr[j]
+ .pwr = MIN(
+ region_chan
+ .chan_pwr[j]
+ .pwr,
+ bssdesc_region_chan
+ .chan_pwr[i]
+ .pwr);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Generate domain info */
+ wlan_11d_generate_domain_info(pmadapter, &region_chan);
+
+ /* Set domain info */
+ ret = wlan_11d_send_domain_info(pmpriv, MNULL);
+ if (ret) {
+ PRINTM(MERROR,
+ "11D: Error sending domain info to FW\n");
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares domain info from scan table and
+ * downloads the domain info command to the FW.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private *pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
+ t_u32 idx;
+
+ ENTER();
+
+ /* Only valid if 11D is enabled */
+ if (wlan_11d_is_enabled(pmpriv) && pmadapter->num_in_scan_table != 0) {
+ for (idx = 0; idx < pmadapter->num_in_scan_table; idx++) {
+ pcountry_full =
+ &pmadapter->pscan_table[idx].country_info;
+
+ ret = wlan_11d_update_chan_pwr_table(
+ pmpriv, &pmadapter->pscan_table[idx]);
+
+ if (*(pcountry_full->country_code) != 0 &&
+ (pcountry_full->len > COUNTRY_CODE_LEN)) {
+ /* Country info found in the BSS Descriptor */
+ ret = wlan_11d_process_country_info(
+ pmpriv, &pmadapter->pscan_table[idx]);
+ }
+ }
+
+ /* Sort parsed_region_chan in ascending channel number */
+ wlan_11d_sort_parsed_region_chan(
+ &pmadapter->parsed_region_chan);
+
+ /* Check if connected */
+ if (pmpriv->media_connected == MTRUE) {
+ ret = wlan_11d_parse_dnld_countryinfo(
+ pmpriv,
+ &pmpriv->curr_bss_params.bss_descriptor);
+ } else {
+ ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function checks country code and maps it when needed
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcountry_code Pointer to the country code string
+ *
+ * @return Pointer to the mapped country code string
+ */
+static t_u8 *wlan_11d_map_country_code(pmlan_adapter pmadapter,
+ t_u8 *pcountry_code)
+{
+ /* Since firmware can only recognize EU as ETSI domain and there is no
+ * memory left for some devices to convert it in firmware, driver need
+ * to convert it before passing country code to firmware through tlv
+ */
+
+ if (wlan_is_etsi_country(pmadapter, pcountry_code))
+ return ("EU ");
+ else
+ return pcountry_code;
+}
+
+/**
+ * @brief This function sets up domain_reg and downloads CMD to FW
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_cfg_domain_info(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11d_domain_info *domain_info = MNULL;
+ mlan_ds_11d_cfg *cfg_11d = MNULL;
+ t_u8 cfp_bg = 0, cfp_a = 0;
+
+ ENTER();
+
+ if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
+ PRINTM(MERROR,
+ "ForceRegionRule is set in the on-chip OTP memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (!wlan_fw_11d_is_enabled(pmpriv))
+ wlan_11d_enable(pmpriv, MNULL, ENABLE_11D);
+
+ cfg_11d = (mlan_ds_11d_cfg *)pioctl_req->pbuf;
+ domain_info = &cfg_11d->param.domain_info;
+ memcpy_ext(pmadapter, pmadapter->country_code,
+ domain_info->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ wlan_11d_set_domain_info(
+ pmpriv, domain_info->band,
+ wlan_11d_map_country_code(pmadapter, domain_info->country_code),
+ domain_info->no_of_sub_band,
+ (IEEEtypes_SubbandSet_t *)domain_info->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ /* Update region code and table based on country code */
+ if (wlan_misc_country_2_cfp_table_code(
+ pmadapter, domain_info->country_code, &cfp_bg, &cfp_a)) {
+ PRINTM(MIOCTL, "Country code %c%c not found!\n",
+ domain_info->country_code[0],
+ domain_info->country_code[1]);
+ goto done;
+ }
+ pmadapter->cfp_code_bg = cfp_bg;
+ pmadapter->cfp_code_a = cfp_a;
+ if (cfp_a)
+ pmadapter->region_code = cfp_a;
+ else if (cfp_bg)
+ pmadapter->region_code = cfp_bg;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
+ pmadapter->config_bands |
+ pmadapter->adhoc_start_band)) {
+ PRINTM(MIOCTL, "Fail to set regiontabl\n");
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief This function handles domain info data from UAP interface.
+ * Checks conditions, sets up domain_reg, then downloads CMD.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band Band interface is operating on
+ * @param domain_tlv Pointer to domain_info tlv
+ * @param pioctl_buf Pointer to the IOCTL buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11d_handle_uap_domain_info(mlan_private *pmpriv, t_u8 band,
+ t_u8 *domain_tlv,
+ t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ MrvlIEtypes_DomainParamSet_t *pdomain_tlv;
+ t_u8 num_sub_band = 0;
+ t_u8 cfp_bg = 0, cfp_a = 0;
+
+ ENTER();
+
+ pdomain_tlv = (MrvlIEtypes_DomainParamSet_t *)domain_tlv;
+
+ /* update region code & table based on country string */
+ if (wlan_misc_country_2_cfp_table_code(
+ pmadapter, pdomain_tlv->country_code, &cfp_bg, &cfp_a) ==
+ MLAN_STATUS_SUCCESS) {
+ pmadapter->cfp_code_bg = cfp_bg;
+ pmadapter->cfp_code_a = cfp_a;
+ if (cfp_a)
+ pmadapter->region_code = cfp_a;
+ else if (cfp_bg)
+ pmadapter->region_code = cfp_bg;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
+ pmadapter->config_bands |
+ pmadapter->adhoc_start_band)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ memcpy_ext(pmadapter, pmadapter->country_code,
+ pdomain_tlv->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ num_sub_band = ((pdomain_tlv->header.len - COUNTRY_CODE_LEN) /
+ sizeof(IEEEtypes_SubbandSet_t));
+
+ /* TODO: don't just clobber pmadapter->domain_reg.
+ * Add some checking or merging between STA & UAP domain_info
+ */
+ wlan_11d_set_domain_info(pmpriv, band, pdomain_tlv->country_code,
+ num_sub_band, pdomain_tlv->sub_band);
+ ret = wlan_11d_send_domain_info(pmpriv, pioctl_buf);
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.c
new file mode 100644
index 000000000000..027ba589d752
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.c
@@ -0,0 +1,4274 @@
+/** @file mlan_11h.c
+ *
+ * @brief This file contains functions for 802.11H.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_11h.h"
+#include "mlan_11n.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Default IBSS DFS recovery interval (in TBTTs); used for adhoc start */
+#define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL 100
+
+/** Default 11h power constraint used to offset the maximum transmit power */
+#define WLAN_11H_TPC_POWERCONSTRAINT 0
+
+/** 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MIN 5
+
+/** 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw */
+#define WLAN_11H_TPC_POWERCAPABILITY_MAX 20
+
+/** Regulatory requirement for the duration of a channel availability check */
+#define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION 60000 /* in ms */
+
+/** Starting Frequency for 11A band */
+#define START_FREQ_11A_BAND 5000 /* in MHz */
+
+/** DFS Channel Move Time */
+#define DFS_CHAN_MOVE_TIME 10 /* in sec */
+
+/** Regulatory requirement for the duration of a non-occupancy period */
+#define WLAN_11H_NON_OCCUPANCY_PERIOD 1800 /* in sec (30mins) */
+
+/** Maximum allowable age (seconds) on DFS report data */
+#define MAX_DFS_REPORT_USABLE_AGE_SEC (120) /* 2 minutes */
+
+/** Minimum delay for CHAN_SW IE to broadcast by FW */
+#define MIN_RDH_CHAN_SW_IE_PERIOD_MSEC (400) /* 4 beacons @ 100ms */
+
+/** Maximum delay for CHAN_SW IE to broadcast by FW */
+#define MAX_RDH_CHAN_SW_IE_PERIOD_MSEC (3000) /* 5 beacons @ 600ms */
+
+/** Maximum retries on selecting new random channel */
+#define MAX_RANDOM_CHANNEL_RETRIES (20)
+
+/** Maximum retries on selecting new random non-dfs channel */
+#define MAX_SWITCH_CHANNEL_RETRIES (30)
+
+/** Value for undetermined priv_curr_idx on first entry to new RDH stage */
+#define RDH_STAGE_FIRST_ENTRY_PRIV_IDX (0xff)
+
+/** Region codes 0x10, 0x20: channels 1 thru 11 supported */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_FCC = {1, 11};
+
+/** Region codes 0x30, 0x32, 0x41, 0x50: channels 1 thru 13 supported */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_EU = {1, 13};
+
+/** Region code 0x40: only channel 14 supported */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_JPN40 = {14,
+ 1};
+
+/** JPN sub-band config : Start Channel = 8, NumChans = 3 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_JPN_bottom_band = {8, 3};
+
+/** U-NII sub-band config : Start Channel = 36, NumChans = 4 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = {36, 4};
+
+/** U-NII sub-band config : Start Channel = 52, NumChans = 4 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = {52,
+ 4};
+
+/** U-NII sub-band config : Start Channel = 100, NumChans = 11 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band = {
+ 100, 11};
+
+/** U-NII sub-band config : Start Channel = 100, NumChans = 5 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band_0 = {
+ 100, 5};
+
+/** U-NII sub-band config : Start Channel = 132, NumChans = 3 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band_1 = {
+ 132, 3};
+
+/** U-NII sub-band config : Start Channel = 149, NumChans = 5 */
+static const IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = {149,
+ 5};
+
+/** Internally passed structure used to send a CMD_802_11_TPC_INFO command */
+typedef struct {
+ t_u8 chan; /**< Channel to which the power constraint applies */
+ t_u8 power_constraint; /**< Local power constraint to send to firmware
+ */
+} wlan_11h_tpc_info_param_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Utility function to get a random number based on the underlying OS
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @return random integer
+ */
+static t_u32 wlan_11h_get_random_num(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+
+ ENTER();
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ LEAVE();
+ return (usec << 16) | sec;
+}
+
+/**
+ * @brief Convert an IEEE formatted IE to 16-bit ID/Len NXP
+ * proprietary format
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pout_buf Output parameter: Buffer to output NXP formatted IE
+ * @param pin_ie Pointer to IEEE IE to be converted to NXP format
+ *
+ * @return Number of bytes output to pout_buf parameter return
+ */
+static t_u32 wlan_11h_convert_ieee_to_mrvl_ie(mlan_adapter *pmadapter,
+ t_u8 *pout_buf,
+ const t_u8 *pin_ie)
+{
+ MrvlIEtypesHeader_t mrvl_ie_hdr;
+ t_u8 *ptmp_buf = pout_buf;
+
+ ENTER();
+ /* Assign the Element Id and Len to the NXP struct attributes */
+ mrvl_ie_hdr.type = wlan_cpu_to_le16(pin_ie[0]);
+ mrvl_ie_hdr.len = wlan_cpu_to_le16(pin_ie[1]);
+
+ /* If the element ID is zero, return without doing any copying */
+ if (!mrvl_ie_hdr.type) {
+ LEAVE();
+ return 0;
+ }
+
+ /* Copy the header to the buffer pointer */
+ memcpy_ext(pmadapter, ptmp_buf, &mrvl_ie_hdr, sizeof(mrvl_ie_hdr),
+ sizeof(mrvl_ie_hdr));
+
+ /* Increment the temp buffer pointer by the size appended */
+ ptmp_buf += sizeof(mrvl_ie_hdr);
+
+ /* Append the data section of the IE; length given by the IEEE IE length
+ */
+ memcpy_ext(pmadapter, ptmp_buf, pin_ie + 2, pin_ie[1], pin_ie[1]);
+
+ LEAVE();
+ /* Return the number of bytes appended to pout_buf */
+ return sizeof(mrvl_ie_hdr) + pin_ie[1];
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Setup the IBSS DFS element passed to the firmware in adhoc start
+ * and join commands
+ *
+ * The DFS Owner and recovery fields are set to be our MAC address and
+ * a predetermined constant recovery value. If we are joining an adhoc
+ * network, these values are replaced with the existing IBSS values.
+ * They are valid only when starting a new IBSS.
+ *
+ * The IBSS DFS Element is variable in size based on the number of
+ * channels supported in our current region.
+ *
+ * @param priv Private driver information structure
+ * @param pdfs Output parameter: Pointer to the IBSS DFS element setup by
+ * this function.
+ *
+ * @return
+ * - Length of the returned element in pdfs output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u32 wlan_11h_set_ibss_dfs_ie(mlan_private *priv,
+ IEEEtypes_IBSS_DFS_t *pdfs)
+{
+ t_u8 num_chans = 0;
+ MeasRptBasicMap_t initial_map;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ /*
+ * A basic measurement report is included with each channel in the
+ * map field. Initial value for the map for each supported channel
+ * is with only the unmeasured bit set.
+ */
+ memset(adapter, &initial_map, 0x00, sizeof(initial_map));
+ initial_map.unmeasured = 1;
+
+ /* Set the DFS Owner and recovery interval fields */
+ memcpy_ext(adapter, pdfs->dfs_owner, priv->curr_addr,
+ sizeof(pdfs->dfs_owner), sizeof(pdfs->dfs_owner));
+ pdfs->dfs_recovery_interval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
+
+ for (; (num_chans < adapter->parsed_region_chan.no_of_chan) &&
+ (num_chans < WLAN_11H_MAX_IBSS_DFS_CHANNELS);
+ num_chans++) {
+ pdfs->channel_map[num_chans].channel_number =
+ adapter->parsed_region_chan.chan_pwr[num_chans].chan;
+
+ /*
+ * Set the initial map field with a basic measurement
+ */
+ pdfs->channel_map[num_chans].rpt_map = initial_map;
+ }
+
+ /*
+ * If we have an established channel map, include it and return
+ * a valid DFS element
+ */
+ if (num_chans) {
+ PRINTM(MINFO, "11h: Added %d channels to IBSS DFS Map\n",
+ num_chans);
+
+ pdfs->element_id = IBSS_DFS;
+ pdfs->len = (sizeof(pdfs->dfs_owner) +
+ sizeof(pdfs->dfs_recovery_interval) +
+ num_chans * sizeof(IEEEtypes_ChannelMap_t));
+
+ LEAVE();
+ return pdfs->len + sizeof(pdfs->len) + sizeof(pdfs->element_id);
+ }
+
+ /* Ensure the element is zeroed out for an invalid return */
+ memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+ LEAVE();
+ return 0;
+}
+#endif
+
+/**
+ * @brief Setup the Supported Channel IE sent in association requests
+ *
+ * The Supported Channels IE is required to be sent when the spectrum
+ * management capability (11h) is enabled. The element contains a
+ * starting channel and number of channels tuple for each sub-band
+ * the STA supports. This information is based on the operating region.
+ *
+ * @param priv Private driver information structure
+ * @param band Band in use
+ * @param psup_chan Output parameter: Pointer to the Supported Chan element
+ * setup by this function.
+ *
+ * @return
+ * - Length of the returned element in psup_chan output parameter
+ * - 0 if returned element is not setup
+ */
+static t_u16
+wlan_11h_set_supp_channels_ie(mlan_private *priv, t_u8 band,
+ IEEEtypes_SupportedChannels_t *psup_chan)
+{
+ t_u16 num_subbands = 0;
+ t_u16 ret_len = 0;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+ memset(priv->adapter, psup_chan, 0x00,
+ sizeof(IEEEtypes_SupportedChannels_t));
+
+ cfp_bg = cfp_a = priv->adapter->region_code;
+ if (!priv->adapter->region_code) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = priv->adapter->cfp_code_bg;
+ cfp_a = priv->adapter->cfp_code_a;
+ }
+
+ if ((band & BAND_B) || (band & BAND_G)) {
+ /*
+ * Channels are contiguous in 2.4GHz, usually only one subband.
+ */
+ switch (cfp_bg) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ default:
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_2_4G_region_FCC;
+ break;
+ case 0x30: /* Europe ETSI */
+ case 0x41: /* Japan */
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_2_4G_region_EU;
+ break;
+ case 0x40: /* Japan */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_2_4G_region_JPN40;
+ break;
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_2_4G_region_EU;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_2_4G_region_JPN40;
+ break;
+ }
+ } else if (band & BAND_A) {
+ /*
+ * Set the supported channel elements based on the region code,
+ * incrementing num_subbands for each sub-band we append to the
+ * element.
+ */
+ switch (cfp_a) {
+ case 0x10: /* USA FCC */
+ case 0x20: /* Canada IC */
+ case 0x30: /* Europe ETSI */
+ default:
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_mid_upper_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ case 0x50: /* China */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ case 0x40: /* Japan */
+ case 0x41: /* Japan */
+ case 0xff: /* Japan special */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_JPN_bottom_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x1: /* Low band (5150-5250 MHz) channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ break;
+ case 0x2: /* Lower middle band (5250-5350 MHz) channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ break;
+ case 0x3: /* Upper middle band (5470-5725 MHz) channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_mid_upper_band;
+ break;
+ case 0x4: /* High band (5725-5850 MHz) channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ case 0x5: /* Low band (5150-5250 MHz) and High band (5725-5850
+ MHz) channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ case 0x6: /* Low band (5150-5250 MHz) and Lower middle band
+ (5250-5350 MHz) and High band (5725-5850 MHz)
+ channels */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ case 0x7:
+ /* 36-48 */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_lower_band;
+ /* 52-64 */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_middle_band;
+ /* 100-116 */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_mid_upper_band_0;
+ /* 132-140 */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_mid_upper_band_1;
+ /* 149-165 */
+ psup_chan->subband[num_subbands++] =
+ wlan_11h_unii_upper_band;
+ break;
+ }
+ }
+
+ /*
+ * If we have setup any supported subbands in the element, return a
+ * valid IE along with its size, else return 0.
+ */
+ if (num_subbands) {
+ psup_chan->element_id = SUPPORTED_CHANNELS;
+ psup_chan->len =
+ num_subbands * sizeof(IEEEtypes_SupportChan_Subband_t);
+
+ ret_len = (t_u16)(psup_chan->len + sizeof(psup_chan->len) +
+ sizeof(psup_chan->element_id));
+
+ HEXDUMP("11h: SupChan", (t_u8 *)psup_chan, ret_len);
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_11h_cmd_tpc_request(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf)
+{
+ ENTER();
+
+ memcpy_ext(priv->adapter, &pcmd_ptr->params.tpc_req, pinfo_buf,
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ),
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+
+ pcmd_ptr->params.tpc_req.req.timeout =
+ wlan_cpu_to_le16(pcmd_ptr->params.tpc_req.req.timeout);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
+
+ HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (t_u8 *)pcmd_ptr,
+ (t_u32)pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_TPC_INFO firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf wlan_11h_tpc_info_param_t passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_11h_cmd_tpc_info(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf)
+{
+ HostCmd_DS_802_11_TPC_INFO *ptpc_info = &pcmd_ptr->params.tpc_info;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint =
+ &ptpc_info->local_constraint;
+ MrvlIEtypes_PowerCapability_t *pcap = &ptpc_info->power_cap;
+
+ wlan_11h_device_state_t *pstate = &priv->adapter->state_11h;
+ const wlan_11h_tpc_info_param_t *ptpc_info_param =
+ (wlan_11h_tpc_info_param_t *)pinfo_buf;
+
+ ENTER();
+
+ pcap->min_power = pstate->min_tx_power_capability;
+ pcap->max_power = pstate->max_tx_power_capability;
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+
+ pconstraint->chan = ptpc_info_param->chan;
+ pconstraint->constraint = ptpc_info_param->power_constraint;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
+
+ HEXDUMP("11h: TPC INFO", (t_u8 *)pcmd_ptr, (t_u32)pcmd_ptr->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_802_11_CHAN_SW_ANN firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_11h_cmd_chan_sw_ann(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf)
+{
+ const HostCmd_DS_802_11_CHAN_SW_ANN *pch_sw_ann =
+ (HostCmd_DS_802_11_CHAN_SW_ANN *)pinfo_buf;
+
+ ENTER();
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
+
+ memcpy_ext(priv->adapter, &pcmd_ptr->params.chan_sw_ann, pch_sw_ann,
+ sizeof(HostCmd_DS_802_11_CHAN_SW_ANN),
+ sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
+
+ PRINTM(MINFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
+ pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
+ pcmd_ptr->result);
+ PRINTM(MINFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
+ pch_sw_ann->new_chan, pch_sw_ann->switch_count,
+ pch_sw_ann->switch_mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_CHAN_REPORT_REQUEST firmware command
+ *
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being
+ * prepared to for firmware
+ * @param pinfo_buf HostCmd_DS_CHAN_RPT_REQ passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
+ */
+static mlan_status wlan_11h_cmd_chan_rpt_req(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf)
+{
+ HostCmd_DS_CHAN_RPT_REQ *pchan_rpt_req =
+ (HostCmd_DS_CHAN_RPT_REQ *)pinfo_buf;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ MrvlIEtypes_ChanRpt11hBasic_t *ptlv_basic;
+ t_bool is_cancel_req = MFALSE;
+ t_u8 dfs53cfg = priv->adapter->dfs53cfg;
+ MrvlIEtypes_DfsW53Cfg_t *ptlv_dfs53cfg;
+
+ ENTER();
+
+ /*
+ * pchan_rpt_req->millisec_dwell_time would be zero if the chan_rpt_req
+ * is to cancel current ongoing report
+ */
+ if (pchan_rpt_req->millisec_dwell_time == 0)
+ is_cancel_req = MTRUE;
+
+ if (pstate_dfs->dfs_check_pending && !is_cancel_req) {
+ PRINTM(MERROR,
+ "11h: ChanRptReq - previous CMD_CHAN_REPORT_REQUEST has"
+ " not returned its result yet (as EVENT_CHANNEL_READY)."
+ " This command will be dropped.\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+
+ /* Converted to little endian in wlan_11h_cmd_process */
+ pcmd_ptr->size = sizeof(HostCmd_DS_CHAN_RPT_REQ) + S_DS_GEN;
+
+ memcpy_ext(priv->adapter, &pcmd_ptr->params.chan_rpt_req, pchan_rpt_req,
+ sizeof(HostCmd_DS_CHAN_RPT_REQ),
+ sizeof(HostCmd_DS_CHAN_RPT_REQ));
+ pcmd_ptr->params.chan_rpt_req.chan_desc.startFreq =
+ wlan_cpu_to_le16(pchan_rpt_req->chan_desc.startFreq);
+ pcmd_ptr->params.chan_rpt_req.millisec_dwell_time =
+ wlan_cpu_to_le32(pchan_rpt_req->millisec_dwell_time);
+
+ /* if DFS channel, add BASIC report TLV, and set radar bit */
+ if (!is_cancel_req && wlan_11h_radar_detect_required(
+ priv, pchan_rpt_req->chan_desc.chanNum)) {
+ ptlv_basic =
+ (MrvlIEtypes_ChanRpt11hBasic_t *)(((t_u8 *)(pcmd_ptr)) +
+ pcmd_ptr->size);
+ ptlv_basic->Header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
+ ptlv_basic->Header.len =
+ wlan_cpu_to_le16(sizeof(MeasRptBasicMap_t));
+ memset(priv->adapter, &ptlv_basic->map, 0,
+ sizeof(MeasRptBasicMap_t));
+ ptlv_basic->map.radar = 1;
+ pcmd_ptr->size += sizeof(MrvlIEtypes_ChanRpt11hBasic_t);
+ }
+
+ if ((priv->adapter->region_code == COUNTRY_CODE_JP_40 ||
+ priv->adapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (dfs53cfg != DFS_W53_DEFAULT_FW)) {
+ ptlv_dfs53cfg =
+ (MrvlIEtypes_DfsW53Cfg_t *)(((t_u8 *)(pcmd_ptr)) +
+ pcmd_ptr->size);
+ ptlv_dfs53cfg->Header.type =
+ wlan_cpu_to_le16(TLV_TYPE_DFS_W53_CFG);
+ ptlv_dfs53cfg->Header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ ptlv_dfs53cfg->dfs53cfg = dfs53cfg;
+ pcmd_ptr->size += sizeof(MrvlIEtypes_DfsW53Cfg_t);
+ }
+
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+
+ /* update dfs sturcture.
+ * dfs_check_pending is set when we receive CMD_RESP == SUCCESS */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_priv = MNULL;
+
+ if (!is_cancel_req)
+ pstate_dfs->dfs_check_channel =
+ pchan_rpt_req->chan_desc.chanNum;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set the local power capability and constraint TLV
+ *
+ * @param ppbuffer The buffer to add these two TLVs
+ * @param channel Channel to which the power constraint applies
+ * @param power_constraint Power constraint to be applied on the channel
+ * @param min_tx_power_capability Min. Tx Power in Power Capability IE
+ * @param max_tx_power_capability Max. Tx Power in Power Capability IE
+ *
+ * @return The len increased
+ */
+static t_u32 wlan_11h_set_local_power_constraint_tlv(
+ t_u8 **ppbuffer, t_u8 channel, t_u8 power_constraint,
+ t_u8 min_tx_power_capability, t_u8 max_tx_power_capability)
+{
+ MrvlIEtypes_PowerCapability_t *pcap;
+ MrvlIEtypes_LocalPowerConstraint_t *pconstraint;
+ t_u8 *start_ptr = MNULL;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *)(*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ start_ptr = (t_u8 *)(*ppbuffer);
+
+ PRINTM(MINFO,
+ "11h: Set local power constraint = %d channel=%d min_tx_pwr=%d max_tx_pwr=%d\n",
+ power_constraint, channel, min_tx_power_capability,
+ max_tx_power_capability);
+
+ pcap = (MrvlIEtypes_PowerCapability_t *)*ppbuffer;
+ pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+ pcap->header.len = wlan_cpu_to_le16(2);
+ pcap->min_power = min_tx_power_capability;
+ pcap->max_power = max_tx_power_capability;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ pconstraint = (MrvlIEtypes_LocalPowerConstraint_t *)*ppbuffer;
+ pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+ pconstraint->header.len = wlan_cpu_to_le16(2);
+ pconstraint->chan = channel;
+ pconstraint->constraint = power_constraint;
+ *ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
+
+ LEAVE();
+ return (t_u32)(*ppbuffer - start_ptr);
+}
+
+/**
+ * @brief Utility function to process a join to an infrastructure BSS
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32 wlan_11h_process_infra_join(mlan_private *priv, t_u8 **ppbuffer,
+ t_u8 band, t_u32 channel,
+ wlan_11h_bss_info_t *p11h_bss_info)
+{
+ MrvlIEtypesHeader_t ie_header;
+ IEEEtypes_SupportedChannels_t sup_chan_ie;
+ t_u32 ret_len = 0;
+ t_u16 sup_chan_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if ((ppbuffer == MNULL) || (((t_u8 *)(*ppbuffer)) == MNULL)) {
+ LEAVE();
+ return 0;
+ }
+
+ ret_len += wlan_11h_set_local_power_constraint_tlv(
+ ppbuffer, (t_u8)channel,
+ (t_u8)p11h_bss_info->power_constraint.local_constraint,
+ (t_u8)priv->adapter->state_11h.min_tx_power_capability,
+ (t_u8)priv->adapter->state_11h.max_tx_power_capability);
+
+ /* Setup the Supported Channels IE */
+ sup_chan_len = wlan_11h_set_supp_channels_ie(priv, band, &sup_chan_ie);
+
+ /*
+ * If we returned a valid Supported Channels IE, wrap and append it
+ */
+ if (sup_chan_len) {
+ /* Wrap the supported channels IE with a passthrough TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(sup_chan_len);
+ memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
+ sizeof(ie_header), sizeof(ie_header));
+
+ /*
+ * Increment the return size and the return buffer
+ * pointer param
+ */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /*
+ * Copy the supported channels IE to the output buf,
+ * advance pointer
+ */
+ memcpy_ext(priv->adapter, *ppbuffer, &sup_chan_ie, sup_chan_len,
+ sup_chan_len);
+ *ppbuffer += sup_chan_len;
+ ret_len += sup_chan_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Utility function to process a start or join to an adhoc network
+ *
+ * Add the elements to the TLV buffer needed in the start/join adhoc commands:
+ * - IBSS DFS IE
+ * - Quiet IE
+ *
+ * Also send the local constraint to the firmware in a TPC_INFO command.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param channel Channel on which we are starting/joining the IBSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this network
+ * that was parsed out of the scan response. NULL
+ * indicates we are starting the adhoc network
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer)
+ */
+static t_u32 wlan_11h_process_adhoc(mlan_private *priv, t_u8 **ppbuffer,
+ t_u32 channel,
+ wlan_11h_bss_info_t *p11h_bss_info)
+{
+ IEEEtypes_IBSS_DFS_t dfs_elem;
+ t_u32 size_appended;
+ t_u32 ret_len = 0;
+ t_s8 local_constraint = 0;
+ mlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ /* Format our own IBSS DFS Element. Include our channel map fields */
+ wlan_11h_set_ibss_dfs_ie(priv, &dfs_elem);
+#endif
+
+ if (p11h_bss_info) {
+ /*
+ * Copy the DFS Owner/Recovery Interval from the BSS
+ * we are joining
+ */
+ memcpy_ext(adapter, dfs_elem.dfs_owner,
+ p11h_bss_info->ibss_dfs.dfs_owner,
+ sizeof(dfs_elem.dfs_owner),
+ sizeof(dfs_elem.dfs_owner));
+ dfs_elem.dfs_recovery_interval =
+ p11h_bss_info->ibss_dfs.dfs_recovery_interval;
+ }
+
+ /* Append the dfs element to the TLV buffer */
+ size_appended = wlan_11h_convert_ieee_to_mrvl_ie(
+ adapter, (t_u8 *)*ppbuffer, (t_u8 *)&dfs_elem);
+
+ HEXDUMP("11h: IBSS-DFS", (t_u8 *)*ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+
+ /*
+ * Check to see if we are joining a network. Join is indicated by the
+ * BSS Info pointer being valid (not NULL)
+ */
+ if (p11h_bss_info) {
+ /*
+ * If there was a quiet element, include it in
+ * adhoc join command
+ */
+ if (p11h_bss_info->quiet.element_id == QUIET) {
+ size_appended = wlan_11h_convert_ieee_to_mrvl_ie(
+ adapter, (t_u8 *)*ppbuffer,
+ (t_u8 *)&p11h_bss_info->quiet);
+ HEXDUMP("11h: Quiet", (t_u8 *)*ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+
+ /* Copy the local constraint from the network */
+ local_constraint =
+ p11h_bss_info->power_constraint.local_constraint;
+ } else {
+ /*
+ * If we are the adhoc starter, we can add a quiet element
+ */
+ if (adapter->state_11h.quiet_ie.quiet_period) {
+ size_appended = wlan_11h_convert_ieee_to_mrvl_ie(
+ adapter, (t_u8 *)*ppbuffer,
+ (t_u8 *)&adapter->state_11h.quiet_ie);
+ HEXDUMP("11h: Quiet", (t_u8 *)*ppbuffer, size_appended);
+ *ppbuffer += size_appended;
+ ret_len += size_appended;
+ }
+ /* Use the local_constraint configured in the driver state */
+ local_constraint = adapter->state_11h.usr_def_power_constraint;
+ }
+
+ PRINTM(MINFO, "WEILIE 1: ppbuffer = %p\n", *ppbuffer);
+
+ ret_len += wlan_11h_set_local_power_constraint_tlv(
+ ppbuffer, (t_u8)channel, (t_u8)local_constraint,
+ (t_u8)priv->adapter->state_11h.min_tx_power_capability,
+ (t_u8)priv->adapter->state_11h.max_tx_power_capability);
+ PRINTM(MINFO, "WEILIE 2: ppbuffer = %p\n", *ppbuffer);
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Return whether the driver has enabled 11h for the interface
+ *
+ * Association/Join commands are dynamic in that they enable 11h in the
+ * driver/firmware when they are detected in the existing BSS.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h is enabled
+ * - MFALSE otherwise
+ */
+static t_bool wlan_11h_is_enabled(mlan_private *priv)
+{
+ ENTER();
+ LEAVE();
+ return priv->intf_state_11h.is_11h_enabled;
+}
+
+/**
+ * @brief Return whether the device has activated slave radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if slave radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+static t_bool wlan_11h_is_slave_radar_det_active(mlan_private *priv)
+{
+ ENTER();
+ LEAVE();
+ return priv->adapter->state_11h.is_slave_radar_det_active;
+}
+/**
+ * @brief Return whether the slave interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs slave interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is slave, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool wlan_11h_is_slave_active_on_dfs_chan(mlan_private *priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if ((priv->media_connected == MTRUE) &&
+ (priv->curr_bss_params.band & BAND_A) &&
+ wlan_11h_radar_detect_required(
+ priv, priv->curr_bss_params.bss_descriptor.channel))
+ ret = MTRUE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Return whether the master interface is active, and on DFS channel.
+ * priv is assumed to already be a dfs master interface, doesn't check this.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if priv is master, and meets both conditions
+ * - MFALSE otherwise
+ */
+static t_bool wlan_11h_is_master_active_on_dfs_chan(mlan_private *priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ /* Ad-hoc creator */
+ if (((priv->media_connected == MTRUE) ||
+ (priv->adhoc_state == ADHOC_STARTING)) &&
+ (priv->adapter->adhoc_start_band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv, priv->adhoc_channel))
+ ret = MTRUE;
+ } else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /* UAP */
+#ifdef UAP_SUPPORT
+ if ((priv->uap_bss_started == MTRUE) &&
+ (priv->uap_state_chan_cb.bandcfg.chanBand == BAND_5GHZ) &&
+ wlan_11h_radar_detect_required(
+ priv, priv->uap_state_chan_cb.channel))
+ ret = MTRUE;
+#endif
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Determine if priv is DFS Master interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static t_bool wlan_11h_is_dfs_master(mlan_private *priv)
+{
+ t_bool ret = MFALSE;
+
+ ENTER();
+ /* UAP: all are master */
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ ret = MTRUE;
+
+ /* STA: only ad-hoc creator is master */
+ else if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->bss_mode == MLAN_BSS_MODE_IBSS) &&
+ (priv->adhoc_state == ADHOC_STARTED ||
+ priv->adhoc_state == ADHOC_STARTING))
+ ret = MTRUE;
+
+ /* all other cases = slave interface */
+ LEAVE();
+ return ret;
+}
+
+/* Need this as function to pass to wlan_count_priv_cond() */
+/**
+ * @brief Determine if priv is DFS Slave interface
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+
+static t_bool wlan_11h_is_dfs_slave(mlan_private *priv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+ ret = !wlan_11h_is_dfs_master(priv);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if interface is active.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_is_intf_active(mlan_private *pmpriv)
+{
+ t_bool ret = MFALSE;
+ ENTER();
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ /*
+ * NOTE: UAP's media_connected == true only after first STA
+ * associated. Need different variable to tell if UAP
+ * has been started.
+ */
+ ret = pmpriv->uap_bss_started;
+ else
+#endif
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ ret = pmpriv->media_connected;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets current radar detect flags
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return 11H MIB setting for radar detect
+ */
+static t_u32 wlan_11h_get_current_radar_detect_flags(mlan_adapter *pmadapter)
+{
+ t_u32 radar_det_flags = 0;
+
+ ENTER();
+ if (pmadapter->state_11h.is_master_radar_det_active)
+ radar_det_flags |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.is_slave_radar_det_active)
+ radar_det_flags |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_curr=0x%x\n", __func__,
+ radar_det_flags);
+
+ LEAVE();
+ return radar_det_flags;
+}
+
+/**
+ * @brief This function checks if radar detect flags have/should be changed.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pnew_state Output param with new state, if return MTRUE.
+ *
+ * @return MTRUE (need update) or MFALSE (no change in flags)
+ */
+static t_bool wlan_11h_check_radar_det_state(mlan_adapter *pmadapter,
+ t_u32 *pnew_state)
+{
+ t_u32 radar_det_state_new = 0;
+ t_bool ret;
+
+ ENTER();
+ PRINTM(MINFO,
+ "%s: master_radar_det_pending=%d, "
+ " slave_radar_det_pending=%d\n",
+ __func__, pmadapter->state_11h.master_radar_det_enable_pending,
+ pmadapter->state_11h.slave_radar_det_enable_pending);
+
+ /* new state comes from evaluating interface states & pending starts */
+ if (pmadapter->state_11h.master_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master) > 0))
+ radar_det_state_new |= MASTER_RADAR_DET_MASK;
+ if (pmadapter->state_11h.slave_radar_det_enable_pending ||
+ (wlan_count_priv_cond(pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave) > 0))
+ radar_det_state_new |= SLAVE_RADAR_DET_MASK;
+
+ PRINTM(MINFO, "%s: radar_det_state_new=0x%x\n", __func__,
+ radar_det_state_new);
+
+ /* now compare flags with current state */
+ ret = (wlan_11h_get_current_radar_detect_flags(pmadapter) !=
+ radar_det_state_new) ?
+ MTRUE :
+ MFALSE;
+ if (ret)
+ *pnew_state = radar_det_state_new;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief generate the channel center frequency index
+ *
+ * @param channel_num channel number
+ *
+ * @return frenquency index
+ */
+static t_u8 wlan_11h_get_channel_freq_idx(t_u8 channel_num)
+{
+ t_u8 index;
+ t_u8 center_freq[] = {42, 58, 106, 122, 138, 155};
+ t_u8 chan_idx, ret = 0;
+
+ chan_idx = channel_num - 100;
+
+ for (index = 0; index < sizeof(center_freq); index++) {
+ if ((chan_idx >= (center_freq[index] - 6)) &&
+ (chan_idx <= (center_freq[index] + 6))) {
+ ret = center_freq[index];
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Prepare ioctl for add/remove CHAN_SW IE - RADAR_DETECTED event
+ * handling
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to completed mlan_ioctl_req (allocated
+ * inside)
+ * @param ppcust_chansw_ie Poniter to customer ie
+ * @param is_adding_ie CHAN_SW IE is to be added (MTRUE), or removed
+ * (MFALSE)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_11h_prepare_custom_ie_chansw(mlan_adapter *pmadapter,
+ mlan_ioctl_req **ppioctl_req,
+ t_bool is_adding_ie)
+{
+ mlan_ioctl_req *pioctl_req = MNULL;
+ mlan_ds_misc_cfg *pds_misc_cfg = MNULL;
+ custom_ie *pcust_chansw_ie = MNULL;
+ IEEEtypes_ChanSwitchAnn_t *pchansw_ie = MNULL;
+ mlan_status ret;
+ IEEEtypes_Header_t *pChanSwWrap_ie = MNULL;
+ IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = MNULL;
+ IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = MNULL;
+ t_u8 index;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ if (pmadapter == MNULL || ppioctl_req == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* allocate buffer for mlan_ioctl_req and mlan_ds_misc_cfg */
+ /* FYI - will be freed as part of cmd_response handler */
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle,
+ sizeof(mlan_ioctl_req) + sizeof(mlan_ds_misc_cfg), MLAN_MEM_DEF,
+ (t_u8 **)&pioctl_req);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR, "%s(): Could not allocate ioctl req\n",
+ __func__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pds_misc_cfg = (mlan_ds_misc_cfg *)((t_u8 *)pioctl_req +
+ sizeof(mlan_ioctl_req));
+
+ /* prepare mlan_ioctl_req */
+ memset(pmadapter, pioctl_req, 0x00, sizeof(mlan_ioctl_req));
+ pioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ pioctl_req->action = MLAN_ACT_SET;
+ pioctl_req->pbuf = (t_u8 *)pds_misc_cfg;
+ pioctl_req->buf_len = sizeof(mlan_ds_misc_cfg);
+
+ /* prepare mlan_ds_misc_cfg */
+ memset(pmadapter, pds_misc_cfg, 0x00, sizeof(mlan_ds_misc_cfg));
+ pds_misc_cfg->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ pds_misc_cfg->param.cust_ie.type = TLV_TYPE_MGMT_IE;
+ pds_misc_cfg->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
+
+ /* configure custom_ie api settings */
+ pcust_chansw_ie =
+ (custom_ie *)&pds_misc_cfg->param.cust_ie.ie_data_list[0];
+ pcust_chansw_ie->ie_index = 0xffff; /* Auto index */
+ pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
+ pcust_chansw_ie->mgmt_subtype_mask =
+ (is_adding_ie) ? MBIT(8) | MBIT(5) /* add IE for BEACON |
+ PROBE_RSP */
+ :
+ 0; /* remove IE */
+
+ /* prepare CHAN_SW IE inside ioctl */
+ pchansw_ie = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
+ pchansw_ie->element_id = CHANNEL_SWITCH_ANN;
+ pchansw_ie->len =
+ sizeof(IEEEtypes_ChanSwitchAnn_t) - sizeof(IEEEtypes_Header_t);
+ pchansw_ie->chan_switch_mode = 1; /* STA should not transmit */
+ pchansw_ie->new_channel_num = pmadapter->state_rdh.new_channel;
+
+ pchansw_ie->chan_switch_count = pmadapter->dfs_cs_count;
+ PRINTM(MCMD_D, "New Channel = %d Channel switch count = %d\n",
+ pmadapter->state_rdh.new_channel, pchansw_ie->chan_switch_count);
+
+ for (index = 0; index < pmadapter->state_rdh.priv_list_count; index++) {
+ pmpriv = pmadapter->state_rdh.priv_list[index];
+ /*find the first AP interface*/
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ if (pmpriv->is_11ac_enabled) {
+ pChanSwWrap_ie =
+ (IEEEtypes_Header_t
+ *)((t_u8 *)pchansw_ie +
+ sizeof(IEEEtypes_ChanSwitchAnn_t));
+ pChanSwWrap_ie->element_id = EXT_POWER_CONSTR;
+ /*will have multiple sub IEs*/
+ pChanSwWrap_ie->len = 0;
+
+ /* prepare the Wide Bandwidth Channel Switch IE
+ * Channel Switch IE */
+ pbwchansw_ie =
+ (IEEEtypes_WideBWChanSwitch_t
+ *)((t_u8 *)pChanSwWrap_ie +
+ sizeof(IEEEtypes_Header_t));
+ pbwchansw_ie->ieee_hdr.element_id =
+ BW_CHANNEL_SWITCH;
+ pbwchansw_ie->ieee_hdr.len =
+ sizeof(IEEEtypes_WideBWChanSwitch_t) -
+ sizeof(IEEEtypes_Header_t);
+ /*fix 80MHZ now*/
+ pbwchansw_ie->new_channel_width =
+ VHT_OPER_CHWD_80MHZ;
+ pbwchansw_ie->new_channel_center_freq0 =
+ wlan_11h_get_channel_freq_idx(
+ pmadapter->state_rdh
+ .new_channel);
+ pbwchansw_ie->new_channel_center_freq1 =
+ wlan_11h_get_channel_freq_idx(
+ pmadapter->state_rdh
+ .new_channel);
+ pChanSwWrap_ie->len +=
+ sizeof(IEEEtypes_WideBWChanSwitch_t);
+
+ /*prepare the VHT Transmit Power Envelope IE*/
+ pvhttpcEnv_ie =
+ (IEEEtypes_VhtTpcEnvelope_t
+ *)((t_u8 *)pChanSwWrap_ie +
+ sizeof(IEEEtypes_Header_t) +
+ sizeof(IEEEtypes_WideBWChanSwitch_t));
+ pvhttpcEnv_ie->ieee_hdr.element_id =
+ VHT_TX_POWER_ENV;
+ pvhttpcEnv_ie->ieee_hdr.len =
+ sizeof(IEEEtypes_VhtTpcEnvelope_t) -
+ sizeof(IEEEtypes_Header_t);
+ /* Local Max TX Power Count= 3,
+ * Local TX Power Unit Inter=EIP(0) */
+ pvhttpcEnv_ie->tpc_info = 3;
+ pvhttpcEnv_ie->local_max_tp_20mhz = 0xff;
+ pvhttpcEnv_ie->local_max_tp_40mhz = 0xff;
+ pvhttpcEnv_ie->local_max_tp_80mhz = 0xff;
+ pChanSwWrap_ie->len +=
+ sizeof(IEEEtypes_VhtTpcEnvelope_t);
+
+ pcust_chansw_ie->ie_length +=
+ sizeof(IEEEtypes_WideBWChanSwitch_t) +
+ sizeof(IEEEtypes_VhtTpcEnvelope_t) +
+ sizeof(IEEEtypes_Header_t);
+
+ PRINTM(MINFO,
+ "Append Wide Bandwidth Channel Switch IE\n");
+ break;
+ }
+ }
+ }
+
+ pds_misc_cfg->param.cust_ie.len += pcust_chansw_ie->ie_length;
+ DBG_HEXDUMP(MCMD_D, "11h: custom_ie containing CHAN_SW IE",
+ (t_u8 *)pcust_chansw_ie, pds_misc_cfg->param.cust_ie.len);
+
+ /* assign output pointer before returning */
+ *ppioctl_req = pioctl_req;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef UAP_SUPPORT
+/** Bits 2,3 of band config define the band width */
+#define UAP_BAND_WIDTH_MASK 0x0C
+
+/**
+ * @brief Check if start channel 165 is allowed to operate in
+ * previous uAP channel's band config
+ *
+ * @param start_chn Random Start channel choosen after radar detection
+ * @param uap_band_cfg Private driver uAP band configuration information
+ * structure
+ *
+ * @return MFALSE if the channel is not allowed in given band
+ */
+static t_bool wlan_11h_is_band_valid(t_u8 start_chn, Band_Config_t uap_band_cfg)
+{
+ /* if band width is not 20MHZ (either 40 or 80MHz)
+ * return MFALSE, 165 is not allowed in bands other than 20MHZ
+ */
+ if (start_chn == 165 && (uap_band_cfg.chanWidth != CHAN_BW_20MHZ)) {
+ return MFALSE;
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and 5GHz band is selected in band_config
+ * return a random channel in A band, else one from BG band.
+ *
+ * @param priv Private driver information structure
+ * @param uap_band_cfg Private driver information structure
+ *
+ * @return Starting channel
+ */
+static t_u8 wlan_11h_get_uap_start_channel(mlan_private *priv,
+ Band_Config_t uap_band_cfg)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ /*TODO: right now mostly a copy of wlan_11h_get_adhoc_start_channel.
+ * Improve to be more specfic to UAP, e.g.
+ * 1. take into account COUNTRY_CODE -> region_code
+ * 2. check domain_info for value channels
+ */
+ ENTER();
+
+ /*
+ * Set start_chn to the Default.
+ * Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if (uap_band_cfg.chanBand == BAND_5GHZ) {
+ /*
+ * Set default to the A Band default.
+ * Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM);
+ region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band
+ */
+ if (chn_tbl->valid &&
+ chn_tbl->region == adapter->region_code &&
+ chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random
+ * number and use it to pick an entry
+ * in the table between 0 and the number
+ * of channels in the table (NumCFP).
+ */
+ rand_entry = wlan_11h_get_random_num(
+ adapter) %
+ chn_tbl->num_cfp;
+ start_chn =
+ (t_u8)chn_tbl->pcfp[rand_entry]
+ .channel;
+ /* Loop until a non-dfs channel is found
+ * with compatible band bounded by
+ * chn_tbl->num_cfp entries in the
+ * channel table
+ */
+ while (((chn_tbl->pcfp[rand_entry]
+ .dynamic.flags &
+ NXP_CHANNEL_DISABLED) ||
+ (wlan_11h_is_channel_under_nop(
+ adapter, start_chn) ||
+ ((adapter->state_rdh.stage ==
+ RDH_GET_INFO_CHANNEL) &&
+ wlan_11h_radar_detect_required(
+ priv, start_chn)) ||
+ !(wlan_11h_is_band_valid(
+ start_chn,
+ uap_band_cfg)))) &&
+ (++rand_tries <
+ chn_tbl->num_cfp)) {
+ rand_entry++;
+ rand_entry = rand_entry %
+ chn_tbl->num_cfp;
+ start_chn =
+ (t_u8)chn_tbl
+ ->pcfp[rand_entry]
+ .channel;
+ PRINTM(MINFO,
+ "start chan=%d rand_entry=%d\n",
+ start_chn, rand_entry);
+ }
+
+ if (rand_tries == chn_tbl->num_cfp) {
+ PRINTM(MERROR,
+ "Failed to get UAP start channel\n");
+ start_chn = 0;
+ }
+ }
+ }
+ }
+ }
+
+ PRINTM(MCMD_D, "11h: UAP Get Start Channel %d\n", start_chn);
+ LEAVE();
+ return start_chn;
+}
+#endif /* UAP_SUPPORT */
+
+#ifdef DEBUG_LEVEL1
+static const char *DFS_TS_REPR_STRINGS[] = {"", "NOP_start", "CAC_completed"};
+#endif
+
+/**
+ * @brief Search for a dfs timestamp in the list with desired channel.
+ *
+ * Assumes there will only be one timestamp per channel in the list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static wlan_dfs_timestamp_t *
+wlan_11h_find_dfs_timestamp(mlan_adapter *pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pts = MNULL, *pts_found = MNULL;
+
+ ENTER();
+ pts = (wlan_dfs_timestamp_t *)util_peek_list(
+ pmadapter->pmoal_handle, &pmadapter->state_dfs.dfs_ts_head,
+ MNULL, MNULL);
+
+ while (pts && pts != (wlan_dfs_timestamp_t *)&pmadapter->state_dfs
+ .dfs_ts_head) {
+ PRINTM(MINFO,
+ "dfs_timestamp(@ %p) - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n",
+ pts, pts->channel, pts->represents,
+ DFS_TS_REPR_STRINGS[pts->represents], pts->ts_sec,
+ pts->ts_usec);
+
+ if (pts->channel == channel) {
+ pts_found = pts;
+ break;
+ }
+ pts = pts->pnext;
+ }
+
+ LEAVE();
+ return pts_found;
+}
+
+/**
+ * @brief Removes dfs timestamp from list.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pdfs_ts Pointer to dfs_timestamp to remove
+ */
+static t_void wlan_11h_remove_dfs_timestamp(mlan_adapter *pmadapter,
+ wlan_dfs_timestamp_t *pdfs_ts)
+{
+ ENTER();
+ /* dequeue and delete timestamp */
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list)pdfs_ts, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pdfs_ts);
+ LEAVE();
+}
+
+/**
+ * @brief Add a dfs timestamp to the list
+ *
+ * Assumes there will only be one timestamp per channel in the list,
+ * and that timestamp modes (represents) are mutually exclusive.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param repr Timestamp 'represents' value (see _dfs_timestamp_repr_e)
+ * @param channel Channel number
+ *
+ * @return Pointer to timestamp if found, or MNULL
+ */
+static mlan_status wlan_11h_add_dfs_timestamp(mlan_adapter *pmadapter,
+ t_u8 repr, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (!pdfs_ts) {
+ /* need to allocate new timestamp */
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, sizeof(wlan_dfs_timestamp_t),
+ MLAN_MEM_DEF, (t_u8 **)&pdfs_ts);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pdfs_ts) {
+ PRINTM(MERROR, "%s(): Could not allocate dfs_ts\n",
+ __func__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, (t_u8 *)pdfs_ts, 0,
+ sizeof(wlan_dfs_timestamp_t));
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->state_dfs.dfs_ts_head,
+ (pmlan_linked_list)pdfs_ts, MNULL,
+ MNULL);
+ pdfs_ts->channel = channel;
+ }
+ /* (else, use existing timestamp for channel; see assumptions above) */
+
+ /* update params */
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &pdfs_ts->ts_sec, &pdfs_ts->ts_usec);
+ pdfs_ts->represents = repr;
+
+ PRINTM(MCMD_D,
+ "11h: add/update dfs_timestamp - chan=%d, repr=%d(%s),"
+ " time(sec.usec)=%lu.%06lu\n",
+ pdfs_ts->channel, pdfs_ts->represents,
+ DFS_TS_REPR_STRINGS[pdfs_ts->represents], pdfs_ts->ts_sec,
+ pdfs_ts->ts_usec);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Return whether the device has activated master radar detection.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if master radar detection is enabled in firmware
+ * - MFALSE otherwise
+ */
+t_bool wlan_11h_is_master_radar_det_active(mlan_private *priv)
+{
+ ENTER();
+ LEAVE();
+ return priv->adapter->state_11h.is_master_radar_det_active;
+}
+
+/**
+ * @brief Configure master radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable master radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status wlan_11h_config_master_radar_det(mlan_private *priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ /* Force disable master radar detection on in-AP interfaces */
+ if (priv->adapter->dfs_repeater)
+ enable = MFALSE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_master(priv) &&
+ priv->adapter->init_para.dfs_master_radar_det_en) {
+ priv->adapter->state_11h.master_radar_det_enable_pending =
+ enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure slave radar detection.
+ * Call wlan_11h_check_update_radar_det_state() afterwards
+ * to push this to firmware.
+ *
+ * @param priv Private driver information structure
+ * @param enable Whether to enable or disable slave radar detection
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ * @sa wlan_11h_check_update_radar_det_state
+ */
+mlan_status wlan_11h_config_slave_radar_det(mlan_private *priv, t_bool enable)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ /* Force disable radar detection on STA interfaces */
+ if (priv->adapter->dfs_repeater)
+ enable = MFALSE;
+
+ ENTER();
+ if (wlan_11h_is_dfs_slave(priv) &&
+ priv->adapter->init_para.dfs_slave_radar_det_en) {
+ priv->adapter->state_11h.slave_radar_det_enable_pending =
+ enable;
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks all interfaces and determines if radar_detect flag states
+ * have/should be changed. If so, sends SNMP_MIB 11H command to FW.
+ * Call this function on any interface enable/disable/channel change.
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS (update or not)
+ * or MLAN_STATUS_FAILURE (cmd failure)
+ *
+ * @sa wlan_11h_check_radar_det_state
+ */
+mlan_status wlan_11h_check_update_radar_det_state(mlan_private *pmpriv)
+{
+ t_u32 new_radar_det_state = 0;
+ t_u32 mib_11h = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_11h_check_radar_det_state(pmpriv->adapter,
+ &new_radar_det_state)) {
+ PRINTM(MCMD_D, "%s: radar_det_state being updated.\n",
+ __func__);
+
+ mib_11h |= new_radar_det_state;
+ /* keep priv's existing 11h state */
+ if (pmpriv->intf_state_11h.is_11h_active)
+ mib_11h |= ENABLE_11H_MASK;
+
+ /* Send cmd to FW to enable/disable 11h function in firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11H_i, MNULL,
+ &mib_11h);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ /* updated state sent OR no change, thus no longer pending */
+ pmpriv->adapter->state_11h.master_radar_det_enable_pending = MFALSE;
+ pmpriv->adapter->state_11h.slave_radar_det_enable_pending = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query 11h firmware enabled state.
+ *
+ * Return whether the firmware currently has 11h extensions enabled
+ *
+ * @param priv Private driver information structure
+ *
+ * @return
+ * - MTRUE if 11h has been activated in the firmware
+ * - MFALSE otherwise
+ *
+ * @sa wlan_11h_activate
+ */
+t_bool wlan_11h_is_active(mlan_private *priv)
+{
+ ENTER();
+ LEAVE();
+ return priv->intf_state_11h.is_11h_active;
+}
+
+/**
+ * @brief Enable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void wlan_11h_tx_enable(mlan_private *priv)
+{
+ ENTER();
+ if (priv->intf_state_11h.tx_disabled) {
+ if (priv->media_connected == MTRUE) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_START_TX, MNULL);
+ priv->intf_state_11h.tx_disabled = MFALSE;
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Disable the transmit interface and record the state.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return N/A
+ */
+t_void wlan_11h_tx_disable(mlan_private *priv)
+{
+ ENTER();
+ if (!priv->intf_state_11h.tx_disabled) {
+ if (priv->media_connected == MTRUE) {
+ priv->intf_state_11h.tx_disabled = MTRUE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_STOP_TX, MNULL);
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Enable or Disable the 11h extensions in the firmware
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param flag Enable 11h if MTRUE, disable otherwise
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_activate(mlan_private *priv, t_void *pioctl_buf,
+ t_bool flag)
+{
+ t_u32 enable = flag & ENABLE_11H_MASK;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* add bits for master/slave radar detect into enable. */
+ enable |= wlan_11h_get_current_radar_detect_flags(priv->adapter);
+
+ /* Whenever repeater mode is on make sure
+ * we do not enable master or slave radar det mode.
+ * HW will not detect radar in dfs_repeater mode.
+ */
+ if (priv->adapter->dfs_repeater) {
+ enable &= ~(MASTER_RADAR_DET_MASK | SLAVE_RADAR_DET_MASK);
+ }
+
+ /*
+ * Send cmd to FW to enable/disable 11h function in firmware
+ */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11H_i,
+ (t_void *)pioctl_buf, &enable);
+ if (ret)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ /* Set boolean flag in driver 11h state */
+ priv->intf_state_11h.is_11h_active = flag;
+
+ PRINTM(MINFO, "11h: %s\n", flag ? "Activate" : "Deactivate");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_11h_init(mlan_adapter *adapter)
+{
+ wlan_11h_device_state_t *pstate_11h = &adapter->state_11h;
+ IEEEtypes_Quiet_t *pquiet = &adapter->state_11h.quiet_ie;
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &adapter->state_rdh;
+ wlan_dfs_testing_settings_t *pdfs_test = &adapter->dfs_test_params;
+
+ ENTER();
+
+ /* Initialize 11H struct */
+ pstate_11h->usr_def_power_constraint = WLAN_11H_TPC_POWERCONSTRAINT;
+ pstate_11h->min_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
+ pstate_11h->max_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
+
+ pstate_11h->recvd_chanswann_event = MFALSE;
+ pstate_11h->master_radar_det_enable_pending = MFALSE;
+ pstate_11h->slave_radar_det_enable_pending = MFALSE;
+ pstate_11h->is_master_radar_det_active = MFALSE;
+ pstate_11h->is_slave_radar_det_active = MFALSE;
+
+ /*Initialize quiet_ie*/
+ memset(adapter, pquiet, 0, sizeof(IEEEtypes_Quiet_t));
+ pquiet->element_id = QUIET;
+ pquiet->len =
+ (sizeof(pquiet->quiet_count) + sizeof(pquiet->quiet_period) +
+ sizeof(pquiet->quiet_duration) + sizeof(pquiet->quiet_offset));
+
+ /* Initialize DFS struct */
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_radar_found = MFALSE;
+ pstate_dfs->dfs_check_channel = 0;
+ pstate_dfs->dfs_report_time_sec = 0;
+ util_init_list((pmlan_linked_list)&pstate_dfs->dfs_ts_head);
+
+ /* Initialize RDH struct */
+ pstate_rdh->stage = RDH_OFF;
+ pstate_rdh->priv_list_count = 0;
+ pstate_rdh->priv_curr_idx = 0;
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ memset(adapter, &(pstate_rdh->uap_band_cfg), 0,
+ sizeof(pstate_rdh->uap_band_cfg));
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ memset(adapter, pstate_rdh->priv_list, 0,
+ sizeof(pstate_rdh->priv_list));
+
+ /* Initialize dfs channel switch count */
+#define DFS_CS_COUNT 5
+ adapter->dfs_cs_count = DFS_CS_COUNT;
+
+ /* Initialize DFS testing struct */
+ pdfs_test->user_cac_period_msec = 0;
+ pdfs_test->user_nop_period_sec = 0;
+ pdfs_test->no_channel_change_on_radar = MFALSE;
+ pdfs_test->fixed_new_channel_on_radar = 0;
+ pdfs_test->cac_restart = 0;
+ pdfs_test->millisec_dwell_time = 0;
+ adapter->dfs53cfg = adapter->init_para.dfs53cfg;
+
+ LEAVE();
+}
+
+/**
+ * @brief Cleanup for the 11h parameters that allocated memory, etc.
+ *
+ * @param adapter mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_11h_cleanup(mlan_adapter *adapter)
+{
+ wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
+ wlan_dfs_timestamp_t *pdfs_ts;
+
+ ENTER();
+
+ /* cleanup dfs_timestamp list */
+ pdfs_ts = (wlan_dfs_timestamp_t *)util_peek_list(
+ adapter->pmoal_handle, &pstate_dfs->dfs_ts_head, MNULL, MNULL);
+ while (pdfs_ts) {
+ util_unlink_list(adapter->pmoal_handle,
+ &pstate_dfs->dfs_ts_head,
+ (pmlan_linked_list)pdfs_ts, MNULL, MNULL);
+ adapter->callbacks.moal_mfree(adapter->pmoal_handle,
+ (t_u8 *)pdfs_ts);
+
+ pdfs_ts = (wlan_dfs_timestamp_t *)util_peek_list(
+ adapter->pmoal_handle, &pstate_dfs->dfs_ts_head, MNULL,
+ MNULL);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ * @param pmpriv Pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_11h_priv_init(mlan_private *pmpriv)
+{
+ wlan_11h_interface_state_t *pistate_11h = &pmpriv->intf_state_11h;
+
+ ENTER();
+
+ pistate_11h->is_11h_enabled = MTRUE;
+ pistate_11h->is_11h_active = MFALSE;
+ pistate_11h->adhoc_auto_sel_chan = MTRUE;
+ pistate_11h->tx_disabled = MFALSE;
+ pistate_11h->dfs_slave_csa_chan = 0;
+ pistate_11h->dfs_slave_csa_expire_at_sec = 0;
+
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ * If 11h is enabled and an A-Band channel start band preference
+ * configured in the driver, the start channel must be random in order
+ * to meet with
+ *
+ * @param priv Private driver information structure
+ *
+ * @return Starting channel
+ */
+t_u8 wlan_11h_get_adhoc_start_channel(mlan_private *priv)
+{
+ t_u8 start_chn;
+ mlan_adapter *adapter = priv->adapter;
+ t_u32 region;
+ t_u32 rand_entry;
+ region_chan_t *chn_tbl;
+ t_u8 rand_tries = 0;
+
+ ENTER();
+
+ /*
+ * Set start_chn to the Default. Used if 11h is disabled or the band
+ * does not require 11h support.
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL;
+
+ /*
+ * Check that we are looking for a channel in the A Band
+ */
+ if ((adapter->adhoc_start_band & BAND_A)) {
+ /*
+ * Set default to the A Band default.
+ * Used if random selection fails
+ * or if 11h is not enabled
+ */
+ start_chn = DEFAULT_AD_HOC_CHANNEL_A;
+
+ /*
+ * Check that 11h is enabled in the driver
+ */
+ if (wlan_11h_is_enabled(priv)) {
+ /*
+ * Search the region_channel tables for a channel table
+ * that is marked for the A Band.
+ */
+ for (region = 0; (region < MAX_REGION_CHANNEL_NUM);
+ region++) {
+ chn_tbl = &adapter->region_channel[region];
+
+ /* Check if table is valid and marked for A Band
+ */
+ if (chn_tbl->valid &&
+ chn_tbl->region == adapter->region_code &&
+ chn_tbl->band & BAND_A) {
+ /*
+ * Set the start channel. Get a random
+ * number and use it to pick an entry
+ * in the table between 0 and the number
+ * of channels in the table (NumCFP).
+ */
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(
+ adapter) %
+ chn_tbl->num_cfp;
+ start_chn =
+ (t_u8)chn_tbl
+ ->pcfp[rand_entry]
+ .channel;
+ } while (
+ (wlan_11h_is_channel_under_nop(
+ adapter, start_chn) ||
+ ((adapter->state_rdh.stage ==
+ RDH_GET_INFO_CHANNEL) &&
+ wlan_11h_radar_detect_required(
+ priv, start_chn))) &&
+ (++rand_tries <
+ MAX_RANDOM_CHANNEL_RETRIES));
+ }
+ }
+ }
+ }
+
+ PRINTM(MINFO, "11h: %s: AdHoc Channel set to %u\n",
+ wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", start_chn);
+
+ LEAVE();
+ return start_chn;
+}
+
+/**
+ * @brief Retrieve channel closed for operation by Channel Switch Announcement
+ *
+ * After receiving CSA, we must not transmit in any form on the original
+ * channel for a certain duration. This checks the time, and returns
+ * the channel if valid.
+ *
+ * @param priv Private driver information structure
+ *
+ * @return Closed channel, else 0
+ */
+t_u8 wlan_11h_get_csa_closed_channel(mlan_private *priv)
+{
+ t_u32 sec, usec;
+
+ ENTER();
+
+ if (!priv->intf_state_11h.dfs_slave_csa_chan) {
+ LEAVE();
+ return 0;
+ }
+
+ /* have csa channel, check if expired or not */
+ priv->adapter->callbacks.moal_get_system_time(
+ priv->adapter->pmoal_handle, &sec, &usec);
+ if (sec > priv->intf_state_11h.dfs_slave_csa_expire_at_sec) {
+ /* expired: remove channel from blacklist table, and clear vars
+ */
+ wlan_set_chan_blacklist(priv, BAND_A,
+ priv->intf_state_11h.dfs_slave_csa_chan,
+ MFALSE);
+ priv->intf_state_11h.dfs_slave_csa_chan = 0;
+ priv->intf_state_11h.dfs_slave_csa_expire_at_sec = 0;
+ }
+
+ LEAVE();
+ return priv->intf_state_11h.dfs_slave_csa_chan;
+}
+
+/**
+ * @brief Check if the current region's regulations require the input channel
+ * to be scanned for radar.
+ *
+ * Based on statically defined requirements for sub-bands per regulatory
+ * agency requirements.
+ *
+ * Used in adhoc start to determine if channel availability check is required
+ *
+ * @param priv Private driver information structure
+ * @param channel Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+/** @sa wlan_11h_issue_radar_detect
+ */
+t_bool wlan_11h_radar_detect_required(mlan_private *priv, t_u8 channel)
+{
+ t_bool required = MFALSE;
+
+ ENTER();
+
+ /*
+ * No checks for 11h or measurement code being enabled is placed here
+ * since regulatory requirements exist whether we support them or not.
+ */
+
+ required = wlan_get_cfp_radar_detect(priv, channel);
+
+ if (!priv->adapter->region_code) {
+ PRINTM(MINFO,
+ "11h: Radar detection in CFP code BG:%#x "
+ ", A:%#x "
+ "is %srequired for channel %d\n",
+ priv->adapter->cfp_code_bg, priv->adapter->cfp_code_a,
+ (required ? "" : "not "), channel);
+ } else
+ PRINTM(MINFO,
+ "11h: Radar detection in region %#02x "
+ "is %srequired for channel %d\n",
+ priv->adapter->region_code, (required ? "" : "not "),
+ channel);
+
+ if (required == MTRUE && priv->media_connected == MTRUE &&
+ priv->curr_bss_params.bss_descriptor.channel == channel) {
+ required = MFALSE;
+
+ PRINTM(MINFO, "11h: Radar detection not required. "
+ "Already operating on the channel\n");
+ }
+
+ LEAVE();
+ return required;
+}
+
+t_s32 wlan_11h_cancel_radar_detect(mlan_private *priv)
+{
+ t_s32 ret;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+ memset(priv->adapter, &chan_rpt_req, 0x00, sizeof(chan_rpt_req));
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)MNULL,
+ (t_void *)&chan_rpt_req);
+ return ret;
+}
+
+/**
+ * @brief Perform a radar measurement if required on given channel
+ *
+ * Check to see if the provided channel requires a channel availability
+ * check (60 second radar detection measurement). If required, perform
+ * measurement, stalling calling thread until the measurement completes
+ * and then report result.
+ *
+ * Used when starting an adhoc or AP network.
+ *
+ * @param priv Private driver information structure
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param channel Channel on which to perform radar measurement
+ * @param bandcfg Channel Band config structure
+ *
+ * @return
+ * - MTRUE if radar measurement request was successfully issued
+ * - MFALSE if radar detection is not required
+ * - < 0 for error during radar detection (if performed)
+ *
+ * @sa wlan_11h_radar_detect_required
+ */
+t_s32 wlan_11h_issue_radar_detect(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req, t_u8 channel,
+ Band_Config_t bandcfg)
+{
+ t_s32 ret;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+
+ ENTER();
+
+ ret = wlan_11h_radar_detect_required(priv, channel);
+ if (ret) {
+ /* Prepare and issue CMD_CHAN_RPT_REQ. */
+ memset(priv->adapter, &chan_rpt_req, 0x00,
+ sizeof(chan_rpt_req));
+
+ chan_rpt_req.chan_desc.startFreq = START_FREQ_11A_BAND;
+
+ if (pmadapter->chanrpt_param_bandcfg) {
+ chan_rpt_req.chan_desc.bandcfg = bandcfg;
+ } else {
+ *((t_u8 *)&chan_rpt_req.chan_desc.bandcfg) =
+ (t_u8)bandcfg.chanWidth;
+ }
+
+ chan_rpt_req.chan_desc.chanNum = channel;
+ chan_rpt_req.millisec_dwell_time =
+ WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
+
+ /* ETSI new requirement for ch 120, 124 and 128 */
+ if (wlan_is_etsi_country(pmadapter, pmadapter->country_code)) {
+ if (channel == 120 || channel == 124 ||
+ channel == 128) {
+ chan_rpt_req.millisec_dwell_time =
+ WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION *
+ 10;
+ }
+ if (channel == 116 &&
+ ((bandcfg.chanWidth == CHAN_BW_40MHZ) ||
+ (bandcfg.chanWidth == CHAN_BW_80MHZ))) {
+ chan_rpt_req.millisec_dwell_time =
+ WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION *
+ 10;
+ }
+ }
+
+ /* Save dwell time information to be used later in moal */
+ if (pioctl_req) {
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ if (!ds_11hcfg->param.chan_rpt_req.host_based) {
+ ds_11hcfg->param.chan_rpt_req
+ .millisec_dwell_time =
+ chan_rpt_req.millisec_dwell_time;
+ }
+ }
+
+ if (priv->adapter->dfs_test_params.user_cac_period_msec) {
+ PRINTM(MCMD_D,
+ "dfs_testing - user CAC period=%d (msec)\n",
+ priv->adapter->dfs_test_params
+ .user_cac_period_msec);
+ chan_rpt_req.millisec_dwell_time =
+ priv->adapter->dfs_test_params
+ .user_cac_period_msec;
+ }
+ if (priv->adapter->dfs_test_params.cac_restart) {
+ priv->adapter->dfs_test_params.chan =
+ chan_rpt_req.chan_desc.chanNum;
+ if (chan_rpt_req.millisec_dwell_time)
+ priv->adapter->dfs_test_params
+ .millisec_dwell_time =
+ chan_rpt_req.millisec_dwell_time;
+ else
+ chan_rpt_req.millisec_dwell_time =
+ priv->adapter->dfs_test_params
+ .millisec_dwell_time;
+ memcpy_ext(priv->adapter,
+ &priv->adapter->dfs_test_params.bandcfg,
+ &bandcfg, sizeof(bandcfg), sizeof(bandcfg));
+ }
+ PRINTM(MMSG,
+ "11h: issuing DFS Radar check for channel=%d."
+ " Please wait for response...\n",
+ channel);
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&chan_rpt_req);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Checks if a radar measurement was performed on channel,
+ * and if so, whether radar was detected on it.
+ *
+ * Used when starting an adhoc network.
+ *
+ * @param priv Private driver information structure
+ * @param chan Channel to check upon
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if no radar on channel
+ * - MLAN_STATUS_FAILURE if radar was found on channel
+ * - (TBD??) MLAN_STATUS_PENDING if radar report NEEDS TO BE REISSUED
+ *
+ * @sa wlan_11h_issue_radar_detect
+ * @sa wlan_11h_process_start
+ */
+mlan_status wlan_11h_check_chan_report(mlan_private *priv, t_u8 chan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ t_u32 sec, usec;
+
+ ENTER();
+
+ /* check report we hold is valid or not */
+ priv->adapter->callbacks.moal_get_system_time(
+ priv->adapter->pmoal_handle, &sec, &usec);
+
+ PRINTM(MINFO, "11h: %s()\n", __func__);
+ PRINTM(MINFO, "- sec_now=%d, sec_report=%d.\n", sec,
+ pstate_dfs->dfs_report_time_sec);
+ PRINTM(MINFO, "- rpt_channel=%d, rpt_radar=%d.\n",
+ pstate_dfs->dfs_check_channel, pstate_dfs->dfs_radar_found);
+
+ if ((!pstate_dfs->dfs_check_pending) &&
+ (chan == pstate_dfs->dfs_check_channel) &&
+ ((sec - pstate_dfs->dfs_report_time_sec) <
+ MAX_DFS_REPORT_USABLE_AGE_SEC)) {
+ /* valid and not out-dated, check if radar */
+ if (pstate_dfs->dfs_radar_found) {
+ PRINTM(MMSG, "Radar was detected on channel %d.\n",
+ chan);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ /* When Cache is not valid. This is required during extending
+ * cache validity during bss_stop
+ */
+ pstate_dfs->dfs_check_channel = 0;
+
+ /*TODO: reissue report request if not pending.
+ * BUT HOW to make the code wait for it???
+ * For now, just fail since we don't have the info. */
+
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Adhoc start command.
+ *
+ * Activate 11h functionality in the firmware if driver has is enabled
+ * for 11h (configured by the application via IOCTL).
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param channel Channel on which we are starting the IBSS
+ * @param p11h_bss_info Input/Output parameter: Pointer to the 11h BSS
+ * information for this network that we are establishing.
+ * 11h sensed flag set on output if warranted.
+ *
+ * @return
+ * - MLAN_STATUS_SUCCESS if 11h is disabled
+ * - Integer number of bytes appended to the TLV output buffer (ppbuffer)
+ * - < 0 for error (e.g. radar detected on channel)
+ */
+t_s32 wlan_11h_process_start(mlan_private *priv, t_u8 **ppbuffer,
+ IEEEtypes_CapInfo_t *pcap_info, t_u32 channel,
+ wlan_11h_bss_info_t *p11h_bss_info)
+{
+ mlan_adapter *adapter = priv->adapter;
+ t_s32 ret = MLAN_STATUS_SUCCESS;
+ t_bool is_dfs_chan = MFALSE;
+
+ ENTER();
+ if (wlan_11h_is_enabled(priv) &&
+ ((adapter->adhoc_start_band & BAND_A))) {
+ if (!wlan_fw_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_create_dnld_countryinfo(
+ priv, adapter->adhoc_start_band);
+#endif
+ }
+
+ /*
+ * Activate 11h functions in firmware,
+ * turns on capability bit
+ */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ is_dfs_chan = wlan_11h_radar_detect_required(priv, channel);
+ if (is_dfs_chan) {
+ if (!wlan_11h_is_master_radar_det_active(priv))
+ wlan_11h_config_master_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ /* Set flag indicating this BSS we are starting is using 11h */
+ p11h_bss_info->sensed_11h = MTRUE;
+
+ if (is_dfs_chan) {
+ /* check if this channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(adapter, channel))
+ ret = MLAN_STATUS_FAILURE;
+ /* check last channel report, if this channel is free of
+ * radar */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_check_chan_report(priv, channel);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
+ MNULL);
+ else
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an TLV buffer for a pending BSS Join command for
+ * both adhoc and infra networks
+ *
+ * The TLV command processing for a BSS join for either adhoc or
+ * infrastructure network is performed with this function. The
+ * capability bits are inspected for the IBSS flag and the appropriate
+ * local routines are called to setup the necessary TLVs.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network information for the BSS we are
+ * joining.
+ *
+ * @param priv Private driver information structure
+ * @param ppbuffer Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended 11h TLVs
+ * @param pcap_info Pointer to the capability info for the BSS to join
+ * @param band Band on which we are joining the BSS
+ * @param channel Channel on which we are joining the BSS
+ * @param p11h_bss_info Pointer to the 11h BSS information for this
+ * network that was parsed out of the scan response.
+ *
+ * @return Integer number of bytes appended to the TLV output
+ * buffer (ppbuffer), MLAN_STATUS_FAILURE (-1),
+ * or MLAN_STATUS_SUCCESS (0)
+ */
+t_s32 wlan_11h_process_join(mlan_private *priv, t_u8 **ppbuffer,
+ IEEEtypes_CapInfo_t *pcap_info, t_u8 band,
+ t_u32 channel, wlan_11h_bss_info_t *p11h_bss_info)
+{
+ t_s32 ret = 0;
+
+ ENTER();
+
+ if (priv->media_connected == MTRUE) {
+ if (wlan_11h_is_active(priv) == p11h_bss_info->sensed_11h) {
+ /*
+ * Assume DFS parameters are the same for roaming as
+ * long as the current & next APs have the same spectrum
+ * mgmt capability bit setting
+ */
+ ret = MLAN_STATUS_SUCCESS;
+
+ } else {
+ /* No support for roaming between DFS/non-DFS yet */
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+ }
+
+ if (p11h_bss_info->sensed_11h) {
+ if (!wlan_fw_11d_is_enabled(priv)) {
+ /* No use having 11h enabled without 11d enabled */
+ wlan_11d_enable(priv, MNULL, ENABLE_11D);
+#ifdef STA_SUPPORT
+ wlan_11d_parse_dnld_countryinfo(
+ priv, priv->pattempted_bss_desc);
+#endif
+ }
+ /*
+ * Activate 11h functions in firmware,
+ * turns on capability bit
+ */
+ wlan_11h_activate(priv, MNULL, MTRUE);
+ pcap_info->spectrum_mgmt = MTRUE;
+
+ /* If using a DFS channel, enable radar detection. */
+ if ((band & BAND_A) &&
+ wlan_11h_radar_detect_required(priv, channel)) {
+ if (!wlan_11h_is_slave_radar_det_active(priv))
+ wlan_11h_config_slave_radar_det(priv, MTRUE);
+ }
+ wlan_11h_check_update_radar_det_state(priv);
+
+ if (pcap_info->ibss) {
+ PRINTM(MINFO, "11h: Adhoc join: Sensed\n");
+ ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
+ p11h_bss_info);
+ } else {
+ PRINTM(MINFO, "11h: Infra join: Sensed\n");
+ ret = wlan_11h_process_infra_join(
+ priv, ppbuffer, band, channel, p11h_bss_info);
+ }
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ wlan_11h_activate(priv, MNULL, MFALSE);
+ pcap_info->spectrum_mgmt = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ *
+ * @brief Prepare the HostCmd_DS_Command structure for an 11h command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer pass through with data necessary for a
+ * specific command type
+ */
+/** @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE
+ * or MLAN_STATUS_PENDING
+ */
+/** @sa wlan_11h_cmd_tpc_request
+ * @sa wlan_11h_cmd_tpc_info
+ * @sa wlan_11h_cmd_chan_sw_ann
+ */
+/** @sa wlan_11h_cmd_chan_report_req
+ */
+mlan_status wlan_11h_cmd_process(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ ret = wlan_11h_cmd_tpc_request(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_TPC_INFO:
+ ret = wlan_11h_cmd_tpc_info(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ ret = wlan_11h_cmd_chan_sw_ann(priv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_chan_rpt_req(priv, pcmd_ptr, pinfo_buf);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware if from an 11h command
+ *
+ * Use the Command field to determine if the command response being
+ * is for 11h. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ * - HostCmd_CMD_802_11_TPC_INFO
+ * - HostCmd_CMD_802_11_CHAN_SW_ANN
+ */
+/** - HostCmd_CMD_CHAN_REPORT_REQUEST
+ */
+/**
+ * @param priv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware
+ * command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_cmdresp_process(mlan_private *priv,
+ const HostCmd_DS_COMMAND *resp)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ HEXDUMP("11h: TPC REQUEST Rsp:", (t_u8 *)resp,
+ (t_u32)resp->size);
+ memcpy_ext(priv->adapter, priv->adapter->curr_cmd->pdata_buf,
+ &resp->params.tpc_req,
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ),
+ sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+ break;
+
+ case HostCmd_CMD_802_11_TPC_INFO:
+ HEXDUMP("11h: TPC INFO Rsp Data:", (t_u8 *)resp,
+ (t_u32)resp->size);
+ break;
+
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ PRINTM(MINFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ priv->adapter->state_dfs.dfs_check_priv = priv;
+ priv->adapter->state_dfs.dfs_check_pending = MTRUE;
+
+ if (resp->params.chan_rpt_req.millisec_dwell_time == 0) {
+ /* from wlan_11h_ioctl_dfs_chan_report */
+ priv->adapter->state_dfs.dfs_check_pending = MFALSE;
+ priv->adapter->state_dfs.dfs_check_priv = MNULL;
+ priv->adapter->state_dfs.dfs_check_channel = 0;
+ PRINTM(MINFO, "11h: Cancelling Chan Report \n");
+ } else {
+ PRINTM(MERROR,
+ "11h: Ret ChanRptReq. Set dfs_check_pending and wait"
+ " for EVENT_CHANNEL_REPORT.\n");
+ }
+
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process an element from a scan response, copy relevant info for 11h
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param p11h_bss_info Output parameter: Pointer to the 11h BSS information
+ * for the network that is being processed
+ * @param pelement Pointer to the current IE we are inspecting for 11h
+ * relevance
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_process_bss_elem(mlan_adapter *pmadapter,
+ wlan_11h_bss_info_t *p11h_bss_info,
+ const t_u8 *pelement)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 element_len = *((t_u8 *)pelement + 1);
+
+ ENTER();
+ switch (*pelement) {
+ case POWER_CONSTRAINT:
+ PRINTM(MINFO, "11h: Power Constraint IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->power_constraint,
+ pelement, element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_PowerConstraint_t));
+ p11h_bss_info->power_constraint.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerConstraint_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case POWER_CAPABILITY:
+ PRINTM(MINFO, "11h: Power Capability IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->power_capability,
+ pelement, element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_PowerCapability_t));
+ p11h_bss_info->power_capability.len =
+ MIN(element_len, (sizeof(IEEEtypes_PowerCapability_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case TPC_REPORT:
+ PRINTM(MINFO, "11h: Tpc Report IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->tpc_report, pelement,
+ element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_TPCReport_t));
+ p11h_bss_info->tpc_report.len =
+ MIN(element_len, (sizeof(IEEEtypes_TPCReport_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CHANNEL_SWITCH_ANN:
+ PRINTM(MINFO, "11h: Channel Switch Ann IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->chan_switch_ann, pelement,
+ element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_ChanSwitchAnn_t));
+ p11h_bss_info->chan_switch_ann.len =
+ MIN(element_len, (sizeof(IEEEtypes_ChanSwitchAnn_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case QUIET:
+ PRINTM(MINFO, "11h: Quiet IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->quiet, pelement,
+ element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_Quiet_t));
+ p11h_bss_info->quiet.len =
+ MIN(element_len, (sizeof(IEEEtypes_Quiet_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_DFS:
+ PRINTM(MINFO, "11h: Ibss Dfs IE Found\n");
+ p11h_bss_info->sensed_11h = MTRUE;
+ memcpy_ext(pmadapter, &p11h_bss_info->ibss_dfs, pelement,
+ element_len + sizeof(IEEEtypes_Header_t),
+ sizeof(IEEEtypes_IBSS_DFS_t));
+ p11h_bss_info->ibss_dfs.len =
+ MIN(element_len, (sizeof(IEEEtypes_IBSS_DFS_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ /*
+ * These elements are not in beacons/probe responses.
+ * Included here to cover set of enumerated 11h elements.
+ */
+ break;
+
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_SWITCH_ANN event
+ *
+ * @param priv Pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status wlan_11h_handle_event_chanswann(mlan_private *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ mlan_deauth_param deauth_param;
+#endif
+ t_u32 sec, usec;
+#ifdef UAP_SUPPORT
+ mlan_adapter *pmadapter = priv->adapter;
+ int i;
+ t_u8 radar_detected = MFALSE;
+ mlan_private *pmpriv = MNULL;
+#endif
+
+ ENTER();
+#ifdef UAP_SUPPORT
+ if (priv->adapter->state_11h.is_master_radar_det_active) {
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM);
+ i++) {
+ if (pmadapter->priv[i] &&
+ (pmadapter->priv[i]->bss_role ==
+ MLAN_BSS_ROLE_UAP) &&
+ pmadapter->priv[i]->uap_bss_started &&
+ (priv->curr_bss_params.bss_descriptor.channel ==
+ pmadapter->priv[i]->uap_channel)) {
+ PRINTM(MCMND,
+ "Receive channel switch Ann event on uap_channel=%d\n",
+ pmadapter->priv[i]->uap_channel);
+ radar_detected = MTRUE;
+ pmpriv = pmadapter->priv[i];
+ break;
+ }
+ }
+ if (radar_detected) {
+ if (!pmpriv->intf_state_11h.is_11h_host) {
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage =
+ RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(
+ pmadapter, pmpriv);
+ if (pmpriv->uap_host_based)
+ wlan_recv_event(
+ pmpriv,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MNULL);
+ } else {
+ PRINTM(MEVENT,
+ "Ignore Event Radar Detected - handling already in progress.\n");
+ }
+ } else {
+ if (pmpriv->adapter->dfs_test_params
+ .no_channel_change_on_radar ||
+ pmpriv->adapter->dfs_test_params
+ .fixed_new_channel_on_radar) {
+ if (pmadapter->state_rdh.stage ==
+ RDH_OFF ||
+ pmadapter->state_rdh.stage ==
+ RDH_SET_CUSTOM_IE) {
+ pmadapter->state_rdh.stage =
+ RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(
+ pmadapter, pmpriv);
+ } else
+ PRINTM(MEVENT,
+ "Ignore Event Radar Detected - handling already in progress.\n");
+ } else {
+ pmpriv->intf_state_11h.tx_disabled =
+ MTRUE;
+ wlan_recv_event(
+ pmpriv,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ MNULL);
+ }
+ }
+ }
+ }
+ if (pmadapter->ecsa_enable) {
+ t_u8 stop_tx = *(t_u8 *)pmadapter->event_body;
+ if (stop_tx)
+ pmadapter->state_rdh.tx_block = MTRUE;
+ LEAVE();
+ return ret;
+ }
+#endif
+ priv->adapter->state_11h.recvd_chanswann_event = MTRUE;
+
+ /* unlikely: clean up previous csa if still on-going */
+ if (priv->intf_state_11h.dfs_slave_csa_chan) {
+ wlan_set_chan_blacklist(priv, BAND_A,
+ priv->intf_state_11h.dfs_slave_csa_chan,
+ MFALSE);
+ }
+
+ /* record channel and time of occurence */
+ priv->intf_state_11h.dfs_slave_csa_chan =
+ priv->curr_bss_params.bss_descriptor.channel;
+ priv->adapter->callbacks.moal_get_system_time(
+ priv->adapter->pmoal_handle, &sec, &usec);
+ priv->intf_state_11h.dfs_slave_csa_expire_at_sec =
+ sec + DFS_CHAN_MOVE_TIME;
+
+#ifdef STA_SUPPORT
+ /* do directed deauth. recvd_chanswann_event flag will cause different
+ * reason code */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - sending deauth\n");
+ memcpy_ext(priv->adapter, deauth_param.mac_addr,
+ &priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ deauth_param.reason_code = DEF_DEAUTH_REASON_CODE;
+ ret = wlan_disconnect(priv, MNULL, &deauth_param);
+
+ /* clear region table so next scan will be all passive */
+ PRINTM(MINFO, "11h: handle_event_chanswann() - clear region table\n");
+ wlan_11d_clear_parsedtable(priv);
+
+ /* add channel to blacklist table */
+ PRINTM(MINFO,
+ "11h: handle_event_chanswann() - scan blacklist csa channel\n");
+ wlan_set_chan_blacklist(priv, BAND_A,
+ priv->intf_state_11h.dfs_slave_csa_chan, MTRUE);
+#endif
+
+ priv->adapter->state_11h.recvd_chanswann_event = MFALSE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h DFS Testing configuration
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ mlan_ds_11h_dfs_testing *dfs_test = MNULL;
+ wlan_dfs_testing_settings_t *pdfs_test_params = MNULL;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ dfs_test = &ds_11hcfg->param.dfs_testing;
+ pdfs_test_params = &pmadapter->dfs_test_params;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ dfs_test->usr_cac_period_msec =
+ pdfs_test_params->user_cac_period_msec;
+ dfs_test->usr_nop_period_sec =
+ pdfs_test_params->user_nop_period_sec;
+ dfs_test->usr_no_chan_change =
+ pdfs_test_params->no_channel_change_on_radar;
+ dfs_test->usr_fixed_new_chan =
+ pdfs_test_params->fixed_new_channel_on_radar;
+ dfs_test->usr_cac_restart = pdfs_test_params->cac_restart;
+ } else {
+ pdfs_test_params->user_cac_period_msec =
+ dfs_test->usr_cac_period_msec;
+ pdfs_test_params->user_nop_period_sec =
+ dfs_test->usr_nop_period_sec;
+ pdfs_test_params->no_channel_change_on_radar =
+ dfs_test->usr_no_chan_change;
+ pdfs_test_params->fixed_new_channel_on_radar =
+ dfs_test->usr_fixed_new_chan;
+ pdfs_test_params->cac_restart = dfs_test->usr_cac_restart;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief 802.11h IOCTL to handle channel NOP status check
+ * @brief If given channel is under NOP, return a new non-dfs
+ * @brief channel
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_ioctl_get_channel_nop_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ t_s32 ret = MLAN_STATUS_FAILURE;
+ mlan_ds_11h_chan_nop_info *ch_nop_info = MNULL;
+
+ ENTER();
+
+ if (pioctl_req) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ ch_nop_info = &ds_11hcfg->param.ch_nop_info;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ch_nop_info->chan_under_nop =
+ wlan_11h_is_channel_under_nop(
+ pmadapter, ch_nop_info->curr_chan);
+ if (ch_nop_info->chan_under_nop) {
+ wlan_11h_switch_non_dfs_chan(
+ pmpriv, &ch_nop_info->new_chan.channel);
+ if (ch_nop_info->chan_width == CHAN_BW_80MHZ ||
+ ch_nop_info->chan_width == CHAN_BW_40MHZ)
+ wlan_11h_update_bandcfg(
+ &ch_nop_info->new_chan.bandcfg,
+ ch_nop_info->new_chan.channel);
+ if (ch_nop_info->chan_width == CHAN_BW_80MHZ)
+ ch_nop_info->new_chan.center_chan =
+ wlan_get_center_freq_idx(
+ pmpriv, BAND_AAC,
+ ch_nop_info->new_chan
+ .channel,
+ ch_nop_info->chan_width);
+ }
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h DFS Channel Switch Count Configuration
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_ioctl_chan_switch_count(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ t_s32 ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (pioctl_req) {
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ds_11hcfg->param.cs_count = pmadapter->dfs_cs_count;
+ } else {
+ pmadapter->dfs_cs_count = ds_11hcfg->param.cs_count;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h DFS chan report
+ *
+ * @param priv Pointer to mlan_private
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_ioctl_dfs_chan_report(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ HostCmd_DS_CHAN_RPT_REQ *chan_rpt_req = MNULL;
+ t_s32 ret;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+
+ chan_rpt_req =
+ (HostCmd_DS_CHAN_RPT_REQ *)&ds_11hcfg->param.chan_rpt_req;
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)chan_rpt_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Check if channel is under NOP (Non-Occupancy Period)
+ * If so, the channel should not be used until the period expires.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param channel Channel number
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_11h_is_channel_under_nop(mlan_adapter *pmadapter, t_u8 channel)
+{
+ wlan_dfs_timestamp_t *pdfs_ts = MNULL;
+ t_u32 now_sec, now_usec;
+ t_bool ret = MFALSE;
+ ENTER();
+ pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
+
+ if (pdfs_ts && (pdfs_ts->channel == channel) &&
+ (pdfs_ts->represents == DFS_TS_REPR_NOP_START)) {
+ /* found NOP_start timestamp entry on channel */
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &now_sec, &now_usec);
+ if (pmadapter->dfs_test_params.user_nop_period_sec) {
+ PRINTM(MCMD_D,
+ "dfs_testing - user NOP period=%d (sec)\n",
+ pmadapter->dfs_test_params.user_nop_period_sec);
+ if ((now_sec - pdfs_ts->ts_sec) <=
+ pmadapter->dfs_test_params.user_nop_period_sec) {
+ ret = MTRUE;
+ }
+ } else {
+ if ((now_sec - pdfs_ts->ts_sec) <=
+ WLAN_11H_NON_OCCUPANCY_PERIOD)
+ ret = MTRUE;
+ }
+
+ /* if entry is expired, remove it */
+ if (!ret) {
+ wlan_11h_remove_dfs_timestamp(pmadapter, pdfs_ts);
+ } else
+ PRINTM(MMSG,
+ "11h: channel %d is under NOP - can't use.\n",
+ channel);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for CHANNEL_REPORT_RDY event
+ * This event will have the channel report data appended.
+ *
+ * @param priv Pointer to mlan_private
+ * @param pevent Pointer to mlan_event
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_handle_event_chanrpt_ready(mlan_private *priv,
+ mlan_event *pevent,
+ t_u8 *radar_chan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_CHAN_RPT_RSP *pchan_rpt_rsp;
+ MrvlIEtypes_Data_t *ptlv;
+ MeasRptBasicMap_t *pmeas_rpt_basic;
+ t_u8 *pbuffer;
+ t_s32 evt_len;
+ t_u16 tlv_len;
+ t_u32 sec, usec;
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ t_u8 dfs_radar_found = MFALSE;
+ t_u8 dfs_check_channel = pstate_dfs->dfs_check_channel;
+
+ ENTER();
+ pchan_rpt_rsp = (HostCmd_DS_CHAN_RPT_RSP *)&pevent->event_buf;
+ DBG_HEXDUMP(MCMD_D, "11h: Event ChanRptReady (HostCmd_DS_CHAN_RPT_RSP)",
+ (t_u8 *)pchan_rpt_rsp, pevent->event_len);
+
+ if (wlan_le32_to_cpu(pchan_rpt_rsp->cmd_result) ==
+ MLAN_CMD_RESULT_SUCCESS) {
+ pbuffer = (t_u8 *)&pchan_rpt_rsp->tlv_buffer;
+ evt_len = pevent->event_len;
+ evt_len -= sizeof(HostCmd_DS_CHAN_RPT_RSP) -
+ sizeof(pchan_rpt_rsp->tlv_buffer);
+
+ while (evt_len >= sizeof(MrvlIEtypesHeader_t)) {
+ ptlv = (MrvlIEtypes_Data_t *)pbuffer;
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+
+ switch (wlan_le16_to_cpu(ptlv->header.type)) {
+ case TLV_TYPE_CHANRPT_11H_BASIC:
+ pmeas_rpt_basic =
+ (MeasRptBasicMap_t *)&ptlv->data;
+ if (pmeas_rpt_basic->radar)
+ dfs_radar_found = MTRUE;
+ break;
+ default:
+ break;
+ }
+
+ pbuffer += (tlv_len + sizeof(ptlv->header));
+ evt_len -= (tlv_len + sizeof(ptlv->header));
+ evt_len = (evt_len > 0) ? evt_len : 0;
+ }
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ }
+ if (dfs_radar_found) {
+ PRINTM(MMSG, "RADAR Detected on channel %d!\n",
+ dfs_check_channel);
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(priv->adapter, DFS_TS_REPR_NOP_START,
+ dfs_check_channel);
+ }
+ *radar_chan = dfs_check_channel;
+ pstate_dfs->dfs_radar_found = dfs_radar_found;
+ /* Update DFS structure. */
+ priv->adapter->callbacks.moal_get_system_time(
+ priv->adapter->pmoal_handle, &sec, &usec);
+ pstate_dfs->dfs_report_time_sec = sec;
+ pstate_dfs->dfs_check_pending = MFALSE;
+ pstate_dfs->dfs_check_priv = MNULL;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Print debug info in RADAR_DETECTED event
+ * This event may have the dfs record data appended.
+ *
+ * @param priv Pointer to mlan_private
+ * @param pevent Pointer to mlan_event
+ * @param radar_chan Pointer to radar channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_print_event_radar_detected(mlan_private *priv,
+ mlan_event *pevent,
+ t_u8 *radar_chan)
+{
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ ENTER();
+ *radar_chan = pstate_dfs->dfs_check_channel;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Check if RADAR_DETECTED handling is blocking data tx
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_11h_radar_detected_tx_blocked(mlan_adapter *pmadapter)
+{
+ if (pmadapter->state_rdh.tx_block)
+ return MTRUE;
+ switch (pmadapter->state_rdh.stage) {
+ case RDH_OFF:
+ case RDH_CHK_INTFS:
+ case RDH_STOP_TRAFFIC:
+ return MFALSE;
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Callback for RADAR_DETECTED event driver handling
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_radar_detected_callback(t_void *priv)
+{
+ mlan_status ret;
+ ENTER();
+ ret = wlan_11h_radar_detected_handling(
+ ((mlan_private *)(priv))->adapter, (mlan_private *)priv);
+ LEAVE();
+ return ret;
+}
+
+#ifdef UAP_SUPPORT
+/**
+ * @brief Function for handling sta disconnect event in dfs_repeater mode
+ *
+ * @param pmadapter pointer to mlan_adapter
+ *
+ * @return NONE
+ */
+void wlan_dfs_rep_disconnect(mlan_adapter *pmadapter)
+{
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+ mlan_private *pmpriv = MNULL;
+ t_u8 pcount, i;
+
+ memset(pmadapter, priv_list, 0x00, sizeof(priv_list));
+ pcount = wlan_get_privs_by_cond(pmadapter, wlan_is_intf_active,
+ priv_list);
+
+ /* Stop all the active BSSes */
+ for (i = 0; i < pcount; i++) {
+ pmpriv = priv_list[i];
+
+ if (GET_BSS_ROLE(pmpriv) != MLAN_BSS_ROLE_UAP)
+ continue;
+
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pmadapter->dfsr_channel)) {
+ wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ }
+ }
+}
+
+/**
+ * @brief Function for handling sta BW change event in dfs_repeater mode
+ *
+ * @param pmadapter pointer to mlan_adapter
+ *
+ * @return NONE
+ */
+void wlan_dfs_rep_bw_change(mlan_adapter *pmadapter)
+{
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+ mlan_private *pmpriv = MNULL;
+ t_u8 pcount, i;
+
+ memset(pmadapter, priv_list, 0x00, sizeof(priv_list));
+ pcount = wlan_get_privs_by_cond(pmadapter, wlan_is_intf_active,
+ priv_list);
+ if (pcount == 1) {
+ pmpriv = priv_list[0];
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ PRINTM(MMSG,
+ "dfs-repeater: BW change detected\n"
+ "no active priv's, skip event handling.\n");
+ return;
+ }
+ }
+
+ /* Stop all the active BSSes */
+ for (i = 0; i < pcount; i++) {
+ pmpriv = priv_list[i];
+
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ /* Check if uAPs running on non-dfs channel. If they do
+ * then there is no need to restart the uAPs
+ */
+ if (!wlan_11h_radar_detect_required(
+ pmpriv, pmadapter->dfsr_channel))
+ return;
+
+ wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ }
+ }
+
+ /* Start all old active BSSes */
+ for (i = 0; i < pcount; i++) {
+ pmpriv = priv_list[i];
+
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ }
+ }
+}
+#endif
+
+/**
+ * @brief Update band config for the new channel
+ *
+ * @param uap_band_cfg uap's old channel's band configuration
+ * @param new_channel new channel that the device is switching to
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+void wlan_11h_update_bandcfg(Band_Config_t *uap_band_cfg, t_u8 new_channel)
+{
+ t_u8 chan_offset;
+ ENTER();
+
+ /* Update the channel offset for 20MHz, 40MHz and 80MHz
+ * Clear the channel bandwidth for 20MHz
+ * since channel switch could be happening from 40/80MHz to 20MHz
+ */
+ chan_offset = wlan_get_second_channel_offset(new_channel);
+ uap_band_cfg->chan2Offset = chan_offset;
+
+ if (!chan_offset) { /* 40MHz/80MHz */
+ PRINTM(MCMD_D, "20MHz channel, clear channel bandwidth\n");
+ uap_band_cfg->chanWidth = CHAN_BW_20MHZ;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Get priv current index -- this is used to enter correct rdh_state
+ * during radar handling
+ *
+ * @param pmpriv Pointer to mlan_private
+ * @param pstate_rdh Pointer to radar detected state handler
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_get_priv_curr_idx(mlan_private *pmpriv,
+ wlan_radar_det_hndlg_state_t *pstate_rdh)
+{
+ t_bool found = MFALSE;
+ ENTER();
+
+ PRINTM(MINFO, "%s:pmpriv =%p\n", __func__, pmpriv);
+ while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
+ if (pmpriv ==
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx]) {
+ PRINTM(MINFO, "found matching priv: priv_idx=%d\n",
+ pstate_rdh->priv_curr_idx);
+ found = MTRUE;
+ break;
+ }
+ }
+ return (found == MTRUE) ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief Driver handling for remove customeie
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pmpriv Pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status wlan_11h_remove_custom_ie(mlan_adapter *pmadapter,
+ mlan_private *pmpriv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &pmadapter->state_rdh;
+ mlan_ioctl_req *pioctl_req = MNULL;
+
+ ENTER();
+ if (pstate_rdh->stage == RDH_SET_CUSTOM_IE) {
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ PRINTM(MMSG, "Removing CHAN_SW IE from interfaces.\n");
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ if (!wlan_11h_is_dfs_master(pmpriv))
+ continue;
+ ret = wlan_11h_prepare_custom_ie_chansw(
+ pmadapter, &pioctl_req, MFALSE);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
+ PRINTM(MERROR,
+ "%s(): Error in preparing CHAN_SW IE.\n",
+ __func__);
+ goto done;
+ }
+
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(
+ pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS &&
+ ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not remove IE for priv=%p [priv_bss_idx=%d]!\n",
+ __func__, pmpriv, pmpriv->bss_index);
+ /* TODO: hiow to handle this error case??
+ * ignore & continue? */
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pioctl_req);
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Driver handling for RADAR_DETECTED event
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pmpriv Pointer to mlan_private
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status wlan_11h_radar_detected_handling(mlan_adapter *pmadapter,
+ mlan_private *pmpriv)
+{
+#ifdef DEBUG_LEVEL1
+ const char *rdh_stage_str[] = {"RDH_OFF",
+ "RDH_CHK_INTFS",
+ "RDH_STOP_TRAFFIC",
+ "RDH_GET_INFO_CHANNEL",
+ "RDH_GET_INFO_BEACON_DTIM",
+ "RDH_SET_CUSTOM_IE",
+ "RDH_REM_CUSTOM_IE",
+ "RDH_STOP_INTFS",
+ "RDH_SET_NEW_CHANNEL",
+ "RDH_RESTART_INTFS",
+ "RDH_RESTART_TRAFFIC"};
+#endif
+
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 i;
+ wlan_radar_det_hndlg_state_t *pstate_rdh = &pmadapter->state_rdh;
+
+ ENTER();
+
+ if (!pmpriv) {
+ PRINTM(MERROR, "Invalid radar priv -- Exit radar handling\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (pstate_rdh->stage) {
+ case RDH_CHK_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage]);
+
+ /* get active interfaces */
+ memset(pmadapter, pstate_rdh->priv_list, 0x00,
+ sizeof(pstate_rdh->priv_list));
+ pstate_rdh->priv_list_count = wlan_get_privs_by_cond(
+ pmadapter, wlan_is_intf_active, pstate_rdh->priv_list);
+ PRINTM(MCMD_D, "%s(): priv_list_count = %d\n", __func__,
+ pstate_rdh->priv_list_count);
+ for (i = 0; i < pstate_rdh->priv_list_count; i++)
+ PRINTM(MINFO, "%s(): priv_list[%d] = %p\n", __func__,
+ i, pstate_rdh->priv_list[i]);
+
+ if (pstate_rdh->priv_list_count == 0) {
+ /* no interfaces active... nothing to do */
+ PRINTM(MMSG, "11h: Radar Detected - no active priv's,"
+ " skip event handling.\n");
+ pstate_rdh->stage = RDH_OFF;
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
+ __func__, pstate_rdh->stage,
+ rdh_stage_str[pstate_rdh->stage]);
+ break; /* EXIT CASE */
+ }
+
+ /* else: start handling */
+ pstate_rdh->curr_channel = 0;
+ pstate_rdh->new_channel = 0;
+ memset(pmadapter, &(pstate_rdh->uap_band_cfg), 0,
+ sizeof(pstate_rdh->uap_band_cfg));
+ pstate_rdh->max_bcn_dtim_ms = 0;
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_TRAFFIC;
+ /* fall through */
+
+ case RDH_STOP_TRAFFIC:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage]);
+
+ PRINTM(MMSG,
+ "11h: Radar Detected - stopping host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++)
+ wlan_11h_tx_disable(pstate_rdh->priv_list[i]);
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_CHANNEL;
+ /* fall through */
+
+ case RDH_GET_INFO_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* here, prefer STA info over UAP info - one less CMD to send */
+ if (pstate_rdh->priv_curr_idx ==
+ RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_11h_get_priv_curr_idx(pmpriv,
+ pstate_rdh);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Unable to locate pmpriv in current active priv_list\n");
+ break; /* EXIT CASE */
+ }
+
+ /* send cmd to get first UAP's info */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr =
+ MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_channel(pmpriv);
+ break; /* EXIT CASE */
+ } else
+#endif
+ {
+ /* Assume all STAs on same channel, find first
+ * STA */
+ MASSERT(pstate_rdh->priv_list_count > 0);
+ for (i = 0; i < pstate_rdh->priv_list_count;
+ i++) {
+ pmpriv = pstate_rdh->priv_list[i];
+ if (GET_BSS_ROLE(pmpriv) ==
+ MLAN_BSS_ROLE_STA)
+ break;
+ }
+ /* STA info kept in driver, just copy */
+ pstate_rdh->curr_channel =
+ pmpriv->curr_bss_params.bss_descriptor
+ .channel;
+ }
+ }
+#ifdef UAP_SUPPORT
+ else if (pstate_rdh->priv_curr_idx <
+ pstate_rdh->priv_list_count) {
+ /* repeat entry: UAP return with info */
+ pstate_rdh->curr_channel =
+ pmpriv->uap_state_chan_cb.channel;
+ pstate_rdh->uap_band_cfg =
+ pmpriv->uap_state_chan_cb.bandcfg;
+ PRINTM(MCMD_D,
+ "%s(): uap_band_cfg=0x%02x curr_chan=%d, curr_idx=%d bss_role=%d\n",
+ __func__, pstate_rdh->uap_band_cfg,
+ pstate_rdh->curr_channel,
+ pstate_rdh->priv_curr_idx, GET_BSS_ROLE(pmpriv));
+ }
+#endif
+
+ /* add channel to NOP list */
+ wlan_11h_add_dfs_timestamp(pmadapter, DFS_TS_REPR_NOP_START,
+ pstate_rdh->curr_channel);
+
+ /* choose new channel (!= curr channel) and move on */
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ pstate_rdh->new_channel =
+ wlan_11h_get_uap_start_channel(
+ pmpriv,
+ pmpriv->uap_state_chan_cb.bandcfg);
+ else
+#endif
+ pstate_rdh->new_channel =
+ wlan_11h_get_adhoc_start_channel(pmpriv);
+
+ if (!pstate_rdh->new_channel ||
+ (pstate_rdh->new_channel ==
+ pstate_rdh->curr_channel)) { /* report error */
+ PRINTM(MERROR,
+ "%s(): ERROR - Failed to choose new_chan"
+ " (!= curr_chan) !!\n",
+ __func__);
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0,
+ MNULL, MNULL);
+ PRINTM(MERROR,
+ "STOP UAP and exit radar handling...\n");
+ pstate_rdh->stage = RDH_OFF;
+ break; /* leads to exit case */
+ }
+#endif
+ }
+ if (!pmadapter->dfs_test_params.no_channel_change_on_radar &&
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
+ pmadapter->dfs_test_params
+ .fixed_new_channel_on_radar);
+ pstate_rdh->new_channel =
+ pmadapter->dfs_test_params
+ .fixed_new_channel_on_radar;
+ }
+ /* applies to DFS with ECSA support */
+ if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
+ pstate_rdh->new_channel = pstate_rdh->curr_channel;
+ }
+ PRINTM(MCMD_D, "%s(): curr_chan=%d, new_chan=%d\n", __func__,
+ pstate_rdh->curr_channel, pstate_rdh->new_channel);
+
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_GET_INFO_BEACON_DTIM;
+ /* fall through */
+
+ case RDH_GET_INFO_BEACON_DTIM:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+#ifdef UAP_SUPPORT
+ /* check all intfs in this stage to find longest period */
+ /* UAP intf callback returning with info */
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
+ t_u16 bcn_dtim_msec;
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+ PRINTM(MCMD_D, "%s(): uap.bcn_pd=%d, uap.dtim_pd=%d\n",
+ __func__,
+ pmpriv->uap_state_chan_cb.beacon_period,
+ pmpriv->uap_state_chan_cb.dtim_period);
+ bcn_dtim_msec =
+ (pmpriv->uap_state_chan_cb.beacon_period *
+ pmpriv->uap_state_chan_cb.dtim_period);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
+ }
+#endif
+
+ /* check next intf */
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr =
+ MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_11h_radar_detected_callback;
+ ret = wlan_uap_get_beacon_dtim(pmpriv);
+ break; /* leads to exit case */
+ } else
+#endif
+ { /* get STA info from driver and compare here */
+ t_u16 bcn_pd_msec = 100;
+ t_u16 dtim_pd_msec = 1;
+ t_u16 bcn_dtim_msec;
+
+ /* adhoc creator */
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ bcn_pd_msec = pmpriv->beacon_period;
+ } else {
+ bcn_pd_msec = pmpriv->curr_bss_params
+ .bss_descriptor
+ .beacon_period;
+ /* if (priv->bss_mode !=
+ * MLAN_BSS_MODE_IBSS) */
+ /* TODO: mlan_scan.c needs to parse TLV
+ * 0x05 (TIM) for dtim_period */
+ }
+ PRINTM(MCMD_D,
+ "%s(): sta.bcn_pd=%d, sta.dtim_pd=%d\n",
+ __func__, bcn_pd_msec, dtim_pd_msec);
+ bcn_dtim_msec = (bcn_pd_msec * dtim_pd_msec);
+ if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
+ pstate_rdh->max_bcn_dtim_ms =
+ bcn_dtim_msec;
+ }
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
+ break; /* EXIT CASE (for UAP) */
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_CUSTOM_IE;
+ /* fall through */
+
+ case RDH_SET_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* add CHAN_SW IE - Need apply on each interface */
+ if (pstate_rdh->priv_curr_idx ==
+ RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+ PRINTM(MMSG,
+ "11h: Radar Detected - adding CHAN_SW IE to interfaces.\n");
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list
+ [pstate_rdh->priv_curr_idx];
+ if (!wlan_11h_is_dfs_master(pmpriv))
+ continue;
+ ret = wlan_11h_prepare_custom_ie_chansw(
+ pmadapter, &pioctl_req, MTRUE);
+ if ((ret != MLAN_STATUS_SUCCESS) ||
+ !pioctl_req) {
+ PRINTM(MERROR,
+ "%s(): Error in preparing CHAN_SW IE.\n",
+ __func__);
+ break; /* EXIT CASE */
+ }
+
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(
+ pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS &&
+ ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
+ __func__, pmpriv,
+ pmpriv->bss_index);
+ /* TODO: how to handle this error case??
+ * ignore & continue? */
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pioctl_req);
+ }
+ break; /* EXIT CASE */
+ }
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_REM_CUSTOM_IE;
+ /* fall through */
+
+ case RDH_REM_CUSTOM_IE:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* remove CHAN_SW IE - Need apply on each interface */
+ if (pstate_rdh->priv_curr_idx ==
+ RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+ /*
+ * first entry to this stage, do delay
+ * DFS requires a minimum of 5 chances for clients to
+ * hear this IE. Use delay: 5 beacons <=
+ * (BCN_DTIM_MSEC*5) <= 3 seconds).
+ */
+ t_u16 delay_ms =
+ MAX(MIN_RDH_CHAN_SW_IE_PERIOD_MSEC,
+ MIN((4 * pstate_rdh->max_bcn_dtim_ms),
+ MAX_RDH_CHAN_SW_IE_PERIOD_MSEC));
+ PRINTM(MMSG,
+ "11h: Radar Detected - delay %d ms for FW to"
+ " broadcast CHAN_SW IE.\n",
+ delay_ms);
+ wlan_mdelay(pmadapter, delay_ms);
+ PRINTM(MMSG,
+ "11h: Radar Detected - delay over, removing"
+ " CHAN_SW IE from interfaces.\n");
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list
+ [pstate_rdh->priv_curr_idx];
+ if (!wlan_11h_is_dfs_master(pmpriv))
+ continue;
+ ret = wlan_11h_prepare_custom_ie_chansw(
+ pmadapter, &pioctl_req, MFALSE);
+ if ((ret != MLAN_STATUS_SUCCESS) ||
+ !pioctl_req) {
+ PRINTM(MERROR,
+ "%s(): Error in preparing CHAN_SW IE.\n",
+ __func__);
+ break; /* EXIT CASE */
+ }
+
+ pioctl_req->bss_index = pmpriv->bss_index;
+ ret = wlan_misc_ioctl_custom_ie_list(
+ pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS &&
+ ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not remove IE for priv=%p [priv_bss_idx=%d]!\n",
+ __func__, pmpriv,
+ pmpriv->bss_index);
+ /* TODO: hiow to handle this error
+ * case?? ignore & continue? */
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pioctl_req);
+ }
+ break; /* EXIT CASE */
+ }
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_STOP_INTFS;
+ /* fall through */
+
+ case RDH_STOP_INTFS:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* issues one cmd (DEAUTH/ADHOC_STOP/BSS_STOP) to each intf */
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0,
+ MNULL, MNULL);
+ break; /* leads to exit case */
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* Save ad-hoc creator state before stop
+ * clears it */
+ pmpriv->adhoc_state_prev =
+ pmpriv->adhoc_state;
+ }
+ if (pmpriv->media_connected == MTRUE) {
+ wlan_disconnect(pmpriv, MNULL, MNULL);
+ break; /* leads to exit case */
+ }
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
+ ret == MLAN_STATUS_FAILURE)
+ break; /* EXIT CASE */
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_SET_NEW_CHANNEL;
+
+ if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
+ PRINTM(MCMD_D,
+ "dfs_testing - no channel change on radar."
+ " Overwrite new_chan = curr_chan.\n");
+ pstate_rdh->new_channel = pstate_rdh->curr_channel;
+ pstate_rdh->priv_curr_idx =
+ RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_INTFS;
+ goto rdh_restart_intfs; /* skip next stage */
+ }
+ /* fall through */
+
+ case RDH_SET_NEW_CHANNEL:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* only set new channel for UAP intfs */
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ pmpriv->uap_state_chan_cb.pioctl_req_curr =
+ MNULL;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_11h_radar_detected_callback;
+
+ /* DFS only in 5GHz */
+ wlan_11h_update_bandcfg(
+ &pstate_rdh->uap_band_cfg,
+ pstate_rdh->new_channel);
+ PRINTM(MCMD_D,
+ "RDH_SET_NEW_CHANNEL: uAP band config = 0x%x channel=%d\n",
+ pstate_rdh->uap_band_cfg,
+ pstate_rdh->new_channel);
+
+ ret = wlan_uap_set_channel(
+ pmpriv, pstate_rdh->uap_band_cfg,
+ pstate_rdh->new_channel);
+ break; /* leads to exit case */
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
+ ret == MLAN_STATUS_FAILURE)
+ break; /* EXIT CASE (for UAP) */
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_INTFS;
+ /* fall through */
+
+ case RDH_RESTART_INTFS:
+ rdh_restart_intfs:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage],
+ pstate_rdh->priv_curr_idx);
+
+ /* can only restart master intfs */
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv =
+ pstate_rdh->priv_list[pstate_rdh->priv_curr_idx];
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ if (wlan_11h_radar_detect_required(
+ pmpriv, pstate_rdh->new_channel)) {
+ /* Radar detection is required for this
+ channel, make sure 11h is activated
+ in the firmware */
+ ret = wlan_11h_activate(pmpriv, MNULL,
+ MTRUE);
+ ret = wlan_11h_config_master_radar_det(
+ pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(
+ pmpriv);
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0,
+ MNULL, MNULL);
+ break; /* leads to exit case */
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ /* Check previous state to find former
+ * Ad-hoc creator interface. Set new
+ * state to Starting, so it'll be seen
+ * as a DFS master. */
+ if (pmpriv->adhoc_state_prev == ADHOC_STARTED) {
+ pmpriv->adhoc_state = ADHOC_STARTING;
+ pmpriv->adhoc_state_prev = ADHOC_IDLE;
+ }
+ if (wlan_11h_is_dfs_master(pmpriv)) {
+ /* set new adhoc channel here */
+ pmpriv->adhoc_channel =
+ pstate_rdh->new_channel;
+ if (wlan_11h_radar_detect_required(
+ pmpriv,
+ pstate_rdh->new_channel)) {
+ /* Radar detection is required
+ for this channel, make sure
+ 11h is activated in the
+ firmware */
+ ret = wlan_11h_activate(
+ pmpriv, MNULL, MTRUE);
+ if (ret)
+ break;
+ ret = wlan_11h_config_master_radar_det(
+ pmpriv, MTRUE);
+ if (ret)
+ break;
+ ret = wlan_11h_check_update_radar_det_state(
+ pmpriv);
+ if (ret)
+ break;
+ }
+ ret = wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->adhoc_last_start_ssid);
+ break; /* leads to exit case */
+ }
+
+ /* NOTE: DON'T reconnect slave STA intfs -
+ * infra/adhoc_joiner Do we want to return to
+ * same AP/network (on radar channel)? If want
+ * to connect back, depend on either:
+ * 1. driver's reassoc thread
+ * 2. wpa_supplicant, or other user-space
+ * app
+ */
+ }
+#endif
+ }
+
+ if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
+ ret == MLAN_STATUS_FAILURE)
+ break; /* EXIT CASE (for UAP) */
+ /* else */
+ pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ pstate_rdh->stage = RDH_RESTART_TRAFFIC;
+ /* fall through */
+
+ case RDH_RESTART_TRAFFIC:
+ PRINTM(MCMD_D, "%s(): stage(%d)=%s\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage]);
+ /* remove custome ie */
+ if (pmadapter->ecsa_enable) {
+ mlan_ioctl_req *pioctl_req = MNULL;
+ pstate_rdh->priv_curr_idx =
+ RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
+ while ((++pstate_rdh->priv_curr_idx) <
+ pstate_rdh->priv_list_count) {
+ pmpriv = pstate_rdh->priv_list
+ [pstate_rdh->priv_curr_idx];
+ if (!wlan_11h_is_dfs_master(pmpriv))
+ continue;
+ ret = wlan_11h_prepare_custom_ie_chansw(
+ pmadapter, &pioctl_req, MFALSE);
+ if ((ret != MLAN_STATUS_SUCCESS) ||
+ !pioctl_req) {
+ PRINTM(MERROR,
+ "%s(): Error in preparing CHAN_SW IE.\n",
+ __func__);
+ break; /* EXIT CASE */
+ }
+
+ pioctl_req->bss_index = pmpriv->bss_index;
+
+ ret = wlan_misc_ioctl_custom_ie_list(
+ pmadapter, pioctl_req, MFALSE);
+ if (ret != MLAN_STATUS_SUCCESS &&
+ ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not remove IE for priv=%p [priv_bss_idx=%d]!\n",
+ __func__, pmpriv,
+ pmpriv->bss_index);
+ /* TODO: hiow to handle this error
+ * case?? ignore & continue? */
+ }
+ /* free ioctl buffer memory before we leave */
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pioctl_req);
+ }
+ }
+ /* continue traffic for reactivated interfaces */
+ PRINTM(MMSG,
+ "11h: Radar Detected - restarting host tx traffic.\n");
+ for (i = 0; i < pstate_rdh->priv_list_count; i++)
+ wlan_11h_tx_enable(pstate_rdh->priv_list[i]);
+
+ pstate_rdh->stage = RDH_OFF; /* DONE! */
+ PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n", __func__,
+ pstate_rdh->stage, rdh_stage_str[pstate_rdh->stage]);
+
+ break;
+
+ default:
+ pstate_rdh->stage = RDH_OFF; /* cancel RDH to unblock Tx packets
+ */
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief DFS Event Preprocessing.
+ * Operates directly on pmadapter variables.
+ *
+ * 1. EVENT_RADAR_DETECTED comes from firmware without specific
+ * bss_num/bss_type. Find it an appropriate interface and
+ * update event_cause field in event_buf.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS (update successful)
+ * or MLAN_STATUS_FAILURE (no change)
+ */
+mlan_status wlan_11h_dfs_event_preprocessing(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = MNULL;
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM] = {0};
+
+ ENTER();
+ switch (pmadapter->event_cause & EVENT_ID_MASK) {
+ case EVENT_RADAR_DETECTED:
+ /* find active intf: prefer dfs_master over dfs_slave */
+ if (wlan_get_privs_by_two_cond(
+ pmadapter, wlan_11h_is_master_active_on_dfs_chan,
+ wlan_11h_is_dfs_master, MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_master priv=%p\n",
+ __func__, pmpriv);
+ } else if (wlan_get_privs_by_two_cond(
+ pmadapter,
+ wlan_11h_is_slave_active_on_dfs_chan,
+ wlan_11h_is_dfs_slave, MTRUE, priv_list)) {
+ pmpriv = priv_list[0];
+ PRINTM(MINFO, "%s: found dfs_slave priv=%p\n", __func__,
+ pmpriv);
+ } else if (pmadapter->state_dfs.dfs_check_pending) {
+ pmpriv = (mlan_private *)(pmadapter->state_dfs
+ .dfs_check_priv);
+ PRINTM(MINFO, "%s: found dfs priv=%p\n", __func__,
+ pmpriv);
+ }
+
+ /* update event_cause if we found an appropriate priv */
+ if (pmpriv) {
+ pmlan_buffer pmevbuf = pmadapter->pmlan_buffer_event;
+ t_u32 new_event_cause =
+ pmadapter->event_cause & EVENT_ID_MASK;
+ new_event_cause |=
+ ((GET_BSS_NUM(pmpriv) & 0xff) << 16) |
+ ((pmpriv->bss_type & 0xff) << 24);
+ PRINTM(MINFO, "%s: priv - bss_num=%d, bss_type=%d\n",
+ __func__, GET_BSS_NUM(pmpriv), pmpriv->bss_type);
+ memcpy_ext(pmadapter,
+ pmevbuf->pbuf + pmevbuf->data_offset,
+ &new_event_cause, sizeof(new_event_cause),
+ sizeof(new_event_cause));
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR,
+ "Failed to find dfs master/slave priv\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief try to switch to a non-dfs channel
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @param chan pointer to channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
+ */
+mlan_status wlan_11h_switch_non_dfs_chan(mlan_private *priv, t_u8 *chan)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u32 i;
+ t_u32 rand_entry;
+ t_u8 def_chan;
+ t_u8 rand_tries = 0;
+ region_chan_t *chn_tbl = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!pmadapter->dfs_test_params.no_channel_change_on_radar &&
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
+ PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
+ pmadapter->dfs_test_params.fixed_new_channel_on_radar);
+ *chan = pmadapter->dfs_test_params.fixed_new_channel_on_radar;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /*get the channel table first*/
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (pmadapter->region_channel[i].band == BAND_A &&
+ pmadapter->region_channel[i].valid) {
+ chn_tbl = &pmadapter->region_channel[i];
+ break;
+ }
+ }
+
+ if (!chn_tbl || !chn_tbl->pcfp)
+ goto done;
+
+ do {
+ rand_entry =
+ wlan_11h_get_random_num(pmadapter) % chn_tbl->num_cfp;
+ def_chan = (t_u8)chn_tbl->pcfp[rand_entry].channel;
+ rand_tries++;
+ } while ((wlan_11h_is_channel_under_nop(pmadapter, def_chan) ||
+ chn_tbl->pcfp[rand_entry].passive_scan_or_radar_detect ==
+ MTRUE) &&
+ (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
+
+ /* meet max retries, use the lowest non-dfs channel */
+ if (rand_tries == MAX_SWITCH_CHANNEL_RETRIES) {
+ for (i = 0; i < chn_tbl->num_cfp; i++) {
+ if (chn_tbl->pcfp[i].passive_scan_or_radar_detect ==
+ MFALSE &&
+ !wlan_11h_is_channel_under_nop(
+ pmadapter,
+ (t_u8)chn_tbl->pcfp[i].channel)) {
+ def_chan = (t_u8)chn_tbl->pcfp[i].channel;
+ break;
+ }
+ }
+ if (i == chn_tbl->num_cfp)
+ goto done;
+ }
+
+ *chan = def_chan;
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set dfs check channel
+ *
+ * @param priv Void pointer to mlan_private
+ *
+ * @param chan pointer to channel
+ *
+ * @return N/A
+ */
+void wlan_11h_set_dfs_check_chan(mlan_private *priv, t_u8 chan)
+{
+ wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
+ ENTER();
+ pstate_dfs->dfs_check_channel = chan;
+ PRINTM(MCMND, "Set dfs_check_channel=%d\n", chan);
+ LEAVE();
+}
+
+/**
+ * @brief 802.11h DFS W53 configuration
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_11h_ioctl_dfs_w53_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ mlan_ds_11h_dfs_w53_cfg *dfs_w53_cfg = MNULL;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ dfs_w53_cfg = &ds_11hcfg->param.dfs_w53_cfg;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ dfs_w53_cfg->dfs53cfg = pmadapter->dfs53cfg;
+ } else {
+ pmadapter->dfs53cfg = dfs_w53_cfg->dfs53cfg;
+ }
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.h
new file mode 100644
index 000000000000..05766a99bb35
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11h.h
@@ -0,0 +1,201 @@
+/** @file mlan_11h.h
+ *
+ * @brief This header file contains data structures and
+ * function declarations of 802.11h
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/26/2009: initial creation
+*************************************************************/
+
+#ifndef _MLAN_11H_
+#define _MLAN_11H_
+
+/** 11H OID bitmasks */
+#define ENABLE_11H_MASK MBIT(0)
+#define MASTER_RADAR_DET_MASK MBIT(1)
+#define SLAVE_RADAR_DET_MASK MBIT(2)
+
+/** DFS Master Radar Detect global enable */
+#define DFS_MASTER_RADAR_DETECT_EN (MTRUE)
+/** DFS Slave Radar Detect global enable */
+#define DFS_SLAVE_RADAR_DETECT_EN (MFALSE)
+
+#define CHANNEL_OFFSET_MASK 0x30
+#define CHANNEL_BANDWIDTH_MASK 0x0C
+
+/**
+ * 11H APIs
+ */
+
+/* Is master radar detection enabled in firmware? */
+extern t_bool wlan_11h_is_master_radar_det_active(mlan_private *priv);
+
+/** Configure master radar detection.
+ * Need call wlan_11h_check_update_radar_det_state() after.
+ */
+extern mlan_status wlan_11h_config_master_radar_det(mlan_private *priv,
+ t_bool enable);
+
+/** Configure slave radar detection.
+ * Need call wlan_11h_check_update_radar_det_state() after.
+ */
+extern mlan_status wlan_11h_config_slave_radar_det(mlan_private *priv,
+ t_bool enable);
+
+/** Checks all interfaces and updates radar detect flags if necessary */
+extern mlan_status wlan_11h_check_update_radar_det_state(mlan_private *pmpriv);
+
+/** Return 1 if 11h is active in the firmware, 0 if it is inactive */
+extern t_bool wlan_11h_is_active(mlan_private *priv);
+
+/** Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_enable(mlan_private *priv);
+
+/** Disable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_disable(mlan_private *priv);
+
+/** Activate 11h extensions in the firmware */
+extern mlan_status wlan_11h_activate(mlan_private *priv, t_void *pioctl_buf,
+ t_bool flag);
+
+/** Initialize the 11h device structure */
+extern void wlan_11h_init(mlan_adapter *pmadapter);
+
+/** Cleanup for the 11h device structure */
+extern void wlan_11h_cleanup(mlan_adapter *pmadapter);
+
+/** Initialize the 11h interface structure */
+extern void wlan_11h_priv_init(mlan_private *pmpriv);
+
+/** Get an initial random channel to start an adhoc network on */
+extern t_u8 wlan_11h_get_adhoc_start_channel(mlan_private *priv);
+
+/** Get channel that has been closed via Channel Switch Announcement */
+extern t_u8 wlan_11h_get_csa_closed_channel(mlan_private *priv);
+
+/** Check if radar detection is required on the specified channel */
+extern t_bool wlan_11h_radar_detect_required(mlan_private *priv, t_u8 channel);
+
+/** Perform a standard availibility check on the specified channel */
+extern t_s32 wlan_11h_issue_radar_detect(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req,
+ t_u8 channel, Band_Config_t bandcfg);
+
+/** Check previously issued radar report for a channel */
+extern mlan_status wlan_11h_check_chan_report(mlan_private *priv, t_u8 chan);
+
+/** Add any 11h TLVs necessary to complete an adhoc start command */
+extern t_s32 wlan_11h_process_start(mlan_private *priv, t_u8 **ppbuffer,
+ IEEEtypes_CapInfo_t *pcap_info,
+ t_u32 channel,
+ wlan_11h_bss_info_t *p11h_bss_info);
+
+/** Add any 11h TLVs necessary to complete a join command (adhoc or infra) */
+extern t_s32 wlan_11h_process_join(mlan_private *priv, t_u8 **ppbuffer,
+ IEEEtypes_CapInfo_t *pcap_info, t_u8 band,
+ t_u32 channel,
+ wlan_11h_bss_info_t *p11h_bss_info);
+
+/** Complete the firmware command preparation for an 11h command function */
+extern mlan_status wlan_11h_cmd_process(mlan_private *priv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf);
+
+/** Process the response of an 11h firmware command */
+extern mlan_status wlan_11h_cmdresp_process(mlan_private *priv,
+ const HostCmd_DS_COMMAND *resp);
+
+/** Receive IEs from scan processing and record any needed info for 11h */
+extern mlan_status wlan_11h_process_bss_elem(mlan_adapter *pmadapter,
+ wlan_11h_bss_info_t *p11h_bss_info,
+ const t_u8 *pelement);
+
+/** Handler for EVENT_CHANNEL_SWITCH_ANN */
+extern mlan_status wlan_11h_handle_event_chanswann(mlan_private *priv);
+
+/** Handler for EVENT_CHANNEL_REPORT_RDY */
+extern mlan_status wlan_11h_handle_event_chanrpt_ready(mlan_private *priv,
+ mlan_event *pevent,
+ t_u8 *radar_chan);
+
+/** Debug output for EVENT_RADAR_DETECTED */
+mlan_status wlan_11h_print_event_radar_detected(mlan_private *priv,
+ mlan_event *pevent,
+ t_u8 *radar_chan);
+
+t_s32 wlan_11h_cancel_radar_detect(mlan_private *priv);
+/** Handler for DFS_TESTING IOCTL */
+extern mlan_status wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+extern mlan_status
+wlan_11h_ioctl_get_channel_nop_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+extern mlan_status wlan_11h_ioctl_dfs_chan_report(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req);
+extern mlan_status wlan_11h_ioctl_chan_switch_count(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** get/set dfs w53 cfg */
+mlan_status wlan_11h_ioctl_dfs_w53_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** Check if channel is under a NOP duration (should not be used) */
+extern t_bool wlan_11h_is_channel_under_nop(mlan_adapter *pmadapter,
+ t_u8 channel);
+
+/** Check if RADAR_DETECTED handling is blocking data tx */
+extern t_bool wlan_11h_radar_detected_tx_blocked(mlan_adapter *pmadapter);
+
+/** Callback for RADAR_DETECTED (for UAP cmdresp) */
+extern mlan_status wlan_11h_radar_detected_callback(t_void *priv);
+/** set dfs check channel */
+void wlan_11h_set_dfs_check_chan(mlan_private *priv, t_u8 chan);
+
+#ifdef UAP_SUPPORT
+/** BW_change event Handler for dfs_repeater */
+void wlan_dfs_rep_bw_change(mlan_adapter *pmadapter);
+
+/** disconnect event Handler for dfs_repeater */
+void wlan_dfs_rep_disconnect(mlan_adapter *pmadapter);
+#endif
+
+/** Handler for RADAR_DETECTED */
+extern mlan_status wlan_11h_radar_detected_handling(mlan_adapter *pmadapter,
+ mlan_private *priv);
+
+mlan_status wlan_11h_remove_custom_ie(mlan_adapter *pmadapter,
+ mlan_private *pmpriv);
+
+/** DFS Event pre-processing */
+extern mlan_status wlan_11h_dfs_event_preprocessing(mlan_adapter *pmadapter);
+
+/** DFS switch to non-DFS channel */
+extern mlan_status wlan_11h_switch_non_dfs_chan(mlan_private *priv, t_u8 *chan);
+
+extern void wlan_11h_update_bandcfg(Band_Config_t *uap_band_cfg,
+ t_u8 new_channel);
+
+/** function checks if interface is active. **/
+extern t_bool wlan_is_intf_active(mlan_private *pmpriv);
+
+#endif /*_MLAN_11H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.c
new file mode 100644
index 000000000000..6be3969ea5ca
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.c
@@ -0,0 +1,3092 @@
+/** @file mlan_11n.c
+ *
+ * @brief This file contains functions for 11n handling.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ *
+ * @brief set/get max tx buf size
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise
+ * fail
+ */
+static mlan_status wlan_11n_ioctl_max_tx_buf_size(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ cfg->param.tx_buf_size = (t_u32)pmadapter->max_tx_buf_size;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get htcapinfo configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise
+ * fail
+ */
+static mlan_status wlan_11n_ioctl_htusrcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (((cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP) &
+ pmpriv->adapter->hw_dot_11n_dev_cap) !=
+ (cfg->param.htcap_cfg.htcap & ~IGN_HW_DEV_CAP)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ pmpriv->usr_dot_11n_dev_cap_bg =
+ cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO,
+ "Set: UsrDot11nCap for 2.4GHz 0x%x\n",
+ pmpriv->usr_dot_11n_dev_cap_bg);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ pmpriv->usr_dot_11n_dev_cap_a =
+ cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO,
+ "Set: UsrDot11nCap for 5GHz 0x%x\n",
+ pmpriv->usr_dot_11n_dev_cap_a);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BOTH) {
+ pmpriv->usr_dot_11n_dev_cap_bg =
+ cfg->param.htcap_cfg.htcap;
+ pmpriv->usr_dot_11n_dev_cap_a =
+ cfg->param.htcap_cfg.htcap;
+ PRINTM(MINFO,
+ "Set: UsrDot11nCap for 2.4GHz and 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ } else {
+ /* Hardware 11N device capability required */
+ if (cfg->param.htcap_cfg.hw_cap_req)
+ cfg->param.htcap_cfg.htcap =
+ pmadapter->hw_dot_11n_dev_cap;
+ else {
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_BG) {
+ cfg->param.htcap_cfg.htcap =
+ pmpriv->usr_dot_11n_dev_cap_bg;
+ PRINTM(MINFO,
+ "Get: UsrDot11nCap for 2.4GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ if (cfg->param.htcap_cfg.misc_cfg == BAND_SELECT_A) {
+ cfg->param.htcap_cfg.htcap =
+ pmpriv->usr_dot_11n_dev_cap_a;
+ PRINTM(MINFO,
+ "Get: UsrDot11nCap for 5GHz 0x%x\n",
+ cfg->param.htcap_cfg.htcap);
+ }
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable AMSDU AGGR CTRL
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_amsdu_aggr_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AMSDU_AGGR_CTRL, cmd_action,
+ 0, (t_void *)pioctl_req,
+ (t_void *)&cfg->param.amsdu_aggr_ctrl);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get 11n configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_httxcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.tx_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming capabilities
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_11n_ioctl_tx_bf_cap(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ pmpriv->tx_bf_cap = cfg->param.tx_bf_cap;
+ else
+ cfg->param.tx_bf_cap = pmpriv->tx_bf_cap;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get TX beamforming configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_tx_bf_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_BF_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.tx_bf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_stream_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.stream_cfg = pmpriv->usr_dev_mcs_support;
+ } else if (pioctl_req->action == MLAN_ACT_SET) {
+ switch (cfg->param.stream_cfg) {
+ case HT_STREAM_MODE_2X2:
+ if (pmadapter->hw_dev_mcs_support ==
+ HT_STREAM_MODE_1X1) {
+ PRINTM(MERROR,
+ "HW does not support this mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else
+ pmpriv->usr_dev_mcs_support =
+ cfg->param.stream_cfg;
+ break;
+ case HT_STREAM_MODE_1X1:
+ pmpriv->usr_dev_mcs_support = cfg->param.stream_cfg;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid stream mode\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get control to coex RX window size configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_coex_rx_winsize(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cfg->param.coex_rx_winsize = pmadapter->coex_rx_winsize;
+ else if (pioctl_req->action == MLAN_ACT_SET)
+ pmadapter->coex_rx_winsize = (t_u8)cfg->param.coex_rx_winsize;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will resend addba request to all
+ * the peer in the TxBAStreamTbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+static void wlan_11n_update_addba_request(mlan_private *priv)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptx_tbl) {
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ wlan_send_addba(priv, ptx_tbl->tid, ptx_tbl->ra);
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ wlan_release_ralist_lock(priv);
+ /* Signal MOAL to trigger mlan_main_process */
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set/get addba parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_11n_ioctl_addba_param(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u32 timeout;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfg->param.addba_param.timeout = pmpriv->add_ba_param.timeout;
+ cfg->param.addba_param.txwinsize =
+ pmpriv->add_ba_param.tx_win_size;
+ cfg->param.addba_param.rxwinsize =
+ pmpriv->add_ba_param.rx_win_size;
+ cfg->param.addba_param.txamsdu = pmpriv->add_ba_param.tx_amsdu;
+ cfg->param.addba_param.rxamsdu = pmpriv->add_ba_param.rx_amsdu;
+ } else {
+ timeout = pmpriv->add_ba_param.timeout;
+ pmpriv->add_ba_param.timeout = cfg->param.addba_param.timeout;
+ pmpriv->add_ba_param.tx_win_size =
+ cfg->param.addba_param.txwinsize;
+
+ pmpriv->add_ba_param.rx_win_size =
+ cfg->param.addba_param.rxwinsize;
+ pmpriv->user_rxwinsize = pmpriv->add_ba_param.rx_win_size;
+ pmpriv->add_ba_param.tx_amsdu = cfg->param.addba_param.txamsdu;
+ pmpriv->add_ba_param.rx_amsdu = cfg->param.addba_param.rxamsdu;
+ if (timeout != pmpriv->add_ba_param.timeout)
+ wlan_11n_update_addba_request(pmpriv);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function send delba to specific tid
+ *
+ * @param priv A pointer to mlan_priv
+ * @param tid tid
+ * @return N/A
+ */
+void wlan_11n_delba(mlan_private *priv, int tid)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->tid == tid) {
+ PRINTM(MIOCTL, "Send delba to tid=%d, " MACSTR "\n",
+ tid, MAC2STR(rx_reor_tbl_ptr->ta));
+ wlan_send_delba(priv, MNULL, tid, rx_reor_tbl_ptr->ta,
+ 0);
+ LEAVE();
+ return;
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set/get addba reject set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_addba_reject(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MINFO, "Get Addba reject\n");
+ memcpy_ext(pmadapter, cfg->param.addba_reject,
+ pmpriv->addba_reject, MAX_NUM_TID, MAX_NUM_TID);
+ } else {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if (cfg->param.addba_reject[i] >
+ ADDBA_RSP_STATUS_REJECT) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->addba_reject[i] = cfg->param.addba_reject[i];
+ }
+ if (pmpriv->media_connected == MTRUE) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (cfg->param.addba_reject[i] ==
+ ADDBA_RSP_STATUS_REJECT) {
+ PRINTM(MIOCTL,
+ "Receive addba reject: tid=%d\n",
+ i);
+ wlan_11n_delba(pmpriv, i);
+ }
+ }
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get ibss ampdu param
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_ibss_ampdu_param(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MINFO, "Get IBSS AMPDU param\n");
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg->param.ibss_ampdu.ampdu[i] = pmpriv->ibss_ampdu[i];
+ cfg->param.ibss_ampdu.addba_reject[i] =
+ pmpriv->ibss_addba_reject[i];
+ }
+ } else {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU RX*/
+ if (cfg->param.ibss_ampdu.addba_reject[i] >
+ ADDBA_RSP_STATUS_REJECT) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ pmpriv->ibss_addba_reject[i] =
+ cfg->param.ibss_ampdu.addba_reject[i];
+ /* For AMPDU TX*/
+ if ((cfg->param.ibss_ampdu.ampdu[i] > HIGH_PRIO_TID) &&
+ (cfg->param.ibss_ampdu.ampdu[i] !=
+ BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ pmpriv->ibss_ampdu[i] = cfg->param.ibss_ampdu.ampdu[i];
+ }
+ PRINTM(MMSG, "IBSS addba reject: %d %d %d %d %d %d %d %d\n",
+ pmpriv->ibss_addba_reject[0],
+ pmpriv->ibss_addba_reject[1],
+ pmpriv->ibss_addba_reject[2],
+ pmpriv->ibss_addba_reject[3],
+ pmpriv->ibss_addba_reject[4],
+ pmpriv->ibss_addba_reject[5],
+ pmpriv->ibss_addba_reject[6],
+ pmpriv->ibss_addba_reject[7]);
+ PRINTM(MMSG, "IBSS ampdu %d %d %d %d %d %d %d %d\n",
+ pmpriv->ibss_ampdu[0], pmpriv->ibss_ampdu[1],
+ pmpriv->ibss_ampdu[2], pmpriv->ibss_ampdu[3],
+ pmpriv->ibss_ampdu[4], pmpriv->ibss_ampdu[5],
+ pmpriv->ibss_ampdu[6], pmpriv->ibss_ampdu[7]);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Minimum BA Threshold
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status
+wlan_11n_ioctl_min_ba_threshold_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+ ENTER();
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cfg->param.min_ba_threshold = pmadapter->min_ba_threshold;
+ else
+ pmadapter->min_ba_threshold = cfg->param.min_ba_threshold;
+ pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will send DELBA to entries in the priv's
+ * Tx BA stream table
+ *
+ * @param priv A pointer to mlan_private
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param tid TID
+ * @param peer_address A pointer to peer address
+ * @param last_tx_ba_to_delete A pointer to the last entry in TxBAStreamTbl
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
+ */
+static mlan_status wlan_send_delba_to_entry_in_txbastream_tbl(
+ pmlan_private priv, pmlan_ioctl_req pioctl_req, t_u8 tid,
+ t_u8 *peer_address, TxBAStreamTbl *last_tx_ba_to_delete)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ TxBAStreamTbl *tx_ba_stream_tbl_ptr;
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ tx_ba_stream_tbl_ptr =
+ (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!tx_ba_stream_tbl_ptr) {
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return ret;
+ }
+
+ while (tx_ba_stream_tbl_ptr !=
+ (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ if (tx_ba_stream_tbl_ptr->ba_status ==
+ BA_STREAM_SETUP_COMPLETE) {
+ if (((tid == DELBA_ALL_TIDS) ||
+ (tid == tx_ba_stream_tbl_ptr->tid)) &&
+ (!memcmp(pmadapter, peer_address, zero_mac,
+ MLAN_MAC_ADDR_LENGTH) ||
+ !memcmp(pmadapter, peer_address,
+ tx_ba_stream_tbl_ptr->ra,
+ MLAN_MAC_ADDR_LENGTH))) {
+ if (last_tx_ba_to_delete &&
+ (tx_ba_stream_tbl_ptr ==
+ last_tx_ba_to_delete))
+ ret = wlan_send_delba(
+ priv, pioctl_req,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ else
+ ret = wlan_send_delba(
+ priv, MNULL,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ }
+ }
+ tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
+ }
+ wlan_release_ralist_lock(priv);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will send DELBA to entries in the priv's
+ * rx reordering table
+ *
+ * @param priv A pointer to mlan_private
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param tid TID
+ * @param peer_address A pointer to peer address
+ * @param last_rx_ba_to_delete A pointer to the last entry in RxReorderTbl
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
+ */
+static mlan_status wlan_send_delba_to_entry_in_reorder_tbl(
+ pmlan_private priv, pmlan_ioctl_req pioctl_req, t_u8 tid,
+ t_u8 *peer_address, RxReorderTbl *last_rx_ba_to_delete)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ RxReorderTbl *rx_reor_tbl_ptr;
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ pmadapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return ret;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->ba_status == BA_STREAM_SETUP_COMPLETE) {
+ if (((tid == DELBA_ALL_TIDS) ||
+ (tid == rx_reor_tbl_ptr->tid)) &&
+ (!memcmp(pmadapter, peer_address, zero_mac,
+ MLAN_MAC_ADDR_LENGTH) ||
+ !memcmp(pmadapter, peer_address,
+ rx_reor_tbl_ptr->ta,
+ MLAN_MAC_ADDR_LENGTH))) {
+ if (last_rx_ba_to_delete &&
+ (rx_reor_tbl_ptr == last_rx_ba_to_delete))
+ ret = wlan_send_delba(
+ priv, pioctl_req,
+ rx_reor_tbl_ptr->tid,
+ rx_reor_tbl_ptr->ta, 0);
+ else
+ ret = wlan_send_delba(
+ priv, MNULL,
+ rx_reor_tbl_ptr->tid,
+ rx_reor_tbl_ptr->ta, 0);
+ }
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief IOCTL to delete BA
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_delba(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ TxBAStreamTbl *tx_ba_stream_tbl_ptr, *last_tx_ba_to_delete = MNULL;
+ RxReorderTbl *rx_reor_tbl_ptr, *last_rx_ba_to_delete = MNULL;
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
+ t_u8 tid, *peer_address;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ tid = cfg->param.del_ba.tid;
+ peer_address = cfg->param.del_ba.peer_mac_addr;
+
+ PRINTM(MINFO, "DelBA: direction %d, TID %d, peer address " MACSTR "\n",
+ cfg->param.del_ba.direction, tid, MAC2STR(peer_address));
+
+ if (cfg->param.del_ba.direction & DELBA_RX) {
+ rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ pmadapter->pmoal_handle, &pmpriv->rx_reorder_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ if (rx_reor_tbl_ptr) {
+ while (rx_reor_tbl_ptr !=
+ (RxReorderTbl *)&pmpriv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->ba_status ==
+ BA_STREAM_SETUP_COMPLETE) {
+ if (((tid == DELBA_ALL_TIDS) ||
+ (tid == rx_reor_tbl_ptr->tid)) &&
+ (!memcmp(pmadapter, peer_address,
+ zero_mac,
+ MLAN_MAC_ADDR_LENGTH) ||
+ !memcmp(pmadapter, peer_address,
+ rx_reor_tbl_ptr->ta,
+ MLAN_MAC_ADDR_LENGTH))) {
+ /* Found RX BA to delete */
+ last_rx_ba_to_delete =
+ rx_reor_tbl_ptr;
+ }
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+ }
+ }
+
+ if ((last_rx_ba_to_delete == MNULL) &&
+ (cfg->param.del_ba.direction & DELBA_TX)) {
+ wlan_request_ralist_lock(pmpriv);
+ tx_ba_stream_tbl_ptr = (TxBAStreamTbl *)util_peek_list(
+ pmadapter->pmoal_handle, &pmpriv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+
+ if (tx_ba_stream_tbl_ptr) {
+ while (tx_ba_stream_tbl_ptr !=
+ (TxBAStreamTbl *)&pmpriv->tx_ba_stream_tbl_ptr) {
+ if (tx_ba_stream_tbl_ptr->ba_status ==
+ BA_STREAM_SETUP_COMPLETE) {
+ if (((tid == DELBA_ALL_TIDS) ||
+ (tid ==
+ tx_ba_stream_tbl_ptr->tid)) &&
+ (!memcmp(pmadapter, peer_address,
+ zero_mac,
+ MLAN_MAC_ADDR_LENGTH) ||
+ !memcmp(pmadapter, peer_address,
+ tx_ba_stream_tbl_ptr->ra,
+ MLAN_MAC_ADDR_LENGTH))) {
+ /* Found TX BA to delete */
+ last_tx_ba_to_delete =
+ tx_ba_stream_tbl_ptr;
+ }
+ }
+ tx_ba_stream_tbl_ptr =
+ tx_ba_stream_tbl_ptr->pnext;
+ }
+ }
+ wlan_release_ralist_lock(pmpriv);
+ }
+
+ if (cfg->param.del_ba.direction & DELBA_TX) {
+ if (last_rx_ba_to_delete)
+ ret = wlan_send_delba_to_entry_in_txbastream_tbl(
+ pmpriv, MNULL, tid, peer_address, MNULL);
+ else
+ ret = wlan_send_delba_to_entry_in_txbastream_tbl(
+ pmpriv, pioctl_req, tid, peer_address,
+ last_tx_ba_to_delete);
+ }
+ if (last_rx_ba_to_delete) {
+ ret = wlan_send_delba_to_entry_in_reorder_tbl(
+ pmpriv, pioctl_req, tid, peer_address,
+ last_rx_ba_to_delete);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief IOCTL to reject addba req
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_rejectaddbareq(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_REJECT_ADDBA_REQ, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &cfg->param.reject_addba_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will send DELBA to entries in the priv's
+ * Tx BA stream table
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID
+ *
+ * @return N/A
+ */
+static void wlan_send_delba_txbastream_tbl(pmlan_private priv, t_u8 tid)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ TxBAStreamTbl *tx_ba_stream_tbl_ptr;
+
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ tx_ba_stream_tbl_ptr =
+ (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!tx_ba_stream_tbl_ptr) {
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return;
+ }
+
+ while (tx_ba_stream_tbl_ptr !=
+ (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ if (tx_ba_stream_tbl_ptr->ba_status ==
+ BA_STREAM_SETUP_COMPLETE) {
+ if (tid == tx_ba_stream_tbl_ptr->tid) {
+ PRINTM(MIOCTL,
+ "Tx:Send delba to tid=%d, " MACSTR "\n",
+ tid, MAC2STR(tx_ba_stream_tbl_ptr->ra));
+ wlan_release_ralist_lock(priv);
+ wlan_send_delba(priv, MNULL,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ LEAVE();
+ return;
+ }
+ }
+ tx_ba_stream_tbl_ptr = tx_ba_stream_tbl_ptr->pnext;
+ }
+ wlan_release_ralist_lock(priv);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief update station list for the new aggr_prio_tbl setting
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ *
+ * @return N/A
+ */
+void wlan_update_all_stations_ampdu(mlan_private *priv)
+{
+ sta_node *sta_ptr;
+ mlan_adapter *pmadapter = priv->adapter;
+ int i = 0;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ sta_ptr = (sta_node *)util_peek_list(pmadapter->pmoal_handle,
+ &priv->sta_list, MNULL, MNULL);
+ if (!sta_ptr) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+ }
+ while (sta_ptr != (sta_node *)&priv->sta_list) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (sta_ptr->is_11n_enabled)
+ sta_ptr->ampdu_sta[i] =
+ priv->aggr_prio_tbl[i].ampdu_user;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set/get aggr_prio_tbl
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_aggr_prio_tbl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ int i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg->param.aggr_prio_tbl.ampdu[i] =
+ pmpriv->aggr_prio_tbl[i].ampdu_user;
+ cfg->param.aggr_prio_tbl.amsdu[i] =
+ pmpriv->aggr_prio_tbl[i].amsdu;
+ }
+ } else {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ /* For AMPDU */
+ if ((cfg->param.aggr_prio_tbl.ampdu[i] >
+ HIGH_PRIO_TID) &&
+ (cfg->param.aggr_prio_tbl.ampdu[i] !=
+ BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pmpriv->aggr_prio_tbl[i].ampdu_ap =
+ pmpriv->aggr_prio_tbl[i].ampdu_user =
+ cfg->param.aggr_prio_tbl.ampdu[i];
+
+ /* For AMSDU */
+ if ((cfg->param.aggr_prio_tbl.amsdu[i] >
+ HIGH_PRIO_TID &&
+ cfg->param.aggr_prio_tbl.amsdu[i] !=
+ BA_STREAM_NOT_ALLOWED)) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ } else {
+ pmpriv->aggr_prio_tbl[i].amsdu =
+ cfg->param.aggr_prio_tbl.amsdu[i];
+ }
+ }
+ if (pmpriv->media_connected == MTRUE) {
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (cfg->param.aggr_prio_tbl.ampdu[i] ==
+ BA_STREAM_NOT_ALLOWED) {
+ PRINTM(MIOCTL,
+ "Receive aggrpriotbl: BA not allowed tid=%d\n",
+ i);
+ wlan_send_delba_txbastream_tbl(pmpriv,
+ i);
+ }
+ }
+ wlan_update_all_stations_ampdu(pmpriv);
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function update all the tx_win_size
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ *
+ * @return N/A
+ */
+void wlan_update_ampdu_txwinsize(pmlan_adapter pmadapter)
+{
+ t_u8 i;
+ t_u32 tx_win_size = 0;
+ pmlan_private priv = MNULL;
+
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ tx_win_size = priv->add_ba_param.tx_win_size;
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->add_ba_param.tx_win_size =
+ MLAN_STA_AMPDU_DEF_TXWINSIZE;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->add_ba_param.tx_win_size =
+ MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->add_ba_param.tx_win_size =
+ MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+#endif
+ if (pmadapter->coex_win_size &&
+ pmadapter->coex_tx_win_size)
+ priv->add_ba_param.tx_win_size =
+ pmadapter->coex_tx_win_size;
+
+ if (tx_win_size != priv->add_ba_param.tx_win_size) {
+ if (priv->media_connected == MTRUE) {
+ for (i = 0; i < MAX_NUM_TID; i++)
+ wlan_send_delba_txbastream_tbl(
+ priv, i);
+ wlan_recv_event(
+ priv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get supported MCS set
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_11n_ioctl_supported_mcs_set(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ int rx_mcs_supp;
+ t_u8 mcs_set[NUM_MCS_FIELD];
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Set operation is not supported\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rx_mcs_supp = GET_RXMCSSUPP(pmpriv->usr_dev_mcs_support);
+ /* Set MCS for 1x1/2x2*/
+ memset(pmadapter, (t_u8 *)mcs_set, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset(pmadapter, (t_u8 *)&mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ if ((ISSUPP_CHANWIDTH40(pmpriv->usr_dot_11n_dev_cap_bg) ||
+ ISSUPP_CHANWIDTH40(pmpriv->usr_dot_11n_dev_cap_a)) &&
+ !(pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
+ SETHT_MCS32(mcs_set);
+
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ memcpy_ext(pmadapter, cfg->param.supported_mcs_set, mcs_set,
+ NUM_MCS_FIELD, NUM_MCS_FIELD);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the given pointer is valid entry of
+ * Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptxtblptr Pointer to tx ba stream entry
+ *
+ * @return MTRUE or MFALSE
+ */
+static int wlan_is_txbastreamptr_valid(mlan_private *priv,
+ TxBAStreamTbl *ptxtblptr)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptx_tbl) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl == ptxtblptr) {
+ LEAVE();
+ return MTRUE;
+ }
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to a entry in BA Stream
+ * table which matches the ba_status requested
+ *
+ * @param priv A pointer to mlan_private
+ * @param ba_status Current status of the BA stream
+ *
+ * @return A pointer to first entry matching status in BA stream
+ * NULL if not found
+ */
+static TxBAStreamTbl *wlan_11n_get_txbastream_status(mlan_private *priv,
+ baStatus_e ba_status)
+{
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptx_tbl) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ if (ptx_tbl->ba_status == ba_status) {
+ LEAVE();
+ return ptx_tbl;
+ }
+ ptx_tbl = ptx_tbl->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function fills the cap info
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+static void wlan_fill_cap_info(mlan_private *priv, HTCap_t *ht_cap, t_u8 bands)
+{
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
+
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ SETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
+ else
+ RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
+
+ if (ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
+ SETHT_GREENFIELD(ht_cap->ht_cap_info);
+ else
+ RESETHT_GREENFIELD(ht_cap->ht_cap_info);
+
+ if (ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI20(ht_cap->ht_cap_info);
+ else
+ RESETHT_SHORTGI20(ht_cap->ht_cap_info);
+
+ if (ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
+ SETHT_SHORTGI40(ht_cap->ht_cap_info);
+ else
+ RESETHT_SHORTGI40(ht_cap->ht_cap_info);
+ if (ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
+ SETHT_RXSTBC(ht_cap->ht_cap_info, 1);
+ else
+ RESETHT_RXSTBC(ht_cap->ht_cap_info);
+
+ if (ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
+ SETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
+ else
+ RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
+
+ /** if current channel only allow 20Mhz, we should cler 40Mhz support */
+ if (priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
+ RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
+ RESETHT_SHORTGI40(ht_cap->ht_cap_info);
+ RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
+ }
+ /* No user config for LDPC coding capability yet */
+ if (ISSUPP_RXLDPC(usr_dot_11n_dev_cap))
+ SETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
+ else
+ RESETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
+
+ /* No user config for TX STBC yet */
+ if (ISSUPP_TXSTBC(usr_dot_11n_dev_cap))
+ SETHT_TXSTBC(ht_cap->ht_cap_info);
+ else
+ RESETHT_TXSTBC(ht_cap->ht_cap_info);
+
+ /* No user config for Delayed BACK yet */
+ RESETHT_DELAYEDBACK(ht_cap->ht_cap_info);
+
+ /* Need change to support 8k AMSDU receive */
+ RESETHT_MAXAMSDU(ht_cap->ht_cap_info);
+ /* SM power save */
+ if (ISSUPP_MIMOPS(priv->adapter->hw_dot_11n_dev_cap))
+ RESETHT_SM_POWERSAVE(ht_cap->ht_cap_info); /* Enable HT SMPS*/
+ else
+ SETHT_STATIC_SMPS(ht_cap->ht_cap_info); /* Disable HT SMPS */
+
+ LEAVE();
+}
+
+/**
+ * @brief This function clear the bit in cap info which we don't support
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+static void wlan_reset_cap_info(mlan_private *priv, HTCap_t *ht_cap, t_u8 bands)
+{
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
+
+ if (!ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap))
+ RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
+
+ if (!ISSUPP_GREENFIELD(usr_dot_11n_dev_cap))
+ RESETHT_GREENFIELD(ht_cap->ht_cap_info);
+
+ if (!ISSUPP_SHORTGI20(usr_dot_11n_dev_cap))
+ RESETHT_SHORTGI20(ht_cap->ht_cap_info);
+
+ if (!ISSUPP_SHORTGI40(usr_dot_11n_dev_cap))
+ RESETHT_SHORTGI40(ht_cap->ht_cap_info);
+ if (!ISSUPP_RXSTBC(usr_dot_11n_dev_cap))
+ RESETHT_RXSTBC(ht_cap->ht_cap_info);
+
+ if (!ISENABLED_40MHZ_INTOLARENT(usr_dot_11n_dev_cap))
+ RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
+
+ /** if current channel only allow 20Mhz, we should cler 40Mhz support */
+ if (priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
+ RESETHT_SUPPCHANWIDTH(ht_cap->ht_cap_info);
+ RESETHT_SHORTGI40(ht_cap->ht_cap_info);
+ RESETHT_40MHZ_INTOLARANT(ht_cap->ht_cap_info);
+ }
+ /* No user config for LDPC coding capability yet */
+ if (!ISSUPP_RXLDPC(usr_dot_11n_dev_cap))
+ RESETHT_LDPCCODINGCAP(ht_cap->ht_cap_info);
+
+ /* No user config for TX STBC yet */
+ if (!ISSUPP_TXSTBC(usr_dot_11n_dev_cap))
+ RESETHT_TXSTBC(ht_cap->ht_cap_info);
+
+ /* No user config for Delayed BACK yet */
+ RESETHT_DELAYEDBACK(ht_cap->ht_cap_info);
+
+ /* Need change to support 8k AMSDU receive */
+ RESETHT_MAXAMSDU(ht_cap->ht_cap_info);
+ /* SM power save */
+ if (!ISSUPP_MIMOPS(priv->adapter->hw_dot_11n_dev_cap))
+ SETHT_STATIC_SMPS(ht_cap->ht_cap_info); /* Disable HT SMPS */
+
+ LEAVE();
+}
+
+/**
+ * @brief This function fills the HT cap tlv
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
+ * @param bands Band configuration
+ * @param fill A flag for fill the htcap info
+ *
+ * @return N/A
+ */
+void wlan_fill_ht_cap_tlv(mlan_private *priv, MrvlIETypes_HTCap_t *pht_cap,
+ t_u16 bands, t_u8 fill)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ int rx_mcs_supp;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
+
+ /* Fill HT cap info */
+ if (fill)
+ wlan_fill_cap_info(priv, &pht_cap->ht_cap, bands);
+ else
+ wlan_reset_cap_info(priv, &pht_cap->ht_cap, bands);
+
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);
+
+ /* Set ampdu param */
+ SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
+ SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
+
+ rx_mcs_supp = GET_RXMCSSUPP(priv->usr_dev_mcs_support);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ if (bands & BAND_A)
+ rx_mcs_supp = MIN(
+ rx_mcs_supp,
+ GET_RXMCSSUPP(pmadapter->user_htstream >> 8));
+ else
+ rx_mcs_supp =
+ MIN(rx_mcs_supp,
+ GET_RXMCSSUPP(pmadapter->user_htstream));
+ }
+#endif
+ memset(pmadapter, (t_u8 *)pht_cap->ht_cap.supported_mcs_set, 0xff,
+ rx_mcs_supp);
+ /* Clear all the other values to get the minimum mcs set btw STA and AP
+ */
+ memset(pmadapter,
+ (t_u8 *)&pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ /* if current channel only support 20MHz, we should not set 40Mz
+ * supprot*/
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ !(priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
+ SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
+
+ /* Clear RD responder bit */
+ RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
+ pht_cap->ht_cap.ht_ext_cap =
+ wlan_cpu_to_le16(pht_cap->ht_cap.ht_ext_cap);
+
+ /* Set Tx BF cap */
+ pht_cap->ht_cap.tx_bf_cap = wlan_cpu_to_le32(priv->tx_bf_cap);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function fills the HT cap ie
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pht_cap A pointer to IEEEtypes_HTCap_t structure
+ * @param bands Band configuration
+ *
+ * @return N/A
+ */
+void wlan_fill_ht_cap_ie(mlan_private *priv, IEEEtypes_HTCap_t *pht_cap,
+ t_u16 bands)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ int rx_mcs_supp;
+ t_u32 usr_dot_11n_dev_cap;
+
+ ENTER();
+
+ pht_cap->ieee_hdr.element_id = HT_CAPABILITY;
+ pht_cap->ieee_hdr.len = sizeof(HTCap_t);
+ if (bands & BAND_A)
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = priv->usr_dot_11n_dev_cap_bg;
+
+ /* Fill HT cap info */
+ wlan_fill_cap_info(priv, &pht_cap->ht_cap, bands);
+
+ /* Set ampdu param */
+ SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
+ SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);
+
+ rx_mcs_supp = GET_RXMCSSUPP(priv->usr_dev_mcs_support);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ if (bands & BAND_A)
+ rx_mcs_supp = MIN(
+ rx_mcs_supp,
+ GET_RXMCSSUPP(pmadapter->user_htstream >> 8));
+ else
+ rx_mcs_supp =
+ MIN(rx_mcs_supp,
+ GET_RXMCSSUPP(pmadapter->user_htstream));
+ }
+#endif
+ memset(pmadapter, (t_u8 *)pht_cap->ht_cap.supported_mcs_set, 0xff,
+ rx_mcs_supp);
+ /* Clear all the other values to get the minimum mcs set btw STA and AP
+ */
+ memset(pmadapter,
+ (t_u8 *)&pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp], 0,
+ NUM_MCS_FIELD - rx_mcs_supp);
+ /* Set MCS32 with 40MHz support */
+ /* if current channel only support 20MHz, we should not set 40Mz
+ * supprot*/
+ if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ !(priv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ priv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS))
+ SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);
+
+ /* Clear RD responder bit */
+ RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);
+
+ /* Set Tx BF cap */
+ pht_cap->ht_cap.tx_bf_cap = priv->tx_bf_cap;
+
+ LEAVE();
+ return;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function prints the 802.11n device capability
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cap Capability value
+ *
+ * @return N/A
+ */
+void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
+ (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
+ PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
+ (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
+ (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
+ (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
+ (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
+ (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
+ (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
+ (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
+ (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
+ (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
+
+ PRINTM(MINFO, "GET_HW_SPEC: Number of Tx BA streams supported = %d\n",
+ ISSUPP_GETTXBASTREAM(cap));
+ PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
+ PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
+ (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
+
+ if (ISSUPP_RXANTENNAA(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
+ if (ISSUPP_RXANTENNAB(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
+ if (ISSUPP_RXANTENNAC(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
+ if (ISSUPP_RXANTENNAD(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
+ if (ISSUPP_TXANTENNAA(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
+ if (ISSUPP_TXANTENNAB(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
+ if (ISSUPP_TXANTENNAC(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
+ if (ISSUPP_TXANTENNAD(cap))
+ PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prints the 802.11n device MCS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param support Support value
+ *
+ * @return N/A
+ */
+void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support)
+{
+ ENTER();
+
+ PRINTM(MINFO, "GET_HW_SPEC: MCSs for %dx%d MIMO\n",
+ GET_RXMCSSUPP(support), GET_TXMCSSUPP(support));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *resp)
+{
+ int tid;
+ TxBAStreamTbl *ptx_ba_tbl;
+ HostCmd_DS_11N_DELBA *pdel_ba =
+ (HostCmd_DS_11N_DELBA *)&resp->params.del_ba;
+
+ ENTER();
+
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+ if (pdel_ba->del_result == BA_RESULT_SUCCESS) {
+ mlan_11n_delete_bastream_tbl(
+ priv, tid, pdel_ba->peer_mac_addr, TYPE_DELBA_SENT,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set), 0);
+ wlan_request_ralist_lock(priv);
+ ptx_ba_tbl = wlan_11n_get_txbastream_status(
+ priv, BA_STREAM_SETUP_INPROGRESS);
+ wlan_release_ralist_lock(priv);
+ if (ptx_ba_tbl)
+ wlan_send_addba(priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra);
+ } else { /*
+ * In case of failure, recreate
+ * the deleted stream in case
+ * we initiated the ADDBA
+ */
+ if (INITIATOR_BIT(pdel_ba->del_ba_param_set)) {
+ wlan_request_ralist_lock(priv);
+ if (!wlan_11n_get_txbastream_tbl(
+ priv, tid, pdel_ba->peer_mac_addr, MFALSE))
+ wlan_11n_create_txbastream_tbl(
+ priv, pdel_ba->peer_mac_addr, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ ptx_ba_tbl = wlan_11n_get_txbastream_status(
+ priv, BA_STREAM_SETUP_INPROGRESS);
+ wlan_release_ralist_lock(priv);
+ if (ptx_ba_tbl) {
+ mlan_11n_delete_bastream_tbl(
+ priv, ptx_ba_tbl->tid, ptx_ba_tbl->ra,
+ TYPE_DELBA_SENT, MTRUE, 0);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * add a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11n_addba_req(mlan_private *priv, HostCmd_DS_COMMAND *resp)
+{
+ t_u8 tid;
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *)&resp->params.add_ba_rsp;
+ TxBAStreamTbl *ptx_ba_tbl;
+ raListTbl *ra_list = MNULL;
+ int tid_down;
+
+ ENTER();
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = (wlan_le16_to_cpu(padd_ba_rsp->ssn)) & SSN_MASK;
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK) >>
+ BLOCKACKPARAM_TID_POS;
+ tid_down = wlan_get_wmm_tid_down(priv, tid);
+ ra_list = wlan_wmm_get_ralist_node(priv, tid_down,
+ padd_ba_rsp->peer_mac_addr);
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ ptx_ba_tbl = wlan_11n_get_txbastream_tbl(
+ priv, tid, padd_ba_rsp->peer_mac_addr, MTRUE);
+ if (ptx_ba_tbl) {
+ PRINTM(MCMND,
+ "ADDBA REQ: " MACSTR
+ " tid=%d ssn=%d win_size=%d,amsdu=%d\n",
+ MAC2STR(padd_ba_rsp->peer_mac_addr), tid,
+ padd_ba_rsp->ssn,
+ ((padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_WINSIZE_MASK) >>
+ BLOCKACKPARAM_WINSIZE_POS),
+ padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_AMSDU_SUPP_MASK);
+ ptx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu !=
+ BA_STREAM_NOT_ALLOWED))
+ ptx_ba_tbl->amsdu = MTRUE;
+ else
+ ptx_ba_tbl->amsdu = MFALSE;
+ if (ra_list) {
+ ra_list->amsdu_in_ampdu = ptx_ba_tbl->amsdu;
+ ra_list->ba_status = BA_STREAM_SETUP_COMPLETE;
+ }
+ } else {
+ PRINTM(MERROR, "BA stream not created\n");
+ }
+ } else {
+ if (ra_list) {
+ ra_list->amsdu_in_ampdu = MFALSE;
+ ra_list->ba_status = BA_STREAM_NOT_SETUP;
+ }
+ mlan_11n_delete_bastream_tbl(priv, tid,
+ padd_ba_rsp->peer_mac_addr,
+ TYPE_DELBA_SENT, MTRUE, 0);
+ if (padd_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ disable_station_ampdu(
+ priv, tid, padd_ba_rsp->peer_mac_addr);
+#endif /* UAP_SUPPORT */
+ priv->aggr_prio_tbl[tid].ampdu_ap =
+ BA_STREAM_NOT_ALLOWED;
+
+ } else {
+ if (ra_list) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(
+ priv->adapter);
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function restore tx_pause flag
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param flag MTRUE/MFALSE;
+ *
+ * @return N/A
+ */
+void wlan_set_tx_pause_flag(mlan_private *priv, t_u8 flag)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i;
+ for (i = 0; i < priv->adapter->priv_num; i++) {
+ pmpriv = priv->adapter->priv[i];
+ if (pmpriv)
+ pmpriv->tx_pause = flag;
+ }
+}
+
+/**
+ * @brief This function prepares command of reconfigure tx buf
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_recfg_tx_buf(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ int cmd_action, void *pdata_buf)
+{
+ HostCmd_DS_TXBUF_CFG *ptx_buf = &cmd->params.tx_buf;
+ t_u16 action = (t_u16)cmd_action;
+ t_u16 buf_size = *((t_u16 *)pdata_buf);
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TXBUF_CFG) + S_DS_GEN);
+ ptx_buf->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ PRINTM(MCMND, "set tx_buf = %d\n", buf_size);
+ ptx_buf->buff_size = wlan_cpu_to_le16(buf_size);
+ /** stop tx traffic */
+ wlan_set_tx_pause_flag(priv, MTRUE);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ ptx_buf->buff_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of amsdu aggr control
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private *priv,
+ HostCmd_DS_COMMAND *cmd, int cmd_action,
+ void *pdata_buf)
+{
+ HostCmd_DS_AMSDU_AGGR_CTRL *pamsdu_ctrl = &cmd->params.amsdu_aggr_ctrl;
+ t_u16 action = (t_u16)cmd_action;
+ mlan_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
+ (mlan_ds_11n_amsdu_aggr_ctrl *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_AMSDU_AGGR_CTRL) + S_DS_GEN);
+ pamsdu_ctrl->action = wlan_cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ pamsdu_ctrl->enable = wlan_cpu_to_le16(aa_ctrl->enable);
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ pamsdu_ctrl->curr_buf_size = 0;
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of amsdu aggr ctrl
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_amsdu_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_AMSDU_AGGR_CTRL *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
+ cfg->param.amsdu_aggr_ctrl.enable =
+ wlan_le16_to_cpu(amsdu_ctrl->enable);
+ cfg->param.amsdu_aggr_ctrl.curr_buf_size =
+ wlan_le16_to_cpu(amsdu_ctrl->curr_buf_size);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares 11n cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11n_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_11N_CFG *htcfg = &cmd->params.htcfg;
+ mlan_ds_11n_tx_cfg *txcfg = (mlan_ds_11n_tx_cfg *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_CFG) + S_DS_GEN);
+ htcfg->action = wlan_cpu_to_le16(cmd_action);
+ htcfg->ht_tx_cap = wlan_cpu_to_le16(txcfg->httxcap);
+ htcfg->ht_tx_info = wlan_cpu_to_le16(txcfg->httxinfo);
+ htcfg->misc_config = wlan_cpu_to_le16(txcfg->misc_cfg);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of 11ncfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11n_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_11N_CFG *htcfg = &resp->params.htcfg;
+
+ ENTER();
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(htcfg->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
+ cfg->param.tx_cfg.httxcap = wlan_le16_to_cpu(htcfg->ht_tx_cap);
+ cfg->param.tx_cfg.httxinfo =
+ wlan_le16_to_cpu(htcfg->ht_tx_info);
+ cfg->param.tx_cfg.misc_cfg =
+ wlan_le16_to_cpu(htcfg->misc_config);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares reject addba req command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_reject_addba_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_REJECT_ADDBA_REQ *preject_addba_req =
+ &cmd->params.rejectaddbareq;
+ mlan_ds_reject_addba_req *prejaddbareq =
+ (mlan_ds_reject_addba_req *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_REJECT_ADDBA_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_REJECT_ADDBA_REQ) +
+ S_DS_GEN);
+ preject_addba_req->action = wlan_cpu_to_le16(cmd_action);
+ preject_addba_req->conditions =
+ wlan_cpu_to_le32(prejaddbareq->conditions);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of reject addba req
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_reject_addba_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_11n_cfg *cfg = MNULL;
+ HostCmd_DS_REJECT_ADDBA_REQ *preject_addba_req =
+ &resp->params.rejectaddbareq;
+
+ ENTER();
+ if (pioctl_buf && (wlan_le16_to_cpu(preject_addba_req->action) ==
+ HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
+ cfg->param.reject_addba_req.conditions =
+ wlan_le32_to_cpu(preject_addba_req->conditions);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares TX BF configuration command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_tx_bf_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &cmd->params.tx_bf_cfg;
+ mlan_ds_11n_tx_bf_cfg *txbf = (mlan_ds_11n_tx_bf_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_BF_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_BF_CFG) + S_DS_GEN);
+
+ if (txbf->bf_action == SET_GET_BF_PERIODICITY) {
+ memcpy_ext(pmadapter, txbfcfg->body.bf_periodicity.peer_mac,
+ txbf->body.bf_periodicity[0].peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ }
+ txbfcfg->action = wlan_cpu_to_le16(txbf->action);
+ txbfcfg->bf_action = wlan_cpu_to_le16(txbf->bf_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbfcfg->body.bf_global_cfg.bf_enbl =
+ txbf->body.bf_global_cfg.bf_enbl;
+ txbfcfg->body.bf_global_cfg.sounding_enbl =
+ txbf->body.bf_global_cfg.sounding_enbl;
+ txbfcfg->body.bf_global_cfg.fb_type =
+ txbf->body.bf_global_cfg.fb_type;
+ txbfcfg->body.bf_global_cfg.snr_threshold =
+ txbf->body.bf_global_cfg.snr_threshold;
+ txbfcfg->body.bf_global_cfg.sounding_interval =
+ wlan_cpu_to_le16(txbf->body.bf_global_cfg
+ .sounding_interval);
+ txbfcfg->body.bf_global_cfg.bf_mode =
+ txbf->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy_ext(pmadapter,
+ txbfcfg->body.bf_sound_args.peer_mac,
+ txbf->body.bf_sound[0].peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ txbfcfg->body.bf_periodicity.interval =
+ wlan_cpu_to_le16(
+ txbf->body.bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ memcpy_ext(pmadapter, txbfcfg->body.tx_bf_peer.peer_mac,
+ txbf->body.tx_bf_peer[0].peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.tx_bf_peer.bf_enbl =
+ txbf->body.tx_bf_peer[0].bf_enbl;
+ txbfcfg->body.tx_bf_peer.sounding_enbl =
+ txbf->body.tx_bf_peer[0].sounding_enbl;
+ txbfcfg->body.tx_bf_peer.fb_type =
+ txbf->body.tx_bf_peer[0].fb_type;
+ break;
+ case SET_SNR_THR_PEER:
+ memcpy_ext(pmadapter, txbfcfg->body.bf_snr.peer_mac,
+ txbf->body.bf_snr[0].peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ txbfcfg->body.bf_snr.snr = txbf->body.bf_snr[0].snr;
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response
+ * of TX BF configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_tx_bf_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_TX_BF_CFG *txbfcfg = &resp->params.tx_bf_cfg;
+ mlan_ds_11n_cfg *cfg_11n = MNULL;
+ mlan_ds_11n_tx_bf_cfg *txbf = MNULL;
+ bf_peer_args *tx_bf_peer;
+ bf_snr_thr_t *bf_snr;
+ int i;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ cfg_11n = (mlan_ds_11n_cfg *)pioctl_buf->pbuf;
+ txbf = (mlan_ds_11n_tx_bf_cfg *)&cfg_11n->param.tx_bf;
+ txbf->bf_action = wlan_le16_to_cpu(txbfcfg->bf_action);
+ switch (txbf->bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ txbf->body.bf_global_cfg.bf_enbl =
+ txbfcfg->body.bf_global_cfg.bf_enbl;
+ txbf->body.bf_global_cfg.sounding_enbl =
+ txbfcfg->body.bf_global_cfg.sounding_enbl;
+ txbf->body.bf_global_cfg.fb_type =
+ txbfcfg->body.bf_global_cfg.fb_type;
+ txbf->body.bf_global_cfg.snr_threshold =
+ txbfcfg->body.bf_global_cfg.snr_threshold;
+ txbf->body.bf_global_cfg.sounding_interval =
+ wlan_le16_to_cpu(txbfcfg->body.bf_global_cfg
+ .sounding_interval);
+ txbf->body.bf_global_cfg.bf_mode =
+ txbfcfg->body.bf_global_cfg.bf_mode;
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ memcpy_ext(pmadapter, txbf->body.bf_sound[0].peer_mac,
+ txbfcfg->body.bf_sound_args.peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_sound[0].status =
+ txbfcfg->body.bf_sound_args.status;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ memcpy_ext(pmadapter,
+ txbf->body.bf_periodicity->peer_mac,
+ txbfcfg->body.bf_periodicity.peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_periodicity->interval = wlan_le16_to_cpu(
+ txbfcfg->body.bf_periodicity.interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ txbf->no_of_peers = *(t_u8 *)&txbfcfg->body;
+ tx_bf_peer = (bf_peer_args *)((t_u8 *)&txbfcfg->body +
+ sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy_ext(pmadapter,
+ txbf->body.tx_bf_peer[i].peer_mac,
+ (t_u8 *)tx_bf_peer->peer_mac,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ txbf->body.tx_bf_peer[i].bf_enbl =
+ tx_bf_peer->bf_enbl;
+ txbf->body.tx_bf_peer[i].sounding_enbl =
+ tx_bf_peer->sounding_enbl;
+ txbf->body.tx_bf_peer[i].fb_type =
+ tx_bf_peer->fb_type;
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ txbf->no_of_peers = *(t_u8 *)&txbfcfg->body;
+ bf_snr = (bf_snr_thr_t *)((t_u8 *)&txbfcfg->body +
+ sizeof(t_u8));
+ for (i = 0; i < txbf->no_of_peers; i++) {
+ memcpy_ext(pmadapter,
+ txbf->body.bf_snr[i].peer_mac,
+ (t_u8 *)bf_snr->peer_mac,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ txbf->body.bf_snr[i].snr = bf_snr->snr;
+ bf_snr++;
+ }
+ break;
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get second channel offset
+ *
+ * @param chan channel num
+ * @return second channel offset
+ */
+t_u8 wlan_get_second_channel_offset(int chan)
+{
+ t_u8 chan2Offset = SEC_CHAN_NONE;
+
+ switch (chan) {
+ case 36:
+ case 44:
+ case 52:
+ case 60:
+ case 100:
+ case 108:
+ case 116:
+ case 124:
+ case 132:
+ case 140:
+ case 149:
+ case 157:
+ chan2Offset = SEC_CHAN_ABOVE;
+ break;
+ case 40:
+ case 48:
+ case 56:
+ case 64:
+ case 104:
+ case 112:
+ case 120:
+ case 128:
+ case 136:
+ case 144:
+ case 153:
+ case 161:
+ chan2Offset = SEC_CHAN_BELOW;
+ break;
+ case 165:
+ /* Special Case: 20Mhz-only Channel */
+ chan2Offset = SEC_CHAN_NONE;
+ break;
+ }
+ return chan2Offset;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief validate the channel offset for Infra/Ad-hoc band configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param band band
+ * @param chan primary channel
+ * @param chan_bw channel bandwidth
+ *
+ * @return channel offset (NO_SEC_CHANNEL, SEC_CHANNEL_ABOVE,
+ * SEC_CHANNEL_BELOW)
+ */
+t_u8 wlan_validate_chan_offset(mlan_private *pmpriv, t_u16 band, t_u32 chan,
+ t_u8 chan_bw)
+{
+ t_u8 chan_offset;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE)
+ chan_offset = SEC_CHAN_ABOVE;
+ else if (chan_bw == CHANNEL_BW_40MHZ_BELOW)
+ chan_offset = SEC_CHAN_BELOW;
+ else
+ chan_offset = SEC_CHAN_NONE;
+
+ /* validation */
+ if (chan_offset != SEC_CHAN_NONE) {
+ if (band & BAND_GN) {
+ if ((chan == 1) || (chan == 2) || (chan == 3) ||
+ (chan == 4))
+ chan_offset = SEC_CHAN_ABOVE;
+ else if ((chan == 10) || (chan == 11) || (chan == 12) ||
+ (chan == 13))
+ chan_offset = SEC_CHAN_BELOW;
+
+ /* check if channel 12 is supported in the region */
+ if (!wlan_find_cfp_by_band_and_channel(pmadapter, band,
+ 12))
+ if ((chan == 8) || (chan == 9))
+ chan_offset = SEC_CHAN_BELOW;
+ } else if (band & BAND_AN)
+ chan_offset = wlan_get_second_channel_offset(chan);
+ }
+ return chan_offset;
+}
+
+/**
+ * @brief This function check if ht40 is allowed in current region
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static int wlan_check_chan_width_ht40_by_region(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ int i = 0;
+ int cover_pri_chan = MFALSE;
+ t_u8 pri_chan;
+ t_u8 chan_offset;
+ t_u8 num_cfp;
+
+ ENTER();
+
+ if (pbss_desc->pht_info == MNULL) {
+ PRINTM(MERROR, "ht_info pointer NULL, force use HT20\n");
+ LEAVE();
+ return MFALSE;
+ }
+ if (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS &&
+ pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS) {
+ LEAVE();
+ return MFALSE;
+ }
+
+ pri_chan = pbss_desc->pht_info->ht_info.pri_chan;
+ chan_offset = GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.field2);
+ if ((chan_offset == SEC_CHAN_ABOVE) &&
+ (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40PLUS)) {
+ pmpriv->curr_chan_flags |=
+ CHAN_FLAGS_NO_HT40MINUS | CHAN_FLAGS_NO_80MHZ;
+ return MFALSE;
+ }
+ if ((chan_offset == SEC_CHAN_BELOW) &&
+ (pmpriv->curr_chan_flags & CHAN_FLAGS_NO_HT40MINUS)) {
+ pmpriv->curr_chan_flags |=
+ CHAN_FLAGS_NO_HT40PLUS | CHAN_FLAGS_NO_80MHZ;
+ return MFALSE;
+ }
+ if (pmpriv->curr_chan_flags & CHAN_FLAGS_MAX)
+ return MTRUE;
+
+ num_cfp = pmadapter->region_channel[0].num_cfp;
+
+ if ((pbss_desc->bss_band & (BAND_B | BAND_G)) &&
+ pmadapter->region_channel[0].valid) {
+ for (i = 0; i < num_cfp; i++) {
+ if (pri_chan ==
+ pmadapter->region_channel[0].pcfp[i].channel) {
+ cover_pri_chan = MTRUE;
+ break;
+ }
+ }
+ if (!cover_pri_chan) {
+ PRINTM(MERROR, "Invalid channel, force use HT20\n");
+ LEAVE();
+ return MFALSE;
+ }
+
+ if (chan_offset == SEC_CHAN_ABOVE) {
+ if (pri_chan > num_cfp - 4) {
+ PRINTM(MERROR,
+ "Invalid second channel offset, force use HT20\n");
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ }
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief This function append the 802_11N tlv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param ppbuffer A Pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+int wlan_cmd_append_11n_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIETypes_HTCap_t *pht_cap;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list;
+ MrvlIETypes_2040BSSCo_t *p2040_bss_co;
+ MrvlIETypes_ExtCap_t *pext_cap;
+ t_u32 usr_dot_11n_dev_cap, orig_usr_dot_11n_dev_cap = 0;
+ t_u32 usr_vht_cap_info;
+ t_u8 usr_dot_11ac_bw;
+ int ret_len = 0;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (pbss_desc == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ if (pbss_desc->bss_band & BAND_A)
+ usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap = pmpriv->usr_dot_11n_dev_cap_bg;
+
+ if (pbss_desc->bss_band & BAND_A)
+ usr_vht_cap_info = pmpriv->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = pmpriv->usr_dot_11ac_dev_cap_bg;
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ usr_dot_11ac_bw = BW_FOLLOW_VHTCAP;
+ else
+ usr_dot_11ac_bw = pmpriv->usr_dot_11ac_bw;
+ if ((pbss_desc->bss_band & (BAND_B | BAND_G | BAND_A)) &&
+ ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ !wlan_check_chan_width_ht40_by_region(pmpriv, pbss_desc)) {
+ orig_usr_dot_11n_dev_cap = usr_dot_11n_dev_cap;
+ RESETSUPP_CHANWIDTH40(usr_dot_11n_dev_cap);
+ RESET_40MHZ_INTOLARENT(usr_dot_11n_dev_cap);
+ RESETSUPP_SHORTGI40(usr_dot_11n_dev_cap);
+ pmpriv->usr_dot_11n_dev_cap_bg = usr_dot_11n_dev_cap;
+ pbss_desc->curr_bandwidth = BW_20MHZ;
+ }
+ if (pbss_desc->pht_cap) {
+ pht_cap = (MrvlIETypes_HTCap_t *)*ppbuffer;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ memcpy_ext(pmadapter,
+ (t_u8 *)pht_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *)pbss_desc->pht_cap +
+ sizeof(IEEEtypes_Header_t),
+ pht_cap->header.len, pht_cap->header.len);
+
+ pht_cap->ht_cap.ht_cap_info =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
+ pht_cap->ht_cap.ht_ext_cap =
+ wlan_le16_to_cpu(pht_cap->ht_cap.ht_ext_cap);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pbss_desc->bss_band,
+ MTRUE);
+
+ /** check if need support 80+80MHZ */
+ /** reset the 2 spatial stream rate for 80 + 80 Mhz */
+ if (wlan_is_80_80_support(pmpriv, pbss_desc))
+ pht_cap->ht_cap.supported_mcs_set[1] = 0;
+ HEXDUMP("HT_CAPABILITIES IE", (t_u8 *)pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
+ ret_len += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ } else {
+ // AP don't support 11N
+ LEAVE();
+ return 0;
+ }
+
+ if (pbss_desc->pht_info) {
+ pchan_list = (MrvlIEtypes_ChanListParamSet_t *)*ppbuffer;
+ memset(pmadapter, pchan_list, 0,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_list->header.len =
+ sizeof(MrvlIEtypes_ChanListParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t);
+ pchan_list->chan_scan_param[0].chan_number =
+ pbss_desc->pht_info->ht_info.pri_chan;
+ pchan_list->chan_scan_param[0].bandcfg.chanBand =
+ wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
+ /* support the VHT if the network to be join has the VHT
+ * operation */
+ if (ISSUPP_11ACENABLED(pmadapter->fw_cap_info) &&
+ (usr_dot_11ac_bw == BW_FOLLOW_VHTCAP) &&
+ (!(pmpriv->curr_chan_flags & CHAN_FLAGS_NO_80MHZ)) &&
+ wlan_11ac_bandconfig_allowed(pmpriv, pbss_desc->bss_band) &&
+ pbss_desc->pvht_oprat &&
+ pbss_desc->pvht_oprat->chan_width == VHT_OPER_CHWD_80MHZ) {
+ pchan_list->chan_scan_param[0].bandcfg.chanWidth =
+ CHAN_BW_80MHZ;
+ pchan_list->chan_scan_param[0].bandcfg.chan2Offset =
+ GET_SECONDARYCHAN(
+ pbss_desc->pht_info->ht_info.field2);
+ pbss_desc->curr_bandwidth = BW_80MHZ;
+ } else if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) &&
+ ISALLOWED_CHANWIDTH40(
+ pbss_desc->pht_info->ht_info.field2) &&
+ wlan_check_chan_width_ht40_by_region(pmpriv,
+ pbss_desc)) {
+ pchan_list->chan_scan_param[0].bandcfg.chan2Offset =
+ GET_SECONDARYCHAN(
+ pbss_desc->pht_info->ht_info.field2);
+ pbss_desc->curr_bandwidth = BW_40MHZ;
+ pchan_list->chan_scan_param[0].bandcfg.chanWidth =
+ CHAN_BW_40MHZ;
+ }
+ pchan_list->chan_scan_param[0].bandcfg.scanMode =
+ SCAN_MODE_USER;
+ HEXDUMP("ChanList", (t_u8 *)pchan_list,
+ sizeof(MrvlIEtypes_ChanListParamSet_t));
+ HEXDUMP("pht_info", (t_u8 *)pbss_desc->pht_info,
+ sizeof(MrvlIETypes_HTInfo_t) - 2);
+ *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
+ pchan_list->header.len =
+ wlan_cpu_to_le16(pchan_list->header.len);
+ }
+
+ if (pbss_desc->pbss_co_2040) {
+ p2040_bss_co = (MrvlIETypes_2040BSSCo_t *)*ppbuffer;
+ memset(pmadapter, p2040_bss_co, 0,
+ sizeof(MrvlIETypes_2040BSSCo_t));
+ p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
+ p2040_bss_co->header.len = sizeof(BSSCo2040_t);
+
+ memcpy_ext(pmadapter,
+ (t_u8 *)p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *)pbss_desc->pbss_co_2040 +
+ sizeof(IEEEtypes_Header_t),
+ p2040_bss_co->header.len, p2040_bss_co->header.len);
+
+ HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *)p2040_bss_co,
+ sizeof(MrvlIETypes_2040BSSCo_t));
+ *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
+ ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
+ p2040_bss_co->header.len =
+ wlan_cpu_to_le16(p2040_bss_co->header.len);
+ }
+
+ if (pbss_desc->pext_cap) {
+ pext_cap = (MrvlIETypes_ExtCap_t *)*ppbuffer;
+ memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
+ pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
+ pext_cap->header.len = sizeof(ExtCap_t);
+
+ memcpy_ext(pmadapter,
+ (t_u8 *)pext_cap + sizeof(MrvlIEtypesHeader_t),
+ (t_u8 *)&pmpriv->ext_cap, sizeof(ExtCap_t),
+ pext_cap->header.len);
+ if (!pmadapter->ecsa_enable)
+ RESET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap);
+ else
+ SET_EXTCAP_EXT_CHANNEL_SWITCH(pext_cap->ext_cap);
+
+ HEXDUMP("Extended Capabilities IE", (t_u8 *)pext_cap,
+ sizeof(MrvlIETypes_ExtCap_t));
+ *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
+ ret_len += sizeof(MrvlIETypes_ExtCap_t);
+ pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
+ } else if (wlan_is_ext_capa_support(pmpriv) ||
+ (pmpriv->config_bands & BAND_AAC)) {
+ wlan_add_ext_capa_info_ie(pmpriv, pbss_desc, ppbuffer);
+ ret_len += sizeof(MrvlIETypes_ExtCap_t);
+ }
+ PRINTM(MCMND, "curr_bandwidth=%d\n", pbss_desc->curr_bandwidth);
+ if (orig_usr_dot_11n_dev_cap)
+ pmpriv->usr_dot_11n_dev_cap_bg = orig_usr_dot_11n_dev_cap;
+
+ LEAVE();
+ return ret_len;
+}
+
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief 11n configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11n_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_cfg *cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11n_cfg)) {
+ PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11n_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ cfg = (mlan_ds_11n_cfg *)pioctl_req->pbuf;
+ switch (cfg->sub_command) {
+ case MLAN_OID_11N_CFG_TX:
+ status = wlan_11n_ioctl_httxcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_HTCAP_CFG:
+ status = wlan_11n_ioctl_htusrcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AGGR_PRIO_TBL:
+ status = wlan_11n_ioctl_aggr_prio_tbl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_REJECT:
+ status = wlan_11n_ioctl_addba_reject(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_ADDBA_PARAM:
+ status = wlan_11n_ioctl_addba_param(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_DELBA:
+ status = wlan_11n_ioctl_delba(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_REJECT_ADDBA_REQ:
+ status = wlan_11n_ioctl_rejectaddbareq(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE:
+ status = wlan_11n_ioctl_max_tx_buf_size(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL:
+ status = wlan_11n_ioctl_amsdu_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_SUPPORTED_MCS_SET:
+ status =
+ wlan_11n_ioctl_supported_mcs_set(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CAP:
+ status = wlan_11n_ioctl_tx_bf_cap(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_TX_BF_CFG:
+ status = wlan_11n_ioctl_tx_bf_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_STREAM_CFG:
+ status = wlan_11n_ioctl_stream_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_COEX_RX_WINSIZE:
+ status = wlan_11n_ioctl_coex_rx_winsize(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM:
+ status = wlan_11n_ioctl_ibss_ampdu_param(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11N_CFG_MIN_BA_THRESHOLD:
+ status = wlan_11n_ioctl_min_ba_threshold_cfg(pmadapter,
+ pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function will delete the given entry in Tx BA Stream table
+ *
+ * @param priv Pointer to mlan_private
+ * @param ptx_tbl Pointer to tx ba stream entry to delete
+ *
+ * @return N/A
+ */
+void wlan_11n_delete_txbastream_tbl_entry(mlan_private *priv,
+ TxBAStreamTbl *ptx_tbl)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!ptx_tbl || !wlan_is_txbastreamptr_valid(priv, ptx_tbl))
+ goto exit;
+ PRINTM(MINFO, "Delete BA stream table entry: %p\n", ptx_tbl);
+ util_unlink_list(pmadapter->pmoal_handle, &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list)ptx_tbl, MNULL, MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)ptx_tbl);
+exit:
+ LEAVE();
+}
+
+/**
+ * @brief This function will delete all the entries in Tx BA Stream table
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void wlan_11n_deleteall_txbastream_tbl(mlan_private *priv)
+{
+ int i;
+ TxBAStreamTbl *del_tbl_ptr = MNULL;
+
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ while ((del_tbl_ptr = (TxBAStreamTbl *)util_peek_list(
+ priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MNULL, MNULL))) {
+ wlan_11n_delete_txbastream_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list)&priv->tx_ba_stream_tbl_ptr);
+ wlan_release_ralist_lock(priv);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will return the pointer to an entry in BA Stream
+ * table which matches the give RA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to find in reordering table
+ * @param ra RA to find in reordering table
+ * @param lock flag for request the spin_lock
+ *
+ * @return A pointer to first entry matching RA/TID in BA stream
+ * NULL if not found
+ */
+TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private *priv, int tid,
+ t_u8 *ra, int lock)
+{
+ TxBAStreamTbl *ptx_tbl;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (lock)
+ wlan_request_ralist_lock(priv);
+ ptx_tbl = (TxBAStreamTbl *)util_peek_list(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptx_tbl) {
+ if (lock)
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return MNULL;
+ }
+
+ while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ PRINTM(MDAT_D, "get_txbastream_tbl TID %d\n", ptx_tbl->tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ptx_tbl->ra, MLAN_MAC_ADDR_LENGTH);
+
+ if ((!memcmp(pmadapter, ptx_tbl->ra, ra,
+ MLAN_MAC_ADDR_LENGTH)) &&
+ (ptx_tbl->tid == tid)) {
+ if (lock)
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return ptx_tbl;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ if (lock)
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will create a entry in tx ba stream table for the
+ * given RA/TID.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in reordering table
+ * @param tid TID to find in reordering table
+ * @param ba_status BA stream status to create the stream with
+ *
+ * @return N/A
+ */
+void wlan_11n_create_txbastream_tbl(mlan_private *priv, t_u8 *ra, int tid,
+ baStatus_e ba_status)
+{
+ TxBAStreamTbl *new_node = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ raListTbl *ra_list = MNULL;
+ int tid_down;
+
+ ENTER();
+
+ PRINTM(MDAT_D, "create_txbastream_tbl TID %d\n", tid);
+ DBG_HEXDUMP(MDAT_D, "RA", ra, MLAN_MAC_ADDR_LENGTH);
+
+ if (pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, sizeof(TxBAStreamTbl),
+ MLAN_MEM_DEF, (t_u8 **)&new_node)) {
+ PRINTM(MERROR,
+ "wlan_11n_create_txbastream_tbl Failed to allocate new_node\n");
+ LEAVE();
+ return;
+ }
+ tid_down = wlan_get_wmm_tid_down(priv, tid);
+ ra_list = wlan_wmm_get_ralist_node(priv, tid_down, ra);
+ if (ra_list) {
+ ra_list->amsdu_in_ampdu = MFALSE;
+ ra_list->ba_status = ba_status;
+ }
+ util_init_list((pmlan_linked_list)new_node);
+
+ new_node->tid = tid;
+ new_node->ba_status = ba_status;
+ memcpy_ext(pmadapter, new_node->ra, ra, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ (pmlan_linked_list)new_node, MNULL, MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will send a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int wlan_send_addba(mlan_private *priv, int tid, t_u8 *peer_mac)
+{
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ static t_u8 dialog_tok;
+ mlan_status ret;
+
+ ENTER();
+
+ PRINTM(MCMND, "Send addba: TID %d\n", tid);
+ DBG_HEXDUMP(MCMD_D, "Send addba RA", peer_mac, MLAN_MAC_ADDR_LENGTH);
+
+ add_ba_req.block_ack_param_set = (t_u16)(
+ (tid << BLOCKACKPARAM_TID_POS) |
+ (priv->add_ba_param.tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
+ IMMEDIATE_BLOCK_ACK);
+ /** enable AMSDU inside AMPDU */
+ if (priv->add_ba_param.tx_amsdu &&
+ (priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED))
+ add_ba_req.block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ add_ba_req.block_ack_tmo = (t_u16)priv->add_ba_param.timeout;
+
+ ++dialog_tok;
+
+ if (dialog_tok == 0)
+ dialog_tok = 1;
+
+ add_ba_req.dialog_token = dialog_tok;
+ memcpy_ext(priv->adapter, &add_ba_req.peer_mac_addr, peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ /* We don't wait for the response of this command */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, 0, 0, MNULL,
+ &add_ba_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete a block ack to given tid/ra
+ *
+ * @param priv A pointer to mlan_private
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param tid TID to send the ADDBA
+ * @param peer_mac MAC address to send the ADDBA
+ * @param initiator MTRUE if we have initiated ADDBA, MFALSE otherwise
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+int wlan_send_delba(mlan_private *priv, pmlan_ioctl_req pioctl_req, int tid,
+ t_u8 *peer_mac, int initiator)
+{
+ HostCmd_DS_11N_DELBA delba;
+ mlan_status ret;
+
+ ENTER();
+
+ memset(priv->adapter, &delba, 0, sizeof(delba));
+ delba.del_ba_param_set = (tid << DELBA_TID_POS);
+
+ if (initiator)
+ DELBA_INITIATOR(delba.del_ba_param_set);
+ else
+ DELBA_RECIPIENT(delba.del_ba_param_set);
+
+ memcpy_ext(priv->adapter, &delba.peer_mac_addr, peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, HostCmd_ACT_GEN_SET,
+ 0, (t_void *)pioctl_req, (t_void *)&delba);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of
+ * delete a block ack request
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param del_ba A pointer to command response buffer
+ *
+ * @return N/A
+ */
+void wlan_11n_delete_bastream(mlan_private *priv, t_u8 *del_ba)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)del_ba;
+ int tid;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Delba:", (t_u8 *)pdel_ba, 20);
+ pdel_ba->del_ba_param_set = wlan_le16_to_cpu(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_le16_to_cpu(pdel_ba->reason_code);
+
+ tid = pdel_ba->del_ba_param_set >> DELBA_TID_POS;
+
+ mlan_11n_delete_bastream_tbl(priv, tid, pdel_ba->peer_mac_addr,
+ TYPE_DELBA_RECEIVE,
+ INITIATOR_BIT(pdel_ba->del_ba_param_set),
+ pdel_ba->reason_code);
+
+ LEAVE();
+}
+
+/**
+ * @brief Get Rx reordering table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to rx_reorder_tbl structure
+ * @return number of rx reorder table entry
+ */
+int wlan_get_rxreorder_tbl(mlan_private *priv, rx_reorder_tbl *buf)
+{
+ int i;
+ rx_reorder_tbl *ptbl = buf;
+ RxReorderTbl *rx_reorder_tbl_ptr;
+ int count = 0;
+ ENTER();
+ priv->adapter->callbacks.moal_spin_lock(priv->adapter->pmoal_handle,
+ priv->rx_reorder_tbl_ptr.plock);
+ rx_reorder_tbl_ptr =
+ (RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr, MNULL,
+ MNULL);
+ if (!rx_reorder_tbl_ptr) {
+ priv->adapter->callbacks.moal_spin_unlock(
+ priv->adapter->pmoal_handle,
+ priv->rx_reorder_tbl_ptr.plock);
+ LEAVE();
+ return count;
+ }
+ while (rx_reorder_tbl_ptr !=
+ (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ ptbl->tid = (t_u16)rx_reorder_tbl_ptr->tid;
+ memcpy_ext(priv->adapter, ptbl->ta, rx_reorder_tbl_ptr->ta,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ ptbl->start_win = rx_reorder_tbl_ptr->start_win;
+ ptbl->win_size = rx_reorder_tbl_ptr->win_size;
+ ptbl->amsdu = rx_reorder_tbl_ptr->amsdu;
+ for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+ ptbl->buffer[i] = MTRUE;
+ else
+ ptbl->buffer[i] = MFALSE;
+ }
+ rx_reorder_tbl_ptr = rx_reorder_tbl_ptr->pnext;
+ ptbl++;
+ count++;
+ if (count >= MLAN_MAX_RX_BASTREAM_SUPPORTED)
+ break;
+ }
+ priv->adapter->callbacks.moal_spin_unlock(
+ priv->adapter->pmoal_handle, priv->rx_reorder_tbl_ptr.plock);
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief Get transmit BA stream table
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to tx_ba_stream_tbl structure
+ * @return number of ba stream table entry
+ */
+int wlan_get_txbastream_tbl(mlan_private *priv, tx_ba_stream_tbl *buf)
+{
+ TxBAStreamTbl *ptxtbl;
+ tx_ba_stream_tbl *ptbl = buf;
+ int count = 0;
+ t_u32 bastream_max = 0;
+
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ ptxtbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptxtbl) {
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return count;
+ }
+ bastream_max = ISSUPP_GETTXBASTREAM(priv->adapter->hw_dot_11n_dev_cap);
+ if (bastream_max == 0)
+ bastream_max = MLAN_MAX_TX_BASTREAM_DEFAULT;
+
+ while (ptxtbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ ptbl->tid = (t_u16)ptxtbl->tid;
+ PRINTM(MINFO, "tid=%d\n", ptbl->tid);
+ memcpy_ext(priv->adapter, ptbl->ra, ptxtbl->ra,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ ptbl->amsdu = ptxtbl->amsdu;
+ ptxtbl = ptxtbl->pnext;
+ ptbl++;
+ count++;
+ if (count >= bastream_max)
+ break;
+ }
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function check if 11AC is allowed in bandcfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_band bss band
+ *
+ * @return 0--not allowed, other value allowed
+ */
+t_u8 wlan_11n_bandconfig_allowed(mlan_private *pmpriv, t_u8 bss_band)
+{
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ if (bss_band & BAND_G)
+ return (pmpriv->adapter->adhoc_start_band & BAND_GN);
+ else if (bss_band & BAND_A)
+ return (pmpriv->adapter->adhoc_start_band & BAND_AN);
+ } else {
+ if (bss_band & BAND_G)
+ return (pmpriv->config_bands & BAND_GN);
+ else if (bss_band & BAND_A)
+ return (pmpriv->config_bands & BAND_AN);
+ }
+ return 0;
+}
+
+/**
+ * @brief This function cleans up txbastream_tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra RA to find in txbastream_tbl
+ * @return N/A
+ */
+void wlan_11n_cleanup_txbastream_tbl(mlan_private *priv, t_u8 *ra)
+{
+ TxBAStreamTbl *ptx_tbl = MNULL;
+ t_u8 i;
+ ENTER();
+
+ wlan_request_ralist_lock(priv);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ptx_tbl = wlan_11n_get_txbastream_tbl(priv, i, ra, MFALSE);
+ if (ptx_tbl)
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptx_tbl);
+ }
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return;
+}
+
+void wlan_update_11n_cap(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ pmpriv->usr_dev_mcs_support = pmadapter->hw_dev_mcs_support;
+ pmpriv->usr_dot_11n_dev_cap_bg =
+ pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_BG;
+ pmpriv->usr_dot_11n_dev_cap_a =
+ pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_A;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.h
new file mode 100644
index 000000000000..9e3de59c5542
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n.h
@@ -0,0 +1,408 @@
+/** @file mlan_11n.h
+ *
+ * @brief Interface for the 802.11n mlan_11n module implemented in mlan_11n.c
+ *
+ * Driver interface functions and type declarations for the 11n module
+ * implemented in mlan_11n.c.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 12/01/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_H_
+#define _MLAN_11N_H_
+
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#include "mlan_wmm.h"
+
+/** Print the 802.11n device capability */
+void wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap);
+/** Print the 802.11n device MCS */
+void wlan_show_devmcssupport(pmlan_adapter pmadapter, t_u8 support);
+/** Handle the command response of a delete block ack request */
+mlan_status wlan_ret_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *resp);
+/** Handle the command response of an add block ack request */
+mlan_status wlan_ret_11n_addba_req(mlan_private *priv,
+ HostCmd_DS_COMMAND *resp);
+/** Handle the command response of 11ncfg command */
+mlan_status wlan_ret_11n_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** Prepare 11ncfg command */
+mlan_status wlan_cmd_11n_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+/** Prepare reject addba requst command */
+mlan_status wlan_cmd_reject_addba_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+/** Handle the command response of rejecting addba request */
+mlan_status wlan_ret_reject_addba_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** Prepare TX BF configuration command */
+mlan_status wlan_cmd_tx_bf_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+/** Handle the command response TX BF configuration */
+mlan_status wlan_ret_tx_bf_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+#ifdef STA_SUPPORT
+t_u8 wlan_11n_bandconfig_allowed(mlan_private *pmpriv, t_u8 bss_band);
+/** Append the 802_11N tlv */
+int wlan_cmd_append_11n_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **ppbuffer);
+/** wlan fill HT cap tlv */
+void wlan_fill_ht_cap_tlv(mlan_private *priv, MrvlIETypes_HTCap_t *pht_cap,
+ t_u16 band, t_u8 fill);
+/** wlan fill HT cap IE */
+void wlan_fill_ht_cap_ie(mlan_private *priv, IEEEtypes_HTCap_t *pht_cap,
+ t_u16 bands);
+#endif /* STA_SUPPORT */
+/** Miscellaneous configuration handler */
+mlan_status wlan_11n_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/** Delete Tx BA stream table entry */
+void wlan_11n_delete_txbastream_tbl_entry(mlan_private *priv,
+ TxBAStreamTbl *ptx_tbl);
+/** Delete all Tx BA stream table entries */
+void wlan_11n_deleteall_txbastream_tbl(mlan_private *priv);
+/** Get Tx BA stream table */
+TxBAStreamTbl *wlan_11n_get_txbastream_tbl(mlan_private *priv, int tid,
+ t_u8 *ra, int lock);
+/** Create Tx BA stream table */
+void wlan_11n_create_txbastream_tbl(mlan_private *priv, t_u8 *ra, int tid,
+ baStatus_e ba_status);
+/** Send ADD BA request */
+int wlan_send_addba(mlan_private *priv, int tid, t_u8 *peer_mac);
+/** Send DEL BA request */
+int wlan_send_delba(mlan_private *priv, pmlan_ioctl_req pioctl_req, int tid,
+ t_u8 *peer_mac, int initiator);
+/** This function handles the command response of delete a block ack request*/
+void wlan_11n_delete_bastream(mlan_private *priv, t_u8 *del_ba);
+/** get rx reorder table */
+int wlan_get_rxreorder_tbl(mlan_private *priv, rx_reorder_tbl *buf);
+/** get tx ba stream table */
+int wlan_get_txbastream_tbl(mlan_private *priv, tx_ba_stream_tbl *buf);
+/** send delba */
+void wlan_11n_delba(mlan_private *priv, int tid);
+/** update amdpdu tx win size */
+void wlan_update_ampdu_txwinsize(pmlan_adapter pmadapter);
+/** Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+/** AMSDU Aggr control cmd resp */
+mlan_status wlan_ret_amsdu_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+void wlan_set_tx_pause_flag(mlan_private *priv, t_u8 flag);
+/** reconfigure tx buf size */
+mlan_status wlan_cmd_recfg_tx_buf(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ int cmd_action, void *pdata_buf);
+/** AMSDU aggr control cmd */
+mlan_status wlan_cmd_amsdu_aggr_ctrl(mlan_private *priv,
+ HostCmd_DS_COMMAND *cmd, int cmd_action,
+ void *pdata_buf);
+
+t_u8 wlan_validate_chan_offset(mlan_private *pmpriv, t_u16 band, t_u32 chan,
+ t_u8 chan_bw);
+/** get channel offset */
+t_u8 wlan_get_second_channel_offset(int chan);
+
+void wlan_update_11n_cap(mlan_private *pmpriv);
+
+/** clean up txbastream_tbl */
+void wlan_11n_cleanup_txbastream_tbl(mlan_private *priv, t_u8 *ra);
+/**
+ * @brief This function checks whether a station has 11N enabled or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 is_station_11n_enabled(mlan_private *priv, t_u8 *mac)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr)
+ return (sta_ptr->is_11n_enabled) ? MTRUE : MFALSE;
+ return MFALSE;
+}
+
+/**
+ * @brief This function get station max amsdu size
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station mac address
+ * @return max amsdu size statio supported
+ */
+static INLINE t_u16 get_station_max_amsdu_size(mlan_private *priv, t_u8 *mac)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr)
+ return sta_ptr->max_amsdu;
+ return 0;
+}
+
+/**
+ * @brief This function checks whether a station allows AMPDU or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 is_station_ampdu_allowed(mlan_private *priv, raListTbl *ptr,
+ int tid)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, ptr->ra);
+ if (sta_ptr) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (priv->sec_info.wapi_enabled &&
+ !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ return (sta_ptr->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ?
+ MTRUE :
+ MFALSE;
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function disable station ampdu for specific tid
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid index
+ * @param ra station mac address
+ * @return N/A
+ */
+static INLINE void disable_station_ampdu(mlan_private *priv, t_u8 tid, t_u8 *ra)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, ra);
+ if (sta_ptr)
+ sta_ptr->ampdu_sta[tid] = BA_STREAM_NOT_ALLOWED;
+ return;
+}
+
+/**
+ * @brief This function reset station ampdu for specific id to user setting.
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid index
+ * @param ra station mac address
+ * @return N/A
+ */
+static INLINE void reset_station_ampdu(mlan_private *priv, t_u8 tid, t_u8 *ra)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, ra);
+ if (sta_ptr)
+ sta_ptr->ampdu_sta[tid] = priv->aggr_prio_tbl[tid].ampdu_user;
+ return;
+}
+
+#define IS_BG_RATE (priv->bitmap_rates[0] || priv->bitmap_rates[1])
+/**
+ * @brief This function checks whether AMPDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 wlan_is_ampdu_allowed(mlan_private *priv, raListTbl *ptr,
+ int tid)
+{
+ if ((!priv->is_data_rate_auto) && IS_BG_RATE)
+ return MFALSE;
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ return is_station_ampdu_allowed(priv, ptr, tid);
+#endif /* UAP_SUPPORT */
+ if (priv->sec_info.wapi_enabled && !priv->sec_info.wapi_key_on)
+ return MFALSE;
+ return (priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) ?
+ MTRUE :
+ MFALSE;
+}
+
+#define BA_RSSI_HIGH_THRESHOLD -70
+
+static INLINE void wlan_update_station_del_ba_count(mlan_private *priv,
+ raListTbl *ptr)
+{
+ sta_node *sta_ptr = MNULL;
+ t_s8 rssi;
+ sta_ptr = wlan_get_station_entry(priv, ptr->ra);
+ if (sta_ptr) {
+ rssi = sta_ptr->snr - sta_ptr->nf;
+ if (rssi > BA_RSSI_HIGH_THRESHOLD)
+ ptr->del_ba_count = 0;
+ }
+ return;
+}
+
+static INLINE void wlan_update_del_ba_count(mlan_private *priv, raListTbl *ptr)
+{
+ t_s8 rssi;
+#ifdef UAP_802_11N
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ return wlan_update_station_del_ba_count(priv, ptr);
+#endif /* UAP_SUPPORT */
+#endif /* UAP_802_11N */
+ rssi = priv->snr - priv->nf;
+ if (rssi > BA_RSSI_HIGH_THRESHOLD)
+ ptr->del_ba_count = 0;
+}
+
+/**
+ * @brief This function checks whether AMSDU is allowed or not
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param tid TID value for ptr
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 wlan_is_amsdu_allowed(mlan_private *priv, raListTbl *ptr,
+ int tid)
+{
+#ifdef UAP_SUPPORT
+ sta_node *sta_ptr = MNULL;
+#endif
+ if (priv->amsdu_disable)
+ return MFALSE;
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ sta_ptr = wlan_get_station_entry(priv, ptr->ra);
+ if (sta_ptr) {
+ if (priv->sec_info.wapi_enabled &&
+ !sta_ptr->wapi_key_on)
+ return MFALSE;
+ }
+ }
+#endif /* UAP_SUPPORT */
+#define TXRATE_BITMAP_INDEX_MCS0_7 2
+ return ((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) &&
+ ((priv->is_data_rate_auto) ||
+ !(((priv->bitmap_rates[TXRATE_BITMAP_INDEX_MCS0_7]) & 0x03) ||
+ IS_BG_RATE))) ?
+ MTRUE :
+ MFALSE;
+}
+
+/**
+ * @brief This function checks whether a BA stream is available or not
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 wlan_is_bastream_avail(mlan_private *priv)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i = 0;
+ t_u32 bastream_num = 0;
+ t_u32 bastream_max = 0;
+ for (i = 0; i < priv->adapter->priv_num; i++) {
+ pmpriv = priv->adapter->priv[i];
+ if (pmpriv)
+ bastream_num += wlan_wmm_list_len(
+ (pmlan_list_head)&pmpriv->tx_ba_stream_tbl_ptr);
+ }
+ bastream_max = ISSUPP_GETTXBASTREAM(priv->adapter->hw_dot_11n_dev_cap);
+ if (bastream_max == 0)
+ bastream_max = MLAN_MAX_TX_BASTREAM_DEFAULT;
+ return (bastream_num < bastream_max) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief This function finds the stream to delete
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptr_tid TID value of ptr
+ * @param ptid A pointer to TID of stream to delete, if return MTRUE
+ * @param ra RA of stream to delete, if return MTRUE
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 wlan_find_stream_to_delete(mlan_private *priv,
+ raListTbl *ptr, int ptr_tid,
+ int *ptid, t_u8 *ra)
+{
+ int tid;
+ t_u8 ret = MFALSE;
+ TxBAStreamTbl *ptx_tbl;
+
+ ENTER();
+
+ ptx_tbl = (TxBAStreamTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ MNULL, MNULL);
+ if (!ptx_tbl) {
+ LEAVE();
+ return ret;
+ }
+
+ tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
+
+ while (ptx_tbl != (TxBAStreamTbl *)&priv->tx_ba_stream_tbl_ptr) {
+ if (tid > priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user) {
+ tid = priv->aggr_prio_tbl[ptx_tbl->tid].ampdu_user;
+ *ptid = ptx_tbl->tid;
+ memcpy_ext(priv->adapter, ra, ptx_tbl->ra,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ ret = MTRUE;
+ }
+
+ ptx_tbl = ptx_tbl->pnext;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks whether 11n is supported
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE int wlan_is_11n_enabled(mlan_private *priv, t_u8 *ra)
+{
+ int ret = MFALSE;
+ ENTER();
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if ((!(ra[0] & 0x01)) && (priv->is_11n_enabled))
+ ret = is_station_11n_enabled(priv, ra);
+ }
+#endif /* UAP_SUPPORT */
+ LEAVE();
+ return ret;
+}
+#endif /* !_MLAN_11N_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.c
new file mode 100644
index 000000000000..17cd78d02eb0
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.c
@@ -0,0 +1,603 @@
+/** @file mlan_11n_aggr.c
+ *
+ * @brief This file contains functions for 11n Aggregation.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_aggr.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Aggregate individual packets into one AMSDU packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param amsdu_buf A pointer to packet buffer
+ * @param data A pointer to aggregated data packet being formed
+ * @param pkt_len Length of current packet to aggregate
+ * @param pad Pad
+ *
+ * @return Final packet size
+ */
+static int wlan_11n_form_amsdu_pkt(pmlan_adapter pmadapter, t_u8 *amsdu_buf,
+ t_u8 *data, int pkt_len, int *pad)
+{
+ int dt_offset, amsdu_buf_offset;
+ Rfc1042Hdr_t snap = {
+ 0xaa, /* LLC DSAP */
+ 0xaa, /* LLC SSAP */
+ 0x03, /* LLC CTRL */
+ {0x00, 0x00, 0x00}, /* SNAP OUI */
+ 0x0000 /* SNAP type */
+ /*
+ * This field will be overwritten
+ * later with ethertype
+ */
+ };
+
+ ENTER();
+
+ memcpy_ext(pmadapter, amsdu_buf, data, (MLAN_MAC_ADDR_LENGTH)*2,
+ (MLAN_MAC_ADDR_LENGTH)*2);
+ dt_offset = amsdu_buf_offset = (MLAN_MAC_ADDR_LENGTH)*2;
+
+ snap.snap_type = *(t_u16 *)(data + dt_offset);
+ dt_offset += sizeof(t_u16);
+ *(t_u16 *)(amsdu_buf + amsdu_buf_offset) =
+ mlan_htons(pkt_len + LLC_SNAP_LEN -
+ ((2 * MLAN_MAC_ADDR_LENGTH) + sizeof(t_u16)));
+ amsdu_buf_offset += sizeof(t_u16);
+ memcpy_ext(pmadapter, amsdu_buf + amsdu_buf_offset, &snap, LLC_SNAP_LEN,
+ LLC_SNAP_LEN);
+ amsdu_buf_offset += LLC_SNAP_LEN;
+
+ memcpy_ext(pmadapter, amsdu_buf + amsdu_buf_offset, data + dt_offset,
+ pkt_len - dt_offset, pkt_len - dt_offset);
+ *pad = (((pkt_len + LLC_SNAP_LEN) & 3)) ?
+ (4 - (((pkt_len + LLC_SNAP_LEN)) & 3)) :
+ 0;
+
+ LEAVE();
+ return pkt_len + LLC_SNAP_LEN + *pad;
+}
+
+/**
+ * @brief Add TxPD to AMSDU header
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf Pointer to buffer where the TxPD will be formed
+ *
+ * @return N/A
+ */
+static void wlan_11n_form_amsdu_txpd(mlan_private *priv, mlan_buffer *mbuf)
+{
+ TxPD *ptx_pd;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+
+ ptx_pd = (TxPD *)mbuf->pbuf;
+ memset(pmadapter, ptx_pd, 0, sizeof(TxPD));
+
+ /*
+ * Original priority has been overwritten
+ */
+ ptx_pd->priority = (t_u8)mbuf->priority;
+ ptx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(priv, mbuf);
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+ /* Always zero as the data is followed by TxPD */
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ ptx_pd->tx_pkt_type = PKT_TYPE_AMSDU;
+ if (ptx_pd->tx_control == 0)
+ /* TxCtrl set by user or default */
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+
+ endian_convert_TxPD(ptx_pd);
+
+ LEAVE();
+}
+
+/**
+ * @brief Update the TxPktLength field in TxPD after the complete AMSDU
+ * packet is formed
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param mbuf TxPD buffer
+ *
+ * @return N/A
+ */
+static INLINE void wlan_11n_update_pktlen_amsdu_txpd(mlan_private *priv,
+ pmlan_buffer mbuf)
+{
+ TxPD *ptx_pd;
+ ENTER();
+
+ ptx_pd = (TxPD *)mbuf->pbuf;
+ ptx_pd->tx_pkt_length =
+ (t_u16)wlan_cpu_to_le16(mbuf->data_len - sizeof(TxPD));
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->adapter->pps_uapsd_mode)) {
+ if (MTRUE == wlan_check_last_packet_indication(priv)) {
+ priv->adapter->tx_lock_flag = MTRUE;
+ ptx_pd->flags |= MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+#endif /* STA_SUPPORT */
+ LEAVE();
+}
+
+/**
+ * @brief Get number of aggregated packets
+ *
+ * @param data A pointer to packet data
+ * @param total_pkt_len Total packet length
+ *
+ * @return Number of packets
+ */
+static int wlan_11n_get_num_aggrpkts(t_u8 *data, int total_pkt_len)
+{
+ int pkt_count = 0, pkt_len, pad;
+ t_u8 hdr_len = sizeof(Eth803Hdr_t);
+
+ ENTER();
+ while (total_pkt_len >= hdr_len) {
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs(
+ (*(t_u16 *)(data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ if (pkt_len > total_pkt_len) {
+ PRINTM(MERROR, "Error in packet length.\n");
+ break;
+ }
+
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) :
+ 0;
+ data += pkt_len + pad + sizeof(Eth803Hdr_t);
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+ ++pkt_count;
+ }
+ LEAVE();
+ return pkt_count;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Deaggregate the received AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to aggregated data packet
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_11n_deaggregate_pkt(mlan_private *priv, pmlan_buffer pmbuf)
+{
+ t_u16 pkt_len;
+ int total_pkt_len;
+ t_u8 *data;
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE;
+ int pad;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ RxPacketHdr_t *prx_pkt;
+ mlan_buffer *daggr_mbuf = MNULL;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = {0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0x00};
+ t_u8 hdr_len = sizeof(Eth803Hdr_t);
+ t_u8 eapol_type[2] = {0x88, 0x8e};
+
+ ENTER();
+
+ data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ total_pkt_len = pmbuf->data_len;
+
+ /* Sanity test */
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type) &&
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable) {
+ max_rx_data_size =
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_max;
+ if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_NUM) {
+ max_rx_data_size *=
+ MAX(MLAN_USB_MAX_PKT_SIZE,
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align);
+ max_rx_data_size =
+ MAX(max_rx_data_size, MLAN_RX_DATA_BUF_SIZE);
+ }
+ }
+#endif
+ if (total_pkt_len > max_rx_data_size) {
+ PRINTM(MERROR,
+ "Total packet length greater than tx buffer"
+ " size %d\n",
+ total_pkt_len);
+ goto done;
+ }
+
+ pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len);
+
+ // rx_trace 7
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf, 7 /*RX_DROP_P3*/);
+ if (pmadapter->tp_state_drop_point == 7 /*RX_DROP_P3*/)
+ goto done;
+
+ while (total_pkt_len >= hdr_len) {
+ prx_pkt = (RxPacketHdr_t *)data;
+ /* Length will be in network format, change it to host */
+ pkt_len = mlan_ntohs(
+ (*(t_u16 *)(data + (2 * MLAN_MAC_ADDR_LENGTH))));
+ if (pkt_len > total_pkt_len) {
+ PRINTM(MERROR,
+ "Error in packet length: total_pkt_len = %d, pkt_len = %d\n",
+ total_pkt_len, pkt_len);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ?
+ (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) :
+ 0;
+
+ total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t);
+
+ if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr, rfc1042_eth_hdr,
+ sizeof(rfc1042_eth_hdr)) == 0) {
+ memmove(pmadapter, data + LLC_SNAP_LEN, data,
+ (2 * MLAN_MAC_ADDR_LENGTH));
+ data += LLC_SNAP_LEN;
+ pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN;
+ } else {
+ *(t_u16 *)(data + (2 * MLAN_MAC_ADDR_LENGTH)) =
+ (t_u16)0;
+ pkt_len += sizeof(Eth803Hdr_t);
+ }
+ daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter,
+ pkt_len + MLAN_NET_IP_ALIGN,
+ 0, MOAL_ALLOC_MLAN_BUFFER);
+ if (daggr_mbuf == MNULL) {
+ PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ daggr_mbuf->data_offset += MLAN_NET_IP_ALIGN;
+ daggr_mbuf->bss_index = pmbuf->bss_index;
+ daggr_mbuf->buf_type = pmbuf->buf_type;
+ daggr_mbuf->data_len = pkt_len;
+ daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec;
+ daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec;
+ daggr_mbuf->pparent = pmbuf;
+ daggr_mbuf->priority = pmbuf->priority;
+ memcpy_ext(pmadapter,
+ daggr_mbuf->pbuf + daggr_mbuf->data_offset, data,
+ pkt_len, daggr_mbuf->data_len);
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_uap_recv_packet(priv, daggr_mbuf);
+ } else {
+#endif /* UAP_SUPPORT */
+ /** send EAPOL from AMSDU pkt to firmware */
+ if (priv->sec_info.ewpa_enabled &&
+ (!memcmp(pmadapter,
+ daggr_mbuf->pbuf +
+ daggr_mbuf->data_offset +
+ MLAN_ETHER_PKT_TYPE_OFFSET,
+ eapol_type, sizeof(eapol_type)))) {
+ ret = wlan_prepare_cmd(
+ priv, HostCmd_CMD_802_11_EAPOL_PKT, 0,
+ 0, MNULL, daggr_mbuf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ wlan_recv_event(
+ priv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ wlan_free_mlan_buffer(pmadapter, daggr_mbuf);
+ data += pkt_len + pad;
+ continue;
+ }
+
+ ret = pmadapter->callbacks.moal_recv_packet(
+ pmadapter->pmoal_handle, daggr_mbuf);
+#ifdef UAP_SUPPORT
+ }
+#endif /* UAP_SUPPORT */
+ switch (ret) {
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_FAILURE:
+ PRINTM(MERROR, "Deaggr, send to moal failed\n");
+ daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ /* fall through */
+ case MLAN_STATUS_SUCCESS:
+ wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ data += pkt_len + pad;
+ }
+
+done:
+ priv->msdu_in_rx_amsdu_cnt += pmbuf->use_count;
+ priv->amsdu_rx_cnt++;
+ /** we should free the aggr buffer after deaggr */
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Aggregate multiple packets into one single AMSDU packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pra_list Pointer to the RA List table containing the pointers
+ * to packets.
+ * @param headroom Any interface specific headroom that may be need. TxPD
+ * will be formed leaving this headroom.
+ * @param ptrindex Pointer index
+ *
+ * @return Final packet size or MLAN_STATUS_FAILURE
+ */
+int wlan_11n_aggregate_pkt(mlan_private *priv, raListTbl *pra_list,
+ int headroom, int ptrindex)
+{
+ int pkt_size = 0;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_buffer *pmbuf_aggr, *pmbuf_src;
+ t_u8 *data;
+ int pad = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+ mlan_tx_param tx_param;
+#ifdef STA_SUPPORT
+ TxPD *ptx_pd = MNULL;
+#endif
+ t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size);
+ ENTER();
+
+ PRINTM(MDAT_D, "Handling Aggr packet\n");
+
+ pmbuf_src = (pmlan_buffer)util_peek_list(
+ pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL);
+ if (pmbuf_src) {
+ pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter,
+ pmadapter->tx_buf_size, 0,
+ MOAL_MALLOC_BUFFER);
+ if (!pmbuf_aggr) {
+ PRINTM(MERROR, "Error allocating mlan_buffer\n");
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ data = pmbuf_aggr->pbuf + headroom;
+ pmbuf_aggr->bss_index = pmbuf_src->bss_index;
+ pmbuf_aggr->buf_type = pmbuf_src->buf_type;
+ pmbuf_aggr->priority = pmbuf_src->priority;
+ pmbuf_aggr->pbuf = data;
+ pmbuf_aggr->data_offset = 0;
+ pmbuf_aggr->in_ts_sec = pmbuf_src->in_ts_sec;
+ pmbuf_aggr->in_ts_usec = pmbuf_src->in_ts_usec;
+ if (pmbuf_src->flags & MLAN_BUF_FLAG_TCP_ACK)
+ pmbuf_aggr->flags |= MLAN_BUF_FLAG_TCP_ACK;
+
+ /* Form AMSDU */
+ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr);
+ pkt_size = sizeof(TxPD);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ ptx_pd = (TxPD *)pmbuf_aggr->pbuf;
+#endif
+ priv->msdu_in_tx_amsdu_cnt++;
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ goto exit;
+ }
+
+ while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) +
+ headroom) <= max_amsdu_size)) {
+ pmbuf_src =
+ (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head,
+ MNULL, MNULL);
+ /* Collects TP statistics */
+ if (pmadapter->tp_state_on && (pkt_size > sizeof(TxPD)))
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf_src->pdesc, 3);
+ pra_list->total_pkts--;
+
+ /* decrement for every PDU taken from the list */
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+
+ if (pmbuf_src) {
+ pkt_size += wlan_11n_form_amsdu_pkt(
+ pmadapter, (data + pkt_size),
+ pmbuf_src->pbuf + pmbuf_src->data_offset,
+ pmbuf_src->data_len, &pad);
+
+ DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src,
+ sizeof(mlan_buffer));
+ wlan_write_data_complete(pmadapter, pmbuf_src,
+ MLAN_STATUS_SUCCESS);
+ }
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf_src =
+ (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
+ &pra_list->buf_head, MNULL,
+ MNULL);
+ priv->msdu_in_tx_amsdu_cnt++;
+ }
+
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ /* Last AMSDU packet does not need padding */
+ pkt_size -= pad;
+ pmbuf_aggr->data_len = pkt_size;
+ wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr);
+ pmbuf_aggr->data_len += headroom;
+ pmbuf_aggr->pbuf = data - headroom;
+ tx_param.next_pkt_len =
+ ((pmbuf_src) ? pmbuf_src->data_len + sizeof(TxPD) : 0);
+ /* Collects TP statistics */
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(pmadapter->pmoal_handle,
+ pmbuf_aggr, 4);
+
+ /* Drop Tx packets at drop point 4 */
+ if (pmadapter->tp_state_drop_point == 4) {
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ goto exit;
+ } else
+ ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA,
+ pmbuf_aggr, &tx_param);
+ switch (ret) {
+#ifdef USB
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ break;
+#endif
+ case MLAN_STATUS_RESOURCE:
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef STA_SUPPORT
+ /* reset tx_lock_flag */
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode &&
+ (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ if (ptx_pd != MNULL)
+ ptx_pd->flags = 0;
+ }
+#endif
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pra_list->buf_head,
+ (pmlan_linked_list)pmbuf_aggr, MNULL,
+ MNULL);
+
+ pra_list->total_pkts++;
+
+ /* add back only one: aggregated packet is requeued as one */
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ goto exit;
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority]
+ .bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ }
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+ priv->amsdu_tx_cnt++;
+
+exit:
+ LEAVE();
+ return pkt_size + headroom;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.h
new file mode 100644
index 000000000000..96a278312ac2
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_aggr.h
@@ -0,0 +1,38 @@
+/** @file mlan_11n_aggr.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n aggregation functionalities
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_AGGR_H_
+#define _MLAN_11N_AGGR_H_
+
+/** Aggregate 11N packets */
+mlan_status wlan_11n_deaggregate_pkt(pmlan_private priv, pmlan_buffer pmbuf);
+/** Deaggregate 11N packets */
+int wlan_11n_aggregate_pkt(mlan_private *priv, raListTbl *ptr, int headroom,
+ int ptrindex);
+
+#endif /* !_MLAN_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.c
new file mode 100644
index 000000000000..68dbd07d9f68
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.c
@@ -0,0 +1,1497 @@
+/** @file mlan_11n_rxreorder.c
+ *
+ * @brief This file contains the handling of RxReordering in wlan
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function will dispatch amsdu packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_11n_dispatch_amsdu_pkt(mlan_private *priv,
+ pmlan_buffer pmbuf)
+{
+ RxPD *prx_pd;
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+
+ ENTER();
+ if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ pmbuf->data_len = prx_pd->rx_pkt_length;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ wlan_11n_deaggregate_pkt(priv, pmbuf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function will process the rx packet and
+ * forward it to kernel/upper layer
+ *
+ * @param priv A pointer to mlan_private
+ * @param payload A pointer to rx packet payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_11n_dispatch_pkt(t_void *priv, t_void *payload)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ pmlan_adapter pmadapter = ((pmlan_private)priv)->adapter;
+#endif
+ ENTER();
+ if (payload == (t_void *)RX_PKT_DROPPED_IN_FW) {
+ LEAVE();
+ return ret;
+ }
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE((mlan_private *)priv) == MLAN_BSS_ROLE_UAP) {
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
+ (pmlan_buffer)payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_uap_rx_packet(priv, (pmlan_buffer)payload);
+ LEAVE();
+ return ret;
+ }
+#endif /* UAP_SUPPORT */
+
+#ifdef STA_SUPPORT
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
+ (pmlan_buffer)payload)) {
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer)payload);
+#endif /* STA_SUPPORT */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function restarts the reordering timeout timer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static void mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,
+ RxReorderTbl *rx_reor_tbl_ptr)
+{
+ t_u16 min_flush_time = 0;
+ ENTER();
+
+ if (rx_reor_tbl_ptr->win_size >= 32)
+ min_flush_time = MIN_FLUSH_TIMER_15_MS;
+ else
+ min_flush_time = MIN_FLUSH_TIMER_MS;
+
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set)
+ pmadapter->callbacks.moal_stop_timer(
+ pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.timer);
+
+ pmadapter->callbacks.moal_start_timer(
+ pmadapter->pmoal_handle, rx_reor_tbl_ptr->timer_context.timer,
+ MFALSE, (rx_reor_tbl_ptr->win_size * min_flush_time));
+
+ rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
+ LEAVE();
+}
+
+/**
+ * @brief This function dispatches all the packets in the buffer.
+ * There could be holes in the buffer.
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ * @param start_win Start window
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_11n_dispatch_pkt_until_start_win(
+ t_void *priv, RxReorderTbl *rx_reor_tbl_ptr, int start_win)
+{
+ int no_pkt_to_send, i, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *)priv;
+
+ ENTER();
+
+ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+ MIN((start_win - rx_reor_tbl_ptr->start_win),
+ rx_reor_tbl_ptr->win_size) :
+ rx_reor_tbl_ptr->win_size;
+
+ for (i = 0; i < no_pkt_to_send; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+ rx_tmp_ptr = MNULL;
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ }
+ pmpriv->adapter->callbacks.moal_spin_unlock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+ if (rx_tmp_ptr)
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
+ for (i = 0; i < xchg; ++i) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
+ }
+
+ rx_reor_tbl_ptr->start_win = start_win;
+ pmpriv->adapter->callbacks.moal_spin_unlock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will display the rxReorder table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,
+ RxReorderTbl *rx_reor_tbl_ptr)
+{
+ ENTER();
+
+ DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
+ sizeof(t_void *) * rx_reor_tbl_ptr->win_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will dispatch all packets sequentially
+ * from start_win until a hole is found and adjust the
+ * start_win appropriately
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_11n_scan_and_dispatch(t_void *priv,
+ RxReorderTbl *rx_reor_tbl_ptr)
+{
+ int i, j, xchg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ void *rx_tmp_ptr = MNULL;
+ mlan_private *pmpriv = (mlan_private *)priv;
+
+ ENTER();
+
+ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+ pmpriv->adapter->callbacks.moal_spin_lock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ pmpriv->adapter->callbacks.moal_spin_unlock(
+ pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ break;
+ }
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
+ pmpriv->adapter->callbacks.moal_spin_unlock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+ wlan_11n_dispatch_pkt(priv, rx_tmp_ptr);
+ }
+
+ pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
+ pmpriv->rx_pkt_lock);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ if (i > 0) {
+ xchg = rx_reor_tbl_ptr->win_size - i;
+ for (j = 0; j < xchg; ++j) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
+ }
+ }
+
+ rx_reor_tbl_ptr->start_win =
+ (rx_reor_tbl_ptr->start_win + i) & (MAX_TID_VALUE - 1);
+
+ pmpriv->adapter->callbacks.moal_spin_unlock(
+ pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function delete rxreorder table's entry
+ * and free the memory
+ *
+ * @param priv A pointer to mlan_private
+ * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void wlan_11n_delete_rxreorder_tbl_entry(mlan_private *priv,
+ RxReorderTbl *rx_reor_tbl_ptr)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+ mlan_block_rx_process(pmadapter, MTRUE);
+
+ wlan_11n_dispatch_pkt_until_start_win(
+ priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win + rx_reor_tbl_ptr->win_size) &
+ (MAX_TID_VALUE - 1));
+
+ if (rx_reor_tbl_ptr->timer_context.timer) {
+ if (rx_reor_tbl_ptr->timer_context.timer_is_set) {
+ priv->adapter->callbacks.moal_stop_timer(
+ pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.timer);
+ rx_reor_tbl_ptr->timer_context.timer_is_set = MFALSE;
+ }
+ priv->adapter->callbacks.moal_free_timer(
+ pmadapter->pmoal_handle,
+ rx_reor_tbl_ptr->timer_context.timer);
+ rx_reor_tbl_ptr->timer_context.timer = MNULL;
+ }
+
+ PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
+ util_unlink_list(pmadapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list)rx_reor_tbl_ptr,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)rx_reor_tbl_ptr->rx_reorder_ptr);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)rx_reor_tbl_ptr);
+ mlan_block_rx_process(pmadapter, MFALSE);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the last used sequence number
+ *
+ * @param rx_reorder_tbl_ptr A pointer to structure RxReorderTbl
+ *
+ * @return Last used sequence number
+ */
+static int wlan_11n_find_last_seqnum(RxReorderTbl *rx_reorder_tbl_ptr)
+{
+ int i;
+
+ ENTER();
+ for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief This function flushes all data
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param rx_reor_tbl_ptr A pointer to RxReorderTbl
+ *
+ * @return N/A
+ */
+static t_void wlan_start_flush_data(mlan_private *priv,
+ RxReorderTbl *rx_reor_tbl_ptr)
+{
+ int startWin;
+
+ ENTER();
+ wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
+
+ startWin = wlan_11n_find_last_seqnum(rx_reor_tbl_ptr);
+ if (startWin >= 0) {
+ PRINTM(MINFO, "Flush data %d\n", startWin);
+ wlan_11n_dispatch_pkt_until_start_win(
+ priv, rx_reor_tbl_ptr,
+ ((rx_reor_tbl_ptr->start_win + startWin + 1) &
+ (MAX_TID_VALUE - 1)));
+ }
+ wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
+ LEAVE();
+}
+
+/**
+ * @brief This function set the flag to flushes data
+ *
+ * @param context Reorder context pointer
+ *
+ * @return N/A
+ */
+static t_void wlan_flush_data(t_void *context)
+{
+ reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *)context;
+ ENTER();
+ /* Set the flag to flush data */
+ reorder_cnxt->priv->adapter->flush_data = MTRUE;
+ reorder_cnxt->ptr->flush_data = MTRUE;
+ reorder_cnxt->timer_is_set = MFALSE;
+ wlan_recv_event(reorder_cnxt->priv, MLAN_EVENT_ID_DRV_DEFER_RX_WORK,
+ MNULL);
+ LEAVE();
+}
+
+/**
+ * @brief This function will create a entry in rx reordering table for the
+ * given ta/tid and will initialize it with seq_num, win_size
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ * @param win_size win_size for the give ta/tid pair.
+ * @param seq_num Starting sequence number for current entry.
+ *
+ * @return N/A
+ */
+static t_void wlan_11n_create_rxreorder_tbl(mlan_private *priv, t_u8 *ta,
+ int tid, int win_size, int seq_num)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ RxReorderTbl *rx_reor_tbl_ptr, *new_node;
+ sta_node *sta_ptr = MNULL;
+ t_u16 last_seq = 0;
+
+ ENTER();
+
+ /*
+ * If we get a TID, ta pair which is already present dispatch all the
+ * the packets and move the window size until the ssn
+ */
+ rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta);
+ if (rx_reor_tbl_ptr) {
+ PRINTM(MCMND, "%s: delete %p old_size=%d, win_size=%d\n",
+ __func__, rx_reor_tbl_ptr, rx_reor_tbl_ptr->win_size,
+ win_size);
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ }
+ mlan_block_rx_process(pmadapter, MTRUE);
+ PRINTM(MCMND, "%s: seq_num %d, tid %d, ta " MACSTR ", win_size %d\n",
+ __func__, seq_num, tid, MAC2STR(ta), win_size);
+ if (pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(RxReorderTbl), MLAN_MEM_DEF,
+ (t_u8 **)&new_node)) {
+ PRINTM(MERROR, "Rx reorder memory allocation failed\n");
+ mlan_block_rx_process(pmadapter, MFALSE);
+ LEAVE();
+ return;
+ }
+
+ util_init_list((pmlan_linked_list)new_node);
+ if (pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, sizeof(pmlan_buffer) * win_size,
+ MLAN_MEM_DEF, (t_u8 **)&new_node->rx_reorder_ptr)) {
+ PRINTM(MERROR, "Rx reorder table memory allocation"
+ "failed\n");
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)new_node);
+ mlan_block_rx_process(pmadapter, MFALSE);
+ LEAVE();
+ return;
+ }
+ PRINTM(MDAT_D, "Create ReorderPtr: %p start_win=%d last_seq=%d\n",
+ new_node, new_node->start_win, last_seq);
+ new_node->timer_context.ptr = new_node;
+ new_node->timer_context.priv = priv;
+ new_node->timer_context.timer_is_set = MFALSE;
+ pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle,
+ &new_node->timer_context.timer,
+ wlan_flush_data,
+ &new_node->timer_context);
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ (pmlan_linked_list)new_node,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ new_node->tid = tid;
+ memcpy_ext(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ new_node->start_win = seq_num;
+ new_node->pkt_count = 0;
+ if (queuing_ra_based(priv)) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ sta_ptr = wlan_get_station_entry(priv, ta);
+ if (sta_ptr)
+ last_seq = sta_ptr->rx_seq[tid];
+ }
+ PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq,
+ new_node->start_win);
+ } else {
+ last_seq = priv->rx_seq[tid];
+ }
+ new_node->last_seq = last_seq;
+ new_node->win_size = win_size;
+ new_node->force_no_drop = MFALSE;
+ new_node->check_start_win = MTRUE;
+ new_node->ba_status = BA_STREAM_SETUP_INPROGRESS;
+ for (i = 0; i < win_size; ++i)
+ new_node->rx_reorder_ptr[i] = MNULL;
+ mlan_block_rx_process(pmadapter, MFALSE);
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function will return the pointer to a entry in rx reordering
+ * table which matches the give TA/TID pair
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @param tid tid to find in reordering table
+ *
+ * @return A pointer to structure RxReorderTbl
+ */
+RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private *priv, int tid, t_u8 *ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ rx_reor_tbl_ptr =
+ (RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr, MNULL,
+ MNULL);
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return MNULL;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ if ((!memcmp(priv->adapter, rx_reor_tbl_ptr->ta, ta,
+ MLAN_MAC_ADDR_LENGTH)) &&
+ (rx_reor_tbl_ptr->tid == tid)) {
+ LEAVE();
+ return rx_reor_tbl_ptr;
+ }
+
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function prepares command for adding a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11n_addba_req(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_REQ *padd_ba_req =
+ (HostCmd_DS_11N_ADDBA_REQ *)&cmd->params.add_ba_req;
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) + S_DS_GEN);
+
+ memcpy_ext(priv->adapter, padd_ba_req, pdata_buf,
+ sizeof(HostCmd_DS_11N_ADDBA_REQ),
+ sizeof(HostCmd_DS_11N_ADDBA_REQ));
+ padd_ba_req->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
+ padd_ba_req->block_ack_tmo =
+ wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
+ padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
+ padd_ba_req->add_req_result = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function check if AMPDU Rx allowed
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param tid TID
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 wlan_is_addba_reject(mlan_private *priv, t_u8 tid)
+{
+#ifdef STA_SUPPORT
+#endif
+ return priv->addba_reject[tid];
+}
+/**
+ * @brief This function prepares command for adding a block ack
+ * response.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11n_addba_rspgen(mlan_private *priv,
+ HostCmd_DS_COMMAND *cmd, void *pdata_buf)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *)&cmd->params.add_ba_rsp;
+ HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
+ (HostCmd_DS_11N_ADDBA_REQ *)pdata_buf;
+ t_u8 tid = 0;
+ int win_size = 0;
+
+ ENTER();
+
+ pevt_addba_req->block_ack_param_set =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
+ pevt_addba_req->block_ack_tmo =
+ wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
+ pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
+
+ memcpy_ext(priv->adapter, padd_ba_rsp->peer_mac_addr,
+ pevt_addba_req->peer_mac_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
+ padd_ba_rsp->block_ack_tmo =
+ wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
+ padd_ba_rsp->add_rsp_result = 0;
+
+ padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK) >>
+ BLOCKACKPARAM_TID_POS;
+ if (wlan_is_addba_reject(priv, tid)
+#ifdef STA_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ priv->wps.session_enable)
+#endif
+#ifdef UAP_SUPPORT
+ || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ (util_scalar_read(priv->adapter->pmoal_handle,
+ &priv->adapter->pending_bridge_pkts,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock) >
+ RX_LOW_THRESHOLD))
+#endif
+ )
+ padd_ba_rsp->status_code =
+ wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+ else
+ padd_ba_rsp->status_code =
+ wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
+ padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
+ if (!priv->add_ba_param.rx_amsdu)
+ /* We do not support AMSDU inside AMPDU, hence reset the bit */
+ padd_ba_rsp->block_ack_param_set &=
+ ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+
+ padd_ba_rsp->block_ack_param_set |=
+ (priv->add_ba_param.rx_win_size << BLOCKACKPARAM_WINSIZE_POS);
+ win_size = (padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_WINSIZE_MASK) >>
+ BLOCKACKPARAM_WINSIZE_POS;
+
+ if (win_size == 0)
+ padd_ba_rsp->status_code =
+ wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
+
+ padd_ba_rsp->block_ack_param_set =
+ wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
+
+ if (padd_ba_rsp->status_code ==
+ wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT))
+ wlan_11n_create_rxreorder_tbl(priv,
+ pevt_addba_req->peer_mac_addr,
+ tid, win_size,
+ pevt_addba_req->ssn);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command for deleting a block ack
+ * request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ void *pdata_buf)
+{
+ HostCmd_DS_11N_DELBA *pdel_ba =
+ (HostCmd_DS_11N_DELBA *)&cmd->params.del_ba;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
+
+ memcpy_ext(priv->adapter, pdel_ba, pdata_buf,
+ sizeof(HostCmd_DS_11N_DELBA), sizeof(HostCmd_DS_11N_DELBA));
+ pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
+ pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
+ pdel_ba->del_result = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will identify if RxReodering is needed for the packet
+ * and will do the reordering if required before sending it to kernel
+ *
+ * @param priv A pointer to mlan_private
+ * @param seq_num Seqence number of the current packet
+ * @param tid Tid of the current packet
+ * @param ta Transmiter address of the current packet
+ * @param pkt_type Packetype for the current packet (to identify if its a BAR)
+ * @param payload Pointer to the payload
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
+ t_u8 *ta, t_u8 pkt_type, void *payload)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ int prev_start_win, start_win, end_win, win_size;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = ((mlan_private *)priv)->adapter;
+
+ ENTER();
+
+ rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl((mlan_private *)priv, tid, ta);
+ if (!rx_reor_tbl_ptr || rx_reor_tbl_ptr->win_size <= 1) {
+ if (pkt_type != PKT_TYPE_BAR)
+ wlan_11n_dispatch_pkt(priv, payload);
+
+ LEAVE();
+ return ret;
+
+ } else {
+ if (rx_reor_tbl_ptr->flush_data) {
+ rx_reor_tbl_ptr->flush_data = MFALSE;
+ wlan_start_flush_data(priv, rx_reor_tbl_ptr);
+ }
+ if ((pkt_type == PKT_TYPE_AMSDU) && !rx_reor_tbl_ptr->amsdu) {
+ wlan_11n_dispatch_pkt(priv, payload);
+ LEAVE();
+ return ret;
+ }
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D, "BAR ");
+ if (pkt_type == PKT_TYPE_AMSDU)
+ PRINTM(MDAT_D, "AMSDU ");
+
+ if (rx_reor_tbl_ptr->check_start_win) {
+ if (seq_num == rx_reor_tbl_ptr->start_win)
+ rx_reor_tbl_ptr->check_start_win = MFALSE;
+ else {
+ rx_reor_tbl_ptr->pkt_count++;
+ if (rx_reor_tbl_ptr->pkt_count <
+ (rx_reor_tbl_ptr->win_size / 2)) {
+ if (rx_reor_tbl_ptr->last_seq ==
+ seq_num) {
+ /** drop duplicate packet */
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ /** forward the packet to kernel
+ */
+ rx_reor_tbl_ptr->last_seq =
+ seq_num;
+ if (pkt_type != PKT_TYPE_BAR)
+ wlan_11n_dispatch_pkt(
+ priv, payload);
+ }
+ LEAVE();
+ return ret;
+ }
+ rx_reor_tbl_ptr->check_start_win = MFALSE;
+ if ((seq_num != rx_reor_tbl_ptr->start_win) &&
+ (rx_reor_tbl_ptr->last_seq !=
+ DEFAULT_SEQ_NUM)) {
+ end_win = (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size -
+ 1) &
+ (MAX_TID_VALUE - 1);
+ if (((end_win >
+ rx_reor_tbl_ptr->start_win) &&
+ (rx_reor_tbl_ptr->last_seq >=
+ rx_reor_tbl_ptr->start_win) &&
+ (rx_reor_tbl_ptr->last_seq <
+ end_win)) ||
+ ((end_win <
+ rx_reor_tbl_ptr->start_win) &&
+ ((rx_reor_tbl_ptr->last_seq >=
+ rx_reor_tbl_ptr->start_win) ||
+ (rx_reor_tbl_ptr->last_seq <
+ end_win)))) {
+ PRINTM(MDAT_D,
+ "Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
+ rx_reor_tbl_ptr->last_seq,
+ rx_reor_tbl_ptr
+ ->start_win,
+ seq_num);
+ rx_reor_tbl_ptr->start_win =
+ rx_reor_tbl_ptr
+ ->last_seq +
+ 1;
+ } else if ((seq_num <
+ rx_reor_tbl_ptr->start_win) &&
+ (seq_num >
+ rx_reor_tbl_ptr->last_seq)) {
+ PRINTM(MDAT_D,
+ "Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
+ rx_reor_tbl_ptr->last_seq,
+ rx_reor_tbl_ptr
+ ->start_win,
+ seq_num);
+ rx_reor_tbl_ptr->start_win =
+ rx_reor_tbl_ptr
+ ->last_seq +
+ 1;
+ }
+ }
+ }
+ }
+ if (rx_reor_tbl_ptr->force_no_drop) {
+ wlan_11n_dispatch_pkt_until_start_win(
+ priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size) &
+ (MAX_TID_VALUE - 1));
+ if (pkt_type != PKT_TYPE_BAR)
+ rx_reor_tbl_ptr->start_win = seq_num;
+ mlan_11n_rxreorder_timer_restart(pmadapter,
+ rx_reor_tbl_ptr);
+ }
+
+ prev_start_win = start_win = rx_reor_tbl_ptr->start_win;
+ win_size = rx_reor_tbl_ptr->win_size;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D, "TID %d, TA " MACSTR "\n", tid, MAC2STR(ta));
+ PRINTM(MDAT_D,
+ "1:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+ /*
+ * If seq_num is less then starting win then ignore and drop
+ * the packet
+ */
+ if (rx_reor_tbl_ptr->force_no_drop) {
+ PRINTM(MDAT_D, "No drop packet\n");
+ rx_reor_tbl_ptr->force_no_drop = MFALSE;
+ } else {
+ /* Wrap */
+ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
+ if (seq_num >= ((start_win + (TWOPOW11)) &
+ (MAX_TID_VALUE - 1)) &&
+ (seq_num < start_win)) {
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D,
+ "BAR: start_win=%d, end_win=%d, seq_num=%d\n",
+ start_win, end_win,
+ seq_num);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else if ((seq_num < start_win) ||
+ (seq_num >= (start_win + (TWOPOW11)))) {
+ if (pkt_type == PKT_TYPE_BAR)
+ PRINTM(MDAT_D,
+ "BAR: start_win=%d, end_win=%d, seq_num=%d\n",
+ start_win, end_win, seq_num);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /*
+ * If this packet is a BAR we adjust seq_num as
+ * WinStart = seq_num
+ */
+ if (pkt_type == PKT_TYPE_BAR)
+ seq_num = ((seq_num + win_size) - 1) &
+ (MAX_TID_VALUE - 1);
+
+ PRINTM(MDAT_D,
+ "2:seq_num %d start_win %d win_size %d end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+
+ if (((end_win < start_win) && (seq_num < start_win) &&
+ (seq_num > end_win)) ||
+ ((end_win > start_win) &&
+ ((seq_num > end_win) || (seq_num < start_win)))) {
+ end_win = seq_num;
+ if (((seq_num - win_size) + 1) >= 0)
+ start_win = (end_win - win_size) + 1;
+ else
+ start_win =
+ (MAX_TID_VALUE - (win_size - seq_num)) +
+ 1;
+ ret = wlan_11n_dispatch_pkt_until_start_win(
+ priv, rx_reor_tbl_ptr, start_win);
+ if (ret)
+ goto done;
+ }
+
+ PRINTM(MDAT_D,
+ "3:seq_num %d start_win %d win_size %d"
+ " end_win %d\n",
+ seq_num, start_win, win_size, end_win);
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (seq_num >= start_win) {
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[seq_num -
+ start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr
+ ->rx_reorder_ptr[seq_num - start_win] =
+ payload;
+ } else { /* Wrap condition */
+ if (rx_reor_tbl_ptr
+ ->rx_reorder_ptr[(seq_num +
+ (MAX_TID_VALUE)) -
+ start_win]) {
+ PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_reor_tbl_ptr
+ ->rx_reorder_ptr[(seq_num +
+ (MAX_TID_VALUE)) -
+ start_win] = payload;
+ }
+ }
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+
+ /*
+ * Dispatch all packets sequentially from start_win until a
+ * hole is found and adjust the start_win appropriately
+ */
+ ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+ wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
+ }
+
+done:
+ if (!rx_reor_tbl_ptr->timer_context.timer_is_set ||
+ (prev_start_win != rx_reor_tbl_ptr->start_win)) {
+ mlan_11n_rxreorder_timer_restart(pmadapter, rx_reor_tbl_ptr);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will delete an entry for a given tid/ta pair. tid/ta
+ * are taken from delba_event body
+ *
+ * @param priv A pointer to mlan_private
+ * @param tid tid to send delba
+ * @param peer_mac MAC address to send delba
+ * @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
+ * @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
+ * @param reason_code delete ba reason
+ *
+ * @return N/A
+ */
+void mlan_11n_delete_bastream_tbl(mlan_private *priv, int tid, t_u8 *peer_mac,
+ t_u8 type, int initiator, t_u16 reason_code)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+ TxBAStreamTbl *ptxtbl;
+ t_u8 cleanup_rx_reorder_tbl;
+ raListTbl *ra_list = MNULL;
+ int tid_down;
+
+ ENTER();
+
+ if (type == TYPE_DELBA_RECEIVE)
+ cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
+ else
+ cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
+
+ PRINTM(MEVENT,
+ "delete_bastream_tbl: " MACSTR " tid=%d, type=%d"
+ "initiator=%d reason=%d\n",
+ MAC2STR(peer_mac), tid, type, initiator, reason_code);
+
+ if (cleanup_rx_reorder_tbl) {
+ rx_reor_tbl_ptr =
+ wlan_11n_get_rxreorder_tbl(priv, tid, peer_mac);
+ if (!rx_reor_tbl_ptr) {
+ PRINTM(MWARN, "TID, TA not found in table!\n");
+ LEAVE();
+ return;
+ }
+ wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ } else {
+ wlan_request_ralist_lock(priv);
+ ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac,
+ MFALSE);
+ if (!ptxtbl) {
+ PRINTM(MWARN, "TID, RA not found in table!\n");
+ wlan_release_ralist_lock(priv);
+ LEAVE();
+ return;
+ }
+ wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
+ wlan_release_ralist_lock(priv);
+ tid_down = wlan_get_wmm_tid_down(priv, tid);
+ ra_list = wlan_wmm_get_ralist_node(priv, tid_down, peer_mac);
+ if (ra_list) {
+ ra_list->amsdu_in_ampdu = MFALSE;
+ ra_list->ba_status = BA_STREAM_NOT_SETUP;
+ if (type == TYPE_DELBA_RECEIVE) {
+ if (reason_code == REASON_CODE_STA_TIMEOUT)
+ ra_list->del_ba_count = 0;
+ else
+ ra_list->del_ba_count++;
+ ra_list->packet_count = 0;
+/** after delba, we will try to set up BA again after sending 1k packets*/
+#define MIN_BA_SETUP_PACKET_REQIRED 1024
+ ra_list->ba_packet_threshold =
+ MIN_BA_SETUP_PACKET_REQIRED +
+ wlan_get_random_ba_threshold(
+ priv->adapter);
+ }
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of
+ * a block ack response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_11n_addba_resp(mlan_private *priv,
+ HostCmd_DS_COMMAND *resp)
+{
+ HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
+ (HostCmd_DS_11N_ADDBA_RSP *)&resp->params.add_ba_rsp;
+ int tid;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+
+ ENTER();
+
+ padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
+ padd_ba_rsp->block_ack_param_set =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
+ padd_ba_rsp->block_ack_tmo =
+ wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
+ padd_ba_rsp->ssn = wlan_le16_to_cpu(padd_ba_rsp->ssn);
+
+ tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK) >>
+ BLOCKACKPARAM_TID_POS;
+ /* Check if we had rejected the ADDBA, if yes then do not create the
+ * stream
+ */
+ if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
+ PRINTM(MCMND,
+ "ADDBA RSP: " MACSTR
+ " tid=%d ssn=%d win_size=%d,amsdu=%d\n",
+ MAC2STR(padd_ba_rsp->peer_mac_addr), tid,
+ padd_ba_rsp->ssn,
+ ((padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_WINSIZE_MASK) >>
+ BLOCKACKPARAM_WINSIZE_POS),
+ padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_AMSDU_SUPP_MASK);
+
+ rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
+ priv, tid, padd_ba_rsp->peer_mac_addr);
+ if (rx_reor_tbl_ptr) {
+ rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_COMPLETE;
+ if ((padd_ba_rsp->block_ack_param_set &
+ BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
+ priv->add_ba_param.rx_amsdu)
+ rx_reor_tbl_ptr->amsdu = MTRUE;
+ else
+ rx_reor_tbl_ptr->amsdu = MFALSE;
+ }
+ } else {
+ PRINTM(MCMND, "ADDBA RSP: Failed(" MACSTR " tid=%d)\n",
+ MAC2STR(padd_ba_rsp->peer_mac_addr), tid);
+ rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
+ priv, tid, padd_ba_rsp->peer_mac_addr);
+ if (rx_reor_tbl_ptr)
+ wlan_11n_delete_rxreorder_tbl_entry(priv,
+ rx_reor_tbl_ptr);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles ba_stream_timeout event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
+ *
+ * @return N/A
+ */
+void wlan_11n_ba_stream_timeout(mlan_private *priv,
+ HostCmd_DS_11N_BATIMEOUT *event)
+{
+ HostCmd_DS_11N_DELBA delba;
+
+ ENTER();
+
+ DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *)event, 20);
+
+ memset(priv->adapter, &delba, 0, sizeof(HostCmd_DS_11N_DELBA));
+ memcpy_ext(priv->adapter, delba.peer_mac_addr, event->peer_mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ delba.del_ba_param_set |= (t_u16)event->tid << DELBA_TID_POS;
+ delba.del_ba_param_set |= (t_u16)event->origninator
+ << DELBA_INITIATOR_POS;
+ delba.reason_code = REASON_CODE_STA_TIMEOUT;
+ wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function cleans up reorder tbl
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void wlan_11n_cleanup_reorder_tbl(mlan_private *priv)
+{
+ RxReorderTbl *del_tbl_ptr;
+
+ ENTER();
+
+ while ((del_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
+ }
+
+ util_init_list((pmlan_linked_list)&priv->rx_reorder_tbl_ptr);
+
+ memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+ LEAVE();
+}
+
+/**
+ * @brief This function handle the rxba_sync event
+ *
+ * @param priv A pointer to mlan_private
+ * @param event_buf A pointer to event buf
+ * @param len event_buf length
+ * @return N/A
+ */
+void wlan_11n_rxba_sync_event(mlan_private *priv, t_u8 *event_buf, t_u16 len)
+{
+ MrvlIEtypes_RxBaSync_t *tlv_rxba = (MrvlIEtypes_RxBaSync_t *)event_buf;
+ t_u16 tlv_type, tlv_len;
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i, j;
+ t_u16 seq_num = 0;
+ int tlv_buf_left = len;
+ ENTER();
+
+ DBG_HEXDUMP(MEVT_D, "RXBA_SYNC_EVT", event_buf, len);
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_RxBaSync_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv_rxba->header.type);
+ tlv_len = wlan_le16_to_cpu(tlv_rxba->header.len);
+ if (tlv_type != TLV_TYPE_RXBA_SYNC) {
+ PRINTM(MERROR, "Wrong TLV id=0x%x\n", tlv_type);
+ goto done;
+ }
+ tlv_rxba->seq_num = wlan_le16_to_cpu(tlv_rxba->seq_num);
+ tlv_rxba->bitmap_len = wlan_le16_to_cpu(tlv_rxba->bitmap_len);
+ PRINTM(MEVENT, MACSTR " tid=%d seq_num=%d bitmap_len=%d\n",
+ MAC2STR(tlv_rxba->mac), tlv_rxba->tid, tlv_rxba->seq_num,
+ tlv_rxba->bitmap_len);
+ rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
+ priv, tlv_rxba->tid, tlv_rxba->mac);
+ if (!rx_reor_tbl_ptr) {
+ PRINTM(MEVENT, "Can not find rx_reorder_tbl\n");
+ goto done;
+ }
+ if (rx_reor_tbl_ptr->force_no_drop) {
+ PRINTM(MEVENT, "Ignore RXBA_SYNC_EVT in resume\n");
+ goto done;
+ }
+ for (i = 0; i < tlv_rxba->bitmap_len; i++) {
+ for (j = 0; j < 8; j++) {
+ if (tlv_rxba->bitmap[i] & (1 << j)) {
+ seq_num = (tlv_rxba->seq_num + i * 8 +
+ j) &
+ (MAX_TID_VALUE - 1);
+ PRINTM(MEVENT,
+ "Fw dropped packet, seq=%d start_win=%d, win_size=%d\n",
+ seq_num,
+ rx_reor_tbl_ptr->start_win,
+ rx_reor_tbl_ptr->win_size);
+ if (MLAN_STATUS_SUCCESS !=
+ mlan_11n_rxreorder_pkt(
+ priv, seq_num,
+ tlv_rxba->tid,
+ tlv_rxba->mac, 0,
+ (t_void *)
+ RX_PKT_DROPPED_IN_FW)) {
+ PRINTM(MERROR,
+ "Fail to handle dropped packet, seq=%d\n",
+ seq_num);
+ }
+ }
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv_rxba =
+ (MrvlIEtypes_RxBaSync_t *)((t_u8 *)tlv_rxba + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function cleans up reorder tbl for specific station
+ *
+ * @param priv A pointer to mlan_private
+ * @param ta ta to find in reordering table
+ * @return N/A
+ */
+void wlan_cleanup_reorder_tbl(mlan_private *priv, t_u8 *ta)
+{
+ RxReorderTbl *rx_reor_tbl_ptr = MNULL;
+ t_u8 i;
+ ENTER();
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, i, ta);
+ if (rx_reor_tbl_ptr)
+ wlan_11n_delete_rxreorder_tbl_entry(priv,
+ rx_reor_tbl_ptr);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will set force_no_drop flag in rxreorder_tbl.
+ *
+ * @param priv A pointer to mlan_private
+ * @param flag MTRUE/MFALSE
+ *
+ * @return N/A
+ */
+void wlan_set_rxreorder_tbl_no_drop_flag(mlan_private *priv, t_u8 flag)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ rx_reor_tbl_ptr->force_no_drop = flag;
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function update all the rx_reorder_tbl's force_no_drop flag
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param flag MTRUE/MFALSE
+ * @return N/A
+ */
+void wlan_update_rxreorder_tbl(pmlan_adapter pmadapter, t_u8 flag)
+{
+ t_u8 i;
+ pmlan_private priv = MNULL;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ wlan_set_rxreorder_tbl_no_drop_flag(priv, flag);
+ }
+ }
+ return;
+}
+
+/**
+ * @brief This function will flush the data in rxreorder_tbl.
+ * which has flush_data flag on.
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+void wlan_flush_priv_rxreorder_tbl(mlan_private *priv)
+{
+ RxReorderTbl *rx_reor_tbl_ptr;
+
+ ENTER();
+
+ rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (!rx_reor_tbl_ptr) {
+ LEAVE();
+ return;
+ }
+
+ while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
+ if (rx_reor_tbl_ptr->flush_data) {
+ rx_reor_tbl_ptr->flush_data = MFALSE;
+ wlan_start_flush_data(priv, rx_reor_tbl_ptr);
+ }
+ rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function update all the rx_reorder_tbl's force_no_drop flag
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @return N/A
+ */
+void wlan_flush_rxreorder_tbl(pmlan_adapter pmadapter)
+{
+ t_u8 i;
+ pmlan_private priv = MNULL;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ wlan_flush_priv_rxreorder_tbl(priv);
+ }
+ }
+ return;
+}
+
+/**
+ * @brief This function update all the rx_win_size based on coex flag
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param coex_flag coex flag
+ *
+ * @return N/A
+ */
+void wlan_update_ampdu_rxwinsize(pmlan_adapter pmadapter, t_u8 coex_flag)
+{
+ t_u8 i;
+ t_u32 rx_win_size = 0;
+ pmlan_private priv = MNULL;
+
+ ENTER();
+ if (!pmadapter->coex_rx_winsize) {
+ LEAVE();
+ return;
+ }
+ PRINTM(MEVENT, "Update rxwinsize %d\n", coex_flag);
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ rx_win_size = priv->add_ba_param.rx_win_size;
+ if (coex_flag == MTRUE) {
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MLAN_STA_COEX_AMPDU_DEF_RXWINSIZE;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->add_ba_param.rx_win_size =
+ MLAN_WFD_COEX_AMPDU_DEF_RXWINSIZE;
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MLAN_UAP_COEX_AMPDU_DEF_RXWINSIZE;
+#endif
+
+ } else {
+ priv->add_ba_param.rx_win_size =
+ priv->user_rxwinsize;
+ }
+ if (pmadapter->coex_win_size &&
+ pmadapter->coex_rx_win_size)
+ priv->add_ba_param.rx_win_size =
+ pmadapter->coex_rx_win_size;
+ if (rx_win_size != priv->add_ba_param.rx_win_size) {
+ if (priv->media_connected == MTRUE) {
+ for (i = 0; i < MAX_NUM_TID; i++)
+ wlan_11n_delba(priv, i);
+ wlan_recv_event(
+ priv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief check coex for
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+void wlan_coex_ampdu_rxwinsize(pmlan_adapter pmadapter)
+{
+ t_u8 i;
+ pmlan_private priv = MNULL;
+ t_u8 count = 0;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE((mlan_private *)priv) ==
+ MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected == MTRUE)
+ count++;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE((mlan_private *)priv) ==
+ MLAN_BSS_ROLE_UAP) {
+ if (priv->uap_bss_started)
+ count++;
+ }
+#endif
+ }
+ if (count >= 2)
+ break;
+ }
+ if (count >= 2)
+ wlan_update_ampdu_rxwinsize(pmadapter, MTRUE);
+ else
+ wlan_update_ampdu_rxwinsize(pmadapter, MFALSE);
+ return;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.h
new file mode 100644
index 000000000000..7cab4350b1be
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_11n_rxreorder.h
@@ -0,0 +1,104 @@
+/** @file mlan_11n_rxreorder.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of 11n RxReordering functionalities
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/10/2008: initial version
+********************************************************/
+
+#ifndef _MLAN_11N_RXREORDER_H_
+#define _MLAN_11N_RXREORDER_H_
+
+/** Max value a TID can take = 2^12 = 4096 */
+#define MAX_TID_VALUE (2 << 11)
+/** 2^11 = 2048 */
+#define TWOPOW11 (2 << 10)
+
+/** Tid Mask used for extracting TID from BlockAckParamSet */
+#define BLOCKACKPARAM_TID_MASK 0x3C
+/** Tid position in BlockAckParamSet */
+#define BLOCKACKPARAM_TID_POS 2
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_MASK 0xffc0
+/** WinSize Mask used for extracting WinSize from BlockAckParamSet */
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
+/** WinSize position in BlockAckParamSet */
+#define BLOCKACKPARAM_WINSIZE_POS 6
+/** Position of TID in DelBA Param set */
+#define DELBA_TID_POS 12
+/** Position of INITIATOR in DelBA Param set */
+#define DELBA_INITIATOR_POS 11
+/** Reason code: Requested from peer STA as it does not want to
+ * use the mechanism */
+#define REASON_CODE_STA_DONT_WANT 37
+/** Reason code: Requested from peer STA due to timeout*/
+#define REASON_CODE_STA_TIMEOUT 39
+/** Type: send delba command */
+#define TYPE_DELBA_SENT 1
+/** Type: recieve delba command */
+#define TYPE_DELBA_RECEIVE 2
+/** Set Initiator Bit */
+#define DELBA_INITIATOR(paramset) (paramset = (paramset | (1 << 11)))
+/** Reset Initiator Bit for recipient */
+#define DELBA_RECIPIENT(paramset) (paramset = (paramset & ~(1 << 11)))
+/** Immediate block ack */
+#define IMMEDIATE_BLOCK_ACK 0x2
+
+/** The request has been declined */
+#define ADDBA_RSP_STATUS_DECLINED 37
+/** ADDBA response status : Reject */
+#define ADDBA_RSP_STATUS_REJECT 1
+/** ADDBA response status : Accept */
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+/** DEFAULT SEQ NUM */
+#define DEFAULT_SEQ_NUM 0xffff
+
+/** Indicate packet has been dropped in FW */
+#define RX_PKT_DROPPED_IN_FW 0xffffffff
+
+mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seqNum, t_u16 tid,
+ t_u8 *ta, t_u8 pkttype, void *payload);
+void mlan_11n_delete_bastream_tbl(mlan_private *priv, int tid,
+ t_u8 *PeerMACAddr, t_u8 type, int initiator,
+ t_u16 reason_code);
+void wlan_11n_ba_stream_timeout(mlan_private *priv,
+ HostCmd_DS_11N_BATIMEOUT *event);
+mlan_status wlan_ret_11n_addba_resp(mlan_private *priv,
+ HostCmd_DS_COMMAND *resp);
+mlan_status wlan_cmd_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_rspgen(mlan_private *priv,
+ HostCmd_DS_COMMAND *cmd, void *pdata_buf);
+mlan_status wlan_cmd_11n_addba_req(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
+ void *pdata_buf);
+void wlan_11n_cleanup_reorder_tbl(mlan_private *priv);
+RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private *priv, int tid, t_u8 *ta);
+void wlan_11n_rxba_sync_event(mlan_private *priv, t_u8 *event_buf, t_u16 len);
+void wlan_update_rxreorder_tbl(pmlan_adapter pmadapter, t_u8 flag);
+void wlan_flush_rxreorder_tbl(pmlan_adapter pmadapter);
+void wlan_coex_ampdu_rxwinsize(pmlan_adapter pmadapter);
+
+/** clean up reorder_tbl */
+void wlan_cleanup_reorder_tbl(mlan_private *priv, t_u8 *ta);
+#endif /* _MLAN_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cfp.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cfp.c
new file mode 100644
index 000000000000..6ad3cca77be2
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cfp.c
@@ -0,0 +1,3608 @@
+/**
+ * @file mlan_cfp.c
+ *
+ * @brief This file contains WLAN client mode channel, frequency and power
+ * related code
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+ * Change Log:
+ * 04/16/2009: initial version
+ ************************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_join.h"
+#include "mlan_main.h"
+
+/********************************************************
+ * Local Variables
+ ********************************************************/
+
+/** 100mW */
+#define WLAN_TX_PWR_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_00_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20
+/** 100mW */
+#define WLAN_TX_PWR_JP_BG_DEFAULT 20
+/** 200mW */
+#define WLAN_TX_PWR_JP_A_DEFAULT 23
+/** 100mW */
+#define WLAN_TX_PWR_FR_100MW 20
+/** 10mW */
+#define WLAN_TX_PWR_FR_10MW 10
+/** 100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20
+/** 2000mW */
+#define WLAN_TX_PWR_CN_2000MW 33
+/** 200mW */
+#define WLAN_TX_PWR_200MW 23
+/** 1000mW */
+#define WLAN_TX_PWR_1000MW 30
+/** 30mW */
+#define WLAN_TX_PWR_SP_30MW 14
+/** 60mW */
+#define WLAN_TX_PWR_SP_60MW 17
+/** 25mW */
+#define WLAN_TX_PWR_25MW 14
+/** 250mW */
+#define WLAN_TX_PWR_250MW 24
+
+/** Region code mapping */
+typedef struct _country_code_mapping {
+ /** Region */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Code for B/G CFP table */
+ t_u8 cfp_code_bg;
+ /** Code for A CFP table */
+ t_u8 cfp_code_a;
+} country_code_mapping_t;
+
+#define EU_CFP_CODE_BG 0x30
+#define EU_CFP_CODE_A 0x30
+
+/** Region code mapping table */
+static country_code_mapping_t country_code_mapping[] = {
+ {"WW", 0x00, 0x00}, /* World */
+ {"US", 0x10, 0x10}, /* US FCC */
+ {"CA", 0x10, 0x20}, /* IC Canada */
+ {"SG", 0x10, 0x10}, /* Singapore */
+ {"EU", 0x30, 0x30}, /* ETSI */
+ {"AU", 0x30, 0x30}, /* Australia */
+ {"KR", 0x30, 0x30}, /* Republic Of Korea */
+ {"JP", 0xFF, 0x40}, /* Japan */
+ {"CN", 0x30, 0x50}, /* China */
+ {"BR", 0x01, 0x09}, /* Brazil */
+ {"RU", 0x30, 0x0f}, /* Russia */
+ {"IN", 0x10, 0x06}, /* India */
+ {"MY", 0x30, 0x06}, /* Malaysia */
+ {"NZ", 0x30, 0x30}, /* New Zeland */
+ {"MX", 0x10, 0x07}, /* Mexico */
+};
+
+/** Country code for ETSI */
+static t_u8 eu_country_code_table[][COUNTRY_CODE_LEN] = {
+ "AL", "AD", "AT", "AU", "BY", "BE", "BA", "BG", "HR", "CY", "CZ", "DK",
+ "EE", "FI", "FR", "MK", "DE", "GR", "HU", "IS", "IE", "IT", "KR", "LV",
+ "LI", "LT", "LU", "MT", "MD", "MC", "ME", "NL", "NO", "PL", "RO", "RU",
+ "SM", "RS", "SI", "SK", "ES", "SE", "CH", "TR", "UA", "UK", "GB", "NZ"};
+
+/**
+ * The structure for Channel-Frequency-Power table
+ */
+typedef struct _cfp_table {
+ /** Region or Code */
+ t_u8 code;
+ /** Frequency/Power */
+ chan_freq_power_t *cfp;
+ /** No of CFP flag */
+ int cfp_no;
+} cfp_table_t;
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/** Band : 'B/G', Region: World Wide Safe */
+static chan_freq_power_t channel_freq_power_00_BG[] = {
+ {1, 2412, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {2, 2417, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {3, 2422, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {4, 2427, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {5, 2432, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {6, 2437, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {7, 2442, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {8, 2447, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {9, 2452, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {10, 2457, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {11, 2462, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x1c, 0}},
+ {12, 2467, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x1f, 0}},
+ {13, 2472, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x1f, 0}}};
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/** Band: 'B/G', Region: USA FCC/Canada IC */
+static chan_freq_power_t channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT, MFALSE}};
+
+/** Band: 'B/G', Region: Europe ETSI/China */
+static chan_freq_power_t channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE}};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN41_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN40_BG[] = {
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}};
+
+/** Band: 'B/G', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPNFE_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MTRUE}};
+
+/** Band : 'B/G', Region: Brazil */
+static chan_freq_power_t channel_freq_power_BR_BG[] = {
+ {1, 2412, WLAN_TX_PWR_1000MW, MFALSE},
+ {2, 2417, WLAN_TX_PWR_1000MW, MFALSE},
+ {3, 2422, WLAN_TX_PWR_1000MW, MFALSE},
+ {4, 2427, WLAN_TX_PWR_1000MW, MFALSE},
+ {5, 2432, WLAN_TX_PWR_1000MW, MFALSE},
+ {6, 2437, WLAN_TX_PWR_1000MW, MFALSE},
+ {7, 2442, WLAN_TX_PWR_1000MW, MFALSE},
+ {8, 2447, WLAN_TX_PWR_1000MW, MFALSE},
+ {9, 2452, WLAN_TX_PWR_1000MW, MFALSE},
+ {10, 2457, WLAN_TX_PWR_1000MW, MFALSE},
+ {11, 2462, WLAN_TX_PWR_1000MW, MFALSE},
+ {12, 2467, WLAN_TX_PWR_1000MW, MFALSE},
+ {13, 2472, WLAN_TX_PWR_1000MW, MFALSE},
+};
+
+/** Band : 'B/G', Region: Special */
+static chan_freq_power_t channel_freq_power_SPECIAL_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {2, 2417, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {3, 2422, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {4, 2427, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {5, 2432, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {6, 2437, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {7, 2442, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {8, 2447, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {9, 2452, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {10, 2457, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {11, 2462, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {12, 2467, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {13, 2472, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE},
+ {14, 2484, WLAN_TX_PWR_JP_BG_DEFAULT, MFALSE}};
+
+/**
+ * The 2.4GHz CFP tables
+ */
+static cfp_table_t cfp_table_BG[] = {
+ {
+ 0x01, /* Brazil */
+ channel_freq_power_BR_BG,
+ NELEMENTS(channel_freq_power_BR_BG),
+ },
+ {
+ 0x00, /* World FCC */
+ channel_freq_power_00_BG,
+ NELEMENTS(channel_freq_power_00_BG),
+ },
+ {
+ 0x10, /* US FCC */
+ channel_freq_power_US_BG,
+ NELEMENTS(channel_freq_power_US_BG),
+ },
+ {
+ 0x20, /* CANADA IC */
+ channel_freq_power_US_BG,
+ NELEMENTS(channel_freq_power_US_BG),
+ },
+ {
+ 0x30, /* EU */
+ channel_freq_power_EU_BG,
+ NELEMENTS(channel_freq_power_EU_BG),
+ },
+ {
+ 0x40, /* JAPAN */
+ channel_freq_power_JPN40_BG,
+ NELEMENTS(channel_freq_power_JPN40_BG),
+ },
+ {
+ 0x41, /* JAPAN */
+ channel_freq_power_JPN41_BG,
+ NELEMENTS(channel_freq_power_JPN41_BG),
+ },
+ {
+ 0x50, /* China */
+ channel_freq_power_EU_BG,
+ NELEMENTS(channel_freq_power_EU_BG),
+ },
+ {
+ 0xfe, /* JAPAN */
+ channel_freq_power_JPNFE_BG,
+ NELEMENTS(channel_freq_power_JPNFE_BG),
+ },
+ {
+ 0xff, /* Special */
+ channel_freq_power_SPECIAL_BG,
+ NELEMENTS(channel_freq_power_SPECIAL_BG),
+ },
+ /* Add new region here */
+};
+
+/** Number of the CFP tables for 2.4GHz */
+#define MLAN_CFP_TABLE_SIZE_BG (NELEMENTS(cfp_table_BG))
+
+/* Format { Channel, Frequency (MHz), MaxTxPower, DFS } */
+/** Band: 'A', Region: World Wide Safe */
+static chan_freq_power_t channel_freq_power_00_A[] = {
+ {36, 5180, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x10, 0}},
+ {40, 5200, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x10, 0}},
+ {44, 5220, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x10, 0}},
+ {48, 5240, WLAN_TX_PWR_00_DEFAULT, MFALSE, {0x10, 0}},
+ {52, 5260, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {56, 5280, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {60, 5300, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {64, 5320, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {100, 5500, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {104, 5520, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {108, 5540, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {112, 5560, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {116, 5580, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {120, 5600, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {124, 5620, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {128, 5640, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {132, 5660, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {136, 5680, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {140, 5700, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {144, 5720, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {149, 5745, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {153, 5765, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {157, 5785, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {161, 5805, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}},
+ {165, 5825, WLAN_TX_PWR_00_DEFAULT, MTRUE, {0x13, 0}}};
+/* Format { Channel, Frequency (MHz), MaxTxPower, DFS } */
+/** Band: 'A', Region: USA FCC */
+static chan_freq_power_t channel_freq_power_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {144, 5720, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}};
+
+/** Band: 'A', Region: Canada IC */
+static chan_freq_power_t channel_freq_power_CAN_A[] = {
+ {36, 5180, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {144, 5720, WLAN_TX_PWR_US_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_US_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_US_DEFAULT, MFALSE}};
+
+/** Band: 'A', Region: Europe ETSI */
+static chan_freq_power_t channel_freq_power_EU_A[] = {
+ {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE}};
+
+/** Band: 'A', Region: Japan */
+static chan_freq_power_t channel_freq_power_JPN_A[] = {
+ {36, 5180, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_JP_A_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE},
+ {144, 5720, WLAN_TX_PWR_JP_A_DEFAULT, MTRUE}};
+
+/** Band: 'A', Region: China */
+static chan_freq_power_t channel_freq_power_CN_A[] = {
+ {36, 5180, WLAN_TX_PWR_200MW, MFALSE},
+ {40, 5200, WLAN_TX_PWR_200MW, MFALSE},
+ {44, 5220, WLAN_TX_PWR_200MW, MFALSE},
+ {48, 5240, WLAN_TX_PWR_200MW, MFALSE},
+ {52, 5260, WLAN_TX_PWR_200MW, MTRUE},
+ {56, 5280, WLAN_TX_PWR_200MW, MTRUE},
+ {60, 5300, WLAN_TX_PWR_200MW, MTRUE},
+ {64, 5320, WLAN_TX_PWR_200MW, MTRUE},
+ {149, 5745, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {153, 5765, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {157, 5785, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {161, 5805, WLAN_TX_PWR_CN_2000MW, MFALSE},
+ {165, 5825, WLAN_TX_PWR_CN_2000MW, MFALSE}};
+
+/** Band: 'A', NULL */
+static chan_freq_power_t channel_freq_power_NULL_A[] = {};
+
+/** Band: 'A', Region: Spain/Austria/Brazil */
+static chan_freq_power_t channel_freq_power_SPN2_A[] = {
+ {36, 5180, WLAN_TX_PWR_200MW, MFALSE},
+ {40, 5200, WLAN_TX_PWR_200MW, MFALSE},
+ {44, 5220, WLAN_TX_PWR_200MW, MFALSE},
+ {48, 5240, WLAN_TX_PWR_200MW, MFALSE},
+ {52, 5260, WLAN_TX_PWR_200MW, MTRUE},
+ {56, 5280, WLAN_TX_PWR_200MW, MTRUE},
+ {60, 5300, WLAN_TX_PWR_200MW, MTRUE},
+ {64, 5320, WLAN_TX_PWR_200MW, MTRUE},
+};
+
+/** Band: 'A', Region: Brazil */
+static chan_freq_power_t channel_freq_power_BR1_A[] = {
+ {100, 5500, WLAN_TX_PWR_250MW, MTRUE},
+ {104, 5520, WLAN_TX_PWR_250MW, MTRUE},
+ {108, 5540, WLAN_TX_PWR_250MW, MTRUE},
+ {112, 5560, WLAN_TX_PWR_250MW, MTRUE},
+ {116, 5580, WLAN_TX_PWR_250MW, MTRUE},
+ {120, 5600, WLAN_TX_PWR_250MW, MTRUE},
+ {124, 5620, WLAN_TX_PWR_250MW, MTRUE},
+ {128, 5640, WLAN_TX_PWR_250MW, MTRUE},
+ {132, 5660, WLAN_TX_PWR_250MW, MTRUE},
+ {136, 5680, WLAN_TX_PWR_250MW, MTRUE},
+ {140, 5700, WLAN_TX_PWR_250MW, MTRUE},
+};
+
+/** Band: 'A', Region: Brazil */
+static chan_freq_power_t channel_freq_power_BR2_A[] = {
+ {149, 5745, WLAN_TX_PWR_1000MW, MFALSE},
+ {153, 5765, WLAN_TX_PWR_1000MW, MFALSE},
+ {157, 5785, WLAN_TX_PWR_1000MW, MFALSE},
+ {161, 5805, WLAN_TX_PWR_1000MW, MFALSE},
+ {165, 5825, WLAN_TX_PWR_1000MW, MFALSE}};
+
+/** Band: 'A', Region: Russia */
+static chan_freq_power_t channel_freq_power_RU_A[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {56, 5280, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {60, 5300, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {64, 5320, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {132, 5660, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {136, 5680, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {140, 5700, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+};
+
+/** Band: 'A', Region: Mexico */
+static chan_freq_power_t channel_freq_power_MX_A[] = {
+ {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT, MTRUE},
+ {149, 5745, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_EMEA_DEFAULT, MFALSE}};
+
+/** Band: 'A', Code: 1, Low band (5150-5250 MHz) channels */
+static chan_freq_power_t channel_freq_power_low_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+};
+
+/** Band: 'A', Code: 2, Lower middle band (5250-5350 MHz) channels */
+static chan_freq_power_t channel_freq_power_lower_middle_band[] = {
+ {52, 5260, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {56, 5280, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {60, 5300, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {64, 5320, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 3, Upper middle band (5470-5725 MHz) channels */
+static chan_freq_power_t channel_freq_power_upper_middle_band[] = {
+ {100, 5500, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {104, 5520, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {108, 5540, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {112, 5560, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {116, 5580, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {120, 5600, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {124, 5620, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {128, 5640, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {132, 5660, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {136, 5680, WLAN_TX_PWR_DEFAULT, MTRUE},
+ {140, 5700, WLAN_TX_PWR_DEFAULT, MTRUE},
+};
+
+/** Band: 'A', Code: 4, High band (5725-5850 MHz) channels */
+static chan_freq_power_t channel_freq_power_high_band[] = {
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}};
+
+/** Band: 'A', Code: 5, Low band (5150-5250 MHz) and
+ * High band (5725-5850 MHz) channels
+ */
+static chan_freq_power_t channel_freq_power_low_high_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}};
+
+/** Band: 'A', Code: 6, Low band (5150-5250 MHz) and
+ * mid low (5260-5320) and High band (5725-5850 MHz) channels
+ */
+static chan_freq_power_t channel_freq_power_low_middle_high_band[] = {
+ {36, 5180, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {40, 5200, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {44, 5220, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {48, 5240, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {52, 5260, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {56, 5280, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {60, 5300, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {64, 5320, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {149, 5745, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {153, 5765, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {157, 5785, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {161, 5805, WLAN_TX_PWR_DEFAULT, MFALSE},
+ {165, 5825, WLAN_TX_PWR_DEFAULT, MFALSE}};
+
+/**
+ * The 5GHz CFP tables
+ */
+static cfp_table_t cfp_table_A[] = {
+ {0x1, /* Low band (5150-5250 MHz) channels */
+ channel_freq_power_low_band, NELEMENTS(channel_freq_power_low_band)},
+ {0x2, /* Lower middle band (5250-5350 MHz) channels */
+ channel_freq_power_lower_middle_band,
+ NELEMENTS(channel_freq_power_lower_middle_band)},
+ {0x3, /* Upper middle band (5470-5725 MHz) channels */
+ channel_freq_power_upper_middle_band,
+ NELEMENTS(channel_freq_power_upper_middle_band)},
+ {0x4, /* High band (5725-5850 MHz) channels */
+ channel_freq_power_high_band, NELEMENTS(channel_freq_power_high_band)},
+ {0x5, /* Low band (5150-5250 MHz) and
+ * High band (5725-5850 MHz) channels
+ */
+ channel_freq_power_low_high_band,
+ NELEMENTS(channel_freq_power_low_high_band)},
+ {0x6, /* Low band (5150-5250 MHz)
+ * Mid band (5260-5320) and
+ * High band (5725-5850 MHz) channels
+ */
+ channel_freq_power_low_middle_high_band,
+ NELEMENTS(channel_freq_power_low_middle_high_band)},
+ {
+ 0x07, /* Mexico */
+ channel_freq_power_MX_A,
+ NELEMENTS(channel_freq_power_MX_A),
+ },
+
+ {
+ 0x09, /* SPAIN/Austria/Brazil */
+ channel_freq_power_SPN2_A,
+ NELEMENTS(channel_freq_power_SPN2_A),
+ },
+ {
+ 0x0c, /* Brazil */
+ channel_freq_power_BR1_A,
+ NELEMENTS(channel_freq_power_BR1_A),
+ },
+ {
+ 0x0e, /* Brazil */
+ channel_freq_power_BR2_A,
+ NELEMENTS(channel_freq_power_BR2_A),
+ },
+ {
+ 0x0f, /* Russia */
+ channel_freq_power_RU_A,
+ NELEMENTS(channel_freq_power_RU_A),
+ },
+ {
+ 0x00, /* World */
+ channel_freq_power_00_A,
+ NELEMENTS(channel_freq_power_00_A),
+ },
+ {
+ 0x10, /* US FCC */
+ channel_freq_power_A,
+ NELEMENTS(channel_freq_power_A),
+ },
+ {
+ 0x20, /* CANADA IC */
+ channel_freq_power_CAN_A,
+ NELEMENTS(channel_freq_power_CAN_A),
+ },
+ {
+ 0x30, /* EU */
+ channel_freq_power_EU_A,
+ NELEMENTS(channel_freq_power_EU_A),
+ },
+ {
+ 0x40, /* JAPAN */
+ channel_freq_power_JPN_A,
+ NELEMENTS(channel_freq_power_JPN_A),
+ },
+ {
+ 0x41, /* JAPAN */
+ channel_freq_power_JPN_A,
+ NELEMENTS(channel_freq_power_JPN_A),
+ },
+ {
+ 0x50, /* China */
+ channel_freq_power_CN_A,
+ NELEMENTS(channel_freq_power_CN_A),
+ },
+ {
+ 0xfe, /* JAPAN */
+ channel_freq_power_NULL_A,
+ NELEMENTS(channel_freq_power_NULL_A),
+ },
+ {
+ 0xff, /* Special */
+ channel_freq_power_JPN_A,
+ NELEMENTS(channel_freq_power_JPN_A),
+ },
+ /* Add new region here */
+};
+/** Number of the CFP tables for 5GHz */
+#define MLAN_CFP_TABLE_SIZE_A (NELEMENTS(cfp_table_A))
+
+enum { RATEID_DBPSK1Mbps, //(0)
+ RATEID_DQPSK2Mbps, //(1)
+ RATEID_CCK5_5Mbps, //(2)
+ RATEID_CCK11Mbps, //(3)
+ RATEID_CCK22Mbps, //(4)
+ RATEID_OFDM6Mbps, //(5)
+ RATEID_OFDM9Mbps, //(6)
+ RATEID_OFDM12Mbps, //(7)
+ RATEID_OFDM18Mbps, //(8)
+ RATEID_OFDM24Mbps, //(9)
+ RATEID_OFDM36Mbps, //(10)
+ RATEID_OFDM48Mbps, //(11)
+ RATEID_OFDM54Mbps, //(12)
+ RATEID_OFDM72Mbps, //(13)
+};
+
+static const t_u8 rateUnit_500Kbps[] = {
+ (10 / 5), /* 1Mbps */
+ (20 / 5), /* 2Mbps */
+
+ (55 / 5), /* 5.5Mbps */
+ (110 / 5), /* 11Mbps */
+ (10 / 5), /* 22Mbps, intentionally set to 1Mbps
+ * because it's not available
+ */
+
+ (60 / 5), /* 6Mbps */
+ (90 / 5), /* 9Mbps */
+ (120 / 5), /* 12Mbps */
+ (180 / 5), /* 18Mbps */
+ (240 / 5), /* 24Mbps */
+ (360 / 5), /* 36Mbps */
+ (480 / 5), /* 48Mbps */
+ (540 / 5), /* 54Mbps */
+ (60 / 5), /* 72Mbps, intentionally set to 6Mbps
+ * because it's not available
+ */
+};
+
+typedef struct _rate_map {
+ /** Rate, in 0.5Mbps */
+ t_u32 rate;
+ /** Mrvl rate id, refer to RATEID_XXX in FW */
+ t_u32 id;
+ /** nss: 0-nss1, 1-nss2 */
+ t_u8 nss;
+} rate_map;
+
+/** If user configure to 1x1 or we found peer device only support 1x1,
+ * then we need skip the nss1 part when map to Mrvl rate.
+ */
+const rate_map rate_map_table_2x2[] = {
+ /* LG <--> Mrvl rate idx */
+ {2, 0, 0}, // RATEID_DBPSK1Mbps
+ {4, 1, 0}, // RATEID_DQPSK2Mbps
+ {11, 2, 0}, // RATEID_CCK5_5Mbps
+ {22, 3, 0}, // RATEID_CCK11Mbps
+ {44, 4, 0}, // RATEID_CCK22Mbps
+ {12, 5, 0}, // RATEID_OFDM6Mbps
+ {18, 6, 0}, // RATEID_OFDM9Mbps
+ {24, 7, 0}, // RATEID_OFDM12Mbps
+ {36, 8, 0}, // RATEID_OFDM18Mbps
+ {48, 9, 0}, // RATEID_OFDM24Mbps
+ {72, 10, 0}, // RATEID_OFDM36Mbps
+ {96, 11, 0}, // RATEID_OFDM48Mbps
+ {108, 12, 0}, // RATEID_OFDM54Mbps
+ {144, 13, 0}, // RATEID_OFDM72Mbps
+
+ /* HT bw20 <--> Mrvl rate idx - nss2 */
+ {26, 22, 1}, // RATEID_MCS8_13Mbps
+ {52, 23, 1}, // RATEID_MCS9_26Mbps
+ {78, 24, 1}, // RATEID_MCS10_39Mbps
+ {104, 25, 1}, // RATEID_MCS11_52Mbps
+ {156, 26, 1}, // RATEID_MCS12_78Mbps
+ {208, 27, 1}, // RATEID_MCS13_104Mbps
+ {234, 28, 1}, // RATEID_MCS14_117Mbps
+ {260, 29, 1}, // RATEID_MCS15_130Mbps
+ /* HT bw20 <--> Mrvl rate idx - nss1 */
+ {13, 14, 0}, // RATEID_MCS0_6d5Mbps
+ {26, 15, 0}, // RATEID_MCS1_13Mbps
+ {39, 16, 0}, // RATEID_MCS2_19d5Mbps
+ {52, 17, 0}, // RATEID_MCS3_26Mbps
+ {78, 18, 0}, // RATEID_MCS4_39Mbps
+ {104, 19, 0}, // RATEID_MCS5_52Mbps
+ {117, 20, 0}, // RATEID_MCS6_58d5Mbps
+ {130, 21, 0}, // RATEID_MCS7_65Mbps
+
+ /* HT bw40<--> Mrvl rate idx - nss2 */
+ {54, 39, 1}, // RATEID_MCS8BW40_27Mbps
+ {108, 40, 1}, // RATEID_MCS9BW40_54Mbps
+ {162, 41, 1}, // RATEID_MCS10BW40_81Mbps
+ {216, 42, 1}, // RATEID_MCS11BW40_108Mbps
+ {324, 43, 1}, // RATEID_MCS12BW40_162Mbps
+ {432, 44, 1}, // RATEID_MCS13BW40_216Mbps
+ {486, 45, 1}, // RATEID_MCS14BW40_243Mbps
+ {540, 46, 1}, // RATEID_MCS15BW40_270Mbps
+ /* HT bw40<--> Mrvl rate idx - nss1 */
+ {12, 30, 0}, // RATEID_MCS32BW40_6Mbps
+ {27, 31, 0}, // RATEID_MCS0BW40_13d5Mbps
+ {54, 32, 0}, // RATEID_MCS1BW40_27Mbps
+ {81, 33, 0}, // RATEID_MCS2BW40_40d5Mbps
+ {108, 34, 0}, // RATEID_MCS3BW40_54Mbps
+ {162, 35, 0}, // RATEID_MCS4BW40_81Mbps
+ {216, 36, 0}, // RATEID_MCS5BW40_108Mbps
+ {243, 37, 0}, // RATEID_MCS6BW40_121d5Mbps
+ {270, 38, 0}, // RATEID_MCS7BW40_135Mbps
+
+ /* VHT bw20<--> Mrvl rate idx - nss2 */
+ {26, 57, 1}, // RATEID_VHT_MCS0_2SS_BW20 13 Mbps
+ {52, 58, 1}, // RATEID_VHT_MCS1_2SS_BW20 26 Mbps
+ {78, 59, 1}, // RATEID_VHT_MCS2_2SS_BW20 39 Mbps
+ {104, 60, 1}, // RATEID_VHT_MCS3_2SS_BW20 52 Mbps
+ {156, 61, 1}, // RATEID_VHT_MCS4_2SS_BW20 78 Mbps
+ {208, 62, 1}, // RATEID_VHT_MCS5_2SS_BW20 104 Mbps
+ {234, 63, 1}, // RATEID_VHT_MCS6_2SS_BW20 117 Mbps
+ {260, 64, 1}, // RATEID_VHT_MCS7_2SS_BW20 130 Mbps
+ {312, 65, 1}, // RATEID_VHT_MCS8_2SS_BW20 156 Mbps
+ {0, 66, 1}, // RATEID_VHT_MCS9_2SS_BW20 173.3 Mbps(INVALID)
+ /* VHT bw20<--> Mrvl rate idx - nss1 */
+ {13, 47, 0}, // RATEID_VHT_MCS0_1SS_BW20 6.5 Mbps
+ {26, 48, 0}, // RATEID_VHT_MCS1_1SS_BW20 13 Mbps
+ {39, 49, 0}, // RATEID_VHT_MCS2_1SS_BW20 19.5 Mbps
+ {52, 50, 0}, // RATEID_VHT_MCS3_1SS_BW20 26 Mbps
+ {78, 51, 0}, // RATEID_VHT_MCS4_1SS_BW20 39 Mbps
+ {104, 52, 0}, // RATEID_VHT_MCS5_1SS_BW20 52 Mbps
+ {117, 53, 0}, // RATEID_VHT_MCS6_1SS_BW20 58.5 Mbps
+ {130, 54, 0}, // RATEID_VHT_MCS7_1SS_BW20 65 Mbps
+ {156, 55, 0}, // RATEID_VHT_MCS8_1SS_BW20 78 Mbps
+ {0, 56, 0}, // RATEID_VHT_MCS9_1SS_BW20 86.7 Mbps(INVALID)
+
+ /* VHT bw40<--> Mrvl rate idx - nss2 */
+ {54, 77, 1}, // RATEID_VHT_MCS0_2SS_BW40 27 Mbps
+ {108, 78, 1}, // RATEID_VHT_MCS1_2SS_BW40 54 Mbps
+ {162, 79, 1}, // RATEID_VHT_MCS2_2SS_BW40 81 Mbps
+ {216, 80, 1}, // RATEID_VHT_MCS3_2SS_BW40 108 Mbps
+ {324, 81, 1}, // RATEID_VHT_MCS4_2SS_BW40 162 Mbps
+ {432, 82, 1}, // RATEID_VHT_MCS5_2SS_BW40 216 Mbps
+ {486, 83, 1}, // RATEID_VHT_MCS6_2SS_BW40 243 Mbps
+ {540, 84, 1}, // RATEID_VHT_MCS7_2SS_BW40 270 Mbps
+ {648, 85, 1}, // RATEID_VHT_MCS8_2SS_BW40 324 Mbps
+ {720, 86, 1}, // RATEID_VHT_MCS9_2SS_BW40 360 Mbps
+ /* VHT bw40<--> Mrvl rate idx - nss1 */
+ {27, 67, 0}, // RATEID_VHT_MCS0_1SS_BW40 13.5 Mbps
+ {54, 68, 0}, // RATEID_VHT_MCS1_1SS_BW40 27 Mbps
+ {81, 69, 0}, // RATEID_VHT_MCS2_1SS_BW40 40.5 Mbps
+ {108, 70, 0}, // RATEID_VHT_MCS3_1SS_BW40 54 Mbps
+ {162, 71, 0}, // RATEID_VHT_MCS4_1SS_BW40 81 Mbps
+ {216, 72, 0}, // RATEID_VHT_MCS5_1SS_BW40 108 Mbps
+ {243, 73, 0}, // RATEID_VHT_MCS6_1SS_BW40 121.5 Mbps
+ {270, 74, 0}, // RATEID_VHT_MCS7_1SS_BW40 135 Mbps
+ {324, 75, 0}, // RATEID_VHT_MCS8_1SS_BW40 162 Mbps
+ {360, 76, 0}, // RATEID_VHT_MCS9_1SS_BW40 180 Mbps
+
+ /* VHT bw80<--> Mrvl rate idx - nss2 */
+ {117, 97, 1}, // RATEID_VHT_MCS0_2SS_BW80 58.5 Mbps
+ {234, 98, 1}, // RATEID_VHT_MCS1_2SS_BW80 117 Mbps
+ {350, 99, 1}, // RATEID_VHT_MCS2_2SS_BW80 175 Mbps
+ {468, 100, 1}, // RATEID_VHT_MCS3_2SS_BW80 234 Mbps
+ {702, 101, 1}, // RATEID_VHT_MCS4_2SS_BW80 351 Mbps
+ {936, 102, 1}, // RATEID_VHT_MCS5_2SS_BW80 468 Mbps
+ {1053, 103, 1}, // RATEID_VHT_MCS6_2SS_BW80 526.5 Mbps
+ {1170, 104, 1}, // RATEID_VHT_MCS7_2SS_BW80 585 Mbps
+ {1404, 105, 1}, // RATEID_VHT_MCS8_2SS_BW80 702 Mbps
+ {1560, 106, 1}, // RATEID_VHT_MCS9_2SS_BW80 780 Mbps
+ /* VHT bw80<--> Mrvl rate idx - nss1 */
+ {58, 87, 0}, // RATEID_VHT_MCS0_1SS_BW80 29.3 Mbps, 29.3x2 could
+ // correspond to 58
+ {59, 87, 0}, // RATEID_VHT_MCS0_1SS_BW80 29.3 Mbps, 29.3*2 could
+ // correspond to 59 too
+ {117, 88, 0}, // RATEID_VHT_MCS1_1SS_BW80 58.5 Mbps
+ {175, 89, 0}, // RATEID_VHT_MCS2_1SS_BW80 87.8 Mbps, 87.8x2 could
+ // correspond to 175
+ {176, 89, 0}, // RATEID_VHT_MCS2_1SS_BW80 87.8 Mbps, 87.8x2 could
+ // correspond to 176 too
+ {234, 90, 0}, // RATEID_VHT_MCS3_1SS_BW80 117 Mbps
+ {351, 91, 0}, // RATEID_VHT_MCS4_1SS_BW80 175.5 Mbps
+ {468, 92, 0}, // RATEID_VHT_MCS5_1SS_BW80 234 Mbps
+ {526, 93, 0}, // RATEID_VHT_MCS6_1SS_BW80 263.3 Mbps, 263.3x2 could
+ // correspond to 526
+ {527, 93, 0}, // RATEID_VHT_MCS6_1SS_BW80 263.3 Mbps, 263.3x2 could
+ // correspond to 527 too
+ {585, 94, 0}, // RATEID_VHT_MCS7_1SS_BW80 292.5 Mbps
+ {702, 95, 0}, // RATEID_VHT_MCS8_1SS_BW80 351 Mbps
+ {780, 96, 0}, // RATEID_VHT_MCS9_1SS_BW80 390 Mbps
+};
+
+/** rate_map_table_1x1 is based on rate_map_table_2x2 and remove nss2 part.
+ * For the chip who only support 1x1, Mrvl rate idx define is different with 2x2
+ * in FW We need redefine a bitrate to Mrvl rate idx table for 1x1 chip.
+ */
+const rate_map rate_map_table_1x1[] = {
+ /* LG <--> Mrvl rate idx */
+ {2, 0, 0}, // RATEID_DBPSK1Mbps
+ {4, 1, 0}, // RATEID_DQPSK2Mbps
+ {11, 2, 0}, // RATEID_CCK5_5Mbps
+ {22, 3, 0}, // RATEID_CCK11Mbps
+ {44, 4, 0}, // RATEID_CCK22Mbps
+ {12, 5, 0}, // RATEID_OFDM6Mbps
+ {18, 6, 0}, // RATEID_OFDM9Mbps
+ {24, 7, 0}, // RATEID_OFDM12Mbps
+ {36, 8, 0}, // RATEID_OFDM18Mbps
+ {48, 9, 0}, // RATEID_OFDM24Mbps
+ {72, 10, 0}, // RATEID_OFDM36Mbps
+ {96, 11, 0}, // RATEID_OFDM48Mbps
+ {108, 12, 0}, // RATEID_OFDM54Mbps
+ {144, 13, 0}, // RATEID_OFDM72Mbps
+
+ /* HT bw20 <--> Mrvl rate idx */
+ {13, 14, 0}, // RATEID_MCS0_6d5Mbps
+ {26, 15, 0}, // RATEID_MCS1_13Mbps
+ {39, 16, 0}, // RATEID_MCS2_19d5Mbps
+ {52, 17, 0}, // RATEID_MCS3_26Mbps
+ {78, 18, 0}, // RATEID_MCS4_39Mbps
+ {104, 19, 0}, // RATEID_MCS5_52Mbps
+ {117, 20, 0}, // RATEID_MCS6_58d5Mbps
+ {130, 21, 0}, // RATEID_MCS7_65Mbps
+
+ /* HT bw40<--> Mrvl rate idx */
+ {12, 22, 0}, // RATEID_MCS32BW40_6Mbps, for 1x1 start from 22
+ {27, 23, 0}, // RATEID_MCS0BW40_13d5Mbps
+ {54, 24, 0}, // RATEID_MCS1BW40_27Mbps
+ {81, 25, 0}, // RATEID_MCS2BW40_40d5Mbps
+ {108, 26, 0}, // RATEID_MCS3BW40_54Mbps
+ {162, 27, 0}, // RATEID_MCS4BW40_81Mbps
+ {216, 28, 0}, // RATEID_MCS5BW40_108Mbps
+ {243, 29, 0}, // RATEID_MCS6BW40_121d5Mbps
+ {270, 30, 0}, // RATEID_MCS7BW40_135Mbps
+
+ /* VHT bw20<--> Mrvl rate idx */
+ {13, 31, 0}, // RATEID_VHT_MCS0_1SS_BW20 6.5 Mbps
+ {26, 32, 0}, // RATEID_VHT_MCS1_1SS_BW20 13 Mbps
+ {39, 33, 0}, // RATEID_VHT_MCS2_1SS_BW20 19.5 Mbps
+ {52, 34, 0}, // RATEID_VHT_MCS3_1SS_BW20 26 Mbps
+ {78, 35, 0}, // RATEID_VHT_MCS4_1SS_BW20 39 Mbps
+ {104, 36, 0}, // RATEID_VHT_MCS5_1SS_BW20 52 Mbps
+ {117, 37, 0}, // RATEID_VHT_MCS6_1SS_BW20 58.5 Mbps
+ {130, 38, 0}, // RATEID_VHT_MCS7_1SS_BW20 65 Mbps
+ {156, 39, 0}, // RATEID_VHT_MCS8_1SS_BW20 78 Mbps
+ {0, 40, 0}, // RATEID_VHT_MCS9_1SS_BW20 86.7 Mbps(INVALID)
+
+ /* VHT bw40<--> Mrvl rate idx */
+ {27, 41, 0}, // RATEID_VHT_MCS0_1SS_BW40 13.5 Mbps
+ {54, 42, 0}, // RATEID_VHT_MCS1_1SS_BW40 27 Mbps
+ {81, 43, 0}, // RATEID_VHT_MCS2_1SS_BW40 40.5 Mbps
+ {108, 44, 0}, // RATEID_VHT_MCS3_1SS_BW40 54 Mbps
+ {162, 45, 0}, // RATEID_VHT_MCS4_1SS_BW40 81 Mbps
+ {216, 46, 0}, // RATEID_VHT_MCS5_1SS_BW40 108 Mbps
+ {243, 47, 0}, // RATEID_VHT_MCS6_1SS_BW40 121.5 Mbps
+ {270, 48, 0}, // RATEID_VHT_MCS7_1SS_BW40 135 Mbps
+ {324, 49, 0}, // RATEID_VHT_MCS8_1SS_BW40 162 Mbps
+ {360, 50, 0}, // RATEID_VHT_MCS9_1SS_BW40 180 Mbps
+
+ /* VHT bw80<--> Mrvl rate idx */
+ {58, 51, 0}, // RATEID_VHT_MCS0_1SS_BW80 29.3 Mbps, 29.3x2 could
+ // correspond to 58
+ {59, 51, 0}, // RATEID_VHT_MCS0_1SS_BW80 29.3 Mbps, 29.3x2 could
+ // correspond to 59 too
+ {117, 52, 0}, // RATEID_VHT_MCS1_1SS_BW80 58.5 Mbps
+ {175, 53, 0}, // RATEID_VHT_MCS2_1SS_BW80 87.8 Mbps, 87.8x2 could
+ // correspond to 175
+ {176, 53, 0}, // RATEID_VHT_MCS2_1SS_BW80 87.8 Mbps, 87.8x2 could
+ // correspond to 176 too
+ {234, 54, 0}, // RATEID_VHT_MCS3_1SS_BW80 117 Mbps
+ {351, 55, 0}, // RATEID_VHT_MCS4_1SS_BW80 175.5 Mbps
+ {468, 56, 0}, // RATEID_VHT_MCS5_1SS_BW80 234 Mbps
+ {526, 57, 0}, // RATEID_VHT_MCS6_1SS_BW80 263.3 Mbps, 263.3x2 could
+ // correspond to 526
+ {527, 57, 0}, // RATEID_VHT_MCS6_1SS_BW80 263.3 Mbps, 263.3x2 could
+ // correspond to 527 too
+ {585, 58, 0}, // RATEID_VHT_MCS7_1SS_BW80 292.5 Mbps
+ {702, 59, 0}, // RATEID_VHT_MCS8_1SS_BW80 351 Mbps
+ {780, 60, 0}, // RATEID_VHT_MCS9_1SS_BW80 390 Mbps
+};
+
+/********************************************************
+ * Global Variables
+ ********************************************************/
+/**
+ * The table to keep region code
+ */
+
+t_u16 region_code_index[MRVDRV_MAX_REGION_CODE] = {0x00, 0x10, 0x20, 0x30, 0x40,
+ 0x41, 0x50, 0xfe, 0xff};
+
+/** The table to keep CFP code for BG */
+t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG] = {};
+/** The table to keep CFP code for A */
+t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A] = {0x1, 0x2, 0x3, 0x4, 0x5};
+
+/**
+ * The rates supported for ad-hoc B mode
+ */
+t_u8 AdhocRates_B[B_SUPPORTED_RATES] = {0x82, 0x84, 0x8b, 0x96, 0};
+
+/**
+ * The rates supported for ad-hoc G mode
+ */
+t_u8 AdhocRates_G[G_SUPPORTED_RATES] = {0x8c, 0x12, 0x98, 0x24, 0xb0,
+ 0x48, 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported for ad-hoc BG mode
+ */
+t_u8 AdhocRates_BG[BG_SUPPORTED_RATES] = {0x82, 0x84, 0x8b, 0x96, 0x0c,
+ 0x12, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported in A mode for ad-hoc
+ */
+t_u8 AdhocRates_A[A_SUPPORTED_RATES] = {0x8c, 0x12, 0x98, 0x24, 0xb0,
+ 0x48, 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported in A mode (used for BAND_A)
+ */
+t_u8 SupportedRates_A[A_SUPPORTED_RATES] = {0x0c, 0x12, 0x18, 0x24, 0xb0,
+ 0x48, 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported by the card
+ */
+t_u16 WlanDataRates[WLAN_SUPPORTED_RATES_EXT] = {
+ 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6C, 0x90, 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82,
+ 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00};
+
+/**
+ * The rates supported in B mode
+ */
+t_u8 SupportedRates_B[B_SUPPORTED_RATES] = {0x02, 0x04, 0x0b, 0x16, 0x00};
+
+/**
+ * The rates supported in G mode (BAND_G, BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_G[G_SUPPORTED_RATES] = {0x0c, 0x12, 0x18, 0x24, 0x30,
+ 0x48, 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported in BG mode (BAND_B|BAND_G, BAND_B|BAND_G|BAND_GN)
+ */
+t_u8 SupportedRates_BG[BG_SUPPORTED_RATES] = {0x02, 0x04, 0x0b, 0x0c, 0x12,
+ 0x16, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0x00};
+
+/**
+ * The rates supported in N mode
+ */
+t_u8 SupportedRates_N[N_SUPPORTED_RATES] = {0x02, 0x04, 0};
+
+#define MCS_NUM_AX 12
+// for MCS0/MCS1/MCS3/MCS4 have 4 additional DCM=1 value
+// note: the value in the table is 2 multiplier of the actual rate
+t_u16 ax_mcs_rate_nss1[12][MCS_NUM_AX + 4] = {
+ {0x90, 0x48, 0x120, 0x90, 0x1B0, 0x240, 0x120, 0x360, 0x1B0, 0x481,
+ 0x511, 0x5A1, 0x6C1, 0x781, 0x871, 0x962}, /*SG 160M*/
+ {0x88, 0x44, 0x110, 0x88, 0x198, 0x220, 0x110, 0x330, 0x198, 0x440,
+ 0x4C9, 0x551, 0x661, 0x716, 0x7F9, 0x8DC}, /*MG 160M*/
+ {0x7A, 0x3D, 0xF5, 0x7A, 0x16F, 0x1EA, 0xF5, 0x2DF, 0x16F, 0x3D4, 0x44E,
+ 0x4C9, 0x5BE, 0x661, 0x72D, 0x7F9}, /*LG 160M*/
+ {0x48, 0x24, 0x90, 0x48, 0xD8, 0x120, 0x90, 0x1B0, 0xD8, 0x240, 0x288,
+ 0x2D0, 0x360, 0x3C0, 0x438, 0x4B0}, /*SG 80M*/
+ {0x44, 0x22, 0x88, 0x44, 0xCC, 0x110, 0x88, 0x198, 0xCC, 0x220, 0x264,
+ 0x2A8, 0x330, 0x38B, 0x3FC, 0x46E}, /*MG 80M*/
+ {0x3D, 0x1E, 0x7A, 0x3D, 0xB7, 0xF5, 0x7A, 0x16F, 0xB7, 0x1EA, 0x227,
+ 0x264, 0x2DF, 0x330, 0x396, 0x3FC}, /*LG 80M*/
+ {0x22, 0x11, 0x44, 0x22, 0x67, 0x89, 0x44, 0xCE, 0x67, 0x113, 0x135,
+ 0x158, 0x19D, 0x1CA, 0x204, 0x23D}, /*SG 40M*/
+ {0x20, 0x10, 0x41, 0x20, 0x61, 0x82, 0x41, 0xC3, 0x61, 0x104, 0x124,
+ 0x145, 0x186, 0x1B1, 0x1E7, 0x21D}, /*MG 40M*/
+ {0x1D, 0xE, 0x3A, 0x1D, 0x57, 0x75, 0x3A, 0xAF, 0x57, 0xEA, 0x107,
+ 0x124, 0x15F, 0x186, 0x1B6, 0x1E7}, /*LG 40M*/
+ {0x11, 0x8, 0x22, 0x11, 0x33, 0x44, 0x22, 0x67, 0x33, 0x89, 0x9A, 0xAC,
+ 0xCE, 0xE5, 0x102, 0x11E}, /*SG 20M*/
+ {0x10, 0x8, 0x20, 0x10, 0x30, 0x41, 0x20, 0x61, 0x30, 0x82, 0x92, 0xA2,
+ 0xC3, 0xD8, 0xF3, 0x10E}, /*MG 20M*/
+ {0xE, 0x7, 0x1D, 0xE, 0x2B, 0x3A, 0x1D, 0x57, 0x2B, 0x75, 0x83, 0x92,
+ 0xAF, 0xC3, 0xDB, 0xF3} /*LG 20M*/
+};
+
+// note: the value in the table is 2 multiplier of the actual rate
+t_u16 ax_tone_ru_rate_nss1[9][MCS_NUM_AX + 4] = {
+ {0x8, 0x4, 0xF, 0x8, 0x17, 0x1E, 0xF, 0x2D, 0x17, 0x3C, 0x44, 0x4B,
+ 0x5A, 0x64, 0x71, 0x7D}, /*SG 106-tone*/
+ {0x7, 0x4, 0xF, 0x7, 0x16, 0x1D, 0xF, 0x2B, 0x16, 0x39, 0x40, 0x47,
+ 0x55, 0x5F, 0x6B, 0x76}, /*MG 106-tone*/
+ {0x7, 0x3, 0xD, 0x6, 0x14, 0x1A, 0xD, 0x27, 0x14, 0x33, 0x3A, 0x40,
+ 0x4D, 0x55, 0x60, 0x6B}, /*LG 106-tone*/
+ {0x4, 0x2, 0x7, 0x4, 0xB, 0xF, 0x7, 0x16, 0xB, 0x1D, 0x20, 0x22, 0x2B,
+ 0x2F, 0x35, 0x3B}, /*SG 52-tone*/
+ {0x4, 0x2, 0x7, 0x4, 0xA, 0xE, 0x7, 0x14, 0xA, 0x1B, 0x1E, 0x22, 0x28,
+ 0x2D, 0x32, 0x38}, /*MG 52-tone*/
+ {0x3, 0x2, 0x6, 0x3, 0x9, 0xC, 0x6, 0x12, 0x9, 0x18, 0x1B, 0x1E, 0x24,
+ 0x28, 0x2D, 0x32}, /*LG 52-tone*/
+ {0x2, 0x1, 0x4, 0x2, 0x6, 0x7, 0x4, 0xB, 0x5, 0xE, 0x10, 0x12, 0x15,
+ 0x18, 0x1A, 0x1D}, /*SG 26-tone*/
+ {0x2, 0x1, 0x4, 0x2, 0x5, 0x6, 0x4, 0xA, 0x5, 0xD, 0xF, 0x11, 0x14,
+ 0x16, 0x19, 0x1C}, /*MG 26-tone*/
+ {0x2, 0x1, 0x3, 0x2, 0x5, 0x6, 0x3, 0x9, 0x4, 0xC, 0xE, 0xF, 0x12, 0x14,
+ 0x17, 0x19} /*LG 26-tone*/
+};
+
+// note: the value in the table is 2 multiplier of the actual rate
+t_u16 ax_mcs_rate_nss2[12][MCS_NUM_AX + 4] = {
+ {0x120, 0x90, 0x240, 0x120, 0x360, 0x481, 0x240, 0x61C, 0x360, 0x901,
+ 0xA22, 0xB42, 0xD82, 0xF03, 0x10E3, 0x12C3}, /*SG 160M*/
+ {0x110, 0x88, 0x220, 0x110, 0x330, 0x440, 0x220, 0x661, 0x330, 0x881,
+ 0x992, 0xAA2, 0xCAC, 0xE2D, 0xFF3, 0x11B9}, /*MG 160M*/
+ {0xF5, 0x7A, 0x1EA, 0xF5, 0x2DF, 0x3D4, 0x1EA, 0x5BE, 0x2DF, 0x7A8,
+ 0x1134, 0x992, 0xB7C, 0xCC2, 0xE5B, 0xFF3}, /*LG 160M*/
+ {0x90, 0x48, 0x120, 0x90, 0x1B0, 0x240, 0x120, 0x360, 0x1B0, 0x481,
+ 0x511, 0x5A1, 0x6C1, 0x781, 0x871, 0x962}, /*SG 80M*/
+ {0x88, 0x44, 0x110, 0x88, 0x198, 0x220, 0x110, 0x330, 0x198, 0x440,
+ 0x4C9, 0x551, 0x661, 0x716, 0x7F9, 0x8DC}, /*MG 80M*/
+ {0x7A, 0x3D, 0xF5, 0x7A, 0x16F, 0x1EA, 0xF5, 0x2DF, 0x16F, 0x3D4, 0x44E,
+ 0x4C9, 0x5BE, 0x661, 0x72D, 0x7F9}, /*LG 80M*/
+ {0x44, 0x22, 0x89, 0x44, 0xCE, 0x113, 0x89, 0x19D, 0xCE, 0x226, 0x26B,
+ 0x2B0, 0x339, 0x395, 0x408, 0x47B}, /*SG 40M*/
+ {0x41, 0x20, 0x82, 0x41, 0xC3, 0x104, 0x82, 0x186, 0xC3, 0x208, 0x249,
+ 0x28A, 0x30C, 0x362, 0x3CE, 0x43B}, /*MG 40M*/
+ {0x3A, 0x1D, 0x75, 0x3A, 0xAF, 0xEA, 0x75, 0x15F, 0xAF, 0x1D4, 0x20E,
+ 0x249, 0x2BE, 0x30C, 0x36D, 0x3CF}, /*LG 40M*/
+ {0x22, 0x11, 0x44, 0x22, 0x67, 0x89, 0x44, 0xCE, 0x67, 0x113, 0x135,
+ 0x158, 0x19D, 0x1CA, 0x204, 0x23D}, /*SG 20M*/
+ {0x20, 0x10, 0x41, 0x20, 0x61, 0x82, 0x41, 0xC3, 0x61, 0x104, 0x124,
+ 0x145, 0x186, 0x1B1, 0x1E7, 0x21D}, /*MG 20M*/
+ {0x1D, 0xE, 0x3A, 0x1D, 0x57, 0x75, 0x3A, 0xAF, 0x57, 0xEA, 0x107,
+ 0x124, 0x15F, 0x186, 0x1B6, 0x1E7} /*LG 20M*/
+};
+
+// note: the value in the table is 2 multiplier of the actual rate
+t_u16 ax_tone_ru_rate_nss2[9][MCS_NUM_AX + 4] = {
+ {0xF, 0x8, 0x1E, 0xF, 0x2D, 0x3C, 0x1E, 0x5A, 0x2D, 0x78, 0x87, 0x96,
+ 0xB4, 0xC8, 0xE1, 0xFA}, /*SG 106-tone*/
+ {0xE, 0x7, 0x1D, 0xE, 0x2B, 0x39, 0x1D, 0x55, 0x2B, 0x72, 0x80, 0x8E,
+ 0xAA, 0xBD, 0xD5, 0xED}, /*MG 106-tone*/
+ {0xD, 0x7, 0x1A, 0xD, 0x27, 0x33, 0x1A, 0x4D, 0x27, 0x66, 0x73, 0x80,
+ 0x99, 0xAA, 0xC0, 0xD5}, /*LG 106-tone*/
+ {0x7, 0x4, 0xF, 0x7, 0x16, 0x1D, 0xF, 0x2A, 0x16, 0x39, 0x40, 0x47,
+ 0x55, 0x5F, 0x6A, 0x76}, /*SG 52-tone*/
+ {0x7, 0x4, 0xE, 0x7, 0x14, 0x1B, 0xE, 0x28, 0x14, 0x36, 0x3C, 0x43,
+ 0x50, 0x59, 0x64, 0x70}, /*MG 52-tone*/
+ {0x6, 0x3, 0xC, 0x6, 0x12, 0x18, 0xC, 0x24, 0x12, 0x30, 0x36, 0x3C,
+ 0x48, 0x50, 0x5A, 0x64}, /*LG 52-tone*/
+ {0x4, 0x2, 0x7, 0x4, 0xB, 0xF, 0x7, 0x16, 0xB, 0x1D, 0x20, 0x22, 0x2B,
+ 0x2F, 0x35, 0x3B}, /*SG 26-tone*/
+ {0x4, 0x2, 0x7, 0x4, 0xA, 0xE, 0x7, 0x14, 0xA, 0x1B, 0x1E, 0x22, 0x28,
+ 0x2D, 0x32, 0x38}, /*MG 26-tone*/
+ {0x3, 0x2, 0x6, 0x3, 0x9, 0xC, 0x6, 0x12, 0x9, 0x18, 0x1B, 0x1E, 0x24,
+ 0x28, 0x2D, 0x32} /*LG 26-tone*/
+};
+
+/********************************************************
+ * Local Functions
+ ********************************************************/
+/**
+ * @brief Find a character in a string.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to string
+ * @param c Character to be located
+ * @param n The length of string
+ *
+ * @return A pointer to the first occurrence of c in string, or MNULL if
+ * c is not found.
+ */
+static void *wlan_memchr(pmlan_adapter pmadapter, void *s, int c, int n)
+{
+ const t_u8 *p = (t_u8 *)s;
+
+ ENTER();
+
+ while (n--) {
+ if ((t_u8)c == *p++) {
+ LEAVE();
+ return (void *)(p - 1);
+ }
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function finds the CFP in
+ * cfp_table_BG/A based on region/code and band parameter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ *
+ * @return A pointer to CFP
+ */
+static chan_freq_power_t *wlan_get_region_cfp_table(pmlan_adapter pmadapter,
+ t_u8 region, t_u8 band,
+ int *cfp_no)
+{
+ t_u32 i;
+ t_u8 cfp_bg, cfp_a;
+
+ ENTER();
+
+ cfp_bg = cfp_a = region;
+ if (!region) {
+ /* Invalid region code, use CFP code */
+ cfp_bg = pmadapter->cfp_code_bg;
+ cfp_a = pmadapter->cfp_code_a;
+ }
+
+ if (band & (BAND_B | BAND_G | BAND_GN | BAND_GAC)) {
+ /* Return the FW cfp table for requested region code, if
+ * available. If region is not forced and the requested region
+ * code is different, simply return the corresponding
+ * pre-defined table.
+ */
+ if (pmadapter->otp_region && pmadapter->cfp_otp_bg) {
+ if (pmadapter->otp_region->force_reg ||
+ (cfp_bg ==
+ (t_u8)pmadapter->otp_region->region_code)) {
+ *cfp_no = pmadapter->tx_power_table_bg_rows;
+ LEAVE();
+ return pmadapter->cfp_otp_bg;
+ }
+ }
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ PRINTM(MINFO, "cfp_table_BG[%d].code=%d\n", i,
+ cfp_table_BG[i].code);
+ /* Check if region/code matches for BG bands */
+ if (cfp_table_BG[i].code == cfp_bg) {
+ /* Select by band */
+ *cfp_no = cfp_table_BG[i].cfp_no;
+ LEAVE();
+ return cfp_table_BG[i].cfp;
+ }
+ }
+ }
+ if (band & (BAND_A | BAND_AN | BAND_AAC)) {
+ /* Return the FW cfp table for requested region code */
+ if (pmadapter->otp_region && pmadapter->cfp_otp_a) {
+ if (pmadapter->otp_region->force_reg ||
+ (cfp_a ==
+ (t_u8)pmadapter->otp_region->region_code)) {
+ *cfp_no = pmadapter->tx_power_table_a_rows;
+ LEAVE();
+ return pmadapter->cfp_otp_a;
+ }
+ }
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ PRINTM(MINFO, "cfp_table_A[%d].code=%d\n", i,
+ cfp_table_A[i].code);
+ /* Check if region/code matches for A bands */
+ if (cfp_table_A[i].code == cfp_a) {
+ /* Select by band */
+ *cfp_no = cfp_table_A[i].cfp_no;
+ LEAVE();
+ return cfp_table_A[i].cfp;
+ }
+ }
+ }
+
+ if (!region)
+ PRINTM(MERROR, "Error Band[0x%x] or code[BG:%#x, A:%#x]\n",
+ band, cfp_bg, cfp_a);
+ else
+ PRINTM(MERROR, "Error Band[0x%x] or region[%#x]\n", band,
+ region);
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function copies dynamic CFP elements from one table to another.
+ * Only copy elements where channel numbers match.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cfp Destination table
+ * @param num_cfp Number of elements in dest table
+ * @param cfp_src Source table
+ * @param num_cfp_src Number of elements in source table
+ */
+static t_void wlan_cfp_copy_dynamic(pmlan_adapter pmadapter,
+ chan_freq_power_t *cfp, t_u8 num_cfp,
+ chan_freq_power_t *cfp_src,
+ t_u8 num_cfp_src)
+{
+ int i, j;
+
+ ENTER();
+
+ if (cfp == cfp_src) {
+ LEAVE();
+ return;
+ }
+
+ /* first clear dest dynamic blacklisted entries */
+ for (i = 0; i < num_cfp; i++) {
+ cfp[i].dynamic.blacklist = MFALSE;
+ cfp[i].dynamic.flags = 0;
+ }
+
+ /* copy dynamic blacklisted entries from source where channels match */
+ if (cfp_src) {
+ for (i = 0; i < num_cfp; i++)
+ for (j = 0; j < num_cfp_src; j++)
+ if (cfp[i].channel == cfp_src[j].channel) {
+ cfp[i].dynamic.blacklist =
+ cfp_src[j].dynamic.blacklist;
+ cfp[i].dynamic.flags =
+ cfp_src[j].dynamic.flags;
+ break;
+ }
+ }
+
+ LEAVE();
+}
+
+/********************************************************
+ * Global Functions
+ ********************************************************/
+/**
+ * @brief This function converts region string to integer code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param country_code Country string
+ * @param cfp_bg Pointer to buffer
+ * @param cfp_a Pointer to buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_country_2_cfp_table_code(pmlan_adapter pmadapter,
+ t_u8 *country_code, t_u8 *cfp_bg,
+ t_u8 *cfp_a)
+{
+ t_u8 i;
+
+ ENTER();
+
+ /* Look for code in mapping table */
+ for (i = 0; i < NELEMENTS(country_code_mapping); i++) {
+ if (!memcmp(pmadapter, country_code_mapping[i].country_code,
+ country_code, COUNTRY_CODE_LEN - 1)) {
+ *cfp_bg = country_code_mapping[i].cfp_code_bg;
+ *cfp_a = country_code_mapping[i].cfp_code_a;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ /* If still not found, look for code in EU country code table */
+ for (i = 0; i < NELEMENTS(eu_country_code_table); i++) {
+ if (!memcmp(pmadapter, eu_country_code_table[i], country_code,
+ COUNTRY_CODE_LEN - 1)) {
+ *cfp_bg = EU_CFP_CODE_BG;
+ *cfp_a = EU_CFP_CODE_A;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function finds if given country code is in EU table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param country_code Country string
+ *
+ * @return MTRUE or MFALSE
+ */
+t_bool wlan_is_etsi_country(pmlan_adapter pmadapter, t_u8 *country_code)
+{
+ t_u8 i;
+
+ ENTER();
+
+ /* Look for code in EU country code table */
+ for (i = 0; i < NELEMENTS(eu_country_code_table); i++) {
+ if (!memcmp(pmadapter, eu_country_code_table[i], country_code,
+ COUNTRY_CODE_LEN - 1)) {
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+#define BAND_MASK_5G 0x03
+#define ANTENNA_OFFSET 2
+/**
+ * @brief This function adjust the antenna index
+ *
+ * V16_FW_API: Bit0: ant A, Bit 1:ant B, Bit0 & Bit 1: A+B
+ * 8887: case1: 0 - 2.4G ant A, 1- 2.4G antB, 2-- 5G ant C
+ * case2: 0 - 2.4G ant A, 1- 2.4G antB, 0x80- 5G antA, 0x81-5G ant B
+ * @param priv A pointer to mlan_private structure
+ * @param prx_pd A pointer to the RxPD structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+t_u8 wlan_adjust_antenna(pmlan_private priv, RxPD *prx_pd)
+{
+ t_u8 antenna = prx_pd->antenna;
+#if defined(SD8887) || defined(SD8987)
+ t_u32 rx_channel = (prx_pd->rx_info & RXPD_CHAN_MASK) >> 5;
+#endif
+ if (prx_pd->antenna == 0xff)
+ return 0;
+ if (priv->adapter->pcard_info->v16_fw_api) {
+ if ((antenna & MBIT(0)) && (antenna & MBIT(1)))
+ antenna = 2;
+ else if (antenna & MBIT(1))
+ antenna = 1;
+ else if (antenna & MBIT(0))
+ antenna = 0;
+ }
+
+#if defined(SD8887) || defined(SD8987)
+ if (MFALSE
+#ifdef SD8887
+ || IS_SD8887(priv->adapter->card_type)
+#endif
+#ifdef SD8987
+ || IS_SD8987(priv->adapter->card_type)
+#endif
+ ) {
+ if ((priv->adapter->antinfo & ANT_DIVERSITY_2G) &&
+ (priv->adapter->antinfo & ANT_DIVERSITY_5G)) {
+#define MAX_2G_CHAN 14
+ if (rx_channel > MAX_2G_CHAN)
+ antenna += ANTENNA_OFFSET;
+ }
+ }
+#endif
+
+ return antenna;
+}
+
+/**
+ * @brief This function adjust the rate index
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param rx_rate rx rate
+ * @param rate_info rate info
+ * @return rate index
+ */
+t_u16 wlan_adjust_data_rate(mlan_private *priv, t_u8 rx_rate, t_u8 rate_info)
+{
+ t_u16 rate_index = 0;
+ t_u8 bw = 0;
+ t_u8 nss = 0;
+ t_bool sgi_enable = 0;
+ t_u8 gi = 0;
+#define MAX_MCS_NUM_AX 12
+
+#define MAX_MCS_NUM_SUPP 16
+#define MAX_MCS_NUM_AC 10
+#define RATE_INDEX_MCS0 12
+ bw = (rate_info & 0xC) >> 2;
+ sgi_enable = (rate_info & 0x10) >> 4;
+ if ((rate_info & 0x3) == 0) {
+ rate_index = (rx_rate > MLAN_RATE_INDEX_OFDM0) ? rx_rate - 1 :
+ rx_rate;
+ } else if ((rate_info & 0x03) == 1) {
+ rate_index = RATE_INDEX_MCS0 +
+ MAX_MCS_NUM_SUPP * 2 * sgi_enable +
+ MAX_MCS_NUM_SUPP * bw + rx_rate;
+ } else if ((rate_info & 0x3) == 2) {
+ if (IS_STREAM_2X2(priv->adapter->feature_control))
+ nss = rx_rate >> 4; // 0:NSS1, 1:NSS2
+ rate_index = RATE_INDEX_MCS0 + MAX_MCS_NUM_SUPP * 4 +
+ MAX_MCS_NUM_AC * 6 * sgi_enable +
+ MAX_MCS_NUM_AC * 2 * bw + MAX_MCS_NUM_AC * nss +
+ (rx_rate & 0x0f);
+ } else if ((rate_info & 0x3) == 3) {
+ gi = (rate_info & 0x10) >> 4 | (rate_info & 0x80) >> 6;
+ if (IS_STREAM_2X2(priv->adapter->feature_control))
+ nss = rx_rate >> 4; // 0:NSS1, 1:NSS2
+ rate_index = RATE_INDEX_MCS0 + MAX_MCS_NUM_SUPP * 4 +
+ MAX_MCS_NUM_AC * 12 + MAX_MCS_NUM_AX * 6 * gi +
+ MAX_MCS_NUM_AX * 2 * bw + MAX_MCS_NUM_AX * nss +
+ (rx_rate & 0x0f);
+ }
+ return rate_index;
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Use index to get the data rate
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param index The index of data rate
+ * @param tx_rate_info Tx rate info
+ * @param ext_rate_info Extend tx rate info
+ *
+ * @return Data rate or 0
+ */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 tx_rate_info, t_u8 ext_rate_info)
+{
+#define MCS_NUM_SUPP 16
+ t_u16 mcs_rate[4][MCS_NUM_SUPP] = {
+ {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e, 0x36, 0x6c,
+ 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c}, /*LG 40M*/
+ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c, 0x3c, 0x78,
+ 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258}, /*SG 40M */
+ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82, 0x1a, 0x34,
+ 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104}, /*LG 20M */
+ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, 0x1c, 0x39,
+ 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120}}; /*SG 20M */
+
+#define MCS_NUM_AC 10
+ /* NSS 1. note: the value in the table is 2 multiplier of the actual
+ * rate in other words, it is in the unit of 500 Kbs
+ */
+ t_u16 ac_mcs_rate_nss1[8][MCS_NUM_AC] = {
+ {0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, 0x492, 0x57C,
+ 0x618}, /* LG 160M*/
+ {0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, 0x514, 0x618,
+ 0x6C6}, /* SG 160M*/
+ {0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F, 0x249, 0x2BE,
+ 0x30C}, /* LG 80M */
+ {0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249, 0x28A, 0x30C,
+ 0x363}, /* SG 80M */
+ {0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x144,
+ 0x168}, /* LG 40M */
+ {0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E, 0x12C, 0x168,
+ 0x190}, /* SG 40M */
+ {0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C,
+ 0x00}, /* LG 20M */
+ {0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE,
+ 0x00}, /* SG 20M */
+ };
+ /* NSS 2. note: the value in the table is 2 multiplier of the actual
+ * rate
+ */
+ t_u16 ac_mcs_rate_nss2[8][MCS_NUM_AC] = {
+ {0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A, 0x924, 0xAF8,
+ 0xC30}, /*LG 160M*/
+ {0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924, 0xA28, 0xC30,
+ 0xD8B}, /*SG 160M*/
+
+ {0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, 0x492, 0x57C,
+ 0x618}, /*LG 80M*/
+ {0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, 0x514, 0x618,
+ 0x6C6}, /*SG 80M*/
+ {0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6, 0x21C, 0x288,
+ 0x2D0}, /*LG 40M*/
+ {0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C, 0x258, 0x2D0,
+ 0x320}, /*SG 40M*/
+ {0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104, 0x138,
+ 0x00}, /*LG 20M*/
+ {0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121, 0x15B,
+ 0x00}, /*SG 20M*/
+ };
+
+ t_u32 rate = 0;
+ t_u8 mcs_index = 0;
+ t_u8 he_dcm = 0;
+ t_u8 he_tone = 0;
+ t_u8 stbc = 0;
+
+ t_u8 bw = 0;
+ t_u8 gi = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "%s:index=%d, tx_rate_info=%d, ext_rate_info=%d\n",
+ __func__, index, tx_rate_info, ext_rate_info);
+
+ if ((tx_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT) {
+ /* VHT rate */
+ mcs_index = index & 0xF;
+
+ if (mcs_index > 9)
+ mcs_index = 9;
+
+ /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
+ bw = (tx_rate_info & 0xC) >> 2;
+ /* LGI: gi =0, SGI: gi = 1 */
+ gi = (tx_rate_info & 0x10) >> 4;
+ if ((index >> 4) == 1) {
+ /* NSS = 2 */
+ rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
+ } else
+ /* NSS = 1 */
+ rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
+ } else
+
+ if ((tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) {
+ /* VHT rate */
+ mcs_index = index & 0xF;
+ he_dcm = ext_rate_info & MBIT(0);
+
+ if (mcs_index > MCS_NUM_AX - 1)
+ mcs_index = MCS_NUM_AX - 1;
+
+ /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
+ bw = (tx_rate_info & (MBIT(3) | MBIT(2))) >> 2;
+ /* BIT7:BIT4 0:0= 0.8us,0:1= 0.8us, 1:0=1.6us, 1:1=3.2us or
+ * 0.8us
+ */
+ gi = (tx_rate_info & MBIT(4)) >> 4 |
+ (tx_rate_info & MBIT(7)) >> 6;
+ /* STBC: BIT5 in tx rate info */
+ stbc = (tx_rate_info & MBIT(5)) >> 5;
+
+ if (gi > 3) {
+ PRINTM(MERROR, "Invalid gi value");
+ return 0;
+ }
+
+ if ((gi == 3) && stbc && he_dcm) {
+ gi = 0;
+ stbc = 0;
+ he_dcm = 0;
+ }
+ /* map to gi 0:0.8us,1:1.6us 2:3.2us*/
+ if (gi > 0)
+ gi = gi - 1;
+
+ // TODO: hardcode he_tone here, wait for FW value ready.
+ he_tone = 4;
+
+ // he_tone = (ext_rate_info & 0xE) >> 1;
+
+ if ((index >> 4) == 1) {
+ switch (mcs_index) {
+ case 0:
+ case 1:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss2[3*(2-he_tone)+gi][mcs_index*2
+ //+ he_dcm];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss2[3 * (3 - bw) + gi]
+ [mcs_index * 2 + he_dcm];
+ break;
+ case 2:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss2[3*(2-he_tone)+gi][mcs_index*2];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss2[3 * (3 - bw) + gi]
+ [mcs_index * 2];
+ break;
+ case 3:
+ case 4:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss2[3*(2-he_tone)+gi][mcs_index*2
+ //- 1 + he_dcm];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss2[3 * (3 - bw) + gi]
+ [mcs_index * 2 - 1 +
+ he_dcm];
+ break;
+
+ default:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss2[3*(2-he_tone)+gi][mcs_index
+ //+ 4];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss2[3 * (3 - bw) + gi]
+ [mcs_index + 4];
+ break;
+ }
+ } else {
+ switch (mcs_index) {
+ case 0:
+ case 1:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss1[3*(2-he_tone)+gi][mcs_index*2
+ //+ he_dcm];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss1[3 * (3 - bw) + gi]
+ [mcs_index * 2 + he_dcm];
+ break;
+ case 2:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss1[3*(2-he_tone)+gi][mcs_index*2];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss1[3 * (3 - bw) + gi]
+ [mcs_index * 2];
+ break;
+ case 3:
+ case 4:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss1[3*(2-he_tone)+gi][mcs_index*2
+ //- 1 + he_dcm];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss1[3 * (3 - bw) + gi]
+ [mcs_index * 2 - 1 +
+ he_dcm];
+ break;
+
+ default:
+ // #if 0
+ // if (he_tone < 3) {
+ // rate =
+ //ax_tone_ru_rate_nss1[3*(2-he_tone)+gi][mcs_index
+ //+ 4];
+ // } else {
+ // #endif
+ rate = ax_mcs_rate_nss1[3 * (3 - bw) + gi]
+ [mcs_index + 4];
+ break;
+ }
+ }
+ } else if ((tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HT) {
+ /* HT rate */
+ /* 20M: bw=0, 40M: bw=1 */
+ bw = (tx_rate_info & 0xC) >> 2;
+ /* LGI: gi =0, SGI: gi = 1 */
+ gi = (tx_rate_info & 0x10) >> 4;
+ if (index == MLAN_RATE_BITMAP_MCS0) {
+ if (gi == 1)
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < MCS_NUM_SUPP) {
+ if (bw <= 1)
+ rate = mcs_rate[2 * (1 - bw) + gi][index];
+ else
+ rate = WlanDataRates[0];
+ } else
+ rate = WlanDataRates[0];
+ } else {
+ /* 11n non HT rates */
+ if (index >= WLAN_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = WlanDataRates[index];
+ }
+ LEAVE();
+ return rate;
+}
+
+/**
+ * @brief Use rate to get the index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rate Data rate
+ *
+ * @return Index or 0
+ */
+t_u8 wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate)
+{
+ t_u16 *ptr;
+
+ ENTER();
+ if (rate) {
+ ptr = wlan_memchr(pmadapter, WlanDataRates, (t_u8)rate,
+ sizeof(WlanDataRates));
+ if (ptr) {
+ LEAVE();
+ return (t_u8)(ptr - WlanDataRates);
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the active rates
+ *
+ * @return The number of Rates
+ */
+t_u32 wlan_get_active_data_rates(mlan_private *pmpriv, t_u32 bss_mode,
+ t_u16 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k;
+
+ ENTER();
+
+ if (pmpriv->media_connected != MTRUE) {
+ k = wlan_get_supported_rates(pmpriv, bss_mode, config_bands,
+ rates);
+ } else {
+ k = wlan_copy_rates(rates, 0,
+ pmpriv->curr_bss_params.data_rates,
+ pmpriv->curr_bss_params.num_of_rates);
+ }
+
+ LEAVE();
+ return k;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function search through all the regions cfp table to find the
+ * channel, if the channel is found then gets the MIN txpower of the channel
+ * present in all the regions.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number.
+ *
+ * @return The Tx power
+ */
+t_u8 wlan_get_txpwr_of_chan_from_cfp(mlan_private *pmpriv, t_u8 channel)
+{
+ t_u8 i = 0;
+ t_u8 j = 0;
+ t_u8 tx_power = 0;
+ t_u32 cfp_no;
+ chan_freq_power_t *cfp = MNULL;
+ chan_freq_power_t *cfp_a = MNULL;
+ t_u32 cfp_no_a;
+
+ ENTER();
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ /* Get CFP */
+ cfp = cfp_table_BG[i].cfp;
+ cfp_no = cfp_table_BG[i].cfp_no;
+ /* Find matching channel and get Tx power */
+ for (j = 0; j < cfp_no; j++) {
+ if ((cfp + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power = MIN(tx_power,
+ (cfp + j)->max_tx_power);
+ else
+ tx_power =
+ (t_u8)(cfp + j)->max_tx_power;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ /* Get CFP */
+ cfp_a = cfp_table_A[i].cfp;
+ cfp_no_a = cfp_table_A[i].cfp_no;
+ for (j = 0; j < cfp_no_a; j++) {
+ if ((cfp_a + j)->channel == channel) {
+ if (tx_power != 0)
+ tx_power =
+ MIN(tx_power,
+ (cfp_a + j)->max_tx_power);
+ else
+ tx_power = (t_u8)(
+ (cfp_a + j)->max_tx_power);
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return tx_power;
+}
+
+/**
+ * @brief Get the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ * @param region_channel A pointer to region_chan_t structure
+ *
+ * @return A pointer to chan_freq_power_t structure or
+ * MNULL if not found.
+ */
+
+chan_freq_power_t *
+wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter, t_u8 band,
+ t_u16 channel, region_chan_t *region_channel)
+{
+ region_chan_t *rc;
+ chan_freq_power_t *cfp = MNULL;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &region_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
+ /* Fall Through */
+ case BAND_A: /* Matching BAND_A */
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_GN | BAND_GAC:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC:
+ case BAND_G | BAND_GN | BAND_GAC:
+ case BAND_B | BAND_G:
+ /* Fall Through */
+ case BAND_B: /* Matching BAND_B/G */
+ /* Fall Through */
+ case BAND_G:
+ /* Fall Through */
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ if (channel == FIRST_VALID_CHANNEL)
+ cfp = &rc->pcfp[0];
+ else {
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].channel == channel) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ PRINTM(MCMND, "%s: can not find cfp by band %d & channel %d\n",
+ __func__, band, channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param channel The channel to search for
+ *
+ * @return A pointer to chan_freq_power_t structure or MNULL if not
+ * found.
+ */
+chan_freq_power_t *wlan_find_cfp_by_band_and_channel(mlan_adapter *pmadapter,
+ t_u8 band, t_u16 channel)
+{
+ chan_freq_power_t *cfp = MNULL;
+
+ ENTER();
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ cfp = wlan_get_cfp_by_band_and_channel(
+ pmadapter, band, channel, pmadapter->universal_channel);
+ else
+ cfp = wlan_get_cfp_by_band_and_channel(
+ pmadapter, band, channel, pmadapter->region_channel);
+
+ LEAVE();
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info for a specific frequency
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param band It can be BAND_A, BAND_G or BAND_B
+ * @param freq The frequency to search for
+ *
+ * @return Pointer to chan_freq_power_t structure; MNULL if not found
+ */
+chan_freq_power_t *wlan_find_cfp_by_band_and_freq(mlan_adapter *pmadapter,
+ t_u8 band, t_u32 freq)
+{
+ chan_freq_power_t *cfp = MNULL;
+ region_chan_t *rc;
+ int i, j;
+
+ ENTER();
+
+ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+ rc = &pmadapter->region_channel[j];
+
+ /* Any station(s) with 11D enabled */
+ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled,
+ wlan_is_station) > 0)
+ rc = &pmadapter->universal_channel[j];
+
+ if (!rc->valid || !rc->pcfp)
+ continue;
+ switch (rc->band) {
+ case BAND_A:
+ switch (band) {
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
+ /* Fall Through */
+ case BAND_A: /* Matching BAND_A */
+ break;
+ default:
+ continue;
+ }
+ break;
+ case BAND_B:
+ case BAND_G:
+ switch (band) {
+ case BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_G | BAND_GN:
+ case BAND_GN | BAND_GAC:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC:
+ case BAND_G | BAND_GN | BAND_GAC:
+ case BAND_B | BAND_G:
+ /* Fall Through */
+ case BAND_B:
+ /* Fall Through */
+ case BAND_G:
+ /* Fall Through */
+ case 0:
+ break;
+ default:
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+ for (i = 0; i < rc->num_cfp; i++) {
+ if (rc->pcfp[i].freq == freq) {
+ cfp = &rc->pcfp[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ PRINTM(MERROR, "%s: cannot find cfp by band %d & freq %d\n",
+ __func__, band, freq);
+
+ LEAVE();
+ return cfp;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Check if Rate Auto
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8 wlan_is_rate_auto(mlan_private *pmpriv)
+{
+ t_u32 i;
+ int rate_num = 0;
+
+ ENTER();
+
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates); i++)
+ if (pmpriv->bitmap_rates[i])
+ rate_num++;
+
+ LEAVE();
+ if (rate_num > 1)
+ return MTRUE;
+ else
+ return MFALSE;
+}
+
+/**
+ * @brief Covert Rate Bitmap to Rate index
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param rate_bitmap Pointer to rate bitmap
+ * @param size Size of the bitmap array
+ *
+ * @return Rate index
+ */
+int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 *rate_bitmap, int size)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < size * 8; i++) {
+ if (rate_bitmap[i / 16] & (1 << (i % 16))) {
+ LEAVE();
+ return i;
+ }
+ }
+
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Get supported data rates
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_mode The specified BSS mode (Infra/IBSS)
+ * @param config_bands The specified band configuration
+ * @param rates The buf to return the supported rates
+ *
+ * @return The number of Rates
+ */
+t_u32 wlan_get_supported_rates(mlan_private *pmpriv, t_u32 bss_mode,
+ t_u16 config_bands, WLAN_802_11_RATES rates)
+{
+ t_u32 k = 0;
+
+ ENTER();
+
+ if (bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Infra. mode */
+ switch (config_bands) {
+ case (t_u8)BAND_B:
+ PRINTM(MINFO, "Infra Band=%d SupportedRates_B\n",
+ config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_B,
+ sizeof(SupportedRates_B));
+ break;
+ case (t_u8)BAND_G:
+ case BAND_G | BAND_GN:
+ case BAND_G | BAND_GN | BAND_GAC:
+ case BAND_G | BAND_GN | BAND_GAC | BAND_GAX:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_G\n",
+ config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ 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_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC |
+ BAND_GAC:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC |
+ BAND_AAX:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC |
+ BAND_GAC | BAND_AAX | BAND_GAX:
+ case BAND_B | BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_BG\n",
+ config_bands);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ k = wlan_copy_rates(rates, k, SupportedRates_G,
+ sizeof(SupportedRates_G));
+ else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#else
+ k = wlan_copy_rates(rates, k, SupportedRates_BG,
+ sizeof(SupportedRates_BG));
+#endif
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n",
+ config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ case BAND_A | BAND_AN | BAND_AAC:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
+ case BAND_A | BAND_AN | BAND_AAC | BAND_AAX:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_A\n",
+ config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_A,
+ sizeof(SupportedRates_A));
+ break;
+ case BAND_GN:
+ case BAND_GN | BAND_GAC:
+ case BAND_GN | BAND_GAC | BAND_GAX:
+ PRINTM(MINFO, "Infra band=%d SupportedRates_N\n",
+ config_bands);
+ k = wlan_copy_rates(rates, k, SupportedRates_N,
+ sizeof(SupportedRates_N));
+ break;
+ }
+ } else {
+ /* Ad-hoc mode */
+ switch (config_bands) {
+ case (t_u8)BAND_B:
+ PRINTM(MINFO, "Band: Adhoc B\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_B,
+ sizeof(AdhocRates_B));
+ break;
+ case (t_u8)BAND_G:
+ PRINTM(MINFO, "Band: Adhoc G only\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_G,
+ sizeof(AdhocRates_G));
+ break;
+ case BAND_B | BAND_G:
+ PRINTM(MINFO, "Band: Adhoc BG\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_BG,
+ sizeof(AdhocRates_BG));
+ break;
+ case BAND_A:
+ case BAND_A | BAND_AN | BAND_AAC:
+ case BAND_A | BAND_AN | BAND_AAC | BAND_AAX:
+
+ PRINTM(MINFO, "Band: Adhoc A\n");
+ k = wlan_copy_rates(rates, k, AdhocRates_A,
+ sizeof(AdhocRates_A));
+ break;
+ }
+ }
+
+ LEAVE();
+ return k;
+}
+
+#define COUNTRY_ID_US 0
+#define COUNTRY_ID_JP 1
+#define COUNTRY_ID_CN 2
+#define COUNTRY_ID_EU 3
+typedef struct _oper_bw_chan {
+ /*non-global operating class*/
+ t_u8 oper_class;
+ /*global operating class*/
+ t_u8 global_oper_class;
+ /*bandwidth 0-20M 1-40M 2-80M 3-160M*/
+ t_u8 bandwidth;
+ /*channel list*/
+ t_u8 channel_list[13];
+} oper_bw_chan;
+
+/** oper class table for US*/
+static oper_bw_chan oper_bw_chan_us[] = {
+ /** non-Global oper class, global oper class, bandwidth, channel list*/
+ {1, 115, 0, {36, 40, 44, 48}},
+ {2, 118, 0, {52, 56, 60, 64}},
+ {3, 124, 0, {149, 153, 157, 161}},
+ {4,
+ 121,
+ 0,
+ {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144}},
+ {5, 125, 0, {149, 153, 157, 161, 165}},
+ {12, 81, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}},
+ {22, 116, 1, {36, 44}},
+ {23, 119, 1, {52, 60}},
+ {24, 122, 1, {100, 108, 116, 124, 132, 140}},
+ {25, 126, 1, {149, 157}},
+ {26, 126, 1, {149, 157}},
+ {27, 117, 1, {40, 48}},
+ {28, 120, 1, {56, 64}},
+ {29, 123, 1, {104, 112, 120, 128, 136, 144}},
+ {30, 127, 1, {153, 161}},
+ {31, 127, 1, {153, 161}},
+ {32, 83, 1, {1, 2, 3, 4, 5, 6, 7}},
+ {33, 84, 1, {5, 6, 7, 8, 9, 10, 11}},
+ {128, 128, 2, {42, 58, 106, 122, 138, 155}},
+ {129, 129, 3, {50, 114}},
+ {130, 130, 2, {42, 58, 106, 122, 138, 155}},
+};
+/** oper class table for EU*/
+static oper_bw_chan oper_bw_chan_eu[] = {
+ /** non-global oper class,global oper class, bandwidth, channel list*/
+ {1, 115, 0, {36, 40, 44, 48}},
+ {2, 118, 0, {52, 56, 60, 64}},
+ {3, 121, 0, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}},
+ {4, 81, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {5, 116, 1, {36, 44}},
+ {6, 119, 1, {52, 60}},
+ {7, 122, 1, {100, 108, 116, 124, 132}},
+ {8, 117, 1, {40, 48}},
+ {9, 120, 1, {56, 64}},
+ {10, 123, 1, {104, 112, 120, 128, 136}},
+ {11, 83, 1, {1, 2, 3, 4, 5, 6, 7, 8, 9}},
+ {12, 84, 1, {5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {17, 125, 0, {149, 153, 157, 161, 165, 169}},
+ {128, 128, 2, {42, 58, 106, 122, 138, 155}},
+ {129, 129, 3, {50, 114}},
+ {130, 130, 2, {42, 58, 106, 122, 138, 155}},
+};
+/** oper class table for Japan*/
+static oper_bw_chan oper_bw_chan_jp[] = {
+ /** non-Global oper class,global oper class, bandwidth, channel list*/
+ {1, 115, 0, {34, 38, 42, 46, 36, 40, 44, 48}},
+ {30, 81, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {31, 82, 0, {14}},
+ {32, 118, 0, {52, 56, 60, 64}},
+ {33, 118, 0, {52, 56, 60, 64}},
+ {34, 121, 0, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}},
+ {35, 121, 0, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}},
+ {36, 116, 1, {36, 44}},
+ {37, 119, 1, {52, 60}},
+ {38, 119, 1, {52, 60}},
+ {39, 122, 1, {100, 108, 116, 124, 132}},
+ {40, 122, 1, {100, 108, 116, 124, 132}},
+ {41, 117, 1, {40, 48}},
+ {42, 120, 1, {56, 64}},
+ {43, 120, 1, {56, 64}},
+ {44, 123, 1, {104, 112, 120, 128, 136}},
+ {45, 123, 1, {104, 112, 120, 128, 136}},
+ {56, 83, 1, {1, 2, 3, 4, 5, 6, 7, 8, 9}},
+ {57, 84, 1, {5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {58, 121, 0, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}},
+ {128, 128, 2, {42, 58, 106, 122, 138, 155}},
+ {129, 129, 3, {50, 114}},
+ {130, 130, 2, {42, 58, 106, 122, 138, 155}},
+};
+/** oper class table for China*/
+static oper_bw_chan oper_bw_chan_cn[] = {
+ /** non-Global oper class,global oper class, bandwidth, channel list*/
+ {1, 115, 0, {36, 40, 44, 48}},
+ {2, 118, 0, {52, 56, 60, 64}},
+ {3, 125, 0, {149, 153, 157, 161, 165}},
+ {4, 116, 1, {36, 44}},
+ {5, 119, 1, {52, 60}},
+ {6, 126, 1, {149, 157}},
+ {7, 81, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {8, 83, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9}},
+ {9, 84, 1, {5, 6, 7, 8, 9, 10, 11, 12, 13}},
+ {128, 128, 2, {42, 58, 106, 122, 138, 155}},
+ {129, 129, 3, {50, 114}},
+ {130, 130, 2, {42, 58, 106, 122, 138, 155}},
+};
+
+/**
+ * @brief Get non-global operaing class table according to country
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param arraysize A pointer to table size
+ *
+ * @return A pointer to oper_bw_chan
+ */
+oper_bw_chan *wlan_get_nonglobal_operclass_table(mlan_private *pmpriv,
+ int *arraysize)
+{
+ t_u8 country_code[][COUNTRY_CODE_LEN] = {"US", "JP", "CN"};
+ int country_id = 0;
+ oper_bw_chan *poper_bw_chan = MNULL;
+
+ ENTER();
+
+ for (country_id = 0; country_id < 3; country_id++)
+ if (!memcmp(pmpriv->adapter, pmpriv->adapter->country_code,
+ country_code[country_id], COUNTRY_CODE_LEN - 1))
+ break;
+ if (country_id >= 3)
+ country_id = COUNTRY_ID_US; /*Set default to US*/
+ if (wlan_is_etsi_country(pmpriv->adapter,
+ pmpriv->adapter->country_code))
+ country_id = COUNTRY_ID_EU; /** Country in EU */
+
+ switch (country_id) {
+ case COUNTRY_ID_US:
+ poper_bw_chan = oper_bw_chan_us;
+ *arraysize = sizeof(oper_bw_chan_us);
+ break;
+ case COUNTRY_ID_JP:
+ poper_bw_chan = oper_bw_chan_jp;
+ *arraysize = sizeof(oper_bw_chan_jp);
+ break;
+ case COUNTRY_ID_CN:
+ poper_bw_chan = oper_bw_chan_cn;
+ *arraysize = sizeof(oper_bw_chan_cn);
+ break;
+ case COUNTRY_ID_EU:
+ poper_bw_chan = oper_bw_chan_eu;
+ *arraysize = sizeof(oper_bw_chan_eu);
+ break;
+ default:
+ PRINTM(MERROR, "Country not support!\n");
+ break;
+ }
+
+ LEAVE();
+ return poper_bw_chan;
+}
+
+/**
+ * @brief Check validation of given channel and oper class
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number
+ * @param oper_class operating class
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_check_operclass_validation(mlan_private *pmpriv, t_u8 channel,
+ t_u8 oper_class)
+{
+ int arraysize = 0, i = 0, channum = 0;
+ oper_bw_chan *poper_bw_chan = MNULL;
+ t_u8 center_freq_idx = 0;
+ t_u8 center_freqs[] = {42, 50, 58, 106, 114, 122, 138, 155};
+
+ ENTER();
+
+ for (i = 0; i < sizeof(center_freqs); i++) {
+ if (channel == center_freqs[i]) {
+ PRINTM(MERROR, "Invalid channel number %d!\n", channel);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ if (oper_class <= 0 || oper_class > 130) {
+ PRINTM(MERROR, "Invalid operating class!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (oper_class >= 128) {
+ center_freq_idx = wlan_get_center_freq_idx(
+ pmpriv, BAND_AAC, channel, CHANNEL_BW_80MHZ);
+ channel = center_freq_idx;
+ }
+ poper_bw_chan = wlan_get_nonglobal_operclass_table(pmpriv, &arraysize);
+
+ if (!poper_bw_chan) {
+ PRINTM(MCMND, "Operating class table do not find!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ for (i = 0; i < arraysize / sizeof(oper_bw_chan); i++) {
+ if (poper_bw_chan[i].oper_class == oper_class ||
+ poper_bw_chan[i].global_oper_class == oper_class) {
+ for (channum = 0;
+ channum < sizeof(poper_bw_chan[i].channel_list);
+ channum++) {
+ if (poper_bw_chan[i].channel_list[channum] &&
+ poper_bw_chan[i].channel_list[channum] ==
+ channel) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+
+ PRINTM(MCMND, "Operating class %d do not match channel %d!\n",
+ oper_class, channel);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief Get current operating class from channel and bandwidth
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param channel Channel number
+ * @param bw Bandwidth
+ * @param oper_class A pointer to current operating class
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_get_curr_oper_class(mlan_private *pmpriv, t_u8 channel,
+ t_u8 bw, t_u8 *oper_class)
+{
+ oper_bw_chan *poper_bw_chan = MNULL;
+ t_u8 center_freq_idx = 0;
+ t_u8 center_freqs[] = {42, 50, 58, 106, 114, 122, 138, 155};
+ int i = 0, arraysize = 0, channum = 0;
+
+ ENTER();
+
+ poper_bw_chan = wlan_get_nonglobal_operclass_table(pmpriv, &arraysize);
+
+ if (!poper_bw_chan) {
+ PRINTM(MCMND, "Operating class table do not find!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ for (i = 0; i < sizeof(center_freqs); i++) {
+ if (channel == center_freqs[i]) {
+ PRINTM(MERROR, "Invalid channel number %d!\n", channel);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ if (bw == BW_80MHZ) {
+ center_freq_idx = wlan_get_center_freq_idx(
+ pmpriv, BAND_AAC, channel, CHANNEL_BW_80MHZ);
+ channel = center_freq_idx;
+ }
+
+ for (i = 0; i < arraysize / sizeof(oper_bw_chan); i++) {
+ if (poper_bw_chan[i].bandwidth == bw) {
+ for (channum = 0;
+ channum < sizeof(poper_bw_chan[i].channel_list);
+ channum++) {
+ if (poper_bw_chan[i].channel_list[channum] &&
+ poper_bw_chan[i].channel_list[channum] ==
+ channel) {
+ *oper_class =
+ poper_bw_chan[i].oper_class;
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+
+ PRINTM(MCMND, "Operating class not find!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief Add Supported operating classes IE
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pptlv_out A pointer to TLV to fill in
+ * @param curr_oper_class Current operating class
+ *
+ * @return Length
+ */
+int wlan_add_supported_oper_class_ie(mlan_private *pmpriv, t_u8 **pptlv_out,
+ t_u8 curr_oper_class)
+{
+ t_u8 oper_class_us[] = {1, 2, 3, 4, 5, 12, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 128, 129, 130};
+ t_u8 oper_class_eu[] = {1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 17, 128, 129, 130};
+ t_u8 oper_class_jp[] = {1, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 56, 57, 58, 128, 129, 130};
+ t_u8 oper_class_cn[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 129, 130};
+ t_u8 country_code[][COUNTRY_CODE_LEN] = {"US", "JP", "CN"};
+ int country_id = 0, ret = 0;
+ MrvlIETypes_SuppOperClass_t *poper_class = MNULL;
+
+ ENTER();
+
+ for (country_id = 0; country_id < 3; country_id++)
+ if (!memcmp(pmpriv->adapter, pmpriv->adapter->country_code,
+ country_code[country_id], COUNTRY_CODE_LEN - 1))
+ break;
+ if (country_id >= 3)
+ country_id = COUNTRY_ID_US; /*Set default to US*/
+ if (wlan_is_etsi_country(pmpriv->adapter,
+ pmpriv->adapter->country_code))
+ country_id = COUNTRY_ID_EU; /** Country in EU */
+ poper_class = (MrvlIETypes_SuppOperClass_t *)*pptlv_out;
+ memset(pmpriv->adapter, poper_class, 0,
+ sizeof(MrvlIETypes_SuppOperClass_t));
+ poper_class->header.type = wlan_cpu_to_le16(REGULATORY_CLASS);
+ if (country_id == COUNTRY_ID_US) {
+ poper_class->header.len = sizeof(oper_class_us);
+ memcpy_ext(pmpriv->adapter, &poper_class->oper_class,
+ oper_class_us, sizeof(oper_class_us),
+ poper_class->header.len);
+ } else if (country_id == COUNTRY_ID_JP) {
+ poper_class->header.len = sizeof(oper_class_jp);
+ memcpy_ext(pmpriv->adapter, &poper_class->oper_class,
+ oper_class_jp, sizeof(oper_class_jp),
+ poper_class->header.len);
+ } else if (country_id == COUNTRY_ID_CN) {
+ poper_class->header.len = sizeof(oper_class_cn);
+ memcpy_ext(pmpriv->adapter, &poper_class->oper_class,
+ oper_class_cn, sizeof(oper_class_cn),
+ poper_class->header.len);
+ } else if (country_id == COUNTRY_ID_EU) {
+ poper_class->header.len = sizeof(oper_class_eu);
+ memcpy_ext(pmpriv->adapter, &poper_class->oper_class,
+ oper_class_eu, sizeof(oper_class_eu),
+ poper_class->header.len);
+ }
+ poper_class->current_oper_class = curr_oper_class;
+ poper_class->header.len += sizeof(poper_class->current_oper_class);
+ DBG_HEXDUMP(MCMD_D, "Operating class", (t_u8 *)poper_class,
+ sizeof(MrvlIEtypesHeader_t) + poper_class->header.len);
+ ret = sizeof(MrvlIEtypesHeader_t) + poper_class->header.len;
+ *pptlv_out += ret;
+ poper_class->header.len = wlan_cpu_to_le16(poper_class->header.len);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets region table.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param region The region code
+ * @param band The band
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_set_regiontable(mlan_private *pmpriv, t_u8 region, t_u8 band)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ int i = 0, j;
+ chan_freq_power_t *cfp;
+ int cfp_no;
+ region_chan_t region_chan_old[MAX_REGION_CHANNEL_NUM];
+ t_u8 cfp_code_bg = region;
+ t_u8 cfp_code_a = region;
+
+ ENTER();
+
+ memcpy_ext(pmadapter, region_chan_old, pmadapter->region_channel,
+ sizeof(pmadapter->region_channel), sizeof(region_chan_old));
+ memset(pmadapter, pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+
+ if (band & (BAND_B | BAND_G | BAND_GN)) {
+ if (pmadapter->cfp_code_bg)
+ cfp_code_bg = pmadapter->cfp_code_bg;
+ PRINTM(MCMND, "%s: 2.4G 0x%x\n", __func__, cfp_code_bg);
+ cfp = wlan_get_region_cfp_table(pmadapter, cfp_code_bg,
+ BAND_G | BAND_B | BAND_GN,
+ &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8)cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band B-G\n",
+ region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ if (band & BAND_GN)
+ pmadapter->region_channel[i].band = BAND_G;
+ else
+ pmadapter->region_channel[i].band =
+ (band & BAND_G) ? BAND_G : BAND_B;
+
+ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) {
+ if (region_chan_old[j].band & (BAND_B | BAND_G))
+ break;
+ }
+
+ if ((j < MAX_REGION_CHANNEL_NUM) &&
+ (region_chan_old[j].valid == MTRUE)) {
+ wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no,
+ region_chan_old[j].pcfp,
+ region_chan_old[j].num_cfp);
+ } else if (region) {
+ wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, MNULL, 0);
+ }
+ i++;
+ }
+ if (band & (BAND_A | BAND_AN | BAND_AAC)) {
+ if (pmadapter->cfp_code_bg)
+ cfp_code_a = pmadapter->cfp_code_a;
+ PRINTM(MCMND, "%s: 5G 0x%x\n", __func__, cfp_code_a);
+ cfp = wlan_get_region_cfp_table(pmadapter, cfp_code_a, BAND_A,
+ &cfp_no);
+ if (cfp) {
+ pmadapter->region_channel[i].num_cfp = (t_u8)cfp_no;
+ pmadapter->region_channel[i].pcfp = cfp;
+ } else {
+ PRINTM(MERROR, "wrong region code %#x in Band A\n",
+ region);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->region_channel[i].valid = MTRUE;
+ pmadapter->region_channel[i].region = region;
+ pmadapter->region_channel[i].band = BAND_A;
+
+ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) {
+ if (region_chan_old[j].band & BAND_A)
+ break;
+ }
+ if ((j < MAX_REGION_CHANNEL_NUM) && region_chan_old[j].valid) {
+ wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no,
+ region_chan_old[j].pcfp,
+ region_chan_old[j].num_cfp);
+ } else if (region) {
+ wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, MNULL, 0);
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get if radar detection is enabled or not on a certain channel
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine radar detection requirements
+ *
+ * @return
+ * - MTRUE if radar detection is required
+ * - MFALSE otherwise
+ */
+t_bool wlan_get_cfp_radar_detect(mlan_private *priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool required = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /*get the cfp table first*/
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band == BAND_A) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /* This means operation in BAND-A is not support, we can
+ * just return false here, it's harmless
+ */
+ goto done;
+ }
+
+ /*get the radar detection requirements according to chan num*/
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ required = pcfp[j].passive_scan_or_radar_detect;
+ break;
+ }
+ }
+
+done:
+ LEAVE();
+ return required;
+}
+
+/**
+ * @brief Get if scan type is passive or not on a certain channel for b/g band
+ *
+ * @param priv Private driver information structure
+ * @param chnl Channel to determine scan type
+ *
+ * @return
+ * - MTRUE if scan type is passive
+ * - MFALSE otherwise
+ */
+
+t_bool wlan_bg_scan_type_is_passive(mlan_private *priv, t_u8 chnl)
+{
+ int i, j;
+ t_bool passive = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /*get the cfp table first*/
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & (BAND_B | BAND_G)) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (!pcfp) {
+ /*This means operation in BAND-B or BAND_G is not support, we
+ * can just return false here
+ */
+ goto done;
+ }
+
+ /*get the bg scan type according to chan num*/
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chnl) {
+ passive = pcfp[j].passive_scan_or_radar_detect;
+ break;
+ }
+ }
+
+done:
+ LEAVE();
+ return passive;
+}
+
+/**
+ * @brief Get if a channel is NO_IR (passive) or not
+ *
+ * @param priv Private driver information structure
+ * @param band Band to check
+ * @param chan Channel to check
+ *
+ * @return
+ * - MTRUE if channel is passive
+ * - MFALSE otherwise
+ */
+
+t_bool wlan_is_chan_passive(mlan_private *priv, t_u8 band, t_u8 chan)
+{
+ int i, j;
+ t_bool passive = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & band) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (pcfp) {
+ /* check table according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chan) {
+ if (pcfp[j].dynamic.flags & NXP_CHANNEL_PASSIVE)
+ passive = MTRUE;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return passive;
+}
+
+/**
+ * @brief Get if a channel is disabled or not
+ *
+ * @param priv Private driver information structure
+ * @param band Band to check
+ * @param chan Channel to check
+ *
+ * @return
+ * - MTRUE if channel is disabled
+ * - MFALSE otherwise
+ */
+
+t_bool wlan_is_chan_disabled(mlan_private *priv, t_u8 band, t_u8 chan)
+{
+ int i, j;
+ t_bool disabled = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /* get the cfp table first */
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & band) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (pcfp) {
+ /* check table according to chan num */
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chan) {
+ if (pcfp[j].dynamic.flags &
+ NXP_CHANNEL_DISABLED)
+ disabled = MTRUE;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return disabled;
+}
+
+/**
+ * @brief Get if a channel is blacklisted or not
+ *
+ * @param priv Private driver information structure
+ * @param band Band to check
+ * @param chan Channel to check
+ *
+ * @return
+ * - MTRUE if channel is blacklisted
+ * - MFALSE otherwise
+ */
+
+t_bool wlan_is_chan_blacklisted(mlan_private *priv, t_u8 band, t_u8 chan)
+{
+ int i, j;
+ t_bool blacklist = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /*get the cfp table first*/
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & band) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (pcfp) {
+ /*check table according to chan num*/
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chan) {
+ blacklist = pcfp[j].dynamic.blacklist;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return blacklist;
+}
+
+/**
+ * @brief Set a channel as blacklisted or not
+ *
+ * @param priv Private driver information structure
+ * @param band Band to check
+ * @param chan Channel to check
+ * @param bl Blacklist if MTRUE
+ *
+ * @return
+ * - MTRUE if channel setting is updated
+ * - MFALSE otherwise
+ */
+
+t_bool wlan_set_chan_blacklist(mlan_private *priv, t_u8 band, t_u8 chan,
+ t_bool bl)
+{
+ int i, j;
+ t_bool set_bl = MFALSE;
+ chan_freq_power_t *pcfp = MNULL;
+
+ ENTER();
+
+ /*get the cfp table first*/
+ for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
+ if (priv->adapter->region_channel[i].band & band) {
+ pcfp = priv->adapter->region_channel[i].pcfp;
+ break;
+ }
+ }
+
+ if (pcfp) {
+ /*check table according to chan num*/
+ for (j = 0; j < priv->adapter->region_channel[i].num_cfp; j++) {
+ if (pcfp[j].channel == chan) {
+ pcfp[j].dynamic.blacklist = bl;
+ set_bl = MTRUE;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return set_bl;
+}
+
+/**
+ * @brief Convert rateid in IEEE format to MRVL format
+ *
+ * @param priv Private driver information structure
+ * @param IeeeMacRate Rate in terms of IEEE format
+ * @param pmbuf A pointer to packet buffer
+ *
+ * @return
+ * Rate ID in terms of MRVL format
+ */
+t_u8 wlan_ieee_rateid_to_mrvl_rateid(mlan_private *priv, t_u16 IeeeMacRate,
+ t_u8 *dst_mac)
+{
+ /* Set default rate ID to RATEID_DBPSK1Mbps */
+ t_u8 mrvlRATEID = 0;
+ const rate_map *rate_tbl = rate_map_table_1x1;
+ t_u32 cnt = sizeof(rate_map_table_1x1) / sizeof(rate_map);
+ t_u8 skip_nss2 = MTRUE;
+ t_u32 i = 0;
+ IEEEtypes_HTCap_t *htcap = MNULL;
+ t_u8 tx_mcs_supp = GET_TXMCSSUPP(priv->usr_dev_mcs_support);
+#ifdef UAP_SUPPORT
+ psta_node sta_ptr = MNULL;
+#endif
+
+ ENTER();
+
+ if (priv->adapter->hw_dev_mcs_support == HT_STREAM_MODE_2X2) {
+ rate_tbl = rate_map_table_2x2;
+ cnt = sizeof(rate_map_table_2x2) / sizeof(rate_map);
+ }
+
+#ifdef UAP_SUPPORT
+ if (priv->bss_role == MLAN_BSS_ROLE_UAP) {
+ if (!dst_mac) {
+ LEAVE();
+ return mrvlRATEID;
+ }
+ sta_ptr = (sta_node *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (!sta_ptr) {
+ LEAVE();
+ return mrvlRATEID;
+ }
+ while (sta_ptr != (sta_node *)&priv->sta_list) {
+ if (memcmp(priv->adapter, dst_mac, sta_ptr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ htcap = &(sta_ptr->HTcap);
+ break;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (priv->bss_role == MLAN_BSS_ROLE_STA)
+ htcap = priv->curr_bss_params.bss_descriptor.pht_cap;
+#endif
+ if (htcap) {
+ /* If user configure tx to 2x2 and peer device rx is 2x2 */
+ if (tx_mcs_supp >= 2 && htcap->ht_cap.supported_mcs_set[1])
+ skip_nss2 = MFALSE;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ if (rate_tbl[i].nss && skip_nss2)
+ continue;
+ if (rate_tbl[i].rate == IeeeMacRate) {
+ mrvlRATEID = rate_tbl[i].id;
+ break;
+ }
+ }
+
+ return mrvlRATEID;
+}
+
+/**
+ * @brief Convert rateid in MRVL format to IEEE format
+ *
+ * @param IeeeMacRate Rate in terms of MRVL format
+ *
+ * @return
+ * Rate ID in terms of IEEE format
+ */
+t_u8 wlan_mrvl_rateid_to_ieee_rateid(t_u8 rate)
+{
+ return rateUnit_500Kbps[rate];
+}
+
+/**
+ * @brief Update CFP tables and power tables from FW
+ *
+ * @param priv Private driver information structure
+ * @param buf Pointer to the buffer holding TLV data
+ * from 0x242 command response.
+ * @param buf_left bufsize
+ *
+ * @return
+ * None
+ */
+void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ MrvlIEtypesHeader_t *head;
+ t_u16 tlv;
+ t_u16 tlv_buf_len;
+ t_u16 tlv_buf_left;
+ t_u16 i;
+ int k = 0, rows, cols;
+ t_u16 max_tx_pwr_bg = WLAN_TX_PWR_DEFAULT;
+ t_u16 max_tx_pwr_a = WLAN_TX_PWR_DEFAULT;
+ t_u8 *tlv_buf;
+ t_u8 *data;
+ t_u8 *tmp;
+ mlan_status ret;
+
+ ENTER();
+
+ if (!buf) {
+ PRINTM(MERROR, "CFP table update failed!\n");
+ goto out;
+ }
+ if (pmadapter->otp_region)
+ wlan_free_fw_cfp_tables(pmadapter);
+ pmadapter->tx_power_table_bg_rows = FW_CFP_TABLE_MAX_ROWS_BG;
+ pmadapter->tx_power_table_bg_cols = FW_CFP_TABLE_MAX_COLS_BG;
+ pmadapter->tx_power_table_a_rows = FW_CFP_TABLE_MAX_ROWS_A;
+ pmadapter->tx_power_table_a_cols = FW_CFP_TABLE_MAX_COLS_A;
+ tlv_buf = (t_u8 *)buf;
+ tlv_buf_left = buf_left;
+
+ while (tlv_buf_left >= sizeof(*head)) {
+ head = (MrvlIEtypesHeader_t *)tlv_buf;
+ tlv = wlan_le16_to_cpu(head->type);
+ tlv_buf_len = wlan_le16_to_cpu(head->len);
+
+ if (tlv_buf_left < (sizeof(*head) + tlv_buf_len))
+ break;
+ data = (t_u8 *)head + sizeof(*head);
+
+ switch (tlv) {
+ case TLV_TYPE_REGION_INFO:
+ /* Skip adding fw region info if it already exists or
+ * if this TLV has no set data
+ */
+ if (*data == 0)
+ break;
+ if (pmadapter->otp_region)
+ break;
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(otp_region_info_t),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->otp_region);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->otp_region) {
+ PRINTM(MERROR,
+ "Memory allocation for the otp region info struct failed!\n");
+ break;
+ }
+ /* Save region info values from OTP in the otp_region
+ * structure
+ */
+ memcpy_ext(pmadapter, pmadapter->otp_region, data,
+ sizeof(otp_region_info_t),
+ sizeof(otp_region_info_t));
+ data += sizeof(otp_region_info_t);
+ /* Get pre-defined cfp tables corresponding to the
+ * region code in OTP
+ */
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_BG; i++) {
+ if (cfp_table_BG[i].code ==
+ pmadapter->otp_region->region_code) {
+ max_tx_pwr_bg = (cfp_table_BG[i].cfp)
+ ->max_tx_power;
+ break;
+ }
+ }
+ for (i = 0; i < MLAN_CFP_TABLE_SIZE_A; i++) {
+ if (cfp_table_A[i].code ==
+ pmadapter->otp_region->region_code) {
+ max_tx_pwr_a = (cfp_table_A[i].cfp)
+ ->max_tx_power;
+ break;
+ }
+ }
+ /* Update the region code and the country code in
+ * pmadapter
+ */
+ pmadapter->region_code =
+ pmadapter->otp_region->region_code;
+ pmadapter->country_code[0] =
+ pmadapter->otp_region->country_code[0];
+ pmadapter->country_code[1] =
+ pmadapter->otp_region->country_code[1];
+ pmadapter->country_code[2] = '\0';
+ pmadapter->domain_reg.country_code[0] =
+ pmadapter->otp_region->country_code[0];
+ pmadapter->domain_reg.country_code[1] =
+ pmadapter->otp_region->country_code[1];
+ pmadapter->domain_reg.country_code[2] = '\0';
+ pmadapter->cfp_code_bg =
+ pmadapter->otp_region->region_code;
+ pmadapter->cfp_code_a =
+ pmadapter->otp_region->region_code;
+ break;
+ case TLV_TYPE_CHAN_ATTR_CFG:
+ /* Skip adding fw cfp tables if they already exist or
+ * if this TLV has no set data
+ */
+ if (*data == 0)
+ break;
+ if (pmadapter->cfp_otp_bg || pmadapter->cfp_otp_a) {
+ break;
+ }
+
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ pmadapter->tx_power_table_bg_rows *
+ sizeof(chan_freq_power_t),
+ MLAN_MEM_DEF, (t_u8 **)&pmadapter->cfp_otp_bg);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->cfp_otp_bg) {
+ PRINTM(MERROR,
+ "Memory allocation for storing otp bg table data failed!\n");
+ break;
+ }
+ /* Save channel usability flags from OTP data in the fw
+ * cfp bg table and set frequency and max_tx_power
+ * values
+ */
+ for (i = 0; i < pmadapter->tx_power_table_bg_rows;
+ i++) {
+ (pmadapter->cfp_otp_bg + i)->channel = *data;
+ if (*data == 14)
+ (pmadapter->cfp_otp_bg + i)->freq =
+ 2484;
+ else
+ (pmadapter->cfp_otp_bg + i)->freq =
+ 2412 + 5 * (*data - 1);
+ (pmadapter->cfp_otp_bg + i)->max_tx_power =
+ max_tx_pwr_bg;
+ data++;
+ (pmadapter->cfp_otp_bg + i)->dynamic.flags =
+ *data;
+ if (*data & NXP_CHANNEL_DFS)
+ (pmadapter->cfp_otp_bg + i)
+ ->passive_scan_or_radar_detect =
+ MTRUE;
+ data++;
+ }
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ pmadapter->tx_power_table_a_rows *
+ sizeof(chan_freq_power_t),
+ MLAN_MEM_DEF, (t_u8 **)&pmadapter->cfp_otp_a);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->cfp_otp_a) {
+ PRINTM(MERROR,
+ "Memory allocation for storing otp a table data failed!\n");
+ break;
+ }
+ /* Save channel usability flags from OTP data in the fw
+ * cfp a table and set frequency and max_tx_power values
+ */
+ for (i = 0; i < pmadapter->tx_power_table_a_rows; i++) {
+ (pmadapter->cfp_otp_a + i)->channel = *data;
+ if (*data < 183)
+ /* 5GHz channels */
+ (pmadapter->cfp_otp_a + i)->freq =
+ 5035 + 5 * (*data - 7);
+ else
+ /* 4GHz channels */
+ (pmadapter->cfp_otp_a + i)->freq =
+ 4915 + 5 * (*data - 183);
+ (pmadapter->cfp_otp_a + i)->max_tx_power =
+ max_tx_pwr_a;
+ data++;
+ (pmadapter->cfp_otp_a + i)->dynamic.flags =
+ *data;
+ if (*data & NXP_CHANNEL_DFS)
+ (pmadapter->cfp_otp_a + i)
+ ->passive_scan_or_radar_detect =
+ MTRUE;
+ data++;
+ }
+ break;
+ case TLV_TYPE_POWER_TABLE:
+ /* Skip adding fw power tables if this TLV has no data
+ * or if they already exists but force reg rule is set
+ * in the otp
+ */
+ if (*data == 0)
+ break;
+ if (pmadapter->otp_region &&
+ pmadapter->otp_region->force_reg &&
+ pmadapter->tx_power_table_bg)
+ break;
+
+ /* Save the tlv data in power tables for band BG and A
+ */
+ tmp = data;
+ i = 0;
+ while ((i <
+ pmadapter->tx_power_table_bg_rows *
+ pmadapter->tx_power_table_bg_cols) &&
+ (i < tlv_buf_len) && (*tmp != 36)) {
+ i++;
+ tmp++;
+ }
+ if (!pmadapter->tx_power_table_bg) {
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle, i,
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->tx_power_table_bg);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->tx_power_table_bg) {
+ PRINTM(MERROR,
+ "Memory allocation for the BG-band power table failed!\n");
+ break;
+ }
+ }
+ memcpy_ext(pmadapter, pmadapter->tx_power_table_bg,
+ data, i, i);
+ pmadapter->tx_power_table_bg_size = i;
+ data += i;
+ i = 0;
+ while ((i < pmadapter->tx_power_table_a_rows *
+ pmadapter->tx_power_table_a_cols) &&
+ (i < (tlv_buf_len -
+ pmadapter->tx_power_table_bg_size))) {
+ i++;
+ }
+ if (!pmadapter->tx_power_table_a) {
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle, i,
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->tx_power_table_a);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->tx_power_table_a) {
+ PRINTM(MERROR,
+ "Memory allocation for the A-band power table failed!\n");
+ break;
+ }
+ }
+ memcpy_ext(pmadapter, pmadapter->tx_power_table_a, data,
+ i, i);
+ pmadapter->tx_power_table_a_size = i;
+ break;
+ case TLV_TYPE_POWER_TABLE_ATTR:
+ pmadapter->tx_power_table_bg_rows =
+ ((power_table_attr_t *)data)->rows_2g;
+ pmadapter->tx_power_table_bg_cols =
+ ((power_table_attr_t *)data)->cols_2g;
+ pmadapter->tx_power_table_a_rows =
+ ((power_table_attr_t *)data)->rows_5g;
+ pmadapter->tx_power_table_a_cols =
+ ((power_table_attr_t *)data)->cols_5g;
+ break;
+ default:
+ break;
+ }
+ tlv_buf += (sizeof(*head) + tlv_buf_len);
+ tlv_buf_left -= (sizeof(*head) + tlv_buf_len);
+ }
+ if (!pmadapter->cfp_otp_bg || !pmadapter->tx_power_table_bg)
+ goto out;
+ /* Set remaining flags for BG */
+ rows = pmadapter->tx_power_table_bg_rows;
+ cols = pmadapter->tx_power_table_bg_cols;
+
+ for (i = 0; i < rows; i++) {
+ k = (i * cols) + 1;
+ if ((pmadapter->cfp_otp_bg + i)->dynamic.flags &
+ NXP_CHANNEL_DISABLED)
+ continue;
+
+ if (pmadapter->tx_power_table_bg[k + MOD_CCK] == 0)
+ (pmadapter->cfp_otp_bg + i)->dynamic.flags |=
+ NXP_CHANNEL_NO_CCK;
+
+ if (pmadapter->tx_power_table_bg[k + MOD_OFDM_PSK] == 0 &&
+ pmadapter->tx_power_table_bg[k + MOD_OFDM_QAM16] == 0 &&
+ pmadapter->tx_power_table_bg[k + MOD_OFDM_QAM64] == 0) {
+ (pmadapter->cfp_otp_bg + i)->dynamic.flags |=
+ NXP_CHANNEL_NO_OFDM;
+ }
+ }
+
+out:
+ LEAVE();
+}
+
+/**
+ * @brief This function deallocates otp cfp and power tables memory.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ */
+void wlan_free_fw_cfp_tables(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+ if (pmadapter->otp_region)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->otp_region);
+ if (pmadapter->cfp_otp_bg)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->cfp_otp_bg);
+ if (pmadapter->tx_power_table_bg)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->tx_power_table_bg);
+ pmadapter->otp_region = MNULL;
+ pmadapter->cfp_otp_bg = MNULL;
+ pmadapter->tx_power_table_bg = MNULL;
+ pmadapter->tx_power_table_bg_size = 0;
+ if (pmadapter->cfp_otp_a)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->cfp_otp_a);
+ if (pmadapter->tx_power_table_a)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->tx_power_table_a);
+ pmadapter->cfp_otp_a = MNULL;
+ pmadapter->tx_power_table_a = MNULL;
+ pmadapter->tx_power_table_a_size = 0;
+ LEAVE();
+}
+
+/**
+ * @brief Get DFS chan list
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pioctl_req Pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_get_cfp_table(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *ds_misc_cfg = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ chan_freq_power_t *cfp = MNULL;
+ t_u32 cfp_no = 0;
+
+ ENTER();
+ if (pioctl_req) {
+ ds_misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfp = wlan_get_region_cfp_table(
+ pmadapter, pmadapter->region_code,
+ ds_misc_cfg->param.cfp.band, &cfp_no);
+ if (cfp) {
+ ds_misc_cfg->param.cfp.num_chan = cfp_no;
+ memcpy_ext(pmadapter,
+ ds_misc_cfg->param.cfp.cfp_tbl, cfp,
+ cfp_no * sizeof(chan_freq_power_t),
+ cfp_no * sizeof(chan_freq_power_t));
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power tables and cfp tables for set region code
+ * into the IOCTL request buffer
+ *
+ * @param pmadapter Private mlan adapter structure
+ * @param pioctl_req Pointer to the IOCTL request structure
+ *
+ * @return success, otherwise fail
+ *
+ */
+mlan_status wlan_get_cfpinfo(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ chan_freq_power_t *cfp_bg = MNULL;
+ t_u32 cfp_no_bg = 0;
+ chan_freq_power_t *cfp_a = MNULL;
+ t_u32 cfp_no_a = 0;
+ t_u8 cfp_code_a = pmadapter->region_code;
+ t_u8 cfp_code_bg = pmadapter->region_code;
+ t_u32 len = 0, size = 0;
+ t_u8 *req_buf, *tmp;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!pioctl_req || !pioctl_req->pbuf) {
+ PRINTM(MERROR, "MLAN IOCTL information is not present!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ /* Calculate the total response size required to return region,
+ * country codes, cfp tables and power tables
+ */
+ size = sizeof(pmadapter->country_code) + sizeof(pmadapter->region_code);
+ /* Add size to store region, country and environment codes */
+ size += sizeof(t_u32);
+ if (pmadapter->cfp_code_bg)
+ cfp_code_bg = pmadapter->cfp_code_bg;
+
+ /* Get cfp table and its size corresponding to the region code */
+ cfp_bg = wlan_get_region_cfp_table(pmadapter, cfp_code_bg,
+ BAND_G | BAND_B, &cfp_no_bg);
+ size += cfp_no_bg * sizeof(chan_freq_power_t);
+ if (pmadapter->cfp_code_a)
+ cfp_code_a = pmadapter->cfp_code_a;
+ cfp_a = wlan_get_region_cfp_table(pmadapter, cfp_code_a, BAND_A,
+ &cfp_no_a);
+ size += cfp_no_a * sizeof(chan_freq_power_t);
+ if (pmadapter->otp_region)
+ size += sizeof(pmadapter->otp_region->environment);
+
+ /* Get power table size */
+ if (pmadapter->tx_power_table_bg) {
+ size += pmadapter->tx_power_table_bg_size;
+ /* Add size to store table size, rows and cols */
+ size += 3 * sizeof(t_u32);
+ }
+ if (pmadapter->tx_power_table_a) {
+ size += pmadapter->tx_power_table_a_size;
+ size += 3 * sizeof(t_u32);
+ }
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < size) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->buf_len_needed = size;
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto out;
+ }
+ /* Copy the total size of region code, country code and environment
+ * in first four bytes of the IOCTL request buffer and then copy
+ * codes respectively in following bytes
+ */
+ req_buf = (t_u8 *)pioctl_req->pbuf;
+ size = sizeof(pmadapter->country_code) + sizeof(pmadapter->region_code);
+ if (pmadapter->otp_region)
+ size += sizeof(pmadapter->otp_region->environment);
+ tmp = (t_u8 *)&size;
+ memcpy_ext(pmadapter, req_buf, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+ memcpy_ext(pmadapter, req_buf + len, &pmadapter->region_code,
+ sizeof(pmadapter->region_code),
+ sizeof(pmadapter->region_code));
+ len += sizeof(pmadapter->region_code);
+ memcpy_ext(pmadapter, req_buf + len, &pmadapter->country_code,
+ sizeof(pmadapter->country_code),
+ sizeof(pmadapter->country_code));
+ len += sizeof(pmadapter->country_code);
+ if (pmadapter->otp_region) {
+ memcpy_ext(pmadapter, req_buf + len,
+ &pmadapter->otp_region->environment,
+ sizeof(pmadapter->otp_region->environment),
+ sizeof(pmadapter->otp_region->environment));
+ len += sizeof(pmadapter->otp_region->environment);
+ }
+ /* copy the cfp table size followed by the entire table */
+ if (!cfp_bg)
+ goto out;
+ size = cfp_no_bg * sizeof(chan_freq_power_t);
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+ memcpy_ext(pmadapter, req_buf + len, cfp_bg, size, size);
+ len += size;
+ if (!cfp_a)
+ goto out;
+ size = cfp_no_a * sizeof(chan_freq_power_t);
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+ memcpy_ext(pmadapter, req_buf + len, cfp_a, size, size);
+ len += size;
+ /* Copy the size of the power table, number of rows, number of cols
+ * and the entire power table
+ */
+ if (!pmadapter->tx_power_table_bg)
+ goto out;
+ size = pmadapter->tx_power_table_bg_size;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+
+ /* No. of rows */
+ size = pmadapter->tx_power_table_bg_rows;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+
+ /* No. of cols */
+ size = pmadapter->tx_power_table_bg_size /
+ pmadapter->tx_power_table_bg_rows;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+ memcpy_ext(pmadapter, req_buf + len, pmadapter->tx_power_table_bg,
+ pmadapter->tx_power_table_bg_size,
+ pmadapter->tx_power_table_bg_size);
+ len += pmadapter->tx_power_table_bg_size;
+ if (!pmadapter->tx_power_table_a)
+ goto out;
+ size = pmadapter->tx_power_table_a_size;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+
+ /* No. of rows */
+ size = pmadapter->tx_power_table_a_rows;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+
+ /* No. of cols */
+ size = pmadapter->tx_power_table_a_size /
+ pmadapter->tx_power_table_a_rows;
+ memcpy_ext(pmadapter, req_buf + len, tmp, sizeof(size), sizeof(size));
+ len += sizeof(size);
+ memcpy_ext(pmadapter, req_buf + len, pmadapter->tx_power_table_a,
+ pmadapter->tx_power_table_a_size,
+ pmadapter->tx_power_table_a_size);
+ len += pmadapter->tx_power_table_a_size;
+out:
+ if (pioctl_req)
+ pioctl_req->data_read_written = len;
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cmdevt.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cmdevt.c
new file mode 100644
index 000000000000..6393ae6045f7
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_cmdevt.c
@@ -0,0 +1,8377 @@
+/**
+ * @file mlan_cmdevt.c
+ *
+ * @brief This file contains the handling of CMD/EVENT in MLAN
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/12/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif /* SDIO */
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+#include "mlan_init.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/*******************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef STA_SUPPORT
+/**
+ * @brief This function inserts scan command node to scan_pending_q.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @return N/A
+ */
+static t_void wlan_queue_scan_cmd(mlan_private *pmpriv,
+ cmd_ctrl_node *pcmd_node)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ pcmd_node->cmd_flag |= CMD_F_SCAN;
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+
+done:
+ LEAVE();
+}
+
+/**
+ * @brief Internal function used to flush the scan pending queue
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+void wlan_check_scan_queue(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ t_u16 num = 0;
+
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ MNULL, MNULL);
+ if (!pcmd_node) {
+ PRINTM(MERROR, "No pending scan command\n");
+ return;
+ }
+ while (pcmd_node != (cmd_ctrl_node *)&pmadapter->scan_pending_q) {
+ num++;
+ pcmd_node = pcmd_node->pnext;
+ }
+ PRINTM(MERROR, "num_pending_scan=%d\n", num);
+}
+#endif
+
+/**
+ * @brief This function will dump the pending commands id
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+static void wlan_dump_pending_commands(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_COMMAND *pcmd;
+
+ ENTER();
+ wlan_request_cmd_lock(pmadapter);
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+ if (!pcmd_node) {
+ wlan_release_cmd_lock(pmadapter);
+ LEAVE();
+ return;
+ }
+ while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) {
+ pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ PRINTM(MERROR, "pending command id: 0x%x ioctl_buf=%p\n",
+ wlan_le16_to_cpu(pcmd->command), pcmd_node->pioctl_buf);
+ pcmd_node = pcmd_node->pnext;
+ }
+#ifdef STA_SUPPORT
+ wlan_check_scan_queue(pmadapter);
+#endif
+ wlan_release_cmd_lock(pmadapter);
+ LEAVE();
+ return;
+}
+
+#define REASON_CODE_NO_CMD_NODE 1
+#define REASON_CODE_CMD_TIMEOUT 2
+#define REASON_CODE_CMD_TO_CARD_FAILURE 3
+#define REASON_CODE_EXT_SCAN_TIMEOUT 4
+/**
+ * @brief This function dump debug info
+ *
+ * @return N/A
+ */
+t_void wlan_dump_info(mlan_adapter *pmadapter, t_u8 reason)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+ t_u8 i;
+#ifdef SDIO
+ t_u8 j;
+ t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+#endif
+ t_u16 cmd_id, cmd_act;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ PRINTM(MERROR, "------------Dump info-----------\n", reason);
+ switch (reason) {
+ case REASON_CODE_NO_CMD_NODE:
+ pmadapter->dbg.num_no_cmd_node++;
+ PRINTM(MERROR, "No Free command node\n");
+ break;
+ case REASON_CODE_CMD_TIMEOUT:
+ PRINTM(MERROR, "Commmand Timeout\n");
+ break;
+ case REASON_CODE_CMD_TO_CARD_FAILURE:
+ PRINTM(MERROR, "Command to card failure\n");
+ break;
+ case REASON_CODE_EXT_SCAN_TIMEOUT:
+ PRINTM(MERROR, "EXT_SCAN_STATUS event Timeout\n");
+ break;
+ default:
+ break;
+ }
+ if ((reason == REASON_CODE_NO_CMD_NODE) &&
+ (pmadapter->dbg.num_no_cmd_node > 1)) {
+ if (pmadapter->dbg.num_no_cmd_node >= 5)
+ wlan_recv_event(wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ LEAVE();
+ return;
+ }
+ wlan_dump_pending_commands(pmadapter);
+ if (reason != REASON_CODE_CMD_TIMEOUT) {
+ if (!pmadapter->curr_cmd) {
+ PRINTM(MERROR, "CurCmd Empty\n");
+ } else {
+ pcmd_node = pmadapter->curr_cmd;
+ cmd_id = pmadapter->dbg.last_cmd_id
+ [pmadapter->dbg.last_cmd_index];
+ cmd_act = pmadapter->dbg.last_cmd_act
+ [pmadapter->dbg.last_cmd_index];
+ PRINTM_GET_SYS_TIME(MERROR, &sec, &usec);
+ PRINTM(MERROR,
+ "Current cmd id (%lu.%06lu) = 0x%x, act = 0x%x\n",
+ sec, usec, cmd_id, cmd_act);
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type) &&
+ pcmd_node->cmdbuf) {
+ t_u8 *pcmd_buf;
+ pcmd_buf = pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset +
+ pmadapter->ops.intf_header_len;
+ for (i = 0; i < 16; i++)
+ PRINTM(MERROR, "%02x ", *pcmd_buf++);
+ PRINTM(MERROR, "\n");
+ }
+#endif
+ pmpriv = pcmd_node->priv;
+ if (pmpriv)
+ PRINTM(MERROR, "BSS type = %d BSS role= %d\n",
+ pmpriv->bss_type, pmpriv->bss_role);
+ }
+ }
+ PRINTM(MERROR, "mlan_processing =%d\n", pmadapter->mlan_processing);
+ PRINTM(MERROR, "main_lock_flag =%d\n", pmadapter->main_lock_flag);
+ PRINTM(MERROR, "main_process_cnt =%d\n", pmadapter->main_process_cnt);
+ PRINTM(MERROR, "delay_task_flag =%d\n", pmadapter->delay_task_flag);
+ PRINTM(MERROR, "mlan_rx_processing =%d\n",
+ pmadapter->mlan_rx_processing);
+ PRINTM(MERROR, "rx_pkts_queued=%d\n", pmadapter->rx_pkts_queued);
+ PRINTM(MERROR, "more_task_flag = %d\n", pmadapter->more_task_flag);
+ PRINTM(MERROR, "num_cmd_timeout = %d\n", pmadapter->num_cmd_timeout);
+ PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index);
+ PRINTM(MERROR, "last_cmd_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++)
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]);
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_act = ");
+ for (i = 0; i < DBG_CMD_NUM; i++)
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]);
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n",
+ pmadapter->dbg.last_cmd_resp_index);
+ PRINTM(MERROR, "last_cmd_resp_id = ");
+ for (i = 0; i < DBG_CMD_NUM; i++)
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]);
+ PRINTM(MERROR, "\n");
+ PRINTM(MERROR, "last_event_index = %d\n",
+ pmadapter->dbg.last_event_index);
+ PRINTM(MERROR, "last_event = ");
+ for (i = 0; i < DBG_CMD_NUM; i++)
+ PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]);
+ PRINTM(MERROR, "\n");
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ pmadapter->dbg.num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ pmadapter->dbg.num_cmd_host_to_card_failure);
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ pmadapter->dbg.num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ pmadapter->dbg.num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n",
+ pmadapter->dbg.num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n",
+ pmadapter->dbg.last_int_status);
+ }
+#endif
+ PRINTM(MERROR, "num_alloc_buffer_failure = %d\n",
+ pmadapter->dbg.num_alloc_buffer_failure);
+ PRINTM(MERROR, "num_pkt_dropped = %d\n",
+ pmadapter->dbg.num_pkt_dropped);
+ PRINTM(MERROR, "num_no_cmd_node = %d\n",
+ pmadapter->dbg.num_no_cmd_node);
+ PRINTM(MERROR, "num_event_deauth = %d\n",
+ pmadapter->dbg.num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n",
+ pmadapter->dbg.num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n",
+ pmadapter->dbg.num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", pmadapter->dbg.num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
+ pmadapter->dbg.num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
+ pmadapter->dbg.num_cmd_assoc_failure);
+ PRINTM(MERROR, "num_cons_assoc_failure = %d\n",
+ pmadapter->dbg.num_cons_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received=%d\n", pmadapter->cmd_resp_received);
+ PRINTM(MERROR, "event_received=%d\n", pmadapter->event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size=%d\n", pmadapter->max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size=%d\n", pmadapter->tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size=%d\n", pmadapter->curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent,
+ pmadapter->cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode,
+ pmadapter->ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d wakeup_timeout=%d\n",
+ pmadapter->pm_wakeup_card_req, pmadapter->pm_wakeup_fw_try,
+ pmadapter->pm_wakeup_timeout);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ pmadapter->is_hs_configured, pmadapter->hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ pmadapter->pps_uapsd_mode, pmadapter->sleep_period.period);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", pmadapter->tx_lock_flag);
+ PRINTM(MERROR, "scan_processing = %d\n", pmadapter->scan_processing);
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ pmadapter->pcard_sd->mp_rd_bitmap,
+ pmadapter->pcard_sd->curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ pmadapter->pcard_sd->mp_wr_bitmap,
+ pmadapter->pcard_sd->curr_wr_port);
+ PRINTM(MERROR, "mp_invalid_update=%d\n",
+ pmadapter->pcard_sd->mp_invalid_update);
+ PRINTM(MERROR, "last_recv_wr_bitmap=0x%x last_mp_index=%d\n",
+ pmadapter->pcard_sd->last_recv_wr_bitmap,
+ pmadapter->pcard_sd->last_mp_index);
+ for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
+ PRINTM(MERROR,
+ "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n",
+ pmadapter->pcard_sd->last_mp_wr_bitmap[i],
+ pmadapter->pcard_sd->last_mp_wr_ports[i],
+ pmadapter->pcard_sd->last_mp_wr_len[i],
+ pmadapter->pcard_sd->last_curr_wr_port[i]);
+ for (j = 0; j < mp_aggr_pkt_limit; j++) {
+ PRINTM(MERROR, "0x%02x ",
+ pmadapter->pcard_sd->last_mp_wr_info
+ [i * mp_aggr_pkt_limit + j]);
+ }
+ PRINTM(MERROR, "\n");
+ }
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type)) {
+ PRINTM(MERROR, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n",
+ pmadapter->pcard_pcie->txbd_rdptr,
+ pmadapter->pcard_pcie->txbd_wrptr);
+ PRINTM(MERROR, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n",
+ pmadapter->pcard_pcie->rxbd_rdptr,
+ pmadapter->pcard_pcie->rxbd_wrptr);
+ PRINTM(MERROR, "evtbd_rdptr=0x%x evt_wrptr=0x%x\n",
+ pmadapter->pcard_pcie->evtbd_rdptr,
+ pmadapter->pcard_pcie->evtbd_wrptr);
+ PRINTM(MERROR, "last_wr_index:%d\n",
+ pmadapter->pcard_pcie->txbd_wrptr &
+ (MLAN_MAX_TXRX_BD - 1));
+ PRINTM(MERROR, "Tx pkt size:\n");
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ PRINTM(MERROR, "%04d ",
+ pmadapter->pcard_pcie->last_tx_pkt_size[i]);
+ if (((i + 1) % 16) == 0)
+ PRINTM(MERROR, "\n");
+ }
+ }
+#endif
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ if (pmadapter->priv[i])
+ wlan_dump_ralist(pmadapter->priv[i]);
+ }
+ if (reason != REASON_CODE_CMD_TIMEOUT) {
+ if ((pmadapter->dbg.num_no_cmd_node >= 5) ||
+ (pmadapter->pm_wakeup_card_req &&
+ pmadapter->pm_wakeup_fw_try) ||
+ (reason == REASON_CODE_EXT_SCAN_TIMEOUT)) {
+ if (pmpriv)
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_DRV_DBG_DUMP,
+ MNULL);
+ else
+ wlan_recv_event(
+ wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ }
+ }
+ PRINTM(MERROR, "-------- Dump info End---------\n", reason);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function convert a given character to hex
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted hex if chr is a valid hex, else 0
+ */
+static t_u32 wlan_hexval(t_u8 chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+/**
+ * @brief This function convert a given string to hex
+ *
+ * @param a A pointer to string to be converted
+ *
+ * @return The converted hex value if param a is a valid hex, else
+ * 0
+ */
+int wlan_atox(t_u8 *a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (wlan_isxdigit(*a))
+ i = i * 16 + wlan_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief This function parse cal data from ASCII to hex
+ *
+ * @param src A pointer to source data
+ * @param len Source data length
+ * @param dst A pointer to a buf to store the parsed data
+ *
+ * @return The parsed hex data length
+ */
+static t_u32 wlan_parse_cal_cfg(t_u8 *src, t_size len, t_u8 *dst)
+{
+ t_u8 *ptr;
+ t_u8 *dptr;
+
+ ENTER();
+ ptr = src;
+ dptr = dst;
+
+ while (ptr - src < len) {
+ if (*ptr && (wlan_isspace(*ptr) || *ptr == '\t')) {
+ ptr++;
+ continue;
+ }
+
+ if (wlan_isxdigit(*ptr)) {
+ *dptr++ = wlan_atox(ptr);
+ ptr += 2;
+ } else {
+ ptr++;
+ }
+ }
+ LEAVE();
+ return dptr - dst;
+}
+
+/**
+ * @brief This function finds first occurrence of a char in a string
+ *
+ * @param s A pointer to the string to be searched
+ * @param c The character to search for
+ *
+ * @return Location of the first occurrence of the char
+ * if found, else NULL
+ */
+t_u8 *wlan_strchr(t_u8 *s, int c)
+{
+ t_u8 *pos = s;
+ while (*pos != '\0') {
+ if (*pos == (t_u8)c)
+ return pos;
+ pos++;
+ }
+ return MNULL;
+}
+
+#define CFG_TYPE_HOSTCMD 0
+#define CFG_TYPE_DPDFILE 1
+
+/**
+ * @brief WOAL parse ASCII format raw data to hex format
+ *
+ * @param pmpriv MOAL handle
+ * @param cfg_type Conf file type
+ * @param data Source data
+ * @param size data length
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 wlan_process_hostcmd_cfg(pmlan_private pmpriv, t_u16 cfg_type,
+ t_u8 *data, t_size size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = data;
+ t_u8 *intf_s, *intf_e;
+ t_u8 *buf = MNULL;
+ t_u8 *ptr = MNULL;
+ t_u32 cmd_len = 0;
+ t_u8 start_raw = MFALSE;
+ mlan_ds_misc_cmd *hostcmd;
+ HostCmd_DS_GEN *pcmd = MNULL;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_cmd = MNULL;
+ mlan_adapter *pmadapter = MNULL;
+ mlan_callbacks *pcb = MNULL;
+ t_u8 hostcmd_flag = MFALSE;
+
+ ENTER();
+ if (!pmpriv) {
+ PRINTM(MERROR, "pmpriv is NULL\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter = pmpriv->adapter;
+ pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF,
+ (t_u8 **)&hostcmd);
+ if (ret || !hostcmd) {
+ PRINTM(MERROR, "Could not allocate buffer space!\n");
+ LEAVE();
+ return ret;
+ }
+ buf = hostcmd->cmd;
+ ptr = buf;
+ while ((pos - data) < size) {
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '#') { /* Line comment */
+ while (*pos != '\n')
+ pos++;
+ pos++;
+ }
+ if ((*pos == '\r' && *(pos + 1) == '\n') || *pos == '\n' ||
+ *pos == '\0') {
+ pos++;
+ continue; /* Needn't process this line */
+ }
+
+ if (*pos == '}') {
+ if (cfg_type == CFG_TYPE_DPDFILE && pcmd) {
+ /* Fill command head for DPD RAW data conf */
+ hostcmd->len = ptr - buf;
+ pcmd->command =
+ wlan_cpu_to_le16(HostCmd_CMD_CFG_DATA);
+ pcmd->size = wlan_cpu_to_le16(hostcmd->len);
+ pcfg_cmd = (HostCmd_DS_802_11_CFG_DATA
+ *)((t_u8 *)pcmd + S_DS_GEN);
+ pcfg_cmd->action =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ pcfg_cmd->type = wlan_cpu_to_le16(OID_TYPE_DPD);
+ pcfg_cmd->data_len = wlan_cpu_to_le16(
+ hostcmd->len - S_DS_GEN -
+ sizeof(HostCmd_DS_802_11_CFG_DATA));
+ pcmd = MNULL;
+ pcfg_cmd = MNULL;
+ } else {
+ /* For hostcmd data conf */
+ cmd_len = *((t_u16 *)(buf + sizeof(t_u16)));
+ hostcmd->len = cmd_len;
+ }
+ ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, MNULL,
+ (t_void *)hostcmd);
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ ptr = buf;
+ start_raw = MFALSE;
+ pos++;
+ continue;
+ }
+
+ if (start_raw == MFALSE) {
+ intf_s = wlan_strchr(pos, '=');
+ if (intf_s) {
+ if (*(intf_s + 1) == '=')
+ hostcmd_flag = MTRUE;
+ intf_e = wlan_strchr(intf_s, '{');
+ } else
+ intf_e = MNULL;
+
+ if (intf_s && intf_e) {
+ start_raw = MTRUE;
+ pos = intf_e + 1;
+ /* Reserve command head for DPD RAW data conf */
+ if (cfg_type == CFG_TYPE_DPDFILE &&
+ !hostcmd_flag) {
+ pcmd = (HostCmd_DS_GEN *)ptr;
+ ptr += S_DS_GEN +
+ sizeof(HostCmd_DS_802_11_CFG_DATA);
+ }
+ continue;
+ }
+ }
+
+ if (start_raw) {
+ /* Raw data block exists */
+ while (*pos != '\n') {
+ if ((*pos <= 'f' && *pos >= 'a') ||
+ (*pos <= 'F' && *pos >= 'A') ||
+ (*pos <= '9' && *pos >= '0')) {
+ *ptr++ = wlan_atox(pos);
+ pos += 2;
+ } else
+ pos++;
+ }
+ }
+ }
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param cmd_no cmd id
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return N/A
+ */
+static void wlan_init_cmd_node(pmlan_private pmpriv, cmd_ctrl_node *pcmd_node,
+ t_u32 cmd_no, t_void *pioctl_buf,
+ t_void *pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->priv = pmpriv;
+ pcmd_node->cmd_no = cmd_no;
+ pcmd_node->pioctl_buf = pioctl_buf;
+ pcmd_node->pdata_buf = pdata_buf;
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pcmd_node->cmdbuf =
+ wlan_alloc_mlan_buffer(pmadapter,
+ MRVDRV_SIZE_OF_CMD_BUFFER, 0,
+ MOAL_MALLOC_BUFFER);
+ if (!pcmd_node->cmdbuf) {
+ PRINTM(MERROR, "Failed to allocate cmd_buffer\n");
+ LEAVE();
+ return;
+ }
+ }
+#endif /* USB */
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type))
+ pcmd_node->cmdbuf = pcmd_node->pmbuf;
+#endif
+
+ /* Make sure head_ptr for cmd buf is Align */
+ pcmd_node->cmdbuf->data_offset = 0;
+ memset(pmadapter, pcmd_node->cmdbuf->pbuf, 0,
+ MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ /* Prepare mlan_buffer for command sending */
+ pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD;
+#ifdef USB
+ if (IS_USB(pmadapter->card_type))
+ pcmd_node->cmdbuf->data_offset += MLAN_TYPE_LEN;
+#endif
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type))
+ pcmd_node->cmdbuf->data_offset +=
+ pmadapter->ops.intf_header_len;
+#endif
+
+ LEAVE();
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL
+ */
+static cmd_ctrl_node *wlan_get_cmd_node(mlan_adapter *pmadapter)
+{
+ cmd_ctrl_node *pcmd_node;
+
+ ENTER();
+
+ if (pmadapter == MNULL) {
+ LEAVE();
+ return MNULL;
+ }
+ wlan_request_cmd_lock(pmadapter);
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ MNULL, MNULL)) {
+ pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->cmd_free_q, MNULL,
+ MNULL);
+ } else {
+ PRINTM(MERROR,
+ "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ pcmd_node = MNULL;
+ }
+ wlan_release_cmd_lock(pmadapter);
+ LEAVE();
+ return pcmd_node;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+static t_void wlan_clean_cmd_node(pmlan_adapter pmadapter,
+ cmd_ctrl_node *pcmd_node)
+{
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ LEAVE();
+ return;
+ }
+ pcmd_node->cmd_no = 0;
+ pcmd_node->cmd_flag = 0;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->pdata_buf = MNULL;
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type) && pcmd_node->cmdbuf) {
+ wlan_free_mlan_buffer(pmadapter, pcmd_node->cmdbuf);
+ pcmd_node->cmdbuf = MNULL;
+ }
+#endif
+
+ if (pcmd_node->respbuf) {
+ pmadapter->ops.cmdrsp_complete(pmadapter, pcmd_node->respbuf,
+ MLAN_STATUS_SUCCESS);
+ pcmd_node->respbuf = MNULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which is scan command
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+static cmd_ctrl_node *wlan_get_pending_scan_cmd(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+ if (!pcmd_node) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) {
+ if (pcmd_node->cmd_flag & CMD_F_SCAN) {
+ LEAVE();
+ return pcmd_node;
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+#endif
+
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which matches the given pioctl_req
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+static cmd_ctrl_node *wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+ if (!pcmd_node) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) {
+ if (pcmd_node->pioctl_buf &&
+ (pcmd_node->pioctl_buf == pioctl_req)) {
+ LEAVE();
+ return pcmd_node;
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will return the pointer to the first entry in
+ * pending cmd which matches the given bss_index
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_index bss_index
+ *
+ * @return A pointer to first entry match pioctl_req
+ */
+static cmd_ctrl_node *wlan_get_bss_pending_ioctl_cmd(pmlan_adapter pmadapter,
+ t_u32 bss_index)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ ENTER();
+
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+ if (!pcmd_node) {
+ LEAVE();
+ return MNULL;
+ }
+ while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) {
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ if (pioctl_buf->bss_index == bss_index) {
+ LEAVE();
+ return pcmd_node;
+ }
+ }
+ pcmd_node = pcmd_node->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function handles the command response of host_cmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_host_cmd(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc;
+ t_u16 size = wlan_le16_to_cpu(resp->size);
+
+ ENTER();
+
+ PRINTM(MINFO, "host command response size = %d\n", size);
+ size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc->param.hostcmd.len = size;
+ memcpy_ext(pmpriv->adapter, misc->param.hostcmd.cmd,
+ (void *)resp, size, MRVDRV_SIZE_OF_CMD_BUFFER);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends host command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_host_cmd(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
+{
+ mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *)pdata_buf;
+
+ ENTER();
+
+ /* Copy the HOST command to command buffer */
+ memcpy_ext(pmpriv->adapter, (void *)cmd, pcmd_ptr->cmd, pcmd_ptr->len,
+ MRVDRV_SIZE_OF_CMD_BUFFER);
+ PRINTM(MINFO, "Host command size = %d\n", pcmd_ptr->len);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function get the cmd timeout value
+ *
+ * @param cmd_id cmd id
+ *
+ * @return timeout value for this command
+ */
+static t_u16 wlan_get_cmd_timeout(t_u16 cmd_id)
+{
+ t_u16 timeout;
+ ENTER();
+ switch (cmd_id) {
+ case HostCmd_CMD_802_11_SCAN:
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ timeout = MRVDRV_TIMER_10S * 2;
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ case HostCmd_CMD_802_11_DISASSOCIATE:
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ case HostCmd_CMD_11N_DELBA:
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ case HostCmd_CMD_SOFT_RESET:
+#ifdef UAP_SUPPORT
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_BSS_START:
+ case HOST_CMD_APCMD_BSS_STOP:
+ case HOST_CMD_APCMD_STA_DEAUTH:
+#endif
+ case HostCMD_APCMD_ACS_SCAN:
+ timeout = MRVDRV_TIMER_5S;
+ break;
+ default:
+ timeout = MRVDRV_TIMER_1S * 2;
+ break;
+ }
+ LEAVE();
+ return timeout;
+}
+
+/**
+ * @brief This function downloads a command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_dnld_cmd_to_fw(mlan_private *pmpriv,
+ cmd_ctrl_node *pcmd_node)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ t_u16 cmd_code;
+ t_u16 cmd_size;
+ t_u32 age_ts_usec;
+#ifdef USB
+ t_u32 tmp;
+#endif
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+ t_u16 timeout = 0;
+
+ ENTER();
+
+ if (pcmd_node)
+ if (pcmd_node->pioctl_buf != MNULL)
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ if (!pmadapter || !pcmd_node) {
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+
+ /* Sanity test */
+ if (pcmd == MNULL || pcmd->size == 0) {
+ PRINTM(MERROR,
+ "DNLD_CMD: pcmd is null or command size is zero, "
+ "Not sending\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Set command sequence number */
+ pmadapter->seq_num++;
+ pcmd->seq_num = wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO(
+ pmadapter->seq_num, pcmd_node->priv->bss_num,
+ pcmd_node->priv->bss_type));
+ cmd_code = wlan_le16_to_cpu(pcmd->command);
+ pcmd_node->cmd_no = cmd_code;
+ timeout = wlan_get_cmd_timeout(cmd_code);
+ cmd_size = wlan_le16_to_cpu(pcmd->size);
+
+ pcmd_node->cmdbuf->data_len = cmd_size;
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->curr_cmd = pcmd_node;
+ wlan_release_cmd_lock(pmadapter);
+
+ /* Save the last command id and action to debug log */
+ pmadapter->dbg.last_cmd_index =
+ (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
+ wlan_le16_to_cpu(*(t_u16 *)((t_u8 *)pcmd + S_DS_GEN));
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->dnld_cmd_in_secs,
+ &age_ts_usec);
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ /* Add extra header for USB */
+ if (pcmd_node->cmdbuf->data_offset < MLAN_TYPE_LEN) {
+ PRINTM(MERROR,
+ "DNLD_CMD: data_offset is too small=%d\n",
+ pcmd_node->cmdbuf->data_offset);
+ if (pioctl_buf)
+ pioctl_buf->status_code =
+ MLAN_ERROR_CMD_DNLD_FAIL;
+
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ if (pmadapter->dbg.last_cmd_index)
+ pmadapter->dbg.last_cmd_index--;
+ else
+ pmadapter->dbg.last_cmd_index = DBG_CMD_NUM - 1;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ tmp = wlan_cpu_to_le32(MLAN_USB_TYPE_CMD);
+ memcpy_ext(pmadapter, (t_u8 *)pcmd - MLAN_TYPE_LEN,
+ (t_u8 *)&tmp, MLAN_TYPE_LEN, MLAN_TYPE_LEN);
+ pcmd_node->cmdbuf->data_offset -= MLAN_TYPE_LEN;
+ pcmd_node->cmdbuf->data_len += MLAN_TYPE_LEN;
+ }
+#endif
+
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
+ PRINTM_NETINTF(MCMND, pmpriv);
+ PRINTM(MCMND,
+ "DNLD_CMD (%lu.%06lu): 0x%x, act 0x%x, len %d, seqno 0x%x timeout %d\n",
+ sec, usec, cmd_code,
+ wlan_le16_to_cpu(*(t_u16 *)((t_u8 *)pcmd + S_DS_GEN)), cmd_size,
+ wlan_le16_to_cpu(pcmd->seq_num), timeout);
+ DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *)pcmd, cmd_size);
+
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ pcmd_node->cmdbuf->data_offset -=
+ pmadapter->ops.intf_header_len;
+ pcmd_node->cmdbuf->data_len += pmadapter->ops.intf_header_len;
+ }
+#endif
+
+ /* Send the command to lower layer */
+ ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_CMD,
+ pcmd_node->cmdbuf, MNULL);
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type) && (ret == MLAN_STATUS_PENDING))
+ pcmd_node->cmdbuf = MNULL;
+#endif
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ if (pmadapter->dbg.last_cmd_index)
+ pmadapter->dbg.last_cmd_index--;
+ else
+ pmadapter->dbg.last_cmd_index = DBG_CMD_NUM - 1;
+
+ pmadapter->dbg.num_cmd_host_to_card_failure++;
+ wlan_dump_info(pmadapter, REASON_CODE_CMD_TO_CARD_FAILURE);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Clear BSS_NO_BITS from HostCmd */
+ cmd_code &= HostCmd_CMD_ID_MASK;
+
+ /* For the command who has no command response, we should return here */
+ if (cmd_code == HostCmd_CMD_FW_DUMP_EVENT ||
+ cmd_code == HostCmd_CMD_SOFT_RESET) {
+ if (pcmd_node->pioctl_buf) {
+ PRINTM(MMSG,
+ "CMD(0x%x) has no cmd resp: free curr_cmd and do ioctl_complete\n",
+ cmd_code);
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter,
+ pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ }
+ goto done;
+ }
+
+ /* Setup the timer after transmit command */
+ pcb->moal_start_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer, MFALSE, timeout);
+
+ pmadapter->cmd_timer_is_set = MTRUE;
+
+ ret = MLAN_STATUS_SUCCESS;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends sleep confirm command to firmware.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_dnld_sleep_confirm_cmd(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ static t_u32 i;
+#if defined(SDIO) || defined(PCIE)
+ t_u16 cmd_len = 0;
+#endif
+ opt_sleep_confirm_buffer *sleep_cfm_buf =
+ (opt_sleep_confirm_buffer *)(pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset);
+ mlan_buffer *pmbuf = MNULL;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (!pmpriv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ cmd_len = sizeof(OPT_Confirm_Sleep);
+ pmbuf = pmadapter->psleep_cfm;
+ }
+#endif
+ pmadapter->seq_num++;
+ sleep_cfm_buf->ps_cfm_sleep.seq_num =
+ wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO(
+ pmadapter->seq_num, pmpriv->bss_num, pmpriv->bss_type));
+ DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep,
+ sizeof(OPT_Confirm_Sleep));
+
+ /* Send sleep confirm command to firmware */
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter,
+ sizeof(opt_sleep_confirm_buffer),
+ 0, MOAL_MALLOC_BUFFER);
+
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "Failed to allocate sleep confirm buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmbuf->buf_type = MLAN_BUF_TYPE_CMD;
+ pmbuf->data_len = pmadapter->psleep_cfm->data_len;
+ memcpy_ext(pmadapter, pmbuf->pbuf + pmbuf->data_offset,
+ pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset,
+ pmadapter->psleep_cfm->data_len, pmbuf->data_len);
+ }
+#endif /* USB */
+
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type))
+ pmadapter->psleep_cfm->data_len =
+ cmd_len + pmadapter->ops.intf_header_len;
+#endif
+
+ if (pmbuf)
+ ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_CMD, pmbuf,
+ MNULL);
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type) && (ret != MLAN_STATUS_PENDING))
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+#endif
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "SLEEP_CFM: failed\n");
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+ goto done;
+ } else {
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) {
+ /* Response is not needed for sleep confirm
+ * command */
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ } else {
+ pmadapter->ps_state = PS_STATE_SLEEP_CFM;
+ }
+
+ if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl &&
+ (pmadapter->is_hs_configured &&
+ !pmadapter->sleep_period.period)) {
+ pmadapter->pm_wakeup_card_req = MTRUE;
+ wlan_host_sleep_activated_event(
+ wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_STA),
+ MTRUE);
+ }
+ }
+#endif /* STA_SUPPORT */
+
+ PRINTM_NETINTF(MEVENT, pmpriv);
+#define NUM_SC_PER_LINE 16
+ if (++i % NUM_SC_PER_LINE == 0)
+ PRINTM(MEVENT, "+\n");
+ else
+ PRINTM(MEVENT, "+");
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Event handler
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param event_id Event ID
+ * @param pmevent Event buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_recv_event(pmlan_private priv, mlan_event_id event_id,
+ t_void *pmevent)
+{
+ pmlan_callbacks pcb = MNULL;
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pcb = &priv->adapter->callbacks;
+
+ if (pmevent)
+ /* The caller has provided the event. */
+ pcb->moal_recv_event(priv->adapter->pmoal_handle,
+ (pmlan_event)pmevent);
+ else {
+ mlan_event mevent;
+
+ memset(priv->adapter, &mevent, 0, sizeof(mlan_event));
+ mevent.bss_index = priv->bss_index;
+ mevent.event_id = event_id;
+ mevent.event_len = 0;
+
+ pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates the command buffer and links
+ * it to command free queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_alloc_cmd_buffer(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array = MNULL;
+ t_u32 buf_size;
+ t_u32 i;
+
+ ENTER();
+
+ /* Allocate and initialize cmd_ctrl_node */
+ buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pcmd_array);
+ if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->cmd_pool = pcmd_array;
+ memset(pmadapter, pmadapter->cmd_pool, 0, buf_size);
+
+#if defined(PCIE) || defined(SDIO)
+ if (!IS_USB(pmadapter->card_type)) {
+ /* Allocate and initialize command buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ pcmd_array[i].pmbuf = wlan_alloc_mlan_buffer(
+ pmadapter, MRVDRV_SIZE_OF_CMD_BUFFER, 0,
+ MOAL_MALLOC_BUFFER);
+ if (!pcmd_array[i].pmbuf) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+#endif
+ wlan_request_cmd_lock(pmadapter);
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++)
+ wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]);
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_free_cmd_buffer(mlan_adapter *pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_array;
+ t_u32 i;
+
+ ENTER();
+
+ /* Need to check if cmd pool is allocated or not */
+ if (pmadapter->cmd_pool == MNULL) {
+ PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n");
+ goto done;
+ }
+
+ pcmd_array = pmadapter->cmd_pool;
+
+ /* Release shared memory buffers */
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+#ifdef USB
+ if (IS_USB(pmadapter->card_type) && pcmd_array[i].cmdbuf) {
+ PRINTM(MINFO, "Free all the USB command buffer.\n");
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].cmdbuf);
+ pcmd_array[i].cmdbuf = MNULL;
+ }
+#endif
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type) && pcmd_array[i].pmbuf) {
+ PRINTM(MINFO, "Free all the command buffer.\n");
+ wlan_free_mlan_buffer(pmadapter, pcmd_array[i].pmbuf);
+ pcmd_array[i].pmbuf = MNULL;
+ }
+#endif
+ if (pcmd_array[i].respbuf) {
+#ifdef USB
+ if (IS_USB(pmadapter->card_type))
+ pmadapter->callbacks.moal_recv_complete(
+ pmadapter->pmoal_handle,
+ pcmd_array[i].respbuf,
+ pmadapter->rx_cmd_ep,
+ MLAN_STATUS_SUCCESS);
+#endif
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type))
+ wlan_free_mlan_buffer(pmadapter,
+ pcmd_array[i].respbuf);
+#endif
+ pcmd_array[i].respbuf = MNULL;
+ }
+ }
+ /* Release cmd_ctrl_node */
+ if (pmadapter->cmd_pool) {
+ PRINTM(MINFO, "Free command pool.\n");
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->cmd_pool);
+ pmadapter->cmd_pool = MNULL;
+ }
+
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_event(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u32 eventcause = pmadapter->event_cause;
+#ifdef DEBUG_LEVEL1
+ t_u32 in_ts_sec = 0, in_ts_usec = 0;
+#endif
+ ENTER();
+
+ /* Save the last event to debug log */
+ pmadapter->dbg.last_event_index =
+ (pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] =
+ (t_u16)eventcause;
+
+ if ((eventcause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) {
+ if (wlan_11h_dfs_event_preprocessing(pmadapter) ==
+ MLAN_STATUS_SUCCESS) {
+ memcpy_ext(pmadapter, (t_u8 *)&eventcause,
+ pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(eventcause), sizeof(eventcause));
+ } else {
+ priv = wlan_get_priv_by_id(
+ pmadapter, EVENT_GET_BSS_NUM(eventcause),
+ EVENT_GET_BSS_TYPE(eventcause));
+ if (priv)
+ PRINTM_NETINTF(MEVENT, priv);
+ PRINTM(MERROR, "Error processing DFS Event: 0x%x\n",
+ eventcause);
+ goto done;
+ }
+ }
+ /* Get BSS number and corresponding priv */
+ priv = wlan_get_priv_by_id(pmadapter, EVENT_GET_BSS_NUM(eventcause),
+ EVENT_GET_BSS_TYPE(eventcause));
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ pmadapter->event_cause = eventcause;
+
+ if (pmbuf) {
+ pmbuf->bss_index = priv->bss_index;
+ memcpy_ext(pmadapter, pmbuf->pbuf + pmbuf->data_offset,
+ (t_u8 *)&eventcause, sizeof(eventcause),
+ sizeof(eventcause));
+ }
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ eventcause != EVENT_FW_DUMP_INFO) {
+ PRINTM_GET_SYS_TIME(MEVENT, &in_ts_sec, &in_ts_usec);
+ PRINTM_NETINTF(MEVENT, priv);
+ PRINTM(MEVENT, "%lu.%06lu : Event: 0x%x\n", in_ts_sec,
+ in_ts_usec, eventcause);
+ }
+
+ ret = priv->ops.process_event(priv);
+done:
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ if (pmbuf)
+ pmadapter->ops.event_complete(pmadapter, pmbuf,
+ MLAN_STATUS_SUCCESS);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function requests a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_request_cmd_lock(mlan_adapter *pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin lock callback function */
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function releases a lock on command queue.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_release_cmd_lock(mlan_adapter *pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin unlock callback function */
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_lock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_prepare_cmd(mlan_private *pmpriv, t_u16 cmd_no,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pioctl_buf, t_void *pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_COMMAND *cmd_ptr = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ if (!pmpriv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter = pmpriv->adapter;
+
+ /* Sanity test */
+ if (!pmadapter || pmadapter->surprise_removed) {
+ PRINTM(MERROR, "PREP_CMD: Card is Removed\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->hw_status == WlanHardwareStatusReset) {
+ if ((cmd_no != HostCmd_CMD_FUNC_INIT)
+#ifdef PCIE
+ && (cmd_no != HostCmd_CMD_PCIE_HOST_BUF_DETAILS)
+#endif
+ ) {
+ PRINTM(MERROR, "PREP_CMD: FW is in reset state\n");
+ if (pioctl_req)
+ pioctl_req->status_code =
+ MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Get a new command node */
+ pcmd_node = wlan_get_cmd_node(pmadapter);
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd node\n");
+ wlan_dump_info(pmadapter, REASON_CODE_NO_CMD_NODE);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** reset num no cmd node */
+ pmadapter->dbg.num_no_cmd_node = 0;
+
+ /* Initialize the command node */
+ wlan_init_cmd_node(pmpriv, pcmd_node, cmd_no, pioctl_buf, pdata_buf);
+
+ if (pcmd_node->cmdbuf == MNULL) {
+ PRINTM(MERROR, "PREP_CMD: No free cmd buf\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd_ptr = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ cmd_ptr->command = cmd_no;
+ cmd_ptr->result = 0;
+
+ /* Prepare command */
+ if (cmd_no)
+ ret = pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action,
+ cmd_oid, pioctl_buf, pdata_buf,
+ cmd_ptr);
+ else {
+ ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf);
+ pcmd_node->cmd_flag |= CMD_F_HOSTCMD;
+ }
+
+ /* Return error, since the command preparation failed */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n",
+ cmd_no);
+ pcmd_node->pioctl_buf = MNULL;
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_DNLD_FAIL;
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ /* Send command */
+#ifdef STA_SUPPORT
+ if (cmd_no == HostCmd_CMD_802_11_SCAN ||
+ cmd_no == HostCmd_CMD_802_11_SCAN_EXT) {
+ if (cmd_no == HostCmd_CMD_802_11_SCAN_EXT &&
+ pmadapter->ext_scan && pmadapter->ext_scan_enh &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
+ MFALSE);
+ } else
+ wlan_queue_scan_cmd(pmpriv, pcmd_node);
+ } else {
+#endif
+ if ((cmd_no == HostCmd_CMD_802_11_HS_CFG_ENH) &&
+ (cmd_action == HostCmd_ACT_GEN_SET) &&
+ (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL))
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
+ MFALSE);
+ else
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
+ MTRUE);
+#ifdef STA_SUPPORT
+ }
+#endif
+ wlan_release_cmd_lock(pmadapter);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function inserts command node to cmd_free_q
+ * after cleaning it.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ *
+ * @return N/A
+ */
+t_void wlan_insert_cmd_to_free_q(mlan_adapter *pmadapter,
+ cmd_ctrl_node *pcmd_node)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ ENTER();
+
+ if (pcmd_node == MNULL)
+ goto done;
+ if (pcmd_node->pioctl_buf) {
+ pioctl_req = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR)
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req,
+ MLAN_STATUS_FAILURE);
+ else
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ /* Clean the node */
+ wlan_clean_cmd_node(pmadapter, pcmd_node);
+
+ /* Insert node into cmd_free_q */
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->cmd_free_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+done:
+ LEAVE();
+}
+
+/**
+ * @brief This function queues the command to cmd list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pcmd_node A pointer to cmd_ctrl_node structure
+ * @param add_tail Specify if the cmd needs to be queued in the header or
+ * tail
+ *
+ * @return N/A
+ */
+t_void wlan_insert_cmd_to_pending_q(mlan_adapter *pmadapter,
+ cmd_ctrl_node *pcmd_node, t_u32 add_tail)
+{
+ HostCmd_DS_COMMAND *pcmd = MNULL;
+ t_u16 command;
+
+ ENTER();
+
+ if (pcmd_node == MNULL) {
+ PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n");
+ goto done;
+ }
+
+ pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+
+ command = wlan_le16_to_cpu(pcmd->command);
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh;
+ if (wlan_le16_to_cpu(pm->action) == DIS_AUTO_PS) {
+ if (pmadapter->ps_state != PS_STATE_AWAKE)
+ add_tail = MFALSE;
+ }
+ }
+
+ if (add_tail) {
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL,
+ MNULL);
+ } else {
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL,
+ MNULL);
+ }
+
+ PRINTM_NETINTF(MCMND, pcmd_node->priv);
+ PRINTM(MCMND, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put firmware back to PS mode
+ * if applicable.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_exec_next_cmd(mlan_adapter *pmadapter)
+{
+ mlan_private *priv = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_COMMAND *pcmd;
+
+ ENTER();
+
+ /* Sanity test */
+ if (pmadapter == MNULL) {
+ PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Check if already in processing */
+ if (pmadapter->curr_cmd) {
+ PRINTM(MERROR,
+ "EXEC_NEXT_CMD: there is command in processing!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ /* Check if any command is pending */
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+
+ if (pcmd_node) {
+ pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset);
+ priv = pcmd_node->priv;
+
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ PRINTM(MERROR,
+ "Cannot send command in sleep state, this should not happen\n");
+ wlan_release_cmd_lock(pmadapter);
+ goto done;
+ }
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ wlan_release_cmd_lock(pmadapter);
+ ret = wlan_dnld_cmd_to_fw(priv, pcmd_node);
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Any command sent to the firmware when host is in sleep mode,
+ * should de-configure host sleep */
+ /* We should skip the host sleep configuration command itself
+ * though */
+ if (priv && (pcmd->command !=
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(priv, MFALSE);
+ }
+ }
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_cmdresp(mlan_adapter *pmadapter)
+{
+ HostCmd_DS_COMMAND *resp = MNULL;
+ mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ mlan_private *pmpriv_next = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 orig_cmdresp_no;
+ t_u16 cmdresp_no;
+ t_u16 cmdresp_result;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+ t_u32 i;
+
+ ENTER();
+
+ if (pmadapter->curr_cmd)
+ if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *)
+ pmadapter->curr_cmd->pioctl_buf;
+ }
+
+ if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
+ resp = (HostCmd_DS_COMMAND *)pmadapter->upld_buf;
+ resp->command = wlan_le16_to_cpu(resp->command);
+ PRINTM(MERROR, "CMD_RESP: No curr_cmd, 0x%x\n", resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "CMD_RESP",
+ pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset,
+ pmadapter->curr_cmd->respbuf->data_len);
+
+ resp = (HostCmd_DS_COMMAND *)(pmadapter->curr_cmd->respbuf->pbuf +
+ pmadapter->curr_cmd->respbuf->data_offset);
+ orig_cmdresp_no = wlan_le16_to_cpu(resp->command);
+ cmdresp_no = (orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+ if (pmadapter->curr_cmd->cmd_no != cmdresp_no) {
+ PRINTM(MERROR, "cmdresp error: cmd=0x%x cmd_resp=0x%x\n",
+ pmadapter->curr_cmd->cmd_no, cmdresp_no);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->dnld_cmd_in_secs = 0;
+ /* Now we got response from FW, cancel the command timer */
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ /* Cancel command timeout timer */
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+ pmadapter->num_cmd_timeout = 0;
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pmadapter->curr_cmd = MNULL;
+ PRINTM(MCMND, "CMD_RESP: 0x%x been canceled!\n",
+ wlan_le16_to_cpu(resp->command));
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ wlan_release_cmd_lock(pmadapter);
+ }
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ /* Copy original response back to response buffer */
+ if (pmpriv)
+ wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
+ }
+ resp->size = wlan_le16_to_cpu(resp->size);
+ resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
+ resp->result = wlan_le16_to_cpu(resp->result);
+
+ /* Get BSS number and corresponding priv */
+ pmpriv = wlan_get_priv_by_id(pmadapter,
+ HostCmd_GET_BSS_NO(resp->seq_num),
+ HostCmd_GET_BSS_TYPE(resp->seq_num));
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ /* Clear RET_BIT from HostCmd */
+ resp->command = (orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+ if (!pmpriv) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cmdresp_no = resp->command;
+
+ cmdresp_result = resp->result;
+
+ /* Save the last command response to debug log */
+ pmadapter->dbg.last_cmd_resp_index =
+ (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+ pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
+ orig_cmdresp_no;
+
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
+ PRINTM_NETINTF(MCMND, pmadapter->curr_cmd->priv);
+ PRINTM(MCMND,
+ "CMD_RESP (%lu.%06lu): 0x%x, result %d, len %d, seqno 0x%x\n",
+ sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
+ resp->seq_num);
+
+ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+ PRINTM(MERROR, "CMD_RESP: Invalid response to command!\n");
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+ if ((cmdresp_result == HostCmd_RESULT_OK) &&
+ (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ } else {
+ /* handle response */
+ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp,
+ pioctl_buf);
+ }
+
+ /* Check init command response */
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing ||
+ pmadapter->hw_status == WlanHardwareStatusGetHwSpec) {
+ if (ret == MLAN_STATUS_FAILURE) {
+#ifdef STA_SUPPORT
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset failure */
+ pmadapter->pwarm_reset_ioctl_req->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_FAILURE);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ PRINTM(MERROR,
+ "cmd 0x%02x failed during initialization\n",
+ cmdresp_no);
+ wlan_init_fw_complete(pmadapter);
+ goto done;
+ }
+#ifdef STA_SUPPORT
+#ifdef PCIE
+ /* init adma write pointer */
+ if (IS_PCIE(pmadapter->card_type) &&
+ cmdresp_no == HostCmd_CMD_FUNC_SHUTDOWN &&
+ pmadapter->pwarm_reset_ioctl_req) {
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+#endif
+ wlan_pcie_init_fw(pmadapter);
+ }
+#endif
+#endif
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ if (pmadapter->curr_cmd) {
+ cmd_ctrl_node *free_cmd = pmadapter->curr_cmd;
+ pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf;
+ pmadapter->curr_cmd = MNULL;
+ if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ else if (pioctl_buf && (ret == MLAN_STATUS_FAILURE) &&
+ !pioctl_buf->status_code)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_insert_cmd_to_free_q(pmadapter, free_cmd);
+ }
+ wlan_release_cmd_lock(pmadapter);
+
+ if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
+ (pmadapter->last_init_cmd == cmdresp_no)) {
+ i = pmpriv->bss_index + 1;
+ while (i < pmadapter->priv_num &&
+ (!(pmpriv_next = pmadapter->priv[i]) ||
+ pmpriv_next->bss_virtual))
+ i++;
+ if (!pmpriv_next || i >= pmadapter->priv_num) {
+#ifdef STA_SUPPORT
+ if (pmadapter->pwarm_reset_ioctl_req) {
+ /* warm reset complete */
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ pmadapter->pwarm_reset_ioctl_req,
+ MLAN_STATUS_SUCCESS);
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+ goto done;
+ }
+#endif
+ pmadapter->hw_status = WlanHardwareStatusInitdone;
+ } else {
+ /* Issue init commands for the next interface */
+ ret = pmpriv_next->ops.init_cmd(pmpriv_next, MFALSE);
+ }
+ } else if ((pmadapter->hw_status == WlanHardwareStatusGetHwSpec) &&
+ (HostCmd_CMD_GET_HW_SPEC == cmdresp_no)) {
+ pmadapter->hw_status = WlanHardwareStatusGetHwSpecdone;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @param function_context A pointer to function_context
+ * @return N/A
+ */
+t_void wlan_cmd_timeout_func(t_void *function_context)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)function_context;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+#if defined(SDIO) || defined(PCIE)
+ t_u8 i;
+#endif
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+ if (!pmadapter->curr_cmd) {
+ if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
+ pmadapter->scan_processing) {
+ PRINTM(MMSG, "Ext scan enh timeout\n");
+ pmadapter->ext_scan_timeout = MTRUE;
+ wlan_dump_info(pmadapter, REASON_CODE_EXT_SCAN_TIMEOUT);
+ goto exit;
+ }
+ PRINTM(MWARN, "CurCmd Empty\n");
+ goto exit;
+ }
+ pmadapter->num_cmd_timeout++;
+ pcmd_node = pmadapter->curr_cmd;
+ if (pcmd_node->pioctl_buf != MNULL) {
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT;
+ }
+
+ pmadapter->dbg.timeout_cmd_id =
+ pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index];
+ pmadapter->dbg.timeout_cmd_act =
+ pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index];
+ PRINTM_GET_SYS_TIME(MERROR, &sec, &usec);
+ PRINTM(MERROR, "Timeout cmd id (%lu.%06lu) = 0x%x, act = 0x%x\n", sec,
+ usec, pmadapter->dbg.timeout_cmd_id,
+ pmadapter->dbg.timeout_cmd_act);
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type) && pcmd_node->cmdbuf) {
+ t_u8 *pcmd_buf;
+ pcmd_buf = pcmd_node->cmdbuf->pbuf +
+ pcmd_node->cmdbuf->data_offset +
+ pmadapter->ops.intf_header_len;
+ for (i = 0; i < 16; i++)
+ PRINTM(MERROR, "%02x ", *pcmd_buf++);
+ PRINTM(MERROR, "\n");
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type))
+ pmadapter->ops.debug_dump(pmadapter);
+#endif
+ pmpriv = pcmd_node->priv;
+ if (pmpriv)
+ PRINTM(MERROR, "BSS type = %d BSS role= %d\n", pmpriv->bss_type,
+ pmpriv->bss_role);
+ wlan_dump_info(pmadapter, REASON_CODE_CMD_TIMEOUT);
+
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing ||
+ pmadapter->hw_status == WlanHardwareStatusGetHwSpec)
+ wlan_init_fw_complete(pmadapter);
+ else {
+ /* Signal MOAL to perform extra handling for debugging */
+ if (pmpriv) {
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP,
+ MNULL);
+ } else {
+ wlan_recv_event(wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ }
+ }
+
+exit:
+ LEAVE();
+ return;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Internal function used to flush the scan pending queue
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_flush_scan_queue(pmlan_adapter pmadapter)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+
+ ENTER();
+
+ wlan_request_cmd_lock(pmadapter);
+ while ((pcmd_node = (cmd_ctrl_node *)util_peek_list(
+ pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ pcmd_node->pioctl_buf = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+
+ pmadapter->scan_processing = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+}
+
+/**
+ * @brief Cancel pending SCAN ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to pmlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING
+ */
+mlan_status wlan_cancel_pending_scan_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+ pmlan_private priv = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ PRINTM(MIOCTL, "Cancel scan command\n");
+ wlan_request_cmd_lock(pmadapter);
+ /* IOCTL will be completed, avoid calling IOCTL complete again from
+ * EVENT/CMDRESP */
+ if (pmadapter->pscan_ioctl_req) {
+ pioctl_buf = pmadapter->pscan_ioctl_req;
+ priv = pmadapter->priv[pioctl_buf->bss_index];
+ pmadapter->pscan_ioctl_req = MNULL;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+
+ if (pmadapter->curr_cmd && pmadapter->curr_cmd->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf;
+ if (pioctl_buf->req_id == MLAN_IOCTL_SCAN) {
+ PRINTM(MIOCTL, "wlan_cancel_scan: current command\n");
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->cmd_flag |= CMD_F_CANCELED;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+ }
+ while ((pcmd_node = wlan_get_pending_scan_cmd(pmadapter)) != MNULL) {
+ PRINTM(MIOCTL,
+ "wlan_cancel_scan: find scan command in cmd_pending_q\n");
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ if (pmadapter->scan_processing &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ if (priv) {
+ if (MLAN_STATUS_FAILURE ==
+ wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN_EXT,
+ HostCmd_ACT_GEN_SET, 0, pioctl_req,
+ MNULL))
+ PRINTM(MERROR, "Failed to prepare command");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ status = MLAN_STATUS_PENDING;
+ }
+ } else
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ LEAVE();
+ return status;
+}
+#endif
+
+/**
+ * @brief Cancel all pending cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param flag MTRUE/MFALSE
+ *
+ * @return N/A
+ */
+t_void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter, t_u8 flag)
+{
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+#ifdef STA_SUPPORT
+ pmlan_private priv = MNULL;
+#endif
+ ENTER();
+ /* Cancel current cmd */
+ wlan_request_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ /* IOCTL will be completed, avoid calling IOCTL complete again from
+ * EVENT/CMDRESP */
+ if (pmadapter->pscan_ioctl_req) {
+ pioctl_buf = pmadapter->pscan_ioctl_req;
+ priv = pmadapter->priv[pioctl_buf->bss_index];
+ pmadapter->pscan_ioctl_req = MNULL;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+#endif
+ if (pmadapter->curr_cmd && flag) {
+ pcmd_node = pmadapter->curr_cmd;
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ pcmd_node->pioctl_buf = MNULL;
+ }
+ pmadapter->curr_cmd = MNULL;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+
+ /* Cancel all pending command */
+ while ((pcmd_node = (cmd_ctrl_node *)util_peek_list(
+ pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ MNULL, MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ if (pcmd_node->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ pcmd_node->pioctl_buf = MNULL;
+ }
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_release_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (pmadapter->scan_processing &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ if (priv) {
+ if (MLAN_STATUS_FAILURE ==
+ wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN_EXT,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ MNULL))
+ PRINTM(MERROR, "Failed to prepare command");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ } else
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+#endif
+ LEAVE();
+}
+
+/**
+ * @brief Cancel specific bss's pending ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_index BSS index
+ *
+ * @return N/A
+ */
+t_void wlan_cancel_bss_pending_cmd(pmlan_adapter pmadapter, t_u32 bss_index)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_ioctl_req *pioctl_buf = MNULL;
+#ifdef STA_SUPPORT
+ t_u8 flash_scan = MFALSE;
+#endif
+#ifdef STA_SUPPORT
+ pmlan_private priv = MNULL;
+#endif
+ ENTER();
+
+ PRINTM(MIOCTL, "MOAL Cancel BSS IOCTL: bss_index=%d\n", (int)bss_index);
+ wlan_request_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (pmadapter->pscan_ioctl_req &&
+ (pmadapter->pscan_ioctl_req->bss_index == bss_index)) {
+ /* IOCTL will be completed, avoid calling IOCTL complete again
+ * from EVENT/CMDRESP */
+ flash_scan = MTRUE;
+ pioctl_buf = pmadapter->pscan_ioctl_req;
+ priv = pmadapter->priv[pioctl_buf->bss_index];
+ pmadapter->pscan_ioctl_req = MNULL;
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+#endif
+ if (pmadapter->curr_cmd && pmadapter->curr_cmd->pioctl_buf) {
+ pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf;
+ if (pioctl_buf->bss_index == bss_index) {
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->cmd_flag |= CMD_F_CANCELED;
+#ifdef STA_SUPPORT
+ if (pioctl_buf->req_id == MLAN_IOCTL_SCAN)
+ flash_scan = MTRUE;
+#endif
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+ }
+ while ((pcmd_node = wlan_get_bss_pending_ioctl_cmd(
+ pmadapter, bss_index)) != MNULL) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf;
+ pcmd_node->pioctl_buf = MNULL;
+#ifdef STA_SUPPORT
+ if (pioctl_buf->req_id == MLAN_IOCTL_SCAN)
+ flash_scan = MTRUE;
+#endif
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_release_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (flash_scan) {
+ if (pmadapter->scan_processing &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ if (priv) {
+ if (MLAN_STATUS_FAILURE ==
+ wlan_prepare_cmd(
+ priv, HostCmd_CMD_802_11_SCAN_EXT,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ MNULL))
+ PRINTM(MERROR,
+ "failed to prepare command");
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ } else
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ }
+#endif
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Cancel pending ioctl cmd.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pioctl_req A pointer to mlan_ioctl_req buf
+ *
+ * @return N/A
+ */
+t_void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ t_u8 find = MFALSE;
+#ifdef STA_SUPPORT
+ pmlan_private priv = MNULL;
+#endif
+
+ ENTER();
+
+ PRINTM(MIOCTL, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n",
+ pioctl_req->req_id, *((t_u32 *)pioctl_req->pbuf),
+ (int)pioctl_req->action);
+
+ wlan_request_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ /* IOCTL will be completed, avoid calling IOCTL complete again from
+ * EVENT/CMDRESP */
+ if (pmadapter->pscan_ioctl_req == pioctl_req) {
+ priv = pmadapter->priv[pioctl_req->bss_index];
+ pmadapter->pscan_ioctl_req = MNULL;
+ find = MTRUE;
+ }
+#endif
+ if ((pmadapter->curr_cmd) &&
+ (pmadapter->curr_cmd->pioctl_buf == pioctl_req)) {
+ pcmd_node = pmadapter->curr_cmd;
+ pcmd_node->pioctl_buf = MNULL;
+ pcmd_node->cmd_flag |= CMD_F_CANCELED;
+ find = MTRUE;
+ }
+
+ while ((pcmd_node = wlan_get_pending_ioctl_cmd(pmadapter,
+ pioctl_req)) != MNULL) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ (pmlan_linked_list)pcmd_node, MNULL, MNULL);
+ pcmd_node->pioctl_buf = MNULL;
+ find = MTRUE;
+ wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
+ }
+ wlan_release_cmd_lock(pmadapter);
+#ifdef STA_SUPPORT
+ if (pioctl_req->req_id == MLAN_IOCTL_SCAN) {
+ if (pmadapter->scan_processing &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ if (priv) {
+ if (MLAN_STATUS_FAILURE ==
+ wlan_prepare_cmd(
+ priv, HostCmd_CMD_802_11_SCAN_EXT,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ MNULL))
+ PRINTM(MERROR,
+ "Failed to prepare command");
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ } else
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+ }
+#endif
+ if (find) {
+ pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function convert mlan_wifi_rate to wifi_rate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmlan_rate A pointer to mlan_wifi_rate structure
+ * @param prate A pointer to wifi_rate
+ *
+ * @return N/A
+ */
+t_void wlan_fill_hal_wifi_rate(pmlan_private pmpriv, mlan_wifi_rate *pmlan_rate,
+ wifi_rate *prate)
+{
+ t_u8 index = 0;
+ t_u8 rate_info = 0;
+
+ ENTER();
+
+ prate->preamble = pmlan_rate->preamble;
+ prate->nss = pmlan_rate->nss;
+ prate->bw = pmlan_rate->bw;
+ prate->rateMcsIdx = pmlan_rate->rateMcsIdx;
+ prate->reserved = 0;
+ prate->bitrate = wlan_le32_to_cpu(pmlan_rate->bitrate);
+
+ if (!prate->bitrate) {
+ index = prate->rateMcsIdx;
+ index |= prate->nss << 4;
+ if (prate->preamble == WIFI_PREAMBLE_HT)
+ rate_info = MLAN_RATE_FORMAT_HT;
+ else if (prate->preamble == WIFI_PREAMBLE_VHT)
+ rate_info = MLAN_RATE_FORMAT_VHT;
+ else
+ rate_info = MLAN_RATE_FORMAT_LG;
+ rate_info |= prate->bw << 2;
+ PRINTM(MCMND, "index=0x%x rate_info=0x%x\n", index, rate_info);
+ /** For rateMcsIdx, OFDM/CCK rate code would be as per ieee std
+ * in the units of 0.5mbps. HT/VHT it would be mcs index */
+ /** For bitrate, in 100kbps */
+ if (rate_info == MLAN_RATE_FORMAT_LG)
+ prate->bitrate = prate->rateMcsIdx * 5;
+ else
+ prate->bitrate =
+ wlan_index_to_data_rate(pmpriv->adapter, index,
+ rate_info, 0) *
+ 5;
+ PRINTM(MCMND, "bitrate(in 100kbps)=%d\n", prate->bitrate);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Handle the version_ext resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_ver_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_VERSION_EXT *ver_ext = &resp->params.verext;
+ mlan_ds_get_info *info;
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ info->param.ver_ext.version_str_sel = ver_ext->version_str_sel;
+ memcpy_ext(pmpriv->adapter, info->param.ver_ext.version_str,
+ ver_ext->version_str, sizeof(char) * 128,
+ sizeof(char) * MLAN_MAX_VER_STR_LEN);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the rx mgmt forward registration resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_rx_mgmt_ind(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ ENTER();
+
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc->param.mgmt_subtype_mask = wlan_le32_to_cpu(
+ resp->params.rx_mgmt_ind.mgmt_subtype_mask);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks conditions and prepares to
+ * send sleep confirm command to firmware if OK.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_check_ps_cond(mlan_adapter *pmadapter)
+{
+ ENTER();
+
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd &&
+ !pmadapter->keep_wakeup && !wlan_is_tx_pending(pmadapter) &&
+ !IS_CARD_RX_RCVD(pmadapter)) {
+ wlan_dnld_sleep_confirm_cmd(pmadapter);
+ } else {
+ PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s%s)\n",
+ (pmadapter->cmd_sent) ? "D" : "",
+ (pmadapter->curr_cmd) ? "C" : "",
+ (wlan_is_tx_pending(pmadapter)) ? "T" : "",
+ (IS_CARD_RX_RCVD(pmadapter)) ? "R" : "");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the HS_ACTIVATED event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param activated MTRUE if activated, MFALSE if de-activated
+ *
+ * @return N/A
+ */
+t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated)
+{
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return;
+ }
+
+ if (activated) {
+ if (priv->adapter->is_hs_configured) {
+ priv->adapter->hs_activated = MTRUE;
+ wlan_update_rxreorder_tbl(priv->adapter, MTRUE);
+ PRINTM(MEVENT, "hs_activated\n");
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED,
+ MNULL);
+ } else
+ PRINTM(MWARN, "hs_activated: HS not configured !!!\n");
+ } else {
+ PRINTM(MEVENT, "hs_deactived\n");
+ priv->adapter->hs_activated = MFALSE;
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sends the HS_WAKEUP event to the application
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_host_sleep_wakeup_event(pmlan_private priv)
+{
+ ENTER();
+
+ if (priv->adapter->is_hs_configured)
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL);
+ else
+ PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n");
+
+ LEAVE();
+}
+
+/**
+ * @brief This function handles the command response of hs_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_802_11_hs_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg;
+
+ ENTER();
+
+ phs_cfg->params.hs_config.conditions =
+ wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions);
+ phs_cfg->action = wlan_le16_to_cpu(phs_cfg->action);
+ PRINTM(MCMND,
+ "CMD_RESP: HS_CFG cmd reply result=%#x,"
+ " action=0x%x conditions=0x%x gpio=0x%x gap=0x%x\n",
+ resp->result, phs_cfg->action,
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap);
+ if ((phs_cfg->action == HS_ACTIVATE &&
+ !pmadapter->pcard_info->supp_ps_handshake) ||
+ pmadapter->pcard_info->supp_ps_handshake) {
+ /* clean up curr_cmd to allow suspend */
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;
+ /* Clean up and put current command back to cmd_free_q */
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+ if (!pmadapter->pcard_info->supp_ps_handshake) {
+ wlan_host_sleep_activated_event(pmpriv, MTRUE);
+ goto done;
+ }
+ }
+ if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) {
+ pmadapter->is_hs_configured = MTRUE;
+ if (pmadapter->pcard_info->supp_ps_handshake)
+ wlan_host_sleep_activated_event(pmpriv, MTRUE);
+ } else {
+ pmadapter->is_hs_configured = MFALSE;
+ if (pmadapter->hs_activated)
+ wlan_host_sleep_activated_event(pmpriv, MFALSE);
+ }
+
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Perform hs related activities on receiving the power up interrupt
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @return N/A
+ */
+t_void wlan_process_hs_config(pmlan_adapter pmadapter)
+{
+ ENTER();
+ PRINTM(MINFO, "Recevie interrupt/data in HS mode\n");
+ if (pmadapter->hs_cfg.gap == HOST_SLEEP_CFG_GAP_FF)
+ pmadapter->ops.wakeup_card(pmadapter, MTRUE);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Check sleep confirm command response and set the state to ASLEEP
+ *
+ * @param pmadapter A pointer to the adapter structure
+ * @param pbuf A pointer to the command response buffer
+ * @param upld_len Command response buffer length
+ * @return N/A
+ */
+void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 *pbuf,
+ t_u32 upld_len)
+{
+ HostCmd_DS_COMMAND *cmd;
+ pmlan_private pmpriv;
+
+ ENTER();
+
+ if (!upld_len) {
+ PRINTM(MERROR, "Command size is 0\n");
+ LEAVE();
+ return;
+ }
+ cmd = (HostCmd_DS_COMMAND *)pbuf;
+ cmd->result = wlan_le16_to_cpu(cmd->result);
+ cmd->command = wlan_le16_to_cpu(cmd->command);
+ cmd->seq_num = wlan_le16_to_cpu(cmd->seq_num);
+
+ pmpriv =
+ wlan_get_priv_by_id(pmadapter, HostCmd_GET_BSS_NO(cmd->seq_num),
+ HostCmd_GET_BSS_TYPE(cmd->seq_num));
+ /* Update sequence number */
+ cmd->seq_num = HostCmd_GET_SEQ_NO(cmd->seq_num);
+ /* Clear RET_BIT from HostCmd */
+ cmd->command &= HostCmd_CMD_ID_MASK;
+ if (!pmpriv)
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+ PRINTM(MERROR,
+ "Received unexpected response for command %x, result = %x\n",
+ cmd->command, cmd->result);
+ LEAVE();
+ return;
+ }
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "#\n");
+ if (cmd->result != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Sleep confirm command failed\n");
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ LEAVE();
+ return;
+ }
+ pmadapter->pm_wakeup_card_req = MTRUE;
+
+ if (pmadapter->is_hs_configured) {
+ wlan_host_sleep_activated_event(
+ wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), MTRUE);
+ }
+ pmadapter->ps_state = PS_STATE_SLEEP;
+ LEAVE();
+}
+
+/**
+ * @brief This function prepares command of power mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param ps_bitmap PS bitmap
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_u16 ps_bitmap, t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_PS_MODE_ENH *psmode_enh = &cmd->params.psmode_enh;
+ t_u8 *tlv = MNULL;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "PS Command: action = 0x%x, bitmap = 0x%x\n", cmd_action,
+ ps_bitmap);
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ if (cmd_action == DIS_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(DIS_AUTO_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == GET_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(GET_PS);
+ psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
+ } else if (cmd_action == EN_AUTO_PS) {
+ psmode_enh->action = wlan_cpu_to_le16(EN_AUTO_PS);
+ psmode_enh->params.auto_ps.ps_bitmap =
+ wlan_cpu_to_le16(ps_bitmap);
+ cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE;
+ tlv = (t_u8 *)cmd + cmd_size;
+ if (ps_bitmap & BITMAP_STA_PS) {
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypes_ps_param_t *ps_tlv =
+ (MrvlIEtypes_ps_param_t *)tlv;
+ ps_param *ps_mode = &ps_tlv->param;
+ ps_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PS_PARAM);
+ ps_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_ps_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_ps_param_t);
+ tlv += sizeof(MrvlIEtypes_ps_param_t);
+ ps_mode->null_pkt_interval =
+ wlan_cpu_to_le16(pmadapter->null_pkt_interval);
+ ps_mode->multiple_dtims =
+ wlan_cpu_to_le16(pmadapter->multiple_dtim);
+ ps_mode->bcn_miss_timeout =
+ wlan_cpu_to_le16(pmadapter->bcn_miss_time_out);
+ ps_mode->local_listen_interval = wlan_cpu_to_le16(
+ pmadapter->local_listen_interval);
+ ps_mode->delay_to_ps =
+ wlan_cpu_to_le16(pmadapter->delay_to_ps);
+ ps_mode->mode =
+ wlan_cpu_to_le16(pmadapter->enhanced_ps_mode);
+ }
+ if (ps_bitmap & BITMAP_BCN_TMO) {
+ MrvlIEtypes_bcn_timeout_t *bcn_tmo_tlv =
+ (MrvlIEtypes_bcn_timeout_t *)tlv;
+ mlan_ds_bcn_timeout *bcn_tmo =
+ (mlan_ds_bcn_timeout *)pdata_buf;
+ bcn_tmo_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_BCN_TIMEOUT);
+ bcn_tmo_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_bcn_timeout_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ bcn_tmo_tlv->bcn_miss_tmo_window =
+ wlan_cpu_to_le16(bcn_tmo->bcn_miss_tmo_window);
+ bcn_tmo_tlv->bcn_miss_tmo_period =
+ wlan_cpu_to_le16(bcn_tmo->bcn_miss_tmo_period);
+ bcn_tmo_tlv->bcn_rq_tmo_window =
+ wlan_cpu_to_le16(bcn_tmo->bcn_rq_tmo_window);
+ bcn_tmo_tlv->bcn_rq_tmo_period =
+ wlan_cpu_to_le16(bcn_tmo->bcn_rq_tmo_period);
+ cmd_size += sizeof(MrvlIEtypes_bcn_timeout_t);
+ tlv += sizeof(MrvlIEtypes_bcn_timeout_t);
+
+ psmode_enh->params.auto_ps.ps_bitmap = wlan_cpu_to_le16(
+ (ps_bitmap & (~BITMAP_BCN_TMO)) |
+ BITMAP_STA_PS);
+ }
+ if (ps_bitmap & BITMAP_AUTO_DS) {
+ MrvlIEtypes_auto_ds_param_t *auto_ps_tlv =
+ (MrvlIEtypes_auto_ds_param_t *)tlv;
+ auto_ds_param *auto_ds = &auto_ps_tlv->param;
+ t_u16 idletime = 0;
+ auto_ps_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
+ auto_ps_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_auto_ds_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd_size += sizeof(MrvlIEtypes_auto_ds_param_t);
+ tlv += sizeof(MrvlIEtypes_auto_ds_param_t);
+ if (pdata_buf)
+ idletime =
+ ((mlan_ds_auto_ds *)pdata_buf)->idletime;
+ auto_ds->deep_sleep_timeout =
+ wlan_cpu_to_le16(idletime);
+ }
+#if defined(UAP_SUPPORT)
+ if (pdata_buf &&
+ (ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS))) {
+ mlan_ds_ps_mgmt *ps_mgmt = (mlan_ds_ps_mgmt *)pdata_buf;
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL;
+ if (ps_mgmt->flags & PS_FLAG_SLEEP_PARAM) {
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *)tlv;
+ sleep_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_AP_SLEEP_PARAM);
+ sleep_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_sleep_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ sleep_tlv->ctrl_bitmap = wlan_cpu_to_le32(
+ ps_mgmt->sleep_param.ctrl_bitmap);
+ sleep_tlv->min_sleep = wlan_cpu_to_le32(
+ ps_mgmt->sleep_param.min_sleep);
+ sleep_tlv->max_sleep = wlan_cpu_to_le32(
+ ps_mgmt->sleep_param.max_sleep);
+ cmd_size += sizeof(MrvlIEtypes_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_sleep_param_t);
+ }
+ if (ps_mgmt->flags & PS_FLAG_INACT_SLEEP_PARAM) {
+ inact_tlv =
+ (MrvlIEtypes_inact_sleep_param_t *)tlv;
+ inact_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_AP_INACT_SLEEP_PARAM);
+ inact_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_inact_sleep_param_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ inact_tlv->inactivity_to = wlan_cpu_to_le32(
+ ps_mgmt->inact_param.inactivity_to);
+ inact_tlv->min_awake = wlan_cpu_to_le32(
+ ps_mgmt->inact_param.min_awake);
+ inact_tlv->max_awake = wlan_cpu_to_le32(
+ ps_mgmt->inact_param.max_awake);
+ cmd_size +=
+ sizeof(MrvlIEtypes_inact_sleep_param_t);
+ tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
+ }
+ }
+#endif
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ps_mode_enh
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_enh_power_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ MrvlIEtypesHeader_t *mrvl_tlv = MNULL;
+ MrvlIEtypes_auto_ds_param_t *auto_ds_tlv = MNULL;
+ HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = &resp->params.psmode_enh;
+
+ ENTER();
+
+ ps_mode->action = wlan_le16_to_cpu(ps_mode->action);
+ PRINTM(MINFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, ps_mode->action);
+ if (ps_mode->action == EN_AUTO_PS) {
+ ps_mode->params.auto_ps.ps_bitmap =
+ wlan_le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap);
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) {
+ PRINTM(MCMND, "Enabled auto deep sleep\n");
+ pmpriv->adapter->is_deep_sleep = MTRUE;
+ mrvl_tlv = (MrvlIEtypesHeader_t *)((t_u8 *)ps_mode +
+ AUTO_PS_FIX_SIZE);
+ while (wlan_le16_to_cpu(mrvl_tlv->type) !=
+ TLV_TYPE_AUTO_DS_PARAM) {
+ mrvl_tlv =
+ (MrvlIEtypesHeader_t
+ *)((t_u8 *)mrvl_tlv +
+ wlan_le16_to_cpu(
+ mrvl_tlv->len) +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ auto_ds_tlv = (MrvlIEtypes_auto_ds_param_t *)mrvl_tlv;
+ pmpriv->adapter->idle_time = wlan_le16_to_cpu(
+ auto_ds_tlv->param.deep_sleep_timeout);
+ }
+ if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Enabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ PRINTM(MCMND,
+ "Setting uapsd/pps mode to TRUE\n");
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.auto_ps.ps_bitmap &
+ (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ PRINTM(MCMND, "Enabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == DIS_AUTO_PS) {
+ ps_mode->params.ps_bitmap =
+ wlan_cpu_to_le16(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) {
+ pmpriv->adapter->is_deep_sleep = MFALSE;
+ PRINTM(MCMND, "Disabled auto deep sleep\n");
+ }
+ if (ps_mode->params.ps_bitmap & BITMAP_STA_PS) {
+ PRINTM(MCMND, "Disabled STA power save\n");
+ if (pmadapter->sleep_period.period) {
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ }
+ }
+#if defined(UAP_SUPPORT)
+ if (ps_mode->params.ps_bitmap &
+ (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) {
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "Disabled uAP power save\n");
+ }
+#endif
+ } else if (ps_mode->action == GET_PS) {
+ ps_mode->params.ps_bitmap =
+ wlan_le16_to_cpu(ps_mode->params.ps_bitmap);
+ if (ps_mode->params.auto_ps.ps_bitmap &
+ (BITMAP_STA_PS | BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS))
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ PRINTM(MCMND, "ps_bitmap=0x%x\n", ps_mode->params.ps_bitmap);
+ if (pioctl_buf) {
+ mlan_ds_pm_cfg *pm_cfg =
+ (mlan_ds_pm_cfg *)pioctl_buf->pbuf;
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_IEEE_PS) {
+ if (ps_mode->params.auto_ps.ps_bitmap &
+ BITMAP_STA_PS)
+ pm_cfg->param.ps_mode = 1;
+ else
+ pm_cfg->param.ps_mode = 0;
+ }
+#if defined(UAP_SUPPORT)
+ if (pm_cfg->sub_command == MLAN_OID_PM_CFG_PS_MODE) {
+ MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL;
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv =
+ MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ t_u16 tlv_buf_left = 0;
+ pm_cfg->param.ps_mgmt.flags = PS_FLAG_PS_MODE;
+ if (ps_mode->params.ps_bitmap &
+ BITMAP_UAP_INACT_PS)
+ pm_cfg->param.ps_mgmt.ps_mode =
+ PS_MODE_INACTIVITY;
+ else if (ps_mode->params.ps_bitmap &
+ BITMAP_UAP_DTIM_PS)
+ pm_cfg->param.ps_mgmt.ps_mode =
+ PS_MODE_PERIODIC_DTIM;
+ else
+ pm_cfg->param.ps_mgmt.ps_mode =
+ PS_MODE_DISABLE;
+ tlv_buf_left = resp->size -
+ (S_DS_GEN + AUTO_PS_FIX_SIZE);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)ps_mode +
+ AUTO_PS_FIX_SIZE);
+ while (tlv_buf_left >=
+ sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ switch (tlv_type) {
+ case TLV_TYPE_AP_SLEEP_PARAM:
+ sleep_tlv =
+ (MrvlIEtypes_sleep_param_t
+ *)tlv;
+ pm_cfg->param.ps_mgmt.flags |=
+ PS_FLAG_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt
+ .sleep_param
+ .ctrl_bitmap = wlan_le32_to_cpu(
+ sleep_tlv->ctrl_bitmap);
+ pm_cfg->param.ps_mgmt
+ .sleep_param
+ .min_sleep = wlan_le32_to_cpu(
+ sleep_tlv->min_sleep);
+ pm_cfg->param.ps_mgmt
+ .sleep_param
+ .max_sleep = wlan_le32_to_cpu(
+ sleep_tlv->max_sleep);
+ break;
+ case TLV_TYPE_AP_INACT_SLEEP_PARAM:
+ inact_tlv =
+ (MrvlIEtypes_inact_sleep_param_t
+ *)tlv;
+ pm_cfg->param.ps_mgmt.flags |=
+ PS_FLAG_INACT_SLEEP_PARAM;
+ pm_cfg->param.ps_mgmt
+ .inact_param
+ .inactivity_to = wlan_le32_to_cpu(
+ inact_tlv->inactivity_to);
+ pm_cfg->param.ps_mgmt
+ .inact_param
+ .min_awake = wlan_le32_to_cpu(
+ inact_tlv->min_awake);
+ pm_cfg->param.ps_mgmt
+ .inact_param
+ .max_awake = wlan_le32_to_cpu(
+ inact_tlv->max_awake);
+ break;
+ }
+ tlv_buf_left -=
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t
+ *)((t_u8 *)tlv +
+ tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+#endif
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx rate query
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_802_11_tx_rate_query(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *rate = MNULL;
+ ENTER();
+
+ pmpriv->tx_rate = resp->params.tx_rate.tx_rate;
+ pmpriv->tx_rate_info = resp->params.tx_rate.tx_rate_info;
+ if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE)
+ pmpriv->ext_tx_rate_info =
+ resp->params.tx_rate.ext_tx_rate_info;
+ else
+ pmpriv->ext_tx_rate_info = 0;
+
+ if (!pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate =
+ wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_rate_info,
+ pmpriv->ext_tx_rate_info);
+ }
+
+ if (pioctl_buf) {
+ rate = (mlan_ds_rate *)pioctl_buf->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG) {
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
+ if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_VHT ||
+ ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE))
+
+ /* VHT rate */
+ rate->param.rate_cfg.rate =
+ (pmpriv->tx_rate) & 0xF;
+ else if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HT)
+ /* HT rate */
+ rate->param.rate_cfg.rate =
+ pmpriv->tx_rate +
+ MLAN_RATE_INDEX_MCS0;
+ else
+ /* LG rate */
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY,
+ * there is a hole (0x4) in rate table
+ * between HR/DSSS and OFDM rates,
+ * so minus 1 for OFDM rate index */
+ rate->param.rate_cfg.rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ?
+ pmpriv->tx_rate - 1 :
+ pmpriv->tx_rate;
+ } else {
+ /* rate_type = MLAN_RATE_VALUE */
+ rate->param.rate_cfg.rate =
+ wlan_index_to_data_rate(
+ pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_rate_info,
+ pmpriv->ext_tx_rate_info);
+ }
+ } else if (rate->sub_command == MLAN_OID_GET_DATA_RATE) {
+ /* Tx rate info */
+ if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_VHT ||
+ (pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE) {
+ /* AX/VHT rate */
+ rate->param.data_rate.tx_rate_format =
+ pmpriv->tx_rate_info & 0x3;
+ rate->param.data_rate.tx_ht_bw =
+ (pmpriv->tx_rate_info & 0xC) >> 2;
+ if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE)
+ rate->param.data_rate.tx_ht_gi =
+ (pmpriv->tx_rate_info & 0x10) >>
+ 4 |
+ (pmpriv->tx_rate_info & 0x80) >>
+ 6;
+ else
+ rate->param.data_rate.tx_ht_gi =
+ (pmpriv->tx_rate_info & 0x10) >>
+ 4;
+ rate->param.data_rate.tx_nss =
+ ((pmpriv->tx_rate) >> 4) & 0x03;
+ rate->param.data_rate.tx_mcs_index =
+ (pmpriv->tx_rate) & 0xF;
+ if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_VHT ||
+ (pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE)
+ rate->param.data_rate.tx_data_rate =
+ wlan_index_to_data_rate(
+ pmadapter,
+ pmpriv->tx_rate,
+ pmpriv->tx_rate_info,
+ pmpriv->ext_tx_rate_info);
+ } else if ((pmpriv->tx_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HT) {
+ /* HT rate */
+ rate->param.data_rate.tx_rate_format =
+ MLAN_RATE_FORMAT_HT;
+ rate->param.data_rate.tx_ht_bw =
+ (pmpriv->tx_rate_info & 0xC) >> 2;
+
+ rate->param.data_rate.tx_ht_gi =
+ (pmpriv->tx_rate_info & 0x10) >> 4;
+ rate->param.data_rate.tx_mcs_index =
+ pmpriv->tx_rate;
+ rate->param.data_rate.tx_data_rate =
+ wlan_index_to_data_rate(
+ pmadapter, pmpriv->tx_rate,
+ pmpriv->tx_rate_info,
+ pmpriv->ext_tx_rate_info);
+ } else {
+ /* LG rate */
+ rate->param.data_rate.tx_rate_format =
+ MLAN_RATE_FORMAT_LG;
+ /* For HostCmd_CMD_802_11_TX_RATE_QUERY,
+ * there is a hole in rate table
+ * between HR/DSSS and OFDM rates,
+ * so minus 1 for OFDM rate index */
+ rate->param.data_rate.tx_data_rate =
+ (pmpriv->tx_rate >
+ MLAN_RATE_INDEX_OFDM0) ?
+ pmpriv->tx_rate - 1 :
+ pmpriv->tx_rate;
+ }
+
+ /* Rx rate info */
+ if ((pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_VHT ||
+ (pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE) {
+ /* VHT rate */
+ rate->param.data_rate.rx_rate_format =
+ pmpriv->rxpd_rate_info & 0x3;
+ rate->param.data_rate.rx_ht_bw =
+ (pmpriv->rxpd_rate_info & 0xC) >> 2;
+ if ((pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE)
+ rate->param.data_rate.rx_ht_gi =
+ (pmpriv->rxpd_rate_info &
+ 0x10) >>
+ 4 |
+ (pmpriv->rxpd_rate_info &
+ 0x80) >>
+ 6;
+ else
+ rate->param.data_rate.rx_ht_gi =
+ (pmpriv->rxpd_rate_info &
+ 0x10) >>
+ 4;
+ rate->param.data_rate.rx_nss =
+ ((pmpriv->rxpd_rate) >> 4) & 0x3;
+ rate->param.data_rate.rx_mcs_index =
+ (pmpriv->rxpd_rate) & 0xF;
+ if ((pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_VHT ||
+ (pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HE)
+ rate->param.data_rate.rx_data_rate =
+ wlan_index_to_data_rate(
+ pmadapter,
+ pmpriv->rxpd_rate,
+ pmpriv->rxpd_rate_info,
+ pmpriv->rxpd_rx_info);
+ } else if ((pmpriv->rxpd_rate_info & 0x3) ==
+ MLAN_RATE_FORMAT_HT) {
+ /* HT rate */
+ rate->param.data_rate.rx_rate_format =
+ MLAN_RATE_FORMAT_HT;
+ rate->param.data_rate.rx_ht_bw =
+ (pmpriv->rxpd_rate_info & 0xC) >> 2;
+ rate->param.data_rate.rx_ht_gi =
+ (pmpriv->rxpd_rate_info & 0x10) >> 4;
+ rate->param.data_rate.rx_mcs_index =
+ pmpriv->rxpd_rate;
+ rate->param.data_rate.rx_data_rate =
+ wlan_index_to_data_rate(
+ pmadapter, pmpriv->rxpd_rate,
+ pmpriv->rxpd_rate_info, 0);
+ } else {
+ /* LG rate */
+ rate->param.data_rate.rx_rate_format =
+ MLAN_RATE_FORMAT_LG;
+ /* For rate index in RxPD,
+ * there is a hole in rate table
+ * between HR/DSSS and OFDM rates,
+ * so minus 1 for OFDM rate index */
+ rate->param.data_rate.rx_data_rate =
+ (pmpriv->rxpd_rate >
+ MLAN_RATE_INDEX_OFDM0) ?
+ pmpriv->rxpd_rate - 1 :
+ pmpriv->rxpd_rate;
+ }
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_data_rate) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of robustcoex.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_robustcoex(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf)
+{
+ HostCmd_DS_802_11_ROBUSTCOEX *rbstcx = &cmd->params.robustcoexparams;
+ mlan_ds_misc_robustcoex_params *robustcoex_params = MNULL;
+ MrvlIEtypes_RobustcoexSourceGPIO_t *tlv =
+ (MrvlIEtypes_RobustcoexSourceGPIO_t *)(rbstcx->tlv_buf);
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ROBUSTCOEX);
+ cmd->size = sizeof(HostCmd_DS_802_11_ROBUSTCOEX) + S_DS_GEN;
+ rbstcx->action = wlan_cpu_to_le16(cmd_action);
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ robustcoex_params = (mlan_ds_misc_robustcoex_params *)pdata_buf;
+ if (robustcoex_params->method == ROBUSTCOEX_GPIO_CFG) {
+ cmd->size += sizeof(MrvlIEtypes_RobustcoexSourceGPIO_t);
+ tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_ROBUSTCOEX);
+ tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_RobustcoexSourceGPIO_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv->enable = (t_u8)robustcoex_params->enable;
+ tlv->gpio_num = (t_u8)robustcoex_params->gpio_num;
+ tlv->gpio_polarity =
+ (t_u8)robustcoex_params->gpio_polarity;
+ }
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(PCIE)
+/**
+ * @brief This function enables SSU support.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_ssu(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf)
+{
+ HostCmd_DS_SSU_CFG *ssu_cfg_cmd = &cmd->params.ssu_params;
+ mlan_ds_ssu_params *ssu_params = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SSU);
+ cmd->size = sizeof(HostCmd_DS_SSU_CFG) + S_DS_GEN;
+ ssu_cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ case HostCmd_ACT_GEN_SET_DEFAULT:
+ ssu_params = (mlan_ds_ssu_params *)pdata_buf;
+ ssu_cfg_cmd->nskip = wlan_cpu_to_le32(ssu_params->nskip);
+ ssu_cfg_cmd->nsel = wlan_cpu_to_le32(ssu_params->nsel);
+ ssu_cfg_cmd->adcdownsample =
+ wlan_cpu_to_le32(ssu_params->adcdownsample);
+ ssu_cfg_cmd->mask_adc_pkt =
+ wlan_cpu_to_le32(ssu_params->mask_adc_pkt);
+ ssu_cfg_cmd->out_16bits =
+ wlan_cpu_to_le32(ssu_params->out_16bits);
+ ssu_cfg_cmd->spec_pwr_enable =
+ wlan_cpu_to_le32(ssu_params->spec_pwr_enable);
+ ssu_cfg_cmd->rate_deduction =
+ wlan_cpu_to_le32(ssu_params->rate_deduction);
+ ssu_cfg_cmd->n_pkt_avg =
+ wlan_cpu_to_le32(ssu_params->n_pkt_avg);
+ /* Initialize PCIE ring buffer */
+ ret = wlan_alloc_ssu_pcie_buf(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ PRINTM(MERROR,
+ "Failed to allocate PCIE host buffers for SSU\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ssu_cfg_cmd->buffer_base_addr[0] =
+ wlan_cpu_to_le32((t_u32)pmadapter->ssu_buf->buf_pa);
+ ssu_cfg_cmd->buffer_base_addr[1] = wlan_cpu_to_le32(
+ (t_u32)((t_u64)(pmadapter->ssu_buf->buf_pa >> 32)));
+ ssu_cfg_cmd->buffer_pool_size =
+ wlan_cpu_to_le32(MLAN_SSU_BUF_SIZE);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function prepares command of dmcs config.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_DMCS_CFG *dmcs = &cmd->params.dmcs;
+ mlan_ds_misc_mapping_policy *dmcs_params = MNULL;
+ t_u8 *mapping_policy = (t_u8 *)dmcs->tlv_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DMCS_CONFIG);
+ cmd->size = sizeof(HostCmd_DS_DMCS_CFG) + S_DS_GEN;
+ dmcs->action = wlan_cpu_to_le16(cmd_action);
+ dmcs_params = (mlan_ds_misc_mapping_policy *)pdata_buf;
+ dmcs->subcmd = wlan_cpu_to_le16(dmcs_params->subcmd);
+ switch (dmcs->subcmd) {
+ case 0:
+ cmd->size += sizeof(t_u8);
+ *mapping_policy = dmcs_params->mapping_policy;
+ break;
+ case 1:
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of dmcs config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_DMCS_CFG *dmcs = &resp->params.dmcs;
+ MrvlIEtypes_DmcsStatus_t *dmcs_status;
+ mlan_ds_misc_cfg *cfg = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0, tlv_len = 0;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ int i = 0;
+
+ ENTER();
+ if (pioctl_buf) {
+ cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)dmcs +
+ sizeof(HostCmd_DS_DMCS_CFG));
+ tlv_buf_left =
+ resp->size - (sizeof(HostCmd_DS_DMCS_CFG) + S_DS_GEN);
+ while (tlv_buf_left > sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if (tlv_buf_left <
+ (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error while processing DMCS status tlv, bytes_left < TLV len\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_DMCS_STATUS:
+ dmcs_status = (MrvlIEtypes_DmcsStatus_t *)tlv;
+ cfg->param.dmcs_status.mapping_policy =
+ dmcs_status->mapping_policy;
+ memset(pmpriv->adapter,
+ &cfg->param.dmcs_status.radio_status, 0,
+ sizeof(dmcsStatus_t));
+ for (i = 0; i < MAX_NUM_MAC; i++) {
+ memcpy_ext(
+ pmpriv->adapter,
+ &cfg->param.dmcs_status
+ .radio_status[i],
+ &dmcs_status->radio_status[i],
+ sizeof(dmcsStatus_t),
+ sizeof(dmcsStatus_t));
+ }
+ break;
+ default:
+ break;
+ }
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t
+ *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_misc_dmcs_status);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of tx_rate_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @param pioctl_buf A pointer to ioctl buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_TX_RATE_CFG *rate_cfg =
+ (HostCmd_DS_TX_RATE_CFG *)&(cmd->params.tx_rate_cfg);
+ MrvlRateScope_t *rate_scope;
+ MrvlRateDropPattern_t *rate_drop;
+ MrvlIETypes_rate_setting_t *rate_setting_tlv;
+ mlan_ds_rate *ds_rate = MNULL;
+ t_u16 *pbitmap_rates = (t_u16 *)pdata_buf;
+
+ t_u32 i;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+ rate_cfg->action = wlan_cpu_to_le16(cmd_action);
+
+ rate_scope = (MrvlRateScope_t *)rate_cfg->tlv_buf;
+ rate_scope->type = wlan_cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+ rate_scope->length = wlan_cpu_to_le16(sizeof(MrvlRateScope_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (pbitmap_rates != MNULL) {
+ rate_scope->hr_dsss_rate_bitmap =
+ wlan_cpu_to_le16(pbitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ wlan_cpu_to_le16(pbitmap_rates[1]);
+ for (i = 0; i < NELEMENTS(rate_scope->ht_mcs_rate_bitmap); i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pbitmap_rates[2 + i]);
+ for (i = 0; i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap); i++)
+ rate_scope->vht_mcs_rate_bitmap[i] = wlan_cpu_to_le16(
+ pbitmap_rates
+ [2 +
+ NELEMENTS(
+ rate_scope->ht_mcs_rate_bitmap) +
+ i]);
+ if (IS_FW_SUPPORT_11AX(pmpriv->adapter)) {
+ for (i = 0;
+ i < NELEMENTS(rate_scope->he_mcs_rate_bitmap); i++)
+ rate_scope->he_mcs_rate_bitmap
+ [i] = wlan_cpu_to_le16(
+ pbitmap_rates
+ [2 +
+ NELEMENTS(
+ rate_scope
+ ->ht_mcs_rate_bitmap) +
+ NELEMENTS(
+ rate_scope
+ ->vht_mcs_rate_bitmap) +
+ i]);
+ } else {
+ rate_scope->length = wlan_cpu_to_le16(
+ sizeof(MrvlRateScope_t) -
+ sizeof(rate_scope->he_mcs_rate_bitmap) -
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ } else {
+ rate_scope->hr_dsss_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[1]);
+ for (i = 0; i < NELEMENTS(rate_scope->ht_mcs_rate_bitmap); i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ wlan_cpu_to_le16(pmpriv->bitmap_rates[2 + i]);
+ for (i = 0; i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap); i++)
+ rate_scope->vht_mcs_rate_bitmap[i] = wlan_cpu_to_le16(
+ pmpriv->bitmap_rates
+ [2 +
+ NELEMENTS(
+ rate_scope->ht_mcs_rate_bitmap) +
+ i]);
+ if (IS_FW_SUPPORT_11AX(pmpriv->adapter)) {
+ for (i = 0;
+ i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap);
+ i++)
+ rate_scope->he_mcs_rate_bitmap
+ [i] = wlan_cpu_to_le16(
+ pmpriv->bitmap_rates
+ [2 +
+ NELEMENTS(
+ rate_scope
+ ->ht_mcs_rate_bitmap) +
+ NELEMENTS(
+ rate_scope
+ ->vht_mcs_rate_bitmap) +
+ i]);
+ } else {
+ rate_scope->length = wlan_cpu_to_le16(
+ sizeof(MrvlRateScope_t) -
+ sizeof(rate_scope->he_mcs_rate_bitmap) -
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+
+ rate_drop =
+ (MrvlRateDropPattern_t *)((t_u8 *)rate_scope +
+ wlan_le16_to_cpu(rate_scope->length) +
+ sizeof(MrvlIEtypesHeader_t));
+ rate_drop->type = wlan_cpu_to_le16(TLV_TYPE_RATE_DROP_PATTERN);
+ rate_drop->length = wlan_cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+ rate_drop->rate_drop_mode = 0;
+
+ cmd->size = wlan_cpu_to_le16(
+ S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) + rate_scope->length +
+ sizeof(MrvlIEtypesHeader_t) + sizeof(MrvlRateDropPattern_t));
+ if (pioctl_buf && pmpriv->adapter->pcard_info->v17_fw_api) {
+ ds_rate = (mlan_ds_rate *)pioctl_buf->pbuf;
+ rate_setting_tlv = (MrvlIETypes_rate_setting_t
+ *)((t_u8 *)rate_drop +
+ sizeof(MrvlRateDropPattern_t));
+ rate_setting_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_TX_RATE_CFG);
+ rate_setting_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(rate_setting_tlv->rate_setting));
+ rate_setting_tlv->rate_setting =
+ wlan_cpu_to_le16(ds_rate->param.rate_cfg.rate_setting);
+ PRINTM(MCMND, "he rate setting = %d\n",
+ rate_setting_tlv->rate_setting);
+ cmd->size = wlan_cpu_to_le16(
+ S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) +
+ rate_scope->length + sizeof(MrvlIEtypesHeader_t) +
+ sizeof(MrvlRateDropPattern_t) +
+ sizeof(MrvlIETypes_rate_setting_t));
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_rate_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_rate *ds_rate = MNULL;
+ HostCmd_DS_TX_RATE_CFG *prate_cfg = MNULL;
+ MrvlRateScope_t *prate_scope;
+ MrvlIEtypesHeader_t *head = MNULL;
+ t_u16 tlv, tlv_buf_len = 0;
+ t_u8 *tlv_buf;
+ t_u32 i;
+ t_s32 index;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ MrvlIETypes_rate_setting_t *rate_setting_tlv = MNULL;
+ t_u16 rate_setting = 0xffff;
+
+ ENTER();
+
+ if (resp == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ prate_cfg = (HostCmd_DS_TX_RATE_CFG *)&(resp->params.tx_rate_cfg);
+
+ tlv_buf = (t_u8 *)prate_cfg->tlv_buf;
+ if (tlv_buf) {
+ tlv_buf_len = resp->size -
+ (sizeof(HostCmd_DS_TX_RATE_CFG) + S_DS_GEN);
+ tlv_buf_len = wlan_le16_to_cpu(tlv_buf_len);
+ }
+
+ while (tlv_buf && tlv_buf_len > 0) {
+ tlv = (*tlv_buf);
+ tlv = tlv | (*(tlv_buf + 1) << 8);
+
+ switch (tlv) {
+ case TLV_TYPE_RATE_SCOPE:
+ prate_scope = (MrvlRateScope_t *)tlv_buf;
+ pmpriv->bitmap_rates[0] = wlan_le16_to_cpu(
+ prate_scope->hr_dsss_rate_bitmap);
+ pmpriv->bitmap_rates[1] =
+ wlan_le16_to_cpu(prate_scope->ofdm_rate_bitmap);
+ for (i = 0;
+ i < NELEMENTS(prate_scope->ht_mcs_rate_bitmap);
+ i++)
+ pmpriv->bitmap_rates[2 + i] = wlan_le16_to_cpu(
+ prate_scope->ht_mcs_rate_bitmap[i]);
+ for (i = 0;
+ i < NELEMENTS(prate_scope->vht_mcs_rate_bitmap);
+ i++)
+ pmpriv->bitmap_rates
+ [2 +
+ sizeof(prate_scope->ht_mcs_rate_bitmap) /
+ sizeof(t_u16) +
+ i] =
+ wlan_le16_to_cpu(
+ prate_scope
+ ->vht_mcs_rate_bitmap[i]);
+ if (IS_FW_SUPPORT_11AX(pmadapter)) {
+ for (i = 0;
+ i <
+ NELEMENTS(prate_scope->he_mcs_rate_bitmap);
+ i++)
+ pmpriv->bitmap_rates
+ [2 +
+ sizeof(prate_scope
+ ->ht_mcs_rate_bitmap) /
+ sizeof(t_u16) +
+ sizeof(prate_scope
+ ->vht_mcs_rate_bitmap) /
+ sizeof(t_u16) +
+ i] =
+ wlan_le16_to_cpu(
+ prate_scope
+ ->he_mcs_rate_bitmap
+ [i]);
+ }
+ break;
+ case TLV_TYPE_TX_RATE_CFG:
+ rate_setting_tlv =
+ (MrvlIETypes_rate_setting_t *)tlv_buf;
+ rate_setting = rate_setting_tlv->rate_setting;
+ break;
+ /* Add RATE_DROP tlv here */
+ }
+
+ head = (MrvlIEtypesHeader_t *)tlv_buf;
+ head->len = wlan_le16_to_cpu(head->len);
+ tlv_buf += head->len + sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -= (head->len + sizeof(MrvlIEtypesHeader_t));
+ }
+
+ pmpriv->is_data_rate_auto = wlan_is_rate_auto(pmpriv);
+
+ if (pmpriv->is_data_rate_auto) {
+ pmpriv->data_rate = 0;
+ } else {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ }
+
+ if (pioctl_buf) {
+ ds_rate = (mlan_ds_rate *)pioctl_buf->pbuf;
+ if (ds_rate == MNULL) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmpriv->is_data_rate_auto) {
+ ds_rate->param.rate_cfg.is_rate_auto = MTRUE;
+ ds_rate->param.rate_cfg.rate_format =
+ MLAN_RATE_FORMAT_AUTO;
+ } else {
+ ds_rate->param.rate_cfg.is_rate_auto = MFALSE;
+ /* check the LG rate */
+ index = wlan_get_rate_index(
+ pmadapter, &pmpriv->bitmap_rates[0], 4);
+ if (index != -1) {
+ if ((index >= MLAN_RATE_BITMAP_OFDM0) &&
+ (index <= MLAN_RATE_BITMAP_OFDM7))
+ index -= (MLAN_RATE_BITMAP_OFDM0 -
+ MLAN_RATE_INDEX_OFDM0);
+ ds_rate->param.rate_cfg.rate_format =
+ MLAN_RATE_FORMAT_LG;
+ ds_rate->param.rate_cfg.rate = index;
+ }
+ /* check the HT rate */
+ index = wlan_get_rate_index(
+ pmadapter, &pmpriv->bitmap_rates[2], 16);
+ if (index != -1) {
+ ds_rate->param.rate_cfg.rate_format =
+ MLAN_RATE_FORMAT_HT;
+ ds_rate->param.rate_cfg.rate = index;
+ }
+ /* check the VHT rate */
+ index = wlan_get_rate_index(
+ pmadapter, &pmpriv->bitmap_rates[10], 16);
+ if (index != -1) {
+ ds_rate->param.rate_cfg.rate_format =
+ MLAN_RATE_FORMAT_VHT;
+ ds_rate->param.rate_cfg.rate = index % 16;
+ ds_rate->param.rate_cfg.nss = index / 16;
+ ds_rate->param.rate_cfg.nss += MLAN_RATE_NSS1;
+ }
+ /* check the HE rate */
+ if (IS_FW_SUPPORT_11AX(pmadapter)) {
+ index = wlan_get_rate_index(
+ pmadapter, &pmpriv->bitmap_rates[18],
+ 16);
+ if (index != -1) {
+ ds_rate->param.rate_cfg.rate_format =
+ MLAN_RATE_FORMAT_HE;
+ ds_rate->param.rate_cfg.rate =
+ index % 16;
+ ds_rate->param.rate_cfg.nss =
+ index / 16;
+ ds_rate->param.rate_cfg.nss +=
+ MLAN_RATE_NSS1;
+ }
+ }
+ ds_rate->param.rate_cfg.rate_setting = rate_setting;
+ PRINTM(MINFO, "Rate index is %d\n",
+ ds_rate->param.rate_cfg.rate);
+ }
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ ds_rate->param.rate_cfg.bitmap_rates[i] =
+ pmpriv->bitmap_rates[i];
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues adapter specific commands
+ * to initialize firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_adapter_get_hw_spec(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+#if defined(SDIO)
+ /*
+ * This should be issued in the very first to config
+ * SDIO_GPIO interrupt mode.
+ */
+ if (IS_SD(pmadapter->card_type) &&
+ (wlan_set_sdio_gpio_int(priv) != MLAN_STATUS_SUCCESS)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type) &&
+ (MLAN_STATUS_SUCCESS != wlan_set_pcie_buf_config(priv))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, HostCmd_ACT_GEN_SET,
+ 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** DPD data dnld cmd prepare */
+ if ((pmadapter->pdpd_data) && (pmadapter->dpd_data_len > 0)) {
+ ret = wlan_process_hostcmd_cfg(priv, CFG_TYPE_DPDFILE,
+ pmadapter->pdpd_data,
+ pmadapter->dpd_data_len);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pdpd_data = MNULL;
+ pmadapter->dpd_data_len = 0;
+ }
+ if ((pmadapter->ptxpwr_data) && (pmadapter->txpwr_data_len > 0)) {
+ ret = wlan_process_hostcmd_cfg(priv, CFG_TYPE_HOSTCMD,
+ pmadapter->ptxpwr_data,
+ pmadapter->txpwr_data_len);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->ptxpwr_data = MNULL;
+ pmadapter->txpwr_data_len = 0;
+ }
+ if (!pmadapter->pdpd_data &&
+ (pmadapter->dpd_data_len == UNKNOW_DPD_LENGTH)) {
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_GET, OID_TYPE_DPD, MNULL,
+ MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /** Cal data dnld cmd prepare */
+ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) {
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_SET, OID_TYPE_CAL, MNULL,
+ MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcal_data = MNULL;
+ pmadapter->cal_data_len = 0;
+ }
+ /* Get FW region and cfp tables */
+ if (pmadapter->init_para.fw_region) {
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /*
+ * Get HW spec
+ */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_PENDING;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues adapter specific commands
+ * to initialize firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_adapter_init_cmd(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = MNULL;
+#ifdef STA_SUPPORT
+ pmlan_private pmpriv_sta = MNULL;
+#endif
+ ENTER();
+
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+#ifdef STA_SUPPORT
+ pmpriv_sta = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA);
+#endif
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ }
+#endif
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmadapter->max_tx_buf_size);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+#if defined(STA_SUPPORT)
+ if (pmpriv_sta &&
+ (pmpriv_sta->state_11d.user_enable_11d == ENABLE_11D)) {
+ /* Send command to FW to enable 11d */
+ ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i, MNULL,
+ &pmpriv_sta->state_11d.user_enable_11d);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+#ifdef STA_SUPPORT
+ if (pmpriv_sta && (pmadapter->ps_mode == Wlan802_11PowerModePSP)) {
+ ret = wlan_prepare_cmd(pmpriv_sta,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+
+ if (pmadapter->init_auto_ds) {
+ mlan_ds_auto_ds auto_ds;
+ /* Enable auto deep sleep */
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_AUTO_DS, MNULL,
+ &auto_ds);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ if (pmadapter->init_para.indrstcfg != 0xffffffff) {
+ mlan_ds_ind_rst_cfg ind_rst_cfg;
+ ind_rst_cfg.ir_mode = pmadapter->init_para.indrstcfg & 0xff;
+ ind_rst_cfg.gpio_pin =
+ (pmadapter->init_para.indrstcfg & 0xff00) >> 8;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_INDEPENDENT_RESET_CFG,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ (t_void *)&ind_rst_cfg);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ if (pmadapter->inact_tmo) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmadapter->inact_tmo);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_PENDING;
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef RX_PACKET_COALESCE
+mlan_status wlan_cmd_rx_pkt_coalesce_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ mlan_ds_misc_rx_packet_coalesce *rx_pkt_cfg =
+ (mlan_ds_misc_rx_packet_coalesce *)pdata_buf;
+ HostCmd_DS_RX_PKT_COAL_CFG *prx_coal_cfg =
+ (HostCmd_DS_RX_PKT_COAL_CFG *)&cmd->params.rx_pkt_coal_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RX_PKT_COALESCE_CFG);
+ prx_coal_cfg->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ prx_coal_cfg->packet_threshold =
+ wlan_cpu_to_le32(rx_pkt_cfg->packet_threshold);
+ prx_coal_cfg->delay = wlan_cpu_to_le16(rx_pkt_cfg->delay);
+ PRINTM(MCMND,
+ "Set RX coal config: packet threshold=%d delay=%d\n",
+ rx_pkt_cfg->packet_threshold, rx_pkt_cfg->delay);
+ cmd->size = wlan_cpu_to_le16(
+ S_DS_GEN + sizeof(HostCmd_DS_RX_PKT_COAL_CFG));
+ } else {
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(cmd_action));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of RX_PACKET_COAL_CFG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_rx_pkt_coalesce_cfg(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *pcfg = MNULL;
+ const HostCmd_DS_RX_PKT_COAL_CFG *presp_cfg =
+ &resp->params.rx_pkt_coal_cfg;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ pcfg->param.rx_coalesce.packet_threshold =
+ wlan_le32_to_cpu(presp_cfg->packet_threshold);
+ pcfg->param.rx_coalesce.delay =
+ wlan_le16_to_cpu(presp_cfg->delay);
+ PRINTM(MCMND,
+ "Get rx pkt coalesce info: packet threshold=%d delay=%d\n",
+ pcfg->param.rx_coalesce.packet_threshold,
+ pcfg->param.rx_coalesce.delay);
+ pioctl_buf->buf_len = sizeof(mlan_ds_misc_rx_packet_coalesce);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#endif
+
+/**
+ * @brief This function download the vdll block.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param block A pointer to VDLL block
+ * @param block_len The VDLL block length
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_download_vdll_block(mlan_adapter *pmadapter, t_u8 *block,
+ t_u16 block_len)
+{
+ mlan_status status = MLAN_STATUS_FAILURE;
+ mlan_status ret = MLAN_STATUS_PENDING;
+#if defined(SDIO) || defined(PCIE)
+ pvdll_dnld_ctrl ctrl = &pmadapter->vdll_ctrl;
+#endif
+ mlan_buffer *pmbuf = MNULL;
+ mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ HostCmd_DS_GEN *cmd_hdr = MNULL;
+ t_u16 msg_len = block_len + sizeof(HostCmd_DS_GEN);
+#ifdef USB
+ t_u32 tmp;
+#endif
+ ENTER();
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ pmbuf = ctrl->cmd_buf;
+ if (pmbuf)
+ pmbuf->data_offset += pmadapter->ops.intf_header_len;
+ }
+#endif
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter,
+ MRVDRV_SIZE_OF_CMD_BUFFER, 0,
+ MOAL_MALLOC_BUFFER);
+ if (pmbuf) {
+ tmp = wlan_cpu_to_le32(MLAN_USB_TYPE_VDLL);
+ memcpy_ext(pmadapter,
+ (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset),
+ (t_u8 *)&tmp, MLAN_TYPE_LEN, MLAN_TYPE_LEN);
+ pmbuf->data_offset += MLAN_TYPE_LEN;
+ }
+ }
+#endif
+ if (!pmbuf) {
+ PRINTM(MERROR, "dnld vdll: Fail to alloc vdll buf");
+ goto done;
+ }
+ cmd_hdr = (HostCmd_DS_GEN *)(pmbuf->pbuf + pmbuf->data_offset);
+ cmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_VDLL);
+ cmd_hdr->seq_num = wlan_cpu_to_le16(0xFF00);
+ cmd_hdr->size = wlan_cpu_to_le16(msg_len);
+
+ pmadapter->callbacks.moal_memcpy_ext(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(HostCmd_DS_GEN),
+ block, block_len, block_len);
+
+ pmbuf->data_len = msg_len;
+
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ pmbuf->data_offset -= pmadapter->ops.intf_header_len;
+ pmbuf->data_len += pmadapter->ops.intf_header_len;
+ }
+#endif
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pmbuf->data_offset -= MLAN_TYPE_LEN;
+ pmbuf->data_len += MLAN_TYPE_LEN;
+ }
+#endif
+ PRINTM_NETINTF(MCMND, pmpriv);
+ PRINTM(MCMND, "DNLD_VDLL : block_len=%d\n", block_len);
+
+ ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_VDLL, pmbuf, MNULL);
+
+ if (ret == MLAN_STATUS_FAILURE)
+ PRINTM(MERROR, "DNLD_VDLL: Host to Card Failed\n");
+ else
+ status = MLAN_STATUS_SUCCESS;
+
+done:
+ if ((ret == MLAN_STATUS_FAILURE) || (ret == MLAN_STATUS_SUCCESS)) {
+#ifdef USB
+ if (IS_USB(pmadapter->card_type))
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+#endif
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief The function Get the VDLL image from moal
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param offset offset
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+static mlan_status wlan_get_vdll_image(pmlan_adapter pmadapter, t_u32 vdll_len)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (ctrl->vdll_mem) {
+ PRINTM(MCMND, "VDLL mem is not empty: %p len=%d\n",
+ ctrl->vdll_mem, ctrl->vdll_len);
+ goto done;
+ }
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ status = pcb->moal_vmalloc(pmadapter->pmoal_handle, vdll_len,
+ (t_u8 **)&ctrl->vdll_mem);
+ else
+ status = pcb->moal_malloc(pmadapter->pmoal_handle, vdll_len,
+ MLAN_MEM_DEF,
+ (t_u8 **)&ctrl->vdll_mem);
+
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "VDLL: Fail to alloc vdll memory");
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_get_vdll_data(pmadapter->pmoal_handle, vdll_len,
+ ctrl->vdll_mem)) {
+ PRINTM(MERROR, "VDLL: firmware image not available\n");
+ status = MLAN_STATUS_FAILURE;
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)ctrl->vdll_mem);
+ else
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)ctrl->vdll_mem);
+ ctrl->vdll_mem = MNULL;
+ ctrl->vdll_len = 0;
+ goto done;
+ }
+ /*allocate a memory to store all VDLL images*/
+ ctrl->vdll_len = vdll_len;
+ PRINTM(MMSG, "VDLL image: len=%d\n", ctrl->vdll_len);
+done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function handle the multi_chan info event
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pevent A pointer to event buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_process_vdll_event(pmlan_private pmpriv, pmlan_buffer pevent)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ vdll_ind *ind = MNULL;
+ t_u32 offset = 0;
+ t_u16 block_len = 0;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl;
+
+ ENTER();
+ ind = (vdll_ind *)(pevent->pbuf + pevent->data_offset +
+ sizeof(mlan_event_id));
+ switch (wlan_le16_to_cpu(ind->type)) {
+ case VDLL_IND_TYPE_REQ:
+ offset = wlan_le32_to_cpu(ind->offset);
+ block_len = wlan_le16_to_cpu(ind->block_len);
+ PRINTM(MEVENT, "VDLL_IND: type=%d offset = 0x%x, len = %d\n",
+ wlan_le16_to_cpu(ind->type), offset, block_len);
+ if (offset <= ctrl->vdll_len) {
+ block_len = MIN(block_len, ctrl->vdll_len - offset);
+ if (!pmadapter->cmd_sent) {
+ status = wlan_download_vdll_block(
+ pmadapter, ctrl->vdll_mem + offset,
+ block_len);
+ if (status)
+ PRINTM(MERROR,
+ "Fail to download VDLL block\n");
+ } else {
+ PRINTM(MCMND,
+ "cmd_sent=1, delay download VDLL block\n");
+ ctrl->pending_block_len = block_len;
+ ctrl->pending_block = ctrl->vdll_mem + offset;
+ }
+ } else {
+ PRINTM(MERROR,
+ "Invalid VDLL req: offset=0x%x, len=%d, vdll_len=%d\n",
+ offset, block_len, ctrl->vdll_len);
+ }
+ break;
+
+ case VDLL_IND_TYPE_OFFSET:
+ offset = wlan_le32_to_cpu(ind->offset);
+ PRINTM(MEVENT, "VDLL_IND (OFFSET): offset=0x%x\n", offset);
+ wlan_get_vdll_image(pmadapter, offset);
+ break;
+ default:
+ PRINTM(MERROR, "unknow vdll ind type=%d\n", ind->type);
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function prepares command of get_hw_spec.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &pcmd->params.hw_spec;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+ memcpy_ext(pmpriv->adapter, hw_spec->permanent_addr, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef SDIO
+/**
+ * @brief This function prepares command of sdio rx aggr command.
+ *
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action: GET or SET
+ * @param pdata_buf A pointer to new setting buf
+
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_sdio_rx_aggr_cfg(HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_SDIO_SP_RX_AGGR_CFG *cfg = &pcmd->params.sdio_rx_aggr;
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_SP_RX_AGGR_CFG);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_SDIO_SP_RX_AGGR_CFG) +
+ S_DS_GEN);
+ cfg->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ cfg->enable = *(t_u8 *)pdata_buf;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sdio rx aggr command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_sdio_rx_aggr_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_SDIO_SP_RX_AGGR_CFG *cfg = &resp->params.sdio_rx_aggr;
+
+ pmadapter->pcard_sd->sdio_rx_aggr_enable = cfg->enable;
+ pmadapter->pcard_sd->sdio_rx_block_size =
+ wlan_le16_to_cpu(cfg->sdio_block_size);
+ PRINTM(MMSG, "SDIO rx aggr: %d block_size=%d\n", cfg->enable,
+ pmadapter->pcard_sd->sdio_rx_block_size);
+ if (!pmadapter->pcard_sd->sdio_rx_block_size)
+ pmadapter->pcard_sd->sdio_rx_aggr_enable = MFALSE;
+ if (pmadapter->pcard_sd->sdio_rx_aggr_enable) {
+ pmadapter->pcard_sd->max_sp_rx_size = SDIO_CMD53_MAX_SIZE;
+ wlan_re_alloc_sdio_rx_mpa_buffer(pmadapter);
+ }
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function prepares command of set_cfg_data.
+ *
+ * @param pmpriv A pointer to mlan_private strcture
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action: GET or SET
+ * @param pdata_buf A pointer to cal_data buf
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_cfg_data(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_data = &(pcmd->params.cfg_data);
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u32 len = 0;
+ t_u32 data_offset;
+ t_u8 *temp_pcmd = (t_u8 *)pcmd;
+
+ ENTER();
+
+ data_offset = S_DS_GEN + sizeof(HostCmd_DS_802_11_CFG_DATA);
+
+ if ((cmd_oid == OID_TYPE_CAL) && (pmadapter->pcal_data) &&
+ (pmadapter->cal_data_len > 0)) {
+ len = wlan_parse_cal_cfg((t_u8 *)pmadapter->pcal_data,
+ pmadapter->cal_data_len,
+ (t_u8 *)(temp_pcmd + data_offset));
+ }
+
+ pcfg_data->action = cmd_action;
+ pcfg_data->type = cmd_oid;
+ pcfg_data->data_len = len;
+
+ pcmd->command = HostCmd_CMD_CFG_DATA;
+ pcmd->size = pcfg_data->data_len + data_offset;
+
+ pcmd->command = wlan_cpu_to_le16(pcmd->command);
+ pcmd->size = wlan_cpu_to_le16(pcmd->size);
+
+ pcfg_data->action = wlan_cpu_to_le16(pcfg_data->action);
+ pcfg_data->type = wlan_cpu_to_le16(pcfg_data->type);
+ pcfg_data->data_len = wlan_cpu_to_le16(pcfg_data->data_len);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of set_cfg_data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to A pointer to mlan_ioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_cfg_data(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND *resp,
+ IN t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 event_buf[100];
+ mlan_cmdresp_event *pevent = (mlan_cmdresp_event *)event_buf;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_CFG_DATA *pcfg_data = &resp->params.cfg_data;
+ t_u16 action;
+ t_u16 type;
+
+ ENTER();
+
+ if (resp->result != HostCmd_RESULT_OK) {
+ PRINTM(MERROR, "CFG data cmd resp failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ if (!pmadapter->pdpd_data &&
+ (pmadapter->dpd_data_len == UNKNOW_DPD_LENGTH) &&
+ pmadapter->hw_status == WlanHardwareStatusGetHwSpec) {
+ action = wlan_le16_to_cpu(pcfg_data->action);
+ type = wlan_le16_to_cpu(pcfg_data->type);
+ if (action == HostCmd_ACT_GEN_GET && (type == OID_TYPE_DPD)) {
+ pcfg_data->action =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_STORE_HOST_CMD_RESP;
+ pevent->resp = (t_u8 *)resp;
+ pevent->event_len = wlan_le16_to_cpu(resp->size);
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_STORE_HOST_CMD_RESP,
+ (mlan_event *)pevent);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of mac_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_MAC_CONTROL *pmac = &pcmd->params.mac_ctrl;
+ t_u32 action = *((t_u32 *)pdata_buf);
+
+ ENTER();
+
+ if (cmd_action != HostCmd_ACT_GEN_SET) {
+ PRINTM(MERROR, "wlan_cmd_mac_control(): support SET only.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+ pcmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+ pmac->action = wlan_cpu_to_le32(action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ ENTER();
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_hw_spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf)
+{
+ HostCmd_DS_GET_HW_SPEC *hw_spec = &resp->params.hw_spec;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 i;
+ t_u16 left_len;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ MrvlIEtypes_fw_ver_info_t *api_rev = MNULL;
+ t_u16 api_id = 0;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+ MrvlIEtypes_Max_Conn_t *tlv_max_conn = MNULL;
+ MrvlIEtypes_Extension_t *ext_tlv = MNULL;
+ MrvlIEtypes_fw_cap_info_t *fw_cap_tlv = MNULL;
+
+ ENTER();
+
+ pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info);
+ pmadapter->fw_cap_info &= pmadapter->init_para.dev_cap_mask;
+
+ PRINTM(MMSG, "fw_cap_info=0x%x, dev_cap_mask=0x%x\n",
+ wlan_le32_to_cpu(hw_spec->fw_cap_info),
+ pmadapter->init_para.dev_cap_mask);
+#ifdef STA_SUPPORT
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter))
+ pmadapter->fw_bands = (t_u8)GET_FW_DEFAULT_BANDS(pmadapter);
+ else
+ pmadapter->fw_bands = BAND_B;
+
+ if ((pmadapter->fw_bands & BAND_A) && (pmadapter->fw_bands & BAND_GN))
+ pmadapter->fw_bands |= BAND_AN;
+ if (!(pmadapter->fw_bands & BAND_G) && (pmadapter->fw_bands & BAND_GN))
+ pmadapter->fw_bands &= ~BAND_GN;
+
+ pmadapter->config_bands = pmadapter->fw_bands;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands = pmadapter->fw_bands;
+ }
+
+ if (pmadapter->fw_bands & BAND_A) {
+ if (pmadapter->fw_bands & BAND_AN) {
+ pmadapter->config_bands |= BAND_AN;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |=
+ BAND_AN;
+ }
+ }
+ if (pmadapter->fw_bands & BAND_AAC) {
+ pmadapter->config_bands |= BAND_AAC;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |=
+ BAND_AAC;
+ }
+ }
+ if (pmadapter->fw_bands & BAND_GAC) {
+ pmadapter->config_bands |= BAND_GAC;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |=
+ BAND_GAC;
+ }
+ }
+ pmadapter->adhoc_start_band = BAND_A;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+ } else if (pmadapter->fw_bands & BAND_G) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ } else if (pmadapter->fw_bands & BAND_B) {
+ pmadapter->adhoc_start_band = BAND_B;
+ pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ }
+#endif /* STA_SUPPORT */
+
+ pmadapter->fw_release_number =
+ wlan_le32_to_cpu(hw_spec->fw_release_number);
+ pmadapter->number_of_antenna =
+ wlan_le16_to_cpu(hw_spec->number_of_antenna) & 0x00ff;
+ pmadapter->antinfo =
+ (wlan_le16_to_cpu(hw_spec->number_of_antenna) & 0xff00) >> 8;
+ PRINTM(MCMND, "num_ant=%d, antinfo=0x%x\n",
+ pmadapter->number_of_antenna, pmadapter->antinfo);
+
+ PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n",
+ pmadapter->fw_release_number);
+ PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- " MACSTR "\n",
+ MAC2STR(hw_spec->permanent_addr));
+ PRINTM(MINFO, "GET_HW_SPEC: hw_if_version=0x%X version=0x%X\n",
+ wlan_le16_to_cpu(hw_spec->hw_if_version),
+ wlan_le16_to_cpu(hw_spec->version));
+
+ if (pmpriv->curr_addr[0] == 0xff)
+ memmove(pmadapter, pmpriv->curr_addr, hw_spec->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ memmove(pmadapter, pmadapter->permanent_addr, hw_spec->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ pmadapter->hw_dot_11n_dev_cap =
+ wlan_le32_to_cpu(hw_spec->dot_11n_dev_cap);
+ pmadapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_update_11n_cap(pmadapter->priv[i]);
+ }
+
+ wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap);
+ wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ pmadapter->user_htstream = pmadapter->hw_dev_mcs_support;
+ /** separate stream config for 2.4G and 5G, will be changed according to
+ * antenna cfg*/
+ if (pmadapter->fw_bands & BAND_A)
+ pmadapter->user_htstream |= (pmadapter->user_htstream << 8);
+ PRINTM(MCMND, "user_htstream=0x%x\n", pmadapter->user_htstream);
+#endif
+
+ if (ISSUPP_BEAMFORMING(pmadapter->hw_dot_11n_dev_cap)) {
+ PRINTM(MCMND, "Enable Beamforming\n");
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->tx_bf_cap =
+ pmadapter->pcard_info
+ ->default_11n_tx_bf_cap;
+ }
+ }
+ pmadapter->hw_dot_11ac_dev_cap =
+ wlan_le32_to_cpu(hw_spec->Dot11acDevCap);
+ pmadapter->hw_dot_11ac_mcs_support =
+ wlan_le32_to_cpu(hw_spec->Dot11acMcsSupport);
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_update_11ac_cap(pmadapter->priv[i]);
+ }
+ wlan_show_dot11acdevcap(pmadapter, pmadapter->hw_dot_11ac_dev_cap);
+ wlan_show_dot11acmcssupport(pmadapter,
+ pmadapter->hw_dot_11ac_mcs_support);
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ pmadapter->pcard_sd->mp_end_port =
+ wlan_le16_to_cpu(hw_spec->mp_end_port);
+
+ for (i = 1; i <= (unsigned)(MAX_PORT -
+ pmadapter->pcard_sd->mp_end_port);
+ i++)
+ pmadapter->pcard_sd->mp_data_port_mask &=
+ ~(1 << (MAX_PORT - i));
+ }
+#endif
+
+ pmadapter->max_mgmt_ie_index =
+ wlan_le16_to_cpu(hw_spec->mgmt_buf_count);
+ PRINTM(MCMND, "GET_HW_SPEC: mgmt IE count=%d\n",
+ pmadapter->max_mgmt_ie_index);
+ if (!pmadapter->max_mgmt_ie_index ||
+ pmadapter->max_mgmt_ie_index > MAX_MGMT_IE_INDEX)
+ pmadapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+
+ pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code);
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (pmadapter->region_code == region_code_index[i])
+ break;
+ }
+ /* If it's unidentified region code, use the default */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ pmadapter->region_code = MRVDRV_DEFAULT_REGION_CODE;
+ PRINTM(MWARN,
+ "unidentified region code, use the default (0x%02x)\n",
+ MRVDRV_DEFAULT_REGION_CODE);
+ }
+ /* Synchronize CFP code with region code */
+ pmadapter->cfp_code_bg = pmadapter->region_code;
+ pmadapter->cfp_code_a = pmadapter->region_code;
+
+ if (pmadapter->fw_cap_info & ENHANCE_EXT_SCAN_ENABLE)
+ pmadapter->ext_scan_enh = MTRUE;
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ if ((pmadapter->fw_cap_info & SDIO_SP_RX_AGGR_ENABLE) &&
+ pmadapter->pcard_sd->sdio_rx_aggr_enable) {
+ t_u8 sdio_sp_rx_aggr = MTRUE;
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_SDIO_SP_RX_AGGR_CFG,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &sdio_sp_rx_aggr);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+ pmadapter->pcard_sd->sdio_rx_aggr_enable = MFALSE;
+ PRINTM(MCMND, "FW: SDIO rx aggr disabled 0x%x\n",
+ pmadapter->fw_cap_info);
+ }
+ }
+#endif
+
+ if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
+ pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif /* STA_SUPPORT */
+ if (pmadapter->fw_cap_info & FW_CAPINFO_ECSA) {
+ t_u8 ecsa_enable = MTRUE;
+ pmadapter->ecsa_enable = MTRUE;
+ PRINTM(MCMND, "pmadapter->ecsa_enable=%d\n",
+ pmadapter->ecsa_enable);
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, ECSAEnable_i, MNULL,
+ &ecsa_enable);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (pmadapter->fw_cap_info & FW_CAPINFO_GET_LOG) {
+ pmadapter->getlog_enable = MTRUE;
+ PRINTM(MCMND, "pmadapter->getlog_enable=%d\n",
+ pmadapter->getlog_enable);
+ }
+
+ left_len = resp->size - sizeof(HostCmd_DS_GET_HW_SPEC) - S_DS_GEN;
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)hw_spec +
+ sizeof(HostCmd_DS_GET_HW_SPEC));
+ while (left_len > sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ switch (tlv_type) {
+ case TLV_TYPE_FW_VER_INFO:
+ api_rev = (MrvlIEtypes_fw_ver_info_t *)tlv;
+ api_id = wlan_le16_to_cpu(api_rev->api_id);
+ switch (api_id) {
+ case FW_API_VER_ID:
+ pmadapter->fw_ver = api_rev->major_ver;
+ pmadapter->fw_min_ver = api_rev->minor_ver;
+ PRINTM(MCMND, "fw ver=%d.%d\n",
+ api_rev->major_ver, api_rev->minor_ver);
+ break;
+ case UAP_FW_API_VER_ID:
+ pmadapter->uap_fw_ver = api_rev->major_ver;
+ PRINTM(MCMND, "uap fw ver=%d.%d\n",
+ api_rev->major_ver, api_rev->minor_ver);
+ break;
+ case CHANRPT_API_VER_ID:
+ pmadapter->chanrpt_param_bandcfg =
+ api_rev->minor_ver;
+ PRINTM(MCMND, "chanrpt api ver=%d.%d\n",
+ api_rev->major_ver, api_rev->minor_ver);
+ break;
+ default:
+ break;
+ }
+ break;
+ case TLV_TYPE_MAX_CONN:
+ tlv_max_conn = (MrvlIEtypes_Max_Conn_t *)tlv;
+ PRINTM(MMSG, "max_p2p_conn = %d, max_sta_conn = %d\n",
+ tlv_max_conn->max_p2p_conn,
+ tlv_max_conn->max_sta_conn);
+ if (tlv_max_conn->max_p2p_conn &&
+ tlv_max_conn->max_sta_conn)
+ pmadapter->max_sta_conn =
+ MIN(tlv_max_conn->max_sta_conn,
+ tlv_max_conn->max_p2p_conn);
+ else if (tlv_max_conn->max_sta_conn)
+ pmadapter->max_sta_conn =
+ tlv_max_conn->max_sta_conn;
+ else if (tlv_max_conn->max_p2p_conn)
+ pmadapter->max_sta_conn =
+ tlv_max_conn->max_p2p_conn;
+ else
+ pmadapter->max_sta_conn = 0;
+ break;
+ case TLV_TYPE_EXTENSION_ID:
+ ext_tlv = (MrvlIEtypes_Extension_t *)tlv;
+ if (ext_tlv->ext_id == HE_CAPABILITY) {
+ ext_tlv->type = tlv_type;
+ ext_tlv->len = tlv_len;
+ wlan_update_11ax_cap(
+ pmadapter,
+ (MrvlIEtypes_Extension_t *)ext_tlv);
+ }
+
+ break;
+ case TLV_TYPE_FW_CAP_INFO:
+ fw_cap_tlv = (MrvlIEtypes_fw_cap_info_t *)tlv;
+ pmadapter->fw_cap_info =
+ wlan_le32_to_cpu(fw_cap_tlv->fw_cap_info);
+ pmadapter->fw_cap_ext =
+ wlan_le32_to_cpu(fw_cap_tlv->fw_cap_ext);
+ PRINTM(MCMND, "fw_cap_info=0x%x fw_cap_ext=0x%x\n",
+ pmadapter->fw_cap_info, pmadapter->fw_cap_ext);
+ break;
+ default:
+ break;
+ }
+ left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of radio_control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_radio_control(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_control = &cmd->params.radio;
+ t_u32 radio_ctl;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL)) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+ pradio_control->action = wlan_cpu_to_le16(cmd_action);
+ memcpy_ext(pmpriv->adapter, &radio_ctl, pdata_buf, sizeof(t_u32),
+ sizeof(radio_ctl));
+ pradio_control->control = wlan_cpu_to_le16((t_u16)radio_ctl);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of radio_control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_802_11_radio_control(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RADIO_CONTROL *pradio_ctrl =
+ (HostCmd_DS_802_11_RADIO_CONTROL *)&resp->params.radio;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+ pmadapter->radio_on = wlan_le16_to_cpu(pradio_ctrl->control);
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_buf->pbuf;
+ radio_cfg->param.radio_on_off = (t_u32)pmadapter->radio_on;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of remain_on_channel.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_remain_on_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel =
+ &cmd->params.remain_on_chan;
+ mlan_ds_remain_chan *cfg = (mlan_ds_remain_chan *)pdata_buf;
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_REMAIN_ON_CHANNEL)) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_REMAIN_ON_CHANNEL);
+ remain_channel->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if (cfg->remove) {
+ remain_channel->action = HostCmd_ACT_GEN_REMOVE;
+ } else {
+ remain_channel->bandcfg = cfg->bandcfg;
+ remain_channel->channel = cfg->channel;
+ remain_channel->remain_period =
+ wlan_cpu_to_le32(cfg->remain_period);
+ }
+ }
+ remain_channel->action = wlan_cpu_to_le16(remain_channel->action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of remain_on_channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_remain_on_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel =
+ &resp->params.remain_on_chan;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_buf->pbuf;
+ radio_cfg->param.remain_chan.status = remain_channel->status;
+ radio_cfg->param.remain_chan.bandcfg = remain_channel->bandcfg;
+ radio_cfg->param.remain_chan.channel = remain_channel->channel;
+ radio_cfg->param.remain_chan.remain_period =
+ wlan_le32_to_cpu(remain_channel->remain_period);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief This function prepares command of wifi direct mode.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wifi_direct_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &cmd->params.wifi_direct_mode;
+ t_u16 mode = *((t_u16 *)pdata_buf);
+ ENTER();
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_WIFI_DIRECT_MODE)) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_WIFI_DIRECT_MODE_CONFIG);
+ wfd_mode->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ wfd_mode->mode = wlan_cpu_to_le16(mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of wifi direct mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wifi_direct_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &resp->params.wifi_direct_mode;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ bss->param.wfd_mode = wlan_le16_to_cpu(wfd_mode->mode);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_bss);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of p2p_params_config.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_p2p_params_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG *p2p_config =
+ &cmd->params.p2p_params_config;
+ mlan_ds_wifi_direct_config *cfg =
+ (mlan_ds_wifi_direct_config *)pdata_buf;
+ MrvlIEtypes_NoA_setting_t *pnoa_tlv = MNULL;
+ MrvlIEtypes_OPP_PS_setting_t *popp_ps_tlv = MNULL;
+ t_u8 *tlv = MNULL;
+ ENTER();
+
+ cmd->size = sizeof(HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG) + S_DS_GEN;
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_P2P_PARAMS_CONFIG);
+ p2p_config->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ tlv = (t_u8 *)p2p_config->tlv_buf;
+ if (cfg->flags & WIFI_DIRECT_NOA) {
+ pnoa_tlv = (MrvlIEtypes_NoA_setting_t *)tlv;
+ pnoa_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_NOA);
+ pnoa_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_NoA_setting_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ pnoa_tlv->enable = cfg->noa_enable;
+ pnoa_tlv->index = wlan_cpu_to_le16(cfg->index);
+ pnoa_tlv->noa_count = cfg->noa_count;
+ pnoa_tlv->noa_duration =
+ wlan_cpu_to_le32(cfg->noa_duration);
+ pnoa_tlv->noa_interval =
+ wlan_cpu_to_le32(cfg->noa_interval);
+ cmd->size += sizeof(MrvlIEtypes_NoA_setting_t);
+ tlv += sizeof(MrvlIEtypes_NoA_setting_t);
+ PRINTM(MCMND,
+ "Set NOA: enable=%d index=%d, count=%d, duration=%d interval=%d\n",
+ cfg->noa_enable, cfg->index, cfg->noa_count,
+ (int)cfg->noa_duration, (int)cfg->noa_interval);
+ }
+ if (cfg->flags & WIFI_DIRECT_OPP_PS) {
+ popp_ps_tlv = (MrvlIEtypes_OPP_PS_setting_t *)tlv;
+ popp_ps_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_OPP_PS);
+ popp_ps_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_OPP_PS_setting_t) -
+ sizeof(MrvlIEtypesHeader_t));
+
+ popp_ps_tlv->enable = cfg->ct_window;
+ popp_ps_tlv->enable |= cfg->opp_ps_enable << 7;
+ cmd->size += sizeof(MrvlIEtypes_OPP_PS_setting_t);
+ PRINTM(MCMND, "Set OPP_PS: enable=%d ct_win=%d\n",
+ cfg->opp_ps_enable, cfg->ct_window);
+ }
+ } else if (cmd_action == HostCmd_ACT_GEN_GET) {
+ tlv = (t_u8 *)p2p_config->tlv_buf;
+ if (cfg->flags & WIFI_DIRECT_NOA) {
+ pnoa_tlv = (MrvlIEtypes_NoA_setting_t *)tlv;
+ pnoa_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_NOA);
+ pnoa_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_NoA_setting_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += sizeof(MrvlIEtypes_NoA_setting_t);
+ tlv += sizeof(MrvlIEtypes_NoA_setting_t);
+ }
+
+ if (cfg->flags & WIFI_DIRECT_OPP_PS) {
+ popp_ps_tlv = (MrvlIEtypes_OPP_PS_setting_t *)tlv;
+ popp_ps_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_OPP_PS);
+ popp_ps_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_OPP_PS_setting_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += sizeof(MrvlIEtypes_OPP_PS_setting_t);
+ }
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of p2p_params_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_p2p_params_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG *p2p_config =
+ &resp->params.p2p_params_config;
+ mlan_ds_misc_cfg *cfg = MNULL;
+ MrvlIEtypes_NoA_setting_t *pnoa_tlv = MNULL;
+ MrvlIEtypes_OPP_PS_setting_t *popp_ps_tlv = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+
+ ENTER();
+ if (wlan_le16_to_cpu(p2p_config->action) == HostCmd_ACT_GEN_GET) {
+ if (pioctl_buf) {
+ cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ tlv = (MrvlIEtypesHeader_t *)(p2p_config->tlv_buf);
+ tlv_buf_left =
+ resp->size -
+ (sizeof(HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG) +
+ S_DS_GEN);
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if (tlv_buf_left <
+ (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error processing p2p param config TLVs, bytes left < TLV length\n");
+ break;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_WIFI_DIRECT_NOA:
+ pnoa_tlv = (MrvlIEtypes_NoA_setting_t *)
+ tlv;
+ cfg->param.p2p_config.flags |=
+ WIFI_DIRECT_NOA;
+ cfg->param.p2p_config.noa_enable =
+ pnoa_tlv->enable;
+ cfg->param.p2p_config.index =
+ wlan_le16_to_cpu(
+ pnoa_tlv->index);
+ cfg->param.p2p_config.noa_count =
+ pnoa_tlv->noa_count;
+ cfg->param.p2p_config.noa_duration =
+ wlan_le32_to_cpu(
+ pnoa_tlv->noa_duration);
+ cfg->param.p2p_config.noa_interval =
+ wlan_le32_to_cpu(
+ pnoa_tlv->noa_interval);
+ PRINTM(MCMND,
+ "Get NOA: enable=%d index=%d, count=%d, duration=%d interval=%d\n",
+ cfg->param.p2p_config.noa_enable,
+ cfg->param.p2p_config.index,
+ cfg->param.p2p_config.noa_count,
+ (int)cfg->param.p2p_config
+ .noa_duration,
+ (int)cfg->param.p2p_config
+ .noa_interval);
+ break;
+ case TLV_TYPE_WIFI_DIRECT_OPP_PS:
+ popp_ps_tlv =
+ (MrvlIEtypes_OPP_PS_setting_t *)
+ tlv;
+ cfg->param.p2p_config.flags |=
+ WIFI_DIRECT_OPP_PS;
+ cfg->param.p2p_config.opp_ps_enable =
+ (popp_ps_tlv->enable & 0x80) >>
+ 7;
+ cfg->param.p2p_config.ct_window =
+ popp_ps_tlv->enable & 0x7f;
+ PRINTM(MCMND,
+ "Get OPP_PS: enable=%d ct_win=%d\n",
+ cfg->param.p2p_config
+ .opp_ps_enable,
+ cfg->param.p2p_config.ct_window);
+ break;
+ default:
+ break;
+ }
+ tlv_buf_left -=
+ tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t
+ *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_wifi_direct_config);
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function prepares command of mimo switch configuration.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_mimo_switch(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_MIMO_SWITCH *mimo_switch_cmd = &cmd->params.mimo_switch;
+ mlan_ds_mimo_switch *pmimo_switch = (mlan_ds_mimo_switch *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MIMO_SWITCH);
+ cmd->size =
+ wlan_cpu_to_le16((sizeof(HostCmd_DS_MIMO_SWITCH)) + S_DS_GEN);
+ mimo_switch_cmd->txpath_antmode = pmimo_switch->txpath_antmode;
+ mimo_switch_cmd->rxpath_antmode = pmimo_switch->rxpath_antmode;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of hs wakeup reason.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_hs_wakeup_reason(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON);
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_HS_WAKEUP_REASON)) +
+ S_DS_GEN);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * hs wakeup reason
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_hs_wakeup_reason(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_HS_WAKEUP_REASON *hs_wakeup_reason =
+ (HostCmd_DS_HS_WAKEUP_REASON *)&resp->params.hs_wakeup_reason;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf;
+ pm_cfg->param.wakeup_reason.hs_wakeup_reason =
+ wlan_le16_to_cpu(hs_wakeup_reason->wakeup_reason);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_pm_cfg);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of tx_rx_pkt_stats
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @param pdata_buf A pointer to information buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_tx_rx_pkt_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ pmlan_ioctl_req pioctl_buf,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_TX_RX_HISTOGRAM *ptx_rx_histogram =
+ &cmd->params.tx_rx_histogram;
+ mlan_ds_misc_tx_rx_histogram *ptx_rx_pkt_stats =
+ (mlan_ds_misc_tx_rx_histogram *)pdata_buf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!ptx_rx_pkt_stats) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_TX_RX_PKT_STATS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_RX_HISTOGRAM) + S_DS_GEN);
+
+ ptx_rx_histogram->enable = ptx_rx_pkt_stats->enable;
+ ptx_rx_histogram->action = wlan_cpu_to_le16(ptx_rx_pkt_stats->action);
+done:
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief This function handles the command response of tx_rx_pkt_stats
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_tx_rx_pkt_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_TX_RX_HISTOGRAM *ptx_rx_histogram =
+ &resp->params.tx_rx_histogram;
+ mlan_ds_misc_cfg *info;
+ t_u16 cmdsize = wlan_le16_to_cpu(resp->size), length;
+ t_u32 *pos, count = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ ptx_rx_histogram->action =
+ wlan_le16_to_cpu(ptx_rx_histogram->action);
+ info = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ length =
+ cmdsize - S_DS_GEN - sizeof(HostCmd_DS_TX_RX_HISTOGRAM);
+ if (length > 0) {
+ info->param.tx_rx_histogram.size = length;
+ memcpy_ext(pmpriv->adapter,
+ info->param.tx_rx_histogram.value,
+ (t_u8 *)ptx_rx_histogram +
+ sizeof(HostCmd_DS_TX_RX_HISTOGRAM),
+ length, info->param.tx_rx_histogram.size);
+ pos = (t_u32 *)info->param.tx_rx_histogram.value;
+ while (length - 4 * count) {
+ *pos = wlan_le32_to_cpu(*pos);
+ pos += 4;
+ count++;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/*
+ * @brief This function prepares command of cwmode control.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_cw_mode_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CW_MODE_CTRL *cwmode_ctrl = &cmd->params.cwmode;
+ mlan_ds_cw_mode_ctrl *cw_mode = (mlan_ds_cw_mode_ctrl *)pdata_buf;
+ ENTER();
+ cmd->size =
+ wlan_cpu_to_le16((sizeof(HostCmd_DS_CW_MODE_CTRL)) + S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CW_MODE_CTRL);
+ cwmode_ctrl->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cwmode_ctrl->mode = cw_mode->mode;
+ cwmode_ctrl->channel = cw_mode->channel;
+ cwmode_ctrl->chanInfo = cw_mode->chanInfo;
+ cwmode_ctrl->txPower = wlan_cpu_to_le16(cw_mode->txPower);
+ cwmode_ctrl->rateInfo = wlan_cpu_to_le32(cw_mode->rateInfo);
+ cwmode_ctrl->pktLength = wlan_cpu_to_le16(cw_mode->pktLength);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/*
+ * @brief This function handles the command response of cwmode_ctrl
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_cw_mode_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CW_MODE_CTRL *cwmode_resp = &resp->params.cwmode;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc->param.cwmode.mode = cwmode_resp->mode;
+ misc->param.cwmode.channel = cwmode_resp->channel;
+ misc->param.cwmode.chanInfo = cwmode_resp->chanInfo;
+ misc->param.cwmode.txPower =
+ wlan_le16_to_cpu(cwmode_resp->txPower);
+ misc->param.cwmode.rateInfo =
+ wlan_le32_to_cpu(cwmode_resp->rateInfo);
+ ;
+ misc->param.cwmode.pktLength =
+ wlan_le16_to_cpu(cwmode_resp->pktLength);
+ ;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_misc_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_antenna.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_rf_antenna(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna;
+ mlan_ds_ant_cfg *ant_cfg = (mlan_ds_ant_cfg *)pdata_buf;
+ typedef struct _HostCmd_DS_802_11_RF_ANTENNA_1X1 {
+ /** Action */
+ t_u16 action;
+ /** Antenna or 0xffff (diversity) */
+ t_u16 antenna_mode;
+ /** Evaluate time */
+ t_u16 evaluate_time;
+ /** Current antenna */
+ t_u16 current_antenna;
+ } HostCmd_DS_802_11_RF_ANTENNA_1X1;
+ HostCmd_DS_802_11_RF_ANTENNA_1X1 *pantenna_1x1 =
+ (HostCmd_DS_802_11_RF_ANTENNA_1X1 *)&cmd->params.antenna;
+ mlan_ds_ant_cfg_1x1 *ant_cfg_1x1 = (mlan_ds_ant_cfg_1x1 *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+ if (!IS_STREAM_2X2(pmpriv->adapter->feature_control))
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_RF_ANTENNA_1X1) + S_DS_GEN);
+ else
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) {
+ pantenna->action_tx =
+ wlan_cpu_to_le16(HostCmd_ACT_SET_TX);
+ pantenna->tx_antenna_mode =
+ wlan_cpu_to_le16((t_u16)ant_cfg->tx_antenna);
+ pantenna->action_rx =
+ wlan_cpu_to_le16(HostCmd_ACT_SET_RX);
+ pantenna->rx_antenna_mode =
+ wlan_cpu_to_le16((t_u16)ant_cfg->rx_antenna);
+ } else {
+ pantenna_1x1->action =
+ wlan_cpu_to_le16(HostCmd_ACT_SET_BOTH);
+ pantenna_1x1->antenna_mode =
+ wlan_cpu_to_le16((t_u16)ant_cfg_1x1->antenna);
+ pantenna_1x1->evaluate_time = wlan_cpu_to_le16(
+ (t_u16)ant_cfg_1x1->evaluate_time);
+ }
+ } else {
+ if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) {
+ pantenna->action_tx =
+ wlan_cpu_to_le16(HostCmd_ACT_GET_TX);
+ pantenna->action_rx =
+ wlan_cpu_to_le16(HostCmd_ACT_GET_RX);
+ } else {
+ pantenna_1x1->action =
+ wlan_cpu_to_le16(HostCmd_ACT_GET_BOTH);
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_antenna
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_802_11_rf_antenna(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna;
+ t_u16 tx_ant_mode = wlan_le16_to_cpu(pantenna->tx_antenna_mode);
+ t_u16 rx_ant_mode = wlan_le16_to_cpu(pantenna->rx_antenna_mode);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#endif
+ typedef struct _HostCmd_DS_802_11_RF_ANTENNA_1X1 {
+ /** Action */
+ t_u16 action;
+ /** Antenna or 0xffff (diversity) */
+ t_u16 antenna_mode;
+ /** Evaluate time */
+ t_u16 evaluate_time;
+ /** Current antenna */
+ t_u16 current_antenna;
+ } HostCmd_DS_802_11_RF_ANTENNA_1X1;
+ HostCmd_DS_802_11_RF_ANTENNA_1X1 *pantenna_1x1 =
+ (HostCmd_DS_802_11_RF_ANTENNA_1X1 *)&resp->params.antenna;
+ t_u16 ant_mode = wlan_le16_to_cpu(pantenna_1x1->antenna_mode);
+ t_u16 evaluate_time = wlan_le16_to_cpu(pantenna_1x1->evaluate_time);
+ t_u16 current_antenna = wlan_le16_to_cpu(pantenna_1x1->current_antenna);
+ mlan_ds_radio_cfg *radio = MNULL;
+
+ ENTER();
+
+ if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) {
+ PRINTM(MCMND,
+ "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x"
+ " Rx action = 0x%x, Rx Mode = 0x%04x\n",
+ wlan_le16_to_cpu(pantenna->action_tx), tx_ant_mode,
+ wlan_le16_to_cpu(pantenna->action_rx), rx_ant_mode);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ tx_ant_mode &= 0x0303;
+ rx_ant_mode &= 0x0303;
+ /** 2G antcfg TX */
+ if (tx_ant_mode & 0x00FF) {
+ pmadapter->user_htstream &= ~0xF0;
+ pmadapter->user_htstream |=
+ (bitcount(tx_ant_mode & 0x00FF) << 4);
+ }
+ /* 5G antcfg tx */
+ if (tx_ant_mode & 0xFF00) {
+ pmadapter->user_htstream &= ~0xF000;
+ pmadapter->user_htstream |=
+ (bitcount(tx_ant_mode & 0xFF00) << 12);
+ }
+ /* 2G antcfg RX */
+ if (rx_ant_mode & 0x00FF) {
+ pmadapter->user_htstream &= ~0xF;
+ pmadapter->user_htstream |=
+ bitcount(rx_ant_mode & 0x00FF);
+ }
+ /* 5G antcfg RX */
+ if (rx_ant_mode & 0xFF00) {
+ pmadapter->user_htstream &= ~0xF00;
+ pmadapter->user_htstream |=
+ (bitcount(rx_ant_mode & 0xFF00) << 8);
+ }
+ PRINTM(MCMND,
+ "user_htstream=0x%x, tx_antenna=0x%x rx_antenna=0x%x\n",
+ pmadapter->user_htstream, tx_ant_mode,
+ rx_ant_mode);
+ }
+#endif
+ } else
+ PRINTM(MINFO,
+ "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x, Evaluate time = %d, Current antenna = %d\n",
+ wlan_le16_to_cpu(pantenna_1x1->action), ant_mode,
+ evaluate_time, current_antenna);
+
+ if (pioctl_buf) {
+ radio = (mlan_ds_radio_cfg *)pioctl_buf->pbuf;
+ if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) {
+ radio->param.ant_cfg.tx_antenna = tx_ant_mode;
+ radio->param.ant_cfg.rx_antenna = rx_ant_mode;
+ } else {
+ radio->param.ant_cfg_1x1.antenna = ant_mode;
+ radio->param.ant_cfg_1x1.evaluate_time = evaluate_time;
+ radio->param.ant_cfg_1x1.current_antenna =
+ current_antenna;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of reg_access.
+ *
+ * @param priv A pointer to mlan_priv register.
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_reg_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ mlan_ds_reg_rw *reg_rw;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ MrvlIEtypes_Reg_type_t *tlv;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#endif
+
+ ENTER();
+
+ reg_rw = (mlan_ds_reg_rw *)pdata_buf;
+ switch (cmd->command) {
+ case HostCmd_CMD_MAC_REG_ACCESS: {
+ HostCmd_DS_MAC_REG_ACCESS *mac_reg;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) +
+ S_DS_GEN);
+ mac_reg = (HostCmd_DS_MAC_REG_ACCESS *)&cmd->params.mac_reg;
+ mac_reg->action = wlan_cpu_to_le16(cmd_action);
+ mac_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ mac_reg->value = wlan_cpu_to_le32(reg_rw->value);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ if ((reg_rw->type == MLAN_REG_MAC2) &&
+ (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type))) {
+ tlv = (MrvlIEtypes_Reg_type_t
+ *)((t_u8 *)cmd +
+ sizeof(HostCmd_DS_MAC_REG_ACCESS) +
+ S_DS_GEN);
+ tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL);
+ tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv->type = MLAN_REG_MAC2;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN +
+ sizeof(MrvlIEtypes_Reg_type_t));
+ }
+#endif
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS: {
+ HostCmd_DS_BBP_REG_ACCESS *bbp_reg;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) +
+ S_DS_GEN);
+ bbp_reg = (HostCmd_DS_BBP_REG_ACCESS *)&cmd->params.bbp_reg;
+ bbp_reg->action = wlan_cpu_to_le16(cmd_action);
+ bbp_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ bbp_reg->value = (t_u8)reg_rw->value;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ if ((reg_rw->type == MLAN_REG_BBP2) &&
+ (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type))) {
+ tlv = (MrvlIEtypes_Reg_type_t
+ *)((t_u8 *)cmd +
+ sizeof(HostCmd_DS_BBP_REG_ACCESS) +
+ S_DS_GEN);
+ tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL);
+ tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv->type = MLAN_REG_BBP2;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN +
+ sizeof(MrvlIEtypes_Reg_type_t));
+ }
+#endif
+ break;
+ }
+ case HostCmd_CMD_RF_REG_ACCESS: {
+ HostCmd_DS_RF_REG_ACCESS *rf_reg;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) +
+ S_DS_GEN);
+ rf_reg = (HostCmd_DS_RF_REG_ACCESS *)&cmd->params.rf_reg;
+ rf_reg->action = wlan_cpu_to_le16(cmd_action);
+ rf_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ rf_reg->value = (t_u8)reg_rw->value;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ if ((reg_rw->type == MLAN_REG_RF2) &&
+ (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type))) {
+ tlv = (MrvlIEtypes_Reg_type_t
+ *)((t_u8 *)cmd +
+ sizeof(HostCmd_DS_RF_REG_ACCESS) +
+ S_DS_GEN);
+ tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL);
+ tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv->type = MLAN_REG_RF2;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN +
+ sizeof(MrvlIEtypes_Reg_type_t));
+ }
+#endif
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS: {
+ HostCmd_DS_RF_REG_ACCESS *cau_reg;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) +
+ S_DS_GEN);
+ cau_reg = (HostCmd_DS_RF_REG_ACCESS *)&cmd->params.rf_reg;
+ cau_reg->action = wlan_cpu_to_le16(cmd_action);
+ cau_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ cau_reg->value = (t_u8)reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_TARGET_ACCESS: {
+ HostCmd_DS_TARGET_ACCESS *target;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TARGET_ACCESS) +
+ S_DS_GEN);
+ target = (HostCmd_DS_TARGET_ACCESS *)&cmd->params.target;
+ target->action = wlan_cpu_to_le16(cmd_action);
+ target->csu_target = wlan_cpu_to_le16(MLAN_CSU_TARGET_PSU);
+ target->address = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ target->data = (t_u8)reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS: {
+ mlan_ds_read_eeprom *rd_eeprom =
+ (mlan_ds_read_eeprom *)pdata_buf;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *)&cmd->params.eeprom;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) + S_DS_GEN);
+ cmd_eeprom->action = wlan_cpu_to_le16(cmd_action);
+ cmd_eeprom->offset = wlan_cpu_to_le16(rd_eeprom->offset);
+ cmd_eeprom->byte_count =
+ wlan_cpu_to_le16(rd_eeprom->byte_count);
+ cmd_eeprom->value = 0;
+ break;
+ }
+ case HostCmd_CMD_BCA_REG_ACCESS: {
+ HostCmd_DS_BCA_REG_ACCESS *bca_reg;
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_BCA_REG_ACCESS) +
+ S_DS_GEN);
+ bca_reg = (HostCmd_DS_BCA_REG_ACCESS *)&cmd->params.bca_reg;
+ bca_reg->action = wlan_cpu_to_le16(cmd_action);
+ bca_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset);
+ bca_reg->value = wlan_cpu_to_le32(reg_rw->value);
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ if ((reg_rw->type == MLAN_REG_BCA2) &&
+ (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type))) {
+ tlv = (MrvlIEtypes_Reg_type_t
+ *)((t_u8 *)cmd +
+ sizeof(HostCmd_DS_BCA_REG_ACCESS) +
+ S_DS_GEN);
+ tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL);
+ tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv->type = MLAN_REG_BCA2;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_BCA_REG_ACCESS) + S_DS_GEN +
+ sizeof(MrvlIEtypes_Reg_type_t));
+ }
+#endif
+ break;
+ }
+ default:
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of reg_access
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type The type of reg access (MAC, BBP or RF)
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_reg_access(mlan_adapter *pmadapter, t_u16 type,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_reg_rw *reg_rw = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *)pioctl_buf->pbuf;
+ reg_rw = &reg_mem->param.reg_rw;
+ switch (type) {
+ case HostCmd_CMD_MAC_REG_ACCESS: {
+ HostCmd_DS_MAC_REG_ACCESS *reg;
+ reg = (HostCmd_DS_MAC_REG_ACCESS *)&resp->params.mac_reg;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = wlan_le32_to_cpu(reg->value);
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS: {
+ HostCmd_DS_BBP_REG_ACCESS *reg;
+ reg = (HostCmd_DS_BBP_REG_ACCESS *)&resp->params.bbp_reg;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32)reg->value;
+ break;
+ }
+
+ case HostCmd_CMD_RF_REG_ACCESS: {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *)&resp->params.rf_reg;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32)reg->value;
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS: {
+ HostCmd_DS_RF_REG_ACCESS *reg;
+ reg = (HostCmd_DS_RF_REG_ACCESS *)&resp->params.rf_reg;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = (t_u32)reg->value;
+ break;
+ }
+ case HostCmd_CMD_TARGET_ACCESS: {
+ HostCmd_DS_TARGET_ACCESS *reg;
+ reg = (HostCmd_DS_TARGET_ACCESS *)&resp->params.target;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->address);
+ reg_rw->value = (t_u32)reg->data;
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS: {
+ mlan_ds_read_eeprom *eeprom = &reg_mem->param.rd_eeprom;
+ HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom =
+ (HostCmd_DS_802_11_EEPROM_ACCESS *)&resp->params
+ .eeprom;
+ cmd_eeprom->byte_count =
+ wlan_le16_to_cpu(cmd_eeprom->byte_count);
+ PRINTM(MINFO, "EEPROM read len=%x\n",
+ cmd_eeprom->byte_count);
+ if (eeprom->byte_count < cmd_eeprom->byte_count) {
+ eeprom->byte_count = 0;
+ PRINTM(MINFO,
+ "EEPROM read return length is too big\n");
+ pioctl_buf->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ eeprom->offset = wlan_le16_to_cpu(cmd_eeprom->offset);
+ eeprom->byte_count = cmd_eeprom->byte_count;
+ if (eeprom->byte_count > 0) {
+ memcpy_ext(pmadapter, &eeprom->value,
+ &cmd_eeprom->value,
+ eeprom->byte_count, MAX_EEPROM_DATA);
+ HEXDUMP("EEPROM", (char *)&eeprom->value,
+ MIN(MAX_EEPROM_DATA,
+ eeprom->byte_count));
+ }
+ break;
+ }
+ case HostCmd_CMD_BCA_REG_ACCESS: {
+ HostCmd_DS_BCA_REG_ACCESS *reg;
+ reg = (HostCmd_DS_BCA_REG_ACCESS *)&resp->params.bca_reg;
+ reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset);
+ reg_rw->value = wlan_le32_to_cpu(reg->value);
+ break;
+ }
+ default:
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mem_access.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_mem_access(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ mlan_ds_mem_rw *mem_rw = (mlan_ds_mem_rw *)pdata_buf;
+ HostCmd_DS_MEM_ACCESS *mem_access =
+ (HostCmd_DS_MEM_ACCESS *)&cmd->params.mem;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MEM_ACCESS) + S_DS_GEN);
+
+ mem_access->action = wlan_cpu_to_le16(cmd_action);
+ mem_access->addr = wlan_cpu_to_le32(mem_rw->addr);
+ mem_access->value = wlan_cpu_to_le32(mem_rw->value);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mem_access
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_mem_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_ds_mem_rw *mem_rw = MNULL;
+ HostCmd_DS_MEM_ACCESS *mem = (HostCmd_DS_MEM_ACCESS *)&resp->params.mem;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ reg_mem = (mlan_ds_reg_mem *)pioctl_buf->pbuf;
+ mem_rw = &reg_mem->param.mem_rw;
+
+ mem_rw->addr = wlan_le32_to_cpu(mem->addr);
+ mem_rw->value = wlan_le32_to_cpu(mem->value);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ *
+ * @brief This function handles coex events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+void wlan_bt_coex_wlan_param_update_event(pmlan_private priv,
+ pmlan_buffer pevent)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ MrvlIETypes_BtCoexAggrWinSize_t *pCoexWinsize = MNULL;
+ MrvlIEtypes_BtCoexScanTime_t *pScantlv = MNULL;
+ t_s32 len = pevent->data_len - sizeof(t_u32);
+ t_u8 *pCurrent_ptr = pevent->pbuf + pevent->data_offset + sizeof(t_u32);
+ t_u16 tlv_type, tlv_len;
+
+ ENTER();
+
+ while (len >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv = (MrvlIEtypesHeader_t *)pCurrent_ptr;
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ if ((tlv_len + sizeof(MrvlIEtypesHeader_t)) > len)
+ break;
+ switch (tlv_type) {
+ case TLV_BTCOEX_WL_AGGR_WINSIZE:
+ pCoexWinsize = (MrvlIETypes_BtCoexAggrWinSize_t *)tlv;
+ pmadapter->coex_win_size = pCoexWinsize->coex_win_size;
+ pmadapter->coex_tx_win_size = pCoexWinsize->tx_win_size;
+ pmadapter->coex_rx_win_size = pCoexWinsize->rx_win_size;
+ wlan_coex_ampdu_rxwinsize(pmadapter);
+ wlan_update_ampdu_txwinsize(pmadapter);
+ break;
+ case TLV_BTCOEX_WL_SCANTIME:
+ pScantlv = (MrvlIEtypes_BtCoexScanTime_t *)tlv;
+ pmadapter->coex_scan = pScantlv->coex_scan;
+ pmadapter->coex_min_scan_time =
+ wlan_le16_to_cpu(pScantlv->min_scan_time);
+ pmadapter->coex_max_scan_time =
+ wlan_le16_to_cpu(pScantlv->max_scan_time);
+ break;
+ default:
+ break;
+ }
+ len -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ pCurrent_ptr += tlv_len + sizeof(MrvlIEtypesHeader_t);
+ }
+ PRINTM(MEVENT,
+ "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
+ pmadapter->coex_scan, pmadapter->coex_min_scan_time,
+ pmadapter->coex_win_size, pmadapter->coex_tx_win_size,
+ pmadapter->coex_rx_win_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function prepares command of supplicant pmk
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_802_11_supplicant_pmk(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *ppassphrase_tlv = MNULL;
+ MrvlIEtypes_SAE_Password_t *psae_password_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ HostCmd_DS_802_11_SUPPLICANT_PMK *pesupplicant_psk =
+ &cmd->params.esupplicant_psk;
+ t_u8 *ptlv_buffer = (t_u8 *)pesupplicant_psk->tlv_buffer;
+ mlan_ds_sec_cfg *sec = (mlan_ds_sec_cfg *)pdata_buf;
+ mlan_ds_passphrase *psk = MNULL;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ t_u8 ssid_flag = 0, bssid_flag = 0, pmk_flag = 0, passphrase_flag = 0;
+ t_u8 sae_password_flag = 0;
+
+ ENTER();
+ psk = (mlan_ds_passphrase *)&sec->param.passphrase;
+
+ /*
+ * Parse the rest of the buf here
+ * 1) <ssid="valid ssid"> - This will get the passphrase, AKMP
+ * for specified ssid, if none specified then it will get all.
+ * Eg: iwpriv <mlanX> passphrase 0:ssid=nxp
+ * 2) <psk="psk">:<passphrase="passphare">:<bssid="00:50:43:ef:23:f3">
+ * <ssid="valid ssid"> - passphrase and psk cannot be provided to
+ * the same SSID, Takes one SSID at a time, If ssid= is present
+ * the it should contain a passphrase or psk. If no arguments are
+ * provided then AKMP=802.1x, and passphrase should be provided
+ * after association.
+ * End of each parameter should be followed by a ':'(except for the
+ * last parameter) as the delimiter. If ':' has to be used in
+ * an SSID then a '/' should be preceded to ':' as a escape.
+ * Eg:iwpriv <mlanX> passphrase
+ * "1:ssid=mrvl AP:psk=abcdefgh:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase
+ * "1:ssid=nxp/: AP:psk=abcdefgd:bssid=00:50:43:ef:23:f3"
+ * iwpriv <mlanX> passphrase "1:ssid=mrvlAP:psk=abcdefgd"
+ * 3) <ssid="valid ssid"> - This will clear the passphrase
+ * for specified ssid, if none specified then it will clear all.
+ * Eg: iwpriv <mlanX> passphrase 2:ssid=nxp
+ */
+
+ /* -1 is for t_u8 TlvBuffer[1] as this should not be included */
+ cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1;
+ if (psk && memcmp(pmpriv->adapter, (t_u8 *)&psk->bssid, zero_mac,
+ sizeof(zero_mac))) {
+ pbssid_tlv = (MrvlIEtypes_Bssid_t *)ptlv_buffer;
+ pbssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BSSID);
+ pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
+ memcpy_ext(pmpriv->adapter, pbssid_tlv->bssid,
+ (t_u8 *)&psk->bssid, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ ptlv_buffer +=
+ (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pbssid_tlv->header.len =
+ wlan_cpu_to_le16(pbssid_tlv->header.len);
+ bssid_flag = 1;
+ }
+ if (psk && (psk->psk_type == MLAN_PSK_PMK)) {
+ ppmk_tlv = (MrvlIEtypes_PMK_t *)ptlv_buffer;
+ ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK);
+ ppmk_tlv->header.len = MLAN_MAX_KEY_LENGTH;
+ memcpy_ext(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk,
+ MLAN_MAX_KEY_LENGTH, MLAN_MAX_KEY_LENGTH);
+ ptlv_buffer +=
+ (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len);
+ pmk_flag = 1;
+ }
+ if (psk->ssid.ssid_len) {
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *)ptlv_buffer;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len =
+ (t_u16)MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len);
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pssid_tlv->ssid,
+ (t_u8 *)psk->ssid.ssid, psk->ssid.ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ ptlv_buffer +=
+ (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ cmd->size +=
+ (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t));
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+ ssid_flag = 1;
+ }
+ if (psk->psk_type == MLAN_PSK_PASSPHRASE) {
+ ppassphrase_tlv = (MrvlIEtypes_Passphrase_t *)ptlv_buffer;
+ ppassphrase_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PASSPHRASE);
+ ppassphrase_tlv->header.len =
+ (t_u16)MIN(MLAN_MAX_PASSPHRASE_LENGTH,
+ psk->psk.passphrase.passphrase_len);
+ memcpy_ext(pmpriv->adapter, ppassphrase_tlv->passphrase,
+ psk->psk.passphrase.passphrase,
+ psk->psk.passphrase.passphrase_len,
+ MLAN_MAX_PASSPHRASE_LENGTH);
+ ptlv_buffer += (ppassphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (ppassphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ ppassphrase_tlv->header.len =
+ wlan_cpu_to_le16(ppassphrase_tlv->header.len);
+ passphrase_flag = 1;
+ }
+ if (psk->psk_type == MLAN_PSK_SAE_PASSWORD) {
+ psae_password_tlv = (MrvlIEtypes_SAE_Password_t *)ptlv_buffer;
+ psae_password_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SAE_PASSWORD);
+ psae_password_tlv->header.len =
+ (t_u16)MIN(MLAN_MAX_SAE_PASSWORD_LENGTH,
+ psk->psk.sae_password.sae_password_len);
+ memcpy_ext(pmpriv->adapter, psae_password_tlv->sae_password,
+ psk->psk.sae_password.sae_password,
+ psk->psk.sae_password.sae_password_len,
+ MLAN_MAX_SAE_PASSWORD_LENGTH);
+ ptlv_buffer += (psae_password_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (psae_password_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ psae_password_tlv->header.len =
+ wlan_cpu_to_le16(psae_password_tlv->header.len);
+ sae_password_flag = 1;
+ }
+ if ((cmd_action == HostCmd_ACT_GEN_SET) &&
+ ((ssid_flag || bssid_flag) && (!pmk_flag && !passphrase_flag) &&
+ (!pmk_flag && !sae_password_flag))) {
+ PRINTM(MERROR,
+ "Invalid case,ssid/bssid present without pmk, passphrase or sae password\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK);
+ pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action);
+ pesupplicant_psk->cache_result = 0;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant pmk response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_supplicant_pmk(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PMK *supplicant_pmk_resp =
+ &resp->params.esupplicant_psk;
+ mlan_ds_sec_cfg *sec_buf = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ MrvlIEtypes_PMK_t *ppmk_tlv = MNULL;
+ MrvlIEtypes_Passphrase_t *passphrase_tlv = MNULL;
+ MrvlIEtypes_SAE_Password_t *psae_password_tlv = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL;
+ MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL;
+ t_u8 *tlv_buf = (t_u8 *)supplicant_pmk_resp->tlv_buffer;
+ t_u16 action = wlan_le16_to_cpu(supplicant_pmk_resp->action);
+ int tlv_buf_len = 0;
+ t_u16 tlv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ tlv_buf_len = resp->size -
+ (sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1);
+
+ if (pioctl_buf) {
+ if (((mlan_ds_bss *)pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS) {
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_sec_cfg),
+ MLAN_MEM_DEF, (t_u8 **)&sec_buf);
+ if (ret || !sec_buf) {
+ PRINTM(MERROR, "Could not allocate sec_buf!\n");
+ LEAVE();
+ return ret;
+ }
+ sec = sec_buf;
+ } else {
+ sec = (mlan_ds_sec_cfg *)pioctl_buf->pbuf;
+ }
+ if (action == HostCmd_ACT_GEN_GET) {
+ while (tlv_buf_len > 0) {
+ tlv = (*tlv_buf) | (*(tlv_buf + 1) << 8);
+ if ((tlv != TLV_TYPE_SSID) &&
+ (tlv != TLV_TYPE_BSSID) &&
+ (tlv != TLV_TYPE_PASSPHRASE) &&
+ (tlv != TLV_TYPE_PMK) &&
+ (tlv != TLV_TYPE_SAE_PASSWORD))
+ break;
+ switch (tlv) {
+ case TLV_TYPE_SSID:
+ pssid_tlv =
+ (MrvlIEtypes_SsIdParamSet_t *)
+ tlv_buf;
+ pssid_tlv->header.len =
+ wlan_le16_to_cpu(
+ pssid_tlv->header.len);
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.passphrase.ssid.ssid,
+ pssid_tlv->ssid,
+ pssid_tlv->header.len,
+ MLAN_MAX_SSID_LENGTH);
+ sec->param.passphrase.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH,
+ pssid_tlv->header.len);
+ tlv_buf += pssid_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pssid_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_BSSID:
+ pbssid_tlv =
+ (MrvlIEtypes_Bssid_t *)tlv_buf;
+ pbssid_tlv->header.len =
+ wlan_le16_to_cpu(
+ pbssid_tlv->header.len);
+ memcpy_ext(pmpriv->adapter,
+ &sec->param.passphrase.bssid,
+ pbssid_tlv->bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ tlv_buf += pbssid_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (pbssid_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PASSPHRASE:
+ passphrase_tlv =
+ (MrvlIEtypes_Passphrase_t *)
+ tlv_buf;
+ passphrase_tlv->header
+ .len = wlan_le16_to_cpu(
+ passphrase_tlv->header.len);
+ sec->param.passphrase.psk_type =
+ MLAN_PSK_PASSPHRASE;
+ sec->param.passphrase.psk.passphrase
+ .passphrase_len =
+ passphrase_tlv->header.len;
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.passphrase.psk
+ .passphrase.passphrase,
+ passphrase_tlv->passphrase,
+ passphrase_tlv->header.len,
+ MLAN_MAX_PASSPHRASE_LENGTH);
+ tlv_buf += passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (passphrase_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_SAE_PASSWORD:
+ psae_password_tlv =
+ (MrvlIEtypes_SAE_Password_t *)
+ tlv_buf;
+ psae_password_tlv->header
+ .len = wlan_le16_to_cpu(
+ psae_password_tlv->header.len);
+ sec->param.passphrase.psk_type =
+ MLAN_PSK_SAE_PASSWORD;
+ sec->param.passphrase.psk.sae_password
+ .sae_password_len =
+ psae_password_tlv->header.len;
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.passphrase.psk
+ .sae_password
+ .sae_password,
+ psae_password_tlv->sae_password,
+ psae_password_tlv->header.len,
+ MLAN_MAX_SAE_PASSWORD_LENGTH);
+ tlv_buf +=
+ psae_password_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (psae_password_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_PMK:
+ ppmk_tlv = (MrvlIEtypes_PMK_t *)tlv_buf;
+ ppmk_tlv->header.len = wlan_le16_to_cpu(
+ ppmk_tlv->header.len);
+ sec->param.passphrase.psk_type =
+ MLAN_PSK_PMK;
+ memcpy_ext(pmpriv->adapter,
+ sec->param.passphrase.psk.pmk
+ .pmk,
+ ppmk_tlv->pmk,
+ ppmk_tlv->header.len,
+ MLAN_MAX_KEY_LENGTH);
+ tlv_buf += ppmk_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -=
+ (ppmk_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ }
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA &&
+ ((mlan_ds_bss *)pioctl_buf->pbuf)->sub_command ==
+ MLAN_OID_BSS_FIND_BSS) {
+ wlan_set_ewpa_mode(pmpriv,
+ &sec->param.passphrase);
+ ret = wlan_find_bss(pmpriv, pioctl_buf);
+ }
+#endif
+
+ } else if (action == HostCmd_ACT_GEN_SET) {
+ PRINTM(MINFO, "Esupp PMK set: enable ewpa query\n");
+ pmpriv->ewpa_query = MTRUE;
+ }
+ if (sec_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)sec_buf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of independent reset.
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_ind_rst_cfg(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ mlan_ds_ind_rst_cfg *pdata_ind_rst = (mlan_ds_ind_rst_cfg *)pdata_buf;
+ HostCmd_DS_INDEPENDENT_RESET_CFG *ind_rst_cfg =
+ (HostCmd_DS_INDEPENDENT_RESET_CFG *)&cmd->params.ind_rst_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_INDEPENDENT_RESET_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_INDEPENDENT_RESET_CFG) +
+ S_DS_GEN);
+
+ ind_rst_cfg->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ ind_rst_cfg->ir_mode = pdata_ind_rst->ir_mode;
+ ind_rst_cfg->gpio_pin = pdata_ind_rst->gpio_pin;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of independent reset
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_ind_rst_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ const HostCmd_DS_INDEPENDENT_RESET_CFG *ind_rst_cfg =
+ (HostCmd_DS_INDEPENDENT_RESET_CFG *)&resp->params.ind_rst_cfg;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ if (wlan_le16_to_cpu(ind_rst_cfg->action) ==
+ HostCmd_ACT_GEN_GET) {
+ misc->param.ind_rst_cfg.ir_mode = ind_rst_cfg->ir_mode;
+ misc->param.ind_rst_cfg.gpio_pin =
+ ind_rst_cfg->gpio_pin;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ps inactivity timeout.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_ps_inactivity_timeout(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ t_u16 timeout = *((t_u16 *)pdata_buf);
+ HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT *ps_inact_tmo =
+ (HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT *)&cmd->params
+ .ps_inact_tmo;
+
+ ENTER();
+
+ cmd->command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT) + S_DS_GEN);
+
+ ps_inact_tmo->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ ps_inact_tmo->inact_tmo = wlan_cpu_to_le16(timeout);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of HostCmd_CMD_GET_TSF
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF);
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_TSF)) + S_DS_GEN);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of HostCmd_CMD_GET_TSF
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ HostCmd_DS_TSF *tsf_pointer = (HostCmd_DS_TSF *)&resp->params.tsf;
+
+ ENTER();
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.misc_tsf = wlan_le64_to_cpu(tsf_pointer->tsf);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of chan_region_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_chan_region_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 action;
+ HostCmd_DS_CHAN_REGION_CFG *reg = MNULL;
+ t_u8 *tlv_buf = MNULL;
+ t_u16 tlv_buf_left;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ mlan_ds_misc_chnrgpwr_cfg *cfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ reg = (HostCmd_DS_CHAN_REGION_CFG *)&resp->params.reg_cfg;
+ if (!reg) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ action = wlan_le16_to_cpu(reg->action);
+ if (action != HostCmd_ACT_GEN_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ tlv_buf = (t_u8 *)reg + sizeof(*reg);
+ tlv_buf_left = wlan_le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*reg);
+
+ /* Add FW cfp tables and region info */
+ wlan_add_fw_cfp_tables(pmpriv, tlv_buf, tlv_buf_left);
+
+ if (!pioctl_buf)
+ goto done;
+
+ if (!pioctl_buf->pbuf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ if (misc_cfg->sub_command == MLAN_OID_MISC_GET_REGIONPWR_CFG) {
+ cfg = (mlan_ds_misc_chnrgpwr_cfg *)&(
+ misc_cfg->param.rgchnpwr_cfg);
+ cfg->length = wlan_le16_to_cpu(resp->size);
+ memcpy_ext(pmpriv->adapter, cfg->chnrgpwr_buf, (t_u8 *)resp,
+ cfg->length, sizeof(cfg->chnrgpwr_buf));
+ } else {
+ memset(pmpriv->adapter, &misc_cfg->param.custom_reg_domain, 0,
+ sizeof(mlan_ds_custom_reg_domain));
+ if (pmadapter->otp_region)
+ memcpy_ext(pmpriv->adapter,
+ &misc_cfg->param.custom_reg_domain.region,
+ pmadapter->otp_region,
+ sizeof(otp_region_info_t),
+ sizeof(otp_region_info_t));
+ if (pmadapter->cfp_otp_bg) {
+ misc_cfg->param.custom_reg_domain.num_bg_chan =
+ pmadapter->tx_power_table_bg_rows;
+ memcpy_ext(pmpriv->adapter,
+ (t_u8 *)misc_cfg->param.custom_reg_domain
+ .cfp_tbl,
+ (t_u8 *)pmadapter->cfp_otp_bg,
+ pmadapter->tx_power_table_bg_rows *
+ sizeof(chan_freq_power_t),
+ pmadapter->tx_power_table_bg_rows *
+ sizeof(chan_freq_power_t));
+ }
+ if (pmadapter->cfp_otp_a) {
+ misc_cfg->param.custom_reg_domain.num_a_chan =
+ pmadapter->tx_power_table_a_rows;
+ memcpy_ext(pmpriv->adapter,
+ (t_u8 *)misc_cfg->param.custom_reg_domain
+ .cfp_tbl +
+ pmadapter->tx_power_table_bg_rows *
+ sizeof(chan_freq_power_t),
+ (t_u8 *)pmadapter->cfp_otp_a,
+ pmadapter->tx_power_table_a_rows *
+ sizeof(chan_freq_power_t),
+ pmadapter->tx_power_table_a_rows *
+ sizeof(chan_freq_power_t));
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of packet aggragation
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_packet_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_PACKET_AGGR_CTRL *aggr_ctrl = &cmd->params.aggr_ctrl;
+ mlan_ds_misc_aggr_ctrl *aggr = (mlan_ds_misc_aggr_ctrl *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PACKET_AGGR_CTRL);
+ aggr_ctrl->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_PACKET_AGGR_CTRL) +
+ S_DS_GEN);
+ aggr_ctrl->aggr_enable = 0;
+
+ if (aggr->tx.enable)
+ aggr_ctrl->aggr_enable |= MBIT(0);
+ aggr_ctrl->aggr_enable = wlan_cpu_to_le16(aggr_ctrl->aggr_enable);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * packet aggregation
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_packet_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ HostCmd_DS_PACKET_AGGR_CTRL *aggr_ctrl = &resp->params.aggr_ctrl;
+ mlan_ds_misc_aggr_ctrl *aggr = MNULL;
+#if defined(USB)
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 i;
+ t_u8 change = 0;
+ usb_tx_aggr_params *pusb_tx_aggr = MNULL;
+#endif
+
+ ENTER();
+
+ aggr_ctrl->aggr_enable = wlan_le16_to_cpu(aggr_ctrl->aggr_enable);
+ aggr_ctrl->tx_aggr_max_size =
+ wlan_le16_to_cpu(aggr_ctrl->tx_aggr_max_size);
+ aggr_ctrl->tx_aggr_max_num =
+ wlan_le16_to_cpu(aggr_ctrl->tx_aggr_max_num);
+ aggr_ctrl->tx_aggr_align = wlan_le16_to_cpu(aggr_ctrl->tx_aggr_align);
+ PRINTM(MCMND, "enable=0x%x, tx_size=%d, tx_num=%d, tx_align=%d\n",
+ aggr_ctrl->aggr_enable, aggr_ctrl->tx_aggr_max_size,
+ aggr_ctrl->tx_aggr_max_num, aggr_ctrl->tx_aggr_align);
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ if (aggr_ctrl->aggr_enable & MBIT(0)) {
+ if (!pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.enable) {
+ pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.enable = MTRUE;
+ change = MTRUE;
+ }
+
+ } else {
+ if (pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.enable) {
+ pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.enable = MFALSE;
+ change = MTRUE;
+ }
+ }
+ pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_mode =
+ MLAN_USB_AGGR_MODE_LEN_V2;
+ pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_align =
+ aggr_ctrl->tx_aggr_align;
+ pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_max =
+ aggr_ctrl->tx_aggr_max_size;
+ pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_tmo =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
+ if (change) {
+ wlan_reset_usb_tx_aggr(pmadapter);
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ if (pmadapter->priv[i]) {
+ pusb_tx_aggr =
+ wlan_get_usb_tx_aggr_params(
+ pmadapter,
+ pmadapter->priv[i]
+ ->port);
+ if (pusb_tx_aggr &&
+ pusb_tx_aggr->aggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_LEN_V2)
+ pmadapter->priv[i]->intf_hr_len =
+ MLAN_USB_TX_AGGR_HEADER;
+ else
+ pmadapter->priv[i]->intf_hr_len =
+ USB_INTF_HEADER_LEN;
+ }
+ }
+ }
+ }
+#endif
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ aggr = (mlan_ds_misc_aggr_ctrl *)&(misc->param.aggr_params);
+ if (aggr_ctrl->aggr_enable & MBIT(0))
+ aggr->tx.enable = MTRUE;
+ else
+ aggr->tx.enable = MFALSE;
+ aggr->tx.aggr_align = aggr_ctrl->tx_aggr_align;
+ aggr->tx.aggr_max_size = aggr_ctrl->tx_aggr_max_size;
+ aggr->tx.aggr_max_num = aggr_ctrl->tx_aggr_max_num;
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type))
+ aggr->tx.aggr_tmo = pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.aggr_tmo;
+#endif
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends fw dump event command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd Hostcmd ID
+ * @param cmd_action Command action
+ * @param pdata_buf A void pointer to information buffer
+ * @return N/A
+ */
+mlan_status wlan_cmd_fw_dump_event(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_FW_DUMP_EVENT);
+ cmd->size = S_DS_GEN;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of get link layer statistics.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_cmd_802_11_link_statistic(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_get_info *info = (mlan_ds_get_info *)(pioctl_buf->pbuf);
+ HostCmd_DS_802_11_LINK_STATISTIC *ll_stat =
+ &cmd->params.get_link_statistic;
+ wifi_link_layer_params *ll_params = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_LINK_STATS);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN +
+ sizeof(HostCmd_DS_802_11_LINK_STATISTIC));
+ ll_stat->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ ll_params =
+ (wifi_link_layer_params *)info->param.link_statistic;
+ ll_stat->mpdu_size_threshold =
+ wlan_cpu_to_le32(ll_params->mpdu_size_threshold);
+ ll_stat->aggressive_statistics_gathering = wlan_cpu_to_le32(
+ ll_params->aggressive_statistics_gathering);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ /** ll_stat->stat_type = wlan_cpu_to_le16(stat_type); */
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function fill link layer statistic from firmware
+ *
+ * @param priv A pointer to
+ * mlan_private structure
+ * @param link_statistic_ioctl_buf, A pointer to fill ioctl buffer
+ * @param resp A pointer to
+ * HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static void wlan_fill_link_statistic(mlan_private *priv,
+ char *link_statistic_ioctl_buf,
+ HostCmd_DS_COMMAND *resp)
+{
+ char *link_statistic = link_statistic_ioctl_buf;
+ wifi_radio_stat *radio_stat = MNULL;
+ wifi_iface_stat *iface_stat = MNULL;
+ mlan_wifi_iface_stat *fw_ifaceStat = MNULL;
+ mlan_wifi_radio_stat *fw_radioStat = MNULL;
+ t_u32 num_radio = 0;
+ int i = 0, chan_idx = 0, peerIdx = 0, rate_idx = 0;
+ t_u16 left_len = 0, tlv_type = 0, tlv_len = 0;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ HostCmd_DS_802_11_LINK_STATISTIC *plink_stat =
+ (HostCmd_DS_802_11_LINK_STATISTIC *)&resp->params
+ .get_link_statistic;
+
+ /* TLV parse */
+ left_len = resp->size - sizeof(HostCmd_DS_802_11_LINK_STATISTIC) -
+ S_DS_GEN;
+ tlv = (MrvlIEtypesHeader_t *)(plink_stat->value);
+ DBG_HEXDUMP(MCMD_D, "tlv:", (void *)tlv, 1024);
+ while (left_len > sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ switch (tlv_type) {
+ case TLV_TYPE_LL_STAT_IFACE:
+ fw_ifaceStat = (mlan_wifi_iface_stat
+ *)((t_u8 *)tlv +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ case TLV_TYPE_LL_STAT_RADIO:
+ fw_radioStat = (mlan_wifi_radio_stat
+ *)((t_u8 *)tlv +
+ sizeof(MrvlIEtypesHeader_t));
+ num_radio = MAX_RADIO;
+ break;
+ default:
+ break;
+ }
+ left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ if (!fw_ifaceStat || !fw_radioStat) {
+ PRINTM(MERROR, "!fw_ifaceStat || !fw_radioStat\n");
+ return;
+ }
+
+ *((t_u32 *)link_statistic) = num_radio;
+ link_statistic += sizeof(num_radio);
+
+ /* Fill radio stats array*/
+ for (i = 0; i < num_radio; i++) {
+ radio_stat = (wifi_radio_stat *)link_statistic;
+ link_statistic += sizeof(wifi_radio_stat);
+
+ radio_stat->radio = wlan_le32_to_cpu(fw_radioStat[i].radio);
+
+ radio_stat->on_time = wlan_le32_to_cpu(fw_radioStat[i].on_time);
+ radio_stat->tx_time = wlan_le32_to_cpu(fw_radioStat[i].tx_time);
+ radio_stat->reserved0 =
+ wlan_le32_to_cpu(fw_radioStat[i].reserved0);
+ radio_stat->rx_time = wlan_le32_to_cpu(fw_radioStat[i].rx_time);
+ radio_stat->on_time_scan =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_scan);
+ radio_stat->on_time_nbd =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_nbd);
+ radio_stat->on_time_gscan =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_gscan);
+ radio_stat->on_time_roam_scan =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_roam_scan);
+ radio_stat->on_time_pno_scan =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_pno_scan);
+ radio_stat->on_time_hs20 =
+ wlan_le32_to_cpu(fw_radioStat[i].on_time_hs20);
+
+ radio_stat->num_channels =
+ wlan_le32_to_cpu(fw_radioStat[i].num_channels);
+ for (chan_idx = 0; chan_idx < radio_stat->num_channels;
+ chan_idx++) {
+ if (radio_stat->num_channels > MAX_NUM_CHAN) {
+ radio_stat->num_channels =
+ wlan_le32_to_cpu(MAX_NUM_CHAN);
+ PRINTM(MERROR,
+ "%s : radio_stat->num_channels=%d\n",
+ __func__, radio_stat->num_channels);
+ break;
+ }
+ radio_stat->channels[chan_idx].channel.width =
+ wlan_le32_to_cpu(fw_radioStat[i]
+ .channels[chan_idx]
+ .channel.width);
+ radio_stat->channels[chan_idx].channel.center_freq =
+ wlan_le32_to_cpu(fw_radioStat[i]
+ .channels[chan_idx]
+ .channel.center_freq);
+ radio_stat->channels[chan_idx].channel.center_freq0 =
+ wlan_le32_to_cpu(fw_radioStat[i]
+ .channels[chan_idx]
+ .channel.center_freq0);
+ radio_stat->channels[chan_idx].channel.center_freq1 =
+ wlan_le32_to_cpu(fw_radioStat[i]
+ .channels[chan_idx]
+ .channel.center_freq1);
+
+ radio_stat->channels[chan_idx]
+ .on_time = wlan_le32_to_cpu(
+ fw_radioStat[i].channels[chan_idx].on_time);
+ radio_stat->channels[chan_idx].cca_busy_time =
+ wlan_le32_to_cpu(fw_radioStat[i]
+ .channels[chan_idx]
+ .cca_busy_time);
+ }
+ }
+
+ /* Fill iface stats*/
+ iface_stat = (wifi_iface_stat *)link_statistic;
+
+ /* get wifi_interface_link_layer_info in driver, not in firmware */
+ if (priv->bss_role == MLAN_BSS_ROLE_STA) {
+ iface_stat->info.mode = MLAN_INTERFACE_STA;
+ if (priv->media_connected)
+ iface_stat->info.state = MLAN_ASSOCIATING;
+ else
+ iface_stat->info.state = MLAN_DISCONNECTED;
+ iface_stat->info.roaming = MLAN_ROAMING_IDLE;
+ iface_stat->info.capabilities = MLAN_CAPABILITY_QOS;
+ memcpy_ext(priv->adapter, iface_stat->info.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ MLAN_MAX_SSID_LENGTH, MLAN_MAX_SSID_LENGTH);
+ memcpy_ext(priv->adapter, iface_stat->info.bssid,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ iface_stat->info.mode = MLAN_INTERFACE_SOFTAP;
+ iface_stat->info.capabilities = MLAN_CAPABILITY_QOS;
+ }
+ memcpy_ext(priv->adapter, iface_stat->info.mac_addr, priv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(priv->adapter, iface_stat->info.ap_country_str,
+ priv->adapter->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ memcpy_ext(priv->adapter, iface_stat->info.country_str,
+ priv->adapter->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+
+ iface_stat->beacon_rx = wlan_le32_to_cpu(fw_ifaceStat->beacon_rx);
+ iface_stat->average_tsf_offset =
+ wlan_le64_to_cpu(fw_ifaceStat->average_tsf_offset);
+ iface_stat->leaky_ap_detected =
+ wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_detected);
+ iface_stat->leaky_ap_avg_num_frames_leaked =
+ wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_avg_num_frames_leaked);
+ iface_stat->leaky_ap_guard_time =
+ wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_guard_time);
+
+ /* Value of iface_stat should be Reaccumulate by each peer */
+ iface_stat->mgmt_rx = wlan_le32_to_cpu(fw_ifaceStat->mgmt_rx);
+ iface_stat->mgmt_action_rx =
+ wlan_le32_to_cpu(fw_ifaceStat->mgmt_action_rx);
+ iface_stat->mgmt_action_tx =
+ wlan_le32_to_cpu(fw_ifaceStat->mgmt_action_tx);
+
+ iface_stat->rssi_mgmt = wlan_le32_to_cpu(fw_ifaceStat->rssi_mgmt);
+ iface_stat->rssi_data = wlan_le32_to_cpu(fw_ifaceStat->rssi_data);
+ iface_stat->rssi_ack = wlan_le32_to_cpu(fw_ifaceStat->rssi_ack);
+
+ for (i = WMM_AC_BK; i <= WMM_AC_VO; i++) {
+ iface_stat->ac[i].ac = i;
+ iface_stat->ac[i].tx_mpdu =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_mpdu);
+ iface_stat->ac[i].rx_mpdu =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_mpdu);
+ iface_stat->ac[i].tx_mcast =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_mcast);
+ iface_stat->ac[i].rx_mcast =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_mcast);
+ iface_stat->ac[i].rx_ampdu =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_ampdu);
+ iface_stat->ac[i].tx_ampdu =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_ampdu);
+ iface_stat->ac[i].mpdu_lost =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].mpdu_lost);
+ iface_stat->ac[i].retries =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries);
+ iface_stat->ac[i].retries_short =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries_short);
+ iface_stat->ac[i].retries_long =
+ wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries_long);
+ iface_stat->ac[i].contention_time_min = wlan_le32_to_cpu(
+ fw_ifaceStat->ac[i].contention_time_min);
+ iface_stat->ac[i].contention_time_max = wlan_le32_to_cpu(
+ fw_ifaceStat->ac[i].contention_time_max);
+ iface_stat->ac[i].contention_time_avg = wlan_le32_to_cpu(
+ fw_ifaceStat->ac[i].contention_time_avg);
+ iface_stat->ac[i].contention_num_samples = wlan_le32_to_cpu(
+ fw_ifaceStat->ac[i].contention_num_samples);
+ }
+
+ /* LL_STAT V3: STA-solution: support maxium 1 peers for AP*/
+ iface_stat->num_peers = wlan_le32_to_cpu(fw_ifaceStat->num_peers);
+ for (peerIdx = 0; peerIdx < iface_stat->num_peers; peerIdx++) {
+ iface_stat->peer_info[peerIdx].type =
+ fw_ifaceStat->peer_info[peerIdx].type;
+ memcpy_ext(priv->adapter,
+ iface_stat->peer_info[peerIdx].peer_mac_address,
+ fw_ifaceStat->peer_info[peerIdx].peer_mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ iface_stat->peer_info[peerIdx].capabilities = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx].capabilities);
+ iface_stat->peer_info[peerIdx].num_rate = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx].num_rate);
+
+ PRINTM(MINFO,
+ "bitrate tx_mpdu rx_mpdu mpdu_lost retries retries_short retries_long\n");
+ for (rate_idx = 0;
+ rate_idx < iface_stat->peer_info[peerIdx].num_rate;
+ rate_idx++) {
+ wlan_fill_hal_wifi_rate(priv,
+ &fw_ifaceStat
+ ->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rate,
+ &iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rate);
+
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .tx_mpdu = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .tx_mpdu);
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rx_mpdu = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rx_mpdu);
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .mpdu_lost = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .mpdu_lost);
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries);
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_short = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_short);
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_long = wlan_le32_to_cpu(
+ fw_ifaceStat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_long);
+ PRINTM(MCMND,
+ "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rate.bitrate,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .tx_mpdu,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .rx_mpdu,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .mpdu_lost,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_short,
+ iface_stat->peer_info[peerIdx]
+ .rate_stats[rate_idx]
+ .retries_long);
+ }
+ }
+}
+
+/**
+ * @brief This function handles the command response of get_link_statistic
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_get_link_statistic(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_get_info *info;
+ t_u8 *link_statistic = MNULL;
+ t_u16 action = wlan_le16_to_cpu(resp->params.get_link_statistic.action);
+
+ ENTER();
+
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ link_statistic = info->param.link_statistic;
+
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ wlan_fill_link_statistic(pmpriv, link_statistic, resp);
+ break;
+ case HostCmd_ACT_GEN_SET:
+ case HostCmd_ACT_GEN_REMOVE:
+ /* nothing to do */
+ break;
+ default:
+ break;
+ }
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written =
+ BUF_MAXLEN + MLAN_SUB_COMMAND_SIZE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends boot sleep configure command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd Hostcmd ID
+ * @param cmd_action Command action
+ * @param pdata_buf A void pointer to information buffer
+ * @return MLAN_STATUS_SUCCESS/ MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_BOOT_SLEEP *boot_sleep = MNULL;
+ t_u16 enable = *(t_u16 *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_BOOT_SLEEP);
+ boot_sleep = &cmd->params.boot_sleep;
+ boot_sleep->action = wlan_cpu_to_le16(cmd_action);
+ boot_sleep->enable = wlan_cpu_to_le16(enable);
+
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_BOOT_SLEEP);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of boot sleep cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_BOOT_SLEEP *boot_sleep = &resp->params.boot_sleep;
+ mlan_ds_misc_cfg *cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ ENTER();
+
+ cfg->param.boot_sleep = wlan_le16_to_cpu(boot_sleep->enable);
+ PRINTM(MCMND, "boot sleep cfg status %u", cfg->param.boot_sleep);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+
+/**
+ * @brief This function handles send crypto command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd Hostcmd ID
+ * @param cmd_action Command action
+ * @param pdata_buf A void pointer to information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_crypto(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf)
+{
+ HostCmd_DS_CRYPTO *cry_cmd = &cmd->params.crypto_cmd;
+ mlan_ds_sup_cfg *cfg = (mlan_ds_sup_cfg *)pdata_buf;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ subcmd_prf_hmac_sha1_t *prf_hmac_sha1 = MNULL;
+ subcmd_hmac_sha1_t *hmac_sha1 = MNULL;
+ subcmd_hmac_sha256_t *hmac_sha256 = MNULL;
+ subcmd_sha256_t *sha256 = MNULL;
+ subcmd_rijndael_t *rijndael = MNULL;
+ subcmd_rc4_t *rc4 = MNULL;
+ subcmd_md5_t *md5 = MNULL;
+ subcmd_mrvl_f_t *mrvl_f = MNULL;
+ subcmd_sha256_kdf_t *sha256_kdf = MNULL;
+ t_u8 *ptlv = MNULL;
+ t_u8 tlv_bitmap = 0;
+ t_u32 i = 0;
+#endif
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CRYPTO);
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_CRYPTO);
+ cry_cmd->action = wlan_cpu_to_le16(cmd_action);
+ cry_cmd->subCmdCode = cfg->sub_command;
+ switch (cfg->sub_command) {
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ case HostCmd_CMD_CRYPTO_SUBCMD_PRF_HMAC_SHA1:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_PREFIX |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ prf_hmac_sha1 = (subcmd_prf_hmac_sha1_t *)cry_cmd->subCmd;
+ prf_hmac_sha1->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = prf_hmac_sha1->tlv;
+ cmd->size += sizeof(subcmd_prf_hmac_sha1_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_HMAC_SHA1:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ hmac_sha1 = (subcmd_hmac_sha1_t *)cry_cmd->subCmd;
+ hmac_sha1->output_len = cfg->output_len;
+ hmac_sha1->data_blks_nr = cfg->data_blks_nr;
+ /* set tlv start */
+ ptlv = hmac_sha1->tlv;
+ cmd->size += sizeof(subcmd_hmac_sha1_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_HMAC_SHA256:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ hmac_sha256 = (subcmd_hmac_sha256_t *)cry_cmd->subCmd;
+ hmac_sha256->output_len = cfg->output_len;
+ hmac_sha256->data_blks_nr = cfg->data_blks_nr;
+ /* set tlv start */
+ ptlv = hmac_sha256->tlv;
+ cmd->size += sizeof(subcmd_hmac_sha256_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_SHA256:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ sha256 = (subcmd_sha256_t *)cry_cmd->subCmd;
+ sha256->output_len = cfg->output_len;
+ sha256->data_blks_nr = cfg->data_blks_nr;
+ /* set tlv start */
+ ptlv = sha256->tlv;
+ cmd->size += sizeof(subcmd_sha256_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_RIJNDAEL:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ rijndael = (subcmd_rijndael_t *)cry_cmd->subCmd;
+ rijndael->sub_action_code = cfg->sub_action_code;
+ rijndael->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = rijndael->tlv;
+ cmd->size += sizeof(subcmd_rijndael_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_RC4:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_IV |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ rc4 = (subcmd_rc4_t *)cry_cmd->subCmd;
+ rc4->skip_bytes = cfg->skip_bytes;
+ rc4->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = rc4->tlv;
+ cmd->size += sizeof(subcmd_rc4_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_MD5:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ md5 = (subcmd_md5_t *)cry_cmd->subCmd;
+ md5->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = md5->tlv;
+ cmd->size += sizeof(subcmd_md5_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_MRVL_F:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ mrvl_f = (subcmd_mrvl_f_t *)cry_cmd->subCmd;
+ mrvl_f->iterations = cfg->iteration;
+ mrvl_f->count = cfg->count;
+ mrvl_f->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = mrvl_f->tlv;
+ cmd->size += sizeof(subcmd_mrvl_f_t);
+ break;
+ case HostCmd_CMD_CRYPTO_SUBCMD_SHA256_KDF:
+ tlv_bitmap = BIT_TLV_TYPE_CRYPTO_KEY |
+ BIT_TLV_TYPE_CRYPTO_KEY_PREFIX |
+ BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK;
+ /* set subcmd start */
+ sha256_kdf = (subcmd_sha256_kdf_t *)cry_cmd->subCmd;
+ sha256_kdf->output_len = cfg->output_len;
+ /* set tlv start */
+ ptlv = sha256_kdf->tlv;
+ cmd->size += sizeof(subcmd_sha256_kdf_t);
+ break;
+#endif
+ default:
+ break;
+ }
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ /* add tlv */
+ if (tlv_bitmap & BIT_TLV_TYPE_CRYPTO_KEY) {
+ ((MrvlIEParamSet_t *)ptlv)->Type =
+ wlan_cpu_to_le16(TLV_TYPE_CRYPTO_KEY);
+ ((MrvlIEParamSet_t *)ptlv)->Length =
+ wlan_cpu_to_le16(cfg->key_len);
+ memcpy_ext(pmpriv->adapter,
+ (t_u8 *)ptlv + sizeof(MrvlIEParamSet_t), cfg->key,
+ cfg->key_len, cfg->key_len);
+ cmd->size += cfg->key_len + sizeof(MrvlIEParamSet_t);
+ ptlv += cfg->key_len + sizeof(MrvlIEParamSet_t);
+ }
+
+ if (tlv_bitmap & BIT_TLV_TYPE_CRYPTO_KEY_PREFIX) {
+ ((MrvlIEParamSet_t *)ptlv)->Type =
+ wlan_cpu_to_le16(TLV_TYPE_CRYPTO_KEY_PREFIX);
+ ((MrvlIEParamSet_t *)ptlv)->Length =
+ wlan_cpu_to_le16(cfg->key_prefix_len);
+ memcpy_ext(pmpriv->adapter, ptlv + sizeof(MrvlIEParamSet_t),
+ cfg->key_prefix, cfg->key_prefix_len,
+ cfg->key_prefix_len);
+ cmd->size += cfg->key_prefix_len + sizeof(MrvlIEParamSet_t);
+ ptlv += cfg->key_prefix_len + sizeof(MrvlIEParamSet_t);
+ }
+
+ if (tlv_bitmap & BIT_TLV_TYPE_CRYPTO_KEY_IV) {
+ ((MrvlIEParamSet_t *)ptlv)->Type =
+ wlan_cpu_to_le16(TLV_TYPE_CRYPTO_KEY_IV);
+ ((MrvlIEParamSet_t *)ptlv)->Length =
+ wlan_cpu_to_le16(cfg->key_iv_len);
+ memcpy_ext(pmpriv->adapter, ptlv + sizeof(MrvlIEParamSet_t),
+ cfg->key_iv, cfg->key_iv_len, cfg->key_iv_len);
+ cmd->size += cfg->key_iv_len + sizeof(MrvlIEParamSet_t);
+ ptlv += cfg->key_iv_len + sizeof(MrvlIEParamSet_t);
+ }
+
+ if (tlv_bitmap & BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK) {
+ t_u16 data_blk_len = 0;
+ t_u8 *pdata_blk = MNULL;
+ for (i = 0; i < cfg->data_blks_nr; i++) {
+ data_blk_len = *(cfg->key_data_blk_len + i);
+ pdata_blk = *(cfg->key_data_blk + i);
+ ((MrvlIEParamSet_t *)ptlv)->Type =
+ wlan_cpu_to_le16(TLV_TYPE_CRYPTO_KEY_DATA_BLK);
+ ((MrvlIEParamSet_t *)ptlv)->Length =
+ wlan_cpu_to_le16(data_blk_len);
+ memcpy_ext(pmpriv->adapter,
+ ptlv + sizeof(MrvlIEParamSet_t), pdata_blk,
+ data_blk_len, data_blk_len);
+ cmd->size += data_blk_len + sizeof(MrvlIEParamSet_t);
+ ptlv += data_blk_len + sizeof(MrvlIEParamSet_t);
+ }
+ }
+#endif
+ HEXDUMP("HostCmd_DS_COMMAND wlan_cmd_crypto", cmd, cmd->size);
+
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of crypto command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_crypto(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CRYPTO *crypto_cmd = &resp->params.crypto_cmd;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
+ mlan_ds_sup_cfg *cfg = (mlan_ds_sup_cfg *)pioctl_buf->pbuf;
+#endif
+
+ ENTER();
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ if (!cfg) {
+ PRINTM(MERROR, "wlan_ret_crypto cfg is null \n");
+ goto done;
+ }
+ if (resp->result == HostCmd_RESULT_OK) {
+ /* copy the result */
+ memcpy_ext(pmpriv->adapter, cfg->output,
+ (t_u8 *)crypto_cmd + sizeof(HostCmd_DS_CRYPTO) +
+ sizeof(cfg->output_len),
+ cfg->output_len, cfg->output_len);
+ }
+
+ /* Prevent the ioctl from completing when the cmd is freed */
+ if (cfg->call_back) {
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ /* trigger wait q */
+ pcb->moal_notify_hostcmd_complete(pmadapter->pmoal_handle,
+ pmpriv->bss_index);
+ }
+#endif
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function prepares command of mac_address.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_mac_address(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.mac_addr.action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy_ext(pmpriv->adapter, cmd->params.mac_addr.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ /* HEXDUMP("SET_CMD: MAC ADDRESS-", priv->CurrentAddr, 6); */
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of mac_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_802_11_mac_address(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_MAC_ADDRESS *pmac_addr = &resp->params.mac_addr;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ memcpy_ext(pmpriv->adapter, pmpriv->curr_addr, pmac_addr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ PRINTM(MINFO, "MAC address: " MACSTR "\n", MAC2STR(pmpriv->curr_addr));
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ memcpy_ext(pmpriv->adapter, &bss->param.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ pioctl_buf->data_read_written =
+ MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Rx abort cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_RX_ABORT_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_RX_ABORT_CFG *)&cmd->params.rx_abort_cfg;
+ mlan_ds_misc_rx_abort_cfg *cfg = (mlan_ds_misc_rx_abort_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RX_ABORT_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RX_ABORT_CFG) +
+ S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->enable = (t_u8)cfg->enable;
+ cfg_cmd->rssi_threshold = (t_s8)cfg->rssi_threshold;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Rx Abort Cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_RX_ABORT_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_RX_ABORT_CFG *)&resp->params.rx_abort_cfg;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.rx_abort_cfg.enable = (t_u8)cfg_cmd->enable;
+ misc_cfg->param.rx_abort_cfg.rssi_threshold =
+ (t_s8)cfg_cmd->rssi_threshold;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Rx abort cfg ext
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_rxabortcfg_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_RX_ABORT_CFG_EXT *cfg_cmd =
+ (HostCmd_DS_CMD_RX_ABORT_CFG_EXT *)&cmd->params.rx_abort_cfg_ext;
+ mlan_ds_misc_rx_abort_cfg_ext *cfg =
+ (mlan_ds_misc_rx_abort_cfg_ext *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RX_ABORT_CFG_EXT);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RX_ABORT_CFG_EXT) +
+ S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->enable = (t_u8)cfg->enable;
+ cfg_cmd->rssi_margin = (t_s8)cfg->rssi_margin;
+ cfg_cmd->ceil_rssi_threshold = (t_s8)cfg->ceil_rssi_threshold;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Rx Abort Cfg ext
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_rxabortcfg_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_RX_ABORT_CFG_EXT *cfg_cmd =
+ (HostCmd_DS_CMD_RX_ABORT_CFG_EXT *)&resp->params
+ .rx_abort_cfg_ext;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.rx_abort_cfg_ext.enable = cfg_cmd->enable;
+ misc_cfg->param.rx_abort_cfg_ext.rssi_margin =
+ cfg_cmd->rssi_margin;
+ misc_cfg->param.rx_abort_cfg_ext.ceil_rssi_threshold =
+ cfg_cmd->ceil_rssi_threshold;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Dot11mc unassoc ftm cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *)&cmd->params
+ .dot11mc_unassoc_ftm_cfg;
+ mlan_ds_misc_dot11mc_unassoc_ftm_cfg *cfg =
+ (mlan_ds_misc_dot11mc_unassoc_ftm_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG) + S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->state = wlan_cpu_to_le16(cfg->state);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Dot11mc unassoc ftm cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *)&resp->params
+ .dot11mc_unassoc_ftm_cfg;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.dot11mc_unassoc_ftm_cfg.state =
+ wlan_le16_to_cpu(cfg_cmd->state);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Tx ampdu prot mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_tx_ampdu_prot_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *cfg_cmd =
+ (HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *)&cmd->params
+ .tx_ampdu_prot_mode;
+ mlan_ds_misc_tx_ampdu_prot_mode *cfg =
+ (mlan_ds_misc_tx_ampdu_prot_mode *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_AMPDU_PROT_MODE);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_TX_AMPDU_PROT_MODE) +
+ S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->mode = wlan_cpu_to_le16(cfg->mode);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Tx ampdu prot mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_tx_ampdu_prot_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *cfg_cmd =
+ (HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *)&resp->params
+ .tx_ampdu_prot_mode;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.tx_ampdu_prot_mode.mode =
+ wlan_le16_to_cpu(cfg_cmd->mode);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Rate Adapt cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_rate_adapt_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_RATE_ADAPT_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_RATE_ADAPT_CFG *)&cmd->params.rate_adapt_cfg;
+ mlan_ds_misc_rate_adapt_cfg *cfg =
+ (mlan_ds_misc_rate_adapt_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RATE_ADAPT_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RATE_ADAPT_CFG) +
+ S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->sr_rateadapt = (t_u8)cfg->sr_rateadapt;
+ cfg_cmd->ra_low_thresh = (t_u8)cfg->ra_low_thresh;
+ cfg_cmd->ra_high_thresh = (t_u8)cfg->ra_high_thresh;
+ cfg_cmd->ra_interval = wlan_cpu_to_le16(cfg->ra_interval);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Rate Adapt Cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_rate_adapt_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_RATE_ADAPT_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_RATE_ADAPT_CFG *)&resp->params.rate_adapt_cfg;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.rate_adapt_cfg.sr_rateadapt =
+ (t_u8)cfg_cmd->sr_rateadapt;
+ misc_cfg->param.rate_adapt_cfg.ra_low_thresh =
+ (t_u8)cfg_cmd->ra_low_thresh;
+ misc_cfg->param.rate_adapt_cfg.ra_high_thresh =
+ (t_u8)cfg_cmd->ra_high_thresh;
+ misc_cfg->param.rate_adapt_cfg.ra_interval =
+ wlan_le16_to_cpu(cfg_cmd->ra_interval);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of CCK Desense cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_cck_desense_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_CCK_DESENSE_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_CCK_DESENSE_CFG *)&cmd->params.cck_desense_cfg;
+ mlan_ds_misc_cck_desense_cfg *cfg =
+ (mlan_ds_misc_cck_desense_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CCK_DESENSE_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_CCK_DESENSE_CFG) +
+ S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->mode = wlan_cpu_to_le16(cfg->mode);
+ cfg_cmd->margin = (t_s8)cfg->margin;
+ cfg_cmd->ceil_thresh = (t_s8)cfg->ceil_thresh;
+ cfg_cmd->num_on_intervals = (t_u8)cfg->num_on_intervals;
+ cfg_cmd->num_off_intervals = (t_u8)cfg->num_off_intervals;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of CCK Desense Cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_cck_desense_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_CCK_DESENSE_CFG *cfg_cmd =
+ (HostCmd_DS_CMD_CCK_DESENSE_CFG *)&resp->params.cck_desense_cfg;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.cck_desense_cfg.mode =
+ wlan_le16_to_cpu(cfg_cmd->mode);
+ misc_cfg->param.cck_desense_cfg.margin = (t_s8)cfg_cmd->margin;
+ misc_cfg->param.cck_desense_cfg.ceil_thresh =
+ (t_s8)cfg_cmd->ceil_thresh;
+ misc_cfg->param.cck_desense_cfg.num_on_intervals =
+ (t_u8)cfg_cmd->num_on_intervals;
+ misc_cfg->param.cck_desense_cfg.num_off_intervals =
+ (t_u8)cfg_cmd->num_off_intervals;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends dynamic bandwidth command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd Hostcmd ID
+ * @param cmd_action Command action
+ * @param pdata_buf A void pointer to information buffer
+ * @return N/A
+ */
+mlan_status wlan_cmd_config_dyn_bw(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_DYN_BW *dyn_bw_cmd = &cmd->params.dyn_bw;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DYN_BW);
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_DYN_BW);
+ dyn_bw_cmd->action = wlan_cpu_to_le16(cmd_action);
+ dyn_bw_cmd->dyn_bw = wlan_cpu_to_le16(*(t_u16 *)pdata_buf);
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of dyn_bw
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_dyn_bw(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *cfg = MNULL;
+ HostCmd_DS_DYN_BW *dyn_bw = &resp->params.dyn_bw;
+
+ ENTER();
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(dyn_bw->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cfg->param.dyn_bw = wlan_le16_to_cpu(dyn_bw->dyn_bw);
+ PRINTM(MCMND, "Get dynamic bandwidth 0x%x\n",
+ cfg->param.dyn_bw);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of CHAN_TRPC_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_get_chan_trpc_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CHANNEL_TRPC_CONFIG *trpc_cfg = &cmd->params.ch_trpc_config;
+ mlan_ds_misc_chan_trpc_cfg *cfg =
+ (mlan_ds_misc_chan_trpc_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CHANNEL_TRPC_CONFIG);
+ trpc_cfg->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CHANNEL_TRPC_CONFIG) +
+ S_DS_GEN);
+ trpc_cfg->sub_band = wlan_cpu_to_le16(cfg->sub_band);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+/**
+ * @brief This function prepares command of LOW_POWER_MODE_CFG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_set_get_low_power_mode_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_LOW_POWER_MODE_CFG *lpm_cfg = &cmd->params.lpm_cfg;
+ t_u16 lpm = *(t_u16 *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_LOW_POWER_MODE_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_LOW_POWER_MODE_CFG) +
+ S_DS_GEN);
+ lpm_cfg->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ lpm_cfg->lpm = wlan_cpu_to_le16(lpm);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of low power mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+
+ */
+mlan_status wlan_ret_set_get_low_power_mode_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_power_cfg *cfg = MNULL;
+ HostCmd_DS_LOW_POWER_MODE_CFG *lpm_cfg = &resp->params.lpm_cfg;
+
+ ENTER();
+
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(lpm_cfg->action) == HostCmd_ACT_GEN_GET)) {
+ cfg = (mlan_ds_power_cfg *)pioctl_buf->pbuf;
+ cfg->param.lpm = wlan_le16_to_cpu(lpm_cfg->lpm);
+ PRINTM(MCMND, "Get low power mode %d\n", cfg->param.lpm);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+/**
+ * @brief This function handles the command response of
+ * packet aggregation
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_get_chan_trpc_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ HostCmd_DS_CHANNEL_TRPC_CONFIG *trpc_cfg = &resp->params.ch_trpc_config;
+ mlan_ds_misc_chan_trpc_cfg *cfg = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+ if (pioctl_buf) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cfg = (mlan_ds_misc_chan_trpc_cfg *)&(misc->param.trpc_cfg);
+ cfg->sub_band = wlan_le16_to_cpu(trpc_cfg->sub_band);
+ cfg->length = wlan_le16_to_cpu(resp->size);
+ memcpy_ext(pmadapter, cfg->trpc_buf, (t_u8 *)resp, cfg->length,
+ sizeof(cfg->trpc_buf));
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of RANGE_EXT
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_RANGE_EXT *range_ext = &cmd->params.range_ext;
+ t_u8 mode = *(t_u8 *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RANGE_EXT);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RANGE_EXT) + S_DS_GEN);
+ range_ext->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ range_ext->mode = mode;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of RANGE_EXT
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ HostCmd_DS_RANGE_EXT *range_ext = &resp->params.range_ext;
+
+ ENTER();
+
+ if (pioctl_buf &&
+ (wlan_le16_to_cpu(range_ext->action) == HostCmd_ACT_GEN_GET)) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.range_ext_mode = range_ext->mode;
+ PRINTM(MCMND, "Get range ext mode %d\n",
+ misc_cfg->param.range_ext_mode);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_decl.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_decl.h
new file mode 100644
index 000000000000..7d0b75cc3c54
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_decl.h
@@ -0,0 +1,1988 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "215.p2"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef signed char t_s8, *t_ps8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8, *t_pu8;
+/** Signed short (2-bytes) */
+typedef short t_s16, *t_ps16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16, *t_pu16;
+/** Signed long (4-bytes) */
+typedef int t_s32, *t_ps32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32, *t_pu32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64, *t_ps64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64, *t_pu64;
+/** Void pointer (4-bytes) */
+typedef void t_void, *t_pvoid;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+#ifndef MACSTR
+/** MAC address security format */
+#define MACSTR "%02x:XX:XX:XX:%02x:%02x"
+#endif
+
+#ifndef MAC2STR
+/** MAC address security print arguments */
+#define MAC2STR(a) (a)[0], (a)[4], (a)[5]
+#endif
+
+#ifndef FULL_MACSTR
+#define FULL_MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+#ifndef FULL_MAC2STR
+#define FULL_MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#endif
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) (((p) + ((a)-1)) & ~((a)-1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr) & (((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+#else
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (2)
+#endif
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 2
+
+/** DMA alignment */
+/* SDIO3.0 Inrevium Adapter require 32 bit DMA alignment */
+#define DMA_ALIGNMENT 32
+
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT + MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 16
+#define MLAN_MAX_TX_BASTREAM_DEFAULT 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+#ifdef STA_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 64
+/** Default Win size attached during ADDBA response */
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_STA_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 64
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_UAP_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** WFD use the same window size for tx/rx */
+#define MLAN_WFD_AMPDU_DEF_TXRXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_WFD_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif
+
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 0
+/** Rate index for MCS 2 */
+#define MLAN_RATE_INDEX_MCS2 2
+/** Rate index for MCS 4 */
+#define MLAN_RATE_INDEX_MCS4 4
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 7
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 9
+/** Rate index for MCS11 */
+#define MLAN_RATE_INDEX_MCS11 11
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 15
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 32
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 127
+#define MLAN_RATE_NSS1 1
+#define MLAN_RATE_NSS2 2
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+#define MLAN_RATE_BITMAP_NSS1_MCS0 160
+#define MLAN_RATE_BITMAP_NSS1_MCS9 169
+#define MLAN_RATE_BITMAP_NSS2_MCS0 176
+#define MLAN_RATE_BITMAP_NSS2_MCS9 185
+
+/** MU beamformer */
+#define DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK (MBIT(19))
+
+/** Size of rx data buffer 4096+256 */
+#define MLAN_RX_DATA_BUF_SIZE 4352
+
+/** Size of command buffer */
+/** because cal_data_size 2.4 k */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE MRVDRV_SIZE_OF_CMD_BUFFER
+/** Upload size */
+#define WLAN_UPLD_SIZE MRVDRV_SIZE_OF_CMD_BUFFER
+
+#if defined(PCIE)
+#define MLAN_SSU_MAX_PKT_SIZE (283 * 4)
+#define MLAN_SSU_HEADER_SIZE 256
+/**
+ * Size of DMA buffer to collect 10ms SSU data:
+ * 2500 spectral packets, plus header
+ */
+#define MLAN_SSU_BUF_SIZE_1MS (MLAN_SSU_MAX_PKT_SIZE * 250)
+#define MLAN_SSU_BUF_SIZE (MLAN_SSU_HEADER_SIZE + MLAN_SSU_BUF_SIZE_1MS * 10)
+#define MLAN_SSU_BUF_SIZE_HOST (MLAN_SSU_BUF_SIZE)
+#endif
+
+/** driver initial the fw reset */
+#define FW_RELOAD_SDIO_INBAND_RESET 1
+/** out band reset trigger reset, no interface re-emulation */
+#define FW_RELOAD_NO_EMULATION 2
+/** out band reset with interface re-emulation */
+#define FW_RELOAD_WITH_EMULATION 3
+#ifdef PCIE
+/** pcie card reset */
+#define FW_RELOAD_PCIE_RESET 4
+#endif
+
+#ifdef USB
+#define MLAN_USB_BLOCK_SIZE (512)
+#define MLAN_USB_AGGR_MODE_NUM (0)
+#define MLAN_USB_AGGR_MODE_LEN (1)
+#define MLAN_USB_AGGR_MODE_LEN_V2 (2)
+#define MLAN_USB_TX_AGGR_MAX_LEN (16000)
+#define MLAN_USB_TX_AGGR_MAX_NUM 10
+#define MLAN_USB_TX_AGGR_V2_ALIGN 4
+#define MLAN_USB_TX_AGGR_HEADER 4
+#define MLAN_USB_MAX_PKT_SIZE (MLAN_USB_BLOCK_SIZE * 4)
+
+#define MLAN_USB_RX_ALIGN_SIZE MLAN_USB_BLOCK_SIZE
+#define MLAN_USB_RX_MAX_AGGR_NUM (8)
+#define MLAN_USB_RX_DEAGGR_TIMEOUT_USEC (200)
+
+#define MLAN_USB_TX_AGGR_ALIGN (MLAN_USB_BLOCK_SIZE * 4)
+#define MLAN_USB_TX_MAX_AGGR_NUM (8)
+#define MLAN_USB_TX_MAX_AGGR_SIZE \
+ (MLAN_USB_BLOCK_SIZE * 4 * MLAN_USB_TX_MAX_AGGR_NUM)
+#define MLAN_USB_TX_MIN_AGGR_TIMEOUT (1)
+#define MLAN_USB_TX_MAX_AGGR_TIMEOUT (4)
+#define MLAN_USB_TX_AGGR_TIMEOUT_MSEC MLAN_USB_TX_MIN_AGGR_TIMEOUT
+#define MLAN_USB_TX_AGGR_TIMEOUT_DYN (0xFFFF)
+#endif /*USB*/
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+#ifdef SDIO
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE MLAN_RX_DATA_BUF_SIZE
+/** SDIO MP aggr pkt limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT (16)
+/** max SDIO MP aggr pkt limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX (16)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+#endif /* SDIO */
+
+/** SD Interface */
+#define INTF_SD MBIT(0)
+#define IS_SD(ct) (ct & (INTF_SD << 8))
+/** PCIE Interface */
+#define INTF_PCIE MBIT(1)
+#define IS_PCIE(ct) (ct & (INTF_PCIE << 8))
+/** USB Interface */
+#define INTF_USB MBIT(2)
+#define IS_USB(ct) (ct & (INTF_USB << 8))
+
+/** 8887 card type */
+#define CARD_TYPE_8887 0x01
+/** 8897 card type */
+#define CARD_TYPE_8897 0x02
+/** 8977 card type */
+#define CARD_TYPE_8977 0x03
+/** 8997 card type */
+#define CARD_TYPE_8997 0x04
+/** 8987 card type */
+#define CARD_TYPE_8987 0x05
+/** 9098 card type */
+#define CARD_TYPE_9098 0x06
+/** 9097 card type */
+#define CARD_TYPE_9097 0x07
+/** 8978 card type */
+#define CARD_TYPE_8978 0x08
+
+/** 9098 A0 reverion num */
+#define CHIP_9098_REV_A0 1
+#define CHIP_9098_REV_A1 2
+/** 9097 CHIP REV */
+#define CHIP_9097_REV_B0 1
+
+#define INTF_MASK 0xff
+#define CARD_TYPE_MASK 0xff
+
+#ifdef SDIO
+/** SD8887 card type */
+#define CARD_TYPE_SD8887 (CARD_TYPE_8887 | (INTF_SD << 8))
+/** SD8897 card type */
+#define CARD_TYPE_SD8897 (CARD_TYPE_8897 | (INTF_SD << 8))
+/** SD8977 card type */
+#define CARD_TYPE_SD8977 (CARD_TYPE_8977 | (INTF_SD << 8))
+/** SD8978 card type */
+#define CARD_TYPE_SD8978 (CARD_TYPE_8978 | (INTF_SD << 8))
+/** SD8997 card type */
+#define CARD_TYPE_SD8997 (CARD_TYPE_8997 | (INTF_SD << 8))
+/** SD8987 card type */
+#define CARD_TYPE_SD8987 (CARD_TYPE_8987 | (INTF_SD << 8))
+/** SD9097 card type */
+#define CARD_TYPE_SD9097 (CARD_TYPE_9097 | (INTF_SD << 8))
+/** SD9098 card type */
+#define CARD_TYPE_SD9098 (CARD_TYPE_9098 | (INTF_SD << 8))
+
+#define IS_SD8887(ct) (CARD_TYPE_SD8887 == (ct))
+#define IS_SD8897(ct) (CARD_TYPE_SD8897 == (ct))
+#define IS_SD8977(ct) (CARD_TYPE_SD8977 == (ct))
+#define IS_SD8978(ct) (CARD_TYPE_SD8978 == (ct))
+#define IS_SD8997(ct) (CARD_TYPE_SD8997 == (ct))
+#define IS_SD8987(ct) (CARD_TYPE_SD8987 == (ct))
+#define IS_SD9097(ct) (CARD_TYPE_SD9097 == (ct))
+#define IS_SD9098(ct) (CARD_TYPE_SD9098 == (ct))
+
+/** SD8887 Card */
+#define CARD_SD8887 "SD8887"
+/** SD8897 Card */
+#define CARD_SD8897 "SD8897"
+/** SD8977 Card */
+#define CARD_SD8977 "SD8977"
+/** SD8978 Card */
+#define CARD_SD8978 "SD8978"
+/** SD8997 Card */
+#define CARD_SD8997 "SD8997"
+/** SD8987 Card */
+#define CARD_SD8987 "SD8987"
+/** SD9097 Card */
+#define CARD_SD9097 "SD9097"
+/** SD9098 Card */
+#define CARD_SD9098 "SD9098"
+#endif
+
+#ifdef PCIE
+/** PCIE8897 card type */
+#define CARD_TYPE_PCIE8897 (CARD_TYPE_8897 | (INTF_PCIE << 8))
+/** PCIE8997 card type */
+#define CARD_TYPE_PCIE8997 (CARD_TYPE_8997 | (INTF_PCIE << 8))
+/** PCIE9097 card type */
+#define CARD_TYPE_PCIE9097 (CARD_TYPE_9097 | (INTF_PCIE << 8))
+/** PCIE9098 card type */
+#define CARD_TYPE_PCIE9098 (CARD_TYPE_9098 | (INTF_PCIE << 8))
+
+#define IS_PCIE8897(ct) (CARD_TYPE_PCIE8897 == (ct))
+#define IS_PCIE8997(ct) (CARD_TYPE_PCIE8997 == (ct))
+#define IS_PCIE9097(ct) (CARD_TYPE_PCIE9097 == (ct))
+#define IS_PCIE9098(ct) (CARD_TYPE_PCIE9098 == (ct))
+
+/** PCIE8897 Card */
+#define CARD_PCIE8897 "PCIE8897"
+/** PCIE8997 Card */
+#define CARD_PCIE8997 "PCIE8997"
+/** PCIE9097 Card */
+#define CARD_PCIE9097 "PCIE9097"
+/** PCIE9000S Card */
+#define CARD_PCIE9000S "PCIE9000S"
+/** PCIE9098 Card */
+#define CARD_PCIE9098 "PCIE9098"
+#endif
+
+#ifdef USB
+/** USB8897 card type */
+#define CARD_TYPE_USB8897 (CARD_TYPE_8897 | (INTF_USB << 8))
+/** USB8997 card type */
+#define CARD_TYPE_USB8997 (CARD_TYPE_8997 | (INTF_USB << 8))
+/** USB8978 card type */
+#define CARD_TYPE_USB8978 (CARD_TYPE_8978 | (INTF_USB << 8))
+/** USB9098 card type */
+#define CARD_TYPE_USB9098 (CARD_TYPE_9098 | (INTF_USB << 8))
+/** USB9097 card type */
+#define CARD_TYPE_USB9097 (CARD_TYPE_9097 | (INTF_USB << 8))
+
+#define IS_USB8897(ct) (CARD_TYPE_USB8897 == (ct))
+#define IS_USB8997(ct) (CARD_TYPE_USB8997 == (ct))
+#define IS_USB8978(ct) (CARD_TYPE_USB8978 == (ct))
+#define IS_USB9098(ct) (CARD_TYPE_USB9098 == (ct))
+#define IS_USB9097(ct) (CARD_TYPE_USB9097 == (ct))
+
+/** USB8897 Card */
+#define CARD_USB8897 "USB8897"
+/** USB8997 Card */
+#define CARD_USB8997 "USB8997"
+/** USB8978 Card */
+#define CARD_USB8978 "USB8978"
+/** USB9098 Card */
+#define CARD_USB9098 "USB9098"
+/** USB9097 Card */
+#define CARD_USB9097 "USB9097"
+#endif
+
+#define IS_CARD8887(ct) (CARD_TYPE_8887 == ((ct)&0xf))
+#define IS_CARD8897(ct) (CARD_TYPE_8897 == ((ct)&0xf))
+#define IS_CARD8977(ct) (CARD_TYPE_8977 == ((ct)&0xf))
+#define IS_CARD8997(ct) (CARD_TYPE_8997 == ((ct)&0xf))
+#define IS_CARD8987(ct) (CARD_TYPE_8987 == ((ct)&0xf))
+#define IS_CARD9098(ct) (CARD_TYPE_9098 == ((ct)&0xf))
+#define IS_CARD9097(ct) (CARD_TYPE_9097 == ((ct)&0xf))
+
+typedef struct _card_type_entry {
+ t_u16 card_type;
+ t_u16 func_id;
+ char *name;
+} card_type_entry;
+
+#if defined(SDIO) || defined(PCIE)
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+#endif /* SDIO || PCIE */
+
+#ifdef PCIE
+typedef enum {
+ PCIE_INT_MODE_LEGACY = 0,
+ PCIE_INT_MODE_MSI,
+ PCIE_INT_MODE_MSIX,
+ PCIE_INT_MODE_MAX,
+} PCIE_INT_MODE;
+#endif /* PCIE */
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef USB
+/** Buffer flag for deaggregated rx packet */
+#define MLAN_BUF_FLAG_RX_DEAGGR MBIT(5)
+
+/** Buffer flag for sleep confirm resp packet */
+#define MLAN_BUF_FLAG_SLEEPCFM_RESP MBIT(6)
+
+/** Buffer flag for USB TX AGGR */
+#define MLAN_BUF_FLAG_USB_TX_AGGR MBIT(7)
+#endif
+
+/** Buffer flag for TCP_ACK */
+#define MLAN_BUF_FLAG_TCP_ACK MBIT(9)
+
+/** Buffer flag for TX_STATUS */
+#define MLAN_BUF_FLAG_TX_STATUS MBIT(10)
+
+/** Buffer flag for NULL data packet */
+#define MLAN_BUF_FLAG_NULL_PKT MBIT(12)
+/** Buffer flag for Diag pkt */
+#define MLAN_BUF_FLAG_DIAG_BUF MBIT(13)
+
+#define MLAN_BUF_FLAG_TX_CTRL MBIT(14)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MREG_D MBIT(9)
+
+#define MMPA_D MBIT(15)
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status {
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+#ifdef USB
+ /* Status pending and no resource */
+ MLAN_STATUS_PRESOURCE,
+#endif
+ MLAN_STATUS_COMPLETE,
+ MLAN_STATUS_FILE_ERR,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code {
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY = 0x00000002,
+ MLAN_ERROR_FW_CMDRESP = 0x00000003,
+ MLAN_ERROR_DATA_TX_FAIL = 0x00000004,
+ MLAN_ERROR_DATA_RX_FAIL = 0x00000005,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT = 0x80000002,
+ MLAN_ERROR_PKT_INVALID = 0x80000003,
+ MLAN_ERROR_CMD_INVALID = 0x80000004,
+ MLAN_ERROR_CMD_TIMEOUT = 0x80000005,
+ MLAN_ERROR_CMD_DNLD_FAIL = 0x80000006,
+ MLAN_ERROR_CMD_CANCEL = 0x80000007,
+ MLAN_ERROR_CMD_RESP_FAIL = 0x80000008,
+ MLAN_ERROR_CMD_ASSOC_FAIL = 0x80000009,
+ MLAN_ERROR_CMD_SCAN_FAIL = 0x8000000A,
+ MLAN_ERROR_IOCTL_INVALID = 0x8000000B,
+ MLAN_ERROR_IOCTL_FAIL = 0x8000000C,
+ MLAN_ERROR_EVENT_UNKNOWN = 0x8000000D,
+ MLAN_ERROR_INVALID_PARAMETER = 0x8000000E,
+ MLAN_ERROR_NO_MEM = 0x8000000F,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type {
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+#ifdef SDIO
+ MLAN_BUF_TYPE_SPA_DATA,
+#endif
+} mlan_buf_type;
+
+#ifdef USB
+/** mlan_usb_ep */
+typedef enum _mlan_usb_ep {
+ MLAN_USB_EP_CTRL = 0,
+ MLAN_USB_EP_CMD_EVENT = 1,
+ MLAN_USB_EP_DATA = 2,
+ MLAN_USB_EP_DATA_CH2 = 3,
+ MLAN_USB_EP_CMD_EVENT_IF2 = 4,
+ MLAN_USB_EP_DATA_IF2 = 5,
+ MLAN_USB_EP_DATA_CH2_IF2 = 6,
+} mlan_usb_ep;
+
+/** Timeout in milliseconds for usb_bulk_msg function */
+#define MLAN_USB_BULK_MSG_TIMEOUT 100
+#endif /* USB */
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type {
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role {
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role mask */
+#define BSS_ROLE_MASK (MBIT(0) | MBIT(1))
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type {
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id {
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED = 0x00000002,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST = 0x00000003,
+ MLAN_EVENT_ID_FW_DISCONNECTED = 0x00000004,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI = 0x00000005,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL = 0x00000006,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW = 0x00000007,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH = 0x00000008,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW = 0x00000009,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH = 0x0000000A,
+ MLAN_EVENT_ID_FW_MAX_FAIL = 0x0000000B,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW = 0x0000000C,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH = 0x0000000D,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW = 0x0000000E,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH = 0x0000000F,
+ MLAN_EVENT_ID_FW_LINK_QUALITY = 0x00000010,
+ MLAN_EVENT_ID_FW_PORT_RELEASE = 0x00000011,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST = 0x00000012,
+ MLAN_EVENT_ID_FW_DEBUG_INFO = 0x00000013,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE = 0x0000001A,
+ MLAN_EVENT_ID_FW_HS_WAKEUP = 0x0000001B,
+ MLAN_EVENT_ID_FW_BG_SCAN = 0x0000001D,
+ MLAN_EVENT_ID_FW_BG_SCAN_STOPPED = 0x0000001E,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR = 0x00000020,
+ MLAN_EVENT_ID_FW_STOP_TX = 0x00000021,
+ MLAN_EVENT_ID_FW_START_TX = 0x00000022,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN = 0x00000023,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED = 0x00000024,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY = 0x00000025,
+ MLAN_EVENT_ID_FW_BW_CHANGED = 0x00000026,
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED = 0x0000002B,
+
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START = 0x0000002C,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE = 0x0000002D,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE = 0x0000002E,
+ MLAN_EVENT_ID_UAP_FW_MIC_COUNTERMEASURES = 0x0000002F,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT = 0x00000030,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT = 0x00000031,
+#endif
+
+ MLAN_EVENT_ID_FW_DUMP_INFO = 0x00000033,
+
+ MLAN_EVENT_ID_FW_TX_STATUS = 0x00000034,
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE = 0x00000036,
+#if defined(PCIE)
+ MLAN_EVENT_ID_SSU_DUMP_FILE = 0x00000039,
+#endif /* SSU_SUPPORT */
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING = 0x80000002,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED = 0x80000003,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED = 0x80000004,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME = 0x80000005,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM = 0x80000006,
+ MLAN_EVENT_ID_DRV_PASSTHRU = 0x80000007,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT = 0x80000009,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT = 0x8000000A,
+ MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT = 0x8000000B,
+ MLAN_EVENT_ID_DRV_REPORT_STRING = 0x8000000F,
+ MLAN_EVENT_ID_DRV_DBG_DUMP = 0x80000012,
+ MLAN_EVENT_ID_DRV_BGSCAN_RESULT = 0x80000013,
+ MLAN_EVENT_ID_DRV_FLUSH_RX_WORK = 0x80000015,
+ MLAN_EVENT_ID_DRV_DEFER_RX_WORK = 0x80000016,
+ MLAN_EVENT_ID_DRV_FT_RESPONSE = 0x80000018,
+ MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK = 0x80000019,
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_DRV_UAP_CHAN_INFO = 0x80000020,
+#endif
+ MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER = 0x80000026,
+ MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER = 0x80000027,
+ MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER = 0x80000028,
+ MLAN_EVENT_ID_DRV_WIFI_STATUS = 0x80000029,
+ MLAN_EVENT_ID_STORE_HOST_CMD_RESP = 0x80000030,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image {
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+ /** Firmware reload flag */
+ t_u8 fw_reload;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** MrvlIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlIEtypesHeader {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} MLAN_PACK_END MrvlIEtypesHeader_t;
+
+/** MrvlExtIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlExtIEtypesHeader {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+ /** ext id */
+ t_u8 ext_id;
+} MLAN_PACK_END MrvlExtIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlExtIEtypes_Data_t {
+ /** Header */
+ MrvlExtIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[];
+} MLAN_PACK_END MrvlExtIEtypes_Data_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Data_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[];
+} MLAN_PACK_END MrvlIEtypes_Data_t;
+
+#define OID_TYPE_CAL 0x2
+#define OID_TYPE_DPD 0xa
+#define UNKNOW_DPD_LENGTH 0xffffffff
+
+/** Custom data structure */
+typedef struct _mlan_init_param {
+ /** DPD data buffer pointer */
+ t_u8 *pdpd_data_buf;
+ /** DPD data length */
+ t_u32 dpd_data_len;
+ /** region txpowerlimit cfg data buffer pointer */
+ t_u8 *ptxpwr_data_buf;
+ /** region txpowerlimit cfg data length */
+ t_u32 txpwr_data_len;
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** channel type */
+enum mlan_channel_type {
+ CHAN_NO_HT,
+ CHAN_HT20,
+ CHAN_HT40MINUS,
+ CHAN_HT40PLUS,
+ CHAN_VHT80
+};
+
+/** channel band */
+enum { BAND_2GHZ = 0,
+ BAND_5GHZ = 1,
+ BAND_4GHZ = 2,
+};
+
+/** channel offset */
+enum { SEC_CHAN_NONE = 0,
+ SEC_CHAN_ABOVE = 1,
+ SEC_CHAN_5MHZ = 2,
+ SEC_CHAN_BELOW = 3 };
+
+/** channel bandwidth */
+enum { CHAN_BW_20MHZ = 0,
+ CHAN_BW_10MHZ,
+ CHAN_BW_40MHZ,
+ CHAN_BW_80MHZ,
+};
+
+/** scan mode */
+enum { SCAN_MODE_MANUAL = 0,
+ SCAN_MODE_ACS,
+ SCAN_MODE_USER,
+};
+
+/** max cac time 10 minutes */
+#define MAX_CAC_DWELL_TIME 600000
+/** default cac time 60 seconds */
+#define DEF_CAC_DWELL_TIME 60000
+/** start freq for 5G */
+#define START_FREQ_11A_BAND 5000
+/** DFS state */
+typedef enum _dfs_state_t {
+ /** Channel can be used, CAC (Channel Availability Check) must be done
+ before using it */
+ DFS_USABLE = 0,
+ /** Channel is not available, radar was detected */
+ DFS_UNAVAILABLE = 1,
+ /** Channel is Available, CAC is done and is free of radar */
+ DFS_AVAILABLE = 2,
+} dfs_state_t;
+
+typedef enum _dfs_w53_cfg_t {
+ /** DFS W53 Default Fw Value */
+ DFS_W53_DEFAULT_FW = 0,
+ /** DFS W53 New W53 Rules/Standard */
+ DFS_W53_NEW = 1,
+ /** DFS W53 Old W53 Rules/Standard */
+ DFS_W53_OLD = 2
+} dfs_w53_cfg_t;
+
+/** Band_Config_t */
+typedef MLAN_PACK_START struct _Band_Config_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=user*/
+ t_u8 scanMode : 2;
+ /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */
+ t_u8 chan2Offset : 2;
+ /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */
+ t_u8 chanWidth : 2;
+ /** Band Info - (00)=2.4GHz, (01)=5GHz */
+ t_u8 chanBand : 2;
+#else
+ /** Band Info - (00)=2.4GHz, (01)=5GHz */
+ t_u8 chanBand : 2;
+ /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */
+ t_u8 chanWidth : 2;
+ /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */
+ t_u8 chan2Offset : 2;
+ /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=Adoption mode*/
+ t_u8 scanMode : 2;
+#endif
+} MLAN_PACK_END Band_Config_t;
+
+/** channel_band_t */
+typedef MLAN_PACK_START struct _chan_band_info {
+ /** Band Configuration */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** 11n flag */
+ t_u8 is_11n_enabled;
+ /** center channel */
+ t_u8 center_chan;
+ /** dfs channel flag */
+ t_u8 is_dfs_chan;
+} MLAN_PACK_END chan_band_info, *pchan_band_info;
+
+/** Channel usability flags */
+#define NXP_CHANNEL_NO_OFDM MBIT(9)
+#define NXP_CHANNEL_NO_CCK MBIT(8)
+#define NXP_CHANNEL_DISABLED MBIT(7)
+/* BIT 5/6 resevered for FW */
+#define NXP_CHANNEL_NOHT160 MBIT(4)
+#define NXP_CHANNEL_NOHT80 MBIT(3)
+#define NXP_CHANNEL_NOHT40 MBIT(2)
+#define NXP_CHANNEL_DFS MBIT(1)
+#define NXP_CHANNEL_PASSIVE MBIT(0)
+
+/** CFP dynamic (non-const) elements */
+typedef struct _cfp_dyn_t {
+ /** extra flags to specify channel usability
+ * bit 9 : if set, channel is non-OFDM
+ * bit 8 : if set, channel is non-CCK
+ * bit 7 : if set, channel is disabled
+ * bit 5/6 resevered for FW
+ * bit 4 : if set, 160MHz on channel is disabled
+ * bit 3 : if set, 80MHz on channel is disabled
+ * bit 2 : if set, 40MHz on channel is disabled
+ * bit 1 : if set, channel is DFS channel
+ * bit 0 : if set, channel is passive
+ */
+ t_u16 flags;
+ /** TRUE: Channel is blacklisted (do not use) */
+ t_bool blacklist;
+} cfp_dyn_t;
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _chan_freq_power_t {
+ /** Channel Number */
+ t_u16 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+ /** Max allowed Tx power level */
+ t_u16 max_tx_power;
+ /** TRUE:radar detect required for BAND A or passive scan for BAND B/G;
+ * FALSE:radar detect not required for BAND A or active scan for BAND
+ * B/G*/
+ t_bool passive_scan_or_radar_detect;
+ /** Elements associated to cfp that change at run-time */
+ cfp_dyn_t dynamic;
+} chan_freq_power_t;
+
+/** mlan_event data structure */
+typedef struct _mlan_event {
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[];
+} mlan_event, *pmlan_event;
+
+/** mlan_cmdresp_event data structure */
+typedef struct _mlan_cmdresp_event {
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** resp buffer pointer */
+ t_u8 *resp;
+} mlan_cmdresp_event, *pmlan_cmdresp_event;
+
+/** csi event data structure */
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req {
+ /** Pointer to previous mlan_ioctl_req */
+ struct _mlan_ioctl_req *pprev;
+ /** Pointer to next mlan_ioctl_req */
+ struct _mlan_ioctl_req *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** txpower structure */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Host tx power ctrl:
+ 0x0: use fw setting for TX power
+ 0x1: value specified in bit[6] and bit[5:0] are valid */
+ t_u8 hostctl : 1;
+ /** Sign of the power specified in bit[5:0] */
+ t_u8 sign : 1;
+ /** Power to be used for transmission(in dBm) */
+ t_u8 abs_val : 6;
+#else
+ /** Power to be used for transmission(in dBm) */
+ t_u8 abs_val : 6;
+ /** Sign of the power specified in bit[5:0] */
+ t_u8 sign : 1;
+ /** Host tx power ctrl:
+ 0x0: use fw setting for TX power
+ 0x1: value specified in bit[6] and bit[5:0] are valid */
+ t_u8 hostctl : 1;
+#endif
+} MLAN_PACK_END tx_power_t;
+/* pkt_txctrl */
+typedef MLAN_PACK_START struct _pkt_txctrl {
+ /**Data rate in unit of 0.5Mbps */
+ t_u16 data_rate;
+ /*Channel number to transmit the frame */
+ t_u8 channel;
+ /** Bandwidth to transmit the frame*/
+ t_u8 bw;
+ /** Power to be used for transmission*/
+ union {
+ tx_power_t tp;
+ t_u8 val;
+ } tx_power;
+ /** Retry time of tx transmission*/
+ t_u8 retry_limit;
+} MLAN_PACK_END pkt_txctrl, *ppkt_txctrl;
+
+/** pkt_rxinfo */
+typedef MLAN_PACK_START struct _pkt_rxinfo {
+ /** Data rate of received paccket*/
+ t_u16 data_rate;
+ /** Channel on which packet was received*/
+ t_u8 channel;
+ /** Rx antenna*/
+ t_u8 antenna;
+ /** Rx Rssi*/
+ t_u8 rssi;
+} MLAN_PACK_END pkt_rxinfo, *ppkt_rxinfo;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer {
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+#ifdef PCIE
+ /** Physical address of the pbuf pointer */
+ t_u64 buf_pa;
+ t_u32 total_pcie_buf_len;
+#endif
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+ /** tx_seq_num */
+ t_u32 tx_seq_num;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+ union {
+ pkt_txctrl tx_info;
+ pkt_rxinfo rx_info;
+ } u;
+} mlan_buffer, *pmlan_buffer, **ppmlan_buffer;
+
+/** mlan_fw_info data structure */
+typedef struct _mlan_hw_info {
+ t_u32 fw_cap;
+} mlan_hw_info, *pmlan_hw_info;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr {
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+ /** The BSS is virtual */
+ t_u32 bss_virtual;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+/** bss tbl data structure */
+typedef struct _mlan_bss_tbl {
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+} mlan_bss_tbl, *pmlan_bss_tbl;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e {
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e {
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e {
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e {
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct {
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+ /** Type definition of mlan_ds_wmm_ts_status for
+ MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie {
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 26
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info {
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+/** channel width */
+typedef enum wifi_channel_width {
+ WIFI_CHAN_WIDTH_20 = 0,
+ WIFI_CHAN_WIDTH_40 = 1,
+ WIFI_CHAN_WIDTH_80 = 2,
+ WIFI_CHAN_WIDTH_160 = 3,
+ WIFI_CHAN_WIDTH_80P80 = 4,
+ WIFI_CHAN_WIDTH_5 = 5,
+ WIFI_CHAN_WIDTH_10 = 6,
+ WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width_t;
+
+/** channel information */
+typedef struct {
+ /** channel width (20, 40, 80, 80+80, 160) */
+ wifi_channel_width_t width;
+ /** primary 20 MHz channel */
+ int center_freq;
+ /** center frequency (MHz) first segment */
+ int center_freq0;
+ /** center frequency (MHz) second segment */
+ int center_freq1;
+} wifi_channel_info;
+
+/** wifi rate */
+typedef struct {
+ /** 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ t_u32 preamble : 3;
+ /** 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ t_u32 nss : 2;
+ /** 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
+ t_u32 bw : 3;
+ /** OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps
+ */
+ /** HT/VHT it would be mcs index */
+ t_u32 rateMcsIdx : 8;
+ /** reserved */
+ t_u32 reserved : 16;
+ /** units of 100 Kbps */
+ t_u32 bitrate;
+} wifi_rate;
+
+/** wifi Preamble type */
+typedef enum {
+ WIFI_PREAMBLE_LEGACY = 0x1,
+ WIFI_PREAMBLE_HT = 0x2,
+ WIFI_PREAMBLE_VHT = 0x4
+} wifi_preamble;
+
+/** timeval */
+typedef struct {
+ /** Time (seconds) */
+ t_u32 time_sec;
+ /** Time (micro seconds) */
+ t_u32 time_usec;
+} wifi_timeval;
+
+#define MAX_NUM_RATE 32
+#define MAX_RADIO 2
+#define MAX_NUM_CHAN 1
+#define VHT_NUM_SUPPORT_MCS 10
+#define MCS_NUM_SUPP 16
+
+#define BUF_MAXLEN 4096
+/** connection state */
+typedef enum {
+ MLAN_DISCONNECTED = 0,
+ MLAN_AUTHENTICATING = 1,
+ MLAN_ASSOCIATING = 2,
+ MLAN_ASSOCIATED = 3,
+ /** if done by firmware/driver */
+ MLAN_EAPOL_STARTED = 4,
+ /** if done by firmware/driver */
+ MLAN_EAPOL_COMPLETED = 5,
+} mlan_connection_state;
+/** roam state */
+typedef enum {
+ MLAN_ROAMING_IDLE = 0,
+ MLAN_ROAMING_ACTIVE = 1,
+} mlan_roam_state;
+/** interface mode */
+typedef enum {
+ MLAN_INTERFACE_STA = 0,
+ MLAN_INTERFACE_SOFTAP = 1,
+ MLAN_INTERFACE_IBSS = 2,
+ MLAN_INTERFACE_P2P_CLIENT = 3,
+ MLAN_INTERFACE_P2P_GO = 4,
+ MLAN_INTERFACE_NAN = 5,
+ MLAN_INTERFACE_MESH = 6,
+} mlan_interface_mode;
+
+/** set for QOS association */
+#define MLAN_CAPABILITY_QOS 0x00000001
+/** set for protected association (802.11 beacon frame control protected bit
+ * set) */
+#define MLAN_CAPABILITY_PROTECTED 0x00000002
+/** set if 802.11 Extended Capabilities element interworking bit is set */
+#define MLAN_CAPABILITY_INTERWORKING 0x00000004
+/** set for HS20 association */
+#define MLAN_CAPABILITY_HS20 0x00000008
+/** set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */
+#define MLAN_CAPABILITY_SSID_UTF8 0x00000010
+/** set is 802.11 Country Element is present */
+#define MLAN_CAPABILITY_COUNTRY 0x00000020
+
+/** link layer status */
+typedef struct {
+ /** interface mode */
+ mlan_interface_mode mode;
+ /** interface mac address (self) */
+ t_u8 mac_addr[6];
+ /** connection state (valid for STA, CLI only) */
+ mlan_connection_state state;
+ /** roaming state */
+ mlan_roam_state roaming;
+ /** WIFI_CAPABILITY_XXX (self) */
+ t_u32 capabilities;
+ /** null terminated SSID */
+ t_u8 ssid[33];
+ /** bssid */
+ t_u8 bssid[6];
+ /** country string advertised by AP */
+ t_u8 ap_country_str[3];
+ /** country string for this association */
+ t_u8 country_str[3];
+} mlan_interface_link_layer_info, *mlan_interface_handle;
+
+/** channel statistics */
+typedef struct {
+ /** channel */
+ wifi_channel_info channel;
+ /** msecs the radio is awake (32 bits number accruing over time) */
+ t_u32 on_time;
+ /** msecs the CCA register is busy (32 bits number accruing over time)
+ */
+ t_u32 cca_busy_time;
+} wifi_channel_stat;
+
+#define timeval_to_msec(timeval) \
+ (t_u64)((t_u64)(timeval.time_sec) * 1000 + \
+ (t_u64)(timeval.time_usec) / 1000)
+#define timeval_to_usec(timeval) \
+ (t_u64)((t_u64)(timeval.time_sec) * 1000 * 1000 + \
+ (t_u64)(timeval.time_usec))
+#define is_zero_timeval(timeval) \
+ ((timeval.time_sec == 0) && (timeval.time_usec == 0))
+
+/** radio statistics */
+typedef struct {
+ /** wifi radio (if multiple radio supported) */
+ int radio;
+ /** msecs the radio is awake (32 bits number accruing over time) */
+ t_u32 on_time;
+ /** msecs the radio is transmitting (32 bits number accruing over time)
+ */
+ t_u32 tx_time;
+ /** TBD: num_tx_levels: number of radio transmit power levels */
+ t_u32 reserved0;
+ /** TBD: tx_time_per_levels: pointer to an array of radio transmit per
+ * power levels in msecs accured over time */
+ /* t_u32 *reserved1;*/
+ /** msecs the radio is in active receive (32 bits number accruing over
+ * time) */
+ t_u32 rx_time;
+ /** msecs the radio is awake due to all scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_scan;
+ /** msecs the radio is awake due to NAN (32 bits number accruing over
+ * time) */
+ t_u32 on_time_nbd;
+ /** msecs the radio is awake due to G?scan (32 bits number accruing over
+ * time) */
+ t_u32 on_time_gscan;
+ /** msecs the radio is awake due to roam?scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_roam_scan;
+ /** msecs the radio is awake due to PNO scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_pno_scan;
+ /** msecs the radio is awake due to HS2.0 scans and GAS exchange (32
+ * bits number accruing over time) */
+ t_u32 on_time_hs20;
+ /** number of channels */
+ t_u32 num_channels;
+ /** channel statistics */
+ wifi_channel_stat channels[MAX_NUM_CHAN];
+} wifi_radio_stat;
+
+/** per rate statistics */
+typedef struct {
+ /** rate information */
+ wifi_rate rate;
+ /** number of successfully transmitted data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received data pkts */
+ t_u32 rx_mpdu;
+ /** number of data packet losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+} wifi_rate_stat;
+
+/** wifi peer type */
+typedef enum {
+ WIFI_PEER_STA,
+ WIFI_PEER_AP,
+ WIFI_PEER_P2P_GO,
+ WIFI_PEER_P2P_CLIENT,
+ WIFI_PEER_NAN,
+ WIFI_PEER_TDLS,
+ WIFI_PEER_INVALID,
+} wifi_peer_type;
+
+/** per peer statistics */
+typedef struct {
+ /** peer type (AP, TDLS, GO etc.) */
+ wifi_peer_type type;
+ /** mac address */
+ t_u8 peer_mac_address[6];
+ /** peer WIFI_CAPABILITY_XXX */
+ t_u32 capabilities;
+ /** number of rates */
+ t_u32 num_rate;
+ /** per rate statistics, number of entries = num_rate */
+ wifi_rate_stat rate_stats[];
+} wifi_peer_info;
+
+/** per access category statistics */
+typedef struct {
+ /** access category (VI, VO, BE, BK) */
+ mlan_wmm_ac_e ac;
+ /** number of successfully transmitted unicast data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received unicast mpdus */
+ t_u32 rx_mpdu;
+ /** number of succesfully transmitted multicast data packets */
+ /** STA case: implies ACK received from AP for the unicast packet in
+ * which mcast pkt was sent */
+ t_u32 tx_mcast;
+ /** number of received multicast data packets */
+ t_u32 rx_mcast;
+ /** number of received unicast a-mpdus */
+ t_u32 rx_ampdu;
+ /** number of transmitted unicast a-mpdus */
+ t_u32 tx_ampdu;
+ /** number of data pkt losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+ /** data pkt min contention time (usecs) */
+ t_u32 contention_time_min;
+ /** data pkt max contention time (usecs) */
+ t_u32 contention_time_max;
+ /** data pkt avg contention time (usecs) */
+ t_u32 contention_time_avg;
+ /** num of data pkts used for contention statistics */
+ t_u32 contention_num_samples;
+} wifi_wmm_ac_stat;
+
+/** interface statistics */
+typedef struct {
+ /** wifi interface */
+ /* wifi_interface_handle iface;*/
+ /** current state of the interface */
+ mlan_interface_link_layer_info info;
+ /** access point beacon received count from connected AP */
+ t_u32 beacon_rx;
+ /** Average beacon offset encountered (beacon_TSF - TBTT)
+ * the average_tsf_offset field is used so as to calculate the
+ * typical beacon contention time on the channel as well may be
+ * used to debug beacon synchronization and related power consumption
+ * issue
+ */
+ t_u64 average_tsf_offset;
+ /** indicate that this AP typically leaks packets beyond the driver
+ * guard time */
+ t_u32 leaky_ap_detected;
+ /** average number of frame leaked by AP after frame with PM bit set was
+ * ACK'ed by AP */
+ t_u32 leaky_ap_avg_num_frames_leaked;
+ /** Guard time currently in force (when implementing IEEE power
+ * management based on frame control PM bit), How long driver waits
+ * before shutting down the radio and after receiving an ACK for a data
+ * frame with PM bit set)
+ */
+ t_u32 leaky_ap_guard_time;
+ /** access point mgmt frames received count from connected AP (including
+ * Beacon) */
+ t_u32 mgmt_rx;
+ /** action frames received count */
+ t_u32 mgmt_action_rx;
+ /** action frames transmit count */
+ t_u32 mgmt_action_tx;
+ /** access Point Beacon and Management frames RSSI (averaged) */
+ t_s32 rssi_mgmt;
+ /** access Point Data Frames RSSI (averaged) from connected AP */
+ t_s32 rssi_data;
+ /** access Point ACK RSSI (averaged) from connected AP */
+ t_s32 rssi_ack;
+ /** per ac data packet statistics */
+ wifi_wmm_ac_stat ac[MAX_AC_QUEUES];
+ /** number of peers */
+ t_u32 num_peers;
+ /** per peer statistics */
+ wifi_peer_info peer_info[];
+} wifi_iface_stat;
+
+/** link layer stat configuration params */
+typedef struct {
+ /** threshold to classify the pkts as short or long */
+ t_u32 mpdu_size_threshold;
+ /** wifi statistics bitmap */
+ t_u32 aggressive_statistics_gathering;
+} wifi_link_layer_params;
+
+/** wifi statistics bitmap */
+#define WIFI_STATS_RADIO 0x00000001 /** all radio statistics */
+#define WIFI_STATS_RADIO_CCA \
+ 0x00000002 /** cca_busy_time (within radio statistics) */
+#define WIFI_STATS_RADIO_CHANNELS \
+ 0x00000004 /** all channel statistics (within radio statistics) */
+#define WIFI_STATS_RADIO_SCAN \
+ 0x00000008 /** all scan statistics (within radio statistics) */
+#define WIFI_STATS_IFACE 0x00000010 /** all interface statistics */
+#define WIFI_STATS_IFACE_TXRATE \
+ 0x00000020 /** all tx rate statistics (within interface statistics) */
+#define WIFI_STATS_IFACE_AC \
+ 0x00000040 /** all ac statistics (within interface statistics) */
+#define WIFI_STATS_IFACE_CONTENTION \
+ 0x00000080 /** all contention (min, max, avg) statistics (within ac \
+ statisctics) */
+
+/** station stats */
+typedef struct _sta_stats {
+ t_u64 last_rx_in_msec;
+} sta_stats;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks {
+ /** moal_get_fw_data */
+ mlan_status (*moal_get_fw_data)(t_void *pmoal_handle, t_u32 offset,
+ t_u32 len, t_u8 *pbuf);
+ mlan_status (*moal_get_vdll_data)(t_void *pmoal_handle, t_u32 len,
+ t_u8 *pbuf);
+ /** moal_get_hw_spec_complete */
+ mlan_status (*moal_get_hw_spec_complete)(t_void *pmoal_handle,
+ mlan_status status,
+ pmlan_hw_info phw,
+ pmlan_bss_tbl ptbl);
+ /** moal_init_fw_complete */
+ mlan_status (*moal_init_fw_complete)(t_void *pmoal_handle,
+ mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status (*moal_shutdown_fw_complete)(t_void *pmoal_handle,
+ mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status (*moal_send_packet_complete)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf,
+ mlan_status status);
+ /** moal_recv_complete */
+ mlan_status (*moal_recv_complete)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ mlan_status status);
+ /** moal_recv_packet */
+ mlan_status (*moal_recv_packet)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status (*moal_recv_event)(t_void *pmoal_handle,
+ pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status (*moal_ioctl_complete)(t_void *pmoal_handle,
+ pmlan_ioctl_req pioctl_req,
+ mlan_status status);
+
+ /** moal_alloc_mlan_buffer */
+ mlan_status (*moal_alloc_mlan_buffer)(t_void *pmoal_handle, t_u32 size,
+ ppmlan_buffer pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status (*moal_free_mlan_buffer)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf);
+
+#ifdef USB
+ /** moal_write_data_async */
+ mlan_status (*moal_write_data_async)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port);
+#endif /* USB */
+#if defined(SDIO) || defined(PCIE)
+ /** moal_write_reg */
+ mlan_status (*moal_write_reg)(t_void *pmoal_handle, t_u32 reg,
+ t_u32 data);
+ /** moal_read_reg */
+ mlan_status (*moal_read_reg)(t_void *pmoal_handle, t_u32 reg,
+ t_u32 *data);
+#endif /* SDIO || PCIE */
+ /** moal_write_data_sync */
+ mlan_status (*moal_write_data_sync)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status (*moal_read_data_sync)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ t_u32 timeout);
+ /** moal_malloc */
+ mlan_status (*moal_malloc)(t_void *pmoal_handle, t_u32 size, t_u32 flag,
+ t_u8 **ppbuf);
+ /** moal_mfree */
+ mlan_status (*moal_mfree)(t_void *pmoal_handle, t_u8 *pbuf);
+ /** moal_vmalloc */
+ mlan_status (*moal_vmalloc)(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf);
+ /** moal_vfree */
+ mlan_status (*moal_vfree)(t_void *pmoal_handle, t_u8 *pbuf);
+#ifdef PCIE
+ /** moal_malloc_consistent */
+ mlan_status (*moal_malloc_consistent)(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf, t_u64 *pbuf_pa);
+ /** moal_mfree_consistent */
+ mlan_status (*moal_mfree_consistent)(t_void *pmoal_handle, t_u32 size,
+ t_u8 *pbuf, t_u64 buf_pa);
+ /** moal_map_memory */
+ mlan_status (*moal_map_memory)(t_void *pmoal_handle, t_u8 *pbuf,
+ t_u64 *pbuf_pa, t_u32 size, t_u32 flag);
+ /** moal_unmap_memory */
+ mlan_status (*moal_unmap_memory)(t_void *pmoal_handle, t_u8 *pbuf,
+ t_u64 buf_pa, t_u32 size, t_u32 flag);
+#endif /* PCIE */
+ /** moal_memset */
+ t_void *(*moal_memset)(t_void *pmoal_handle, t_void *pmem, t_u8 byte,
+ t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num);
+ /** moal_memcpy_ext */
+ t_void *(*moal_memcpy_ext)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num,
+ t_u32 dest_size);
+ /** moal_memmove */
+ t_void *(*moal_memmove)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num);
+ /** moal_memcmp */
+ t_s32 (*moal_memcmp)(t_void *pmoal_handle, const t_void *pmem1,
+ const t_void *pmem2, t_u32 num);
+ /** moal_udelay */
+ t_void (*moal_udelay)(t_void *pmoal_handle, t_u32 udelay);
+ /** moal_usleep_range */
+ t_void (*moal_usleep_range)(t_void *pmoal_handle, t_u32 min_delay,
+ t_u32 max_delay);
+ /** moal_get_boot_ktime */
+ mlan_status (*moal_get_boot_ktime)(t_void *pmoal_handle, t_u64 *pnsec);
+ /** moal_get_system_time */
+ mlan_status (*moal_get_system_time)(t_void *pmoal_handle, t_u32 *psec,
+ t_u32 *pusec);
+ /** moal_init_timer*/
+ mlan_status (*moal_init_timer)(t_void *pmoal_handle, t_void **pptimer,
+ IN t_void (*callback)(t_void *pcontext),
+ t_void *pcontext);
+ /** moal_free_timer */
+ mlan_status (*moal_free_timer)(t_void *pmoal_handle, t_void *ptimer);
+ /** moal_start_timer*/
+ mlan_status (*moal_start_timer)(t_void *pmoal_handle, t_void *ptimer,
+ t_u8 periodic, t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status (*moal_stop_timer)(t_void *pmoal_handle, t_void *ptimer);
+ /** moal_init_lock */
+ mlan_status (*moal_init_lock)(t_void *pmoal_handle, t_void **pplock);
+ /** moal_free_lock */
+ mlan_status (*moal_free_lock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_spin_lock */
+ mlan_status (*moal_spin_lock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_spin_unlock */
+ mlan_status (*moal_spin_unlock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_print */
+ t_void (*moal_print)(t_void *pmoal_handle, t_u32 level, char *pformat,
+ IN...);
+ /** moal_print_netintf */
+ t_void (*moal_print_netintf)(t_void *pmoal_handle, t_u32 bss_index,
+ t_u32 level);
+ /** moal_assert */
+ t_void (*moal_assert)(t_void *pmoal_handle, t_u32 cond);
+
+ /** moal_hist_data_add */
+ t_void (*moal_hist_data_add)(t_void *pmoal_handle, t_u32 bss_index,
+ t_u16 rx_rate, t_s8 snr, t_s8 nflr,
+ t_u8 antenna);
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ mlan_status (*moal_wait_hostcmd_complete)(t_void *pmoal_handle,
+ t_u32 bss_index);
+ mlan_status (*moal_notify_hostcmd_complete)(t_void *pmoal_handle,
+ t_u32 bss_index);
+#endif
+ void (*moal_tp_accounting)(t_void *pmoal_handle, t_void *buf,
+ t_u32 drop_point);
+ void (*moal_tp_accounting_rx_param)(t_void *pmoal_handle,
+ unsigned int type,
+ unsigned int rsvd1);
+
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Parameter unchanged, use MLAN default setting */
+#define ROBUSTCOEX_GPIO_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define ROBUSTCOEX_GPIO_CFG 1
+
+#if defined(SDIO)
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+/** New mode: GPIO-1 as a duplicated signal of interrupt as appear of SDIO_DAT1
+ */
+#define GPIO_INT_NEW_MODE 255
+#endif
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** Control bit for stream 2X2 */
+#define FEATURE_CTRL_STREAM_2X2 MBIT(0)
+/** Control bit for DFS support */
+#define FEATURE_CTRL_DFS_SUPPORT MBIT(1)
+#ifdef USB
+/** Control bit for winner check & not wait for FW ready event */
+#define FEATURE_CTRL_USB_NEW_INIT MBIT(2)
+#endif
+/** Default feature control */
+#define FEATURE_CTRL_DEFAULT 0xffffffff
+/** Check if stream 2X2 enabled */
+#define IS_STREAM_2X2(x) ((x)&FEATURE_CTRL_STREAM_2X2)
+/** Check if DFS support enabled */
+#define IS_DFS_SUPPORT(x) ((x)&FEATURE_CTRL_DFS_SUPPORT)
+#ifdef USB
+/** Check if winner check & not wait for FW ready event */
+#define IS_USB_NEW_INIT(x) ((x)&FEATURE_CTRL_USB_NEW_INIT)
+#endif
+
+/*
+#define DRV_MODE_NAN MBIT(4)
+#define DRV_MODE_11P MBIT(5)
+#define DRV_MODE_MAC80211 MBIT(6)
+#define DRV_MODE_DFS MBIT(7)*/
+#define DRV_MODE_MASK (MBIT(4) | MBIT(5) | MBIT(6) | MBIT(7))
+
+/** mlan_device data structure */
+typedef struct _mlan_device {
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+#if defined(SDIO)
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#endif
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ /** allocate fixed buffer size for scan beacon buffer*/
+ t_u32 fixed_beacon_buffer;
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#ifdef SDIO
+ /** SDIO Single port rx aggr */
+ t_u8 sdio_rx_aggr_enable;
+ /* see blk_queue_max_segment_size */
+ t_u32 max_seg_size;
+ /* see blk_queue_max_segments */
+ t_u16 max_segs;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+ /** Feature control bitmask */
+ t_u32 feature_control;
+ /** enable/disable rx work */
+ t_u8 rx_work;
+ /** dev cap mask */
+ t_u32 dev_cap_mask;
+ /** oob independent reset */
+ t_u32 indrstcfg;
+ /** dtim interval */
+ t_u16 multi_dtim;
+ /** IEEE ps inactivity timeout value */
+ t_u16 inact_tmo;
+ /** card type */
+ t_u16 card_type;
+ /** card rev */
+ t_u8 card_rev;
+ /** Host sleep wakeup interval */
+ t_u32 hs_wake_interval;
+ /** GPIO to indicate wakeup source */
+ t_u8 indication_gpio;
+ /** Dynamic MIMO-SISO switch for hscfg*/
+ t_u8 hs_mimo_switch;
+#ifdef USB
+ /** Tx CMD endpoint address */
+ t_u8 tx_cmd_ep;
+ /** Rx CMD/EVT endpoint address */
+ t_u8 rx_cmd_ep;
+
+ /** Rx data endpoint address */
+ t_u8 rx_data_ep;
+ /** Tx data endpoint address */
+ t_u8 tx_data_ep;
+#endif
+ /** fw region */
+ t_bool fw_region;
+ /** passive to active scan */
+ t_u8 passive_to_active_scan;
+ /** uap max supported station per chip */
+ t_u8 uap_max_sta;
+ /** drv mode */
+ t_u32 drv_mode;
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(pmlan_device pmdevice,
+ t_void **ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(t_void *pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(t_void *pmlan_adapter, pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(t_void *pmlan_adapter,
+ pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(t_void *pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(t_void *pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(t_void *pmlan_adapter);
+
+/** Rx process */
+mlan_status mlan_rx_process(t_void *pmlan_adapter, t_u8 *rx_pkts);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf);
+
+#ifdef USB
+/** mlan_write_data_async_complete */
+MLAN_API mlan_status mlan_write_data_async_complete(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf,
+ t_u32 port,
+ mlan_status status);
+
+/** Packet Reception */
+MLAN_API mlan_status mlan_recv(t_void *pmlan_adapter, pmlan_buffer pmbuf,
+ t_u32 port);
+#endif /* USB */
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf,
+ mlan_status status);
+
+#if defined(SDIO) || defined(PCIE)
+/** interrupt handler */
+MLAN_API mlan_status mlan_interrupt(t_u16 msg_id, t_void *pmlan_adapter);
+
+#if defined(SYSKT)
+/** GPIO IRQ callback function */
+MLAN_API t_void mlan_hs_callback(t_void *pctx);
+#endif /* SYSKT_MULTI || SYSKT */
+#endif /* SDIO || PCIE */
+
+MLAN_API t_void mlan_pm_wakeup_card(t_void *pmlan_adapter, t_u8 keep_wakeup);
+
+MLAN_API t_u8 mlan_is_main_process_running(t_void *adapter);
+#ifdef PCIE
+MLAN_API t_void mlan_set_int_mode(t_void *adapter, t_u32 int_mode,
+ t_u8 func_num);
+#endif
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(t_void *pmlan_adapter,
+ pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(t_void *pmlan_adapter, t_u8 bss_num,
+ t_u8 tid);
+
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_fw.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_fw.h
new file mode 100644
index 000000000000..2011e2459f07
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_fw.h
@@ -0,0 +1,7410 @@
+/** @file mlan_fw.h
+ *
+ * @brief This file contains firmware specific defines.
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/27/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_FW_H_
+#define _MLAN_FW_H_
+
+/** Interface header length */
+#ifdef USB
+#define USB_INTF_HEADER_LEN 0
+#endif /* USB */
+#ifdef SDIO
+#define SDIO_INTF_HEADER_LEN 4
+#endif /* SDIO */
+#ifdef PCIE
+#define PCIE_INTF_HEADER_LEN 4
+#endif /* PCIE */
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+#define WPA_GCMP_KEY_LEN 32
+
+#define WPA_CCMP_256_KEY_LEN 32
+
+/** Ethernet header */
+typedef MLAN_PACK_START struct {
+ /** Ethernet header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet header length */
+ t_u16 h803_len;
+
+} MLAN_PACK_END Eth803Hdr_t;
+
+/** RFC 1042 header */
+typedef MLAN_PACK_START struct {
+ /** LLC DSAP */
+ t_u8 llc_dsap;
+ /** LLC SSAP */
+ t_u8 llc_ssap;
+ /** LLC CTRL */
+ t_u8 llc_ctrl;
+ /** SNAP OUI */
+ t_u8 snap_oui[3];
+ /** SNAP type */
+ t_u16 snap_type;
+
+} MLAN_PACK_END Rfc1042Hdr_t;
+
+/** Rx packet header */
+typedef MLAN_PACK_START struct {
+ /** Etherner header */
+ Eth803Hdr_t eth803_hdr;
+ /** RFC 1042 header */
+ Rfc1042Hdr_t rfc1042_hdr;
+
+} MLAN_PACK_END RxPacketHdr_t;
+
+/** Rates supported in band B */
+#define B_SUPPORTED_RATES 5
+/** Rates supported in band G */
+#define G_SUPPORTED_RATES 9
+/** Rates supported in band BG */
+#define BG_SUPPORTED_RATES 13
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define A_SUPPORTED_RATES 9
+
+/** CapInfo Short Slot Time Disabled */
+/* #define SHORT_SLOT_TIME_DISABLED(CapInfo)
+ * ((IEEEtypes_CapInfo_t)(CapInfo).short_slot_time = 0) */
+#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~MBIT(10))
+/** CapInfo Short Slot Time Enabled */
+#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= MBIT(10))
+/** CapInfo Spectrum Mgmt Disabled */
+#define SPECTRUM_MGMT_DISABLED(CapInfo) (CapInfo &= ~MBIT(8))
+/** CapInfo Spectrum Mgmt Enabled */
+#define SPECTRUM_MGMT_ENABLED(CapInfo) (CapInfo |= MBIT(8))
+/** CapInfo Radio Measurement Disabled */
+#define RADIO_MEASUREMENT_DISABLED(CapInfo) (CapInfo &= ~MBIT(12))
+/** CapInfo Radio Measurement Enabled */
+#define RADIO_MEASUREMENT_ENABLED(CapInfo) (CapInfo |= MBIT(12))
+
+/** Setup the number of rates passed in the driver/firmware API */
+#define HOSTCMD_SUPPORTED_RATES 14
+
+/** Rates supported in band N */
+#define N_SUPPORTED_RATES 3
+#ifdef STA_SUPPORT
+/** All bands (B, G, N, AAC, GAC) */
+#define ALL_802_11_BANDS \
+ (BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AAC | BAND_GAC)
+#else
+/** All bands (B, G, A) */
+#define ALL_802_11_BANDS (BAND_B | BAND_G | BAND_A)
+#endif /* STA_SUPPORT */
+
+#ifdef STA_SUPPORT
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT \
+ (MBIT(8) | MBIT(9) | MBIT(10) | MBIT(11) | MBIT(12) | MBIT(13))
+#else
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT (MBIT(8) | MBIT(9) | MBIT(10))
+#endif /* STA_SUPPORT */
+/** Check if multiple bands support is enabled in firmware */
+#define IS_SUPPORT_MULTI_BANDS(_adapter) \
+ (_adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+/** Get default bands of the firmware */
+/* need to shift bit 12 and bit 13 in fw_cap_info from the firmware
+ * to bit 13 and 14 for 11ac so that bit 11 is for GN, bit 12 for AN,
+ * bit 13 for GAC, and bit 14 for AAC, in order to be compatible with
+ * the band capability defined in the driver after right shift of 8 bits */
+#define GET_FW_DEFAULT_BANDS(_adapter) \
+ (((((_adapter->fw_cap_info & 0x3000) << 1) | \
+ (_adapter->fw_cap_info & ~0xF000)) >> \
+ 8) & \
+ ALL_802_11_BANDS)
+
+extern t_u8 SupportedRates_B[B_SUPPORTED_RATES];
+extern t_u8 SupportedRates_G[G_SUPPORTED_RATES];
+extern t_u8 SupportedRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 SupportedRates_A[A_SUPPORTED_RATES];
+extern t_u8 SupportedRates_N[N_SUPPORTED_RATES];
+extern t_u8 AdhocRates_G[G_SUPPORTED_RATES];
+extern t_u8 AdhocRates_B[B_SUPPORTED_RATES];
+extern t_u8 AdhocRates_BG[BG_SUPPORTED_RATES];
+extern t_u8 AdhocRates_A[A_SUPPORTED_RATES];
+
+/** Default auto deep sleep mode */
+#define DEFAULT_AUTO_DS_MODE MTRUE
+/** Default power save mode */
+#define DEFAULT_PS_MODE Wlan802_11PowerModePSP
+
+/** WEP Key index mask */
+#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
+/** Length of WEP 40 bit key */
+#define WEP_40_BIT_LEN 5
+/** Length of WEP 104 bit key */
+#define WEP_104_BIT_LEN 13
+
+/** Key information enabled */
+#define KEY_INFO_ENABLED 0x01
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID {
+ /** Key type : WEP */
+ KEY_TYPE_ID_WEP = 0,
+ /** Key type : TKIP */
+ KEY_TYPE_ID_TKIP = 1,
+ /** Key type : AES */
+ KEY_TYPE_ID_AES = 2,
+ KEY_TYPE_ID_WAPI = 3,
+ KEY_TYPE_ID_AES_CMAC = 4,
+ /** Key type : GCMP */
+ KEY_TYPE_ID_GCMP = 5,
+ /** Key type : GCMP_256 */
+ KEY_TYPE_ID_GCMP_256 = 6,
+ /** Key type : CCMP_256 */
+ KEY_TYPE_ID_CCMP_256 = 7,
+} KEY_TYPE_ID;
+
+/** Key Info flag for multicast key */
+#define KEY_INFO_MCAST_KEY 0x01
+/** Key Info flag for unicast key */
+#define KEY_INFO_UCAST_KEY 0x02
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP {
+ KEY_INFO_WEP_MCAST = 0x01,
+ KEY_INFO_WEP_UNICAST = 0x02,
+ KEY_INFO_WEP_ENABLED = 0x04
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP {
+ KEY_INFO_TKIP_MCAST = 0x01,
+ KEY_INFO_TKIP_UNICAST = 0x02,
+ KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES {
+ KEY_INFO_AES_MCAST = 0x01,
+ KEY_INFO_AES_UNICAST = 0x02,
+ KEY_INFO_AES_ENABLED = 0x04,
+ KEY_INFO_AES_MCAST_IGTK = 0x400,
+} KEY_INFO_AES;
+
+/** WPA AES key length */
+#define WPA_AES_KEY_LEN 16
+/** WPA TKIP key length */
+#define WPA_TKIP_KEY_LEN 32
+/** WPA AES IGTK key length */
+#define CMAC_AES_KEY_LEN 16
+/** IGTK key length */
+#define WPA_IGTK_KEY_LEN 16
+
+/** WAPI key length */
+#define WAPI_KEY_LEN 50
+/** KEY_INFO_WAPI*/
+typedef enum _KEY_INFO_WAPI {
+ KEY_INFO_WAPI_MCAST = 0x01,
+ KEY_INFO_WAPI_UNICAST = 0x02,
+ KEY_INFO_WAPI_ENABLED = 0x04
+} KEY_INFO_WAPI;
+
+/** Maximum ethernet frame length sans FCS */
+#define MV_ETH_FRAME_LEN 1514
+
+#if defined(SDIO) || defined(PCIE)
+/** Length of SNAP header */
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES 100
+
+/** The number of times to try when waiting for downloaded firmware to
+ become active when multiple interface is present */
+#define MAX_MULTI_INTERFACE_POLL_TRIES 150
+/** The number of times to try when waiting for downloaded firmware to
+ become active. (polling the scratch register). */
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+/** FW fill in rx_len with extra 204 bytes */
+#define EXTRA_LEN 256
+
+/** Buffer size for ethernet Tx packets */
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
+
+/** Buffer size for ethernet Rx packets */
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (MV_ETH_FRAME_LEN + sizeof(RxPD) + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+#endif /* SDIO || PCIE */
+
+#ifdef SDIO
+/* Macros in interface module */
+/** Firmware ready */
+#define SDIO_FIRMWARE_READY 0xfedc
+#endif /* SDIO */
+
+#ifdef PCIE
+/* Macros in interface module */
+/** Firmware ready */
+#define PCIE_FIRMWARE_READY 0xfedcba00
+#endif
+
+/** Enumeration definition*/
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER {
+ Wlan802_11PrivFilterAcceptAll,
+ Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS {
+ Wlan802_11WEPEnabled,
+ Wlan802_11WEPDisabled,
+ Wlan802_11WEPKeyAbsent,
+ Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNR calculation */
+#define CAL_SNR(RSSI, NF) ((t_s16)((t_s16)(RSSI) - (t_s16)(NF)))
+
+/** 2K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_2K 2048
+
+/** Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+/** TLV type : SSID */
+#define TLV_TYPE_SSID 0x0000
+/** TLV type : Rates */
+#define TLV_TYPE_RATES 0x0001
+/** TLV type : PHY FH */
+#define TLV_TYPE_PHY_FH 0x0002
+/** TLV type : PHY DS */
+#define TLV_TYPE_PHY_DS 0x0003
+/** TLV type : CF */
+#define TLV_TYPE_CF 0x0004
+/** TLV type : IBSS */
+#define TLV_TYPE_IBSS 0x0006
+
+/** TLV type : Domain */
+#define TLV_TYPE_DOMAIN 0x0007
+
+/** TLV type : Power constraint */
+#define TLV_TYPE_POWER_CONSTRAINT 0x0020
+
+/** TLV type : Power capability */
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+#define TLV_TYPE_HT_CAPABILITY 0x002d
+
+#define TLV_TYPE_EXTENSION_ID 0x00ff
+
+/**TLV type : Host MLME Flag*/
+#define TLV_TYPE_HOST_MLME (PROPRIETARY_TLV_BASE_ID + 307)
+
+/** TLV type : Vendor Specific IE */
+#define TLV_TYPE_VENDOR_SPECIFIC_IE 0x00dd
+
+/** TLV type : Key material */
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0x00) /* 0x0100 */
+/** TLV type : Channel list */
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 0x01) /* 0x0101 */
+/** TLV type : Number of probes */
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 0x02) /* 0x0102 */
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 0x04) /* 0x0104 */
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 0x05) /* 0x0105 */
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 0x06) /* 0x0106 */
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x07) /* 0x0107 */
+/** TLV type : LED behavior */
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 0x09) /* 0x0109 */
+/** TLV type : Passthrough */
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 0x0a) /* 0x010a */
+/** TLV type : Power TBL 2.4 Ghz */
+#define TLV_TYPE_POWER_TBL_2_4GHZ \
+ (PROPRIETARY_TLV_BASE_ID + 0x0c) /* 0x010c \
+ */
+/** TLV type : Power TBL 5 GHz */
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 0x0d) /* 0x010d */
+/** TLV type : WMM queue status */
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 0x10) /* 0x0110 */
+/** TLV type : Wildcard SSID */
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 0x12) /* 0x0112 */
+/** TLV type : TSF timestamp */
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 0x13) /* 0x0113 */
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 0x16) /* 0x0116 */
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 0x17) /* 0x0117 */
+/** TLV type : Start BG scan later */
+#define TLV_TYPE_STARTBGSCANLATER \
+ (PROPRIETARY_TLV_BASE_ID + 0x1e) /* 0x011e \
+ */
+/** TLV type: BG scan repeat count */
+#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 0xb0) /* 0x01b0 */
+/** TLV type : Authentication type */
+#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 0x1f) /* 0x011f */
+/** TLV type : BSSID */
+#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 0x23) /* 0x0123 */
+
+/** TLV type : Link Quality */
+#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 0x24) /* 0x0124 */
+
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x26) /* 0x0126 */
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 0x27) /* 0x0127 */
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x28) /* 0x0128 */
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 0x29) /* 0x0129 */
+
+/** TLV type : Channel band list */
+#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 0x2a) /* 0x012a */
+
+/** TLV type : Security Cfg */
+#define TLV_TYPE_SECURITY_CFG (PROPRIETARY_TLV_BASE_ID + 0x3a) /* 0x013a */
+
+/** TLV type : Passphrase */
+#define TLV_TYPE_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 0x3c) /* 0x013c */
+/** TLV type : SAE Password */
+#define TLV_TYPE_SAE_PASSWORD (PROPRIETARY_TLV_BASE_ID + 0x141) /* 0x0241 */
+/** TLV type : Encryption Protocol TLV */
+#define TLV_TYPE_ENCRYPTION_PROTO \
+ (PROPRIETARY_TLV_BASE_ID + 0x40) /* 0x0140 \
+ */
+/** TLV type : Cipher TLV */
+#define TLV_TYPE_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x42) /* 0x0142 */
+/** TLV type : PMK */
+#define TLV_TYPE_PMK (PROPRIETARY_TLV_BASE_ID + 0x44) /* 0x0144 */
+
+/** TLV type : BCN miss */
+#define TLV_TYPE_PRE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 0x49) /* 0x0149 */
+
+/** TLV type: WAPI IE */
+#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 0x5e) /* 0x015e */
+
+/** TLV type: MGMT IE */
+#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0x69) /* 0x0169 */
+/** TLV type: MAX_MGMT_IE */
+#define TLV_TYPE_MAX_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 0xaa) /* 0x01aa */
+
+/** TLV type: key param v2 */
+#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 0x9C) /* 0x019C */
+
+/** TLV type: ps params in hs */
+#define TLV_TYPE_PS_PARAMS_IN_HS (PROPRIETARY_TLV_BASE_ID + 0xB5) /* 0x01b5 */
+/** TLV type: hs wake hold off */
+#define TLV_TYPE_HS_WAKE_HOLDOFF (PROPRIETARY_TLV_BASE_ID + 0xB6) /* 0x01b6 */
+/** TLV type: wake up source */
+#define TLV_TYPE_HS_WAKEUP_SOURCE_GPIO \
+ (PROPRIETARY_TLV_BASE_ID + 0x105) /* 0x0205 */
+/** TLV type: management filter */
+#define TLV_TYPE_MGMT_FRAME_WAKEUP \
+ (PROPRIETARY_TLV_BASE_ID + 0x116) /* 0x0216 */
+/** TLV type: extend wakeup source */
+#define TLV_TYPE_WAKEUP_EXTEND (PROPRIETARY_TLV_BASE_ID + 0x118) /* 0x0218 */
+/** TLV type: HS antenna mode */
+#define TLV_TYPE_HS_ANTMODE (PROPRIETARY_TLV_BASE_ID + 0x119) /* 0x0219 */
+
+/** TLV type: robustcoex mode */
+#define TLV_TYPE_ROBUSTCOEX (PROPRIETARY_TLV_BASE_ID + 0x11B) /* 0x021B */
+
+#define TLV_TYPE_DMCS_STATUS (PROPRIETARY_TLV_BASE_ID + 0x13A) /* 0x023A */
+
+/** TLV type : HT Capabilities */
+#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 0x4a) /* 0x014a */
+/** TLV type : HT Information */
+#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 0x4b) /* 0x014b */
+/** TLV type : Secondary Channel Offset */
+#define TLV_SECONDARY_CHANNEL_OFFSET \
+ (PROPRIETARY_TLV_BASE_ID + 0x4c) /* 0x014c */
+/** TLV type : 20/40 BSS Coexistence */
+#define TLV_TYPE_2040BSS_COEXISTENCE \
+ (PROPRIETARY_TLV_BASE_ID + 0x4d) /* 0x014d */
+/** TLV type : Overlapping BSS Scan Parameters */
+#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM \
+ (PROPRIETARY_TLV_BASE_ID + 0x4e) /* 0x014e */
+/** TLV type : Extended capabilities */
+#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 0x4f) /* 0x014f */
+/** TLV type : Set of MCS values that STA desires to use within the BSS */
+#define TLV_TYPE_HT_OPERATIONAL_MCS_SET \
+ (PROPRIETARY_TLV_BASE_ID + 0x50) /* 0x0150 */
+/** TLV ID : Management Frame */
+#define TLV_TYPE_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 0x68) /* 0x0168 */
+/** TLV type : RXBA_SYNC */
+#define TLV_TYPE_RXBA_SYNC (PROPRIETARY_TLV_BASE_ID + 0x99) /* 0x0199 */
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** TLV type : AP PSK */
+#define TLV_TYPE_UAP_PSK (PROPRIETARY_TLV_BASE_ID + 0xa8) /* 0x01a8 */
+/** TLV type : p2p NOA */
+#define TLV_TYPE_WIFI_DIRECT_NOA (PROPRIETARY_TLV_BASE_ID + 0x83)
+/** TLV type : p2p opp ps */
+#define TLV_TYPE_WIFI_DIRECT_OPP_PS (PROPRIETARY_TLV_BASE_ID + 0x84)
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** TLV : 20/40 coex config */
+#define TLV_TYPE_2040_BSS_COEX_CONTROL \
+ (PROPRIETARY_TLV_BASE_ID + 0x98) /* 0x0198 */
+
+/** TLV type : aggr win size */
+#define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 0xca)
+/** TLV type : scan time */
+#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 0Xcb)
+/** TLV type : Ewpa_eapol_pkt */
+#define TLV_TYPE_EAPOL_PKT (PROPRIETARY_TLV_BASE_ID + 0xcf)
+
+#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 0x9a)
+
+/** TLV type : EES Configuration */
+#define TLV_TYPE_EES_CFG (PROPRIETARY_TLV_BASE_ID + 0xda)
+/** TLV type : EES Network Configuration */
+#define TLV_TYPE_EES_NET_CFG (PROPRIETARY_TLV_BASE_ID + 0xdb)
+
+#define TLV_TYPE_LL_STAT_IFACE (PROPRIETARY_TLV_BASE_ID + 300)
+#define TLV_TYPE_LL_STAT_RADIO (PROPRIETARY_TLV_BASE_ID + 301)
+
+/** TLV type: fw cap info */
+#define TLV_TYPE_FW_CAP_INFO (PROPRIETARY_TLV_BASE_ID + 318)
+
+/** ADDBA TID mask */
+#define ADDBA_TID_MASK (MBIT(2) | MBIT(3) | MBIT(4) | MBIT(5))
+/** DELBA TID mask */
+#define DELBA_TID_MASK (MBIT(12) | MBIT(13) | MBIT(14) | MBIT(15))
+/** ADDBA Starting Sequence Number Mask */
+#define SSN_MASK 0xfff0
+
+/** Block Ack result status */
+/** Block Ack Result : Success */
+#define BA_RESULT_SUCCESS 0x0
+/** Block Ack Result : Execution failure */
+#define BA_RESULT_FAILURE 0x1
+/** Block Ack Result : Timeout */
+#define BA_RESULT_TIMEOUT 0x2
+/** Block Ack Result : Data invalid */
+#define BA_RESULT_DATA_INVALID 0x3
+
+/** Get the baStatus (NOT_SETUP, COMPLETE, IN_PROGRESS)
+ * in Tx BA stream table */
+#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
+
+/** An AMPDU/AMSDU could be disallowed for certain TID. 0xff means
+ * no aggregation is enabled for the assigned TID */
+#define BA_STREAM_NOT_ALLOWED 0xff
+
+#ifdef STA_SUPPORT
+#endif
+
+/** Test if 11n is enabled by checking the HTCap IE */
+#define IS_11N_ENABLED(priv) \
+ ((priv->config_bands & BAND_GN || priv->config_bands & BAND_AN) && \
+ priv->curr_bss_params.bss_descriptor.pht_cap && \
+ !priv->curr_bss_params.bss_descriptor.disable_11n)
+/** Find out if we are the initiator or not */
+#define INITIATOR_BIT(DelBAParamSet) \
+ (((DelBAParamSet)&MBIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+/** 4K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_4K 4096
+/** 8K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_8K 8192
+/** 12K buf size */
+#define MLAN_TX_DATA_BUF_SIZE_12K 12288
+/** Max Rx AMPDU Size */
+#define MAX_RX_AMPDU_SIZE_64K 0x03
+/** Non green field station */
+#define NON_GREENFIELD_STAS 0x04
+
+/** Greenfield support */
+#define HWSPEC_GREENFIELD_SUPP MBIT(29)
+/** RX STBC support */
+#define HWSPEC_RXSTBC_SUPP MBIT(26)
+/** ShortGI @ 40Mhz support */
+#define HWSPEC_SHORTGI40_SUPP MBIT(24)
+/** ShortGI @ 20Mhz support */
+#define HWSPEC_SHORTGI20_SUPP MBIT(23)
+/** RX LDPC support */
+#define HWSPEC_LDPC_SUPP MBIT(22)
+/** Channel width 40Mhz support */
+#define HWSPEC_CHANBW40_SUPP MBIT(17)
+/** 40Mhz intolarent enable */
+#define CAPINFO_40MHZ_INTOLARENT MBIT(8)
+
+/** Default 11n capability mask for 2.4GHz */
+#define DEFAULT_11N_CAP_MASK_BG \
+ (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP | HWSPEC_LDPC_SUPP)
+/** Default 11n capability mask for 5GHz */
+#define DEFAULT_11N_CAP_MASK_A \
+ (HWSPEC_CHANBW40_SUPP | HWSPEC_SHORTGI20_SUPP | \
+ HWSPEC_SHORTGI40_SUPP | HWSPEC_RXSTBC_SUPP | HWSPEC_LDPC_SUPP)
+
+/** Default 11n TX BF capability 2X2 chip **/
+#define DEFAULT_11N_TX_BF_CAP_2X2 0x19E74618
+/** Default 11n TX BF capability 1X1 chip **/
+#define DEFAULT_11N_TX_BF_CAP_1X1 0x19E74608
+
+/** Bits to ignore in hw_dev_cap as these bits are set in get_hw_spec */
+#define IGN_HW_DEV_CAP (CAPINFO_40MHZ_INTOLARENT)
+
+/** HW_SPEC FwCapInfo */
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & MBIT(11))
+
+/** HW_SPEC Dot11nDevCap : MAX AMSDU supported */
+#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & MBIT(31))
+/** HW_SPEC Dot11nDevCap : Beamforming support */
+#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & MBIT(30))
+/** HW_SPEC Dot11nDevCap : Green field support */
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & MBIT(29))
+/** HW_SPEC Dot11nDevCap : AMPDU support */
+#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & MBIT(28))
+/** HW_SPEC Dot11nDevCap : MIMO PS support */
+#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & MBIT(27))
+/** HW_SPEC Dot11nDevCap : Rx STBC support */
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(26))
+/** HW_SPEC Dot11nDevCap : Tx STBC support */
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & MBIT(25))
+/** HW_SPEC Dot11nDevCap : Short GI @ 40Mhz support */
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & MBIT(24))
+/** HW_SPEC Dot11nDevCap : Reset Short GI @ 40Mhz support */
+#define RESETSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(24))
+/** HW_SPEC Dot11nDevCap : Short GI @ 20Mhz support */
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & MBIT(23))
+/** HW_SPEC Dot11nDevCap : Rx LDPC support */
+#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & MBIT(22))
+/** HW_SPEC Dot11nDevCap : Number of TX BA streams supported */
+#define ISSUPP_GETTXBASTREAM(Dot11nDevCap) ((Dot11nDevCap >> 18) & 0xF)
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 40Mhz support */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & MBIT(17))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 20Mhz support */
+#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & MBIT(16))
+/** HW_SPEC Dot11nDevCap : Channel BW support @ 10Mhz support */
+#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & MBIT(15))
+/** Dot11nUsrCap : 40Mhz intolarance enabled */
+#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & MBIT(8))
+/** Dot11nUsrCap : Reset 40Mhz intolarance enabled */
+#define RESET_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(8))
+/** HW_SPEC Dot11nDevCap : Rx AntennaD support */
+#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(7))
+/** HW_SPEC Dot11nDevCap : Rx AntennaC support */
+#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(6))
+/** HW_SPEC Dot11nDevCap : Rx AntennaB support */
+#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(5))
+/** HW_SPEC Dot11nDevCap : Rx AntennaA support */
+#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(4))
+/** HW_SPEC Dot11nDevCap : Tx AntennaD support */
+#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & MBIT(3))
+/** HW_SPEC Dot11nDevCap : Tx AntennaC support */
+#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & MBIT(2))
+/** HW_SPEC Dot11nDevCap : Tx AntennaB support */
+#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & MBIT(1))
+/** HW_SPEC Dot11nDevCap : Tx AntennaA support */
+#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & MBIT(0))
+
+/** HW_SPEC Dot11nDevCap : Set support of channel bw @ 40Mhz */
+#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= MBIT(17))
+/** HW_SPEC Dot11nDevCap : Reset support of channel bw @ 40Mhz */
+#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~MBIT(17))
+
+/** DevMCSSupported : Tx MCS supported */
+#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4)
+/** DevMCSSupported : Rx MCS supported */
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+
+/** GET HTCapInfo : Supported Channel BW */
+#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & MBIT(1))
+/** GET HTCapInfo : Support for Greenfield */
+#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & MBIT(4))
+/** GET HTCapInfo : Support for Short GI @ 20Mhz */
+#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & MBIT(5))
+/** GET HTCapInfo : Support for Short GI @ 40Mhz */
+#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & MBIT(6))
+/** GET HTCapInfo : Support for Tx STBC */
+#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & MBIT(7))
+
+/** GET HTCapInfo : Support for Rx STBC */
+#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03)
+/** GET HTCapInfo : Support for Delayed ACK */
+#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & MBIT(10))
+/** GET HTCapInfo : Support for Max AMSDU */
+#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & MBIT(11))
+
+/** GET HTCapInfo : Support 40Mhz Intolarence */
+#define GETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo & MBIT(14))
+
+/** SET HTCapInfo : Set support for LDPC coding capability */
+#define SETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo |= MBIT(0))
+/** SET HTCapInfo : Set support for Channel BW */
+#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= MBIT(1))
+/** SET HTCapInfo : Set support for Greenfield */
+#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= MBIT(4))
+/** SET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= MBIT(5))
+/** SET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= MBIT(6))
+/** SET HTCapInfo : Set support for Tx STBC */
+#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= MBIT(7))
+/** SET HTCapInfo : Set support for Rx STBC */
+#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8))
+/** SET HTCapInfo : Set support for delayed block ack */
+#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= MBIT(10))
+/** SET HTCapInfo : Set support for Max size AMSDU */
+#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= MBIT(11))
+/** SET HTCapInfo : Set support for DSSS/CCK Rates @ 40Mhz */
+#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= MBIT(12))
+/** SET HTCapInfo : Enable 40Mhz Intolarence */
+#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= MBIT(14))
+/** SET HTCapInfo : Disable Static SM power save */
+#define SETHT_STATIC_SMPS(HTCapInfo) ((HTCapInfo) |= (MBIT(2) | MBIT(3)))
+
+/** RESET HTCapInfo : Set support for LDPC coding capability */
+#define RESETHT_LDPCCODINGCAP(HTCapInfo) (HTCapInfo &= ~MBIT(0))
+/** RESET HTCapInfo : Set support for Channel BW */
+#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~MBIT(1))
+/** RESET HTCapInfo : Set support for Greenfield */
+#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~MBIT(4))
+/** RESET HTCapInfo : Set support for Short GI @ 20Mhz */
+#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~MBIT(5))
+/** RESET HTCapInfo : Set support for Short GI @ 40Mhz */
+#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~MBIT(6))
+/** RESET HTCapInfo : Set support for Tx STBC */
+#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~MBIT(7))
+/** RESET HTCapInfo : Set support for Rx STBC */
+#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8))
+/** RESET HTCapInfo : Set support for delayed block ack */
+#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~MBIT(10))
+/** RESET HTCapInfo : Set support for Max size AMSDU */
+#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~MBIT(11))
+/** RESET HTCapInfo : Disable 40Mhz Intolarence */
+#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~MBIT(14))
+/** RESET HTCapInfo: Enable SM power save */
+#define RESETHT_SM_POWERSAVE(HTCapInfo) ((HTCapInfo) &= ~(MBIT(2) | MBIT(3)))
+/** RESET HTExtCap : Clear RD Responder bit */
+#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~MBIT(11))
+/** SET MCS32 */
+#define SETHT_MCS32(x) (x[4] |= 1)
+/** Set mcs set defined bit */
+#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1)
+/** Set the highest Rx data rate */
+#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(t_u16 *)(x + 10)) = y)
+/** AMPDU factor size */
+#define AMPDU_FACTOR_64K 0x03
+/** Set AMPDU size in A-MPDU paramter field */
+#define SETAMPDU_SIZE(x, y) \
+ do { \
+ x = x & ~0x03; \
+ x |= y & 0x03; \
+ } while (0) /** Set AMPDU spacing in A-MPDU paramter field */
+#define SETAMPDU_SPACING(x, y) \
+ do { \
+ x = x & ~0x1c; \
+ x |= (y & 0x07) << 2; \
+ } while (0)
+
+/** RadioType : Support for Band A */
+#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & MBIT(10))
+/** RadioType : Support for 40Mhz channel BW */
+#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & MBIT(2))
+/** RadioType : Set support 40Mhz channel */
+#define SET_CHANWIDTH40(Field2) (Field2 |= MBIT(2))
+/** RadioType : Reset support 40Mhz channel */
+#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(MBIT(0) | MBIT(1) | MBIT(2)))
+/** RadioType : Get secondary channel */
+#define GET_SECONDARYCHAN(Field2) (Field2 & (MBIT(0) | MBIT(1)))
+
+/** ExtCap : Support for FILS */
+#define ISSUPP_EXTCAP_FILS(ext_cap) (ext_cap.FILS)
+/** ExtCap : Set support FILS */
+#define SET_EXTCAP_FILS(ext_cap) (ext_cap.FILS = 1)
+/** ExtCap : Reset support FILS */
+#define RESET_EXTCAP_FILS(ext_cap) (ext_cap.FILS = 0)
+
+/** ExtCap : Support for TDLS */
+#define ISSUPP_EXTCAP_TDLS(ext_cap) (ext_cap.TDLSSupport)
+/** ExtCap : Set support TDLS */
+#define SET_EXTCAP_TDLS(ext_cap) (ext_cap.TDLSSupport = 1)
+/** ExtCap : Reset support TDLS */
+#define RESET_EXTCAP_TDLS(ext_cap) (ext_cap.TDLSSupport = 0)
+/** ExtCap : Support for TDLS UAPSD */
+#define ISSUPP_EXTCAP_TDLS_UAPSD(ext_cap) (ext_cap.TDLSPeerUAPSDSupport)
+/** ExtCap : Set support TDLS UAPSD */
+#define SET_EXTCAP_TDLS_UAPSD(ext_cap) (ext_cap.TDLSPeerUAPSDSupport = 1)
+/** ExtCap : Reset support TDLS UAPSD */
+#define RESET_EXTCAP_TDLS_UAPSD(ext_cap) (ext_cap.TDLSPeerUAPSDSupport = 0)
+/** ExtCap : Support for TDLS CHANNEL SWITCH */
+#define ISSUPP_EXTCAP_TDLS_CHAN_SWITCH(ext_cap) (ext_cap.TDLSChannelSwitching)
+/** ExtCap : Set support TDLS CHANNEL SWITCH */
+#define SET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap) (ext_cap.TDLSChannelSwitching = 1)
+/** ExtCap : Reset support TDLS CHANNEL SWITCH */
+#define RESET_EXTCAP_TDLS_CHAN_SWITCH(ext_cap) \
+ (ext_cap.TDLSChannelSwitching = 0)
+/** ExtCap : Set support Multi BSSID */
+#define SET_EXTCAP_MULTI_BSSID(ext_cap) (ext_cap.MultipleBSSID = 1)
+/** ExtCap : Support for Interworking */
+#define ISSUPP_EXTCAP_INTERWORKING(ext_cap) (ext_cap.Interworking)
+/** ExtCap : Set support Interworking */
+#define SET_EXTCAP_INTERWORKING(ext_cap) (ext_cap.Interworking = 1)
+/** ExtCap : Reset support Interworking */
+#define RESET_EXTCAP_INTERWORKING(ext_cap) (ext_cap.Interworking = 0)
+/** ExtCap : Support for Operation Mode Notification */
+#define ISSUPP_EXTCAP_OPERMODENTF(ext_cap) (ext_cap.OperModeNtf)
+/** ExtCap : Set support Operation Mode Notification */
+#define SET_EXTCAP_OPERMODENTF(ext_cap) (ext_cap.OperModeNtf = 1)
+/** ExtCap : Reset support Operation Mode Notification */
+#define RESET_EXTCAP_OPERMODENTF(ext_cap) (ext_cap.OperModeNtf = 0)
+/** ExtCap : Support for QosMap */
+#define ISSUPP_EXTCAP_QOS_MAP(ext_cap) (ext_cap.Qos_Map)
+/** ExtCap : Set Support QosMap */
+#define SET_EXTCAP_QOS_MAP(ext_cap) (ext_cap.Qos_Map = 1)
+/** ExtCap : Reset support QosMap */
+#define RESET_EXTCAP_QOS_MAP(ext_cap) (ext_cap.Qos_Map = 0)
+/** ExtCap : Support for BSS_Transition */
+#define ISSUPP_EXTCAP_BSS_TRANSITION(ext_cap) (ext_cap.BSS_Transition)
+/** ExtCap : Set Support BSS_Transition */
+#define SET_EXTCAP_BSS_TRANSITION(ext_cap) (ext_cap.BSS_Transition = 1)
+/** ExtCap : Reset support BSS_Transition */
+#define RESET_EXTCAP_BSS_TRANSITION(ext_cap) (ext_cap.BSS_Transition = 0)
+
+/** ExtCap : Support for TDLS wider bandwidth */
+#define ISSUPP_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap) (ext_cap.TDLSWildBandwidth)
+/** ExtCap : Set support TDLS wider bandwidth */
+#define SET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap) (ext_cap.TDLSWildBandwidth = 1)
+/** ExtCap : Reset support TDLS wider bandwidth */
+#define RESET_EXTCAP_TDLS_WIDER_BANDWIDTH(ext_cap) \
+ (ext_cap.TDLSWildBandwidth = 0)
+
+/** ExtCap : Support for extend channel switch */
+#define ISSUPP_EXTCAP_EXT_CHANNEL_SWITCH(ext_cap) (ext_cap.ExtChanSwitching)
+/** ExtCap : Set support Ext Channel Switch */
+#define SET_EXTCAP_EXT_CHANNEL_SWITCH(ext_cap) (ext_cap.ExtChanSwitching = 1)
+/** ExtCap: Set Timing Measurement */
+#define SET_EXTCAP_EXT_TIMING_MEASUREMENT(ext_cap) \
+ (ext_cap.TimingMeasurement = 1)
+/** ExtCap : Reset support Ext Channel Switch */
+#define RESET_EXTCAP_EXT_CHANNEL_SWITCH(ext_cap) (ext_cap.ExtChanSwitching = 0)
+
+/** ExtCap : Support for TWT RESP */
+#define ISSUPP_EXTCAP_EXT_TWT_RESP(ext_cap) (ext_cap.TWTResp)
+/** ExtCap : Set support Ext TWT_REQ */
+#define SET_EXTCAP_TWT_REQ(ext_cap) (ext_cap.TWTReq = 1)
+/** ExtCap : ReSet support Ext TWT REQ */
+#define RESET_EXTCAP_TWT_REQ(ext_cap) (ext_cap.TWTReq = 0)
+
+/** LLC/SNAP header len */
+#define LLC_SNAP_LEN 8
+
+/** bandwidth following HTCAP */
+#define BW_FOLLOW_HTCAP 0
+/** bandwidth following VHTCAP */
+#define BW_FOLLOW_VHTCAP 1
+
+/** HW_SPEC FwCapInfo */
+#define HWSPEC_11ACSGI80_SUPP MBIT(5)
+#define HWSPEC_11ACRXSTBC_SUPP MBIT(8)
+
+#define ISSUPP_11ACENABLED(FwCapInfo) (FwCapInfo & (MBIT(12) | MBIT(13)))
+
+#define ISSUPP_11AC2GENABLED(FwCapInfo) (FwCapInfo & MBIT(12))
+#define ISSUPP_11AC5GENABLED(FwCapInfo) (FwCapInfo & MBIT(13))
+
+/** HW_SPEC Dot11acDevCap : HTC-VHT supported */
+#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & MBIT(22))
+/** HW_SPEC Dot11acDevCap : VHT TXOP PS support */
+#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & MBIT(21))
+/** HW_SPEC Dot11acDevCap : MU RX beamformee support */
+#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & MBIT(20))
+/** HW_SPEC Dot11acDevCap : MU TX beamformee support */
+#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & MBIT(19))
+/** HW_SPEC Dot11acDevCap : SU Beamformee support */
+#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & MBIT(12))
+/** HW_SPEC Dot11acDevCap : SU Beamformer support */
+#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & MBIT(11))
+/** HW_SPEC Dot11acDevCap : Rx STBC support */
+#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & MBIT(8))
+/** HW_SPEC Dot11acDevCap : Tx STBC support */
+#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & MBIT(7))
+/** HW_SPEC Dot11acDevCap : Short GI support for 160MHz BW */
+#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & MBIT(6))
+/** HW_SPEC Dot11acDevCap : Short GI support for 80MHz BW */
+#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & MBIT(5))
+/** HW_SPEC Dot11acDevCap : LDPC coding support */
+#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & MBIT(4))
+/** HW_SPEC Dot11acDevCap : Channel BW 20/40/80/160/80+80 MHz support */
+#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & MBIT(3))
+/** HW_SPEC Dot11acDevCap : Channel BW 20/40/80/160 MHz support */
+#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & MBIT(2))
+
+/** Set VHT Cap Info: Max MPDU length */
+#define SET_VHTCAP_MAXMPDULEN(VHTCapInfo, value) (VHTCapInfo |= (value & 0x03))
+/** SET VHT CapInfo: Supported Channel Width SET (2 bits)*/
+#define SET_VHTCAP_CHWDSET(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x3) << 2))
+/** SET VHT CapInfo: Rx STBC (3 bits) */
+#define SET_VHTCAP_RXSTBC(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x7) << 8))
+/** SET VHT CapInfo: Commpressed Steering Num of BFer Ant Supported (3 bits) */
+#define SET_VHTCAP_SNBFERANT(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x7) << 13))
+/** SET VHT CapInfo: Num of Sounding Dimensions (3 bits) */
+#define SET_VHTCAP_NUMSNDDM(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x7) << 16))
+/** SET VHT CapInfo: Max AMPDU Length Exponent (3 bits) */
+#define SET_VHTCAP_MAXAMPDULENEXP(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x7) << 23))
+/** SET VHT CapInfo: VHT Link Adaptation Capable (2 bits) */
+#define SET_VHTCAP_LINKADPCAP(VHTCapInfo, value) \
+ (VHTCapInfo |= ((value & 0x3) << 26))
+
+/** HW_SPEC Dot11acDevCap : ReSet VHT Link Adapation Capable */
+#define RESET_11ACVHTLINKCAPA(Dot11acDevCap, value) (Dot11acDevCap &= ~(0x03))
+/** HW_SPEC Dot11acDevCap : ReSet Maximum AMPDU Length Exponent */
+#define RESET_11ACAMPDULENEXP(Dot11acDevCap, value) (Dot11acDevCap &= ~(0x07))
+/** HW_SPEC Dot11acDevCap : ReSet support of HTC-VHT */
+#define RESET_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(22))
+/** HW_SPEC Dot11acDevCap : ReSet support of VHT TXOP PS */
+#define RESET_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(21))
+/** HW_SPEC Dot11acDevCap : ReSet support of MU RX beamformee */
+#define RESET_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(20))
+/** HW_SPEC Dot11acDevCap : ReSet support of MU TX beamformee */
+#define RESET_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(19))
+/** HW_SPEC Dot11acDevCap : ReSet Number of Sounding Dimensions */
+#define RESET_11ACSOUNDINGNUM(Dot11acDevCap) (Dot11acDevCap &= ~((0x07) << 16))
+/** HW_SPEC Dot11acDevCap : ReSet Compressed Steering Number
+ * of Beamformer Antenna */
+#define RESET_11ACBFANTNUM(Dot11acDevCap) (Dot11acDevCap &= ~((0x07) << 13))
+/** HW_SPEC Dot11acDevCap : ReSet support of SU Beamformee */
+#define RESET_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(12))
+/** HW_SPEC Dot11acDevCap : ReSet support of SU Beamformer */
+#define RESET_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(11))
+/** HW_SPEC Dot11acDevCap : ReSet support of Rx STBC */
+#define RESET_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap &= ~((0x07) << 8))
+/** HW_SPEC Dot11acDevCap : ReSet support of Tx STBC */
+#define RESET_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(7))
+/** HW_SPEC Dot11acDevCap : ReSet support of Short GI support for 160MHz BW */
+#define RESET_11ACSGI160(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(6))
+/** HW_SPEC Dot11acDevCap : ReSet support of Short GI support for 80MHz BW */
+#define RESET_11ACSGI80(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(5))
+/** HW_SPEC Dot11acDevCap : ReSet support of LDPC coding */
+#define RESET_11ACLDPC(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(4))
+/** HW_SPEC Dot11acDevCap : ReSet support of
+ * Channel BW 20/40/80/160/80+80 MHz */
+#define RESET_11ACBW8080(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(3))
+/** HW_SPEC Dot11acDevCap : ReSet support of
+ * Channel BW 20/40/80/160 MHz */
+#define RESET_11ACBW160(Dot11acDevCap) (Dot11acDevCap &= ~MBIT(2))
+/** HW_SPEC Dot11acDevCap : ReSet Max MPDU length */
+#define RESET_11ACMAXMPDULEN(Dot11acDevCap) (Dot11acDevCap &= ~(0x03))
+
+/** Default 11ac capability mask for 2.4GHz */
+#define DEFAULT_11AC_CAP_MASK_BG \
+ (HWSPEC_11ACSGI80_SUPP | HWSPEC_11ACRXSTBC_SUPP)
+/** Default 11ac capability mask for 5GHz */
+#define DEFAULT_11AC_CAP_MASK_A (HWSPEC_11ACSGI80_SUPP | HWSPEC_11ACRXSTBC_SUPP)
+/** GET VHT CapInfo : MAX MPDU Length */
+#define GET_VHTCAP_MAXMPDULEN(VHTCapInfo) (VHTCapInfo & 0x3)
+/** GET VHT CapInfo: Supported Channel Width SET (2 bits)*/
+#define GET_VHTCAP_CHWDSET(VHTCapInfo) ((VHTCapInfo >> 2) & 0x3)
+/** GET VHT CapInfo: Rx STBC (3 bits) */
+#define GET_VHTCAP_RXSTBC(VHTCapInfo) ((VHTCapInfo >> 8) & 0x7)
+/** GET VHT CapInfo: Compressed Steering Num of BFer Ant Supported (3 bits) */
+#define GET_VHTCAP_SNBFERANT(VHTCapInfo) ((VHTCapInfo >> 13) & 0x7)
+/** GET VHT CapInfo: Num of Sounding Dimensions (3 bits) */
+#define GET_VHTCAP_NUMSNDDM(VHTCapInfo) ((VHTCapInfo >> 16) & 0x7)
+/** GET VHT CapInfo: Max AMPDU Length Exponent (3 bits) */
+#define GET_VHTCAP_MAXAMPDULENEXP(VHTCapInfo) ((VHTCapInfo >> 23) & 0x7)
+/** GET VHT CapInfo: VHT Link Adaptation Capable (2 bits) */
+#define GET_VHTCAP_LINKADPCAP(VHTCapInfo) ((VHTCapInfo >> 26) & 0x3)
+/**SET OPERATING MODE:Channel Width:80M*/
+#define SET_OPER_MODE_80M(oper_mode) \
+ (oper_mode = (oper_mode & ~MBIT(0)) | MBIT(1))
+/**SET OPERATING MODE:Channel Width:40M*/
+#define SET_OPER_MODE_40M(oper_mode) \
+ (oper_mode = (oper_mode & ~MBIT(1)) | MBIT(0))
+/**SET OPERATING MODE:Channel Width:20M*/
+#define SET_OPER_MODE_20M(oper_mode) (oper_mode &= ~(0x03))
+#define IS_OPER_MODE_20M(oper_mode) (((oper_mode) & (MBIT(0) | MBIT(1))) == 0)
+/**SET OPERATING MODE:Rx NSS:2*/
+#define SET_OPER_MODE_2NSS(oper_mode) \
+ (oper_mode = (oper_mode & ~(MBIT(5) | MBIT(6))) | MBIT(4))
+/**SET OPERATING MODE:Rx NSS:1*/
+#define SET_OPER_MODE_1NSS(oper_mode) \
+ (oper_mode &= ~(MBIT(4) | MBIT(5) | MBIT(6)))
+
+#define GET_VHTMCS(MCSMapSet) (MCSMapSet & 0xFFFF)
+#define GET_VHTNSSMCS(MCSMapSet, nss) ((MCSMapSet >> (2 * (nss - 1))) & 0x3)
+#define RET_VHTNSSMCS(MCSMapSet, nss) ((MCSMapSet >> (2 * (nss - 1))) & 0x3)
+#define SET_VHTNSSMCS(MCSMapSet, nss, value) \
+ (MCSMapSet |= (value & 0x3) << (2 * (nss - 1)))
+
+/** DevMCSSupported : Tx MCS supported */
+#define GET_DEVTXMCSMAP(DevMCSMap) (DevMCSMap >> 16)
+#define GET_DEVNSSTXMCS(DevMCSMap, nss) \
+ ((DevMCSMap >> (2 * (nss - 1) + 16)) & 0x3)
+#define SET_DEVNSSTXMCS(DevMCSMap, nss, value) \
+ (DevMCSMap |= (value & 0x3) << (2 * (nss - 1) + 16))
+#define RESET_DEVTXMCSMAP(DevMCSMap) (DevMCSMap &= 0xFFFF)
+/** DevMCSSupported : Rx MCS supported */
+#define GET_DEVRXMCSMAP(DevMCSMap) (DevMCSMap & 0xFFFF)
+#define GET_DEVNSSRXMCS(DevMCSMap, nss) ((DevMCSMap >> (2 * (nss - 1))) & 0x3)
+#define SET_DEVNSSRXMCS(DevMCSMap, nss, value) \
+ (DevMCSMap |= (value & 0x3) << (2 * (nss - 1)))
+#define RESET_DEVRXMCSMAP(DevMCSMap) (DevMCSMap &= 0xFFFF0000)
+
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_DROP_PATTERN \
+ (PROPRIETARY_TLV_BASE_ID + 0x51) /* 0x0151 \
+ */
+/** TLV type : Rate drop pattern */
+#define TLV_TYPE_RATE_DROP_CONTROL \
+ (PROPRIETARY_TLV_BASE_ID + 0x52) /* 0x0152 \
+ */
+/** TLV type : Rate scope */
+#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 0x53) /* 0x0153 */
+
+/** TLV type : Power group */
+#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 0x54) /* 0x0154 */
+
+/** Modulation class for DSSS Rates */
+#define MOD_CLASS_HR_DSSS 0x03
+/** Modulation class for OFDM Rates */
+#define MOD_CLASS_OFDM 0x07
+/** Modulation class for HT Rates */
+#define MOD_CLASS_HT 0x08
+/** Modulation class for VHT Rates */
+#define MOD_CLASS_VHT 0x09
+/** HT bandwidth 20 MHz */
+#define HT_BW_20 0
+/** HT bandwidth 40 MHz */
+#define HT_BW_40 1
+/** HT bandwidth 80 MHz */
+#define HT_BW_80 2
+
+/** TLV type : TX RATE CFG, rename from TLV_TYPE_GI_LTF_SIZE to include CMD and
+ * HE ER SU settings to this tlv */
+#define TLV_TYPE_TX_RATE_CFG (PROPRIETARY_TLV_BASE_ID + 319) /* 0x023f */
+
+/** TLV type : Scan Response */
+#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 0x56) /* 0x0156 */
+/** TLV type : Scan Response Stats */
+#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 0x57) /* 0x0157 */
+
+/** TLV type : 11h Basic Rpt */
+#define TLV_TYPE_CHANRPT_11H_BASIC \
+ (PROPRIETARY_TLV_BASE_ID + 0x5b) /* 0x015b \
+ */
+
+/** TLV type : DFS W53 Configuration */
+#define TLV_TYPE_DFS_W53_CFG (PROPRIETARY_TLV_BASE_ID + 0x145) // + 325
+#ifdef OPCHAN
+/** TLV type : OpChannel control */
+#define TLV_TYPE_OPCHAN_CONTROL_DESC \
+ (PROPRIETARY_TLV_BASE_ID + 0x79) /* 0x0179 */
+/** TLV type : OpChannel channel group control */
+#define TLV_TYPE_OPCHAN_CHANGRP_CTRL \
+ (PROPRIETARY_TLV_BASE_ID + 0x7a) /* 0x017a */
+#endif
+
+/** TLV type : Action frame */
+#define TLV_TYPE_IEEE_ACTION_FRAME \
+ (PROPRIETARY_TLV_BASE_ID + 0x8c) /* 0x018c \
+ */
+
+/** TLV type : SCAN channel gap */
+#define TLV_TYPE_SCAN_CHANNEL_GAP \
+ (PROPRIETARY_TLV_BASE_ID + 0xc5) /* 0x01c5 \
+ */
+/** TLV type : Channel statistics */
+#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 0xc6) /* 0x01c6 */
+/** TLV type : BSS_MODE */
+#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 0xce) /* 0x01ce */
+
+/** Firmware Host Command ID Constants */
+/** Host Command ID : Get hardware specifications */
+#define HostCmd_CMD_GET_HW_SPEC 0x0003
+/** Host Command ID : 802.11 scan */
+#define HostCmd_CMD_802_11_SCAN 0x0006
+/** Host Command ID : 802.11 get log */
+#define HostCmd_CMD_802_11_GET_LOG 0x000b
+
+/** Host Command id: GET_TX_RX_PKT_STATS */
+#define HOST_CMD_TX_RX_PKT_STATS 0x008d
+
+/** Host Command ID : 802.11 get/set link layer statistic */
+#define HostCmd_CMD_802_11_LINK_STATS 0x0256
+
+/** Host Command ID : MAC multicast address */
+#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
+/** Host Command ID : 802.11 associate */
+#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
+
+/** Host Command ID : 802.11 SNMP MIB */
+#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
+/** Host Command ID : MAC register access */
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+/** Host Command ID : BBP register access */
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+/** Host Command ID : RF register access */
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+
+/** Host Command ID : 802.11 radio control */
+#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c
+/** Host Command ID : 802.11 RF channel */
+#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
+/** Host Command ID : 802.11 RF Tx power */
+#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e
+
+/** Host Command ID : 802.11 RF antenna */
+#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020
+
+/** Host Command ID : 802.11 deauthenticate */
+#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
+/** Host Command ID: 802.11 disassoicate */
+#define HostCmd_CMD_802_11_DISASSOCIATE 0x0026
+/** Host Command ID : MAC control */
+#define HostCmd_CMD_MAC_CONTROL 0x0028
+/** Host Command ID : 802.11 Ad-Hoc start */
+#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
+/** Host Command ID : 802.11 Ad-Hoc join */
+#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
+
+/** Host Command ID: CW Mode */
+#define HostCmd_CMD_CW_MODE_CTRL 0x0239
+/** Host Command ID : 802.11 key material */
+#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
+
+/** Host Command ID : 802.11 Ad-Hoc stop */
+#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
+
+/** Host Command ID : 802.22 MAC address */
+#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
+
+/** Host Command ID : WMM Traffic Stream Status */
+#define HostCmd_CMD_WMM_TS_STATUS 0x005d
+
+/** Host Command ID : 802.11 D domain information */
+#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
+
+/*This command gets/sets the Transmit Rate-based Power Control (TRPC) channel
+ * configuration.*/
+#define HostCmd_CHANNEL_TRPC_CONFIG 0x00fb
+
+/** Host Command ID : 802.11 TPC information */
+#define HostCmd_CMD_802_11_TPC_INFO 0x005f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ 0x0060
+/** Host Command ID : 802.11 channel SW ann */
+#define HostCmd_CMD_802_11_CHAN_SW_ANN 0x0061
+
+/** Host Command ID : Measurement request */
+#define HostCmd_CMD_MEASUREMENT_REQUEST 0x0062
+/** Host Command ID : Measurement report */
+#define HostCmd_CMD_MEASUREMENT_REPORT 0x0063
+
+/** Host Command ID : 802.11 sleep parameters */
+#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066
+
+/** Host Command ID : 802.11 ps inactivity timeout */
+#define HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT 0x0067
+
+/** Host Command ID : 802.11 sleep period */
+#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068
+
+/** Host Command ID: 802.11 BG scan config */
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
+/** Host Command ID : 802.11 BG scan query */
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
+
+/** Host Command ID : WMM ADDTS req */
+#define HostCmd_CMD_WMM_ADDTS_REQ 0x006E
+/** Host Command ID : WMM DELTS req */
+#define HostCmd_CMD_WMM_DELTS_REQ 0x006F
+/** Host Command ID : WMM queue configuration */
+#define HostCmd_CMD_WMM_QUEUE_CONFIG 0x0070
+/** Host Command ID : 802.11 get status */
+#define HostCmd_CMD_WMM_GET_STATUS 0x0071
+
+/** Host Command ID : 802.11 subscribe event */
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
+
+/** Host Command ID : 802.11 Tx rate query */
+#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
+/** Host Command ID :Get timestamp value */
+#define HostCmd_CMD_GET_TSF 0x0080
+
+/** Host Command ID : WMM queue stats */
+#define HostCmd_CMD_WMM_QUEUE_STATS 0x0081
+
+/** Host Command ID : KEEP ALIVE command */
+#define HostCmd_CMD_AUTO_TX 0x0082
+
+/** Host Command ID : 802.11 IBSS coalescing status */
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+/** Host Command ID : Memory access */
+#define HostCmd_CMD_MEM_ACCESS 0x0086
+
+#if defined(SDIO)
+/** Host Command ID : SDIO GPIO interrupt configuration */
+#define HostCmd_CMD_SDIO_GPIO_INT_CONFIG 0x0088
+#endif
+
+/** Host Command ID : Mfg command */
+#define HostCmd_CMD_MFG_COMMAND 0x0089
+/** Host Command ID : Inactivity timeout ext */
+#define HostCmd_CMD_INACTIVITY_TIMEOUT_EXT 0x008a
+
+/** Host Command ID : DBGS configuration */
+#define HostCmd_CMD_DBGS_CFG 0x008b
+/** Host Command ID : Get memory */
+#define HostCmd_CMD_GET_MEM 0x008c
+
+/** Host Command ID : Cal data dnld */
+#define HostCmd_CMD_CFG_DATA 0x008f
+
+/** Host Command ID : SDIO pull control */
+#define HostCmd_CMD_SDIO_PULL_CTRL 0x0093
+
+/** Host Command ID : ECL system clock configuration */
+#define HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG 0x0094
+
+/** Host Command ID : Extended version */
+#define HostCmd_CMD_VERSION_EXT 0x0097
+
+/** Host Command ID : MEF configuration */
+#define HostCmd_CMD_MEF_CFG 0x009a
+/** Host Command ID : 802.11 RSSI INFO*/
+#define HostCmd_CMD_RSSI_INFO 0x00a4
+/** Host Command ID : Function initialization */
+#define HostCmd_CMD_FUNC_INIT 0x00a9
+/** Host Command ID : Function shutdown */
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+
+/** Host Command ID : Robustcoex */
+#define HostCmd_CMD_802_11_ROBUSTCOEX 0x00e0
+
+/** Host Command ID :EAPOL PKT */
+#define HostCmd_CMD_802_11_EAPOL_PKT 0x012e
+
+/** Host Command ID :MIMO SWITCH **/
+#define HostCmd_CMD_802_11_MIMO_SWITCH 0x0235
+
+/** Host Command ID : 802.11 RSSI INFO EXT*/
+#define HostCmd_CMD_RSSI_INFO_EXT 0x0237
+
+#ifdef RX_PACKET_COALESCE
+/** TLV ID for RX pkt coalesce config */
+#define TLV_TYPE_RX_PKT_COAL_CONFIG (PROPRIETARY_TLV_BASE_ID + 0xC9)
+#endif
+
+/** Host Command ID : Channel report request */
+#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
+
+/** Host Command ID: SUPPLICANT_PMK */
+#define HostCmd_CMD_SUPPLICANT_PMK 0x00c4
+/** Host Command ID: SUPPLICANT_PROFILE */
+#define HostCmd_CMD_SUPPLICANT_PROFILE 0x00c5
+
+/** Host Command ID : Add Block Ack Request */
+#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_CFG 0x00cd
+/** Host Command ID : Add Block Ack Response */
+#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
+/** Host Command ID : Delete a Block Ack Request */
+#define HostCmd_CMD_11N_DELBA 0x00d0
+/** Host Command ID: Configure Tx Buf size */
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+/** Host Command ID: AMSDU Aggr Ctrl */
+#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
+/** Host Command ID: 11AC config */
+#define HostCmd_CMD_11AC_CFG 0x0112
+/** Host Command ID: Configure TX Beamforming capability */
+#define HostCmd_CMD_TX_BF_CFG 0x0104
+
+/** Host Command ID : 802.11 TX power configuration */
+#define HostCmd_CMD_TXPWR_CFG 0x00d1
+
+/** Host Command ID : Soft Reset */
+#define HostCmd_CMD_SOFT_RESET 0x00d5
+
+/** Host Command ID : 802.11 b/g/n rate configration */
+#define HostCmd_CMD_TX_RATE_CFG 0x00d6
+
+/** Host Command ID : Enhanced PS mode */
+#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
+
+/** Host command action : Host sleep configuration */
+#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
+
+/** Host Command ID : CAU register access */
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+
+/** Host Command ID : mgmt IE list */
+#define HostCmd_CMD_MGMT_IE_LIST 0x00f2
+
+#define HostCmd_CMD_802_11_BAND_STEERING 0x026f
+
+#ifdef SDIO
+/** Host Command ID : SDIO single port RX aggr */
+#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223
+
+/** fw_cap_info bit16 for sdio sp rx aggr flag*/
+#define SDIO_SP_RX_AGGR_ENABLE MBIT(16)
+
+#endif
+
+/* fw_cap_info bit18 for ecsa support*/
+#define FW_CAPINFO_ECSA MBIT(18)
+
+/* fw_cap_info bit20 for get log*/
+#define FW_CAPINFO_GET_LOG MBIT(20)
+
+/** fw_cap_info bit22 for embedded supplicant support*/
+#define FW_CAPINFO_SUPPLICANT_SUPPORT MBIT(21)
+
+/** fw_cap_info bit23 for embedded authenticator support*/
+#define FW_CAPINFO_AUTH_SUPPORT MBIT(22)
+
+/** fw_cap_info bit25 for adhoc support*/
+#define FW_CAPINFO_ADHOC_SUPPORT MBIT(25)
+/** Check if adhoc is supported by firmware */
+#define IS_FW_SUPPORT_ADHOC(_adapter) \
+ (_adapter->fw_cap_info & FW_CAPINFO_ADHOC_SUPPORT)
+
+/** Check if supplicant is supported by firmware */
+#define IS_FW_SUPPORT_SUPPLICANT(_adapter) \
+ (_adapter->fw_cap_info & FW_CAPINFO_SUPPLICANT_SUPPORT)
+
+/** Check if authenticator is supported by firmware */
+#define IS_FW_SUPPORT_AUTHENTICATOR(_adapter) \
+ (_adapter->fw_cap_info & FW_CAPINFO_AUTH_SUPPORT)
+
+/** Ext fw cap info bit0 only 1x1 5G is available */
+#define FW_CAPINFO_EXT_5G_1X1_ONLY MBIT(0)
+/** Ext fw cap info bit1 1x1 5G is not available */
+#define FW_CAPINFO_EXT_NO_5G_1X1 MBIT(1)
+/** Ext fw cap info bit 2 only 1x1 2G is available */
+#define FW_CAPINFO_EXT_2G_1X1_ONLY MBIT(2)
+/**Ext fw cap info bit3 1x1 2G is not available */
+#define FW_CAPINFO_EXT_NO_2G_1X1 MBIT(3)
+/** Ext fw cap info bit4 1x1 + 1x1 5G mode is unavailable */
+#define FW_CAPINFO_EXT_NO_5G_1X1_PLUS_1X1 MBIT(4)
+/** Ext fw cap info bit5 80 + 80 MHz capability disabled */
+#define FW_CAPINFO_EXT_NO_80MHz_PLUS_80MHz MBIT(5)
+/** Ext fw cap info bit6 1024 QAM is disabled */
+#define FW_CAPINFO_EXT_NO_1024_QAM MBIT(6)
+/** FW cap info bit 7 11AX */
+#define FW_CAPINFO_EXT_802_11AX MBIT(7)
+/** FW cap info bit 8: 80MHZ disabled */
+#define FW_CAPINFO_EXT_NO_80MHZ MBIT(8)
+
+/** Check if 5G 1x1 only is supported by firmware */
+#define IS_FW_SUPPORT_5G_1X1_ONLY(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_5G_1X1_ONLY)
+/** Check if 5G 1x1 is unavailable in firmware */
+#define IS_FW_SUPPORT_NO_5G_1X1(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_5G_1X1)
+/** Check if 2G 1x1 only is supported by firmware */
+#define IS_FW_SUPPORT_2G_1X1_ONLY(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_2G_1X1_ONLY)
+/** Check if 2G 1x1 is unavailable in firmware */
+#define IS_FW_SUPPORT_NO_2G_1X1(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_2G_1X1)
+/** Check if 5G 1x1 + 1x1 mode is disabled in firmware */
+#define IS_FW_SUPPORT_NO_5G_1X1_PLUS_1X1(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_5G_1X1_PLUS_1X1)
+/** Check if 80 + 80MHz is disabled in firmware */
+#define IS_FW_SUPPORT_NO_80MHz_PLUS_80MHz(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_80MHz_PLUS_80MHz)
+/** Check if 1024 QAM disabled in firmware */
+#define IS_FW_SUPPORT_NO_1024_QAM(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_1024_QAM)
+/** Check if 80MHZ disabled in firmware */
+#define IS_FW_SUPPORT_NO_80MHZ(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_NO_80MHZ)
+
+/** FW cap info TLV */
+typedef MLAN_PACK_START struct _MrvlIEtypes_fw_cap_info_t {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+ /** Fw cap info bitmap */
+ t_u32 fw_cap_info;
+ /** Extended fw cap info bitmap */
+ t_u32 fw_cap_ext;
+} MLAN_PACK_END MrvlIEtypes_fw_cap_info_t, *pMrvlIEtypes_fw_cap_info_t;
+
+/** Check if 11AX is supported by firmware */
+#define IS_FW_SUPPORT_11AX(_adapter) \
+ (_adapter->fw_cap_ext & FW_CAPINFO_EXT_802_11AX)
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Extension_t {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** payload */
+ t_u8 data[];
+} MLAN_PACK_END MrvlIEtypes_Extension_t, *pMrvlIEtypes_Extension_t;
+
+/* HE MAC Capabilities Information field BIT 1 for TWT Req */
+#define HE_MAC_CAP_TWT_REQ_SUPPORT MBIT(1)
+/* HE MAC Capabilities Information field BIT 2 for TWT Resp*/
+#define HE_MAC_CAP_TWT_RESP_SUPPORT MBIT(2)
+typedef MLAN_PACK_START struct _MrvlIEtypes_He_cap_t {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** he mac capability info */
+ t_u8 he_mac_cap[6];
+ /** he phy capability info */
+ t_u8 he_phy_cap[11];
+ /** he txrx mcs support , size would be 4 or 8 or 12 */
+ t_u8 he_txrx_mcs_support[4];
+ /** 160Mhz tx rx mcs support*/
+ t_u8 he160_txrx_mcs_support[4];
+ /** 80+80 Mhz tx rx mcs suport */
+ t_u8 he8080_txrx_mcs_support[4];
+ /** PPE Thresholds (optional) */
+ t_u8 val[20];
+} MLAN_PACK_END MrvlIEtypes_He_cap_t, *pMrvlIEtypes_he_cap_t;
+
+#ifdef RX_PACKET_COALESCE
+/** Host Command ID : Rx packet coalescing configuration */
+#define HostCmd_CMD_RX_PKT_COALESCE_CFG 0x012c
+#endif
+
+/** Host Command ID : Extended scan support */
+#define HostCmd_CMD_802_11_SCAN_EXT 0x0107
+
+/** Host Command ID : Forward mgmt frame */
+#define HostCmd_CMD_RX_MGMT_IND 0x010c
+
+#ifdef PCIE
+/** Host Command ID: Host buffer description */
+#define HostCmd_CMD_PCIE_HOST_BUF_DETAILS 0x00fa
+#endif
+
+/** Host Command ID : Set BSS_MODE */
+#define HostCmd_CMD_SET_BSS_MODE 0x00f7
+
+#ifdef UAP_SUPPORT
+/** Host Command id: SYS_INFO */
+#define HOST_CMD_APCMD_SYS_INFO 0x00ae
+/** Host Command id: sys_reset */
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
+/** Host Command id: SYS_CONFIGURE */
+#define HOST_CMD_APCMD_SYS_CONFIGURE 0x00b0
+/** Host Command id: BSS_START */
+#define HOST_CMD_APCMD_BSS_START 0x00b1
+/** Host Command id: BSS_STOP */
+#define HOST_CMD_APCMD_BSS_STOP 0x00b2
+/** Host Command id: sta_list */
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
+/** Host Command id: STA_DEAUTH */
+#define HOST_CMD_APCMD_STA_DEAUTH 0x00b5
+
+/** Host Command id: REPORT_MIC */
+#define HOST_CMD_APCMD_REPORT_MIC 0x00ee
+/** Host Command id: UAP_OPER_CTRL */
+#define HOST_CMD_APCMD_OPER_CTRL 0x0233
+#endif /* UAP_SUPPORT */
+
+/** Host Command id: PMIC CONFIGURE*/
+#define HOST_CMD_PMIC_CONFIGURE 0x23E
+
+/** Host Command ID: Tx data pause */
+#define HostCmd_CMD_CFG_TX_DATA_PAUSE 0x0103
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Host Command ID: P2P PARAMS CONFIG */
+#define HOST_CMD_P2P_PARAMS_CONFIG 0x00ea
+/** Host Command ID: WIFI_DIRECT_MODE_CONFIG */
+#define HOST_CMD_WIFI_DIRECT_MODE_CONFIG 0x00eb
+#endif
+
+/** Host Command ID: Remain On Channel */
+#define HostCmd_CMD_802_11_REMAIN_ON_CHANNEL 0x010d
+
+#define HostCmd_CMD_COALESCE_CFG 0x010a
+
+/** Host Command ID: GTK REKEY OFFLOAD CFG */
+#define HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG 0x010f
+
+/** Host Command ID : OTP user data */
+#define HostCmd_CMD_OTP_READ_USER_DATA 0x0114
+
+/** Host Command ID: HS wakeup reason */
+#define HostCmd_CMD_HS_WAKEUP_REASON 0x0116
+
+/** Host Command ID: reject addba request */
+#define HostCmd_CMD_REJECT_ADDBA_REQ 0x0119
+
+#define HostCmd_CMD_FW_DUMP_EVENT 0x0125
+
+#define HostCMD_CONFIG_LOW_POWER_MODE 0x0128
+
+/** Host Command ID : Target device access */
+#define HostCmd_CMD_TARGET_ACCESS 0x012a
+
+/** Host Command ID: BCA device access */
+#define HostCmd_CMD_BCA_REG_ACCESS 0x0272
+
+/** Host Command ID: DFS repeater mode */
+#define HostCmd_DFS_REPEATER_MODE 0x012b
+
+/** Host Command ID: ACS scan */
+#define HostCMD_APCMD_ACS_SCAN 0x0224
+
+/** Host Command ID: Get sensor temp*/
+#define HostCmd_DS_GET_SENSOR_TEMP 0x0227
+
+/** Host Command ID : Configure ADHOC_OVER_IP parameters */
+#define HostCmd_CMD_WMM_PARAM_CONFIG 0x023a
+
+#ifdef STA_SUPPORT
+/** Host Command ID : set/get sta configure */
+#define HostCmd_CMD_STA_CONFIGURE 0x023f
+#endif
+
+/** Host Command ID : GPIO independent reset configure */
+#define HostCmd_CMD_INDEPENDENT_RESET_CFG 0x0243
+
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+/* TLV type: reg type */
+#define TLV_TYPE_REG_ACCESS_CTRL (PROPRIETARY_TLV_BASE_ID + 0x13C) /* 0x023c*/
+/** MrvlIEtypes_Reg_type_t*/
+typedef MLAN_PACK_START struct _MrvlIEtypes_Reg_type_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** type: 0x81/0x82/0x83 */
+ t_u8 type;
+} MLAN_PACK_END MrvlIEtypes_Reg_type_t;
+
+#endif
+#define HostCmd_CMD_CHAN_REGION_CFG 0x0242
+/* mod_grp */
+typedef enum _mod_grp {
+ MOD_CCK, // 0
+ MOD_OFDM_PSK, // 1
+ MOD_OFDM_QAM16, // 2
+ MOD_OFDM_QAM64, // 3
+ MOD_HT_20_PSK, // 4
+ MOD_HT_20_QAM16, // 5
+ MOD_HT_20_QAM64, // 6
+ MOD_HT_40_PSK, // 7
+ MOD_HT_40_QAM16, // 8
+ MOD_HT_40_QAM64, // 9
+#ifdef STREAM_2x2
+ MOD_HT2_20_PSK, // 10
+ MOD_HT2_20_QAM16, // 11
+ MOD_HT2_20_QAM64, // 12
+ MOD_HT2_40_PSK, // 13
+ MOD_HT2_40_QAM16, // 14
+ MOD_HT2_40_QAM64, // 15
+#endif
+
+ MOD_VHT_20_QAM256, // 16
+ MOD_VHT_40_QAM256, // 17
+ MOD_VHT_80_PSK, // 18
+ MOD_VHT_80_QAM16, // 19
+ MOD_VHT_80_QAM64, // 20
+ MOD_VHT_80_QAM256, // 21
+#ifdef STREAM_2x2
+ MOD_VHT2_20_QAM256, // 22
+ MOD_VHT2_40_QAM256, // 23
+ MOD_VHT2_80_PSK, // 24
+ MOD_VHT2_80_QAM16, // 25
+ MOD_VHT2_80_QAM64, // 26
+ MOD_VHT2_80_QAM256, // 27
+#endif
+} mod_grp;
+
+typedef MLAN_PACK_START struct _power_table_attr {
+ t_u8 rows_2g;
+ t_u8 cols_2g;
+ t_u8 rows_5g;
+ t_u8 cols_5g;
+} MLAN_PACK_END power_table_attr_t;
+
+#define FW_CFP_TABLE_MAX_ROWS_BG 14
+#define FW_CFP_TABLE_MAX_COLS_BG 17
+
+#define FW_CFP_TABLE_MAX_ROWS_A 39
+#define FW_CFP_TABLE_MAX_COLS_A 29
+
+#define HostCmd_CMD_DYN_BW 0x0252
+
+#define HostCmd_CMD_BOOT_SLEEP 0x0258
+
+#define HostCmd_CMD_RX_ABORT_CFG 0x0261
+#define HostCmd_CMD_RX_ABORT_CFG_EXT 0x0262
+#define HostCmd_CMD_TX_AMPDU_PROT_MODE 0x0263
+#define HostCmd_CMD_RATE_ADAPT_CFG 0x0264
+#define HostCmd_CMD_CCK_DESENSE_CFG 0x0265
+
+#define HostCmd_CMD_VDLL 0x0240
+#if defined(PCIE)
+#define HostCmd_CMD_SSU 0x0259
+#endif
+
+#define HostCmd_CMD_DMCS_CONFIG 0x0260
+
+/** Host Command ID: 11AX config */
+#define HostCmd_CMD_11AX_CFG 0x0266
+/** Host Command ID: 11AX command */
+#define HostCmd_CMD_11AX_CMD 0x026d
+/** Host Command ID: Range ext command */
+#define HostCmd_CMD_RANGE_EXT 0x0274
+/** Host Command ID: TWT cfg command */
+#define HostCmd_CMD_TWT_CFG 0x0270
+
+#define HostCmd_CMD_LOW_POWER_MODE_CFG 0x026e
+#define HostCmd_CMD_UAP_BEACON_STUCK_CFG 0x0271
+#define HostCmd_CMD_ARB_CONFIG 0x0273
+#define HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG 0x0275
+
+/** Enhanced PS modes */
+typedef enum _ENH_PS_MODES {
+ GET_PS = 0,
+ SLEEP_CONFIRM = 5,
+ DIS_AUTO_PS = 0xfe,
+ EN_AUTO_PS = 0xff,
+} ENH_PS_MODES;
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT 0x8000
+
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET 0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** General purpose action : Set Default */
+#define HostCmd_ACT_GEN_SET_DEFAULT 0x0002
+/** General purpose action : Get_Current */
+#define HostCmd_ACT_GEN_GET_CURRENT 0x0003
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE 0x0004
+/** General purpose action : Reset */
+#define HostCmd_ACT_GEN_RESET 0x0005
+
+/** Host command action : Set Rx */
+#define HostCmd_ACT_SET_RX 0x0001
+/** Host command action : Set Tx */
+#define HostCmd_ACT_SET_TX 0x0002
+/** Host command action : Set both Rx and Tx */
+#define HostCmd_ACT_SET_BOTH 0x0003
+/** Host command action : Get Rx */
+#define HostCmd_ACT_GET_RX 0x0004
+/** Host command action : Get Tx */
+#define HostCmd_ACT_GET_TX 0x0008
+/** Host command action : Get both Rx and Tx */
+#define HostCmd_ACT_GET_BOTH 0x000c
+
+/** General Result Code*/
+/** General result code OK */
+#define HostCmd_RESULT_OK 0x0000
+/** Genenral error */
+#define HostCmd_RESULT_ERROR 0x0001
+/** Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT 0x0002
+/** Command is pending */
+#define HostCmd_RESULT_PENDING 0x0003
+/** System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY 0x0004
+/** Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA 0x0005
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+/** MAC action : Rx on */
+#define HostCmd_ACT_MAC_RX_ON 0x0001
+/** MAC action : Tx on */
+#define HostCmd_ACT_MAC_TX_ON 0x0002
+/** MAC action : WEP enable */
+#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
+/** MAC action : EthernetII enable */
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
+/** MAC action : Promiscous mode enable */
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+/** MAC action : All multicast enable */
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+/** MAC action : RTS/CTS enable */
+#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
+/** MAC action : Strict protection enable */
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+/** MAC action : Force 11n protection disable */
+#define HostCmd_ACT_MAC_FORCE_11N_PROTECTION_OFF 0x0800
+/** MAC action : Ad-Hoc G protection on */
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
+/** MAC action : Static-Dynamic BW enable */
+#define HostCmd_ACT_MAC_STATIC_DYNAMIC_BW_ENABLE MBIT(16)
+/** MAC action : Dynamic BW */
+#define HostCmd_ACT_MAC_DYNAMIC_BW MBIT(17)
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : BSS */
+#define HostCmd_BSS_MODE_BSS 0x0001
+/** Scan type : IBSS */
+#define HostCmd_BSS_MODE_IBSS 0x0002
+/** Scan type : Any */
+#define HostCmd_BSS_MODE_ANY 0x0003
+
+/** Define bitmap conditions for HOST_SLEEP_CFG : GPIO FF */
+#define HOST_SLEEP_CFG_GPIO_FF 0xff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GAP FF */
+#define HOST_SLEEP_CFG_GAP_FF 0xff
+
+/** Buffer Constants */
+/** Number of command buffers */
+#define MRVDRV_NUM_OF_CMD_BUFFER 40
+/** Maximum number of BSS Descriptors */
+#define MRVDRV_MAX_BSSID_LIST 200
+
+/** Host command flag in command */
+#define CMD_F_HOSTCMD (1 << 0)
+/** command cancel flag in command */
+#define CMD_F_CANCELED (1 << 1)
+/** scan command flag */
+#define CMD_F_SCAN (1 << 2)
+
+/** Host Command ID bit mask (bit 11:0) */
+#define HostCmd_CMD_ID_MASK 0x0fff
+
+/** Host Command Sequence number mask (bit 7:0) */
+#define HostCmd_SEQ_NUM_MASK 0x00ff
+
+/** Host Command BSS number mask (bit 11:8) */
+#define HostCmd_BSS_NUM_MASK 0x0f00
+
+/** Host Command BSS type mask (bit 15:12) */
+#define HostCmd_BSS_TYPE_MASK 0xf000
+
+/** Set BSS information to Host Command */
+#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) \
+ ((((seq)&0x00ff) | (((num)&0x000f) << 8)) | (((type)&0x000f) << 12))
+
+/** Get Sequence Number from Host Command (bit 7:0) */
+#define HostCmd_GET_SEQ_NO(seq) ((seq)&HostCmd_SEQ_NUM_MASK)
+
+/** Get BSS number from Host Command (bit 11:8) */
+#define HostCmd_GET_BSS_NO(seq) (((seq)&HostCmd_BSS_NUM_MASK) >> 8)
+
+/** Get BSS type from Host Command (bit 15:12) */
+#define HostCmd_GET_BSS_TYPE(seq) (((seq)&HostCmd_BSS_TYPE_MASK) >> 12)
+
+/** Card Event definition : Dummy host wakeup signal */
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
+/** Card Event definition : Link lost */
+#define EVENT_LINK_LOST 0x00000003
+/** Card Event definition : Link sensed */
+#define EVENT_LINK_SENSED 0x00000004
+/** Card Event definition : MIB changed */
+#define EVENT_MIB_CHANGED 0x00000006
+/** Card Event definition : Init done */
+#define EVENT_INIT_DONE 0x00000007
+/** Card Event definition : Deauthenticated */
+#define EVENT_DEAUTHENTICATED 0x00000008
+/** Card Event definition : Disassociated */
+#define EVENT_DISASSOCIATED 0x00000009
+/** Card Event definition : Power save awake */
+#define EVENT_PS_AWAKE 0x0000000a
+/** Card Event definition : Power save sleep */
+#define EVENT_PS_SLEEP 0x0000000b
+/** Card Event definition : MIC error multicast */
+#define EVENT_MIC_ERR_MULTICAST 0x0000000d
+/** Card Event definition : MIC error unicast */
+#define EVENT_MIC_ERR_UNICAST 0x0000000e
+
+/** Card Event definition : Ad-Hoc BCN lost */
+#define EVENT_ADHOC_BCN_LOST 0x00000011
+
+/** Card Event definition : Stop Tx */
+#define EVENT_STOP_TX 0x00000013
+/** Card Event definition : Start Tx */
+#define EVENT_START_TX 0x00000014
+/** Card Event definition : Channel switch */
+#define EVENT_CHANNEL_SWITCH 0x00000015
+
+/** Card Event definition : MEAS report ready */
+#define EVENT_MEAS_REPORT_RDY 0x00000016
+
+/** Card Event definition : WMM status change */
+#define EVENT_WMM_STATUS_CHANGE 0x00000017
+
+/** Card Event definition : BG scan report */
+#define EVENT_BG_SCAN_REPORT 0x00000018
+/** Card Event definition : BG scan stopped */
+#define EVENT_BG_SCAN_STOPPED 0x00000065
+
+/** Card Event definition : Beacon RSSI low */
+#define EVENT_RSSI_LOW 0x00000019
+/** Card Event definition : Beacon SNR low */
+#define EVENT_SNR_LOW 0x0000001a
+/** Card Event definition : Maximum fail */
+#define EVENT_MAX_FAIL 0x0000001b
+/** Card Event definition : Beacon RSSI high */
+#define EVENT_RSSI_HIGH 0x0000001c
+/** Card Event definition : Beacon SNR high */
+#define EVENT_SNR_HIGH 0x0000001d
+
+/** Card Event definition : IBSS coalsced */
+#define EVENT_IBSS_COALESCED 0x0000001e
+
+/** Event definition : IBSS station connected */
+#define EVENT_IBSS_STATION_CONNECT 0x00000020
+/** Event definition : IBSS station dis-connected */
+#define EVENT_IBSS_STATION_DISCONNECT 0x00000021
+
+/** Card Event definition : Data RSSI low */
+#define EVENT_DATA_RSSI_LOW 0x00000024
+/** Card Event definition : Data SNR low */
+#define EVENT_DATA_SNR_LOW 0x00000025
+/** Card Event definition : Data RSSI high */
+#define EVENT_DATA_RSSI_HIGH 0x00000026
+/** Card Event definition : Data SNR high */
+#define EVENT_DATA_SNR_HIGH 0x00000027
+
+/** Card Event definition : Link Quality */
+#define EVENT_LINK_QUALITY 0x00000028
+
+/** Card Event definition : Port release event */
+#define EVENT_PORT_RELEASE 0x0000002b
+
+/** Card Event definition : Pre-Beacon Lost */
+#define EVENT_PRE_BEACON_LOST 0x00000031
+
+#define EVENT_WATCHDOG_TMOUT 0x00000032
+
+/** Card Event definition : Add BA event */
+#define EVENT_ADDBA 0x00000033
+/** Card Event definition : Del BA event */
+#define EVENT_DELBA 0x00000034
+/** Card Event definition: BA stream timeout*/
+#define EVENT_BA_STREAM_TIMEOUT 0x00000037
+
+/** Card Event definition : AMSDU aggr control */
+#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+
+/** Card Event definition: WEP ICV error */
+#define EVENT_WEP_ICV_ERR 0x00000046
+
+/** Card Event definition : Host sleep enable */
+#define EVENT_HS_ACT_REQ 0x00000047
+
+/** Card Event definition : BW changed */
+#define EVENT_BW_CHANGE 0x00000048
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** WIFIDIRECT generic event */
+#define EVENT_WIFIDIRECT_GENERIC_EVENT 0x00000049
+/** WIFIDIRECT service discovery event */
+#define EVENT_WIFIDIRECT_SERVICE_DISCOVERY 0x0000004a
+#endif
+/** Remain on Channel expired event */
+#define EVENT_REMAIN_ON_CHANNEL_EXPIRED 0x0000005f
+
+#define EVENT_MEF_HOST_WAKEUP 0x0000004f
+
+/** Card Event definition: Channel switch pending announcment */
+#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
+
+/** Event definition: Radar Detected by card */
+#define EVENT_RADAR_DETECTED 0x00000053
+
+/** Event definition: Radar Detected by card */
+#define EVENT_CHANNEL_REPORT_RDY 0x00000054
+
+/** Event definition: Scan results through event */
+#define EVENT_EXT_SCAN_REPORT 0x00000058
+/** Enhance ext scan done event */
+#define EVENT_EXT_SCAN_STATUS_REPORT 0x0000007f
+
+/** Event definition : FW debug information */
+#define EVENT_FW_DEBUG_INFO 0x00000063
+
+/** Event definition: RXBA_SYNC */
+#define EVENT_RXBA_SYNC 0x00000059
+
+#ifdef UAP_SUPPORT
+/** Event ID: STA deauth */
+#define EVENT_MICRO_AP_STA_DEAUTH 0x0000002c
+/** Event ID: STA assoicated */
+#define EVENT_MICRO_AP_STA_ASSOC 0x0000002d
+/** Event ID: BSS started */
+#define EVENT_MICRO_AP_BSS_START 0x0000002e
+/** Event ID: BSS idle event */
+#define EVENT_MICRO_AP_BSS_IDLE 0x00000043
+/** Event ID: BSS active event */
+#define EVENT_MICRO_AP_BSS_ACTIVE 0x00000044
+
+/** Event ID: MIC countermeasures event */
+#define EVENT_MICRO_AP_MIC_COUNTERMEASURES 0x0000004c
+#endif /* UAP_SUPPORT */
+
+/** Event ID: TX data pause event */
+#define EVENT_TX_DATA_PAUSE 0x00000055
+
+/** Event ID: SAD Report */
+#define EVENT_SAD_REPORT 0x00000066
+
+/** Event ID: Tx status */
+#define EVENT_TX_STATUS_REPORT 0x00000074
+
+#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0x00000076
+
+#if defined(PCIE)
+#define EVENT_SSU_DUMP_DMA 0x0000008C
+#endif
+
+#define EVENT_VDLL_IND 0x00000081
+#define EVENT_EXCEED_MAX_P2P_CONN 0x00000089
+
+#define EVENT_FW_HANG_REPORT 0x0000008F
+
+#define EVENT_FW_DUMP_INFO 0x00000073
+/** Event ID mask */
+#define EVENT_ID_MASK 0xffff
+
+/** BSS number mask */
+#define BSS_NUM_MASK 0xf
+
+/** Get BSS number from event cause (bit 23:16) */
+#define EVENT_GET_BSS_NUM(event_cause) (((event_cause) >> 16) & BSS_NUM_MASK)
+
+/** Get BSS type from event cause (bit 31:24) */
+#define EVENT_GET_BSS_TYPE(event_cause) (((event_cause) >> 24) & 0x00ff)
+
+/** Event_WEP_ICV_ERR structure */
+typedef MLAN_PACK_START struct _Event_WEP_ICV_ERR {
+ /** Reason code */
+ t_u16 reason_code;
+ /** Source MAC address */
+ t_u8 src_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** WEP decryption used key */
+ t_u8 wep_key_index;
+ /** WEP key length */
+ t_u8 wep_key_length;
+ /** WEP key */
+ t_u8 key[MAX_WEP_KEY_SIZE];
+} MLAN_PACK_END Event_WEP_ICV_ERR;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_FIXED_IEs {
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** Capabilities*/
+ t_u16 capabilities;
+} MLAN_PACK_END WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef MLAN_PACK_START struct _WLAN_802_11_VARIABLE_IEs {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 length;
+ /** IE data */
+ t_u8 data[1];
+} MLAN_PACK_END WLAN_802_11_VARIABLE_IEs;
+
+/** TLV related data structures*/
+#if defined(STA_SUPPORT)
+/** Pairwise Cipher Suite length */
+#define PAIRWISE_CIPHER_SUITE_LEN 4
+/** AKM Suite length */
+#define AKM_SUITE_LEN 4
+/** MFPC bit in RSN capability */
+#define MFPC_BIT 7
+/** MFPR bit in RSN capability */
+#define MFPR_BIT 6
+#endif
+/** Bit mask for TxPD status field for null packet */
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+/** Bit mask for TxPD status field for last packet */
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Bit mask for TxPD flags field for Tx status report */
+#define MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS MBIT(5)
+
+/** Packet type: 802.11 */
+#define PKT_TYPE_802DOT11 0x05
+#define PKT_TYPE_MGMT_FRAME 0xE5
+/** Packet type: AMSDU */
+#define PKT_TYPE_AMSDU 0xE6
+/** Packet type: BAR */
+#define PKT_TYPE_BAR 0xE7
+
+/** Packet type: debugging */
+#define PKT_TYPE_DEBUG 0xEF
+
+/** channel number at bit 5-13 */
+#define RXPD_CHAN_MASK 0x3FE0
+/** Rate control mask 15-23 */
+#define TXPD_RATE_MASK 0xff8000
+/** enable bw ctrl in TxPD */
+#define TXPD_BW_ENABLE MBIT(20)
+/** enable tx power ctrl in TxPD */
+#define TXPD_TXPW_ENABLE MBIT(7)
+/** sign of power */
+#define TXPD_TXPW_NEGATIVE MBIT(6)
+/** Enable Rate ctrl in TxPD */
+#define TXPD_TXRATE_ENABLE MBIT(15)
+/** enable retry limit in TxPD */
+#define TXPD_RETRY_ENABLE MBIT(12)
+
+/** TxPD descriptor */
+typedef MLAN_PACK_START struct _TxPD {
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Tx packet length */
+ t_u16 tx_pkt_length;
+ /** Tx packet offset */
+ t_u16 tx_pkt_offset;
+ /** Tx packet type */
+ t_u16 tx_pkt_type;
+ /** Tx Control */
+ t_u32 tx_control;
+ /** Pkt Priority */
+ t_u8 priority;
+ /** Transmit Pkt Flags*/
+ t_u8 flags;
+ /** Amount of time the packet has been queued
+ * in the driver (units = 2ms)*/
+ t_u8 pkt_delay_2ms;
+ /** reserved */
+ t_u8 reserved;
+ /** Tx Control */
+ t_u32 tx_control_1;
+} MLAN_PACK_END TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef MLAN_PACK_START struct _RxPD {
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Rx Packet Length */
+ t_u16 rx_pkt_length;
+ /** Rx Pkt offset */
+ t_u16 rx_pkt_offset;
+ /** Rx packet type */
+ t_u16 rx_pkt_type;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Packet Priority */
+ t_u8 priority;
+ /** Rx Packet Rate */
+ t_u8 rx_rate;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10
+ * [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01 BW80 = 10 BW160
+ * = 11 [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1 [Bit 5] STBC
+ * support Enabled = 1 [Bit 6] LDPC support Enabled = 1 [Bit 7] [Bit4,
+ * Bit7] AX Guard interval, 00, 01, 10 */
+ t_u8 rate_info;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** TDLS flags, bit 0: 0=InfraLink, 1=DirectLink */
+ t_u8 flags;
+ /**For SD8887 antenna info: 0 = 2.4G antenna a; 1 = 2.4G antenna b; 3 =
+ * 5G antenna; 0xff = invalid value */
+ t_u8 antenna;
+ /* [31:0] ToA of the rx packet, [63:32] ToD of the ack for the rx packet
+ * Both ToA and ToD are in nanoseconds */
+ t_u64 toa_tod_tstamps;
+ /** rx info */
+ t_u32 rx_info;
+} MLAN_PACK_END RxPD, *PRxPD;
+
+/** IEEEtypes_FrameCtl_t*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t {
+ /** Order */
+ t_u8 order : 1;
+ /** Wep */
+ t_u8 wep : 1;
+ /** More Data */
+ t_u8 more_data : 1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt : 1;
+ /** Retry */
+ t_u8 retry : 1;
+ /** More Frag */
+ t_u8 more_frag : 1;
+ /** From DS */
+ t_u8 from_ds : 1;
+ /** To DS */
+ t_u8 to_ds : 1;
+ /** Sub Type */
+ t_u8 sub_type : 4;
+ /** Type */
+ t_u8 type : 2;
+ /** Protocol Version */
+ t_u8 protocol_version : 2;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_FrameCtl_t {
+ /** Protocol Version */
+ t_u8 protocol_version : 2;
+ /** Type */
+ t_u8 type : 2;
+ /** Sub Type */
+ t_u8 sub_type : 4;
+ /** To DS */
+ t_u8 to_ds : 1;
+ /** From DS */
+ t_u8 from_ds : 1;
+ /** More Frag */
+ t_u8 more_frag : 1;
+ /** Retry */
+ t_u8 retry : 1;
+ /** Power Mgmt */
+ t_u8 pwr_mgmt : 1;
+ /** More Data */
+ t_u8 more_data : 1;
+ /** Wep */
+ t_u8 wep : 1;
+ /** Order */
+ t_u8 order : 1;
+} MLAN_PACK_END IEEEtypes_FrameCtl_t;
+#endif
+
+/** MrvlIETypes_MgmtFrameSet_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_MgmtFrameSet_t {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** Frame Control */
+ IEEEtypes_FrameCtl_t frame_control;
+ /* t_u8 frame_contents[]; */
+} MLAN_PACK_END MrvlIETypes_MgmtFrameSet_t;
+
+/** Beacon */
+typedef MLAN_PACK_START struct _IEEEtypes_Beacon_t {
+ /** time stamp */
+ t_u8 time_stamp[8];
+ /** beacon interval */
+ t_u16 beacon_interval;
+ /** cap info */
+ t_u16 cap_info;
+} MLAN_PACK_END IEEEtypes_Beacon_t;
+
+/** Fixed size of station association event */
+#define ASSOC_EVENT_FIX_SIZE 12
+
+/** MrvlIEtypes_channel_band_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_channel_band_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Band Configuration */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+} MLAN_PACK_END MrvlIEtypes_channel_band_t;
+
+#ifdef UAP_SUPPORT
+/** IEEEtypes_AssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRqst_t {
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /* t_u8 ie_buffer[]; */
+} MLAN_PACK_END IEEEtypes_AssocRqst_t;
+
+/** IEEEtypes_ReAssocRqst_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ReAssocRqst_t {
+ /** Capability Info */
+ t_u16 cap_info;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Current AP Address */
+ t_u8 current_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /* t_u8 ie_buffer[]; */
+} MLAN_PACK_END IEEEtypes_ReAssocRqst_t;
+#endif /* UAP_SUPPORT */
+
+/** wlan_802_11_header */
+typedef MLAN_PACK_START struct _wlan_802_11_header {
+ /** Frame Control */
+ t_u16 frm_ctl;
+ /** Duration ID */
+ t_u16 duration_id;
+ /** Address1 */
+ mlan_802_11_mac_addr addr1;
+ /** Address2 */
+ mlan_802_11_mac_addr addr2;
+ /** Address3 */
+ mlan_802_11_mac_addr addr3;
+ /** Sequence Control */
+ t_u16 seq_ctl;
+ /** Address4 */
+ mlan_802_11_mac_addr addr4;
+} MLAN_PACK_END wlan_802_11_header;
+
+/** wlan_802_11_header packet from FW with length */
+typedef MLAN_PACK_START struct _wlan_mgmt_pkt {
+ /** Packet Length */
+ t_u16 frm_len;
+ /** wlan_802_11_header */
+ wlan_802_11_header wlan_header;
+} MLAN_PACK_END wlan_mgmt_pkt;
+
+#ifdef STA_SUPPORT
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) */
+#define MAX_NO_OF_CHAN 40
+
+/** Channel-power table entries */
+typedef MLAN_PACK_START struct _chan_power_11d {
+ /** 11D channel */
+ t_u8 chan;
+ /** Band for channel */
+ t_u8 band;
+ /** 11D channel power */
+ t_u8 pwr;
+ /** AP seen on channel */
+ t_u8 ap_seen;
+} MLAN_PACK_END chan_power_11d_t;
+
+/** Region channel info */
+typedef MLAN_PACK_START struct _parsed_region_chan_11d {
+ /** 11D channel power per channel */
+ chan_power_11d_t chan_pwr[MAX_NO_OF_CHAN];
+ /** 11D number of channels */
+ t_u8 no_of_chan;
+} MLAN_PACK_END parsed_region_chan_11d_t;
+#endif /* STA_SUPPORT */
+
+/** ChanScanMode_t */
+typedef MLAN_PACK_START struct _ChanScanMode_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved_7 : 1;
+ /** First passive scan then active scan */
+ t_u8 passive_to_active_scan : 1;
+ /** First channel in scan */
+ t_u8 first_chan : 1;
+ /** Enable hidden ssid report */
+ t_u8 hidden_ssid_report : 1;
+ /** Enable probe response timeout */
+ t_u8 rsp_timeout_en : 1;
+ /** Multidomain scan mode */
+ t_u8 multidomain_scan : 1;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt : 1;
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan : 1;
+#else
+ /** Channel scan mode passive flag */
+ t_u8 passive_scan : 1;
+ /** Disble channel filtering flag */
+ t_u8 disable_chan_filt : 1;
+ /** Multidomain scan mode */
+ t_u8 multidomain_scan : 1;
+ /** Enable probe response timeout */
+ t_u8 rsp_timeout_en : 1;
+ /** Enable hidden ssid report */
+ t_u8 hidden_ssid_report : 1;
+ /** First channel in scan */
+ t_u8 first_chan : 1;
+ /** First passive scan then active scan */
+ t_u8 passive_to_active_scan : 1;
+ /** Reserved */
+ t_u8 reserved_7 : 1;
+#endif
+} MLAN_PACK_END ChanScanMode_t;
+
+/** ChanScanParamSet_t */
+typedef MLAN_PACK_START struct _ChanScanParamSet_t {
+ /** Channel scan parameter : band config */
+ Band_Config_t bandcfg;
+ /** Channel scan parameter : Channel number */
+ t_u8 chan_number;
+ /** Channel scan parameter : Channel scan mode */
+ ChanScanMode_t chan_scan_mode;
+ /** Channel scan parameter : Minimum scan time */
+ t_u16 min_scan_time;
+ /** Channel scan parameter : Maximum scan time */
+ t_u16 max_scan_time;
+} MLAN_PACK_END ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanListParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel scan parameters */
+ ChanScanParamSet_t chan_scan_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanListParamSet_t;
+
+/** MrvlIEtypes_EESParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_EESParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** EES scan mode */
+ t_u16 ees_mode;
+ /** EES report condition */
+ t_u16 report_cond;
+ /** EES High Period scan interval */
+ t_u16 high_period;
+ /** EES High Period scan count */
+ t_u16 high_period_count;
+ /** EES Medium Period scan interval */
+ t_u16 mid_period;
+ /** EES Medium Period scan count */
+ t_u16 mid_period_count;
+ /** EES Low Period scan interval */
+ t_u16 low_period;
+ /** EES Low Period scan count */
+ t_u16 low_period_count;
+} MLAN_PACK_END MrvlIEtypes_EESParamSet_t;
+
+/** MrvlIEtype_EESNetworkCfg_t */
+typedef MLAN_PACK_START struct _MrvlIEtype_EESNetworkCfg_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of networks in the list */
+ t_u8 network_count;
+ /** Maximum number of connection */
+ t_u8 max_conn_count;
+ /** Black List Exp */
+ t_u8 black_list_exp;
+} MLAN_PACK_END MrvlIEtype_EESNetworkCfg_t;
+
+/** ChanBandParamSet_t */
+typedef struct _ChanBandParamSet_t {
+ /** Channel scan parameter : band config */
+ Band_Config_t bandcfg;
+ /** Channel number */
+ t_u8 chan_number;
+} ChanBandParamSet_t;
+
+/** MrvlIEtypes_ChanBandListParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChanBandListParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Channel Band parameters */
+ ChanBandParamSet_t chan_band_param[1];
+} MLAN_PACK_END MrvlIEtypes_ChanBandListParamSet_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RatesParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Rates */
+ t_u8 rates[1];
+} MLAN_PACK_END MrvlIEtypes_RatesParamSet_t;
+
+/** _MrvlIEtypes_Bssid_List_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bssid_List_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_Bssid_List_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsIdParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_SsIdParamSet_t;
+
+/**MrvlIEtypes_AssocType_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_HostMlme_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u8 host_mlme;
+} MLAN_PACK_END MrvlIEtypes_HostMlme_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_NumProbes_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Number of probes */
+ t_u16 num_probes;
+} MLAN_PACK_END MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WildCardSsIdParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Maximum SSID length */
+ t_u8 max_ssid_length;
+ /** SSID */
+ t_u8 ssid[1];
+} MLAN_PACK_END MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/**TSF data size */
+#define TSF_DATA_SIZE 8
+/** Table of TSF values returned in the scan result */
+typedef MLAN_PACK_START struct _MrvlIEtypes_TsfTimestamp_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** the length of each TSF data is 8 bytes, could be multiple TSF here
+ */
+ t_u8 tsf_data[1];
+} MLAN_PACK_END MrvlIEtypes_TsfTimestamp_t;
+
+/** CfParamSet_t */
+typedef MLAN_PACK_START struct _CfParamSet_t {
+ /** CF parameter : Count */
+ t_u8 cfp_cnt;
+ /** CF parameter : Period */
+ t_u8 cfp_period;
+ /** CF parameter : Duration */
+ t_u16 cfp_max_duration;
+ /** CF parameter : Duration remaining */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef MLAN_PACK_START struct _IbssParamSet_t {
+ /** ATIM window value */
+ t_u16 atim_window;
+} MLAN_PACK_END IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SsParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** CF/IBSS parameters sets */
+ union {
+ /** CF parameter set */
+ CfParamSet_t cf_param_set[1];
+ /** IBSS parameter set */
+ IbssParamSet_t ibss_param_set[1];
+ } cf_ibss;
+} MLAN_PACK_END MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef MLAN_PACK_START struct _FhParamSet_t {
+ /** FH parameter : Dwell time */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END FhParamSet_t;
+
+/** DsParamSet_t */
+typedef MLAN_PACK_START struct _DsParamSet_t {
+ /** Current channel number */
+ t_u8 current_chan;
+} MLAN_PACK_END DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PhyParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** FH/DS parameters */
+ union {
+ /** FH parameter set */
+ FhParamSet_t fh_param_set[1];
+ /** DS parameter set */
+ DsParamSet_t ds_param_set[1];
+ } fh_ds;
+} MLAN_PACK_END MrvlIEtypes_PhyParamSet_t;
+
+/* Auth type to be used in the Authentication portion of an Assoc seq */
+/** MrvlIEtypes_AuthType_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_AuthType_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u16 auth_type;
+} MLAN_PACK_END MrvlIEtypes_AuthType_t;
+
+/** MrvlIEtypes_ScanChanGap_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ScanChanGap_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Time gap in units to TUs to be used between
+ * two consecutive channels scan */
+ t_u16 gap;
+} MLAN_PACK_END MrvlIEtypes_ScanChanGap_t;
+
+/** channel statictics */
+typedef MLAN_PACK_START struct _chan_statistics_t {
+ /** channle number */
+ t_u8 chan_num;
+ /** band info */
+ Band_Config_t bandcfg;
+ /** flags */
+ t_u8 flags;
+ /** noise */
+ t_s8 noise;
+ /** total network */
+ t_u16 total_networks;
+ /** scan duration */
+ t_u16 cca_scan_duration;
+ /** busy duration */
+ t_u16 cca_busy_duration;
+} MLAN_PACK_END chan_statistics_t;
+
+/** channel statictics tlv */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ChannelStats_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** channel statictics */
+ chan_statistics_t chanStat[];
+} MLAN_PACK_END MrvlIEtypes_ChannelStats_t;
+
+/** MrvlIETypes_ActionFrame_t */
+typedef MLAN_PACK_START struct {
+ MrvlIEtypesHeader_t header; /**< Header */
+
+ t_u8 srcAddr[MLAN_MAC_ADDR_LENGTH];
+ t_u8 dstAddr[MLAN_MAC_ADDR_LENGTH];
+
+ IEEEtypes_ActionFrame_t actionFrame;
+
+} MLAN_PACK_END MrvlIETypes_ActionFrame_t;
+
+/** MrvlIEtypes_RxBaSync_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RxBaSync_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** tid */
+ t_u8 tid;
+ /** reserved field */
+ t_u8 reserved;
+ /** start seq num */
+ t_u16 seq_num;
+ /** bitmap len */
+ t_u16 bitmap_len;
+ /** bitmap */
+ t_u8 bitmap[1];
+} MLAN_PACK_END MrvlIEtypes_RxBaSync_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RsnParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSN IE */
+ t_u8 rsn_ie[];
+} MLAN_PACK_END MrvlIEtypes_RsnParamSet_t;
+
+/** MrvlIEtypes_SecurityCfg_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SecurityCfg_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** enable 11w */
+ t_u8 use_mfp;
+} MLAN_PACK_END MrvlIEtypes_SecurityCfg_t;
+
+/** Host Command ID : _HostCmd_DS_BEACON_STUCK_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_BEACON_STUCK_CFG {
+ /** ACT_GET/ACT_SET */
+ t_u8 action;
+ /** No of beacon interval after which firmware will check if beacon Tx
+ * is going fine */
+ t_u8 beacon_stuck_detect_count;
+ /** Upon performing MAC reset, no of beacon interval after which
+ * firmware will check if recovery was successful */
+ t_u8 recovery_confirm_count;
+} MLAN_PACK_END HostCmd_DS_BEACON_STUCK_CFG;
+
+/** Key Info flag for multicast key */
+#define KEY_INFO_MCAST_KEY 0x01
+/** Key Info flag for unicast key */
+#define KEY_INFO_UCAST_KEY 0x02
+/** Key Info flag for enable key */
+#define KEY_INFO_ENABLE_KEY 0x04
+/** Key Info flag for default key */
+#define KEY_INFO_DEFAULT_KEY 0x08
+/** Key Info flag for TX key */
+#define KEY_INFO_TX_KEY 0x10
+/** Key Info flag for RX key */
+#define KEY_INFO_RX_KEY 0x20
+#define KEY_INFO_CMAC_AES_KEY 0x400
+/** PN size for WPA/WPA2 */
+#define WPA_PN_SIZE 8
+/** PN size for PMF IGTK */
+#define IGTK_PN_SIZE 8
+/** WAPI KEY size */
+#define WAPI_KEY_SIZE 32
+/** key params fix size */
+#define KEY_PARAMS_FIXED_LEN 10
+/** key index mask */
+#define KEY_INDEX_MASK 0xf
+
+/** wep_param */
+typedef MLAN_PACK_START struct _wep_param_t {
+ /** key_len */
+ t_u16 key_len;
+ /** wep key */
+ t_u8 key[MAX_WEP_KEY_SIZE];
+} MLAN_PACK_END wep_param_t;
+
+/** tkip_param */
+typedef MLAN_PACK_START struct _tkip_param {
+ /** Rx packet num */
+ t_u8 pn[WPA_PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** tkip key */
+ t_u8 key[WPA_TKIP_KEY_LEN];
+} MLAN_PACK_END tkip_param;
+
+/** aes_param */
+typedef MLAN_PACK_START struct _aes_param {
+ /** Rx packet num */
+ t_u8 pn[WPA_PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** aes key */
+ t_u8 key[WPA_AES_KEY_LEN];
+} MLAN_PACK_END aes_param;
+
+/** wapi_param */
+typedef MLAN_PACK_START struct _wapi_param {
+ /** Rx packet num */
+ t_u8 pn[PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** wapi key */
+ t_u8 key[WAPI_KEY_SIZE];
+} MLAN_PACK_END wapi_param;
+
+/** cmac_aes_param */
+typedef MLAN_PACK_START struct _cmac_aes_param {
+ /** IGTK pn */
+ t_u8 ipn[IGTK_PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** aes key */
+ t_u8 key[CMAC_AES_KEY_LEN];
+} MLAN_PACK_END cmac_aes_param;
+
+/** gmac_param */
+typedef MLAN_PACK_START struct _gcmp_param {
+ /** GCMP pn */
+ t_u8 pn[WPA_PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** aes key */
+ t_u8 key[WPA_GCMP_KEY_LEN];
+} MLAN_PACK_END gcmp_param;
+
+/** ccmp256_param */
+typedef MLAN_PACK_START struct _ccmp256_param {
+ /** CCMP pn */
+ t_u8 pn[WPA_PN_SIZE];
+ /** key_len */
+ t_u16 key_len;
+ /** ccmp256 key */
+ t_u8 key[WPA_CCMP_256_KEY_LEN];
+} MLAN_PACK_END ccmp_256_param;
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtype_KeyParamSetV2_t {
+ /** Type ID */
+ t_u16 type;
+ /** Length of Payload */
+ t_u16 length;
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** key index */
+ t_u8 key_idx;
+ /** Type of Key: WEP=0, TKIP=1, AES=2, WAPI=3 AES_CMAC=4 */
+ t_u8 key_type;
+ /** Key Control Info specific to a key_type_id */
+ t_u16 key_info;
+ union {
+ /** wep key param */
+ wep_param_t wep;
+ /** tkip key param */
+ tkip_param tkip;
+ /** aes key param */
+ aes_param aes;
+ /** wapi key param */
+ wapi_param wapi;
+ /** IGTK key param */
+ cmac_aes_param cmac_aes;
+ /** gcmp key param */
+ gcmp_param gcmp;
+ /** ccmp 256 key parameters */
+ ccmp_256_param ccmp256;
+ } key_params;
+} MLAN_PACK_END MrvlIEtype_KeyParamSetV2_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_KEY_MATERIAL {
+ /** Action */
+ t_u16 action;
+ /** Key parameter set */
+ MrvlIEtype_KeyParamSetV2_t key_param_set;
+} MLAN_PACK_END HostCmd_DS_802_11_KEY_MATERIAL;
+
+/** HostCmd_DS_GTK_REKEY_PARAMS */
+typedef MLAN_PACK_START struct _HostCmd_DS_GTK_REKEY_PARAMS {
+ /** Action */
+ t_u16 action;
+ /** Key confirmation key */
+ t_u8 kck[MLAN_KCK_LEN];
+ /** Key encryption key */
+ t_u8 kek[MLAN_KEK_LEN];
+ /** Replay counter low 32 bit */
+ t_u32 replay_ctr_low;
+ /** Replay counter high 32 bit */
+ t_u32 replay_ctr_high;
+} MLAN_PACK_END HostCmd_DS_GTK_REKEY_PARAMS;
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _WmmQosInfo_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmQosInfo_t, *pWmmQosInfo_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _WmmEcw_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmEcw_t, *pWmmEcw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _WmmAciAifsn_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aifsn */
+ t_u8 aifsn : 4;
+#else
+ /** Aifsn */
+ t_u8 aifsn : 4;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Reserved */
+ t_u8 reserved : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END WmmAciAifsn_t, *pWmmAciAifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _WmmAcParameters_t {
+ WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END WmmAcParameters_t, *pWmmAcParameters_t;
+
+/** Data structure of WMM parameter */
+typedef MLAN_PACK_START struct _WmmParameter_t {
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END WmmParameter_t, *pWmmParameter_t;
+
+/** Data structure of Host command WMM_PARAM_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_WMM_PARAM_CONFIG {
+ /** action */
+ t_u16 action;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END HostCmd_DS_WMM_PARAM_CONFIG;
+
+/* Definition of firmware host command */
+/** HostCmd_DS_GEN */
+typedef MLAN_PACK_START struct _HostCmd_DS_GEN {
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+} MLAN_PACK_END HostCmd_DS_GEN
+
+ ;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
+
+/** mod_group_setting */
+typedef MLAN_PACK_START struct _mod_group_setting {
+ /** modulation group */
+ t_u8 mod_group;
+ /** power */
+ t_u8 power;
+} MLAN_PACK_END mod_group_setting;
+
+/** MrvlIETypes_ChanTRPCConfig_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_ChanTRPCConfig_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** start freq */
+ t_u16 start_freq;
+ /* channel width */
+ t_u8 width;
+ /** channel number */
+ t_u8 chan_num;
+ /** mode groups */
+ mod_group_setting mod_group[];
+} MLAN_PACK_END MrvlIETypes_ChanTRPCConfig_t;
+
+/* HostCmd_DS_CHANNEL_TRPC_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CHANNEL_TRPC_CONFIG {
+ /** action */
+ t_u16 action;
+ /** 0/1/2/3 */
+ t_u16 sub_band;
+ /** chan TRPC config */
+ MrvlIETypes_ChanTRPCConfig_t tlv[];
+} MLAN_PACK_END HostCmd_DS_CHANNEL_TRPC_CONFIG;
+
+typedef MLAN_PACK_START struct _HostCmd_DS_MEF_CFG {
+ /** Criteria */
+ t_u32 criteria;
+ /** Number of entries */
+ t_u16 nentries;
+} MLAN_PACK_END HostCmd_DS_MEF_CFG;
+
+#define MAX_NUM_STACK_BYTES 100
+/** mef stack struct*/
+typedef MLAN_PACK_START struct _mef_stack {
+ /** length of byte*/
+ t_u16 sp;
+ /** data of filter items*/
+ t_u8 byte[MAX_NUM_STACK_BYTES];
+} MLAN_PACK_END mef_stack;
+
+/** mef entry struct */
+typedef MLAN_PACK_START struct _mef_entry_header {
+ /**mode:1->hostsleep;2->non hostsleep mode*/
+ t_u8 mode;
+ /**action=0->discard and not wake host
+ * action=1->discard and wake host
+ * action=3->allow and wake host*/
+ t_u8 action;
+} MLAN_PACK_END mef_entry_header;
+
+/** mef op struct is to help to generate mef data*/
+typedef MLAN_PACK_START struct _mef_op {
+ /** operand_type*/
+ t_u8 operand_type;
+ /** reserved*/
+ t_u8 rsvd[3];
+ /** data */
+ t_u8 val[MAX_NUM_BYTE_SEQ + 1];
+} MLAN_PACK_END mef_op;
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PERIOD {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+
+ /** Sleep Period in msec */
+ t_u16 sleep_pd;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SLEEP_PARAMS {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** Sleep clock error in ppm */
+ t_u16 error;
+ /** Wakeup offset in usec */
+ t_u16 offset;
+ /** Clock stabilization time in usec */
+ t_u16 stable_time;
+ /** Control periodic calibration */
+ t_u8 cal_control;
+ /** Control the use of external sleep clock */
+ t_u8 external_sleep_clk;
+ /** Reserved field, should be set to zero */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/** Sleep response control */
+typedef enum _sleep_resp_ctrl {
+ RESP_NOT_NEEDED = 0,
+ RESP_NEEDED,
+} sleep_resp_ctrl;
+
+/** Structure definition for the new ieee power save parameters*/
+typedef MLAN_PACK_START struct __ps_param {
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+ /** Num dtims */
+ t_u16 multiple_dtims;
+ /** becaon miss interval */
+ t_u16 bcn_miss_timeout;
+ /** local listen interval */
+ t_u16 local_listen_interval;
+ /** Adhoc awake period */
+ t_u16 adhoc_wake_period;
+ /** mode - (0x01 - firmware to automatically choose PS_POLL or NULL
+ * mode, 0x02 - PS_POLL, 0x03 - NULL mode )
+ */
+ t_u16 mode;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+} MLAN_PACK_END ps_param;
+
+/** Structure definition for the new auto deep sleep command */
+typedef MLAN_PACK_START struct __auto_ds_param {
+ /** Deep sleep inactivity timeout */
+ t_u16 deep_sleep_timeout;
+} MLAN_PACK_END auto_ds_param;
+
+/** Structure definition for sleep confirmation in the new ps command */
+typedef MLAN_PACK_START struct __sleep_confirm_param {
+ /** response control 0x00 - response not needed, 0x01 - response needed
+ */
+ t_u16 resp_ctrl;
+} MLAN_PACK_END sleep_confirm_param;
+
+/** bitmap for get auto deepsleep */
+#define BITMAP_AUTO_DS 0x01
+/** bitmap for sta power save */
+#define BITMAP_STA_PS 0x10
+/** bitmap for beacon timeout */
+#define BITMAP_BCN_TMO 0x20
+/** bitmap for uap inactivity based PS */
+#define BITMAP_UAP_INACT_PS 0x100
+/** bitmap for uap DTIM PS */
+#define BITMAP_UAP_DTIM_PS 0x200
+/** Structure definition for the new ieee power save parameters*/
+typedef MLAN_PACK_START struct _auto_ps_param {
+ /** bitmap for enable power save mode */
+ t_u16 ps_bitmap;
+ /* auto deep sleep parameter,
+ * sta power save parameter
+ * uap inactivity parameter
+ * uap DTIM parameter */
+} MLAN_PACK_END auto_ps_param;
+
+/** fix size for auto ps */
+#define AUTO_PS_FIX_SIZE 4
+
+/** TLV type : auto ds param */
+#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x71) /* 0x0171 */
+/** TLV type : ps param */
+#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 0x72) /* 0x0172 */
+/** TLV type : beacon timeout */
+#define TLV_TYPE_BCN_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 0x11F) /* 0x011F */
+
+/** MrvlIEtypes_auto_ds_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auto_ds_param_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** auto ds param */
+ auto_ds_param param;
+} MLAN_PACK_END MrvlIEtypes_auto_ds_param_t;
+
+/** MrvlIEtypes_ps_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_param_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** ps param */
+ ps_param param;
+} MLAN_PACK_END MrvlIEtypes_ps_param_t;
+
+/** MrvlIEtypes_bcn_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bcn_timeout_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Beacon miss timeout period window */
+ t_u16 bcn_miss_tmo_window;
+ /** Beacon miss timeout period */
+ t_u16 bcn_miss_tmo_period;
+ /** Beacon reacquire timeout period window */
+ t_u16 bcn_rq_tmo_window;
+ /** Beacon reacquire timeout period */
+ t_u16 bcn_rq_tmo_period;
+} MLAN_PACK_END MrvlIEtypes_bcn_timeout_t;
+
+/** Structure definition for low power mode cfg command */
+typedef MLAN_PACK_START struct _HostCmd_DS_LOW_POWER_MODE_CFG {
+ /** Action */
+ t_u16 action;
+ /** Low power mode */
+ t_u16 lpm;
+} MLAN_PACK_END HostCmd_DS_LOW_POWER_MODE_CFG;
+
+/** Structure definition for new power save command */
+typedef MLAN_PACK_START struct _HostCmd_DS_PS_MODE_ENH {
+ /** Action */
+ t_u16 action;
+ /** Data speciifc to action */
+ /* For IEEE power save data will be as
+ * UINT16 mode (0x01 - firmware to automatically choose PS_POLL or NULL
+ * mode, 0x02 - PS_POLL, 0x03 - NULL mode ) UINT16 NullpacketInterval
+ * UINT16 NumDtims
+ * UINT16 BeaconMissInterval
+ * UINT16 locallisteninterval
+ * UINT16 adhocawakeperiod */
+
+ /* For auto deep sleep */
+ /* UINT16 Deep sleep inactivity timeout*/
+
+ /* For PS sleep confirm
+ * UINT16 responeCtrl - 0x00 - reponse from fw not needed, 0x01 -
+ * response from fw is needed */
+
+ union {
+ /** PS param definition */
+ ps_param opt_ps;
+ /** Auto ds param definition */
+ auto_ds_param auto_ds;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+ /** bitmap for get PS info and Disable PS mode */
+ t_u16 ps_bitmap;
+ /** auto ps param */
+ auto_ps_param auto_ps;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_PS_MODE_ENH;
+
+/** FW VERSION tlv */
+#define TLV_TYPE_FW_VER_INFO (PROPRIETARY_TLV_BASE_ID + 0xC7) /* 0x1C7 */
+
+/** MrvlIEtypes_fw_ver_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_fw_ver_info_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** API id */
+ t_u16 api_id;
+ /** major version */
+ t_u8 major_ver;
+ /** minor version */
+ t_u8 minor_ver;
+} MLAN_PACK_END MrvlIEtypes_fw_ver_info_t;
+
+/** API ID */
+enum API_VER_ID {
+ KEY_API_VER_ID = 1,
+ FW_API_VER_ID = 2,
+ UAP_FW_API_VER_ID = 3,
+ CHANRPT_API_VER_ID = 4,
+};
+
+/** FW AP V15 */
+#define HOST_API_VERSION_V15 15
+/** FW minor version 1 */
+#define FW_MINOR_VERSION_1 1
+
+/** UAP FW version 2 */
+#define UAP_FW_VERSION_2 0x2
+
+/** HostCMD_DS_APCMD_ACS_SCAN */
+typedef MLAN_PACK_START struct _HostCMD_DS_APCMD_ACS_SCAN {
+ /** band */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 chan;
+} MLAN_PACK_END HostCMD_DS_APCMD_ACS_SCAN;
+
+/** HostCmd_DS_GET_HW_SPEC */
+typedef MLAN_PACK_START struct _HostCmd_DS_GET_HW_SPEC {
+ /** HW Interface version number */
+ t_u16 hw_if_version;
+ /** HW version number */
+ t_u16 version;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Max no of Multicast address */
+ t_u16 num_of_mcast_adr;
+ /** MAC address */
+ t_u8 permanent_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Region Code */
+ t_u16 region_code;
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+ /** FW release number, example 0x1234=1.2.3.4 */
+ t_u32 fw_release_number;
+ /** Reserved field */
+ t_u32 reserved_1;
+ /** Reserved field */
+ t_u32 reserved_2;
+ /** Reserved field */
+ t_u32 reserved_3;
+ /** FW/HW Capability */
+ t_u32 fw_cap_info;
+ /** 802.11n Device Capabilities */
+ t_u32 dot_11n_dev_cap;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 dev_mcs_support;
+ /** Valid end port at init */
+ t_u16 mp_end_port;
+ /** mgmt IE buffer count */
+ t_u16 mgmt_buf_count;
+ /** Reserved */
+ t_u32 reserved_8;
+ /** Reserved */
+ t_u32 reserved_9;
+ /** 802.11ac Device Capabilities */
+ t_u32 Dot11acDevCap;
+ /** MCSs supported by 802.11ac device */
+ t_u32 Dot11acMcsSupport;
+} MLAN_PACK_END HostCmd_DS_GET_HW_SPEC;
+
+#ifdef SDIO
+/* HostCmd_DS_SDIO_SP_RX_AGGR_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_SP_RX_AGGR_CFG {
+ t_u8 action;
+ t_u8 enable;
+ t_u16 sdio_block_size;
+} MLAN_PACK_END HostCmd_DS_SDIO_SP_RX_AGGR_CFG;
+#endif
+
+/** HostCmd_DS_802_11_CFG_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_CFG_DATA {
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+} MLAN_PACK_END HostCmd_DS_802_11_CFG_DATA;
+
+/** HostCmd_DS_CMD_802_11_RSSI_INFO_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO_EXT {
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for Beacon */
+ t_u16 nbcn;
+ /** Last RSSI beacon TSF(only for Get action) */
+ t_u64 tsfbcn;
+ /** TLV info**/
+ t_u8 *tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO_EXT;
+
+/** TLV rssi info */
+#define TLV_TYPE_RSSI_INFO (PROPRIETARY_TLV_BASE_ID + 0xe5) /* 0x01E5 */
+
+/** MrvlIEtypes_eapol_pkt_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RSSI_EXT_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Path ID
+ [Bit1:Bit0] = [0:1]: path A
+ [Bit1:Bit0] = [1:0]: path B
+ [Bit1:Bit0] = [1:1]: combined signal of path A and path B
+ [Bit7:Bit2] : Reserved
+ **/
+ t_u16 path_id;
+ /** Last Data RSSI in dBm */
+ t_s16 data_rssi_last;
+ /** Last Data NF in dBm */
+ t_s16 data_nf_last;
+ /** AVG DATA RSSI in dBm */
+ t_s16 data_rssi_avg;
+ /** AVG DATA NF in dBm */
+ t_s16 data_nf_avg;
+ /** Last BEACON RSSI in dBm */
+ t_s16 bcn_rssi_last;
+ /** Last BEACON NF in dBm */
+ t_s16 bcn_nf_last;
+ /** AVG BEACON RSSI in dBm */
+ t_s16 bcn_rssi_avg;
+ /** AVG BEACON NF in dBm */
+ t_s16 bcn_nf_avg;
+} MLAN_PACK_END MrvlIEtypes_RSSI_EXT_t;
+
+/** HostCmd_DS_CMD_802_11_RSSI_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO {
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for Beacon */
+ t_u16 nbcn;
+ /** Reserved field 0 */
+ t_u16 reserved[9];
+ /** Reserved field 1 */
+ t_u64 reserved_1;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO;
+
+/** HostCmd_DS_802_11_RSSI_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RSSI_INFO_RSP {
+ /** Action */
+ t_u16 action;
+ /** Parameter used for exponential averaging for Data */
+ t_u16 ndata;
+ /** Parameter used for exponential averaging for beacon */
+ t_u16 nbcn;
+ /** Last Data RSSI in dBm */
+ t_s16 data_rssi_last;
+ /** Last Data NF in dBm */
+ t_s16 data_nf_last;
+ /** AVG DATA RSSI in dBm */
+ t_s16 data_rssi_avg;
+ /** AVG DATA NF in dBm */
+ t_s16 data_nf_avg;
+ /** Last BEACON RSSI in dBm */
+ t_s16 bcn_rssi_last;
+ /** Last BEACON NF in dBm */
+ t_s16 bcn_nf_last;
+ /** AVG BEACON RSSI in dBm */
+ t_s16 bcn_rssi_avg;
+ /** AVG BEACON NF in dBm */
+ t_s16 bcn_nf_avg;
+ /** Last RSSI Beacon TSF */
+ t_u64 tsf_bcn;
+} MLAN_PACK_END HostCmd_DS_802_11_RSSI_INFO_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_MAC_ADDRESS {
+ /** Action */
+ t_u16 action;
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_DS_MAC_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_CONTROL {
+ /** Action */
+ t_u32 action;
+} MLAN_PACK_END HostCmd_DS_MAC_CONTROL;
+
+/** HostCmd_DS_CMD_TX_DATA_PAUSE */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_TX_DATA_PAUSE {
+ /** Action */
+ t_u16 action;
+ /** Enable/disable Tx data pause */
+ t_u8 enable_tx_pause;
+ /** Max number of TX buffers allowed for all PS clients*/
+ t_u8 pause_tx_count;
+} MLAN_PACK_END HostCmd_DS_CMD_TX_DATA_PAUSE;
+
+/** TLV type : TX pause TLV */
+#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 0x94) /* 0x0194 */
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_pause_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** peer mac address */
+ t_u8 peermac[MLAN_MAC_ADDR_LENGTH];
+ /** Tx pause state, 1--pause, 0--free flowing */
+ t_u8 tx_pause;
+ /** total packets queued for the client */
+ t_u8 pkt_cnt;
+} MLAN_PACK_END MrvlIEtypes_tx_pause_t;
+
+/** HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_MULTICAST_ADR {
+ /** Action */
+ t_u16 action;
+ /** Number of addresses */
+ t_u16 num_of_adrs;
+ /** List of MAC */
+ t_u8 mac_list[MLAN_MAC_ADDR_LENGTH * MLAN_MAX_MULTICAST_LIST_SIZE];
+} MLAN_PACK_END HostCmd_DS_MAC_MULTICAST_ADR;
+
+/** HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_DEAUTHENTICATE {
+ /** MAC address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Deauthentication resaon code */
+ t_u16 reason_code;
+} MLAN_PACK_END HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE {
+ /** Peer STA address */
+ t_u8 peer_sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+
+ /**
+ * MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_PhyParamSet_t PhyParamSet;
+ * MrvlIEtypes_SsParamSet_t SsParamSet;
+ * MrvlIEtypes_RatesParamSet_t RatesParamSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_CMD_802_11_ASSOCIATE response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ASSOCIATE_RSP {
+ /** Association response structure */
+ IEEEtypes_AssocRsp_t assoc_rsp;
+} MLAN_PACK_END HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START {
+ /** AdHoc SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_START_RESULT {
+ /** Padding */
+ t_u8 pad[3];
+ /** AdHoc BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Padding to sync with FW structure*/
+ t_u8 pad2[2];
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_START_RESULT;
+
+/** HostCmd_CMD_802_11_AD_HOC_START response */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN_RESULT {
+ /** Result */
+ t_u8 result;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN_RESULT;
+
+/** AdHoc_BssDesc_t */
+typedef MLAN_PACK_START struct _AdHoc_BssDesc_t {
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** DTIM period */
+ t_u8 dtim_period;
+ /** Timestamp */
+ t_u8 time_stamp[8];
+ /** Local time */
+ t_u8 local_time[8];
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap;
+ /** Supported data rates */
+ t_u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+ * It is used in the Adhoc join command and will cause a
+ * binary layout mismatch with the firmware
+ */
+} MLAN_PACK_END AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_AD_HOC_JOIN {
+ /** AdHoc BSS descriptor */
+ AdHoc_BssDesc_t bss_descriptor;
+ /** Reserved field */
+ t_u16 reserved1;
+ /** Reserved field */
+ t_u16 reserved2;
+} MLAN_PACK_END HostCmd_DS_802_11_AD_HOC_JOIN;
+
+#if defined(SDIO)
+/** Interrupt Raising Edge */
+#define INT_RASING_EDGE 0
+/** Interrupt Falling Edge */
+#define INT_FALLING_EDGE 1
+
+/** Delay 1 usec */
+#define DELAY_1_US 1
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_GPIO_INT_CONFIG {
+ /** Action */
+ t_u16 action;
+ /** GPIO interrupt pin */
+ t_u16 gpio_pin;
+ /** GPIO interrupt edge, 1: failing edge; 0: raising edge */
+ t_u16 gpio_int_edge;
+ /** GPIO interrupt pulse widthin usec units */
+ t_u16 gpio_pulse_width;
+} MLAN_PACK_END HostCmd_DS_SDIO_GPIO_INT_CONFIG;
+#endif /* GPIO_SDIO_INT_CTRL */
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SDIO_PULL_CTRL {
+ /** Action */
+ t_u16 action;
+ /** The delay of pulling up in us */
+ t_u16 pull_up;
+ /** The delay of pulling down in us */
+ t_u16 pull_down;
+} MLAN_PACK_END HostCmd_DS_SDIO_PULL_CTRL;
+
+/** HostCmd_DS_802_11_GET_LOG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_GET_LOG {
+ /** Number of multicast transmitted frames */
+ t_u32 mcast_tx_frame;
+ /** Number of failures */
+ t_u32 failed;
+ /** Number of retries */
+ t_u32 retry;
+ /** Number of multiretries */
+ t_u32 multiretry;
+ /** Number of duplicate frames */
+ t_u32 frame_dup;
+ /** Number of RTS success */
+ t_u32 rts_success;
+ /** Number of RTS failure */
+ t_u32 rts_failure;
+ /** Number of acknowledgement failure */
+ t_u32 ack_failure;
+ /** Number of fragmented packets received */
+ t_u32 rx_frag;
+ /** Number of multicast frames received */
+ t_u32 mcast_rx_frame;
+ /** FCS error */
+ t_u32 fcs_error;
+ /** Number of transmitted frames */
+ t_u32 tx_frame;
+ /** Reserved field */
+ t_u32 reserved;
+ /** Number of WEP icv error for each key */
+ t_u32 wep_icv_err_cnt[4];
+ /** Beacon received count */
+ t_u32 bcn_rcv_cnt;
+ /** Beacon missed count */
+ t_u32 bcn_miss_cnt;
+ /** Tx frag count */
+ t_u32 tx_frag_cnt;
+ /** Qos Tx frag count */
+ t_u32 qos_tx_frag_cnt[8];
+ /** Qos failed count */
+ t_u32 qos_failed_cnt[8];
+ /** Qos retry count */
+ t_u32 qos_retry_cnt[8];
+ /** Qos multi retry count */
+ t_u32 qos_multi_retry_cnt[8];
+ /** Qos frame dup count */
+ t_u32 qos_frm_dup_cnt[8];
+ /** Qos rts success count */
+ t_u32 qos_rts_suc_cnt[8];
+ /** Qos rts failure count */
+ t_u32 qos_rts_failure_cnt[8];
+ /** Qos ack failure count */
+ t_u32 qos_ack_failure_cnt[8];
+ /** Qos Rx frag count */
+ t_u32 qos_rx_frag_cnt[8];
+ /** Qos Tx frame count */
+ t_u32 qos_tx_frm_cnt[8];
+ /** Qos discarded frame count */
+ t_u32 qos_discarded_frm_cnt[8];
+ /** Qos mpdus Rx count */
+ t_u32 qos_mpdus_rx_cnt[8];
+ /** Qos retry rx count */
+ t_u32 qos_retries_rx_cnt[8];
+ /** CMAC ICV errors count */
+ t_u32 cmacicv_errors;
+ /** CMAC replays count */
+ t_u32 cmac_replays;
+ /** mgmt CCMP replays count */
+ t_u32 mgmt_ccmp_replays;
+ /** TKIP ICV errors count */
+ t_u32 tkipicv_errors;
+ /** TKIP replays count */
+ t_u32 tkip_replays;
+ /** CCMP decrypt errors count */
+ t_u32 ccmp_decrypt_errors;
+ /** CCMP replays count */
+ t_u32 ccmp_replays;
+ /** Tx amsdu count */
+ t_u32 tx_amsdu_cnt;
+ /** failed amsdu count */
+ t_u32 failed_amsdu_cnt;
+ /** retry amsdu count */
+ t_u32 retry_amsdu_cnt;
+ /** multi-retry amsdu count */
+ t_u32 multi_retry_amsdu_cnt;
+ /** Tx octets in amsdu count */
+ t_u64 tx_octets_in_amsdu_cnt;
+ /** amsdu ack failure count */
+ t_u32 amsdu_ack_failure_cnt;
+ /** Rx amsdu count */
+ t_u32 rx_amsdu_cnt;
+ /** Rx octets in amsdu count */
+ t_u64 rx_octets_in_amsdu_cnt;
+ /** Tx ampdu count */
+ t_u32 tx_ampdu_cnt;
+ /** tx mpdus in ampdu count */
+ t_u32 tx_mpdus_in_ampdu_cnt;
+ /** tx octets in ampdu count */
+ t_u64 tx_octets_in_ampdu_cnt;
+ /** ampdu Rx count */
+ t_u32 ampdu_rx_cnt;
+ /** mpdu in Rx ampdu count */
+ t_u32 mpdu_in_rx_ampdu_cnt;
+ /** Rx octets ampdu count */
+ t_u64 rx_octets_in_ampdu_cnt;
+ /** ampdu delimiter CRC error count */
+ t_u32 ampdu_delimiter_crc_error_cnt;
+ /** Rx Stuck Related Info*/
+ /** Rx Stuck Issue count */
+ t_u32 rx_stuck_issue_cnt[2];
+ /** Rx Stuck Recovery count */
+ t_u32 rx_stuck_recovery_cnt;
+ /** Rx Stuck TSF */
+ t_u64 rx_stuck_tsf[2];
+ /** Tx Watchdog Recovery Related Info */
+ /** Tx Watchdog Recovery count */
+ t_u32 tx_watchdog_recovery_cnt;
+ /** Tx Watchdog TSF */
+ t_u64 tx_watchdog_tsf[2];
+ /** Channel Switch Related Info */
+ /** Channel Switch Announcement Sent */
+ t_u32 channel_switch_ann_sent;
+ /** Channel Switch State */
+ t_u32 channel_switch_state;
+ /** Register Class */
+ t_u32 reg_class;
+ /** Channel Number */
+ t_u32 channel_number;
+ /** Channel Switch Mode */
+ t_u32 channel_switch_mode;
+} MLAN_PACK_END HostCmd_DS_802_11_GET_LOG;
+
+/* maln wifi rate */
+typedef MLAN_PACK_START struct _mlan_wifi_rate {
+ /** 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ t_u8 preamble;
+ /** 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ t_u8 nss;
+ /** 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
+ t_u8 bw;
+ /** OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps
+ */
+ /** HT/VHT it would be mcs index */
+ t_u8 rateMcsIdx;
+ /** units of 100 Kbps */
+ t_u32 bitrate;
+} MLAN_PACK_START mlan_wifi_rate;
+
+/** channel information */
+typedef MLAN_PACK_START struct {
+ /** channel width (20, 40, 80, 80+80, 160) */
+ t_u32 width;
+ /** primary 20 MHz channel */
+ t_u32 center_freq;
+ /** center frequency (MHz) first segment */
+ t_u32 center_freq0;
+ /** center frequency (MHz) second segment */
+ t_u32 center_freq1;
+} MLAN_PACK_END mlan_wifi_channel_info;
+
+/** channel statistics */
+typedef MLAN_PACK_START struct {
+ /** channel */
+ mlan_wifi_channel_info channel;
+ /** msecs the radio is awake (32 bits number accruing over time) */
+ t_u32 on_time;
+ /** msecs the CCA register is busy (32 bits number accruing over time)
+ */
+ t_u32 cca_busy_time;
+} MLAN_PACK_END mlan_wifi_channel_stat;
+
+/** radio statistics */
+typedef MLAN_PACK_START struct {
+ /** supported wifi in case of multi radio */
+ t_u32 radio;
+ /** msecs the radio is awake */
+ t_u32 on_time;
+ /** msecs the radio is transmitting */
+ t_u32 tx_time;
+ /** TBD: num_tx_levels: number of radio transmit power levels */
+ t_u32 reserved0;
+ /** TBD: tx_time_per_levels: pointer to an array of radio transmit per
+ * power levels in msecs accured over time */
+ t_u32 reserved1;
+ /** msecs the radio is in active receive */
+ t_u32 rx_time;
+ /** msecs the radio is awake due to all scan */
+ t_u32 on_time_scan;
+ /** msecs the radio is awake due to NAN */
+ t_u32 on_time_nbd;
+ /** msecs the radio is awake due to G?scan */
+ t_u32 on_time_gscan;
+ /** msecs the radio is awake due to roam?scan */
+ t_u32 on_time_roam_scan;
+ /** msecs the radio is awake due to PNO scan */
+ t_u32 on_time_pno_scan;
+ /** msecs the radio is awake due to HS2.0 scans and GAS exchange */
+ t_u32 on_time_hs20;
+ /** number of channels */
+ t_u32 num_channels;
+ /** channel statistics */
+ mlan_wifi_channel_stat channels[MAX_NUM_CHAN]; // support only 1
+ // channel, so keep it.
+} MLAN_PACK_END mlan_wifi_radio_stat;
+
+/** per rate statistics */
+typedef MLAN_PACK_START struct {
+ /** rate information */
+ mlan_wifi_rate rate;
+ /** number of successfully transmitted data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received data pkts */
+ t_u32 rx_mpdu;
+ /** number of data packet losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+} MLAN_PACK_END mlan_wifi_rate_stat;
+
+/** per peer statistics */
+typedef MLAN_PACK_START struct {
+ /** peer type (AP, TDLS, GO etc.) */
+ t_u8 type;
+ /** mac address */
+ t_u8 peer_mac_address[6];
+ /** peer WIFI_CAPABILITY_XXX */
+ t_u32 capabilities;
+ /** number of rates */
+ t_u32 num_rate;
+ /** per rate statistics, number of entries = num_rate */
+ mlan_wifi_rate_stat rate_stats[];
+} MLAN_PACK_END mlan_wifi_peer_info;
+
+/* per access category statistics */
+typedef MLAN_PACK_START struct {
+ /** access category (VI, VO, BE, BK) */
+ t_u32 ac;
+ /** number of successfully transmitted unicast data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received unicast mpdus */
+ t_u32 rx_mpdu;
+ /** number of succesfully transmitted multicast data packets */
+ /** STA case: implies ACK received from AP for the unicast packet in
+ * which mcast pkt was sent */
+ t_u32 tx_mcast;
+ /** number of received multicast data packets */
+ t_u32 rx_mcast;
+ /** number of received unicast a-mpdus */
+ t_u32 rx_ampdu;
+ /** number of transmitted unicast a-mpdus */
+ t_u32 tx_ampdu;
+ /** number of data pkt losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+ /** data pkt min contention time (usecs) */
+ t_u32 contention_time_min;
+ /** data pkt max contention time (usecs) */
+ t_u32 contention_time_max;
+ /** data pkt avg contention time (usecs) */
+ t_u32 contention_time_avg;
+ /** num of data pkts used for contention statistics */
+ t_u32 contention_num_samples;
+} MLAN_PACK_END mlan_wifi_wmm_ac_stat;
+
+/** interface statistics */
+typedef MLAN_PACK_START struct {
+ /** access point beacon received count from connected AP */
+ t_u32 beacon_rx;
+ /** Average beacon offset encountered (beacon_TSF - TBTT)
+ * the average_tsf_offset field is used so as to calculate the
+ * typical beacon contention time on the channel as well may be
+ * used to debug beacon synchronization and related power consumption
+ * issue
+ */
+ t_u64 average_tsf_offset;
+ /** indicate that this AP typically leaks packets beyond the driver
+ * guard time */
+ t_u32 leaky_ap_detected;
+ /** average number of frame leaked by AP after frame with PM bit set was
+ * ACK'ed by AP */
+ t_u32 leaky_ap_avg_num_frames_leaked;
+ /** Guard time currently in force (when implementing IEEE power
+ * management based on frame control PM bit), How long driver waits
+ * before shutting down the radio and after receiving an ACK for a data
+ * frame with PM bit set)
+ */
+ t_u32 leaky_ap_guard_time;
+ /** access point mgmt frames received count from connected AP (including
+ * Beacon) */
+ t_u32 mgmt_rx;
+ /** action frames received count */
+ t_u32 mgmt_action_rx;
+ /** action frames transmit count */
+ t_u32 mgmt_action_tx;
+ /** access Point Beacon and Management frames RSSI (averaged) */
+ t_u32 rssi_mgmt;
+ /** access Point Data Frames RSSI (averaged) from connected AP */
+ t_u32 rssi_data;
+ /** access Point ACK RSSI (averaged) from connected AP */
+ t_u32 rssi_ack;
+ /** per ac data packet statistics */
+ mlan_wifi_wmm_ac_stat ac[MAX_AC_QUEUES];
+ /** number of peers */
+ t_u32 num_peers;
+ /** per peer statistics */
+ mlan_wifi_peer_info peer_info[];
+} MLAN_PACK_END mlan_wifi_iface_stat;
+
+/** MrvlIETypes_llStatIface_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_llStatIface_t {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** Frame Control */
+ mlan_wifi_iface_stat ifaceStat;
+ /* t_u8 frame_contents[]; */
+} MLAN_PACK_END MrvlIETypes_llStatIface_t;
+
+/** MrvlIETypes_llStatRadio_t */
+typedef MLAN_PACK_START struct _MrvlIETypes_llStatRadio_t {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** Frame Control */
+ mlan_wifi_radio_stat radioStat[MAX_RADIO];
+ /* t_u8 frame_contents[]; */
+} MLAN_PACK_END MrvlIETypes_llStatRadio_t;
+
+#define TYPE_IFACE_STAT MBIT(0)
+#define TYPE_RADIO_STAT MBIT(1)
+#define TYPE_PEER_INFO MBIT(2)
+/** HostCmd_DS_802_11_LINK_STATISTIC */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_LINK_STATISTIC {
+ /** Action : HostCmd_ACT_GEN_GET/SET/REMOVE */
+ t_u16 action;
+ /** statistic which would be get in action HostCmd_ACT_GEN_GET :
+ * TYPE_IFACE_STAT/RADIO_STAT/PEER_INFO */
+ t_u16 stat_type;
+ /* threshold to classify the pkts as short or long, packet size <
+ * mpdu_size_threshold => short */
+ t_u32 mpdu_size_threshold;
+ /* set for field debug mode. Driver should collect all statistics
+ * regardless of performance impact. */
+ t_u32 aggressive_statistics_gathering;
+ /** Value */
+ t_u8 value[];
+} MLAN_PACK_END HostCmd_DS_802_11_LINK_STATISTIC;
+
+/**_HostCmd_TX_RATE_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_TX_RATE_QUERY {
+ /** Tx rate */
+ t_u8 tx_rate;
+ /** Tx Rate Info:
+ * [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2
+ * [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3
+ * [Bit 4] HT/VHT Guard Interval: LGI = 0, SGI = 1
+ * [Bit4,Bit7] AX Guard Interval: 00, 01, 02 */
+ t_u8 tx_rate_info;
+ /**
+ * BIT0: DCM
+ * BIT3-BIT1: tone mode
+ ** 000: 26 tone
+ ** 001: 52 tone
+ ** 010: 106 tone
+ ** 011: 242 tone
+ ** 100: 484 tone
+ ** 101: 996 tone
+ * BIT7-BIT4: resvd
+ **/
+ t_u8 ext_tx_rate_info;
+} MLAN_PACK_END HostCmd_TX_RATE_QUERY;
+
+typedef MLAN_PACK_START struct _hs_config_param {
+ /** bit0=1: broadcast data
+ * bit1=1: unicast data
+ * bit2=1: mac events
+ * bit3=1: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u8 gpio;
+ /** gap in milliseconds or or 0xff for special setting when
+ * GPIO is used to wakeup host
+ */
+ t_u8 gap;
+} MLAN_PACK_END hs_config_param;
+
+/** HS Action 0x0001 - Configure enhanced host sleep mode,
+ * 0x0002 - Activate enhanced host sleep mode
+ */
+typedef enum _Host_Sleep_Action {
+ HS_CONFIGURE = 0x0001,
+ HS_ACTIVATE = 0x0002,
+} Host_Sleep_Action;
+
+/** Structure definition for activating enhanced hs */
+typedef MLAN_PACK_START struct __hs_activate_param {
+ /** response control 0x00 - response not needed, 0x01 - response needed
+ */
+ t_u16 resp_ctrl;
+} MLAN_PACK_END hs_activate_param;
+
+/** HostCmd_DS_802_11_HS_CFG_ENH */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_HS_CFG_ENH {
+ /** Action 0x0001 - Configure enhanced host sleep mode,
+ * 0x0002 - Activate enhanced host sleep mode
+ */
+ t_u16 action;
+
+ union {
+ /** Configure enhanced hs */
+ hs_config_param hs_config;
+ /** Activate enhanced hs */
+ hs_activate_param hs_activate;
+ } params;
+} MLAN_PACK_END HostCmd_DS_802_11_HS_CFG_ENH;
+
+/** HostCmd_CMD_802_11_ROBUSTCOEX */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_ROBUSTCOEX {
+ /** Action */
+ t_u16 action;
+ /** RSVD */
+ t_u16 rsvd;
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_802_11_ROBUSTCOEX;
+
+/** HostCmd_CMD_DMCS_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_DMCS_CFG {
+ /** Action */
+ t_u16 action;
+ /** SubCmd of DMCS */
+ t_u16 subcmd;
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_DMCS_CFG;
+
+#if defined(PCIE)
+/** HostCmd_CMD_SSU */
+typedef MLAN_PACK_START struct _HostCmd_DS_SSU_CFG {
+ /** Action */
+ t_u16 action;
+ /** # of FFT sample to skip */
+ t_u32 nskip;
+ /** # of FFT sample selected to dump */
+ t_u32 nsel;
+ /** Down sample ADC input for buffering */
+ t_u32 adcdownsample;
+ /** Mask Out ADC Data From Spectral Packet */
+ t_u32 mask_adc_pkt;
+ /** Enable 16-Bit FFT Output Data Precision in Spectral Packet */
+ t_u32 out_16bits;
+ /** Enable power spectrum in dB for spectral packet */
+ t_u32 spec_pwr_enable;
+ /** Enable Spectral Packet Rate Reduction in dB output format */
+ t_u32 rate_deduction;
+ /** # of Spectral packets over which spectral data to be averaged */
+ t_u32 n_pkt_avg;
+ /** ret: Calculated fft length in dw */
+ t_u32 fft_len;
+ /** ret: Calculated adc length in dw */
+ t_u32 adc_len;
+ /** ret: Calculated record length in dw */
+ t_u32 rec_len;
+ /** Mapped address of DMA buffer */
+ t_u32 buffer_base_addr[2];
+ /** Total size of allocated buffer for SSU DMA */
+ t_u32 buffer_pool_size;
+ /** ret: Calculated buffer numbers */
+ t_u32 number_of_buffers;
+ /** ret: Calculated buffer size in byte for each descriptor */
+ t_u32 buffer_size;
+} MLAN_PACK_END HostCmd_DS_SSU_CFG;
+#endif
+
+/** SNMP_MIB_INDEX */
+typedef enum _SNMP_MIB_INDEX {
+ OpRateSet_i = 1,
+ DtimPeriod_i = 3,
+ RtsThresh_i = 5,
+ ShortRetryLim_i = 6,
+ LongRetryLim_i = 7,
+ FragThresh_i = 8,
+ Dot11D_i = 9,
+ Dot11H_i = 10,
+ WwsMode_i = 17,
+ Thermal_i = 34,
+ NullPktPeriod_i = 37,
+ SignalextEnable_i = 41,
+ ECSAEnable_i = 42,
+ StopDeauth_i = 44,
+} SNMP_MIB_INDEX;
+
+/** max SNMP buf size */
+#define MAX_SNMP_BUF_SIZE 128
+
+#ifdef UAP_SUPPORT
+/** HostCmd_CMD_802_11_SNMP_MIB */
+typedef MLAN_PACK_START struct _HostCmd_DS_UAP_802_11_SNMP_MIB {
+ /** SNMP query type */
+ t_u16 query_type;
+ /** snmp oid buf */
+ t_u8 snmp_data[];
+} MLAN_PACK_END HostCmd_DS_UAP_802_11_SNMP_MIB;
+#endif
+
+/** HostCmd_CMD_802_11_SNMP_MIB */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SNMP_MIB {
+ /** SNMP query type */
+ t_u16 query_type;
+ /** SNMP object ID */
+ t_u16 oid;
+ /** SNMP buffer size */
+ t_u16 buf_size;
+ /** Value */
+ t_u8 value[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SNMP_MIB;
+
+/** Radio on */
+#define RADIO_ON 0x01
+/** Radio off */
+#define RADIO_OFF 0x00
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RADIO_CONTROL {
+ /** Action */
+ t_u16 action;
+ /** Control */
+ t_u16 control;
+} MLAN_PACK_END HostCmd_DS_802_11_RADIO_CONTROL;
+
+/** MrvlRateScope_t */
+typedef MLAN_PACK_START struct _MrvlRateScope_t {
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Bitmap of HR/DSSS rates */
+ t_u16 hr_dsss_rate_bitmap;
+ /** Bitmap of OFDM rates */
+ t_u16 ofdm_rate_bitmap;
+ /** Bitmap of HT-MCSs allowed for initial rate */
+ t_u16 ht_mcs_rate_bitmap[8];
+ t_u16 vht_mcs_rate_bitmap[8];
+ t_u16 he_mcs_rate_bitmap[8];
+} MLAN_PACK_END MrvlRateScope_t;
+
+/** MrvlRateDropPattern_t */
+typedef MLAN_PACK_START struct _MrvlRateDropPattern_t {
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /** Rate Drop Mode */
+ t_u32 rate_drop_mode;
+ /* MrvlRateDropControl_t RateDropControl[]; */
+} MLAN_PACK_END MrvlRateDropPattern_t;
+
+typedef MLAN_PACK_START struct _MrvlIETypes_rate_setting_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Rate Setting */
+ t_u16 rate_setting;
+} MLAN_PACK_END MrvlIETypes_rate_setting_t;
+
+/** HostCmd_DS_TX_RATE_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_RATE_CFG {
+ /** Action */
+ t_u16 action;
+ t_u16 reserved_1;
+ /* MrvlRateScope_t RateScope;
+ * MrvlRateDropPattern_t RateDrop; */
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_TX_RATE_CFG;
+
+/** Power_Group_t */
+typedef MLAN_PACK_START struct _Power_Group_t {
+ /** Modulation Class */
+ t_u8 modulation_class;
+ /** MCS Code or Legacy RateID */
+ t_u8 first_rate_code;
+ /** MCS Code or Legacy RateID */
+ t_u8 last_rate_code;
+ /** Power Adjustment Step */
+ t_s8 power_step;
+ /** Minimal Tx Power Level [dBm] */
+ t_s8 power_min;
+ /** Maximal Tx Power Level [dBm] */
+ t_s8 power_max;
+ /** 0: HTBW20, 1: HTBW40 */
+ t_u8 ht_bandwidth;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END Power_Group_t;
+
+/** MrvlTypes_Power_Group_t */
+typedef MLAN_PACK_START struct _MrvlTypes_Power_Group_t {
+ /** Header Type */
+ t_u16 type;
+ /** Header Length */
+ t_u16 length;
+ /* Power_Group_t PowerGroups */
+} MLAN_PACK_END MrvlTypes_Power_Group_t;
+
+/** HostCmd_CMD_TXPWR_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TXPWR_CFG {
+ /** Action */
+ t_u16 action;
+ /** Power group configuration index */
+ t_u16 cfg_index;
+ /** Power group configuration mode */
+ t_u32 mode;
+ /* MrvlTypes_Power_Group_t PowerGrpCfg[]*/
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_TXPWR_CFG;
+
+/** HostCmd_CMD_802_11_RF_TX_POWER */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_TX_POWER {
+ /** Action */
+ t_u16 action;
+ /** Current power level */
+ t_s16 current_level;
+ /** Maximum power */
+ t_s8 max_power;
+ /** Minimum power */
+ t_s8 min_power;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_TX_POWER;
+
+/** Connection type infra */
+#define CONNECTION_TYPE_INFRA 0
+/** Connection type adhoc */
+#define CONNECTION_TYPE_ADHOC 1
+#ifdef WIFI_DIRECT_SUPPORT
+/** BSS Mode: WIFIDIRECT Client */
+#define BSS_MODE_WIFIDIRECT_CLIENT 0
+/** BSS Mode: WIFIDIRECT GO */
+#define BSS_MODE_WIFIDIRECT_GO 2
+#endif
+/** HostCmd_DS_SET_BSS_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_SET_BSS_MODE {
+ /** connection type */
+ t_u8 con_type;
+} MLAN_PACK_END HostCmd_DS_SET_BSS_MODE;
+
+/** HT Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTCap_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END MrvlIETypes_HTCap_t;
+/** VHT Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_VHTCap_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** VHTCap struct */
+ VHT_capa_t vht_cap;
+} MLAN_PACK_END MrvlIETypes_VHTCap_t;
+
+/** HostCmd_DS_REMAIN_ON_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_REMAIN_ON_CHANNEL {
+ /** Action 0-GET, 1-SET, 4 CLEAR*/
+ t_u16 action;
+ /** Not used set to zero */
+ t_u8 status;
+ /** Not used set to zero */
+ t_u8 reserved;
+ /** Band cfg */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} MLAN_PACK_END HostCmd_DS_REMAIN_ON_CHANNEL;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** HostCmd_DS_WIFI_DIRECT_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_WIFI_DIRECT_MODE {
+ /** Action 0-GET, 1-SET*/
+ t_u16 action;
+ /**0:disable 1:listen 2:GO 3:p2p client 4:find 5:stop find*/
+ t_u16 mode;
+} MLAN_PACK_END HostCmd_DS_WIFI_DIRECT_MODE;
+
+/** MrvlIEtypes_NoA_setting_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_NoA_setting_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** enable/disable */
+ t_u8 enable;
+ /** index */
+ t_u16 index;
+ /** NoA count */
+ t_u8 noa_count;
+ /** NoA duration */
+ t_u32 noa_duration;
+ /** NoA interval */
+ t_u32 noa_interval;
+} MLAN_PACK_END MrvlIEtypes_NoA_setting_t;
+
+/** MrvlIEtypes_NoA_setting_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_OPP_PS_setting_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** enable/disable && ct_window */
+ t_u8 enable;
+} MLAN_PACK_END MrvlIEtypes_OPP_PS_setting_t;
+
+/** HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG {
+ /** Action 0-GET, 1-SET */
+ t_u16 action;
+ /** MrvlIEtypes_NoA_setting_t
+ * MrvlIEtypes_OPP_PS_setting_t
+ */
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG;
+#endif
+
+MLAN_PACK_START struct coalesce_filt_field_param {
+ t_u8 operation;
+ t_u8 operand_len;
+ t_u16 offset;
+ t_u8 operand_byte_stream[4];
+} MLAN_PACK_END;
+
+MLAN_PACK_START struct coalesce_receive_filt_rule {
+ MrvlIEtypesHeader_t header;
+ t_u8 num_of_fields;
+ t_u8 pkt_type;
+ t_u16 max_coalescing_delay;
+ struct coalesce_filt_field_param params[];
+} MLAN_PACK_END;
+
+/** HostCmd_DS_COALESCE_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_COALESCE_CONFIG {
+ /** Action 0-GET, 1-SET */
+ t_u16 action;
+ t_u16 num_of_rules;
+ struct coalesce_receive_filt_rule rule[];
+} MLAN_PACK_END HostCmd_DS_COALESCE_CONFIG;
+
+/** TLV type : FW support max connection TLV */
+#define TLV_TYPE_MAX_CONN (PROPRIETARY_TLV_BASE_ID + 0x117) /* 0x0217 */
+/** MrvlIEtypes_Max_Conn_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Max_Conn_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** FW support max P2P connection */
+ t_u8 max_p2p_conn;
+ /** FW support max STA connection */
+ t_u8 max_sta_conn;
+} MLAN_PACK_END MrvlIEtypes_Max_Conn_t;
+
+/** exceed max p2p connection event */
+typedef MLAN_PACK_START struct _event_exceed_max_p2p_conn {
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** When exceed max, the mac address who request p2p connect */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END event_exceed_max_p2p_conn;
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command process module to configure the firmware
+ * scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef MLAN_PACK_START struct _wlan_scan_cmd_config {
+ /**
+ * BSS Type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+
+ /**
+ * Specific BSSID used to filter scan results in the firmware
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+
+ /**
+ * Length of TLVs sent in command starting at tlvBuffer
+ */
+ t_u32 tlv_buf_len;
+
+ /**
+ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+ * TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+ */
+ t_u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored here */
+} MLAN_PACK_END wlan_scan_cmd_config;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef MLAN_PACK_START struct {
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry
+ * structures. Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} MLAN_PACK_END wlan_get_scan_table_info;
+
+/** Generic structure defined for parsing WPA/RSN IEs for GTK/PTK OUIs */
+typedef MLAN_PACK_START struct {
+ /** Group key oui */
+ t_u8 GrpKeyOui[4];
+ /** Number of PTKs */
+ t_u8 PtkCnt[2];
+ /** Ptk body starts here */
+ t_u8 PtkBody[4];
+} MLAN_PACK_END IEBody;
+#endif /* STA_SUPPORT */
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN {
+ /** BSS mode */
+ t_u8 bss_mode;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN;
+
+/** fw_cap_info bit to indicate enhance ext scan type */
+#define ENHANCE_EXT_SCAN_ENABLE MBIT(19)
+/** mlan_event_scan_result data structure */
+typedef MLAN_PACK_START struct _mlan_event_scan_result {
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** More event available or not */
+ t_u8 more_event;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** Size of the response buffer */
+ t_u16 buf_size;
+ /** Number of BSS in scan response */
+ t_u8 num_of_set;
+} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result;
+
+/** ext scan status report event */
+typedef MLAN_PACK_START struct _mlan_event_scan_status {
+ /** Event ID */
+ t_u16 event_id;
+ /** BSS index number for multiple BSS support */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** scan status */
+ t_u8 scan_status;
+ /** result */
+ t_u16 buf_len;
+ /** event buf */
+ t_u8 event_buf[];
+} MLAN_PACK_END mlan_event_scan_status, *pmlan_event_scan_status;
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for HostCmd_CMD_802_11_SCAN_EXT
+ */
+/** HostCmd_DS_802_11_SCAN_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_EXT {
+ /** Scan type for ext scan
+ * 0: default type: cmd resp after ext scan report event
+ * 1: enhanced type: cmd resp before ext scan report event
+ * 2: scan cancelled: cancel scan during scan processing
+ */
+ t_u8 ext_scan_type;
+ /** Reserved */
+ t_u8 reserved[3];
+ /** TLV buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_Bssid_List_t BssIdList;
+ * MrvlIEtypes_SsIdParamSet_t SSIDParamSet;
+ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
+ * MrvlIEtypes_RatesParamSet_t OpRateSet;
+ * MrvlIEtypes_NumProbes_t NumProbes;
+ * MrvlIEtypes_WildCardSsIdParamSet_t WildCardSSIDParamSet;
+ * MrvlIEtypes_BssMode_t BssMode;
+ */
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_EXT;
+
+/** MrvlIEtypes_BssMode */
+typedef MLAN_PACK_START struct _MrvlIEtypes_BssMode_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* INFRA/IBSS/AUTO */
+ t_u8 bss_mode;
+} MLAN_PACK_END MrvlIEtypes_BssMode_t;
+
+/** BSS scan Rsp */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Rsp_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSSID of the BSS descriptor */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon/Probe response buffer */
+ t_u8 frame_body[1];
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Rsp_t;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bss_Scan_Info_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** RSSI for scan entry */
+ t_s16 rssi;
+ /** Channel ANPI */
+ t_s16 anpi;
+ /** Channel load (parts per 255) */
+ t_u8 cca_busy_fraction;
+ /** Band */
+ Band_Config_t bandcfg;
+ /** Channel */
+ t_u8 channel;
+ /** Reserved */
+ t_u8 reserved;
+ /** TSF data */
+ t_u64 tsf;
+} MLAN_PACK_END MrvlIEtypes_Bss_Scan_Info_t;
+
+/** HostCmd_DS_RX_MGMT_IND */
+typedef MLAN_PACK_START struct _HostCmd_DS_RX_MGMT_IND {
+ /** Action */
+ t_u16 action;
+ /** Mgmt frame subtype mask */
+ t_u32 mgmt_subtype_mask;
+} MLAN_PACK_END HostCmd_DS_RX_MGMT_IND;
+
+/** HostCmd_DS_802_11_SCAN_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SCAN_RSP {
+ /** Size of BSS descriptor */
+ t_u16 bss_descript_size;
+ /** Numner of sets */
+ t_u8 number_of_sets;
+ /** BSS descriptor and TLV buffer */
+ t_u8 bss_desc_and_tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_CONFIG {
+ /** action */
+ t_u16 action;
+ /** 0: disable, 1: enable */
+ t_u8 enable;
+ /** bss type */
+ t_u8 bss_type;
+ /** num of channel per scan */
+ t_u8 chan_per_scan;
+ /** reserved field */
+ t_u8 reserved;
+ /** reserved field */
+ t_u16 reserved1;
+ /** interval between consecutive scans */
+ t_u32 scan_interval;
+ /** reserved field */
+ t_u32 reserved2;
+ /** condition to trigger report to host */
+ t_u32 report_condition;
+ /** reserved field */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_CONFIG;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY {
+ /** Flush */
+ t_u8 flush;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP {
+ /** Report condition */
+ t_u32 report_condition;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+} MLAN_PACK_END HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** MrvlIEtypes_StartLater_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_StartLater_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* 0 - BGScan start immediately, 1 - BGScan will start later after "Scan
+ * Interval" */
+ t_u16 value;
+} MLAN_PACK_END MrvlIEtypes_StartLater_t;
+
+/** MrvlIEtypes_RepeatCount_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RepeatCount_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /* Repeat count */
+ t_u16 repeat_count;
+} MLAN_PACK_END MrvlIEtypes_RepeatCount_t;
+
+/** MrvlIEtypes_DomainParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_DomainParamSet {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END MrvlIEtypes_DomainParamSet_t;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO {
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** HostCmd_DS_802_11D_DOMAIN_INFO_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP {
+ /** Action */
+ t_u16 action;
+ /** Domain parameter set */
+ MrvlIEtypes_DomainParamSet_t domain;
+} MLAN_PACK_END HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+/** HostCmd_DS_11N_ADDBA_REQ */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_REQ {
+ /** Result of the ADDBA Request Operation */
+ t_u8 add_req_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_REQ;
+
+/** HostCmd_DS_11N_ADDBA_RSP */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_ADDBA_RSP {
+ /** Result of the ADDBA Response Operation */
+ t_u8 add_rsp_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Dialog Token */
+ t_u8 dialog_token;
+ /** Status Code */
+ t_u16 status_code;
+ /** Block Ack Parameter Set */
+ t_u16 block_ack_param_set;
+ /** Block Act Timeout Value */
+ t_u16 block_ack_tmo;
+ /** Starting Sequence Number */
+ t_u16 ssn;
+} MLAN_PACK_END HostCmd_DS_11N_ADDBA_RSP;
+
+/** HostCmd_DS_11N_DELBA */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_DELBA {
+ /** Result of the ADDBA Request Operation */
+ t_u8 del_result;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u16 del_ba_param_set;
+ /** Reason Code sent for DELBA */
+ t_u16 reason_code;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END HostCmd_DS_11N_DELBA;
+
+/** HostCmd_DS_11N_BATIMEOUT */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_BATIMEOUT {
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Delete Block Ack Parameter Set */
+ t_u8 origninator;
+} MLAN_PACK_END HostCmd_DS_11N_BATIMEOUT;
+
+/** HostCmd_DS_11N_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11N_CFG {
+ /** Action */
+ t_u16 action;
+ /** HTTxCap */
+ t_u16 ht_tx_cap;
+ /** HTTxInfo */
+ t_u16 ht_tx_info;
+ /** Misc configuration */
+ t_u16 misc_config;
+} MLAN_PACK_END HostCmd_DS_11N_CFG;
+
+/** HostCmd_DS_11N_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_REJECT_ADDBA_REQ {
+ /** Action */
+ t_u16 action;
+ /** Bit0 : host sleep activated
+ * Bit1 : auto reconnect enabled
+ * Others : reserved
+ */
+ t_u32 conditions;
+} MLAN_PACK_END HostCmd_DS_REJECT_ADDBA_REQ;
+
+/** HostCmd_DS_TXBUF_CFG*/
+typedef MLAN_PACK_START struct _HostCmd_DS_TXBUF_CFG {
+ /** Action */
+ t_u16 action;
+ /** Buffer Size */
+ t_u16 buff_size;
+ /** End Port_for Multiport */
+ t_u16 mp_end_port;
+ /** Reserved */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_TXBUF_CFG;
+
+/** HostCmd_DS_AMSDU_AGGR_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_AMSDU_AGGR_CTRL {
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** Get the current Buffer Size valid */
+ t_u16 curr_buf_size;
+} MLAN_PACK_END HostCmd_DS_AMSDU_AGGR_CTRL;
+
+/** HostCmd_DS_11AC_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11AC_CFG {
+ /** Action */
+ t_u16 action;
+ /** BandConfig */
+ t_u8 band_config;
+ /** Misc Configuration */
+ t_u8 misc_config;
+ /** VHT Capability Info */
+ t_u32 vht_cap_info;
+ /** VHT Support MCS Set */
+ t_u8 vht_supp_mcs_set[VHT_MCS_SET_LEN];
+} MLAN_PACK_END HostCmd_DS_11AC_CFG;
+
+/** HostCmd_DS_11ACTXBUF_CFG*/
+typedef MLAN_PACK_START struct _HostCmd_DS_11ACTXBUF_CFG {
+ /** Action */
+ t_u16 action;
+ /** Buffer Size */
+ t_u16 buff_size;
+ /** End Port_for Multiport */
+ t_u16 mp_end_port;
+ /** Reserved */
+ t_u16 reserved3;
+} MLAN_PACK_END HostCmd_DS_11ACTXBUF_CFG;
+
+/** HostCmd_DS_11AX_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11AX_CFG {
+ /** Action */
+ t_u16 action;
+ /** BandConfig */
+ t_u8 band_config;
+ /** TLV for HE capability or HE operation */
+ t_u8 val[];
+} MLAN_PACK_END HostCmd_DS_11AX_CFG;
+
+/** HostCmd_DS_11AX_CMD_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_11AX_CMD_CFG {
+ /** Action */
+ t_u16 action;
+ /** CMD_SUBID */
+ t_u16 sub_id;
+ /** TLV or value for cmd */
+ t_u8 val[];
+} MLAN_PACK_END HostCmd_DS_11AX_CMD_CFG;
+
+/** HostCmd_DS_RANGE_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_RANGE_EXT {
+ /** Action */
+ t_u16 action;
+ /** Range ext mode */
+ t_u8 mode;
+} MLAN_PACK_END HostCmd_DS_RANGE_EXT;
+
+/** Type definition of hostcmd_twt_setup */
+typedef struct MLAN_PACK_START _hostcmd_twt_setup {
+ /** Implicit, 0: TWT session is explicit, 1: Session is implicit */
+ t_u8 implicit;
+ /** Announced, 0: Unannounced, 1: Announced TWT */
+ t_u8 announced;
+ /** Trigger Enabled, 0: Non-Trigger enabled, 1: Trigger enabled TWT */
+ t_u8 trigger_enabled;
+ /** TWT Information Disabled, 0: TWT info enabled, 1: TWT info disabled
+ */
+ t_u8 twt_info_disabled;
+ /** Negotiation Type, 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** TWT Wakeup Duration, time after which the TWT requesting STA can
+ * transition to doze state */
+ t_u8 twt_wakeup_duration;
+ /** Flow Identifier. Range: [0-7]*/
+ t_u8 flow_identifier;
+ /** Hard Constraint, 0: FW can tweak the TWT setup parameters if it is
+ *rejected by AP.
+ ** 1: Firmware should not tweak any parameters. */
+ t_u8 hard_constraint;
+ /** TWT Exponent, Range: [0-63] */
+ t_u8 twt_exponent;
+ /** TWT Mantissa Range: [0-sizeof(UINT16)] */
+ t_u16 twt_mantissa;
+ /** TWT Request Type, 0: REQUEST_TWT, 1: SUGGEST_TWT*/
+ t_u8 twt_request;
+ /** TWT Setup State. Set to 0 by driver, filled by FW in response*/
+ t_u8 twt_setup_state;
+ /** Reserved, set to 0. */
+ t_u8 reserved[2];
+} MLAN_PACK_END hostcmd_twt_setup, *phostcmd_twt_setup;
+
+/** Type definition of hostcmd_twt_teardown */
+typedef struct MLAN_PACK_START _hostcmd_twt_teardown {
+ /** TWT Flow Identifier. Range: [0-7] */
+ t_u8 flow_identifier;
+ /** Negotiation Type. 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** Tear down all TWT. 1: To teardown all TWT, 0 otherwise */
+ t_u8 teardown_all_twt;
+ /** TWT Teardown State. Set to 0 by driver, filled by FW in response */
+ t_u8 twt_teardown_state;
+ /** Reserved, set to 0. */
+ t_u8 reserved[3];
+} MLAN_PACK_END hostcmd_twt_teardown, *phostcmd_twt_teardown;
+
+/** HostCmd_DS_TWT_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TWT_CFG {
+ /** Action */
+ t_u16 action;
+ /** CMD_SUBID */
+ t_u16 sub_id;
+ /** TWT Setup/Teardown configuration parameters */
+ union {
+ /** TWT Setup config for Sub ID: MLAN_11AX_TWT_SETUP_SUBID */
+ hostcmd_twt_setup twt_setup;
+ /** TWT Teardown config for Sub ID: MLAN_11AX_TWT_TEARDOWN_SUBID
+ */
+ hostcmd_twt_teardown twt_teardown;
+ } param;
+} MLAN_PACK_END HostCmd_DS_TWT_CFG;
+
+/** HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG {
+ /** Action */
+ t_u16 action;
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Length of clocks */
+ t_u16 sys_clk_len;
+ /** System clocks */
+ t_u16 sys_clk[16];
+} MLAN_PACK_END HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WmmParamSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM IE */
+ t_u8 wmm_ie[1];
+} MLAN_PACK_END MrvlIEtypes_WmmParamSet_t;
+
+/** MrvlIEtypes_WmmQueueStatus_t */
+typedef MLAN_PACK_START struct {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Queue index */
+ t_u8 queue_index;
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Medium time allocation in 32us units*/
+ t_u16 medium_time;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END MrvlIEtypes_WmmQueueStatus_t;
+
+/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE 63
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES 256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS 7
+
+/**
+ * @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ * Used to retrieve the status of each WMM AC Queue in TLV
+ * format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ * parameter IE advertised by the AP.
+ *
+ * Used in response to a EVENT_WMM_STATUS_CHANGE event signaling
+ * a QOS change on one of the ACs or a change in the WMM Parameter in
+ * the Beacon.
+ *
+ * TLV based command, byte arrays used for max sizing purpose. There are no
+ * arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef MLAN_PACK_START struct {
+ /** Queue status TLV */
+ t_u8 queue_status_tlv[sizeof(MrvlIEtypes_WmmQueueStatus_t) *
+ MAX_AC_QUEUES];
+ /** WMM parameter TLV */
+ t_u8 wmm_param_tlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+} MLAN_PACK_END HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct {
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_status_code; /**< IEEE status code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+ t_u8 addts_extra_ie_buf[WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buffer
+ */
+} MLAN_PACK_END HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef MLAN_PACK_START struct {
+ mlan_cmd_result_e command_result; /**< Command result */
+ t_u8 dialog_token; /**< Dialog token */
+ t_u8 ieee_reason_code; /**< IEEE reason code */
+ t_u8 tspec_data[WMM_TSPEC_SIZE]; /**< TSPEC data */
+} MLAN_PACK_END HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ * Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ */
+typedef MLAN_PACK_START struct {
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ /** @brief MSDU lifetime expiry per 802.11e
+ *
+ * - Ignored if 0 on a set command
+ * - Set to the 802.11e specified 500 TUs when defaulted
+ */
+ t_u16 msdu_lifetime_expiry;
+ t_u8 tlv_buffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; /**< Not supported */
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ * Turn statistical collection on/off for a given AC or retrieve the
+ * accumulated stats for an AC and clear them in the firmware.
+ */
+typedef MLAN_PACK_START struct {
+ mlan_wmm_queue_stats_action_e action; /**< Start, Stop, or Get */
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 select_bin : 7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+ t_u8 select_is_userpri : 1; /**< Set if select_bin is UP, Clear for AC
+ */
+#else
+ t_u8 select_is_userpri : 1; /**< Set if select_bin is UP, Clear for AC
+ */
+ t_u8 select_bin : 7; /**< WMM_AC_BK(0) to WMM_AC_VO(3), or TID */
+#endif
+ t_u16 pkt_count; /**< Number of successful packets transmitted */
+ t_u16 pkt_loss; /**< Packets lost; not included in pktCount */
+ t_u32 avg_queue_delay; /**< Average Queue delay in microsec */
+ t_u32 avg_tx_delay; /**< Average Transmission delay in microsec */
+ t_u16 used_time; /**< Calc used time - units of 32 microsec */
+ t_u16 policed_time; /**< Calc policed time - units of 32 microsec */
+ /** @brief Queue Delay Histogram; number of packets per queue delay
+ * range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[WMM_STATS_PKTS_HIST_BINS];
+ /** Reserved */
+ t_u16 reserved_1;
+} MLAN_PACK_END HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ * @brief Command structure for the HostCmd_CMD_WMM_TS_STATUS firmware cmd
+ *
+ * Query the firmware to get the status of the WMM Traffic Streams
+ */
+typedef MLAN_PACK_START struct {
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Uplink(1), Downlink(2), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END HostCmd_DS_WMM_TS_STATUS;
+
+/** Firmware status for a specific AC */
+typedef MLAN_PACK_START struct {
+ /** Disabled flag */
+ t_u8 disabled;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+} MLAN_PACK_END WmmAcStatus_t;
+
+/** Local Power Capability */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PowerCapability_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Minmum power */
+ t_s8 min_power;
+ /** Maximum power */
+ t_s8 max_power;
+} MLAN_PACK_END MrvlIEtypes_PowerCapability_t;
+
+/** HT Information element */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTInfo_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END MrvlIETypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence element */
+typedef MLAN_PACK_START struct _MrvlIETypes_2040BSSCo_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END MrvlIETypes_2040BSSCo_t;
+
+/** Extended Capabilities element */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtCap_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END MrvlIETypes_ExtCap_t;
+
+/** Supported operating classes element */
+typedef MLAN_PACK_START struct _MrvlIETypes_SuppOperClass_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Current operationg class **/
+ t_u8 current_oper_class;
+ /** Operating class list */
+ t_u8 oper_class[1];
+} MLAN_PACK_END MrvlIETypes_SuppOperClass_t;
+
+/** Oper_class channel bandwidth element */
+typedef MLAN_PACK_START struct _MrvlIEtypes_chan_bw_oper_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** channel oper bandwidth*/
+ mlan_ds_bw_chan_oper ds_chan_bw_oper;
+} MLAN_PACK_END MrvlIEtypes_chan_bw_oper_t;
+
+/** Qos Info */
+typedef MLAN_PACK_START struct _MrvlIETypes_qosinfo_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** qos_info*/
+ t_u8 qos_info;
+} MLAN_PACK_END MrvlIETypes_qosinfo_t;
+
+/** Overlapping BSS Scan Parameters element */
+typedef MLAN_PACK_START struct _MrvlIETypes_OverlapBSSScanParam_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END MrvlIETypes_OverlapBSSScanParam_t;
+
+/** Set of MCS values that STA desires to use within the BSS */
+typedef MLAN_PACK_START struct _MrvlIETypes_HTOperationalMCSSet_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** Bitmap indicating MCSs that STA desires to use within the BSS */
+ t_u8 ht_operational_mcs_bitmap[16];
+} MLAN_PACK_END MrvlIETypes_HTOperationalMCSSet_t;
+
+/** VHT Operations IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_VHTOprat_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ t_u8 chan_width;
+ t_u8 chan_center_freq_1;
+ t_u8 chan_center_freq_2;
+ /** Basic MCS set map, each 2 bits stands for a Nss */
+ t_u16 basic_MCS_map;
+} MLAN_PACK_END MrvlIETypes_VHTOprat_t;
+
+/** VHT Transmit Power Envelope IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_VHTtxpower_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ t_u8 max_tx_power;
+ t_u8 chan_center_freq;
+ t_u8 chan_width;
+} MLAN_PACK_END MrvlIETypes_VHTtxpower_t;
+
+/** Extended Power Constraint IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtPwerCons_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** channel width */
+ t_u8 chan_width;
+ /** local power constraint */
+ t_u8 local_power_cons;
+} MLAN_PACK_END MrvlIETypes_ExtPwerCons_t;
+
+/** Extended BSS Load IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_ExtBSSload_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ t_u8 MU_MIMO_capa_count;
+ t_u8 stream_underutilization;
+ t_u8 VHT40_util;
+ t_u8 VHT80_util;
+ t_u8 VHT160_util;
+} MLAN_PACK_END MrvlIETypes_ExtBSSload_t;
+
+/** Quiet Channel IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_QuietChan_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ t_u8 AP_quiet_mode;
+ t_u8 quiet_count;
+ t_u8 quiet_period;
+ t_u16 quiet_dur;
+ t_u16 quiet_offset;
+} MLAN_PACK_END MrvlIETypes_QuietChan_t;
+
+/** Wide Bandwidth Channel Switch IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_BWSwitch_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ t_u8 new_chan_width;
+ t_u8 new_chan_center_freq_1;
+ t_u8 new_chan_center_freq_2;
+} MLAN_PACK_END MrvlIETypes_BWSwitch_t;
+
+/** AID IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_AID_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** AID number */
+ t_u16 AID;
+} MLAN_PACK_END MrvlIETypes_AID_t;
+
+/** Operating Mode Notification IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_OperModeNtf_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** operating mdoe */
+ t_u8 oper_mode;
+} MLAN_PACK_END MrvlIETypes_OperModeNtf_t;
+
+/** bf global args */
+typedef struct MLAN_PACK_START _bf_global_cfg_args {
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} MLAN_PACK_END bf_global_cfg_args;
+
+/** bf_trigger_sound_args_t */
+typedef MLAN_PACK_START struct _bf_trigger_sound_args_t {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_trigger_sound_args_t;
+
+/** bf periodicity args */
+typedef MLAN_PACK_START struct _bf_periodicity_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} MLAN_PACK_END bf_periodicity_args;
+
+/** bf peer configuration args */
+typedef struct MLAN_PACK_START _bf_peer_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} MLAN_PACK_END bf_peer_args;
+
+/** bf_snr_thr_t */
+typedef MLAN_PACK_START struct _bf_snr_thr_t {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR */
+ t_u8 snr;
+} MLAN_PACK_END bf_snr_thr_t;
+
+/** HostCmd_DS_TX_BF_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_BF_CFG {
+ /* Beamforming action */
+ t_u16 bf_action;
+ /* action - SET/GET*/
+ t_u16 action;
+
+ MLAN_PACK_START union {
+ bf_global_cfg_args bf_global_cfg;
+ bf_trigger_sound_args_t bf_sound_args;
+ bf_periodicity_args bf_periodicity;
+ bf_peer_args tx_bf_peer;
+ bf_snr_thr_t bf_snr;
+ } MLAN_PACK_END body;
+} MLAN_PACK_END HostCmd_DS_TX_BF_CFG;
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** MrvlIEtypes_psk_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_psk_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PSK */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_psk_t;
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** MrvlIEtypes_PMK_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PMK_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PMK */
+ t_u8 pmk[1];
+} MLAN_PACK_END MrvlIEtypes_PMK_t;
+
+/** MrvlIEtypes_Passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Passphrase_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Passphrase */
+ char passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_Passphrase_t;
+
+/** MrvlIEtypes_SAE_Password_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_SAE_Password_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** SAE Password */
+ char sae_password[1];
+} MLAN_PACK_END MrvlIEtypes_SAE_Password_t;
+
+/* rsnMode -
+ * Bit 0 : No RSN
+ * Bit 1-2 : RFU
+ * Bit 3 : WPA
+ * Bit 4 : WPA-NONE
+ * Bit 5 : WPA2
+ * Bit 6 : AES CCKM
+ * Bit 7-15 : RFU
+ */
+/** MrvlIEtypes_EncrProto_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_EncrProto_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** EncrProto */
+ t_u16 rsn_mode;
+} MLAN_PACK_END MrvlIEtypes_EncrProto_t;
+
+/** MrvlIEtypes_Bssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Bssid_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_Bssid_t;
+
+/*
+ * This struct will handle GET,SET,CLEAR function for embedded
+ * supplicant.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PMK
+ */
+/** HostCmd_DS_802_11_SUPPLICANT_PMK */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PMK {
+ /** CMD Action GET/SET/CLEAR */
+ t_u16 action;
+ /** CacheResult initialized to 0 */
+ t_u16 cache_result;
+ /** TLV Buffer */
+ t_u8 tlv_buffer[1];
+ /** MrvlIEtypes_SsidParamSet_t SsidParamSet;
+ * MrvlIEtypes_PMK_t Pmk;
+ * MrvlIEtypes_Passphrase_t Passphrase;
+ * MrvlIEtypes_Bssid_t Bssid;
+ **/
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PMK;
+
+/*
+ * This struct will GET the Supplicant supported bitmaps
+ * The GET_CURRENT action will get the network profile used
+ * for the current assocation.
+ * Define data structure for HostCmd_CMD_802_11_SUPPLICANT_PROFILE
+ */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_SUPPLICANT_PROFILE {
+ /** GET/SET/GET_CURRENT */
+ t_u16 action;
+ /** Reserved */
+ t_u16 reserved;
+ /** TLVBuffer */
+ t_u8 tlv_buf[1];
+ /* MrvlIEtypes_EncrProto_t */
+} MLAN_PACK_END HostCmd_DS_802_11_SUPPLICANT_PROFILE;
+
+/* unicastCipher -
+ * Bit 0 : RFU
+ * Bit 1 : RFU
+ * Bit 2 : TKIP
+ * Bit 3 : AES CCKM
+ * Bit 2-7 : RFU
+ * multicastCipher -
+ * Bit 0 : WEP40
+ * Bit 1 : WEP104
+ * Bit 2 : TKIP
+ * Bit 3 : AES
+ * Bit 4-7 : Reserved for now
+ */
+/** MrvlIEtypes_Cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Cipher_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END MrvlIEtypes_Cipher_t;
+
+/** RFType */
+typedef MLAN_PACK_START struct _RFType_t {
+ /** band info */
+ Band_Config_t bandcfg;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END RFType_t;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_CHANNEL {
+ /** Action */
+ t_u16 action;
+ /** Current channel */
+ t_u16 current_channel;
+ /** RF type */
+ RFType_t rf_type;
+ /** Reserved field */
+ t_u16 reserved;
+#ifdef STA_SUPPORT
+ /** Reserved */
+ t_u8 reserved_1[32];
+#else /* STA_SUPPORT */
+ /** List of channels */
+ t_u8 channel_list[32];
+#endif /* !STA_SUPPORT */
+} MLAN_PACK_END HostCmd_DS_802_11_RF_CHANNEL;
+
+/** HostCmd_DS_VERSION_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_VERSION_EXT {
+ /** Selected version string */
+ t_u8 version_str_sel;
+ /** Version string */
+ char version_str[128];
+} MLAN_PACK_END HostCmd_DS_VERSION_EXT;
+
+#define TLV_TYPE_CHAN_ATTR_CFG (PROPRIETARY_TLV_BASE_ID + 237)
+#define TLV_TYPE_REGION_INFO (PROPRIETARY_TLV_BASE_ID + 238)
+#define TLV_TYPE_POWER_TABLE (PROPRIETARY_TLV_BASE_ID + 262)
+#define TLV_TYPE_POWER_TABLE_ATTR (PROPRIETARY_TLV_BASE_ID + 317)
+/** HostCmd_DS_CHAN_REGION_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CHAN_REGION_CFG {
+ /** Action */
+ t_u16 action;
+} MLAN_PACK_END HostCmd_DS_CHAN_REGION_CFG;
+
+/** HostCmd_CMD_CW_MODE_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_CW_MODE_CTRL {
+ /** Action for CW Tone Control */
+ t_u16 action;
+ /** Mode of Operation 0: Disbale 1: Tx Continuous Packet 2: Tx
+ * Continuous Wave */
+ t_u8 mode;
+ /** channel */
+ t_u8 channel;
+ /** channel info*/
+ t_u8 chanInfo;
+ /** Tx Power level in dBm */
+ t_u16 txPower;
+ /** Packet Length */
+ t_u16 pktLength;
+ /** bit rate Info */
+ t_u32 rateInfo;
+} MLAN_PACK_END HostCmd_DS_CW_MODE_CTRL;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_RF_ANTENNA {
+ /** Action for Tx antenna */
+ t_u16 action_tx;
+ /** Tx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 tx_antenna_mode;
+ /** Action for Rx antenna */
+ t_u16 action_rx;
+ /** Rx antenna mode Bit0:1, Bit1:2, Bit0-1:1+2, 0xffff: diversity */
+ t_u16 rx_antenna_mode;
+} MLAN_PACK_END HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_DS_802_11_IBSS_STATUS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_IBSS_STATUS {
+ /** Action */
+ t_u16 action;
+ /** Enable */
+ t_u16 enable;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Beacon interval */
+ t_u16 beacon_interval;
+ /** ATIM window interval */
+ t_u16 atim_window;
+ /** User G rate protection */
+ t_u16 use_g_rate_protect;
+} MLAN_PACK_END HostCmd_DS_802_11_IBSS_STATUS;
+
+/** HostCmd_DS_MGMT_IE_LIST_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_MGMT_IE_LIST {
+ /** Action */
+ t_u16 action;
+ /** Get/Set mgmt IE */
+ mlan_ds_misc_custom_ie ds_mgmt_ie;
+} MLAN_PACK_END HostCmd_DS_MGMT_IE_LIST_CFG;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MAC_REG_ACCESS {
+ /** Action */
+ t_u16 action;
+ /** MAC register offset */
+ t_u16 offset;
+ /** MAC register value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BCA_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_BCA_REG_ACCESS {
+ /** Action */
+ t_u16 action;
+ /** BCA register offset */
+ t_u16 offset;
+ /** BCA register value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_BCA_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_BBP_REG_ACCESS {
+ /** Acion */
+ t_u16 action;
+ /** BBP register offset */
+ t_u16 offset;
+ /** BBP register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_BBP_REG_ACCESS;
+
+/** HostCmd_CMD_RF_REG_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_RF_REG_ACCESS {
+ /** Action */
+ t_u16 action;
+ /** RF register offset */
+ t_u16 offset;
+ /** RF register value */
+ t_u8 value;
+ /** Reserved field */
+ t_u8 reserved[3];
+} MLAN_PACK_END HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_EEPROM_ACCESS {
+ /** Action */
+ t_u16 action;
+
+ /** multiple 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value;
+} MLAN_PACK_END HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_MEM_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_MEM_ACCESS {
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} MLAN_PACK_END HostCmd_DS_MEM_ACCESS;
+
+/** HostCmd_DS_TARGET_ACCESS */
+typedef MLAN_PACK_START struct _HostCmd_DS_TARGET_ACCESS {
+ /** Action */
+ t_u16 action;
+ /** CSU Target Device. 1: CSU, 2: PSU */
+ t_u16 csu_target;
+ /** Target Device Address */
+ t_u16 address;
+ /** Data */
+ t_u8 data;
+} MLAN_PACK_END HostCmd_DS_TARGET_ACCESS;
+
+/** HostCmd_DS_SUBSCRIBE_EVENT */
+typedef MLAN_PACK_START struct _HostCmd_DS_SUBSCRIBE_EVENT {
+ /** Action */
+ t_u16 action;
+ /** Bitmap of subscribed events */
+ t_u16 event_bitmap;
+} MLAN_PACK_END HostCmd_DS_SUBSCRIBE_EVENT;
+
+/** HostCmd_DS_OTP_USER_DATA */
+typedef MLAN_PACK_START struct _HostCmd_DS_OTP_USER_DATA {
+ /** Action */
+ t_u16 action;
+ /** Reserved field */
+ t_u16 reserved;
+ /** User data length */
+ t_u16 user_data_length;
+ /** User data */
+ t_u8 user_data[1];
+} MLAN_PACK_END HostCmd_DS_OTP_USER_DATA;
+
+/** HostCmd_CMD_HS_WAKEUP_REASON */
+typedef MLAN_PACK_START struct _HostCmd_DS_HS_WAKEUP_REASON {
+ /** wakeupReason:
+ * 0: unknown
+ * 1: Broadcast data matched
+ * 2: Multicast data matched
+ * 3: Unicast data matched
+ * 4: Maskable event matched
+ * 5. Non-maskable event matched
+ * 6: Non-maskable condition matched (EAPoL rekey)
+ * 7: Magic pattern matched
+ * Others: reserved. (set to 0) */
+ t_u16 wakeup_reason;
+} MLAN_PACK_END HostCmd_DS_HS_WAKEUP_REASON;
+
+/** MrvlIEtypes_HsWakeHoldoff_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_HsWakeHoldoff_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Minimum delay between HsActive and HostWake (in msec) */
+ t_u16 min_wake_holdoff;
+} MLAN_PACK_END MrvlIEtypes_HsWakeHoldoff_t;
+
+/** MrvlIEtypes_PsParamsInHs_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_PsParamsInHs_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Host sleep wake interval(in msec) */
+ t_u32 hs_wake_interval;
+ /** Host sleep inactivity timeout (in msec) */
+ t_u32 hs_inactivity_timeout;
+} MLAN_PACK_END MrvlIEtypes_PsParamsInHs_t;
+
+/** MrvlIEtypes_WakeupSourceGPIO_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_WakeupSourceGPIO_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** GPIO for indication of wakeup source */
+ t_u8 ind_gpio;
+ /** Level on ind_gpio for normal wakeup source */
+ t_u8 level;
+} MLAN_PACK_END MrvlIEtypes_WakeupSourceGPIO_t;
+
+/** MrvlIEtypes_RobustcoexSourceGPIO_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_RobustcoexSourceGPIO_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** GPIO cfg for external bt request */
+ t_u8 enable;
+ /** GPIO number */
+ t_u8 gpio_num;
+ /** GPIO Polarity */
+ t_u8 gpio_polarity;
+} MLAN_PACK_END MrvlIEtypes_RobustcoexSourceGPIO_t;
+
+#define MAX_NUM_MAC 2
+
+typedef MLAN_PACK_START struct _dmcs_chan_status {
+ /** Channel number */
+ t_u8 channel;
+ /** Number of AP on this channel */
+ t_u8 ap_count;
+ /** Number of STA on this channel*/
+ t_u8 sta_count;
+} MLAN_PACK_END dmcs_chan_status;
+
+typedef MLAN_PACK_START struct _dmcs_status {
+ /** radio ID */
+ t_u8 radio_id;
+ /** Running mode
+ ** 0 - Idle
+ ** 1 - DBC
+ ** 2 - DRCS
+ */
+ t_u8 running_mode;
+ /** Channel status of this radio */
+ dmcs_chan_status chan_status[2];
+} MLAN_PACK_END dmcs_status;
+
+/** MrvlIEtypes_DmcsConfig_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_DmcsConfig_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Mapping policy */
+ t_u8 mapping_policy;
+ /** Radio status of DMCS */
+ dmcs_status radio_status[MAX_NUM_MAC];
+} MLAN_PACK_END MrvlIEtypes_DmcsStatus_t;
+
+#define ANTMODE_FW_DECISION 0xff
+/** MrvlIEtypes_HS_Antmode_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_HS_Antmode_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Tx Path antenna mode*/
+ t_u8 txpath_antmode;
+ /** Rx Path antenna mode */
+ t_u8 rxpath_antmode;
+} MLAN_PACK_END MrvlIEtypes_HS_Antmode_t;
+
+typedef MLAN_PACK_START struct _MrvlIEtypes_WakeupExtend_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Events that will be forced ignore **/
+ t_u32 event_force_ignore;
+ /** Events that will use extend gap to inform host*/
+ t_u32 event_use_ext_gap;
+ /** Extend gap*/
+ t_u8 ext_gap;
+ /** GPIO wave level*/
+ t_u8 gpio_wave;
+} MLAN_PACK_END MrvlIEtypes_WakeupExtend_t;
+
+#define EVENT_MANAGEMENT_FRAME_WAKEUP 136
+typedef MLAN_PACK_START struct _mgmt_frame_filter {
+ /** action - bitmap
+ ** On matching rx'd pkt and filter during NON_HOSTSLEEP mode:
+ ** Action[1]=0 Discard
+ ** Action[1]=1 Allow
+ ** Note that default action on non-match is "Allow".
+ **
+ ** On matching rx'd pkt and filter during HOSTSLEEP mode:
+ ** Action[1:0]=00 Discard and Not Wake host
+ ** Action[1:0]=01 Discard and Wake host
+ ** Action[1:0]=10 Invalid
+ ** Note that default action on non-match is "Discard and Not Wake
+ *host".
+ **/
+ t_u8 action;
+ /** Frame type(p2p...)
+ ** type=0: invalid
+ ** type=1: p2p
+ ** type=0xff: management frames(assoc req/rsp, probe req/rsp,...)
+ ** type=others: reserved
+ **/
+ t_u8 type;
+ /** Frame mask according to each type
+ ** When type=1 for p2p, frame-mask have following define:
+ ** Bit Frame
+ ** 0 GO Negotiation Request
+ ** 1 GO Negotiation Response
+ ** 2 GO Negotiation Confirmation
+ ** 3 P2P Invitation Request
+ ** 4 P2P Invitation Response
+ ** 5 Device Discoverability Request
+ ** 6 Device Discoverability Response
+ ** 7 Provision Discovery Request
+ ** 8 Provision Discovery Response
+ ** 9 Notice of Absence
+ ** 10 P2P Presence Request
+ ** 11 P2P Presence Response
+ ** 12 GO Discoverability Request
+ ** 13-31 Reserved
+ **
+ ** When type=others, frame-mask is reserved.
+ **/
+ t_u32 frame_mask;
+} MLAN_PACK_END mgmt_frame_filter;
+
+#define MAX_MGMT_FRAME_FILTER 2
+/** MrvlIEtypes_MgmtFrameFilter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_MgmtFrameFilter_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** management frame filters */
+ mgmt_frame_filter filter[MAX_MGMT_FRAME_FILTER];
+} MLAN_PACK_END MrvlIEtypes_MgmtFrameFilter_t;
+
+/** HostCmd_DS_INACTIVITY_TIMEOUT_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_INACTIVITY_TIMEOUT_EXT {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** uS, 0 means 1000uS(1ms) */
+ t_u16 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u16 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u16 mcast_timeout;
+ /** Timeout for additional RX traffic after Null PM1 packet exchange */
+ t_u16 ps_entry_timeout;
+ /** Reserved to further expansion */
+ t_u16 reserved;
+} MLAN_PACK_END HostCmd_DS_INACTIVITY_TIMEOUT_EXT;
+
+/** HostCmd_DS_INDEPENDENT_RESET_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_INDEPENDENT_RESET_CFG {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** out band independent reset */
+ t_u8 ir_mode;
+ /** gpio pin */
+ t_u8 gpio_pin;
+} MLAN_PACK_END HostCmd_DS_INDEPENDENT_RESET_CFG;
+
+/** HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT */
+typedef MLAN_PACK_START struct _HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** ps inactivity timeout value */
+ t_u16 inact_tmo;
+} MLAN_PACK_END HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT;
+
+/** TLV type : STA Mac address */
+#define TLV_TYPE_STA_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x20) /* 0x0120 */
+
+#define TLV_TYPE_RANDOM_MAC (PROPRIETARY_TLV_BASE_ID + 0xEC) /*0x01EC*/
+
+/** MrvlIEtypes_MacAddr_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_MacAddr_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END MrvlIEtypes_MacAddr_t;
+
+/** Assoc Request */
+#define SUBTYPE_ASSOC_REQUEST 0
+/** ReAssoc Request */
+#define SUBTYPE_REASSOC_REQUEST 2
+/** Probe Resp */
+#define SUBTYPE_PROBE_RESP 5
+/** Disassoc Request */
+#define SUBTYPE_DISASSOC 10
+/** Auth Request */
+#define SUBTYPE_AUTH 11
+/** Deauth Request */
+#define SUBTYPE_DEAUTH 12
+/** Action frame */
+#define SUBTYPE_ACTION 13
+/** beacon */
+#define SUBTYPE_BEACON 8
+
+#ifdef UAP_SUPPORT
+/** TLV type : AP Channel band Config */
+#define TLV_TYPE_UAP_CHAN_BAND_CONFIG \
+ (PROPRIETARY_TLV_BASE_ID + 0x2a) /* 0x012a */
+/** TLV type : AP Mac address */
+#define TLV_TYPE_UAP_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 0x2b) /* 0x012b */
+/** TLV type : AP Beacon period */
+#define TLV_TYPE_UAP_BEACON_PERIOD \
+ (PROPRIETARY_TLV_BASE_ID + 0x2c) /* 0x012c \
+ */
+/** TLV type : AP DTIM period */
+#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 0x2d) /* 0x012d */
+/** TLV type : AP Tx power */
+#define TLV_TYPE_UAP_TX_POWER (PROPRIETARY_TLV_BASE_ID + 0x2f) /* 0x012f */
+/** TLV type : AP SSID broadcast control */
+#define TLV_TYPE_UAP_BCAST_SSID_CTL \
+ (PROPRIETARY_TLV_BASE_ID + 0x30) /* 0x0130 */
+/** TLV type : AP Preamble control */
+#define TLV_TYPE_UAP_PREAMBLE_CTL \
+ (PROPRIETARY_TLV_BASE_ID + 0x31) /* 0x0131 \
+ */
+/** TLV type : AP Antenna control */
+#define TLV_TYPE_UAP_ANTENNA_CTL (PROPRIETARY_TLV_BASE_ID + 0x32) /* 0x0132 */
+/** TLV type : AP RTS threshold */
+#define TLV_TYPE_UAP_RTS_THRESHOLD \
+ (PROPRIETARY_TLV_BASE_ID + 0x33) /* 0x0133 \
+ */
+/** TLV type : AP Tx data rate */
+#define TLV_TYPE_UAP_TX_DATA_RATE \
+ (PROPRIETARY_TLV_BASE_ID + 0x35) /* 0x0135 \
+ */
+/** TLV type: AP Packet forwarding control */
+#define TLV_TYPE_UAP_PKT_FWD_CTL (PROPRIETARY_TLV_BASE_ID + 0x36) /* 0x0136 */
+/** TLV type: STA information */
+#define TLV_TYPE_UAP_STA_INFO (PROPRIETARY_TLV_BASE_ID + 0x37) /* 0x0137 */
+/** TLV type: AP STA MAC address filter */
+#define TLV_TYPE_UAP_STA_MAC_ADDR_FILTER \
+ (PROPRIETARY_TLV_BASE_ID + 0x38) /* 0x0138 */
+/** TLV type: AP STA ageout timer */
+#define TLV_TYPE_UAP_STA_AGEOUT_TIMER \
+ (PROPRIETARY_TLV_BASE_ID + 0x39) /* 0x0139 */
+/** TLV type: AP WEP keys */
+#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 0x3b) /* 0x013b */
+/** TLV type: AP WPA passphrase */
+#define TLV_TYPE_UAP_WPA_PASSPHRASE \
+ (PROPRIETARY_TLV_BASE_ID + 0x3c) /* 0x013c */
+/** TLV type: AP protocol */
+#define TLV_TYPE_UAP_ENCRYPT_PROTOCOL \
+ (PROPRIETARY_TLV_BASE_ID + 0x40) /* 0x0140 */
+/** TLV type: AP AKMP */
+#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 0x41) /* 0x0141 */
+/** TLV type: AP Fragment threshold */
+#define TLV_TYPE_UAP_FRAG_THRESHOLD \
+ (PROPRIETARY_TLV_BASE_ID + 0x46) /* 0x0146 */
+/** TLV type: AP Group rekey timer */
+#define TLV_TYPE_UAP_GRP_REKEY_TIME \
+ (PROPRIETARY_TLV_BASE_ID + 0x47) /* 0x0147 */
+/**TLV type : AP Max Station number */
+#define TLV_TYPE_UAP_MAX_STA_CNT (PROPRIETARY_TLV_BASE_ID + 0x55) /* 0x0155 */
+/**TLV type : AP Max Station number per chip */
+#define TLV_TYPE_UAP_MAX_STA_CNT_PER_CHIP \
+ (PROPRIETARY_TLV_BASE_ID + 0x140) /* 0x0240 */
+/**TLV type : AP Retry limit */
+#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 0x5d) /* 0x015d */
+/** TLV type : AP MCBC data rate */
+#define TLV_TYPE_UAP_MCBC_DATA_RATE \
+ (PROPRIETARY_TLV_BASE_ID + 0x62) /* 0x0162 */
+/**TLV type: AP RSN replay protection */
+#define TLV_TYPE_UAP_RSN_REPLAY_PROTECT \
+ (PROPRIETARY_TLV_BASE_ID + 0x64) /* 0x0164 */
+/**TLV type: AP mgmt IE passthru mask */
+#define TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK \
+ (PROPRIETARY_TLV_BASE_ID + 0x70) /* 0x0170 */
+
+/**TLV type: AP pairwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT \
+ (PROPRIETARY_TLV_BASE_ID + 0x75) /* 0x0175 */
+/**TLV type: AP pairwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES \
+ (PROPRIETARY_TLV_BASE_ID + 0x76) /* 0x0176 */
+/**TLV type: AP groupwise handshake timeout */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT \
+ (PROPRIETARY_TLV_BASE_ID + 0x77) /* 0x0177 */
+/**TLV type: AP groupwise handshake retries */
+#define TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES \
+ (PROPRIETARY_TLV_BASE_ID + 0x78) /* 0x0178 */
+/** TLV type: AP PS STA ageout timer */
+#define TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER \
+ (PROPRIETARY_TLV_BASE_ID + 0x7b) /* 0x017b */
+/** TLV type : Pairwise Cipher */
+#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x91) /* 0x0191 */
+/** TLV type : Group Cipher */
+#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 0x92) /* 0x0192 */
+/** TLV type : BSS Status */
+#define TLV_TYPE_BSS_STATUS (PROPRIETARY_TLV_BASE_ID + 0x93) /* 0x0193 */
+/** TLV type : AP WMM params */
+#define TLV_TYPE_AP_WMM_PARAM (PROPRIETARY_TLV_BASE_ID + 0xd0) /* 0x01d0 */
+/** TLV type : AP Tx beacon rate */
+#define TLV_TYPE_UAP_TX_BEACON_RATE \
+ (PROPRIETARY_TLV_BASE_ID + 288) /* 0x0220 \
+ */
+
+/** MrvlIEtypes_beacon_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_beacon_period_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** beacon period */
+ t_u16 beacon_period;
+} MLAN_PACK_END MrvlIEtypes_beacon_period_t;
+
+/** MrvlIEtypes_dtim_period_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_dtim_period_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** DTIM period */
+ t_u8 dtim_period;
+} MLAN_PACK_END MrvlIEtypes_dtim_period_t;
+
+/** MrvlIEtypes_tx_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_rate_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx data rate */
+ t_u16 tx_data_rate;
+} MLAN_PACK_END MrvlIEtypes_tx_rate_t;
+
+/** MrvlIEtypes_mcbc_rate_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mcbc_rate_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mcbc data rate */
+ t_u16 mcbc_data_rate;
+} MLAN_PACK_END MrvlIEtypes_mcbc_rate_t;
+
+/** MrvlIEtypes_tx_power_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_tx_power_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** tx power */
+ t_u8 tx_power;
+} MLAN_PACK_END MrvlIEtypes_tx_power_t;
+
+/** MrvlIEtypes_bcast_ssid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bcast_ssid_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** bcast ssid control*/
+ t_u8 bcast_ssid_ctl;
+} MLAN_PACK_END MrvlIEtypes_bcast_ssid_t;
+
+/** MrvlIEtypes_antenna_mode_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_antenna_mode_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** which antenna */
+ t_u8 which_antenna;
+ /** antenna mode*/
+ t_u8 antenna_mode;
+} MLAN_PACK_END MrvlIEtypes_antenna_mode_t;
+
+/** MrvlIEtypes_pkt_forward_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pkt_forward_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pkt foward control */
+ t_u8 pkt_forward_ctl;
+} MLAN_PACK_END MrvlIEtypes_pkt_forward_t;
+
+/** MrvlIEtypes_max_sta_count_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_max_sta_count_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** max station count */
+ t_u16 max_sta_count;
+} MLAN_PACK_END MrvlIEtypes_max_sta_count_t;
+
+/** MrvlIEtypes_uap_max_sta_cnt */
+typedef MLAN_PACK_START struct _MrvlIEtypes_uap_max_sta_cnt_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** max station count */
+ t_u16 uap_max_sta;
+} MLAN_PACK_END MrvlIEtypes_uap_max_sta_cnt_t;
+
+/** MrvlIEtypes_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_ageout_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_sta_ageout_t;
+
+/** MrvlIEtypes_rts_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rts_threshold_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rts threshold */
+ t_u16 rts_threshold;
+} MLAN_PACK_END MrvlIEtypes_rts_threshold_t;
+
+/** MrvlIEtypes_frag_threshold_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_frag_threshold_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** frag threshold */
+ t_u16 frag_threshold;
+} MLAN_PACK_END MrvlIEtypes_frag_threshold_t;
+
+/** MrvlIEtypes_retry_limit_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_retry_limit_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** retry limit */
+ t_u8 retry_limit;
+} MLAN_PACK_END MrvlIEtypes_retry_limit_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_timeout_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_pwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pwk_hsk_retries_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_pwk_hsk_retries_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_timeout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_timeout_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_timeout_t;
+
+/** MrvlIEtypes_eapol_gwk_hsk_retries_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_gwk_hsk_retries_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+} MLAN_PACK_END MrvlIEtypes_eapol_gwk_hsk_retries_t;
+
+/** MrvlIEtypes_mgmt_ie_passthru_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mgmt_ie_passthru_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** mgmt IE mask value */
+ t_u32 mgmt_ie_mask;
+} MLAN_PACK_END MrvlIEtypes_mgmt_ie_passthru_t;
+
+/** MrvlIEtypes_mac_filter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_mac_filter_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Filter mode */
+ t_u8 filter_mode;
+ /** Number of STA MACs */
+ t_u8 count;
+ /** STA MAC addresses buffer */
+ t_u8 mac_address[1];
+} MLAN_PACK_END MrvlIEtypes_mac_filter_t;
+
+/** MrvlIEtypes_auth_type_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_auth_type_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Authentication type */
+ t_u8 auth_type;
+} MLAN_PACK_END MrvlIEtypes_auth_type_t;
+
+/** MrvlIEtypes_encrypt_protocol_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_encrypt_protocol_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** encryption protocol */
+ t_u16 protocol;
+} MLAN_PACK_END MrvlIEtypes_encrypt_protocol_t;
+
+/** MrvlIEtypes_pwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_pwk_cipher_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** protocol */
+ t_u16 protocol;
+ /** pairwise cipher */
+ t_u8 pairwise_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_pwk_cipher_t;
+
+/** MrvlIEtypes_gwk_cipher_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_gwk_cipher_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** reserved */
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIEtypes_gwk_cipher_t;
+
+/** MrvlIEtypes_akmp_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_akmp_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key management */
+ t_u16 key_mgmt;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+} MLAN_PACK_END MrvlIEtypes_akmp_t;
+
+/** MrvlIEtypes_passphrase_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_passphrase_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** passphrase */
+ t_u8 passphrase[1];
+} MLAN_PACK_END MrvlIEtypes_passphrase_t;
+
+/** MrvlIEtypes_rsn_replay_prot_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_rsn_replay_prot_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** rsn replay proection */
+ t_u8 rsn_replay_prot;
+} MLAN_PACK_END MrvlIEtypes_rsn_replay_prot_t;
+
+/** MrvlIEtypes_group_rekey_time_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_group_rekey_time_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** group key rekey time */
+ t_u32 gk_rekey_time;
+} MLAN_PACK_END MrvlIEtypes_group_rekey_time_t;
+
+/** MrvlIEtypes_wep_key_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wep_key_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** key index */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** key data */
+ t_u8 key[1];
+} MLAN_PACK_END MrvlIEtypes_wep_key_t;
+
+/** MrvlIEtypes_bss_status_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_bss_status_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** BSS status, READ only */
+ t_u16 bss_status;
+} MLAN_PACK_END MrvlIEtypes_bss_status_t;
+
+/** MrvlIEtypes_preamble_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_preamble_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** preamble type, READ only */
+ t_u8 preamble_type;
+} MLAN_PACK_END MrvlIEtypes_preamble_t;
+
+/** MrvlIEtypes_wmm_parameter_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wmm_parameter_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** WMM parameter */
+ WmmParameter_t wmm_para;
+} MLAN_PACK_END MrvlIEtypes_wmm_parameter_t;
+
+/** SNMP_MIB_UAP_INDEX */
+typedef enum _SNMP_MIB_UAP_INDEX {
+ tkip_mic_failures = 0x0b,
+ ccmp_decrypt_errors = 0x0c,
+ wep_undecryptable_count = 0x0d,
+ wep_icv_error_count = 0x0e,
+ decrypt_failure_count = 0xf,
+ dot11_failed_count = 0x12,
+ dot11_retry_count = 0x13,
+ dot11_multi_retry_count = 0x14,
+ dot11_frame_dup_count = 0x15,
+ dot11_rts_success_count = 0x16,
+ dot11_rts_failure_count = 0x17,
+ dot11_ack_failure_count = 0x18,
+ dot11_rx_fragment_count = 0x19,
+ dot11_mcast_rx_frame_count = 0x1a,
+ dot11_fcs_error_count = 0x1b,
+ dot11_tx_frame_count = 0x1c,
+ dot11_rsna_tkip_cm_invoked = 0x1d,
+ dot11_rsna_4way_hshk_failures = 0x1e,
+ dot11_mcast_tx_count = 0x1f,
+} SNMP_MIB_UAP_INDEX;
+
+/** MrvlIEtypes_snmp_oid_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_snmp_oid_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** data */
+ t_u32 data;
+} MLAN_PACK_END MrvlIEtypes_snmp_oid_t;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_CONFIG {
+ /** CMD Action GET/SET*/
+ t_u16 action;
+ /** Tlv buffer */
+ t_u8 tlv_buffer[1];
+} MLAN_PACK_END HostCmd_DS_SYS_CONFIG;
+
+/** HostCmd_SYS_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_SYS_INFO {
+ /** sys info */
+ t_u8 sys_info[64];
+} MLAN_PACK_END HostCmd_DS_SYS_INFO;
+
+/** HostCmd_DS_STA_DEAUTH */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_DEAUTH {
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ /** reason code */
+ t_u16 reason;
+} MLAN_PACK_END HostCmd_DS_STA_DEAUTH;
+
+/** HostCmd_DS_REPORT_MIC */
+typedef MLAN_PACK_START struct _HostCmd_DS_REPORT_MIC {
+ /** mac address */
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END HostCmd_DS_REPORT_MIC;
+
+/** HostCmd_UAP_OPER_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_UAP_OPER_CTRL {
+ /** CMD Action GET/SET*/
+ t_u16 action;
+ /** control*/
+ t_u16 ctrl;
+ /**channel operation*/
+ t_u16 chan_opt;
+ /**channel band tlv*/
+ MrvlIEtypes_channel_band_t channel_band;
+} MLAN_PACK_END HostCmd_DS_UAP_OPER_CTRL;
+
+/** Host Command id: POWER_MGMT */
+#define HOST_CMD_POWER_MGMT_EXT 0x00ef
+/** TLV type: AP Sleep param */
+#define TLV_TYPE_AP_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 0x6a) /* 0x016a */
+/** TLV type: AP Inactivity Sleep param */
+#define TLV_TYPE_AP_INACT_SLEEP_PARAM \
+ (PROPRIETARY_TLV_BASE_ID + 0x6b) /* 0x016b */
+
+/** MrvlIEtypes_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sleep_param_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** min_sleep */
+ t_u32 min_sleep;
+ /** max_sleep */
+ t_u32 max_sleep;
+} MLAN_PACK_END MrvlIEtypes_sleep_param_t;
+
+/** MrvlIEtypes_inact_sleep_param_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_inact_sleep_param_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** inactivity timeout */
+ t_u32 inactivity_to;
+
+ /** min_awake */
+ t_u32 min_awake;
+ /** max_awake */
+ t_u32 max_awake;
+} MLAN_PACK_END MrvlIEtypes_inact_sleep_param_t;
+
+/** HostCmd_DS_POWER_MGMT */
+typedef MLAN_PACK_START struct _HostCmd_DS_POWER_MGMT_EXT {
+ /** CMD Action Get/Set*/
+ t_u16 action;
+ /** power mode */
+ t_u16 power_mode;
+} MLAN_PACK_END HostCmd_DS_POWER_MGMT_EXT;
+
+/** MrvlIEtypes_ps_sta_ageout_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_ps_sta_ageout_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station age out timer */
+ t_u32 ps_sta_ageout_timer;
+} MLAN_PACK_END MrvlIEtypes_ps_sta_ageout_t;
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_sta_info_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power Mgmt status */
+ t_u8 power_mgmt_status;
+ /** RSSI */
+ t_s8 rssi;
+ /** ie_buf */
+ t_u8 ie_buf[];
+} MLAN_PACK_END MrvlIEtypes_sta_info_t;
+
+/** HostCmd_DS_STA_LIST */
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_LIST {
+ /** Number of STAs */
+ t_u16 sta_count;
+ /* MrvlIEtypes_sta_info_t sta_info[]; */
+ t_u8 tlv_buf[];
+} MLAN_PACK_END HostCmd_DS_STA_LIST;
+
+/** TLV ID : WAPI Information */
+#define TLV_TYPE_AP_WAPI_INFO (PROPRIETARY_TLV_BASE_ID + 0x67) /* 0x0167 */
+
+/** MrvlIEtypes_sta_info_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_wapi_info_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Multicast PN */
+ t_u8 multicast_PN[16];
+} MLAN_PACK_END MrvlIEtypes_wapi_info_t;
+#endif /* UAP_SUPPORT */
+
+/** HostCmd_DS_TX_RX_HISTOGRAM */
+typedef MLAN_PACK_START struct _HostCmd_DS_TX_RX_HISTOGRAM {
+ /** Enable or disable */
+ t_u8 enable;
+ /** Choose to get TX, RX or both */
+ t_u16 action;
+} MLAN_PACK_END HostCmd_DS_TX_RX_HISTOGRAM;
+
+/** TLV buffer : 2040 coex config */
+typedef MLAN_PACK_START struct _MrvlIEtypes_2040_coex_enable_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Enable */
+ t_u8 enable_2040coex;
+} MLAN_PACK_END MrvlIEtypes_2040_coex_enable_t;
+
+/**BT coexit scan time setting*/
+typedef MLAN_PACK_START struct _MrvlIEtypes_BtCoexScanTime_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /**coex scan state 0: disable 1: enable*/
+ t_u8 coex_scan;
+ /**reserved*/
+ t_u8 reserved;
+ /**min scan time*/
+ t_u16 min_scan_time;
+ /**max scan time*/
+ t_u16 max_scan_time;
+} MLAN_PACK_END MrvlIEtypes_BtCoexScanTime_t;
+
+/**BT coexit aggr win size */
+typedef MLAN_PACK_START struct _MrvlIETypes_BtCoexAggrWinSize_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /**winsize 0: restore default winsize, 1: use below winsize */
+ t_u8 coex_win_size;
+ /**tx win size*/
+ t_u8 tx_win_size;
+ /**rx win size*/
+ t_u8 rx_win_size;
+ /**reserved*/
+ t_u8 reserved;
+} MLAN_PACK_END MrvlIETypes_BtCoexAggrWinSize_t;
+
+/** MrvlIEtypes_eapol_pkt_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_eapol_pkt_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** eapol pkt buf */
+ t_u8 pkt_buf[];
+} MLAN_PACK_END MrvlIEtypes_eapol_pkt_t;
+
+/** HostCmd_DS_EAPOL_PKT */
+typedef MLAN_PACK_START struct _HostCmd_DS_EAPOL_PKT {
+ /** Action */
+ t_u16 action;
+ /** TLV buffer */
+ MrvlIEtypes_eapol_pkt_t tlv_eapol;
+} MLAN_PACK_END HostCmd_DS_EAPOL_PKT;
+
+/** HostCmd_DS_OXYGEN_MIMO_SWITCH */
+typedef MLAN_PACK_START struct _HostCmd_DS_MIMO_SWITCH {
+ /** Tx path antanne mode */
+ t_u8 txpath_antmode;
+ /** Rx path antanne mode */
+ t_u8 rxpath_antmode;
+} MLAN_PACK_END HostCmd_DS_MIMO_SWITCH;
+
+#ifdef RX_PACKET_COALESCE
+typedef MLAN_PACK_START struct _HostCmd_DS_RX_PKT_COAL_CFG {
+ /** Action */
+ t_u16 action;
+ /** Packet threshold */
+ t_u32 packet_threshold;
+ /** Timeout */
+ t_u16 delay;
+} MLAN_PACK_END HostCmd_DS_RX_PKT_COAL_CFG;
+#endif
+
+/** HostCmd_DS_DYN_BW */
+typedef MLAN_PACK_START struct _HostCmd_DS_DYN_BW {
+ /** Action */
+ t_u16 action;
+ /** Dynamic bandwidth */
+ t_u16 dyn_bw;
+} MLAN_PACK_END HostCmd_DS_DYN_BW;
+
+/** Host Command ID : Packet aggregation CTRL */
+#define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251
+
+/** HostCmd_DS_PACKET_AGGR_CTRL */
+typedef MLAN_PACK_START struct _HostCmd_DS_PACKET_AGGR_AGGR_CTRL {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /** enable aggregation, BIT(0) TX, BIT(1)RX */
+ t_u16 aggr_enable;
+ /** Tx aggregation alignment */
+ t_u16 tx_aggr_max_size;
+ /** Tx aggregation max packet number */
+ t_u16 tx_aggr_max_num;
+ /** Tx aggregation alignment */
+ t_u16 tx_aggr_align;
+} MLAN_PACK_END HostCmd_DS_PACKET_AGGR_CTRL;
+
+#ifdef USB
+/** Host Command ID : Packet aggregation over host interface */
+#define HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE 0x0117
+
+/** TLV ID : USB Aggregation parameters */
+#define MRVL_USB_AGGR_PARAM_TLV_ID \
+ (PROPRIETARY_TLV_BASE_ID + 0xB1) /* 0x1B1 \
+ */
+
+/** TLV size : USB Aggregation parameters, except header */
+#define MRVL_USB_AGGR_PARAM_TLV_LEN (14)
+
+/** VHT Operations IE */
+typedef MLAN_PACK_START struct _MrvlIETypes_USBAggrParam_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+
+ /** Enable */
+ t_u16 enable;
+ /** Rx aggregation mode */
+ t_u16 rx_aggr_mode;
+ /** Rx aggregation alignment */
+ t_u16 rx_aggr_align;
+ /** Rx aggregation max packet/size */
+ t_u16 rx_aggr_max;
+ /** Rx aggrgation timeout, in microseconds */
+ t_u16 rx_aggr_tmo;
+ /** Tx aggregation mode */
+ t_u16 tx_aggr_mode;
+ /** Tx aggregation alignment */
+ t_u16 tx_aggr_align;
+} MLAN_PACK_END MrvlIETypes_USBAggrParam_t;
+
+/** HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE */
+typedef MLAN_PACK_START struct _HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE {
+ /** ACT_GET/ACT_SET */
+ t_u16 action;
+ /**
+ * Host interface aggregation control TLV(s) to be sent in the firmware
+ * command
+ *
+ * TLV_USB_AGGR_PARAM, MrvlIETypes_USBAggrParam_t
+ */
+ t_u8 tlv_buf[1];
+} MLAN_PACK_END HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE;
+#endif /* USB */
+
+/** HostCmd_CONFIG_LOW_PWR_MODE */
+typedef MLAN_PACK_START struct _HostCmd_CONFIG_LOW_PWR_MODE {
+ /** Enable LPM */
+ t_u8 enable;
+} MLAN_PACK_END HostCmd_CONFIG_LOW_PWR_MODE;
+
+/** HostCmd_CMD_GET_TSF */
+typedef MLAN_PACK_START struct _HostCmd_DS_TSF {
+ /** tsf value*/
+ t_u64 tsf;
+} MLAN_PACK_END HostCmd_DS_TSF;
+/* WLAN_GET_TSF*/
+
+typedef struct _HostCmd_DS_DFS_REPEATER_MODE {
+ /** Set or Get */
+ t_u16 action;
+ /** 1 on or 0 off */
+ t_u16 mode;
+} HostCmd_DS_DFS_REPEATER_MODE;
+
+/** HostCmd_DS_BOOT_SLEEP */
+typedef MLAN_PACK_START struct _HostCmd_DS_BOOT_SLEEP {
+ /** Set or Get */
+ t_u16 action;
+ /** 1 on or 0 off */
+ t_u16 enable;
+} MLAN_PACK_END HostCmd_DS_BOOT_SLEEP;
+
+/**
+ * @brief 802.11h Local Power Constraint NXP extended TLV
+ */
+typedef MLAN_PACK_START struct {
+ MrvlIEtypesHeader_t header; /**< NXP TLV header: ID/Len */
+ t_u8 chan; /**< Channel local constraint applies to */
+
+ /** Power constraint included in beacons
+ * and used by fw to offset 11d info
+ */
+ t_u8 constraint;
+
+} MLAN_PACK_END MrvlIEtypes_LocalPowerConstraint_t;
+
+/*
+ *
+ * Data structures for driver/firmware command processing
+ *
+ */
+
+/** TPC Info structure sent in CMD_802_11_TPC_INFO command to firmware */
+typedef MLAN_PACK_START struct {
+ /**< Local constraint */
+ MrvlIEtypes_LocalPowerConstraint_t local_constraint;
+ /**< Power Capability */
+ MrvlIEtypes_PowerCapability_t power_cap;
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_INFO;
+
+/** TPC Request structure sent in CMD_802_11_TPC_ADAPT_REQ
+ * command to firmware
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 dest_mac[MLAN_MAC_ADDR_LENGTH]; /**< Destination STA address */
+ t_u16 timeout; /**< Response timeout in ms */
+ t_u8 rate_index; /**< IEEE Rate index to send request */
+
+} MLAN_PACK_END HostCmd_TpcRequest;
+
+/** TPC Response structure received from the
+ * CMD_802_11_TPC_ADAPT_REQ command
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 tpc_ret_code; /**< Firmware command result status code */
+ t_s8 tx_power; /**< Reported TX Power from the TPC Report element */
+ t_s8 link_margin; /**< Reported link margin from the TPC Report element
+ */
+ t_s8 rssi; /**< RSSI of the received TPC Report frame */
+
+} MLAN_PACK_END HostCmd_TpcResponse;
+
+/** CMD_802_11_TPC_ADAPT_REQ substruct.
+ * Union of the TPC request and response
+ */
+typedef MLAN_PACK_START union {
+ HostCmd_TpcRequest req; /**< Request struct sent to firmware */
+ HostCmd_TpcResponse resp; /**< Response struct received from firmware */
+
+} MLAN_PACK_END HostCmd_DS_802_11_TPC_ADAPT_REQ;
+
+/** CMD_802_11_CHAN_SW_ANN firmware command substructure */
+typedef MLAN_PACK_START struct {
+ t_u8 switch_mode; /**< Set to 1 for a quiet switch request, no STA tx */
+ t_u8 new_chan; /**< Requested new channel */
+ t_u8 switch_count; /**< Number of TBTTs until the switch is to occur */
+} MLAN_PACK_END HostCmd_DS_802_11_CHAN_SW_ANN;
+
+/**
+ * @brief Enumeration of measurement types, including max supported
+ * enum for 11h/11k
+ */
+typedef MLAN_PACK_START enum _MeasType_t {
+ WLAN_MEAS_BASIC = 0, /**< 11h: Basic */
+ WLAN_MEAS_NUM_TYPES, /**< Number of enumerated measurements */
+ WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_BASIC, /**< Max 11h measurement */
+
+} MLAN_PACK_END MeasType_t;
+
+/**
+ * @brief Mode octet of the measurement request element (7.3.2.21)
+ */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+ /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 duration_mandatory : 1;
+ /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 report : 1;
+ /**< 11h: en/disable requests of specified type */
+ t_u8 request : 1;
+ /**< 11h: enable report/request bits */
+ t_u8 enable : 1;
+ /**< 11k: series or parallel with previous meas */
+ t_u8 parallel : 1;
+#else
+ /**< 11k: series or parallel with previous meas */
+ t_u8 parallel : 1;
+ /**< 11h: enable report/request bits */
+ t_u8 enable : 1;
+ /**< 11h: en/disable requests of specified type */
+ t_u8 request : 1;
+ /**< 11h: en/disable report rcpt. of spec. type */
+ t_u8 report : 1;
+ /**< 11k: duration spec. for meas. is mandatory */
+ t_u8 duration_mandatory : 1;
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasReqMode_t;
+
+/**
+ * @brief Common measurement request structure (7.3.2.21.1 to 7.3.2.21.3)
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel; /**< Channel to measure */
+ t_u64 start_time; /**< TSF Start time of measurement (0 for immediate)
+ */
+ t_u16 duration; /**< TU duration of the measurement */
+
+} MLAN_PACK_END MeasReqCommonFormat_t;
+
+/**
+ * @brief Basic measurement request structure (7.3.2.21.1)
+ */
+typedef MeasReqCommonFormat_t MeasReqBasic_t;
+
+/**
+ * @brief CCA measurement request structure (7.3.2.21.2)
+ */
+typedef MeasReqCommonFormat_t MeasReqCCA_t;
+
+/**
+ * @brief RPI measurement request structure (7.3.2.21.3)
+ */
+typedef MeasReqCommonFormat_t MeasReqRPI_t;
+
+/**
+ * @brief Union of the availble measurement request types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union {
+ MeasReqBasic_t basic; /**< Basic measurement request */
+ MeasReqCCA_t cca; /**< CCA measurement request */
+ MeasReqRPI_t rpi; /**< RPI measurement request */
+
+} MeasRequest_t;
+
+/**
+ * @brief Mode octet of the measurement report element (7.3.2.22)
+ */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 rsvd3_7 : 5; /**< Reserved */
+ t_u8 refused : 1; /**< Measurement refused */
+ t_u8 incapable : 1; /**< Incapable of performing measurement */
+ t_u8 late : 1; /**< Start TSF time missed for measurement */
+#else
+ t_u8 late : 1; /**< Start TSF time missed for measurement */
+ t_u8 incapable : 1; /**< Incapable of performing measurement */
+ t_u8 refused : 1; /**< Measurement refused */
+ t_u8 rsvd3_7 : 5; /**< Reserved */
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptMode_t;
+
+/**
+ * @brief Basic measurement report (7.3.2.22.1)
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ MeasRptBasicMap_t map; /**< Basic measurement report */
+
+} MLAN_PACK_END MeasRptBasic_t;
+
+/**
+ * @brief CCA measurement report (7.3.2.22.2)
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 busy_fraction; /**< Fractional duration CCA indicated chan busy */
+
+} MLAN_PACK_END MeasRptCCA_t;
+
+/**
+ * @brief RPI measurement report (7.3.2.22.3)
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel; /**< Channel to measured */
+ t_u64 start_time; /**< Start time (TSF) of measurement */
+ t_u16 duration; /**< Duration of measurement in TUs */
+ t_u8 density[8]; /**< RPI Density histogram report */
+
+} MLAN_PACK_END MeasRptRPI_t;
+
+/**
+ * @brief Union of the availble measurement report types. Passed in the
+ * driver/firmware interface.
+ */
+typedef union {
+ MeasRptBasic_t basic; /**< Basic measurement report */
+ MeasRptCCA_t cca; /**< CCA measurement report */
+ MeasRptRPI_t rpi; /**< RPI measurement report */
+
+} MeasReport_t;
+
+/**
+ * @brief Structure passed to firmware to perform a measurement
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog toke */
+ MeasReqMode_t req_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasRequest_t req; /**< Measurement request data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REQUEST,
+ *pHostCmd_DS_MEASUREMENT_REQUEST;
+
+/**
+ * @brief Structure passed back from firmware with a measurement report,
+ * also can be to send a measurement report to another STA
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; /**< Reporting STA address */
+ t_u8 dialog_token; /**< Measurement dialog token */
+ MeasRptMode_t rpt_mode; /**< Report mode */
+ MeasType_t meas_type; /**< Measurement type */
+ MeasReport_t rpt; /**< Measurement report data */
+
+} MLAN_PACK_END HostCmd_DS_MEASUREMENT_REPORT, *pHostCmd_DS_MEASUREMENT_REPORT;
+
+typedef MLAN_PACK_START struct {
+ t_u16 startFreq;
+ Band_Config_t bandcfg;
+ t_u8 chanNum;
+
+} MLAN_PACK_END MrvlChannelDesc_t;
+
+#ifdef OPCHAN
+typedef MLAN_PACK_START struct {
+ MrvlIEtypesHeader_t header; /**< Header */
+
+ MrvlChannelDesc_t chanDesc;
+
+ t_u16 controlFlags;
+ t_u16 reserved;
+
+ t_u8 actPower;
+ t_u8 mdMinPower;
+ t_u8 mdMaxPower;
+ t_u8 mdPower;
+
+} MLAN_PACK_END MrvlIEtypes_ChanControlDesc_t;
+
+typedef MLAN_PACK_START struct {
+ MrvlIEtypesHeader_t header; /**< Header */
+
+ t_u16 chanGroupBitmap;
+ ChanScanMode_t scanMode;
+ t_u8 numChan;
+
+ MrvlChannelDesc_t chanDesc[50];
+
+} MLAN_PACK_END MrvlIEtypes_ChanGroupControl_t;
+
+typedef MLAN_PACK_START struct {
+ t_u16 action; /**< CMD Action Get/Set*/
+
+ t_u8 tlv_buffer[1];
+
+} MLAN_PACK_END HostCmd_DS_OPCHAN_CONFIG;
+
+typedef MLAN_PACK_START struct {
+ t_u16 action; /**< CMD Action Get/Set*/
+
+ t_u8 tlv_buffer[1];
+
+} MLAN_PACK_END HostCmd_DS_OPCHAN_CHANGROUP_CONFIG;
+
+#define HostCmd_CMD_OPCHAN_CONFIG 0x00f8
+#define HostCmd_CMD_OPCHAN_CHANGROUP_CONFIG 0x00f9
+#endif
+
+typedef MLAN_PACK_START struct {
+ MrvlIEtypesHeader_t Header; /**< Header */
+
+ MeasRptBasicMap_t map; /**< IEEE 802.11h basic meas report */
+} MLAN_PACK_END MrvlIEtypes_ChanRpt11hBasic_t;
+
+/* MrvlIEtypes_DfsW53Cfg_t*/
+typedef MLAN_PACK_START struct {
+ /* header */
+ MrvlIEtypesHeader_t Header;
+ /** df53cfg vlue*/
+ t_u8 dfs53cfg;
+} MLAN_PACK_END MrvlIEtypes_DfsW53Cfg_t;
+
+typedef MLAN_PACK_START struct {
+ MrvlChannelDesc_t chan_desc; /**< Channel band, number */
+ t_u32 millisec_dwell_time; /**< Channel dwell time in milliseconds */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_REQ;
+
+typedef MLAN_PACK_START struct {
+ t_u32 cmd_result; /**< Rpt request command result (0 == SUCCESS) */
+ t_u64 start_tsf; /**< TSF Measurement started */
+ t_u32 duration; /**< Duration of measurement in microsecs */
+ t_u8 tlv_buffer[1]; /**< TLV Buffer */
+} MLAN_PACK_END HostCmd_DS_CHAN_RPT_RSP;
+
+/** statistics threshold */
+typedef MLAN_PACK_START struct {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** value */
+ t_u8 value;
+ /** reporting frequency */
+ t_u8 frequency;
+} MLAN_PACK_END MrvlIEtypes_BeaconHighRssiThreshold_t,
+ MrvlIEtypes_BeaconLowRssiThreshold_t,
+ MrvlIEtypes_BeaconHighSnrThreshold_t,
+ MrvlIEtypes_BeaconLowSnrThreshold_t, MrvlIEtypes_FailureCount_t,
+ MrvlIEtypes_DataLowRssiThreshold_t, MrvlIEtypes_DataHighRssiThreshold_t,
+ MrvlIEtypes_DataLowSnrThreshold_t, MrvlIEtypes_DataHighSnrThreshold_t,
+ MrvlIETypes_PreBeaconMissed_t, MrvlIEtypes_BeaconsMissed_t;
+
+/** statistics threshold for LinkQuality */
+typedef MLAN_PACK_START struct {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Link SNR threshold (dB) */
+ t_u16 link_snr;
+ /** Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+} MLAN_PACK_END MrvlIEtypes_LinkQualityThreshold_t;
+
+#ifdef PCIE
+/** PCIE dual descriptor for data/event */
+typedef MLAN_PACK_START struct _dual_desc_buf {
+ /** buf size */
+ t_u16 len;
+ /** buffer descriptor flags */
+ t_u16 flags;
+ /** pkt size */
+ t_u16 pkt_size;
+ /** reserved */
+ t_u16 reserved;
+ /** Physical address of the buffer */
+ t_u64 paddr;
+} MLAN_PACK_END adma_dual_desc_buf, *padma_dual_desc_buf;
+
+#if defined(PCIE8997) || defined(PCIE8897)
+/** PCIE ring buffer description for DATA */
+typedef MLAN_PACK_START struct _mlan_pcie_data_buf {
+ /** Buffer descriptor flags */
+ t_u16 flags;
+ /** Offset of fragment/pkt to start of ip header */
+ t_u16 offset;
+ /** Fragment length of the buffer */
+ t_u16 frag_len;
+ /** Length of the buffer */
+ t_u16 len;
+ /** Physical address of the buffer */
+ t_u64 paddr;
+ /** Reserved */
+ t_u32 reserved;
+} MLAN_PACK_END mlan_pcie_data_buf, *pmlan_pcie_data_buf;
+
+/** PCIE ring buffer description for EVENT */
+typedef MLAN_PACK_START struct _mlan_pcie_evt_buf {
+ /** Physical address of the buffer */
+ t_u64 paddr;
+ /** Length of the buffer */
+ t_u16 len;
+ /** Buffer descriptor flags */
+ t_u16 flags;
+} MLAN_PACK_END mlan_pcie_evt_buf, *pmlan_pcie_evt_buf;
+
+/** PCIE host buffer configuration */
+typedef MLAN_PACK_START struct _HostCmd_DS_PCIE_HOST_BUF_DETAILS {
+ /** TX buffer descriptor ring address */
+ t_u32 txbd_addr_lo;
+ t_u32 txbd_addr_hi;
+ /** TX buffer descriptor ring count */
+ t_u32 txbd_count;
+
+ /** RX buffer descriptor ring address */
+ t_u32 rxbd_addr_lo;
+ t_u32 rxbd_addr_hi;
+ /** RX buffer descriptor ring count */
+ t_u32 rxbd_count;
+
+ /** Event buffer descriptor ring address */
+ t_u32 evtbd_addr_lo;
+ t_u32 evtbd_addr_hi;
+ /** Event buffer descriptor ring count */
+ t_u32 evtbd_count;
+} HostCmd_DS_PCIE_HOST_BUF_DETAILS;
+#endif
+#endif
+
+typedef MLAN_PACK_START struct _HostCmd_DS_SENSOR_TEMP {
+ t_u32 temperature;
+} MLAN_PACK_END HostCmd_DS_SENSOR_TEMP;
+
+#ifdef STA_SUPPORT
+typedef MLAN_PACK_START struct _HostCmd_DS_STA_CONFIGURE {
+ /** Action Set or get */
+ t_u16 action;
+ /** Tlv buffer */
+ t_u8 tlv_buffer[];
+ /**MrvlIEtypes_channel_band_t band_channel; */
+} MLAN_PACK_END HostCmd_DS_STA_CONFIGURE;
+#endif
+
+/** HostCmd_DS_AUTO_TX structure */
+typedef MLAN_PACK_START struct _HostCmd_DS_AUTO_TX {
+ /** Action Set or get */
+ t_u16 action;
+ /** Tlv buffer */
+ t_u8 tlv_buffer[];
+} MLAN_PACK_END HostCmd_DS_AUTO_TX;
+
+#define OID_CLOUD_KEEP_ALIVE 0
+#define EVENT_CLOUD_KEEP_ALIVE_RETRY_FAIL 133
+/** TLV for cloud keep alive control info */
+#define TLV_TYPE_CLOUD_KEEP_ALIVE \
+ (PROPRIETARY_TLV_BASE_ID + 0x102) /* 0x0100 + 258 */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Cloud_Keep_Alive_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** ID for cloud keep alive */
+ t_u8 keep_alive_id;
+ /** Enable/disable for this ID */
+ t_u8 enable;
+ /** TLV buffer */
+ t_u8 tlv[];
+} MLAN_PACK_END MrvlIEtypes_Cloud_Keep_Alive_t;
+
+/** TLV for cloud keep alive control info */
+#define TLV_TYPE_KEEP_ALIVE_CTRL \
+ (PROPRIETARY_TLV_BASE_ID + 0x103) /* 0x0100 + 259 */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Keep_Alive_Ctrl_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** period to send keep alive packet */
+ t_u32 snd_interval;
+ /** period to send retry packet */
+ t_u16 retry_interval;
+ /** count to send retry packet */
+ t_u16 retry_count;
+} MLAN_PACK_END MrvlIEtypes_Keep_Alive_Ctrl_t;
+
+/** TLV for cloud keep alive packet */
+#define TLV_TYPE_KEEP_ALIVE_PKT \
+ (PROPRIETARY_TLV_BASE_ID + 0x104) /* 0x0100 + 260 */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Keep_Alive_Pkt_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Ethernet Header */
+ Eth803Hdr_t eth_header;
+ /** packet buffer*/
+ t_u8 ip_packet[];
+} MLAN_PACK_END MrvlIEtypes_Keep_Alive_Pkt_t;
+
+/** TLV to indicate firmware only keep probe response while scan */
+#define TLV_TYPE_ONLYPROBERESP (PROPRIETARY_TLV_BASE_ID + 0xE9) /* 0x01E9 */
+typedef MLAN_PACK_START struct _MrvlIEtypes_OnlyProberesp_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** only keep probe response */
+ t_u8 proberesp_only;
+} MLAN_PACK_END MrvlIEtypes_OnlyProberesp_t;
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+#define HostCmd_CMD_CRYPTO 0x025e
+
+#define HostCmd_CMD_CRYPTO_SUBCMD_PRF_HMAC_SHA1 (0x1)
+#define HostCmd_CMD_CRYPTO_SUBCMD_HMAC_SHA1 (0x2)
+#define HostCmd_CMD_CRYPTO_SUBCMD_HMAC_SHA256 (0x3)
+#define HostCmd_CMD_CRYPTO_SUBCMD_SHA256 (0x4)
+#define HostCmd_CMD_CRYPTO_SUBCMD_RIJNDAEL (0x5)
+#define HostCmd_CMD_CRYPTO_SUBCMD_RC4 (0x6)
+#define HostCmd_CMD_CRYPTO_SUBCMD_MD5 (0x7)
+#define HostCmd_CMD_CRYPTO_SUBCMD_MRVL_F (0x8)
+#define HostCmd_CMD_CRYPTO_SUBCMD_SHA256_KDF (0x9)
+
+#define TLV_TYPE_CRYPTO_KEY (PROPRIETARY_TLV_BASE_ID + 308)
+#define TLV_TYPE_CRYPTO_KEY_IV (PROPRIETARY_TLV_BASE_ID + 309)
+#define TLV_TYPE_CRYPTO_KEY_PREFIX (PROPRIETARY_TLV_BASE_ID + 310)
+#define TLV_TYPE_CRYPTO_KEY_DATA_BLK (PROPRIETARY_TLV_BASE_ID + 311)
+
+/** MrvlIEParamSet_t */
+typedef MLAN_PACK_START struct {
+ /** Type */
+ t_u16 Type;
+ /** Length */
+ t_u16 Length;
+} MLAN_PACK_END MrvlIEParamSet_t;
+
+/** HostCmd_DS_CRYPTO */
+typedef MLAN_PACK_START struct _HostCmd_DS_CRYPTO {
+ /** action */
+ t_u16 action;
+ /** subCmdCode */
+ t_u8 subCmdCode;
+ /** subCmd start */
+ t_u8 subCmd[];
+} MLAN_PACK_END HostCmd_DS_CRYPTO;
+
+/** subcmd_prf_hmac_sha1 used by prf_hmac_sha1, md5 and sha256_kdf */
+typedef MLAN_PACK_START struct _subcmd_prf_hmac_sha1 {
+ /** output_len */
+ t_u16 output_len;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END subcmd_prf_hmac_sha1_t, subcmd_md5_t, subcmd_sha256_kdf_t;
+
+/** subcmd_hmac_sha1 used by hmac_sha1, hmac_sha256, sha256 */
+typedef MLAN_PACK_START struct _subcmd_hmac_sha1 {
+ /** output_len */
+ t_u16 output_len;
+ /** number of data blocks */
+ t_u16 data_blks_nr;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END subcmd_hmac_sha1_t, subcmd_hmac_sha256_t, subcmd_sha256_t;
+
+/** subcmd_rijndael, used by rijndael */
+typedef MLAN_PACK_START struct _subcmd_rijndael {
+ /** output_len */
+ t_u16 output_len;
+ /** sub action code */
+ t_u8 sub_action_code;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END subcmd_rijndael_t;
+
+/** subcmd_rc4, used by rc4 */
+typedef MLAN_PACK_START struct _subcmd_rc4 {
+ /** output_len */
+ t_u16 output_len;
+ /** skip bytes */
+ t_u16 skip_bytes;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END subcmd_rc4_t;
+
+/** subcmd_mrvf_f, used by mrvl_f*/
+typedef MLAN_PACK_START struct _subcmd_mrvf_f {
+ /** output_len */
+ t_u16 output_len;
+ /** iterations */
+ t_u32 iterations;
+ /** count */
+ t_u32 count;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END subcmd_mrvl_f_t;
+
+#endif
+
+#ifdef UAP_SUPPORT
+/** action add station */
+#define HostCmd_ACT_ADD_STA 0x1
+/** remove station */
+#define HostCmd_ACT_REMOVE_STA 0x0
+/** HostCmd_DS_ADD_STATION */
+typedef MLAN_PACK_START struct _HostCmd_DS_ADD_STATION {
+ /** 1 -add, 0 --delete */
+ t_u16 action;
+ /** aid */
+ t_u16 aid;
+ /** peer_mac */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Listen Interval */
+ int listen_interval;
+ /** Capability Info */
+ t_u16 cap_info;
+ /** tlv start */
+ t_u8 tlv[];
+} MLAN_PACK_END HostCmd_DS_ADD_STATION;
+
+/** Host Command ID : Add New Station */
+#define HostCmd_CMD_ADD_NEW_STATION 0x025f
+/** TLV id: station flag */
+#define TLV_TYPE_UAP_STA_FLAGS (PROPRIETARY_TLV_BASE_ID + 313)
+/**MrvlIEtypes_Sta_Flag_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_StaFlag_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** station flag */
+ t_u32 sta_flags;
+} MLAN_PACK_END MrvlIEtypes_StaFlag_t;
+#endif
+
+/** Host Command ID : _HostCmd_DS_BAND_STEERING */
+typedef MLAN_PACK_START struct _HostCmd_DS_BAND_STEERING {
+ /** ACT_GET/ACT_SET */
+ t_u8 action;
+ /** State */
+ t_u8 state;
+ /** probe requests to be blocked on 2g */
+ t_u8 block_2g_prb_req;
+ /** limit the btm request sent to STA at <max_btm_req_allowed>*/
+ t_u8 max_btm_req_allowed;
+} MLAN_PACK_END HostCmd_DS_BAND_STEERING;
+
+/** HostCmd_CMD_RX_ABORT_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_RX_ABORT_CFG {
+ /** Action */
+ t_u16 action;
+ /** Enable/disable rx abort on weak pkt rssi */
+ t_u8 enable;
+ /** rx weak rssi pkt threshold */
+ t_s8 rssi_threshold;
+} MLAN_PACK_END HostCmd_DS_CMD_RX_ABORT_CFG;
+/** HostCmd_CMD_RX_ABORT_CFG_EXT */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_RX_ABORT_CFG_EXT {
+ /** Action */
+ t_u16 action;
+ /** Enable/disable dyn rx abort on weak pkt rssi */
+ t_u8 enable;
+ /** specify rssi margin */
+ t_s8 rssi_margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_rssi_threshold;
+} MLAN_PACK_END HostCmd_DS_CMD_RX_ABORT_CFG_EXT;
+
+/** HostCmd_CMD_ARB_CONFIG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_ARB_CONFIG {
+ /** Action */
+ t_u16 action;
+ /** 0-4 */
+ t_u32 arb_mode;
+ /** 1: use FW enhancement, 0: use FW default */
+ t_u32 reserved;
+} MLAN_PACK_END HostCmd_DS_CMD_ARB_CONFIG;
+
+/** HostCmd_DS_CMD_TX_AMPDU_PROT_MODE */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_TX_AMPDU_PROT_MODE {
+ /** Action */
+ t_u16 action;
+ /** Prot mode */
+ t_u16 mode;
+} MLAN_PACK_END HostCmd_DS_CMD_TX_AMPDU_PROT_MODE;
+
+/** HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG {
+ /** Action */
+ t_u16 action;
+ /** Cfg state */
+ t_u16 state;
+} MLAN_PACK_END HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG;
+
+/** HostCmd_CMD_RATE_ADAPT_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_RATE_ADAPT_CFG {
+ /** Action */
+ t_u16 action;
+ /** SR Rateadapt*/
+ t_u8 sr_rateadapt;
+ /** set low threshold */
+ t_u8 ra_low_thresh;
+ /** set high threshold */
+ t_u8 ra_high_thresh;
+ /** set interval */
+ t_u16 ra_interval;
+} MLAN_PACK_END HostCmd_DS_CMD_RATE_ADAPT_CFG;
+
+/** HostCmd_CMD_CCK_DESENSE_CFG */
+typedef MLAN_PACK_START struct _HostCmd_DS_CMD_CCK_DESENSE_CFG {
+ /** Action */
+ t_u16 action;
+ /** cck desense mode: 0:disable 1:normal 2:dynamic */
+ t_u16 mode;
+ /** specify rssi margin */
+ t_s8 margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_thresh;
+ /** cck desense "on" interval count */
+ t_u8 num_on_intervals;
+ /** cck desense "off" interval count */
+ t_u8 num_off_intervals;
+} MLAN_PACK_END HostCmd_DS_CMD_CCK_DESENSE_CFG;
+
+/** HostCmd_DS_COMMAND */
+typedef struct MLAN_PACK_START _HostCmd_DS_COMMAND {
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command Body */
+ union {
+ /** Hardware specifications */
+ HostCmd_DS_GET_HW_SPEC hw_spec;
+#ifdef SDIO
+ HostCmd_DS_SDIO_SP_RX_AGGR_CFG sdio_rx_aggr;
+#endif
+ /** Cfg data */
+ HostCmd_DS_802_11_CFG_DATA cfg_data;
+ /** MAC control */
+ HostCmd_DS_MAC_CONTROL mac_ctrl;
+ /** MAC address */
+ HostCmd_DS_802_11_MAC_ADDRESS mac_addr;
+ /** MAC muticast address */
+ HostCmd_DS_MAC_MULTICAST_ADR mc_addr;
+ /** Get log */
+ HostCmd_DS_802_11_GET_LOG get_log;
+ /** Get link layer statistic */
+ HostCmd_DS_802_11_LINK_STATISTIC get_link_statistic;
+ /** RSSI information */
+ HostCmd_DS_802_11_RSSI_INFO_EXT rssi_info_ext;
+ /** RSSI information */
+ HostCmd_DS_802_11_RSSI_INFO rssi_info;
+ /** RSSI information response */
+ HostCmd_DS_802_11_RSSI_INFO_RSP rssi_info_rsp;
+ /** SNMP MIB */
+ HostCmd_DS_802_11_SNMP_MIB smib;
+#ifdef UAP_SUPPORT
+ /** UAP SNMP MIB */
+ HostCmd_DS_UAP_802_11_SNMP_MIB uap_smib;
+#endif
+ /** Radio control */
+ HostCmd_DS_802_11_RADIO_CONTROL radio;
+ /** RF channel */
+ HostCmd_DS_802_11_RF_CHANNEL rf_channel;
+ /** Tx rate query */
+ HostCmd_TX_RATE_QUERY tx_rate;
+ /** Tx rate configuration */
+ HostCmd_DS_TX_RATE_CFG tx_rate_cfg;
+ /** Tx power configuration */
+ HostCmd_DS_TXPWR_CFG txp_cfg;
+ /** RF Tx power configuration */
+ HostCmd_DS_802_11_RF_TX_POWER txp;
+
+ /** RF antenna */
+ HostCmd_DS_802_11_RF_ANTENNA antenna;
+
+ /** CW Mode: Tx CW Level control */
+ HostCmd_DS_CW_MODE_CTRL cwmode;
+ /** Enhanced power save command */
+ HostCmd_DS_802_11_PS_MODE_ENH psmode_enh;
+ HostCmd_DS_802_11_HS_CFG_ENH opt_hs_cfg;
+ /** Scan */
+ HostCmd_DS_802_11_SCAN scan;
+ /** Extended Scan */
+ HostCmd_DS_802_11_SCAN_EXT ext_scan;
+
+ /** Mgmt frame subtype mask */
+ HostCmd_DS_RX_MGMT_IND rx_mgmt_ind;
+ /** Scan response */
+ HostCmd_DS_802_11_SCAN_RSP scan_resp;
+
+ HostCmd_DS_802_11_BG_SCAN_CONFIG bg_scan_config;
+ HostCmd_DS_802_11_BG_SCAN_QUERY bg_scan_query;
+ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bg_scan_query_resp;
+ HostCmd_DS_SUBSCRIBE_EVENT subscribe_event;
+ HostCmd_DS_OTP_USER_DATA otp_user_data;
+ /** Associate */
+ HostCmd_DS_802_11_ASSOCIATE associate;
+
+ /** Associate response */
+ HostCmd_DS_802_11_ASSOCIATE_RSP associate_rsp;
+ /** Deauthenticate */
+ HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+ /** Ad-Hoc start */
+ HostCmd_DS_802_11_AD_HOC_START adhoc_start;
+ /** Ad-Hoc start result */
+ HostCmd_DS_802_11_AD_HOC_START_RESULT adhoc_start_result;
+ /** Ad-Hoc join result */
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT adhoc_join_result;
+ /** Ad-Hoc join */
+ HostCmd_DS_802_11_AD_HOC_JOIN adhoc_join;
+ /** Domain information */
+ HostCmd_DS_802_11D_DOMAIN_INFO domain_info;
+ /** Domain information response */
+ HostCmd_DS_802_11D_DOMAIN_INFO_RSP domain_info_resp;
+ HostCmd_DS_802_11_TPC_ADAPT_REQ tpc_req;
+ HostCmd_DS_802_11_TPC_INFO tpc_info;
+ HostCmd_DS_802_11_CHAN_SW_ANN chan_sw_ann;
+ HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
+ HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+ /** Add BA request */
+ HostCmd_DS_11N_ADDBA_REQ add_ba_req;
+ /** Add BA response */
+ HostCmd_DS_11N_ADDBA_RSP add_ba_rsp;
+ /** Delete BA entry */
+ HostCmd_DS_11N_DELBA del_ba;
+ /** Tx buffer configuration */
+ HostCmd_DS_TXBUF_CFG tx_buf;
+ /** AMSDU Aggr Ctrl configuration */
+ HostCmd_DS_AMSDU_AGGR_CTRL amsdu_aggr_ctrl;
+ /** 11n configuration */
+ HostCmd_DS_11N_CFG htcfg;
+ /** reject addba req conditions configuration */
+ HostCmd_DS_REJECT_ADDBA_REQ rejectaddbareq;
+ /* RANDYTODO need add more */
+ /** HostCmd_DS_11AC_CFG */
+ HostCmd_DS_11AC_CFG vhtcfg;
+ /** HostCmd_DS_11ACTXBUF_CFG*/
+ HostCmd_DS_11ACTXBUF_CFG ac_tx_buf;
+ /** 11n configuration */
+ HostCmd_DS_TX_BF_CFG tx_bf_cfg;
+ /** WMM status get */
+ HostCmd_DS_WMM_GET_STATUS get_wmm_status;
+ /** WMM ADDTS */
+ HostCmd_DS_WMM_ADDTS_REQ add_ts;
+ /** WMM DELTS */
+ HostCmd_DS_WMM_DELTS_REQ del_ts;
+ /** WMM set/get queue config */
+ HostCmd_DS_WMM_QUEUE_CONFIG queue_config;
+ /** WMM param config*/
+ HostCmd_DS_WMM_PARAM_CONFIG param_config;
+ /** WMM on/of/get queue statistics */
+ HostCmd_DS_WMM_QUEUE_STATS queue_stats;
+ /** WMM get traffic stream status */
+ HostCmd_DS_WMM_TS_STATUS ts_status;
+ /** Key material */
+ HostCmd_DS_802_11_KEY_MATERIAL key_material;
+ /** GTK Rekey parameters */
+ HostCmd_DS_GTK_REKEY_PARAMS gtk_rekey;
+ /** E-Supplicant PSK */
+ HostCmd_DS_802_11_SUPPLICANT_PMK esupplicant_psk;
+ /** E-Supplicant profile */
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE esupplicant_profile;
+ /** Extended version */
+ HostCmd_DS_VERSION_EXT verext;
+ /** Adhoc Coalescing */
+ HostCmd_DS_802_11_IBSS_STATUS ibss_coalescing;
+ /** Mgmt IE list configuration */
+ HostCmd_DS_MGMT_IE_LIST_CFG mgmt_ie_list;
+ /** System clock configuration */
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG sys_clock_cfg;
+ /** MAC register access */
+ HostCmd_DS_MAC_REG_ACCESS mac_reg;
+ /** BBP register access */
+ HostCmd_DS_BBP_REG_ACCESS bbp_reg;
+ /** RF register access */
+ HostCmd_DS_RF_REG_ACCESS rf_reg;
+ /** EEPROM register access */
+ HostCmd_DS_802_11_EEPROM_ACCESS eeprom;
+ /** Memory access */
+ HostCmd_DS_MEM_ACCESS mem;
+ /** Target device access */
+ HostCmd_DS_TARGET_ACCESS target;
+ /** BCA register access */
+ HostCmd_DS_BCA_REG_ACCESS bca_reg;
+ /** Inactivity timeout extend */
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT inactivity_to;
+#ifdef UAP_SUPPORT
+ HostCmd_DS_SYS_CONFIG sys_config;
+ HostCmd_DS_SYS_INFO sys_info;
+ HostCmd_DS_STA_DEAUTH sta_deauth;
+ HostCmd_DS_STA_LIST sta_list;
+ HostCmd_DS_POWER_MGMT_EXT pm_cfg;
+ HostCmd_DS_REPORT_MIC report_mic;
+ HostCmd_DS_UAP_OPER_CTRL uap_oper_ctrl;
+#endif /* UAP_SUPPORT */
+ HostCmd_DS_TX_RX_HISTOGRAM tx_rx_histogram;
+
+ /** Sleep period command */
+ HostCmd_DS_802_11_SLEEP_PERIOD sleep_pd;
+ /** Sleep params command */
+ HostCmd_DS_802_11_SLEEP_PARAMS sleep_param;
+
+#ifdef SDIO
+ /** SDIO GPIO interrupt config command */
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_gpio_int;
+ HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctl;
+#endif
+ HostCmd_DS_SET_BSS_MODE bss_mode;
+ HostCmd_DS_CMD_TX_DATA_PAUSE tx_data_pause;
+#if defined(PCIE)
+#if defined(PCIE8997) || defined(PCIE8897)
+ HostCmd_DS_PCIE_HOST_BUF_DETAILS pcie_host_spec;
+#endif
+#endif
+ HostCmd_DS_REMAIN_ON_CHANNEL remain_on_chan;
+#ifdef WIFI_DIRECT_SUPPORT
+ HostCmd_DS_WIFI_DIRECT_MODE wifi_direct_mode;
+ HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG p2p_params_config;
+#endif
+ HostCmd_DS_COALESCE_CONFIG coalesce_config;
+ HostCmd_DS_HS_WAKEUP_REASON hs_wakeup_reason;
+ HostCmd_DS_PACKET_AGGR_CTRL aggr_ctrl;
+#ifdef USB
+ HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE packet_aggr;
+#endif
+ HostCmd_CONFIG_LOW_PWR_MODE low_pwr_mode_cfg;
+ HostCmd_DS_TSF tsf;
+ HostCmd_DS_DFS_REPEATER_MODE dfs_repeater;
+#ifdef RX_PACKET_COALESCE
+ HostCmd_DS_RX_PKT_COAL_CFG rx_pkt_coal_cfg;
+#endif
+ HostCmd_DS_EAPOL_PKT eapol_pkt;
+ HostCmd_DS_SENSOR_TEMP temp_sensor;
+ HostCMD_DS_APCMD_ACS_SCAN acs_scan;
+ HostCmd_DS_MIMO_SWITCH mimo_switch;
+#ifdef STA_SUPPORT
+ HostCmd_DS_STA_CONFIGURE sta_cfg;
+#endif
+ /** GPIO Independent reset configure */
+ HostCmd_DS_INDEPENDENT_RESET_CFG ind_rst_cfg;
+ HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT ps_inact_tmo;
+ HostCmd_DS_CHAN_REGION_CFG reg_cfg;
+ HostCmd_DS_AUTO_TX auto_tx;
+ HostCmd_DS_DYN_BW dyn_bw;
+ HostCmd_DS_802_11_ROBUSTCOEX robustcoexparams;
+ HostCmd_DS_DMCS_CFG dmcs;
+#if defined(PCIE)
+ HostCmd_DS_SSU_CFG ssu_params;
+#endif
+ /** boot sleep configure */
+ HostCmd_DS_BOOT_SLEEP boot_sleep;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ /** crypto cmd */
+ HostCmd_DS_CRYPTO crypto_cmd;
+#endif
+#ifdef UAP_SUPPORT
+ /** Add station cmd */
+ HostCmd_DS_ADD_STATION sta_info;
+#endif
+ /** HostCmd_DS_11AX_CFG */
+ HostCmd_DS_11AX_CFG axcfg;
+ /** HostCmd_DS_11AX_CMD_CFG */
+ HostCmd_DS_11AX_CMD_CFG axcmd;
+ HostCmd_DS_RANGE_EXT range_ext;
+ /** HostCmd_DS_TWT_CFG */
+ HostCmd_DS_TWT_CFG twtcfg;
+
+ HostCmd_DS_CMD_RX_ABORT_CFG rx_abort_cfg;
+ HostCmd_DS_CMD_RX_ABORT_CFG_EXT rx_abort_cfg_ext;
+ HostCmd_DS_CMD_TX_AMPDU_PROT_MODE tx_ampdu_prot_mode;
+ HostCmd_DS_CMD_RATE_ADAPT_CFG rate_adapt_cfg;
+ HostCmd_DS_CMD_CCK_DESENSE_CFG cck_desense_cfg;
+ /** trpc_config */
+ HostCmd_DS_CHANNEL_TRPC_CONFIG ch_trpc_config;
+ HostCmd_DS_LOW_POWER_MODE_CFG lpm_cfg;
+ HostCmd_DS_BAND_STEERING band_steer_info;
+ HostCmd_DS_BEACON_STUCK_CFG beacon_stuck_cfg;
+ struct mfg_cmd_generic_cfg mfg_generic_cfg;
+ struct mfg_cmd_tx_cont mfg_tx_cont;
+ struct mfg_cmd_tx_frame2 mfg_tx_frame2;
+ HostCmd_DS_CMD_ARB_CONFIG arb_cfg;
+ HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG dot11mc_unassoc_ftm_cfg;
+ } params;
+} MLAN_PACK_END HostCmd_DS_COMMAND, *pHostCmd_DS_COMMAND;
+
+/** PS_CMD_ConfirmSleep */
+typedef MLAN_PACK_START struct _OPT_Confirm_Sleep {
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+ /** Sequence number */
+ t_u16 seq_num;
+ /** Result */
+ t_u16 result;
+ /** Action */
+ t_u16 action;
+ /** Sleep comfirm param definition */
+ sleep_confirm_param sleep_cfm;
+} MLAN_PACK_END OPT_Confirm_Sleep;
+
+typedef struct MLAN_PACK_START _opt_sleep_confirm_buffer {
+ /** Header for interface */
+ t_u32 hdr;
+ /** New power save command used to send
+ * sleep confirmation to the firmware */
+ OPT_Confirm_Sleep ps_cfm_sleep;
+} MLAN_PACK_END opt_sleep_confirm_buffer;
+
+/** req host side download vdll block */
+#define VDLL_IND_TYPE_REQ 0
+/** notify vdll start offset in firmware image */
+#define VDLL_IND_TYPE_OFFSET 1
+
+/** vdll indicate event structure */
+typedef MLAN_PACK_START struct _vdll_ind {
+ /*VDLL ind type*/
+ t_u16 type;
+ /*reserved*/
+ t_u16 reserved;
+ /*indicate the offset downloaded so far*/
+ t_u32 offset;
+ /*VDLL block size*/
+ t_u16 block_len;
+} MLAN_PACK_END vdll_ind, *pvdll_ind;
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+#endif /* !_MLAN_FW_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ieee.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ieee.h
new file mode 100644
index 000000000000..03b5fd4ffc92
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ieee.h
@@ -0,0 +1,1888 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 11/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension */
+#define WLAN_SUPPORTED_RATES_EXT 60
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE {
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound*/
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc)&0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc)&0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/* Reason codes */
+#define IEEE_80211_REASONCODE_UNSPECIFIED 1
+
+typedef enum _IEEEtypes_Ext_ElementId_e {
+ HE_CAPABILITY = 35,
+ HE_OPERATION = 36
+} IEEEtypes_Ext_ElementId_e;
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e {
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+ COUNTRY_INFO = 7,
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ CHANNEL_SWITCH_ANN = 37,
+ EXTEND_CHANNEL_SWITCH_ANN = 60,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ SUPPORTED_CHANNELS = 36,
+ REGULATORY_CLASS = 59,
+ HT_CAPABILITY = 45,
+ QOS_INFO = 46,
+ HT_OPERATION = 61,
+ MULTI_BSSID = 71,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ NONTX_BSSID_CAP = 83,
+ MBSSID_INDEX = 85,
+ EXT_CAPABILITY = 127,
+ /*IEEE802.11r*/
+ MOBILITY_DOMAIN = 54,
+ FAST_BSS_TRANSITION = 55,
+ TIMEOUT_INTERVAL = 56,
+ RIC = 57,
+ QOS_MAPPING = 110,
+ VHT_CAPABILITY = 191,
+ VHT_OPERATION = 192,
+ EXT_BSS_LOAD = 193,
+ BW_CHANNEL_SWITCH = 194,
+ VHT_TX_POWER_ENV = 195,
+ EXT_POWER_CONSTR = 196,
+ AID_INFO = 197,
+ QUIET_CHAN = 198,
+ OPER_MODE_NTF = 199,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+ /* WPA */
+ WPA_IE = VENDOR_SPECIFIC_221,
+ /* WPA2 */
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+ FRAGMENT = 242,
+ EXTENSION = 255
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t {
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+} MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+} MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/**ft capability policy*/
+typedef MLAN_PACK_START struct _IEEEtypes_FtCapPolicy_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 6;
+ /** RIC support */
+ t_u8 ric : 1;
+ /** FT over the DS capable */
+ t_u8 ft_over_ds : 1;
+#else
+ /** FT over the DS capable */
+ t_u8 ft_over_ds : 1;
+ /** RIC support */
+ t_u8 ric : 1;
+ /** Reserved */
+ t_u8 reserved : 6;
+#endif
+} MLAN_PACK_END IEEEtypes_FtCapPolicy_t;
+
+/** Mobility domain IE */
+typedef MLAN_PACK_START struct _IEEEtypes_MobilityDomain_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Mobility Domain ID */
+ t_u16 mdid;
+ /** FT Capability policy */
+ t_u8 ft_cap;
+} MLAN_PACK_END IEEEtypes_MobilityDomain_t;
+
+/**FT MIC Control*/
+typedef MLAN_PACK_START struct _IEEEtypes_FT_MICControl_t {
+ /** reserved */
+ t_u8 reserved;
+ /** element count */
+ t_u8 element_count;
+} MLAN_PACK_END IEEEtypes_FT_MICControl_t;
+
+/** FTIE MIC LEN */
+#define FTIE_MIC_LEN 16
+
+/**FT IE*/
+typedef MLAN_PACK_START struct _IEEEtypes_FastBssTransElement_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** mic control */
+ IEEEtypes_FT_MICControl_t mic_control;
+ /** mic */
+ t_u8 mic[FTIE_MIC_LEN];
+ /** ANonce */
+ t_u8 a_nonce[32];
+ /** SNonce */
+ t_u8 s_nonce[32];
+ /** sub element */
+ t_u8 sub_element[1];
+} MLAN_PACK_END IEEEtypes_FastBssTransElement_t;
+
+/*Category for FT*/
+#define FT_CATEGORY 6
+/** FT ACTION request */
+#define FT_ACTION_REQUEST 1
+/** FT ACTION response */
+#define FT_ACTION_RESPONSE 2
+
+/*FT response and FT ack*/
+typedef MLAN_PACK_START struct {
+ /** category */
+ t_u8 category;
+ /** action */
+ t_u8 action;
+ /** sta address */
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** target ap address */
+ t_u8 target_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /** status code */
+ t_u16 status_code;
+ /** varible */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Ft_action_response;
+
+/**FT request */
+typedef MLAN_PACK_START struct {
+ /** category */
+ t_u8 category;
+ /** action */
+ t_u8 action;
+ /** sta address */
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** target ap address */
+ t_u8 target_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /** varible */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Ft_action_request;
+
+/** auth frame body*/
+typedef MLAN_PACK_START struct {
+ /** auth alg */
+ t_u16 auth_alg;
+ /** auth transaction */
+ t_u16 auth_transaction;
+ /** status code */
+ t_u16 status_code;
+ /** variable */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Auth_framebody;
+
+/** associate request frame */
+typedef MLAN_PACK_START struct {
+ t_u16 capab_info;
+ t_u16 listen_interval;
+ /** followed by SSID and Supported rates */
+ t_u8 variablep[];
+} MLAN_PACK_END IEEEtypes_assoc_req;
+
+/*Mgmt frame*/
+typedef MLAN_PACK_START struct {
+ /** frame control */
+ t_u16 frame_control;
+ /** duration */
+ t_u16 duration;
+ /** dest address */
+ t_u8 da[MLAN_MAC_ADDR_LENGTH];
+ /** source address */
+ t_u8 sa[MLAN_MAC_ADDR_LENGTH];
+ /** bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** seq control */
+ t_u16 seq_ctrl;
+ /** address 4 */
+ t_u8 addr4[MLAN_MAC_ADDR_LENGTH];
+ union {
+ IEEEtypes_Auth_framebody auth;
+ IEEEtypes_assoc_req assoc_req;
+ IEEEtypes_Ft_action_response ft_resp;
+ IEEEtypes_Ft_action_request ft_req;
+ } u;
+} MLAN_PACK_END IEEE80211_MGMT;
+
+/** TLV header */
+typedef MLAN_PACK_START struct _TLV_Generic_t {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+} MLAN_PACK_END TLV_Generic_t, *pTLV_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t {
+ t_u8 rsrvd1 : 2;
+ t_u8 dsss_ofdm : 1;
+ t_u8 radio_measurement : 1;
+ t_u8 rsvrd2 : 1;
+ t_u8 short_slot_time : 1;
+ t_u8 rsrvd3 : 1;
+ t_u8 spectrum_mgmt : 1;
+ t_u8 chan_agility : 1;
+ t_u8 pbcc : 1;
+ t_u8 short_preamble : 1;
+ t_u8 privacy : 1;
+ t_u8 cf_poll_rqst : 1;
+ t_u8 cf_pollable : 1;
+ t_u8 ibss : 1;
+ t_u8 ess : 1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t {
+ /** Capability Bit Map : ESS */
+ t_u8 ess : 1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss : 1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable : 1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst : 1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy : 1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble : 1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc : 1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility : 1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3 : 1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time : 1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2 : 1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1 : 2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_Ssid_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Ssid_t {
+ /** SSID: Element ID */
+ t_u8 element_id;
+ /** SSID : Length */
+ t_u8 len;
+ /** ssid */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} MLAN_PACK_END IEEEtypes_Ssid_t, *pIEEEtypes_Ssid_t;
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t {
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t {
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t {
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t {
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t {
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** Fixed size in assoc_resp */
+#define ASSOC_RESP_FIXED_SIZE 6
+
+/** IEEEtypes_SeqCtl_t */
+typedef MLAN_PACK_START struct _IEEEtypes_SeqCtl_t {
+ /** Fragment Number */
+ t_u16 FragNum : 4;
+ /** Sequence Number */
+ t_u16 SeqNum : 12;
+} MLAN_PACK_END IEEEtypes_SeqCtl_t;
+
+/** IEEEtypes_MgmtHdr_t */
+typedef MLAN_PACK_START struct _IEEEtypes_MgmtHdr_t {
+ /** FrmCtl*/
+ t_u16 FrmCtl;
+ /** Duration*/
+ t_u16 Duration;
+ /** Destination Addr*/
+ t_u8 DestAddr[6];
+ /** Source Addr*/
+ t_u8 SrcAddr[6];
+ /** BSSID */
+ t_u8 BssId[6];
+ /** IEEEtypes_SeqCtl_t */
+ IEEEtypes_SeqCtl_t SeqCtl;
+} MLAN_PACK_END IEEEtypes_MgmtHdr_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t {
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+/** AKM: PSK SHA256 */
+#define RSN_AKM_PSK_SHA256 6
+
+/** AKM: PSK SHA256 */
+#define RSN_AKM_SAE 8
+/** AKM: PSK SHA256 */
+#define RSN_AKM_OWE 18
+
+#if defined(STA_SUPPORT)
+/** Pairwise Cipher Suite length */
+#define PAIRWISE_CIPHER_SUITE_LEN 4
+/** AKM Suite length */
+#define AKM_SUITE_LEN 4
+/** MFPC bit in RSN capability */
+#define MFPC_BIT 7
+/** MFPR bit in RSN capability */
+#define MFPR_BIT 6
+/** PMF ORing mask */
+#define PMF_MASK 0x00c0
+#endif
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t {
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct {
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t {
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t {
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aifsn */
+ t_u8 aifsn : 4;
+#else
+ /** Aifsn */
+ t_u8 aifsn : 4;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Reserved */
+ t_u8 reserved : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t {
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t {
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t {
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e {
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e {
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e {
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e {
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23 : 7; /* ! Reserved */
+ t_u8 Schedule : 1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy : 2;
+ t_u8 UserPri : 3; /* ! 802.1d User Priority */
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior : 1; /* !
+ Legacy/Trigg
+ */
+ t_u8 Aggregation : 1; /* ! Reserved */
+ t_u8 AccessPolicy2 : 1; /* ! */
+ t_u8 AccessPolicy1 : 1; /* ! */
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction : 2;
+ t_u8 TID : 4; /* ! Unique identifier */
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType : 1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType : 1;
+ t_u8 TID : 4; /* ! Unique identifier */
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction : 2;
+ t_u8 AccessPolicy1 : 1; /* ! */
+ t_u8 AccessPolicy2 : 1; /* ! */
+ t_u8 Aggregation : 1; /* ! Reserved */
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior : 1; /* !
+ Legacy/Trigg
+ */
+ t_u8 UserPri : 3; /* ! 802.1d User Priority */
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy : 2;
+ t_u8 Schedule : 1;
+ t_u8 Reserved17_23 : 7; /* ! Reserved */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed : 1; /* ! 1: Fixed size given in Size, 0: Var, size is
+ nominal */
+ t_u16 Size : 15; /* ! Nominal size in octets */
+#else
+ t_u16 Size : 15; /* ! Nominal size in octets */
+ t_u16 Fixed : 1; /* ! 1: Fixed size given in Size, 0: Var, size is
+ nominal */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole : 3; /* ! Whole portion */
+ t_u16 Fractional : 13; /* ! Fractional portion */
+#else
+ t_u16 Fractional : 13; /* ! Fractional portion */
+ t_u16 Whole : 3; /* ! Whole portion */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct {
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e {
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e {
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union {
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t {
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t {
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t {
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t {
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+#define MAX_DSCP_EXCEPTION_NUM 21
+/** DSCP Range */
+typedef struct MLAN_PACK_START _DSCP_Exception_t {
+ /* DSCP value 0 to 63 or ff */
+ t_u8 dscp_value;
+ /* user priority 0-7*/
+ t_u8 user_priority;
+} MLAN_PACK_END DSCP_Exception_t, *pDSCP_Exception_t;
+
+/** DSCP Range */
+typedef struct MLAN_PACK_START _DSCP_Range_t {
+ /* DSCP low value */
+ t_u8 dscp_low_value;
+ /* DSCP high value */
+ t_u8 dscp_high_value;
+} MLAN_PACK_END DSCP_Range_t, *pDSCP_Range_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t {
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** VHT MCS rate set field, refer to 802.11ac */
+typedef MLAN_PACK_START struct _VHT_MCS_set {
+ t_u16 rx_mcs_map;
+ t_u16 rx_max_rate; /* bit 29-31 reserved */
+ t_u16 tx_mcs_map;
+ t_u16 tx_max_rate; /* bit 61-63 reserved */
+} MLAN_PACK_END VHT_MCS_set_t, *pVHT_MCS_set_t;
+
+/** VHT Capabilities info field, reference 802.11ac D1.4 p89 */
+typedef MLAN_PACK_START struct _VHT_capa {
+#if 0
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 mpdu_max_len:2;
+ t_u8 chan_width:2;
+ t_u8 rx_LDPC:1;
+ t_u8 sgi_80:1;
+ t_u8 sgi_160:1;
+ t_u8 tx_STBC:1;
+ t_u8 rx_STBC:3;
+ t_u8 SU_beamformer_capa:1;
+ t_u8 SU_beamformee_capa:1;
+ t_u8 beamformer_ante_num:3;
+ t_u8 sounding_dim_num:3;
+ t_u8 MU_beamformer_capa:1;
+ t_u8 MU_beamformee_capa:1;
+ t_u8 VHT_TXOP_ps:1;
+ t_u8 HTC_VHT_capa:1;
+ t_u8 max_ampdu_len:3;
+ t_u8 link_apapt_capa:2;
+ t_u8 reserved_1:4;
+#else
+ t_u8 reserved_1:4;
+ t_u8 link_apapt_capa:2;
+ t_u8 max_ampdu_len:3;
+ t_u8 HTC_VHT_capa:1;
+ t_u8 VHT_TXOP_ps:1;
+ t_u8 MU_beamformee_capa:1;
+ t_u8 MU_beamformer_capa:1;
+ t_u8 sounding_dim_num:3;
+ t_u8 beamformer_ante_num:3;
+ t_u8 SU_beamformee_capa:1;
+ t_u8 SU_beamformer_capa:1;
+ t_u8 rx_STBC:3;
+ t_u8 tx_STBC:1;
+ t_u8 sgi_160:1;
+ t_u8 sgi_80:1;
+ t_u8 rx_LDPC:1;
+ t_u8 chan_width:2;
+ t_u8 mpdu_max_len:2;
+#endif /* BIG_ENDIAN_SUPPORT */
+#endif
+ t_u32 vht_cap_info;
+ VHT_MCS_set_t mcs_sets;
+} MLAN_PACK_END VHT_capa_t, *pVHT_capa_t;
+
+/** VHT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ VHT_capa_t vht_cap;
+} MLAN_PACK_END IEEEtypes_VHTCap_t, *pIEEEtypes_VHTCap_t;
+
+#define VHT_CAP_CHWD_80MHZ 0
+#define VHT_CAP_CHWD_160MHZ 1
+#define VHT_CAP_CHWD_80_80MHZ 2
+
+/** VHT Operations IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTOprat_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 chan_width;
+ t_u8 chan_center_freq_1;
+ t_u8 chan_center_freq_2;
+ /** Basic MCS set map, each 2 bits stands for a Nss */
+ t_u16 basic_MCS_map;
+} MLAN_PACK_END IEEEtypes_VHTOprat_t, *pIEEEtypes_VHTOprat_t;
+
+#define VHT_OPER_CHWD_20_40MHZ 0
+#define VHT_OPER_CHWD_80MHZ 1
+#define VHT_OPER_CHWD_160MHZ 2
+#define VHT_OPER_CHWD_80_80MHZ 3
+
+/** VHT Transmit Power Envelope IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTtxpower_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 max_tx_power;
+ t_u8 chan_center_freq;
+ t_u8 chan_width;
+} MLAN_PACK_END IEEEtypes_VHTtxpower_t, *pIEEEtypes_VHTtxpower_t;
+
+/** Extended Power Constraint IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtPwerCons_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** channel width */
+ t_u8 chan_width;
+ /** local power constraint */
+ t_u8 local_power_cons;
+} MLAN_PACK_END IEEEtypes_ExtPwerCons_t, *pIEEEtypes_ExtPwerCons_t;
+
+/** Extended BSS Load IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtBSSload_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 MU_MIMO_capa_count;
+ t_u8 stream_underutilization;
+ t_u8 VHT40_util;
+ t_u8 VHT80_util;
+ t_u8 VHT160_util;
+} MLAN_PACK_END IEEEtypes_ExtBSSload_t, *pIEEEtypes_ExtBSSload_t;
+
+/** Quiet Channel IE */
+typedef MLAN_PACK_START struct _IEEEtypes_QuietChan_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 AP_quiet_mode;
+ t_u8 quiet_count;
+ t_u8 quiet_period;
+ t_u16 quiet_dur;
+ t_u16 quiet_offset;
+} MLAN_PACK_END IEEEtypes_QuietChan_t, *pIEEEtypes_QuietChan_t;
+
+/** Wide Bandwidth Channel Switch IE */
+typedef MLAN_PACK_START struct _IEEEtypes_BWSwitch_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 new_chan_width;
+ t_u8 new_chan_center_freq_1;
+ t_u8 new_chan_center_freq_2;
+} MLAN_PACK_END IEEEtypes_BWSwitch_t, *pIEEEtypes_BWSwitch_t;
+
+/** AID IE */
+typedef MLAN_PACK_START struct _IEEEtypes_AID_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** AID number */
+ t_u16 AID;
+} MLAN_PACK_END IEEEtypes_AID_t, *pIEEEtypes_AID_t;
+
+/** Operating Mode Notificaton IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OperModeNtf_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Operating Mode */
+ t_u8 oper_mode;
+} MLAN_PACK_END IEEEtypes_OperModeNtf_t, *pIEEEtypes_OperModeNtf_t;
+
+typedef MLAN_PACK_START struct _IEEEtypes_Extension_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** payload */
+ t_u8 data[];
+} MLAN_PACK_END IEEEtypes_Extension_t, *pIEEEtypes_Extension_t;
+
+typedef MLAN_PACK_START struct _IEEEtypes_HECap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** he mac capability info */
+ t_u8 he_mac_cap[6];
+ /** he phy capability info */
+ t_u8 he_phy_cap[11];
+ /** he txrx mcs support , size would be 4 or 8 or 12 */
+ t_u8 he_txrx_mcs_support[4];
+ /** PPE Thresholds (optional) */
+} MLAN_PACK_END IEEEtypes_HECap_t, *pIEEEtypes_HECap_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d
+ chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame
+ (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/** default channel switch count */
+#define DEF_CHAN_SWITCH_COUNT 5
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/** data structure for extended channel switch */
+typedef MLAN_PACK_START struct {
+ /** IEEE element ID = 60 */
+ t_u8 element_id;
+ /** Element length after id and len, set to 4 */
+ t_u8 len;
+ /** STA should not transmit any frames if 1 */
+ t_u8 chan_switch_mode;
+ /** Operate class # that AP/IBSS is moving to */
+ t_u8 new_oper_class;
+ /** Channel # that AP/IBSS is moving to */
+ t_u8 new_channel_num;
+ /** of TBTTs before channel switch */
+ t_u8 chan_switch_count;
+} MLAN_PACK_END IEEEtypes_ExtChanSwitchAnn_t;
+
+/* IEEE Wide Bandwidth Channel Switch Element */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a wide bandwidth chan
+ * switch element.
+ */
+typedef MLAN_PACK_START struct {
+ /** Generic IE header IEEE Element ID = 194*/
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 new_channel_width;
+ t_u8 new_channel_center_freq0;
+ t_u8 new_channel_center_freq1;
+} MLAN_PACK_END IEEEtypes_WideBWChanSwitch_t;
+
+/* IEEE VHT Transmit Power Envelope Element */
+/**
+ * Provided in beacons and probe responses. Used to advertise the max
+ * TX power in sepeate bandwidth and as a sub element of Channel Switch
+ * Wrapper IE.
+ */
+typedef MLAN_PACK_START struct {
+ /** Generic IE header IEEE Element ID = 195*/
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 tpc_info; /**< Transmit Power Information>*/
+ t_u8 local_max_tp_20mhz; /**< Local Maximum Transmit Power for 20 MHZ>*/
+ t_u8 local_max_tp_40mhz; /**< Local Maximum Transmit Power for 40 MHZ>*/
+ t_u8 local_max_tp_80mhz; /**< Local Maximum Transmit Power for 80 MHZ>*/
+} MLAN_PACK_END IEEEtypes_VhtTpcEnvelope_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet
+ period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods
+ */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet
+ period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+ /**< Channel is unmeasured */
+ t_u8 unmeasured : 1;
+ /**< Radar detected on channel */
+ t_u8 radar : 1;
+ /**< Unidentified signal found on channel */
+ t_u8 unidentified_sig : 1;
+ /**< OFDM preamble detected on channel */
+ t_u8 ofdm_preamble : 1;
+ /**< At least one valid MPDU received on channel */
+ t_u8 bss : 1;
+#else
+ /**< At least one valid MPDU received on channel */
+ t_u8 bss : 1;
+ /**< OFDM preamble detected on channel */
+ t_u8 ofdm_preamble : 1;
+ /**< Unidentified signal found on channel */
+ t_u8 unidentified_sig : 1;
+ /**< Radar detected on channel */
+ t_u8 radar : 1;
+ /**< Channel is unmeasured */
+ t_u8 unmeasured : 1;
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel
+ */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel
+ */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct {
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE
+ */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE
+ */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch
+ Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+/** action code for 20/40 BSS Coexsitence Management frame */
+#define BSS_20_40_COEX 0
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Maximum length of BSSID list */
+#define MAX_BSSID_FILTER_LIST 5
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid {
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan {
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/** channel statictics */
+typedef MLAN_PACK_START struct _ChanStatistics_t {
+ /** channle number */
+ t_u8 chan_num;
+ /** band info */
+ Band_Config_t bandcfg;
+ /** flags */
+ t_u8 flags;
+ /** noise */
+ t_s8 noise;
+ /** total network */
+ t_u16 total_networks;
+ /** scan duration */
+ t_u16 cca_scan_duration;
+ /** busy duration */
+ t_u16 cca_busy_duration;
+ /** min rss */
+ t_u8 min_rss;
+ /** max rssi */
+ t_u8 max_rss;
+} MLAN_PACK_END ChanStatistics_t;
+
+/** Enhance ext scan type defination */
+typedef enum _MLAN_EXT_SCAN_TYPE {
+ EXT_SCAN_DEFAULT,
+ EXT_SCAN_ENHANCE,
+ EXT_SCAN_CANCEL,
+} MLAN_EXT_SCAN_TYPE;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct {
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief ssid filter flag
+ */
+ t_u8 ssid_filter;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the
+ * results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+ /** scan channel gap */
+ t_u16 scan_chan_gap;
+ /** scan type: 0 legacy, 1: enhance scan*/
+ t_u8 ext_scan_type;
+ /** flag to filer only probe response */
+ t_u8 proberesp_only;
+ t_u8 random_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Number of BSSIDs to be filtered */
+ t_u8 bssid_num;
+ /** BSSID filter list used in the to limit the scan results */
+ mlan_802_11_mac_addr bssid_list[MAX_BSSID_FILTER_LIST];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/**wait for all channel scan to complete to report scan result*/
+#define BG_SCAN_WAIT_ALL_CHAN_DONE 0x80000000
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 38
+
+/** Enumeration definition */
+/** EES MODE */
+typedef enum {
+ /** EES MODE: LOW */
+ EES_MODE_LOW = 0,
+ /** EES MODE: MID */
+ EES_MODE_MID,
+ /** EES MODE: HIGH */
+ EES_MODE_HIGH,
+ /** EES MODE: OFF */
+ EES_MODE_OFF,
+ /** EES MODE: LOOP */
+ EES_MODE_LOOP = 15,
+} ees_modes;
+
+/** EES Maximum SSID */
+#define EES_MAX_SSIDS 2
+
+/** ees_ssid_config */
+typedef MLAN_PACK_START struct {
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END ees_ssid_config;
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct {
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
+ /** start later flag */
+ t_u16 start_later;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+ /** scan channel gap */
+ t_u16 scan_chan_gap;
+ /** Enable EES configuration */
+ t_u8 config_ees;
+ /** EES scan mode */
+ t_u16 ees_mode;
+ /** EES report condition */
+ t_u16 report_cond;
+ /** EES High Period scan interval */
+ t_u16 high_period;
+ /** EES High Period scan count */
+ t_u16 high_period_count;
+ /** EES Medium Period scan interval */
+ t_u16 mid_period;
+ /** EES Medium Period scan count */
+ t_u16 mid_period_count;
+ /** EES Low Period scan interval */
+ t_u16 low_period;
+ /** EES Low Period scan count */
+ t_u16 low_period_count;
+ /** Number of networks in the list */
+ t_u8 network_count;
+ /** Maximum number of connection count */
+ t_u8 max_conn_count;
+ /** Black List Exp */
+ t_u8 black_list_exp;
+ /** Array of ees config struct */
+ ees_ssid_config ees_ssid_cfg[EES_MAX_SSIDS];
+ t_u8 random_mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t {
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+ /** channel load */
+ t_u8 chan_load;
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Current channel bandwidth
+ * 0 : 20MHZ
+ * 1 : 40MHZ
+ * 2 : 80MHZ
+ * 3 : 160MHZ
+ */
+ t_u8 curr_bandwidth;
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+ /** VHT Capabilities IE */
+ IEEEtypes_VHTCap_t *pvht_cap;
+ /** VHT Capabilities IE offset */
+ t_u16 vht_cap_offset;
+ /** VHT Operations IE */
+ IEEEtypes_VHTOprat_t *pvht_oprat;
+ /** VHT Operations IE offset */
+ t_u16 vht_oprat_offset;
+ /** VHT Transmit Power Envelope IE */
+ IEEEtypes_VHTtxpower_t *pvht_txpower;
+ /** VHT Transmit Power Envelope IE offset */
+ t_u16 vht_txpower_offset;
+ /** Extended Power Constraint IE */
+ IEEEtypes_ExtPwerCons_t *pext_pwer;
+ /** Extended Power Constraint IE offset */
+ t_u16 ext_pwer_offset;
+ /** Extended BSS Load IE */
+ IEEEtypes_ExtBSSload_t *pext_bssload;
+ /** Extended BSS Load IE offset */
+ t_u16 ext_bssload_offset;
+ /** Quiet Channel IE */
+ IEEEtypes_QuietChan_t *pquiet_chan;
+ /** Quiet Channel IE offset */
+ t_u16 quiet_chan_offset;
+ /** Operating Mode Notification IE */
+ IEEEtypes_OperModeNtf_t *poper_mode;
+ /** Operating Mode Notification IE offset */
+ t_u16 oper_mode_offset;
+ /** HE Capability IE */
+ IEEEtypes_HECap_t *phe_cap;
+ /** HE Capability IE offset */
+ t_u16 he_cap_offset;
+ /** HE operation IE */
+ IEEEtypes_Extension_t *phe_oprat;
+ /** HE operation IE offset */
+ t_u16 he_oprat_offset;
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+ /* Hotspot 2.0 OSEN AKM IE*/
+ IEEEtypes_Generic_t *posen_ie;
+ /** osen IE offset in the beacon buffer */
+ t_u16 osen_offset;
+ /* Mobility domain IE */
+ IEEEtypes_MobilityDomain_t *pmd_ie;
+ /** Mobility domain IE offset in the beacon buffer */
+ t_u16 md_offset;
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.c
new file mode 100644
index 000000000000..e81299d690a4
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.c
@@ -0,0 +1,1959 @@
+/** @file mlan_init.c
+ *
+ * @brief This file contains the initialization for FW
+ * and HW.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11h.h"
+#include "mlan_meas.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+#include "hostsa_init.h"
+#endif
+#include "mlan_11ax.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern pmlan_operations mlan_ops[];
+/*******************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function adds a BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_add_bsspriotbl(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ status = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_bssprio_node),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pbssprio);
+ if (status) {
+ PRINTM(MERROR, "Failed to allocate bsspriotbl\n");
+ LEAVE();
+ return status;
+ }
+
+ pbssprio->priv = priv;
+
+ util_init_list((pmlan_linked_list)pbssprio);
+
+ if (!pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur)
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pbssprio;
+
+ util_enqueue_list_tail(
+ pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[priv->bss_priority].bssprio_head,
+ (pmlan_linked_list)pbssprio,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function deletes the BSS priority table
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void wlan_delete_bsspriotbl(pmlan_private priv)
+{
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_bssprio_node *pbssprio_node = MNULL, *ptmp_node = MNULL,
+ **ppcur = MNULL;
+ pmlan_list_head phead;
+
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; ++i) {
+ phead = &pmadapter->bssprio_tbl[i].bssprio_head;
+ ppcur = &pmadapter->bssprio_tbl[i].bssprio_cur;
+ PRINTM(MINFO,
+ "Delete BSS priority table, index = %d, i = %d, phead = %p, pcur = %p\n",
+ priv->bss_index, i, phead, *ppcur);
+ if (*ppcur) {
+ pbssprio_node = (mlan_bssprio_node *)util_peek_list(
+ pmadapter->pmoal_handle, phead,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ while (pbssprio_node &&
+ ((pmlan_list_head)pbssprio_node != phead)) {
+ ptmp_node = pbssprio_node->pnext;
+ if (pbssprio_node->priv == priv) {
+ PRINTM(MINFO,
+ "Delete node, pnode = %p, pnext = %p\n",
+ pbssprio_node, ptmp_node);
+ util_unlink_list(
+ pmadapter->pmoal_handle, phead,
+ (pmlan_linked_list)pbssprio_node,
+ pmadapter->callbacks
+ .moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock);
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pbssprio_node);
+ }
+ pbssprio_node = ptmp_node;
+ }
+ *ppcur = (mlan_bssprio_node *)phead;
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief The function handles VDLL init
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+static mlan_status vdll_init(pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl;
+
+ ENTER();
+ memset(pmadapter, ctrl, 0, sizeof(vdll_dnld_ctrl));
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ ctrl->cmd_buf =
+ wlan_alloc_mlan_buffer(pmadapter,
+ MRVDRV_SIZE_OF_CMD_BUFFER, 0,
+ MOAL_MALLOC_BUFFER);
+ if (!ctrl->cmd_buf) {
+ PRINTM(MERROR,
+ "vdll init: fail to alloc command buffer");
+ status = MLAN_STATUS_FAILURE;
+ }
+ }
+#endif
+ LEAVE();
+ return status;
+}
+/**
+ * @brief The function handles VDLL deinit
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+static t_void vdll_deinit(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ if (pmadapter->vdll_ctrl.vdll_mem != MNULL) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->vdll_ctrl.vdll_mem);
+ else
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->vdll_ctrl.vdll_mem);
+ pmadapter->vdll_ctrl.vdll_mem = MNULL;
+ pmadapter->vdll_ctrl.vdll_len = 0;
+ }
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type) &&
+ pmadapter->vdll_ctrl.cmd_buf != MNULL) {
+ wlan_free_mlan_buffer(pmadapter, pmadapter->vdll_ctrl.cmd_buf);
+ pmadapter->vdll_ctrl.cmd_buf = MNULL;
+ }
+#endif
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function allocates buffer for the members of adapter
+ * structure like command buffer and BSSID list.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_allocate_adapter(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef STA_SUPPORT
+ t_u32 beacon_buffer_size;
+ t_u32 buf_size;
+ BSSDescriptor_t *ptemp_scan_table = MNULL;
+ t_u8 chan_2g[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ t_u8 chan_5g[] = {12, 16, 34, 38, 42, 46, 36, 40, 44, 48, 52,
+ 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128,
+ 132, 136, 140, 144, 149, 153, 157, 161, 165};
+#endif
+#ifdef SDIO
+ t_u32 max_mp_regs = 0;
+ t_u32 mp_tx_aggr_buf_size = 0;
+ t_u32 mp_rx_aggr_buf_size = 0;
+#endif
+
+ ENTER();
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ max_mp_regs = pmadapter->pcard_sd->reg->max_mp_regs;
+ mp_tx_aggr_buf_size = SDIO_MP_AGGR_BUF_SIZE_MAX;
+ mp_rx_aggr_buf_size = SDIO_MP_AGGR_BUF_SIZE_MAX;
+ }
+#endif
+
+#ifdef STA_SUPPORT
+ /* Allocate buffer to store the BSSID list */
+ buf_size = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+ if (pmadapter->callbacks.moal_vmalloc &&
+ pmadapter->callbacks.moal_vfree)
+ ret = pmadapter->callbacks.moal_vmalloc(
+ pmadapter->pmoal_handle, buf_size,
+ (t_u8 **)&ptemp_scan_table);
+ else
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
+ (t_u8 **)&ptemp_scan_table);
+ if (ret != MLAN_STATUS_SUCCESS || !ptemp_scan_table) {
+ PRINTM(MERROR, "Failed to allocate scan table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pscan_table = ptemp_scan_table;
+
+ if (pmadapter->fixed_beacon_buffer)
+ beacon_buffer_size = MAX_SCAN_BEACON_BUFFER;
+ else
+ beacon_buffer_size = DEFAULT_SCAN_BEACON_BUFFER;
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ beacon_buffer_size, MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->bcn_buf);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->bcn_buf) {
+ PRINTM(MERROR, "Failed to allocate bcn buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->bcn_buf_size = beacon_buffer_size;
+
+ pmadapter->num_in_chan_stats = sizeof(chan_2g);
+ pmadapter->num_in_chan_stats += sizeof(chan_5g);
+ buf_size = sizeof(ChanStatistics_t) * pmadapter->num_in_chan_stats;
+ if (pmadapter->callbacks.moal_vmalloc &&
+ pmadapter->callbacks.moal_vfree)
+ ret = pmadapter->callbacks.moal_vmalloc(
+ pmadapter->pmoal_handle, buf_size,
+ (t_u8 **)&pmadapter->pchan_stats);
+ else
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->pchan_stats);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pchan_stats) {
+ PRINTM(MERROR, "Failed to allocate channel statistics\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+
+ /* Allocate command buffer */
+ ret = wlan_alloc_cmd_buffer(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to allocate command buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, max_mp_regs + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->mp_regs_buf);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->mp_regs_buf) {
+ PRINTM(MERROR, "Failed to allocate mp_regs_buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pcard_sd->mp_regs = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->mp_regs_buf, DMA_ALIGNMENT);
+
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle, MAX_SUPPORT_AMSDU_SIZE,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->rx_buffer);
+
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->rx_buffer) {
+ PRINTM(MERROR, "Failed to allocate receive buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pcard_sd->rx_buf = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->rx_buffer, DMA_ALIGNMENT);
+
+ pmadapter->pcard_sd->max_sp_tx_size = MAX_SUPPORT_AMSDU_SIZE;
+ pmadapter->pcard_sd->max_sp_rx_size = MAX_SUPPORT_AMSDU_SIZE;
+ ret = wlan_alloc_sdio_mpa_buffers(
+ pmadapter, mp_tx_aggr_buf_size, mp_rx_aggr_buf_size);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to allocate sdio mp-a buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef DEBUG_LEVEL1
+ if (mlan_drvdbg & MMPA_D) {
+ pmadapter->pcard_sd->mpa_buf_size =
+ SDIO_MP_DBG_NUM * SDIO_MP_AGGR_DEF_PKT_LIMIT *
+ MLAN_SDIO_BLOCK_SIZE;
+ if (pmadapter->callbacks.moal_vmalloc &&
+ pmadapter->callbacks.moal_vfree)
+ ret = pmadapter->callbacks.moal_vmalloc(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->mpa_buf_size,
+ (t_u8 **)&pmadapter->pcard_sd->mpa_buf);
+ else
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->mpa_buf_size,
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->pcard_sd->mpa_buf);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->mpa_buf) {
+ PRINTM(MERROR, "Failed to allocate mpa buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+#endif
+ }
+#endif
+
+ pmadapter->psleep_cfm =
+ wlan_alloc_mlan_buffer(pmadapter,
+ sizeof(opt_sleep_confirm_buffer), 0,
+ MOAL_MALLOC_BUFFER);
+
+#ifdef PCIE
+ /* Initialize PCIE ring buffer */
+ if (IS_PCIE(pmadapter->card_type)) {
+ ret = wlan_alloc_pcie_ring_buf(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ PRINTM(MERROR,
+ "Failed to allocate PCIE host buffers\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+#endif /* PCIE */
+
+ vdll_init(pmadapter);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function initializes the private structure
+ * and sets default values to the members of mlan_private.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_init_priv(pmlan_private priv)
+{
+ t_u32 i;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef USB
+ pusb_tx_aggr_params pusb_tx_aggr = MNULL;
+#endif
+
+ ENTER();
+
+ priv->media_connected = MFALSE;
+ memset(pmadapter, priv->curr_addr, 0xff, MLAN_MAC_ADDR_LENGTH);
+
+#ifdef STA_SUPPORT
+ priv->pkt_tx_ctrl = 0;
+ priv->bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->data_rate = 0; /* Initially indicate the rate as auto */
+ priv->is_data_rate_auto = MTRUE;
+ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ priv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ priv->sec_info.authentication_mode = MLAN_AUTH_MODE_AUTO;
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+ for (i = 0; i < MRVL_NUM_WEP_KEY; i++)
+ memset(pmadapter, &priv->wep_key[i], 0, sizeof(mrvl_wep_key_t));
+ priv->wep_key_curr_index = 0;
+ priv->ewpa_query = MFALSE;
+ priv->curr_pkt_filter = HostCmd_ACT_MAC_STATIC_DYNAMIC_BW_ENABLE |
+ HostCmd_ACT_MAC_RTS_CTS_ENABLE |
+ HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+ HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+ priv->beacon_period = MLAN_BEACON_INTERVAL;
+ priv->pattempted_bss_desc = MNULL;
+ memset(pmadapter, &priv->gtk_rekey, 0,
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+ memset(pmadapter, &priv->curr_bss_params, 0,
+ sizeof(priv->curr_bss_params));
+ priv->listen_interval = MLAN_DEFAULT_LISTEN_INTERVAL;
+
+ memset(pmadapter, &priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+ priv->assoc_rsp_size = 0;
+
+ wlan_11d_priv_init(priv);
+ wlan_11h_priv_init(priv);
+
+#ifdef UAP_SUPPORT
+ priv->uap_bss_started = MFALSE;
+ priv->uap_host_based = MFALSE;
+ memset(pmadapter, &priv->uap_state_chan_cb, 0,
+ sizeof(priv->uap_state_chan_cb));
+#endif
+#ifdef UAP_SUPPORT
+ priv->num_drop_pkts = 0;
+#endif
+#if defined(STA_SUPPORT)
+ priv->adhoc_state_prev = ADHOC_IDLE;
+ memset(pmadapter, &priv->adhoc_last_start_ssid, 0,
+ sizeof(priv->adhoc_last_start_ssid));
+#endif
+ priv->atim_window = 0;
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->tx_power_level = 0;
+ priv->max_tx_power_level = 0;
+ priv->min_tx_power_level = 0;
+ priv->tx_rate = 0;
+ priv->rxpd_rate_info = 0;
+ priv->rx_pkt_info = MFALSE;
+ /* refer to V15 CMD_TX_RATE_QUERY */
+ priv->rxpd_vhtinfo = 0;
+ priv->rxpd_rate = 0;
+ priv->data_rssi_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->data_nf_last = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->bcn_nf_last = 0;
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ memset(pmadapter, &priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ memset(pmadapter, &priv->aes_key, 0, sizeof(priv->aes_key));
+ priv->wpa_ie_len = 0;
+ priv->wpa_is_gtk_set = MFALSE;
+#if defined(STA_SUPPORT)
+ priv->pmfcfg.mfpc = 0;
+ priv->pmfcfg.mfpr = 0;
+#endif
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ memset(pmadapter, &priv->wps, 0, sizeof(priv->wps));
+ memset(pmadapter, &priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+ priv->gen_ie_buf_len = 0;
+#endif /* STA_SUPPORT */
+ priv->wmm_required = MTRUE;
+ priv->wmm_enabled = MFALSE;
+ priv->wmm_qosinfo = 0;
+#ifdef STA_SUPPORT
+ priv->pcurr_bcn_buf = MNULL;
+ priv->curr_bcn_size = 0;
+ memset(pmadapter, &priv->ext_cap, 0, sizeof(priv->ext_cap));
+
+ SET_EXTCAP_OPERMODENTF(priv->ext_cap);
+ SET_EXTCAP_QOS_MAP(priv->ext_cap);
+ /* Save default Extended Capability */
+ memcpy_ext(priv->adapter, &priv->def_ext_cap, &priv->ext_cap,
+ sizeof(priv->ext_cap), sizeof(priv->def_ext_cap));
+#endif /* STA_SUPPORT */
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ priv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ priv->addba_reject[6] = ADDBA_RSP_STATUS_REJECT;
+ priv->addba_reject[7] = ADDBA_RSP_STATUS_REJECT;
+ memcpy_ext(priv->adapter, priv->ibss_addba_reject, priv->addba_reject,
+ sizeof(priv->addba_reject), sizeof(priv->ibss_addba_reject));
+ priv->max_amsdu = 0;
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ priv->add_ba_param.tx_win_size = MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ priv->aggr_prio_tbl[6].ampdu_user =
+ priv->aggr_prio_tbl[7].ampdu_user =
+ BA_STREAM_NOT_ALLOWED;
+ }
+#endif
+ priv->user_rxwinsize = priv->add_ba_param.rx_win_size;
+
+ priv->port_ctrl_mode = MTRUE;
+ priv->port_open = MFALSE;
+
+ priv->intf_hr_len = pmadapter->ops.intf_header_len;
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pusb_tx_aggr =
+ wlan_get_usb_tx_aggr_params(pmadapter, priv->port);
+ if (pusb_tx_aggr && pusb_tx_aggr->aggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_LEN_V2) {
+ priv->intf_hr_len = MLAN_USB_TX_AGGR_HEADER;
+ }
+ priv->port = pmadapter->tx_data_ep;
+ }
+#endif
+ ret = wlan_add_bsspriotbl(priv);
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ hostsa_init(priv);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the adapter structure
+ * and sets default values to the members of adapter.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_init_adapter(pmlan_adapter pmadapter)
+{
+ opt_sleep_confirm_buffer *sleep_cfm_buf = MNULL;
+#ifdef USB
+ t_s32 i = 0;
+#endif
+ ENTER();
+
+ if (pmadapter->psleep_cfm) {
+ sleep_cfm_buf = (opt_sleep_confirm_buffer
+ *)(pmadapter->psleep_cfm->pbuf +
+ pmadapter->psleep_cfm->data_offset);
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->init_para.mfg_mode == MLAN_INIT_PARA_DISABLED)
+ pmadapter->mfg_mode = MFALSE;
+ else
+ pmadapter->mfg_mode = pmadapter->init_para.mfg_mode;
+#endif
+
+#ifdef STA_SUPPORT
+ pmadapter->pwarm_reset_ioctl_req = MNULL;
+#endif
+ pmadapter->cmd_sent = MFALSE;
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ pmadapter->pcard_sd->int_mode = pmadapter->init_para.int_mode;
+ pmadapter->pcard_sd->gpio_pin = pmadapter->init_para.gpio_pin;
+ pmadapter->data_sent = MTRUE;
+ pmadapter->pcard_sd->mp_rd_bitmap = 0;
+ pmadapter->pcard_sd->mp_wr_bitmap = 0;
+ pmadapter->pcard_sd->curr_rd_port = 0;
+ pmadapter->pcard_sd->curr_wr_port = 0;
+ pmadapter->pcard_sd->mp_data_port_mask =
+ pmadapter->pcard_sd->reg->data_port_mask;
+ pmadapter->pcard_sd->mp_invalid_update = 0;
+ memset(pmadapter, pmadapter->pcard_sd->mp_update, 0,
+ sizeof(pmadapter->pcard_sd->mp_update));
+ pmadapter->pcard_sd->mpa_tx.buf_len = 0;
+ pmadapter->pcard_sd->mpa_tx.pkt_cnt = 0;
+ pmadapter->pcard_sd->mpa_tx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_tx_cfg)
+ pmadapter->pcard_sd->mpa_tx.enabled = MFALSE;
+ else if (pmadapter->init_para.mpa_tx_cfg ==
+ MLAN_INIT_PARA_DISABLED)
+ pmadapter->pcard_sd->mpa_tx.enabled = MFALSE;
+ else
+ pmadapter->pcard_sd->mpa_tx.enabled = MTRUE;
+ pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit =
+ SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ pmadapter->pcard_sd->mpa_rx.buf_len = 0;
+ pmadapter->pcard_sd->mpa_rx.pkt_cnt = 0;
+ pmadapter->pcard_sd->mpa_rx.start_port = 0;
+
+ if (!pmadapter->init_para.mpa_rx_cfg)
+ pmadapter->pcard_sd->mpa_rx.enabled = MFALSE;
+ else if (pmadapter->init_para.mpa_rx_cfg ==
+ MLAN_INIT_PARA_DISABLED)
+ pmadapter->pcard_sd->mpa_rx.enabled = MFALSE;
+ else
+ pmadapter->pcard_sd->mpa_rx.enabled = MTRUE;
+ pmadapter->pcard_sd->mpa_rx.pkt_aggr_limit =
+ SDIO_MP_AGGR_DEF_PKT_LIMIT;
+ }
+#endif
+
+ pmadapter->rx_pkts_queued = 0;
+ pmadapter->cmd_resp_received = MFALSE;
+ pmadapter->event_received = MFALSE;
+ pmadapter->data_received = MFALSE;
+
+ pmadapter->cmd_timer_is_set = MFALSE;
+
+ /* PnP and power profile */
+ pmadapter->surprise_removed = MFALSE;
+ /* FW hang report */
+ pmadapter->fw_hang_report = MFALSE;
+
+ if (!pmadapter->init_para.ps_mode) {
+ pmadapter->ps_mode = DEFAULT_PS_MODE;
+ } else if (pmadapter->init_para.ps_mode == MLAN_INIT_PARA_DISABLED)
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->need_to_wakeup = MFALSE;
+
+#ifdef STA_SUPPORT
+ pmadapter->scan_block = MFALSE;
+ /* Scan type */
+ pmadapter->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ /* Scan mode */
+ pmadapter->scan_mode = HostCmd_BSS_MODE_ANY;
+ /* Scan time */
+ pmadapter->specific_scan_time = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+ pmadapter->active_scan_time = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ pmadapter->passive_scan_time = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+ if (!pmadapter->init_para.passive_to_active_scan)
+ pmadapter->passive_to_active_scan = MLAN_PASS_TO_ACT_SCAN_EN;
+ else if (pmadapter->init_para.passive_to_active_scan ==
+ MLAN_INIT_PARA_DISABLED)
+ pmadapter->passive_to_active_scan = MLAN_PASS_TO_ACT_SCAN_DIS;
+ else
+ pmadapter->passive_to_active_scan = MLAN_PASS_TO_ACT_SCAN_EN;
+
+ pmadapter->scan_chan_gap = 0;
+ pmadapter->num_in_scan_table = 0;
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->active_scan_triggered = MFALSE;
+ pmadapter->ext_scan = MTRUE;
+ pmadapter->scan_probes = DEFAULT_PROBES;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ pmadapter->radio_on = RADIO_ON;
+ if (!pmadapter->multiple_dtim)
+ pmadapter->multiple_dtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ pmadapter->local_listen_interval = 0; /* default value in firmware will
+ be used */
+#endif /* STA_SUPPORT */
+
+ pmadapter->is_deep_sleep = MFALSE;
+ pmadapter->idle_time = DEEP_SLEEP_IDLE_TIME;
+ if (!pmadapter->init_para.auto_ds)
+ pmadapter->init_auto_ds = DEFAULT_AUTO_DS_MODE;
+ else if (pmadapter->init_para.auto_ds == MLAN_INIT_PARA_DISABLED)
+ pmadapter->init_auto_ds = MFALSE;
+ else
+ pmadapter->init_auto_ds = MTRUE;
+
+ pmadapter->delay_null_pkt = MFALSE;
+ pmadapter->delay_to_ps = DELAY_TO_PS_DEFAULT;
+ pmadapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+ pmadapter->gen_null_pkt = MFALSE; /* Disable NULL Pkt generation-default
+ */
+ pmadapter->pps_uapsd_mode = MFALSE; /* Disable pps/uapsd mode -default
+ */
+
+ pmadapter->pm_wakeup_card_req = MFALSE;
+
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+
+ if (!pmadapter->init_para.max_tx_buf)
+ pmadapter->max_tx_buf_size =
+ pmadapter->pcard_info->max_tx_buf_size;
+ else
+ pmadapter->max_tx_buf_size =
+ (t_u16)pmadapter->init_para.max_tx_buf;
+ pmadapter->tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+ pmadapter->curr_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K;
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.enable =
+ MFALSE;
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_mode =
+ MLAN_USB_AGGR_MODE_LEN_V2;
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_align =
+ MLAN_USB_TX_AGGR_V2_ALIGN;
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.aggr_max =
+ MLAN_USB_TX_AGGR_MAX_LEN;
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.aggr_tmo =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
+
+ pmadapter->pcard_usb->usb_tx_aggr[i].pmbuf_aggr = MNULL;
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_len = 0;
+ pmadapter->pcard_usb->usb_tx_aggr[i].hold_timeout_msec =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC;
+ pmadapter->pcard_usb->usb_tx_aggr[i].port =
+ pmadapter->tx_data_ep;
+ pmadapter->pcard_usb->usb_tx_aggr[i].phandle =
+ (t_void *)pmadapter;
+ }
+
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable = MFALSE;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_mode =
+ MLAN_USB_AGGR_MODE_NUM;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_align =
+ MLAN_USB_RX_ALIGN_SIZE;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_max =
+ MLAN_USB_RX_MAX_AGGR_NUM;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_tmo =
+ MLAN_USB_RX_DEAGGR_TIMEOUT_USEC;
+
+ pmadapter->pcard_usb->fw_usb_aggr = MTRUE;
+ }
+#endif
+
+ pmadapter->is_hs_configured = MFALSE;
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+ pmadapter->hs_activated = MFALSE;
+ pmadapter->min_wake_holdoff = HOST_SLEEP_DEF_WAKE_HOLDOFF;
+ pmadapter->hs_inactivity_timeout = HOST_SLEEP_DEF_INACTIVITY_TIMEOUT;
+
+ memset(pmadapter, pmadapter->event_body, 0,
+ sizeof(pmadapter->event_body));
+ pmadapter->hw_dot_11n_dev_cap = 0;
+ pmadapter->hw_dev_mcs_support = 0;
+ pmadapter->coex_rx_winsize = 1;
+#ifdef STA_SUPPORT
+ pmadapter->chan_bandwidth = 0;
+#endif /* STA_SUPPORT */
+
+ pmadapter->min_ba_threshold = MIN_BA_THRESHOLD;
+ pmadapter->hw_dot_11ac_dev_cap = 0;
+ pmadapter->hw_dot_11ac_mcs_support = 0;
+ pmadapter->max_sta_conn = 0;
+ /* Initialize 802.11d */
+ wlan_11d_init(pmadapter);
+
+ wlan_11h_init(pmadapter);
+
+ wlan_wmm_init(pmadapter);
+ wlan_init_wmm_param(pmadapter);
+ pmadapter->bypass_pkt_count = 0;
+ if (pmadapter->psleep_cfm) {
+ pmadapter->psleep_cfm->buf_type = MLAN_BUF_TYPE_CMD;
+ pmadapter->psleep_cfm->data_len = sizeof(OPT_Confirm_Sleep);
+ memset(pmadapter, &sleep_cfm_buf->ps_cfm_sleep, 0,
+ sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->ps_cfm_sleep.size =
+ wlan_cpu_to_le16(sizeof(OPT_Confirm_Sleep));
+ sleep_cfm_buf->ps_cfm_sleep.result = 0;
+ sleep_cfm_buf->ps_cfm_sleep.action =
+ wlan_cpu_to_le16(SLEEP_CONFIRM);
+ sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl =
+ wlan_cpu_to_le16(RESP_NEEDED);
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ sleep_cfm_buf->hdr =
+ wlan_cpu_to_le32(MLAN_USB_TYPE_CMD);
+ pmadapter->psleep_cfm->data_len += MLAN_TYPE_LEN;
+ }
+#endif
+ }
+ memset(pmadapter, &pmadapter->sleep_params, 0,
+ sizeof(pmadapter->sleep_params));
+ memset(pmadapter, &pmadapter->sleep_period, 0,
+ sizeof(pmadapter->sleep_period));
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->null_pkt_interval = 0;
+ pmadapter->fw_bands = 0;
+ pmadapter->config_bands = 0;
+ pmadapter->adhoc_start_band = 0;
+ pmadapter->pscan_channels = MNULL;
+ pmadapter->fw_release_number = 0;
+ pmadapter->fw_cap_info = 0;
+ memset(pmadapter, &pmadapter->upld_buf, 0, sizeof(pmadapter->upld_buf));
+ pmadapter->upld_len = 0;
+ pmadapter->event_cause = 0;
+ pmadapter->pmlan_buffer_event = MNULL;
+ memset(pmadapter, &pmadapter->region_channel, 0,
+ sizeof(pmadapter->region_channel));
+ pmadapter->region_code = 0;
+ memcpy_ext(pmadapter, pmadapter->country_code,
+ MRVDRV_DEFAULT_COUNTRY_CODE, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ pmadapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type)) {
+ pmadapter->pcard_pcie->txbd_wrptr = 0;
+ pmadapter->pcard_pcie->txbd_rdptr = 0;
+ pmadapter->pcard_pcie->rxbd_rdptr = 0;
+ pmadapter->pcard_pcie->evtbd_rdptr = 0;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->rxbd_wrptr =
+ pmadapter->pcard_pcie->reg
+ ->txrx_rw_ptr_rollover_ind;
+ pmadapter->pcard_pcie->evtbd_wrptr =
+ EVT_RW_PTR_ROLLOVER_IND;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->rxbd_wrptr = MLAN_MAX_TXRX_BD;
+ pmadapter->pcard_pcie->evtbd_wrptr = MLAN_MAX_EVT_BD;
+ }
+#endif
+ }
+#endif
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the lock variables and
+ * the list heads for interface
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ * @param start_index start index of mlan private
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_init_priv_lock_list(pmlan_adapter pmadapter, t_u8 start_index)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_u32 j = 0;
+ for (i = start_index; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &priv->rx_pkt_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &priv->wmm.ra_list_spinlock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#ifdef STA_SUPPORT
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &priv->curr_bcn_buf_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#endif
+ }
+ }
+ for (i = start_index; i < pmadapter->priv_num; ++i) {
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ MTRUE, pmadapter->callbacks.moal_init_lock);
+ pmadapter->bssprio_tbl[i].bssprio_cur = MNULL;
+ }
+
+ for (i = start_index; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j) {
+ util_init_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list,
+ MTRUE,
+ priv->adapter->callbacks.moal_init_lock);
+ }
+ util_init_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *)pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, 0,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *)pmadapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ HIGH_PRIO_TID,
+ priv->wmm.ra_list_spinlock,
+ pmadapter->callbacks.moal_init_lock);
+ util_init_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->sta_list, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize bypass_txq */
+ util_init_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->bypass_txq, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ }
+ }
+error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function intializes the lock variables and
+ * the list heads.
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_init_lock_list(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+ ENTER();
+
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->pmlan_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->pint_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ }
+#endif
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->pmain_proc_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->prx_proc_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->pmlan_cmd_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pcb->moal_init_lock(pmadapter->pmoal_handle,
+ &pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .paggr_lock) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ }
+ }
+#endif
+
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ util_scalar_init((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts, 0, MNULL,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_free_q */
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize cmd_pending_q */
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+ /* Initialize scan_pending_q */
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+ /* Initialize ioctl_pending_q */
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->ioctl_pending_q, MTRUE,
+ pmadapter->callbacks.moal_init_lock);
+
+error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the lock variables
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void wlan_free_lock_list(pmlan_adapter pmadapter)
+{
+ pmlan_private priv = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_s32 i = 0;
+ t_s32 j = 0;
+
+ ENTER();
+
+ if (pmadapter->pmlan_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pmlan_lock);
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type) && pmadapter->pint_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+#endif
+ if (pmadapter->prx_proc_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ if (pmadapter->pmain_proc_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ if (pmadapter->pmlan_cmd_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_lock);
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pmadapter->pcard_usb->usb_tx_aggr[i].paggr_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .paggr_lock);
+ }
+ }
+#endif
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ if (priv->rx_pkt_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->rx_pkt_lock);
+ if (priv->wmm.ra_list_spinlock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+#ifdef STA_SUPPORT
+ if (priv->curr_bcn_buf_lock)
+ pcb->moal_free_lock(pmadapter->pmoal_handle,
+ priv->curr_bcn_buf_lock);
+#endif
+ }
+ }
+
+ /* Free lists */
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue, pcb->moal_free_lock);
+
+ util_scalar_free((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts, pcb->moal_free_lock);
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->cmd_free_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->ioctl_pending_q,
+ pmadapter->callbacks.moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++)
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[i].bssprio_head,
+ pcb->moal_free_lock);
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+ util_free_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->sta_list,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head(
+ (t_void *)pmadapter->pmoal_handle,
+ &priv->bypass_txq,
+ pmadapter->callbacks.moal_free_lock);
+ for (j = 0; j < MAX_NUM_TID; ++j)
+ util_free_list_head(
+ (t_void *)priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[j].ra_list,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head(
+ (t_void *)priv->adapter->pmoal_handle,
+ &priv->tx_ba_stream_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_free_list_head(
+ (t_void *)priv->adapter->pmoal_handle,
+ &priv->rx_reorder_tbl_ptr,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free(
+ (t_void *)priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ priv->adapter->callbacks.moal_free_lock);
+ util_scalar_free(
+ (t_void *)priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio,
+ priv->adapter->callbacks.moal_free_lock);
+ }
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function intializes the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- on success,
+ * otherwise MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_init_timer(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+ ENTER();
+
+ if (pcb->moal_init_timer(
+ pmadapter->pmoal_handle, &pmadapter->pmlan_cmd_timer,
+ wlan_cmd_timeout_func, pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pcb->moal_init_timer(
+ pmadapter->pmoal_handle,
+ &pmadapter->pcard_usb->usb_tx_aggr[i]
+ .paggr_hold_timer,
+ wlan_usb_tx_aggr_timeout_func,
+ &pmadapter->pcard_usb->usb_tx_aggr[i]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ }
+ }
+#endif
+ if (pcb->moal_init_timer(pmadapter->pmoal_handle,
+ &pmadapter->pwakeup_fw_timer,
+ wlan_wakeup_card_timeout_func,
+ pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->wakeup_fw_timer_is_set = MFALSE;
+error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function releases the timers
+ *
+ * @param pmadapter A pointer to a mlan_adapter structure
+ *
+ * @return None
+ *
+ */
+t_void wlan_free_timer(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+ ENTER();
+
+ if (pmadapter->pmlan_cmd_timer)
+ pcb->moal_free_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pmadapter->pcard_usb->usb_tx_aggr[i]
+ .paggr_hold_timer)
+ pcb->moal_free_timer(pmadapter->pmoal_handle,
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .paggr_hold_timer);
+ }
+ }
+#endif
+
+ if (pmadapter->pwakeup_fw_timer)
+ pcb->moal_free_timer(pmadapter->pmoal_handle,
+ pmadapter->pwakeup_fw_timer);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING or
+ * MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_init_fw(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef PCIE
+ pmlan_private priv = pmadapter->priv[0];
+#endif
+ ENTER();
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ wlan_adapter_get_hw_spec(pmadapter);
+#ifdef MFG_CMD_SUPPORT
+ }
+#ifdef PCIE
+ else if (IS_PCIE(pmadapter->card_type)) {
+ if (MLAN_STATUS_SUCCESS != wlan_set_pcie_buf_config(priv)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif /* PCIE */
+#endif /* MFG_CMD_SUPPORT */
+ if (wlan_is_cmd_pending(pmadapter)) {
+ /* Send the first command in queue and return */
+ if (mlan_main_process(pmadapter) == MLAN_STATUS_FAILURE)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_PENDING;
+#if defined(MFG_CMD_SUPPORT) && defined(PCIE)
+ if (IS_PCIE(pmadapter->card_type) && pmadapter->mfg_mode) {
+ ret = MLAN_STATUS_SUCCESS;
+ }
+#endif
+ }
+#ifdef PCIE
+done:
+#endif
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode == MTRUE) {
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+ ret = wlan_get_hw_spec_complete(pmadapter);
+ }
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function udpate hw spec info to each interface
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING or
+ * MLAN_STATUS_FAILURE
+ */
+void wlan_update_hw_spec(pmlan_adapter pmadapter)
+{
+ t_u32 i;
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter))
+ pmadapter->fw_bands = (t_u8)GET_FW_DEFAULT_BANDS(pmadapter);
+ else
+ pmadapter->fw_bands = BAND_B;
+
+ if ((pmadapter->fw_bands & BAND_A) && (pmadapter->fw_bands & BAND_GN))
+ pmadapter->fw_bands |= BAND_AN;
+ if (!(pmadapter->fw_bands & BAND_G) && (pmadapter->fw_bands & BAND_GN))
+ pmadapter->fw_bands &= ~BAND_GN;
+
+ pmadapter->config_bands = pmadapter->fw_bands;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ pmadapter->priv[i]->config_bands = pmadapter->fw_bands;
+ }
+ }
+
+ if (pmadapter->fw_bands & BAND_A) {
+ if (pmadapter->fw_bands & BAND_AN) {
+ pmadapter->config_bands |= BAND_AN;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |=
+ BAND_AN;
+ }
+ }
+ if (pmadapter->fw_bands & BAND_AAC) {
+ pmadapter->config_bands |= BAND_AAC;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->config_bands |=
+ BAND_AAC;
+ }
+ }
+ pmadapter->adhoc_start_band = BAND_A;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ } else if (pmadapter->fw_bands & BAND_G) {
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ }
+ } else if (pmadapter->fw_bands & BAND_B) {
+ pmadapter->adhoc_start_band = BAND_B;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ }
+ }
+#endif /* STA_SUPPORT */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]->curr_addr[0] == 0xff)
+ memmove(pmadapter, pmadapter->priv[i]->curr_addr,
+ pmadapter->permanent_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_update_11n_cap(pmadapter->priv[i]);
+ }
+ if (ISSUPP_BEAMFORMING(pmadapter->hw_dot_11n_dev_cap)) {
+ PRINTM(MCMND, "Enable Beamforming\n");
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ pmadapter->priv[i]->tx_bf_cap =
+ pmadapter->pcard_info
+ ->default_11n_tx_bf_cap;
+ }
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_update_11ac_cap(pmadapter->priv[i]);
+ }
+ if (IS_FW_SUPPORT_11AX(pmadapter)) {
+ if (pmadapter->hw_2g_hecap_len) {
+ pmadapter->fw_bands |= BAND_GAX;
+ pmadapter->config_bands |= BAND_GAX;
+ }
+ if (pmadapter->hw_hecap_len) {
+ pmadapter->fw_bands |= BAND_AAX;
+ pmadapter->config_bands |= BAND_AAX;
+ }
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ pmadapter->priv[i]->config_bands =
+ pmadapter->config_bands;
+ pmadapter->priv[i]->user_2g_hecap_len =
+ pmadapter->hw_2g_hecap_len;
+ memcpy_ext(pmadapter,
+ pmadapter->priv[i]->user_2g_he_cap,
+ pmadapter->hw_2g_he_cap,
+ pmadapter->hw_2g_hecap_len,
+ sizeof(pmadapter->priv[i]
+ ->user_2g_he_cap));
+ pmadapter->priv[i]->user_hecap_len =
+ pmadapter->hw_hecap_len;
+ memcpy_ext(
+ pmadapter,
+ pmadapter->priv[i]->user_he_cap,
+ pmadapter->hw_he_cap,
+ pmadapter->hw_hecap_len,
+ sizeof(pmadapter->priv[i]->user_he_cap));
+ }
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function initializes firmware for interface
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING or
+ * MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_init_priv_fw(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ wlan_init_priv_lock_list(pmadapter, 1);
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ priv = pmadapter->priv[i];
+
+ /* Initialize private structure */
+ ret = wlan_init_priv(priv);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ wlan_update_hw_spec(pmadapter);
+ /* Issue firmware initialize commands for first BSS,
+ * for other interfaces it will be called after getting
+ * the last init command response of previous interface
+ */
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = priv->ops.init_cmd(priv, MTRUE);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif /* MFG_CMD_SUPPORT */
+
+ if (wlan_is_cmd_pending(pmadapter)) {
+ /* Send the first command in queue and return */
+ if (mlan_main_process(pmadapter) == MLAN_STATUS_FAILURE)
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_PENDING;
+#if defined(MFG_CMD_SUPPORT) && defined(PCIE)
+ if (IS_PCIE(pmadapter->card_type) && pmadapter->mfg_mode) {
+ ret = MLAN_STATUS_SUCCESS;
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ }
+#endif
+ } else {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of adapter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+t_void wlan_free_adapter(pmlan_adapter pmadapter)
+{
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+ ENTER();
+
+ if (!pmadapter) {
+ PRINTM(MERROR, "The adapter is NULL\n");
+ LEAVE();
+ return;
+ }
+
+ wlan_cancel_all_pending_cmd(pmadapter, MTRUE);
+ /* Free command buffer */
+ PRINTM(MINFO, "Free Command buffer\n");
+ wlan_free_cmd_buffer(pmadapter);
+
+ if (pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_hold_timer_is_set) {
+ /* Cancel usb_tx_aggregation timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .paggr_hold_timer);
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_hold_timer_is_set = MFALSE;
+ }
+ }
+ }
+#endif
+ if (pmadapter->wakeup_fw_timer_is_set) {
+ /* Cancel wakeup card timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pwakeup_fw_timer);
+ pmadapter->wakeup_fw_timer_is_set = MFALSE;
+ }
+ wlan_free_fw_cfp_tables(pmadapter);
+#ifdef STA_SUPPORT
+ PRINTM(MINFO, "Free ScanTable\n");
+ if (pmadapter->pscan_table) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pscan_table);
+ else
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pscan_table);
+ pmadapter->pscan_table = MNULL;
+ }
+ if (pmadapter->pchan_stats) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pchan_stats);
+ else
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pchan_stats);
+ pmadapter->pchan_stats = MNULL;
+ }
+ if (pmadapter->bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->bcn_buf);
+ pmadapter->bcn_buf = MNULL;
+ }
+#endif
+
+ wlan_11h_cleanup(pmadapter);
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ if (pmadapter->pcard_sd->mp_regs_buf) {
+ pcb->moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mp_regs_buf);
+ pmadapter->pcard_sd->mp_regs_buf = MNULL;
+ pmadapter->pcard_sd->mp_regs = MNULL;
+ }
+ if (pmadapter->pcard_sd->rx_buffer) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->rx_buffer);
+ pmadapter->pcard_sd->rx_buffer = MNULL;
+ pmadapter->pcard_sd->rx_buf = MNULL;
+ }
+ wlan_free_sdio_mpa_buffers(pmadapter);
+#ifdef DEBUG_LEVEL1
+ if (pmadapter->pcard_sd->mpa_buf) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mpa_buf);
+ else
+ pcb->moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mpa_buf);
+ pmadapter->pcard_sd->mpa_buf = MNULL;
+ pmadapter->pcard_sd->mpa_buf_size = 0;
+ }
+#endif
+ }
+#endif
+
+ wlan_free_mlan_buffer(pmadapter, pmadapter->psleep_cfm);
+ pmadapter->psleep_cfm = MNULL;
+
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type)) {
+ /* Free ssu dma buffer just in case */
+ wlan_free_ssu_pcie_buf(pmadapter);
+ /* Free PCIE ring buffers */
+ wlan_free_pcie_ring_buf(pmadapter);
+ }
+#endif
+
+ /* Free timers */
+ wlan_free_timer(pmadapter);
+
+ /* Free lock variables */
+ wlan_free_lock_list(pmadapter);
+
+#ifdef SDIO
+ if (pmadapter->pcard_sd) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd);
+ pmadapter->pcard_sd = MNULL;
+ }
+#endif
+#ifdef PCIE
+ if (pmadapter->pcard_pcie) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_pcie);
+ pmadapter->pcard_pcie = MNULL;
+ }
+#endif
+#ifdef USB
+ if (pmadapter->pcard_usb) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_usb);
+ pmadapter->pcard_usb = MNULL;
+ }
+#endif
+ vdll_deinit(pmadapter);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function frees the structure of priv
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_free_priv(mlan_private *pmpriv)
+{
+ ENTER();
+ wlan_clean_txrx(pmpriv);
+ wlan_delete_bsspriotbl(pmpriv);
+
+#ifdef STA_SUPPORT
+ wlan_free_curr_bcn(pmpriv);
+#endif /* STA_SUPPORT */
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ hostsa_cleanup(pmpriv);
+#endif /*EMBEDDED AUTHENTICATOR*/
+
+ wlan_delete_station_list(pmpriv);
+ LEAVE();
+}
+
+/**
+ * @brief This function init interface based on pmadapter's bss_attr table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+mlan_status wlan_init_interface(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = MNULL;
+ t_u8 i = 0;
+ t_u32 j = 0;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->bss_attr[i].active == MTRUE) {
+ if (!pmadapter->priv[i]) {
+ /* For valid bss_attr, allocate memory for
+ * private structure */
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ ret = pcb->moal_vmalloc(
+ pmadapter->pmoal_handle,
+ sizeof(mlan_private),
+ (t_u8 **)&pmadapter->priv[i]);
+ else
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ sizeof(mlan_private),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->priv[i]);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->priv[i]) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ pmadapter->priv_num++;
+ memset(pmadapter, pmadapter->priv[i], 0,
+ sizeof(mlan_private));
+ }
+ pmadapter->priv[i]->adapter = pmadapter;
+
+ /* Save bss_type, frame_type & bss_priority */
+ pmadapter->priv[i]->bss_type =
+ (t_u8)pmadapter->bss_attr[i].bss_type;
+ pmadapter->priv[i]->frame_type =
+ (t_u8)pmadapter->bss_attr[i].frame_type;
+ pmadapter->priv[i]->bss_priority =
+ (t_u8)pmadapter->bss_attr[i].bss_priority;
+ if (pmadapter->bss_attr[i].bss_type ==
+ MLAN_BSS_TYPE_STA)
+ pmadapter->priv[i]->bss_role =
+ MLAN_BSS_ROLE_STA;
+ else if (pmadapter->bss_attr[i].bss_type ==
+ MLAN_BSS_TYPE_UAP)
+ pmadapter->priv[i]->bss_role =
+ MLAN_BSS_ROLE_UAP;
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (pmadapter->bss_attr[i].bss_type ==
+ MLAN_BSS_TYPE_WIFIDIRECT) {
+ pmadapter->priv[i]->bss_role =
+ MLAN_BSS_ROLE_STA;
+ if (pmadapter->bss_attr[i].bss_virtual)
+ pmadapter->priv[i]->bss_virtual = MTRUE;
+ }
+#endif
+ /* Save bss_index and bss_num */
+ pmadapter->priv[i]->bss_index = i;
+ pmadapter->priv[i]->bss_num =
+ (t_u8)pmadapter->bss_attr[i].bss_num;
+
+ /* init function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role ==
+ GET_BSS_ROLE(pmadapter->priv[i])) {
+ memcpy_ext(pmadapter,
+ &pmadapter->priv[i]->ops,
+ mlan_ops[j],
+ sizeof(mlan_operations),
+ sizeof(mlan_operations));
+ break;
+ }
+ }
+ }
+ }
+ /*wmm init*/
+ wlan_wmm_init(pmadapter);
+ /* Initialize firmware, may return PENDING */
+ ret = wlan_init_priv_fw(pmadapter);
+ PRINTM(MINFO, "wlan_init_priv_fw returned ret=0x%x\n", ret);
+error:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The cmdresp handler calls this function for init_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization callback succeeded.
+ */
+mlan_status wlan_get_hw_spec_complete(pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_hw_info info;
+ mlan_bss_tbl bss_tbl;
+
+ ENTER();
+#ifdef MFG_CMD_SUPPORT
+ if (pmadapter->mfg_mode != MTRUE) {
+#endif
+ /* Check if hardware is ready */
+ if (pmadapter->hw_status != WlanHardwareStatusInitializing)
+ status = MLAN_STATUS_FAILURE;
+ else {
+ memset(pmadapter, &info, 0, sizeof(info));
+ info.fw_cap = pmadapter->fw_cap_info;
+ memset(pmadapter, &bss_tbl, 0, sizeof(bss_tbl));
+ memcpy_ext(pmadapter, bss_tbl.bss_attr,
+ pmadapter->bss_attr, sizeof(mlan_bss_tbl),
+ sizeof(mlan_bss_tbl));
+ }
+ /* Invoke callback */
+ ret = pcb->moal_get_hw_spec_complete(pmadapter->pmoal_handle,
+ status, &info, &bss_tbl);
+ if (ret == MLAN_STATUS_SUCCESS && status == MLAN_STATUS_SUCCESS)
+ memcpy_ext(pmadapter, pmadapter->bss_attr,
+ bss_tbl.bss_attr, sizeof(mlan_bss_tbl),
+ sizeof(mlan_bss_tbl));
+ else {
+ pmadapter->hw_status = WlanHardwareStatusNotReady;
+ wlan_init_fw_complete(pmadapter);
+ }
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif
+ if (pmadapter->hw_status == WlanHardwareStatusInitializing)
+ ret = wlan_init_interface(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The cmdresp handler calls this function for init_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization callback succeeded.
+ */
+mlan_status wlan_init_fw_complete(pmlan_adapter pmadapter)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_private *pmpriv = MNULL;
+
+ ENTER();
+
+ /* Check if hardware is ready */
+ if (pmadapter->hw_status != WlanHardwareStatusReady)
+ status = MLAN_STATUS_FAILURE;
+
+ /* Reconfigure wmm parameter*/
+ if (status == MLAN_STATUS_SUCCESS) {
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA);
+ if (pmpriv)
+ status = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_WMM_PARAM_CONFIG,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmadapter->ac_params);
+ }
+ /* Invoke callback */
+ ret = pcb->moal_init_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The cmdresp handler calls this function
+ * for shutdown_fw_complete callback
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown callback succeeded.
+ */
+mlan_status wlan_shutdown_fw_complete(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pmadapter->hw_status = WlanHardwareStatusNotReady;
+ /* Invoke callback */
+ ret = pcb->moal_shutdown_fw_complete(pmadapter->pmoal_handle, status);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.h
new file mode 100644
index 000000000000..f32731b6c788
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_init.h
@@ -0,0 +1,125 @@
+/** @file mlan_init.h
+ *
+ * @brief This file defines the FW initialization data
+ * structures.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_INIT_H_
+#define _MLAN_INIT_H_
+
+/** Tx buffer size for firmware download*/
+#define FW_DNLD_TX_BUF_SIZE 2312
+/** Rx buffer size for firmware download*/
+#define FW_DNLD_RX_BUF_SIZE 2048
+/** Max firmware retry */
+#define MAX_FW_RETRY 3
+
+/** Firmware has last block */
+#define FW_HAS_LAST_BLOCK 0x00000004
+/** CMD id for CMD4 */
+#define FW_CMD_4 0x00000004
+/** CMD id for CMD6 */
+#define FW_CMD_6 0x00000006
+/** CMD id for CMD7 */
+#define FW_CMD_7 0x00000007
+/** CMD id for CMD10 */
+#define FW_CMD_10 0x0000000a
+
+/** Firmware data transmit size */
+#define FW_DATA_XMIT_SIZE (sizeof(FWHeader) + DataLength + sizeof(t_u32))
+
+/** FWHeader */
+typedef MLAN_PACK_START struct _FWHeader {
+ /** FW download command */
+ t_u32 dnld_cmd;
+ /** FW base address */
+ t_u32 base_addr;
+ /** FW data length */
+ t_u32 data_length;
+ /** FW CRC */
+ t_u32 crc;
+} MLAN_PACK_END FWHeader;
+
+/** FWData */
+typedef MLAN_PACK_START struct _FWData {
+ /** FW data header */
+ FWHeader fw_header;
+ /** FW data sequence number */
+ t_u32 seq_num;
+ /** FW data buffer */
+ t_u8 data[1];
+} MLAN_PACK_END FWData;
+
+/** FWSyncHeader */
+typedef MLAN_PACK_START struct _FWSyncHeader {
+ /** FW sync header command */
+ t_u32 cmd;
+ /** FW sync header sequence number */
+ t_u32 seq_num;
+ /** Extended header */
+ t_u32 magic;
+ /** Chip rev */
+ t_u32 chip_rev;
+ /** Strap */
+ t_u32 strap;
+ /** Status */
+ t_u32 status;
+ /** Offset */
+ t_u32 offset;
+} MLAN_PACK_END FWSyncHeader;
+
+/** FW Sync pkt */
+typedef MLAN_PACK_START struct _FWSyncPkt {
+ /** pkt type */
+ t_u32 pkt_type;
+ /** FW sync header command */
+ t_u32 cmd;
+ /** FW sync header sequence number */
+ t_u32 seq_num;
+ /** chip rev */
+ t_u32 chip_rev;
+ /** fw status */
+ t_u32 fw_ready;
+} MLAN_PACK_END FWSyncPkt;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert sequence number and command fields
+ * of fwheader to correct endian format
+ */
+#define endian_convert_syncfwheader(x) \
+ { \
+ (x)->cmd = wlan_le32_to_cpu((x)->cmd); \
+ (x)->seq_num = wlan_le32_to_cpu((x)->seq_num); \
+ (x)->status = wlan_le32_to_cpu((x)->status); \
+ (x)->offset = wlan_le32_to_cpu((x)->offset); \
+ }
+#else
+/** Convert sequence number and command fields
+ * of fwheader to correct endian format
+ */
+#define endian_convert_syncfwheader(x)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+#endif /* _MLAN_INIT_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ioctl.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ioctl.h
new file mode 100644
index 000000000000..2315b2a2b79e
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_ioctl.h
@@ -0,0 +1,5159 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id {
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL = 0x00010001,
+ MLAN_OID_SCAN_SPECIFIC_SSID = 0x00010002,
+ MLAN_OID_SCAN_USER_CONFIG = 0x00010003,
+ MLAN_OID_SCAN_CONFIG = 0x00010004,
+ MLAN_OID_SCAN_GET_CURRENT_BSS = 0x00010005,
+ MLAN_OID_SCAN_CANCEL = 0x00010006,
+ MLAN_OID_SCAN_TABLE_FLUSH = 0x0001000A,
+ MLAN_OID_SCAN_BGSCAN_CONFIG = 0x0001000B,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START = 0x00020001,
+ MLAN_OID_BSS_STOP = 0x00020002,
+ MLAN_OID_BSS_MODE = 0x00020003,
+ MLAN_OID_BSS_CHANNEL = 0x00020004,
+ MLAN_OID_BSS_CHANNEL_LIST = 0x00020005,
+ MLAN_OID_BSS_MAC_ADDR = 0x00020006,
+ MLAN_OID_BSS_MULTICAST_LIST = 0x00020007,
+ MLAN_OID_BSS_FIND_BSS = 0x00020008,
+ MLAN_OID_IBSS_BCN_INTERVAL = 0x00020009,
+ MLAN_OID_IBSS_ATIM_WINDOW = 0x0002000A,
+ MLAN_OID_IBSS_CHANNEL = 0x0002000B,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG = 0x0002000C,
+ MLAN_OID_UAP_DEAUTH_STA = 0x0002000D,
+ MLAN_OID_UAP_BSS_RESET = 0x0002000E,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE = 0x0002000F,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE = 0x00020010,
+#endif
+#ifdef STA_SUPPORT
+ MLAN_OID_BSS_LISTEN_INTERVAL = 0x00020011,
+#endif
+ MLAN_OID_BSS_REMOVE = 0x00020014,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_CFG_WMM_PARAM = 0x00020015,
+#endif
+ MLAN_OID_BSS_11D_CHECK_CHANNEL = 0x00020016,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_ACS_SCAN = 0x00020017,
+ MLAN_OID_UAP_SCAN_CHANNELS = 0x00020018,
+ MLAN_OID_UAP_CHANNEL = 0x00020019,
+ MLAN_OID_UAP_OPER_CTRL = 0x0002001A,
+#endif
+#ifdef STA_SUPPORT
+ MLAN_OID_BSS_CHAN_INFO = 0x0002001B,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_ADD_STATION = 0x0002001C,
+#endif
+
+ MLAN_OID_BSS_FIND_BSSID = 0x0002001D,
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL = 0x00030001,
+ MLAN_OID_BAND_CFG = 0x00030002,
+ MLAN_OID_ANT_CFG = 0x00030003,
+ MLAN_OID_REMAIN_CHAN_CFG = 0x00030004,
+ MLAN_OID_MIMO_SWITCH = 0x00030005,
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD = 0x00040001,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD = 0x00040002,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT = 0x00040003,
+ MLAN_OID_SNMP_MIB_DOT11D = 0x00040004,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11H = 0x00040005,
+#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD = 0x00040006,
+ MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE = 0x00040007,
+ MLAN_OID_SNMP_MIB_CTRL_DEAUTH = 0x00040008,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS = 0x00050001,
+ MLAN_OID_GET_SIGNAL = 0x00050002,
+ MLAN_OID_GET_FW_INFO = 0x00050003,
+ MLAN_OID_GET_VER_EXT = 0x00050004,
+ MLAN_OID_GET_BSS_INFO = 0x00050005,
+ MLAN_OID_GET_DEBUG_INFO = 0x00050006,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST = 0x00050007,
+#endif
+ MLAN_OID_GET_SIGNAL_EXT = 0x00050008,
+ MLAN_OID_LINK_STATS = 0x00050009,
+ MLAN_OID_GET_UAP_STATS_LOG = 0x0005000A,
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE = 0x00060001,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE = 0x00060002,
+ MLAN_OID_SEC_CFG_WPA_ENABLED = 0x00060003,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY = 0x00060004,
+ MLAN_OID_SEC_CFG_PASSPHRASE = 0x00060005,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED = 0x00060006,
+ MLAN_OID_SEC_CFG_ESUPP_MODE = 0x00060007,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED = 0x00060009,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED = 0x0006000A,
+#ifdef UAP_SUPPORT
+ MLAN_OID_SEC_CFG_REPORT_MIC_ERR = 0x0006000B,
+#endif
+ MLAN_OID_SEC_QUERY_KEY = 0x0006000C,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG = 0x00070001,
+ MLAN_OID_GET_DATA_RATE = 0x00070002,
+ MLAN_OID_SUPPORTED_RATES = 0x00070003,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG = 0x00080001,
+ MLAN_OID_POWER_CFG_EXT = 0x00080002,
+ MLAN_OID_POWER_LOW_POWER_MODE = 0x00080003,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS = 0x00090001,
+ MLAN_OID_PM_CFG_HS_CFG = 0x00090002,
+ MLAN_OID_PM_CFG_INACTIVITY_TO = 0x00090003,
+ MLAN_OID_PM_CFG_DEEP_SLEEP = 0x00090004,
+ MLAN_OID_PM_CFG_SLEEP_PD = 0x00090005,
+ MLAN_OID_PM_CFG_PS_CFG = 0x00090006,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS = 0x00090008,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE = 0x00090009,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO = 0x0009000A,
+ MLAN_OID_PM_HS_WAKEUP_REASON = 0x0009000B,
+ MLAN_OID_PM_MGMT_FILTER = 0x0009000C,
+ MLAN_OID_PM_CFG_BCN_TIMEOUT = 0x0009000D,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE = 0x000A0001,
+ MLAN_OID_WMM_CFG_QOS = 0x000A0002,
+ MLAN_OID_WMM_CFG_ADDTS = 0x000A0003,
+ MLAN_OID_WMM_CFG_DELTS = 0x000A0004,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG = 0x000A0005,
+ MLAN_OID_WMM_CFG_QUEUE_STATS = 0x000A0006,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS = 0x000A0007,
+ MLAN_OID_WMM_CFG_TS_STATUS = 0x000A0008,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION = 0x000B0001,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX = 0x000C0001,
+ MLAN_OID_11N_HTCAP_CFG = 0x000C0002,
+ MLAN_OID_11N_CFG_ADDBA_REJECT = 0x000C0003,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL = 0x000C0004,
+ MLAN_OID_11N_CFG_ADDBA_PARAM = 0x000C0005,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE = 0x000C0006,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL = 0x000C0007,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET = 0x000C0008,
+ MLAN_OID_11N_CFG_TX_BF_CAP = 0x000C0009,
+ MLAN_OID_11N_CFG_TX_BF_CFG = 0x000C000A,
+ MLAN_OID_11N_CFG_STREAM_CFG = 0x000C000B,
+ MLAN_OID_11N_CFG_DELBA = 0x000C000C,
+ MLAN_OID_11N_CFG_REJECT_ADDBA_REQ = 0x000C000D,
+ MLAN_OID_11N_CFG_COEX_RX_WINSIZE = 0x000C000E,
+ MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM = 0x000C0010,
+ MLAN_OID_11N_CFG_MIN_BA_THRESHOLD = 0x000C0011,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE = 0x000D0001,
+ MLAN_OID_11D_CLR_CHAN_TABLE = 0x000D0002,
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ MLAN_OID_11D_DOMAIN_INFO = 0x000D0003,
+#endif
+ MLAN_OID_11D_DOMAIN_INFO_EXT = 0x000D0004,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW = 0x000E0001,
+ MLAN_OID_EEPROM_RD = 0x000E0002,
+ MLAN_OID_MEM_RW = 0x000E0003,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK = 0x00110001,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT = 0x00110002,
+ MLAN_OID_11H_DFS_TESTING = 0x00110003,
+ MLAN_OID_11H_CHAN_REPORT_REQUEST = 0x00110004,
+ MLAN_OID_11H_CHAN_SWITCH_COUNT = 0x00110005,
+ MLAN_OID_11H_CHAN_NOP_INFO = 0x00110006,
+ MLAN_OID_11H_DFS_W53_CFG = 0x00110008,
+
+ /* 802.11n Configuration Group RANDYTODO for value assign */
+ MLAN_IOCTL_11AC_CFG = 0x00120000,
+ MLAN_OID_11AC_VHT_CFG = 0x00120001,
+ MLAN_OID_11AC_CFG_SUPPORTED_MCS_SET = 0x00120002,
+ MLAN_OID_11AC_OPERMODE_CFG = 0x00120003,
+
+ /* 802.11ax Configuration Group */
+ MLAN_IOCTL_11AX_CFG = 0x00170000,
+ MLAN_OID_11AX_HE_CFG = 0x00170001,
+ MLAN_OID_11AX_CMD_CFG = 0x00170002,
+ MLAN_OID_11AX_TWT_CFG = 0x00170003,
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE = 0x00200001,
+ MLAN_OID_MISC_REGION = 0x00200002,
+ MLAN_OID_MISC_WARM_RESET = 0x00200003,
+#ifdef SDIO
+ MLAN_OID_MISC_SDIO_MPA_CTRL = 0x00200006,
+#endif
+ MLAN_OID_MISC_HOST_CMD = 0x00200007,
+ MLAN_OID_MISC_SYS_CLOCK = 0x00200009,
+ MLAN_OID_MISC_SOFT_RESET = 0x0020000A,
+ MLAN_OID_MISC_WWS = 0x0020000B,
+ MLAN_OID_MISC_ASSOC_RSP = 0x0020000C,
+ MLAN_OID_MISC_INIT_SHUTDOWN = 0x0020000D,
+ MLAN_OID_MISC_CUSTOM_IE = 0x0020000F,
+ MLAN_OID_MISC_TX_DATAPAUSE = 0x00200012,
+ MLAN_OID_MISC_IP_ADDR = 0x00200013,
+ MLAN_OID_MISC_MAC_CONTROL = 0x00200014,
+ MLAN_OID_MISC_MEF_CFG = 0x00200015,
+ MLAN_OID_MISC_CFP_CODE = 0x00200016,
+ MLAN_OID_MISC_COUNTRY_CODE = 0x00200017,
+ MLAN_OID_MISC_THERMAL = 0x00200018,
+ MLAN_OID_MISC_RX_MGMT_IND = 0x00200019,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT = 0x0020001A,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG = 0x0020001B,
+#endif
+ MLAN_OID_MISC_HOTSPOT_CFG = 0x0020001C,
+ MLAN_OID_MISC_OTP_USER_DATA = 0x0020001D,
+#ifdef USB
+ MLAN_OID_MISC_USB_AGGR_CTRL = 0x0020001F,
+#endif
+ MLAN_OID_MISC_TXCONTROL = 0x00200020,
+#ifdef STA_SUPPORT
+ MLAN_OID_MISC_EXT_CAP_CFG = 0x00200021,
+#endif
+#if defined(STA_SUPPORT)
+ MLAN_OID_MISC_PMFCFG = 0x00200022,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_MISC_WIFI_DIRECT_CONFIG = 0x00200025,
+#endif
+ MLAN_OID_MISC_LOW_PWR_MODE = 0x00200029,
+ MLAN_OID_MISC_MEF_FLT_CFG = 0x0020002A,
+ MLAN_OID_MISC_DFS_REAPTER_MODE = 0x0020002B,
+#ifdef RX_PACKET_COALESCE
+ MLAN_OID_MISC_RX_PACKET_COALESCE = 0x0020002C,
+#endif
+ MLAN_OID_MISC_COALESCE_CFG = 0x0020002E,
+ MLAN_OID_MISC_GET_SENSOR_TEMP = 0x00200030,
+ MLAN_OID_MISC_GTK_REKEY_OFFLOAD = 0x00200037,
+ MLAN_OID_MISC_OPER_CLASS = 0x00200038,
+ MLAN_OID_MISC_PMIC_CFG = 0x00200039,
+ MLAN_OID_MISC_IND_RST_CFG = 0x00200040,
+ MLAN_OID_MISC_GET_TSF = 0x00200045,
+ MLAN_OID_MISC_GET_CHAN_REGION_CFG = 0x00200046,
+ MLAN_OID_MISC_CLOUD_KEEP_ALIVE = 0x00200048,
+ MLAN_OID_MISC_OPER_CLASS_CHECK = 0x00200049,
+
+ MLAN_OID_MISC_CWMODE_CTRL = 0x00200051,
+ MLAN_OID_MISC_AGGR_CTRL = 0x00200052,
+ MLAN_OID_MISC_DYN_BW = 0x00200053,
+ MLAN_OID_MISC_FW_DUMP_EVENT = 0x00200054,
+ MLAN_OID_MISC_PER_PKT_CFG = 0x00200055,
+
+ MLAN_OID_MISC_ROBUSTCOEX = 0x00200056,
+ MLAN_OID_MISC_GET_TX_RX_HISTOGRAM = 0x00200057,
+ MLAN_OID_MISC_CFP_INFO = 0x00200060,
+ MLAN_OID_MISC_BOOT_SLEEP = 0x00200061,
+#if defined(PCIE)
+ MLAN_OID_MISC_SSU = 0x00200062,
+#endif
+ MLAN_OID_MISC_DMCS_CONFIG = 0x00200065,
+ MLAN_OID_MISC_RX_ABORT_CFG = 0x00200066,
+ MLAN_OID_MISC_RX_ABORT_CFG_EXT = 0x00200067,
+ MLAN_OID_MISC_TX_AMPDU_PROT_MODE = 0x00200068,
+ MLAN_OID_MISC_RATE_ADAPT_CFG = 0x00200069,
+ MLAN_OID_MISC_CCK_DESENSE_CFG = 0x00200070,
+ MLAN_OID_MISC_GET_CHAN_TRPC_CFG = 0x00200072,
+ MLAN_OID_MISC_BAND_STEERING = 0x00200073,
+ MLAN_OID_MISC_GET_REGIONPWR_CFG = 0x00200074,
+ MLAN_OID_MISC_RF_TEST_GENERIC = 0x00200075,
+ MLAN_OID_MISC_RF_TEST_TX_CONT = 0x00200076,
+ MLAN_OID_MISC_RF_TEST_TX_FRAME = 0x00200077,
+ MLAN_OID_MISC_ARB_CONFIG = 0x00200078,
+ MLAN_OID_MISC_BEACON_STUCK = 0x00200079,
+ MLAN_OID_MISC_CFP_TABLE = 0x0020007A,
+ MLAN_OID_MISC_RANGE_EXT = 0x0020007B,
+ MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG = 0x0020007C,
+ MLAN_OID_MISC_TP_STATE = 0x0020007D,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl {
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL,
+ MLAN_ACT_CLEAR,
+ MLAN_ACT_RESET,
+ MLAN_ACT_DEFAULT
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic { MLAN_ACT_DISABLE = 0, MLAN_ACT_ENABLE = 1 };
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode {
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type {
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE,
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE
+};
+
+/** Enumeration for passive to active scan */
+enum _mlan_pass_to_act_scan {
+ MLAN_PASS_TO_ACT_SCAN_UNCHANGED = 0,
+ MLAN_PASS_TO_ACT_SCAN_EN,
+ MLAN_PASS_TO_ACT_SCAN_DIS
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** Mrvl Proprietary Tlv base */
+#define PROPRIETARY_TLV_BASE_ID 0x100
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+/** Max gap time between 2 scan in milliseconds */
+#define MRVDRV_MAX_SCAN_CHAN_GAP_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 5
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed {
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** channel load */
+ t_u8 chan_load;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid {
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+typedef MLAN_PACK_START struct _tx_status_event {
+ /** packet type */
+ t_u8 packet_type;
+ /** tx_token_id */
+ t_u8 tx_token_id;
+ /** 0--success, 1--fail, 2--watchdogtimeout */
+ t_u8 status;
+} MLAN_PACK_END tx_status_event;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct {
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry
+ * structures. Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry {
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof()
+ * calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params {
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan {
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req {
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp {
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+ /** channel statstics */
+ t_u8 *pchan_stats;
+ /** Number of records in the chan_stats */
+ t_u32 num_in_chan_stats;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+#define EXT_SCAN_TYPE_ENH 2
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg {
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** First passive scan then active scan */
+ t_u8 passive_to_active_scan;
+ /** Ext_scan: 0 disable, 1: enable, 2: enhance scan*/
+ t_u32 ext_scan;
+ /** scan channel gap */
+ t_u32 scan_chan_gap;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode {
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list {
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq {
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list {
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/* This channel is disabled.*/
+#define CHAN_FLAGS_DISABLED MBIT(0)
+/* do not initiate radiation, this includes sending probe requests or beaconing
+ */
+#define CHAN_FLAGS_NO_IR MBIT(1)
+/* Radar detection is required on this channel */
+#define CHAN_FLAGS_RADAR MBIT(3)
+/* extension channel above this channel is not permitted */
+#define CHAN_FLAGS_NO_HT40PLUS MBIT(4)
+/* extension channel below this channel is not permitted */
+#define CHAN_FLAGS_NO_HT40MINUS MBIT(5)
+/* OFDM is not allowed on this channel */
+#define CHAN_FLAGS_NO_OFDM MBIT(6)
+/** 80Mhz can not used on this channel */
+#define CHAN_FLAGS_NO_80MHZ MBIT(7)
+/** 180Mhz can not used on this channel */
+#define CHAN_FLAGS_NO_160MHZ MBIT(8)
+/* Only indoor use is permitted on this channel */
+#define CHAN_FLAGS_INDOOR_ONLY MBIT(9)
+/* IR operation is allowed on this channel if it's
+ * connected concurrently to a BSS on the same channel on
+ * the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
+ * band), and IEEE80211_CHAN_RADAR is not set */
+#define CHAN_FLAGS_IR_CONCURRENT MBIT(10)
+/* 20 MHz operation is not allowed on this channel */
+#define CHAN_FLAGS_20MHZ MBIT(11)
+/* 10 MHz operation is not allowed on this channel */
+#define CHAN_FLAGS_NO_10MHZ MBIT(12)
+/** This channel's flag is valid */
+#define CHAN_FLAGS_MAX MBIT(31)
+
+/** Maximum response buffer length */
+#define ASSOC_RSP_BUF_SIZE 500
+
+/** Type definition of mlan_ds_misc_assoc_rsp for MLAN_OID_MISC_ASSOC_RSP */
+typedef struct _mlan_ds_misc_assoc_rsp {
+ /** Associate response buffer */
+ t_u8 assoc_resp_buf[ASSOC_RSP_BUF_SIZE];
+ /** Response buffer length */
+ t_u32 assoc_resp_len;
+} mlan_ds_misc_assoc_rsp, *pmlan_ds_misc_assoc_rsp;
+
+/** mlan_ssid_bssid data structure for
+ * MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS
+ */
+typedef struct _mlan_ssid_bssid {
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+ /**channel*/
+ t_u16 channel;
+ /**mobility domain value*/
+ t_u16 ft_md;
+ /**ft capability*/
+ t_u8 ft_cap;
+ /**band*/
+ t_u16 bss_band;
+ /** channel flag */
+ t_u32 channel_flags;
+ /** host mlme flag*/
+ t_u8 host_mlme;
+ /** assoicate resp frame/ie from firmware */
+ mlan_ds_misc_assoc_rsp assoc_rsp;
+} mlan_ssid_bssid, *pmlan_ssid_bssid;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aifsn */
+ t_u8 aifsn : 4;
+#else
+ /** Aifsn */
+ t_u8 aifsn : 4;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Reserved */
+ t_u8 reserved : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t {
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param {
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+
+#ifdef UAP_SUPPORT
+/** UAP FLAG: Host based */
+#define UAP_FLAG_HOST_BASED MBIT(0)
+/** UAP FLAG: Host mlme */
+#define UAP_FLAG_HOST_MLME MBIT(1)
+
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 64
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** Maximum value of bcast_ssid_ctl */
+#define MAX_BCAST_SSID_CTL 2
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 50
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** default UAP BAND 2.4G */
+#define DEFAULT_UAP_BAND 0
+/** default UAP channel 6 */
+#define DEFAULT_UAP_CHANNEL 6
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 64
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+/** WPA3 SAE */
+#define PROTOCOL_WPA3_SAE 0x100
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+/** Key_mgmt_psk_sha256 */
+#define KEY_MGMT_PSK_SHA256 0x100
+/** Key_mgmt_sae */
+#define KEY_MGMT_SAE 0x400
+/** Key_mgmt_owe */
+#define KEY_MGMT_OWE 0x200
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Packet forwarding to be done by FW or host */
+#define PKT_FWD_FW_BIT 0x01
+/** Intra-BSS broadcast packet forwarding allow bit */
+#define PKT_FWD_INTRA_BCAST 0x02
+/** Intra-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTRA_UCAST 0x04
+/** Inter-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTER_UCAST 0x08
+/** Intra-BSS unicast packet */
+#define PKT_INTRA_UCAST 0x01
+/** Inter-BSS unicast packet */
+#define PKT_INTER_UCAST 0x02
+/** Enable Host PKT forwarding */
+#define PKT_FWD_ENABLE_BIT 0x01
+
+/** Channel List Entry */
+typedef struct _channel_list {
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ Band_Config_t bandcfg;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter {
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param {
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key {
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param {
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t {
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** MAX BG channel */
+#define MAX_BG_CHANNEL 14
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param {
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** Tx beacon rate */
+ t_u16 tx_beacon_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+
+ /** uap host based config */
+ t_u32 uap_host_based_config;
+} mlan_uap_bss_param, *pmlan_uap_bss_param;
+
+/** mlan_uap_scan_channels */
+typedef struct _mlan_uap_scan_channels {
+ /** flag for remove nop channel*/
+ t_u8 remove_nop_channel;
+ /** num of removed channel */
+ t_u8 num_remvoed_channel;
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+} mlan_uap_scan_channels;
+
+/** mlan_uap_oper_ctrl */
+typedef struct _mlan_uap_oper_ctrl {
+ /** control value
+ * 0: do nothing,
+ * 2: uap stops and restarts automaticaly
+ */
+ t_u16 ctrl_value;
+ /** channel opt
+ * 1: uap restart on default 2.4G/channel 6
+ * 2: uap restart on the band/channel configured by driver previously
+ * 3: uap restart on the band/channel specified by band_cfg and channel
+ */
+ t_u16 chan_opt;
+ /** band cfg 0
+ * 0: 20Mhz 2: 40 Mhz 3: 80Mhz
+ */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+} mlan_uap_oper_ctrl;
+
+/** mlan_uap_acs_scan */
+typedef struct _mlan_uap_acs_scan {
+ /** band */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 chan;
+} mlan_uap_acs_scan;
+
+/** station is authorized (802.1X) */
+#define STA_FLAG_AUTHORIZED MBIT(1)
+/** Station is capable of receiving frames with short barker preamble */
+#define STA_FLAG_SHORT_PREAMBLE MBIT(2)
+/** station is WME/QoS capable */
+#define STA_FLAG_WME MBIT(3)
+/** station uses management frame protection */
+#define STA_FLAG_MFP MBIT(4)
+/** station is authenticated */
+#define STA_FLAG_AUTHENTICATED MBIT(5)
+/** station is a TDLS peer */
+#define STA_FLAG_TDLS_PEER MBIT(6)
+/** station is associated */
+#define STA_FLAG_ASSOCIATED MBIT(7)
+/** mlan_ds_sta_info */
+typedef struct _mlan_ds_sta_info {
+ /** aid */
+ t_u16 aid;
+ /** peer_mac */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Listen Interval */
+ int listen_interval;
+ /** Capability Info */
+ t_u16 cap_info;
+ /** station flag */
+ t_u32 sta_flags;
+ /** tlv len */
+ t_u16 tlv_len;
+ /** tlv start */
+ t_u8 tlv[];
+} mlan_ds_sta_info;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+ /** deauth param for MLAN_OID_BSS_STOP & MLAN_OID_UAP_DEAUTH_STA
+ */
+ mlan_deauth_param deauth_param;
+#ifdef UAP_SUPPORT
+ /** host based flag for MLAN_OID_BSS_START */
+ t_u8 host_based;
+ /** BSS param for AP mode for MLAN_OID_UAP_BSS_CONFIG */
+ mlan_uap_bss_param bss_config;
+ /** AP Wmm parameters for MLAN_OID_UAP_CFG_WMM_PARAM */
+ wmm_parameter_t ap_wmm_para;
+ /** ap scan channels for MLAN_OID_UAP_SCAN_CHANNELS*/
+ mlan_uap_scan_channels ap_scan_channels;
+ /** ap channel for MLAN_OID_UAP_CHANNEL*/
+ chan_band_info ap_channel;
+ /** ap operation control for MLAN_OID_UAP_OPER_CTRL*/
+ mlan_uap_oper_ctrl ap_oper_ctrl;
+ /** AP acs scan MLAN_OID_UAP_ACS_SCAN */
+ mlan_uap_acs_scan ap_acs_scan;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role for MLAN_OID_BSS_ROLE */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ /** wifi direct mode for MLAN_OID_WIFI_DIRECT_MODE */
+ t_u16 wfd_mode;
+#endif
+#ifdef STA_SUPPORT
+ /** Listen interval for MLAN_OID_BSS_LISTEN_INTERVAL */
+ t_u16 listen_interval;
+ /** STA channel info for MLAN_OID_BSS_CHAN_INFO */
+ chan_band_info sta_channel;
+#endif
+#ifdef UAP_SUPPORT
+ /** STA info for MLAN_OID_UAP_ADD_STATION */
+ mlan_ds_sta_info sta_info;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/* OTP Region info */
+typedef MLAN_PACK_START struct _otp_region_info {
+ t_u8 country_code[2];
+ t_u8 region_code;
+ t_u8 environment;
+ t_u16 force_reg : 1;
+ t_u16 reserved : 15;
+} MLAN_PACK_END otp_region_info_t;
+
+/** Type definition of mlan_ds_custom_reg_domain */
+typedef struct _mlan_ds_custom_reg_domain {
+ otp_region_info_t region;
+ /** num of 2g channels in custom_reg_domain */
+ t_u8 num_bg_chan;
+ /** num of 5g channels in custom_reg_domain */
+ t_u8 num_a_chan;
+ /** cfp table */
+ chan_freq_power_t cfp_tbl[];
+} mlan_ds_custom_reg_domain;
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def {
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+ BAND_GAC = 32,
+ BAND_AAC = 64,
+ BAND_GAX = 256,
+ BAND_AAX = 512,
+
+};
+
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+/** secondary channel is 80Mhz bandwidth for 11ac */
+#define CHANNEL_BW_80MHZ 4
+#define CHANNEL_BW_160MHZ 5
+
+/** RF antenna selection */
+#define RF_ANTENNA_MASK(n) ((1 << (n)) - 1)
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO 0xFFFF
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg {
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg {
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+/** Type definition of mlan_ds_mimo_switch for MLAN_OID_MIMO_SWITCH */
+typedef struct _mlan_ds_mimo_switch {
+ /** Tx antenna mode */
+ t_u8 txpath_antmode;
+ /** Rx antenna mode */
+ t_u8 rxpath_antmode;
+} mlan_ds_mimo_switch, *pmlan_ds_mimo_switch;
+/** Type definition of mlan_ds_ant_cfg_1x1 for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg_1x1 {
+ /** Antenna mode */
+ t_u32 antenna;
+ /** Evaluate time */
+ t_u16 evaluate_time;
+ /** Current antenna */
+ t_u16 current_antenna;
+} mlan_ds_ant_cfg_1x1, *pmlan_ds_ant_cfg_1x1;
+
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan {
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna mode for MLAN_OID_MIMO_SWITCH */
+ mlan_ds_mimo_switch mimo_switch_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg_1x1 ant_cfg_1x1;
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+enum COALESCE_OPERATION {
+ RECV_FILTER_MATCH_TYPE_EQ = 0x80,
+ RECV_FILTER_MATCH_TYPE_NE,
+};
+
+enum COALESCE_PACKET_TYPE {
+ PACKET_TYPE_UNICAST = 1,
+ PACKET_TYPE_MULTICAST = 2,
+ PACKET_TYPE_BROADCAST = 3
+};
+
+#define COALESCE_MAX_RULES 8
+#define COALESCE_MAX_BYTESEQ 4 /* non-adjustable */
+#define COALESCE_MAX_FILTERS 4
+#define MAX_COALESCING_DELAY 100 /* in msecs */
+#define MAX_PATTERN_LEN 20
+#define MAX_OFFSET_LEN 100
+
+struct filt_field_param {
+ t_u8 operation;
+ t_u8 operand_len;
+ t_u16 offset;
+ t_u8 operand_byte_stream[COALESCE_MAX_BYTESEQ];
+};
+
+struct coalesce_rule {
+ t_u16 max_coalescing_delay;
+ t_u8 num_of_fields;
+ t_u8 pkt_type;
+ struct filt_field_param params[COALESCE_MAX_FILTERS];
+};
+
+typedef struct _mlan_ds_coalesce_cfg {
+ t_u16 num_of_rules;
+ struct coalesce_rule rule[COALESCE_MAX_RULES];
+} mlan_ds_coalesce_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
+ /** Singal_ext Enable for MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE */
+ t_u8 signalext_enable;
+ /** Control deauth when uap switch channel */
+ t_u8 deauthctrl;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status {
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED,
+ ADHOC_STARTING
+};
+
+typedef struct _mlan_ds_get_stats_org {
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+ /** beacon recv count */
+ t_u32 bcn_rcv_cnt;
+ /** beacon miss count */
+ t_u32 bcn_miss_cnt;
+ /** received amsdu count*/
+ t_u32 amsdu_rx_cnt;
+ /** received msdu count in amsdu*/
+ t_u32 msdu_in_rx_amsdu_cnt;
+ /** tx amsdu count*/
+ t_u32 amsdu_tx_cnt;
+ /** tx msdu count in amsdu*/
+ t_u32 msdu_in_tx_amsdu_cnt;
+} mlan_ds_get_stats_org;
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats {
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+ /** beacon recv count */
+ t_u32 bcn_rcv_cnt;
+ /** beacon miss count */
+ t_u32 bcn_miss_cnt;
+ /** received amsdu count*/
+ t_u32 amsdu_rx_cnt;
+ /** received msdu count in amsdu*/
+ t_u32 msdu_in_rx_amsdu_cnt;
+ /** tx amsdu count*/
+ t_u32 amsdu_tx_cnt;
+ /** tx msdu count in amsdu*/
+ t_u32 msdu_in_tx_amsdu_cnt;
+
+ /** Tx frag count */
+ t_u32 tx_frag_cnt;
+ /** Qos Tx frag count */
+ t_u32 qos_tx_frag_cnt[8];
+ /** Qos failed count */
+ t_u32 qos_failed_cnt[8];
+ /** Qos retry count */
+ t_u32 qos_retry_cnt[8];
+ /** Qos multi retry count */
+ t_u32 qos_multi_retry_cnt[8];
+ /** Qos frame dup count */
+ t_u32 qos_frm_dup_cnt[8];
+ /** Qos rts success count */
+ t_u32 qos_rts_suc_cnt[8];
+ /** Qos rts failure count */
+ t_u32 qos_rts_failure_cnt[8];
+ /** Qos ack failure count */
+ t_u32 qos_ack_failure_cnt[8];
+ /** Qos Rx frag count */
+ t_u32 qos_rx_frag_cnt[8];
+ /** Qos Tx frame count */
+ t_u32 qos_tx_frm_cnt[8];
+ /** Qos discarded frame count */
+ t_u32 qos_discarded_frm_cnt[8];
+ /** Qos mpdus Rx count */
+ t_u32 qos_mpdus_rx_cnt[8];
+ /** Qos retry rx count */
+ t_u32 qos_retries_rx_cnt[8];
+ /** CMAC ICV errors count */
+ t_u32 cmacicv_errors;
+ /** CMAC replays count */
+ t_u32 cmac_replays;
+ /** mgmt CCMP replays count */
+ t_u32 mgmt_ccmp_replays;
+ /** TKIP ICV errors count */
+ t_u32 tkipicv_errors;
+ /** TKIP replays count */
+ t_u32 tkip_replays;
+ /** CCMP decrypt errors count */
+ t_u32 ccmp_decrypt_errors;
+ /** CCMP replays count */
+ t_u32 ccmp_replays;
+ /** Tx amsdu count */
+ t_u32 tx_amsdu_cnt;
+ /** failed amsdu count */
+ t_u32 failed_amsdu_cnt;
+ /** retry amsdu count */
+ t_u32 retry_amsdu_cnt;
+ /** multi-retry amsdu count */
+ t_u32 multi_retry_amsdu_cnt;
+ /** Tx octets in amsdu count */
+ t_u64 tx_octets_in_amsdu_cnt;
+ /** amsdu ack failure count */
+ t_u32 amsdu_ack_failure_cnt;
+ /** Rx amsdu count */
+ t_u32 rx_amsdu_cnt;
+ /** Rx octets in amsdu count */
+ t_u64 rx_octets_in_amsdu_cnt;
+ /** Tx ampdu count */
+ t_u32 tx_ampdu_cnt;
+ /** tx mpdus in ampdu count */
+ t_u32 tx_mpdus_in_ampdu_cnt;
+ /** tx octets in ampdu count */
+ t_u64 tx_octets_in_ampdu_cnt;
+ /** ampdu Rx count */
+ t_u32 ampdu_rx_cnt;
+ /** mpdu in Rx ampdu count */
+ t_u32 mpdu_in_rx_ampdu_cnt;
+ /** Rx octets ampdu count */
+ t_u64 rx_octets_in_ampdu_cnt;
+ /** ampdu delimiter CRC error count */
+ t_u32 ampdu_delimiter_crc_error_cnt;
+ /** Rx Stuck Related Info*/
+ /** Rx Stuck Issue count */
+ t_u32 rx_stuck_issue_cnt[2];
+ /** Rx Stuck Recovery count */
+ t_u32 rx_stuck_recovery_cnt;
+ /** Rx Stuck TSF */
+ t_u64 rx_stuck_tsf[2];
+ /** Tx Watchdog Recovery Related Info */
+ /** Tx Watchdog Recovery count */
+ t_u32 tx_watchdog_recovery_cnt;
+ /** Tx Watchdog TSF */
+ t_u64 tx_watchdog_tsf[2];
+ /** Channel Switch Related Info */
+ /** Channel Switch Announcement Sent */
+ t_u32 channel_switch_ann_sent;
+ /** Channel Switch State */
+ t_u32 channel_switch_state;
+ /** Register Class */
+ t_u32 reg_class;
+ /** Channel Number */
+ t_u32 channel_number;
+ /** Channel Switch Mode */
+ t_u32 channel_switch_mode;
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats {
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+#define MAX_PATH_NUM 3
+/** path A */
+#define PATH_A 0x01
+/** path B */
+#define PATH_B 0x02
+/** path AB */
+#define PATH_AB 0x03
+/** ALL the path */
+#define PATH_ALL 0
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal {
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ *
+ * Bit0: PATH A
+ * Bit1: PATH B
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** bit for 2.4 G antenna diversity */
+#define ANT_DIVERSITY_2G MBIT(3)
+/** bit for 5 G antenna diversity */
+#define ANT_DIVERSITY_5G MBIT(7)
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info {
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** user's MCS setting */
+ t_u8 usr_dev_mcs_support;
+ /** 802.11ac device capabilities */
+ t_u32 hw_dot_11ac_dev_cap;
+ /** 802.11ac device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11ac_dev_cap_bg;
+ /** 802.11ac device Capabilities for 5GHz */
+ t_u32 usr_dot_11ac_dev_cap_a;
+ /** length of hw he capability */
+ t_u8 hw_hecap_len;
+ /** 802.11ax HE capability */
+ t_u8 hw_he_cap[54];
+ /** length of hw 2.4G he capability */
+ t_u8 hw_2g_hecap_len;
+ /** 802.11ax 2.4G HE capability */
+ t_u8 hw_2g_he_cap[54];
+ /** 802.11ac device support for MIMO abstraction of MCSs */
+ t_u32 hw_dot_11ac_mcs_support;
+ /** User conf 802.11ac device support for MIMO abstraction of MCSs */
+ t_u32 usr_dot_11ac_mcs_support;
+ /** fw supported band */
+ t_u16 fw_bands;
+ /** region code */
+ t_u16 region_code;
+ /** force_reg */
+ t_u8 force_reg;
+ /** ECSA support */
+ t_u8 ecsa_enable;
+ /** Get log support */
+ t_u8 getlog_enable;
+ /** FW support for embedded supplicant */
+ t_u8 fw_supplicant_support;
+ /** ant info */
+ t_u8 antinfo;
+ /** max AP associated sta count supported by fw */
+ t_u8 max_ap_assoc_sta;
+ /** Bandwidth not support 80Mhz */
+ t_u8 prohibit_80mhz;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext {
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t {
+ /** Extended Capabilities value */
+ t_u8 rsvdBit79 : 1; /* bit 79 */
+ t_u8 TWTResp : 1; /* bit 78 */
+ t_u8 TWTReq : 1; /* bit 77 */
+ t_u8 rsvdBit76 : 1; /* bit 76 */
+ t_u8 rsvdBit75 : 1; /* bit 75 */
+ t_u8 rsvdBit74 : 1; /* bit 74 */
+ t_u8 rsvdBit73 : 1; /* bit 73 */
+ t_u8 FILS : 1; /* bit 72 */
+ t_u8 FTMI : 1; /* bit 71 */
+ t_u8 FTMR : 1; /* bit 70 */
+ t_u8 CAQ : 1; /* bit 69 */
+ t_u8 rsvdBit68 : 1; /* bit 68 */
+ t_u8 NCC : 1; /* bit 67 */
+ t_u8 rsvdBit66 : 1; /* bit 66 */
+ t_u8 chanSchedMgnt : 1; /* bit 65 */
+ t_u8 MaxAMSDU1 : 1; /* bit 64 */
+ t_u8 MaxAMSDU0 : 1; /* bit 63 */
+ t_u8 OperModeNtf : 1; /* bit 62 */
+ t_u8 TDLSWildBandwidth : 1; /* bit 61 */
+ t_u8 rsvdBit60 : 1; /* bit 60 */
+ t_u8 rsvdBit59 : 1; /* bit 59 */
+ t_u8 rsvdBit58 : 1; /* bit 58 */
+ t_u8 rsvdBit57 : 1; /* bit 57 */
+ t_u8 rsvdBit56 : 1; /* bit 56 */
+ t_u8 rsvdBit55 : 1; /* bit 55 */
+ t_u8 rsvdBit54 : 1; /* bit 54 */
+ t_u8 rsvdBit53 : 1; /* bit 53 */
+ t_u8 rsvdBit52 : 1; /* bit 52 */
+ t_u8 rsvdBit51 : 1; /* bit 51 */
+ t_u8 rsvdBit50 : 1; /* bit 50 */
+ t_u8 rsvdBit49 : 1; /* bit 49 */
+ t_u8 rsvdBit48 : 1; /* bit 48 */
+ t_u8 rsvdBit47 : 1; /* bit 47 */
+ t_u8 rsvdBit46 : 1; /* bit 46 */
+ t_u8 rsvdBit45 : 1; /* bit 45 */
+ t_u8 rsvdBit44 : 1; /* bit 44 */
+ t_u8 rsvdBit43 : 1; /* bit 43 */
+ t_u8 rsvdBit42 : 1; /* bit 42 */
+ t_u8 rsvdBit41 : 1; /* bit 41 */
+ t_u8 rsvdBit40 : 1; /* bit 40 */
+ t_u8 TDLSChlSwitchProhib : 1; /* bit 39 */
+ t_u8 TDLSProhibited : 1; /* bit 38 */
+ t_u8 TDLSSupport : 1; /* bit 37 */
+ t_u8 MSGCF_Capa : 1; /* bit 36 */
+ t_u8 Reserved35 : 1; /* bit 35 */
+ t_u8 SSPN_Interface : 1; /* bit 34 */
+ t_u8 EBR : 1; /* bit 33 */
+ t_u8 Qos_Map : 1; /* bit 32 */
+ t_u8 Interworking : 1; /* bit 31 */
+ t_u8 TDLSChannelSwitching : 1; /* bit 30 */
+ t_u8 TDLSPeerPSMSupport : 1; /* bit 29 */
+ t_u8 TDLSPeerUAPSDSupport : 1; /* bit 28 */
+ t_u8 UTC : 1; /* bit 27 */
+ t_u8 DMS : 1; /* bit 26 */
+ t_u8 SSID_List : 1; /* bit 25 */
+ t_u8 ChannelUsage : 1; /* bit 24 */
+ t_u8 TimingMeasurement : 1; /* bit 23 */
+ t_u8 MultipleBSSID : 1; /* bit 22 */
+ t_u8 AC_StationCount : 1; /* bit 21 */
+ t_u8 QoSTrafficCap : 1; /* bit 20 */
+ t_u8 BSS_Transition : 1; /* bit 19 */
+ t_u8 TIM_Broadcast : 1; /* bit 18 */
+ t_u8 WNM_Sleep : 1; /* bit 17 */
+ t_u8 TFS : 1; /* bit 16 */
+ t_u8 GeospatialLocation : 1; /* bit 15 */
+ t_u8 CivicLocation : 1; /* bit 14 */
+ t_u8 CollocatedIntf : 1; /* bit 13 */
+ t_u8 ProxyARPService : 1; /* bit 12 */
+ t_u8 FMS : 1; /* bit 11 */
+ t_u8 LocationTracking : 1; /* bit 10 */
+ t_u8 MulticastDiagnostics : 1; /* bit 9 */
+ t_u8 Diagnostics : 1; /* bit 8 */
+ t_u8 Event : 1; /* bit 7 */
+ t_u8 SPSMP_Support : 1; /* bit 6 */
+ t_u8 Reserved5 : 1; /* bit 5 */
+ t_u8 PSMP_Capable : 1; /* bit 4 */
+ t_u8 RejectUnadmFrame : 1; /* bit 3 */
+ t_u8 ExtChanSwitching : 1; /* bit 2 */
+ t_u8 Reserved1 : 1; /* bit 1 */
+ t_u8 BSS_CoexistSupport : 1; /* bit 0 */
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+#else
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t {
+ /** Extended Capabilities value */
+ t_u8 BSS_CoexistSupport : 1; /* bit 0 */
+ t_u8 Reserved1 : 1; /* bit 1 */
+ t_u8 ExtChanSwitching : 1; /* bit 2 */
+ t_u8 RejectUnadmFrame : 1; /* bit 3 */
+ t_u8 PSMP_Capable : 1; /* bit 4 */
+ t_u8 Reserved5 : 1; /* bit 5 */
+ t_u8 SPSMP_Support : 1; /* bit 6 */
+ t_u8 Event : 1; /* bit 7 */
+ t_u8 Diagnostics : 1; /* bit 8 */
+ t_u8 MulticastDiagnostics : 1; /* bit 9 */
+ t_u8 LocationTracking : 1; /* bit 10 */
+ t_u8 FMS : 1; /* bit 11 */
+ t_u8 ProxyARPService : 1; /* bit 12 */
+ t_u8 CollocatedIntf : 1; /* bit 13 */
+ t_u8 CivicLocation : 1; /* bit 14 */
+ t_u8 GeospatialLocation : 1; /* bit 15 */
+ t_u8 TFS : 1; /* bit 16 */
+ t_u8 WNM_Sleep : 1; /* bit 17 */
+ t_u8 TIM_Broadcast : 1; /* bit 18 */
+ t_u8 BSS_Transition : 1; /* bit 19 */
+ t_u8 QoSTrafficCap : 1; /* bit 20 */
+ t_u8 AC_StationCount : 1; /* bit 21 */
+ t_u8 MultipleBSSID : 1; /* bit 22 */
+ t_u8 TimingMeasurement : 1; /* bit 23 */
+ t_u8 ChannelUsage : 1; /* bit 24 */
+ t_u8 SSID_List : 1; /* bit 25 */
+ t_u8 DMS : 1; /* bit 26 */
+ t_u8 UTC : 1; /* bit 27 */
+ t_u8 TDLSPeerUAPSDSupport : 1; /* bit 28 */
+ t_u8 TDLSPeerPSMSupport : 1; /* bit 29 */
+ t_u8 TDLSChannelSwitching : 1; /* bit 30 */
+ t_u8 Interworking : 1; /* bit 31 */
+ t_u8 Qos_Map : 1; /* bit 32 */
+ t_u8 EBR : 1; /* bit 33 */
+ t_u8 SSPN_Interface : 1; /* bit 34 */
+ t_u8 Reserved35 : 1; /* bit 35 */
+ t_u8 MSGCF_Capa : 1; /* bit 36 */
+ t_u8 TDLSSupport : 1; /* bit 37 */
+ t_u8 TDLSProhibited : 1; /* bit 38 */
+ t_u8 TDLSChlSwitchProhib : 1; /* bit 39 */
+ t_u8 rsvdBit40 : 1; /* bit 40 */
+ t_u8 rsvdBit41 : 1; /* bit 41 */
+ t_u8 rsvdBit42 : 1; /* bit 42 */
+ t_u8 rsvdBit43 : 1; /* bit 43 */
+ t_u8 rsvdBit44 : 1; /* bit 44 */
+ t_u8 rsvdBit45 : 1; /* bit 45 */
+ t_u8 rsvdBit46 : 1; /* bit 46 */
+ t_u8 rsvdBit47 : 1; /* bit 47 */
+ t_u8 rsvdBit48 : 1; /* bit 48 */
+ t_u8 rsvdBit49 : 1; /* bit 49 */
+ t_u8 rsvdBit50 : 1; /* bit 50 */
+ t_u8 rsvdBit51 : 1; /* bit 51 */
+ t_u8 rsvdBit52 : 1; /* bit 52 */
+ t_u8 rsvdBit53 : 1; /* bit 53 */
+ t_u8 rsvdBit54 : 1; /* bit 54 */
+ t_u8 rsvdBit55 : 1; /* bit 55 */
+ t_u8 rsvdBit56 : 1; /* bit 56 */
+ t_u8 rsvdBit57 : 1; /* bit 57 */
+ t_u8 rsvdBit58 : 1; /* bit 58 */
+ t_u8 rsvdBit59 : 1; /* bit 59 */
+ t_u8 rsvdBit60 : 1; /* bit 60 */
+ t_u8 TDLSWildBandwidth : 1; /* bit 61 */
+ t_u8 OperModeNtf : 1; /* bit 62 */
+ t_u8 MaxAMSDU0 : 1; /* bit 63 */
+ t_u8 MaxAMSDU1 : 1; /* bit 64 */
+ t_u8 chanSchedMgnt : 1; /* bit 65 */
+ t_u8 rsvdBit66 : 1; /* bit 66 */
+ t_u8 NCC : 1; /* bit 67 */
+ t_u8 rsvdBit68 : 1; /* bit 68 */
+ t_u8 CAQ : 1; /* bit 69 */
+ t_u8 FTMR : 1; /* bit 70 */
+ t_u8 FTMI : 1; /* bit 71 */
+ t_u8 FILS : 1; /* bit 72 */
+ t_u8 rsvdBit73 : 1; /* bit 73 */
+ t_u8 rsvdBit74 : 1; /* bit 74 */
+ t_u8 rsvdBit75 : 1; /* bit 75 */
+ t_u8 rsvdBit76 : 1; /* bit 76 */
+ t_u8 TWTReq : 1; /* bit 77 */
+ t_u8 TWTResp : 1; /* bit 78 */
+ t_u8 rsvdBit79 : 1; /* bit 79 */
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+#endif
+
+/** ExtCap : TDLS prohibited */
+#define IS_EXTCAP_TDLS_PROHIBITED(ext_cap) (ext_cap.TDLSProhibited)
+/** ExtCap : TDLS channel switch prohibited */
+#define IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ext_cap) (ext_cap.TDLSChlSwitchProhib)
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info {
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_s32 max_power_level;
+ /** Min power level in dBm */
+ t_s32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** scan block status */
+ t_u8 scan_block;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+ /** extend capability for AP */
+ ExtCap_t ext_cap;
+#endif /* STA_SUPPORT */
+ /** Mobility Domain ID */
+ t_u16 mdid;
+ /** FT Capability policy */
+ t_u8 ft_cap;
+ /** 11h active */
+ t_bool is_11h_active;
+ /** dfs check channel */
+ t_u8 dfs_check_channel;
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct {
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct {
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 10
+
+#ifdef SDIO
+/** sdio mp debug number */
+#define SDIO_MP_DBG_NUM 10
+#endif
+
+#ifdef PCIE
+#define MLAN_MAX_TXRX_BD 0x20
+#endif
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+/** max ralist num */
+#define MLAN_MAX_RALIST_NUM 8
+/** ralist info */
+typedef struct _ralist_info {
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** total packets in RA list */
+ t_u16 total_pkts;
+ /** tid num */
+ t_u8 tid;
+ /** tx_pause flag */
+ t_u8 tx_pause;
+} ralist_info, *pralist_info;
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info {
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** ralist num */
+ t_u32 ralist_num;
+ /** ralist info */
+ ralist_info ralist[MLAN_MAX_RALIST_NUM];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** time stamp when host try to wake up firmware */
+ t_u32 pm_wakeup_in_secs;
+ /** wake up timeout happened */
+ t_u32 pm_wakeup_timeout;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** bypass pkt count */
+ t_u16 bypass_pkt_count;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Corresponds to mlan_processing member of mlan_adapter */
+ t_u32 mlan_processing;
+ /** Corresponds to main_lock_flag member of mlan_adapter */
+ t_u32 main_lock_flag;
+ /** Corresponds to main_process_cnt member of mlan_adapter */
+ t_u32 main_process_cnt;
+ /** Corresponds to delay_task_flag member of mlan_adapter */
+ t_u32 delay_task_flag;
+ /** mlan_rx_processing */
+ t_u32 mlan_rx_processing;
+ /** rx pkts queued */
+ t_u32 rx_pkts_queued;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of allocate buffer failure */
+ t_u32 num_alloc_buffer_failure;
+ /** Number of pkt dropped */
+ t_u32 num_pkt_dropped;
+#ifdef SDIO
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** number of interrupt receive */
+ t_u32 num_of_irq;
+ /** flag for sdio rx aggr */
+ t_u8 sdio_rx_aggr;
+ /** FW update port number */
+ t_u32 mp_update[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX * 2];
+ /** Invalid port update count */
+ t_u32 mp_invalid_update;
+ /** Number of packets tx aggr */
+ t_u32 mpa_tx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** no more packets count*/
+ t_u32 mpa_sent_last_pkt;
+ /** no write_ports count */
+ t_u32 mpa_sent_no_ports;
+ /** last recv wr_bitmap */
+ t_u32 last_recv_wr_bitmap;
+ /** last mp_wr_bitmap */
+ t_u32 last_mp_wr_bitmap[SDIO_MP_DBG_NUM];
+ /** last ports for cmd53 write data */
+ t_u32 last_mp_wr_ports[SDIO_MP_DBG_NUM];
+ /** last len for cmd53 write data */
+ t_u32 last_mp_wr_len[SDIO_MP_DBG_NUM];
+ /** last curr_wr_port */
+ t_u8 last_curr_wr_port[SDIO_MP_DBG_NUM];
+ /** length info for cmd53 write data */
+ t_u16 last_mp_wr_info[SDIO_MP_DBG_NUM * SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** last mp_index */
+ t_u8 last_mp_index;
+ /** buffer for mp debug */
+ t_u8 *mpa_buf;
+ /** length info for mp buf size */
+ t_u32 mpa_buf_size;
+ /** Number of packets rx aggr */
+ t_u32 mpa_rx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** mp aggr_pkt limit */
+ t_u8 mp_aggr_pkt_limit;
+#endif
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of consecutive association failures */
+ t_u32 num_cons_assoc_failure;
+
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+ /** Number of no free command node */
+ t_u16 num_no_cmd_node;
+ /** pending command id */
+ t_u16 pending_cmd;
+ /** time stamp for dnld last cmd */
+ t_u32 dnld_cmd_in_secs;
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+#ifdef PCIE
+ /** PCIE txbd read pointer */
+ t_u32 txbd_rdptr;
+ /** PCIE txbd write pointer */
+ t_u32 txbd_wrptr;
+ /** PCIE rxbd read pointer */
+ t_u32 rxbd_rdptr;
+ /** PCIE rxbd write pointer */
+ t_u32 rxbd_wrptr;
+ /** PCIE eventbd read pointer */
+ t_u32 eventbd_rdptr;
+ /** PCIE eventbd write pointer */
+ t_u32 eventbd_wrptr;
+ /** Last pkt size in transmit */
+ t_u32 last_tx_pkt_size[MLAN_MAX_TXRX_BD];
+ /** txbd ring vbase */
+ t_u8 *txbd_ring_vbase;
+ /** txbd ring size */
+ t_u32 txbd_ring_size;
+ /** rxbd ring vbase */
+ t_u8 *rxbd_ring_vbase;
+ /** rxbd ring size */
+ t_u32 rxbd_ring_size;
+ /** evtbd ring vbase */
+ t_u8 *evtbd_ring_vbase;
+ /** evtbd ring size */
+ t_u32 evtbd_ring_size;
+#endif
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+ /** FW hang report */
+ t_u8 fw_hang_report;
+ /** mlan_adapter pointer */
+ t_void *mlan_adapter;
+ /** mlan_adapter_size */
+ t_u32 mlan_adapter_size;
+ /** mlan_priv vector */
+ t_void *mlan_priv[MLAN_MAX_BSS_NUM];
+ /** mlan_priv_size */
+ t_u32 mlan_priv_size[MLAN_MAX_BSS_NUM];
+ /** mlan_priv_num */
+ t_u8 mlan_priv_num;
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
+
+/** station info */
+typedef struct _sta_info {
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mgmt status */
+ t_u8 power_mgmt_status;
+ /** RSSI */
+ t_s8 rssi;
+ /** station bandmode */
+ t_u16 bandmode;
+ /** station stats */
+ sta_stats stats;
+ /** ie length */
+ t_u16 ie_len;
+ /** ie buffer */
+ t_u8 ie_buf[];
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list {
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info {
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Signal path id for MLAN_OID_GET_SIGNAL_EXT */
+ t_u16 path_id;
+ /** Signal information for MLAN_OID_GET_SIGNAL_EXT */
+ mlan_ds_get_signal signal_ext[MAX_PATH_NUM];
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Statistics information for MLAN_OID_LINK_STATS*/
+ t_u8 link_statistic[1];
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ t_u8 debug_info[1];
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode {
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_FT = 0x02,
+ MLAN_AUTH_MODE_SAE = 0x03,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/**Enumeration for AssocAgent authentication mode, sync from FW.*/
+typedef enum {
+ AssocAgentAuth_Open,
+ AssocAgentAuth_Shared,
+ AssocAgentAuth_FastBss,
+ AssocAgentAuth_FastBss_Skip,
+ AssocAgentAuth_Network_EAP,
+ AssocAgentAuth_Wpa3Sae,
+ AssocAgentAuth_Auto,
+} AssocAgentAuthType_e;
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode {
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+ MLAN_ENCRYPTION_MODE_GCMP = 5,
+ MLAN_ENCRYPTION_MODE_GCMP_256 = 6,
+ MLAN_ENCRYPTION_MODE_CCMP_256 = 7,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type {
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+ MLAN_PSK_SAE_PASSWORD,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+/* #define MLAN_MAX_KEY_LENGTH 32 */
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** Minimum sae_password length */
+#define MLAN_MIN_SAE_PASSWORD_LENGTH 8
+/** Maximum sae_password length */
+#define MLAN_MAX_SAE_PASSWORD_LENGTH 255
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for mcast IGTK */
+#define KEY_FLAG_AES_MCAST_IGTK 0x00000010
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+/** key flag for GCMP */
+#define KEY_FLAG_GCMP 0x00000020
+/** key flag for GCMP_256 */
+#define KEY_FLAG_GCMP_256 0x00000040
+/** key flag for ccmp 256 */
+#define KEY_FLAG_CCMP_256 0x00000080
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key {
+ /** Key disabled, all other fields will be
+ * ignore when this flag set to MTRUE
+ */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set
+ * to MTRUE, only key_index will be check
+ */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index
+ * when is_current_wep_key is set to MTRUE
+ */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t {
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type definition of mlan_sae_password_t */
+typedef struct _mlan_sae_password_t {
+ /** Length of SAE Password */
+ t_u32 sae_password_len;
+ /** SAE Password */
+ t_u8 sae_password[MLAN_MAX_SAE_PASSWORD_LENGTH];
+} mlan_sae_password_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t {
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS \
+ (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase {
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** SAE Password */
+ mlan_sae_password_t sae_password;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode {
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for
+ * MLAN_OID_SEC_CFG_EWPA_ENABLED
+ */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+#ifdef UAP_SUPPORT
+ t_u8 sta_mac[MLAN_MAC_ADDR_LENGTH];
+#endif
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+#define BIT_TLV_TYPE_CRYPTO_KEY (1 << 0)
+#define BIT_TLV_TYPE_CRYPTO_KEY_IV (1 << 1)
+#define BIT_TLV_TYPE_CRYPTO_KEY_PREFIX (1 << 2)
+#define BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK (1 << 3)
+
+/** Type definition of mlan_ds_sup_cfg */
+typedef struct _mlan_ds_sup_cfg {
+ /** Sub-command */
+ t_u8 sub_command;
+ /** output length */
+ t_u16 output_len;
+ /** number of data blks */
+ t_u16 data_blks_nr;
+ /** sub action code */
+ t_u8 sub_action_code;
+ /** skip bytes */
+ t_u16 skip_bytes;
+ /** iteration */
+ t_u32 iteration;
+ /** count */
+ t_u32 count;
+ /** pointer to output */
+ t_u8 *output;
+ /** key length */
+ t_u16 key_len;
+ /** pointer to key */
+ t_u8 *key;
+ /** key iv length */
+ t_u16 key_iv_len;
+ /** pointer to key iv */
+ t_u8 *key_iv;
+ /** key prefix length */
+ t_u16 key_prefix_len;
+ /** pointer to key prefix */
+ t_u8 *key_prefix;
+ /** pointer to data blk length array */
+ t_u32 *key_data_blk_len;
+ /** pointer to key data blk pointer array */
+ t_u8 **key_data_blk;
+ /** callback */
+ t_u8 call_back;
+} mlan_ds_sup_cfg, *pmlan_ds_sup_cfg;
+#endif
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type { MLAN_RATE_INDEX, MLAN_RATE_VALUE, MLAN_RATE_BITMAP };
+
+/** Enumeration for rate format */
+enum _mlan_rate_format {
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_VHT,
+ MLAN_RATE_FORMAT_HE,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 26
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t {
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: value; 2: bitmap */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** NSS */
+ t_u32 nss;
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 rate_format;
+ /** Rate Setting */
+ t_u16 rate_setting;
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw {
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+ /** VHT channel bandwidth */
+ MLAN_VHT_BW80,
+ MLAN_VHT_BW160,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi {
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+typedef enum _mlan_vht_stbc {
+ MLAN_VHT_STBC,
+ MLAN_VHT_NO_STBC,
+} mlan_vht_stbc;
+
+typedef enum _mlan_vht_ldpc {
+ MLAN_VHT_LDPC,
+ MLAN_VHT_NO_LDPC,
+} mlan_vht_ldpc;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate {
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate {
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+ /** MCS index */
+ t_u32 tx_mcs_index;
+ t_u32 rx_mcs_index;
+ /** NSS */
+ t_u32 tx_nss;
+ t_u32 rx_nss;
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 tx_rate_format;
+ t_u32 rx_rate_format;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t {
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_s32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+#define TX_PWR_CFG_AUTO_CTRL_OFF 0xFF
+#define MAX_POWER_GROUP 64
+/** Type definition of mlan_power group info */
+typedef struct mlan_power_group {
+ /** rate format (LG: 0, HT: 1, VHT: 2, no auto ctrl: 0xFF) */
+ t_u32 rate_format;
+ /** bandwidth (LG: 20 MHz, HT: 20/40 MHz, VHT: 80/160/80+80 MHz) */
+ t_u8 bandwidth;
+ /** NSS */
+ t_u32 nss;
+ /** LG: first rate index, HT/VHT: first MCS */
+ t_u8 first_rate_ind;
+ /** LG: last rate index, HT/VHT: last MCS */
+ t_u8 last_rate_ind;
+ /** minmum tx power (dBm) */
+ t_s8 power_min;
+ /** maximum tx power (dBm) */
+ t_s8 power_max;
+ /** tx power step (dB) */
+ t_s8 power_step;
+} mlan_power_group;
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext {
+ /** number of power_groups */
+ t_u32 num_pwr_grp;
+ /** array of power groups */
+ mlan_power_group power_group[MAX_POWER_GROUP];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ /** Low power mode for MLAN_OID_POWER_LOW_POWER_MODE */
+ t_u16 lpm;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/** Type definition of mlan_ds_band_steer_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_band_steer_cfg {
+ /** Set/Get */
+ t_u8 action;
+ /** enable/disable band steering*/
+ t_u8 state;
+ /** Probe Response will be blocked to 2G channel for first
+ * block_2g_prb_req probe requests*/
+ t_u8 block_2g_prb_req;
+ /** When band steering is enabled, limit the btm request sent to STA at
+ * <max_btm_req_allowed>*/
+ t_u8 max_btm_req_allowed;
+} mlan_ds_band_steer_cfg, *pmlan_ds_band_steer_cfg;
+
+/** Type definition of mlan_ds_beacon_stuck_param_cfg for MLAN_IOCTL_POWER_CFG
+ */
+typedef struct _mlan_ds_beacon_stuck_param_cfg {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u8 action;
+ /** No of beacon interval after which firmware will check if beacon Tx
+ * is going fine */
+ t_u8 beacon_stuck_detect_count;
+ /** Upon performing MAC reset, no of beacon interval after which
+ * firmware will check if recovery was successful */
+ t_u8 recovery_confirm_count;
+} mlan_ds_beacon_stuck_param_cfg, *pmlan_ds_beacon_stuck_param_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+/** Host sleep config condition: IPV6 packet */
+#define HOST_SLEEP_COND_IPV6_PACKET MBIT(31)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND 0
+
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+/** Host sleep config min wake holdoff */
+#define HOST_SLEEP_DEF_WAKE_HOLDOFF 0;
+/** Host sleep config inactivity timeout */
+#define HOST_SLEEP_DEF_INACTIVITY_TIMEOUT 10;
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg {
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special
+ * setting when GPIO is used to wakeup host
+ */
+ t_u32 gap;
+ /** Host sleep wake interval */
+ t_u32 hs_wake_interval;
+ /** Parameter type for indication gpio*/
+ t_u8 param_type_ind;
+ /** GPIO pin for indication wakeup source */
+ t_u32 ind_gpio;
+ /** Level on ind_gpio pin for indication normal wakeup source */
+ t_u32 level;
+ /** Parameter type for extend hscfg*/
+ t_u8 param_type_ext;
+ /** Events that will be forced ignore*/
+ t_u32 event_force_ignore;
+ /** Events that will use extend gap to inform host*/
+ t_u32 event_use_ext_gap;
+ /** Ext gap*/
+ t_u8 ext_gap;
+ /** GPIO wave level for extend hscfg*/
+ t_u8 gpio_wave;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+#define MAX_MGMT_FRAME_FILTER 2
+typedef struct _mlan_mgmt_frame_wakeup {
+ /** action - bitmap
+ ** On matching rx'd pkt and filter during NON_HOSTSLEEP mode:
+ ** Action[1]=0 Discard
+ ** Action[1]=1 Allow
+ ** Note that default action on non-match is "Allow".
+ **
+ ** On matching rx'd pkt and filter during HOSTSLEEP mode:
+ ** Action[1:0]=00 Discard and Not Wake host
+ ** Action[1:0]=01 Discard and Wake host
+ ** Action[1:0]=10 Invalid
+ ** Note that default action on non-match is "Discard and Not Wake
+ *host".
+ **/
+ t_u32 action;
+ /** Frame type(p2p, tdls...)
+ ** type=0: invalid
+ ** type=1: p2p
+ ** type=others: reserved
+ **/
+ t_u32 type;
+ /** Frame mask according to each type
+ ** When type=1 for p2p, frame-mask have following define:
+ ** Bit Frame
+ ** 0 GO Negotiation Request
+ ** 1 GO Negotiation Response
+ ** 2 GO Negotiation Confirmation
+ ** 3 P2P Invitation Request
+ ** 4 P2P Invitation Response
+ ** 5 Device Discoverability Request
+ ** 6 Device Discoverability Response
+ ** 7 Provision Discovery Request
+ ** 8 Provision Discovery Response
+ ** 9 Notice of Absence
+ ** 10 P2P Presence Request
+ ** 11 P2P Presence Response
+ ** 12 GO Discoverability Request
+ ** 13-31 Reserved
+ **
+ ** When type=others, frame-mask is reserved.
+ **/
+ t_u32 frame_mask;
+} mlan_mgmt_frame_wakeup, *pmlan_mgmt_frame_wakeup;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds {
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to
+ * for MLAN_OID_PM_CFG_INACTIVITY_TO
+ */
+typedef struct _mlan_ds_inactivity_to {
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg {
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params {
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param {
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param {
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Enable Robust Coex mode */
+#define ROBUSTCOEX_GPIOCFG_ENABLE 1
+/** Disable Robust Coex mode */
+#define ROBUSTCOEX_GPIOCFG_DISABLE 0
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+/** FW wake up method interface */
+#define FW_WAKEUP_METHOD_INTERFACE 1
+/** FW wake up method gpio */
+#define FW_WAKEUP_METHOD_GPIO 2
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt {
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info {
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_wakeup_reason for MLAN_OID_PM_HS_WAKEUP_REASON */
+typedef struct _mlan_ds_hs_wakeup_reason {
+ t_u16 hs_wakeup_reason;
+} mlan_ds_hs_wakeup_reason;
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_bcn_timeout {
+ /** Beacon miss timeout period window */
+ t_u16 bcn_miss_tmo_window;
+ /** Beacon miss timeout period */
+ t_u16 bcn_miss_tmo_period;
+ /** Beacon reacquire timeout period window */
+ t_u16 bcn_rq_tmo_window;
+ /** Beacon reacquire timeout period */
+ t_u16 bcn_rq_tmo_period;
+} mlan_ds_bcn_timeout, *pmlan_ds_bcn_timeout;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS
+ */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ /** hs wakeup reason for MLAN_OID_PM_HS_WAKEUP_REASON */
+ mlan_ds_hs_wakeup_reason wakeup_reason;
+ /** config manamgement frame for hs wakeup */
+ mlan_mgmt_frame_wakeup mgmt_filter[MAX_MGMT_FRAME_FILTER];
+ /** Beacon timout parameters for MLAN_OID_PM_CFG_BCN_TIMEOUT */
+ mlan_ds_bcn_timeout bcn_timeout;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+#ifdef RX_PACKET_COALESCE
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 pkt_threshold; /** Packet threshold */
+ t_u16 delay; /** Timeout value in milliseconds */
+} wlan_ioctl_rx_pkt_coalesce_config_t;
+#endif
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct {
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct {
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+ /** Type definition of mlan_ds_wmm_queue_stats
+ * for MLAN_OID_WMM_CFG_QUEUE_STATS
+ */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct {
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct {
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+ /** Type definition of mlan_ds_wmm_queue_status
+ * for MLAN_OID_WMM_CFG_QUEUE_STATUS
+ */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts {
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u32 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts {
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config
+ * for MLAN_OID_WMM_CFG_QUEUE_CONFIG
+ */
+typedef struct _mlan_ds_wmm_queue_config {
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI,
+ * WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status {
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg {
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param
+ * for MLAN_OID_11N_CFG_ADDBA_PARAM
+ */
+typedef struct _mlan_ds_11n_addba_param {
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg {
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+/** TX Sounding*/
+#define TX_SOUNDING_CFG 0x05
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args {
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg {
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl {
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl
+ * for MLAN_OID_11N_CFG_AGGR_PRIO_TBL
+ */
+typedef struct _mlan_ds_11n_aggr_prio_tbl {
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** DelBA All TIDs */
+#define DELBA_ALL_TIDS 0xff
+/** DelBA Tx */
+#define DELBA_TX MBIT(0)
+/** DelBA Rx */
+#define DELBA_RX MBIT(1)
+
+/** Type definition of mlan_ds_11n_delba for MLAN_OID_11N_CFG_DELBA */
+typedef struct _mlan_ds_11n_delba {
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Direction (Tx: bit 0, Rx: bit 1) */
+ t_u8 direction;
+} mlan_ds_11n_delba, *pmlan_ds_11n_delba;
+
+/** Type definition of mlan_ds_delba for MLAN_OID_11N_CFG_REJECT_ADDBA_REQ */
+typedef struct _mlan_ds_reject_addba_req {
+ /** Bit0 : host sleep activated
+ * Bit1 : auto reconnect enabled
+ * Others : reserved
+ */
+ t_u32 conditions;
+} mlan_ds_reject_addba_req, *pmlan_ds_reject_addba_req;
+
+/** Type definition of mlan_ds_ibss_ampdu_param */
+typedef struct _mlan_ds_ibss_ampdu_param {
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** rx amdpdu setting */
+ t_u8 addba_reject[MAX_NUM_TID];
+} mlan_ds_ibss_ampdu_param, *pmlan_ds_ibss_ampdu_param;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ /** DelBA for MLAN_OID_11N_CFG_DELBA */
+ mlan_ds_11n_delba del_ba;
+ /** Reject Addba Req for MLAN_OID_11N_CFG_REJECT_ADDBA_REQ */
+ mlan_ds_reject_addba_req reject_addba_req;
+ /** Control coex RX window size configuration */
+ t_u32 coex_rx_winsize;
+ /** aggrprirotity table for MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM */
+ mlan_ds_ibss_ampdu_param ibss_ampdu;
+ /** Minimum BA Threshold for MLAN_OID_11N_CFG_MIN_BA_THRESHOLD
+ */
+ t_u8 min_ba_threshold;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+#define NUM_MCS_SUPP 20
+#define VHT_MCS_SET_LEN 8
+
+/** Type definition of mlan_ds_11ac_vhtcap_cfg for MLAN_OID_11AC_VHTCAP_CFG */
+typedef struct _mlan_ds_11ac_vhtcap_cfg {
+ /** HT Capability information */
+ t_u32 vhtcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11ac_vhtcap_cfg, *pmlan_ds_11ac_vhtcap_cfg;
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG_TX */
+typedef struct _mlan_ds_11ac_tx_cfg {
+ /** Band selection */
+ t_u8 band_cfg;
+ /** misc configuration */
+ t_u8 misc_cfg;
+ /** HTTxCap */
+ t_u16 vhttxcap;
+ /** HTTxInfo */
+ t_u16 vhttxinfo;
+} mlan_ds_11ac_tx_cfg, *pmlan_ds_11ac_tx_cfg;
+
+/** Tx */
+#define MLAN_RADIO_TX MBIT(0)
+/** Rx */
+#define MLAN_RADIO_RX MBIT(1)
+/** Tx & Rx */
+#define MLAN_RADIO_TXRX (MLAN_RADIO_TX | MLAN_RADIO_RX)
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG */
+typedef struct _mlan_ds_11ac_vht_cfg {
+ /** Band selection (1: 2.4G, 2: 5 G, 3: both 2.4G and 5G) */
+ t_u32 band;
+ /** TxRx (1: Tx, 2: Rx, 3: both Tx and Rx) */
+ t_u32 txrx;
+ /** BW CFG (0: 11N CFG, 1: vhtcap) */
+ t_u32 bwcfg;
+ /** VHT capabilities. */
+ t_u32 vht_cap_info;
+ /** VHT Tx mcs */
+ t_u32 vht_tx_mcs;
+ /** VHT Rx mcs */
+ t_u32 vht_rx_mcs;
+ /** VHT rx max rate */
+ t_u16 vht_rx_max_rate;
+ /** VHT max tx rate */
+ t_u16 vht_tx_max_rate;
+ /** Skip usr 11ac mcs cfg */
+ t_bool skip_usr_11ac_mcs_cfg;
+} mlan_ds_11ac_vht_cfg, *pmlan_ds_11ac_vht_cfg;
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG */
+typedef struct _mlan_ds_11ac_opermode_cfg {
+ /** channel width: 1-20MHz, 2-40MHz, 3-80MHz, 4-160MHz or 80+80MHz */
+ t_u8 bw;
+ /** Rx NSS */
+ t_u8 nss;
+} mlan_ds_11ac_opermode_cfg, *pmlan_ds_11ac_opermode_cfg;
+
+/** Type definition of mlan_ds_11ac_cfg for MLAN_IOCTL_11AC_CFG */
+typedef struct _mlan_ds_11ac_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** VHT configuration for MLAN_OID_11AC_VHT_CFG */
+ mlan_ds_11ac_vht_cfg vht_cfg;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_SUPP];
+ /** Oper mode configuration for MLAN_OID_11AC_OPERMODE_CFG */
+ mlan_ds_11ac_opermode_cfg opermode_cfg;
+ } param;
+} mlan_ds_11ac_cfg, *pmlan_ds_11ac_cfg;
+
+/** Type definition of mlan_ds_11ax_he_capa for MLAN_OID_11AX_HE_CFG */
+typedef MLAN_PACK_START struct _mlan_ds_11ax_he_capa {
+ /** tlv id of he capability */
+ t_u16 id;
+ /** length of the payload */
+ t_u16 len;
+ /** extension id */
+ t_u8 ext_id;
+ /** he mac capability info */
+ t_u8 he_mac_cap[6];
+ /** he phy capability info */
+ t_u8 he_phy_cap[11];
+ /** he txrx mcs support for 80MHz */
+ t_u8 he_txrx_mcs_support[4];
+ /** val for txrx mcs 160Mhz or 80+80, and PPE thresholds */
+ t_u8 val[28];
+} MLAN_PACK_END mlan_ds_11ax_he_capa, *pmlan_ds_11ax_he_capa;
+
+/** Type definition of mlan_ds_11ax_he_cfg for MLAN_OID_11AX_HE_CFG */
+typedef struct _mlan_ds_11ax_he_cfg {
+ /** band, BIT0:2.4G, BIT1:5G*/
+ t_u8 band;
+ /** mlan_ds_11ax_he_capa */
+ mlan_ds_11ax_he_capa he_cap;
+} mlan_ds_11ax_he_cfg, *pmlan_ds_11ax_he_cfg;
+/** Type definition of mlan_ds_11as_cfg for MLAN_IOCTL_11AX_CFG */
+typedef struct _mlan_ds_11ax_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** HE configuration for MLAN_OID_11AX_HE_CFG */
+ mlan_ds_11ax_he_cfg he_cfg;
+ } param;
+} mlan_ds_11ax_cfg, *pmlan_ds_11ax_cfg;
+
+#define MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET 1
+#define MLAN_11AXCMD_CFG_ID_SR_ENABLE 2
+#define MLAN_11AXCMD_CFG_ID_BEAM_CHANGE 3
+#define MLAN_11AXCMD_CFG_ID_HTC_ENABLE 4
+#define MLAN_11AXCMD_CFG_ID_TXOP_RTS 5
+#define MLAN_11AXCMD_CFG_ID_TX_OMI 6
+#define MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME 7
+
+#define MLAN_11AXCMD_SR_SUBID 0x102
+#define MLAN_11AXCMD_BEAM_SUBID 0x103
+#define MLAN_11AXCMD_HTC_SUBID 0x104
+#define MLAN_11AXCMD_TXOMI_SUBID 0x105
+#define MLAN_11AXCMD_OBSS_TOLTIME_SUBID 0x106
+#define MLAN_11AXCMD_TXOPRTS_SUBID 0x108
+
+#define MLAN_11AX_TWT_SETUP_SUBID 0x114
+#define MLAN_11AX_TWT_TEARDOWN_SUBID 0x115
+
+#define MRVL_DOT11AX_ENABLE_SR_TLV_ID (PROPRIETARY_TLV_BASE_ID + 322)
+#define MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID (PROPRIETARY_TLV_BASE_ID + 323)
+
+/** Type definition of mlan_11axcmdcfg_obss_pd_offset for MLAN_OID_11AX_CMD_CFG
+ */
+typedef struct MLAN_PACK_START _mlan_11axcmdcfg_obss_pd_offset {
+ /** <NON_SRG_OffSET, SRG_OFFSET> */
+ t_u8 offset[2];
+} MLAN_PACK_END mlan_11axcmdcfg_obss_pd_offset;
+
+/** Type definition of mlan_11axcmdcfg_sr_control for MLAN_OID_11AX_CMD_CFG */
+typedef struct MLAN_PACK_START _mlan_11axcmdcfg_sr_control {
+ /** 1 enable, 0 disable */
+ t_u8 control;
+} MLAN_PACK_END mlan_11axcmdcfg_sr_control;
+
+/** Type definition of mlan_ds_11ax_sr_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_11ax_sr_cmd {
+ /** type*/
+ t_u16 type;
+ /** length of TLV */
+ t_u16 len;
+ /** value */
+ union {
+ mlan_11axcmdcfg_obss_pd_offset obss_pd_offset;
+ mlan_11axcmdcfg_sr_control sr_control;
+ } param;
+} MLAN_PACK_END mlan_ds_11ax_sr_cmd, *pmlan_ds_11ax_sr_cmd;
+
+/** Type definition of mlan_ds_11ax_beam_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_beam_cmd {
+ /** command value: 1 is disable, 0 is enable*/
+ t_u8 value;
+} mlan_ds_11ax_beam_cmd, *pmlan_ds_11ax_beam_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_htc_cmd {
+ /** command value: 1 is enable, 0 is disable*/
+ t_u8 value;
+} mlan_ds_11ax_htc_cmd, *pmlan_ds_11ax_htc_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_txop_cmd {
+ /** Two byte rts threshold value of which only 10 bits, bit 0 to bit 9
+ * are valid */
+ t_u16 rts_thres;
+} mlan_ds_11ax_txop_cmd, *pmlan_ds_11ax_txop_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_txomi_cmd {
+ /* 11ax spec 9.2.4.6a.2 OM Control 12 bits. Bit 0 to bit 11 */
+ t_u16 omi;
+} mlan_ds_11ax_txomi_cmd, *pmlan_ds_11ax_txomi_cmd;
+
+/** Type definition of mlan_ds_11ax_toltime_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_toltime_cmd {
+ /* OBSS Narrow Bandwidth RU Tolerance Time */
+ t_u32 tol_time;
+} mlan_ds_11ax_toltime_cmd, *pmlan_ds_11ax_toltime_cmd;
+
+/** Type definition of mlan_ds_11ax_cmd_cfg for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_cmd_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Sub-id */
+ t_u32 sub_id;
+ /** 802.11n configuration parameter */
+ union {
+ /** SR configuration for MLAN_11AXCMD_SR_SUBID */
+ mlan_ds_11ax_sr_cmd sr_cfg;
+ /** Beam configuration for MLAN_11AXCMD_BEAM_SUBID */
+ mlan_ds_11ax_beam_cmd beam_cfg;
+ /** HTC configuration for MLAN_11AXCMD_HTC_SUBID */
+ mlan_ds_11ax_htc_cmd htc_cfg;
+ /** txop RTS configuration for MLAN_11AXCMD_TXOPRTS_SUBID */
+ mlan_ds_11ax_txop_cmd txop_cfg;
+ /** tx omi configuration for MLAN_11AXCMD_TXOMI_SUBID */
+ mlan_ds_11ax_txomi_cmd txomi_cfg;
+ /** OBSS tolerance time configuration for
+ * MLAN_11AXCMD_TOLTIME_SUBID */
+ mlan_ds_11ax_toltime_cmd toltime_cfg;
+ } param;
+} mlan_ds_11ax_cmd_cfg, *pmlan_ds_11ax_cmd_cfg;
+
+/** Type definition of mlan_ds_twt_setup for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twt_setup {
+ /** Implicit, 0: TWT session is explicit, 1: Session is implicit */
+ t_u8 implicit;
+ /** Announced, 0: Unannounced, 1: Announced TWT */
+ t_u8 announced;
+ /** Trigger Enabled, 0: Non-Trigger enabled, 1: Trigger enabled TWT */
+ t_u8 trigger_enabled;
+ /** TWT Information Disabled, 0: TWT info enabled, 1: TWT info disabled
+ */
+ t_u8 twt_info_disabled;
+ /** Negotiation Type, 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** TWT Wakeup Duration, time after which the TWT requesting STA can
+ * transition to doze state */
+ t_u8 twt_wakeup_duration;
+ /** Flow Identifier. Range: [0-7]*/
+ t_u8 flow_identifier;
+ /** Hard Constraint, 0: FW can tweak the TWT setup parameters if it is
+ *rejected by AP.
+ ** 1: Firmware should not tweak any parameters. */
+ t_u8 hard_constraint;
+ /** TWT Exponent, Range: [0-63] */
+ t_u8 twt_exponent;
+ /** TWT Mantissa Range: [0-sizeof(UINT16)] */
+ t_u16 twt_mantissa;
+ /** TWT Request Type, 0: REQUEST_TWT, 1: SUGGEST_TWT*/
+ t_u8 twt_request;
+} MLAN_PACK_END mlan_ds_twt_setup, *pmlan_ds_twt_setup;
+
+/** Type definition of mlan_ds_twt_teardown for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twt_teardown {
+ /** TWT Flow Identifier. Range: [0-7] */
+ t_u8 flow_identifier;
+ /** Negotiation Type. 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** Tear down all TWT. 1: To teardown all TWT, 0 otherwise */
+ t_u8 teardown_all_twt;
+} MLAN_PACK_END mlan_ds_twt_teardown, *pmlan_ds_twt_teardown;
+
+/** Type definition of mlan_ds_twtcfg for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twtcfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Sub-id */
+ t_u32 sub_id;
+ /** TWT Setup/Teardown configuration parameter */
+ union {
+ /** TWT Setup config for Sub ID: MLAN_11AX_TWT_SETUP_SUBID */
+ mlan_ds_twt_setup twt_setup;
+ /** TWT Teardown config for Sub ID: MLAN_11AX_TWT_TEARDOWN_SUBID
+ */
+ mlan_ds_twt_teardown twt_teardown;
+ } param;
+} MLAN_PACK_END mlan_ds_twtcfg, *pmlan_ds_twtcfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t {
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info {
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+#endif /* STA_SUPPORT */
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO_EXT */
+ mlan_ds_11d_domain_info domain_info;
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for CSU target device type */
+enum _mlan_csu_target_type {
+ MLAN_CSU_TARGET_CAU = 1,
+ MLAN_CSU_TARGET_PSU,
+};
+
+/** Enumeration for register type */
+enum _mlan_reg_type {
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU = 5,
+ MLAN_REG_PSU = 6,
+ MLAN_REG_BCA = 7,
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ MLAN_REG_MAC2 = 0x81,
+ MLAN_REG_BBP2 = 0x82,
+ MLAN_REG_RF2 = 0x83,
+ MLAN_REG_BCA2 = 0x87
+#endif
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw {
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom {
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw {
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing {
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u32 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel
+ */
+ t_u8 usr_fixed_new_chan;
+ /** User-configured cac restart */
+ t_u8 usr_cac_restart;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_CHAN_NOP_INFO */
+typedef struct _mlan_ds_11h_chan_nop_info {
+ /** current channel */
+ t_u8 curr_chan;
+ /** channel_width */
+ t_u8 chan_width;
+ /** flag for chan under nop */
+ t_bool chan_under_nop;
+ /** chan_ban_info for new channel */
+ chan_band_info new_chan;
+} mlan_ds_11h_chan_nop_info, *pmlan_ds_11h_chan_nop_info;
+
+typedef struct _mlan_ds_11h_chan_rep_req {
+ t_u16 startFreq;
+ Band_Config_t bandcfg;
+ t_u8 chanNum;
+ t_u32 millisec_dwell_time; /**< Channel dwell time in milliseconds */
+ t_u8 host_based;
+} mlan_ds_11h_chan_rep_req;
+
+typedef struct _mlan_ds_11h_dfs_w53_cfg {
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+} mlan_ds_11h_dfs_w53_cfg;
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ union {
+ /** Local power constraint for
+ * MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+ /** channel NOP information for MLAN_OID_11H_CHAN_NOP_INFO */
+ mlan_ds_11h_chan_nop_info ch_nop_info;
+ /** channel report req for MLAN_OID_11H_CHAN_REPORT_REQUEST */
+ mlan_ds_11h_chan_rep_req chan_rpt_req;
+ /** channel switch count for MLAN_OID_11H_CHAN_SWITCH_COUNT*/
+ t_s8 cs_count;
+ mlan_ds_11h_dfs_w53_cfg dfs_w53_cfg;
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER (3 * 1024)
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type {
+ MLAN_IE_TYPE_GEN_IE = 0,
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie {
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#ifdef SDIO
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl
+ * for MLAN_OID_MISC_SDIO_MPA_CTRL
+ */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl {
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd {
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MRVDRV_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock {
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd {
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause
+ * for MLAN_OID_MISC_TX_DATAPAUSE
+ */
+typedef struct _mlan_ds_misc_tx_datapause {
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg
+ * for MLAN_OID_MISC_RX_ABORT_CFG
+ */
+typedef struct _mlan_ds_misc_rx_abort_cfg {
+ /** enable/disable rx abort */
+ t_u8 enable;
+ /** Rx weak RSSI pkt threshold */
+ t_s8 rssi_threshold;
+} mlan_ds_misc_rx_abort_cfg;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg_ext
+ * for MLAN_OID_MISC_RX_ABORT_CFG_EXT
+ */
+typedef struct _mlan_ds_misc_rx_abort_cfg_ext {
+ /** enable/disable dynamic rx abort */
+ t_u8 enable;
+ /** rssi margin */
+ t_s8 rssi_margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_rssi_threshold;
+} mlan_ds_misc_rx_abort_cfg_ext;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg_ext
+ * for MLAN_OID_MISC_TX_AMDPU_PROT_MODE
+ */
+typedef struct _mlan_ds_misc_tx_ampdu_prot_mode {
+ /** set prot mode */
+ t_u16 mode;
+} mlan_ds_misc_tx_ampdu_prot_mode;
+
+/** Type definition of mlan_ds_misc_dot11mc_unassoc_ftm_cfg
+ * for MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG
+ */
+typedef struct _mlan_ds_misc_dot11mc_unassoc_ftm_cfg {
+ /** set the state */
+ t_u16 state;
+} mlan_ds_misc_dot11mc_unassoc_ftm_cfg;
+
+#define RATEADAPT_ALGO_LEGACY 0
+#define RATEADAPT_ALGO_SR 1
+
+/** Type definition of mlan_ds_misc_rate_adapt_cfg
+ * for MLAN_OID_MISC_RATE_ADAPT_CFG
+ */
+typedef struct _mlan_ds_misc_rate_adapt_cfg {
+ /** SR Rateadapt */
+ t_u8 sr_rateadapt;
+ /** set low threshold */
+ t_u8 ra_low_thresh;
+ /** set high threshold */
+ t_u8 ra_high_thresh;
+ /** set interval */
+ t_u16 ra_interval;
+} mlan_ds_misc_rate_adapt_cfg;
+
+/** Type definition of mlan_ds_misc_cck_desense_cfg
+ * for MLAN_OID_MISC_CCK_DESENSE_CFG
+ */
+typedef struct _mlan_ds_misc_cck_desense_cfg {
+ /** cck desense mode: 0:disable 1:normal 2:dynamic */
+ t_u16 mode;
+ /** specify rssi margin */
+ t_s8 margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_thresh;
+ /** cck desense "on" interval count */
+ t_u8 num_on_intervals;
+ /** cck desense "off" interval count */
+ t_u8 num_off_intervals;
+} mlan_ds_misc_cck_desense_cfg;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - NONE*/
+#define IPADDR_TYPE_NONE (0)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg {
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg {
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code {
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_arb_cfg
+ * for MLAN_OID_MISC_ARB_CFG
+ */
+typedef struct _mlan_ds_misc_arb_cfg {
+ /** arb mode 0-4 */
+ t_u32 arb_mode;
+} mlan_ds_misc_arb_cfg;
+
+/** Type definition of mlan_ds_misc_tp_state
+ * for MLAN_OID_MISC_TP_STATE
+ */
+typedef struct _mlan_ds_misc_tp_state {
+ /** TP account mode 0-disable 1-enable */
+ t_u32 on;
+ /** Packet drop point */
+ t_u32 drop_point;
+} mlan_ds_misc_tp_state;
+
+/** Type definition of mlan_ds_misc_country_code
+ * for MLAN_OID_MISC_COUNTRY_CODE
+ */
+typedef struct _mlan_ds_misc_country_code {
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
+/** action for set */
+#define SUBSCRIBE_EVT_ACT_BITWISE_SET 0x0002
+/** action for clear */
+#define SUBSCRIBE_EVT_ACT_BITWISE_CLR 0x0003
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt {
+ /** evt action */
+ t_u16 evt_action;
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB)*/
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data
+ * for MLAN_OID_MISC_OTP_USER_DATA
+ */
+typedef struct _mlan_ds_misc_otp_user_data {
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
+typedef struct _aggr_ctrl {
+ /** Enable */
+ t_u16 enable;
+ /** Aggregation alignment */
+ t_u16 aggr_align;
+ /** Aggregation max size */
+ t_u16 aggr_max_size;
+ /** Aggregation max packet number */
+ t_u16 aggr_max_num;
+ /** Aggrgation timeout, in microseconds */
+ t_u16 aggr_tmo;
+} aggr_ctrl;
+
+/** Type definition of mlan_ds_misc_aggr_ctrl
+ * for MLAN_OID_MISC_AGGR_CTRL
+ */
+typedef struct _mlan_ds_misc_aggr_ctrl {
+ /** Tx aggregation control */
+ aggr_ctrl tx;
+} mlan_ds_misc_aggr_ctrl;
+
+#ifdef USB
+typedef struct _usb_aggr_ctrl {
+ /** Enable */
+ t_u16 enable;
+ /** Aggregation mode */
+ t_u16 aggr_mode;
+ /** Aggregation alignment */
+ t_u16 aggr_align;
+ /** Aggregation max packet/size */
+ t_u16 aggr_max;
+ /** Aggrgation timeout, in microseconds */
+ t_u16 aggr_tmo;
+} usb_aggr_ctrl;
+
+/** Type definition of mlan_ds_misc_usb_aggr_ctrl
+ * for MLAN_OID_MISC_USB_AGGR_CTRL
+ */
+typedef struct _mlan_ds_misc_usb_aggr_ctrl {
+ /** Tx aggregation control */
+ usb_aggr_ctrl tx_aggr_ctrl;
+ /** Rx deaggregation control */
+ usb_aggr_ctrl rx_deaggr_ctrl;
+} mlan_ds_misc_usb_aggr_ctrl;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** flag for NOA */
+#define WIFI_DIRECT_NOA 1
+/** flag for OPP_PS */
+#define WIFI_DIRECT_OPP_PS 2
+/** Type definition of mlan_ds_wifi_direct_config
+ * for MLAN_OID_MISC_WIFI_DIRECT_CONFIG
+ */
+typedef struct _mlan_ds_wifi_direct_config {
+ /** flags for NOA/OPP_PS */
+ t_u8 flags;
+ /** NoA enable/disable */
+ t_u8 noa_enable;
+ /** index */
+ t_u16 index;
+ /** NoA count */
+ t_u8 noa_count;
+ /** NoA duration */
+ t_u32 noa_duration;
+ /** NoA interval */
+ t_u32 noa_interval;
+ /** opp ps enable/disable */
+ t_u8 opp_ps_enable;
+ /** CT window value */
+ t_u8 ct_window;
+} mlan_ds_wifi_direct_config;
+#endif
+
+#if defined(STA_SUPPORT)
+typedef struct _mlan_ds_misc_pmfcfg {
+ /** Management Frame Protection Capable */
+ t_u8 mfpc;
+ /** Management Frame Protection Required */
+ t_u8 mfpr;
+} mlan_ds_misc_pmfcfg;
+#endif
+
+#define MAX_SSID_NUM 16
+#define MAX_AP_LIST 8
+
+#ifdef RX_PACKET_COALESCE
+typedef struct _mlan_ds_misc_rx_packet_coalesce {
+ /** packet threshold */
+ t_u32 packet_threshold;
+ /** timeout value */
+ t_u16 delay;
+} mlan_ds_misc_rx_packet_coalesce;
+#endif
+
+typedef struct _mlan_ds_misc_dfs_repeater {
+ /** Set or Get */
+ t_u16 action;
+ /** 1 on or 0 off */
+ t_u16 mode;
+} mlan_ds_misc_dfs_repeater;
+
+#define WOWLAN_MAX_PATTERN_LEN 20
+#define WOWLAN_MAX_OFFSET_LEN 50
+#define MAX_NUM_FILTERS 10
+#define MEF_MODE_HOST_SLEEP (1 << 0)
+#define MEF_MODE_NON_HOST_SLEEP (1 << 1)
+#define MEF_ACTION_WAKE (1 << 0)
+#define MEF_ACTION_ALLOW (1 << 1)
+#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
+#define MEF_AUTO_ARP 0x10
+#define MEF_AUTO_PING 0x20
+#define MEF_NS_RESP 0x40
+#define MEF_MAGIC_PKT 0x80
+#define CRITERIA_BROADCAST BIT(0)
+#define CRITERIA_UNICAST BIT(1)
+#define CRITERIA_MULTICAST BIT(3)
+
+#define MAX_NUM_ENTRIES 8
+#define MAX_NUM_BYTE_SEQ 6
+#define MAX_NUM_MASK_SEQ 6
+
+#define OPERAND_DNUM 1
+#define OPERAND_BYTE_SEQ 2
+
+#define MAX_OPERAND 0x40
+#define TYPE_BYTE_EQ (MAX_OPERAND + 1)
+#define TYPE_DNUM_EQ (MAX_OPERAND + 2)
+#define TYPE_BIT_EQ (MAX_OPERAND + 3)
+
+#define RPN_TYPE_AND (MAX_OPERAND + 4)
+#define RPN_TYPE_OR (MAX_OPERAND + 5)
+
+#define ICMP_OF_IP_PROTOCOL 0x01
+#define TCP_OF_IP_PROTOCOL 0x06
+#define UDP_OF_IP_PROTOCOL 0x11
+
+#define IPV4_PKT_OFFSET 20
+#define IP_PROTOCOL_OFFSET 31
+#define PORT_PROTOCOL_OFFSET 44
+
+#define FILLING_TYPE MBIT(0)
+#define FILLING_PATTERN MBIT(1)
+#define FILLING_OFFSET MBIT(2)
+#define FILLING_NUM_BYTES MBIT(3)
+#define FILLING_REPEAT MBIT(4)
+#define FILLING_BYTE_SEQ MBIT(5)
+#define FILLING_MASK_SEQ MBIT(6)
+
+/** Type definition of filter_item
+ * Support three match methods:
+ * <1>Byte comparison type=0x41
+ * <2>Decimal comparison type=0x42
+ * <3>Bit comparison type=0x43
+ */
+typedef struct _mef_filter_t {
+ /** flag*/
+ t_u32 fill_flag;
+ /** BYTE 0X41; Decimal 0X42; Bit 0x43*/
+ t_u16 type;
+ /** value*/
+ t_u32 pattern;
+ /** offset*/
+ t_u16 offset;
+ /** number of bytes*/
+ t_u16 num_bytes;
+ /** repeat*/
+ t_u16 repeat;
+ /** byte number*/
+ t_u8 num_byte_seq;
+ /** array*/
+ t_u8 byte_seq[MAX_NUM_BYTE_SEQ];
+ /** mask numbers*/
+ t_u8 num_mask_seq;
+ /** array*/
+ t_u8 mask_seq[MAX_NUM_MASK_SEQ];
+} mef_filter_t;
+
+typedef struct _mef_entry_t {
+ /** mode: bit0--hostsleep mode; bit1--non hostsleep mode */
+ t_u8 mode;
+ /** action: 0--discard and not wake host;
+ 1--discard and wake host;
+ 3--allow and wake host;*/
+ t_u8 action;
+ /** filter number */
+ t_u8 filter_num;
+ /** filter array*/
+ mef_filter_t filter_item[MAX_NUM_FILTERS];
+ /** rpn array*/
+ t_u8 rpn[MAX_NUM_FILTERS];
+} mef_entry_t;
+
+/** Type definition of mlan_ds_nvflt_mef_entry
+ *for MLAN_OID_MISC_MEF_FLT_CFG
+ */
+typedef struct _mlan_ds_misc_mef_flt_cfg {
+ /** Type of action*/
+ int mef_act_type;
+ /** NV Filter Criteria*/
+ t_u32 criteria;
+ /** NV MEF entry*/
+ mef_entry_t mef_entry;
+} mlan_ds_misc_mef_flt_cfg;
+
+/** Enumeration for action type*/
+enum _mlan_act_mef_act_type {
+ MEF_ACT_ADD = 1,
+ MEF_ACT_ENABLE,
+ MEF_ACT_DISABLE,
+ MEF_ACT_CANCEL,
+ MEF_ACT_AUTOARP,
+ MEF_ACT_WOWLAN,
+ MEF_ACT_IPV6_NS,
+};
+
+typedef struct _mlan_ds_sensor_temp {
+ t_u32 temperature;
+} mlan_ds_sensor_temp;
+
+#define MLAN_KCK_LEN 16
+#define MLAN_KEK_LEN 16
+#define MLAN_REPLAY_CTR_LEN 8
+/** mlan_ds_misc_gtk_rekey_data */
+typedef struct _mlan_ds_misc_gtk_rekey_data {
+ /** key encryption key */
+ t_u8 kek[MLAN_KEK_LEN];
+ /** key confirmation key */
+ t_u8 kck[MLAN_KCK_LEN];
+ /** replay counter */
+ t_u8 replay_ctr[MLAN_REPLAY_CTR_LEN];
+} mlan_ds_misc_gtk_rekey_data;
+typedef struct _mlan_ds_bw_chan_oper {
+ /* bandwidth 20:20M 40:40M 80:80M*/
+ t_u8 bandwidth;
+ /* channel number */
+ t_u8 channel;
+ /* Non-global operating class */
+ t_u8 oper_class;
+} mlan_ds_bw_chan_oper;
+
+typedef struct _mlan_ds_ind_rst_cfg {
+ /** Set or Get */
+ t_u16 action;
+ /** oob mode enable/ disable */
+ t_u8 ir_mode;
+ /** gpio pin */
+ t_u8 gpio_pin;
+} mlan_ds_ind_rst_cfg;
+
+#define MKEEP_ALIVE_IP_PKT_MAX 256
+typedef struct _mlan_ds_misc_keep_alive {
+ t_u8 mkeep_alive_id;
+ t_u8 enable;
+ /** enable/disable tcp reset*/
+ t_u8 reset;
+ /**True means saved in driver, false means not saved or download*/
+ t_u8 cached;
+ t_u32 send_interval;
+ t_u16 retry_interval;
+ t_u16 retry_count;
+ t_u8 dst_mac[MLAN_MAC_ADDR_LENGTH];
+ t_u8 src_mac[MLAN_MAC_ADDR_LENGTH];
+ t_u16 pkt_len;
+ t_u8 packet[MKEEP_ALIVE_IP_PKT_MAX];
+ /** Ethernet type */
+ t_u16 ether_type;
+} mlan_ds_misc_keep_alive, *pmlan_ds_misc_keep_alive;
+
+/** TX and RX histogram statistic parameters*/
+typedef MLAN_PACK_START struct _mlan_ds_misc_tx_rx_histogram {
+ /** Enable or disable get tx/rx histogram statistic */
+ t_u8 enable;
+ /** Choose to get TX, RX or both histogram statistic */
+ t_u16 action;
+ /** Size of Tx/Rx info */
+ t_u16 size;
+ /** Store Tx/Rx info */
+ t_u8 value[1];
+} MLAN_PACK_END mlan_ds_misc_tx_rx_histogram;
+
+typedef MLAN_PACK_START struct _mlan_ds_cw_mode_ctrl {
+ /** Mode of Operation 0: Disable 1: Tx Continuous Packet 2: Tx
+ * Continuous Wave */
+ t_u8 mode;
+ /*channel*/
+ t_u8 channel;
+ /* channel info*/
+ t_u8 chanInfo;
+ /** Tx Power level in dBm */
+ t_u16 txPower;
+ /** Packet Length */
+ t_u16 pktLength;
+ /** bit rate Info */
+ t_u32 rateInfo;
+} MLAN_PACK_END mlan_ds_cw_mode_ctrl;
+
+#define RX_PKT_INFO MBIT(1)
+/** Struct for per-packet configuration */
+typedef struct _mlan_per_pkt_cfg {
+ /** Type ID*/
+ t_u16 type;
+ /** Length of payload*/
+ t_u16 len;
+ /** Tx/Rx per-packet control */
+ t_u8 tx_rx_control;
+ /** Number of ethernet types in ether_type array */
+ t_u8 proto_type_num;
+ /** Array of ether_type for per-packet control */
+ t_u16 ether_type[];
+} mlan_per_pkt_cfg;
+
+/** Type definition of mlan_ds_misc_robustcoex_params for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_robustcoex_params {
+ t_u16 method;
+ /** enable/disable robustcoex gpio cfg */
+ t_u8 enable;
+ /** Number of GPIO */
+ t_u8 gpio_num;
+ /** Polarity of GPIO */
+ t_u8 gpio_polarity;
+} mlan_ds_misc_robustcoex_params;
+
+#if defined(PCIE)
+typedef struct _mlan_ds_ssu_params {
+ t_u32 nskip;
+ t_u32 nsel;
+ t_u32 adcdownsample;
+ t_u32 mask_adc_pkt;
+ t_u32 out_16bits;
+ t_u32 spec_pwr_enable;
+ t_u32 rate_deduction;
+ t_u32 n_pkt_avg;
+} mlan_ds_ssu_params;
+#endif
+
+#define MAX_NUM_MAC 2
+/** Type definition of mlan_ds_misc_mapping_policy */
+typedef struct _mlan_ds_misc_mapping_policy {
+ /** Enable/disable dynamic mapping */
+ t_u16 subcmd;
+ /** Mapping policy */
+ t_u8 mapping_policy;
+} mlan_ds_misc_mapping_policy, *pmlan_ds_misc_mapping_policy;
+
+typedef struct _dmcsChanStatus_t {
+ /** Channel number */
+ t_u8 channel;
+ /** Number of ap on this channel */
+ t_u8 ap_count;
+ /** Number of sta on this channel */
+ t_u8 sta_count;
+} dmcsChanStatus_t, *pdmcsChanStatus_t;
+
+typedef struct _dmcsStatus_t {
+ /** Radio ID */
+ t_u8 radio_id;
+ /** Running mode
+ ** 0 - Idle
+ ** 1 - DBC
+ ** 2 - DRCS
+ */
+ t_u8 running_mode;
+ /** Current channel status */
+ dmcsChanStatus_t chan_status[2];
+} dmcsStatus_t, *pdmcsStatus_t;
+
+/** Type definition of mlan_ds_misc_dmcs_status */
+typedef struct _mlan_ds_misc_dmcs_status {
+ t_u8 mapping_policy;
+ dmcsStatus_t radio_status[MAX_NUM_MAC];
+} mlan_ds_misc_dmcs_status, *pmlan_ds_misc_dmcs_status;
+
+/** Type definition of mlan_ds_misc_chan_trpc_cfg for
+ * MLAN_OID_MISC_GET_CHAN_TRPC_CFG */
+typedef struct _mlan_ds_misc_chan_trpc_cfg {
+ /** sub_band */
+ t_u16 sub_band;
+ /** length */
+ t_u16 length;
+ /** buf */
+ t_u8 trpc_buf[2048];
+} mlan_ds_misc_chan_trpc_cfg;
+
+#define MFG_CMD_SET_TEST_MODE 1
+#define MFG_CMD_UNSET_TEST_MODE 0
+#define MFG_CMD_TX_ANT 0x1004
+#define MFG_CMD_RX_ANT 0x1005
+#define MFG_CMD_TX_CONT 0x1009
+#define MFG_CMD_RF_CHAN 0x100A
+#define MFG_CMD_CLR_RX_ERR 0x1010
+#define MFG_CMD_TX_FRAME 0x1021
+#define MFG_CMD_RFPWR 0x1033
+#define MFG_CMD_RF_BAND_AG 0x1034
+#define MFG_CMD_RF_CHANNELBW 0x1044
+/** MFG CMD generic cfg */
+struct MLAN_PACK_START mfg_cmd_generic_cfg {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** value 1 */
+ t_u32 data1;
+ /** value 2 */
+ t_u32 data2;
+ /** value 3 */
+ t_u32 data3;
+} MLAN_PACK_END;
+
+/** MFG CMD Tx Frame 2 */
+struct MLAN_PACK_START mfg_cmd_tx_frame2 {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** enable */
+ t_u32 enable;
+ /** data_rate */
+ t_u32 data_rate;
+ /** frame pattern */
+ t_u32 frame_pattern;
+ /** frame length */
+ t_u32 frame_length;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Adjust burst sifs */
+ t_u16 adjust_burst_sifs;
+ /** Burst sifs in us*/
+ t_u32 burst_sifs_in_us;
+ /** short preamble */
+ t_u32 short_preamble;
+ /** active sub channel */
+ t_u32 act_sub_ch;
+ /** short GI */
+ t_u32 short_gi;
+ /** Adv coding */
+ t_u32 adv_coding;
+ /** Tx beamforming */
+ t_u32 tx_bf;
+ /** HT Greenfield Mode*/
+ t_u32 gf_mode;
+ /** STBC */
+ t_u32 stbc;
+ /** power id */
+ t_u32 rsvd[2];
+} MLAN_PACK_END;
+
+/* MFG CMD Tx Continuous */
+struct MLAN_PACK_START mfg_cmd_tx_cont {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** enable Tx*/
+ t_u32 enable_tx;
+ /** Continuous Wave mode */
+ t_u32 cw_mode;
+ /** payload pattern */
+ t_u32 payload_pattern;
+ /** CS Mode */
+ t_u32 cs_mode;
+ /** active sub channel */
+ t_u32 act_sub_ch;
+ /** Tx rate */
+ t_u32 tx_rate;
+ /** power id */
+ t_u32 rsvd;
+} MLAN_PACK_END;
+
+typedef struct _mlan_ds_misc_chnrgpwr_cfg {
+ /** length */
+ t_u16 length;
+ /** chnrgpwr buf */
+ t_u8 chnrgpwr_buf[2048];
+} mlan_ds_misc_chnrgpwr_cfg;
+
+/** dfs chan list for MLAN_OID_MISC_CFP_TABLE */
+typedef struct _mlan_ds_misc_cfp_tbl {
+ /** band */
+ t_u8 band;
+ /** num chan */
+ t_u8 num_chan;
+ /** cfp table */
+ chan_freq_power_t cfp_tbl[];
+} mlan_ds_misc_cfp_tbl;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#ifdef SDIO
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Get associate response for MLAN_OID_MISC_ASSOC_RSP */
+ mlan_ds_misc_assoc_rsp assoc_resp;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Config dynamic bandwidth*/
+ t_u16 dyn_bw;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ /** Hotspot config param set */
+ t_u32 hotspot_cfg;
+#ifdef STA_SUPPORT
+ ExtCap_t ext_cap;
+#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
+#ifdef USB
+ /** USB aggregation parameters for MLAN_OID_MISC_USB_AGGR_CTRL
+ */
+ mlan_ds_misc_usb_aggr_ctrl usb_aggr_params;
+#endif
+ mlan_ds_misc_aggr_ctrl aggr_params;
+ /** Tx control */
+ t_u32 tx_control;
+#if defined(STA_SUPPORT)
+ mlan_ds_misc_pmfcfg pmfcfg;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ mlan_ds_wifi_direct_config p2p_config;
+#endif
+ mlan_ds_coalesce_cfg coalesce_cfg;
+ t_u8 low_pwr_mode;
+ /** MEF-FLT-CONFIG for MLAN_OID_MISC_NV_FLT_CFG */
+ mlan_ds_misc_mef_flt_cfg mef_flt_cfg;
+ mlan_ds_misc_dfs_repeater dfs_repeater;
+#ifdef RX_PACKET_COALESCE
+ mlan_ds_misc_rx_packet_coalesce rx_coalesce;
+#endif
+ /** FW reload flag */
+ t_u8 fw_reload;
+ mlan_ds_sensor_temp sensor_temp;
+ /** GTK rekey data */
+ mlan_ds_misc_gtk_rekey_data gtk_rekey;
+ mlan_ds_bw_chan_oper bw_chan_oper;
+ mlan_ds_ind_rst_cfg ind_rst_cfg;
+ t_u64 misc_tsf;
+ mlan_ds_custom_reg_domain custom_reg_domain;
+ mlan_ds_misc_keep_alive keep_alive;
+ mlan_ds_misc_tx_rx_histogram tx_rx_histogram;
+ mlan_ds_cw_mode_ctrl cwmode;
+ /** Tx/Rx per-packet control */
+ t_u8 txrx_pkt_ctrl;
+ mlan_ds_misc_robustcoex_params robustcoexparams;
+#if defined(PCIE)
+ mlan_ds_ssu_params ssu_params;
+#endif
+ /** boot sleep enable or disable */
+ t_u16 boot_sleep;
+ /** Mapping Policy */
+ mlan_ds_misc_mapping_policy dmcs_policy;
+ mlan_ds_misc_dmcs_status dmcs_status;
+ mlan_ds_misc_rx_abort_cfg rx_abort_cfg;
+ mlan_ds_misc_rx_abort_cfg_ext rx_abort_cfg_ext;
+ mlan_ds_misc_tx_ampdu_prot_mode tx_ampdu_prot_mode;
+ mlan_ds_misc_rate_adapt_cfg rate_adapt_cfg;
+ mlan_ds_misc_cck_desense_cfg cck_desense_cfg;
+ mlan_ds_misc_chan_trpc_cfg trpc_cfg;
+ mlan_ds_misc_chnrgpwr_cfg rgchnpwr_cfg;
+
+ mlan_ds_band_steer_cfg band_steer_cfg;
+ mlan_ds_beacon_stuck_param_cfg beacon_stuck_cfg;
+ struct mfg_cmd_generic_cfg mfg_generic_cfg;
+ struct mfg_cmd_tx_cont mfg_tx_cont;
+ struct mfg_cmd_tx_frame2 mfg_tx_frame2;
+ mlan_ds_misc_arb_cfg arb_cfg;
+ mlan_ds_misc_cfp_tbl cfp;
+ t_u8 range_ext_mode;
+ mlan_ds_misc_dot11mc_unassoc_ftm_cfg dot11mc_unassoc_ftm_cfg;
+ mlan_ds_misc_tp_state tp_state;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+/** Hotspot status enable */
+#define HOTSPOT_ENABLED MBIT(0)
+/** Hotspot status disable */
+#define HOTSPOT_DISABLED MFALSE
+/** Keep Hotspot2.0 compatible in mwu and wpa_supplicant */
+#define HOTSPOT_BY_SUPPLICANT MBIT(1)
+
+/** Reason codes */
+#define MLAN_REASON_UNSPECIFIED 1
+#define MLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define MLAN_REASON_DEAUTH_LEAVING 3
+#define MLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define MLAN_REASON_DISASSOC_AP_BUSY 5
+#define MLAN_REASON_CLASS2_FRAME_FROM_NOAUTH_STA 6
+#define MLAN_REASON_CLASS3_FRAME_FROM_NOASSOC_STA 7
+#define MLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define MLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.c
new file mode 100644
index 000000000000..359e0319a6f8
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.c
@@ -0,0 +1,2621 @@
+/** @file mlan_join.c
+ *
+ * @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/30/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#ifdef DRV_EMBEDDED_SUPPLICANT
+#include "authenticator_api.h"
+#endif
+/********************************************************
+ Local Constants
+********************************************************/
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int wlan_cmd_append_generic_ie(mlan_private *priv, t_u8 **ppbuffer)
+{
+ int ret_len = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a generic ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->gen_ie_buf_len) {
+ PRINTM(MINFO, "append generic IE %d to %p\n",
+ priv->gen_ie_buf_len, *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(priv->gen_ie_buf_len);
+ memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
+ sizeof(ie_header), sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the generic IE buffer to the output buffer, advance
+ * pointer */
+ memcpy_ext(priv->adapter, *ppbuffer, priv->gen_ie_buf,
+ priv->gen_ie_buf_len, priv->gen_ie_buf_len);
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += priv->gen_ie_buf_len;
+ ret_len += priv->gen_ie_buf_len;
+
+ /* Reset the generic IE buffer */
+ priv->gen_ie_buf_len = 0;
+ }
+
+ /* return the length appended to the buffer */
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Append IE as a pass through TLV to a TLV buffer.
+ *
+ * This routine appends IE as a pass through TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie A pointer to IE buffer
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int wlan_cmd_append_pass_through_ie(mlan_private *priv,
+ IEEEtypes_Generic_t *ie,
+ t_u8 **ppbuffer)
+{
+ int ret_len = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (ie->ieee_hdr.len) {
+ PRINTM(MINFO, "append generic IE %d to %p\n", ie->ieee_hdr.len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = wlan_cpu_to_le16(ie->ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
+ sizeof(ie_header), sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the generic IE buffer to the output buffer, advance
+ * pointer */
+ memcpy_ext(priv->adapter, *ppbuffer, ie,
+ ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t),
+ ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t));
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
+ ret_len += ie->ieee_hdr.len + sizeof(IEEEtypes_Header_t);
+ }
+ /* return the length appended to the buffer */
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Append TSF tracking info from the scan table for the target AP
+ *
+ * This function is called from the network join command prep. routine.
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ * - the TSF of the target AP from its previous beacon/probe response
+ * - the TSF timestamp of our local MAC at the time we observed the
+ * beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ppbuffer A pointer to command buffer pointer
+ * @param pbss_desc A pointer to the BSS Descriptor from the scan table of
+ * the AP we are trying to join
+ *
+ * @return bytes added to the buffer
+ */
+static int wlan_cmd_append_tsf_tlv(mlan_private *pmriv, t_u8 **ppbuffer,
+ BSSDescriptor_t *pbss_desc)
+{
+ MrvlIEtypes_TsfTimestamp_t tsf_tlv;
+ t_u64 tsf_val;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(pmriv->adapter, &tsf_tlv, 0x00,
+ sizeof(MrvlIEtypes_TsfTimestamp_t));
+
+ tsf_tlv.header.type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+ tsf_tlv.header.len = wlan_cpu_to_le16(2 * sizeof(tsf_val));
+
+ memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_tlv, sizeof(tsf_tlv.header),
+ sizeof(tsf_tlv.header));
+ *ppbuffer += sizeof(tsf_tlv.header);
+
+ /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received
+ */
+ tsf_val = wlan_cpu_to_le64(pbss_desc->network_tsf);
+ memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val),
+ sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ memcpy_ext(pmriv->adapter, &tsf_val, pbss_desc->time_stamp,
+ sizeof(pbss_desc->time_stamp), sizeof(tsf_val));
+
+ PRINTM(MINFO, "ASSOC: TSF offset calc: %016llx - %016llx\n", tsf_val,
+ pbss_desc->network_tsf);
+
+ memcpy_ext(pmriv->adapter, *ppbuffer, &tsf_val, sizeof(tsf_val),
+ sizeof(tsf_val));
+ *ppbuffer += sizeof(tsf_val);
+
+ LEAVE();
+ return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
+}
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_get_common_rates(mlan_private *pmpriv, t_u8 *rate1,
+ t_u32 rate1_size, t_u8 *rate2,
+ t_u32 rate2_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ t_u8 *ptr = rate1;
+ t_u8 *tmp = MNULL;
+ t_u32 i, j;
+
+ ENTER();
+
+ ret = pcb->moal_malloc(pmpriv->adapter->pmoal_handle, rate1_size,
+ MLAN_MEM_DEF, &tmp);
+ if (ret != MLAN_STATUS_SUCCESS || !tmp) {
+ PRINTM(MERROR, "Failed to allocate buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memcpy_ext(pmpriv->adapter, tmp, rate1, rate1_size, rate1_size);
+ memset(pmpriv->adapter, rate1, 0, rate1_size);
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ for (j = 0; tmp[j] && j < rate1_size; j++) {
+ /* Check common rate, excluding the bit
+ * for basic rate */
+ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+ *rate1++ = tmp[j];
+ break;
+ }
+ }
+ }
+
+ HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+ HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+ HEXDUMP("Common Rates", ptr, rate1 - ptr);
+ PRINTM(MINFO, "Tx DataRate is set to 0x%X\n", pmpriv->data_rate);
+
+ if (!pmpriv->is_data_rate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == pmpriv->data_rate) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ ptr++;
+ }
+ PRINTM(MMSG,
+ "Previously set fixed data rate %#x is not "
+ "compatible with the network\n",
+ pmpriv->data_rate);
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ if (tmp)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle, tmp);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create the intersection of the rates supported by a target BSS and
+ * our pmadapter settings for use in an assoc/join command.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc BSS Descriptor whose rates are used in the setup
+ * @param pout_rates Output: Octet array of rates common between the BSS
+ * and the pmadapter supported rates settings
+ * @param pout_rates_size Output: Number of rates/octets set in pout_rates
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_setup_rates_from_bssdesc(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_desc,
+ t_u8 *pout_rates,
+ t_u32 *pout_rates_size)
+{
+ t_u8 card_rates[WLAN_SUPPORTED_RATES];
+ t_u32 card_rates_size = 0;
+ ENTER();
+ /* Copy AP supported rates */
+ memcpy_ext(pmpriv->adapter, pout_rates, pbss_desc->supported_rates,
+ WLAN_SUPPORTED_RATES, WLAN_SUPPORTED_RATES);
+
+ if ((pmpriv->adapter->region_code == COUNTRY_CODE_JP_40 ||
+ pmpriv->adapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (pbss_desc->phy_param_set.ds_param_set.current_chan == 14)) {
+ /* Special Case: For Japan, 11G rates on CH14 are not allowed*/
+ card_rates_size = wlan_get_supported_rates(
+ pmpriv, pmpriv->bss_mode, BAND_B, card_rates);
+ } else {
+ /* Get the STA supported rates */
+ card_rates_size =
+ wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
+ pmpriv->config_bands,
+ card_rates);
+ }
+ /* Get the common rates between AP and STA supported rates */
+ if (wlan_get_common_rates(pmpriv, pout_rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ *pout_rates_size = 0;
+ PRINTM(MERROR, "wlan_get_common_rates failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *pout_rates_size =
+ MIN(wlan_strlen((char *)pout_rates), WLAN_SUPPORTED_RATES);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pnew_bss_desc A pointer to the newly associated AP's scan table entry
+ *
+ * @return N/A
+ */
+static t_void wlan_update_tsf_timestamps(mlan_private *pmpriv,
+ BSSDescriptor_t *pnew_bss_desc)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 table_idx;
+ t_u64 new_tsf_base;
+ t_s64 tsf_delta;
+
+ ENTER();
+
+ memcpy_ext(pmpriv->adapter, &new_tsf_base, pnew_bss_desc->time_stamp,
+ sizeof(pnew_bss_desc->time_stamp), sizeof(new_tsf_base));
+
+ tsf_delta = new_tsf_base - pnew_bss_desc->network_tsf;
+
+ PRINTM(MINFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+ pnew_bss_desc->network_tsf, new_tsf_base);
+
+ for (table_idx = 0; table_idx < pmadapter->num_in_scan_table;
+ table_idx++) {
+ pmadapter->pscan_table[table_idx].network_tsf += tsf_delta;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Append a wapi IE
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a wapi TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int wlan_cmd_append_wapi_ie(mlan_private *priv, t_u8 **ppbuffer)
+{
+ int retlen = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a wapi ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wapi_ie_len) {
+ PRINTM(MCMND, "append wapi ie %d to %p\n", priv->wapi_ie_len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header.len = wlan_cpu_to_le16(priv->wapi_ie_len);
+ memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
+ sizeof(ie_header), sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += sizeof(ie_header);
+ retlen += sizeof(ie_header);
+
+ /* Copy the wapi IE buffer to the output buffer, advance pointer
+ */
+ memcpy_ext(priv->adapter, *ppbuffer, priv->wapi_ie,
+ priv->wapi_ie_len, priv->wapi_ie_len);
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += priv->wapi_ie_len;
+ retlen += priv->wapi_ie_len;
+ }
+ /* return the length appended to the buffer */
+ LEAVE();
+ return retlen;
+}
+
+/**
+ * @brief Append a osen IE
+ *
+ * This function is called from the network join command prep. routine.
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a osen TLV type to the request.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ppbuffer pointer to command buffer pointer
+ *
+ * @return bytes added to the buffer
+ */
+static int wlan_cmd_append_osen_ie(mlan_private *priv, t_u8 **ppbuffer)
+{
+ int retlen = 0;
+ MrvlIEtypesHeader_t ie_header;
+
+ ENTER();
+
+ /* Null Checks */
+ if (ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+ if (*ppbuffer == MNULL) {
+ LEAVE();
+ return 0;
+ }
+
+ /*
+ * If there is a osen ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->osen_ie_len) {
+ PRINTM(MCMND, "append osen ie %d to %p\n", priv->osen_ie_len,
+ *ppbuffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = wlan_cpu_to_le16(TLV_TYPE_VENDOR_SPECIFIC_IE);
+ ie_header.len = wlan_cpu_to_le16(priv->osen_ie[1]);
+ memcpy_ext(priv->adapter, *ppbuffer, &ie_header,
+ sizeof(ie_header), sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += sizeof(ie_header);
+ retlen += sizeof(ie_header);
+
+ /* Copy the osen IE buffer to the output buffer, advance pointer
+ */
+ memcpy_ext(priv->adapter, *ppbuffer, &priv->osen_ie[2],
+ priv->osen_ie[1], priv->osen_ie[1]);
+
+ /* Increment the return size and the return buffer pointer param
+ */
+ *ppbuffer += priv->osen_ie[1];
+ retlen += priv->osen_ie[1];
+ }
+ /* return the length appended to the buffer */
+ LEAVE();
+ return retlen;
+}
+
+/**
+ * @brief This function get the rsn_cap from RSN ie buffer.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @param data A pointer to rsn_ie data after IE header
+ * @param return rsn_cap
+ */
+t_u16 wlan_get_rsn_cap(t_u8 *data)
+{
+ t_u16 rsn_cap = 0;
+ t_u16 *ptr;
+ t_u16 pairwise_cipher_count = 0;
+ t_u16 akm_suite_count = 0;
+ /* rsn_cap = data + 2 bytes version + 4 bytes
+ * group_cipher_suite + 2 bytes pairwise_cipher_count +
+ * pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN + 2 bytes
+ * akm_suite_count + akm_suite_count * AKM_SUITE_LEN
+ */
+ ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8));
+ pairwise_cipher_count = wlan_le16_to_cpu(*ptr);
+ ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN);
+ akm_suite_count = wlan_le16_to_cpu(*ptr);
+ ptr = (t_u16 *)(data + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16) + akm_suite_count * AKM_SUITE_LEN);
+ rsn_cap = wlan_le16_to_cpu(*ptr);
+ PRINTM(MCMND, "rsn_cap=0x%x\n", rsn_cap);
+ return rsn_cap;
+}
+
+/**
+ * @brief This function check if we should enable 11w
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @param BSSDescriptor_t A pointer to BSSDescriptor_t data structure
+ * @param return MTRUE/MFALSE
+ */
+t_u8 wlan_use_mfp(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
+{
+ t_u16 ap_rsn_cap = 0;
+ t_u16 sta_rsn_cap = 0;
+ t_u8 ap_mfpc, ap_mfpr;
+ t_u8 sta_mfpc, sta_mfpr;
+
+ if (pmpriv->wpa_ie[0] != RSN_IE)
+ return 0;
+ sta_rsn_cap = wlan_get_rsn_cap(pmpriv->wpa_ie + 2);
+ if (!pbss_desc->prsn_ie)
+ return 0;
+ ap_rsn_cap = wlan_get_rsn_cap(pbss_desc->prsn_ie->data);
+ ap_mfpc = ((ap_rsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
+ ap_mfpr = ((ap_rsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
+ sta_mfpc = ((sta_rsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
+ sta_mfpr = ((sta_rsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
+ if (!ap_mfpc && !ap_mfpr)
+ return MFALSE;
+ if (!sta_mfpc && !sta_mfpr)
+ return MFALSE;
+ return MTRUE;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function updates RSN IE in the association request.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @param ptlv_rsn_ie A pointer to rsn_ie TLV
+ */
+int wlan_update_rsn_ie(mlan_private *pmpriv,
+ MrvlIEtypes_RsnParamSet_t *ptlv_rsn_ie)
+{
+ t_u16 *prsn_cap;
+ t_u16 *ptr;
+ t_u16 *akm_suite_count_ptr;
+ t_u16 pmf_mask = 0x00;
+ t_u8 *temp;
+ t_u16 pairwise_cipher_count = 0;
+ t_u16 akm_suite_count = 0;
+ t_u16 temp_akm_suite_count = 0;
+ int found = 0;
+ t_u8 sha_256_oui[4] = {0x00, 0x0f, 0xac, 0x06};
+ t_u8 sae_oui[4] = {0x00, 0x0f, 0xac, 0x08};
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ int ap_mfpc = 0, ap_mfpr = 0, ret = MLAN_STATUS_SUCCESS;
+
+ pmf_mask = (((pmpriv->pmfcfg.mfpc << MFPC_BIT) |
+ (pmpriv->pmfcfg.mfpr << MFPR_BIT)) |
+ (~PMF_MASK));
+ /* prsn_cap = prsn_ie->rsn_ie + 2 bytes version + 4 bytes
+ * group_cipher_suite + 2 bytes pairwise_cipher_count +
+ * pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN + 2 bytes
+ * akm_suite_count + akm_suite_count * AKM_SUITE_LEN
+ */
+ ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8));
+ pairwise_cipher_count = wlan_le16_to_cpu(*ptr);
+ ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN);
+ temp_akm_suite_count = wlan_le16_to_cpu(*ptr);
+ akm_suite_count = wlan_le16_to_cpu(*ptr);
+ /* Save pointer to akm_suite_count in RSN IE to update it later */
+ akm_suite_count_ptr = ptr;
+ temp = ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16);
+ /* ptr now points to the 1st AKM suite */
+ if (temp_akm_suite_count > 1) {
+ while (temp_akm_suite_count) {
+ if (pmpriv->sec_info.authentication_mode ==
+ MLAN_AUTH_MODE_SAE) {
+ if (!memcmp(pmadapter, temp, sae_oui,
+ AKM_SUITE_LEN)) {
+ found = 1;
+ break;
+ }
+ } else if (!memcmp(pmadapter, temp, sha_256_oui,
+ AKM_SUITE_LEN)) {
+ found = 1;
+ break;
+ }
+ temp += AKM_SUITE_LEN;
+ temp_akm_suite_count--;
+ }
+ if (found) {
+ /* Copy SHA256 as AKM suite */
+ memcpy_ext(pmadapter,
+ ptlv_rsn_ie->rsn_ie +
+ (sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count *
+ PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16)),
+ temp, AKM_SUITE_LEN, AKM_SUITE_LEN);
+ /* Shift remaining bytes of RSN IE after this */
+ memmove(pmadapter,
+ ptlv_rsn_ie->rsn_ie +
+ (sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count *
+ PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16) + AKM_SUITE_LEN),
+ ptlv_rsn_ie->rsn_ie +
+ (sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count *
+ PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16) +
+ akm_suite_count * AKM_SUITE_LEN),
+ ptlv_rsn_ie->header.len -
+ (sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count *
+ PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16) +
+ akm_suite_count * AKM_SUITE_LEN));
+ ptlv_rsn_ie->header.len =
+ ptlv_rsn_ie->header.len -
+ (akm_suite_count - 1) * AKM_SUITE_LEN;
+ /* Update akm suite count */
+ akm_suite_count = 1;
+ *akm_suite_count_ptr = akm_suite_count;
+ }
+ }
+ ptr = (t_u16 *)(ptlv_rsn_ie->rsn_ie + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) +
+ pairwise_cipher_count * PAIRWISE_CIPHER_SUITE_LEN +
+ sizeof(t_u16) + akm_suite_count * AKM_SUITE_LEN);
+ prsn_cap = ptr;
+
+ ap_mfpc = ((*prsn_cap & (0x1 << MFPC_BIT)) == (0x1 << MFPC_BIT));
+ ap_mfpr = ((*prsn_cap & (0x1 << MFPR_BIT)) == (0x1 << MFPR_BIT));
+
+ if ((!ap_mfpc && !ap_mfpr && pmpriv->pmfcfg.mfpr) ||
+ ((!ap_mfpc) && ap_mfpr) ||
+ (ap_mfpc && ap_mfpr && (!pmpriv->pmfcfg.mfpc))) {
+ PRINTM(MERROR,
+ "Mismatch in PMF config of STA and AP, can't associate to AP\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((pmpriv->pmfcfg.mfpr && pmpriv->pmfcfg.mfpc) ||
+ pmpriv->pmfcfg.mfpc) {
+ *prsn_cap |= PMF_MASK;
+ *prsn_cap &= pmf_mask;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief This function is to find FT AKM in RSN.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @param rsn_ie A pointer to rsn_ie
+ *
+ */
+t_u8 wlan_ft_akm_is_used(mlan_private *pmpriv, t_u8 *rsn_ie)
+{
+ t_u8 *temp;
+ t_u16 count;
+ t_u16 pairwise_cipher_count = 0;
+ t_u16 akm_suite_count = 0;
+ t_u8 found = 0;
+ t_u8 rsn_ft_1x_oui[4] = {0x00, 0x0f, 0xac, 0x03};
+ t_u8 rsn_ft_psk_oui[4] = {0x00, 0x0f, 0xac, 0x04};
+ t_u8 rsn_ft_sae_oui[4] = {0x00, 0x0f, 0xac, 0x09};
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (!rsn_ie)
+ goto done;
+
+ if (rsn_ie[0] != RSN_IE)
+ goto done;
+
+ /* 2 bytes header + 2 bytes version + 4 bytes group_cipher_suite +
+ * 2 bytes pairwise_cipher_count + pairwise_cipher_count *
+ * PAIRWISE_CIPHER_SUITE_LEN (4) + 2 bytes akm_suite_count +
+ * akm_suite_count * AKM_SUITE_LEN (4)
+ */
+ count = *(t_u16 *)(rsn_ie + 2 + 2 + 4 * sizeof(t_u8));
+ pairwise_cipher_count = wlan_le16_to_cpu(count);
+ count = *(t_u16 *)(rsn_ie + 2 + 2 + 4 * sizeof(t_u8) + sizeof(t_u16) +
+ pairwise_cipher_count * 4);
+ akm_suite_count = wlan_le16_to_cpu(count);
+ temp = (t_u8 *)(rsn_ie + 2 + sizeof(t_u16) + 4 * sizeof(t_u8) +
+ sizeof(t_u16) + pairwise_cipher_count * 4 +
+ sizeof(t_u16));
+
+ while (akm_suite_count) {
+ if (!memcmp(pmadapter, temp, rsn_ft_1x_oui,
+ sizeof(rsn_ft_1x_oui)) ||
+ !memcmp(pmadapter, temp, rsn_ft_psk_oui,
+ sizeof(rsn_ft_psk_oui)) ||
+ !memcmp(pmadapter, temp, rsn_ft_sae_oui,
+ sizeof(rsn_ft_sae_oui))) {
+ found = 1;
+ break;
+ }
+ temp += 4;
+ akm_suite_count--;
+ }
+
+done:
+ LEAVE();
+ return found;
+}
+
+/**
+ * @brief This function is to find specific IE.
+ *
+ * @param ie A pointer to ie buffer
+ * @param ie_len Length of ie buffer
+ * @param ie_type Type of ie that wants to be found in ie buffer
+ *
+ * @return MFALSE if not found; MTURE if found
+ */
+t_u8 wlan_find_ie(t_u8 *ie, t_u8 ie_len, t_u8 ie_type)
+{
+ IEEEtypes_Header_t *pheader = MNULL;
+ t_u8 *pos = MNULL;
+ t_s8 ret_len;
+ t_u8 ret = MFALSE;
+
+ ENTER();
+
+ pos = (t_u8 *)ie;
+ ret_len = ie_len;
+ while (ret_len >= 2) {
+ pheader = (IEEEtypes_Header_t *)pos;
+ if (pheader->len + sizeof(IEEEtypes_Header_t) > ret_len) {
+ PRINTM(MMSG, "invalid IE length = %d left len %d\n",
+ pheader->len, ret_len);
+ break;
+ }
+ if (pheader->element_id == ie_type) {
+ ret = MTRUE;
+ break;
+ }
+ ret_len -= pheader->len + sizeof(IEEEtypes_Header_t);
+ pos += pheader->len + sizeof(IEEEtypes_Header_t);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of association.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of BSSDescriptor_t from the
+ * scan table to assoc
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_802_11_associate(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_ASSOCIATE *passo = &cmd->params.associate;
+ BSSDescriptor_t *pbss_desc;
+ MrvlIEtypes_SsIdParamSet_t *pssid_tlv;
+ MrvlIEtypes_PhyParamSet_t *pphy_tlv;
+ MrvlIEtypes_SsParamSet_t *pss_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ MrvlIEtypes_AuthType_t *pauth_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv = MNULL;
+ MrvlIEtypes_SecurityCfg_t *psecurity_cfg_ie = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ t_u16 tmp_cap;
+ t_u8 *pos;
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ void *rsn_wpa_ie_tmp = MNULL;
+#endif
+ t_u8 ft_akm = 0;
+ t_u8 oper_class;
+ t_u8 oper_class_flag = MFALSE;
+ MrvlIEtypes_HostMlme_t *host_mlme_tlv = MNULL;
+
+ ENTER();
+
+ pbss_desc = (BSSDescriptor_t *)pdata_buf;
+ pos = (t_u8 *)passo;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ pmpriv->pattempted_bss_desc = pbss_desc;
+ /* clear assoc_rsp_size */
+ pmpriv->assoc_rsp_size = 0;
+
+ memcpy_ext(pmadapter, passo->peer_sta_addr, pbss_desc->mac_address,
+ sizeof(pbss_desc->mac_address),
+ sizeof(passo->peer_sta_addr));
+ pos += sizeof(passo->peer_sta_addr);
+
+ /* Set the listen interval */
+ passo->listen_interval = wlan_cpu_to_le16(pmpriv->listen_interval);
+ /* Set the beacon period */
+ passo->beacon_period = wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ pos += sizeof(passo->cap_info);
+ pos += sizeof(passo->listen_interval);
+ pos += sizeof(passo->beacon_period);
+ pos += sizeof(passo->dtim_period);
+
+ pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *)pos;
+ pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ pssid_tlv->header.len = (t_u16)pbss_desc->ssid.ssid_len;
+ memcpy_ext(pmadapter, pssid_tlv->ssid, pbss_desc->ssid.ssid,
+ pssid_tlv->header.len, pssid_tlv->header.len);
+ pos += sizeof(pssid_tlv->header) + pssid_tlv->header.len;
+ pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len);
+
+ pphy_tlv = (MrvlIEtypes_PhyParamSet_t *)pos;
+ pphy_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+ pphy_tlv->header.len = sizeof(pphy_tlv->fh_ds.ds_param_set);
+ memcpy_ext(pmadapter, &pphy_tlv->fh_ds.ds_param_set,
+ &pbss_desc->phy_param_set.ds_param_set.current_chan,
+ sizeof(pphy_tlv->fh_ds.ds_param_set),
+ sizeof(pphy_tlv->fh_ds.ds_param_set));
+ pos += sizeof(pphy_tlv->header) + pphy_tlv->header.len;
+ pphy_tlv->header.len = wlan_cpu_to_le16(pphy_tlv->header.len);
+
+ pss_tlv = (MrvlIEtypes_SsParamSet_t *)pos;
+ pss_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CF);
+ pss_tlv->header.len = sizeof(pss_tlv->cf_ibss.cf_param_set);
+ pos += sizeof(pss_tlv->header) + pss_tlv->header.len;
+ pss_tlv->header.len = wlan_cpu_to_le16(pss_tlv->header.len);
+
+ /* Get the common rates supported between the driver and the BSS Desc */
+ if (wlan_setup_rates_from_bssdesc(pmpriv, pbss_desc, rates,
+ &rates_size)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the data rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates, rates,
+ rates_size, WLAN_SUPPORTED_RATES);
+
+ /* Setup the Rates TLV in the association command */
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *)pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16)rates_size);
+ memcpy_ext(pmadapter, prates_tlv->rates, rates, rates_size, rates_size);
+ pos += sizeof(prates_tlv->header) + rates_size;
+ PRINTM(MINFO, "ASSOC_CMD: Rates size = %d\n", rates_size);
+
+ /* Add the Authentication type to be used for Auth frames if needed */
+ if ((pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)) {
+ pauth_tlv = (MrvlIEtypes_AuthType_t *)pos;
+ pauth_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ pauth_tlv->header.len = sizeof(pauth_tlv->auth_type);
+ if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled) ||
+ (pmpriv->sec_info.authentication_mode ==
+ MLAN_AUTH_MODE_NETWORKEAP))
+ pauth_tlv->auth_type = wlan_cpu_to_le16(
+ (t_u16)pmpriv->sec_info.authentication_mode);
+ else if (pmpriv->sec_info.authentication_mode ==
+ MLAN_AUTH_MODE_FT)
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16(AssocAgentAuth_FastBss_Skip);
+ else if (pmpriv->sec_info.authentication_mode ==
+ MLAN_AUTH_MODE_SAE)
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16(AssocAgentAuth_Wpa3Sae);
+ else
+ pauth_tlv->auth_type =
+ wlan_cpu_to_le16(MLAN_AUTH_MODE_OPEN);
+ pos += sizeof(pauth_tlv->header) + pauth_tlv->header.len;
+ pauth_tlv->header.len = wlan_cpu_to_le16(pauth_tlv->header.len);
+ }
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter) &&
+ (pbss_desc->bss_band & pmpriv->config_bands) &&
+ !(ISSUPP_11NENABLED(pmadapter->fw_cap_info) &&
+ (!pbss_desc->disable_11n) &&
+ (pmpriv->config_bands & BAND_GN ||
+ pmpriv->config_bands & BAND_AN) &&
+ (pbss_desc->pht_cap))) {
+ /* Append a channel TLV for the channel the attempted AP was
+ * found on */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "Assoc: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
+ wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
+
+ PRINTM(MINFO, "Assoc: TLV Bandcfg = %x\n",
+ pchan_tlv->chan_scan_param[0].bandcfg);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+ if (!pmpriv->wps.session_enable) {
+ if ((pmpriv->sec_info.wpa_enabled ||
+ pmpriv->sec_info.wpa2_enabled)) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ /* WPA_IE or RSN_IE */
+ prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
+ prsn_ie_tlv->header.type =
+ prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len =
+ prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <=
+ (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
+ &pmpriv->wpa_ie[2],
+ prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ HEXDUMP("ASSOC_CMD: RSN IE", (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ /** parse rsn ie to find whether ft akm is used*/
+ ft_akm = wlan_ft_akm_is_used(pmpriv, pmpriv->wpa_ie);
+ /* Append PMF Configuration coming from cfg80211 layer
+ */
+ psecurity_cfg_ie = (MrvlIEtypes_SecurityCfg_t *)pos;
+ psecurity_cfg_ie->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SECURITY_CFG);
+
+ pmpriv->curr_bss_params.use_mfp =
+ wlan_use_mfp(pmpriv, pbss_desc);
+ PRINTM(MCMND, "use_mfp=%d\n",
+ pmpriv->curr_bss_params.use_mfp);
+
+ if (!pmpriv->curr_bss_params.use_mfp)
+ psecurity_cfg_ie->use_mfp = MFALSE;
+ else
+ psecurity_cfg_ie->use_mfp = MTRUE;
+ psecurity_cfg_ie->header.len = sizeof(t_u8);
+ pos += sizeof(psecurity_cfg_ie->header) +
+ psecurity_cfg_ie->header.len;
+ }
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ else if (supplicantIsEnabled(pmpriv->psapriv)) {
+ supplicantClrEncryptKey(pmpriv->psapriv);
+
+ if (pbss_desc->prsn_ie)
+ rsn_wpa_ie_tmp = pbss_desc->prsn_ie;
+ else if (pbss_desc->pwpa_ie)
+ rsn_wpa_ie_tmp = pbss_desc->pwpa_ie;
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ pos += supplicantFormatRsnWpaTlv(
+ pmpriv->psapriv, rsn_wpa_ie_tmp, prsn_ie_tlv);
+ }
+#endif
+ else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16)(*(pbss_desc->pwpa_ie))
+ .vend_hdr.element_id;
+ prsn_ie_tlv->header.type =
+ prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(
+ prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16)(*(pbss_desc->pwpa_ie))
+ .vend_hdr.len;
+ prsn_ie_tlv->header.len =
+ prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <=
+ (sizeof(pmpriv->wpa_ie))) {
+ memcpy_ext(pmadapter,
+ prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie))
+ .vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE",
+ (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(
+ prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ prsn_ie_tlv->header.type =
+ (t_u16)(*(pbss_desc->prsn_ie))
+ .ieee_hdr.element_id;
+ prsn_ie_tlv->header.type =
+ prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type = wlan_cpu_to_le16(
+ prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16)(*(pbss_desc->prsn_ie))
+ .ieee_hdr.len;
+ prsn_ie_tlv->header.len =
+ prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <=
+ (sizeof(pmpriv->wpa_ie))) {
+ memcpy_ext(pmadapter,
+ prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie))
+ .data[0]),
+ prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ ret = wlan_update_rsn_ie(pmpriv,
+ prsn_ie_tlv);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ goto done;
+ }
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ASSOC_CMD: RSN IE",
+ (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len = wlan_cpu_to_le16(
+ prsn_ie_tlv->header.len);
+ }
+ }
+ }
+
+ if (ISSUPP_11NENABLED(pmadapter->fw_cap_info) &&
+ (!pbss_desc->disable_11n) &&
+ wlan_11n_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
+ wlan_cmd_append_11n_tlv(pmpriv, pbss_desc, &pos);
+ else if ((pmpriv->hotspot_cfg & HOTSPOT_ENABLED) &&
+ !(pmpriv->hotspot_cfg & HOTSPOT_BY_SUPPLICANT))
+ wlan_add_ext_capa_info_ie(pmpriv, pbss_desc, &pos);
+ if (pmpriv->adapter->ecsa_enable) {
+ oper_class_flag =
+ wlan_find_ie(pmpriv->gen_ie_buf, pmpriv->gen_ie_buf_len,
+ REGULATORY_CLASS);
+ if (!oper_class_flag) {
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_get_curr_oper_class(
+ pmpriv,
+ pbss_desc->phy_param_set.ds_param_set
+ .current_chan,
+ pbss_desc->curr_bandwidth, &oper_class))
+ wlan_add_supported_oper_class_ie(pmpriv, &pos,
+ oper_class);
+ }
+ }
+ if (ISSUPP_11ACENABLED(pmadapter->fw_cap_info) &&
+ (!pbss_desc->disable_11n) &&
+ wlan_11ac_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
+ wlan_cmd_append_11ac_tlv(pmpriv, pbss_desc, &pos);
+
+ if ((IS_FW_SUPPORT_11AX(pmadapter)) && (!pbss_desc->disable_11n) &&
+ wlan_11ax_bandconfig_allowed(pmpriv, pbss_desc->bss_band))
+ wlan_cmd_append_11ax_tlv(pmpriv, pbss_desc, &pos);
+
+ wlan_wmm_process_association_req(pmpriv, &pos, &pbss_desc->wmm_ie,
+ pbss_desc->pht_cap);
+ if (pmpriv->sec_info.wapi_enabled && pmpriv->wapi_ie_len)
+ wlan_cmd_append_wapi_ie(pmpriv, &pos);
+
+ if (pmpriv->sec_info.osen_enabled && pmpriv->osen_ie_len)
+ wlan_cmd_append_osen_ie(pmpriv, &pos);
+
+ wlan_cmd_append_generic_ie(pmpriv, &pos);
+
+ if (pbss_desc->pmd_ie)
+ wlan_cmd_append_pass_through_ie(
+ pmpriv, (IEEEtypes_Generic_t *)pbss_desc->pmd_ie, &pos);
+ wlan_cmd_append_tsf_tlv(pmpriv, &pos, pbss_desc);
+
+ if (pmpriv->curr_bss_params.host_mlme) {
+ host_mlme_tlv = (MrvlIEtypes_HostMlme_t *)pos;
+ host_mlme_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_HOST_MLME);
+ host_mlme_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(host_mlme_tlv->host_mlme));
+ host_mlme_tlv->host_mlme = MTRUE;
+ pos += sizeof(host_mlme_tlv->header) +
+ host_mlme_tlv->header.len;
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv,
+ (t_u8)pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv,
+ pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so adhoc/infra 11h
+ * behavior can be properly triggered. pos modified if data is appended
+ */
+ wlan_11h_process_join(
+ pmpriv, &pos, &passo->cap_info, (t_u8)pbss_desc->bss_band,
+ pbss_desc->phy_param_set.ds_param_set.current_chan,
+ &pbss_desc->wlan_11h_bss_info);
+
+ cmd->size = wlan_cpu_to_le16((t_u16)(pos - (t_u8 *)passo) + S_DS_GEN);
+
+ /* Set the Capability info at last */
+ memcpy_ext(pmadapter, &tmp_cap, &pbss_desc->cap_info,
+ sizeof(passo->cap_info), sizeof(tmp_cap));
+
+ if (pmpriv->config_bands == BAND_B)
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+
+ tmp_cap &= CAPINFO_MASK;
+ PRINTM(MINFO, "ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap,
+ CAPINFO_MASK);
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy_ext(pmadapter, &passo->cap_info, &tmp_cap, sizeof(tmp_cap),
+ sizeof(passo->cap_info));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info/Error Return(t_u16): |
+ * | 0xFFFF(-1): Internal error for association |
+ * | 0xFFFE(-2): Authentication unhandled message |
+ * | 0xFFFD(-3): Authentication refused |
+ * | 0xFFFC(-4): Timeout waiting for AP response |
+ * | 0xFFFB(-5): Internal error for authentication |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): |
+ * | If cap_info is -1: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if associate response parameter invlaid, |
+ * | 1 otherwise. |
+ * | |
+ * | If cap_info is -2: |
+ * | An authentication frame was received but was |
+ * | not handled by the firmware. IEEE Status code |
+ * | for the failure is returned. |
+ * | |
+ * | If cap_info is -3: |
+ * | An authentication frame was received and the |
+ * | status_code is the IEEE Status reported in the |
+ * | response. |
+ * | |
+ * | If cap_info is -4: |
+ * | (1) Association response timeout |
+ * | (2) Authentication response timeout |
+ * | |
+ * | If cap_info is -5: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status code |
+ * | is 6 if authentication parameter invlaid, |
+ * | 1 otherwise. |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): 0xFFFF |
+ * .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info(t_u16): IEEE Capability |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): IEEE Status Code |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): IEEE Association ID |
+ * .------------------------------------------------------------.
+ * | IEEE IEs(variable): Any received IEs comprising the |
+ * | remaining portion of a received |
+ * | association response frame. |
+ * .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_associate(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+ IEEEtypes_AssocRsp_t *passoc_rsp;
+ BSSDescriptor_t *pbss_desc;
+ t_u8 enable_data = MTRUE;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *)event_buf;
+ t_u8 cur_mac[MLAN_MAC_ADDR_LENGTH];
+ t_u8 media_connected = pmpriv->media_connected;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ assoc_logger_data *assoc_succ;
+ mlan_ds_bss *bss;
+
+ ENTER();
+
+ if (pmpriv->curr_bss_params.host_mlme)
+ passoc_rsp =
+ (IEEEtypes_AssocRsp_t *)((t_u8 *)(&resp->params) +
+ sizeof(IEEEtypes_MgmtHdr_t));
+ else
+
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)&resp->params;
+ passoc_rsp->status_code = wlan_le16_to_cpu(passoc_rsp->status_code);
+ if (pmpriv->media_connected == MTRUE)
+ memcpy_ext(pmpriv->adapter, cur_mac,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+
+ HEXDUMP("ASSOC_RESP:", (t_u8 *)&resp->params, (resp->size - S_DS_GEN));
+
+ pmpriv->assoc_rsp_size =
+ MIN(resp->size - S_DS_GEN, sizeof(pmpriv->assoc_rsp_buf));
+
+ memcpy_ext(pmpriv->adapter, pmpriv->assoc_rsp_buf, &resp->params,
+ pmpriv->assoc_rsp_size, pmpriv->assoc_rsp_size);
+
+ if (pioctl_req != MNULL) {
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ bss->param.ssid_bssid.assoc_rsp.assoc_resp_len =
+ pmpriv->assoc_rsp_size;
+ memcpy_ext(pmpriv->adapter,
+ bss->param.ssid_bssid.assoc_rsp.assoc_resp_buf,
+ pmpriv->assoc_rsp_buf, pmpriv->assoc_rsp_size,
+ ASSOC_RSP_BUF_SIZE);
+ }
+ if (passoc_rsp->status_code) {
+ if (pmpriv->media_connected == MTRUE) {
+ if (pmpriv->port_ctrl_mode == MTRUE)
+ pmpriv->port_open = pmpriv->prior_port_status;
+ if (!memcmp(pmpriv->adapter, cur_mac,
+ pmpriv->pattempted_bss_desc->mac_address,
+ MLAN_MAC_ADDR_LENGTH))
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ else
+ wlan_recv_event(
+ pmpriv,
+ MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT,
+ MNULL);
+ } else
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ pmpriv->adapter->dbg.num_cmd_assoc_failure++;
+ pmpriv->adapter->dbg.num_cons_assoc_failure++;
+ PRINTM(MERROR,
+ "ASSOC_RESP: Association Failed, "
+ "status code = %d, error = 0x%x, a_id = 0x%x\n",
+ passoc_rsp->status_code,
+ wlan_le16_to_cpu(*(t_u16 *)&passoc_rsp->capability),
+ wlan_le16_to_cpu(passoc_rsp->a_id));
+ memset(pmadapter, event_buf, 0, sizeof(event_buf));
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER;
+ pevent->event_len = sizeof(passoc_rsp->status_code);
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
+ &passoc_rsp->status_code, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER,
+ pevent);
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ pmpriv->adapter->tx_lock_flag = MFALSE;
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+
+ /* Set the attempted BSSID Index to current */
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ PRINTM(MCMND, "ASSOC_RESP: %-32s (a_id = 0x%x)\n", pbss_desc->ssid.ssid,
+ wlan_le16_to_cpu(passoc_rsp->a_id));
+ /* Restore default extended capabilities */
+ memcpy_ext(pmpriv->adapter, &pmpriv->ext_cap, &pmpriv->def_ext_cap,
+ sizeof(pmpriv->ext_cap), sizeof(pmpriv->ext_cap));
+ /* Make a copy of current BSSID descriptor */
+ memcpy_ext(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ pbss_desc, sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
+
+ /* Update curr_bss_params */
+ pmpriv->curr_bss_params.bss_descriptor.channel =
+ pbss_desc->phy_param_set.ds_param_set.current_chan;
+
+ pmpriv->curr_bss_params.band = (t_u8)pbss_desc->bss_band;
+
+ /* Store current channel for further reference.
+ * This would save one extra call to get current
+ * channel when disconnect/bw_ch event is raised.
+ */
+ pmpriv->adapter->dfsr_channel =
+ pmpriv->curr_bss_params.bss_descriptor.channel;
+
+ /*
+ * Adjust the timestamps in the scan table to be relative to the newly
+ * associated AP's TSF
+ */
+ wlan_update_tsf_timestamps(pmpriv, pbss_desc);
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE)
+ pmpriv->curr_bss_params.wmm_enabled = MTRUE;
+ else
+ pmpriv->curr_bss_params.wmm_enabled = MFALSE;
+
+ if ((pmpriv->wmm_required ||
+ (pbss_desc->pht_cap &&
+ (pbss_desc->pht_cap->ieee_hdr.element_id == HT_CAPABILITY))) &&
+ pmpriv->curr_bss_params.wmm_enabled)
+ pmpriv->wmm_enabled = MTRUE;
+ else
+ pmpriv->wmm_enabled = MFALSE;
+
+ pmpriv->curr_bss_params.wmm_uapsd_enabled = MFALSE;
+
+ if (pmpriv->wmm_enabled == MTRUE)
+ pmpriv->curr_bss_params.wmm_uapsd_enabled =
+ pbss_desc->wmm_ie.qos_info.qos_uapsd;
+
+ PRINTM(MINFO, "ASSOC_RESP: curr_pkt_filter is 0x%x\n",
+ pmpriv->curr_pkt_filter);
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled)
+ pmpriv->wpa_is_gtk_set = MFALSE;
+ if (pmpriv->wmm_enabled)
+ /* Don't re-enable carrier until we get the WMM_GET_STATUS event
+ */
+ enable_data = MFALSE;
+ else
+ /* Since WMM is not enabled, setup the queues with the defaults
+ */
+ wlan_wmm_setup_queues(pmpriv);
+
+ if (enable_data)
+ PRINTM(MINFO, "Post association, re-enabling data flow\n");
+
+ /* Reset SNR/NF/RSSI values */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+ pmpriv->rxpd_rate = 0;
+ pmpriv->rxpd_rate_info = 0;
+ /* Reset mib statistics*/
+ pmpriv->amsdu_rx_cnt = 0;
+ pmpriv->amsdu_tx_cnt = 0;
+ pmpriv->msdu_in_rx_amsdu_cnt = 0;
+ pmpriv->msdu_in_tx_amsdu_cnt = 0;
+ if (pbss_desc->pvht_cap && pbss_desc->pht_cap) {
+ if (GET_VHTCAP_MAXMPDULEN(
+ pbss_desc->pvht_cap->vht_cap.vht_cap_info) == 2)
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_12K;
+ else if (GET_VHTCAP_MAXMPDULEN(
+ pbss_desc->pvht_cap->vht_cap.vht_cap_info) ==
+ 1)
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ } else if (pbss_desc->pht_cap) {
+ if (GETHT_MAXAMSDU(pbss_desc->pht_cap->ht_cap.ht_cap_info))
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ pmpriv->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ }
+
+ wlan_save_curr_bcn(pmpriv);
+
+ pmpriv->adapter->dbg.num_cmd_assoc_success++;
+ pmpriv->adapter->dbg.num_cons_assoc_failure = 0;
+ PRINTM(MINFO, "ASSOC_RESP: Associated\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, pevent->event_len);
+
+ /* Add the ra_list here for infra mode as there will be only 1 ra always
+ */
+ if (media_connected) {
+ /** replace ralist's mac address with new mac address */
+ if (0 ==
+ wlan_ralist_update(
+ pmpriv, cur_mac,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address))
+ wlan_ralist_add(pmpriv,
+ pmpriv->curr_bss_params.bss_descriptor
+ .mac_address);
+ wlan_11n_cleanup_reorder_tbl(pmpriv);
+ wlan_11n_deleteall_txbastream_tbl(pmpriv);
+
+ } else
+ wlan_ralist_add(
+ pmpriv,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address);
+
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+
+ /* Send OBSS scan param to the application if available */
+ wlan_2040_coex_event(pmpriv);
+ wlan_coex_ampdu_rxwinsize(pmpriv->adapter);
+
+ if (!pmpriv->sec_info.wpa_enabled && !pmpriv->sec_info.wpa2_enabled &&
+ !pmpriv->sec_info.ewpa_enabled && !pmpriv->sec_info.wapi_enabled &&
+ !pmpriv->wps.session_enable && !pmpriv->sec_info.osen_enabled
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ && !supplicantIsEnabled(pmpriv->psapriv)
+#endif
+ ) {
+ /* We are in Open/WEP mode, open port immediately */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_open = MTRUE;
+ PRINTM(MINFO, "ASSOC_RESP: port_status = OPEN\n");
+ }
+ }
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled ||
+ pmpriv->sec_info.ewpa_enabled || pmpriv->sec_info.wapi_enabled ||
+ pmpriv->wps.session_enable || pmpriv->sec_info.osen_enabled
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ || (supplicantIsEnabled(pmpriv->psapriv))
+#endif
+ )
+ pmpriv->adapter->scan_block = MTRUE;
+
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ supplicantInitSession(
+ pmpriv->psapriv,
+ (t_u8 *)&pmpriv->curr_bss_params.bss_descriptor.ssid.ssid,
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len,
+ (t_u8 *)&pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ (t_u8 *)&pmpriv->curr_addr);
+#endif
+
+ pevent = (mlan_event *)event_buf;
+ memset(pmadapter, event_buf, 0, sizeof(event_buf));
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER;
+ pevent->event_len = sizeof(assoc_logger_data);
+ assoc_succ = (assoc_logger_data *)pevent->event_buf;
+ memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->bssid,
+ pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->oui,
+ pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH / 2,
+ MLAN_MAC_ADDR_LENGTH / 2);
+ memcpy_ext(pmpriv->adapter, (t_u8 *)assoc_succ->ssid,
+ pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ assoc_succ->rssi = pbss_desc->rssi;
+ assoc_succ->channel = pbss_desc->channel;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER, pevent);
+
+done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (passoc_rsp->status_code)
+ pioctl_req->status_code =
+ (wlan_le16_to_cpu(*(t_u16 *)&passoc_rsp
+ ->capability)
+ << 16) +
+ passoc_rsp->status_code;
+ else
+ pioctl_req->status_code =
+ MLAN_ERROR_CMD_ASSOC_FAIL;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_start.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer cast of mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_802_11_ad_hoc_start(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_START *padhoc_start = &cmd->params.adhoc_start;
+ BSSDescriptor_t *pbss_desc;
+ t_u32 cmd_append_size = 0;
+ t_u32 i;
+ t_u16 tmp_cap;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ /* wpa ie for WPA_NONE AES */
+ const t_u8 wpa_ie[24] = {0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01,
+ 0x01, 0x00, 0x00, 0x50, 0xf2, 0x04,
+ 0x01, 0x00, 0x00, 0x50, 0xf2, 0x00,
+ 0x01, 0x00, 0x00, 0x50, 0xf2, 0x00};
+ t_s32 append_size_11h = 0;
+ t_u8 *pos =
+ (t_u8 *)padhoc_start + sizeof(HostCmd_DS_802_11_AD_HOC_START);
+
+ ENTER();
+
+ if (!pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. HostCmd_DS_802_11_AD_HOC_START command
+ * 2. pbss_desc
+ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+ * probe delay, and Cap info.
+ * Firmware will fill up beacon period, Basic rates
+ * and operational rates.
+ */
+
+ memset(pmadapter, padhoc_start->ssid, 0, MLAN_MAX_SSID_LENGTH);
+
+ memcpy_ext(pmadapter, padhoc_start->ssid,
+ ((mlan_802_11_ssid *)pdata_buf)->ssid,
+ ((mlan_802_11_ssid *)pdata_buf)->ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: SSID = %s\n", padhoc_start->ssid);
+
+ memset(pmadapter, pbss_desc->ssid.ssid, 0, MLAN_MAX_SSID_LENGTH);
+ memcpy_ext(pmadapter, pbss_desc->ssid.ssid,
+ ((mlan_802_11_ssid *)pdata_buf)->ssid,
+ ((mlan_802_11_ssid *)pdata_buf)->ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+
+ pbss_desc->ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH,
+ ((mlan_802_11_ssid *)pdata_buf)->ssid_len);
+
+ /* Set the BSS mode */
+ padhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+ pbss_desc->bss_mode = MLAN_BSS_MODE_IBSS;
+ padhoc_start->beacon_period = wlan_cpu_to_le16(pmpriv->beacon_period);
+ pbss_desc->beacon_period = pmpriv->beacon_period;
+
+ /* Set Physical param set */
+/** Parameter IE Id */
+#define DS_PARA_IE_ID 3
+/** Parameter IE length */
+#define DS_PARA_IE_LEN 1
+
+ padhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+ padhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+ if (!wlan_get_cfp_by_band_and_channel(
+ pmadapter, pmadapter->adhoc_start_band,
+ (t_u16)pmpriv->adhoc_channel, pmadapter->region_channel)) {
+ chan_freq_power_t *cfp;
+ cfp = wlan_get_cfp_by_band_and_channel(
+ pmadapter, pmadapter->adhoc_start_band,
+ FIRST_VALID_CHANNEL, pmadapter->region_channel);
+ if (cfp)
+ pmpriv->adhoc_channel = (t_u8)cfp->channel;
+ }
+
+ MASSERT(pmpriv->adhoc_channel);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+ pmpriv->adhoc_channel);
+
+ pmpriv->curr_bss_params.bss_descriptor.channel = pmpriv->adhoc_channel;
+ pmpriv->curr_bss_params.band = pmadapter->adhoc_start_band;
+
+ pbss_desc->channel = pmpriv->adhoc_channel;
+ padhoc_start->phy_param_set.ds_param_set.current_chan =
+ pmpriv->adhoc_channel;
+
+ memcpy_ext(pmadapter, &pbss_desc->phy_param_set,
+ &padhoc_start->phy_param_set,
+ sizeof(IEEEtypes_PhyParamSet_t),
+ sizeof(IEEEtypes_PhyParamSet_t));
+
+ pbss_desc->network_type_use = Wlan802_11DS;
+
+ /* Set IBSS param set */
+/** IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID 6
+/** IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN 2
+
+ padhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+ padhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+ padhoc_start->ss_param_set.ibss_param_set.atim_window =
+ wlan_cpu_to_le16(pmpriv->atim_window);
+ pbss_desc->atim_window = pmpriv->atim_window;
+ memcpy_ext(pmadapter, &pbss_desc->ss_param_set,
+ &padhoc_start->ss_param_set, sizeof(IEEEtypes_SsParamSet_t),
+ sizeof(IEEEtypes_SsParamSet_t));
+
+ /* Set Capability info */
+ padhoc_start->cap.ess = 0;
+ padhoc_start->cap.ibss = 1;
+ pbss_desc->cap_info.ibss = 1;
+
+ /* Set up privacy in pbss_desc */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled ||
+ pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+/** Ad-Hoc capability privacy on */
+#define AD_HOC_CAP_PRIVACY_ON 1
+ PRINTM(MINFO, "ADHOC_S_CMD: wep_status set, Privacy to WEP\n");
+ pbss_desc->privacy = Wlan802_11PrivFilter8021xWEP;
+ padhoc_start->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ PRINTM(MWARN, "ADHOC_S_CMD: wep_status NOT set, Setting "
+ "Privacy to ACCEPT ALL\n");
+ pbss_desc->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ memset(pmadapter, padhoc_start->DataRate, 0,
+ sizeof(padhoc_start->DataRate));
+
+ if ((pmpriv->adapter->region_code == COUNTRY_CODE_JP_40 ||
+ pmpriv->adapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (pbss_desc->phy_param_set.ds_param_set.current_chan == 14)) {
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode, BAND_B,
+ padhoc_start->DataRate);
+ } else {
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ pmadapter->adhoc_start_band,
+ padhoc_start->DataRate);
+ }
+
+ if ((pmadapter->adhoc_start_band & BAND_G) &&
+ (pmpriv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+
+ if (ret) {
+ PRINTM(MERROR,
+ "ADHOC_S_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Find the last non zero */
+ for (i = 0;
+ i < sizeof(padhoc_start->DataRate) && padhoc_start->DataRate[i];
+ i++)
+ /* XXX Do not delete no-operation line */
+ ;
+
+ pmpriv->curr_bss_params.num_of_rates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS rate structure */
+ memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ &padhoc_start->DataRate,
+ pmpriv->curr_bss_params.num_of_rates, WLAN_SUPPORTED_RATES);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x\n",
+ padhoc_start->DataRate[0], padhoc_start->DataRate[1],
+ padhoc_start->DataRate[2], padhoc_start->DataRate[3]);
+
+ PRINTM(MINFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (t_u8)pmpriv->curr_bss_params.bss_descriptor.channel;
+
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
+ wlan_band_to_radio_type(pmpriv->curr_bss_params.band);
+ PRINTM(MINFO, "ADHOC_S_CMD: TLV Bandcfg = %x\n",
+ pchan_tlv->chan_scan_param[0].bandcfg);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv,
+ pmpriv->curr_bss_params.band)) {
+ PRINTM(MERROR, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h start API to add any 11h flags/elements as TLV parameters
+ */
+ append_size_11h =
+ wlan_11h_process_start(pmpriv, &pos, &padhoc_start->cap,
+ pmpriv->adhoc_channel,
+ &pbss_desc->wlan_11h_bss_info);
+ if (append_size_11h >= 0)
+ cmd_append_size += append_size_11h;
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmpriv->sec_info.ewpa_enabled) {
+ memcpy_ext(pmadapter, pmpriv->wpa_ie, wpa_ie, sizeof(wpa_ie),
+ sizeof(pmpriv->wpa_ie));
+ pmpriv->wpa_ie_len = sizeof(wpa_ie);
+ }
+
+ if (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
+ /* WPA_IE or RSN_IE */
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
+ &pmpriv->wpa_ie[2], prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "ADHOC_S_CMD: RSN IE", (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+
+ cmd->size = (t_u16)wlan_cpu_to_le16(
+ (t_u16)(sizeof(HostCmd_DS_802_11_AD_HOC_START) + S_DS_GEN +
+ cmd_append_size));
+
+ memcpy_ext(pmadapter, &tmp_cap, &padhoc_start->cap, sizeof(t_u16),
+ sizeof(tmp_cap));
+
+ if (pmadapter->adhoc_start_band == BAND_B)
+ SHORT_SLOT_TIME_DISABLED(tmp_cap);
+ else
+ SHORT_SLOT_TIME_ENABLED(tmp_cap);
+
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+ memcpy_ext(pmadapter, &padhoc_start->cap, &tmp_cap, sizeof(t_u16),
+ sizeof(padhoc_start->cap));
+
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_join.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void cast of BSSDescriptor_t from the
+ * scan table to join
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_802_11_ad_hoc_join(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_AD_HOC_JOIN *padhoc_join = &cmd->params.adhoc_join;
+ BSSDescriptor_t *pbss_desc = (BSSDescriptor_t *)pdata_buf;
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv;
+ MrvlIEtypes_RsnParamSet_t *prsn_ie_tlv;
+ t_u32 cmd_append_size = 0;
+ t_u16 tmp_cap;
+ t_u32 i, rates_size = 0;
+ t_u32 curr_pkt_filter;
+ t_u8 *pos = (t_u8 *)padhoc_join + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
+
+ ENTER();
+
+/** Use G protection */
+#define USE_G_PROTECTION 0x02
+ if (pbss_desc->erp_flags & USE_G_PROTECTION) {
+ curr_pkt_filter = pmpriv->curr_pkt_filter |
+ HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &curr_pkt_filter);
+ if (ret) {
+ PRINTM(MERROR,
+ "ADHOC_J_CMD: G Protection config failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ pmpriv->pattempted_bss_desc = pbss_desc;
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+ padhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+ padhoc_join->bss_descriptor.beacon_period =
+ wlan_cpu_to_le16(pbss_desc->beacon_period);
+
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.bssid,
+ &pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.ssid,
+ &pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.phy_param_set,
+ &pbss_desc->phy_param_set, sizeof(IEEEtypes_PhyParamSet_t),
+ sizeof(IEEEtypes_PhyParamSet_t));
+
+ padhoc_join->bss_descriptor.phy_param_set.fh_param_set.dwell_time =
+ wlan_cpu_to_le16(padhoc_join->bss_descriptor.phy_param_set
+ .fh_param_set.dwell_time);
+
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.ss_param_set,
+ &pbss_desc->ss_param_set, sizeof(IEEEtypes_SsParamSet_t),
+ sizeof(IEEEtypes_SsParamSet_t));
+ padhoc_join->bss_descriptor.ss_param_set.ibss_param_set.atim_window = 0;
+ padhoc_join->bss_descriptor.ss_param_set.ibss_param_set.atim_window =
+ wlan_cpu_to_le16(padhoc_join->bss_descriptor.ss_param_set
+ .ibss_param_set.atim_window);
+
+ memcpy_ext(pmadapter, &tmp_cap, &pbss_desc->cap_info,
+ sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
+
+ tmp_cap &= CAPINFO_MASK;
+
+ PRINTM(MINFO, "ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", tmp_cap,
+ CAPINFO_MASK);
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
+ sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
+
+ /* Information on BSSID descriptor passed to FW */
+ PRINTM(MINFO, "ADHOC_J_CMD: BSSID = " MACSTR ", SSID = %s\n",
+ MAC2STR(padhoc_join->bss_descriptor.bssid),
+ padhoc_join->bss_descriptor.ssid);
+
+ for (i = 0; i < WLAN_SUPPORTED_RATES && pbss_desc->supported_rates[i];
+ i++)
+ /* XXX Do not delete no-operation line */
+ ;
+ rates_size = i;
+
+ /* Copy Data Rates from the Rates recorded in scan response */
+ memset(pmadapter, padhoc_join->bss_descriptor.data_rates, 0,
+ sizeof(padhoc_join->bss_descriptor.data_rates));
+ memcpy_ext(pmadapter, padhoc_join->bss_descriptor.data_rates,
+ pbss_desc->supported_rates, rates_size,
+ WLAN_SUPPORTED_RATES);
+
+ HEXDUMP("Adapted Rates:", padhoc_join->bss_descriptor.data_rates,
+ rates_size);
+
+ /* Copy the adhoc join rates into Current BSS state structure */
+ pmpriv->curr_bss_params.num_of_rates = rates_size;
+ memcpy_ext(pmadapter, &pmpriv->curr_bss_params.data_rates,
+ pbss_desc->supported_rates, rates_size,
+ WLAN_SUPPORTED_RATES);
+
+ /* Copy the channel information */
+ pmpriv->curr_bss_params.bss_descriptor.channel = pbss_desc->channel;
+ pmpriv->curr_bss_params.band = (t_u8)pbss_desc->bss_band;
+
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled ||
+ pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.ewpa_enabled)
+ padhoc_join->bss_descriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+
+ if (IS_SUPPORT_MULTI_BANDS(pmadapter)) {
+ /* Append a channel TLV */
+ pchan_tlv = (MrvlIEtypes_ChanListParamSet_t *)pos;
+ pchan_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+ memset(pmadapter, pchan_tlv->chan_scan_param, 0x00,
+ sizeof(ChanScanParamSet_t));
+ pchan_tlv->chan_scan_param[0].chan_number =
+ (pbss_desc->phy_param_set.ds_param_set.current_chan);
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Chan = %d\n",
+ pchan_tlv->chan_scan_param[0].chan_number);
+
+ pchan_tlv->chan_scan_param[0].bandcfg.chanBand =
+ wlan_band_to_radio_type((t_u8)pbss_desc->bss_band);
+
+ PRINTM(MINFO, "ADHOC_J_CMD: TLV Bandcfg = %x\n",
+ pchan_tlv->chan_scan_param[0].bandcfg);
+ pos += sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ cmd_append_size +=
+ sizeof(pchan_tlv->header) + sizeof(ChanScanParamSet_t);
+ }
+
+ if (wlan_11d_create_dnld_countryinfo(pmpriv,
+ (t_u8)pbss_desc->bss_band)) {
+ PRINTM(MERROR, "Dnld_countryinfo_11d failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (wlan_11d_parse_dnld_countryinfo(pmpriv,
+ pmpriv->pattempted_bss_desc)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Call 11h join API after capability bits are set so
+ * adhoc/infra 11h behavior can be properly triggered.
+ * pos modified if data is appended
+ */
+ cmd_append_size += wlan_11h_process_join(
+ pmpriv, &pos, &padhoc_join->bss_descriptor.cap,
+ (t_u8)pbss_desc->bss_band, pbss_desc->channel,
+ &pbss_desc->wlan_11h_bss_info);
+
+ if (pmpriv->sec_info.wpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ /* WPA_IE or RSN_IE */
+ prsn_ie_tlv->header.type = (t_u16)pmpriv->wpa_ie[0];
+ prsn_ie_tlv->header.type = prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len = (t_u16)pmpriv->wpa_ie[1];
+ prsn_ie_tlv->header.len = prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <= (sizeof(pmpriv->wpa_ie) - 2))
+ memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
+ &pmpriv->wpa_ie[2], prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ cmd_append_size +=
+ sizeof(prsn_ie_tlv->header) + prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ } else if (pmpriv->sec_info.ewpa_enabled) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ if (pbss_desc->pwpa_ie) {
+ prsn_ie_tlv->header.type =
+ (t_u16)(*(pbss_desc->pwpa_ie))
+ .vend_hdr.element_id;
+ prsn_ie_tlv->header.type =
+ prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16)(*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ prsn_ie_tlv->header.len =
+ prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <=
+ (sizeof(pmpriv->wpa_ie))) {
+ memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->pwpa_ie))
+ .vend_hdr.oui[0]),
+ prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ cmd_append_size += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ if (pbss_desc->prsn_ie) {
+ prsn_ie_tlv = (MrvlIEtypes_RsnParamSet_t *)pos;
+ prsn_ie_tlv->header.type =
+ (t_u16)(*(pbss_desc->prsn_ie))
+ .ieee_hdr.element_id;
+ prsn_ie_tlv->header.type =
+ prsn_ie_tlv->header.type & 0x00FF;
+ prsn_ie_tlv->header.type =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.type);
+ prsn_ie_tlv->header.len =
+ (t_u16)(*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ prsn_ie_tlv->header.len =
+ prsn_ie_tlv->header.len & 0x00FF;
+ if (prsn_ie_tlv->header.len <=
+ (sizeof(pmpriv->wpa_ie))) {
+ memcpy_ext(pmadapter, prsn_ie_tlv->rsn_ie,
+ &((*(pbss_desc->prsn_ie)).data[0]),
+ prsn_ie_tlv->header.len,
+ prsn_ie_tlv->header.len);
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ HEXDUMP("ADHOC_JOIN: RSN IE", (t_u8 *)prsn_ie_tlv,
+ sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len);
+ pos += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ cmd_append_size += sizeof(prsn_ie_tlv->header) +
+ prsn_ie_tlv->header.len;
+ prsn_ie_tlv->header.len =
+ wlan_cpu_to_le16(prsn_ie_tlv->header.len);
+ }
+ }
+
+ cmd->size = (t_u16)wlan_cpu_to_le16(
+ (t_u16)(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN) + S_DS_GEN +
+ cmd_append_size));
+
+ memcpy_ext(pmadapter, &tmp_cap, &padhoc_join->bss_descriptor.cap,
+ sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
+ tmp_cap = wlan_cpu_to_le16(tmp_cap);
+
+ memcpy_ext(pmadapter, &padhoc_join->bss_descriptor.cap, &tmp_cap,
+ sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_start and
+ * ad_hoc_join
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_ad_hoc(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp, t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+ HostCmd_DS_802_11_AD_HOC_START_RESULT *padhoc_start_result =
+ &resp->params.adhoc_start_result;
+ HostCmd_DS_802_11_AD_HOC_JOIN_RESULT *padhoc_join_result =
+ &resp->params.adhoc_join_result;
+ BSSDescriptor_t *pbss_desc;
+ t_u16 command = resp->command;
+ t_u8 result = 0;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *)event_buf;
+ int ie_len = 0;
+ IEEEtypes_WmmParameter_t *pwmm_param_ie = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+
+ ENTER();
+
+ pmpriv->wmm_enabled = MFALSE;
+ if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+ result = padhoc_start_result->result;
+ ie_len = resp->size -
+ (sizeof(HostCmd_DS_802_11_AD_HOC_START_RESULT) +
+ S_DS_GEN);
+ pwmm_param_ie =
+ (IEEEtypes_WmmParameter_t
+ *)((t_u8 *)resp +
+ (sizeof(HostCmd_DS_802_11_AD_HOC_START_RESULT) +
+ S_DS_GEN));
+ } else {
+ result = padhoc_join_result->result;
+ ie_len = resp->size -
+ (sizeof(HostCmd_DS_802_11_AD_HOC_JOIN_RESULT) +
+ S_DS_GEN);
+ pwmm_param_ie =
+ (IEEEtypes_WmmParameter_t
+ *)((t_u8 *)resp +
+ (sizeof(HostCmd_DS_802_11_AD_HOC_JOIN_RESULT) +
+ S_DS_GEN));
+ }
+
+ pbss_desc = pmpriv->pattempted_bss_desc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ PRINTM(MERROR, "ADHOC_RESP Failed 0x%x\n", result);
+ if (pmpriv->media_connected == MTRUE)
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adhoc_state == ADHOC_STARTING)
+ pmpriv->adhoc_state = ADHOC_IDLE;
+
+ memset(pmpriv->adapter, &pmpriv->curr_bss_params.bss_descriptor,
+ 0x00, sizeof(BSSDescriptor_t));
+
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ pmpriv->media_connected = MTRUE;
+
+ if (command == HostCmd_CMD_802_11_AD_HOC_START) {
+ PRINTM(MINFO, "ADHOC_S_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /* Update the created network descriptor with the new BSSID */
+ memcpy_ext(pmpriv->adapter, pbss_desc->mac_address,
+ padhoc_start_result->bssid, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ pmpriv->adhoc_state = ADHOC_STARTED;
+ if (pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *)pmpriv);
+ } else {
+ /*
+ * Now the join cmd should be successful.
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ PRINTM(MINFO, "ADHOC_J_RESP %s\n", pbss_desc->ssid.ssid);
+
+ /*
+ * Make a copy of current BSSID descriptor, only needed
+ * for join since the current descriptor is already
+ * being used for adhoc start
+ */
+ memcpy_ext(pmpriv->adapter,
+ &pmpriv->curr_bss_params.bss_descriptor, pbss_desc,
+ sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
+
+ pmpriv->adhoc_state = ADHOC_JOINED;
+ }
+
+ /** process wmm ie */
+ if (ie_len >= sizeof(IEEEtypes_VendorHeader_t)) {
+ if ((pwmm_param_ie->vend_hdr.element_id ==
+ VENDOR_SPECIFIC_221) &&
+ !memcmp(pmadapter, pwmm_param_ie->vend_hdr.oui, wmm_oui,
+ sizeof(wmm_oui)) &&
+ (pwmm_param_ie->vend_hdr.len + 2 == ie_len)) {
+ DBG_HEXDUMP(MCMD_D, "WMM Param", (t_u8 *)pwmm_param_ie,
+ ie_len);
+ memcpy_ext(pmpriv->adapter,
+ (t_u8 *)&pmpriv->curr_bss_params
+ .bss_descriptor.wmm_ie,
+ pwmm_param_ie,
+ (pwmm_param_ie->vend_hdr.len + 2),
+ sizeof(IEEEtypes_WmmParameter_t));
+ pmpriv->wmm_enabled = MTRUE;
+ wlan_wmm_setup_queue_priorities(pmpriv, pwmm_param_ie);
+ wlan_wmm_setup_ac_downgrade(pmpriv);
+ }
+ }
+ /* Since WMM is not enabled, setup the queues with the defaults */
+ if (!pmpriv->wmm_enabled)
+ wlan_wmm_setup_queues(pmpriv);
+
+ PRINTM(MINFO, "ADHOC_RESP: Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "ADHOC_RESP: BSSID = " MACSTR "\n",
+ MAC2STR(pmpriv->curr_bss_params.bss_descriptor.mac_address));
+
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_CONNECTED;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_CONNECTED, pevent);
+ wlan_save_curr_bcn(pmpriv);
+
+done:
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ if (ret != MLAN_STATUS_SUCCESS)
+ pioctl_req->status_code = MLAN_ERROR_CMD_ASSOC_FAIL;
+ else
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Associated to a specific BSS discovered in a scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor to associate with.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_associate(mlan_private *pmpriv, t_void *pioctl_buf,
+ BSSDescriptor_t *pbss_desc)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 current_bssid[MLAN_MAC_ADDR_LENGTH];
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ /* Return error if the pmadapter or table entry
+ * is not marked as infra */
+ if ((pmpriv->bss_mode != MLAN_BSS_MODE_INFRA) ||
+ (pbss_desc->bss_mode != MLAN_BSS_MODE_INFRA)) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy_ext(pmpriv->adapter, &current_bssid,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(current_bssid), sizeof(current_bssid));
+
+ /* Clear any past association response stored for application retrieval
+ */
+ pmpriv->assoc_rsp_size = 0;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param padhoc_ssid The ssid of the Adhoc Network
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status wlan_adhoc_start(mlan_private *pmpriv, t_void *pioctl_buf,
+ mlan_802_11_ssid *padhoc_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ t_u8 radar = MFALSE;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ /*
+ * If the report indicates no measurement was done, leave the default
+ * return value alone.
+ */
+ if (!pmeas_state->meas_rpt_returned.rpt.basic.map.unmeasured) {
+ radar = pmeas_state->meas_rpt_returned.rpt.basic.map.radar ?
+ MTRUE :
+ MFALSE;
+ }
+
+ if (radar) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+
+ PRINTM(MINFO, "Adhoc Channel = %d\n", pmpriv->adhoc_channel);
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n",
+ pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, padhoc_ssid);
+#if defined(STA_SUPPORT)
+ if (ret == MLAN_STATUS_SUCCESS)
+ memcpy_ext(pmpriv->adapter, &pmpriv->adhoc_last_start_ssid,
+ padhoc_ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pbss_desc A pointer to the BSS descriptor found in a previous
+ * scan to attempt to join
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status wlan_adhoc_join(mlan_private *pmpriv, t_void *pioctl_buf,
+ BSSDescriptor_t *pbss_desc)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid =%s\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: CurBss.ssid_len =%u\n",
+ pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid =%s\n", pbss_desc->ssid.ssid);
+ PRINTM(MINFO, "wlan_adhoc_join: ssid len =%u\n",
+ pbss_desc->ssid.ssid_len);
+
+ /* Check if the requested SSID is already joined */
+ if (pmpriv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+ !wlan_ssid_cmp(pmadapter, &pbss_desc->ssid,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid) &&
+ (pmpriv->curr_bss_params.bss_descriptor.bss_mode ==
+ MLAN_BSS_MODE_IBSS)) {
+ PRINTM(MINFO,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join\n");
+
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "curr_bss_params.channel = %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel);
+ PRINTM(MINFO, "curr_bss_params.band = %d\n",
+ pmpriv->curr_bss_params.band);
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, pioctl_buf, pbss_desc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send Deauthentication Request or Stop the AdHoc network depending on
+ * mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to mlan_ioctl_req structure
+ * @param deauth_param A pointer to mlan_deauth_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail,
+ * MLAN_STATUS_PENDING--pending
+ */
+mlan_status wlan_disconnect(mlan_private *pmpriv, mlan_ioctl_req *pioctl_req,
+ mlan_deauth_param *deauth_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_deauth_param local_param = {.mac_addr = {0, 0, 0, 0, 0, 0},
+ .reason_code = DEF_DEAUTH_REASON_CODE};
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+
+ ENTER();
+
+ if (deauth_param)
+ memcpy_ext(pmpriv->adapter, &local_param, deauth_param,
+ sizeof(*deauth_param), sizeof(local_param));
+ if (pmpriv->media_connected == MTRUE) {
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (!deauth_param ||
+ !memcmp(pmpriv->adapter, deauth_param->mac_addr,
+ zero_mac, sizeof(zero_mac)))
+ memcpy_ext(pmpriv->adapter,
+ local_param.mac_addr,
+ (t_u8 *)&pmpriv->curr_bss_params
+ .bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ ret = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_802_11_DISASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, &local_param);
+ else
+#endif
+ ret = wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, &local_param);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+
+ } else if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS && pioctl_req)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert band to radio type used in channel TLV
+ *
+ * @param band Band enumeration to convert to a channel TLV radio type
+ *
+ * @return Radio type designator for use in a channel TLV
+ */
+t_u8 wlan_band_to_radio_type(t_u8 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
+ ret_radio_type = BAND_5GHZ;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ default:
+ ret_radio_type = BAND_2GHZ;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.h
new file mode 100644
index 000000000000..99d6027c59d5
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_join.h
@@ -0,0 +1,42 @@
+/** @file mlan_join.h
+ *
+ * @brief This file defines the interface for the WLAN infrastructure
+ * and adhoc join routines.
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in mlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_JOIN_H_
+#define _MLAN_JOIN_H_
+
+/** Size of buffer allocated to store the association response from firmware */
+#define MRVDRV_ASSOC_RSP_BUF_SIZE 500
+
+/** Size of buffer allocated to store IEs passed to firmware in the assoc req */
+#define MRVDRV_GENIE_BUF_SIZE 256
+
+#endif /* _MLAN_JOIN_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_main.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_main.h
new file mode 100644
index 000000000000..2e3019f47460
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_main.h
@@ -0,0 +1,4137 @@
+/** @file mlan_main.h
+ *
+ * @brief This file defines the private and adapter data
+ * structures and declares global function prototypes used
+ * in MLAN module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_MAIN_H_
+#define _MLAN_MAIN_H_
+
+#ifdef DEBUG_LEVEL1
+extern t_void (*print_callback)(t_pvoid pmoal_handle, t_u32 level,
+ char *pformat, IN...);
+
+extern mlan_status (*get_sys_time_callback)(t_void *pmoal_handle, t_u32 *psec,
+ t_u32 *pusec);
+
+extern t_u32 mlan_drvdbg;
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(msg...) \
+ do { \
+ if ((mlan_drvdbg & MINFO) && (print_callback)) \
+ print_callback(MNULL, MINFO, msg); \
+ } while (0)
+#define PRINTM_MWARN(msg...) \
+ do { \
+ if ((mlan_drvdbg & MWARN) && (print_callback)) \
+ print_callback(MNULL, MWARN, msg); \
+ } while (0)
+#define PRINTM_MENTRY(msg...) \
+ do { \
+ if ((mlan_drvdbg & MENTRY) && (print_callback)) \
+ print_callback(MNULL, MENTRY, msg); \
+ } while (0)
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+ do { \
+ if ((level & mlan_drvdbg) && (get_sys_time_callback)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+ } while (0)
+
+/** Hexdump for level-2 debugging */
+#define HEXDUMP(x, y, z) \
+ do { \
+ if ((mlan_drvdbg & (MHEX_DUMP | MINFO)) && (print_callback)) \
+ print_callback(MNULL, MHEX_DUMP | MINFO, x, y, z); \
+ } while (0)
+
+#else
+
+#define PRINTM_MINFO(msg...) \
+ do { \
+ } while (0)
+#define PRINTM_MWARN(msg...) \
+ do { \
+ } while (0)
+#define PRINTM_MENTRY(msg...) \
+ do { \
+ } while (0)
+
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+ do { \
+ if ((level & mlan_drvdbg) && (get_sys_time_callback) && \
+ (level != MINFO) && (level != MWARN)) \
+ get_sys_time_callback(MNULL, psec, pusec); \
+ } while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x, y, z) \
+ do { \
+ } while (0)
+
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(msg...) \
+ do { \
+ if ((mlan_drvdbg & MFW_D) && (print_callback)) \
+ print_callback(MNULL, MFW_D, msg); \
+ } while (0)
+#define PRINTM_MCMD_D(msg...) \
+ do { \
+ if ((mlan_drvdbg & MCMD_D) && (print_callback)) \
+ print_callback(MNULL, MCMD_D, msg); \
+ } while (0)
+#define PRINTM_MDAT_D(msg...) \
+ do { \
+ if ((mlan_drvdbg & MDAT_D) && (print_callback)) \
+ print_callback(MNULL, MDAT_D, msg); \
+ } while (0)
+#define PRINTM_MIF_D(msg...) \
+ do { \
+ if ((mlan_drvdbg & MIF_D) && (print_callback)) \
+ print_callback(MNULL, MIF_D, msg); \
+ } while (0)
+
+#define PRINTM_MIOCTL(msg...) \
+ do { \
+ if ((mlan_drvdbg & MIOCTL) && (print_callback)) \
+ print_callback(MNULL, MIOCTL, msg); \
+ } while (0)
+#define PRINTM_MINTR(msg...) \
+ do { \
+ if ((mlan_drvdbg & MINTR) && (print_callback)) \
+ print_callback(MNULL, MINTR, msg); \
+ } while (0)
+#define PRINTM_MEVENT(msg...) \
+ do { \
+ if ((mlan_drvdbg & MEVENT) && (print_callback)) \
+ print_callback(MNULL, MEVENT, msg); \
+ } while (0)
+#define PRINTM_MCMND(msg...) \
+ do { \
+ if ((mlan_drvdbg & MCMND) && (print_callback)) \
+ print_callback(MNULL, MCMND, msg); \
+ } while (0)
+#define PRINTM_MDATA(msg...) \
+ do { \
+ if ((mlan_drvdbg & MDATA) && (print_callback)) \
+ print_callback(MNULL, MDATA, msg); \
+ } while (0)
+#define PRINTM_MERROR(msg...) \
+ do { \
+ if ((mlan_drvdbg & MERROR) && (print_callback)) \
+ print_callback(MNULL, MERROR, msg); \
+ } while (0)
+#define PRINTM_MFATAL(msg...) \
+ do { \
+ if ((mlan_drvdbg & MFATAL) && (print_callback)) \
+ print_callback(MNULL, MFATAL, msg); \
+ } while (0)
+#define PRINTM_MMSG(msg...) \
+ do { \
+ if ((mlan_drvdbg & MMSG) && (print_callback)) \
+ print_callback(MNULL, MMSG, msg); \
+ } while (0)
+
+#define PRINTM(level, msg...) PRINTM_##level((char *)msg)
+
+/** Log debug message */
+#ifdef __GNUC__
+#define PRINTM_NETINTF(level, pmpriv) \
+ do { \
+ if ((mlan_drvdbg & level) && pmpriv && \
+ pmpriv->adapter->callbacks.moal_print_netintf) \
+ pmpriv->adapter->callbacks.moal_print_netintf( \
+ pmpriv->adapter->pmoal_handle, \
+ pmpriv->bss_index, level); \
+ } while (0)
+#endif /* __GNUC__ */
+
+/** Max hex dump data length */
+#define MAX_DATA_DUMP_LEN 64
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level, x, y, z) \
+ do { \
+ if ((mlan_drvdbg & level) && print_callback) \
+ print_callback(MNULL, MHEX_DUMP | level, x, y, z); \
+ } while (0)
+
+#else /* DEBUG_LEVEL1 */
+
+#define PRINTM(level, msg...) \
+ do { \
+ } while (0)
+
+#define PRINTM_NETINTF(level, pmpriv) \
+ do { \
+ } while (0)
+
+/** Debug hexdump for level-1 debugging */
+#define DBG_HEXDUMP(level, x, y, z) \
+ do { \
+ } while (0)
+
+/** Hexdump for debugging */
+#define HEXDUMP(x, y, z) \
+ do { \
+ } while (0)
+
+#define PRINTM_GET_SYS_TIME(level, psec, pusec) \
+ do { \
+ } while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/* Reason Code 3: STA is leaving (or has left) IBSS or ESS */
+#define DEF_DEAUTH_REASON_CODE (0x3)
+
+/** Log entry point for debugging */
+#define ENTER() \
+ do { \
+ PRINTM(MENTRY, "Enter: %s\n", __func__); \
+ } while (0)
+
+/** Log exit point for debugging */
+#define LEAVE() \
+ do { \
+ PRINTM(MENTRY, "Leave: %s\n", __func__); \
+ } while (0)
+
+/** Find minimum */
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef memset
+#undef memset
+#endif
+/** Memset routine */
+#define memset(adapter, s, c, len) \
+ (adapter->callbacks.moal_memset(adapter->pmoal_handle, s, c, len))
+
+#ifdef memmove
+#undef memmove
+#endif
+/** Memmove routine */
+#define memmove(adapter, dest, src, len) \
+ (adapter->callbacks.moal_memmove(adapter->pmoal_handle, dest, src, len))
+
+#ifdef memcpy
+#undef memcpy
+#endif
+/** Memcpy routine */
+#define memcpy(adapter, to, from, len) \
+ (adapter->callbacks.moal_memcpy(adapter->pmoal_handle, to, from, len))
+/* memcpy_ext rountine */
+#define memcpy_ext(adapter, to, from, len, size) \
+ (adapter->callbacks.moal_memcpy_ext(adapter->pmoal_handle, to, from, \
+ len, size))
+
+#ifdef memcmp
+#undef memcmp
+#endif
+/** Memcmp routine */
+#define memcmp(adapter, s1, s2, len) \
+ (adapter->callbacks.moal_memcmp(adapter->pmoal_handle, s1, s2, len))
+
+/** Find number of elements */
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+/** SWAP: swap t_u8 */
+#define SWAP_U8(a, b) \
+ { \
+ t_u8 t; \
+ t = a; \
+ a = b; \
+ b = t; \
+ }
+
+/** SWAP: swap t_u8 */
+#define SWAP_U16(a, b) \
+ { \
+ t_u16 t; \
+ t = a; \
+ a = b; \
+ b = t; \
+ }
+
+/** MLAN MNULL pointer */
+#define MNULL (0)
+
+/** 16 bits byte swap */
+#define swap_byte_16(x) \
+ ((t_u16)((((t_u16)(x)&0x00ffU) << 8) | (((t_u16)(x)&0xff00U) >> 8)))
+
+/** 32 bits byte swap */
+#define swap_byte_32(x) \
+ ((t_u32)((((t_u32)(x)&0x000000ffUL) << 24) | \
+ (((t_u32)(x)&0x0000ff00UL) << 8) | \
+ (((t_u32)(x)&0x00ff0000UL) >> 8) | \
+ (((t_u32)(x)&0xff000000UL) >> 24)))
+
+/** 64 bits byte swap */
+#define swap_byte_64(x) \
+ ((t_u64)((t_u64)(((t_u64)(x)&0x00000000000000ffULL) << 56) | \
+ (t_u64)(((t_u64)(x)&0x000000000000ff00ULL) << 40) | \
+ (t_u64)(((t_u64)(x)&0x0000000000ff0000ULL) << 24) | \
+ (t_u64)(((t_u64)(x)&0x00000000ff000000ULL) << 8) | \
+ (t_u64)(((t_u64)(x)&0x000000ff00000000ULL) >> 8) | \
+ (t_u64)(((t_u64)(x)&0x0000ff0000000000ULL) >> 24) | \
+ (t_u64)(((t_u64)(x)&0x00ff000000000000ULL) >> 40) | \
+ (t_u64)(((t_u64)(x)&0xff00000000000000ULL) >> 56)))
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) x
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) x
+/** Convert n/w to host */
+#define mlan_ntohs(x) x
+/** Convert host to n/w */
+#define mlan_htons(x) x
+/** Convert from 16 bit little endian format to CPU format */
+#define wlan_le16_to_cpu(x) swap_byte_16(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define wlan_le32_to_cpu(x) swap_byte_32(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define wlan_le64_to_cpu(x) swap_byte_64(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define wlan_cpu_to_le16(x) swap_byte_16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define wlan_cpu_to_le32(x) swap_byte_32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define wlan_cpu_to_le64(x) swap_byte_64(x)
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) \
+ { \
+ (x)->tx_pkt_length = wlan_cpu_to_le16((x)->tx_pkt_length); \
+ (x)->tx_pkt_offset = wlan_cpu_to_le16((x)->tx_pkt_offset); \
+ (x)->tx_pkt_type = wlan_cpu_to_le16((x)->tx_pkt_type); \
+ (x)->tx_control = wlan_cpu_to_le32((x)->tx_control); \
+ (x)->tx_control_1 = wlan_cpu_to_le32((x)->tx_control_1); \
+ }
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) \
+ { \
+ (x)->rx_pkt_length = wlan_le16_to_cpu((x)->rx_pkt_length); \
+ (x)->rx_pkt_offset = wlan_le16_to_cpu((x)->rx_pkt_offset); \
+ (x)->rx_pkt_type = wlan_le16_to_cpu((x)->rx_pkt_type); \
+ (x)->seq_num = wlan_le16_to_cpu((x)->seq_num); \
+ (x)->rx_info = wlan_le32_to_cpu((x)->rx_info); \
+ }
+
+#else
+/** Convert ulong n/w to host */
+#define mlan_ntohl(x) swap_byte_32(x)
+/** Convert host ulong to n/w */
+#define mlan_htonl(x) swap_byte_32(x)
+/** Convert n/w to host */
+#define mlan_ntohs(x) swap_byte_16(x)
+/** Convert host to n/w */
+#define mlan_htons(x) swap_byte_16(x)
+/** Do nothing */
+#define wlan_le16_to_cpu(x) x
+/** Do nothing */
+#define wlan_le32_to_cpu(x) x
+/** Do nothing */
+#define wlan_le64_to_cpu(x) x
+/** Do nothing */
+#define wlan_cpu_to_le16(x) x
+/** Do nothing */
+#define wlan_cpu_to_le32(x) x
+/** Do nothing */
+#define wlan_cpu_to_le64(x) x
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x) \
+ do { \
+ } while (0)
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x) \
+ do { \
+ } while (0)
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** Global moal_assert_callback */
+extern t_void (*assert_callback)(t_void *pmoal_handle, t_u32 cond);
+
+/** Assertion */
+#define MASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __func__, \
+ __LINE__); \
+ if (assert_callback) { \
+ assert_callback(MNULL, (t_ptr)(cond)); \
+ } else { \
+ do { \
+ } while (1); \
+ } \
+ } \
+ } while (0)
+
+/** Maximum event buffer size */
+#define MAX_EVENT_SIZE (3 * 1024)
+
+/** 60 seconds */
+#define MRVDRV_TIMER_60S 60000
+/** 10 seconds */
+#define MRVDRV_TIMER_10S 10000
+/** 5 seconds */
+#define MRVDRV_TIMER_5S 5000
+/** 3 seconds */
+#define MRVDRV_TIMER_3S 3000
+/** 1 second */
+#define MRVDRV_TIMER_1S 1000
+
+/** Maximum size of multicast list */
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+/** Maximum size of channel */
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH 32
+/** WEP list macros & data structures */
+/** Size of key buffer in bytes */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16
+/** Maximum length of WPA key */
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+/** Default listen interval */
+#define MLAN_DEFAULT_LISTEN_INTERVAL 20
+
+/** Maximum number of region codes */
+#define MRVDRV_MAX_REGION_CODE 9
+
+/** Maximum number of CFP codes for BG */
+#define MRVDRV_MAX_CFP_CODE_BG 0
+/** Maximum number of CFP codes for A */
+#define MRVDRV_MAX_CFP_CODE_A 5
+
+/** high rx pending packets */
+#define HIGH_RX_PENDING 1000
+/** low rx pending packets */
+#define LOW_RX_PENDING 800
+
+/** Default region code */
+#define MRVDRV_DEFAULT_REGION_CODE 0x10
+/** Default country code */
+#define MRVDRV_DEFAULT_COUNTRY_CODE "US"
+
+/** Japan country code */
+#define COUNTRY_CODE_JP_40 0x40
+/** Japan special country code */
+#define COUNTRY_CODE_JP_FF 0xFF
+
+/** Default factor for calculating beacon average */
+#define DEFAULT_BCN_AVG_FACTOR 8
+/** Default factor for calculating data average */
+#define DEFAULT_DATA_AVG_FACTOR 8
+
+/** The first valid channel for use */
+#define FIRST_VALID_CHANNEL 0xff
+/** Default Ad-Hoc channel */
+#define DEFAULT_AD_HOC_CHANNEL 6
+/** Default Ad-Hoc channel A */
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** Number of WEP keys */
+#define MRVL_NUM_WEP_KEY (4)
+
+/** Default multiple DTIM */
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+/** Default beacon missing timeout */
+#define DEFAULT_BCN_MISS_TIMEOUT 10
+
+/** Maximum buffer space for beacons retrieved from scan responses */
+#define MAX_SCAN_BEACON_BUFFER 49152
+/** Default buffer space for beacons retrieved from scan responses */
+#define DEFAULT_SCAN_BEACON_BUFFER 4096
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ * For each scan response stored, allocate an extra byte pad at the end to
+ * allow easy expansion to store a beacon in the same memory a probe response
+ * previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD 6
+
+/** Scan time specified in the channel TLV
+ * for each channel for passive scans
+ */
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV
+ * for each channel for active scans
+ */
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 200
+
+/** Scan time specified in the channel TLV
+ * for each channel for specific scans
+ */
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 110
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (20s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME (MRVDRV_TIMER_10S * 2 - MRVDRV_TIMER_1S)
+
+/** Offset for GTK as it has version to skip past for GTK */
+#define RSN_GTK_OUI_OFFSET 2
+
+/** If OUI is not found */
+#define MLAN_OUI_NOT_PRESENT 0
+/** If OUI is found */
+#define MLAN_OUI_PRESENT 1
+
+/** Is cmd_resp, event or data packet received? */
+#define IS_CARD_RX_RCVD(adapter) \
+ (adapter->cmd_resp_received || adapter->event_received || \
+ adapter->data_received)
+#ifdef USB
+/** Type length */
+#define MLAN_TYPE_LEN 4
+/** Type Command */
+#define MLAN_USB_TYPE_CMD 0xF00DFACE
+/** Type VDLL */
+#define MLAN_USB_TYPE_VDLL 0xF00DC0DE
+/** Type Data */
+#define MLAN_USB_TYPE_DATA 0xBEADC0DE
+/** Type Event */
+#define MLAN_USB_TYPE_EVENT 0xBEEFFACE
+#endif /* USB */
+/** Type command */
+#define MLAN_TYPE_CMD 1
+/** Type data */
+#define MLAN_TYPE_DATA 0
+/** Type event */
+#define MLAN_TYPE_EVENT 3
+/** Type vdll */
+#define MLAN_TYPE_VDLL 4
+#ifdef SDIO
+/** Type single port aggr data */
+#define MLAN_TYPE_SPA_DATA 10
+/** OFFSET of 512 block number */
+#define OFFSET_OF_BLOCK_NUMBER 15
+/** OFFSET of SDIO Header */
+#define OFFSET_OF_SDIO_HEADER 28
+/** sdio max rx size for cmd53, 255 * 256, reserve 1 block for DMA alignment */
+#define SDIO_CMD53_MAX_SIZE 65280
+#define MAX_SUPPORT_AMSDU_SIZE 4096
+/** Maximum numbfer of registers to read for multiple port */
+#if defined(SD8887) || defined(SD8997) || defined(SD8977) || \
+ defined(SD8987) || defined(SD9098) || defined(SD9097) || \
+ defined(SD8978)
+#define MAX_MP_REGS 196
+#else
+/* upto 0xB7 */
+#define MAX_MP_REGS 184
+#endif
+/** Maximum port */
+#define MAX_PORT 32
+
+/** max MP REGS */
+#define MAX_MP_REGS_MAX (196)
+
+/** Multi port TX aggregation buffer size */
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (65280) /* 64K - 256 */
+
+/** Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (65280) /* 64K - 256 */
+
+#endif /* SDIO */
+
+/** Minimum BA threshold */
+#define MIN_BA_THRESHOLD 16
+
+/** High threshold at which to start drop packets */
+#define RX_HIGH_THRESHOLD 1024
+/** Low threshold to allow Rx BA */
+#define RX_LOW_THRESHOLD 128
+
+#define MFG_CMD_SET_TEST_MODE 1
+#define MFG_CMD_UNSET_TEST_MODE 0
+#define MFG_CMD_TX_ANT 0x1004
+#define MFG_CMD_RX_ANT 0x1005
+#define MFG_CMD_TX_CONT 0x1009
+#define MFG_CMD_RF_CHAN 0x100A
+#define MFG_CMD_CLR_RX_ERR 0x1010
+#define MFG_CMD_TX_FRAME 0x1021
+#define MFG_CMD_RF_BAND_AG 0x1034
+#define MFG_CMD_RF_CHANNELBW 0x1044
+
+/** Debug command number */
+#define DBG_CMD_NUM 10
+
+/** Info for debug purpose */
+typedef struct _wlan_dbg {
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** Number of allocate buffer failure */
+ t_u32 num_alloc_buffer_failure;
+ /** Number of pkt dropped */
+ t_u32 num_pkt_dropped;
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of consecutive association command failures */
+ t_u32 num_cons_assoc_failure;
+
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+ /** Number of no free command node */
+ t_u16 num_no_cmd_node;
+} wlan_dbg;
+
+/** Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS {
+ WlanHardwareStatusReady,
+ WlanHardwareStatusGetHwSpec,
+ WlanHardwareStatusGetHwSpecdone,
+ WlanHardwareStatusInitializing,
+ WlanHardwareStatusInitdone,
+ WlanHardwareStatusReset,
+ WlanHardwareStatusClosing,
+ WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE {
+ Wlan802_11PowerModeCAM,
+ Wlan802_11PowerModePSP
+} WLAN_802_11_POWER_MODE;
+
+/** tx param */
+typedef struct _mlan_tx_param {
+ /** next packet length */
+ t_u32 next_pkt_len;
+} mlan_tx_param;
+
+/** PS_STATE */
+typedef enum _PS_STATE {
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP_CFM,
+ PS_STATE_SLEEP
+} PS_STATE;
+
+/** Minimum flush timer for win size of 1 is 50 ms */
+#define MIN_FLUSH_TIMER_MS 50
+/** Minimum flush timer for win size of 1 is 15 ms */
+#define MIN_FLUSH_TIMER_15_MS 15
+
+/** Tx BA stream table */
+typedef struct _TxBAStreamTbl TxBAStreamTbl;
+
+/** Add BA parameter data structure */
+typedef struct {
+ /** Window size for initiator */
+ t_u32 tx_win_size;
+ /** Window size for receiver */
+ t_u32 rx_win_size;
+ /** Block ack timeout */
+ t_u32 timeout;
+ /** amsdu support for ADDBA request */
+ t_u8 tx_amsdu;
+ /** amsdu support for ADDBA response */
+ t_u8 rx_amsdu;
+} add_ba_param_t;
+
+/** Tx aggregation data structure */
+typedef struct _txAggr_t {
+ /** AMPDU user */
+ t_u8 ampdu_user;
+ /** AMPDU AP */
+ t_u8 ampdu_ap;
+ /** AMSDU */
+ t_u8 amsdu;
+} tx_aggr_t;
+
+/** del ba threshold */
+#define DEL_BA_THRESHOLD 10
+/** BA stream status */
+typedef enum _baStatus_e {
+ BA_STREAM_NOT_SETUP = 0,
+ BA_STREAM_SETUP_INPROGRESS,
+ BA_STREAM_SETUP_COMPLETE
+} baStatus_e;
+
+/** RA list table */
+typedef struct _raListTbl raListTbl, *praListTbl;
+
+/** RA list table */
+struct _raListTbl {
+ /** Pointer to previous node */
+ raListTbl *pprev;
+ /** Pointer to next node */
+ raListTbl *pnext;
+ /** Buffer list head */
+ mlan_list_head buf_head;
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** total packets in RA list */
+ t_u16 total_pkts;
+ /** packets received */
+ t_u16 packet_count;
+ /** packet count threshold to setup BA */
+ t_u8 ba_packet_threshold;
+ /** is 11n enabled */
+ t_u8 is_11n_enabled;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** BA stream status */
+ baStatus_e ba_status;
+ /** del ba count */
+ t_u8 del_ba_count;
+ /** amsdu in ampdu flag */
+ t_u8 amsdu_in_ampdu;
+ /** tx_pause flag */
+ t_u8 tx_pause;
+};
+
+/** TID table */
+typedef struct _tidTbl {
+ /** RA list head */
+ mlan_list_head ra_list;
+ /** Current RA list */
+ raListTbl *ra_list_curr;
+} tid_tbl_t;
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY 7
+/** Highest priority TID */
+#define HIGH_PRIO_TID 7
+/** Lowest priority TID */
+#define LOW_PRIO_TID 0
+/** No packet priority (< lowest) */
+#define NO_PKT_PRIO_TID -1
+
+/** Max driver packet delay in msec */
+#define WMM_DRV_DELAY_MAX 510
+
+/** Struct of WMM DESC */
+typedef struct _wmm_desc {
+ /** TID table */
+ tid_tbl_t tid_tbl_ptr[MAX_NUM_TID];
+ /** Packets out */
+ t_u32 packets_out[MAX_NUM_TID];
+ /** Packets queued */
+ t_u32 pkts_queued[MAX_NUM_TID];
+ /** Packets paused */
+ t_u32 pkts_paused[MAX_NUM_TID];
+ /** Spin lock to protect ra_list */
+ t_void *ra_list_spinlock;
+
+ /** AC status */
+ WmmAcStatus_t ac_status[MAX_AC_QUEUES];
+ /** AC downgraded values */
+ mlan_wmm_ac_e ac_down_graded_vals[MAX_AC_QUEUES];
+
+ /** Max driver packet delay sent to the firmware for expiry eval */
+ t_u32 drv_pkt_delay_max;
+
+ /** WMM queue priority table */
+ t_u8 queue_priority[MAX_AC_QUEUES];
+ /** User priority packet transmission control */
+ t_u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
+
+ /** Number of transmit packets queued */
+ mlan_scalar tx_pkts_queued;
+ /** Tracks highest priority with a packet queued */
+ mlan_scalar highest_queued_prio;
+} wmm_desc_t;
+
+/** Security structure */
+typedef struct _wlan_802_11_security_t {
+ /** WPA enabled flag */
+ t_u8 wpa_enabled;
+ /** E-Supplicant enabled flag */
+ t_u8 ewpa_enabled;
+ /** WPA2 enabled flag */
+ t_u8 wpa2_enabled;
+ /** WAPI enabled flag */
+ t_u8 wapi_enabled;
+ /** WAPI key on flag */
+ t_u8 wapi_key_on;
+ /** WEP status */
+ WLAN_802_11_WEP_STATUS wep_status;
+ /** Authentication mode */
+ t_u32 authentication_mode;
+ /** Encryption mode */
+ t_u32 encryption_mode;
+ /** Hotspot OSEN enabled */
+ t_u8 osen_enabled;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct {
+ /** BSS descriptor */
+ BSSDescriptor_t bss_descriptor;
+ /** WMM enable? */
+ t_u8 wmm_enabled;
+ /** Uapsd enable?*/
+ t_u8 wmm_uapsd_enabled;
+ /** Band */
+ t_u8 band;
+ /** Number of rates supported */
+ t_u32 num_of_rates;
+ /** Supported rates*/
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+ /** Host MLME flag*/
+ t_u8 host_mlme;
+ t_u8 use_mfp;
+} current_bss_params_t;
+
+/** Sleep_params */
+typedef struct _sleep_params_t {
+ /** Sleep parameter error */
+ t_u16 sp_error;
+ /** Sleep parameter offset */
+ t_u16 sp_offset;
+ /** Sleep parameter stable time */
+ t_u16 sp_stable_time;
+ /** Sleep parameter calibration control */
+ t_u8 sp_cal_control;
+ /** Sleep parameter external sleep clock */
+ t_u8 sp_ext_sleep_clk;
+ /** Sleep parameter reserved */
+ t_u16 sp_reserved;
+} sleep_params_t;
+
+/** Sleep_period */
+typedef struct sleep_period_t {
+ /** Sleep period */
+ t_u16 period;
+ /** Reserved */
+ t_u16 reserved;
+} sleep_period_t;
+
+/** mrvl_wep_key_t */
+typedef struct _mrvl_wep_key_t {
+ /** Length */
+ t_u32 length;
+ /** WEP key index */
+ t_u32 key_index;
+ /** WEP key length */
+ t_u32 key_length;
+ /** WEP keys */
+ t_u8 key_material[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} mrvl_wep_key_t;
+
+/** Maximum number of region channel */
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Region-band mapping table */
+typedef struct _region_chan_t {
+ /** TRUE if this entry is valid */
+ t_u8 valid;
+ /** Region code for US, Japan ... */
+ t_u8 region;
+ /** Band B/G/A, used for BAND_CONFIG cmd */
+ t_u8 band;
+ /** Actual No. of elements in the array below */
+ t_u8 num_cfp;
+ /** chan-freq-txpower mapping table */
+ chan_freq_power_t *pcfp;
+} region_chan_t;
+
+/** State of 11d */
+typedef enum _state_11d_t {
+ DISABLE_11D = 0,
+ ENABLE_11D = 1,
+} state_11d_t;
+
+#define DEFAULT_11D_STATE DISABLE_11D
+
+/** Domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg {
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state {
+ /** True for enabling 11D */
+ state_11d_t enable_11d;
+ /** True for user enabling 11D */
+ state_11d_t user_enable_11d;
+} wlan_802_11d_state_t;
+
+/** 802.11h State information kept in the 'mlan_private' driver structure */
+typedef struct {
+ /** Indicate 11h is enabled from host */
+ t_bool is_11h_host;
+ /** Indicates whether 11h is enabled in the driver */
+ t_bool is_11h_enabled;
+ /** Indicates whether 11h is active in the firmware */
+ t_bool is_11h_active;
+ /** Master device using automatic channel select */
+ t_bool adhoc_auto_sel_chan;
+ /** Set when driver receives a STOP TX event from fw */
+ t_bool tx_disabled;
+ /** Channel that ChanSwAnn was received for, non-zero = active */
+ t_u8 dfs_slave_csa_chan;
+ /** Expiry for above variable, seconds in system time */
+ t_u32 dfs_slave_csa_expire_at_sec;
+} wlan_11h_interface_state_t;
+
+#if defined(UAP_SUPPORT)
+/** UAP get info callback state kept in the 'mlan_private' driver structure */
+typedef struct {
+ /** UAP internal callback after wlan_uap_get_channel */
+ /** (parameter is really pointer to mlan_private) */
+ mlan_status (*get_chan_callback)(t_void *);
+ /** current ioctl_req (to be completed in callback) */
+ pmlan_ioctl_req pioctl_req_curr;
+ /** band config from MrvlIEtypes_channel_band_t */
+ Band_Config_t bandcfg;
+ /** channel from MrvlIEtypes_channel_band_t */
+ t_u8 channel;
+ /** beacon period (in msec) from MrvlIEtypes_beacon_period_t */
+ t_u16 beacon_period;
+ /** dtim period (no unit) from MrvlIEtypes_dtim_period_t */
+ t_u8 dtim_period;
+} wlan_uap_get_info_cb_t;
+#endif
+
+/** Data structure for WPS information */
+typedef struct {
+ /** WPS IE */
+ IEEEtypes_VendorSpecific_t wps_ie;
+ /** Session enable flag */
+ t_u8 session_enable;
+} wps_t;
+
+/** mlan_operations data structure */
+typedef struct _mlan_operations {
+ /** cmd init handler */
+ mlan_status (*init_cmd)(t_void *priv, t_u8 first_bss);
+ /** ioctl handler */
+ mlan_status (*ioctl)(t_void *adapter, pmlan_ioctl_req pioctl_req);
+ /** cmd handler */
+ mlan_status (*prepare_cmd)(t_void *priv, t_u16 cmd_no, t_u16 cmd_action,
+ t_u32 cmd_oid, t_void *pioctl_buf,
+ t_void *pdata_buf, t_void *pcmd_buf);
+ /** cmdresp handler */
+ mlan_status (*process_cmdresp)(t_void *priv, t_u16 cmdresp_no,
+ t_void *pcmd_buf, t_void *pioctl);
+ /** rx handler */
+ mlan_status (*process_rx_packet)(t_void *adapter, pmlan_buffer pmbuf);
+ /** event handler */
+ mlan_status (*process_event)(t_void *priv);
+ /** txpd handler */
+ t_void *(*process_txpd)(t_void *priv, pmlan_buffer pmbuf);
+ /** BSS role */
+ mlan_bss_role bss_role;
+} mlan_operations, *pmlan_operations;
+
+/** Private structure for MLAN */
+typedef struct _mlan_private {
+ /** Pointer to mlan_adapter */
+ struct _mlan_adapter *adapter;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** BSS virtual flag */
+ t_u8 bss_virtual;
+ /** BSS Priority */
+ t_u8 bss_priority;
+ /** BSS number */
+ t_u8 bss_num;
+ /** Frame type */
+ t_u8 frame_type;
+ /** MAC address information */
+ t_u8 curr_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Media connection status */
+ t_bool media_connected;
+
+ /** Current packet filter */
+ t_u32 curr_pkt_filter;
+ /** Infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Tx packet control */
+ t_u32 pkt_tx_ctrl;
+
+ /** Tx power level */
+ t_s16 tx_power_level;
+ /** Maximum Tx power level */
+ t_s8 max_tx_power_level;
+ /** Minimum Tx power level */
+ t_s8 min_tx_power_level;
+ /** Tx rate */
+ t_u8 tx_rate;
+ t_u8 tx_rate_info;
+ /*HE tx tone mode and DCM info*/
+ t_u8 ext_tx_rate_info;
+ /*HE rx tone mode and DCM info*/
+ t_u8 rxpd_rx_info;
+ /** rxpd_htinfo */
+ t_u8 rxpd_rate_info;
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** amsdu disable flag */
+ t_u8 amsdu_disable;
+ /** 802.11n Device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11n_dev_cap_bg;
+ /** 802.11n Device Capabilities for 5GHz */
+ t_u32 usr_dot_11n_dev_cap_a;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u8 usr_dev_mcs_support;
+#ifdef UAP_SUPPORT
+ /** UAP 11n flag */
+ t_u8 is_11n_enabled;
+#endif /* UAP_SUPPORT */
+ /** UAP 11ac flag */
+ t_u8 is_11ac_enabled;
+ /** UAP 11ax flag */
+ t_u8 is_11ax_enabled;
+ /** tx vht_info */
+ t_u8 tx_vhtinfo;
+ /** rxpd_vhtinfo */
+ t_u8 rxpd_vhtinfo;
+ /** 802.11ac Device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11ac_dev_cap_bg;
+ /** 802.11ac Device Capabilities for 5GHz */
+ t_u32 usr_dot_11ac_dev_cap_a;
+ /** MIMO abstraction of MCSs supported by device */
+ t_u32 usr_dot_11ac_mcs_support;
+ /** user dot 11ac_BW */
+ t_u8 usr_dot_11ac_bw;
+ /** user dot 11ac_opermode_BW */
+ t_u8 usr_dot_11ac_opermode_bw;
+ /** user dot 11ac_opermode_nss */
+ t_u8 usr_dot_11ac_opermode_nss;
+ /** length of hw he capability */
+ t_u8 user_hecap_len;
+ /** user configured 802.11ax HE capability */
+ t_u8 user_he_cap[54];
+ /** length of hw he capability */
+ t_u8 user_2g_hecap_len;
+ /** user configured 802.11ax HE capability */
+ t_u8 user_2g_he_cap[54];
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#ifdef UAP_SUPPORT
+ /** packet forward control */
+ t_u8 pkt_fwd;
+#endif
+ /** TX beamforming capability */
+ t_u32 tx_bf_cap;
+ /** Rx PD rate */
+ t_u8 rxpd_rate;
+ /** Bitmap rates */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** Data rate */
+ t_u32 data_rate;
+ /** Automatic data rate flag */
+ t_u8 is_data_rate_auto;
+ /** Factor for calculating beacon average */
+ t_u16 bcn_avg_factor;
+ /** Factor for calculating data average */
+ t_u16 data_avg_factor;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** Last data RSSI */
+ t_s16 data_rssi_last;
+ /** Last data Noise Floor */
+ t_s16 data_nf_last;
+ /** Average data RSSI */
+ t_s16 data_rssi_avg;
+ /** Averag data Noise Floor */
+ t_s16 data_nf_avg;
+ /** Last beacon RSSI */
+ t_s16 bcn_rssi_last;
+ /** Last beacon Noise Floor */
+ t_s16 bcn_nf_last;
+ /** Average beacon RSSI */
+ t_s16 bcn_rssi_avg;
+ /** Average beacon Noise Floor */
+ t_s16 bcn_nf_avg;
+ /** Attempted BSS descriptor */
+ BSSDescriptor_t *pattempted_bss_desc;
+
+ /** GTK rekey data*/
+ mlan_ds_misc_gtk_rekey_data gtk_rekey;
+
+ /** Current SSID/BSSID related parameters*/
+ current_bss_params_t curr_bss_params;
+ /** current channel flags */
+ t_u32 curr_chan_flags;
+ /** User selected bands */
+ t_u16 config_bands;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+ /** Listen interval */
+ t_u16 listen_interval;
+ /** ATIM window */
+ t_u16 atim_window;
+
+ /** AdHoc channel */
+ t_u8 adhoc_channel;
+ /** AdHoc link sensed flag */
+ t_u8 adhoc_is_link_sensed;
+ /** AdHoc operating state */
+ t_u8 adhoc_state;
+#if defined(STA_SUPPORT)
+ /** AdHoc operating state backup */
+ t_u8 adhoc_state_prev;
+ /** AdHoc previous ssid used for Start */
+ mlan_802_11_ssid adhoc_last_start_ssid;
+#endif
+ /** FSM variable for 11d support */
+ wlan_802_11d_state_t state_11d;
+ /** FSM variable for 11h support */
+ wlan_11h_interface_state_t intf_state_11h;
+#ifdef UAP_SUPPORT
+ /** Whether UAP interface has started */
+ t_bool uap_bss_started;
+ /** Whether UAP interface start from hostapd */
+ t_bool uap_host_based;
+ /**UAP operating channel*/
+ t_u8 uap_channel;
+ /** state variable for UAP Get Info callback */
+ wlan_uap_get_info_cb_t uap_state_chan_cb;
+#endif /* UAP_SUPPORT */
+
+ /** Security related */
+ /** Encryption parameter */
+ wlan_802_11_security_t sec_info;
+ /** WEP keys */
+ mrvl_wep_key_t wep_key[MRVL_NUM_WEP_KEY];
+ /** Current WEP key index */
+ t_u16 wep_key_curr_index;
+ /** EWPA query 0: disable, 1: enable */
+ t_u8 ewpa_query;
+ /** Encryption Key*/
+ t_u8 wpa_ie[256];
+ /** WPA IE length */
+ t_u8 wpa_ie_len;
+ /** GTK set flag */
+ t_u8 wpa_is_gtk_set;
+ /** AES key material */
+ mlan_ds_encrypt_key aes_key;
+#if defined(STA_SUPPORT)
+ /* Mgmt Frame Protection config */
+ mlan_ds_misc_pmfcfg pmfcfg;
+#endif
+ /** WAPI IE */
+ t_u8 wapi_ie[256];
+ /** WAPI IE length */
+ t_u8 wapi_ie_len;
+ /** OSEN IE */
+ t_u8 osen_ie[256];
+ /** OSEN IE length */
+ t_u8 osen_ie_len;
+ /** Pointer to the station table */
+ mlan_list_head sta_list;
+
+ /** MGMT IE */
+ custom_ie mgmt_ie[MAX_MGMT_IE_INDEX];
+ /** mgmt frame passthru mask */
+ t_u32 mgmt_frame_passthru_mask;
+ /** WMM required */
+ t_u8 wmm_required;
+ /** WMM enabled */
+ t_u8 wmm_enabled;
+ /** WMM qos info */
+ t_u8 wmm_qosinfo;
+ /** WMM related variable*/
+ wmm_desc_t wmm;
+
+ /** Pointer to the Transmit BA stream table*/
+ mlan_list_head tx_ba_stream_tbl_ptr;
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ tx_aggr_t aggr_prio_tbl[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 ibss_ampdu[MAX_NUM_TID];
+ /** Pointer to the priorities for AMSDU/AMPDU table*/
+ t_u8 ibss_addba_reject[MAX_NUM_TID];
+ /** Struct to store ADDBA parameters */
+ add_ba_param_t add_ba_param;
+ /** user rx_win_size */
+ t_u32 user_rxwinsize;
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** Pointer to the Receive Reordering table*/
+ mlan_list_head rx_reorder_tbl_ptr;
+ /** Lock for Rx packets */
+ t_void *rx_pkt_lock;
+
+#ifdef STA_SUPPORT
+ /** Buffer to store the association response for application retrieval
+ */
+ t_u8 assoc_rsp_buf[MRVDRV_ASSOC_RSP_BUF_SIZE];
+ /** Length of the data stored in assoc_rsp_buf */
+ t_u32 assoc_rsp_size;
+
+ /** Generic IEEE IEs passed from the application to be inserted into the
+ * association request to firmware
+ */
+ t_u8 gen_ie_buf[MRVDRV_GENIE_BUF_SIZE];
+ /** Length of the data stored in gen_ie_buf */
+ t_u8 gen_ie_buf_len;
+
+ /** disconnect reason code*/
+ t_u16 disconnect_reason_code;
+ t_u8 *pcurr_bcn_buf;
+ t_u32 curr_bcn_size;
+ t_void *curr_bcn_buf_lock;
+
+ /** WPS */
+ wps_t wps;
+#endif /* STA_SUPPORT */
+
+ /** function table */
+ mlan_operations ops;
+ /** tx pause flag */
+ t_u8 tx_pause;
+ /** Port Control mode */
+ t_u8 port_ctrl_mode;
+
+ /** Port open flag */
+ t_u8 port_open;
+
+ /** Port open flag state at time of association attempt */
+ t_u8 prior_port_status;
+ /** Bypass TX queue */
+ mlan_list_head bypass_txq;
+ /** IP address operation */
+ t_u32 op_code;
+ /** IP address */
+ t_u8 ip_addr[IPADDR_LEN];
+ t_u32 hotspot_cfg;
+#ifdef STA_SUPPORT
+ ExtCap_t ext_cap;
+ ExtCap_t def_ext_cap;
+#endif
+ /** interface header len */
+ t_u8 intf_hr_len;
+#ifdef USB
+ /** USB data port */
+ t_u32 port;
+#endif
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ t_void *psapriv;
+#endif
+ /** rx per packet info */
+ t_u8 rx_pkt_info;
+ /** received amsdu count*/
+ t_u32 amsdu_rx_cnt;
+ /** received msdu count in amsdu*/
+ t_u32 msdu_in_rx_amsdu_cnt;
+ /** tx amsdu count*/
+ t_u32 amsdu_tx_cnt;
+ /** tx msdu count in amsdu*/
+ t_u32 msdu_in_tx_amsdu_cnt;
+} mlan_private, *pmlan_private;
+
+typedef struct _assoc_logger {
+ /** vendor specific */
+ t_u8 oui[3];
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ t_s32 rssi;
+ t_u32 channel;
+} assoc_logger_data;
+
+/** Tx BA stream table */
+struct _TxBAStreamTbl {
+ /** TxBAStreamTbl previous node */
+ TxBAStreamTbl *pprev;
+ /** TxBAStreamTbl next node */
+ TxBAStreamTbl *pnext;
+ /** TID */
+ int tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+};
+
+/** RX reorder table */
+typedef struct _RxReorderTbl RxReorderTbl;
+
+typedef struct {
+ /** Timer for flushing */
+ t_void *timer;
+ /** Timer set flag */
+ t_u8 timer_is_set;
+ /** RxReorderTbl ptr */
+ RxReorderTbl *ptr;
+ /** Priv pointer */
+ mlan_private *priv;
+} reorder_tmr_cnxt_t;
+
+/** RX reorder table */
+struct _RxReorderTbl {
+ /** RxReorderTbl previous node */
+ RxReorderTbl *pprev;
+ /** RxReorderTbl next node */
+ RxReorderTbl *pnext;
+ /** TID */
+ int tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ int start_win;
+ /** last_seq */
+ int last_seq;
+ /** Window size */
+ int win_size;
+ /** Pointer to pointer to RxReorderTbl */
+ t_void **rx_reorder_ptr;
+ /** Timer context */
+ reorder_tmr_cnxt_t timer_context;
+ /** BA stream status */
+ baStatus_e ba_status;
+ t_u8 amsdu;
+ /** no packet drop flag for rx_reorder_tbl */
+ t_u8 force_no_drop;
+ /** flag for check start win */
+ t_u8 check_start_win;
+ /** pkt receive after BA setup */
+ t_u8 pkt_count;
+ /** flush data flag */
+ t_u8 flush_data;
+};
+
+/** BSS priority node */
+typedef struct _mlan_bssprio_node mlan_bssprio_node;
+
+/** BSS priority node */
+struct _mlan_bssprio_node {
+ /** Pointer to previous node */
+ mlan_bssprio_node *pprev;
+ /** Pointer to next node */
+ mlan_bssprio_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+};
+
+/** BSS priority table */
+typedef struct _mlan_bssprio_tbl mlan_bssprio_tbl;
+
+/** BSS priority table */
+struct _mlan_bssprio_tbl {
+ /** BSS priority list head */
+ mlan_list_head bssprio_head;
+ /** Current priority node */
+ mlan_bssprio_node *bssprio_cur;
+};
+
+/** cmd_ctrl_node */
+typedef struct _cmd_ctrl_node cmd_ctrl_node;
+
+/** _cmd_ctrl_node */
+struct _cmd_ctrl_node {
+ /** Pointer to previous node */
+ cmd_ctrl_node *pprev;
+ /** Pointer to next node */
+ cmd_ctrl_node *pnext;
+ /** Pointer to priv */
+ pmlan_private priv;
+ /** Command number */
+ t_u32 cmd_no;
+ /** Command flag */
+ t_u32 cmd_flag;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *cmdbuf;
+ /** Pointer to mlan_buffer */
+ mlan_buffer *respbuf;
+ /** Command parameter */
+ t_void *pdata_buf;
+ /** Pointer to mlan_ioctl_req if command is from IOCTL */
+ t_void *pioctl_buf;
+#if defined(PCIE) || defined(SDIO)
+ /** pre_allocated mlan_buffer for cmd */
+ mlan_buffer *pmbuf;
+#endif
+};
+
+/** station node */
+typedef struct _sta_node sta_node, *psta_node;
+
+/** station node*/
+struct _sta_node {
+ /** previous node */
+ sta_node *pprev;
+ /** next node */
+ sta_node *pnext;
+ /** station mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wmm flag */
+ t_u8 is_wmm_enabled;
+ /** 11n flag */
+ t_u8 is_11n_enabled;
+ /** AMPDU STA */
+ t_u8 ampdu_sta[MAX_NUM_TID];
+ /** last rx_seq */
+ t_u16 rx_seq[MAX_NUM_TID];
+ /** max amsdu size */
+ t_u16 max_amsdu;
+ /** HT cap */
+ IEEEtypes_HTCap_t HTcap;
+ /** 11ac flag */
+ t_u8 is_11ac_enabled;
+ /** UAP 11ax flag */
+ t_u8 is_11ax_enabled;
+ /** SNR */
+ t_s8 snr;
+ /** Noise Floor */
+ t_s8 nf;
+ /** peer capability */
+ t_u16 capability;
+ /** wapi key on off flag */
+ t_u8 wapi_key_on;
+ /** tx pause status */
+ t_u8 tx_pause;
+ /** station band mode */
+ t_u16 bandmode;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ t_void *cm_connectioninfo;
+#endif
+ sta_stats stats;
+};
+
+/** 802.11h State information kept in the 'mlan_adapter' driver structure */
+typedef struct {
+ /** Min TX Power capability sent to FW for 11h use and fw power control
+ */
+ t_s8 min_tx_power_capability;
+ /** Max TX Power capability sent to FW for 11h use and fw power control
+ */
+ t_s8 max_tx_power_capability;
+ /** User provisioned local power constraint sent in association requests
+ */
+ t_s8 usr_def_power_constraint;
+ /** Received CHANNEL_SWITCH_ANN event */
+ t_bool recvd_chanswann_event;
+ /** Indicates an interface wants to enable master radar detection */
+ t_bool master_radar_det_enable_pending;
+ /** Indicates an interface wants to enable slave radar detection */
+ t_bool slave_radar_det_enable_pending;
+ /** Indicates whether master radar detection active in the firmware */
+ t_bool is_master_radar_det_active;
+ /** Indicates whether slave radar detection active in the firmware */
+ t_bool is_slave_radar_det_active;
+ /** Quiet IE */
+ IEEEtypes_Quiet_t quiet_ie;
+} wlan_11h_device_state_t;
+
+/** Enumeration for DFS Timestamp represents field */
+enum _dfs_timestamp_repr_e {
+ /** Ignore entry */
+ DFS_TS_REPR_NOT_IN_USE = 0,
+ /** NOP (Non-Occupancy Period) start time */
+ DFS_TS_REPR_NOP_START = 1,
+ /** CAC (Channel Availability Check) completion time */
+ DFS_TS_REPR_CAC_COMPLETION
+};
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+typedef struct _wlan_dfs_timestamp_t wlan_dfs_timestamp_t;
+
+/** DFS Timestamp type used for marking NOP/CAC events */
+struct _wlan_dfs_timestamp_t {
+ /** Pointer to previous node */
+ wlan_dfs_timestamp_t *pprev;
+ /** Pointer to next node */
+ wlan_dfs_timestamp_t *pnext;
+ /** WLAN Channel number */
+ t_u8 channel;
+ /** What this timestamp represents */
+ t_u8 represents;
+ /** reserved field */
+ t_u16 reserved;
+ /** timestamp - seconds */
+ t_u32 ts_sec;
+ /** timestamp - microseconds */
+ t_u32 ts_usec;
+};
+
+/** DFS State information kept in the 'mlan_adapter' driver structure */
+typedef struct {
+ /** Indicates whether DFS channel check is occurring in firmware */
+ t_bool dfs_check_pending;
+ /** Indicates whether DFS channel check found radar */
+ t_bool dfs_radar_found;
+ /** Channel radar is being checked on. BAND_A is assumed. */
+ t_u8 dfs_check_channel;
+ /** point to the priv which start the DFS check */
+ t_void *dfs_check_priv;
+ /** Timestamp when we got last report,
+ * to determine if data is old or not.
+ */
+ t_u32 dfs_report_time_sec;
+ /** List for holding dfs_timestamps for NOP/CAC events */
+ mlan_list_head dfs_ts_head;
+} wlan_dfs_device_state_t;
+
+/** Enumeration for mlan_ds_11h_radar_det_hndlg stages */
+enum _mlan_ds_11h_rdh_stages {
+ RDH_OFF = 0,
+ RDH_CHK_INTFS = 1,
+ RDH_STOP_TRAFFIC,
+ RDH_GET_INFO_CHANNEL,
+ RDH_GET_INFO_BEACON_DTIM,
+ RDH_SET_CUSTOM_IE,
+ RDH_REM_CUSTOM_IE,
+ RDH_STOP_INTFS,
+ RDH_SET_NEW_CHANNEL,
+ RDH_RESTART_INTFS,
+ RDH_RESTART_TRAFFIC
+};
+
+/** State info for Radar Detected Handling kept in 'mlan_adapter' */
+typedef struct {
+ /** Stage (of Operation) */
+ t_u8 stage;
+ /** Number of interfaces to handle */
+ t_u8 priv_list_count;
+ /** Index of interface in process (used by some stages) */
+ t_u8 priv_curr_idx;
+ /** Current Channel (to leave) */
+ t_u8 curr_channel;
+ /** New Channel (to switch to) */
+ t_u8 new_channel;
+ /** UAP band_config */
+ Band_Config_t uap_band_cfg;
+ /** BEACON*DTIM period (in msec; max of STA/UAP) */
+ t_u16 max_bcn_dtim_ms;
+ /** tx block flag */
+ t_u8 tx_block;
+ /** List of interfaces to handle */
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+} wlan_radar_det_hndlg_state_t;
+
+/** DFS/RDH testing exception settings kept in 'mlan_adapter' */
+typedef struct {
+ /** user-configured CAC period (in msec) */
+ t_u32 user_cac_period_msec;
+ /** user-configured NOP period (in sec) */
+ t_u16 user_nop_period_sec;
+ /** user-configured skip channel change on radar */
+ t_bool no_channel_change_on_radar;
+ /** user-configured new channel to change to on radar */
+ t_u8 fixed_new_channel_on_radar;
+ /** user-configured cac restart */
+ t_u8 cac_restart;
+ /** cac channel */
+ t_u8 chan;
+ /** band cfg */
+ Band_Config_t bandcfg;
+ /** cac time */
+ t_u32 millisec_dwell_time;
+} wlan_dfs_testing_settings_t;
+
+/**
+ * @brief Driver measurement state held in 'mlan_adapter' structure
+ *
+ * Used to record a measurement request that the driver is pending on
+ * the result (received measurement report).
+ */
+typedef struct {
+ /**
+ * Dialog token of a pending measurement request/report. Used to
+ * block execution while waiting for the specific dialog token
+ */
+ t_u8 meas_rpt_pend_on;
+
+ /**
+ * Measurement report received from the firmware that we were pending on
+ */
+ HostCmd_DS_MEASUREMENT_REPORT meas_rpt_returned;
+
+} wlan_meas_state_t;
+
+#ifdef SDIO
+/**
+ * @brief Link buffer into aggregate head buffer
+ *
+ * @param pmbuf_aggr Pointer to aggregation buffer
+ * @param pmbuf Pointer to buffer to copy
+ */
+static inline t_void wlan_link_buf_to_aggr(pmlan_buffer pmbuf_aggr,
+ pmlan_buffer pmbuf)
+{
+ /* link new buf at end of list */
+ pmbuf->pnext = pmbuf_aggr;
+ pmbuf->pprev = pmbuf_aggr->pprev;
+ pmbuf->pparent = pmbuf_aggr;
+ pmbuf_aggr->pprev->pnext = pmbuf;
+ pmbuf_aggr->pprev = pmbuf;
+ pmbuf_aggr->use_count++;
+}
+
+/** data structure for SDIO MPA TX */
+typedef struct _sdio_mpa_tx {
+ /** allocated buf for tx aggreation */
+ t_u8 *head_ptr;
+ /** multiport tx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport tx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport tx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport tx aggregation ports */
+ t_u32 ports;
+ /** multiport tx aggregation starting port */
+ t_u16 start_port;
+ /** multiport tx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport tx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport tx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+ /** multiport write info */
+ t_u16 mp_wr_info[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** multiport rx aggregation mbuf array */
+ pmlan_buffer mbuf_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+} sdio_mpa_tx;
+
+/** data structure for SDIO MPA RX */
+typedef struct _sdio_mpa_rx {
+ /** allocated buf for rx aggreation */
+ t_u8 *head_ptr;
+ /** multiport rx aggregation buffer pointer */
+ t_u8 *buf;
+ /** multiport rx aggregation buffer length */
+ t_u32 buf_len;
+ /** multiport rx aggregation packet count */
+ t_u32 pkt_cnt;
+ /** multiport rx aggregation ports */
+ t_u32 ports;
+ /** multiport rx aggregation starting port */
+ t_u16 start_port;
+
+ /** multiport rx aggregation mbuf array */
+ pmlan_buffer mbuf_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** multiport rx aggregation pkt len array */
+ t_u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+
+ /** multiport rx aggregation enable/disable flag */
+ t_u8 enabled;
+ /** multiport rx aggregation buffer size */
+ t_u32 buf_size;
+ /** multiport rx aggregation pkt aggr limit */
+ t_u32 pkt_aggr_limit;
+} sdio_mpa_rx;
+#endif
+
+#ifdef USB
+/** data structure for USB Rx Deaggregation */
+typedef struct _usb_rx_deaggr_params {
+ /** Rx aggregation control */
+ usb_aggr_ctrl aggr_ctrl;
+} usb_rx_deaggr_params;
+
+#define MAX_USB_TX_PORT_NUM 1
+/** data structure for USB Tx Aggregation */
+typedef struct _usb_tx_aggr_params {
+ /** Tx aggregation control */
+ usb_aggr_ctrl aggr_ctrl;
+ /** allocated pmbuf for tx aggreation */
+ pmlan_buffer pmbuf_aggr;
+ /** packet len used in pmbuf_aggr */
+ t_u32 aggr_len;
+ /** usb_tx_aggr timer */
+ t_void *paggr_hold_timer;
+ /** usb_tx_aggr timer set flag */
+ t_u8 aggr_hold_timer_is_set;
+ /** Timeout duration in milliseconds to wait for aggregation */
+ t_u32 hold_timeout_msec;
+ /** lock for transmission */
+ t_void *paggr_lock;
+ /** port for data transmission */
+ t_u32 port;
+ /** pointer to moal_adatper structure */
+ t_void *phandle;
+} usb_tx_aggr_params, *pusb_tx_aggr_params;
+#endif
+
+/** Type definition of mef_entry*/
+typedef struct _mef_cfg {
+ /** criteria*/
+ t_u32 criteria;
+ /** entry num*/
+ t_u16 entry_num;
+ /** entry pointer*/
+ mef_entry_t *pentry;
+} mef_cfg;
+
+/** Type definition of mef_entry*/
+typedef struct _mef_entry {
+ /** Num for wowlan entry*/
+ int num_wowlan_entry;
+ /** Num for IPv6 neighbor solicitation message offload */
+ int num_ipv6_ns_offload;
+
+ /** criteria*/
+ t_u32 criteria;
+ /** MEF CFG Array to store etted_entry_bitmap;
+ * Caution: 0-3 is for NVIDIA WHITE/BLACK list entries
+ * Caution: 4 is for NVIDIA ping entry
+ * Caution: 5 is for Auto Arp Entry
+ * Caution: 6 is for wowlan Entry
+ * Caution: 7 is for IPv6 Neighbor Solicitation offload Entry
+ */
+ mef_entry_t entry[MAX_NUM_ENTRIES];
+} mef_entry;
+
+/** vdll_dnld_ctrl structure */
+typedef struct _vdll_dnld_ctrl {
+ /** pending VDLL block */
+ t_u8 *pending_block;
+ /* pending VDLL block len */
+ t_u16 pending_block_len;
+ /** memory for VDLL fw image */
+ t_u8 *vdll_mem;
+ /** VDLL fw image len */
+ t_u32 vdll_len;
+#if defined(SDIO) || defined(PCIE)
+ /** mlan_buffer for VDLL download */
+ mlan_buffer *cmd_buf;
+#endif
+} vdll_dnld_ctrl, *pvdll_dnld_ctrl;
+
+/** mlan_init_para structure */
+typedef struct _mlan_init_para {
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+#ifdef SDIO
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+ /** 802.11H DFS Master Radar Detect */
+ t_u32 dfs_master_radar_det_en;
+ /** 802.11H DFS Slave Radar Detect */
+ t_u32 dfs_slave_radar_det_en;
+ /** dev cap mask */
+ t_u32 dev_cap_mask;
+ /** oob independent reset mode */
+ t_u32 indrstcfg;
+ /** fw region */
+ t_bool fw_region;
+ /** passive to active scan */
+ t_u8 passive_to_active_scan;
+ /** uap max sta */
+ t_u8 uap_max_sta;
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+} mlan_init_para, *pmlan_init_para;
+
+#ifdef SDIO
+typedef struct _mlan_sdio_card_reg {
+ t_u8 start_rd_port;
+ t_u8 start_wr_port;
+ t_u8 base_0_reg;
+ t_u8 base_1_reg;
+ t_u8 poll_reg;
+ t_u8 host_int_enable;
+ t_u8 host_int_status;
+ t_u8 status_reg_0;
+ t_u8 status_reg_1;
+ t_u8 sdio_int_mask;
+ t_u32 data_port_mask;
+ t_u8 max_mp_regs;
+ t_u8 rd_bitmap_l;
+ t_u8 rd_bitmap_u;
+ t_u8 rd_bitmap_1l;
+ t_u8 rd_bitmap_1u;
+ t_u8 wr_bitmap_l;
+ t_u8 wr_bitmap_u;
+ t_u8 wr_bitmap_1l;
+ t_u8 wr_bitmap_1u;
+ t_u8 rd_len_p0_l;
+ t_u8 rd_len_p0_u;
+ t_u8 card_config_2_1_reg;
+ t_u8 cmd_config_0;
+ t_u8 cmd_config_1;
+ t_u8 cmd_config_2;
+ t_u8 cmd_config_3;
+ t_u8 cmd_rd_len_0;
+ t_u8 cmd_rd_len_1;
+ t_u8 cmd_rd_len_2;
+ t_u8 cmd_rd_len_3;
+ t_u8 io_port_0_reg;
+ t_u8 io_port_1_reg;
+ t_u8 io_port_2_reg;
+ t_u8 host_int_rsr_reg;
+ t_u8 host_int_mask_reg;
+ t_u8 host_int_status_reg;
+ t_u8 host_restart_reg;
+ t_u8 card_to_host_event_reg;
+ t_u8 host_interrupt_mask_reg;
+ t_u8 card_interrupt_status_reg;
+ t_u8 card_interrupt_rsr_reg;
+ t_u8 card_revision_reg;
+ t_u8 card_ocr_0_reg;
+ t_u8 card_ocr_1_reg;
+ t_u8 card_ocr_3_reg;
+ t_u8 card_config_reg;
+ t_u8 card_misc_cfg_reg;
+ t_u8 debug_0_reg;
+ t_u8 debug_1_reg;
+ t_u8 debug_2_reg;
+ t_u8 debug_3_reg;
+ t_u32 fw_reset_reg;
+ t_u8 fw_reset_val;
+ t_u8 fw_dnld_offset_0_reg;
+ t_u8 fw_dnld_offset_1_reg;
+ t_u8 fw_dnld_offset_2_reg;
+ t_u8 fw_dnld_offset_3_reg;
+ t_u8 fw_dnld_status_0_reg;
+ t_u8 fw_dnld_status_1_reg;
+ t_u8 winner_check_reg;
+} mlan_sdio_card_reg, *pmlan_sdio_card_reg;
+
+typedef struct _mlan_sdio_card {
+ const mlan_sdio_card_reg *reg;
+
+ /** IO port */
+ t_u32 ioport;
+ /** number of interrupt receive */
+ t_u32 num_of_irq;
+ /** max SDIO single port tx size */
+ t_u16 max_sp_tx_size;
+ /** max SDIO single port rx size */
+ t_u16 max_sp_rx_size;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** SDIO end port from txbufcfg */
+ t_u16 mp_end_port;
+ /** SDIO port mask calculated based on txbufcfg end port */
+ t_u32 mp_data_port_mask;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+ /** FW update port number */
+ t_u32 mp_update[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX * 2];
+ /** Invalid port update count */
+ t_u32 mp_invalid_update;
+ /** Array to store values of SDIO multiple port group registers */
+ t_u8 *mp_regs;
+ /** allocated buf to read SDIO multiple port group registers */
+ t_u8 *mp_regs_buf;
+ /** buffer to handle receive packet */
+ t_u8 *rx_buf;
+ /** allocated buf for receive */
+ t_u8 *rx_buffer;
+ /* see blk_queue_max_segment_size */
+ t_u32 max_seg_size;
+ /* see blk_queue_max_segments */
+ t_u16 max_segs;
+
+ /** data structure for SDIO MPA TX */
+ sdio_mpa_tx mpa_tx;
+ /** packet number for tx aggr */
+ t_u32 mpa_tx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** no more packets count*/
+ t_u32 mpa_sent_last_pkt;
+ /** no write_ports count */
+ t_u32 mpa_sent_no_ports;
+ /** last wr_bitmap from FW */
+ t_u32 last_recv_wr_bitmap;
+ /** last mp_wr_bitmap */
+ t_u32 last_mp_wr_bitmap[SDIO_MP_DBG_NUM];
+ /** last ports for cmd53 write data */
+ t_u32 last_mp_wr_ports[SDIO_MP_DBG_NUM];
+ /** last length for cmd53 write data */
+ t_u32 last_mp_wr_len[SDIO_MP_DBG_NUM];
+ /** length info for cmd53 write data */
+ t_u16 last_mp_wr_info[SDIO_MP_DBG_NUM * SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** last curr_wr_port */
+ t_u8 last_curr_wr_port[SDIO_MP_DBG_NUM];
+
+ /** buffer for mp debug */
+ t_u8 *mpa_buf;
+ /** length info for mp buf size */
+ t_u32 mpa_buf_size;
+
+ /** last mp_index */
+ t_u8 last_mp_index;
+
+ /** data structure for SDIO MPA RX */
+ sdio_mpa_rx mpa_rx;
+ /** packet number for tx aggr */
+ t_u32 mpa_rx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+
+ /** flag for sdio rx aggr */
+ t_bool sdio_rx_aggr_enable;
+ /** fw rx block size */
+ t_u16 sdio_rx_block_size;
+} mlan_sdio_card, *pmlan_sdio_card;
+#endif
+
+#ifdef PCIE
+/** 8 Event buffer ring */
+#define MLAN_MAX_EVT_BD 0x08
+/** 32 entry will mapping to 5*/
+#define TX_RX_NUM_DESC 5
+/** 8 entry will mapping to 3 */
+#define EVT_NUM_DESC 3
+typedef struct _mlan_pcie_card_reg {
+ /* TX buffer description rd pointer */
+ t_u32 reg_txbd_rdptr;
+ /* TX buffer description wr pointer */
+ t_u32 reg_txbd_wrptr;
+ /* RX buffer description rd pointer */
+ t_u32 reg_rxbd_rdptr;
+ /* RX buffer description wr pointer */
+ t_u32 reg_rxbd_wrptr;
+ /** evtbd rdptr register */
+ t_u32 reg_evtbd_rdptr;
+ /** evtbd wrptr register */
+ t_u32 reg_evtbd_wrptr;
+ /** host int mask register */
+ t_u16 reg_host_int_mask;
+ /** host int status mask register*/
+ t_u16 reg_host_int_status_mask;
+ /** host int status register */
+ t_u16 reg_host_int_status;
+ /** host int status clr selection */
+ t_u32 reg_host_int_clr_sel;
+ /** cpu int event register */
+ t_u16 reg_cpu_int_event;
+ /** ip revision register */
+ t_u16 reg_ip_rev;
+ /** revision id register */
+ t_u32 reg_rev_id;
+ /** driver ready register */
+ t_u16 reg_drv_ready;
+ /** cpu int status register */
+ t_u16 reg_cpu_int_status;
+ /** scratch 0 register */
+ t_u16 reg_scratch_0;
+ /** scratch 1 register */
+ t_u16 reg_scratch_1;
+ /** scratch 2 register */
+ t_u16 reg_scratch_2;
+ /** scratch 3 register */
+ t_u16 reg_scratch_3;
+ /** scratch 6 register */
+ t_u16 reg_scratch_6;
+ /** scratch 7 register */
+ t_u16 reg_scratch_7;
+ /** host interrupt mask*/
+ t_u32 host_intr_mask;
+ /** data send interrupt for host*/
+ t_u32 host_intr_dnld_done;
+ /** Data receive interrupt for host */
+ t_u32 host_intr_upld_rdy;
+ /** Command sent interrupt for host */
+ t_u32 host_intr_cmd_done;
+ /** Event ready interrupt for host */
+ t_u32 host_intr_event_rdy;
+ t_u32 host_intr_cmd_dnld;
+ /* TX/RX buffer description mask */
+ t_u32 txrx_rw_ptr_mask;
+ /* TX/RX buffer description wrap mask */
+ t_u32 txrx_rw_ptr_wrap_mask;
+ /* TX/RX buffer description indication */
+ t_u32 txrx_rw_ptr_rollover_ind;
+ /** ADMA feature */
+ t_u8 use_adma;
+ /** write to clear interrupt status flag */
+ t_u8 msi_int_wr_clr;
+} mlan_pcie_card_reg, *pmlan_pcie_card_reg;
+
+typedef struct _mlan_pcie_card {
+ const mlan_pcie_card_reg *reg;
+ /** PCIE interrupt modes 0: Legacy, 1: MSI, 2:MSI-X */
+ t_u32 pcie_int_mode;
+ /** PCIE function number */
+ t_u8 func_num;
+ /** pending num of tx ring buffer in firmware */
+ t_u8 txbd_pending;
+ /** Write pointer for TXBD ring */
+ t_u32 txbd_wrptr;
+ /** Shadow copy of TXBD read pointer */
+ t_u32 txbd_rdptr;
+ /** TXBD ring size */
+ t_u32 txbd_ring_size;
+ /** Lock for protecting the TX ring */
+ t_void *tx_ring_lock;
+ /** Virtual base address of txbd_ring */
+ t_u8 *txbd_ring_vbase;
+ /** Physical base address of txbd_ring */
+ t_u64 txbd_ring_pbase;
+ /** Ring of buffer descriptors for TX */
+ t_void *txbd_ring[MLAN_MAX_TXRX_BD];
+ /** A list of mlan_buffer objects used for data tx */
+ mlan_buffer *tx_buf_list[MLAN_MAX_TXRX_BD];
+ /** Flush indicator for txbd_ring */
+ t_bool txbd_flush;
+
+ /** Shadow copy of RXBD write pointer */
+ t_u32 rxbd_wrptr;
+ /** RxBD read pointer */
+ t_u32 rxbd_rdptr;
+ /** RXBD ring size */
+ t_u32 rxbd_ring_size;
+ /** A spinlock for rxbd_ring */
+ t_void *rx_ring_lock;
+ /** Virtual base address of rxbd_ring */
+ t_u8 *rxbd_ring_vbase;
+ /** Physical base address of rxbd_ring */
+ t_u64 rxbd_ring_pbase;
+ /** Ring of buffer descriptors for RX */
+ t_void *rxbd_ring[MLAN_MAX_TXRX_BD];
+ /** A list of mlan_buffer objects used for data rx */
+ mlan_buffer *rx_buf_list[MLAN_MAX_TXRX_BD];
+
+ /** Shadow copy of cmdrsp/evt write pointer */
+ t_u32 evtbd_wrptr;
+ /** Read pointer for cmdrsp/evt ring */
+ t_u32 evtbd_rdptr;
+ /** Size of the cmdrsp/evt ring */
+ t_u32 evtbd_ring_size;
+ /** Virtual base address of evtbd_bd_ring */
+ t_u8 *evtbd_ring_vbase;
+ /** Physical base address of evtbd_bd_ring */
+ t_u64 evtbd_ring_pbase;
+ /** Ring of buffer descriptors for EVENT */
+ t_void *evtbd_ring[MLAN_MAX_EVT_BD];
+ /** A list of mlan_buffer objects used for EVENT */
+ mlan_buffer *evt_buf_list[MLAN_MAX_EVT_BD];
+
+ /** Command buffer */
+ mlan_buffer *cmd_buf;
+ /** Command response buffer */
+ mlan_buffer *cmdrsp_buf;
+ /** Command buffer */
+ mlan_buffer *vdll_cmd_buf;
+ /** last tx_pkt_size */
+ t_u32 last_tx_pkt_size[MLAN_MAX_TXRX_BD];
+} mlan_pcie_card, *pmlan_pcie_card;
+#endif
+
+#ifdef USB
+typedef struct _mlan_usb_card {
+ /** data structure for USB Rx Deaggregation */
+ usb_rx_deaggr_params usb_rx_deaggr;
+ /** data structure for USB Tx Aggregation */
+ usb_tx_aggr_params usb_tx_aggr[MAX_USB_TX_PORT_NUM];
+ /** USB sggregation supported by FW */
+ t_u8 fw_usb_aggr;
+
+} mlan_usb_card, *pmlan_usb_card;
+
+#endif
+
+typedef struct _mlan_card_info {
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf_size;
+ /** support V16_FW_API */
+ t_u8 v16_fw_api;
+ /** support V17_FW_API */
+ t_u8 v17_fw_api;
+ /** suppress PS handshake */
+ t_u8 supp_ps_handshake;
+ /** DEFAULT_11N_TX_BF_CAP */
+ t_u32 default_11n_tx_bf_cap;
+} mlan_card_info, *pmlan_card_info;
+
+typedef struct _mlan_adapter mlan_adapter, *pmlan_adapter;
+
+/**Adapter_operations data structure*/
+typedef struct _adapter_operations {
+ /**firmware download handler*/
+ mlan_status (*dnld_fw)(pmlan_adapter pmadapter, pmlan_fw_image pmfw);
+ /**interrupt handler*/
+ mlan_status (*interrupt)(t_u16 msg_id, pmlan_adapter pmadapter);
+ /**INT process handler*/
+ mlan_status (*process_int_status)(pmlan_adapter pmadapter);
+ /**host to card handler*/
+ mlan_status (*host_to_card)(pmlan_private pmpriv, t_u8 type,
+ mlan_buffer *pmbuf,
+ mlan_tx_param *tx_param);
+ /*wakeup card*/
+ mlan_status (*wakeup_card)(pmlan_adapter pmadapter, t_u8 timeout);
+ /*reset the PM setting of card*/
+ mlan_status (*reset_card)(pmlan_adapter adapter);
+ /** Handle event/cmd complete*/
+ mlan_status (*event_complete)(mlan_adapter *pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+ /** Handle complete receiving data */
+ mlan_status (*data_complete)(mlan_adapter *pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+ /** Handle command response complete */
+ mlan_status (*cmdrsp_complete)(mlan_adapter *pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+ /** Handle rx packet */
+ mlan_status (*handle_rx_packet)(mlan_adapter *pmadapter,
+ pmlan_buffer pmbuf);
+ /** handle dump interface specific info */
+ mlan_status (*debug_dump)(mlan_adapter *pmadapter);
+ /**Interface header length*/
+ t_u32 intf_header_len;
+} mlan_adapter_operations;
+
+/** Adapter data structure for MLAN */
+typedef struct _mlan_adapter {
+ /** MOAL handle structure */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Private pointer */
+ pmlan_private priv[MLAN_MAX_BSS_NUM];
+ /** Total number of Priv number */
+ t_u8 priv_num;
+ /** Priority table for bss */
+ mlan_bssprio_tbl bssprio_tbl[MLAN_MAX_BSS_NUM];
+ /** Callback table */
+ mlan_callbacks callbacks;
+ /** Init parameters */
+ mlan_init_para init_para;
+ /** mlan_lock for init/shutdown */
+ t_void *pmlan_lock;
+ /** main_proc_lock for main_process */
+ t_void *pmain_proc_lock;
+ /** mlan_processing */
+ t_u32 mlan_processing;
+ /** main_process_cnt */
+ t_u32 main_process_cnt;
+ /** mlan_rx_processing */
+ t_u32 mlan_rx_processing;
+ /** rx_proc_lock for main_rx_process */
+ t_void *prx_proc_lock;
+ /** more_rx_task_flag */
+ t_u32 more_rx_task_flag;
+ /** rx work enable flag */
+ t_u8 rx_work_flag;
+ /* number of rx pkts queued */
+ t_u16 rx_pkts_queued;
+ /** more task flag */
+ t_u32 more_task_flag;
+ /** delay task flag */
+ t_u32 delay_task_flag;
+ /** Max tx buf size */
+ t_u16 max_tx_buf_size;
+ /** Tx buf size */
+ t_u16 tx_buf_size;
+ /** current tx buf size in fw */
+ t_u16 curr_tx_buf_size;
+ /** flush data flag */
+ t_u8 flush_data;
+ /** STATUS variables */
+ WLAN_HARDWARE_STATUS hw_status;
+ /** PnP SUPPORT */
+ t_u8 surprise_removed;
+ /** FW hang report */
+ t_u8 fw_hang_report;
+
+ /** ECSA support */
+ t_u8 ecsa_enable;
+
+ /** Get log support */
+ t_u8 getlog_enable;
+
+ /** Radio on flag */
+ t_u16 radio_on;
+
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** firmware version */
+ t_u8 fw_ver;
+ /** firmware minor version */
+ t_u8 fw_min_ver;
+ /** uap firmware version */
+ t_u8 uap_fw_ver;
+ /** mac address retrun from get_hw_spec */
+ t_u8 permanent_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Number of antenna used */
+ t_u16 number_of_antenna;
+ /** antenna info */
+ t_u8 antinfo;
+ /** Firmware capability information */
+ t_u32 fw_cap_info;
+ /** Extended firmware capability information */
+ t_u32 fw_cap_ext;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ /** High byte for 5G, low byte for 2G, like 0x2211 0x22 for 5G, 0x11 for
+ * 2G */
+ t_u16 user_htstream;
+#endif
+ /** vdll ctrl */
+ vdll_dnld_ctrl vdll_ctrl;
+#if defined(SDIO) || defined(PCIE)
+ /** pint_lock for interrupt handling */
+ t_void *pint_lock;
+ /** Interrupt status */
+ t_u32 ireg;
+#endif
+ /** card type */
+ t_u16 card_type;
+ /** card rev */
+ t_u8 card_rev;
+ const mlan_card_info *pcard_info;
+#ifdef SDIO
+ pmlan_sdio_card pcard_sd;
+#endif
+#ifdef PCIE
+ pmlan_pcie_card pcard_pcie;
+#endif
+#ifdef USB
+ pmlan_usb_card pcard_usb;
+#endif
+
+ /** Event cause */
+ t_u32 event_cause;
+ /** Event buffer */
+ pmlan_buffer pmlan_buffer_event;
+ /** Upload length */
+ t_u32 upld_len;
+ /** Upload buffer*/
+ t_u8 upld_buf[WLAN_UPLD_SIZE];
+ /** Data sent:
+ * TRUE - Data is sent to fw, no Tx Done received
+ * FALSE - Tx done received for previous Tx
+ */
+ t_u8 data_sent;
+ /** CMD sent:
+ * TRUE - CMD is sent to fw, no CMD Done received
+ * FALSE - CMD done received for previous CMD
+ */
+ t_u8 cmd_sent;
+ /** CMD Response received:
+ * TRUE - CMD is response is received from fw, and yet to process
+ * FALSE - No cmd response to process
+ */
+ t_u8 cmd_resp_received;
+ /** Event received:
+ * TRUE - Event received from fw, and yet to process
+ * FALSE - No events to process
+ */
+ t_u8 event_received;
+
+ /** Data received:
+ * TRUE - Data received from fw
+ * FALSE - No Data received
+ */
+ t_u8 data_received;
+
+ /** Command-related variables */
+ /** Command sequence number */
+ t_u16 seq_num;
+ /** Command controller nodes */
+ cmd_ctrl_node *cmd_pool;
+ /** Current Command */
+ cmd_ctrl_node *curr_cmd;
+ /** mlan_lock for command */
+ t_void *pmlan_cmd_lock;
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Last init fw command id */
+ t_u16 last_init_cmd;
+ /** Command timer */
+ t_void *pmlan_cmd_timer;
+ /** Command timer set flag */
+ t_u8 cmd_timer_is_set;
+ /** time stamp for command dnld */
+ t_u32 dnld_cmd_in_secs;
+
+ /** Command Queues */
+ /** Free command buffers */
+ mlan_list_head cmd_free_q;
+ /** Pending command buffers */
+ mlan_list_head cmd_pending_q;
+ /** Command queue for scanning */
+ mlan_list_head scan_pending_q;
+ /** ioctl pending queue */
+ mlan_list_head ioctl_pending_q;
+ /** pending_ioctl flag */
+ t_u8 pending_ioctl;
+ pmlan_private pending_disconnect_priv;
+ /** mlan_processing */
+ t_u32 scan_processing;
+ /** ext_scan enh support flag */
+ t_u8 ext_scan_enh;
+ /** scan type: 0 legacy, 1: enhance scan*/
+ t_u8 ext_scan_type;
+ /** ext scan timeout */
+ t_u8 ext_scan_timeout;
+ /** coex scan flag */
+ t_u8 coex_scan;
+ /** coex min scan time */
+ t_u8 coex_min_scan_time;
+ /** coex max scan time */
+ t_u8 coex_max_scan_time;
+ /** coex win size flag */
+ t_u8 coex_win_size;
+ /** coex amdpdu tx win size */
+ t_u8 coex_tx_win_size;
+ /** coex ampdu rx win size */
+ t_u8 coex_rx_win_size;
+ /** Region code */
+ t_u16 region_code;
+ /** Region Channel data */
+ region_chan_t region_channel[MAX_REGION_CHANNEL_NUM];
+ /** CFP table code for 2.4GHz */
+ t_u8 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u8 cfp_code_a;
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+ /** Minimum BA Threshold */
+ t_u8 min_ba_threshold;
+#ifdef STA_SUPPORT
+ /** Universal Channel data */
+ region_chan_t universal_channel[MAX_REGION_CHANNEL_NUM];
+ /** Parsed region channel */
+ parsed_region_chan_11d_t parsed_region_chan;
+#endif /* STA_SUPPORT */
+ /** 11D and Domain Regulatory Data */
+ wlan_802_11d_domain_reg_t domain_reg;
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** FSM variable for 11h support */
+ wlan_11h_device_state_t state_11h;
+ /** FSM variable for DFS support */
+ wlan_dfs_device_state_t state_dfs;
+ /** FSM variable for RDH support */
+ wlan_radar_det_hndlg_state_t state_rdh;
+ /** variable to configure dfs channel switch count */
+ t_s8 dfs_cs_count;
+ /** User configured settings for DFS testing */
+ wlan_dfs_testing_settings_t dfs_test_params;
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+ /** FSM variable for MEAS support */
+ wlan_meas_state_t state_meas;
+ /** Scan table */
+ BSSDescriptor_t *pscan_table;
+ /** scan age in secs */
+ t_u32 age_in_secs;
+ /** Active scan for hidden ssid triggered */
+ t_u8 active_scan_triggered;
+ /** channel statstics */
+ ChanStatistics_t *pchan_stats;
+ /** Number of records in the chan_stats */
+ t_u32 num_in_chan_stats;
+ /** index of chan stats */
+ t_u32 idx_chan_stats;
+ t_u8 bgscan_reported;
+
+ /** Number of records in the scan table */
+ t_u32 num_in_scan_table;
+ /** Scan probes */
+ t_u16 scan_probes;
+
+ /** Scan type */
+ t_u8 scan_type;
+ /** Scan mode */
+ t_u32 scan_mode;
+ /** Specific scan time */
+ t_u16 specific_scan_time;
+ /** Active scan time */
+ t_u16 active_scan_time;
+ /** Passive scan time */
+ t_u16 passive_scan_time;
+ /** Passive scan to active scan */
+ t_u8 passive_to_active_scan;
+ /** scan channel gap time */
+ t_u16 scan_chan_gap;
+ /** Scan block flag */
+ t_u8 scan_block;
+ /** Extended scan or legacy scan */
+ t_u8 ext_scan;
+ t_u16 bcn_buf_size;
+ /** Beacon buffer */
+ t_u8 *bcn_buf;
+ /** Pointer to valid beacon buffer end */
+ t_u8 *pbcn_buf_end;
+ /** allocate fixed scan beacon buffer size*/
+ t_u32 fixed_beacon_buffer;
+
+ /** F/W supported bands */
+ t_u16 fw_bands;
+ /** User selected band to start adhoc network */
+ t_u16 adhoc_start_band;
+ /** User selected bands */
+ t_u16 config_bands;
+ /** Pointer to channel list last sent to the firmware for scanning */
+ ChanScanParamSet_t *pscan_channels;
+
+ /** Tx lock flag */
+ t_u8 tx_lock_flag;
+ /** Rx lock flag */
+ t_u8 rx_lock_flag;
+ /** main lock flag */
+ t_u8 main_lock_flag;
+#ifdef USB
+ /** Tx CMD endpoint address */
+ t_u8 tx_cmd_ep;
+ /** Rx CMD/EVT endpoint address */
+ t_u8 rx_cmd_ep;
+ /** Rx data endpoint address */
+ t_u8 rx_data_ep;
+ /** Tx data endpoint address */
+ t_u8 tx_data_ep;
+#endif
+
+ /** sleep_params_t */
+ sleep_params_t sleep_params;
+ /** sleep_period_t (Enhanced Power Save) */
+ sleep_period_t sleep_period;
+
+ /** Power Save mode */
+ /**
+ * Wlan802_11PowerModeCAM = disable
+ * Wlan802_11PowerModePSP = enable
+ */
+ t_u16 ps_mode;
+ /** Power Save state */
+ t_u32 ps_state;
+ /** Need to wakeup flag */
+ t_u8 need_to_wakeup;
+ /** keep_wakeup */
+ t_u8 keep_wakeup;
+
+ /** Multiple DTIM */
+ t_u16 multiple_dtim;
+ /** Local listen interval */
+ t_u16 local_listen_interval;
+ /** Null packet interval */
+ t_u16 null_pkt_interval;
+
+ /** IEEE ps inactivity timout value */
+ t_u16 inact_tmo;
+ /** Power save confirm sleep command buffer */
+ pmlan_buffer psleep_cfm;
+ /** Beacon miss timeout */
+ t_u16 bcn_miss_time_out;
+
+ /** Deep Sleep flag */
+ t_u8 is_deep_sleep;
+ /** Idle time */
+ t_u16 idle_time;
+ /** Auto Deep Sleep enabled at init time */
+ t_u8 init_auto_ds;
+
+ /** delay null pkt flag */
+ t_u8 delay_null_pkt;
+ /** Delay to PS in milliseconds */
+ t_u16 delay_to_ps;
+ /** Enhanced PS mode */
+ t_u16 enhanced_ps_mode;
+ /** Device wakeup required flag */
+ t_u8 pm_wakeup_card_req;
+
+ /** Gen NULL pkg */
+ t_u16 gen_null_pkt;
+
+ /** PPS/UAPSD mode flag */
+ t_u16 pps_uapsd_mode;
+ /** Number of wakeup tries */
+ t_u32 pm_wakeup_fw_try;
+ /** time stamp when host try to wake up firmware */
+ t_u32 pm_wakeup_in_secs;
+ /** Card wakeup timer */
+ t_void *pwakeup_fw_timer;
+ /** Card wakeup timer */
+ t_u8 wakeup_fw_timer_is_set;
+ /** Number of wake up timeouts */
+ t_u32 pm_wakeup_timeout;
+
+ /** Host Sleep configured flag */
+ t_u8 is_hs_configured;
+ /** Host Sleep configuration */
+ hs_config_param hs_cfg;
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** mef_flt_cfg_mef configuration */
+ mef_entry entry_cfg;
+ /** Event body */
+ t_u8 event_body[MAX_EVENT_SIZE];
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+#ifdef STA_SUPPORT
+ /** Adhoc Secondary Channel Bandwidth */
+ t_u8 chan_bandwidth;
+#endif /* STA_SUPPORT */
+
+ /** 802.11ac device capabilities */
+ t_u32 hw_dot_11ac_dev_cap;
+ /** 802.11ac device support for MIMO abstraction of MCSs */
+ t_u32 hw_dot_11ac_mcs_support;
+ /** length of hw he capability */
+ t_u8 hw_hecap_len;
+ /** 802.11ax HE capability */
+ t_u8 hw_he_cap[54];
+ /** length of hw 2.4G he capability */
+ t_u8 hw_2g_hecap_len;
+ /** 802.11ax 2.4G HE capability */
+ t_u8 hw_2g_he_cap[54];
+ /** max mgmt IE index in device */
+ t_u16 max_mgmt_ie_index;
+ /** Head of Rx data queue */
+ mlan_list_head rx_data_queue;
+#ifdef MFG_CMD_SUPPORT
+ t_u32 mfg_mode;
+#endif
+ /** Debug */
+ wlan_dbg dbg;
+
+ /** RX pending for forwarding packets */
+ mlan_scalar pending_bridge_pkts;
+
+ /** Minimum delay between HsActive and HostWake (in msec) */
+ t_u16 min_wake_holdoff;
+ /** Host sleep wake interval(in msec) */
+ t_u32 hs_wake_interval;
+ /** Host sleep inactivity timeout (in msec) */
+ t_u32 hs_inactivity_timeout;
+ /** Parameter type for indication gpio*/
+ t_u8 param_type_ind;
+ /** GPIO pin for indication wakeup source */
+ t_u32 ind_gpio;
+ /** Level on ind_gpio pin for indication normal wakeup source */
+ t_u32 level;
+ /** Parameter type for extend hscfg*/
+ t_u8 param_type_ext;
+ /** Events that will be forced ignore */
+ t_u32 event_force_ignore;
+ /** Events that will use extend gap to inform host*/
+ t_u32 event_use_ext_gap;
+ /** Extend gap*/
+ t_u8 ext_gap;
+ /** GPIO wave level for extend hscfg */
+ t_u8 gpio_wave;
+ /** Dynamic MIMO-SISO switch for hscfg*/
+ t_u8 hs_mimo_switch;
+ /** management frame wakeup filter config */
+ mlan_mgmt_frame_wakeup mgmt_filter[MAX_MGMT_FRAME_FILTER];
+ /** Bypass TX queue pkt count */
+ t_u16 bypass_pkt_count;
+#ifdef STA_SUPPORT
+ /** warm-reset IOCTL request buffer pointer */
+ pmlan_ioctl_req pwarm_reset_ioctl_req;
+#endif
+ /** SCAN IOCTL request buffer pointer */
+ pmlan_ioctl_req pscan_ioctl_req;
+ /** DPD data pointer */
+ t_u8 *pdpd_data;
+ /** DPD data length */
+ t_u32 dpd_data_len;
+ /** region txpowerlimit cfg data buf pointer */
+ t_u8 *ptxpwr_data;
+ /** region txpowerlimit cfg data len */
+ t_u32 txpwr_data_len;
+ /** Cal data pointer */
+ t_u8 *pcal_data;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Feature control bitmask */
+ t_u32 feature_control;
+
+ /** Control coex RX window size configuration */
+ t_u8 coex_rx_winsize;
+ t_bool dfs_repeater;
+ t_u32 dfsr_channel;
+ t_u8 chanrpt_param_bandcfg;
+#if defined(PCIE)
+ mlan_buffer *ssu_buf;
+#endif
+ /** maximum sta connection */
+ t_u8 max_sta_conn;
+ otp_region_info_t *otp_region;
+ chan_freq_power_t *cfp_otp_bg;
+ t_u8 *tx_power_table_bg;
+ t_u32 tx_power_table_bg_size;
+ t_u8 tx_power_table_bg_rows;
+ t_u8 tx_power_table_bg_cols;
+ chan_freq_power_t *cfp_otp_a;
+ t_u8 *tx_power_table_a;
+ t_u32 tx_power_table_a_size;
+ t_u8 tx_power_table_a_rows;
+ t_u8 tx_power_table_a_cols;
+ /**mlan adapter operations*/
+ mlan_adapter_operations ops;
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ /** authenticator_priv */
+ pmlan_private authenticator_priv;
+#endif
+ /** TP accounting mode 1-enable 0-disable */
+ t_u32 tp_state_on;
+ /** Packet drop point */
+ t_u32 tp_state_drop_point;
+} mlan_adapter, *pmlan_adapter;
+
+/** Check if stream 2X2 enabled */
+#define IS_STREAM_2X2(x) ((x)&FEATURE_CTRL_STREAM_2X2)
+/** Check if DFS support enabled */
+#define IS_DFS_SUPPORT(x) ((x)&FEATURE_CTRL_DFS_SUPPORT)
+#ifdef USB
+/** Check if winner check & not wait for FW ready event */
+#define IS_USB_NEW_INIT(x) ((x)&FEATURE_CTRL_USB_NEW_INIT)
+#endif
+
+/** Ethernet packet type for EAPOL */
+#define MLAN_ETHER_PKT_TYPE_EAPOL (0x888E)
+#define MLAN_ETHER_PKT_TYPE_ARP (0x0806)
+/** Ethernet packet type for WAPI */
+#define MLAN_ETHER_PKT_TYPE_WAPI (0x88B4)
+/** Ethernet packet type offset */
+#define MLAN_ETHER_PKT_TYPE_OFFSET (12)
+
+mlan_status wlan_init_lock_list(pmlan_adapter pmadapter);
+mlan_status wlan_init_priv_lock_list(pmlan_adapter pmadapter, t_u8 start_index);
+t_void wlan_free_lock_list(pmlan_adapter pmadapter);
+mlan_status wlan_init_timer(pmlan_adapter pmadapter);
+t_void wlan_free_timer(pmlan_adapter pmadapter);
+
+/* Function prototype */
+/** Initialize firmware */
+mlan_status wlan_init_fw(pmlan_adapter pmadapter);
+
+/** get hw spec complete */
+mlan_status wlan_get_hw_spec_complete(pmlan_adapter pmadapter);
+
+/** Initialize firmware complete */
+mlan_status wlan_init_fw_complete(pmlan_adapter pmadapter);
+
+/** Shutdown firmware complete */
+mlan_status wlan_shutdown_fw_complete(pmlan_adapter pmadapter);
+
+/** Receive event */
+mlan_status wlan_recv_event(pmlan_private priv, mlan_event_id event_id,
+ t_void *pmevent);
+
+/** Initialize mlan_adapter structure */
+t_void wlan_init_adapter(pmlan_adapter pmadapter);
+
+/** Initialize mlan_private structure */
+mlan_status wlan_init_priv(pmlan_private priv);
+
+mlan_status wlan_download_vdll_block(mlan_adapter *pmadapter, t_u8 *block,
+ t_u16 block_len);
+mlan_status wlan_process_vdll_event(pmlan_private pmpriv, pmlan_buffer pevent);
+/** Process event */
+mlan_status wlan_process_event(pmlan_adapter pmadapter);
+
+/** Prepare command */
+mlan_status wlan_prepare_cmd(pmlan_private priv, t_u16 cmd_no, t_u16 cmd_action,
+ t_u32 cmd_oid, t_void *pioctl_buf,
+ t_void *pdata_buf);
+
+/** cmd timeout handler */
+t_void wlan_cmd_timeout_func(t_void *function_context);
+
+/**
+ * @brief check if Tx pending
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @return MTRUE/MFALSE;
+ */
+static inline t_u8 wlan_is_tx_pending(mlan_adapter *pmadapter)
+{
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type) &&
+ pmadapter->pcard_pcie->txbd_pending)
+ return MTRUE;
+#endif
+ return MFALSE;
+}
+
+/** process host cmd */
+mlan_status wlan_misc_ioctl_host_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/** process init/shutdown cmd*/
+mlan_status wlan_misc_ioctl_init_shutdown(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/** process debug info */
+mlan_status wlan_get_info_debug_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Set/Get BSS role */
+mlan_status wlan_bss_ioctl_bss_role(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+#if defined(PCIE)
+mlan_status wlan_misc_ssu(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_set_ewpa_mode(mlan_private *priv, pmlan_ds_passphrase psec_pp);
+mlan_status wlan_find_bss(mlan_private *pmpriv, pmlan_ioctl_req pioctl_req);
+
+/* block main process */
+void mlan_block_main_process(mlan_adapter *pmadapter, t_u8 block);
+/* block rx process */
+void mlan_block_rx_process(mlan_adapter *pmadapter, t_u8 block);
+/** check pending command */
+int wlan_check_pending_cmd(mlan_adapter *pmadapter);
+/** Allocate memory for adapter structure members */
+mlan_status wlan_allocate_adapter(pmlan_adapter pmadapter);
+/** Free adapter */
+t_void wlan_free_adapter(pmlan_adapter pmadapter);
+/** Free priv */
+t_void wlan_free_priv(mlan_private *pmpriv);
+/** Allocate command buffer */
+mlan_status wlan_alloc_cmd_buffer(mlan_adapter *pmadapter);
+/** Free command buffer */
+mlan_status wlan_free_cmd_buffer(mlan_adapter *pmadapter);
+/** Request command lock */
+t_void wlan_request_cmd_lock(mlan_adapter *pmadapter);
+/** Release command lock */
+t_void wlan_release_cmd_lock(mlan_adapter *pmadapter);
+#ifdef STA_SUPPORT
+/** Flush the scan pending queue */
+t_void wlan_flush_scan_queue(pmlan_adapter pmadapter);
+mlan_status wlan_cancel_pending_scan_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+/**Cancel pending command */
+t_void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter, t_u8 flag);
+/**Cancel pending ioctl */
+t_void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/**Cancel bss pending ioctl */
+t_void wlan_cancel_bss_pending_cmd(pmlan_adapter pmadapter, t_u32 bss_index);
+
+/** Insert command to free queue */
+t_void wlan_insert_cmd_to_free_q(mlan_adapter *pmadapter,
+ cmd_ctrl_node *pcmd_node);
+
+/** Insert command to pending queue */
+t_void wlan_insert_cmd_to_pending_q(mlan_adapter *pmadapter,
+ cmd_ctrl_node *pcmd_node, t_u32 addtail);
+
+/** Execute next command */
+mlan_status wlan_exec_next_cmd(mlan_adapter *pmadapter);
+/** Proecess command response */
+mlan_status wlan_process_cmdresp(mlan_adapter *pmadapter);
+/** Handle received packet, has extra handling for aggregate packets */
+mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Process transmission */
+mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param *tx_param);
+/** Transmit a null data packet */
+mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags);
+
+#ifdef SDIO
+mlan_status wlan_alloc_sdio_mpa_buffers(mlan_adapter *pmadapter,
+ t_u32 mpa_tx_buf_size,
+ t_u32 mpa_rx_buf_size);
+
+mlan_status wlan_free_sdio_mpa_buffers(mlan_adapter *pmadapter);
+#endif
+
+/** Process write data complete */
+mlan_status wlan_write_data_complete(pmlan_adapter pmlan_adapter,
+ pmlan_buffer pmbuf, mlan_status status);
+
+#ifdef USB
+mlan_status wlan_usb_deaggr_rx_pkt(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+
+/**
+ * @brief This function resets USB Tx Aggregation buffers
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return N/A
+ */
+static INLINE t_void wlan_reset_usb_tx_aggr(pmlan_adapter pmadapter)
+{
+ t_s32 i = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ pcb->moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_usb->usb_tx_aggr[i].paggr_lock);
+ if (pmadapter->pcard_usb->usb_tx_aggr[i].aggr_hold_timer_is_set) {
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .paggr_hold_timer);
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_hold_timer_is_set = MFALSE;
+ }
+ if (pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.enable &&
+ pmadapter->pcard_usb->usb_tx_aggr[i].pmbuf_aggr != MNULL) {
+ wlan_write_data_complete(
+ pmadapter,
+ pmadapter->pcard_usb->usb_tx_aggr[i].pmbuf_aggr,
+ MLAN_STATUS_FAILURE); /* did not get sent */
+ pmadapter->pcard_usb->usb_tx_aggr[i].pmbuf_aggr = MNULL;
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_len = 0;
+ }
+ pcb->moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_usb->usb_tx_aggr[i].paggr_lock);
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function get usb_tx_aggr_params
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param port port for TX
+ *
+ * @return A pointer to usb_tx_aggr_params
+ */
+static INLINE usb_tx_aggr_params *
+wlan_get_usb_tx_aggr_params(pmlan_adapter pmadapter, t_u32 port)
+{
+ int i;
+ ENTER();
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ if (pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.enable &&
+ pmadapter->pcard_usb->usb_tx_aggr[i].port == port)
+ return &pmadapter->pcard_usb->usb_tx_aggr[i];
+ }
+ LEAVE();
+ return MNULL;
+}
+
+t_void wlan_usb_tx_aggr_timeout_func(t_void *function_context);
+mlan_status wlan_usb_host_to_card_aggr(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf,
+ mlan_tx_param *tx_param,
+ usb_tx_aggr_params *aggr_params);
+#endif
+
+/** Process receive packet complete */
+mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf, mlan_status status);
+/** Clean Tx Rx queues */
+t_void wlan_clean_txrx(pmlan_private priv);
+
+t_void wlan_add_buf_bypass_txqueue(mlan_adapter *pmadapter, pmlan_buffer pmbuf);
+t_void wlan_process_bypass_tx(mlan_adapter *pmadapter);
+t_void wlan_cleanup_bypass_txq(pmlan_private priv);
+t_u8 wlan_bypass_tx_list_empty(mlan_adapter *pmadapter);
+
+/** Check if this is the last packet */
+t_u8 wlan_check_last_packet_indication(pmlan_private priv);
+
+#define MOAL_ALLOC_MLAN_BUFFER (0)
+#define MOAL_MALLOC_BUFFER (1)
+
+#ifdef PCIE
+/* This defines the direction arg to the DMA mapping routines. */
+#define PCI_DMA_BIDIRECTIONAL 0
+#define PCI_DMA_TODEVICE 1
+#define PCI_DMA_FROMDEVICE 2
+#define PCI_DMA_NONE 3
+#endif
+
+/** function to allocate a mlan_buffer */
+pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter *pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag);
+/** function to free a mlan_buffer */
+t_void wlan_free_mlan_buffer(mlan_adapter *pmadapter, pmlan_buffer pmbuf);
+
+/** command resp handler for version ext */
+mlan_status wlan_ret_ver_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+/** command resp handler for rx mgmt forward registration */
+mlan_status wlan_ret_rx_mgmt_ind(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+/** Check Power Save condition */
+t_void wlan_check_ps_cond(mlan_adapter *pmadapter);
+
+/** handle command for enhanced power save mode */
+mlan_status wlan_cmd_enh_power_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_u16 ps_bitmap, t_void *pdata_buf);
+/** handle command resp for enhanced power save mode */
+mlan_status wlan_ret_enh_power_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+/** handle commnand for cfg data */
+mlan_status wlan_cmd_cfg_data(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pdata_buf);
+/** handle command resp for cfg data */
+mlan_status wlan_ret_cfg_data(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+
+/** Process sleep confirm command response */
+void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 *pbuf,
+ t_u32 len);
+
+/** Perform hs related activities on receving the power up interrupt */
+void wlan_process_hs_config(pmlan_adapter pmadapter);
+
+t_void wlan_wakeup_card_timeout_func(void *function_context);
+
+mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private *priv, t_u8 *payload,
+ t_u32 payload_len, RxPD *prx_pd);
+
+mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_remain_chan_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_remain_on_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_remain_on_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#ifdef WIFI_DIRECT_SUPPORT
+mlan_status wlan_bss_ioctl_wifi_direct_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_wifi_direct_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_wifi_direct_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_p2p_params_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_p2p_params_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_misc_p2p_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+/** get ralist info */
+int wlan_get_ralist_info(mlan_private *priv, pralist_info buf);
+/** dump ralist */
+void wlan_dump_ralist(mlan_private *priv);
+
+/** get pm info */
+mlan_status wlan_get_pm_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_bss_ioctl_bss_remove(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_mimo_switch_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_802_11_mimo_switch(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+mlan_status wlan_misc_per_pkt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_config_mgmt_filter(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_get_hs_wakeup_reason(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_hs_wakeup_reason(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+mlan_status wlan_ret_hs_wakeup_reason(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_get_tx_rx_histogram(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_tx_rx_pkt_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ pmlan_ioctl_req pioctl_buf,
+ t_void *pdata_buf);
+mlan_status wlan_ret_tx_rx_pkt_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_radio_ioctl_radio_ctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_ret_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_rate_ioctl_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_ret_802_11_tx_rate_query(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_rate_ioctl_get_data_rate(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated);
+/** Handles the command response of hs_cfg */
+mlan_status wlan_ret_802_11_hs_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** Sends HS_WAKEUP event to applications */
+t_void wlan_host_sleep_wakeup_event(pmlan_private priv);
+
+/** Prepares command of robustcoex */
+mlan_status wlan_cmd_robustcoex(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf);
+/** Set Robustcoex gpiocfg */
+mlan_status wlan_misc_robustcoex(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+/** Set mapping policy/get DMCS status */
+mlan_status wlan_misc_dmcs_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/** Prepares command of DMCS config */
+mlan_status wlan_cmd_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+/** Handles command response of DMCS config */
+mlan_status wlan_ret_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#if defined(PCIE)
+mlan_status wlan_cmd_ssu(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf);
+#endif
+
+/** send get hw spec command to firmware */
+mlan_status wlan_adapter_get_hw_spec(pmlan_adapter pmadapter);
+/** send adapter specific init cmd to firmware */
+mlan_status wlan_adapter_init_cmd(pmlan_adapter pmadapter);
+/** get/set bandcfg */
+mlan_status wlan_radio_ioctl_band_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef RX_PACKET_COALESCE
+mlan_status wlan_cmd_rx_pkt_coalesce_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_rx_pkt_coalesce_cfg(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+#endif
+
+#ifdef STA_SUPPORT
+/** warm reset */
+mlan_status wlan_misc_ioctl_warm_reset(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/** Process received packet */
+mlan_status wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** ioctl handler for station mode */
+mlan_status wlan_ops_sta_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req);
+
+/** cmd handler for station mode */
+mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pioctl_buf, t_void *pdata_buf,
+ t_void *pcmd_buf);
+
+/** cmdresp handler for station mode */
+mlan_status wlan_ops_sta_process_cmdresp(t_void *priv, t_u16 cmdresp_no,
+ t_void *pcmd_buf, t_void *pioctl);
+
+/** rx handler for station mode */
+mlan_status wlan_ops_sta_process_rx_packet(t_void *adapter, pmlan_buffer pmbuf);
+
+/** event handler for station mode */
+mlan_status wlan_ops_sta_process_event(t_void *priv);
+
+/** fill txpd for station mode */
+t_void *wlan_ops_sta_process_txpd(t_void *priv, pmlan_buffer pmbuf);
+
+/** send init cmd to firmware for station mode */
+mlan_status wlan_ops_sta_init_cmd(t_void *priv, t_u8 first_bss);
+
+/** Flush the scan table */
+mlan_status wlan_flush_scan_table(pmlan_adapter pmadapter);
+
+/** Scan for networks */
+mlan_status wlan_scan_networks(mlan_private *pmpriv, t_void *pioctl_buf,
+ wlan_user_scan_cfg *puser_scan_in);
+
+/** Scan for specific SSID */
+mlan_status wlan_scan_specific_ssid(mlan_private *pmpriv, t_void *pioctl_buf,
+ mlan_802_11_ssid *preq_ssid);
+
+/** Scan command handler */
+mlan_status wlan_cmd_802_11_scan(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf);
+
+/** Handler for scan command response */
+mlan_status wlan_ret_802_11_scan(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+
+/** Extended scan command handler */
+mlan_status wlan_cmd_802_11_scan_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf);
+/** Handler for extended scan command response */
+mlan_status wlan_ret_802_11_scan_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+/** Handler event for extended scan report */
+mlan_status wlan_handle_event_ext_scan_report(mlan_private *pmpriv,
+ mlan_buffer *pmbuf);
+mlan_status wlan_handle_event_ext_scan_status(mlan_private *pmpriv,
+ mlan_buffer *pmbuf);
+
+/** check network compatibility */
+t_s32 wlan_is_network_compatible(mlan_private *pmpriv, t_u32 index, t_u32 mode);
+
+/** Find an SSID in a list */
+t_s32 wlan_find_ssid_in_list(pmlan_private pmpriv, mlan_802_11_ssid *ssid,
+ t_u8 *bssid, t_u32 mode);
+
+/** Find a BSSID in a list */
+t_s32 wlan_find_bssid_in_list(mlan_private *pmpriv, t_u8 *bssid, t_u32 mode);
+
+/** Find best network */
+mlan_status wlan_find_best_network(mlan_private *pmpriv,
+ mlan_ssid_bssid *preq_ssid_bssid);
+
+/** Compare two SSIDs */
+t_s32 wlan_ssid_cmp(pmlan_adapter pmadapter, mlan_802_11_ssid *ssid1,
+ mlan_802_11_ssid *ssid2);
+
+/** Associate */
+mlan_status wlan_associate(mlan_private *pmpriv, IN t_void *pioctl_buf,
+ IN BSSDescriptor_t *pBSSDesc);
+
+/** Associate command handler */
+mlan_status wlan_cmd_802_11_associate(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+/** Handler for association command response */
+mlan_status wlan_ret_802_11_associate(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+
+/** Reset connected state */
+t_void wlan_reset_connect_state(pmlan_private priv, t_u8 drv_disconnect);
+
+t_void wlan_2040_coex_event(pmlan_private pmpriv);
+
+/** convert band to radio type */
+t_u8 wlan_band_to_radio_type(t_u8 band);
+/** convert radio_type to band */
+t_u8 radio_type_to_band(t_u8 chanBand);
+
+/** Disconnect */
+mlan_status wlan_disconnect(mlan_private *pmpriv, mlan_ioctl_req *pioctl_req,
+ mlan_deauth_param *deauth_param);
+
+/** Ad-Hoc start */
+mlan_status wlan_adhoc_start(mlan_private *pmpriv, t_void *pioctl_buf,
+ mlan_802_11_ssid *padhoc_ssid);
+
+/** Ad-Hoc join */
+mlan_status wlan_adhoc_join(mlan_private *pmpriv, t_void *pioctl_buf,
+ BSSDescriptor_t *pBSSDesc);
+
+/** Ad-Hoc start command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_start(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+/** Ad-Hoc command handler */
+mlan_status wlan_cmd_802_11_ad_hoc_join(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+/** Handler for Ad-Hoc commands */
+mlan_status wlan_ret_802_11_ad_hoc(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+
+/** Handler for bgscan query commands */
+mlan_status wlan_cmd_802_11_bg_scan_query(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf);
+/** Handler for bgscan config command */
+mlan_status wlan_cmd_bgscan_config(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd, t_void *pdata_buf);
+/** Hander for bgscan config command response */
+mlan_status wlan_ret_bgscan_config(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_ret_802_11_bgscan_query(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+/** Get Channel-Frequency-Power by band and channel */
+chan_freq_power_t *
+wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter, t_u8 band,
+ t_u16 channel, region_chan_t *region_channel);
+/** Find Channel-Frequency-Power by band and channel */
+chan_freq_power_t *wlan_find_cfp_by_band_and_channel(mlan_adapter *pmadapter,
+ t_u8 band, t_u16 channel);
+/** Find Channel-Frequency-Power by band and frequency */
+chan_freq_power_t *wlan_find_cfp_by_band_and_freq(mlan_adapter *pmadapter,
+ t_u8 band, t_u32 freq);
+/** Get Tx power of channel from Channel-Frequency-Power */
+t_u8 wlan_get_txpwr_of_chan_from_cfp(mlan_private *pmpriv, t_u8 channel);
+/** find frequency from band and channel */
+t_u32 wlan_find_freq_from_band_chan(t_u8, t_u8);
+
+/* Save a beacon buffer of the current bss descriptor */
+t_void wlan_save_curr_bcn(mlan_private *pmpriv);
+/* Free a beacon buffer of the current bss descriptor */
+t_void wlan_free_curr_bcn(mlan_private *pmpriv);
+
+#endif /* STA_SUPPORT */
+
+/* Rate related functions */
+/** Convert index into data rate */
+t_u32 wlan_index_to_data_rate(pmlan_adapter pmadapter, t_u8 index,
+ t_u8 rate_info, t_u8 ext_rate_info);
+/** Get active data rates */
+t_u32 wlan_get_active_data_rates(mlan_private *pmpriv, t_u32 bss_mode,
+ t_u16 config_bands, WLAN_802_11_RATES rates);
+/** Get supported data rates */
+t_u32 wlan_get_supported_rates(mlan_private *pmpriv, t_u32 bss_mode,
+ t_u16 config_bands, WLAN_802_11_RATES rates);
+/** Convert data rate to index */
+t_u8 wlan_data_rate_to_index(pmlan_adapter pmadapter, t_u32 rate);
+/** Check if rate is auto */
+t_u8 wlan_is_rate_auto(mlan_private *pmpriv);
+/** Get rate index */
+int wlan_get_rate_index(pmlan_adapter pmadapter, t_u16 *rateBitmap, int size);
+mlan_status wlan_cmd_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_rxabortcfg_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_rxabortcfg_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_tx_ampdu_prot_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_tx_ampdu_prot_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_rate_adapt_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_rate_adapt_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_cmd_cck_desense_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+
+mlan_status wlan_ret_cck_desense_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_arb_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_arb_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_misc_ioctl_rxabortcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_rxabortcfg_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_tx_ampdu_prot_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_rate_adapt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_cck_desense_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_mfg(pmlan_private pmpriv, pHostCmd_DS_COMMAND cmd,
+ t_u16 cmd_action, t_pvoid pdata_buf);
+mlan_status wlan_ret_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_misc_ioctl_rf_test_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_range_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_arb_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_misc_ioctl_tp_state(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+/* CFP related functions */
+/** Region code index table */
+extern t_u16 region_code_index[MRVDRV_MAX_REGION_CODE];
+/** The table to keep CFP code for BG */
+extern t_u16 cfp_code_index_bg[MRVDRV_MAX_CFP_CODE_BG];
+/** The table to keep CFP code for A */
+extern t_u16 cfp_code_index_a[MRVDRV_MAX_CFP_CODE_A];
+
+/** Set region table */
+mlan_status wlan_set_regiontable(mlan_private *pmpriv, t_u8 region, t_u8 band);
+/** Get radar detection requirements*/
+t_bool wlan_get_cfp_radar_detect(mlan_private *priv, t_u8 chnl);
+/** check if scan type is passive for b/g band*/
+t_bool wlan_bg_scan_type_is_passive(mlan_private *priv, t_u8 chnl);
+/** check if channel is NO_IR (passive) */
+t_bool wlan_is_chan_passive(mlan_private *priv, t_u8 band, t_u8 chan);
+/** check if channel is disabled */
+t_bool wlan_is_chan_disabled(mlan_private *priv, t_u8 band, t_u8 chan);
+/** check if channel is blacklisted */
+t_bool wlan_is_chan_blacklisted(mlan_private *priv, t_u8 band, t_u8 chan);
+/** set blacklist setting for a channel */
+t_bool wlan_set_chan_blacklist(mlan_private *priv, t_u8 band, t_u8 chan,
+ t_bool bl);
+
+/* 802.11D related functions */
+/** Initialize 11D */
+t_void wlan_11d_priv_init(mlan_private *pmpriv);
+/** Initialize 11D */
+t_void wlan_11d_init(mlan_adapter *pmadapter);
+/** Enable 11D */
+mlan_status wlan_11d_enable(mlan_private *pmpriv, t_void *pioctl_buf,
+ state_11d_t flag);
+/** Get if 11D is enabled */
+t_bool wlan_11d_is_enabled(mlan_private *pmpriv);
+/** Get if FW 11D is enabled */
+t_bool wlan_fw_11d_is_enabled(mlan_private *pmpriv);
+/** Get if priv is station */
+t_bool wlan_is_station(mlan_private *pmpriv);
+/** Command handler for 11D country info */
+mlan_status wlan_cmd_802_11d_domain_info(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action);
+/** Handler for 11D country info command response */
+mlan_status wlan_ret_802_11d_domain_info(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp);
+/** Convert channel to frequency */
+t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u8 band);
+#ifdef STA_SUPPORT
+/** Set 11D universal table */
+mlan_status wlan_11d_set_universaltable(mlan_private *pmpriv, t_u8 band);
+/** Clear 11D region table */
+mlan_status wlan_11d_clear_parsedtable(mlan_private *pmpriv);
+/** Create 11D country information for downloading */
+mlan_status wlan_11d_create_dnld_countryinfo(mlan_private *pmpriv, t_u8 band);
+/** Get scan type from 11D info */
+t_u8 wlan_11d_get_scan_type(pmlan_adapter pmadapter, t_u8 band, t_u8 chan,
+ parsed_region_chan_11d_t *parsed_region_chan);
+/** Parse 11D country info */
+mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private *pmpriv,
+ BSSDescriptor_t *pBSSDesc);
+/** Prepare 11D domain information for download */
+mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private *pmpriv);
+/** Parse 11D country information into domain info */
+mlan_status wlan_11d_parse_domain_info(
+ pmlan_adapter pmadapter, IEEEtypes_CountryInfoFullSet_t *country_info,
+ t_u8 band, parsed_region_chan_11d_t *parsed_region_chan);
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Handle 11D domain information from UAP */
+mlan_status wlan_11d_handle_uap_domain_info(mlan_private *pmpriv, t_u8 band,
+ t_u8 *domain_tlv,
+ t_void *pioctl_buf);
+#endif
+/** Configure 11D domain info command */
+mlan_status wlan_11d_cfg_domain_info(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+
+/** This function converts region string to CFP table code */
+mlan_status wlan_misc_country_2_cfp_table_code(pmlan_adapter pmadapter,
+ t_u8 *country_code, t_u8 *cfp_bg,
+ t_u8 *cfp_a);
+
+/** This function finds if given country code is in EU table */
+t_bool wlan_is_etsi_country(pmlan_adapter pmadapter, t_u8 *country_code);
+
+/** check if station list is empty */
+t_u8 wlan_is_station_list_empty(mlan_private *priv);
+/** get station node */
+sta_node *wlan_get_station_entry(mlan_private *priv, t_u8 *mac);
+/** delete station list */
+t_void wlan_delete_station_list(pmlan_private priv);
+/** delete station entry */
+t_void wlan_delete_station_entry(mlan_private *priv, t_u8 *mac);
+/** add station entry */
+sta_node *wlan_add_station_entry(mlan_private *priv, t_u8 *mac);
+/** process uap rx packet */
+
+void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent,
+ sta_node *sta_ptr);
+/** find specific ie */
+t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 *ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id, t_u8 ext_id);
+t_u8 wlan_is_wmm_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, t_u16 buf_len);
+
+/**
+ * @brief This function checks tx_pause flag for peer
+ *
+ * @param priv A pointer to mlan_private
+ * @param ra Address of the receiver STA
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE int wlan_is_tx_pause(mlan_private *priv, t_u8 *ra)
+{
+ sta_node *sta_ptr = MNULL;
+ sta_ptr = wlan_get_station_entry(priv, ra);
+ if (sta_ptr)
+ return sta_ptr->tx_pause;
+ return MFALSE;
+}
+t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause);
+
+#ifdef UAP_SUPPORT
+mlan_status wlan_process_uap_rx_packet(mlan_private *priv, pmlan_buffer pmbuf);
+t_void wlan_drop_tx_pkts(pmlan_private priv);
+#endif /* UAP_SUPPORT */
+
+#ifdef UAP_SUPPORT
+/* process the recevied packet and bridge the packet */
+mlan_status wlan_uap_recv_packet(mlan_private *priv, pmlan_buffer pmbuf);
+#endif /* UAP_SUPPORT */
+
+mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req,
+ t_bool send_ioctl);
+
+mlan_status wlan_cmd_get_hw_spec(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *pcmd);
+mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf);
+#ifdef SDIO
+mlan_status wlan_cmd_sdio_rx_aggr_cfg(HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_sdio_rx_aggr_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp);
+#endif
+
+mlan_status wlan_misc_ioctl_mac_control(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_cw_mode_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_cw_mode_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_802_11_radio_control(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_802_11_radio_control(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_802_11_rf_antenna(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_802_11_rf_antenna(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_ret_reg_access(mlan_adapter *pmadapter, t_u16 type,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_ret_mem_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_reg_mem_ioctl_reg_rw(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_reg_mem_ioctl_read_eeprom(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_reg_mem_ioctl_mem_rw(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_reg_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_cmd_mem_access(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_cmd_802_11_mac_address(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action);
+mlan_status wlan_ret_802_11_mac_address(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_get_info_ver_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_ioctl_link_statistic(mlan_private *pmpriv,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_802_11_link_statistic(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_ret_get_link_statistic(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_reg_rx_mgmt_ind(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef DEBUG_LEVEL1
+mlan_status wlan_set_drvdbg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_misc_hotspot_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#ifdef STA_SUPPORT
+mlan_status wlan_misc_ext_capa_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+t_u32 wlan_is_ext_capa_support(mlan_private *pmpriv);
+#endif
+
+#ifdef STA_SUPPORT
+void wlan_add_ext_capa_info_ie(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **pptlv_out);
+#endif
+
+mlan_status wlan_cmd_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+
+mlan_status wlan_ret_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+mlan_status wlan_cmd_crypto(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 *pdata_buf);
+
+mlan_status wlan_ret_crypto(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+#endif
+
+#define BW_20MHZ 0
+#define BW_40MHZ 1
+#define BW_80MHZ 2
+#define BW_160MHZ 3
+int wlan_add_supported_oper_class_ie(mlan_private *pmpriv, t_u8 **pptlv_out,
+ t_u8 curr_oper_class);
+mlan_status wlan_get_curr_oper_class(mlan_private *pmpriv, t_u8 channel,
+ t_u8 bw, t_u8 *oper_class);
+mlan_status wlan_check_operclass_validation(mlan_private *pmpriv, t_u8 channel,
+ t_u8 oper_class);
+mlan_status wlan_misc_ioctl_operclass_validation(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+mlan_status wlan_misc_ioctl_oper_class(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+
+t_u16 wlan_adjust_data_rate(mlan_private *priv, t_u8 rx_rate, t_u8 rate_info);
+t_u8 wlan_adjust_antenna(pmlan_private priv, RxPD *prx_pd);
+
+mlan_status wlan_misc_otp_user_data(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef USB
+mlan_status wlan_misc_ioctl_usb_aggr_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+mlan_status wlan_misc_ioctl_aggr_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_packet_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_packet_aggr_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+mlan_status wlan_misc_ioctl_txcontrol(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_region(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+#ifdef RX_PACKET_COALESCE
+mlan_status wlan_misc_ioctl_rx_pkt_coalesce_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif
+
+void wlan_bt_coex_wlan_param_update_event(pmlan_private priv,
+ pmlan_buffer pevent);
+
+mlan_status wlan_misc_ioctl_dfs_repeater_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+t_bool wlan_check_interface_active(mlan_adapter *pmadapter);
+
+mlan_status wlan_misc_ioctl_coalesce_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_low_pwr_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_pmic_configure(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_cwmode_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_set_mef_entry(mlan_private *pmpriv, pmlan_adapter pmadapter,
+ mef_cfg *pmef);
+mlan_status wlan_process_mef_cfg_cmd(mlan_private *pmpriv,
+ pmlan_adapter pmadapter);
+mlan_status wlan_misc_ioctl_mef_flt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_ind_rst_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_ind_rst_cfg(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_ind_rst_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_802_11_supplicant_pmk(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+
+mlan_status wlan_ret_802_11_supplicant_pmk(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_sec_ioctl_passphrase(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_get_tsf(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+void wlan_add_fw_cfp_tables(pmlan_private pmpriv, t_u8 *buf, t_u16 buf_left);
+
+void wlan_free_fw_cfp_tables(mlan_adapter *pmadapter);
+
+mlan_status wlan_misc_chan_reg_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_get_cfp_table(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_get_cfpinfo(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_cmd_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action);
+mlan_status wlan_ret_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+t_u8 wlan_ft_akm_is_used(mlan_private *pmpriv, t_u8 *rsn_ie);
+
+mlan_status wlan_get_rgchnpwr_cfg(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+mlan_status wlan_get_chan_trpc_cfg(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+mlan_status wlan_cmd_get_chan_trpc_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_get_chan_trpc_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_ps_inactivity_timeout(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+
+t_u8 wlan_ieee_rateid_to_mrvl_rateid(mlan_private *priv, t_u16 IeeeMacRate,
+ t_u8 *dst_mac);
+t_u8 wlan_mrvl_rateid_to_ieee_rateid(t_u8 rate);
+
+t_u8 wlan_get_center_freq_idx(mlan_private *pmpriv, t_u16 band, t_u32 pri_chan,
+ t_u8 chan_bw);
+
+mlan_status wlan_ret_chan_region_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_misc_ioctl_fw_dump_event(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+mlan_status wlan_cmd_fw_dump_event(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+
+mlan_status wlan_misc_bootsleep(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_misc_ioctl_dyn_bw(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req);
+mlan_status wlan_cmd_config_dyn_bw(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_dyn_bw(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_power_ioctl_set_get_lpm(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+mlan_status wlan_cmd_set_get_low_power_mode_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_ret_set_get_low_power_mode_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_cmd_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf);
+mlan_status wlan_ret_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+/**
+ * @brief RA based queueing
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE t_u8 queuing_ra_based(pmlan_private priv)
+{
+ /*
+ * Currently we assume if we are in Infra, then DA=RA. This might not be
+ * true in the future
+ */
+ if ((priv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA))
+ return MFALSE;
+
+ return MTRUE;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param pos The position for copy
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ *
+ * @return Number of Rates copied
+ */
+static INLINE t_u32 wlan_copy_rates(t_u8 *dest, t_u32 pos, t_u8 *src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(WLAN_802_11_RATES))
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief strlen
+ *
+ * @param str A pointer to string
+ *
+ * @return Length of string
+ */
+static INLINE t_u32 wlan_strlen(const char *str)
+{
+ t_u32 i;
+
+ for (i = 0; str[i] != 0; i++)
+ ;
+
+ return i;
+}
+
+/**
+ * @brief iscdigit
+ *
+ * @param chr A char
+ *
+ * @return Non zero if chr is a hex, else 0
+ */
+static INLINE t_u32 wlan_isxdigit(t_u8 chr)
+{
+ return (chr <= 'f' && chr >= 'a') || (chr <= 'F' && chr >= 'A') ||
+ (chr <= '9' && chr >= '0');
+}
+
+/**
+ * @brief isspace
+ *
+ * @param A chr
+ *
+ * @return Non zero if chr is space etc, else 0
+ */
+static INLINE t_u32 wlan_isspace(t_u8 chr)
+{
+ return chr <= ' ' && (chr == ' ' || (chr <= 13 && chr >= 9));
+}
+
+/** delay unit */
+typedef enum _delay_unit {
+ USEC,
+ MSEC,
+ SEC,
+} t_delay_unit;
+
+/** delay function */
+t_void wlan_delay_func(mlan_adapter *pmadapter, t_u32 delay, t_delay_unit u);
+
+/** delay function wrapper */
+#define wlan_delay(p, n) wlan_delay_func(p, n, SEC)
+/** delay function wrapper */
+#define wlan_mdelay(p, n) wlan_delay_func(p, n, MSEC)
+/** delay function wrapper */
+#define wlan_udelay(p, n) wlan_delay_func(p, n, USEC)
+
+/**
+ * @brief This function check if there are pending cmd
+ * in cmd pending Q
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MTRUE -- cmd pending
+ * MFALSE -- no pending cmd
+ */
+static INLINE int wlan_is_cmd_pending(mlan_adapter *pmadapter)
+{
+ int ret;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ wlan_request_cmd_lock(pmadapter);
+ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q,
+ MNULL, MNULL);
+ if (pcmd_node)
+ ret = MTRUE;
+ else
+ ret = MFALSE;
+ wlan_release_cmd_lock(pmadapter);
+ return ret;
+}
+
+/** Get BSS number from priv */
+#define GET_BSS_NUM(priv) ((priv)->bss_num)
+
+/**
+ * @brief This function returns priv based on the BSS num and BSS type
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_num BSS number
+ * @param bss_type BSS type
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *wlan_get_priv_by_id(mlan_adapter *pmadapter,
+ t_u32 bss_num, t_u32 bss_type)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if ((pmadapter->priv[i]->bss_num == bss_num) &&
+ (pmadapter->priv[i]->bss_type == bss_type))
+ return pmadapter->priv[i];
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to mlan_private
+ */
+static INLINE mlan_private *wlan_get_priv(mlan_adapter *pmadapter,
+ mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(pmadapter->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (pmadapter->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(pmadapter->priv[i]) == bss_role)
+ return pmadapter->priv[i];
+ }
+ }
+ return MNULL;
+}
+
+/**
+ * @brief This function counts the number of occurences for a certain
+ * condition among privs. Which privs are checked can be configured
+ * via a second condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param count_cond Function pointer to condition to count on privs
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be counted or not. Use MNULL to check all privs.
+ *
+ * @return Count of privs where count_cond returned MTRUE.
+ */
+static INLINE int
+wlan_count_priv_cond(mlan_adapter *pmadapter,
+ t_bool (*count_cond)(pmlan_private pmpriv),
+ t_bool (*check_cond)(pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || count_cond == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv) {
+ if ((check_cond == MNULL) ||
+ (check_cond && check_cond(pmpriv))) {
+ if (count_cond(pmpriv))
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function runs a procedure on each priv.
+ * Which privs it is run on can be configured via a condition.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param operation Function pointer to produedure to operate on priv
+ * @param check_cond Function pointer to condition to decide whether priv
+ * operated on or not. Use MNULL to run on all privs.
+ *
+ * @return Number of privs that operation was run on.
+ */
+static INLINE int
+wlan_do_task_on_privs(mlan_adapter *pmadapter,
+ t_void (*operation)(pmlan_private pmpriv),
+ t_bool (*check_cond)(pmlan_private pmpriv))
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || operation == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv) {
+ if ((check_cond == MNULL) ||
+ (check_cond && check_cond(pmpriv))) {
+ operation(pmpriv);
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test for a condition
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. For one-off tasks, the above two functions might be better.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param ppriv_list Output param. Externally supplied array of mlan_private*
+ * to hold priv's that test positive with check_cond.
+ * Array size should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond
+ */
+static INLINE int
+wlan_get_privs_by_cond(mlan_adapter *pmadapter,
+ t_bool (*check_cond)(pmlan_private pmpriv),
+ mlan_private **ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv) {
+ if (check_cond(pmpriv))
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+
+ return count;
+}
+
+/**
+ * @brief This function builds a list of privs that test against two conditions
+ * This is useful if you need to do a number of operations on the same set
+ * of privs. Can choose whether both conditions (AND) or either condition (OR)
+ * is required.
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param check_cond Function pointer to condition to decide whether priv
+ * should be placed in the list.
+ * @param check_cond_2 Function pointer to second condition to check.
+ * @param and_conditions If MTRUE, both conditions must be met (AND),
+ * else either condition can be met (OR).
+ * @param ppriv_list Output param. Externally supplied array of
+ * mlan_private* to hold priv's that test positive with check_cond. Array size
+ * should be at least pmadapter->priv_num.
+ *
+ * @return Number of privs in ppriv_list
+ *
+ * @sa wlan_count_priv_cond, wlan_get_privs_by_cond
+ */
+static INLINE int
+wlan_get_privs_by_two_cond(mlan_adapter *pmadapter,
+ t_bool (*check_cond)(pmlan_private pmpriv),
+ t_bool (*check_cond_2)(pmlan_private pmpriv),
+ t_bool and_conditions, mlan_private **ppriv_list)
+{
+ pmlan_private pmpriv;
+ int count = 0;
+ int i;
+
+ if (pmadapter == MNULL || check_cond == MNULL ||
+ check_cond_2 == MNULL || ppriv_list == MNULL)
+ return 0;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv) {
+ if (and_conditions) {
+ if (check_cond(pmpriv) && check_cond_2(pmpriv))
+ ppriv_list[count++] = pmpriv;
+ } else {
+ if (check_cond(pmpriv) || check_cond_2(pmpriv))
+ ppriv_list[count++] = pmpriv;
+ }
+ }
+ }
+
+ return count;
+}
+#endif /* !_MLAN_MAIN_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.c
new file mode 100644
index 000000000000..38d16af57732
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.c
@@ -0,0 +1,465 @@
+/**
+ * @file mlan_meas.c
+ *
+ * @brief Implementation of measurement interface code with the app/firmware
+ *
+ * Driver implementation for sending and retrieving measurement requests
+ * and responses.
+ *
+ * Current use is limited to 802.11h.
+ *
+ * Requires use of the following preprocessor define:
+ * - ENABLE_MEAS
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/24/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_ioctl.h"
+#include "mlan_meas.h"
+
+/** Default measurement duration when not provided by the application */
+#define WLAN_MEAS_DEFAULT_MEAS_DURATION 1000U /* TUs */
+
+#ifdef DEBUG_LEVEL2
+/** String descriptions of the different measurement enums. Debug display */
+static const char *meas_type_str[WLAN_MEAS_NUM_TYPES] = {
+ "basic",
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Retrieve the measurement string representation of a meas_type enum
+ * Used for debug display only
+ *
+ * @param meas_type Measurement type enumeration input for string lookup
+ *
+ * @return Constant string representing measurement type
+ */
+static const char *wlan_meas_get_meas_type_str(MeasType_t meas_type)
+{
+ if (meas_type <= WLAN_MEAS_11H_MAX_TYPE)
+ return meas_type_str[meas_type];
+
+ return "Invld";
+}
+#endif
+
+/**
+ * @brief Debug print display of the input measurement request
+ *
+ * @param pmeas_req Pointer to the measurement request to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+
+ PRINTM(MINFO, "Meas: Req: mac_addr: " MACSTR "\n",
+ MAC2STR(pmeas_req->mac_addr));
+
+ PRINTM(MINFO, "Meas: Req: dlgTkn: %d\n", pmeas_req->dialog_token);
+ PRINTM(MINFO, "Meas: Req: mode: dm[%c] rpt[%c] req[%c]\n",
+ pmeas_req->req_mode.duration_mandatory ? 'X' : ' ',
+ pmeas_req->req_mode.report ? 'X' : ' ',
+ pmeas_req->req_mode.request ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Req: : en[%c] par[%c]\n",
+ pmeas_req->req_mode.enable ? 'X' : ' ',
+ pmeas_req->req_mode.parallel ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Req: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_req->meas_type));
+#endif
+
+ switch (pmeas_req->meas_type) {
+ case WLAN_MEAS_BASIC:
+ /* Lazy cheat, fields of bas, cca, rpi union match on the
+ * request */
+ PRINTM(MINFO, "Meas: Req: chan: %u\n",
+ pmeas_req->req.basic.channel);
+ PRINTM(MINFO, "Meas: Req: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_req->req.basic.start_time));
+ PRINTM(MINFO, "Meas: Req: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_req->req.basic.duration));
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Req: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Req: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Debug print display of the input measurement report
+ *
+ * @param pmeas_rpt Pointer to measurement report to display
+ *
+ * @return N/A
+ */
+static void
+wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt)
+{
+ MeasType_t type;
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ PRINTM(MINFO, "Meas: Rpt: mac_addr: " MACSTR "\n",
+ MAC2STR(pmeas_rpt->mac_addr));
+
+ PRINTM(MINFO, "Meas: Rpt: dlgTkn: %d\n", pmeas_rpt->dialog_token);
+
+ PRINTM(MINFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n",
+ *(t_u8 *)&pmeas_rpt->rpt_mode,
+ pmeas_rpt->rpt_mode.refused ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.incapable ? 'X' : ' ',
+ pmeas_rpt->rpt_mode.late ? 'X' : ' ');
+#ifdef DEBUG_LEVEL2
+ PRINTM(MINFO, "Meas: Rpt: measTyp: %s\n",
+ wlan_meas_get_meas_type_str(pmeas_rpt->meas_type));
+#endif
+
+ type = wlan_le32_to_cpu(pmeas_rpt->meas_type);
+ switch (type) {
+ case WLAN_MEAS_BASIC:
+ PRINTM(MINFO, "Meas: Rpt: chan: %u\n",
+ pmeas_rpt->rpt.basic.channel);
+ PRINTM(MINFO, "Meas: Rpt: strt: %llu\n",
+ wlan_le64_to_cpu(pmeas_rpt->rpt.basic.start_time));
+ PRINTM(MINFO, "Meas: Rpt: dur: %u\n",
+ wlan_le16_to_cpu(pmeas_rpt->rpt.basic.duration));
+ PRINTM(MINFO, "Meas: Rpt: bas: (%x): unmsd[%c], radar[%c]\n",
+ *(t_u8 *)&(pmeas_rpt->rpt.basic.map),
+ pmeas_rpt->rpt.basic.map.unmeasured ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.radar ? 'X' : ' ');
+ PRINTM(MINFO, "Meas: Rpt: bas: unidSig[%c] ofdm[%c] bss[%c]\n",
+ pmeas_rpt->rpt.basic.map.unidentified_sig ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.ofdm_preamble ? 'X' : ' ',
+ pmeas_rpt->rpt.basic.map.bss ? 'X' : ' ');
+ break;
+ default:
+ PRINTM(MINFO, "Meas: Rpt: <unhandled>\n");
+ break;
+ }
+
+ PRINTM(MINFO, "Meas: Rpt: ------------------------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * Callback from command processing when a measurement report is received
+ * from the firmware. Perform the following when a report is received:
+ *
+ * -# Debug displays the report if compiled with the appropriate flags
+ * -# If we are pending on a specific measurement report token, and it
+ * matches the received report's token, store the report and wake up
+ * any pending threads
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ * passing a HostCmd_DS_MEASUREMENT_REPORT structure.
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int wlan_meas_cmdresp_get_report(mlan_private *pmpriv,
+ const HostCmd_DS_COMMAND *resp)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt = &resp->params.meas_rpt;
+
+ ENTER();
+
+ PRINTM(MINFO, "Meas: Rpt: %#x-%u, Seq=%u, Ret=%u\n", resp->command,
+ resp->size, resp->seq_num, resp->result);
+
+ /* Debug displays the measurement report */
+ wlan_meas_dump_meas_rpt(pmeas_rpt);
+
+ /*
+ * Check if we are pending on a measurement report and it matches
+ * the dialog token of the received report:
+ */
+ if (pmadapter->state_meas.meas_rpt_pend_on &&
+ pmadapter->state_meas.meas_rpt_pend_on == pmeas_rpt->dialog_token) {
+ PRINTM(MINFO, "Meas: Rpt: RCV'd Pend on meas #%d\n",
+ pmadapter->state_meas.meas_rpt_pend_on);
+
+ /* Clear the pending report indicator */
+ pmadapter->state_meas.meas_rpt_pend_on = 0;
+
+ /* Copy the received report into the measurement state for
+ * retrieval */
+ memcpy_ext(pmadapter, &pmadapter->state_meas.meas_rpt_returned,
+ pmeas_rpt,
+ sizeof(pmadapter->state_meas.meas_rpt_returned),
+ sizeof(pmadapter->state_meas.meas_rpt_returned));
+
+ /*
+ * Wake up any threads pending on the wait queue
+ */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ }
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Prepare CMD_MEASURMENT_REPORT firmware command
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf HostCmd_DS_MEASUREMENT_REQUEST passed as void data block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int wlan_meas_cmd_request(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const void *pinfo_buf)
+{
+ const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req =
+ (HostCmd_DS_MEASUREMENT_REQUEST *)pinfo_buf;
+
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REQUEST;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REQUEST) + S_DS_GEN;
+
+ memcpy_ext(pmpriv->adapter, &pcmd_ptr->params.meas_req, pmeas_req,
+ sizeof(pcmd_ptr->params.meas_req),
+ sizeof(pcmd_ptr->params.meas_req));
+
+ PRINTM(MINFO, "Meas: Req: %#x-%u, Seq=%u, Ret=%u\n", pcmd_ptr->command,
+ pcmd_ptr->size, pcmd_ptr->seq_num, pcmd_ptr->result);
+
+ wlan_meas_dump_meas_req(pmeas_req);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieve a measurement report from the firmware
+ *
+ * The firmware will send a EVENT_MEAS_REPORT_RDY event when it
+ * completes or receives a measurement report. The event response
+ * handler will then start a HostCmd_CMD_MEASUREMENT_REPORT firmware command
+ * which gets completed for transmission to the firmware in this routine.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int wlan_meas_cmd_get_report(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd_ptr)
+{
+ ENTER();
+
+ pcmd_ptr->command = HostCmd_CMD_MEASUREMENT_REPORT;
+ pcmd_ptr->size = sizeof(HostCmd_DS_MEASUREMENT_REPORT) + S_DS_GEN;
+
+ memset(pmpriv->adapter, &pcmd_ptr->params.meas_rpt, 0x00,
+ sizeof(pcmd_ptr->params.meas_rpt));
+
+ /*
+ * Set the meas_rpt.mac_addr to our mac address to get a meas report,
+ * setting the mac to another STA address instructs the firmware
+ * to transmit this measurement report frame instead
+ */
+ memcpy_ext(pmpriv->adapter, pcmd_ptr->params.meas_rpt.mac_addr,
+ pmpriv->curr_addr,
+ sizeof(pcmd_ptr->params.meas_rpt.mac_addr),
+ sizeof(pcmd_ptr->params.meas_rpt.mac_addr));
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief Send the input measurement request to the firmware.
+ *
+ * If the dialog token in the measurement request is set to 0, the function
+ * will use an local static auto-incremented token in the measurement
+ * request. This ensures the dialog token is always set.
+ *
+ * If wait_for_resp_timeout is set, the function will block its return on
+ * a timeout or returned measurement report that matches the requests
+ * dialog token.
+ *
+ * @param pmpriv Private driver information structure
+ * @param pmeas_req Pointer to the measurement request to send
+ * @param wait_for_resp_timeout Timeout value of the measurement request
+ * in ms.
+ * @param pioctl_req Pointer to IOCTL request buffer
+ * @param pmeas_rpt Output parameter: Pointer for the resulting
+ * measurement report
+ *
+ * @return
+ * - 0 for success
+ * - -ETIMEDOUT if the measurement report does not return before
+ * the timeout expires
+ * - Error return from wlan_prepare_cmd routine otherwise
+ */
+int wlan_meas_util_send_req(mlan_private *pmpriv,
+ HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req,
+ t_u32 wait_for_resp_timeout,
+ pmlan_ioctl_req pioctl_req,
+ HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt)
+{
+ static t_u8 auto_dialog_tok;
+ wlan_meas_state_t *pmeas_state = &pmpriv->adapter->state_meas;
+ int ret;
+
+ ENTER();
+
+ /* If dialogTok was set to 0 or not provided, autoset */
+ pmeas_req->dialog_token =
+ (pmeas_req->dialog_token ? pmeas_req->dialog_token :
+ ++auto_dialog_tok);
+
+ /* Check for rollover of the dialog token. Avoid using 0 as a token */
+ pmeas_req->dialog_token =
+ (pmeas_req->dialog_token ? pmeas_req->dialog_token : 1);
+
+ /*
+ * If the request is to pend waiting for the result, set the dialog
+ * token of this measurement request in the state structure. The
+ * measurement report handling routines can then check the incoming
+ * measurement reports for a match with this dialog token.
+ */
+ if (wait_for_resp_timeout) {
+ pmeas_state->meas_rpt_pend_on = pmeas_req->dialog_token;
+ PRINTM(MINFO, "Meas: Req: START Pend on meas #%d\n",
+ pmeas_req->dialog_token);
+ }
+
+ /* Send the measurement request to the firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEASUREMENT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (void *)pmeas_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare the HostCmd_DS_Command structure for a measurement command.
+ *
+ * Use the Command field to determine if the command being set up is for
+ * 11h and call one of the local command handlers accordingly for:
+ *
+ * - HostCmd_CMD_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param pcmd_ptr Output parameter: Pointer to the command being prepared
+ * for the firmware
+ * @param pinfo_buf Void buffer passthrough with data necessary for a
+ * specific command type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+int wlan_meas_cmd_process(mlan_private *pmpriv, HostCmd_DS_COMMAND *pcmd_ptr,
+ const void *pinfo_buf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (pcmd_ptr->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ ret = wlan_meas_cmd_request(pmpriv, pcmd_ptr, pinfo_buf);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_get_report(pmpriv, pcmd_ptr);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
+ pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle the command response from the firmware for a measurement
+ * command
+ *
+ * Use the Command field to determine if the command response being
+ * is for meas. Call the local command response handler accordingly for:
+ *
+ * - HostCmd_CMD_802_MEASUREMENT_REQUEST
+ * - HostCmd_CMD_802_MEASUREMENT_REPORT
+ *
+ * @param pmpriv Private driver information structure
+ * @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int wlan_meas_cmdresp_process(mlan_private *pmpriv,
+ const HostCmd_DS_COMMAND *resp)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ switch (resp->command) {
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ PRINTM(MINFO, "Meas: Req Resp: Sz=%u, Seq=%u, Ret=%u\n",
+ resp->size, resp->seq_num, resp->result);
+ break;
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_get_report(pmpriv, resp);
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.h
new file mode 100644
index 000000000000..c69f41890787
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_meas.h
@@ -0,0 +1,55 @@
+/**
+ * @file mlan_meas.h
+ *
+ * @brief Interface for the measurement module implemented in mlan_meas.c
+ *
+ * Driver interface functions and type declarations for the measurement module
+ * implemented in mlan_meas.c
+ *
+ * @sa mlan_meas.c
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 03/25/2009: initial version
+************************************************************/
+
+#ifndef _MLAN_MEAS_H_
+#define _MLAN_MEAS_H_
+
+#include "mlan_fw.h"
+
+/* Send a given measurement request to the firmware, report back the result */
+extern int wlan_meas_util_send_req(pmlan_private pmpriv,
+ pHostCmd_DS_MEASUREMENT_REQUEST pmeas_req,
+ t_u32 wait_for_resp_timeout,
+ pmlan_ioctl_req pioctl_req,
+ pHostCmd_DS_MEASUREMENT_REPORT pmeas_rpt);
+
+/* Setup a measurement command before it is sent to the firmware */
+extern int wlan_meas_cmd_process(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd_ptr,
+ const t_void *pinfo_buf);
+
+/* Handle a given measurement command response from the firmware */
+extern int wlan_meas_cmdresp_process(mlan_private *pmpriv,
+ const HostCmd_DS_COMMAND *resp);
+
+#endif /* _MLAN_MEAS_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_misc.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_misc.c
new file mode 100644
index 000000000000..a6208fa5e5e9
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_misc.c
@@ -0,0 +1,5866 @@
+/**
+ * @file mlan_misc.c
+ *
+ * @brief This file include miscellaneous functions for MLAN module
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif /* STA_SUPPORT */
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+#include "authenticator_api.h"
+#endif
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+extern pmlan_operations mlan_ops[];
+#endif
+extern t_u8 ac_to_tid[4][2];
+
+/********************************************************
+ Local Functions
+********************************************************/
+#if defined(PCIE) || defined(SDIO)
+/**
+ * @brief Check pending irq
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MTRUE/MFALSE;
+ */
+t_u8 wlan_pending_interrupt(pmlan_adapter pmadapter)
+{
+ if (!IS_USB(pmadapter->card_type) && pmadapter->ireg)
+ return MTRUE;
+ return MFALSE;
+}
+#endif
+
+/** Custom IE auto index and mask */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+/** Custom IE mask for delete operation */
+#define MLAN_CUSTOM_IE_DELETE_MASK 0
+/** Custom IE mask for create new index */
+#define MLAN_CUSTOM_IE_NEW_MASK 0x8000
+/** Custom IE header size */
+#define MLAN_CUSTOM_IE_HDR_SIZE (sizeof(custom_ie) - MAX_IE_SIZE)
+
+/**
+ * @brief Check if current custom IE index is used on other interfaces.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param idx index to check for in use
+ *
+ * @return MLAN_STATUS_SUCCESS --unused, otherwise used.
+ */
+static mlan_status wlan_is_custom_ie_index_unused(pmlan_private pmpriv,
+ t_u16 idx)
+{
+ t_u8 i = 0;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_private priv;
+ ENTER();
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ priv = pmadapter->priv[i];
+ /* Check for other interfaces only */
+ if (priv && priv->bss_index != pmpriv->bss_index) {
+ if (priv->mgmt_ie[idx].mgmt_subtype_mask &&
+ priv->mgmt_ie[idx].ie_length) {
+ /* used entry found */
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get the custom IE index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param mask mask value for which the index to be returned
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx will hold the computed index
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_custom_ioctl_get_autoidx(pmlan_private pmpriv,
+ pmlan_ioctl_req pioctl_req,
+ t_u16 mask, custom_ie *ie_data,
+ t_u16 *idx)
+{
+ t_u16 index = 0, insert = MFALSE;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Determine the index where the IE needs to be inserted */
+ while (!insert) {
+ while (index < MIN(pmpriv->adapter->max_mgmt_ie_index,
+ MAX_MGMT_IE_INDEX)) {
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ index++;
+ continue;
+ }
+ if (pmpriv->mgmt_ie[index].mgmt_subtype_mask == mask) {
+ /* Duplicate IE should be avoided */
+ if (pmpriv->mgmt_ie[index].ie_length) {
+ if (!memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index]
+ .ie_buffer,
+ ie_data->ie_buffer,
+ pmpriv->mgmt_ie[index]
+ .ie_length)) {
+ PRINTM(MINFO,
+ "IE with the same mask exists at index %d mask=0x%x\n",
+ index, mask);
+ *idx = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ goto done;
+ }
+ }
+ /* Check if enough space is available */
+ if (pmpriv->mgmt_ie[index].ie_length +
+ ie_data->ie_length >
+ MAX_IE_SIZE) {
+ index++;
+ continue;
+ }
+ insert = MTRUE;
+ break;
+ }
+ index++;
+ }
+ if (!insert) {
+ for (index = 0;
+ index < MIN(pmpriv->adapter->max_mgmt_ie_index,
+ MAX_MGMT_IE_INDEX);
+ index++) {
+ if (pmpriv->mgmt_ie[index].ie_length == 0) {
+ /*
+ * Check if this index is in use
+ * by other interface If yes,
+ * move ahead to next index
+ */
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_is_custom_ie_index_unused(
+ pmpriv, index)) {
+ insert = MTRUE;
+ break;
+ } else {
+ PRINTM(MINFO,
+ "Skipping IE index %d in use.\n",
+ index);
+ }
+ }
+ }
+ }
+ if (index == pmpriv->adapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Set the IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ *idx = index;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Delete custom IE
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ie_data a pointer to custom_ie structure
+ * @param idx index supplied
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+
+static mlan_status wlan_custom_ioctl_auto_delete(pmlan_private pmpriv,
+ pmlan_ioctl_req pioctl_req,
+ custom_ie *ie_data, t_u16 idx)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u16 index = 0, insert = MFALSE, del_len;
+ t_u8 del_ie[MAX_IE_SIZE], ie[MAX_IE_SIZE];
+ t_s32 cnt, tmp_len = 0;
+ t_u8 *tmp_ie;
+
+ ENTER();
+ memset(pmpriv->adapter, del_ie, 0, MAX_IE_SIZE);
+ memcpy_ext(pmpriv->adapter, del_ie, ie_data->ie_buffer,
+ ie_data->ie_length, MAX_IE_SIZE);
+ del_len = MIN(MAX_IE_SIZE - 1, ie_data->ie_length);
+
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx)
+ ie_data->ie_index = 0;
+
+ for (index = 0;
+ index < MIN(pmadapter->max_mgmt_ie_index, MAX_MGMT_IE_INDEX);
+ index++) {
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx &&
+ idx < MAX_MGMT_IE_INDEX)
+ index = idx;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ while (tmp_len) {
+ if (!memcmp(pmpriv->adapter, tmp_ie, del_ie, del_len)) {
+ memcpy_ext(pmpriv->adapter, ie,
+ pmpriv->mgmt_ie[index].ie_buffer,
+ cnt, MAX_IE_SIZE);
+ if (pmpriv->mgmt_ie[index].ie_length >
+ (cnt + del_len))
+ memcpy_ext(
+ pmpriv->adapter, &ie[cnt],
+ &pmpriv->mgmt_ie[index].ie_buffer
+ [MIN((MAX_IE_SIZE - 1),
+ (cnt + del_len))],
+ (pmpriv->mgmt_ie[index]
+ .ie_length -
+ (cnt + del_len)),
+ MAX_IE_SIZE - cnt);
+ memset(pmpriv->adapter,
+ &pmpriv->mgmt_ie[index].ie_buffer, 0,
+ sizeof(pmpriv->mgmt_ie[index].ie_buffer));
+ memcpy_ext(pmpriv->adapter,
+ &pmpriv->mgmt_ie[index].ie_buffer,
+ ie,
+ pmpriv->mgmt_ie[index].ie_length -
+ del_len,
+ MAX_IE_SIZE);
+ pmpriv->mgmt_ie[index].ie_length -= del_len;
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == idx)
+ /* set a bit to indicate caller about
+ * update */
+ ie_data->ie_index |=
+ (((t_u16)1) << index);
+ insert = MTRUE;
+ tmp_ie = pmpriv->mgmt_ie[index].ie_buffer;
+ tmp_len = pmpriv->mgmt_ie[index].ie_length;
+ cnt = 0;
+ continue;
+ }
+ tmp_ie++;
+ tmp_len--;
+ cnt++;
+ }
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK != idx)
+ break;
+ }
+ if (index == pmadapter->max_mgmt_ie_index && !insert) {
+ PRINTM(MERROR, "Failed to Clear IE buffer\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief send host cmd
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_host_cmd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req,
+ (t_void *)&misc->param.hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function init/shutdown command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_init_shutdown(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd;
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_INIT)
+ cmd = HostCmd_CMD_FUNC_INIT;
+ else if (misc_cfg->param.func_init_shutdown == MLAN_FUNC_SHUTDOWN)
+ cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+ else {
+ PRINTM(MERROR, "Unsupported parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd, HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get debug information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status wlan_get_info_debug_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ mlan_debug_info *debug_info = MNULL;
+ t_u32 i;
+ t_u8 *ptid;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *)pioctl_req->pbuf;
+ debug_info = (mlan_debug_info *)info->param.debug_info;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ptid = ac_to_tid[WMM_AC_BK];
+ debug_info->wmm_ac_bk = pmpriv->wmm.packets_out[ptid[0]] +
+ pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_BE];
+ debug_info->wmm_ac_be = pmpriv->wmm.packets_out[ptid[0]] +
+ pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VI];
+ debug_info->wmm_ac_vi = pmpriv->wmm.packets_out[ptid[0]] +
+ pmpriv->wmm.packets_out[ptid[1]];
+ ptid = ac_to_tid[WMM_AC_VO];
+ debug_info->wmm_ac_vo = pmpriv->wmm.packets_out[ptid[0]] +
+ pmpriv->wmm.packets_out[ptid[1]];
+ debug_info->max_tx_buf_size = (t_u32)pmadapter->max_tx_buf_size;
+ debug_info->tx_buf_size = (t_u32)pmadapter->tx_buf_size;
+ debug_info->curr_tx_buf_size =
+ (t_u32)pmadapter->curr_tx_buf_size;
+ debug_info->rx_tbl_num =
+ wlan_get_rxreorder_tbl(pmpriv, debug_info->rx_tbl);
+ debug_info->tx_tbl_num =
+ wlan_get_txbastream_tbl(pmpriv, debug_info->tx_tbl);
+ debug_info->ralist_num =
+ wlan_get_ralist_info(pmpriv, debug_info->ralist);
+ debug_info->ps_mode = pmadapter->ps_mode;
+ debug_info->ps_state = pmadapter->ps_state;
+#ifdef STA_SUPPORT
+ debug_info->is_deep_sleep = pmadapter->is_deep_sleep;
+#endif /* STA_SUPPORT */
+ debug_info->pm_wakeup_card_req = pmadapter->pm_wakeup_card_req;
+ debug_info->pm_wakeup_fw_try = pmadapter->pm_wakeup_fw_try;
+ debug_info->pm_wakeup_in_secs = pmadapter->pm_wakeup_in_secs;
+ debug_info->pm_wakeup_timeout = pmadapter->pm_wakeup_timeout;
+ debug_info->is_hs_configured = pmadapter->is_hs_configured;
+ debug_info->hs_activated = pmadapter->hs_activated;
+ debug_info->pps_uapsd_mode = pmadapter->pps_uapsd_mode;
+ debug_info->sleep_pd = pmadapter->sleep_period.period;
+ debug_info->qos_cfg = pmpriv->wmm_qosinfo;
+ debug_info->tx_lock_flag = pmadapter->tx_lock_flag;
+ debug_info->port_open = pmpriv->port_open;
+ debug_info->bypass_pkt_count = pmadapter->bypass_pkt_count;
+ debug_info->scan_processing = pmadapter->scan_processing;
+ debug_info->mlan_processing = pmadapter->mlan_processing;
+ debug_info->main_lock_flag = pmadapter->main_lock_flag;
+ debug_info->main_process_cnt = pmadapter->main_process_cnt;
+ debug_info->delay_task_flag = pmadapter->delay_task_flag;
+ debug_info->num_cmd_host_to_card_failure =
+ pmadapter->dbg.num_cmd_host_to_card_failure;
+ debug_info->num_cmd_sleep_cfm_host_to_card_failure =
+ pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+ debug_info->num_tx_host_to_card_failure =
+ pmadapter->dbg.num_tx_host_to_card_failure;
+ debug_info->num_alloc_buffer_failure =
+ pmadapter->dbg.num_alloc_buffer_failure;
+ debug_info->num_pkt_dropped = pmadapter->dbg.num_pkt_dropped;
+
+ debug_info->num_event_deauth = pmadapter->dbg.num_event_deauth;
+ debug_info->num_event_disassoc =
+ pmadapter->dbg.num_event_disassoc;
+ debug_info->num_event_link_lost =
+ pmadapter->dbg.num_event_link_lost;
+ debug_info->num_cmd_deauth = pmadapter->dbg.num_cmd_deauth;
+ debug_info->num_cmd_assoc_success =
+ pmadapter->dbg.num_cmd_assoc_success;
+ debug_info->num_cmd_assoc_failure =
+ pmadapter->dbg.num_cmd_assoc_failure;
+ debug_info->num_cmd_timeout = pmadapter->num_cmd_timeout;
+ debug_info->timeout_cmd_id = pmadapter->dbg.timeout_cmd_id;
+ debug_info->timeout_cmd_act = pmadapter->dbg.timeout_cmd_act;
+ memcpy_ext(pmadapter, debug_info->last_cmd_id,
+ pmadapter->dbg.last_cmd_id,
+ sizeof(pmadapter->dbg.last_cmd_id),
+ sizeof(debug_info->last_cmd_id));
+ memcpy_ext(pmadapter, debug_info->last_cmd_act,
+ pmadapter->dbg.last_cmd_act,
+ sizeof(pmadapter->dbg.last_cmd_act),
+ sizeof(debug_info->last_cmd_act));
+ debug_info->last_cmd_index = pmadapter->dbg.last_cmd_index;
+ memcpy_ext(pmadapter, debug_info->last_cmd_resp_id,
+ pmadapter->dbg.last_cmd_resp_id,
+ sizeof(pmadapter->dbg.last_cmd_resp_id),
+ sizeof(debug_info->last_cmd_resp_id));
+ debug_info->last_cmd_resp_index =
+ pmadapter->dbg.last_cmd_resp_index;
+ memcpy_ext(pmadapter, debug_info->last_event,
+ pmadapter->dbg.last_event,
+ sizeof(pmadapter->dbg.last_event),
+ sizeof(debug_info->last_event));
+ debug_info->last_event_index = pmadapter->dbg.last_event_index;
+ debug_info->num_no_cmd_node = pmadapter->dbg.num_no_cmd_node;
+ debug_info->pending_cmd =
+ (pmadapter->curr_cmd) ?
+ pmadapter->dbg.last_cmd_id
+ [pmadapter->dbg.last_cmd_index] :
+ 0;
+ debug_info->dnld_cmd_in_secs = pmadapter->dnld_cmd_in_secs;
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ debug_info->num_cmdevt_card_to_host_failure =
+ pmadapter->dbg.num_cmdevt_card_to_host_failure;
+ debug_info->num_rx_card_to_host_failure =
+ pmadapter->dbg.num_rx_card_to_host_failure;
+ debug_info->num_int_read_failure =
+ pmadapter->dbg.num_int_read_failure;
+ debug_info->last_int_status =
+ pmadapter->dbg.last_int_status;
+ debug_info->mp_rd_bitmap =
+ pmadapter->pcard_sd->mp_rd_bitmap;
+ debug_info->mp_wr_bitmap =
+ pmadapter->pcard_sd->mp_wr_bitmap;
+ debug_info->curr_rd_port =
+ pmadapter->pcard_sd->curr_rd_port;
+ debug_info->curr_wr_port =
+ pmadapter->pcard_sd->curr_wr_port;
+ debug_info->mp_invalid_update =
+ pmadapter->pcard_sd->mp_invalid_update;
+ debug_info->num_of_irq =
+ pmadapter->pcard_sd->num_of_irq;
+ memcpy_ext(pmadapter, debug_info->mp_update,
+ pmadapter->pcard_sd->mp_update,
+ sizeof(pmadapter->pcard_sd->mp_update),
+ sizeof(debug_info->mp_update));
+ memcpy_ext(pmadapter, debug_info->mpa_tx_count,
+ pmadapter->pcard_sd->mpa_tx_count,
+ sizeof(pmadapter->pcard_sd->mpa_tx_count),
+ sizeof(debug_info->mpa_tx_count));
+ debug_info->mpa_sent_last_pkt =
+ pmadapter->pcard_sd->mpa_sent_last_pkt;
+ debug_info->mpa_sent_no_ports =
+ pmadapter->pcard_sd->mpa_sent_no_ports;
+ debug_info->last_recv_wr_bitmap =
+ pmadapter->pcard_sd->last_recv_wr_bitmap;
+ debug_info->last_mp_index =
+ pmadapter->pcard_sd->last_mp_index;
+ memcpy_ext(
+ pmadapter, debug_info->last_mp_wr_bitmap,
+ pmadapter->pcard_sd->last_mp_wr_bitmap,
+ sizeof(pmadapter->pcard_sd->last_mp_wr_bitmap),
+ sizeof(debug_info->last_mp_wr_bitmap));
+ memcpy_ext(
+ pmadapter, debug_info->last_mp_wr_ports,
+ pmadapter->pcard_sd->last_mp_wr_ports,
+ sizeof(pmadapter->pcard_sd->last_mp_wr_ports),
+ sizeof(debug_info->last_mp_wr_ports));
+ memcpy_ext(pmadapter, debug_info->last_mp_wr_len,
+ pmadapter->pcard_sd->last_mp_wr_len,
+ sizeof(pmadapter->pcard_sd->last_mp_wr_len),
+ sizeof(debug_info->last_mp_wr_len));
+ memcpy_ext(pmadapter, debug_info->last_mp_wr_info,
+ pmadapter->pcard_sd->last_mp_wr_info,
+ sizeof(pmadapter->pcard_sd->last_mp_wr_info),
+ sizeof(debug_info->last_mp_wr_info));
+ memcpy_ext(
+ pmadapter, debug_info->last_curr_wr_port,
+ pmadapter->pcard_sd->last_curr_wr_port,
+ sizeof(pmadapter->pcard_sd->last_curr_wr_port),
+ sizeof(debug_info->last_curr_wr_port));
+ debug_info->mpa_buf = pmadapter->pcard_sd->mpa_buf;
+ debug_info->mpa_buf_size =
+ pmadapter->pcard_sd->mpa_buf_size;
+ debug_info->sdio_rx_aggr =
+ pmadapter->pcard_sd->sdio_rx_aggr_enable;
+ memcpy_ext(pmadapter, debug_info->mpa_rx_count,
+ pmadapter->pcard_sd->mpa_rx_count,
+ sizeof(pmadapter->pcard_sd->mpa_rx_count),
+ sizeof(debug_info->mpa_rx_count));
+ debug_info->mp_aggr_pkt_limit =
+ SDIO_MP_AGGR_DEF_PKT_LIMIT;
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type)) {
+ debug_info->txbd_rdptr =
+ pmadapter->pcard_pcie->txbd_rdptr;
+ debug_info->txbd_wrptr =
+ pmadapter->pcard_pcie->txbd_wrptr;
+ debug_info->rxbd_rdptr =
+ pmadapter->pcard_pcie->rxbd_rdptr;
+ debug_info->rxbd_wrptr =
+ pmadapter->pcard_pcie->rxbd_wrptr;
+ debug_info->eventbd_rdptr =
+ pmadapter->pcard_pcie->evtbd_rdptr;
+ debug_info->eventbd_wrptr =
+ pmadapter->pcard_pcie->evtbd_wrptr;
+ debug_info->txbd_ring_vbase =
+ pmadapter->pcard_pcie->txbd_ring_vbase;
+ debug_info->txbd_ring_size =
+ pmadapter->pcard_pcie->txbd_ring_size;
+ debug_info->rxbd_ring_vbase =
+ pmadapter->pcard_pcie->rxbd_ring_vbase;
+ debug_info->rxbd_ring_size =
+ pmadapter->pcard_pcie->rxbd_ring_size;
+ debug_info->evtbd_ring_vbase =
+ pmadapter->pcard_pcie->evtbd_ring_vbase;
+ debug_info->evtbd_ring_size =
+ pmadapter->pcard_pcie->evtbd_ring_size;
+ memcpy_ext(
+ pmadapter, debug_info->last_tx_pkt_size,
+ pmadapter->pcard_pcie->last_tx_pkt_size,
+ sizeof(pmadapter->pcard_pcie->last_tx_pkt_size),
+ sizeof(debug_info->last_tx_pkt_size));
+ }
+#endif
+ debug_info->data_sent = pmadapter->data_sent;
+ debug_info->cmd_sent = pmadapter->cmd_sent;
+ debug_info->cmd_resp_received = pmadapter->cmd_resp_received;
+ debug_info->tx_pkts_queued =
+ util_scalar_read(pmadapter->pmoal_handle,
+ &pmpriv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+#ifdef UAP_SUPPORT
+ debug_info->num_bridge_pkts =
+ util_scalar_read(pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ debug_info->num_drop_pkts = pmpriv->num_drop_pkts;
+#endif
+ debug_info->fw_hang_report = pmadapter->fw_hang_report;
+ debug_info->mlan_processing = pmadapter->mlan_processing;
+ debug_info->mlan_rx_processing = pmadapter->mlan_rx_processing;
+ debug_info->rx_pkts_queued = pmadapter->rx_pkts_queued;
+ debug_info->mlan_adapter = pmadapter;
+ debug_info->mlan_adapter_size = sizeof(mlan_adapter);
+ debug_info->mlan_priv_num = pmadapter->priv_num;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ debug_info->mlan_priv[i] = pmadapter->priv[i];
+ debug_info->mlan_priv_size[i] = sizeof(mlan_private);
+ }
+ }
+
+ pioctl_req->data_read_written =
+ sizeof(mlan_debug_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get the MAC control configuration.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_mac_control(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.mac_ctrl = pmpriv->curr_pkt_filter;
+ } else {
+ pmpriv->curr_pkt_filter = misc->param.mac_ctrl;
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &misc->param.mac_ctrl);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This timer function handles wakeup card timeout.
+ *
+ * @param function_context A pointer to function_context
+ * @return N/A
+ */
+t_void wlan_wakeup_card_timeout_func(void *function_context)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter)function_context;
+
+ ENTER();
+
+ PRINTM(MERROR, "%s: ps_state=%d\n", __FUNCTION__, pmadapter->ps_state);
+ if (pmadapter->ps_state != PS_STATE_AWAKE) {
+ PRINTM(MERROR, "Wakeup card timeout!\n");
+ pmadapter->pm_wakeup_timeout++;
+ wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ }
+ pmadapter->wakeup_fw_timer_is_set = MFALSE;
+
+ LEAVE();
+}
+
+/**
+ * @brief Set/Get HS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_pm_ioctl_hscfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 prev_cond = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+#ifdef STA_SUPPORT
+ if (pmadapter->pps_uapsd_mode) {
+ PRINTM(MINFO,
+ "Host Sleep IOCTL is blocked in UAPSD/PPS mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+#endif /* STA_SUPPORT */
+ if (pm->param.hs_cfg.is_invoke_hostcmd == MTRUE) {
+ if (pm->param.hs_cfg.conditions ==
+ HOST_SLEEP_CFG_CANCEL) {
+ if (pmadapter->is_hs_configured == MFALSE) {
+ /* Already cancelled */
+ break;
+ }
+ /* Save previous condition */
+ prev_cond = pmadapter->hs_cfg.conditions;
+ pmadapter->hs_cfg.conditions =
+ pm->param.hs_cfg.conditions;
+ } else if (pmadapter->hs_cfg.conditions ==
+ HOST_SLEEP_CFG_CANCEL) {
+ /* Return failure if no parameters for HS enable
+ */
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)(&pmadapter->hs_cfg));
+ if (status == MLAN_STATUS_SUCCESS)
+ status = MLAN_STATUS_PENDING;
+ if (pm->param.hs_cfg.conditions ==
+ HOST_SLEEP_CFG_CANCEL) {
+ /* Restore previous condition */
+ pmadapter->hs_cfg.conditions = prev_cond;
+ }
+ } else {
+ pmadapter->hs_cfg.conditions =
+ pm->param.hs_cfg.conditions;
+ pmadapter->hs_cfg.gpio = (t_u8)pm->param.hs_cfg.gpio;
+ pmadapter->hs_cfg.gap = (t_u8)pm->param.hs_cfg.gap;
+ pmadapter->param_type_ind =
+ (t_u8)pm->param.hs_cfg.param_type_ind;
+ pmadapter->ind_gpio = (t_u8)pm->param.hs_cfg.ind_gpio;
+ pmadapter->level = (t_u8)pm->param.hs_cfg.level;
+ pmadapter->param_type_ext =
+ (t_u8)pm->param.hs_cfg.param_type_ext;
+ pmadapter->event_force_ignore =
+ pm->param.hs_cfg.event_force_ignore;
+ pmadapter->event_use_ext_gap =
+ pm->param.hs_cfg.event_use_ext_gap;
+ pmadapter->ext_gap = pm->param.hs_cfg.ext_gap;
+ pmadapter->gpio_wave = pm->param.hs_cfg.gpio_wave;
+ pmadapter->hs_wake_interval =
+ pm->param.hs_cfg.hs_wake_interval;
+ }
+ break;
+ case MLAN_ACT_GET:
+ pm->param.hs_cfg.conditions = pmadapter->hs_cfg.conditions;
+ pm->param.hs_cfg.gpio = pmadapter->hs_cfg.gpio;
+ pm->param.hs_cfg.gap = pmadapter->hs_cfg.gap;
+ pm->param.hs_cfg.param_type_ind = pmadapter->param_type_ind;
+ pm->param.hs_cfg.ind_gpio = pmadapter->ind_gpio;
+ pm->param.hs_cfg.level = pmadapter->level;
+ pm->param.hs_cfg.param_type_ext = pmadapter->param_type_ext;
+ pm->param.hs_cfg.event_force_ignore =
+ pmadapter->event_force_ignore;
+ pm->param.hs_cfg.event_use_ext_gap =
+ pmadapter->event_use_ext_gap;
+ pm->param.hs_cfg.ext_gap = pmadapter->ext_gap;
+ pm->param.hs_cfg.gpio_wave = pmadapter->gpio_wave;
+ pm->param.hs_cfg.hs_wake_interval = pmadapter->hs_wake_interval;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set Robustcoex gpiocfg
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_misc_robustcoex(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+ mlan_ds_misc_cfg *robust_coex_cfg =
+ (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_ROBUSTCOEX,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &robust_coex_cfg->param.robustcoexparams);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get DMCS config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_dmcs_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+ mlan_ds_misc_cfg *dmcs_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DMCS_CONFIG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ &dmcs_cfg->param.dmcs_policy);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+#if defined(PCIE)
+/**
+ * @brief Enable SSU support
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_misc_ssu(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = HostCmd_ACT_GEN_GET;
+ mlan_ds_misc_cfg *ssu_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_DEFAULT)
+ cmd_action = HostCmd_ACT_GEN_SET_DEFAULT;
+ else if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SSU, cmd_action, 0,
+ (t_void *)pioctl_req,
+ &ssu_cfg->param.ssu_params);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function allocates a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param data_len Data length
+ * @param head_room head_room reserved in mlan_buffer
+ * @param malloc_flag flag to user moal_malloc
+ * @return mlan_buffer pointer or MNULL
+ */
+pmlan_buffer wlan_alloc_mlan_buffer(mlan_adapter *pmadapter, t_u32 data_len,
+ t_u32 head_room, t_u32 malloc_flag)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = MNULL;
+ t_u32 buf_size = 0;
+ t_u8 *tmp_buf = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+#ifdef SDIO
+ /* make sure that the data length is at least SDIO block size */
+ if (IS_SD(pmadapter->card_type))
+ data_len = (data_len + MLAN_SDIO_BLOCK_SIZE - 1) /
+ MLAN_SDIO_BLOCK_SIZE * MLAN_SDIO_BLOCK_SIZE;
+#endif
+
+ /* head_room is not implemented for malloc mlan buffer */
+
+ switch (malloc_flag) {
+ case MOAL_MALLOC_BUFFER:
+ buf_size = sizeof(mlan_buffer) + data_len + DMA_ALIGNMENT;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ pmbuf = MNULL;
+ goto exit;
+ }
+ memset(pmadapter, pmbuf, 0, sizeof(mlan_buffer));
+
+ pmbuf->pdesc = MNULL;
+ /* Align address */
+ pmbuf->pbuf = (t_u8 *)ALIGN_ADDR(
+ (t_u8 *)pmbuf + sizeof(mlan_buffer), DMA_ALIGNMENT);
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = data_len;
+ pmbuf->flags |= MLAN_BUF_FLAG_MALLOC_BUF;
+ break;
+
+ case MOAL_ALLOC_MLAN_BUFFER:
+ /* use moal_alloc_mlan_buffer, head_room supported */
+ ret = pcb->moal_alloc_mlan_buffer(
+ pmadapter->pmoal_handle,
+ data_len + DMA_ALIGNMENT + head_room, &pmbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmbuf) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ goto exit;
+ }
+ pmbuf->data_offset = head_room;
+ tmp_buf = (t_u8 *)ALIGN_ADDR(pmbuf->pbuf + pmbuf->data_offset,
+ DMA_ALIGNMENT);
+ pmbuf->data_offset +=
+ (t_u32)(tmp_buf - (pmbuf->pbuf + pmbuf->data_offset));
+ pmbuf->data_len = data_len;
+ pmbuf->flags = 0;
+ break;
+ }
+
+exit:
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function frees a mlan_buffer.
+ *
+ * @param pmadapter Pointer to mlan_adapter
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+t_void wlan_free_mlan_buffer(mlan_adapter *pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ if (pcb && pmbuf) {
+ if (pmbuf->flags & MLAN_BUF_FLAG_BRIDGE_BUF)
+ util_scalar_decrement(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ if (pmbuf->flags & MLAN_BUF_FLAG_MALLOC_BUF)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmbuf);
+ else
+ pcb->moal_free_mlan_buffer(pmadapter->pmoal_handle,
+ pmbuf);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Delay function implementation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param delay Delay value
+ * @param u Units of delay (sec, msec or usec)
+ *
+ * @return N/A
+ */
+t_void wlan_delay_func(mlan_adapter *pmadapter, t_u32 delay, t_delay_unit u)
+{
+ t_u32 now_tv_sec, now_tv_usec;
+ t_u32 upto_tv_sec, upto_tv_usec;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->moal_udelay) {
+ if (u == SEC)
+ delay *= 1000000;
+ else if (u == MSEC)
+ delay *= 1000;
+ pcb->moal_udelay(pmadapter->pmoal_handle, delay);
+ } else {
+ pcb->moal_get_system_time(pmadapter->pmoal_handle, &upto_tv_sec,
+ &upto_tv_usec);
+
+ switch (u) {
+ case SEC:
+ upto_tv_sec += delay;
+ break;
+ case MSEC:
+ delay *= 1000;
+ /* fall through */
+ case USEC:
+ upto_tv_sec += (delay / 1000000);
+ upto_tv_usec += (delay % 1000000);
+ break;
+ }
+
+ do {
+ pcb->moal_get_system_time(pmadapter->pmoal_handle,
+ &now_tv_sec, &now_tv_usec);
+ if (now_tv_sec > upto_tv_sec) {
+ LEAVE();
+ return;
+ }
+
+ if ((now_tv_sec == upto_tv_sec) &&
+ (now_tv_usec >= upto_tv_usec)) {
+ LEAVE();
+ return;
+ }
+ } while (MTRUE);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief BSS remove
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_bss_ioctl_bss_remove(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ ENTER();
+ wlan_cancel_bss_pending_cmd(pmadapter, pioctl_req->bss_index);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_bss_ioctl_bss_role(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_VERSION_EXT dummy;
+#ifdef USB
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pmlan_buffer pmbuf;
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+ t_u8 bss_mode;
+#endif
+ t_u8 i, global_band = 0;
+ int j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_role = GET_BSS_ROLE(pmpriv);
+ } else {
+ if (GET_BSS_ROLE(pmpriv) == bss->param.bss_role) {
+ PRINTM(MIOCTL, "BSS ie already in the desired role!\n");
+ goto done;
+ }
+ mlan_block_rx_process(pmadapter, MTRUE);
+ /** Switch BSS role */
+ wlan_free_priv(pmpriv);
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ while ((pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue,
+ pcb->moal_spin_lock,
+ pcb->moal_spin_unlock))) {
+ pcb->moal_recv_complete(pmadapter->pmoal_handle,
+ pmbuf,
+ pmadapter->rx_data_ep,
+ MLAN_STATUS_FAILURE);
+ }
+ }
+#endif
+ pmpriv->bss_role = bss->param.bss_role;
+ if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP)
+ pmpriv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (pmpriv->bss_type == MLAN_BSS_TYPE_STA)
+ pmpriv->bss_type = MLAN_BSS_TYPE_UAP;
+ /* Initialize private structures */
+ wlan_init_priv(pmpriv);
+ mlan_block_rx_process(pmadapter, MFALSE);
+ /* Initialize function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmpriv)) {
+ memcpy_ext(pmadapter, &pmpriv->ops, mlan_ops[j],
+ sizeof(mlan_operations),
+ sizeof(mlan_operations));
+ }
+ }
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] &&
+ GET_BSS_ROLE(pmadapter->priv[i]) ==
+ MLAN_BSS_ROLE_STA)
+ global_band |= pmadapter->priv[i]->config_bands;
+ }
+
+ if (global_band != pmadapter->config_bands) {
+ if (wlan_set_regiontable(
+ pmpriv, (t_u8)pmadapter->region_code,
+ global_band |
+ pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wlan_11d_set_universaltable(
+ pmpriv,
+ global_band |
+ pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->config_bands = global_band;
+ }
+
+ /* Issue commands to initialize firmware */
+#if defined(WIFI_DIRECT_SUPPORT)
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ bss_mode = BSS_MODE_WIFIDIRECT_CLIENT;
+ else
+ bss_mode = BSS_MODE_WIFIDIRECT_GO;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &bss_mode);
+ if (ret)
+ goto done;
+#endif
+ ret = pmpriv->ops.init_cmd(pmpriv, MFALSE);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+
+ /* Issue dummy Get command to complete the ioctl */
+ memset(pmadapter, &dummy, 0, sizeof(HostCmd_DS_VERSION_EXT));
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET, 0,
+ (t_void *)pioctl_req, (t_void *)&dummy);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set the custom IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param send_ioctl Flag to indicate if ioctl should be sent with cmd
+ * (MTRUE if from moal/user, MFALSE if internal)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_custom_ie_list(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req,
+ t_bool send_ioctl)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ custom_ie *ie_data = MNULL;
+ t_u16 cmd_action = 0, index, mask, i, len, app_data_len;
+ t_s32 ioctl_len;
+ t_u8 *tmp_ie;
+
+ ENTER();
+
+ if ((misc->param.cust_ie.len == 0) ||
+ (misc->param.cust_ie.len == sizeof(t_u16))) {
+ pioctl_req->action = MLAN_ACT_GET;
+ /* Get the IE */
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ /* ioctl_len : ioctl length from application, start with
+ * misc->param.cust_ie.len and reach upto 0 */
+ ioctl_len = misc->param.cust_ie.len;
+
+ /* app_data_len : length from application, start with 0
+ * and reach upto ioctl_len */
+ app_data_len = sizeof(MrvlIEtypesHeader_t);
+ misc->param.cust_ie.len = 0;
+
+ while (ioctl_len > 0) {
+ ie_data = (custom_ie *)(((t_u8 *)&misc->param.cust_ie) +
+ app_data_len);
+ ioctl_len -=
+ (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+ app_data_len +=
+ (ie_data->ie_length + MLAN_CUSTOM_IE_HDR_SIZE);
+
+ index = ie_data->ie_index;
+ mask = ie_data->mgmt_subtype_mask;
+
+ /* Need to be Autohandled */
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == index) {
+ /* Automatic Deletion */
+ if (mask == MLAN_CUSTOM_IE_DELETE_MASK) {
+ ret = wlan_custom_ioctl_auto_delete(
+ pmpriv, pioctl_req, ie_data,
+ index);
+ /* if IE to delete is not found, return
+ * error */
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ index = ie_data->ie_index;
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) *
+ MAX_MGMT_IE_INDEX_TO_FW);
+ len = 0;
+ for (i = 0;
+ i < pmadapter->max_mgmt_ie_index;
+ i++) {
+ /* Check if index is updated
+ * before sending to FW */
+ if (index & ((t_u16)1) << i) {
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)ie_data +
+ len,
+ &i,
+ sizeof(ie_data->ie_index),
+ sizeof(ie_data->ie_index));
+ len += sizeof(
+ ie_data->ie_index);
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)ie_data +
+ len,
+ &pmpriv->mgmt_ie[i]
+ .mgmt_subtype_mask,
+ sizeof(ie_data->mgmt_subtype_mask),
+ sizeof(ie_data->mgmt_subtype_mask));
+ len += sizeof(
+ ie_data->mgmt_subtype_mask);
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)ie_data +
+ len,
+ &pmpriv->mgmt_ie[i]
+ .ie_length,
+ sizeof(ie_data->ie_length),
+ sizeof(ie_data->ie_length));
+ len += sizeof(
+ ie_data->ie_length);
+ if (pmpriv->mgmt_ie[i]
+ .ie_length) {
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)ie_data +
+ len,
+ &pmpriv->mgmt_ie[i]
+ .ie_buffer,
+ pmpriv->mgmt_ie[i]
+ .ie_length,
+ pmpriv->mgmt_ie[i]
+ .ie_length);
+ len += pmpriv->mgmt_ie[i]
+ .ie_length;
+ }
+ }
+ }
+ misc->param.cust_ie.len += len;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else { /* Automatic Addition */
+ if (MLAN_STATUS_FAILURE ==
+ wlan_custom_ioctl_get_autoidx(
+ pmpriv, pioctl_req, mask,
+ ie_data, &index)) {
+ PRINTM(MERROR,
+ "Failed to Set the IE buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mask &= ~MLAN_CUSTOM_IE_NEW_MASK;
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
+ index ||
+ index >= MAX_MGMT_IE_INDEX) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ tmp_ie = (t_u8 *)&pmpriv->mgmt_ie[index]
+ .ie_buffer;
+ memcpy_ext(
+ pmadapter,
+ tmp_ie + pmpriv->mgmt_ie[index]
+ .ie_length,
+ &ie_data->ie_buffer,
+ ie_data->ie_length,
+ ie_data->ie_length);
+ pmpriv->mgmt_ie[index].ie_length +=
+ ie_data->ie_length;
+ pmpriv->mgmt_ie[index].ie_index = index;
+ pmpriv->mgmt_ie[index]
+ .mgmt_subtype_mask = mask;
+
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ ie_data->ie_index = index;
+ ie_data->ie_length =
+ pmpriv->mgmt_ie[index].ie_length;
+ memcpy_ext(
+ pmadapter, &ie_data->ie_buffer,
+ &pmpriv->mgmt_ie[index]
+ .ie_buffer,
+ pmpriv->mgmt_ie[index].ie_length,
+ MAX_IE_SIZE);
+ misc->param.cust_ie.len +=
+ pmpriv->mgmt_ie[index]
+ .ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ }
+ } else {
+ if (index >= pmadapter->max_mgmt_ie_index ||
+ index >= MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid custom IE index %d\n",
+ index);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set/Clear the IE and save it */
+ if (ie_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK &&
+ ie_data->ie_length) {
+ PRINTM(MINFO, "Clear the IE buffer\n");
+ ret = wlan_custom_ioctl_auto_delete(
+ pmpriv, pioctl_req, ie_data,
+ index);
+ /* if IE to delete is not found, return
+ * error */
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ memset(pmadapter, ie_data, 0,
+ sizeof(custom_ie) *
+ MAX_MGMT_IE_INDEX_TO_FW);
+ memcpy_ext(
+ pmadapter, (t_u8 *)ie_data,
+ &pmpriv->mgmt_ie[index],
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE,
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE);
+ } else {
+ /*
+ * Check if this index is being used on
+ * any other interfaces. If yes, then
+ * the request needs to be rejected.
+ */
+ ret = wlan_is_custom_ie_index_unused(
+ pmpriv, index);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "IE index is used by other interface.\n");
+ PRINTM(MERROR,
+ "Set or delete on index %d is not allowed.\n",
+ index);
+ pioctl_req->status_code =
+ MLAN_ERROR_IOCTL_FAIL;
+ goto done;
+ }
+ PRINTM(MINFO, "Set the IE buffer\n");
+ if (ie_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)
+ ie_data->ie_length = 0;
+ else {
+ if ((pmpriv->mgmt_ie[index]
+ .mgmt_subtype_mask ==
+ ie_data->mgmt_subtype_mask) &&
+ (pmpriv->mgmt_ie[index]
+ .ie_length ==
+ ie_data->ie_length) &&
+ !memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index]
+ .ie_buffer,
+ ie_data->ie_buffer,
+ ie_data->ie_length)) {
+ PRINTM(MIOCTL,
+ "same custom ie already configured!\n");
+ if (ioctl_len <= 0 &&
+ misc->param.cust_ie
+ .len ==
+ 0) {
+ goto done;
+ } else {
+ /* remove
+ * matching IE
+ * from app
+ * buffer */
+ app_data_len -=
+ ie_data->ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ memmove(pmadapter,
+ (t_u8 *)ie_data,
+ ie_data->ie_buffer +
+ ie_data->ie_length,
+ ioctl_len);
+ continue;
+ }
+ }
+ }
+ memset(pmadapter,
+ &pmpriv->mgmt_ie[index], 0,
+ sizeof(custom_ie));
+ memcpy_ext(pmadapter,
+ &pmpriv->mgmt_ie[index],
+ ie_data, sizeof(custom_ie),
+ sizeof(custom_ie));
+ }
+
+ misc->param.cust_ie.len +=
+ pmpriv->mgmt_ie[index].ie_length +
+ MLAN_CUSTOM_IE_HDR_SIZE;
+ pioctl_req->action = MLAN_ACT_SET;
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ }
+ }
+
+ /* Send command to firmware */
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
+ ret = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_MGMT_IE_LIST, cmd_action, 0,
+ (send_ioctl) ? (t_void *)pioctl_req : MNULL,
+ &misc->param.cust_ie);
+ }
+#ifdef UAP_SUPPORT
+ else if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
+ ret = wlan_prepare_cmd(
+ pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action, 0,
+ (send_ioctl) ? (t_void *)pioctl_req : MNULL,
+ (send_ioctl) ? MNULL : &misc->param.cust_ie);
+ }
+#endif
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/write adapter register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_reg_mem_ioctl_reg_rw(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0, cmd_no;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ switch (reg_mem->param.reg_rw.type) {
+ case MLAN_REG_MAC:
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ case MLAN_REG_MAC2:
+#endif
+ cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+ break;
+ case MLAN_REG_BBP:
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ case MLAN_REG_BBP2:
+#endif
+ cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+ break;
+ case MLAN_REG_RF:
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ case MLAN_REG_RF2:
+#endif
+ cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+ break;
+ case MLAN_REG_CAU:
+ cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+ break;
+ case MLAN_REG_PSU:
+ cmd_no = HostCmd_CMD_TARGET_ACCESS;
+ break;
+ case MLAN_REG_BCA:
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ case MLAN_REG_BCA2:
+#endif
+ cmd_no = HostCmd_CMD_BCA_REG_ACCESS;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&reg_mem->param.reg_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_reg_mem_ioctl_read_eeprom(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (t_void *)&reg_mem->param.rd_eeprom);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/write memory of device
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_reg_mem_ioctl_mem_rw(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&reg_mem->param.mem_rw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will check if station list is empty
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return MFALSE/MTRUE
+ */
+t_u8 wlan_is_station_list_empty(mlan_private *priv)
+{
+ ENTER();
+ if (!(util_peek_list(priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+ LEAVE();
+ return MTRUE;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function will return the pointer to station entry in station
+ * list table which matches the give mac address
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *wlan_get_station_entry(mlan_private *priv, t_u8 *mac)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+
+ if (!mac) {
+ LEAVE();
+ return MNULL;
+ }
+ sta_ptr = (sta_node *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+
+ while (sta_ptr && (sta_ptr != (sta_node *)&priv->sta_list)) {
+ if (!memcmp(priv->adapter, sta_ptr->mac_addr, mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return sta_ptr;
+ }
+ sta_ptr = sta_ptr->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function will add a pointer to station entry in station list
+ * table with the give mac address, if it does not exist already
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return A pointer to structure sta_node
+ */
+sta_node *wlan_add_station_entry(mlan_private *priv, t_u8 *mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr)
+ goto done;
+ if (priv->adapter->callbacks.moal_malloc(priv->adapter->pmoal_handle,
+ sizeof(sta_node), MLAN_MEM_DEF,
+ (t_u8 **)&sta_ptr)) {
+ PRINTM(MERROR, "Failed to allocate memory for station node\n");
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return MNULL;
+ }
+ memset(priv->adapter, sta_ptr, 0, sizeof(sta_node));
+ memcpy_ext(priv->adapter, sta_ptr->mac_addr, mac, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ util_enqueue_list_tail(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list)sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ IsAuthenticatorEnabled(priv->psapriv))
+ authenticator_init_client(priv->psapriv,
+ &sta_ptr->cm_connectioninfo, mac);
+#endif
+done:
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return sta_ptr;
+}
+
+/**
+ * @brief This function will delete a station entry from station list
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac station's mac address
+ *
+ * @return N/A
+ */
+t_void wlan_delete_station_entry(mlan_private *priv, t_u8 *mac)
+{
+ sta_node *sta_ptr = MNULL;
+ mlan_adapter *pmadapter = priv->adapter;
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ sta_ptr = wlan_get_station_entry(priv, mac);
+ if (sta_ptr) {
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ IsAuthenticatorEnabled(priv->psapriv))
+ authenticator_free_client(priv->psapriv,
+ sta_ptr->cm_connectioninfo);
+#endif
+ util_unlink_list(priv->adapter->pmoal_handle, &priv->sta_list,
+ (pmlan_linked_list)sta_ptr,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *)sta_ptr);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Clean up wapi station list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void wlan_delete_station_list(pmlan_private priv)
+{
+ sta_node *sta_ptr;
+
+ ENTER();
+ while ((sta_ptr = (sta_node *)util_dequeue_list(
+ priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock))) {
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ IsAuthenticatorEnabled(priv->psapriv))
+ authenticator_free_client(priv->psapriv,
+ sta_ptr->cm_connectioninfo);
+#endif
+ priv->adapter->callbacks.moal_mfree(priv->adapter->pmoal_handle,
+ (t_u8 *)sta_ptr);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Set mimo switch configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_radio_ioctl_mimo_switch_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_radio_cfg *radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MIMO_SWITCH, 0, 0,
+ (t_void *)pioctl_req,
+ &(radio_cfg->param.mimo_switch_cfg));
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get extended version information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_get_info_ver_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_get_info *pinfo = (mlan_ds_get_info *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ &pinfo->param.ver_ext.version_str_sel);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function convert mlan_wifi_rate to wifi_rate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param rateStats wifi_rate_stat array
+ * @param pnum_rate A pointer to num_rate
+ *
+ * @return N/A
+ */
+t_void wlan_fill_hal_wifi_rate_in_host(pmlan_private pmpriv,
+ OUT wifi_rate_stat rateStats[],
+ t_u32 *pnumRate)
+{
+ t_u32 total_num_rate = 0;
+ t_u32 mcs_idx = 0;
+ t_u8 index = 0;
+ t_u8 rate_info = 0;
+
+ ENTER();
+
+ /* HT MCS */
+ for (mcs_idx = 0; mcs_idx < MCS_NUM_SUPP; mcs_idx++) {
+ /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ rateStats[total_num_rate].rate.preamble = 2;
+ /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
+ rateStats[total_num_rate].rate.bw = 0;
+ rateStats[total_num_rate].rate.rateMcsIdx = mcs_idx;
+ index = rateStats[total_num_rate].rate.rateMcsIdx;
+ rate_info = MLAN_RATE_FORMAT_HT |
+ (rateStats[total_num_rate].rate.bw << 2);
+ rateStats[total_num_rate].rate.bitrate =
+ wlan_index_to_data_rate(pmpriv->adapter, index,
+ rate_info, 0) *
+ 5;
+ PRINTM(MINFO, "HT[%d] index=0x%x rate_info=0x%x bitrate=0x%x\n",
+ total_num_rate, index, rate_info,
+ rateStats[total_num_rate].rate.bitrate / 5);
+
+ /* Get Tx mpdu */
+ rateStats[total_num_rate].tx_mpdu = 0;
+ rateStats[total_num_rate].rx_mpdu = 0;
+
+ /* Todo: mpdu_lost/retries*, need extend GetTxRxRateInfo */
+ rateStats[total_num_rate].mpdu_lost = 0xC1;
+ rateStats[total_num_rate].retries = 0xC2;
+ rateStats[total_num_rate].retries_short = 0xC3;
+ rateStats[total_num_rate].retries_long = 0xC4;
+
+ total_num_rate++;
+ }
+
+ /* VHT MCS */
+ for (mcs_idx = 0; mcs_idx < VHT_NUM_SUPPORT_MCS; mcs_idx++) {
+ /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ rateStats[total_num_rate].rate.preamble = 3;
+ /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ rateStats[total_num_rate].rate.nss = 0;
+ /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
+ rateStats[total_num_rate].rate.bw = 0;
+ rateStats[total_num_rate].rate.rateMcsIdx = mcs_idx;
+ /* nss 2 ? bw 20MHZ ? */
+ index = rateStats[total_num_rate].rate.rateMcsIdx |
+ (rateStats[total_num_rate].rate.nss << 4);
+ rate_info = MLAN_RATE_FORMAT_VHT |
+ (rateStats[total_num_rate].rate.bw << 2);
+ rateStats[total_num_rate].rate.bitrate =
+ wlan_index_to_data_rate(pmpriv->adapter, index,
+ rate_info, 0) *
+ 5;
+ PRINTM(MINFO,
+ "VHT[%d] index=0x%x rate_info=0x%x bitrate=0x%x\n",
+ total_num_rate, index, rate_info,
+ rateStats[total_num_rate].rate.bitrate / 5);
+
+ rateStats[total_num_rate].tx_mpdu = 0;
+ rateStats[total_num_rate].rx_mpdu = 0;
+
+ /* Todo: mpdu_lost/retries*, need extend GetTxRxRateInfo */
+ rateStats[total_num_rate].mpdu_lost = 0xC1;
+ rateStats[total_num_rate].retries = 0xC2;
+ rateStats[total_num_rate].retries_short = 0xC3;
+ rateStats[total_num_rate].retries_long = 0xC4;
+
+ total_num_rate++;
+ }
+
+ *pnumRate = total_num_rate;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function fill link layer statistic from firmware
+ *
+ * @param priv A pointer to
+ * mlan_private structure
+ * @param link_statistic_ioctl_buf, A pointer to fill ioctl buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static void wlan_fill_link_statistic_in_host(mlan_private *priv,
+ char *link_statistic_ioctl_buf)
+{
+ char *link_statistic = link_statistic_ioctl_buf;
+ wifi_radio_stat *radio_stat = MNULL;
+ wifi_iface_stat *iface_stat = MNULL;
+ t_u32 num_radio = MAX_RADIO;
+ int i = 0, chan_idx = 0;
+ t_u32 num_peers = 0;
+ sta_node *sta_ptr = MNULL;
+#ifdef WMM
+ t_u8 *ptid = MNULL;
+#endif
+
+ ENTER();
+
+ *((t_u32 *)link_statistic) = num_radio;
+ link_statistic += sizeof(num_radio);
+
+ /* Fill radio stats array */
+ for (i = 0; i < num_radio; i++) {
+ radio_stat = (wifi_radio_stat *)link_statistic;
+ link_statistic += sizeof(wifi_radio_stat);
+
+ radio_stat->radio = 0xF0;
+
+ radio_stat->on_time = 0;
+ radio_stat->tx_time = 0;
+ radio_stat->reserved0 = 0;
+ radio_stat->rx_time = 0;
+ radio_stat->on_time_scan = 0;
+ radio_stat->on_time_nbd = 0;
+ radio_stat->on_time_gscan = 0;
+ radio_stat->on_time_roam_scan = 0;
+ radio_stat->on_time_pno_scan = 0;
+ radio_stat->on_time_hs20 = 0;
+
+ radio_stat->num_channels = 1;
+ for (chan_idx = 0; chan_idx < radio_stat->num_channels;
+ chan_idx++) {
+ if (radio_stat->num_channels > MAX_NUM_CHAN) {
+ radio_stat->num_channels = MAX_NUM_CHAN;
+ PRINTM(MERROR,
+ "%s : radio_stat->num_channels=%d\n",
+ __func__, radio_stat->num_channels);
+ break;
+ }
+
+ if (priv->bss_role == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected) {
+ radio_stat->channels[chan_idx]
+ .channel.width =
+ priv->curr_bss_params
+ .bss_descriptor
+ .curr_bandwidth;
+ radio_stat->channels[chan_idx]
+ .channel.center_freq =
+ priv->curr_bss_params
+ .bss_descriptor.freq;
+ radio_stat->channels[chan_idx]
+ .channel.center_freq0 = 0;
+ radio_stat->channels[chan_idx]
+ .channel.center_freq1 = 0;
+ }
+ } else {
+ radio_stat->channels[chan_idx].channel.width =
+ priv->uap_state_chan_cb.bandcfg
+ .chanWidth;
+ radio_stat->channels[chan_idx]
+ .channel
+ .center_freq = wlan_11d_chan_2_freq(
+ priv->adapter,
+ priv->uap_state_chan_cb.channel,
+ (priv->uap_state_chan_cb.channel > 14) ?
+ BAND_A :
+ BAND_G);
+ radio_stat->channels[chan_idx]
+ .channel.center_freq0 = 0;
+ radio_stat->channels[chan_idx]
+ .channel.center_freq1 = 0;
+ }
+ radio_stat->channels[chan_idx].on_time = 0xE3;
+ radio_stat->channels[chan_idx].cca_busy_time = 0xE4;
+ }
+ }
+
+ /* Fill iface stats*/
+ iface_stat = (wifi_iface_stat *)link_statistic;
+
+ /* get wifi_interface_link_layer_info in driver, not in firmware */
+ if (priv->bss_role == MLAN_BSS_ROLE_STA) {
+ iface_stat->info.mode = MLAN_INTERFACE_STA;
+ if (priv->media_connected)
+ iface_stat->info.state = MLAN_ASSOCIATING;
+ else
+ iface_stat->info.state = MLAN_DISCONNECTED;
+ iface_stat->info.roaming = MLAN_ROAMING_IDLE;
+ iface_stat->info.capabilities = MLAN_CAPABILITY_QOS;
+ memcpy_ext(priv->adapter, iface_stat->info.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ MLAN_MAX_SSID_LENGTH, MLAN_MAX_SSID_LENGTH);
+ memcpy_ext(priv->adapter, iface_stat->info.bssid,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ } else {
+ iface_stat->info.mode = MLAN_INTERFACE_SOFTAP;
+ iface_stat->info.capabilities = MLAN_CAPABILITY_QOS;
+ }
+ memcpy_ext(priv->adapter, iface_stat->info.mac_addr, priv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(priv->adapter, iface_stat->info.ap_country_str,
+ priv->adapter->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ memcpy_ext(priv->adapter, iface_stat->info.country_str,
+ priv->adapter->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+
+ iface_stat->beacon_rx = 0;
+ iface_stat->average_tsf_offset = 0;
+ iface_stat->leaky_ap_detected = 0;
+ iface_stat->leaky_ap_avg_num_frames_leaked = 0;
+ iface_stat->leaky_ap_guard_time = 0;
+
+ /* Value of iface_stat should be Reaccumulate by each peer */
+ iface_stat->mgmt_rx = 0;
+ iface_stat->mgmt_action_rx = 0;
+ iface_stat->mgmt_action_tx = 0;
+
+ iface_stat->rssi_mgmt = 0;
+ iface_stat->rssi_data = 0;
+ iface_stat->rssi_ack = 0;
+
+#ifdef WMM
+ for (i = WMM_AC_BK; i <= WMM_AC_VO; i++) {
+ iface_stat->ac[i].ac = i;
+ ptid = ac_to_tid[i];
+ iface_stat->ac[i].tx_mpdu = priv->wmm.packets_out[ptid[0]] +
+ priv->wmm.packets_out[ptid[1]];
+ iface_stat->ac[i].rx_mpdu = 0;
+ iface_stat->ac[i].tx_mcast = 0;
+ iface_stat->ac[i].rx_mcast = 0;
+ iface_stat->ac[i].rx_ampdu = 0;
+ iface_stat->ac[i].tx_ampdu = 0;
+ iface_stat->ac[i].mpdu_lost = 0;
+ iface_stat->ac[i].retries = 0;
+ iface_stat->ac[i].retries_short = 0;
+ iface_stat->ac[i].retries_long = 0;
+ iface_stat->ac[i].contention_time_min = 0;
+ iface_stat->ac[i].contention_time_max = 0;
+ iface_stat->ac[i].contention_time_avg = 0;
+ iface_stat->ac[i].contention_num_samples = 0;
+ }
+#endif
+
+ if (priv->bss_role == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected) {
+ iface_stat->peer_info[0].type = WIFI_PEER_AP;
+ memcpy_ext(
+ priv->adapter,
+ iface_stat->peer_info[0].peer_mac_address,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ iface_stat->peer_info[0].capabilities =
+ MLAN_CAPABILITY_QOS;
+ wlan_fill_hal_wifi_rate_in_host(
+ priv, iface_stat->peer_info[0].rate_stats,
+ &(iface_stat->peer_info[0].num_rate));
+ num_peers = 1;
+ }
+ } else {
+ sta_ptr = (sta_node *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (sta_ptr) {
+ while (sta_ptr != (sta_node *)&priv->sta_list) {
+ iface_stat->peer_info[num_peers].type =
+ WIFI_PEER_STA;
+ memcpy_ext(priv->adapter,
+ iface_stat->peer_info[num_peers]
+ .peer_mac_address,
+ sta_ptr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ iface_stat->peer_info[num_peers].capabilities =
+ MLAN_CAPABILITY_QOS;
+ wlan_fill_hal_wifi_rate_in_host(
+ priv,
+ iface_stat->peer_info[num_peers]
+ .rate_stats,
+ &(iface_stat->peer_info[num_peers]
+ .num_rate));
+ num_peers++;
+
+ sta_ptr = sta_ptr->pnext;
+ }
+ }
+ }
+ iface_stat->num_peers = num_peers;
+
+ LEAVE();
+}
+
+/**
+ * @brief Set/Get link layer statistics
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_ioctl_link_statistic(mlan_private *pmpriv,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info = MNULL;
+ t_u8 *link_statistic = MNULL;
+
+ ENTER();
+
+ /* Check buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /** We will not send HostCmd_CMD_802_11_LINK_STATS to FW */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ info = (mlan_ds_get_info *)pioctl_req->pbuf;
+ link_statistic = info->param.link_statistic;
+ /** Get the LL STATS from driver */
+ wlan_fill_link_statistic_in_host(pmpriv, link_statistic);
+ DBG_HEXDUMP(
+ MCMD_D,
+ "wlan_ioctl_link_statistic() link_statistic in host",
+ (t_u8 *)link_statistic, 800);
+ }
+ ret = MLAN_STATUS_SUCCESS;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get TX/RX histogram statistic
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_get_tx_rx_histogram(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_TX_RX_PKT_STATS,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ &(pmisc->param.tx_rx_histogram));
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks in order to enhance performance
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_set_drvdbg(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set driver debug bit masks */
+ mlan_drvdbg = misc->param.drvdbg;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Rx mgmt frame forward register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_reg_rx_mgmt_ind(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Set passthru mask for mgmt frame */
+ pmpriv->mgmt_frame_passthru_mask = misc->param.mgmt_subtype_mask;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_MGMT_IND,
+ pioctl_req->action, 0, (t_void *)pioctl_req,
+ &misc->param.mgmt_subtype_mask);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes the 802.11 mgmt Frame
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @param payload A pointer to the received buffer
+ * @param payload_len Length of the received buffer
+ * @param prx_pd A pointer to RxPD
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_802dot11_mgmt_pkt(mlan_private *priv, t_u8 *payload,
+ t_u32 payload_len, RxPD *prx_pd)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wlan_802_11_header *pieee_pkt_hdr = MNULL;
+ t_u16 sub_type = 0;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 unicast = 0;
+ t_u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ IEEE80211_MGMT *mgmt = MNULL;
+ t_u8 category = 0;
+ t_u8 action_code = 0;
+#ifdef UAP_SUPPORT
+ sta_node *sta_ptr = MNULL;
+ MrvlIETypes_MgmtFrameSet_t *tlv;
+ pmlan_buffer pmbuf;
+#endif
+
+ ENTER();
+ if (payload_len > (MAX_EVENT_SIZE - sizeof(mlan_event))) {
+ PRINTM(MERROR, "Dropping large mgmt frame,len =%d\n",
+ payload_len);
+ LEAVE();
+ return ret;
+ }
+ /* Check packet type-subtype and compare with mgmt_passthru_mask
+ * If event is needed to host, just eventify it */
+ pieee_pkt_hdr = (wlan_802_11_header *)payload;
+ sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(pieee_pkt_hdr->frm_ctl);
+ if (((1 << sub_type) & priv->mgmt_frame_passthru_mask) == 0) {
+ PRINTM(MINFO, "Dropping mgmt frame for subtype %d snr=%d.\n",
+ sub_type, prx_pd->snr);
+ LEAVE();
+ return ret;
+ }
+ switch (sub_type) {
+ case SUBTYPE_ASSOC_REQUEST:
+ case SUBTYPE_REASSOC_REQUEST:
+#ifdef UAP_SUPPORT
+ if (priv->uap_host_based & UAP_FLAG_HOST_MLME) {
+ PRINTM_NETINTF(MMSG, priv);
+ if (!memcmp(pmadapter, pieee_pkt_hdr->addr3,
+ priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG,
+ "wlan: HostMlme MICRO_AP_STA_ASSOC " MACSTR
+ "\n",
+ MAC2STR(pieee_pkt_hdr->addr2));
+ mgmt = (IEEE80211_MGMT *)payload;
+ sta_ptr = wlan_add_station_entry(
+ priv, pieee_pkt_hdr->addr2);
+ if (sta_ptr) {
+ sta_ptr->capability = wlan_le16_to_cpu(
+ mgmt->u.assoc_req.capab_info);
+ pmbuf = wlan_alloc_mlan_buffer(
+ pmadapter, payload_len, 0,
+ MOAL_MALLOC_BUFFER);
+ if (pmbuf) {
+ PRINTM(MCMND,
+ "check sta capability\n");
+ pmbuf->data_len =
+ ASSOC_EVENT_FIX_SIZE;
+ tlv = (MrvlIETypes_MgmtFrameSet_t
+ *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ pmbuf->data_len);
+ tlv->type = wlan_cpu_to_le16(
+ TLV_TYPE_MGMT_FRAME);
+ tlv->len = sizeof(
+ IEEEtypes_FrameCtl_t);
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)&tlv
+ ->frame_control,
+ &pieee_pkt_hdr->frm_ctl,
+ sizeof(IEEEtypes_FrameCtl_t),
+ sizeof(IEEEtypes_FrameCtl_t));
+ pmbuf->data_len += sizeof(
+ MrvlIETypes_MgmtFrameSet_t);
+ memcpy_ext(
+ pmadapter,
+ pmbuf->pbuf +
+ pmbuf->data_offset +
+ pmbuf->data_len,
+ payload +
+ sizeof(wlan_802_11_header),
+ payload_len -
+ sizeof(wlan_802_11_header),
+ payload_len -
+ sizeof(wlan_802_11_header));
+ pmbuf->data_len +=
+ payload_len -
+ sizeof(wlan_802_11_header);
+ tlv->len +=
+ payload_len -
+ sizeof(wlan_802_11_header);
+ tlv->len = wlan_cpu_to_le16(
+ tlv->len);
+ DBG_HEXDUMP(
+ MCMD_D, "assoc_req",
+ pmbuf->pbuf +
+ pmbuf->data_offset,
+ pmbuf->data_len);
+ wlan_check_sta_capability(
+ priv, pmbuf, sta_ptr);
+ wlan_free_mlan_buffer(pmadapter,
+ pmbuf);
+ }
+ }
+ } else {
+ PRINTM(MMSG,
+ "wlan: Drop MICRO_AP_STA_ASSOC " MACSTR
+ " from unknown BSSID " MACSTR "\n",
+ MAC2STR(pieee_pkt_hdr->addr2),
+ MAC2STR(pieee_pkt_hdr->addr3));
+ }
+ }
+ unicast = MTRUE;
+ break;
+#endif
+ case SUBTYPE_AUTH:
+ unicast = MTRUE;
+ PRINTM_NETINTF(MMSG, priv);
+ PRINTM(MMSG, "wlan: HostMlme Auth received from " MACSTR "\n",
+ MAC2STR(pieee_pkt_hdr->addr2));
+ break;
+ case SUBTYPE_PROBE_RESP:
+ unicast = MTRUE;
+ break;
+ case SUBTYPE_DISASSOC:
+ case SUBTYPE_DEAUTH:
+ if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast,
+ MLAN_MAC_ADDR_LENGTH))
+ unicast = MTRUE;
+#ifdef UAP_SUPPORT
+ if (priv->uap_host_based & UAP_FLAG_HOST_MLME) {
+ if (!memcmp(pmadapter, pieee_pkt_hdr->addr3,
+ priv->curr_addr, MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM_NETINTF(MMSG, priv);
+ PRINTM(MMSG,
+ "wlan: HostMlme Deauth Receive from " MACSTR
+ "\n",
+ MAC2STR(pieee_pkt_hdr->addr2));
+ }
+ }
+#endif
+ if (priv->bss_role == MLAN_BSS_ROLE_STA) {
+ if (priv->curr_bss_params.host_mlme) {
+ if (memcmp(pmadapter, pieee_pkt_hdr->addr2,
+ (t_u8 *)priv->curr_bss_params
+ .bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MINFO,
+ "Dropping mgmt frame from others: type=%d " MACSTR
+ "\n",
+ sub_type,
+ MAC2STR(pieee_pkt_hdr->addr2));
+ LEAVE();
+ return ret;
+ }
+ PRINTM_NETINTF(MMSG, priv);
+ PRINTM(MMSG,
+ "wlan: HostMlme Disconnected: sub_type=%d\n",
+ sub_type);
+ pmadapter->pending_disconnect_priv = priv;
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+ break;
+ case SUBTYPE_ACTION:
+ category = *(payload + sizeof(wlan_802_11_header));
+ action_code = *(payload + sizeof(wlan_802_11_header) + 1);
+ if (category == IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK) {
+ PRINTM(MINFO,
+ "Drop BLOCK ACK action frame: action_code=%d\n",
+ action_code);
+ LEAVE();
+ return ret;
+ }
+ if ((category == IEEE_MGMT_ACTION_CATEGORY_PUBLIC) &&
+ (action_code == BSS_20_40_COEX)) {
+ PRINTM(MINFO,
+ "Drop 20/40 BSS Coexistence Management frame\n");
+ LEAVE();
+ return ret;
+ }
+ if (memcmp(pmadapter, pieee_pkt_hdr->addr1, broadcast,
+ MLAN_MAC_ADDR_LENGTH))
+ unicast = MTRUE;
+ break;
+ default:
+ break;
+ }
+ if (unicast == MTRUE) {
+ if (memcmp(pmadapter, pieee_pkt_hdr->addr1, priv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MINFO,
+ "Dropping mgmt frame for others: type=%d " MACSTR
+ "\n",
+ sub_type, MAC2STR(pieee_pkt_hdr->addr1));
+ LEAVE();
+ return ret;
+ }
+ }
+ /* Allocate memory for event buffer */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
+ MLAN_MEM_DEF, &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pevent = (pmlan_event)event_buf;
+ pevent->bss_index = priv->bss_index;
+ mgmt = (IEEE80211_MGMT *)payload;
+ if (!priv->curr_bss_params.host_mlme && sub_type == SUBTYPE_ACTION &&
+ mgmt->u.ft_resp.category == FT_CATEGORY &&
+ mgmt->u.ft_resp.action == FT_ACTION_RESPONSE &&
+ mgmt->u.ft_resp.status_code == 0) {
+ PRINTM(MCMND, "FT Action response received\n");
+#define FT_ACTION_HEAD_LEN (24 + 6 + 16)
+ pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE;
+ pevent->event_len =
+ payload_len + MLAN_MAC_ADDR_LENGTH - FT_ACTION_HEAD_LEN;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ &mgmt->u.ft_resp.target_ap_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmadapter,
+ (t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH),
+ payload + FT_ACTION_HEAD_LEN,
+ payload_len - FT_ACTION_HEAD_LEN,
+ pevent->event_len - MLAN_MAC_ADDR_LENGTH);
+ } else if (!priv->curr_bss_params.host_mlme &&
+ sub_type == SUBTYPE_AUTH &&
+ mgmt->u.auth.auth_alg == MLAN_AUTH_MODE_FT &&
+ mgmt->u.auth.auth_transaction == 2 &&
+ mgmt->u.auth.status_code == 0) {
+ PRINTM(MCMND, "FT auth response received \n");
+#define AUTH_PACKET_LEN (24 + 6 + 6)
+ pevent->event_id = MLAN_EVENT_ID_DRV_FT_RESPONSE;
+ pevent->event_len =
+ payload_len + MLAN_MAC_ADDR_LENGTH - AUTH_PACKET_LEN;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, mgmt->sa,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmadapter,
+ (t_u8 *)(pevent->event_buf + MLAN_MAC_ADDR_LENGTH),
+ payload + AUTH_PACKET_LEN,
+ payload_len - AUTH_PACKET_LEN,
+ pevent->event_len - MLAN_MAC_ADDR_LENGTH);
+ } else {
+ pevent->event_id = MLAN_EVENT_ID_DRV_MGMT_FRAME;
+ pevent->event_len = payload_len + sizeof(pevent->event_id);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)&pevent->event_id, sizeof(pevent->event_id),
+ pevent->event_len);
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)(pevent->event_buf + sizeof(pevent->event_id)),
+ payload, payload_len, payload_len);
+ }
+ wlan_recv_event(priv, pevent->event_id, pevent);
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Extended capabilities configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ext_capa_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (MLAN_ACT_GET == pioctl_req->action)
+ memcpy_ext(pmpriv->adapter, &misc->param.ext_cap,
+ &pmpriv->def_ext_cap, sizeof(misc->param.ext_cap),
+ sizeof(misc->param.ext_cap));
+ else if (MLAN_ACT_SET == pioctl_req->action) {
+ memcpy_ext(pmpriv->adapter, &pmpriv->ext_cap,
+ &misc->param.ext_cap, sizeof(misc->param.ext_cap),
+ sizeof(pmpriv->ext_cap));
+ /* Save default Extended Capability */
+ memcpy_ext(pmpriv->adapter, &pmpriv->def_ext_cap,
+ &pmpriv->ext_cap, sizeof(pmpriv->ext_cap),
+ sizeof(pmpriv->def_ext_cap));
+ if (pmpriv->config_bands & BAND_AAC)
+ SET_EXTCAP_OPERMODENTF(pmpriv->ext_cap);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check whether Extended Capabilities IE support
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE;
+ */
+t_u32 wlan_is_ext_capa_support(mlan_private *pmpriv)
+{
+ ENTER();
+
+ if (ISSUPP_EXTCAP_TDLS(pmpriv->ext_cap) ||
+ ISSUPP_EXTCAP_INTERWORKING(pmpriv->ext_cap) ||
+ ISSUPP_EXTCAP_BSS_TRANSITION(pmpriv->ext_cap) ||
+ ISSUPP_EXTCAP_QOS_MAP(pmpriv->ext_cap) ||
+ ISSUPP_EXTCAP_OPERMODENTF(pmpriv->ext_cap)) {
+ LEAVE();
+ return MTRUE;
+ } else {
+ LEAVE();
+ return MFALSE;
+ }
+}
+#endif
+
+/**
+ * @brief Set hotspot enable/disable
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_hotspot_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (MLAN_ACT_GET == pioctl_req->action)
+ misc->param.hotspot_cfg = pmpriv->hotspot_cfg;
+ else if (MLAN_ACT_SET == pioctl_req->action)
+ pmpriv->hotspot_cfg = misc->param.hotspot_cfg;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Add Extended Capabilities IE
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_desc A pointer to BSSDescriptor_t structure
+ * @param pptlv_out A pointer to TLV to fill in
+ *
+ * @return N/A
+ */
+void wlan_add_ext_capa_info_ie(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc,
+ t_u8 **pptlv_out)
+{
+ MrvlIETypes_ExtCap_t *pext_cap = MNULL;
+
+ ENTER();
+
+ pext_cap = (MrvlIETypes_ExtCap_t *)*pptlv_out;
+ memset(pmpriv->adapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
+ pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
+ pext_cap->header.len = wlan_cpu_to_le16(sizeof(ExtCap_t));
+ if (pmpriv->adapter->ecsa_enable)
+ SET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap);
+ else
+ RESET_EXTCAP_EXT_CHANNEL_SWITCH(pmpriv->ext_cap);
+ if (wlan_check_11ax_twt_supported(pmpriv, pbss_desc))
+ SET_EXTCAP_TWT_REQ(pmpriv->ext_cap);
+ memcpy_ext(pmpriv->adapter, &pext_cap->ext_cap, &pmpriv->ext_cap,
+ sizeof(pmpriv->ext_cap), sizeof(pext_cap->ext_cap));
+ *pptlv_out += sizeof(MrvlIETypes_ExtCap_t);
+
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief Get OTP user data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_otp_user_data(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ if (misc->param.otp_user_data.user_data_length >
+ MAX_OTP_USER_DATA_LEN) {
+ PRINTM(MERROR, "Invalid OTP user data length\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return ret;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_OTP_READ_USER_DATA,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ &misc->param.otp_user_data);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ * @param sta_ptr A pointer to sta_node
+ *
+ * @return N/A
+ */
+void wlan_check_sta_capability(pmlan_private priv, pmlan_buffer pevent,
+ sta_node *sta_ptr)
+{
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ IEEEtypes_HTCap_t *pht_cap = MNULL;
+ IEEEtypes_VHTCap_t *pvht_cap = MNULL;
+ IEEEtypes_Extension_t *phe_cap = MNULL;
+#ifdef UAP_SUPPORT
+ t_u8 *ext_rate = MNULL, *erp = MNULL;
+#endif
+
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
+ ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *)tlv;
+ memcpy_ext(priv->adapter, &frame_control,
+ (t_u8 *)&(mgmt_tlv->frame_control),
+ sizeof(frame_control),
+ sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(
+ frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_BEACON)
+#ifdef UAP_SUPPORT
+ || (frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST)
+#endif
+ )) {
+ if (frame_sub_type == SUBTYPE_BEACON)
+ assoc_ie_len =
+ sizeof(IEEEtypes_Beacon_t);
+#ifdef UAP_SUPPORT
+ else if (frame_sub_type ==
+ SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len =
+ sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type ==
+ SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len =
+ sizeof(IEEEtypes_ReAssocRqst_t);
+#endif
+ ie_len = tlv_len -
+ sizeof(IEEEtypes_FrameCtl_t) -
+ assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *)tlv +
+ sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ sta_ptr->is_wmm_enabled =
+ wlan_is_wmm_ie_present(priv->adapter,
+ assoc_req_ie,
+ ie_len);
+ PRINTM(MCMND, "STA: is_wmm_enabled=%d\n",
+ sta_ptr->is_wmm_enabled);
+ pht_cap = (IEEEtypes_HTCap_t *)
+ wlan_get_specific_ie(priv, assoc_req_ie,
+ ie_len,
+ HT_CAPABILITY, 0);
+ if (pht_cap) {
+ PRINTM(MCMND, "STA supports 11n\n");
+ sta_ptr->is_11n_enabled = MTRUE;
+ memcpy_ext(priv->adapter,
+ (t_u8 *)&sta_ptr->HTcap,
+ pht_cap,
+ sizeof(IEEEtypes_HTCap_t),
+ sizeof(IEEEtypes_HTCap_t));
+ if (GETHT_MAXAMSDU(wlan_le16_to_cpu(
+ pht_cap->ht_cap
+ .ht_cap_info)))
+ sta_ptr->max_amsdu =
+ MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu =
+ MLAN_TX_DATA_BUF_SIZE_4K;
+ } else {
+ PRINTM(MCMND,
+ "STA doesn't support 11n\n");
+ }
+ pvht_cap = (IEEEtypes_VHTCap_t *)
+ wlan_get_specific_ie(priv, assoc_req_ie,
+ ie_len,
+ VHT_CAPABILITY, 0);
+ if (pvht_cap &&
+ (priv->is_11ac_enabled == MTRUE)) {
+ PRINTM(MCMND, "STA supports 11ac\n");
+ sta_ptr->is_11ac_enabled = MTRUE;
+ if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu(
+ pvht_cap->vht_cap
+ .vht_cap_info)) ==
+ 2)
+ sta_ptr->max_amsdu =
+ MLAN_TX_DATA_BUF_SIZE_12K;
+ else if (GET_VHTCAP_MAXMPDULEN(wlan_le32_to_cpu(
+ pvht_cap->vht_cap
+ .vht_cap_info)) ==
+ 1)
+ sta_ptr->max_amsdu =
+ MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu =
+ MLAN_TX_DATA_BUF_SIZE_4K;
+ } else {
+ PRINTM(MCMND,
+ "STA doesn't support 11ac\n");
+ }
+ phe_cap = (IEEEtypes_Extension_t *)
+ wlan_get_specific_ie(priv, assoc_req_ie,
+ ie_len, EXTENSION,
+ HE_CAPABILITY);
+ if (phe_cap &&
+ (priv->is_11ax_enabled == MTRUE)) {
+ PRINTM(MCMND, "STA supports 11ax\n");
+ sta_ptr->is_11ax_enabled = MTRUE;
+ } else {
+ PRINTM(MCMND,
+ "STA doesn't support 11ax\n");
+ }
+#ifdef UAP_SUPPORT
+ /* Note: iphone6 does not have ERP_INFO */
+ ext_rate = wlan_get_specific_ie(
+ priv, assoc_req_ie, ie_len,
+ EXTENDED_SUPPORTED_RATES, 0);
+ erp = wlan_get_specific_ie(priv, assoc_req_ie,
+ ie_len, ERP_INFO, 0);
+ if (!ext_rate)
+ PRINTM(MCMND,
+ "STA doesn't support EXTENDED_SUPPORTED_RATES\n");
+ if (!erp)
+ PRINTM(MCMND,
+ "STA doesn't support ERP_INFO\n");
+ if (sta_ptr->is_11ax_enabled) {
+ if (priv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GAX;
+ else
+ sta_ptr->bandmode = BAND_AAX;
+ } else if (sta_ptr->is_11ac_enabled) {
+ if (priv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GAC;
+ else
+ sta_ptr->bandmode = BAND_AAC;
+ } else if (sta_ptr->is_11n_enabled) {
+ if (priv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GN;
+ else
+ sta_ptr->bandmode = BAND_AN;
+ } else if (ext_rate || erp) {
+ if (priv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_G;
+ else
+ sta_ptr->bandmode = BAND_A;
+ } else
+ sta_ptr->bandmode = BAND_B;
+#endif
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IsAuthenticatorEnabled(priv->psapriv))
+ authenticator_get_sta_security_info(
+ priv->psapriv,
+ sta_ptr->cm_connectioninfo,
+ assoc_req_ie, ie_len);
+#endif
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return;
+}
+
+/**
+ * @brief check if WMM ie present.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pbuf A pointer to IE buffer
+ * @param buf_len IE buffer len
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 wlan_is_wmm_ie_present(pmlan_adapter pmadapter, t_u8 *pbuf, t_u16 buf_len)
+{
+ t_u16 bytes_left = buf_len;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 *pcurrent_ptr = pbuf;
+ t_u8 element_len;
+ t_u16 total_ie_len;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+ t_u8 find_wmm_ie = MFALSE;
+
+ ENTER();
+
+ /* Process variable IE */
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
+ if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
+ wmm_oui, sizeof(wmm_oui))) {
+ find_wmm_ie = MTRUE;
+ PRINTM(MINFO, "find WMM IE\n");
+ }
+ break;
+ default:
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ if (find_wmm_ie)
+ break;
+ }
+
+ LEAVE();
+ return find_wmm_ie;
+}
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ *
+ * @param priv A pointer to mlan_private
+ * @param ie_buf A pointer to ie_buf
+ * @param ie_len total ie length
+ * @param id ie's id
+ * @param ext_id ie's extension id
+ *
+ * @return ie's poiner or MNULL
+ */
+t_u8 *wlan_get_specific_ie(pmlan_private priv, t_u8 *ie_buf, t_u8 ie_len,
+ IEEEtypes_ElementId_e id, t_u8 ext_id)
+{
+ t_u32 bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie_buf;
+ t_u16 total_ie_len;
+ t_u8 *ie_ptr = MNULL;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+ t_u8 element_eid;
+
+ ENTER();
+
+ DBG_HEXDUMP(MDAT_D, "ie", ie_buf, ie_len);
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ element_eid = *((t_u8 *)pcurrent_ptr + 2);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+ if ((!ext_id && element_id == id) ||
+ (id == EXTENSION && element_id == id &&
+ ext_id == element_eid)) {
+ PRINTM(MCMND, "Find IE: id=%d ext_id=%d\n", id, ext_id);
+ DBG_HEXDUMP(MCMD_D, "IE", pcurrent_ptr, total_ie_len);
+ ie_ptr = pcurrent_ptr;
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+
+ LEAVE();
+
+ return ie_ptr;
+}
+
+/**
+ * @brief Get pm info
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status wlan_get_pm_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ pm_cfg->param.ps_info.is_suspend_allowed = MTRUE;
+ wlan_request_cmd_lock(pmadapter);
+ if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
+ MNULL, MNULL) ||
+ pmadapter->curr_cmd || !wlan_bypass_tx_list_empty(pmadapter) ||
+ !wlan_wmm_lists_empty(pmadapter)
+#if defined(SDIO) || defined(PCIE)
+ || wlan_pending_interrupt(pmadapter)
+#endif
+ ) {
+ pm_cfg->param.ps_info.is_suspend_allowed = MFALSE;
+#if defined(SDIO) || defined(PCIE)
+ PRINTM(MIOCTL,
+ "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d irq_pending=%d\n",
+ util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, MNULL, MNULL),
+ pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter),
+ wlan_bypass_tx_list_empty(pmadapter),
+ wlan_pending_interrupt(pmadapter));
+#else
+ PRINTM(MIOCTL,
+ "PM: cmd_pending_q=%p,curr_cmd=%p,wmm_list_empty=%d, by_pass=%d\n",
+ util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->cmd_pending_q, MNULL, MNULL),
+ pmadapter->curr_cmd, wlan_wmm_lists_empty(pmadapter),
+ wlan_bypass_tx_list_empty(pmadapter));
+#endif
+ }
+ wlan_release_cmd_lock(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get hs wakeup reason
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status wlan_get_hs_wakeup_reason(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ pmlan_ds_pm_cfg pm_cfg = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_HS_WAKEUP_REASON,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ &pm_cfg->param.wakeup_reason);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_radio_ioctl_radio_ctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->radio_on == radio_cfg->param.radio_on_off) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ } else {
+ if (pmpriv->media_connected == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ }
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RADIO_CONTROL,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &radio_cfg->param.radio_on_off);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get antenna configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_radio_ioctl_ant_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_ds_ant_cfg *ant_cfg = MNULL;
+ mlan_ds_ant_cfg_1x1 *ant_cfg_1x1 = MNULL;
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ if (IS_STREAM_2X2(pmadapter->feature_control))
+ ant_cfg = &radio_cfg->param.ant_cfg;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* User input validation */
+ if (IS_STREAM_2X2(pmadapter->feature_control)) {
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmadapter->card_type) ||
+ IS_CARD9097(pmadapter->card_type)) {
+ ant_cfg->tx_antenna &= 0x0303;
+ ant_cfg->rx_antenna &= 0x0303;
+ /** 2G antcfg TX */
+ if (ant_cfg->tx_antenna & 0x00FF) {
+ pmadapter->user_htstream &= ~0xF0;
+ pmadapter->user_htstream |=
+ (bitcount(ant_cfg->tx_antenna &
+ 0x00FF)
+ << 4);
+ }
+ /* 5G antcfg tx */
+ if (ant_cfg->tx_antenna & 0xFF00) {
+ pmadapter->user_htstream &= ~0xF000;
+ pmadapter->user_htstream |=
+ (bitcount(ant_cfg->tx_antenna &
+ 0xFF00)
+ << 12);
+ }
+ /* 2G antcfg RX */
+ if (ant_cfg->rx_antenna & 0x00FF) {
+ pmadapter->user_htstream &= ~0xF;
+ pmadapter->user_htstream |= bitcount(
+ ant_cfg->rx_antenna & 0x00FF);
+ }
+ /* 5G antcfg RX */
+ if (ant_cfg->rx_antenna & 0xFF00) {
+ pmadapter->user_htstream &= ~0xF00;
+ pmadapter->user_htstream |=
+ (bitcount(ant_cfg->rx_antenna &
+ 0xFF00)
+ << 8);
+ }
+ PRINTM(MCMND,
+ "user_htstream=0x%x, tx_antenna=0x%x >rx_antenna=0x%x\n",
+ pmadapter->user_htstream,
+ ant_cfg->tx_antenna,
+ ant_cfg->rx_antenna);
+ } else {
+#endif
+
+ ant_cfg->tx_antenna &= 0x0003;
+ ant_cfg->rx_antenna &= 0x0003;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ }
+#endif
+ if (!ant_cfg->tx_antenna ||
+ bitcount(ant_cfg->tx_antenna & 0x00FF) >
+ pmadapter->number_of_antenna ||
+ bitcount(ant_cfg->tx_antenna & 0xFF00) >
+ pmadapter->number_of_antenna) {
+ PRINTM(MERROR,
+ "Invalid TX antenna setting: 0x%x\n",
+ ant_cfg->tx_antenna);
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (ant_cfg->rx_antenna) {
+ if (bitcount(ant_cfg->rx_antenna & 0x00FF) >
+ pmadapter->number_of_antenna ||
+ bitcount(ant_cfg->rx_antenna & 0xFF00) >
+ pmadapter->number_of_antenna) {
+ PRINTM(MERROR,
+ "Invalid RX antenna setting: 0x%x\n",
+ ant_cfg->rx_antenna);
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else
+ ant_cfg->rx_antenna = ant_cfg->tx_antenna;
+ } else if (!radio_cfg->param.ant_cfg_1x1.antenna ||
+ ((radio_cfg->param.ant_cfg_1x1.antenna !=
+ RF_ANTENNA_AUTO) &&
+ (radio_cfg->param.ant_cfg_1x1.antenna & 0xFFFC))) {
+ PRINTM(MERROR, "Invalid antenna setting\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Cast it to t_u16, antenna mode for command
+ * HostCmd_CMD_802_11_RF_ANTENNA requires 2 bytes */
+ if (!IS_STREAM_2X2(pmadapter->feature_control))
+ ant_cfg_1x1 = &radio_cfg->param.ant_cfg_1x1;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (IS_STREAM_2X2(pmadapter->feature_control)) ?
+ (t_void *)ant_cfg :
+ (t_void *)ant_cfg_1x1);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate bitmap
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_get_rate_bitmap(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate bitmap
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_set_rate_bitmap(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *ds_rate = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 *bitmap_rates = MNULL;
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ bitmap_rates = ds_rate->param.rate_cfg.bitmap_rates;
+
+ PRINTM(MINFO,
+ "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x"
+ "%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
+ "IsRateAuto=%d, DataRate=%d\n",
+ bitmap_rates[17], bitmap_rates[16], bitmap_rates[15],
+ bitmap_rates[14], bitmap_rates[13], bitmap_rates[12],
+ bitmap_rates[11], bitmap_rates[10], bitmap_rates[9],
+ bitmap_rates[8], bitmap_rates[7], bitmap_rates[6],
+ bitmap_rates[5], bitmap_rates[4], bitmap_rates[3],
+ bitmap_rates[2], bitmap_rates[1], bitmap_rates[0],
+ pmpriv->is_data_rate_auto, pmpriv->data_rate);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_get_rate_value(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ rate->param.rate_cfg.is_rate_auto = pmpriv->is_data_rate_auto;
+ pioctl_req->data_read_written =
+ sizeof(mlan_rate_cfg_t) + MLAN_SUB_COMMAND_SIZE;
+
+ /* If not connected, set rate to the lowest in each band */
+ if (pmpriv->media_connected != MTRUE) {
+ if (pmpriv->config_bands & (BAND_B | BAND_G)) {
+ /* Return the lowest supported rate for BG band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmpriv->config_bands & (BAND_A | BAND_B)) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_BG[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_A) {
+ /* Return the lowest supported rate for A band */
+ rate->param.rate_cfg.rate = SupportedRates_A[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_G) {
+ /* Return the lowest supported rate for G band */
+ rate->param.rate_cfg.rate = SupportedRates_G[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_B) {
+ /* Return the lowest supported rate for B band */
+ rate->param.rate_cfg.rate = SupportedRates_B[0] & 0x7f;
+ } else if (pmpriv->config_bands & BAND_GN) {
+ /* Return the lowest supported rate for N band */
+ rate->param.rate_cfg.rate = SupportedRates_N[0] & 0x7f;
+ } else {
+ PRINTM(MMSG, "Invalid Band 0x%x\n",
+ pmpriv->config_bands);
+ }
+
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0,
+ (t_void *)pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate value
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_set_rate_value(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *ds_rate = MNULL;
+ WLAN_802_11_RATES rates;
+ t_u8 *rate = MNULL;
+ int rate_index = 0;
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ t_u32 i = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Rates talbe [0] HR/DSSS,[1] OFDM,[2..9] HT,[10..17] VHT */
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 3 - 8; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ /* Support all VHT-MCSs rate */
+ for (i = 0; i < NELEMENTS(pmpriv->bitmap_rates) - 10; i++)
+ bitmap_rates[i + 10] = 0x03FF; /* 10 Bits valid */
+ } else {
+ memset(pmadapter, rates, 0, sizeof(rates));
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode ==
+ MLAN_BSS_MODE_INFRA) ?
+ pmpriv->config_bands :
+ pmadapter->adhoc_start_band,
+ rates);
+ rate = rates;
+ for (i = 0; (rate[i] && i < WLAN_SUPPORTED_RATES); i++) {
+ PRINTM(MINFO, "Rate=0x%X Wanted=0x%X\n", rate[i],
+ ds_rate->param.rate_cfg.rate);
+ if ((rate[i] & 0x7f) ==
+ (ds_rate->param.rate_cfg.rate & 0x7f))
+ break;
+ }
+ if ((i < WLAN_SUPPORTED_RATES && !rate[i]) ||
+ (i == WLAN_SUPPORTED_RATES)) {
+ PRINTM(MERROR,
+ "The fixed data rate 0x%X is out "
+ "of range\n",
+ ds_rate->param.rate_cfg.rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ rate_index = wlan_data_rate_to_index(
+ pmadapter, ds_rate->param.rate_cfg.rate);
+ /* Only allow b/g rates to be set */
+ if (rate_index >= MLAN_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MLAN_RATE_INDEX_HRDSSS3)
+ bitmap_rates[0] = 1 << rate_index;
+ else {
+ rate_index -= 1; /* There is a 0x00 in the table */
+ if (rate_index >= MLAN_RATE_INDEX_OFDM0 &&
+ rate_index <= MLAN_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index -
+ MLAN_RATE_INDEX_OFDM0);
+ }
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_get_rate_index(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set rate index
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_rate_ioctl_set_rate_index(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ t_u32 rate_index;
+ t_u32 rate_format;
+ t_u32 nss;
+ t_u32 i;
+ mlan_ds_rate *ds_rate = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ int tx_mcs_supp = GET_TXMCSSUPP(pmpriv->usr_dev_mcs_support);
+
+ ENTER();
+
+ ds_rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ rate_format = ds_rate->param.rate_cfg.rate_format;
+ nss = ds_rate->param.rate_cfg.nss;
+ rate_index = ds_rate->param.rate_cfg.rate;
+
+ if (ds_rate->param.rate_cfg.is_rate_auto) {
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Rates talbe [0]: HR/DSSS;[1]: OFDM; [2..9] HT; */
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 2; i < 9; i++)
+ bitmap_rates[i] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ /* [10..17] VHT */
+ /* Support all VHT-MCSs rate for NSS 1 and 2 */
+ for (i = 10; i < 12; i++)
+ bitmap_rates[i] = 0x03FF; /* 10 Bits valid */
+ /* Set to 0 as default value for all other NSSs */
+ for (i = 12; i < 17; i++)
+ bitmap_rates[i] = 0x0;
+ /* [18..25] HE */
+ /* Support all HE-MCSs rate for NSS1 and 2 */
+ for (i = 18; i < 20; i++)
+ bitmap_rates[i] = 0x0FFF;
+ for (i = 20; i < NELEMENTS(bitmap_rates); i++)
+ bitmap_rates[i] = 0x0;
+ } else {
+ PRINTM(MINFO, "Rate index is %d\n", rate_index);
+ if ((rate_format == MLAN_RATE_FORMAT_HT) &&
+ (rate_index > MLAN_RATE_INDEX_MCS7 &&
+ rate_index <= MLAN_RATE_INDEX_MCS15) &&
+ (tx_mcs_supp < 2)) {
+ PRINTM(MERROR,
+ "HW don't support 2x2, rate_index=%d hw_mcs_supp=0x%x\n",
+ rate_index, pmpriv->usr_dev_mcs_support);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memset(pmadapter, bitmap_rates, 0, sizeof(bitmap_rates));
+ if (rate_format == MLAN_RATE_FORMAT_LG) {
+ /* Bitmap of HR/DSSS rates */
+ if (rate_index <= MLAN_RATE_INDEX_HRDSSS3) {
+ bitmap_rates[0] = 1 << rate_index;
+ ret = MLAN_STATUS_SUCCESS;
+ /* Bitmap of OFDM rates */
+ } else if ((rate_index >= MLAN_RATE_INDEX_OFDM0) &&
+ (rate_index <= MLAN_RATE_INDEX_OFDM7)) {
+ bitmap_rates[1] = 1 << (rate_index -
+ MLAN_RATE_INDEX_OFDM0);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ } else if (rate_format == MLAN_RATE_FORMAT_HT) {
+ if (rate_index <= MLAN_RATE_INDEX_MCS32) {
+ bitmap_rates[2 + (rate_index / 16)] =
+ 1 << (rate_index % 16);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ }
+ if (rate_format == MLAN_RATE_FORMAT_VHT) {
+ if ((rate_index <= MLAN_RATE_INDEX_MCS9) &&
+ (MLAN_RATE_NSS1 <= nss) &&
+ (nss <= MLAN_RATE_NSS2)) {
+ bitmap_rates[10 + nss - MLAN_RATE_NSS1] =
+ (1 << rate_index);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ }
+ if (rate_format == MLAN_RATE_FORMAT_HE) {
+ if (IS_FW_SUPPORT_11AX(pmadapter)) {
+ if ((rate_index <= MLAN_RATE_INDEX_MCS11) &&
+ (MLAN_RATE_NSS1 <= nss) &&
+ (nss <= MLAN_RATE_NSS2)) {
+ bitmap_rates[18 + nss - MLAN_RATE_NSS1] =
+ (1 << rate_index);
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR,
+ "Error! Fw doesn't support 11AX\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "Invalid MCS index=%d. \n", rate_index);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ PRINTM(MINFO,
+ "RateBitmap=%04x%04x%04x%04x%04x%04x%04x%04x"
+ "%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x, "
+ "IsRateAuto=%d, DataRate=%d\n",
+ bitmap_rates[17], bitmap_rates[16], bitmap_rates[15],
+ bitmap_rates[14], bitmap_rates[13], bitmap_rates[12],
+ bitmap_rates[11], bitmap_rates[10], bitmap_rates[9],
+ bitmap_rates[8], bitmap_rates[7], bitmap_rates[6],
+ bitmap_rates[5], bitmap_rates[4], bitmap_rates[3],
+ bitmap_rates[2], bitmap_rates[1], bitmap_rates[0],
+ pmpriv->is_data_rate_auto, pmpriv->data_rate);
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)bitmap_rates);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_rate_ioctl_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_rate *rate = MNULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ if (rate->param.rate_cfg.rate_type == MLAN_RATE_BITMAP) {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_bitmap(pmadapter,
+ pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_bitmap(pmadapter,
+ pioctl_req);
+ } else if (rate->param.rate_cfg.rate_type == MLAN_RATE_VALUE) {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_value(pmadapter,
+ pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_value(pmadapter,
+ pioctl_req);
+ } else {
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_rate_ioctl_get_rate_index(pmadapter,
+ pioctl_req);
+ else
+ status = wlan_rate_ioctl_set_rate_index(pmadapter,
+ pioctl_req);
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_rate_ioctl_get_data_rate(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get remain on channel setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_radio_ioctl_remain_chan_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_REMAIN_ON_CHANNEL,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &radio_cfg->param.remain_chan);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Set/Get wifi_direct_mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_bss_ioctl_wifi_direct_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_WIFI_DIRECT_MODE_CONFIG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &bss->param.wfd_mode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get p2p config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_misc_p2p_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_P2P_PARAMS_CONFIG, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &misc_cfg->param.p2p_config);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set coalesce config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_coalesce_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_COALESCE_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ &misc_cfg->param.coalesce_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set USB packet aggregation parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_aggr_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_PACKET_AGGR_CTRL, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &misc->param.aggr_params);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef USB
+/**
+ * @brief Get/Set USB packet aggregation parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_usb_aggr_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pmadapter->pcard_usb->fw_usb_aggr == MFALSE) {
+ PRINTM(MERROR, "USB aggregation not supported by FW\n");
+ pioctl_req->status_code = MLAN_ERROR_CMD_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &misc->param.usb_aggr_params);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get/Set Tx control configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_txcontrol(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ pmpriv->pkt_tx_ctrl = misc->param.tx_control;
+ else
+ misc->param.tx_control = pmpriv->pkt_tx_ctrl;
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef RX_PACKET_COALESCE
+/**
+ * @brief Get/Set RX packet coalescing configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_rx_pkt_coalesce_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_PKT_COALESCE_CFG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &misc->param.rx_coalesce);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Is any uAP started or STA connected?
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MTRUE/MFALSE
+ */
+t_bool wlan_check_interface_active(mlan_adapter *pmadapter)
+{
+ t_bool ret = MFALSE;
+ pmlan_private pmpriv;
+ int i;
+
+ if (pmadapter == MNULL)
+ return MFALSE;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv) {
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ ret = pmpriv->uap_bss_started;
+ else
+#endif
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ ret = pmpriv->media_connected;
+ }
+ if (ret)
+ return MTRUE;
+ }
+
+ return MFALSE;
+}
+
+/**
+ * @brief Get/Set DFS REPEATER mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_dfs_repeater_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ /* Make sure no interface is active
+ * before setting the dfs repeater mode
+ */
+ if (wlan_check_interface_active(pmadapter)) {
+ PRINTM(MMSG, "DFS-Repeater active priv found,"
+ " skip enabling the mode.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_DFS_REPEATER_MODE, cmd_action, 0,
+ (t_void *)pioctl_req, &misc->param.dfs_repeater);
+
+done:
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Low Power Mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_low_pwr_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCMD_CONFIG_LOW_POWER_MODE,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ &misc->param.low_pwr_mode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure PMIC in Firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_pmic_configure(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_PMIC_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/* @brief Set/Get CW Mode Level control
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_cwmode_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CW_MODE_CTRL, cmd_action, 0,
+ (t_void *)pioctl_req, &misc->param.cwmode);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief push value to stack
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param len Length of value
+ * @param val A pointer to value
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+inline mlan_status push_n(pmlan_adapter pmadapter, mef_stack *s, t_u8 len,
+ t_u8 *val)
+{
+ if ((s->sp + len) <= MAX_NUM_STACK_BYTES) {
+ memcpy_ext(pmadapter, s->byte + s->sp, val, len,
+ MAX_NUM_STACK_BYTES - s->sp);
+ s->sp += len;
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "Stack is full\n");
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief push value to stack accoring to operand type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param op A pointer to mef_op
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+inline mlan_status mef_push(pmlan_adapter pmadapter, mef_stack *s, mef_op *op)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 nbytes;
+ switch (op->operand_type) {
+ case OPERAND_DNUM:
+ ret = push_n(pmadapter, s, 4, op->val);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = push_n(pmadapter, s, 1, &op->operand_type);
+ else
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ case OPERAND_BYTE_SEQ:
+ nbytes = op->val[0];
+ if (MLAN_STATUS_SUCCESS ==
+ push_n(pmadapter, s, nbytes, op->val + 1) &&
+ MLAN_STATUS_SUCCESS == push_n(pmadapter, s, 1, op->val) &&
+ MLAN_STATUS_SUCCESS ==
+ push_n(pmadapter, s, 1, &op->operand_type))
+ ret = MLAN_STATUS_SUCCESS;
+ else
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ default:
+ ret = push_n(pmadapter, s, 1, &op->operand_type);
+ break;
+ }
+ return ret;
+}
+
+/**
+ * @brief push dnum filter to stack
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param filter A pointer to filter item
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status push_filter_dnum_eq(pmlan_adapter pmadapter, mef_stack *s,
+ mef_filter_t *filter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 dnum;
+ mef_op op;
+
+ ENTER();
+
+ if (!filter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (filter->fill_flag != (FILLING_TYPE | FILLING_PATTERN |
+ FILLING_OFFSET | FILLING_NUM_BYTES)) {
+ PRINTM(MERROR, "Filter item fill error\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Format of decimal num:
+ * | 5 bytes | 5 bytes | 5 bytes | 1 byte | |
+ * pattern | offset | num of bytes | type (TYPE_DNUM_EQ) |
+ */
+
+ /* push pattern */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->pattern;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push offset */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->offset;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push num of bytes */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->num_bytes;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push type */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = TYPE_DNUM_EQ;
+ ret = mef_push(pmadapter, s, &op);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief push byte_eq filter to stack
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param filter A pointer to filter item
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status push_filter_byte_eq(pmlan_adapter pmadapter, mef_stack *s,
+ mef_filter_t *filter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 dnum;
+ mef_op op;
+
+ ENTER();
+
+ if (!filter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT |
+ FILLING_BYTE_SEQ | FILLING_OFFSET)) {
+ PRINTM(MERROR, "Filter item fill error\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Format of decimal num:
+ * | 5 bytes | val | 5 bytes | 1 byte | |
+ * repeat | bytes seq | offset | type (TYPE_BYTE_EQ) |
+ */
+
+ /* push repeat */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->repeat;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push bytes seq */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_BYTE_SEQ;
+ op.val[0] = filter->num_byte_seq;
+ memcpy_ext(pmadapter, &op.val[1], filter->byte_seq,
+ filter->num_byte_seq, MAX_NUM_BYTE_SEQ);
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push offset */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->offset;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push type */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = TYPE_BYTE_EQ;
+ ret = mef_push(pmadapter, s, &op);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief push bite_eq filter to stack
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param filter A pointer to filter item
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status push_filter_bit_eq(pmlan_adapter pmadapter, mef_stack *s,
+ mef_filter_t *filter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 dnum;
+ mef_op op;
+
+ ENTER();
+
+ if (!filter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (filter->fill_flag != (FILLING_TYPE | FILLING_REPEAT |
+ FILLING_BYTE_SEQ | FILLING_OFFSET)) {
+ PRINTM(MERROR, "Filter item fill error\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Format of decimal num:
+ * | val | 5 bytes | val | 1 byte | |
+ * bytes seq | offset | mask seq | type (TYPE_BIT_EQ) |
+ */
+
+ /* push bytes seq */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_BYTE_SEQ;
+ op.val[0] = filter->num_byte_seq;
+ memcpy_ext(pmadapter, &op.val[1], filter->byte_seq,
+ filter->num_byte_seq, MAX_NUM_BYTE_SEQ);
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push offset */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_DNUM;
+ dnum = filter->offset;
+ memcpy_ext(pmadapter, op.val, &dnum, sizeof(dnum), sizeof(op.val));
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push mask seq */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = OPERAND_BYTE_SEQ;
+ op.val[0] = filter->num_mask_seq;
+ memcpy_ext(pmadapter, &op.val[1], filter->mask_seq,
+ filter->num_mask_seq, MAX_NUM_BYTE_SEQ);
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* push type */
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = TYPE_BIT_EQ;
+ ret = mef_push(pmadapter, s, &op);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief push filter to stack
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param filter A pointer to filter item
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status wlan_push_filter(pmlan_adapter pmadapter, mef_stack *s,
+ mef_filter_t *filter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ switch (filter->type) {
+ case TYPE_DNUM_EQ:
+ ret = push_filter_dnum_eq(pmadapter, s, filter);
+ break;
+ case TYPE_BYTE_EQ:
+ ret = push_filter_byte_eq(pmadapter, s, filter);
+ break;
+ case TYPE_BIT_EQ:
+ ret = push_filter_bit_eq(pmadapter, s, filter);
+ break;
+ default:
+ PRINTM(MERROR, "Invalid filter type\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ return ret;
+}
+
+/**
+ * @brief generate mef data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param s A pointer to mef_stack
+ * @param entry A pointer to mef_entry_t
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status wlan_generate_mef_filter_stack(pmlan_adapter pmadapter,
+ mef_stack *s, mef_entry_t *entry)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mef_op op;
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < entry->filter_num; i++) {
+ ret = wlan_push_filter(pmadapter, s, &entry->filter_item[i]);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "push filter to stack error\n");
+ goto done;
+ }
+ if (i != 0) {
+ memset(pmadapter, &op, 0, sizeof(op));
+ op.operand_type = entry->rpn[i];
+ ret = mef_push(pmadapter, s, &op);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "push filter rpn error\n");
+ goto done;
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set the mef entries to firmware
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmef A pointer to mef_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status wlan_set_mef_entry(mlan_private *pmpriv, pmlan_adapter pmadapter,
+ mef_cfg *pmef)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cmd *hostcmd;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mef_hdr;
+ mef_entry_header *entry_hdr;
+ mef_stack *stack;
+ mef_entry_t *pentry;
+ t_u8 *buf;
+ t_u32 i, buf_len;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ if (pmef->entry_num > MAX_NUM_ENTRIES) {
+ PRINTM(MERROR, "Too many entries\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pcb = &pmadapter->callbacks;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF,
+ (t_u8 **)&hostcmd);
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate cmd data buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_handle;
+ }
+
+ /** Fill the cmd header data*/
+ memset(pmadapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+ hostcmd_hdr = (HostCmd_DS_GEN *)buf;
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ buf_len = S_DS_GEN;
+
+ /** Fill HostCmd_DS_MEF_CFG*/
+ mef_hdr = (HostCmd_DS_MEF_CFG *)(buf + buf_len);
+ mef_hdr->criteria = wlan_cpu_to_le32(pmef->criteria);
+ mef_hdr->nentries = wlan_cpu_to_le16(pmef->entry_num);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+
+ /** generate mef entry data*/
+ for (i = 0, pentry = pmef->pentry; i < pmef->entry_num; i++, pentry++) {
+ /** Fill entry header data*/
+ entry_hdr = (mef_entry_header *)(buf + buf_len);
+ entry_hdr->mode = pentry->mode;
+ entry_hdr->action = pentry->action;
+ buf_len += sizeof(mef_entry_header);
+
+ /** Fill Stack data*/
+ stack = (mef_stack *)(buf + buf_len);
+ ret = wlan_generate_mef_filter_stack(pmadapter, stack, pentry);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Generate mef data error\n");
+ goto err_handle;
+ }
+ buf_len += (stack->sp + sizeof(stack->sp));
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = wlan_cpu_to_le32(buf_len);
+
+ DBG_HEXDUMP(MCMD_D, "MEF DATA", (t_u8 *)hostcmd, buf_len + 4);
+
+ /** Send command to firmware*/
+ ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)MNULL,
+ (t_void *)hostcmd);
+
+err_handle:
+ if (hostcmd)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
+done:
+ LEAVE();
+ return ret;
+}
+
+/*
+ * @brief generate Host_CMD_MEF_CFG cmd data to firmware
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or FAIL
+ */
+mlan_status wlan_process_mef_cfg_cmd(mlan_private *pmpriv,
+ pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+ mef_cfg mef;
+ mef_entry_t *pentry;
+ mef_entry *pmef;
+ t_u16 entry_num = 0;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ /** check how many entries in adapter*/
+ pmef = &pmadapter->entry_cfg;
+ entry_num += pmef->num_wowlan_entry;
+ entry_num += pmef->num_ipv6_ns_offload;
+ if (!entry_num) {
+ PRINTM(MIOCTL, "No filter entries\n");
+ goto done;
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mef_entry_t) * entry_num, MLAN_MEM_DEF,
+ (t_u8 **)&mef.pentry);
+ if (ret != MLAN_STATUS_SUCCESS || mef.pentry == MNULL) {
+ PRINTM(MERROR, "Failed to allocate cmd data buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_handle;
+ }
+ /** Fill mef_cfg structure*/
+ mef.criteria = pmef->criteria;
+ mef.entry_num = entry_num;
+ memset(pmadapter, mef.pentry, 0, sizeof(mef_entry_t) * entry_num);
+ pentry = mef.pentry;
+ /** Fill mef_entry_t structure*/
+ /** Copy wowlan entry*/
+ if (pmef->num_wowlan_entry) {
+ memcpy_ext(pmadapter, pentry, &pmef->entry[6],
+ sizeof(mef_entry_t), sizeof(mef_entry_t));
+ pentry += pmef->num_wowlan_entry;
+ }
+ /** Copy IPv6 NS message offload entry */
+ if (pmef->num_ipv6_ns_offload)
+ memcpy_ext(pmadapter, pentry, &pmef->entry[7],
+ sizeof(mef_entry_t), sizeof(mef_entry_t));
+
+ /** Set Entries to firmware*/
+ ret = wlan_set_mef_entry(pmpriv, pmadapter, &mef);
+ if (ret != MLAN_STATUS_SUCCESS)
+ PRINTM(MERROR, "Set MEF entries error\n");
+
+err_handle:
+ if (mef.pentry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)mef.pentry);
+done:
+ LEAVE();
+ return ret;
+}
+
+/* @brief Get/Set NV-FLT-CONFIG parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_misc_ioctl_mef_flt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ mlan_ds_misc_mef_flt_cfg *mef_cfg = MNULL;
+ mef_entry *pmef = MNULL;
+
+ ENTER();
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mef_cfg = &misc_cfg->param.mef_flt_cfg;
+ pmef = &pmadapter->entry_cfg;
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN) {
+ pmef->num_wowlan_entry = 1;
+ pmef->criteria |= mef_cfg->criteria;
+ memcpy_ext(pmadapter, &pmef->entry[6],
+ &mef_cfg->mef_entry, sizeof(mef_entry_t),
+ sizeof(mef_entry_t));
+ }
+ if (mef_cfg->mef_act_type == MEF_ACT_IPV6_NS) {
+ pmef->num_ipv6_ns_offload = 1;
+ pmef->criteria |= mef_cfg->criteria;
+ memcpy_ext(pmadapter, &pmef->entry[7],
+ &mef_cfg->mef_entry, sizeof(mef_entry_t),
+ sizeof(mef_entry_t));
+ }
+ break;
+ case MLAN_ACT_GET:
+ if (mef_cfg->mef_act_type == MEF_ACT_WOWLAN)
+ memcpy_ext(pmadapter, &mef_cfg->mef_entry,
+ &pmef->entry[6], sizeof(mef_entry_t),
+ sizeof(mef_entry_t));
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPA passphrase for esupplicant
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_sec_ioctl_passphrase(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u16 cmd_action = 0;
+#ifdef STA_SUPPORT
+ BSSDescriptor_t *pbss_desc;
+ int i = 0;
+#endif
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA &&
+ !IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY)
+ SupplicantQueryPassphrase(
+ pmpriv->psapriv,
+ (void *)&sec->param.passphrase);
+ else if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
+ SupplicantClearPMK(pmpriv->psapriv,
+ (void *)&sec->param.passphrase);
+ else
+ SupplicantSetPassphrase(pmpriv->psapriv,
+ (void *)&sec->param.passphrase);
+
+ LEAVE();
+ return ret;
+ }
+#endif
+
+ if (!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
+ LEAVE();
+ return ret;
+ }
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_CLEAR)
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else if (pioctl_req->action == MLAN_ACT_CLEAR) {
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ } else {
+ if (sec->param.passphrase.psk_type == MLAN_PSK_QUERY) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA &&
+ sec->param.passphrase.ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(
+ pmpriv,
+ (t_u8 *)&sec->param.passphrase.bssid,
+ MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy_ext(pmadapter,
+ &sec->param.passphrase.ssid,
+ &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ memset(pmadapter,
+ &sec->param.passphrase.bssid, 0,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO,
+ "PSK_QUERY: found ssid=%s\n",
+ sec->param.passphrase.ssid.ssid);
+ }
+ } else
+#endif
+ memset(pmadapter, &sec->param.passphrase.bssid,
+ 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PMK, cmd_action,
+ 0, (t_void *)pioctl_req, (t_void *)sec);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set per packet Txctl and Rxinfo configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_misc_per_pkt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ pmpriv->rx_pkt_info = MFALSE;
+ if (misc->param.txrx_pkt_ctrl & RX_PKT_INFO)
+ pmpriv->rx_pkt_info = MTRUE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_region(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ int i;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.region_code = pmadapter->region_code;
+ } else {
+ if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
+ PRINTM(MERROR,
+ "ForceRegionRule is set in the on-chip OTP"
+ " memory\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (misc->param.region_code == region_code_index[i]) {
+ pmadapter->region_code =
+ (t_u16)misc->param.region_code;
+ break;
+ }
+ }
+ /* It's unidentified region code */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ PRINTM(MERROR, "Region Code not identified\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->cfp_code_bg = misc->param.region_code;
+ pmadapter->cfp_code_a = misc->param.region_code;
+ if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
+ pmadapter->config_bands |
+ pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure GPIO independent reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_ind_rst_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_INDEPENDENT_RESET_CFG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (t_void *)&misc->param.ind_rst_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get timestamp from firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_get_tsf(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, "No support set tsf!");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GET_TSF, cmd_action, 0,
+ (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Create custom regulatory cfg
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_chan_reg_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, "No support set channel region cfg!");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check operating class validation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_operclass_validation(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u8 channel, oper_class;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ channel = misc->param.bw_chan_oper.channel;
+ oper_class = misc->param.bw_chan_oper.oper_class;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ret = wlan_check_operclass_validation(pmpriv, channel,
+ oper_class);
+ } else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Region channel power setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_get_rgchnpwr_cfg(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CHAN_REGION_CFG, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get CHAN_TPRC setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_get_chan_trpc_cfg(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CHANNEL_TRPC_CONFIG, cmd_action,
+ 0, (t_void *)pioctl_req,
+ (t_void *)&misc->param.trpc_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get non-global operating class
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_oper_class(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u8 channel, bandwidth, oper_class = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ channel = misc->param.bw_chan_oper.channel;
+ switch (misc->param.bw_chan_oper.bandwidth) {
+ case 20:
+ bandwidth = BW_20MHZ;
+ break;
+ case 40:
+ bandwidth = BW_40MHZ;
+ break;
+ case 80:
+ bandwidth = BW_80MHZ;
+ break;
+ default:
+ bandwidth = BW_20MHZ;
+ break;
+ }
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ ret = wlan_get_curr_oper_class(pmpriv, channel, bandwidth,
+ &oper_class);
+ misc->param.bw_chan_oper.oper_class = oper_class;
+ } else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config dynamic bandwidth
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_fw_dump_event(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FW_DUMP_EVENT, cmd_action, 0,
+ (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config boot sleep
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_bootsleep(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, "Unsupported cmd_action 0x%x\n",
+ pioctl_req->action);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_BOOT_SLEEP, cmd_action, 0,
+ (t_void *)pioctl_req, &misc->param.boot_sleep);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Infra/Ad-hoc band configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_radio_ioctl_band_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ t_u32 i, global_band = 0;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ infra_band = radio_cfg->param.band_cfg.config_bands;
+ adhoc_band = radio_cfg->param.band_cfg.adhoc_start_band;
+ adhoc_channel = radio_cfg->param.band_cfg.adhoc_channel;
+
+ /* SET Infra band */
+ if ((infra_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* SET Ad-hoc Band */
+ if ((adhoc_band | pmadapter->fw_bands) & ~pmadapter->fw_bands) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!adhoc_band)
+ adhoc_band = pmadapter->adhoc_start_band;
+
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i] &&
+ pmadapter->priv[i] != pmpriv &&
+ GET_BSS_ROLE(pmadapter->priv[i]) ==
+ MLAN_BSS_ROLE_STA)
+ global_band |=
+ (t_u32)pmadapter->priv[i]->config_bands;
+ }
+ global_band |= infra_band;
+
+ if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
+ global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef STA_SUPPORT
+ if (wlan_11d_set_universaltable(pmpriv,
+ global_band | adhoc_band)) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+ pmpriv->config_bands = infra_band;
+ pmadapter->config_bands = global_band;
+
+ pmadapter->adhoc_start_band = adhoc_band;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+
+#ifdef STA_SUPPORT
+ /*
+ * If no adhoc_channel is supplied verify if the existing
+ * adhoc channel compiles with new adhoc_band
+ */
+ if (!adhoc_channel) {
+ if (!wlan_find_cfp_by_band_and_channel(
+ pmadapter, pmadapter->adhoc_start_band,
+ pmpriv->adhoc_channel)) {
+ /* Pass back the default channel */
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL;
+ if ((pmadapter->adhoc_start_band & BAND_A)) {
+ radio_cfg->param.band_cfg.adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ }
+ } else {
+ /* Return error if adhoc_band and adhoc_channel
+ * combination is invalid
+ */
+ if (!wlan_find_cfp_by_band_and_channel(
+ pmadapter, pmadapter->adhoc_start_band,
+ (t_u16)adhoc_channel)) {
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->adhoc_channel = (t_u8)adhoc_channel;
+ }
+
+#endif
+
+ } else {
+ /* Infra Bands */
+ radio_cfg->param.band_cfg.config_bands = pmpriv->config_bands;
+ /* Adhoc Band */
+ radio_cfg->param.band_cfg.adhoc_start_band =
+ pmadapter->adhoc_start_band;
+ /* Adhoc Channel */
+ radio_cfg->param.band_cfg.adhoc_channel = pmpriv->adhoc_channel;
+ /* FW support Bands */
+ radio_cfg->param.band_cfg.fw_bands = pmadapter->fw_bands;
+ PRINTM(MINFO, "Global config band = %d\n",
+ pmadapter->config_bands);
+#ifdef STA_SUPPORT
+#endif
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Rx Abort Cfg
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_rxabortcfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_ABORT_CFG, cmd_action, 0,
+ (t_void *)pioctl_req,
+ &(pmisc->param.rx_abort_cfg));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Rx Abort Cfg ext
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_rxabortcfg_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RX_ABORT_CFG_EXT, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &(pmisc->param.rx_abort_cfg_ext));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Dot11mc unassociated FTM CFG
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.dot11mc_unassoc_ftm_cfg));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Tx ampdu protection mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_tx_ampdu_prot_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_AMPDU_PROT_MODE,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.tx_ampdu_prot_mode));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate adapt config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_rate_adapt_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RATE_ADAPT_CFG, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &(pmisc->param.rate_adapt_cfg));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief CCK Desense config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_cck_desense_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CCK_DESENSE_CFG, cmd_action,
+ 0, (t_void *)pioctl_req,
+ &(pmisc->param.cck_desense_cfg));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config dynamic bandwidth
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_dyn_bw(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DYN_BW, cmd_action, 0,
+ (t_void *)pioctl_req, &misc->param.dyn_bw);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get low power mode configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+mlan_status wlan_power_ioctl_set_get_lpm(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_power_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0, lpm = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_power_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ lpm = pm_cfg->param.lpm;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_LOW_POWER_MODE_CFG,
+ cmd_action, 0, (t_void *)pioctl_req, &lpm);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief RF Test Mode config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_rf_test_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = MNULL;
+ mlan_ds_misc_cfg *pmisc = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (!pioctl_req)
+ goto done;
+
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ switch (pmisc->sub_command) {
+ case MLAN_OID_MISC_RF_TEST_GENERIC:
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.mfg_generic_cfg));
+ break;
+ case MLAN_OID_MISC_RF_TEST_TX_CONT:
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.mfg_tx_cont));
+ break;
+ case MLAN_OID_MISC_RF_TEST_TX_FRAME:
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else {
+ PRINTM(MERROR, "Unsupported cmd_action\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MFG_COMMAND,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.mfg_tx_frame2));
+ break;
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Range ext mode config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_range_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RANGE_EXT, cmd_action, 0,
+ (t_void *)pioctl_req,
+ &(pmisc->param.range_ext_mode));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_module.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_module.c
new file mode 100644
index 000000000000..4e26b90010bb
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_module.c
@@ -0,0 +1,65 @@
+/** @file mlan_module.c
+ *
+ * @brief This file declares the exported symbols from MLAN.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 12/08/2008: initial version
+******************************************************/
+
+#ifdef LINUX
+#include <linux/module.h>
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+
+EXPORT_SYMBOL(mlan_register);
+EXPORT_SYMBOL(mlan_unregister);
+EXPORT_SYMBOL(mlan_init_fw);
+EXPORT_SYMBOL(mlan_set_init_param);
+EXPORT_SYMBOL(mlan_dnld_fw);
+EXPORT_SYMBOL(mlan_shutdown_fw);
+#ifdef USB
+EXPORT_SYMBOL(mlan_write_data_async_complete);
+EXPORT_SYMBOL(mlan_recv);
+#endif
+EXPORT_SYMBOL(mlan_send_packet);
+EXPORT_SYMBOL(mlan_ioctl);
+EXPORT_SYMBOL(mlan_main_process);
+EXPORT_SYMBOL(mlan_rx_process);
+EXPORT_SYMBOL(mlan_select_wmm_queue);
+#if defined(SDIO) || defined(PCIE)
+EXPORT_SYMBOL(mlan_interrupt);
+#if defined(SYSKT)
+EXPORT_SYMBOL(mlan_hs_callback);
+#endif /* SYSKT_MULTI || SYSKT */
+#endif /* SDIO || PCIE */
+
+EXPORT_SYMBOL(mlan_pm_wakeup_card);
+EXPORT_SYMBOL(mlan_is_main_process_running);
+#ifdef PCIE
+EXPORT_SYMBOL(mlan_set_int_mode);
+#endif
+
+MODULE_DESCRIPTION("M-WLAN MLAN Driver");
+MODULE_AUTHOR("NXP");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
+#endif /* LINUX */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.c
new file mode 100644
index 000000000000..51e55a90b73b
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.c
@@ -0,0 +1,4205 @@
+/** @file mlan_pcie.c
+ *
+ * @brief This file contains PCI-E specific code
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/01/2012: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_pcie.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+static mlan_status wlan_pcie_delete_evtbd_ring(pmlan_adapter pmadapter);
+static mlan_status wlan_pcie_delete_rxbd_ring(pmlan_adapter pmadapter);
+
+#if defined(PCIE9098) || defined(PCIE9097)
+/**
+ * @brief This function init the adma setting
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param adma_type TX/RX data, event, cmd/cmdresp
+ * @param pbase physical address
+ * @param size desc num/dma_size
+ * @param init init flag
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_init_adma(mlan_adapter *pmadapter, t_u8 type,
+ t_u64 pbase, t_u16 size, t_u8 init)
+{
+ t_u32 dma_cfg, dma_cfg2, int_mapping;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 q_addr = 0;
+ t_u8 direction = 0;
+ t_u8 dma_mode = 0;
+ t_u32 msix_data;
+ t_u32 msix_vector;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ if (init)
+ PRINTM(MCMND, "Init ADMA: type=%d, size=%d init=%d\n", type,
+ size, init);
+ switch (type) {
+ case ADMA_TX_DATA:
+ q_addr = ADMA_CHAN0_Q0;
+ direction = ADMA_HOST_TO_DEVICE;
+ dma_mode = DMA_MODE_DUAL_DESC;
+ msix_vector = ADMA_VECTOR_CHAN0_Q0;
+ break;
+ case ADMA_RX_DATA:
+ q_addr = ADMA_CHAN1_Q0;
+ direction = ADMA_DEVICE_TO_HOST;
+ dma_mode = DMA_MODE_DUAL_DESC;
+ msix_vector = AMDA_VECTOR_CHAN1_Q0;
+ break;
+ case ADMA_EVENT:
+ q_addr = ADMA_CHAN1_Q1;
+ direction = ADMA_DEVICE_TO_HOST;
+ dma_mode = DMA_MODE_DUAL_DESC;
+ msix_vector = AMDA_VECTOR_CHAN1_Q1;
+ break;
+ case ADMA_CMD:
+ q_addr = ADMA_CHAN2_Q0;
+ direction = ADMA_HOST_TO_DEVICE;
+ dma_mode = DMA_MODE_DIRECT;
+ msix_vector = AMDA_VECTOR_CHAN2_Q0;
+ break;
+ case ADMA_CMDRESP:
+ q_addr = ADMA_CHAN2_Q1;
+ direction = ADMA_DEVICE_TO_HOST;
+ dma_mode = DMA_MODE_DIRECT;
+ msix_vector = AMDA_VECTOR_CHAN2_Q1;
+ break;
+ default:
+ PRINTM(MERROR, "unknow adma type\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ if (ret)
+ goto done;
+ if (init) {
+ if (dma_mode == DMA_MODE_DUAL_DESC) {
+ if (direction == ADMA_HOST_TO_DEVICE)
+ int_mapping = DEST_INT_TO_DEVICE;
+ else
+ int_mapping = DEST_INT_TO_HOST;
+ } else {
+ int_mapping = 0;
+ }
+ /* set INT_MAPPING register */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_INT_MAPPING,
+ (t_u32)int_mapping)) {
+ PRINTM(MERROR,
+ "Failed to write ADMA_INT_MAPPING register.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Read the dma_cfg2 register */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_DMA_CFG2, &dma_cfg2)) {
+ PRINTM(MERROR, "Fail to read DMA CFG2 register\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ dma_cfg2 &= ~(ADMA_SRC_DMA_DONE_INT_BYPASS_EN |
+ ADMA_DST_DMA_DONE_INT_BYPASS_EN |
+ ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN |
+ ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN |
+ ADMA_MSI_LEGACY_ENABLE | ADMA_MSIX_ENABLE |
+ ADMA_MSIX_INT_SRC_DST_SEL);
+
+ if (dma_mode == DMA_MODE_DUAL_DESC) {
+ if (direction == ADMA_HOST_TO_DEVICE) {
+ dma_cfg2 |= ADMA_SRC_DMA_DONE_INT_BYPASS_EN;
+ if (pmadapter->pcard_pcie->pcie_int_mode !=
+ PCIE_INT_MODE_MSIX)
+ dma_cfg2 |=
+ ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN;
+ } else {
+ dma_cfg2 |= ADMA_DST_DMA_DONE_INT_BYPASS_EN;
+ if (pmadapter->pcard_pcie->pcie_int_mode !=
+ PCIE_INT_MODE_MSIX)
+ dma_cfg2 |=
+ ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN;
+ }
+ } else {
+ if (direction == ADMA_HOST_TO_DEVICE)
+ dma_cfg2 |= ADMA_SRC_ADDR_IS_HOST;
+ else
+ dma_cfg2 |= ADMA_DST_ADDR_IS_HOST;
+ }
+
+ if (pmadapter->pcard_pcie->pcie_int_mode ==
+ PCIE_INT_MODE_MSIX) {
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_MSIX_DOORBELL_DATA,
+ &msix_data)) {
+ PRINTM(MERROR,
+ "Fail to read DMA MSIX data register\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ msix_data &= ~ADMA_MSIX_VECTOR_MASK;
+ msix_data &= ~ADMA_MSIX_PF_MASK;
+ msix_data |= msix_vector;
+ msix_data |= pmadapter->pcard_pcie->func_num
+ << ADMA_MSIX_PF_BIT;
+ PRINTM(MCMND, "msix_data=0x%x\n", msix_data);
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr +
+ ADMA_MSIX_DOORBELL_DATA,
+ (t_u32)msix_data)) {
+ PRINTM(MERROR,
+ "Failed to write DMA DOORBELL_DATA.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ dma_cfg2 |= ADMA_MSIX_ENABLE;
+ } else
+ dma_cfg2 |= ADMA_MSI_LEGACY_ENABLE;
+ PRINTM(MCMND, "dma_cfg2=0x%x\n", dma_cfg2);
+
+ /* enable INT_BYPASS_EN in the dma_cfg2 register */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_DMA_CFG2,
+ (t_u32)dma_cfg2)) {
+ PRINTM(MERROR, "Failed to write DMA CFG2.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ /* Read the TX ring read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle, q_addr + ADMA_DMA_CFG,
+ &dma_cfg)) {
+ PRINTM(MERROR, "Fail to read DMA CFG register\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (direction == ADMA_HOST_TO_DEVICE) {
+ /* Write the lower 32bits of the physical address to
+ * ADMA_SRC_LOW */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_SRC_LOW, (t_u32)pbase)) {
+ PRINTM(MERROR, "Failed to write ADMA_SRC_LOW.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the upper 32bits of the physical address to
+ * ADMA_SRC_HIGH */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_SRC_HIGH,
+ (t_u32)((t_u64)pbase >> 32))) {
+ PRINTM(MERROR, "Failed to write ADMA_SRC_HIGH.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (init) {
+ /** Enable DMA done interrupt */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ q_addr + ADMA_SRC_INT_STATUS_MASK,
+ DEF_ADMA_INT_MASK)) {
+ PRINTM(MERROR,
+ "Failed to write ADMA_SRC_INT_STATUS_MASK.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_SRC_INT_MASK,
+ DEF_ADMA_INT_MASK)) {
+ PRINTM(MERROR,
+ "Failed to write ADMA_SRC_INT_MASK.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (dma_mode == DMA_MODE_DUAL_DESC) {
+ dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
+ SRC_NUM_DESC_MASK | DMA_SIZE_MASK);
+ dma_cfg |= (t_u32)size << SRC_NUM_DESC_BIT;
+ dma_cfg |= DESC_MODE_RING << 2;
+ } else {
+ dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
+ SRC_NUM_DESC_MASK | DST_NUM_DESC_MASK |
+ DMA_SIZE_MASK);
+ dma_cfg |= (t_u32)size << DMA_SIZE_BIT;
+ }
+ } else {
+ /* Write the lower 32bits of the physical address to
+ * ADMA_DST_LOW */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_DST_LOW, (t_u32)pbase)) {
+ PRINTM(MERROR, "Failed to write ADMA_DST_LOW.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the upper 32bits of the physical address to
+ * ADMA_DST_HIGH */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_DST_HIGH,
+ (t_u32)((t_u64)pbase >> 32))) {
+ PRINTM(MERROR, "Failed to write ADMA_DST_HIGH.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (init && (dma_mode == DMA_MODE_DUAL_DESC)) {
+ /** Enable DMA done interrupt */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ q_addr + ADMA_DST_INT_STATUS_MASK,
+ DEF_ADMA_INT_MASK)) {
+ PRINTM(MERROR,
+ "Failed to write ADMA_SRC_INT_STATUS_MASK.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_DST_INT_MASK,
+ DEF_ADMA_INT_MASK)) {
+ PRINTM(MERROR,
+ "Failed to write ADMA_SRC_INT_MASK.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (dma_mode == DMA_MODE_DUAL_DESC) {
+ dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
+ DST_NUM_DESC_MASK | DMA_SIZE_MASK);
+ dma_cfg |= (t_u32)size << DST_NUM_DESC_BIT;
+ dma_cfg |= DESC_MODE_RING << 2;
+ } else {
+ dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
+ SRC_NUM_DESC_MASK | DST_NUM_DESC_MASK);
+ }
+ }
+ dma_cfg |= (t_u32)dma_mode;
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle, q_addr + ADMA_DMA_CFG,
+ dma_cfg)) {
+ PRINTM(MERROR, "Fail to set DMA CFG register\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (type == ADMA_CMD && !init) {
+ /* Write 1 to src_wr_ptr to trigger direct dma */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ q_addr + ADMA_SRC_RW_PTR, 1)) {
+ PRINTM(MERROR, "Failed to write ADMA_SRC_HIGH.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+/**
+ * @brief This function set the host interrupt select mask
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param enable 0-disable 1-enable
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_set_host_int_select_mask(mlan_adapter *pmadapter,
+ t_u8 enable)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 int_sel_mask = 0;
+ t_u32 int_clr_mask = 0;
+ ENTER();
+
+ if (enable) {
+ int_sel_mask = PCIE9098_HOST_INTR_SEL_MASK;
+ int_clr_mask = pmadapter->pcard_pcie->reg->host_intr_mask;
+ }
+
+ /* Simply write the mask to the register */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle, PCIE9098_HOST_INT_SEL,
+ int_sel_mask)) {
+ PRINTM(MWARN, "Set host interrupt select register failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
+ if (!pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
+ /** enable read to clear interrupt */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_host_int_clr_sel,
+ int_clr_mask)) {
+ PRINTM(MWARN,
+ "enable read to clear interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+/**
+ * @brief This function handles command response completion
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_vdll_complete(mlan_adapter *pmadapter)
+{
+ mlan_buffer *pcmdbuf;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ /*unmap the cmd pmbuf, so the cpu can not access the memory in the
+ * command node*/
+ pcmdbuf = pmadapter->pcard_pcie->vdll_cmd_buf;
+ if (pcmdbuf) {
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pcmdbuf->pbuf + pcmdbuf->data_offset,
+ pcmdbuf->buf_pa, pcmdbuf->data_len,
+ PCI_DMA_TODEVICE);
+ pmadapter->pcard_pcie->vdll_cmd_buf = MNULL;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function downloads VDLL image to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_vdll(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u16 *tmp;
+ t_u8 *payload;
+
+ ENTER();
+ pmadapter->cmd_sent = MTRUE;
+ payload = pmbuf->pbuf + pmbuf->data_offset;
+
+ tmp = (t_u16 *)&payload[0];
+ *tmp = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
+ tmp = (t_u16 *)&payload[2];
+ *tmp = wlan_cpu_to_le16(MLAN_TYPE_VDLL);
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(
+ pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, pmbuf->data_len, PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR,
+ "PCIE - Download VDLL block: moal_map_memory failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcard_pcie->vdll_cmd_buf = pmbuf;
+ /* issue the DMA */
+ /* send the VDLL block down to the firmware */
+ wlan_init_adma(pmadapter, ADMA_CMD, pmbuf->buf_pa, pmbuf->data_len,
+ MFALSE);
+
+ PRINTM(MINFO, "PCIE - Download VDLL Block: successful.\n");
+done:
+ if (ret == MLAN_STATUS_FAILURE)
+ pmadapter->cmd_sent = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function disables the host interrupt
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_disable_host_int_mask(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_mask,
+ 0x00000000)) {
+ PRINTM(MWARN, "Disable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupt
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_enable_host_int_mask(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ /* Simply write the mask to the register */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_mask,
+ pmadapter->pcard_pcie->reg->host_intr_mask)) {
+ PRINTM(MWARN, "Enable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param enable 0-disable 1-enable
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_pcie_enable_host_int_status_mask(mlan_adapter *pmadapter, t_u8 enable)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 host_int_status_mask = 0;
+ ENTER();
+ if (enable)
+ host_int_status_mask =
+ pmadapter->pcard_pcie->reg->host_intr_mask;
+ /* Enable host int status mask */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_status_mask,
+ host_int_status_mask)) {
+ PRINTM(MWARN, "Enable host interrupt status mask failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_disable_pcie_host_int(mlan_adapter *pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_pcie_enable_host_int_status_mask(pmadapter, MFALSE);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
+ (pmadapter->card_type == CARD_TYPE_PCIE9097)) {
+ ret = wlan_pcie_set_host_int_select_mask(pmadapter, MFALSE);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+#endif
+ ret = wlan_pcie_disable_host_int_mask(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and
+ * handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_clear_pending_int_status(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 pcie_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX)
+ goto done;
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_status,
+ &pcie_ireg)) {
+ PRINTM(MERROR, "Read host int status register failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ PRINTM(MMSG, "pcie_ireg=0x%x\n", pcie_ireg);
+ if (pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_host_int_status,
+ ~pcie_ireg)) {
+ PRINTM(MERROR,
+ "Write host int status register failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_enable_pcie_host_int(mlan_adapter *pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ wlan_clear_pending_int_status(pmadapter);
+ ret = wlan_pcie_enable_host_int_status_mask(pmadapter, MTRUE);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
+ (pmadapter->card_type == CARD_TYPE_PCIE9097)) {
+ ret = wlan_pcie_set_host_int_select_mask(pmadapter, MTRUE);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+#endif
+ ret = wlan_pcie_enable_host_int_mask(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function creates buffer descriptor ring for TX
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_create_txbd_ring(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 i;
+#if defined(PCIE8997) || defined(PCIE8897)
+ pmlan_pcie_data_buf ptx_bd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ padma_dual_desc_buf padma_bd_buf;
+#endif
+
+ ENTER();
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer.
+ */
+ pmadapter->pcard_pcie->txbd_wrptr = 0;
+ pmadapter->pcard_pcie->txbd_pending = 0;
+ pmadapter->pcard_pcie->txbd_rdptr = 0;
+
+ /* allocate shared memory for the BD ring and divide the same in to
+ several descriptors */
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma)
+ pmadapter->pcard_pcie->txbd_ring_size =
+ sizeof(mlan_pcie_data_buf) * MLAN_MAX_TXRX_BD;
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ pmadapter->pcard_pcie->txbd_ring_size =
+ sizeof(adma_dual_desc_buf) * MLAN_MAX_TXRX_BD;
+#endif
+ PRINTM(MINFO, "TX ring: allocating %d bytes\n",
+ pmadapter->pcard_pcie->txbd_ring_size);
+
+ ret = pcb->moal_malloc_consistent(
+ pmadapter->pmoal_handle, pmadapter->pcard_pcie->txbd_ring_size,
+ &pmadapter->pcard_pcie->txbd_ring_vbase,
+ &pmadapter->pcard_pcie->txbd_ring_pbase);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
+ __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO,
+ "TX ring: - base: %p, pbase: %#x:%x,"
+ "len: %x\n",
+ pmadapter->pcard_pcie->txbd_ring_vbase,
+ (t_u32)((t_u64)pmadapter->pcard_pcie->txbd_ring_pbase >> 32),
+ (t_u32)pmadapter->pcard_pcie->txbd_ring_pbase,
+ pmadapter->pcard_pcie->txbd_ring_size);
+
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ pmadapter->pcard_pcie->tx_buf_list[i] = MNULL;
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf
+ *)(pmadapter->pcard_pcie
+ ->txbd_ring_vbase +
+ (sizeof(adma_dual_desc_buf) * i));
+ pmadapter->pcard_pcie->txbd_ring[i] =
+ (t_void *)padma_bd_buf;
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_SRC_HOST |
+ ADMA_BD_FLAG_SOP | ADMA_BD_FLAG_EOP;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ ptx_bd_buf =
+ (mlan_pcie_data_buf
+ *)(pmadapter->pcard_pcie
+ ->txbd_ring_vbase +
+ (sizeof(mlan_pcie_data_buf) * i));
+ pmadapter->pcard_pcie->txbd_ring[i] =
+ (t_void *)ptx_bd_buf;
+ ptx_bd_buf->paddr = 0;
+ ptx_bd_buf->len = 0;
+ ptx_bd_buf->flags = 0;
+ ptx_bd_buf->frag_len = 0;
+ ptx_bd_buf->offset = 0;
+ }
+#endif
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees TX buffer descriptor ring
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_delete_txbd_ring(mlan_adapter *pmadapter)
+{
+ t_u32 i;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_data_buf *ptx_bd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ if (pmadapter->pcard_pcie->tx_buf_list[i]) {
+ pmbuf = pmadapter->pcard_pcie->tx_buf_list[i];
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa,
+ MLAN_RX_DATA_BUF_SIZE,
+ PCI_DMA_TODEVICE);
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ }
+ pmadapter->pcard_pcie->tx_buf_list[i] = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ ptx_bd_buf =
+ (mlan_pcie_data_buf *)
+ pmadapter->pcard_pcie->txbd_ring[i];
+
+ if (ptx_bd_buf) {
+ ptx_bd_buf->paddr = 0;
+ ptx_bd_buf->len = 0;
+ ptx_bd_buf->flags = 0;
+ ptx_bd_buf->frag_len = 0;
+ ptx_bd_buf->offset = 0;
+ }
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)
+ pmadapter->pcard_pcie->txbd_ring[i];
+
+ if (padma_bd_buf) {
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+ }
+#endif
+ pmadapter->pcard_pcie->txbd_ring[i] = MNULL;
+ }
+
+ if (pmadapter->pcard_pcie->txbd_ring_vbase) {
+ pmadapter->callbacks.moal_mfree_consistent(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->txbd_ring_size,
+ pmadapter->pcard_pcie->txbd_ring_vbase,
+ pmadapter->pcard_pcie->txbd_ring_pbase);
+ }
+ pmadapter->pcard_pcie->txbd_pending = 0;
+ pmadapter->pcard_pcie->txbd_ring_size = 0;
+ pmadapter->pcard_pcie->txbd_wrptr = 0;
+ pmadapter->pcard_pcie->txbd_rdptr = 0;
+ pmadapter->pcard_pcie->txbd_ring_vbase = MNULL;
+ pmadapter->pcard_pcie->txbd_ring_pbase = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function creates buffer descriptor ring for RX
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_create_rxbd_ring(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+ t_u32 i;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_data_buf *prxbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+
+ pmadapter->pcard_pcie->rxbd_rdptr = 0;
+#if defined(PCIE8997) || defined(PCIE8897)
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer. The read pointer starts at 0 (zero) while the write pointer
+ * starts at zero with rollover bit set
+ */
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->rxbd_wrptr =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ /* allocate shared memory for the BD ring and divide the same in
+ to several descriptors */
+ pmadapter->pcard_pcie->rxbd_ring_size =
+ sizeof(mlan_pcie_data_buf) * MLAN_MAX_TXRX_BD;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer. The read pointer starts at 0 (zero) while the write pointer
+ * starts at MLAN_MAX_TXRX_BD
+ */
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->rxbd_wrptr = MLAN_MAX_TXRX_BD;
+ pmadapter->pcard_pcie->rxbd_ring_size =
+ sizeof(adma_dual_desc_buf) * MLAN_MAX_TXRX_BD;
+ }
+#endif
+
+ PRINTM(MINFO, "RX ring: allocating %d bytes\n",
+ pmadapter->pcard_pcie->rxbd_ring_size);
+
+ ret = pcb->moal_malloc_consistent(
+ pmadapter->pmoal_handle, pmadapter->pcard_pcie->rxbd_ring_size,
+ &pmadapter->pcard_pcie->rxbd_ring_vbase,
+ &pmadapter->pcard_pcie->rxbd_ring_pbase);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
+ __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO,
+ "RX ring: - base: %p, pbase: %#x:%x,"
+ "len: %#x\n",
+ pmadapter->pcard_pcie->rxbd_ring_vbase,
+ (t_u32)((t_u64)pmadapter->pcard_pcie->rxbd_ring_pbase >> 32),
+ (t_u32)pmadapter->pcard_pcie->rxbd_ring_pbase,
+ pmadapter->pcard_pcie->rxbd_ring_size);
+
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ /* Allocate buffer here so that firmware can DMA data on it */
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, MLAN_RX_DATA_BUF_SIZE,
+ MLAN_RX_HEADER_LEN,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "RX ring create : Unable to allocate mlan_buffer\n");
+ wlan_pcie_delete_rxbd_ring(pmadapter);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmadapter->pcard_pcie->rx_buf_list[i] = pmbuf;
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE)) {
+ PRINTM(MERROR,
+ "Rx ring create : moal_map_memory failed\n");
+ wlan_pcie_delete_rxbd_ring(pmadapter);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO,
+ "RX ring: add new mlan_buffer base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n",
+ pmbuf, pmbuf->pbuf, (t_u32)((t_u64)pmbuf->buf_pa >> 32),
+ (t_u32)pmbuf->buf_pa, pmbuf->data_len);
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ prxbd_buf =
+ (mlan_pcie_data_buf
+ *)(pmadapter->pcard_pcie
+ ->rxbd_ring_vbase +
+ (sizeof(mlan_pcie_data_buf) * i));
+ pmadapter->pcard_pcie->rxbd_ring[i] =
+ (t_void *)prxbd_buf;
+ prxbd_buf->paddr = pmbuf->buf_pa;
+ prxbd_buf->len = (t_u16)pmbuf->data_len;
+ prxbd_buf->flags = MLAN_BD_FLAG_SOP | MLAN_BD_FLAG_EOP;
+ prxbd_buf->offset = 0;
+ prxbd_buf->frag_len = (t_u16)pmbuf->data_len;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf
+ *)(pmadapter->pcard_pcie
+ ->rxbd_ring_vbase +
+ (sizeof(adma_dual_desc_buf) * i));
+ pmadapter->pcard_pcie->rxbd_ring[i] =
+ (t_void *)padma_bd_buf;
+ padma_bd_buf->paddr = pmbuf->buf_pa;
+ padma_bd_buf->len =
+ ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees RX buffer descriptor ring
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_delete_rxbd_ring(mlan_adapter *pmadapter)
+{
+ t_u32 i;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_data_buf *prxbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ if (pmadapter->pcard_pcie->rx_buf_list[i]) {
+ pmbuf = pmadapter->pcard_pcie->rx_buf_list[i];
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa,
+ MLAN_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ wlan_free_mlan_buffer(
+ pmadapter,
+ pmadapter->pcard_pcie->rx_buf_list[i]);
+ }
+ pmadapter->pcard_pcie->rx_buf_list[i] = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ prxbd_buf = (mlan_pcie_data_buf *)
+ pmadapter->pcard_pcie->rxbd_ring[i];
+
+ if (prxbd_buf) {
+ prxbd_buf->paddr = 0;
+ prxbd_buf->offset = 0;
+ prxbd_buf->frag_len = 0;
+ }
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)
+ pmadapter->pcard_pcie->rxbd_ring[i];
+
+ if (padma_bd_buf) {
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ padma_bd_buf->len = 0;
+ }
+ }
+#endif
+ pmadapter->pcard_pcie->rxbd_ring[i] = MNULL;
+ }
+
+ if (pmadapter->pcard_pcie->rxbd_ring_vbase)
+ pmadapter->callbacks.moal_mfree_consistent(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->rxbd_ring_size,
+ pmadapter->pcard_pcie->rxbd_ring_vbase,
+ pmadapter->pcard_pcie->rxbd_ring_pbase);
+ pmadapter->pcard_pcie->rxbd_ring_size = 0;
+ pmadapter->pcard_pcie->rxbd_rdptr = 0;
+ pmadapter->pcard_pcie->rxbd_wrptr = 0;
+ pmadapter->pcard_pcie->rxbd_ring_vbase = MNULL;
+ pmadapter->pcard_pcie->rxbd_ring_pbase = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function creates buffer descriptor ring for Events
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_create_evtbd_ring(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+ t_u32 i;
+#if defined(PCIE8997) || defined(PCIE8897)
+ pmlan_pcie_evt_buf pevtbd_buf;
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer. The read pointer starts at 0 (zero) while the write pointer
+ * starts at zero with rollover bit set
+ */
+ pmadapter->pcard_pcie->evtbd_rdptr = 0;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->evtbd_wrptr = EVT_RW_PTR_ROLLOVER_IND;
+ pmadapter->pcard_pcie->evtbd_ring_size =
+ sizeof(mlan_pcie_evt_buf) * MLAN_MAX_EVT_BD;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ pmadapter->pcard_pcie->evtbd_wrptr = MLAN_MAX_EVT_BD;
+ pmadapter->pcard_pcie->evtbd_ring_size =
+ sizeof(adma_dual_desc_buf) * MLAN_MAX_EVT_BD;
+ }
+#endif
+ PRINTM(MINFO, "Evt ring: allocating %d bytes\n",
+ pmadapter->pcard_pcie->evtbd_ring_size);
+
+ ret = pcb->moal_malloc_consistent(
+ pmadapter->pmoal_handle, pmadapter->pcard_pcie->evtbd_ring_size,
+ &pmadapter->pcard_pcie->evtbd_ring_vbase,
+ &pmadapter->pcard_pcie->evtbd_ring_pbase);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
+ __FUNCTION__);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ PRINTM(MINFO,
+ "Evt ring: - base: %p, pbase: %#x:%x,"
+ "len: %#x\n",
+ pmadapter->pcard_pcie->evtbd_ring_vbase,
+ (t_u32)((t_u64)pmadapter->pcard_pcie->evtbd_ring_pbase >> 32),
+ (t_u32)pmadapter->pcard_pcie->evtbd_ring_pbase,
+ pmadapter->pcard_pcie->evtbd_ring_size);
+
+ for (i = 0; i < MLAN_MAX_EVT_BD; i++) {
+ /* Allocate buffer here so that firmware can DMA data on it */
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, MAX_EVENT_SIZE,
+ MLAN_RX_HEADER_LEN,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "Event ring create : Unable to allocate mlan_buffer\n");
+ wlan_pcie_delete_evtbd_ring(pmadapter);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmadapter->pcard_pcie->evt_buf_list[i] = pmbuf;
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE)) {
+ PRINTM(MERROR,
+ "Event ring create : moal_map_memory failed\n");
+ wlan_pcie_delete_evtbd_ring(pmadapter);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pevtbd_buf =
+ (mlan_pcie_evt_buf
+ *)(pmadapter->pcard_pcie
+ ->evtbd_ring_vbase +
+ (sizeof(mlan_pcie_evt_buf) * i));
+ pmadapter->pcard_pcie->evtbd_ring[i] =
+ (t_void *)pevtbd_buf;
+ pevtbd_buf->paddr = pmbuf->buf_pa;
+ pevtbd_buf->len = (t_u16)pmbuf->data_len;
+ pevtbd_buf->flags = 0;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf
+ *)(pmadapter->pcard_pcie
+ ->evtbd_ring_vbase +
+ (sizeof(adma_dual_desc_buf) * i));
+ pmadapter->pcard_pcie->evtbd_ring[i] =
+ (t_void *)padma_bd_buf;
+ padma_bd_buf->paddr = pmbuf->buf_pa;
+ padma_bd_buf->len =
+ ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees event buffer descriptor ring
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_delete_evtbd_ring(mlan_adapter *pmadapter)
+{
+ t_u32 i;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_evt_buf *pevtbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+ for (i = 0; i < MLAN_MAX_EVT_BD; i++) {
+ if (pmadapter->pcard_pcie->evt_buf_list[i]) {
+ pmbuf = pmadapter->pcard_pcie->evt_buf_list[i];
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ pmadapter->pcard_pcie->evt_buf_list[i] = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pevtbd_buf =
+ (mlan_pcie_evt_buf *)
+ pmadapter->pcard_pcie->evtbd_ring[i];
+
+ if (pevtbd_buf) {
+ pevtbd_buf->paddr = 0;
+ pevtbd_buf->len = 0;
+ pevtbd_buf->flags = 0;
+ }
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)
+ pmadapter->pcard_pcie->evtbd_ring[i];
+
+ if (padma_bd_buf) {
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+ }
+#endif
+ pmadapter->pcard_pcie->evtbd_ring[i] = MNULL;
+ }
+
+ if (pmadapter->pcard_pcie->evtbd_ring_vbase)
+ pmadapter->callbacks.moal_mfree_consistent(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->evtbd_ring_size,
+ pmadapter->pcard_pcie->evtbd_ring_vbase,
+ pmadapter->pcard_pcie->evtbd_ring_pbase);
+
+ pmadapter->pcard_pcie->evtbd_rdptr = 0;
+ pmadapter->pcard_pcie->evtbd_wrptr = 0;
+ pmadapter->pcard_pcie->evtbd_ring_size = 0;
+ pmadapter->pcard_pcie->evtbd_ring_vbase = MNULL;
+ pmadapter->pcard_pcie->evtbd_ring_pbase = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates buffer for CMD and CMDRSP
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_alloc_cmdrsp_buf(mlan_adapter *pmadapter)
+{
+ mlan_buffer *pmbuf = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ /** Virtual base address of command response */
+ t_u8 *cmdrsp_vbase;
+ /** Physical base address of command response */
+ t_u64 cmdrsp_pbase = 0;
+
+ ENTER();
+
+ /* Allocate memory for receiving command response data */
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, 0, 0, MOAL_MALLOC_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "Command resp buffer create : Unable to allocate mlan_buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = pcb->moal_malloc_consistent(pmadapter->pmoal_handle,
+ MRVDRV_SIZE_OF_CMD_BUFFER,
+ &cmdrsp_vbase, &cmdrsp_pbase);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
+ __FUNCTION__);
+ /* free pmbuf */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf->buf_pa = cmdrsp_pbase;
+ pmbuf->pbuf = cmdrsp_vbase;
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = MRVDRV_SIZE_OF_CMD_BUFFER;
+ pmbuf->total_pcie_buf_len = MRVDRV_SIZE_OF_CMD_BUFFER;
+ pmadapter->pcard_pcie->cmdrsp_buf = pmbuf;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees CMD and CMDRSP buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_delete_cmdrsp_buf(mlan_adapter *pmadapter)
+{
+ mlan_buffer *pmbuf = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *cmdrsp_vbase;
+ t_u64 cmdrsp_pbase;
+ ENTER();
+
+ if (!pmadapter) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->pcard_pcie->cmdrsp_buf) {
+ pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
+ cmdrsp_vbase = pmbuf->pbuf;
+ cmdrsp_pbase = pmbuf->buf_pa;
+ if (cmdrsp_vbase)
+ pmadapter->callbacks.moal_mfree_consistent(
+ pmadapter->pmoal_handle,
+ pmbuf->total_pcie_buf_len, cmdrsp_vbase,
+ cmdrsp_pbase);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
+ }
+ if (pmadapter->pcard_pcie->cmd_buf) {
+ pmbuf = pmadapter->pcard_pcie->cmd_buf;
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, MRVDRV_SIZE_OF_CMD_BUFFER,
+ PCI_DMA_TODEVICE);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#if defined(PCIE8997) || defined(PCIE8897)
+#define PCIE_TXBD_EMPTY(wrptr, rdptr, mask, rollover_ind) \
+ (((wrptr & mask) == (rdptr & mask)) && \
+ ((wrptr & rollover_ind) == (rdptr & rollover_ind)))
+
+/**
+ * @brief This function flushes the TX buffer descriptor ring
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_flush_txbd_ring(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+
+ ENTER();
+
+ if (!PCIE_TXBD_EMPTY(pmadapter->pcard_pcie->txbd_wrptr,
+ pmadapter->pcard_pcie->txbd_rdptr,
+ txrx_rw_ptr_mask, txrx_rw_ptr_rollover_ind)) {
+ pmadapter->pcard_pcie->txbd_flush = MTRUE;
+ /* write pointer already set at last send */
+ /* send dnld-rdy intr again, wait for completion */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_cpu_int_event,
+ CPU_INTR_DNLD_RDY)) {
+ PRINTM(MERROR,
+ "SEND DATA (FLUSH): failed to assert dnld-rdy interrupt.\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function check the tx pending buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rdptr tx rdptr
+ *
+ * @return MTRUE/MFALSE;
+ */
+static t_u8 wlan_check_tx_pending_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
+{
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if (((pmadapter->pcard_pcie->txbd_rdptr & txrx_rw_ptr_mask) !=
+ (rdptr & txrx_rw_ptr_mask)) ||
+ ((pmadapter->pcard_pcie->txbd_rdptr &
+ txrx_rw_ptr_rollover_ind) !=
+ (rdptr & txrx_rw_ptr_rollover_ind)))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ if ((pmadapter->pcard_pcie->txbd_rdptr &
+ ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+ return MFALSE;
+}
+
+/**
+ * @brief This function unmaps and frees downloaded data buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_data_complete(mlan_adapter *pmadapter)
+{
+ const t_u32 num_tx_buffs = MLAN_MAX_TXRX_BD;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf;
+ t_u32 wrdoneidx;
+ t_u32 rdptr;
+ t_u32 unmap_count = 0;
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ mlan_pcie_data_buf *ptx_bd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+ t_u32 wrptr;
+#endif
+
+ ENTER();
+
+ /* Read the TX ring read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_txbd_rdptr,
+ &rdptr)) {
+ PRINTM(MERROR,
+ "SEND DATA COMP: failed to read REG_TXBD_RDPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MINFO, "SEND DATA COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+ pmadapter->pcard_pcie->txbd_rdptr, rdptr);
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma)
+ rdptr = rdptr >> TXBD_RW_PTR_START;
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ wrptr = rdptr & 0xffff;
+ rdptr = rdptr >> ADMA_RPTR_START;
+ if (wrptr != pmadapter->pcard_pcie->txbd_wrptr)
+ PRINTM(MERROR, "wlan: Unexpected wrptr 0x%x 0x%x\n",
+ wrptr, pmadapter->pcard_pcie->txbd_wrptr);
+ }
+#endif
+
+ /* free from previous txbd_rdptr to current txbd_rdptr */
+ while (wlan_check_tx_pending_buffer(pmadapter, rdptr)) {
+ wrdoneidx =
+ pmadapter->pcard_pcie->txbd_rdptr & (num_tx_buffs - 1);
+ pmbuf = pmadapter->pcard_pcie->tx_buf_list[wrdoneidx];
+ if (pmbuf) {
+ PRINTM(MDAT_D,
+ "SEND DATA COMP: Detach pmbuf %p at tx_ring[%d], pmadapter->txbd_rdptr=0x%x\n",
+ pmbuf, wrdoneidx,
+ pmadapter->pcard_pcie->txbd_rdptr);
+ ret = pcb->moal_unmap_memory(
+ pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->buf_pa,
+ pmbuf->data_len, PCI_DMA_TODEVICE);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "%s: moal_unmap_memory failed\n",
+ __FUNCTION__);
+ break;
+ }
+ unmap_count++;
+ pmadapter->pcard_pcie->txbd_pending--;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (pmadapter->pcard_pcie->txbd_flush)
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ else
+#endif
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_SUCCESS);
+ }
+
+ pmadapter->pcard_pcie->tx_buf_list[wrdoneidx] = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ ptx_bd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
+ ->txbd_ring[wrdoneidx];
+ ptx_bd_buf->paddr = 0;
+ ptx_bd_buf->len = 0;
+ ptx_bd_buf->flags = 0;
+ ptx_bd_buf->frag_len = 0;
+ ptx_bd_buf->offset = 0;
+ pmadapter->pcard_pcie->txbd_rdptr++;
+ if ((pmadapter->pcard_pcie->txbd_rdptr &
+ txrx_rw_ptr_mask) == num_tx_buffs)
+ pmadapter->pcard_pcie->txbd_rdptr =
+ ((pmadapter->pcard_pcie->txbd_rdptr &
+ txrx_rw_ptr_rollover_ind) ^
+ txrx_rw_ptr_rollover_ind);
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)pmadapter->pcard_pcie
+ ->txbd_ring[wrdoneidx];
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ pmadapter->pcard_pcie->txbd_rdptr++;
+ pmadapter->pcard_pcie->txbd_rdptr &=
+ ADMA_RW_PTR_WRAP_MASK;
+ }
+#endif
+ }
+
+ if (unmap_count)
+ pmadapter->data_sent = MFALSE;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (pmadapter->pcard_pcie->txbd_flush) {
+ if (PCIE_TXBD_EMPTY(pmadapter->pcard_pcie->txbd_wrptr,
+ pmadapter->pcard_pcie->txbd_rdptr,
+ txrx_rw_ptr_mask, txrx_rw_ptr_rollover_ind))
+ pmadapter->pcard_pcie->txbd_flush = MFALSE;
+ else
+ wlan_pcie_flush_txbd_ring(pmadapter);
+ }
+#endif
+done:
+ LEAVE();
+ return ret;
+}
+
+#if defined(PCIE8997) || defined(PCIE8897)
+#define PCIE_TXBD_NOT_FULL(wrptr, rdptr, mask, rollover_ind) \
+ (((wrptr & mask) != (rdptr & mask)) || \
+ ((wrptr & rollover_ind) == (rdptr & rollover_ind)))
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+#define ADMA_TXBD_IS_FULL(wrptr, rdptr) \
+ (((wrptr & TXRX_RW_PTR_MASK) == (rdptr & TXRX_RW_PTR_MASK)) && \
+ ((wrptr & TXRX_RW_PTR_ROLLOVER_IND) != \
+ (rdptr & TXRX_RW_PTR_ROLLOVER_IND)))
+#endif
+
+static t_u8 wlan_check_txbd_not_full(mlan_adapter *pmadapter)
+{
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if (PCIE_TXBD_NOT_FULL(pmadapter->pcard_pcie->txbd_wrptr,
+ pmadapter->pcard_pcie->txbd_rdptr,
+ txrx_rw_ptr_mask,
+ txrx_rw_ptr_rollover_ind))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ if (!ADMA_TXBD_IS_FULL(pmadapter->pcard_pcie->txbd_wrptr,
+ pmadapter->pcard_pcie->txbd_rdptr))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+ return MFALSE;
+}
+
+/**
+ * @brief This function downloads data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type packet type
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * PCIE header)
+ * @param tx_param A pointer to mlan_tx_param
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_data(mlan_adapter *pmadapter, t_u8 type,
+ mlan_buffer *pmbuf,
+ mlan_tx_param *tx_param)
+{
+ t_u32 reg_txbd_wrptr = pmadapter->pcard_pcie->reg->reg_txbd_wrptr;
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ mlan_pcie_data_buf *ptx_bd_buf = MNULL;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf = MNULL;
+#endif
+ const t_u32 num_tx_buffs = MLAN_MAX_TXRX_BD;
+ mlan_status ret = MLAN_STATUS_PENDING;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 rxbd_val = 0;
+ t_u32 wrindx;
+ t_u16 *tmp;
+ t_u8 *payload;
+ t_u32 wr_ptr_start = 0;
+
+ ENTER();
+
+ if (!(pmadapter && pmbuf)) {
+ PRINTM(MERROR, "%s() has no buffer", __FUNCTION__);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (!(pmbuf->pbuf && pmbuf->data_len)) {
+ PRINTM(MERROR, "Invalid parameter <%p, %#x>\n", pmbuf->pbuf,
+ pmbuf->data_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "SEND DATA: <Rd: %#x, Wr: %#x>\n",
+ pmadapter->pcard_pcie->txbd_rdptr,
+ pmadapter->pcard_pcie->txbd_wrptr);
+
+ if (wlan_check_txbd_not_full(pmadapter)) {
+ pmadapter->data_sent = MTRUE;
+
+ payload = pmbuf->pbuf + pmbuf->data_offset;
+ tmp = (t_u16 *)&payload[0];
+ *tmp = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
+ tmp = (t_u16 *)&payload[2];
+ *tmp = wlan_cpu_to_le16(type);
+
+ /* Map pmbuf, and attach to tx ring */
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, pmbuf->data_len,
+ PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR,
+ "SEND DATA: failed to moal_map_memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ wrindx = pmadapter->pcard_pcie->txbd_wrptr & (num_tx_buffs - 1);
+ PRINTM(MDAT_D,
+ "SEND DATA: Attach pmbuf %p at tx_ring[%d], txbd_wrptr=0x%x\n",
+ pmbuf, wrindx, pmadapter->pcard_pcie->txbd_wrptr);
+ pmadapter->pcard_pcie->tx_buf_list[wrindx] = pmbuf;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ wr_ptr_start = TXBD_RW_PTR_START;
+ ptx_bd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
+ ->txbd_ring[wrindx];
+ ptx_bd_buf->paddr = pmbuf->buf_pa;
+ ptx_bd_buf->len = (t_u16)pmbuf->data_len;
+ ptx_bd_buf->flags = MLAN_BD_FLAG_SOP | MLAN_BD_FLAG_EOP;
+ ptx_bd_buf->frag_len = (t_u16)pmbuf->data_len;
+ ptx_bd_buf->offset = 0;
+ pmadapter->pcard_pcie->last_tx_pkt_size[wrindx] =
+ pmbuf->data_len;
+ pmadapter->pcard_pcie->txbd_wrptr++;
+ if ((pmadapter->pcard_pcie->txbd_wrptr &
+ txrx_rw_ptr_mask) == num_tx_buffs)
+ pmadapter->pcard_pcie->txbd_wrptr =
+ ((pmadapter->pcard_pcie->txbd_wrptr &
+ txrx_rw_ptr_rollover_ind) ^
+ txrx_rw_ptr_rollover_ind);
+ rxbd_val = pmadapter->pcard_pcie->rxbd_wrptr &
+ pmadapter->pcard_pcie->reg
+ ->txrx_rw_ptr_wrap_mask;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ wr_ptr_start = ADMA_WPTR_START;
+ padma_bd_buf = (adma_dual_desc_buf *)pmadapter
+ ->pcard_pcie->txbd_ring[wrindx];
+ padma_bd_buf->paddr = pmbuf->buf_pa;
+ padma_bd_buf->len =
+ ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_SOP | ADMA_BD_FLAG_EOP |
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_SRC_HOST;
+ if (padma_bd_buf->len < ADMA_MIN_PKT_SIZE)
+ padma_bd_buf->len = ADMA_MIN_PKT_SIZE;
+ padma_bd_buf->pkt_size = pmbuf->data_len;
+ pmadapter->pcard_pcie->last_tx_pkt_size[wrindx] =
+ pmbuf->data_len;
+ pmadapter->pcard_pcie->txbd_wrptr++;
+ pmadapter->pcard_pcie->txbd_wrptr &=
+ ADMA_RW_PTR_WRAP_MASK;
+ }
+#endif
+ pmadapter->pcard_pcie->txbd_pending++;
+ PRINTM(MINFO, "REG_TXBD_WRPT(0x%x) = 0x%x\n", reg_txbd_wrptr,
+ ((pmadapter->pcard_pcie->txbd_wrptr << wr_ptr_start) |
+ rxbd_val));
+ /* Write the TX ring write pointer in to REG_TXBD_WRPTR */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle, reg_txbd_wrptr,
+ (pmadapter->pcard_pcie->txbd_wrptr
+ << wr_ptr_start) |
+ rxbd_val)) {
+ PRINTM(MERROR,
+ "SEND DATA: failed to write REG_TXBD_WRPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done_unmap;
+ }
+ PRINTM(MINFO, "SEND DATA: Updated <Rd: %#x, Wr: %#x>\n",
+ pmadapter->pcard_pcie->txbd_rdptr,
+ pmadapter->pcard_pcie->txbd_wrptr);
+
+ if (wlan_check_txbd_not_full(pmadapter))
+ pmadapter->data_sent = MFALSE;
+
+ PRINTM(MINFO, "Sent packet to firmware successfully\n");
+ } else {
+ PRINTM(MERROR,
+ "TX Ring full, can't send anymore packets to firmware\n");
+ PRINTM(MINFO, "SEND DATA (FULL!): <Rd: %#x, Wr: %#x>\n",
+ pmadapter->pcard_pcie->txbd_rdptr,
+ pmadapter->pcard_pcie->txbd_wrptr);
+ pmadapter->data_sent = MTRUE;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ /* Send the TX ready interrupt */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_cpu_int_event,
+ CPU_INTR_DNLD_RDY))
+ PRINTM(MERROR,
+ "SEND DATA (FULL): failed to assert dnld-rdy interrupt\n");
+ }
+#endif
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ LEAVE();
+ return ret;
+
+done_unmap:
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_unmap_memory(
+ pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, pmbuf->data_len, PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR, "SEND DATA: failed to moal_unmap_memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pcard_pcie->txbd_pending--;
+ pmadapter->pcard_pcie->tx_buf_list[wrindx] = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma && ptx_bd_buf) {
+ ptx_bd_buf->paddr = 0;
+ ptx_bd_buf->len = 0;
+ ptx_bd_buf->flags = 0;
+ ptx_bd_buf->frag_len = 0;
+ ptx_bd_buf->offset = 0;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma && padma_bd_buf) {
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function check the rx pending buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rdptr rx rdptr
+ *
+ * @return MTRUE/MFALSE;
+ */
+static t_u8 wlan_check_rx_pending_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
+{
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if (((rdptr & txrx_rw_ptr_mask) !=
+ (pmadapter->pcard_pcie->rxbd_rdptr & txrx_rw_ptr_mask)) ||
+ ((rdptr & txrx_rw_ptr_rollover_ind) !=
+ (pmadapter->pcard_pcie->rxbd_rdptr &
+ txrx_rw_ptr_rollover_ind)))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ if ((pmadapter->pcard_pcie->rxbd_rdptr &
+ ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+ return MFALSE;
+}
+
+/**
+ * @brief This function handles received buffer ring and
+ * dispatches packets to upper
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_process_recv_data(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 rdptr, rd_index;
+ mlan_buffer *pmbuf = MNULL;
+ t_u32 txbd_val = 0;
+ t_u16 rx_len, rx_type;
+ const t_u32 num_rx_buffs = MLAN_MAX_TXRX_BD;
+ t_u32 reg_rxbd_rdptr = pmadapter->pcard_pcie->reg->reg_rxbd_rdptr;
+#if defined(PCIE8997) || defined(PCIE8897)
+ t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
+ t_u32 txrx_rw_ptr_rollover_ind =
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
+ mlan_pcie_data_buf *prxbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+
+ /* Read the RX ring Read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle, reg_rxbd_rdptr,
+ &rdptr)) {
+ PRINTM(MERROR, "RECV DATA: failed to read REG_RXBD_RDPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ rdptr = rdptr >> ADMA_RPTR_START;
+#endif
+
+ while (wlan_check_rx_pending_buffer(pmadapter, rdptr)) {
+ /* detach pmbuf (with data) from Rx Ring */
+ rd_index =
+ pmadapter->pcard_pcie->rxbd_rdptr & (num_rx_buffs - 1);
+ if (rd_index > MLAN_MAX_TXRX_BD - 1) {
+ PRINTM(MERROR, "RECV DATA: Invalid Rx buffer index.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmbuf = pmadapter->pcard_pcie->rx_buf_list[rd_index];
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE)) {
+ PRINTM(MERROR,
+ "RECV DATA: moal_unmap_memory failed.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcard_pcie->rx_buf_list[rd_index] = MNULL;
+ PRINTM(MDAT_D,
+ "RECV DATA: Detach pmbuf %p at rx_ring[%d], pmadapter->rxbd_rdptr=0x%x\n",
+ pmbuf, rd_index, pmadapter->pcard_pcie->rxbd_rdptr);
+
+ /* Get data length from interface header -
+ first 2 bytes are len, second 2 bytes are type */
+ rx_len = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
+ rx_len = wlan_le16_to_cpu(rx_len);
+ rx_type = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset + 2));
+ rx_type = wlan_le16_to_cpu(rx_type);
+
+ PRINTM(MINFO,
+ "RECV DATA: <Wr: %#x, Rd: %#x>, Len=%d rx_type=%d\n",
+ pmadapter->pcard_pcie->rxbd_wrptr, rdptr, rx_len,
+ rx_type);
+
+ if (rx_len <= MLAN_RX_DATA_BUF_SIZE) {
+ /* send buffer to host (which will free it) */
+ pmbuf->data_len = rx_len - PCIE_INTF_HEADER_LEN;
+ pmbuf->data_offset += PCIE_INTF_HEADER_LEN;
+ // rx_trace 5
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf,
+ 5 /*RX_DROP_P1*/);
+ if (pmadapter->tp_state_drop_point ==
+ 5 /*RX_DROP_P1*/) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf,
+ ret);
+ } else {
+ PRINTM(MINFO,
+ "RECV DATA: Received packet from FW successfully\n");
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ util_enqueue_list_tail(
+ pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue,
+ (pmlan_linked_list)pmbuf, MNULL, MNULL);
+ pmadapter->rx_pkts_queued++;
+ pmadapter->callbacks.moal_tp_accounting_rx_param(
+ pmadapter->pmoal_handle, 1,
+ pmadapter->rx_pkts_queued);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+
+ pmadapter->data_received = MTRUE;
+ }
+ /* Create new buffer and attach it to Rx Ring */
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter,
+ MLAN_RX_DATA_BUF_SIZE,
+ MLAN_RX_HEADER_LEN,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "RECV DATA: Unable to allocate mlan_buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+ /* Queue the mlan_buffer again */
+ PRINTM(MERROR, "PCIE: Drop invalid packet, length=%d",
+ rx_len);
+ }
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE)) {
+ PRINTM(MERROR, "RECV DATA: moal_map_memory failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MDAT_D,
+ "RECV DATA: Attach new pmbuf %p at rx_ring[%d]\n", pmbuf,
+ rd_index);
+ pmadapter->pcard_pcie->rx_buf_list[rd_index] = pmbuf;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ prxbd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
+ ->rxbd_ring[rd_index];
+ prxbd_buf->paddr = pmbuf->buf_pa;
+ prxbd_buf->len = (t_u16)pmbuf->data_len;
+ prxbd_buf->flags = MLAN_BD_FLAG_SOP | MLAN_BD_FLAG_EOP;
+ prxbd_buf->offset = 0;
+ prxbd_buf->frag_len = (t_u16)pmbuf->data_len;
+
+ /* update rxbd's rdptrs */
+ if ((++pmadapter->pcard_pcie->rxbd_rdptr &
+ txrx_rw_ptr_mask) == MLAN_MAX_TXRX_BD) {
+ pmadapter->pcard_pcie->rxbd_rdptr =
+ ((pmadapter->pcard_pcie->rxbd_rdptr &
+ txrx_rw_ptr_rollover_ind) ^
+ txrx_rw_ptr_rollover_ind);
+ }
+
+ /* update rxbd's wrptrs */
+ if ((++pmadapter->pcard_pcie->rxbd_wrptr &
+ txrx_rw_ptr_mask) == MLAN_MAX_TXRX_BD) {
+ pmadapter->pcard_pcie->rxbd_wrptr =
+ ((pmadapter->pcard_pcie->rxbd_wrptr &
+ txrx_rw_ptr_rollover_ind) ^
+ txrx_rw_ptr_rollover_ind);
+ }
+ txbd_val = pmadapter->pcard_pcie->txbd_wrptr &
+ pmadapter->pcard_pcie->reg
+ ->txrx_rw_ptr_wrap_mask;
+ txbd_val = txbd_val << TXBD_RW_PTR_START;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)pmadapter->pcard_pcie
+ ->rxbd_ring[rd_index];
+ padma_bd_buf->paddr = pmbuf->buf_pa;
+ padma_bd_buf->len =
+ ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ pmadapter->pcard_pcie->rxbd_rdptr++;
+ pmadapter->pcard_pcie->rxbd_wrptr++;
+ pmadapter->pcard_pcie->rxbd_rdptr &=
+ ADMA_RW_PTR_WRAP_MASK;
+ pmadapter->pcard_pcie->rxbd_wrptr &=
+ ADMA_RW_PTR_WRAP_MASK;
+ }
+#endif
+ PRINTM(MINFO, "RECV DATA: Updated <Wr: %#x, Rd: %#x>\n",
+ pmadapter->pcard_pcie->rxbd_wrptr, rdptr);
+
+ /* Write the RX ring write pointer in to REG_RXBD_WRPTR */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_rxbd_wrptr,
+ pmadapter->pcard_pcie->rxbd_wrptr | txbd_val)) {
+ PRINTM(MERROR,
+ "RECV DATA: failed to write REG_RXBD_WRPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Read the RX ring read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle, reg_rxbd_rdptr,
+ &rdptr)) {
+ PRINTM(MERROR,
+ "RECV DATA: failed to read REG_RXBD_RDPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ rdptr = rdptr >> ADMA_RPTR_START;
+#endif
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads command to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * PCIE header)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_cmd(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *payload = MNULL;
+
+ ENTER();
+ if (!(pmadapter && pmbuf)) {
+ PRINTM(MERROR, "%s() has no buffer", __FUNCTION__);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (!(pmbuf->pbuf && pmbuf->data_len)) {
+ PRINTM(MERROR, "Invalid parameter <%p, %#x>\n", pmbuf->pbuf,
+ pmbuf->data_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Make sure a command response buffer is available */
+ if (!pmadapter->pcard_pcie->cmdrsp_buf) {
+ PRINTM(MERROR,
+ "No response buffer available, send command failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->cmd_sent = MTRUE;
+ payload = pmbuf->pbuf + pmbuf->data_offset;
+ *(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
+ *(t_u16 *)&payload[2] = wlan_cpu_to_le16(MLAN_TYPE_CMD);
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(
+ pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, MLAN_RX_CMD_BUF_SIZE, PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR, "Command buffer : moal_map_memory failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter->pcard_pcie->cmd_buf = pmbuf;
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ /* To send a command, the driver will:
+ 1. Write the 64bit physical address of the data buffer to
+ SCRATCH1 + SCRATCH0
+ 2. Ring the door bell (i.e. set the door bell interrupt)
+
+ In response to door bell interrupt, the firmware will
+ perform the DMA of the command packet (first header to obtain
+ the total length and then rest of the command).
+ */
+
+ if (pmadapter->pcard_pcie->cmdrsp_buf) {
+ /* Write the lower 32bits of the cmdrsp buffer physical
+ address */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ REG_CMDRSP_ADDR_LO,
+ (t_u32)pmadapter->pcard_pcie
+ ->cmdrsp_buf->buf_pa)) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle, REG_CMDRSP_ADDR_HI,
+ (t_u32)((t_u64)pmadapter->pcard_pcie
+ ->cmdrsp_buf->buf_pa >>
+ 32))) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Write the lower 32bits of the physical address to
+ * REG_CMD_ADDR_LO */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle, REG_CMD_ADDR_LO,
+ (t_u32)pmadapter->pcard_pcie->cmd_buf->buf_pa)) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the upper 32bits of the physical address to
+ * REG_CMD_ADDR_HI */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ REG_CMD_ADDR_HI,
+ (t_u32)((t_u64)pmadapter->pcard_pcie
+ ->cmd_buf->buf_pa >>
+ 32))) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Write the command length to REG_CMD_SIZE */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle, REG_CMD_SIZE,
+ pmadapter->pcard_pcie->cmd_buf->data_len)) {
+ PRINTM(MERROR,
+ "Failed to write command length to REG_CMD_SIZE\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Ring the door bell */
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_cpu_int_event,
+ CPU_INTR_DOOR_BELL)) {
+ PRINTM(MERROR,
+ "Failed to assert door-bell interrupt.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ /* To send a command, the driver will:
+ 1. driver prepare the cmdrep buffer for adma
+ 2. driver programs dma_mode field to direct programming mode
+ and programs dma_size field to define DMA data transfer size.
+ 3. driver programs src_base_addr register to define source
+ location of DMA data
+ 4. driver sets src_wptr to 1 to initiate DMA operation
+ */
+ wlan_init_adma(pmadapter, ADMA_CMDRESP,
+ pmadapter->pcard_pcie->cmdrsp_buf->buf_pa,
+ MRVDRV_SIZE_OF_CMD_BUFFER, MFALSE);
+ wlan_init_adma(pmadapter, ADMA_CMD,
+ pmadapter->pcard_pcie->cmd_buf->buf_pa,
+ pmadapter->pcard_pcie->cmd_buf->data_len,
+ MFALSE);
+ }
+#endif
+done:
+ if ((ret == MLAN_STATUS_FAILURE) && pmadapter)
+ pmadapter->cmd_sent = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(PCIE8997) || defined(PCIE8897)
+#define MLAN_SLEEP_COOKIE_DEF 0xBEEFBEEF
+#define MAX_DELAY_LOOP_COUNT 100
+
+static void mlan_delay_for_sleep_cookie(mlan_adapter *pmadapter,
+ t_u32 max_delay_loop_cnt)
+{
+ t_u8 *buffer;
+ t_u32 sleep_cookie = 0;
+ t_u32 count = 0;
+ pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
+
+ for (count = 0; count < max_delay_loop_cnt; count++) {
+ buffer = pmbuf->pbuf;
+ sleep_cookie = *(t_u32 *)buffer;
+
+ if (sleep_cookie == MLAN_SLEEP_COOKIE_DEF) {
+ PRINTM(MINFO, "sleep cookie FOUND at count = %d!!\n",
+ count);
+ break;
+ }
+ wlan_udelay(pmadapter, 20);
+ }
+
+ if (count >= max_delay_loop_cnt)
+ PRINTM(MERROR, "sleep cookie not found!!\n");
+}
+#endif
+
+/**
+ * @brief This function handles command complete interrupt
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_process_cmd_resp(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
+ pmlan_buffer cmd_buf = MNULL;
+ t_u16 resp_len = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "Rx CMD Response\n");
+
+ if (pmbuf == MNULL) {
+ PRINTM(MMSG, "Rx CMD response pmbuf is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Get data length from interface header -
+ first 2 bytes are len, second 2 bytes are type */
+ resp_len = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
+
+ pmadapter->upld_len = wlan_le16_to_cpu(resp_len);
+ pmadapter->upld_len -= PCIE_INTF_HEADER_LEN;
+
+ if (!pmadapter->curr_cmd) {
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ wlan_process_sleep_confirm_resp(
+ pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset +
+ PCIE_INTF_HEADER_LEN,
+ pmadapter->upld_len);
+ /* We are sending sleep confirm done interrupt in the
+ * middle of sleep handshake. There is a corner case
+ * when Tx done interrupt is received from firmware
+ * during sleep handshake due to which host and firmware
+ * power states go out of sync causing Tx data timeout
+ * problem. Hence sleep confirm done interrupt is sent
+ * at the end of sleep handshake to fix the problem
+ *
+ * Host could be reading the interrupt during polling
+ * (while loop) or to address a FW interrupt. In either
+ * case, after clearing the interrupt driver needs to
+ * send a sleep confirm event at the end of processing
+ * command response right here. This marks the end of
+ * the sleep handshake with firmware.
+ */
+ wlan_pcie_enable_host_int_mask(pmadapter);
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_cpu_int_event,
+ CPU_INTR_SLEEP_CFM_DONE)) {
+ PRINTM(MERROR, "Write register failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_delay_for_sleep_cookie(pmadapter,
+ MAX_DELAY_LOOP_COUNT);
+#endif
+ cmd_buf = pmadapter->pcard_pcie->cmd_buf;
+ if (cmd_buf) {
+ pcb->moal_unmap_memory(
+ pmadapter->pmoal_handle,
+ cmd_buf->pbuf + cmd_buf->data_offset,
+ cmd_buf->buf_pa, WLAN_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
+ pmadapter->pcard_pcie->cmd_buf = MNULL;
+ }
+ }
+ memcpy_ext(pmadapter, pmadapter->upld_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ PCIE_INTF_HEADER_LEN,
+ pmadapter->upld_len, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ } else {
+ pmadapter->cmd_resp_received = MTRUE;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmbuf->data_offset += PCIE_INTF_HEADER_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+
+ /* Take the pointer and set it to CMD node and will
+ return in the response complete callback */
+ pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ /* Clear the cmd-rsp buffer address in scratch
+ registers. This will prevent firmware from writing to
+ the same response buffer again. */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ REG_CMDRSP_ADDR_LO, 0)) {
+ PRINTM(MERROR,
+ "Rx CMD: failed to clear cmd_rsp address.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ REG_CMDRSP_ADDR_HI, 0)) {
+ PRINTM(MERROR,
+ "Rx CMD: failed to clear cmd_rsp address.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ /* Clear the cmd-rsp buffer address in adma registers.
+ This will prevent firmware from writing to the same
+ response buffer again. */
+ if (wlan_init_adma(pmadapter, ADMA_CMDRESP, 0, 0,
+ MFALSE)) {
+ PRINTM(MERROR,
+ "Rx CMD: failed to clear cmd_rsp address.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles command response completion
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_cmdrsp_complete(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf, mlan_status status)
+{
+ mlan_buffer *pcmdmbuf;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /*return the cmd response pmbuf*/
+ if (pmbuf) {
+ pmbuf->data_len = MRVDRV_SIZE_OF_CMD_BUFFER;
+ pmbuf->data_offset -= PCIE_INTF_HEADER_LEN;
+ pmadapter->pcard_pcie->cmdrsp_buf = pmbuf;
+ }
+
+ /*unmap the cmd pmbuf, so the cpu can not access the memory in the
+ * command node*/
+ pcmdmbuf = pmadapter->pcard_pcie->cmd_buf;
+
+ if (pcmdmbuf) {
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pcmdmbuf->pbuf + pcmdmbuf->data_offset,
+ pcmdmbuf->buf_pa, WLAN_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
+ pmadapter->pcard_pcie->cmd_buf = MNULL;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function check pending evt buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rdptr evt rdptr
+ *
+ * @return MTRUE/MFALSE;
+ */
+static t_u8 wlan_check_evt_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
+{
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if (((rdptr & EVT_RW_PTR_MASK) !=
+ (pmadapter->pcard_pcie->evtbd_rdptr & EVT_RW_PTR_MASK)) ||
+ ((rdptr & EVT_RW_PTR_ROLLOVER_IND) !=
+ (pmadapter->pcard_pcie->evtbd_rdptr &
+ EVT_RW_PTR_ROLLOVER_IND)))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ if ((pmadapter->pcard_pcie->evtbd_rdptr &
+ ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+#endif
+ return MFALSE;
+}
+
+/**
+ * @brief This function handles FW event ready interrupt
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_process_event_ready(mlan_adapter *pmadapter)
+{
+ t_u32 rd_index =
+ pmadapter->pcard_pcie->evtbd_rdptr & (MLAN_MAX_EVT_BD - 1);
+ t_u32 rdptr, event;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_evt_buf *pevtbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+ ENTER();
+
+ if (pmadapter->event_received) {
+ PRINTM(MINFO, "Event being processed, do not "
+ "process this interrupt just yet\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ if (rd_index >= MLAN_MAX_EVT_BD) {
+ PRINTM(MINFO, "Invalid rd_index...\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Read the event ring read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_evtbd_rdptr,
+ &rdptr)) {
+ PRINTM(MERROR, "EvtRdy: failed to read REG_EVTBD_RDPTR\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ rdptr = rdptr >> ADMA_RPTR_START;
+#endif
+ PRINTM(MINFO, "EvtRdy: Initial <Wr: 0x%x, Rd: 0x%x>\n",
+ pmadapter->pcard_pcie->evtbd_wrptr, rdptr);
+ if (wlan_check_evt_buffer(pmadapter, rdptr)) {
+ mlan_buffer *pmbuf_evt;
+ t_u16 evt_len;
+
+ PRINTM(MINFO, "EvtRdy: Read Index: %d\n", rd_index);
+ pmbuf_evt = pmadapter->pcard_pcie->evt_buf_list[rd_index];
+
+ /*unmap the pmbuf for CPU Access*/
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf_evt->pbuf + pmbuf_evt->data_offset,
+ pmbuf_evt->buf_pa, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+ /* Take the pointer and set it to event pointer in adapter
+ and will return back after event handling callback */
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pevtbd_buf = (mlan_pcie_evt_buf *)pmadapter->pcard_pcie
+ ->evtbd_ring[rd_index];
+ pevtbd_buf->paddr = 0;
+ pevtbd_buf->len = 0;
+ pevtbd_buf->flags = 0;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf =
+ (adma_dual_desc_buf *)pmadapter->pcard_pcie
+ ->evtbd_ring[rd_index];
+ padma_bd_buf->paddr = 0;
+ padma_bd_buf->len = 0;
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+ pmadapter->pcard_pcie->evt_buf_list[rd_index] = MNULL;
+
+ event = *((t_u32 *)&pmbuf_evt->pbuf[pmbuf_evt->data_offset +
+ PCIE_INTF_HEADER_LEN]);
+ pmadapter->event_cause = wlan_le32_to_cpu(event);
+ /* The first 4bytes will be the event transfer header
+ len is 2 bytes followed by type which is 2 bytes */
+ evt_len = *((t_u16 *)&pmbuf_evt->pbuf[pmbuf_evt->data_offset]);
+ evt_len = wlan_le16_to_cpu(evt_len);
+
+ if ((evt_len > 0) && (evt_len > MLAN_EVENT_HEADER_LEN) &&
+ (evt_len - MLAN_EVENT_HEADER_LEN < MAX_EVENT_SIZE))
+ memcpy_ext(pmadapter, pmadapter->event_body,
+ pmbuf_evt->pbuf + pmbuf_evt->data_offset +
+ MLAN_EVENT_HEADER_LEN,
+ evt_len - MLAN_EVENT_HEADER_LEN,
+ sizeof(pmadapter->event_body));
+
+ pmbuf_evt->data_offset += PCIE_INTF_HEADER_LEN;
+ pmbuf_evt->data_len = evt_len - PCIE_INTF_HEADER_LEN;
+ PRINTM(MINFO, "Event length: %d\n", pmbuf_evt->data_len);
+
+ pmadapter->event_received = MTRUE;
+ pmadapter->pmlan_buffer_event = pmbuf_evt;
+ pmadapter->pcard_pcie->evtbd_rdptr++;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if ((pmadapter->pcard_pcie->evtbd_rdptr &
+ EVT_RW_PTR_MASK) == MLAN_MAX_EVT_BD) {
+ pmadapter->pcard_pcie->evtbd_rdptr =
+ ((pmadapter->pcard_pcie->evtbd_rdptr &
+ EVT_RW_PTR_ROLLOVER_IND) ^
+ EVT_RW_PTR_ROLLOVER_IND);
+ }
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ pmadapter->pcard_pcie->evtbd_rdptr &=
+ ADMA_RW_PTR_WRAP_MASK;
+#endif
+
+ /* Do not update the event write pointer here, wait till the
+ buffer is released. This is just to make things simpler,
+ we need to find a better method of managing these buffers.
+ */
+ } else {
+ PRINTM(MINTR, "------>EVENT DONE\n");
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_cpu_int_event,
+ CPU_INTR_EVENT_DONE)) {
+ PRINTM(MERROR,
+ "Failed to asset event done interrupt\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles event completion
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_event_complete(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf, mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 wrptr =
+ pmadapter->pcard_pcie->evtbd_wrptr & (MLAN_MAX_EVT_BD - 1);
+ t_u32 rdptr;
+#if defined(PCIE8997) || defined(PCIE8897)
+ mlan_pcie_evt_buf *pevtbd_buf;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ adma_dual_desc_buf *padma_bd_buf;
+#endif
+
+ ENTER();
+ if (!pmbuf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (wrptr >= MLAN_MAX_EVT_BD) {
+ PRINTM(MERROR, "EvtCom: Invalid wrptr 0x%x\n", wrptr);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Read the event ring read pointer set by firmware */
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_evtbd_rdptr,
+ &rdptr)) {
+ PRINTM(MERROR, "EvtCom: failed to read REG_EVTBD_RDPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ rdptr = rdptr >> ADMA_RPTR_START;
+#endif
+
+ if (!pmadapter->pcard_pcie->evt_buf_list[wrptr]) {
+ pmbuf->data_len = MAX_EVENT_SIZE;
+ pmbuf->data_offset -= PCIE_INTF_HEADER_LEN;
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE)) {
+ PRINTM(MERROR, "EvtCom: failed to moal_map_memory\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmadapter->pcard_pcie->evt_buf_list[wrptr] = pmbuf;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ pevtbd_buf = (mlan_pcie_evt_buf *)pmadapter->pcard_pcie
+ ->evtbd_ring[wrptr];
+ pevtbd_buf->paddr = pmbuf->buf_pa;
+ pevtbd_buf->len = (t_u16)pmbuf->data_len;
+ pevtbd_buf->flags = 0;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ padma_bd_buf = (adma_dual_desc_buf *)pmadapter
+ ->pcard_pcie->evtbd_ring[wrptr];
+ padma_bd_buf->paddr = pmbuf->buf_pa;
+ padma_bd_buf->len =
+ ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
+ padma_bd_buf->flags = 0;
+ padma_bd_buf->flags =
+ ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST;
+ padma_bd_buf->pkt_size = 0;
+ padma_bd_buf->reserved = 0;
+ }
+#endif
+ pmbuf = MNULL;
+ } else {
+ PRINTM(MINFO,
+ "EvtCom: ERROR: Buffer is still valid at "
+ "index %d, <%p, %p>\n",
+ wrptr, pmadapter->pcard_pcie->evt_buf_list[wrptr],
+ pmbuf);
+ }
+
+ pmadapter->pcard_pcie->evtbd_wrptr++;
+
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ if ((pmadapter->pcard_pcie->evtbd_wrptr & EVT_RW_PTR_MASK) ==
+ MLAN_MAX_EVT_BD) {
+ pmadapter->pcard_pcie->evtbd_wrptr =
+ ((pmadapter->pcard_pcie->evtbd_wrptr &
+ EVT_RW_PTR_ROLLOVER_IND) ^
+ EVT_RW_PTR_ROLLOVER_IND);
+ }
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma)
+ pmadapter->pcard_pcie->evtbd_wrptr &= ADMA_RW_PTR_WRAP_MASK;
+#endif
+ PRINTM(MINFO, "EvtCom: Updated <Wr: 0x%x, Rd: 0x%x>\n",
+ pmadapter->pcard_pcie->evtbd_wrptr, rdptr);
+
+ /* Write the event ring write pointer in to REG_EVTBD_WRPTR */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_evtbd_wrptr,
+ pmadapter->pcard_pcie->evtbd_wrptr)) {
+ PRINTM(MERROR, "EvtCom: failed to write REG_EVTBD_WRPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+done:
+ /* Free the buffer for failure case */
+ if (ret && pmbuf)
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+
+ PRINTM(MINFO, "EvtCom: Check Events Again\n");
+ ret = wlan_pcie_process_event_ready(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads boot command to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_send_boot_cmd(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pmadapter || !pmbuf) {
+ PRINTM(MERROR, "NULL Pointer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_map_memory(
+ pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
+ &pmbuf->buf_pa, WLAN_UPLD_SIZE, PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR, "BootCmd: failed to moal_map_memory\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (!(pmbuf->pbuf && pmbuf->data_len && pmbuf->buf_pa)) {
+ PRINTM(MERROR, "%s: Invalid buffer <%p, %#x:%x, len=%d>\n",
+ __func__, pmbuf->pbuf,
+ (t_u32)((t_u64)pmbuf->buf_pa >> 32),
+ (t_u32)pmbuf->buf_pa, pmbuf->data_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Write the lower 32bits of the physical address to scratch
+ * register 0 */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_0,
+ (t_u32)pmbuf->buf_pa)) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Write the upper 32bits of the physical address to scratch
+ * register 1 */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_1,
+ (t_u32)((t_u64)pmbuf->buf_pa >> 32))) {
+ PRINTM(MERROR,
+ "Failed to write download command to boot code\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Write the command length to scratch register 2 */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_2,
+ pmbuf->data_len)) {
+ PRINTM(MERROR,
+ "Failed to write command length to scratch register 2\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Ring the door bell */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_cpu_int_event,
+ CPU_INTR_DOOR_BELL)) {
+ PRINTM(MERROR, "Failed to assert door-bell interrupt\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ LEAVE();
+ return ret;
+
+done:
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_unmap_memory(
+ pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, WLAN_UPLD_SIZE, PCI_DMA_TODEVICE))
+ PRINTM(MERROR, "BootCmd: failed to moal_unmap_memory\n");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function init rx port in firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_init_fw(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 txbd_val = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ txbd_val = pmadapter->pcard_pcie->txbd_wrptr &
+ pmadapter->pcard_pcie->reg->txrx_rw_ptr_wrap_mask;
+ txbd_val = txbd_val << TXBD_RW_PTR_START;
+ }
+#endif
+ /* Write the RX ring write pointer in to REG_RXBD_WRPTR */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_rxbd_wrptr,
+ pmadapter->pcard_pcie->rxbd_wrptr | txbd_val)) {
+ PRINTM(MERROR, "Init FW: failed to write REG_RXBD_WRPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Write the event ring write pointer in to REG_EVTBD_WRPTR */
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_evtbd_wrptr,
+ pmadapter->pcard_pcie->evtbd_wrptr)) {
+ PRINTM(MERROR, "Init FW: failed to write REG_EVTBD_WRPTR\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+done:
+ return ret;
+}
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param fw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_pcie_prog_fw_w_helper(mlan_adapter *pmadapter,
+ mlan_fw_image *fw)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *firmware = fw->pfw_buf;
+ t_u32 firmware_len = fw->fw_len;
+ t_u32 offset = 0;
+ mlan_buffer *pmbuf = MNULL;
+ t_u32 txlen, tx_blocks = 0, tries, len;
+ t_u32 block_retry_cnt = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+#if defined(PCIE9098)
+ t_u32 rev_id_reg = 0;
+ t_u32 revision_id = 0;
+#endif
+ t_u8 check_fw_status = MFALSE;
+ t_u32 fw_dnld_status = 0;
+ t_u32 fw_dnld_offset = 0;
+ t_u8 mic_retry = 0;
+
+ ENTER();
+ if (!pmadapter) {
+ PRINTM(MERROR, "adapter structure is not valid\n");
+ goto done;
+ }
+
+ if (!firmware || !firmware_len) {
+ PRINTM(MERROR,
+ "No firmware image found! Terminating download\n");
+ goto done;
+ }
+
+ PRINTM(MINFO, "Downloading FW image (%d bytes)\n", firmware_len);
+
+ if (wlan_disable_pcie_host_int(pmadapter)) {
+ PRINTM(MERROR, "prog_fw: Disabling interrupts failed\n");
+ goto done;
+ }
+
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, WLAN_UPLD_SIZE, 0,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR, "prog_fw: Unable to allocate mlan_buffer\n");
+ goto done;
+ }
+#if defined(PCIE9098)
+ if (IS_PCIE9098(pmadapter->card_type)) {
+ rev_id_reg = pmadapter->pcard_pcie->reg->reg_rev_id;
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle, rev_id_reg,
+ &revision_id);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to read PCIe revision id register\n");
+ goto done;
+ }
+ /* Skyhawk A0, need to check both CRC and MIC error */
+ if (revision_id >= CHIP_9098_REV_A0)
+ check_fw_status = MTRUE;
+ }
+#endif
+ /* For PCIE9097, need check both CRC and MIC error */
+#if defined(PCIE9097)
+ if (IS_PCIE9097(pmadapter->card_type))
+ check_fw_status = MTRUE;
+#endif
+
+ /* Perform firmware data transfer */
+ do {
+ t_u32 ireg_intr = 0;
+ t_u32 read_retry_cnt = 0;
+
+ /* More data? */
+ if (offset >= firmware_len)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = pcb->moal_read_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_2,
+ &len);
+ if (ret) {
+ PRINTM(MWARN,
+ "Failed reading length from boot code\n");
+ goto done;
+ }
+ if (len || offset)
+ break;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ if (!len) {
+ break;
+ } else if (len > WLAN_UPLD_SIZE) {
+ PRINTM(MERROR,
+ "FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & MBIT(0)) {
+ if (check_fw_status) {
+ /* Get offset from fw dnld offset Register */
+ ret = pcb->moal_read_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_scratch_6,
+ &fw_dnld_offset);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "FW download failure @ %d, reading fw dnld offset failed\n",
+ offset);
+ goto done;
+ }
+ /* Get CRC MIC error from fw dnld status
+ * Register */
+ ret = pcb->moal_read_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_scratch_7,
+ &fw_dnld_status);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "FW download failure @ %d, reading fw dnld status failed\n",
+ offset);
+ goto done;
+ }
+ PRINTM(MERROR,
+ "FW download error: status=0x%x offset = 0x%x fw offset = 0x%x\n",
+ fw_dnld_status, offset, fw_dnld_offset);
+ }
+ block_retry_cnt++;
+ if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(MERROR,
+ "FW download failure @ %d, over max "
+ "retry count\n",
+ offset);
+ goto done;
+ }
+ PRINTM(MERROR,
+ "FW CRC error indicated by the "
+ "helper: len = 0x%04X, txlen = %d\n",
+ len, txlen);
+ len &= ~MBIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ if (fw_dnld_status & (MBIT(6) | MBIT(7))) {
+ offset = 0;
+ mic_retry++;
+ if (mic_retry > MAX_FW_RETRY) {
+ PRINTM(MERROR,
+ "FW download failure @ %d, over max "
+ "mic retry count\n",
+ offset);
+ goto done;
+ }
+ }
+ } else {
+ block_retry_cnt = 0;
+ /* Set blocksize to transfer - checking for last block
+ */
+ if (firmware_len - offset < txlen)
+ txlen = firmware_len - offset;
+
+ PRINTM(MINFO, ".");
+
+ tx_blocks = (txlen + MLAN_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
+ MLAN_PCIE_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ memmove(pmadapter, pmbuf->pbuf + pmbuf->data_offset,
+ &firmware[offset], txlen);
+ pmbuf->data_len = txlen;
+ }
+
+ /* Send the boot command to device */
+ if (wlan_pcie_send_boot_cmd(pmadapter, pmbuf)) {
+ PRINTM(MERROR,
+ "Failed to send firmware download command\n");
+ goto done;
+ }
+ /* Wait for the command done interrupt */
+ do {
+ if (read_retry_cnt > MAX_READ_REG_RETRY) {
+ PRINTM(MERROR,
+ "prog_fw: Failed to get command done interrupt "
+ "retry count = %d\n",
+ read_retry_cnt);
+ goto done;
+ }
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_cpu_int_status,
+ &ireg_intr)) {
+ PRINTM(MERROR,
+ "prog_fw: Failed to read "
+ "interrupt status during fw dnld\n");
+ /* buffer was mapped in send_boot_cmd, unmap
+ * first */
+ pcb->moal_unmap_memory(
+ pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, WLAN_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
+ goto done;
+ }
+ read_retry_cnt++;
+ pcb->moal_usleep_range(pmadapter->pmoal_handle, 10, 20);
+ } while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
+ CPU_INTR_DOOR_BELL);
+ /* got interrupt - can unmap buffer now */
+ if (MLAN_STATUS_FAILURE ==
+ pcb->moal_unmap_memory(pmadapter->pmoal_handle,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->buf_pa, WLAN_UPLD_SIZE,
+ PCI_DMA_TODEVICE)) {
+ PRINTM(MERROR,
+ "prog_fw: failed to moal_unmap_memory\n");
+ goto done;
+ }
+ offset += txlen;
+ } while (MTRUE);
+
+ PRINTM(MMSG, "FW download over, size %d bytes\n", offset);
+
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ if (pmbuf)
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function get pcie device from card type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_get_pcie_device(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 card_type = pmadapter->card_type;
+
+ ENTER();
+
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_pcie_card),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->pcard_pcie);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_pcie) {
+ PRINTM(MERROR, "Failed to allocate pcard_pcie\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (card_type) {
+#ifdef PCIE8897
+ case CARD_TYPE_PCIE8897:
+ pmadapter->pcard_pcie->reg = &mlan_reg_pcie8897;
+ pmadapter->pcard_info = &mlan_card_info_pcie8897;
+ break;
+#endif
+#ifdef PCIE8997
+ case CARD_TYPE_PCIE8997:
+ pmadapter->pcard_pcie->reg = &mlan_reg_pcie8997;
+ pmadapter->pcard_info = &mlan_card_info_pcie8997;
+ break;
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ case CARD_TYPE_PCIE9097:
+ case CARD_TYPE_PCIE9098:
+ pmadapter->pcard_pcie->reg = &mlan_reg_pcie9098;
+ pmadapter->pcard_info = &mlan_card_info_pcie9098;
+#ifdef PCIE9097
+ if (card_type == CARD_TYPE_PCIE9097 &&
+ pmadapter->card_rev == CHIP_9097_REV_B0)
+ pmadapter->pcard_pcie->reg = &mlan_reg_pcie9097_b0;
+#endif
+ break;
+#endif
+ default:
+ PRINTM(MERROR, "can't get right pcie card type \n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief PCIE wakeup handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_wakeup(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 data = 0;
+ ENTER();
+ /* Enable interrupts or any chip access will wakeup device */
+ ret = pmadapter->callbacks.moal_read_reg(
+ pmadapter->pmoal_handle, pmadapter->pcard_pcie->reg->reg_ip_rev,
+ &data);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO,
+ "PCIE wakeup: Read PCI register to wakeup device ...\n");
+ } else {
+ PRINTM(MINFO, "PCIE wakeup: Failed to wakeup device ...\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ */
+/**
+ * @param msg_id A message id
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_FAILURE -- if the intererupt is not for us
+ */
+mlan_status wlan_pcie_interrupt(t_u16 msg_id, pmlan_adapter pmadapter)
+{
+ t_u32 pcie_ireg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_void *pmoal_handle = pmadapter->pmoal_handle;
+ t_void *pint_lock = pmadapter->pint_lock;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
+ pcb->moal_spin_lock(pmoal_handle, pint_lock);
+ pmadapter->ireg = 1;
+ pcb->moal_spin_unlock(pmoal_handle, pint_lock);
+ } else if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX) {
+ pcie_ireg = (1 << msg_id) &
+ pmadapter->pcard_pcie->reg->host_intr_mask;
+ if (pcie_ireg) {
+ if (!pmadapter->pps_uapsd_mode &&
+ (pmadapter->ps_state == PS_STATE_SLEEP)) {
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ }
+ }
+ pcb->moal_spin_lock(pmoal_handle, pint_lock);
+ pmadapter->ireg |= pcie_ireg;
+ pcb->moal_spin_unlock(pmoal_handle, pint_lock);
+
+ PRINTM(MINTR, "ireg: 0x%08x\n", pcie_ireg);
+ } else {
+ wlan_pcie_disable_host_int_mask(pmadapter);
+ if (pcb->moal_read_reg(
+ pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_status,
+ &pcie_ireg)) {
+ PRINTM(MWARN, "Read register failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ PRINTM(MINTR, "pcie_ireg=0x%x\n", pcie_ireg);
+ if (!pmadapter->pps_uapsd_mode &&
+ (pmadapter->ps_state == PS_STATE_SLEEP)) {
+ /* Potentially for PCIe we could get other
+ * interrupts like shared. */
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ }
+ pcb->moal_spin_lock(pmoal_handle, pint_lock);
+ pmadapter->ireg |= pcie_ireg;
+ pcb->moal_spin_unlock(pmoal_handle, pint_lock);
+
+ /* Clear the pending interrupts */
+ if (pcb->moal_write_reg(pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_host_int_status,
+ ~pcie_ireg)) {
+ PRINTM(MWARN, "Write register failed\n");
+ LEAVE();
+ return ret;
+ }
+ } else {
+ wlan_pcie_enable_host_int_mask(pmadapter);
+ PRINTM(MINFO, "This is not our interrupt\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the msix interrupt status and
+ * handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_msix_int(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 pcie_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ pcie_ireg =
+ pmadapter->ireg & pmadapter->pcard_pcie->reg->host_intr_mask;
+ pmadapter->ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+
+ if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_dnld_done) {
+ PRINTM(MINFO, "<--- DATA sent Interrupt --->\n");
+ ret = wlan_pcie_send_data_complete(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_upld_rdy) {
+ PRINTM(MINFO, "Rx DATA\n");
+ ret = wlan_pcie_process_recv_data(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_event_rdy) {
+ PRINTM(MINFO, "Rx EVENT\n");
+ ret = wlan_pcie_process_event_ready(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_cmd_done) {
+ if (pmadapter->cmd_sent) {
+ PRINTM(MINFO, "<--- CMD sent Interrupt --->\n");
+ pmadapter->cmd_sent = MFALSE;
+ }
+ ret = wlan_pcie_process_cmd_resp(pmadapter);
+ if (ret)
+ goto done;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->host_intr_cmd_dnld &&
+ (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_cmd_dnld)) {
+ if (pmadapter->cmd_sent)
+ pmadapter->cmd_sent = MFALSE;
+ if (pmadapter->pcard_pcie->vdll_cmd_buf)
+ wlan_pcie_send_vdll_complete(pmadapter);
+ PRINTM(MINFO, "<--- CMD DNLD DONE Interrupt --->\n");
+ }
+#endif
+ PRINTM(MINFO, "cmd_sent=%d data_sent=%d\n", pmadapter->cmd_sent,
+ pmadapter->data_sent);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and
+ * handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_pcie_int_status(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 pcie_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX) {
+ wlan_process_msix_int(pmadapter);
+ goto done;
+ }
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ if (pmadapter->pcard_pcie->pcie_int_mode != PCIE_INT_MODE_MSI)
+ pcie_ireg = pmadapter->ireg;
+ pmadapter->ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
+ if (pcb->moal_read_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_status,
+ &pcie_ireg)) {
+ PRINTM(MWARN, "Read register failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ PRINTM(MINTR, "pcie_ireg=0x%x\n", pcie_ireg);
+ if (pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_host_int_status,
+ ~pcie_ireg)) {
+ PRINTM(MWARN,
+ "Write register failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (!pmadapter->pps_uapsd_mode &&
+ (pmadapter->ps_state == PS_STATE_SLEEP)) {
+ /* Potentially for PCIe we could get other
+ * interrupts like shared. */
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ }
+ }
+ }
+ while (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_mask) {
+ if (pcie_ireg &
+ pmadapter->pcard_pcie->reg->host_intr_dnld_done) {
+ pcie_ireg &=
+ ~pmadapter->pcard_pcie->reg->host_intr_dnld_done;
+ PRINTM(MINFO, "<--- DATA sent Interrupt --->\n");
+ ret = wlan_pcie_send_data_complete(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg &
+ pmadapter->pcard_pcie->reg->host_intr_upld_rdy) {
+ pcie_ireg &=
+ ~pmadapter->pcard_pcie->reg->host_intr_upld_rdy;
+ PRINTM(MINFO, "Rx DATA\n");
+ pmadapter->callbacks.moal_tp_accounting_rx_param(
+ pmadapter->pmoal_handle, 0, 0);
+ ret = wlan_pcie_process_recv_data(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg &
+ pmadapter->pcard_pcie->reg->host_intr_event_rdy) {
+ pcie_ireg &=
+ ~pmadapter->pcard_pcie->reg->host_intr_event_rdy;
+ PRINTM(MINFO, "Rx EVENT\n");
+ ret = wlan_pcie_process_event_ready(pmadapter);
+ if (ret)
+ goto done;
+ }
+ if (pcie_ireg &
+ pmadapter->pcard_pcie->reg->host_intr_cmd_done) {
+ pcie_ireg &=
+ ~pmadapter->pcard_pcie->reg->host_intr_cmd_done;
+ if (pmadapter->cmd_sent) {
+ PRINTM(MINFO, "<--- CMD sent Interrupt --->\n");
+ pmadapter->cmd_sent = MFALSE;
+ }
+ ret = wlan_pcie_process_cmd_resp(pmadapter);
+ if (ret)
+ goto done;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->host_intr_cmd_dnld &&
+ (pcie_ireg &
+ pmadapter->pcard_pcie->reg->host_intr_cmd_dnld)) {
+ pcie_ireg &=
+ ~pmadapter->pcard_pcie->reg->host_intr_cmd_dnld;
+ if (pmadapter->cmd_sent)
+ pmadapter->cmd_sent = MFALSE;
+ if (pmadapter->pcard_pcie->vdll_cmd_buf)
+ wlan_pcie_send_vdll_complete(pmadapter);
+ PRINTM(MINFO, "<--- CMD DNLD DONE Interrupt --->\n");
+ }
+#endif
+ if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ pmadapter->ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ }
+ if (pcb->moal_read_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_host_int_status,
+ &pcie_ireg)) {
+ PRINTM(MWARN, "Read register failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ PRINTM(MINTR, "Poll: pcie_ireg=0x%x\n", pcie_ireg);
+ if ((pmadapter->pcard_pcie->pcie_int_mode ==
+ PCIE_INT_MODE_LEGACY) ||
+ pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
+ if (pcb->moal_write_reg(
+ pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg
+ ->reg_host_int_status,
+ ~pcie_ireg)) {
+ PRINTM(MWARN,
+ "Write register failed\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ if (pmadapter->pcard_pcie->pcie_int_mode !=
+ PCIE_INT_MODE_MSI) {
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ pcie_ireg |= pmadapter->ireg;
+ pmadapter->ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ }
+ /* Don't update the pmadapter->pcie_ireg,
+ * serving the status right now */
+ }
+ }
+ PRINTM(MINFO, "cmd_sent=%d data_sent=%d\n", pmadapter->cmd_sent,
+ pmadapter->data_sent);
+ if (pmadapter->pcard_pcie->pcie_int_mode != PCIE_INT_MODE_MSI) {
+ if (pmadapter->ps_state != PS_STATE_SLEEP ||
+ pmadapter->pcard_info->supp_ps_handshake)
+ wlan_pcie_enable_host_int_mask(pmadapter);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets DRV_READY register
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param val Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_set_drv_ready_reg(mlan_adapter *pmadapter, t_u32 val)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_drv_ready,
+ val)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interface is present
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param val Winner status (0: winner)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_pcie_check_winner_status(mlan_adapter *pmadapter, t_u32 *val)
+{
+ t_u32 winner = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_3,
+ &winner)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ *val = winner;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pollnum Maximum polling number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_check_fw_status(mlan_adapter *pmadapter, t_u32 pollnum)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 firmware_stat;
+ t_u32 tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_pcie->reg->reg_scratch_3,
+ &firmware_stat))
+ ret = MLAN_STATUS_FAILURE;
+ else
+ ret = MLAN_STATUS_SUCCESS;
+ if (ret)
+ continue;
+ if (firmware_stat == PCIE_FIRMWARE_READY) {
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ } else {
+ wlan_mdelay(pmadapter, 100);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function init the pcie interface
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_init(mlan_adapter *pmadapter)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Setting driver ready signature\n");
+ if (wlan_set_drv_ready_reg(pmadapter, PCIE_FIRMWARE_READY)) {
+ PRINTM(MERROR, "Failed to write driver ready signature\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_dnld_fw(pmlan_adapter pmadapter, pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 poll_num = 1;
+ t_u32 winner = 0;
+
+ ENTER();
+
+ ret = wlan_pcie_init(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN PCIE init failed\n", ret);
+ LEAVE();
+ return ret;
+ }
+ /* Check if firmware is already running */
+ ret = wlan_pcie_check_fw_status(pmadapter, poll_num);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG, "WLAN FW already running! Skip FW download\n");
+ goto done;
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if other interface is downloading */
+ ret = wlan_pcie_check_winner_status(pmadapter, &winner);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MFATAL, "WLAN read winner status failed!\n");
+ goto done;
+ }
+ if (winner) {
+ PRINTM(MMSG,
+ "WLAN is not the winner (0x%x). Skip FW download\n",
+ winner);
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+
+ /* Download the firmware image via helper */
+ ret = wlan_pcie_prog_fw_w_helper(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "prog_fw failed ret=%#x\n", ret);
+ LEAVE();
+ return ret;
+ }
+poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = wlan_pcie_check_fw_status(pmadapter, poll_num);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW failed to be active in time!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+done:
+
+ /* re-enable host interrupt for mlan after fw dnld is successful */
+ wlan_enable_pcie_host_int(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card
+ * by this function. This function adds the PCIE specific header
+ * to the front of the buffer before transferring. The header
+ * contains the length of the packet and the type. The firmware
+ * handles the packets based upon this set type.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * PCIE header)
+ * @param tx_param A pointer to mlan_tx_param (can be MNULL if type is
+ * command)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pcie_host_to_card(pmlan_private pmpriv, t_u8 type,
+ mlan_buffer *pmbuf, mlan_tx_param *tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MERROR, "Passed NULL pmbuf to %s\n", __FUNCTION__);
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (type == MLAN_TYPE_DATA)
+ ret = wlan_pcie_send_data(pmadapter, type, pmbuf, tx_param);
+ else if (type == MLAN_TYPE_CMD)
+ ret = wlan_pcie_send_cmd(pmadapter, pmbuf);
+#if defined(PCIE9098) || defined(PCIE9097)
+ else if (type == MLAN_TYPE_VDLL)
+ ret = wlan_pcie_send_vdll(pmadapter, pmbuf);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function allocates the PCIE buffer for SSU
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_alloc_ssu_pcie_buf(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+ /** Virtual base address of ssu buffer */
+ t_u8 *ssu_vbase;
+ /** Physical base address of ssu buffer */
+ t_u64 ssu_pbase = 0;
+
+ ENTER();
+
+ if (pmadapter->ssu_buf) {
+ PRINTM(MCMND, "ssu buffer already allocated\n");
+ LEAVE();
+ return ret;
+ }
+ /* Allocate buffer here so that firmware can DMA data on it */
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, 0, 0, MOAL_MALLOC_BUFFER);
+ if (!pmbuf) {
+ PRINTM(MERROR,
+ "SSU buffer create : Unable to allocate mlan_buffer\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = pcb->moal_malloc_consistent(pmadapter->pmoal_handle,
+ MLAN_SSU_BUF_SIZE, &ssu_vbase,
+ &ssu_pbase);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
+ __FUNCTION__);
+ /* free pmbuf */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf->buf_pa = ssu_pbase;
+ pmbuf->pbuf = ssu_vbase;
+ pmbuf->data_offset = 0;
+ pmbuf->data_len = MLAN_SSU_BUF_SIZE;
+ pmbuf->total_pcie_buf_len = MLAN_SSU_BUF_SIZE;
+
+ PRINTM(MCMND,
+ "SSU buffer: add new mlan_buffer base: %p, "
+ "buf_base: %p, data_offset: %x, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n",
+ pmbuf, pmbuf->pbuf, pmbuf->data_offset,
+ (t_u32)((t_u64)pmbuf->buf_pa >> 32), (t_u32)pmbuf->buf_pa,
+ pmbuf->data_len);
+
+ pmadapter->ssu_buf = pmbuf;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the allocated ssu buffer.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_free_ssu_pcie_buf(pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer *pmbuf = MNULL;
+ t_u8 *ssu_vbase;
+ t_u64 ssu_pbase;
+
+ ENTER();
+ if (!pmadapter) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->ssu_buf) {
+ pmbuf = pmadapter->ssu_buf;
+ ssu_vbase = pmbuf->pbuf;
+ ssu_pbase = pmbuf->buf_pa;
+ if (ssu_vbase)
+ pcb->moal_mfree_consistent(pmadapter->pmoal_handle,
+ pmbuf->total_pcie_buf_len,
+ ssu_vbase, ssu_pbase);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ pmadapter->ssu_buf = MNULL;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates the PCIE ring buffers
+ *
+ * The following initializations steps are followed -
+ * - Allocate TXBD ring buffers
+ * - Allocate RXBD ring buffers
+ * - Allocate event BD ring buffers
+ * - Allocate command and command response buffer
+ * - Allocate sleep cookie buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_alloc_pcie_ring_buf(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
+ ret = wlan_pcie_create_txbd_ring(pmadapter);
+ if (ret)
+ goto err_cre_txbd;
+ ret = wlan_pcie_create_rxbd_ring(pmadapter);
+ if (ret)
+ goto err_cre_rxbd;
+ ret = wlan_pcie_create_evtbd_ring(pmadapter);
+ if (ret)
+ goto err_cre_evtbd;
+ ret = wlan_pcie_alloc_cmdrsp_buf(pmadapter);
+ if (ret)
+ goto err_alloc_cmdbuf;
+ return ret;
+err_alloc_cmdbuf:
+ wlan_pcie_delete_evtbd_ring(pmadapter);
+err_cre_evtbd:
+ wlan_pcie_delete_rxbd_ring(pmadapter);
+err_cre_rxbd:
+ wlan_pcie_delete_txbd_ring(pmadapter);
+err_cre_txbd:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the allocated ring buffers.
+ *
+ * The following are freed by this function -
+ * - TXBD ring buffers
+ * - RXBD ring buffers
+ * - Event BD ring buffers
+ * - Command and command response buffer
+ * - Sleep cookie buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_free_pcie_ring_buf(pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ wlan_pcie_delete_cmdrsp_buf(pmadapter);
+ wlan_pcie_delete_evtbd_ring(pmadapter);
+ wlan_pcie_delete_rxbd_ring(pmadapter);
+ wlan_pcie_delete_txbd_ring(pmadapter);
+ pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
+#ifdef RPTR_MEM_COP
+ if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
+ (pmadapter->card_type == CARD_TYPE_PCIE9097))
+ wlan_pcie_free_rdptrs(pmadapter);
+#endif
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function cleans up packets in the ring buffers.
+ *
+ * The following are cleaned by this function -
+ * - TXBD ring buffers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_clean_pcie_ring_buf(pmlan_adapter pmadapter)
+{
+ ENTER();
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma)
+ wlan_pcie_flush_txbd_ring(pmadapter);
+#endif
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command to set PCI-Express
+ * host buffer configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_set_pcie_buf_config(mlan_private *pmpriv)
+{
+ pmlan_adapter pmadapter = MNULL;
+#if defined(PCIE8997) || defined(PCIE8897)
+ HostCmd_DS_PCIE_HOST_BUF_DETAILS host_spec;
+#endif
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (!pmpriv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter = pmpriv->adapter;
+#if defined(PCIE8997) || defined(PCIE8897)
+ if (!pmadapter->pcard_pcie->reg->use_adma) {
+ memset(pmadapter, &host_spec, 0,
+ sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS));
+
+ /* Send the ring base addresses and count to firmware */
+ host_spec.txbd_addr_lo =
+ (t_u32)(pmadapter->pcard_pcie->txbd_ring_pbase);
+ host_spec.txbd_addr_hi = (t_u32)(
+ ((t_u64)pmadapter->pcard_pcie->txbd_ring_pbase) >> 32);
+ host_spec.txbd_count = MLAN_MAX_TXRX_BD;
+ host_spec.rxbd_addr_lo =
+ (t_u32)(pmadapter->pcard_pcie->rxbd_ring_pbase);
+ host_spec.rxbd_addr_hi = (t_u32)(
+ ((t_u64)pmadapter->pcard_pcie->rxbd_ring_pbase) >> 32);
+ host_spec.rxbd_count = MLAN_MAX_TXRX_BD;
+ host_spec.evtbd_addr_lo =
+ (t_u32)(pmadapter->pcard_pcie->evtbd_ring_pbase);
+ host_spec.evtbd_addr_hi = (t_u32)(
+ ((t_u64)pmadapter->pcard_pcie->evtbd_ring_pbase) >> 32);
+ host_spec.evtbd_count = MLAN_MAX_EVT_BD;
+
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_PCIE_HOST_BUF_DETAILS,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &host_spec);
+ if (ret) {
+ PRINTM(MERROR,
+ "PCIE_HOST_BUF_CFG: send command failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+#endif
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (pmadapter->pcard_pcie->reg->use_adma) {
+ /** config ADMA for Tx Data */
+ wlan_init_adma(pmadapter, ADMA_TX_DATA,
+ pmadapter->pcard_pcie->txbd_ring_pbase,
+ TX_RX_NUM_DESC, MTRUE);
+ /** config ADMA for Rx Data */
+ wlan_init_adma(pmadapter, ADMA_RX_DATA,
+ pmadapter->pcard_pcie->rxbd_ring_pbase,
+ TX_RX_NUM_DESC, MTRUE);
+ /** config ADMA for Rx Event */
+ wlan_init_adma(pmadapter, ADMA_EVENT,
+ pmadapter->pcard_pcie->evtbd_ring_pbase,
+ EVT_NUM_DESC, MTRUE);
+ /** config ADMA for cmd */
+ wlan_init_adma(pmadapter, ADMA_CMD, 0, 0, MTRUE);
+ /** config ADMA for cmdresp */
+ wlan_init_adma(pmadapter, ADMA_CMDRESP,
+ pmadapter->pcard_pcie->cmdrsp_buf->buf_pa, 0,
+ MTRUE);
+ }
+#endif
+ wlan_pcie_init_fw(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+#if defined(PCIE8997) || defined(PCIE8897)
+/**
+ * @brief This function prepares command PCIE host buffer config.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_pcie_host_buf_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_pvoid pdata_buf)
+{
+ HostCmd_DS_PCIE_HOST_BUF_DETAILS *ppcie_hoost_spec =
+ &cmd->params.pcie_host_spec;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PCIE_HOST_BUF_DETAILS);
+ cmd->size = wlan_cpu_to_le16(
+ (sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS)) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy_ext(pmpriv->adapter, ppcie_hoost_spec, pdata_buf,
+ sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS),
+ sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param timeout set timeout flag
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pm_pcie_wakeup_card(pmlan_adapter pmadapter, t_u8 timeout)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ PRINTM(MEVENT, "Wakeup device...\n");
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->pm_wakeup_in_secs,
+ &age_ts_usec);
+
+ if (timeout) {
+ pmadapter->callbacks.moal_start_timer(
+ pmadapter->pmoal_handle, pmadapter->pwakeup_fw_timer,
+ MFALSE, MRVDRV_TIMER_3S);
+ pmadapter->wakeup_fw_timer_is_set = MTRUE;
+ }
+
+ ret = wlan_pcie_wakeup(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+mlan_status wlan_pcie_debug_dump(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
+ ENTER();
+
+ if (pmbuf == MNULL) {
+ PRINTM(MMSG, "Rx CMD response pmbuf is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ PRINTM(MERROR, "Dump Rx CMD Response Buf:\n");
+ DBG_HEXDUMP(MERROR, "CmdResp Buf", pmbuf->pbuf + pmbuf->data_offset,
+ 64);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handle data complete
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return N/A
+ */
+mlan_status wlan_pcie_data_complete(pmlan_adapter pmadapter, mlan_buffer *pmbuf,
+ mlan_status status)
+{
+ ENTER();
+
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+mlan_adapter_operations mlan_pcie_ops = {
+ .dnld_fw = wlan_pcie_dnld_fw,
+ .interrupt = wlan_pcie_interrupt,
+ .process_int_status = wlan_process_pcie_int_status,
+ .host_to_card = wlan_pcie_host_to_card,
+ .wakeup_card = wlan_pm_pcie_wakeup_card,
+ .reset_card = wlan_pcie_wakeup,
+ .event_complete = wlan_pcie_event_complete,
+ .data_complete = wlan_pcie_data_complete,
+ .cmdrsp_complete = wlan_pcie_cmdrsp_complete,
+ .handle_rx_packet = wlan_handle_rx_packet,
+ .debug_dump = wlan_pcie_debug_dump,
+ .intf_header_len = PCIE_INTF_HEADER_LEN,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.h
new file mode 100644
index 000000000000..af404379e81b
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_pcie.h
@@ -0,0 +1,650 @@
+/** @file mlan_pcie.h
+ *
+ * @brief This file contains definitions for PCIE interface.
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/01/2012: initial version
+********************************************************/
+
+#ifndef _MLAN_PCIE_H_
+#define _MLAN_PCIE_H_
+/** Tx DATA */
+#define ADMA_TX_DATA 0
+/** Rx DATA */
+#define ADMA_RX_DATA 1
+/** EVENT */
+#define ADMA_EVENT 2
+/** CMD */
+#define ADMA_CMD 3
+/** CMD RESP */
+#define ADMA_CMDRESP 4
+/** ADMA direction */
+#define ADMA_HOST_TO_DEVICE 0
+/** ADMA direction Rx */
+#define ADMA_DEVICE_TO_HOST 1
+/** Direct Program mode */
+#define DMA_MODE_DIRECT 0
+/** Single descriptor mode */
+#define DMA_MODE_SINGLE_DESC 1
+/** dual discriptor mode */
+#define DMA_MODE_DUAL_DESC 2
+/** descriptor mode: ring mode */
+#define DESC_MODE_RING 0
+/** descriptor mode: chain mode */
+#define DESC_MODE_CHAIN 1
+/** DMA size start bit */
+#define DMA_SIZE_BIT 16
+/** DMA size mask */
+#define DMA_SIZE_MASK 0xffff0000
+/** Descriptor mode */
+#define DESC_MODE_MASK 0x0004
+/** DMA MODE MASK */
+#define DMA_MODE_MASK 0x0003
+/** Dest Num Descriptor start bits */
+#define DST_NUM_DESC_BIT 12
+/** Destination Num of Descriptor mask */
+#define DST_NUM_DESC_MASK 0xf000
+/** Src Num Descriptor start bits */
+#define SRC_NUM_DESC_BIT 8
+/** Destination Num of Descriptor mask */
+#define SRC_NUM_DESC_MASK 0x0f00
+/** Virtual Q priority mask */
+#define Q_PRIO_WEIGHT_MASK 0x00f0
+/** DMA cfg register offset*/
+#define ADMA_DMA_CFG 0x0000
+/** source base low */
+#define ADMA_SRC_LOW 0x0004
+/** source base high */
+#define ADMA_SRC_HIGH 0x0008
+/** destination base low */
+#define ADMA_DST_LOW 0x000C
+/** destination base high */
+#define ADMA_DST_HIGH 0x0010
+/** source rd/wr pointer */
+#define ADMA_SRC_RW_PTR 0x0014
+/** destination rd/wr pointer */
+#define ADMA_DST_RW_PTR 0x0018
+/** interrupt direction mapping reg, for each virtual Q, used for
+ * dual-descriptor only, only valid for Q0 */
+#define ADMA_INT_MAPPING 0x001C
+/** destination interrupt to device */
+#define DEST_INT_TO_DEVICE MBIT(0)
+/** destination interrupt to host */
+#define DEST_INT_TO_HOST MBIT(1)
+/** interrupt pending status for each virtual Q, only valid for Q0 */
+#define ADMA_INT_PENDING 0x0020
+/** Default ADMA INT mask, We only enable dma done */
+#define DEF_ADMA_INT_MASK MBIT(0)
+/** source interrupt status mask reg */
+#define ADMA_SRC_INT_STATUS_MASK 0x0024
+/** source interrupt mask reg */
+#define ADMA_SRC_INT_MASK 0x0028
+/** source interrupt status reg */
+#define ADMA_SRC_INT_STATUS 0x002C
+/** destination interrupt status mask reg */
+#define ADMA_DST_INT_STATUS_MASK 0x0030
+/** destination interrupt mask reg */
+#define ADMA_DST_INT_MASK 0x0034
+/** destination interrupt status reg */
+#define ADMA_DST_INT_STATUS 0x0038
+/** DMA cfg2 register */
+#define ADMA_DMA_CFG2 0x003C
+/** ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN */
+#define ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN MBIT(22)
+/** ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN */
+#define ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN MBIT(21)
+/* If this bit is set, MSIX trigger event will be from DST, other wise MSIX
+ * trigger event will be from SRC */
+#define ADMA_MSIX_INT_SRC_DST_SEL MBIT(20)
+/** Enable MSI/Legacy for this Queue */
+#define ADMA_MSI_LEGACY_ENABLE MBIT(19)
+/** Enable MSIX for this queue */
+#define ADMA_MSIX_ENABLE MBIT(18)
+/** ADMA_DST_DMA_DONE_INT_BYPASS_EN */
+#define ADMA_DST_DMA_DONE_INT_BYPASS_EN MBIT(17)
+/** SRC_DMA_DONE_INT_BYPASS_EN */
+#define ADMA_SRC_DMA_DONE_INT_BYPASS_EN MBIT(16)
+/* Destination Read Pointer Memory Copy Enable */
+#define ADMA_DST_RPTR_MEM_COPY_EN MBIT(11)
+/* Source Read Pointer Memory Copy Enable */
+#define ADMA_SRC_RPTR_MEM_COPY_EN MBIT(10)
+/** Destination address is host */
+#define ADMA_DST_ADDR_IS_HOST MBIT(2)
+/** Source address is host */
+#define ADMA_SRC_ADDR_IS_HOST MBIT(1)
+
+/** DMA cfg3 register */
+#define ADMA_DMA_CFG3 0x0040
+/** source rd ptr address low */
+#define ADMA_SRC_RD_PTR_LOW 0x0044
+/** source rd ptr address high */
+#define ADMA_SRC_RD_PTR_HIGH 0x0048
+/** destination rd ptr address low */
+#define ADMA_DST_RD_PTR_LOW 0x004C
+/** destination rd ptr address high */
+#define ADMA_DST_RD_PTR_HIGH 0x0050
+/** source active interrupt mask */
+#define ADMA_SRC_ACTV_INT_MASK 0x0054
+/** destination active interrupt mask */
+#define ADMA_DST_ACTV_INT_MASK 0x0058
+/** Read pointer start from bit 16 */
+#define ADMA_RPTR_START 16
+/** write pointer start from bit 0 */
+#define ADMA_WPTR_START 0
+/** Tx/Rx Read/Write pointer's mask */
+#define TXRX_RW_PTR_MASK (MLAN_MAX_TXRX_BD - 1)
+/** Tx/Rx Read/Write pointer's rollover indicate bit */
+#define TXRX_RW_PTR_ROLLOVER_IND MLAN_MAX_TXRX_BD
+/** Start of packet flag */
+#define ADMA_BD_FLAG_SOP MBIT(0)
+/** End of packet flag */
+#define ADMA_BD_FLAG_EOP MBIT(1)
+/** interrupt enable flag */
+#define ADMA_BD_FLAG_INT_EN MBIT(2)
+/** Source address is host side flag */
+#define ADMA_BD_FLAG_SRC_HOST MBIT(3)
+/** Destination address is host side flag */
+#define ADMA_BD_FLAG_DST_HOST MBIT(4)
+/** ADMA MIN PKT SIZE */
+#define ADMA_MIN_PKT_SIZE 128
+/** ADMA dual descriptor mode requir 8 bytes alignment in buf size */
+#define ADMA_ALIGN_SIZE 8
+/** ADMA RW_PTR wrap mask */
+#define ADMA_RW_PTR_WRAP_MASK 0x00001FFF
+/** ADMA MSIX DOORBEEL DATA */
+#define ADMA_MSIX_DOORBELL_DATA 0x0064
+/** MSIX VECTOR MASK: BIT 0-10 */
+#define ADMA_MSIX_VECTOR_MASK 0x3f
+/** PF mask: BIT 24-28 */
+#define ADMA_MSIX_PF_MASK 0x1f000000
+/** PF start bit */
+#define ADMA_MSIX_PF_BIT 24
+
+#if defined(PCIE9098) || defined(PCIE9097)
+/** PCIE9098 dev_id/vendor id reg */
+#define PCIE9098_DEV_ID_REG 0x0000
+/** PCIE revision ID register */
+#define PCIE9098_REV_ID_REG 0x0008
+/** PCIE IP revision register */
+#define PCIE9098_IP_REV_REG 0x1000
+/** PCIE CPU interrupt events */
+#define PCIE9098_CPU_INT_EVENT 0x1C20
+/** PCIE CPU interrupt status */
+#define PCIE9098_CPU_INT_STATUS 0x1C24
+/** PCIe CPU Interrupt Status Mask */
+#define PCIE9098_CPU_INT2ARM_ISM 0x1C28
+/** PCIE host interrupt status */
+#define PCIE9098_HOST_INT_STATUS 0x1C44
+/** PCIE host interrupt mask */
+#define PCIE9098_HOST_INT_MASK 0x1C48
+/** PCIE host interrupt clear select*/
+#define PCIE9098_HOST_INT_CLR_SEL 0x1C4C
+/** PCIE host interrupt status mask */
+#define PCIE9098_HOST_INT_STATUS_MASK 0x1C50
+/** PCIE host interrupt status */
+#define PCIE9097_B0_HOST_INT_STATUS 0x3C44
+/** PCIE host interrupt mask */
+#define PCIE9097_B0_HOST_INT_MASK 0x3C48
+/** PCIE host interrupt clear select*/
+#define PCIE9097_B0_HOST_INT_CLR_SEL 0x3C4C
+/** PCIE host interrupt status mask */
+#define PCIE9097_B0_HOST_INT_STATUS_MASK 0x3C50
+/** PCIE host interrupt select*/
+#define PCIE9098_HOST_INT_SEL 0x1C58
+/** PCIE data exchange register 0 */
+#define PCIE9098_SCRATCH_0_REG 0x1C60
+/** PCIE data exchange register 1 */
+#define PCIE9098_SCRATCH_1_REG 0x1C64
+/** PCIE data exchange register 2 */
+#define PCIE9098_SCRATCH_2_REG 0x1C68
+/** PCIE data exchange register 3 */
+#define PCIE9098_SCRATCH_3_REG 0x1C6C
+/** PCIE data exchange register 4 */
+#define PCIE9098_SCRATCH_4_REG 0x1C70
+/** PCIE data exchange register 5 */
+#define PCIE9098_SCRATCH_5_REG 0x1C74
+/** PCIE data exchange register 6 */
+#define PCIE9098_SCRATCH_6_REG 0x1C78
+/** PCIE data exchange register 7 */
+#define PCIE9098_SCRATCH_7_REG 0x1C7C
+/** PCIE data exchange register 8 */
+#define PCIE9098_SCRATCH_8_REG 0x1C80
+/** PCIE data exchange register 9 */
+#define PCIE9098_SCRATCH_9_REG 0x1C84
+/** PCIE data exchange register 10 */
+#define PCIE9098_SCRATCH_10_REG 0x1C88
+/** PCIE data exchange register 11 */
+#define PCIE9098_SCRATCH_11_REG 0x1C8C
+/** PCIE data exchange register 12 */
+#define PCIE9098_SCRATCH_12_REG 0x1C90
+/** PCIE data exchange register 13 */
+#define PCIE9098_SCRATCH_13_REG 0x1C94
+/** PCIE data exchange register 14 */
+#define PCIE9098_SCRATCH_14_REG 0x1C98
+/** PCIE data exchange register 15 */
+#define PCIE9098_SCRATCH_15_REG 0x1C9C
+/** ADMA CHAN0_Q0 start address, Tx Data */
+#define ADMA_CHAN0_Q0 0x10000
+/** ADMA CHAN1_Q0 start address, Rx Data */
+#define ADMA_CHAN1_Q0 0x10800
+/** ADMA CHAN1_Q1 start address, Rx Event */
+#define ADMA_CHAN1_Q1 0x10880
+/** ADMA CHAN2_Q0 start address, Tx Command */
+#define ADMA_CHAN2_Q0 0x11000
+/** ADMA CHAN2_Q1 start address, Command Resp */
+#define ADMA_CHAN2_Q1 0x11080
+/** CH0-Q0' src rd/wr ptr */
+#define ADMA_SRC_PTR_CH0_Q0 (ADMA_CHAN0_Q0 + ADMA_SRC_RW_PTR)
+/** CH1-Q1' dest rd/wr ptr */
+#define ADMA_DST_PTR_CH1_Q0 (ADMA_CHAN1_Q0 + ADMA_DST_RW_PTR)
+/** CH1-Q1' dest rd/wr ptr */
+#define ADMA_DST_PTR_CH1_Q1 (ADMA_CHAN1_Q1 + ADMA_DST_RW_PTR)
+/* TX buffer description read pointer */
+#define PCIE9098_TXBD_RDPTR ADMA_SRC_PTR_CH0_Q0
+/* TX buffer description write pointer */
+#define PCIE9098_TXBD_WRPTR ADMA_SRC_PTR_CH0_Q0
+/* RX buffer description read pointer */
+#define PCIE9098_RXBD_RDPTR ADMA_DST_PTR_CH1_Q0
+/* RX buffer description write pointer */
+#define PCIE9098_RXBD_WRPTR ADMA_DST_PTR_CH1_Q0
+/* Event buffer description read pointer */
+#define PCIE9098_EVTBD_RDPTR ADMA_DST_PTR_CH1_Q1
+/* Event buffer description write pointer */
+#define PCIE9098_EVTBD_WRPTR ADMA_DST_PTR_CH1_Q1
+/* Driver ready signature write pointer */
+#define PCIE9098_DRV_READY PCIE9098_SCRATCH_12_REG
+
+/** interrupt bit define for ADMA CHAN0 Q0, For Tx DATA */
+#define ADMA_INT_CHAN0_Q0 MBIT(0)
+/** interrupt bit define for ADMA CHAN1 Q0, For Rx Data */
+#define AMDA_INT_CHAN1_Q0 MBIT(16)
+/** interrupt bit define for ADMA CHAN1 Q1, For Rx Event */
+#define AMDA_INT_CHAN1_Q1 MBIT(17)
+/** interrupt bit define for ADMA CHAN2 Q0, For Tx Command */
+#define AMDA_INT_CHAN2_Q0 MBIT(24)
+/** interrupt bit define for ADMA CHAN2 Q1, For Rx Command Resp */
+#define AMDA_INT_CHAN2_Q1 MBIT(25)
+
+/** interrupt vector number for ADMA CHAN0 Q0, For Tx DATA */
+#define ADMA_VECTOR_CHAN0_Q0 0
+/** interrupt vector number for ADMA CHAN1 Q0, For Rx Data */
+#define AMDA_VECTOR_CHAN1_Q0 16
+/** interrupt vector number for ADMA CHAN1 Q1, For Rx Event */
+#define AMDA_VECTOR_CHAN1_Q1 17
+/** interrupt vector number for ADMA CHAN2 Q0, For Tx Command */
+#define AMDA_VECTOR_CHAN2_Q0 24
+/** interrupt vector number for ADMA CHAN2 Q1, For Rx Command Resp */
+#define AMDA_VECTOR_CHAN2_Q1 25
+
+/** Data sent interrupt for host */
+#define PCIE9098_HOST_INTR_DNLD_DONE ADMA_INT_CHAN0_Q0
+/** Data receive interrupt for host */
+#define PCIE9098_HOST_INTR_UPLD_RDY AMDA_INT_CHAN1_Q0
+/** Command sent interrupt for host */
+#define PCIE9098_HOST_INTR_CMD_DONE AMDA_INT_CHAN2_Q1
+/** Event ready interrupt for host */
+#define PCIE9098_HOST_INTR_EVENT_RDY AMDA_INT_CHAN1_Q1
+/** CMD sent interrupt for host */
+#define PCIE9098_HOST_INTR_CMD_DNLD MBIT(7)
+
+/** Interrupt mask for host */
+#define PCIE9098_HOST_INTR_MASK \
+ (PCIE9098_HOST_INTR_DNLD_DONE | PCIE9098_HOST_INTR_UPLD_RDY | \
+ PCIE9098_HOST_INTR_CMD_DONE | PCIE9098_HOST_INTR_CMD_DNLD | \
+ PCIE9098_HOST_INTR_EVENT_RDY)
+
+/** Interrupt select mask for host */
+#define PCIE9098_HOST_INTR_SEL_MASK \
+ (PCIE9098_HOST_INTR_DNLD_DONE | PCIE9098_HOST_INTR_UPLD_RDY | \
+ PCIE9098_HOST_INTR_CMD_DONE | PCIE9098_HOST_INTR_EVENT_RDY)
+#endif
+
+#if defined(PCIE8997) || defined(PCIE8897)
+/* PCIE INTERNAL REGISTERS */
+/** PCIE data exchange register 0 */
+#define PCIE_SCRATCH_0_REG 0x0C10
+/** PCIE data exchange register 1 */
+#define PCIE_SCRATCH_1_REG 0x0C14
+/** PCIE CPU interrupt events */
+#define PCIE_CPU_INT_EVENT 0x0C18
+/** PCIE CPU interrupt status */
+#define PCIE_CPU_INT_STATUS 0x0C1C
+
+/** PCIe CPU Interrupt Status Mask */
+#define PCIE_CPU_INT2ARM_ISM 0x0C28
+/** PCIE host interrupt status */
+#define PCIE_HOST_INT_STATUS 0x0C30
+/** PCIE host interrupt mask */
+#define PCIE_HOST_INT_MASK 0x0C34
+/** PCIE host interrupt status mask */
+#define PCIE_HOST_INT_STATUS_MASK 0x0C3C
+/** PCIE data exchange register 2 */
+#define PCIE_SCRATCH_2_REG 0x0C40
+/** PCIE data exchange register 3 */
+#define PCIE_SCRATCH_3_REG 0x0C44
+
+#define PCIE_IP_REV_REG 0x0C48
+
+/** PCIE data exchange register 4 */
+#define PCIE_SCRATCH_4_REG 0x0CD0
+/** PCIE data exchange register 5 */
+#define PCIE_SCRATCH_5_REG 0x0CD4
+/** PCIE data exchange register 6 */
+#define PCIE_SCRATCH_6_REG 0x0CD8
+/** PCIE data exchange register 7 */
+#define PCIE_SCRATCH_7_REG 0x0CDC
+/** PCIE data exchange register 8 */
+#define PCIE_SCRATCH_8_REG 0x0CE0
+/** PCIE data exchange register 9 */
+#define PCIE_SCRATCH_9_REG 0x0CE4
+/** PCIE data exchange register 10 */
+#define PCIE_SCRATCH_10_REG 0x0CE8
+/** PCIE data exchange register 11 */
+#define PCIE_SCRATCH_11_REG 0x0CEC
+/** PCIE data exchange register 12 */
+#define PCIE_SCRATCH_12_REG 0x0CF0
+#endif
+
+#ifdef PCIE8997
+/* PCIE read data pointer for queue 0 and 1 */
+#define PCIE8997_RD_DATA_PTR_Q0_Q1 0xC1A4 /* 0x8000C1A4 */
+/* PCIE read data pointer for queue 2 and 3 */
+#define PCIE8997_RD_DATA_PTR_Q2_Q3 0xC1A8 /* 0x8000C1A8 */
+/* PCIE write data pointer for queue 0 and 1 */
+#define PCIE8997_WR_DATA_PTR_Q0_Q1 0xC174 /* 0x8000C174 */
+/* PCIE write data pointer for queue 2 and 3 */
+#define PCIE8997_WR_DATA_PTR_Q2_Q3 0xC178 /* 0x8000C178 */
+#endif
+#ifdef PCIE8897
+/* PCIE read data pointer for queue 0 and 1 */
+#define PCIE8897_RD_DATA_PTR_Q0_Q1 0xC08C /* 0x8000C08C */
+/* PCIE read data pointer for queue 2 and 3 */
+#define PCIE8897_RD_DATA_PTR_Q2_Q3 0xC090 /* 0x8000C090 */
+/* PCIE write data pointer for queue 0 and 1 */
+#define PCIE8897_WR_DATA_PTR_Q0_Q1 0xC05C /* 0x8000C05C */
+/* PCIE write data pointer for queue 2 and 3 */
+#define PCIE8897_WR_DATA_PTR_Q2_Q3 0xC060 /* 0x8000C060 */
+#endif
+
+/** Download ready interrupt for CPU */
+#define CPU_INTR_DNLD_RDY MBIT(0)
+/** Command ready interrupt for CPU */
+#define CPU_INTR_DOOR_BELL MBIT(1)
+/** Confirmation that sleep confirm message has been processed.
+ Device will enter sleep after receiving this interrupt */
+#define CPU_INTR_SLEEP_CFM_DONE MBIT(2)
+/** Reset interrupt for CPU */
+#define CPU_INTR_RESET MBIT(3)
+/** Set Event Done interupt to the FW*/
+#define CPU_INTR_EVENT_DONE MBIT(5)
+
+#if defined(PCIE8997) || defined(PCIE8897)
+/** Data sent interrupt for host */
+#define HOST_INTR_DNLD_DONE MBIT(0)
+/** Data receive interrupt for host */
+#define HOST_INTR_UPLD_RDY MBIT(1)
+/** Command sent interrupt for host */
+#define HOST_INTR_CMD_DONE MBIT(2)
+/** Event ready interrupt for host */
+#define HOST_INTR_EVENT_RDY MBIT(3)
+/** Interrupt mask for host */
+#define HOST_INTR_MASK \
+ (HOST_INTR_DNLD_DONE | HOST_INTR_UPLD_RDY | HOST_INTR_CMD_DONE | \
+ HOST_INTR_EVENT_RDY)
+
+/** Lower 32bits command address holding register */
+#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG
+/** Upper 32bits command address holding register */
+#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG
+/** Command length holding register */
+#define REG_CMD_SIZE PCIE_SCRATCH_2_REG
+
+/** Lower 32bits command response address holding register */
+#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG
+/** Upper 32bits command response address holding register */
+#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG
+
+/** TxBD's Read/Write pointer start from bit 16 */
+#define TXBD_RW_PTR_START 16
+/** RxBD's Read/Write pointer start from bit 0 */
+#define RXBD_RW_PTR_STRAT 0
+
+#define MLAN_BD_FLAG_SOP MBIT(0)
+#define MLAN_BD_FLAG_EOP MBIT(1)
+#define MLAN_BD_FLAG_XS_SOP MBIT(2)
+#define MLAN_BD_FLAG_XS_EOP MBIT(3)
+
+/* Event buffer description write pointer */
+#define REG_EVTBD_WRPTR PCIE_SCRATCH_10_REG
+/* Event buffer description read pointer */
+#define REG_EVTBD_RDPTR PCIE_SCRATCH_11_REG
+/* Driver ready signature write pointer */
+#define REG_DRV_READY PCIE_SCRATCH_12_REG
+
+/** Event Read/Write pointer mask */
+#define EVT_RW_PTR_MASK 0x0f
+/** Event Read/Write pointer rollover bit */
+#define EVT_RW_PTR_ROLLOVER_IND MBIT(7)
+#endif
+
+/* Define PCIE block size for firmware download */
+#define MLAN_PCIE_BLOCK_SIZE_FW_DNLD 256
+
+/** Extra added macros **/
+#define MLAN_EVENT_HEADER_LEN 8
+
+/** Max interrupt status register read limit */
+#define MAX_READ_REG_RETRY 10000
+
+#ifdef PCIE8897
+static const struct _mlan_pcie_card_reg mlan_reg_pcie8897 = {
+ .reg_txbd_rdptr = PCIE8897_RD_DATA_PTR_Q0_Q1,
+ .reg_txbd_wrptr = PCIE8897_WR_DATA_PTR_Q0_Q1,
+ .reg_rxbd_rdptr = PCIE8897_RD_DATA_PTR_Q0_Q1,
+ .reg_rxbd_wrptr = PCIE8897_WR_DATA_PTR_Q0_Q1,
+ .reg_evtbd_rdptr = REG_EVTBD_RDPTR,
+ .reg_evtbd_wrptr = REG_EVTBD_WRPTR,
+ .reg_host_int_mask = PCIE_HOST_INT_MASK,
+ .reg_host_int_status_mask = PCIE_HOST_INT_STATUS_MASK,
+ .reg_host_int_status = PCIE_HOST_INT_STATUS,
+ .reg_cpu_int_event = PCIE_CPU_INT_EVENT,
+ .reg_ip_rev = PCIE_IP_REV_REG,
+ .reg_drv_ready = REG_DRV_READY,
+ .reg_cpu_int_status = PCIE_CPU_INT_STATUS,
+ .reg_scratch_0 = PCIE_SCRATCH_0_REG,
+ .reg_scratch_1 = PCIE_SCRATCH_1_REG,
+ .reg_scratch_2 = PCIE_SCRATCH_2_REG,
+ .reg_scratch_3 = PCIE_SCRATCH_3_REG,
+ .host_intr_mask = HOST_INTR_MASK,
+ .host_intr_dnld_done = HOST_INTR_DNLD_DONE,
+ .host_intr_upld_rdy = HOST_INTR_UPLD_RDY,
+ .host_intr_cmd_done = HOST_INTR_CMD_DONE,
+ .host_intr_event_rdy = HOST_INTR_EVENT_RDY,
+ .txrx_rw_ptr_mask = 0x000003FF,
+ .txrx_rw_ptr_wrap_mask = 0x000007FF,
+ .txrx_rw_ptr_rollover_ind = MBIT(10),
+ .use_adma = MFALSE,
+ .msi_int_wr_clr = MTRUE,
+};
+
+static const struct _mlan_card_info mlan_card_info_pcie8897 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 0,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef PCIE8997
+static const struct _mlan_pcie_card_reg mlan_reg_pcie8997 = {
+ .reg_txbd_rdptr = PCIE8997_RD_DATA_PTR_Q0_Q1,
+ .reg_txbd_wrptr = PCIE8997_WR_DATA_PTR_Q0_Q1,
+ .reg_rxbd_rdptr = PCIE8997_RD_DATA_PTR_Q0_Q1,
+ .reg_rxbd_wrptr = PCIE8997_WR_DATA_PTR_Q0_Q1,
+ .reg_evtbd_rdptr = REG_EVTBD_RDPTR,
+ .reg_evtbd_wrptr = REG_EVTBD_WRPTR,
+ .reg_host_int_mask = PCIE_HOST_INT_MASK,
+ .reg_host_int_status_mask = PCIE_HOST_INT_STATUS_MASK,
+ .reg_host_int_status = PCIE_HOST_INT_STATUS,
+ .reg_cpu_int_event = PCIE_CPU_INT_EVENT,
+ .reg_ip_rev = PCIE_IP_REV_REG,
+ .reg_drv_ready = REG_DRV_READY,
+ .reg_cpu_int_status = PCIE_CPU_INT_STATUS,
+ .reg_scratch_0 = PCIE_SCRATCH_0_REG,
+ .reg_scratch_1 = PCIE_SCRATCH_1_REG,
+ .reg_scratch_2 = PCIE_SCRATCH_2_REG,
+ .reg_scratch_3 = PCIE_SCRATCH_3_REG,
+ .host_intr_mask = HOST_INTR_MASK,
+ .host_intr_dnld_done = HOST_INTR_DNLD_DONE,
+ .host_intr_upld_rdy = HOST_INTR_UPLD_RDY,
+ .host_intr_cmd_done = HOST_INTR_CMD_DONE,
+ .host_intr_event_rdy = HOST_INTR_EVENT_RDY,
+ .txrx_rw_ptr_mask = 0x00000FFF,
+ .txrx_rw_ptr_wrap_mask = 0x00001FFF,
+ .txrx_rw_ptr_rollover_ind = MBIT(12),
+ .use_adma = MFALSE,
+ .msi_int_wr_clr = MTRUE,
+};
+
+static const struct _mlan_card_info mlan_card_info_pcie8997 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+static const struct _mlan_pcie_card_reg mlan_reg_pcie9098 = {
+ .reg_txbd_rdptr = PCIE9098_TXBD_RDPTR,
+ .reg_txbd_wrptr = PCIE9098_TXBD_WRPTR,
+ .reg_rxbd_rdptr = PCIE9098_RXBD_RDPTR,
+ .reg_rxbd_wrptr = PCIE9098_RXBD_WRPTR,
+ .reg_evtbd_rdptr = PCIE9098_EVTBD_RDPTR,
+ .reg_evtbd_wrptr = PCIE9098_EVTBD_WRPTR,
+ .reg_host_int_mask = PCIE9098_HOST_INT_MASK,
+ .reg_host_int_status_mask = PCIE9098_HOST_INT_STATUS_MASK,
+ .reg_host_int_status = PCIE9098_HOST_INT_STATUS,
+ .reg_host_int_clr_sel = PCIE9098_HOST_INT_CLR_SEL,
+ .reg_cpu_int_event = PCIE9098_CPU_INT_EVENT,
+ .reg_ip_rev = PCIE9098_DEV_ID_REG,
+ .reg_drv_ready = PCIE9098_DRV_READY,
+ .reg_cpu_int_status = PCIE9098_CPU_INT_STATUS,
+ .reg_rev_id = PCIE9098_REV_ID_REG,
+ .reg_scratch_0 = PCIE9098_SCRATCH_0_REG,
+ .reg_scratch_1 = PCIE9098_SCRATCH_1_REG,
+ .reg_scratch_2 = PCIE9098_SCRATCH_2_REG,
+ .reg_scratch_3 = PCIE9098_SCRATCH_3_REG,
+ .reg_scratch_6 = PCIE9098_SCRATCH_6_REG,
+ .reg_scratch_7 = PCIE9098_SCRATCH_7_REG,
+ .host_intr_mask = PCIE9098_HOST_INTR_MASK,
+ .host_intr_dnld_done = PCIE9098_HOST_INTR_DNLD_DONE,
+ .host_intr_upld_rdy = PCIE9098_HOST_INTR_UPLD_RDY,
+ .host_intr_cmd_done = PCIE9098_HOST_INTR_CMD_DONE,
+ .host_intr_event_rdy = PCIE9098_HOST_INTR_EVENT_RDY,
+ .host_intr_cmd_dnld = PCIE9098_HOST_INTR_CMD_DNLD,
+ .use_adma = MTRUE,
+ .msi_int_wr_clr = MTRUE,
+};
+
+static const struct _mlan_card_info mlan_card_info_pcie9098 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef PCIE9097
+static const struct _mlan_pcie_card_reg mlan_reg_pcie9097_b0 = {
+ .reg_txbd_rdptr = PCIE9098_TXBD_RDPTR,
+ .reg_txbd_wrptr = PCIE9098_TXBD_WRPTR,
+ .reg_rxbd_rdptr = PCIE9098_RXBD_RDPTR,
+ .reg_rxbd_wrptr = PCIE9098_RXBD_WRPTR,
+ .reg_evtbd_rdptr = PCIE9098_EVTBD_RDPTR,
+ .reg_evtbd_wrptr = PCIE9098_EVTBD_WRPTR,
+ .reg_host_int_mask = PCIE9097_B0_HOST_INT_MASK,
+ .reg_host_int_status_mask = PCIE9097_B0_HOST_INT_STATUS_MASK,
+ .reg_host_int_status = PCIE9097_B0_HOST_INT_STATUS,
+ .reg_host_int_clr_sel = PCIE9097_B0_HOST_INT_CLR_SEL,
+ .reg_cpu_int_event = PCIE9098_CPU_INT_EVENT,
+ .reg_ip_rev = PCIE9098_DEV_ID_REG,
+ .reg_drv_ready = PCIE9098_DRV_READY,
+ .reg_cpu_int_status = PCIE9098_CPU_INT_STATUS,
+ .reg_rev_id = PCIE9098_REV_ID_REG,
+ .reg_scratch_0 = PCIE9098_SCRATCH_0_REG,
+ .reg_scratch_1 = PCIE9098_SCRATCH_1_REG,
+ .reg_scratch_2 = PCIE9098_SCRATCH_2_REG,
+ .reg_scratch_3 = PCIE9098_SCRATCH_3_REG,
+ .reg_scratch_6 = PCIE9098_SCRATCH_6_REG,
+ .reg_scratch_7 = PCIE9098_SCRATCH_7_REG,
+ .host_intr_mask = PCIE9098_HOST_INTR_MASK,
+ .host_intr_dnld_done = PCIE9098_HOST_INTR_DNLD_DONE,
+ .host_intr_upld_rdy = PCIE9098_HOST_INTR_UPLD_RDY,
+ .host_intr_cmd_done = PCIE9098_HOST_INTR_CMD_DONE,
+ .host_intr_event_rdy = PCIE9098_HOST_INTR_EVENT_RDY,
+ .host_intr_cmd_dnld = PCIE9098_HOST_INTR_CMD_DNLD,
+ .use_adma = MTRUE,
+ .msi_int_wr_clr = MTRUE,
+};
+#endif
+/* Get pcie device from card type */
+mlan_status wlan_get_pcie_device(pmlan_adapter pmadapter);
+
+/** Set PCIE host buffer configurations */
+mlan_status wlan_set_pcie_buf_config(mlan_private *pmpriv);
+
+/** Init write pointer */
+mlan_status wlan_pcie_init_fw(pmlan_adapter pmadapter);
+
+#if defined(PCIE8997) || defined(PCIE8897)
+/** Prepare command PCIE host buffer config */
+mlan_status wlan_cmd_pcie_host_buf_cfg(pmlan_private pmpriv,
+ pHostCmd_DS_COMMAND cmd,
+ t_u16 cmd_action, t_pvoid pdata_buf);
+#endif
+
+/** Wakeup PCIE card */
+mlan_status wlan_pcie_wakeup(pmlan_adapter pmadapter);
+
+/** Set DRV_READY register */
+mlan_status wlan_set_drv_ready_reg(mlan_adapter *pmadapter, t_u32 val);
+/** PCIE init */
+mlan_status wlan_pcie_init(mlan_adapter *pmadapter);
+
+/** Read interrupt status */
+mlan_status wlan_process_msix_int(mlan_adapter *pmadapter);
+/** Transfer data to card */
+mlan_status wlan_pcie_host_to_card(pmlan_private pmpriv, t_u8 type,
+ mlan_buffer *mbuf, mlan_tx_param *tx_param);
+/** Ring buffer allocation function */
+mlan_status wlan_alloc_pcie_ring_buf(pmlan_adapter pmadapter);
+/** Ring buffer deallocation function */
+mlan_status wlan_free_pcie_ring_buf(pmlan_adapter pmadapter);
+/** Ring buffer cleanup function, e.g. on deauth */
+mlan_status wlan_clean_pcie_ring_buf(pmlan_adapter pmadapter);
+mlan_status wlan_alloc_ssu_pcie_buf(pmlan_adapter pmadapter);
+mlan_status wlan_free_ssu_pcie_buf(pmlan_adapter pmadapter);
+
+#endif /* _MLAN_PCIE_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_scan.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_scan.c
new file mode 100644
index 000000000000..09484b1a7ece
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_scan.c
@@ -0,0 +1,6468 @@
+/** @file mlan_scan.c
+ *
+ * @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preparation and response routines
+ * for sending scan commands to the firmware.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#ifdef DRV_EMBEDDED_SUPPLICANT
+#include "authenticator_api.h"
+#endif
+/********************************************************
+ Local Constants
+********************************************************/
+/** minimum scan time for passive to active scan */
+#define MIN_PASSIVE_TO_ACTIVE_SCAN_TIME 150
+
+#define MRVDRV_MAX_CHANNELS_PER_SCAN 40
+/** The maximum number of channels the firmware can scan per command */
+#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN 4
+
+/**
+ * Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+/** Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE \
+ (sizeof(MrvlIEtypesHeader_t) + \
+ (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN * sizeof(ChanScanParamSet_t)))
+
+/** Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE \
+ (sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
+
+/** Memory needed to store a max number/size WildCard
+ * SSID TLV for a firmware scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE \
+ (MRVDRV_MAX_SSID_LIST_LENGTH * \
+ (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + \
+ MRVDRV_MAX_SSID_LENGTH))
+
+/** Memory needed to store a max number/size BSSID TLV for a firmware scan */
+#define BSSID_LIST_TLV_MAX_SIZE \
+ (sizeof(MrvlIEtypesHeader_t) + \
+ (MRVDRV_MAX_BSSID_LIST * MLAN_MAC_ADDR_LENGTH))
+
+/** WPS TLV MAX size is MAX IE size plus 2 bytes for
+ * t_u16 MRVL TLV extension */
+#define WPS_TLV_MAX_SIZE (sizeof(IEEEtypes_VendorSpecific_t) + 2)
+/** Maximum memory needed for a wlan_scan_cmd_config
+ * with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC \
+ (sizeof(wlan_scan_cmd_config) + sizeof(MrvlIEtypes_NumProbes_t) + \
+ sizeof(MrvlIETypes_HTCap_t) + CHAN_TLV_MAX_SIZE + RATE_TLV_MAX_SIZE + \
+ WILDCARD_SSID_TLV_MAX_SIZE + BSSID_LIST_TLV_MAX_SIZE + \
+ WPS_TLV_MAX_SIZE)
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/**
+ * Interally used to send a configured scan cmd between
+ * driver routines
+ */
+typedef union {
+ /** Scan configuration (variable length) */
+ wlan_scan_cmd_config config;
+ /** Max allocated block */
+ t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+} wlan_scan_cmd_config_tlv;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/** Cipher suite definition */
+enum cipher_suite {
+ CIPHER_SUITE_WEP40,
+ CIPHER_SUITE_TKIP,
+ CIPHER_SUITE_CCMP,
+ CIPHER_SUITE_WEP104,
+ CIPHER_SUITE_GCMP,
+ CIPHER_SUITE_GCMP_256,
+ CIPHER_SUITE_CCMP_256,
+ CIPHER_SUITE_MAX
+};
+
+static t_u8 wpa_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x50, 0xf2, 0x01}, /* WEP40 */
+ {0x00, 0x50, 0xf2, 0x02}, /* TKIP */
+ {0x00, 0x50, 0xf2, 0x04}, /* AES */
+ {0x00, 0x50, 0xf2, 0x05}, /* WEP104 */
+};
+
+static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
+ {0x00, 0x0f, 0xac, 0x01}, /* WEP40 */
+ {0x00, 0x0f, 0xac, 0x02}, /* TKIP */
+ {0x00, 0x0f, 0xac, 0x04}, /* AES */
+ {0x00, 0x0f, 0xac, 0x05}, /* WEP104 */
+ {0x00, 0x0f, 0xac, 0x08}, /* GCMP */
+ {0x00, 0x0f, 0xac, 0x09}, /* GCMP-256 */
+ {0x00, 0x0f, 0xac, 0x0a}, /* CCMP-256 */
+};
+
+/**
+ * @brief Convert radio type scan parameter to a band config used in join cmd
+ *
+ * @param radio_type Scan parameter indicating the radio used for a channel
+ * in a scan command.
+ *
+ * @return Band type conversion of scanBand used in join/assoc cmds
+ *
+ */
+t_u8 radio_type_to_band(t_u8 radio_type)
+{
+ t_u8 ret_band;
+
+ switch (radio_type) {
+ case BAND_5GHZ:
+ ret_band = BAND_A;
+ break;
+ case BAND_2GHZ:
+ default:
+ ret_band = BAND_G;
+ break;
+ }
+
+ return ret_band;
+}
+
+/**
+ * @brief This function will update the channel statistics from scan result
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pchanstats_tlv A pointer to MrvlIEtypes_ChannelStats_t tlv
+ *
+ * @return NA
+ */
+void wlan_update_chan_statistics(mlan_private *pmpriv,
+ MrvlIEtypes_ChannelStats_t *pchanstats_tlv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 i;
+ chan_statistics_t *pchan_stats =
+ (chan_statistics_t *)((t_u8 *)pchanstats_tlv +
+ sizeof(MrvlIEtypesHeader_t));
+ t_u8 num_chan = wlan_le16_to_cpu(pchanstats_tlv->header.len) /
+ sizeof(chan_statistics_t);
+
+ ENTER();
+
+ for (i = 0; i < num_chan; i++) {
+ if (pmadapter->idx_chan_stats >= pmadapter->num_in_chan_stats) {
+ PRINTM(MERROR,
+ "Over flow: idx_chan_stats=%d, num_in_chan_stats=%d\n",
+ pmadapter->idx_chan_stats,
+ pmadapter->num_in_chan_stats);
+ break;
+ }
+ pchan_stats->total_networks =
+ wlan_le16_to_cpu(pchan_stats->total_networks);
+ pchan_stats->cca_scan_duration =
+ wlan_le16_to_cpu(pchan_stats->cca_scan_duration);
+ pchan_stats->cca_busy_duration =
+ wlan_le16_to_cpu(pchan_stats->cca_busy_duration);
+ PRINTM(MCMND,
+ "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+ pchan_stats->chan_num, pchan_stats->noise,
+ pchan_stats->total_networks,
+ pchan_stats->cca_scan_duration,
+ pchan_stats->cca_busy_duration);
+ memcpy_ext(pmadapter,
+ (chan_statistics_t *)&pmadapter
+ ->pchan_stats[pmadapter->idx_chan_stats],
+ pchan_stats, sizeof(chan_statistics_t),
+ sizeof(chan_statistics_t));
+ pmadapter->idx_chan_stats++;
+ pchan_stats++;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will parse a given IE for a given OUI
+ *
+ * Parse a given WPA/RSN IE to find if it has a given oui in PTK,
+ * if no OUI found for PTK it returns 0.
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find OUI, 1 on success.
+ */
+static t_u8 search_oui_in_ie(mlan_adapter *pmadapter, IEBody *ie_body,
+ t_u8 *oui)
+{
+ t_u8 count;
+
+ count = ie_body->PtkCnt[0];
+
+ ENTER();
+ /* There could be multiple OUIs for PTK hence
+ * 1) Take the length.
+ * 2) Check all the OUIs for AES.
+ * 3) If one of them is AES then pass success.
+ */
+ while (count) {
+ if (!memcmp(pmadapter, ie_body->PtkBody, oui,
+ sizeof(ie_body->PtkBody))) {
+ LEAVE();
+ return MLAN_OUI_PRESENT;
+ }
+
+ --count;
+ if (count) {
+ ie_body = (IEBody *)((t_u8 *)ie_body +
+ sizeof(ie_body->PtkBody));
+ }
+ }
+
+ PRINTM(MINFO, "The OUI %x:%x:%x:%x is not found in PTK\n", oui[0],
+ oui[1], oui[2], oui[3]);
+ LEAVE();
+ return MLAN_OUI_NOT_PRESENT;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if RSN IE has AES
+ * OUI in it. If RSN IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8 is_rsn_oui_present(mlan_adapter *pmadapter,
+ BSSDescriptor_t *pbss_desc, t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (pbss_desc->prsn_ie &&
+ (pbss_desc->prsn_ie->ieee_hdr.element_id == RSN_IE) &&
+ (pbss_desc->prsn_ie->ieee_hdr.len > RSN_GTK_OUI_OFFSET)) {
+ ie_body = (IEBody *)(((t_u8 *)pbss_desc->prsn_ie->data) +
+ RSN_GTK_OUI_OFFSET);
+ oui = &rsn_oui[cipher_suite][0];
+ ret = search_oui_in_ie(pmadapter, ie_body, oui);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the wpa_ie for appropriate IE and then check if RSN IE has AES
+ * OUI in it. If RSN IE does not have AES in PTK then return 0;
+ *
+ * @param pmadapter A pointer to mlan adapter.
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8 is_rsn_oui_present_in_wpa_ie(mlan_private *pmpriv,
+ t_u32 cipher_suite)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ IEEEtypes_Generic_t *prsn_ie = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ prsn_ie = (IEEEtypes_Generic_t *)pmpriv->wpa_ie;
+
+ if (prsn_ie && (prsn_ie->ieee_hdr.element_id == RSN_IE) &&
+ (prsn_ie->ieee_hdr.len > RSN_GTK_OUI_OFFSET)) {
+ ie_body = (IEBody *)(prsn_ie->data + RSN_GTK_OUI_OFFSET);
+ oui = &rsn_oui[cipher_suite][0];
+ ret = search_oui_in_ie(pmadapter, ie_body, oui);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will pass the correct ie and oui to search_oui_in_ie
+ *
+ * Check the pbss_desc for appropriate IE and then check if WPA IE has AES
+ * OUI in it. If WPA IE does not have AES in PTK then return 0;
+ *
+ * @param pbss_desc A pointer to current BSS descriptor
+ * @return 0 on failure to find AES OUI, 1 on success.
+ */
+static t_u8 is_wpa_oui_present(mlan_adapter *pmadapter,
+ BSSDescriptor_t *pbss_desc, t_u32 cipher_suite)
+{
+ t_u8 *oui = MNULL;
+ IEBody *ie_body = MNULL;
+ t_u8 ret = MLAN_OUI_NOT_PRESENT;
+
+ ENTER();
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))) {
+ ie_body = (IEBody *)pbss_desc->pwpa_ie->data;
+ oui = &wpa_oui[cipher_suite][0];
+ ret = search_oui_in_ie(pmadapter, ie_body, oui);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief compare config band and a band from the scan result,
+ * which is defined by functiion radio_type_to_band(t_u8 radio_type) above
+ *
+ * @param cfg_band: band configured
+ * scan_band: band from scan result
+ *
+ * @return matched: non-zero. unmatched: 0
+ *
+ */
+static t_u8 wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band)
+{
+ t_u8 band;
+ switch (scan_band) {
+ case BAND_A:
+ band = BAND_A | BAND_AN | BAND_AAC;
+ break;
+ case BAND_G:
+ default:
+ band = BAND_B | BAND_G | BAND_GN | BAND_GAC;
+ }
+ return cfg_band & band;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @return index in BSSID list
+ */
+static t_s32 wlan_find_best_network_in_list(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 mode = pmpriv->bss_mode;
+ t_s32 best_net = -1;
+ t_s32 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(
+ pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(
+ pmadapter->pscan_table[i].rssi);
+ best_net = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return best_net;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan configuration parameters
+ * @param pscan_chan_list Output parameter: Resulting channel list to scan
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID
+ * filter is being sent in the command to firmware. Used to increase the number
+ * of channels sent in a scan command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return N/A
+ */
+static t_void wlan_scan_create_channel_list(
+ mlan_private *pmpriv, const wlan_user_scan_cfg *puser_scan_in,
+ ChanScanParamSet_t *pscan_chan_list, t_u8 filtered_scan)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+ t_u8 band;
+ t_u16 scan_dur = 0;
+
+ ENTER();
+
+ for (region_idx = 0; region_idx < NELEMENTS(pmadapter->region_channel);
+ region_idx++) {
+ if (wlan_11d_is_enabled(pmpriv) &&
+ pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region =
+ &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (puser_scan_in && !puser_scan_in->chan_list[0].chan_number &&
+ puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type = puser_scan_in->chan_list[0].radio_type &
+ ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if ((puser_scan_in &&
+ (puser_scan_in->bss_mode == MLAN_SCAN_MODE_IBSS)) ||
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ band = pmadapter->adhoc_start_band;
+ else
+ band = pmpriv->config_bands;
+ if (!wlan_is_band_compatible(band, pscan_region->band))
+ continue;
+ for (next_chan = 0; next_chan < pscan_region->num_cfp;
+ next_chan++) {
+ /* Set the default scan type to the user specified type,
+ * will later be changed to passive on a per channel
+ * basis if restricted by regulatory requirements (11d
+ * or 11h)
+ */
+ scan_type = pmadapter->scan_type;
+ cfp = pscan_region->pcfp + next_chan;
+ if (cfp->dynamic.flags & NXP_CHANNEL_DISABLED)
+ continue;
+
+ if (wlan_is_chan_passive(pmpriv, pscan_region->band,
+ (t_u8)cfp->channel)) {
+ /* do not send probe requests on this channel */
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ switch (pscan_region->band) {
+ case BAND_A:
+ pscan_chan_list[chan_idx].bandcfg.chanBand =
+ BAND_5GHZ;
+ /* Passive scan on DFS channels */
+ if (wlan_11h_radar_detect_required(
+ pmpriv, (t_u8)cfp->channel) &&
+ scan_type != MLAN_SCAN_TYPE_PASSIVE)
+ scan_type =
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
+ break;
+ case BAND_B:
+ case BAND_G:
+ if (wlan_bg_scan_type_is_passive(
+ pmpriv, (t_u8)cfp->channel)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ pscan_chan_list[chan_idx].bandcfg.chanBand =
+ BAND_2GHZ;
+ break;
+ default:
+ pscan_chan_list[chan_idx].bandcfg.chanBand =
+ BAND_2GHZ;
+ break;
+ }
+
+ if (puser_scan_in &&
+ puser_scan_in->chan_list[0].scan_time) {
+ scan_dur = (t_u16)puser_scan_in->chan_list[0]
+ .scan_time;
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
+ scan_type ==
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else if (filtered_scan) {
+ scan_dur = pmadapter->specific_scan_time;
+ } else {
+ scan_dur = pmadapter->active_scan_time;
+ }
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE &&
+ pmadapter->passive_to_active_scan ==
+ MLAN_PASS_TO_ACT_SCAN_EN) {
+ scan_dur = MAX(scan_dur,
+ MIN_PASSIVE_TO_ACTIVE_SCAN_TIME);
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.passive_to_active_scan =
+ MTRUE;
+ }
+ pscan_chan_list[chan_idx].max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
+ scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.passive_scan = MTRUE;
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.hidden_ssid_report =
+ MTRUE;
+ } else {
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ pscan_chan_list[chan_idx].chan_number =
+ (t_u8)cfp->channel;
+ PRINTM(MINFO,
+ "chan=%d, mode=%d, passive_to_active=%d\n",
+ pscan_chan_list[chan_idx].chan_number,
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.passive_scan,
+ pscan_chan_list[chan_idx]
+ .chan_scan_mode.passive_to_active_scan);
+ chan_idx++;
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Add WPS IE to probe request frame
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pptlv_out A pointer to TLV to fill in
+ *
+ * @return N/A
+ */
+static void wlan_add_wps_probe_request_ie(mlan_private *pmpriv,
+ t_u8 **pptlv_out)
+{
+ MrvlIEtypesHeader_t *tlv;
+
+ ENTER();
+
+ if (pmpriv->wps.wps_ie.vend_hdr.len) {
+ tlv = (MrvlIEtypesHeader_t *)*pptlv_out;
+ tlv->type = wlan_cpu_to_le16(VENDOR_SPECIFIC_221);
+ tlv->len = wlan_cpu_to_le16(pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += sizeof(MrvlIEtypesHeader_t);
+ memcpy_ext(pmpriv->adapter, *pptlv_out,
+ pmpriv->wps.wps_ie.vend_hdr.oui,
+ pmpriv->wps.wps_ie.vend_hdr.len,
+ pmpriv->wps.wps_ie.vend_hdr.len);
+ *pptlv_out += (pmpriv->wps.wps_ie.vend_hdr.len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into max_chan_per_scan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param max_chan_per_scan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filtered_scan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscan_cfg_out Scan configuration used for this scan.
+ * @param pchan_tlv_out Pointer in the pscan_cfg_out where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscan_chan_list List of channels to scan in max_chan_per_scan
+ * segments
+ *
+ * @return MLAN_STATUS_SUCCESS or error return otherwise
+ */
+static mlan_status
+wlan_scan_channel_list(mlan_private *pmpriv, t_void *pioctl_buf,
+ t_u32 max_chan_per_scan, t_u8 filtered_scan,
+ wlan_scan_cmd_config *pscan_cfg_out,
+ MrvlIEtypes_ChanListParamSet_t *pchan_tlv_out,
+ ChanScanParamSet_t *pscan_chan_list)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ChanScanParamSet_t *ptmp_chan_list;
+ ChanScanParamSet_t *pstart_chan;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+ t_u8 *pchan_tlv_out_temp = MNULL;
+ t_u8 *ptlv_temp = MNULL;
+ t_bool foundJPch14 = MFALSE;
+ t_u16 tlv_buf_len = 0;
+ t_u32 tlv_idx;
+ t_u32 total_scan_time;
+ t_u32 done_early;
+ t_u32 cmd_no;
+ t_u32 first_chan = 1;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+
+ ENTER();
+
+ if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
+ PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n", pscan_cfg_out,
+ pchan_tlv_out, pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!pscan_chan_list->chan_number) {
+ PRINTM(MERROR, "Scan: No channel configured\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* check expiry before preparing scan list - may affect blacklist */
+ wlan_11h_get_csa_closed_channel(pmpriv);
+
+ pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list
+ */
+ ptmp_chan_list = pscan_chan_list;
+
+ /*
+ * Loop through the desired channel list, sending a new firmware scan
+ * commands for each max_chan_per_scan channels (or for 1,6,11
+ * individually if configured accordingly)
+ */
+ while (ptmp_chan_list->chan_number) {
+ tlv_idx = 0;
+ total_scan_time = 0;
+ pchan_tlv_out->header.len = 0;
+ pstart_chan = ptmp_chan_list;
+ done_early = MFALSE;
+
+ /*
+ * Construct the Channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlv_idx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired
+ * channel list)
+ * - done_early is set (controlling individual
+ * scanning of 1,6,11)
+ */
+ while (tlv_idx < max_chan_per_scan &&
+ ptmp_chan_list->chan_number && !done_early) {
+ if (wlan_is_chan_blacklisted(
+ pmpriv,
+ radio_type_to_band(
+ ptmp_chan_list->bandcfg.chanBand),
+ ptmp_chan_list->chan_number) ||
+ wlan_is_chan_disabled(
+ pmpriv,
+ radio_type_to_band(
+ ptmp_chan_list->bandcfg.chanBand),
+ ptmp_chan_list->chan_number)) {
+ ptmp_chan_list++;
+ continue;
+ }
+
+ if (first_chan) {
+ ptmp_chan_list->chan_scan_mode.first_chan =
+ MTRUE;
+ first_chan = 0;
+ }
+
+ PRINTM(MINFO,
+ "Scan: Chan(%3d), bandcfg(%x), Mode(%d,%d), Dur(%d)\n",
+ ptmp_chan_list->chan_number,
+ ptmp_chan_list->bandcfg,
+ ptmp_chan_list->chan_scan_mode.passive_scan,
+ ptmp_chan_list->chan_scan_mode.disable_chan_filt,
+ wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
+
+ if (foundJPch14 == MTRUE) {
+ foundJPch14 = MFALSE;
+ /* Restore the TLV buffer */
+ pchan_tlv_out =
+ (MrvlIEtypes_ChanListParamSet_t *)
+ pchan_tlv_out_temp;
+ pchan_tlv_out->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ pchan_tlv_out->header.len = 0;
+ if (ptlv_temp) {
+ memcpy_ext(pmadapter,
+ pscan_cfg_out->tlv_buf,
+ ptlv_temp, tlv_buf_len,
+ tlv_buf_len);
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ ptlv_temp);
+ ptlv_temp = MNULL;
+ }
+ }
+
+ /* Special Case: For Japan, Scan on CH14 for 11G rates
+ is not allowed
+ Hence Rates TLV needs to be updated to support only
+ 11B rates */
+ if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
+ pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (ptmp_chan_list->chan_number == 14) &&
+ (pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)) {
+ t_u8 *ptlv_pos = pscan_cfg_out->tlv_buf;
+ t_u16 old_ratetlv_len, new_ratetlv_len;
+ MrvlIEtypesHeader_t *header;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+
+ /* Preserve the current TLV buffer */
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ MAX_SCAN_CFG_ALLOC - CHAN_TLV_MAX_SIZE,
+ MLAN_MEM_DEF, (t_u8 **)&ptlv_temp);
+ if (ret != MLAN_STATUS_SUCCESS || !ptlv_temp) {
+ PRINTM(MERROR,
+ "Memory allocation for pscan_cfg_out failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code =
+ MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pchan_tlv_out_temp = (t_u8 *)pchan_tlv_out;
+ tlv_buf_len = (t_u32)(pchan_tlv_out_temp -
+ pscan_cfg_out->tlv_buf);
+ memcpy_ext(pmadapter, ptlv_temp, ptlv_pos,
+ tlv_buf_len,
+ MAX_SCAN_CFG_ALLOC -
+ CHAN_TLV_MAX_SIZE);
+
+ /* Search for Rates TLV */
+ while ((!foundJPch14) &&
+ (ptlv_pos < pchan_tlv_out_temp)) {
+ header =
+ (MrvlIEtypesHeader_t *)ptlv_pos;
+ if (header->type ==
+ wlan_cpu_to_le16(TLV_TYPE_RATES))
+ foundJPch14 = MTRUE;
+ else
+ ptlv_pos +=
+ (sizeof(MrvlIEtypesHeader_t) +
+ wlan_le16_to_cpu(
+ header->len));
+ }
+
+ if (foundJPch14) {
+ /* Update the TLV buffer with *new*
+ * Rates TLV and rearrange remaining TLV
+ * buffer*/
+ prates_tlv =
+ (MrvlIEtypes_RatesParamSet_t *)
+ ptlv_pos;
+ old_ratetlv_len =
+ sizeof(MrvlIEtypesHeader_t) +
+ wlan_le16_to_cpu(
+ prates_tlv->header.len);
+
+ prates_tlv->header.len = wlan_copy_rates(
+ prates_tlv->rates, 0,
+ SupportedRates_B,
+ sizeof(SupportedRates_B));
+ new_ratetlv_len =
+ sizeof(MrvlIEtypesHeader_t) +
+ prates_tlv->header.len;
+ prates_tlv->header.len =
+ wlan_cpu_to_le16(
+ prates_tlv->header.len);
+
+ memmove(pmadapter,
+ ptlv_pos + new_ratetlv_len,
+ ptlv_pos + old_ratetlv_len,
+ (t_u32)(pchan_tlv_out_temp -
+ (ptlv_pos +
+ old_ratetlv_len)));
+ pchan_tlv_out =
+ (MrvlIEtypes_ChanListParamSet_t
+ *)(pchan_tlv_out_temp -
+ (old_ratetlv_len -
+ new_ratetlv_len));
+ pchan_tlv_out->header.type =
+ wlan_cpu_to_le16(
+ TLV_TYPE_CHANLIST);
+ pchan_tlv_out->header.len = 0;
+ }
+ }
+
+ /* Copy the current channel TLV to the command being
+ * prepared */
+ memcpy_ext(pmadapter,
+ pchan_tlv_out->chan_scan_param + tlv_idx,
+ ptmp_chan_list,
+ sizeof(pchan_tlv_out->chan_scan_param),
+ sizeof(pchan_tlv_out->chan_scan_param));
+
+ /* Increment the TLV header length by the size appended
+ */
+ pchan_tlv_out->header.len +=
+ sizeof(pchan_tlv_out->chan_scan_param);
+
+ /*
+ * The tlv buffer length is set to the number of
+ * bytes of the between the channel tlv pointer
+ * and the start of the tlv buffer. This
+ * compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscan_cfg_out->tlv_buf_len = (t_u32)(
+ (t_u8 *)pchan_tlv_out - pscan_cfg_out->tlv_buf);
+
+ /* Add the size of the channel tlv header and the data
+ * length */
+ pscan_cfg_out->tlv_buf_len +=
+ (sizeof(pchan_tlv_out->header) +
+ pchan_tlv_out->header.len);
+
+ /* Increment the index to the channel tlv we are
+ * constructing */
+ tlv_idx++;
+
+ /* Count the total scan time per command */
+ total_scan_time +=
+ wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
+
+ done_early = MFALSE;
+
+ /*
+ * Stop the loop if the *current* channel is in the
+ * 1,6,11 set and we are not filtering on a BSSID or
+ * SSID.
+ */
+ if (!filtered_scan &&
+ (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+
+ /*
+ * Stop the loop if the *current* channel is 14
+ * and region code is Japan (0x40 or 0xFF)
+ */
+ if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
+ pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (ptmp_chan_list->chan_number == 14)) {
+ done_early = MTRUE;
+ }
+
+ /* Increment the tmp pointer to the next channel to be
+ * scanned */
+ ptmp_chan_list++;
+
+ /*
+ * Stop the loop if the *next* channel is in the 1,6,11
+ * set. This will cause it to be the only channel
+ * scanned on the next interation
+ */
+ if (!filtered_scan &&
+ (ptmp_chan_list->chan_number == 1 ||
+ ptmp_chan_list->chan_number == 6 ||
+ ptmp_chan_list->chan_number == 11)) {
+ done_early = MTRUE;
+ }
+
+ /*
+ * Stop the loop if the *next* channel is 14
+ * and region code is Japan (0x40 or 0xFF)
+ */
+ if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
+ pmadapter->region_code == COUNTRY_CODE_JP_FF) &&
+ (ptmp_chan_list->chan_number == 14)) {
+ done_early = MTRUE;
+ }
+ if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
+ done_early = MFALSE;
+ }
+
+ /* The total scan time should be less than scan command timeout
+ * value */
+ if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+ PRINTM(MMSG,
+ "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+ total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
+ if (pioctl_req)
+ pioctl_req->status_code =
+ MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ pchan_tlv_out->header.len =
+ wlan_cpu_to_le16(pchan_tlv_out->header.len);
+
+ pmadapter->pscan_channels = pstart_chan;
+
+ /* Send the scan command to the firmware with the specified cfg
+ */
+ if (pmadapter->ext_scan)
+ cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
+ else
+ cmd_no = HostCmd_CMD_802_11_SCAN;
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, HostCmd_ACT_GEN_SET, 0,
+ MNULL, pscan_cfg_out);
+ if (ret)
+ break;
+ }
+
+ LEAVE();
+
+ if (ptlv_temp)
+ pcb->moal_mfree(pmadapter->pmoal_handle, ptlv_temp);
+
+ if (ret)
+ return MLAN_STATUS_FAILURE;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in scan commands
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - Channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param puser_scan_in MNULL or pointer to scan config parameters
+ * @param pscan_cfg_out Output parameter: Resulting scan configuration
+ * @param ppchan_list_out Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscan_chan_list Output parameter: Pointer to the resulting
+ * channel list to scan
+ * @param pmax_chan_per_scan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfiltered_scan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscan_current_only Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_scan_setup_scan_config(
+ mlan_private *pmpriv, wlan_user_scan_cfg *puser_scan_in,
+ wlan_scan_cmd_config *pscan_cfg_out,
+ MrvlIEtypes_ChanListParamSet_t **ppchan_list_out,
+ ChanScanParamSet_t *pscan_chan_list, t_u8 *pmax_chan_per_scan,
+ t_u8 *pfiltered_scan, t_u8 *pscan_current_only)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
+ MrvlIEtypes_RatesParamSet_t *prates_tlv;
+ MrvlIEtypes_Bssid_List_t *pbssid_tlv;
+
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+ t_u8 *ptlv_pos;
+ t_u32 num_probes;
+ t_u32 ssid_len;
+ t_u32 chan_idx;
+ t_u32 chan_list_idx = 0;
+ t_u32 scan_type;
+ t_u16 scan_dur;
+ t_u8 channel;
+ t_u8 radio_type;
+ t_u32 ssid_idx;
+ t_u8 ssid_filter;
+ WLAN_802_11_RATES rates;
+ t_u32 rates_size;
+ MrvlIETypes_HTCap_t *pht_cap;
+
+ MrvlIETypes_VHTCap_t *pvht_cap;
+ MrvlIEtypes_ScanChanGap_t *pscan_gap_tlv;
+ MrvlIEtypes_BssMode_t *pbss_mode;
+ MrvlIEtypes_Extension_t *phe_cap;
+ t_u16 len = 0;
+
+ ENTER();
+
+ /* The tlv_buf_len is calculated for each scan command. The TLVs added
+ * in this routine will be preserved since the routine that sends
+ * the command will append channelTLVs at *ppchan_list_out. The
+ * difference between the *ppchan_list_out and the tlv_buf start will
+ * be used to calculate the size of anything we add in this routine.
+ */
+ pscan_cfg_out->tlv_buf_len = 0;
+
+ /* Running tlv pointer. Assigned to ppchan_list_out at end of function
+ * so later routines know where channels can be added to the command
+ * buf
+ */
+ ptlv_pos = pscan_cfg_out->tlv_buf;
+
+ /* Initialize the scan as un-filtered; the flag is later set to
+ * TRUE below if a SSID or BSSID filter is sent in the command
+ */
+ *pfiltered_scan = MFALSE;
+
+ /* Initialize the scan as not being only on the current channel. If
+ * the channel list is customized, only contains one channel, and
+ * is the active channel, this is set true and data flow is not
+ * halted.
+ */
+ *pscan_current_only = MFALSE;
+
+ if (puser_scan_in) {
+ ssid_filter = MFALSE;
+
+ /* Set the bss type scan filter, use Adapter setting if unset */
+ pscan_cfg_out->bss_mode =
+ (puser_scan_in->bss_mode ?
+ (t_u8)puser_scan_in->bss_mode :
+ (t_u8)pmadapter->scan_mode);
+
+ /* Set the number of probes to send, use Adapter setting if
+ * unset */
+ num_probes =
+ (puser_scan_in->num_probes ? puser_scan_in->num_probes :
+ pmadapter->scan_probes);
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled
+ * (all zeros).
+ */
+ memcpy_ext(pmadapter, pscan_cfg_out->specific_bssid,
+ puser_scan_in->specific_bssid,
+ sizeof(pscan_cfg_out->specific_bssid),
+ sizeof(pscan_cfg_out->specific_bssid));
+
+ if (pmadapter->ext_scan) {
+ if (puser_scan_in->bssid_num) {
+ pbssid_tlv =
+ (MrvlIEtypes_Bssid_List_t *)ptlv_pos;
+ pbssid_tlv->header.type = TLV_TYPE_BSSID;
+ pbssid_tlv->header.len = wlan_cpu_to_le16(
+ MLAN_MAC_ADDR_LENGTH *
+ puser_scan_in->bssid_num);
+ memcpy_ext(pmadapter, pbssid_tlv->bssid,
+ puser_scan_in->bssid_list,
+ MLAN_MAC_ADDR_LENGTH *
+ puser_scan_in->bssid_num,
+ MLAN_MAC_ADDR_LENGTH *
+ puser_scan_in->bssid_num);
+ ptlv_pos += sizeof(MrvlIEtypesHeader_t) +
+ MLAN_MAC_ADDR_LENGTH *
+ puser_scan_in->bssid_num;
+ DBG_HEXDUMP(
+ MCMD_D, "scan bssid filter", pbssid_tlv,
+ sizeof(MrvlIEtypesHeader_t) +
+ MLAN_MAC_ADDR_LENGTH *
+ puser_scan_in
+ ->bssid_num);
+ } else if (memcmp(pmadapter,
+ pscan_cfg_out->specific_bssid,
+ &zero_mac, sizeof(zero_mac))) {
+ pbssid_tlv =
+ (MrvlIEtypes_Bssid_List_t *)ptlv_pos;
+ pbssid_tlv->header.type = TLV_TYPE_BSSID;
+ pbssid_tlv->header.len =
+ wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmadapter, pbssid_tlv->bssid,
+ puser_scan_in->specific_bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ ptlv_pos += sizeof(MrvlIEtypes_Bssid_List_t);
+ }
+ }
+
+ for (ssid_idx = 0;
+ ((ssid_idx < NELEMENTS(puser_scan_in->ssid_list)) &&
+ (*puser_scan_in->ssid_list[ssid_idx].ssid ||
+ puser_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+ ssid_len = wlan_strlen(
+ (char *)puser_scan_in->ssid_list[ssid_idx].ssid);
+
+ pwildcard_ssid_tlv =
+ (MrvlIEtypes_WildCardSsIdParamSet_t *)ptlv_pos;
+ pwildcard_ssid_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len = (t_u16)(
+ ssid_len +
+ sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length =
+ puser_scan_in->ssid_list[ssid_idx].max_len;
+
+ memcpy_ext(pmadapter, pwildcard_ssid_tlv->ssid,
+ puser_scan_in->ssid_list[ssid_idx].ssid,
+ ssid_len, MLAN_MAX_SSID_LENGTH);
+
+ ptlv_pos += (sizeof(pwildcard_ssid_tlv->header) +
+ pwildcard_ssid_tlv->header.len);
+
+ pwildcard_ssid_tlv->header.len = wlan_cpu_to_le16(
+ pwildcard_ssid_tlv->header.len);
+
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
+ pwildcard_ssid_tlv->ssid,
+ pwildcard_ssid_tlv->max_ssid_length);
+
+ if (ssid_len) {
+ ssid_filter = MTRUE;
+ if (!puser_scan_in->ssid_list[ssid_idx].max_len) {
+ PRINTM(MCMND, "user scan: %s\n",
+ pwildcard_ssid_tlv->ssid);
+ puser_scan_in->ssid_filter = MTRUE;
+ }
+ }
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not
+ * truncate scan results. That is not an issue with an SSID or
+ * BSSID filter applied to the scan results in the firmware.
+ */
+ if ((ssid_idx && ssid_filter) ||
+ memcmp(pmadapter, pscan_cfg_out->specific_bssid, &zero_mac,
+ sizeof(zero_mac))) {
+ *pfiltered_scan = MTRUE;
+ }
+
+ } else {
+ pscan_cfg_out->bss_mode = (t_u8)pmadapter->scan_mode;
+ num_probes = pmadapter->scan_probes;
+ }
+
+ /*
+ * If a specific BSSID or SSID is used, the number of channels in
+ * the scan command will be increased to the absolute maximum.
+ */
+ if (*pfiltered_scan)
+ *pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ else
+ *pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ if (puser_scan_in) {
+ if (puser_scan_in->scan_chan_gap) {
+ *pmax_chan_per_scan =
+ MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ PRINTM(MCMND, "Scan: channel gap = 0x%x\n",
+ puser_scan_in->scan_chan_gap);
+ pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
+ pscan_gap_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
+ pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
+ pscan_gap_tlv->gap = wlan_cpu_to_le16(
+ (t_u16)puser_scan_in->scan_chan_gap);
+ ptlv_pos += sizeof(pscan_gap_tlv->header) +
+ pscan_gap_tlv->header.len;
+ pscan_gap_tlv->header.len =
+ wlan_cpu_to_le16(pscan_gap_tlv->header.len);
+ }
+ } else if (pmadapter->scan_chan_gap) {
+ *pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ PRINTM(MCMND, "Scan: channel gap = 0x%x\n",
+ pmadapter->scan_chan_gap);
+ pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
+ pscan_gap_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
+ pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
+ pscan_gap_tlv->gap =
+ wlan_cpu_to_le16((t_u16)pmadapter->scan_chan_gap);
+ ptlv_pos += sizeof(pscan_gap_tlv->header) +
+ pscan_gap_tlv->header.len;
+ }
+ if (pmadapter->ext_scan) {
+ pbss_mode = (MrvlIEtypes_BssMode_t *)ptlv_pos;
+ pbss_mode->header.type = wlan_cpu_to_le16(TLV_TYPE_BSS_MODE);
+ pbss_mode->header.len = sizeof(pbss_mode->bss_mode);
+ pbss_mode->bss_mode = pscan_cfg_out->bss_mode;
+ ptlv_pos += sizeof(pbss_mode->header) + pbss_mode->header.len;
+ pbss_mode->header.len = wlan_cpu_to_le16(pbss_mode->header.len);
+ if (pmadapter->ext_scan_enh) {
+ if (puser_scan_in) {
+ if (puser_scan_in->ext_scan_type ==
+ EXT_SCAN_ENHANCE)
+ pmadapter->ext_scan_type =
+ EXT_SCAN_ENHANCE;
+ else
+ pmadapter->ext_scan_type =
+ EXT_SCAN_DEFAULT;
+ } else if (pmadapter->ext_scan == EXT_SCAN_TYPE_ENH)
+ pmadapter->ext_scan_type = EXT_SCAN_ENHANCE;
+ else
+ pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
+ if (pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
+ *pmax_chan_per_scan =
+ MRVDRV_MAX_CHANNELS_PER_SCAN;
+ }
+ }
+ /* If the input config or adapter has the number of Probes set, add tlv
+ */
+ if (num_probes) {
+ PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
+
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)ptlv_pos;
+ pnum_probes_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len =
+ sizeof(pnum_probes_tlv->num_probes);
+ pnum_probes_tlv->num_probes =
+ wlan_cpu_to_le16((t_u16)num_probes);
+
+ ptlv_pos += sizeof(pnum_probes_tlv->header) +
+ pnum_probes_tlv->header.len;
+
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(pnum_probes_tlv->header.len);
+ }
+
+ /* Append rates tlv */
+ memset(pmadapter, rates, 0, sizeof(rates));
+
+ rates_size = wlan_get_supported_rates(
+ pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ?
+ pmpriv->config_bands :
+ pmadapter->adhoc_start_band,
+ rates);
+
+ prates_tlv = (MrvlIEtypes_RatesParamSet_t *)ptlv_pos;
+ prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ prates_tlv->header.len = wlan_cpu_to_le16((t_u16)rates_size);
+ memcpy_ext(pmadapter, prates_tlv->rates, rates, rates_size, rates_size);
+ ptlv_pos += sizeof(prates_tlv->header) + rates_size;
+
+ PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
+
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_GN ||
+ pmpriv->config_bands & BAND_AN)) {
+ pht_cap = (MrvlIETypes_HTCap_t *)ptlv_pos;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands,
+ MTRUE);
+ HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *)pht_cap,
+ sizeof(MrvlIETypes_HTCap_t));
+ ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+
+ if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_AAC)) {
+ pvht_cap = (MrvlIETypes_VHTCap_t *)ptlv_pos;
+ memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
+ pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
+ pvht_cap->header.len = sizeof(VHT_capa_t);
+ wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pmpriv->config_bands,
+ MFALSE, MFALSE);
+ HEXDUMP("SCAN: VHT_CAPABILITIES IE", (t_u8 *)pvht_cap,
+ sizeof(MrvlIETypes_VHTCap_t));
+ ptlv_pos += sizeof(MrvlIETypes_VHTCap_t);
+ pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
+ }
+
+ if (IS_FW_SUPPORT_11AX(pmadapter) &&
+ (pmpriv->config_bands & BAND_AAX)) {
+ phe_cap = (MrvlIEtypes_Extension_t *)ptlv_pos;
+ len = wlan_fill_he_cap_tlv(pmpriv, BAND_A, phe_cap, MFALSE);
+ HEXDUMP("SCAN: HE_CAPABILITIES IE", (t_u8 *)phe_cap, len);
+ ptlv_pos += len;
+ }
+
+ if (wlan_is_ext_capa_support(pmpriv))
+ wlan_add_ext_capa_info_ie(pmpriv, MNULL, &ptlv_pos);
+ if (pmpriv->adapter->ecsa_enable) {
+ t_u8 bandwidth = BW_20MHZ;
+ t_u8 oper_class = 1;
+ t_u32 usr_dot_11n_dev_cap;
+ if (pmpriv->media_connected) {
+ if (pmpriv->config_bands & BAND_A)
+ usr_dot_11n_dev_cap =
+ pmpriv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap =
+ pmpriv->usr_dot_11n_dev_cap_bg;
+ if (usr_dot_11n_dev_cap & MBIT(17)) {
+ bandwidth = BW_40MHZ;
+ if (ISSUPP_11ACENABLED(
+ pmadapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_AAC))
+ bandwidth = BW_80MHZ;
+ }
+ wlan_get_curr_oper_class(
+ pmpriv,
+ pmpriv->curr_bss_params.bss_descriptor.channel,
+ bandwidth, &oper_class);
+ }
+ wlan_add_supported_oper_class_ie(pmpriv, &ptlv_pos, oper_class);
+ }
+ wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
+
+ if (puser_scan_in && puser_scan_in->proberesp_only) {
+ MrvlIEtypes_OnlyProberesp_t *proberesp_only =
+ (MrvlIEtypes_OnlyProberesp_t *)ptlv_pos;
+ memset(pmadapter, proberesp_only, 0,
+ sizeof(MrvlIEtypes_OnlyProberesp_t));
+ proberesp_only->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_ONLYPROBERESP);
+ proberesp_only->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ proberesp_only->proberesp_only = puser_scan_in->proberesp_only;
+ ptlv_pos += sizeof(MrvlIEtypes_OnlyProberesp_t);
+ }
+
+ if (puser_scan_in && memcmp(pmadapter, puser_scan_in->random_mac,
+ zero_mac, MLAN_MAC_ADDR_LENGTH)) {
+ MrvlIEtypes_MacAddr_t *randomMacParam =
+ (MrvlIEtypes_MacAddr_t *)ptlv_pos;
+ memset(pmadapter, randomMacParam, 0,
+ sizeof(MrvlIEtypes_MacAddr_t));
+ randomMacParam->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_RANDOM_MAC);
+ randomMacParam->header.len =
+ wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmadapter, randomMacParam->mac,
+ puser_scan_in->random_mac, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ ptlv_pos += sizeof(MrvlIEtypes_MacAddr_t);
+ }
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this function (SSID, num_probes).
+ * Channel TLVs will be added past this for each scan command,
+ * preserving the TLVs that were previously added.
+ */
+ *ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *)ptlv_pos;
+
+ if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+
+ for (chan_idx = 0;
+ chan_idx < WLAN_USER_SCAN_CHAN_MAX &&
+ puser_scan_in->chan_list[chan_idx].chan_number;
+ chan_idx++) {
+ radio_type =
+ puser_scan_in->chan_list[chan_idx].radio_type;
+ /*Ignore 5G/2G channels if radio_type do not match
+ * band*/
+ if (!wlan_is_band_compatible(
+ pmpriv->config_bands,
+ radio_type_to_band(radio_type)))
+ continue;
+ (pscan_chan_list + chan_list_idx)->bandcfg.chanBand =
+ radio_type;
+
+ channel =
+ puser_scan_in->chan_list[chan_idx].chan_number;
+ (pscan_chan_list + chan_list_idx)->chan_number =
+ channel;
+
+ scan_type =
+ puser_scan_in->chan_list[chan_idx].scan_type;
+ if (scan_type == MLAN_SCAN_TYPE_UNCHANGED)
+ scan_type = pmadapter->scan_type;
+
+ if (radio_type == BAND_5GHZ) {
+ if (pmadapter->fw_bands & BAND_A)
+ PRINTM(MINFO,
+ "UserScan request for A Band channel %d!!\n",
+ channel);
+ else {
+ PRINTM(MERROR,
+ "Scan in A band is not allowed!!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ }
+
+ if (wlan_is_chan_passive(pmpriv, radio_type, channel)) {
+ /* do not send probe requests on this channel */
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ /* Prevent active scanning on a radar controlled channel
+ */
+ if (radio_type == BAND_5GHZ &&
+ scan_type != MLAN_SCAN_TYPE_PASSIVE) {
+ if (pmadapter->active_scan_triggered == MFALSE)
+ if (wlan_11h_radar_detect_required(
+ pmpriv, channel)) {
+ scan_type =
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
+ }
+ }
+ if (radio_type == BAND_2GHZ &&
+ scan_type != MLAN_SCAN_TYPE_PASSIVE) {
+ if (pmadapter->active_scan_triggered == MFALSE)
+ if (wlan_bg_scan_type_is_passive(
+ pmpriv, channel)) {
+ scan_type =
+ MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
+ scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.passive_scan = MTRUE;
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.hidden_ssid_report =
+ MTRUE;
+ } else {
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ if (puser_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (t_u16)puser_scan_in
+ ->chan_list[chan_idx]
+ .scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE ||
+ scan_type ==
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else if (*pfiltered_scan) {
+ scan_dur =
+ pmadapter->specific_scan_time;
+ } else {
+ scan_dur = pmadapter->active_scan_time;
+ }
+ }
+
+ if (pmadapter->coex_scan &&
+ pmadapter->coex_min_scan_time &&
+ (pmadapter->coex_min_scan_time > scan_dur))
+ scan_dur = pmadapter->coex_min_scan_time;
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE &&
+ pmadapter->passive_to_active_scan ==
+ MLAN_PASS_TO_ACT_SCAN_EN) {
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.passive_to_active_scan =
+ MTRUE;
+ scan_dur = MAX(MIN_PASSIVE_TO_ACTIVE_SCAN_TIME,
+ scan_dur);
+ }
+ PRINTM(MINFO,
+ "chan=%d, mode=%d, passive_to_active=%d\n",
+ (pscan_chan_list + chan_list_idx)->chan_number,
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.passive_scan,
+ (pscan_chan_list + chan_list_idx)
+ ->chan_scan_mode.passive_to_active_scan);
+
+ (pscan_chan_list + chan_list_idx)->min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ (pscan_chan_list + chan_list_idx)->max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ chan_list_idx++;
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chan_idx == 1) &&
+ (puser_scan_in->chan_list[0].chan_number ==
+ pmpriv->curr_bss_params.bss_descriptor.channel)) {
+ *pscan_current_only = MTRUE;
+ PRINTM(MINFO, "Scan: Scanning current channel only\n");
+ }
+
+ } else {
+ PRINTM(MINFO, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(pmpriv, puser_scan_in,
+ pscan_chan_list, *pfiltered_scan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlv_buf_size Size of the TLV buffer
+ * @param req_tlv_type Request TLV's type
+ * @param pptlv Output parameter: Pointer to the request TLV if
+ * found
+ *
+ * @return N/A
+ */
+static t_void wlan_ret_802_11_scan_get_tlv_ptrs(pmlan_adapter pmadapter,
+ MrvlIEtypes_Data_t *ptlv,
+ t_u32 tlv_buf_size,
+ t_u32 req_tlv_type,
+ MrvlIEtypes_Data_t **pptlv)
+{
+ MrvlIEtypes_Data_t *pcurrent_tlv;
+ t_u32 tlv_buf_left;
+ t_u32 tlv_type;
+ t_u32 tlv_len;
+
+ ENTER();
+
+ pcurrent_tlv = ptlv;
+ tlv_buf_left = tlv_buf_size;
+ *pptlv = MNULL;
+
+ PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
+
+ if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
+ PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
+ break;
+ }
+
+ if (req_tlv_type == tlv_type) {
+ switch (tlv_type) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ PRINTM(MINFO,
+ "SCAN_RESP: TSF Timestamp TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
+ break;
+ case TLV_TYPE_CHANNELBANDLIST:
+ PRINTM(MINFO,
+ "SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
+ break;
+ case TLV_TYPE_CHANNEL_STATS:
+ PRINTM(MINFO,
+ "SCAN_RESP: CHANNEL STATS TLV, len = %d\n",
+ tlv_len);
+ *pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
+ break;
+ default:
+ PRINTM(MERROR,
+ "SCAN_RESP: Unhandled TLV = %d\n",
+ tlv_type);
+ /* Give up, this seems corrupted */
+ LEAVE();
+ return;
+ }
+ }
+
+ if (*pptlv) {
+ /* HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4,
+ * tlv_len); */
+ break;
+ }
+
+ tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
+ pcurrent_tlv =
+ (MrvlIEtypes_Data_t *)(pcurrent_tlv->data + tlv_len);
+
+ } /* while */
+
+ LEAVE();
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table BSSDescriptor_t for that entry.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pbss_entry Output parameter: Pointer to the BSS Entry
+ * @param pbeacon_info Pointer to the Beacon information
+ * @param bytes_left Number of bytes left to parse
+ * @param ext_scan extended scan
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_interpret_bss_desc_with_ie(pmlan_adapter pmadapter,
+ BSSDescriptor_t *pbss_entry,
+ t_u8 **pbeacon_info,
+ t_u32 *bytes_left,
+ t_u8 ext_scan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_FhParamSet_t *pfh_param_set;
+ IEEEtypes_DsParamSet_t *pds_param_set;
+ IEEEtypes_CfParamSet_t *pcf_param_set;
+ IEEEtypes_IbssParamSet_t *pibss_param_set;
+ IEEEtypes_CapInfo_t *pcap_info;
+ WLAN_802_11_FIXED_IEs fixed_ie;
+ t_u8 *pcurrent_ptr;
+ t_u8 *prate;
+ t_u8 element_len;
+ t_u16 total_ie_len;
+ t_u8 bytes_to_copy;
+ t_u8 rate_size;
+ t_u16 beacon_size;
+ t_u8 found_data_rate_ie;
+ t_u32 bytes_left_for_current_beacon;
+ IEEEtypes_ERPInfo_t *perp_info;
+
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = {0x00, 0x50, 0xf2, 0x01};
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+ const t_u8 osen_oui[] = {0x50, 0x6f, 0x9a, 0x12};
+
+ IEEEtypes_CountryInfoSet_t *pcountry_info;
+ IEEEtypes_Extension_t *pext_tlv;
+
+ ENTER();
+
+ found_data_rate_ie = MFALSE;
+ rate_size = 0;
+ beacon_size = 0;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy_ext(pmadapter, &beacon_size, *pbeacon_info,
+ sizeof(beacon_size), sizeof(beacon_size));
+ beacon_size = wlan_le16_to_cpu(beacon_size);
+ *bytes_left -= sizeof(beacon_size);
+ *pbeacon_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+ *pbeacon_info += *bytes_left;
+ *bytes_left = 0;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration
+ */
+ pcurrent_ptr = *pbeacon_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeacon_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ bytes_left_for_current_beacon = beacon_size;
+
+ if (bytes_left_for_current_beacon <
+ (MLAN_MAC_ADDR_LENGTH + sizeof(t_u8) +
+ sizeof(WLAN_802_11_FIXED_IEs))) {
+ PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy_ext(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MINFO, "InterpretIE: AP MAC Addr-" MACSTR "\n",
+ MAC2STR(pbss_entry->mac_address));
+
+ pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
+ bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
+
+ /*
+ * Next 4 fields are RSSI (for legacy scan only), time stamp,
+ * beacon interval, and capability information
+ */
+ if (!ext_scan) {
+ /* RSSI is 1 byte long */
+ pbss_entry->rssi = (t_s32)(*pcurrent_ptr);
+ PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
+ pcurrent_ptr += 1;
+ bytes_left_for_current_beacon -= 1;
+ }
+
+ /*
+ * The RSSI is not part of the beacon/probe response. After we have
+ * advanced pcurrent_ptr past the RSSI field, save the remaining
+ * data for use at the application layer
+ */
+ pbss_entry->pbeacon_buf = pcurrent_ptr;
+ pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
+
+ /* Time stamp is 8 bytes long */
+ memcpy_ext(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8,
+ sizeof(fixed_ie.time_stamp));
+ memcpy_ext(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8,
+ sizeof(pbss_entry->time_stamp));
+ pcurrent_ptr += 8;
+ bytes_left_for_current_beacon -= 8;
+
+ /* Beacon interval is 2 bytes long */
+ memcpy_ext(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2,
+ sizeof(fixed_ie.beacon_interval));
+ pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Capability information is 2 bytes long */
+ memcpy_ext(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2,
+ sizeof(fixed_ie.capabilities));
+ PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
+ fixed_ie.capabilities);
+ fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
+ pcap_info = (IEEEtypes_CapInfo_t *)&fixed_ie.capabilities;
+ memcpy_ext(pmadapter, &pbss_entry->cap_info, pcap_info,
+ sizeof(IEEEtypes_CapInfo_t), sizeof(IEEEtypes_CapInfo_t));
+ pcurrent_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Rest of the current buffer are IE's */
+ PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
+ bytes_left_for_current_beacon);
+
+ HEXDUMP("InterpretIE: IE info", (t_u8 *)pcurrent_ptr,
+ bytes_left_for_current_beacon);
+
+ if (pcap_info->privacy) {
+ PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
+ pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
+ } else {
+ pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
+ }
+
+ if (pcap_info->ibss == 1)
+ pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
+ else
+ pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
+
+ if (pcap_info->spectrum_mgmt == 1) {
+ PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
+ "capability bit found\n");
+ pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
+ }
+
+ /* Process variable IE */
+ while (bytes_left_for_current_beacon >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+
+ if (bytes_left_for_current_beacon < total_ie_len) {
+ PRINTM(MERROR, "InterpretIE: Error in processing IE, "
+ "bytes left < IE length\n");
+ bytes_left_for_current_beacon = 0;
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+
+ switch (element_id) {
+ case SSID:
+ if (element_len > MRVDRV_MAX_SSID_LENGTH) {
+ bytes_left_for_current_beacon = 0;
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+ if (!pbss_entry->ssid.ssid_len) {
+ pbss_entry->ssid.ssid_len = element_len;
+ memcpy_ext(pmadapter, pbss_entry->ssid.ssid,
+ (pcurrent_ptr + 2), element_len,
+ sizeof(pbss_entry->ssid.ssid));
+ }
+ PRINTM(MINFO, "InterpretIE: ssid: %-32s\n",
+ pbss_entry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ if (element_len > WLAN_SUPPORTED_RATES) {
+ bytes_left_for_current_beacon = 0;
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+ memcpy_ext(pmadapter, pbss_entry->data_rates,
+ pcurrent_ptr + 2, element_len,
+ sizeof(pbss_entry->data_rates));
+ memcpy_ext(pmadapter, pbss_entry->supported_rates,
+ pcurrent_ptr + 2, element_len,
+ sizeof(pbss_entry->supported_rates));
+ HEXDUMP("InterpretIE: SupportedRates:",
+ pbss_entry->supported_rates, element_len);
+ rate_size = element_len;
+ found_data_rate_ie = MTRUE;
+ break;
+
+ case FH_PARAM_SET:
+ pfh_param_set = (IEEEtypes_FhParamSet_t *)pcurrent_ptr;
+ pbss_entry->network_type_use = Wlan802_11FH;
+ memcpy_ext(pmadapter,
+ &pbss_entry->phy_param_set.fh_param_set,
+ pfh_param_set, total_ie_len,
+ sizeof(IEEEtypes_FhParamSet_t));
+ pbss_entry->phy_param_set.fh_param_set.len = MIN(
+ element_len, (sizeof(IEEEtypes_FhParamSet_t) -
+ sizeof(IEEEtypes_Header_t)));
+ pbss_entry->phy_param_set.fh_param_set.dwell_time =
+ wlan_le16_to_cpu(
+ pbss_entry->phy_param_set.fh_param_set
+ .dwell_time);
+ break;
+
+ case DS_PARAM_SET:
+ pds_param_set = (IEEEtypes_DsParamSet_t *)pcurrent_ptr;
+
+ pbss_entry->network_type_use = Wlan802_11DS;
+ pbss_entry->channel = pds_param_set->current_chan;
+
+ memcpy_ext(pmadapter,
+ &pbss_entry->phy_param_set.ds_param_set,
+ pds_param_set, total_ie_len,
+ sizeof(IEEEtypes_DsParamSet_t));
+ pbss_entry->phy_param_set.ds_param_set.len = MIN(
+ element_len, (sizeof(IEEEtypes_DsParamSet_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case CF_PARAM_SET:
+ pcf_param_set = (IEEEtypes_CfParamSet_t *)pcurrent_ptr;
+ memcpy_ext(pmadapter,
+ &pbss_entry->ss_param_set.cf_param_set,
+ pcf_param_set, total_ie_len,
+ sizeof(IEEEtypes_CfParamSet_t));
+ pbss_entry->ss_param_set.cf_param_set.len = MIN(
+ element_len, (sizeof(IEEEtypes_CfParamSet_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss_param_set =
+ (IEEEtypes_IbssParamSet_t *)pcurrent_ptr;
+ pbss_entry->atim_window =
+ wlan_le16_to_cpu(pibss_param_set->atim_window);
+ memcpy_ext(pmadapter,
+ &pbss_entry->ss_param_set.ibss_param_set,
+ pibss_param_set, total_ie_len,
+ sizeof(IEEEtypes_IbssParamSet_t));
+ pbss_entry->ss_param_set.ibss_param_set.len = MIN(
+ element_len, (sizeof(IEEEtypes_IbssParamSet_t) -
+ sizeof(IEEEtypes_Header_t)));
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountry_info =
+ (IEEEtypes_CountryInfoSet_t *)pcurrent_ptr;
+
+ if (pcountry_info->len <
+ sizeof(pcountry_info->country_code) ||
+ (unsigned)(pcountry_info->len + 2) >
+ sizeof(IEEEtypes_CountryInfoFullSet_t)) {
+ PRINTM(MERROR,
+ "InterpretIE: 11D- Err "
+ "country_info len =%d min=%d max=%d\n",
+ pcountry_info->len,
+ sizeof(pcountry_info->country_code),
+ sizeof(IEEEtypes_CountryInfoFullSet_t));
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memcpy_ext(pmadapter, &pbss_entry->country_info,
+ pcountry_info, pcountry_info->len + 2,
+ sizeof(pbss_entry->country_info));
+ HEXDUMP("InterpretIE: 11D- country_info:",
+ (t_u8 *)pcountry_info,
+ (t_u32)(pcountry_info->len + 2));
+ break;
+
+ case ERP_INFO:
+ perp_info = (IEEEtypes_ERPInfo_t *)pcurrent_ptr;
+ pbss_entry->erp_flags = perp_info->erp_flags;
+ break;
+
+ case POWER_CONSTRAINT:
+ case POWER_CAPABILITY:
+ case TPC_REPORT:
+ case CHANNEL_SWITCH_ANN:
+ case QUIET:
+ case IBSS_DFS:
+ case SUPPORTED_CHANNELS:
+ case TPC_REQUEST:
+ wlan_11h_process_bss_elem(
+ pmadapter, &pbss_entry->wlan_11h_bss_info,
+ pcurrent_ptr);
+ break;
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * Only process extended supported rate
+ * if data rate is already found.
+ * Data rate IE should come before
+ * extended supported rate IE
+ */
+ if (found_data_rate_ie) {
+ if ((element_len + rate_size) >
+ WLAN_SUPPORTED_RATES) {
+ bytes_to_copy = (WLAN_SUPPORTED_RATES -
+ rate_size);
+ } else {
+ bytes_to_copy = element_len;
+ }
+
+ prate = (t_u8 *)pbss_entry->data_rates;
+ prate += rate_size;
+ memcpy_ext(pmadapter, prate, pcurrent_ptr + 2,
+ bytes_to_copy, bytes_to_copy);
+
+ prate = (t_u8 *)pbss_entry->supported_rates;
+ prate += rate_size;
+ memcpy_ext(pmadapter, prate, pcurrent_ptr + 2,
+ bytes_to_copy, bytes_to_copy);
+ }
+ HEXDUMP("InterpretIE: ExtSupportedRates:",
+ pbss_entry->supported_rates,
+ element_len + rate_size);
+ break;
+
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
+
+ if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
+ wpa_oui, sizeof(wpa_oui))) {
+ pbss_entry->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t *)
+ pcurrent_ptr;
+ pbss_entry->wpa_offset = (t_u16)(
+ pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WPA_IE",
+ (t_u8 *)pbss_entry->pwpa_ie,
+ ((*(pbss_entry->pwpa_ie)).vend_hdr.len +
+ sizeof(IEEEtypes_Header_t)));
+ } else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
+ wmm_oui, sizeof(wmm_oui))) {
+ if (total_ie_len ==
+ sizeof(IEEEtypes_WmmParameter_t) ||
+ total_ie_len ==
+ sizeof(IEEEtypes_WmmInfo_t)) {
+ /*
+ * Only accept and copy the WMM IE if
+ * it matches the size expected for the
+ * WMM Info IE or the WMM Parameter IE.
+ */
+ memcpy_ext(pmadapter,
+ (t_u8 *)&pbss_entry->wmm_ie,
+ pcurrent_ptr, total_ie_len,
+ sizeof(pbss_entry->wmm_ie));
+ HEXDUMP("InterpretIE: Resp WMM_IE",
+ (t_u8 *)&pbss_entry->wmm_ie,
+ total_ie_len);
+ }
+ } else if (!memcmp(pmadapter, pvendor_ie->vend_hdr.oui,
+ osen_oui, sizeof(osen_oui))) {
+ pbss_entry->posen_ie =
+ (IEEEtypes_Generic_t *)pcurrent_ptr;
+ pbss_entry->osen_offset = (t_u16)(
+ pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp OSEN_IE",
+ (t_u8 *)pbss_entry->posen_ie,
+ (*(pbss_entry->posen_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ }
+ break;
+ case RSN_IE:
+ pbss_entry->prsn_ie =
+ (IEEEtypes_Generic_t *)pcurrent_ptr;
+ pbss_entry->rsn_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp RSN_IE",
+ (t_u8 *)pbss_entry->prsn_ie,
+ (*(pbss_entry->prsn_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case WAPI_IE:
+ pbss_entry->pwapi_ie =
+ (IEEEtypes_Generic_t *)pcurrent_ptr;
+ pbss_entry->wapi_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp WAPI_IE",
+ (t_u8 *)pbss_entry->pwapi_ie,
+ (*(pbss_entry->pwapi_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_CAPABILITY:
+ pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)pcurrent_ptr;
+ pbss_entry->ht_cap_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTCAP_IE",
+ (t_u8 *)pbss_entry->pht_cap,
+ (*(pbss_entry->pht_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case HT_OPERATION:
+ pbss_entry->pht_info =
+ (IEEEtypes_HTInfo_t *)pcurrent_ptr;
+ pbss_entry->ht_info_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp HTINFO_IE",
+ (t_u8 *)pbss_entry->pht_info,
+ (*(pbss_entry->pht_info)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case BSSCO_2040:
+ pbss_entry->pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t *)pcurrent_ptr;
+ pbss_entry->bss_co_2040_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
+ (t_u8 *)pbss_entry->pbss_co_2040,
+ (*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_CAPABILITY:
+ pbss_entry->pext_cap =
+ (IEEEtypes_ExtCap_t *)pcurrent_ptr;
+ pbss_entry->ext_cap_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTCAP_IE",
+ (t_u8 *)pbss_entry->pext_cap,
+ (*(pbss_entry->pext_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case OVERLAPBSSSCANPARAM:
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t *)pcurrent_ptr;
+ pbss_entry->overlap_bss_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp OBSS_IE",
+ (t_u8 *)pbss_entry->poverlap_bss_scan_param,
+ (*(pbss_entry->poverlap_bss_scan_param))
+ .ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case VHT_CAPABILITY:
+ pbss_entry->pvht_cap =
+ (IEEEtypes_VHTCap_t *)pcurrent_ptr;
+ pbss_entry->vht_cap_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp VHTCAP_IE",
+ (t_u8 *)pbss_entry->pvht_cap,
+ (*(pbss_entry->pvht_cap)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case VHT_OPERATION:
+ pbss_entry->pvht_oprat =
+ (IEEEtypes_VHTOprat_t *)pcurrent_ptr;
+ pbss_entry->vht_oprat_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp VHTOPER_IE",
+ (t_u8 *)pbss_entry->pvht_oprat,
+ (*(pbss_entry->pvht_oprat)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_BSS_LOAD:
+ pbss_entry->pext_bssload =
+ (IEEEtypes_ExtBSSload_t *)pcurrent_ptr;
+ pbss_entry->ext_bssload_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTBSSLOAD_IE",
+ (t_u8 *)pbss_entry->pext_bssload,
+ (*(pbss_entry->pext_bssload)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case VHT_TX_POWER_ENV:
+ pbss_entry->pvht_txpower =
+ (IEEEtypes_VHTtxpower_t *)pcurrent_ptr;
+ pbss_entry->vht_txpower_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp TXPOW_IE",
+ (t_u8 *)pbss_entry->pvht_txpower,
+ (*(pbss_entry->pvht_txpower)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXT_POWER_CONSTR:
+ pbss_entry->pext_pwer =
+ (IEEEtypes_ExtPwerCons_t *)pcurrent_ptr;
+ pbss_entry->ext_pwer_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp EXTPOW_IE",
+ (t_u8 *)pbss_entry->pext_pwer,
+ (*(pbss_entry->pext_pwer)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case QUIET_CHAN:
+ pbss_entry->pquiet_chan =
+ (IEEEtypes_QuietChan_t *)pcurrent_ptr;
+ pbss_entry->quiet_chan_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp QUIETCHAN_IE",
+ (t_u8 *)pbss_entry->pquiet_chan,
+ (*(pbss_entry->pquiet_chan)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case BW_CHANNEL_SWITCH:
+ /* RANDYTODO */
+ break;
+ case AID_INFO:
+ break;
+ case OPER_MODE_NTF:
+ pbss_entry->poper_mode =
+ (IEEEtypes_OperModeNtf_t *)pcurrent_ptr;
+ pbss_entry->oper_mode_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp OPERMODENTF_IE",
+ (t_u8 *)pbss_entry->poper_mode,
+ (*(pbss_entry->poper_mode)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ case EXTENSION:
+ pext_tlv = (IEEEtypes_Extension_t *)pcurrent_ptr;
+ switch (pext_tlv->ext_id) {
+ case HE_CAPABILITY:
+ pbss_entry->phe_cap =
+ (IEEEtypes_HECap_t *)pcurrent_ptr;
+ pbss_entry->he_cap_offset = (t_u16)(
+ pcurrent_ptr - pbss_entry->pbeacon_buf);
+ break;
+ case HE_OPERATION:
+ pbss_entry->phe_oprat = pext_tlv;
+ pbss_entry->he_oprat_offset = (t_u16)(
+ pcurrent_ptr - pbss_entry->pbeacon_buf);
+ break;
+ default:
+ break;
+ }
+ break;
+ case MOBILITY_DOMAIN:
+ PRINTM(MCMND, "Mobility Domain IE received in Scan\n");
+ pbss_entry->pmd_ie =
+ (IEEEtypes_MobilityDomain_t *)pcurrent_ptr;
+ pbss_entry->md_offset =
+ (t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
+ HEXDUMP("InterpretIE: Resp Mobility Domain IE",
+ (t_u8 *)pbss_entry->pmd_ie,
+ (*(pbss_entry->pmd_ie)).ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ break;
+ default:
+ break;
+ }
+
+ pcurrent_ptr += element_len + 2;
+
+ /* Need to account for IE ID and IE Len */
+ bytes_left_for_current_beacon -= (element_len + 2);
+
+ } /* while (bytes_left_for_current_beacon > 2) */
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Adjust ie's position in BSSDescriptor_t
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbss_entry A pointer to BSSDescriptor_t structure
+ *
+ * @return N/A
+ */
+static t_void wlan_adjust_ie_in_bss_entry(mlan_private *pmpriv,
+ BSSDescriptor_t *pbss_entry)
+{
+ ENTER();
+ if (pbss_entry->pbeacon_buf) {
+ if (pbss_entry->pwpa_ie) {
+ pbss_entry->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->wpa_offset);
+ }
+ if (pbss_entry->prsn_ie) {
+ pbss_entry->prsn_ie =
+ (IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
+ pbss_entry->rsn_offset);
+ }
+ if (pbss_entry->pwapi_ie) {
+ pbss_entry->pwapi_ie =
+ (IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
+ pbss_entry->wapi_offset);
+ }
+
+ if (pbss_entry->posen_ie) {
+ pbss_entry->posen_ie =
+ (IEEEtypes_Generic_t *)(pbss_entry->pbeacon_buf +
+ pbss_entry->osen_offset);
+ }
+ if (pbss_entry->pmd_ie) {
+ pbss_entry->pmd_ie =
+ (IEEEtypes_MobilityDomain_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->md_offset);
+ }
+ if (pbss_entry->pht_cap) {
+ pbss_entry->pht_cap =
+ (IEEEtypes_HTCap_t *)(pbss_entry->pbeacon_buf +
+ pbss_entry->ht_cap_offset);
+ }
+ if (pbss_entry->pht_info) {
+ pbss_entry->pht_info =
+ (IEEEtypes_HTInfo_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->ht_info_offset);
+ }
+ if (pbss_entry->pbss_co_2040) {
+ pbss_entry->pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->bss_co_2040_offset);
+ }
+ if (pbss_entry->pext_cap) {
+ pbss_entry->pext_cap =
+ (IEEEtypes_ExtCap_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->ext_cap_offset);
+ }
+ if (pbss_entry->poverlap_bss_scan_param) {
+ pbss_entry->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->overlap_bss_offset);
+ }
+ if (pbss_entry->pvht_cap) {
+ pbss_entry->pvht_cap =
+ (IEEEtypes_VHTCap_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->vht_cap_offset);
+ }
+ if (pbss_entry->pvht_oprat) {
+ pbss_entry->pvht_oprat =
+ (IEEEtypes_VHTOprat_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->vht_oprat_offset);
+ }
+ if (pbss_entry->pvht_txpower) {
+ pbss_entry->pvht_txpower =
+ (IEEEtypes_VHTtxpower_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->vht_txpower_offset);
+ }
+ if (pbss_entry->pext_pwer) {
+ pbss_entry->pext_pwer =
+ (IEEEtypes_ExtPwerCons_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->ext_pwer_offset);
+ }
+ if (pbss_entry->pext_bssload) {
+ pbss_entry->pext_bssload =
+ (IEEEtypes_ExtBSSload_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->ext_bssload_offset);
+ }
+ if (pbss_entry->pquiet_chan) {
+ pbss_entry->pquiet_chan =
+ (IEEEtypes_QuietChan_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->quiet_chan_offset);
+ }
+ if (pbss_entry->poper_mode) {
+ pbss_entry->poper_mode =
+ (IEEEtypes_OperModeNtf_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->oper_mode_offset);
+ }
+ if (pbss_entry->phe_cap) {
+ pbss_entry->phe_cap =
+ (IEEEtypes_HECap_t *)(pbss_entry->pbeacon_buf +
+ pbss_entry->he_cap_offset);
+ }
+
+ if (pbss_entry->phe_oprat) {
+ pbss_entry->phe_oprat =
+ (IEEEtypes_Extension_t
+ *)(pbss_entry->pbeacon_buf +
+ pbss_entry->he_oprat_offset);
+ }
+ } else {
+ pbss_entry->pwpa_ie = MNULL;
+ pbss_entry->wpa_offset = 0;
+ pbss_entry->prsn_ie = MNULL;
+ pbss_entry->rsn_offset = 0;
+ pbss_entry->pwapi_ie = MNULL;
+ pbss_entry->wapi_offset = 0;
+
+ pbss_entry->posen_ie = MNULL;
+ pbss_entry->osen_offset = 0;
+ pbss_entry->pmd_ie = MNULL;
+ pbss_entry->md_offset = 0;
+ pbss_entry->pht_cap = MNULL;
+ pbss_entry->ht_cap_offset = 0;
+ pbss_entry->pht_info = MNULL;
+ pbss_entry->ht_info_offset = 0;
+ pbss_entry->pbss_co_2040 = MNULL;
+ pbss_entry->bss_co_2040_offset = 0;
+ pbss_entry->pext_cap = MNULL;
+ pbss_entry->ext_cap_offset = 0;
+ pbss_entry->poverlap_bss_scan_param = MNULL;
+ pbss_entry->overlap_bss_offset = 0;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Store a beacon or probe response for a BSS returned in the scan
+ *
+ * Store a new scan response or an update for a previous scan response. New
+ * entries need to verify that they do not exceed the total amount of
+ * memory allocated for the table.
+
+ * Replacement entries need to take into consideration the amount of space
+ * currently allocated for the beacon/probe response and adjust the entry
+ * as needed.
+ *
+ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ * for an entry in case it is a beacon since a probe response for the
+ * network will by larger per the standard. This helps to reduce the
+ * amount of memory copying to fit a new probe response into an entry
+ * already occupied by a network's previously stored beacon.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param beacon_idx Index in the scan table to store this entry; may be
+ * replacing an older duplicate entry for this BSS
+ * @param num_of_ent Number of entries currently in the table
+ * @param pnew_beacon Pointer to the new beacon/probe response to save
+ *
+ * @return N/A
+ */
+static t_void wlan_ret_802_11_scan_store_beacon(mlan_private *pmpriv,
+ t_u32 beacon_idx,
+ t_u32 num_of_ent,
+ BSSDescriptor_t *pnew_beacon)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 *pbcn_store;
+ t_u32 new_bcn_size;
+ t_u32 old_bcn_size;
+ t_u32 bcn_space;
+ t_u32 adj_idx;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *tmp_buf;
+ t_u16 bcn_size = 0;
+ t_u32 bcn_offset = 0;
+
+ ENTER();
+
+ if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
+ new_bcn_size = pnew_beacon->beacon_buf_size;
+ old_bcn_size =
+ pmadapter->pscan_table[beacon_idx].beacon_buf_size;
+ bcn_space =
+ pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
+ pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
+
+ /* Set the max to be the same as current entry unless changed
+ * below */
+ pnew_beacon->beacon_buf_size_max = bcn_space;
+
+ if (new_bcn_size == old_bcn_size) {
+ /*
+ * Beacon is the same size as the previous entry.
+ * Replace the previous contents with the scan result
+ */
+ memcpy_ext(pmadapter, pbcn_store,
+ pnew_beacon->pbeacon_buf,
+ pnew_beacon->beacon_buf_size,
+ pnew_beacon->beacon_buf_size);
+
+ } else if (new_bcn_size <= bcn_space) {
+ /*
+ * New beacon size will fit in the amount of space
+ * we have previously allocated for it
+ */
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy_ext(pmadapter, pbcn_store,
+ pnew_beacon->pbeacon_buf, new_bcn_size,
+ new_bcn_size);
+
+ /*
+ * If the old beacon size was less than the
+ * maximum we had allotted for the entry, and
+ * the new entry is even smaller, reset the
+ * max size to the old beacon entry and compress
+ * the storage space (leaving a new pad space of
+ * (old_bcn_size - new_bcn_size).
+ */
+ if (old_bcn_size < bcn_space &&
+ new_bcn_size <= old_bcn_size) {
+ /*
+ * Old Beacon size is smaller than the
+ * allotted storage size. Shrink the
+ * allotted storage space.
+ */
+ PRINTM(MINFO,
+ "AppControl: Smaller Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size,
+ bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end -
+ pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end
+ * of the current beacon. This cleans up any
+ * unused space the old larger beacon was using
+ * in the buffer
+ */
+ memmove(pmadapter,
+ (void *)((t_ptr)pbcn_store +
+ (t_ptr)old_bcn_size),
+ (void *)((t_ptr)pbcn_store +
+ (t_ptr)bcn_space),
+ (t_u32)((t_ptr)pmadapter->pbcn_buf_end -
+ ((t_ptr)pbcn_store +
+ (t_ptr)bcn_space)));
+
+ /*
+ * Decrement the end pointer by the difference
+ * between the old larger size and the new
+ * smaller size since we are using less space
+ * due to the new beacon being smaller
+ */
+ pmadapter->pbcn_buf_end -=
+ (bcn_space - old_bcn_size);
+
+ /*
+ * Set the maximum storage size to the old
+ * beacon size
+ */
+ pnew_beacon->beacon_buf_size_max = old_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past
+ * the current */
+ for (adj_idx = 0; adj_idx < num_of_ent;
+ adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx]
+ .pbeacon_buf > pbcn_store) {
+ pmadapter->pscan_table[adj_idx]
+ .pbeacon_buf -=
+ (bcn_space -
+ old_bcn_size);
+ wlan_adjust_ie_in_bss_entry(
+ pmpriv,
+ &pmadapter->pscan_table
+ [adj_idx]);
+ }
+ }
+ }
+ } else if (pmadapter->pbcn_buf_end +
+ (new_bcn_size - bcn_space) <
+ (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
+ /*
+ * Beacon is larger than space previously allocated
+ * (bcn_space) and there is enough space left in the
+ * beaconBuffer to store the additional data
+ */
+ PRINTM(MINFO,
+ "AppControl: Larger Duplicate Beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size,
+ bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This moves the data for
+ * the beacons after this further in memory to
+ * make space for the new larger beacon we are
+ * about to copy in.
+ */
+ memmove(pmadapter,
+ (void *)((t_ptr)pbcn_store +
+ (t_ptr)new_bcn_size),
+ (void *)((t_ptr)pbcn_store + (t_ptr)bcn_space),
+ (t_u32)((t_ptr)pmadapter->pbcn_buf_end -
+ ((t_ptr)pbcn_store + (t_ptr)bcn_space)));
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy_ext(pmadapter, pbcn_store,
+ pnew_beacon->pbeacon_buf, new_bcn_size,
+ new_bcn_size);
+
+ /*
+ * Move the beacon end pointer by the amount of new
+ * beacon data we are adding
+ */
+ pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
+
+ /*
+ * This entry is bigger than the allotted max space
+ * previously reserved. Increase the max space to
+ * be equal to the new beacon size
+ */
+ pnew_beacon->beacon_buf_size_max = new_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the
+ * current */
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (pmadapter->pscan_table[adj_idx].pbeacon_buf >
+ pbcn_store) {
+ pmadapter->pscan_table[adj_idx]
+ .pbeacon_buf +=
+ (new_bcn_size - bcn_space);
+ wlan_adjust_ie_in_bss_entry(
+ pmpriv,
+ &pmadapter->pscan_table[adj_idx]);
+ }
+ }
+ } else {
+ /*
+ * Beacon is larger than the previously allocated
+ * space, but there is not enough free space to
+ * store the additional data
+ */
+ PRINTM(MERROR,
+ "AppControl: Failed: Larger Duplicate Beacon (%d),"
+ " old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size,
+ bcn_space,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /* Storage failure, keep old beacon intact */
+ pnew_beacon->beacon_buf_size = old_bcn_size;
+ if (pnew_beacon->pwpa_ie)
+ pnew_beacon->wpa_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .wpa_offset;
+ if (pnew_beacon->prsn_ie)
+ pnew_beacon->rsn_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .rsn_offset;
+ if (pnew_beacon->pwapi_ie)
+ pnew_beacon->wapi_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .wapi_offset;
+
+ if (pnew_beacon->posen_ie)
+ pnew_beacon->osen_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .osen_offset;
+ if (pnew_beacon->pmd_ie)
+ pnew_beacon->md_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .md_offset;
+ if (pnew_beacon->pht_cap)
+ pnew_beacon->ht_cap_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .ht_cap_offset;
+ if (pnew_beacon->pht_info)
+ pnew_beacon->ht_info_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .ht_info_offset;
+ if (pnew_beacon->pbss_co_2040)
+ pnew_beacon->bss_co_2040_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .bss_co_2040_offset;
+ if (pnew_beacon->pext_cap)
+ pnew_beacon->ext_cap_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .ext_cap_offset;
+ if (pnew_beacon->poverlap_bss_scan_param)
+ pnew_beacon->overlap_bss_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .overlap_bss_offset;
+ if (pnew_beacon->pvht_cap)
+ pnew_beacon->vht_cap_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .vht_cap_offset;
+ if (pnew_beacon->pvht_oprat)
+ pnew_beacon->vht_oprat_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .vht_oprat_offset;
+ if (pnew_beacon->pvht_txpower)
+ pnew_beacon->vht_txpower_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .vht_txpower_offset;
+ if (pnew_beacon->pext_pwer)
+ pnew_beacon->ext_pwer_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .ext_pwer_offset;
+ if (pnew_beacon->pext_bssload)
+ pnew_beacon->ext_bssload_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .ext_bssload_offset;
+ if (pnew_beacon->pquiet_chan)
+ pnew_beacon->quiet_chan_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .quiet_chan_offset;
+ if (pnew_beacon->poper_mode)
+ pnew_beacon->oper_mode_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .oper_mode_offset;
+ if (pnew_beacon->phe_cap)
+ pnew_beacon->he_cap_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .he_cap_offset;
+ if (pnew_beacon->phe_oprat)
+ pnew_beacon->he_oprat_offset =
+ pmadapter->pscan_table[beacon_idx]
+ .he_oprat_offset;
+ }
+ /* Point the new entry to its permanent storage space */
+ pnew_beacon->pbeacon_buf = pbcn_store;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ } else {
+ if ((pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD >
+ (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) &&
+ (pmadapter->bcn_buf_size < MAX_SCAN_BEACON_BUFFER)) {
+ /* no space for this entry, realloc bcn buffer */
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle,
+ pmadapter->bcn_buf_size +
+ DEFAULT_SCAN_BEACON_BUFFER,
+ MLAN_MEM_DEF, (t_u8 **)&tmp_buf);
+
+ if ((ret == MLAN_STATUS_SUCCESS) && (tmp_buf)) {
+ PRINTM(MCMND,
+ "Realloc Beacon buffer, old size=%d, new_size=%d\n",
+ pmadapter->bcn_buf_size,
+ pmadapter->bcn_buf_size +
+ DEFAULT_SCAN_BEACON_BUFFER);
+ bcn_size = pmadapter->pbcn_buf_end -
+ pmadapter->bcn_buf;
+ memcpy_ext(pmadapter, tmp_buf,
+ pmadapter->bcn_buf, bcn_size,
+ bcn_size);
+ /* Adjust beacon buffer pointers that are past
+ * the current */
+ for (adj_idx = 0; adj_idx < num_of_ent;
+ adj_idx++) {
+ bcn_offset =
+ pmadapter->pscan_table[adj_idx]
+ .pbeacon_buf -
+ pmadapter->bcn_buf;
+ pmadapter->pscan_table[adj_idx]
+ .pbeacon_buf =
+ tmp_buf + bcn_offset;
+ wlan_adjust_ie_in_bss_entry(
+ pmpriv,
+ &pmadapter->pscan_table[adj_idx]);
+ }
+ pmadapter->pbcn_buf_end = tmp_buf + bcn_size;
+ pmadapter->callbacks.moal_mfree(
+ pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->bcn_buf);
+ pmadapter->bcn_buf = tmp_buf;
+ pmadapter->bcn_buf_size +=
+ DEFAULT_SCAN_BEACON_BUFFER;
+ }
+ }
+ /*
+ * No existing beacon data exists for this entry, check to see
+ * if we can fit it in the remaining space
+ */
+ if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD <
+ (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
+ /*
+ * Copy the beacon buffer data from the local entry
+ * to the adapter dev struct buffer space used to
+ * store the raw beacon data for each entry in the
+ * scan table
+ */
+ memcpy_ext(pmadapter, pmadapter->pbcn_buf_end,
+ pnew_beacon->pbeacon_buf,
+ pnew_beacon->beacon_buf_size,
+ pnew_beacon->beacon_buf_size);
+
+ /*
+ * Update the beacon ptr to point to the table
+ * save area
+ */
+ pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
+ pnew_beacon->beacon_buf_size_max =
+ (pnew_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD);
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+
+ /* Increment the end pointer by the size reserved */
+ pmadapter->pbcn_buf_end +=
+ pnew_beacon->beacon_buf_size_max;
+
+ PRINTM(MINFO,
+ "AppControl: Beacon[%02d] sz=%03d,"
+ " used = %04d, left = %04d\n",
+ beacon_idx, pnew_beacon->beacon_buf_size,
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+ } else {
+ /*
+ * No space for new beacon
+ */
+ PRINTM(MCMND,
+ "AppControl: No space beacon (%d): " MACSTR
+ "; sz=%03d, left=%03d\n",
+ beacon_idx, MAC2STR(pnew_beacon->mac_address),
+ pnew_beacon->beacon_buf_size,
+ (pmadapter->bcn_buf_size -
+ (pmadapter->pbcn_buf_end - pmadapter->bcn_buf)));
+
+ /*
+ * Storage failure; clear storage records
+ * for this bcn
+ */
+ pnew_beacon->pbeacon_buf = MNULL;
+ pnew_beacon->beacon_buf_size = 0;
+ pnew_beacon->beacon_buf_size_max = 0;
+ wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief update beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS, otherwise failure
+ */
+static mlan_status wlan_update_curr_bcn(mlan_private *pmpriv)
+{
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
+ pcurr_bss->pbeacon_buf = pmpriv->pcurr_bcn_buf;
+ pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
+ pcurr_bss->beacon_buf_size_max = pmpriv->curr_bcn_size;
+
+ /* adjust the pointers in the current bss descriptor */
+ if (pcurr_bss->pwpa_ie) {
+ pcurr_bss->pwpa_ie =
+ (IEEEtypes_VendorSpecific_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->wpa_offset);
+ }
+ if (pcurr_bss->prsn_ie) {
+ pcurr_bss->prsn_ie =
+ (IEEEtypes_Generic_t *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->rsn_offset);
+ }
+ if (pcurr_bss->pmd_ie) {
+ pcurr_bss->pmd_ie = (IEEEtypes_MobilityDomain_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->md_offset);
+ }
+ if (pcurr_bss->pht_cap) {
+ pcurr_bss->pht_cap =
+ (IEEEtypes_HTCap_t *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->ht_cap_offset);
+ }
+
+ if (pcurr_bss->pht_info) {
+ pcurr_bss->pht_info =
+ (IEEEtypes_HTInfo_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->ht_info_offset);
+ }
+
+ if (pcurr_bss->pbss_co_2040) {
+ pcurr_bss->pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->bss_co_2040_offset);
+ }
+
+ if (pcurr_bss->pext_cap) {
+ pcurr_bss->pext_cap =
+ (IEEEtypes_ExtCap_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->ext_cap_offset);
+ }
+
+ if (pcurr_bss->poverlap_bss_scan_param) {
+ pcurr_bss->poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->overlap_bss_offset);
+ }
+
+ if (pcurr_bss->pvht_cap) {
+ pcurr_bss->pvht_cap =
+ (IEEEtypes_VHTCap_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->vht_cap_offset);
+ }
+
+ if (pcurr_bss->pvht_oprat) {
+ pcurr_bss->pvht_oprat =
+ (IEEEtypes_VHTOprat_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->vht_oprat_offset);
+ }
+
+ if (pcurr_bss->pvht_txpower) {
+ pcurr_bss->pvht_txpower =
+ (IEEEtypes_VHTtxpower_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->vht_txpower_offset);
+ }
+
+ if (pcurr_bss->pext_pwer) {
+ pcurr_bss->pext_pwer =
+ (IEEEtypes_ExtPwerCons_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->ext_pwer_offset);
+ }
+
+ if (pcurr_bss->pext_bssload) {
+ pcurr_bss->pext_bssload =
+ (IEEEtypes_ExtBSSload_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->ext_bssload_offset);
+ }
+
+ if (pcurr_bss->pquiet_chan) {
+ pcurr_bss->pquiet_chan =
+ (IEEEtypes_QuietChan_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->quiet_chan_offset);
+ }
+
+ if (pcurr_bss->poper_mode) {
+ pcurr_bss->poper_mode =
+ (IEEEtypes_OperModeNtf_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->oper_mode_offset);
+ }
+ if (pcurr_bss->phe_cap) {
+ pcurr_bss->phe_cap =
+ (IEEEtypes_HECap_t *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->he_cap_offset);
+ }
+
+ if (pcurr_bss->phe_oprat) {
+ pcurr_bss->phe_oprat =
+ (IEEEtypes_Extension_t
+ *)(pcurr_bss->pbeacon_buf +
+ pcurr_bss->he_oprat_offset);
+ }
+
+ PRINTM(MINFO, "current beacon restored %d\n",
+ pmpriv->curr_bcn_size);
+ } else {
+ PRINTM(MERROR, "curr_bcn_buf not saved\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief get the chan load from chan stats.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param channel channel *
+ *
+ * @return channel load
+ */
+static t_u16 wlan_get_chan_load(mlan_adapter *pmadapter, t_u8 channel)
+{
+ t_u16 chan_load = 0;
+ int i;
+ for (i = 0; i < pmadapter->num_in_chan_stats; i++) {
+ if ((pmadapter->pchan_stats[i].chan_num == channel) &&
+ pmadapter->pchan_stats[i].cca_scan_duration) {
+ chan_load =
+ (pmadapter->pchan_stats[i].cca_busy_duration *
+ 100) /
+ pmadapter->pchan_stats[i].cca_scan_duration;
+ break;
+ }
+ }
+ return chan_load;
+}
+
+/**
+ * @brief get the chan min/max rssi
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param channel channel *
+ * @param min_flag flag to get min rssi
+ * @return rssi
+ */
+static t_u8 wlan_get_chan_rssi(mlan_adapter *pmadapter, t_u8 channel,
+ t_u8 min_flag)
+{
+ t_u8 rssi = 0;
+ int i;
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ if (pmadapter->pscan_table[i].channel == channel) {
+ if (rssi == 0)
+ rssi = (t_s32)pmadapter->pscan_table[i].rssi;
+ else {
+ if (min_flag)
+ rssi = MIN(
+ rssi,
+ pmadapter->pscan_table[i].rssi);
+ else
+ rssi = MAX(
+ rssi,
+ pmadapter->pscan_table[i].rssi);
+ }
+ }
+ }
+ return rssi;
+}
+
+/**
+ * @brief update the min/max rssi for channel statistics.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return N/A
+ */
+static t_void wlan_update_chan_rssi(mlan_adapter *pmadapter)
+{
+ int i;
+ t_s8 min_rssi = 0;
+ t_s8 max_rssi = 0;
+ t_s8 rss = 0;
+ for (i = 0; i < pmadapter->num_in_chan_stats; i++) {
+ if (pmadapter->pchan_stats[i].chan_num &&
+ pmadapter->pchan_stats[i].cca_scan_duration) {
+ min_rssi = -wlan_get_chan_rssi(
+ pmadapter, pmadapter->pchan_stats[i].chan_num,
+ MFALSE);
+ max_rssi = -wlan_get_chan_rssi(
+ pmadapter, pmadapter->pchan_stats[i].chan_num,
+ MTRUE);
+ rss = min_rssi - pmadapter->pchan_stats[i].noise;
+ // rss should always > 0, FW need fix the wrong
+ // rssi/noise in scantable
+ if (rss > 0)
+ pmadapter->pchan_stats[i].min_rss = rss;
+ else
+ pmadapter->pchan_stats[i].min_rss = 0;
+
+ rss = max_rssi - pmadapter->pchan_stats[i].noise;
+ if (rss > 0)
+ pmadapter->pchan_stats[i].max_rss = rss;
+ else
+ pmadapter->pchan_stats[i].max_rss = 0;
+ PRINTM(MCMND,
+ "chan=%d, min_rssi=%d, max_rssi=%d noise=%d min_rss=%d, max_rss=%d\n",
+ pmadapter->pchan_stats[i].chan_num, min_rssi,
+ max_rssi, pmadapter->pchan_stats[i].noise,
+ pmadapter->pchan_stats[i].min_rss,
+ pmadapter->pchan_stats[i].max_rss);
+ }
+ }
+ return;
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the BSSDescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static t_void wlan_scan_process_results(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 j;
+ t_u32 i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE) {
+ j = wlan_find_bssid_in_list(
+ pmpriv,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pmpriv->bss_mode);
+
+ if (j >= 0) {
+ memcpy_ext(pmadapter, &pmadapter->pscan_table[j].ssid,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+
+ pmpriv->curr_bss_params.bss_descriptor.posen_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.osen_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pmd_ie = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.md_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ht_info_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor
+ .bss_co_2040_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor
+ .poverlap_bss_scan_param = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor
+ .overlap_bss_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pvht_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.vht_cap_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pvht_oprat =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.vht_oprat_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pvht_txpower =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor
+ .vht_txpower_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_pwer =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.ext_pwer_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pext_bssload =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor
+ .ext_bssload_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.pquiet_chan =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor
+ .quiet_chan_offset = 0;
+ pmpriv->curr_bss_params.bss_descriptor.poper_mode =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.oper_mode_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.phe_cap = MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.he_cap_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.phe_oprat =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.he_oprat_offset =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf =
+ MNULL;
+ pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size =
+ 0;
+ pmpriv->curr_bss_params.bss_descriptor
+ .beacon_buf_size_max = 0;
+
+ PRINTM(MINFO,
+ "Found current ssid/bssid in list @ index #%d\n",
+ j);
+ /* Make a copy of current BSSID descriptor */
+ memcpy_ext(
+ pmadapter,
+ &pmpriv->curr_bss_params.bss_descriptor,
+ &pmadapter->pscan_table[j],
+ sizeof(pmpriv->curr_bss_params.bss_descriptor),
+ sizeof(pmpriv->curr_bss_params.bss_descriptor));
+
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+ wlan_save_curr_bcn(pmpriv);
+ } else {
+ // Apend to the end of scan table
+ if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF,
+ (t_u8 **)&bss_new_entry);
+ if (ret == MLAN_STATUS_SUCCESS &&
+ bss_new_entry) {
+ memcpy_ext(
+ pmadapter, bss_new_entry,
+ &pmpriv->curr_bss_params
+ .bss_descriptor,
+ sizeof(pmpriv->curr_bss_params
+ .bss_descriptor),
+ sizeof(BSSDescriptor_t));
+ if (pmadapter->num_in_scan_table <
+ MRVDRV_MAX_BSSID_LIST)
+ pmadapter->num_in_scan_table++;
+ pmadapter
+ ->pscan_table
+ [pmadapter->num_in_scan_table -
+ 1]
+ .pbeacon_buf = MNULL;
+ wlan_ret_802_11_scan_store_beacon(
+ pmpriv,
+ pmadapter->num_in_scan_table -
+ 1,
+ pmadapter->num_in_scan_table,
+ bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL)
+ pmadapter->num_in_scan_table--;
+ else
+ memcpy_ext(
+ pmadapter,
+ &pmadapter->pscan_table
+ [pmadapter->num_in_scan_table -
+ 1],
+ bss_new_entry,
+ sizeof(BSSDescriptor_t),
+ sizeof(BSSDescriptor_t));
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)bss_new_entry);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < pmadapter->num_in_scan_table; i++) {
+ PRINTM(MINFO,
+ "Scan:(%02d) " MACSTR ", "
+ "RSSI[%03d], SSID[%s]\n",
+ i, MAC2STR(pmadapter->pscan_table[i].mac_address),
+ (t_s32)pmadapter->pscan_table[i].rssi,
+ pmadapter->pscan_table[i].ssid.ssid);
+ pmadapter->pscan_table[i].chan_load = wlan_get_chan_load(
+ pmadapter, pmadapter->pscan_table[i].channel);
+ }
+ wlan_update_chan_rssi(pmadapter);
+
+ /*
+ * Prepares domain info from scan table and downloads the
+ * domain info command to the FW.
+ */
+ wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
+ PRINTM(MMSG, "wlan: SCAN COMPLETED: scanned AP count=%d\n",
+ pmadapter->num_in_scan_table);
+ LEAVE();
+}
+
+/**
+ * @brief Delete a specific indexed entry from the scan table.
+ *
+ * Delete the scan table entry indexed by table_idx. Compact the remaining
+ * entries and adjust any buffering of beacon/probe response data
+ * if needed.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param table_idx Scan table entry index to delete from the table
+ *
+ * @return N/A
+ *
+ * @pre table_idx must be an index to a valid entry
+ */
+static t_void wlan_scan_delete_table_entry(mlan_private *pmpriv,
+ t_s32 table_idx)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 del_idx;
+ t_u32 beacon_buf_adj;
+ t_u8 *pbeacon_buf;
+
+ ENTER();
+
+ /*
+ * Shift the saved beacon buffer data for the scan table back over the
+ * entry being removed. Update the end of buffer pointer. Save the
+ * deleted buffer allocation size for pointer adjustments for entries
+ * compacted after the deleted index.
+ */
+ beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
+
+ PRINTM(MINFO,
+ "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+ table_idx, beacon_buf_adj);
+
+ /* Check if the table entry had storage allocated for its beacon */
+ if (beacon_buf_adj) {
+ pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
+
+ /*
+ * Remove the entry's buffer space, decrement the table
+ * end pointer by the amount we are removing
+ */
+ pmadapter->pbcn_buf_end -= beacon_buf_adj;
+
+ PRINTM(MINFO,
+ "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+ table_idx, pbeacon_buf, pbeacon_buf + beacon_buf_adj,
+ pmadapter->pbcn_buf_end - pbeacon_buf);
+
+ /*
+ * Compact data storage. Copy all data after the deleted
+ * entry's end address (pbeacon_buf + beacon_buf_adj) back to
+ * the original start address (pbeacon_buf).
+ *
+ * Scan table entries affected by the move will have their entry
+ * pointer adjusted below.
+ *
+ * Use memmove since the dest/src memory regions overlap.
+ */
+ memmove(pmadapter, pbeacon_buf,
+ (void *)((t_ptr)pbeacon_buf + (t_ptr)beacon_buf_adj),
+ (t_u32)((t_ptr)pmadapter->pbcn_buf_end -
+ (t_ptr)pbeacon_buf));
+ }
+
+ PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
+ table_idx, pmadapter->num_in_scan_table);
+
+ /*
+ * Shift all of the entries after the table_idx back by one, compacting
+ * the table and removing the requested entry
+ */
+ for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
+ del_idx++) {
+ /* Copy the next entry over this one */
+ memcpy_ext(pmadapter, pmadapter->pscan_table + del_idx,
+ pmadapter->pscan_table + del_idx + 1,
+ sizeof(BSSDescriptor_t), sizeof(BSSDescriptor_t));
+
+ /*
+ * Adjust this entry's pointer to its beacon buffer based on the
+ * removed/compacted entry from the deleted index. Don't
+ * decrement if the buffer pointer is MNULL (no data stored for
+ * this entry).
+ */
+ if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
+ pmadapter->pscan_table[del_idx].pbeacon_buf -=
+ beacon_buf_adj;
+ if (pmadapter->pscan_table[del_idx].pwpa_ie) {
+ pmadapter->pscan_table[del_idx].pwpa_ie =
+ (IEEEtypes_VendorSpecific_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .wpa_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].prsn_ie) {
+ pmadapter->pscan_table[del_idx].prsn_ie =
+ (IEEEtypes_Generic_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .rsn_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pwapi_ie) {
+ pmadapter->pscan_table[del_idx].pwapi_ie =
+ (IEEEtypes_Generic_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .wapi_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].posen_ie) {
+ pmadapter->pscan_table[del_idx].posen_ie =
+ (IEEEtypes_Generic_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .osen_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pmd_ie) {
+ pmadapter->pscan_table[del_idx].pmd_ie =
+ (IEEEtypes_MobilityDomain_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .md_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pht_cap) {
+ pmadapter->pscan_table[del_idx].pht_cap =
+ (IEEEtypes_HTCap_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .ht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pht_info) {
+ pmadapter->pscan_table[del_idx].pht_info =
+ (IEEEtypes_HTInfo_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .ht_info_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
+ pmadapter->pscan_table[del_idx].pbss_co_2040 =
+ (IEEEtypes_2040BSSCo_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .bss_co_2040_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_cap) {
+ pmadapter->pscan_table[del_idx].pext_cap =
+ (IEEEtypes_ExtCap_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .ext_cap_offset);
+ }
+ if (pmadapter->pscan_table[del_idx]
+ .poverlap_bss_scan_param) {
+ pmadapter->pscan_table[del_idx]
+ .poverlap_bss_scan_param =
+ (IEEEtypes_OverlapBSSScanParam_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .overlap_bss_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pvht_cap) {
+ pmadapter->pscan_table[del_idx].pvht_cap =
+ (IEEEtypes_VHTCap_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .vht_cap_offset);
+ }
+
+ if (pmadapter->pscan_table[del_idx].pvht_oprat) {
+ pmadapter->pscan_table[del_idx].pvht_oprat =
+ (IEEEtypes_VHTOprat_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .vht_oprat_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pvht_txpower) {
+ pmadapter->pscan_table[del_idx].pvht_txpower =
+ (IEEEtypes_VHTtxpower_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .vht_txpower_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_pwer) {
+ pmadapter->pscan_table[del_idx].pext_pwer =
+ (IEEEtypes_ExtPwerCons_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .ext_pwer_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pext_bssload) {
+ pmadapter->pscan_table[del_idx].pext_bssload =
+ (IEEEtypes_ExtBSSload_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .ext_bssload_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].pquiet_chan) {
+ pmadapter->pscan_table[del_idx].pquiet_chan =
+ (IEEEtypes_QuietChan_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .quiet_chan_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].poper_mode) {
+ pmadapter->pscan_table[del_idx].poper_mode =
+ (IEEEtypes_OperModeNtf_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .oper_mode_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].phe_cap) {
+ pmadapter->pscan_table[del_idx].phe_cap =
+ (IEEEtypes_HECap_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .he_cap_offset);
+ }
+ if (pmadapter->pscan_table[del_idx].phe_oprat) {
+ pmadapter->pscan_table[del_idx].phe_oprat =
+ (IEEEtypes_Extension_t
+ *)(pmadapter
+ ->pscan_table[del_idx]
+ .pbeacon_buf +
+ pmadapter
+ ->pscan_table[del_idx]
+ .he_oprat_offset);
+ }
+ }
+ }
+
+ /* The last entry is invalid now that it has been deleted or moved back
+ */
+ memset(pmadapter,
+ pmadapter->pscan_table + pmadapter->num_in_scan_table - 1, 0x00,
+ sizeof(BSSDescriptor_t));
+
+ pmadapter->num_in_scan_table--;
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all occurrences of a given SSID from the scan table
+ *
+ * Iterate through the scan table and delete all entries that match a given
+ * SSID. Compact the remaining scan table entries.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdel_ssid Pointer to an SSID to be used in deleting all
+ * matching SSIDs from the scan table
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_scan_delete_ssid_table_entry(mlan_private *pmpriv,
+ mlan_802_11_ssid *pdel_ssid)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_s32 table_idx;
+
+ ENTER();
+
+ PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
+
+ /*
+ * If the requested SSID is found in the table, delete it. Then keep
+ * searching the table for multiple entries for the SSID until no
+ * more are found
+ */
+ while ((table_idx = wlan_find_ssid_in_list(pmpriv, pdel_ssid, MNULL,
+ MLAN_BSS_MODE_AUTO)) >= 0) {
+ PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n",
+ table_idx);
+ ret = MLAN_STATUS_SUCCESS;
+ wlan_scan_delete_table_entry(pmpriv, table_idx);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 0 1 0 0 x 1x 1 x yes WPA (disable
+ * HT if no AES) 0 0 1 0 x 1x x 1 yes
+ * WPA2 (disable HT if no AES) 0 0 0 1 NONE 1 0 0
+ * yes Ad-hoc AES 1 0 0 0 NONE 1 0 0 yes
+ * Static WEP (disable HT) 0 0 0 0 !=NONE 1 0 0
+ * yes Dynamic WEP
+ *
+ * @param pmpriv A pointer to mlan_private
+ * @param index Index in scan table to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in ScanTable, or negative value if error
+ */
+t_s32 wlan_is_network_compatible(mlan_private *pmpriv, t_u32 index, t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ BSSDescriptor_t *pbss_desc;
+
+ ENTER();
+
+ pbss_desc = &pmadapter->pscan_table[index];
+ /* Don't check for compatibility if roaming */
+ if ((pmpriv->media_connected == MTRUE) &&
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ (pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
+ LEAVE();
+ return index;
+ }
+
+ pbss_desc->disable_11n = MFALSE;
+
+ /* if the HE CAP IE exists, HT CAP IE should exist too */
+ /* 2.4G AX AP, don't have VHT CAP */
+ if (pbss_desc->phe_cap && !pbss_desc->pht_cap) {
+ PRINTM(MINFO,
+ "Disable 11n if VHT CAP/HT CAP IE is not found from the 11AX AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ }
+
+ /* if the VHT CAP IE exists, the HT CAP IE should exist too */
+ if (pbss_desc->pvht_cap && !pbss_desc->pht_cap) {
+ PRINTM(MINFO,
+ "Disable 11n if HT CAP IE is not found from the 11AC AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ }
+
+ if (pbss_desc->wlan_11h_bss_info.chan_switch_ann.element_id ==
+ CHANNEL_SWITCH_ANN) {
+ PRINTM(MINFO,
+ "Don't connect to AP with CHANNEL_SWITCH_ANN IE.\n");
+ LEAVE();
+ return -1;
+ }
+
+ if (pmpriv->wps.session_enable == MTRUE) {
+ PRINTM(MINFO, "Return success directly in WPS period\n");
+ LEAVE();
+ return index;
+ }
+
+ if (pmpriv->sec_info.osen_enabled && pbss_desc->posen_ie &&
+ ((*(pbss_desc->posen_ie)).ieee_hdr.element_id ==
+ VENDOR_SPECIFIC_221)) {
+ /* Hotspot 2.0 OSEN AKM */
+ PRINTM(MMSG,
+ "Return success directly in Hotspot OSEN: index=%d "
+ "encryption_mode=%#x\n",
+ index, pmpriv->sec_info.encryption_mode);
+ LEAVE();
+ return index;
+ }
+
+ if ((pbss_desc->bss_mode == mode) &&
+ (pmpriv->sec_info.ewpa_enabled == MTRUE
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ || supplicantIsEnabled(pmpriv->psapriv)
+#endif
+ )) {
+ if (((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
+ ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap) &&
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_GCMP) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_GCMP_256) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP_256)) {
+ if (is_wpa_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_TKIP) ||
+ is_rsn_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else {
+ PRINTM(MINFO,
+ "ewpa_enabled: Ignore none WPA/WPA2 AP\n");
+ LEAVE();
+ return -1;
+ }
+ }
+
+ if (pmpriv->sec_info.wapi_enabled &&
+ (pbss_desc->pwapi_ie &&
+ ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
+ PRINTM(MINFO, "Return success for WAPI AP\n");
+ LEAVE();
+ return index;
+ }
+
+ if (pbss_desc->bss_mode == mode) {
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled &&
+ !pmpriv->sec_info.wpa_enabled &&
+ !pmpriv->sec_info.wpa2_enabled &&
+ ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE)) &&
+ ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE)) &&
+ pmpriv->sec_info.encryption_mode ==
+ MLAN_ENCRYPTION_MODE_NONE &&
+ !pbss_desc->privacy) {
+ /* No security */
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled &&
+ !pmpriv->sec_info.wpa_enabled &&
+ !pmpriv->sec_info.wpa2_enabled &&
+ pbss_desc->privacy) {
+ /* Static WEP enabled */
+ PRINTM(MINFO, "Disable 11n in WEP mode\n");
+ pbss_desc->disable_11n = MTRUE;
+ /* Reject the following cases: */
+ /*
+ * case 1: RSN IE w/o WEP OUI and WPA IE w/o WEP OUI
+ * case 2: RSN IE w/o WEP OUI and No WPA IE
+ * case 3: WPA IE w/o WEP OUI and No RSN IE
+ */
+ if (((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
+ RSN_IE)) ||
+ ((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
+ WPA_IE))) {
+ if (!is_rsn_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_WEP40) &&
+ !is_rsn_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_WEP104) &&
+ !is_wpa_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_WEP40) &&
+ !is_wpa_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_WEP104))
+ index = -1;
+ }
+
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPDisabled &&
+ pmpriv->sec_info.wpa_enabled &&
+ !pmpriv->sec_info.wpa2_enabled &&
+ ((pbss_desc->pwpa_ie) &&
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
+ WPA_IE))
+ /*
+ * Privacy bit may NOT be set in some APs like
+ * LinkSys WRT54G && pbss_desc->privacy
+ */
+ ) {
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ?
+ (*(pbss_desc->pwpa_ie))
+ .vend_hdr.element_id :
+ 0,
+ (pbss_desc->prsn_ie) ?
+ (*(pbss_desc->prsn_ie))
+ .ieee_hdr.element_id :
+ 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ?
+ "e" :
+ "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap) &&
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP)) {
+ if (is_wpa_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPDisabled &&
+ !pmpriv->sec_info.wpa_enabled &&
+ pmpriv->sec_info.wpa2_enabled &&
+ ((pbss_desc->prsn_ie) &&
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
+ RSN_IE))
+ /*
+ * Privacy bit may NOT be set in some APs like
+ * LinkSys WRT54G && pbss_desc->privacy
+ */
+ ) {
+ /* WPA2 enabled */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+ "privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ?
+ (*(pbss_desc->pwpa_ie))
+ .vend_hdr.element_id :
+ 0,
+ (pbss_desc->prsn_ie) ?
+ (*(pbss_desc->prsn_ie))
+ .ieee_hdr.element_id :
+ 0,
+ (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPEnabled) ?
+ "e" :
+ "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ if (((pmpriv->adapter->config_bands & BAND_GN ||
+ pmpriv->adapter->config_bands & BAND_AN) &&
+ pbss_desc->pht_cap) &&
+ (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_GCMP) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_GCMP_256) &&
+ !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
+ CIPHER_SUITE_CCMP_256)) {
+ if (is_rsn_oui_present(pmpriv->adapter,
+ pbss_desc,
+ CIPHER_SUITE_TKIP)) {
+ PRINTM(MINFO,
+ "Disable 11n if AES is not supported by AP\n");
+ pbss_desc->disable_11n = MTRUE;
+ } else if (is_rsn_oui_present_in_wpa_ie(
+ pmpriv, CIPHER_SUITE_CCMP) ||
+ is_rsn_oui_present_in_wpa_ie(
+ pmpriv, CIPHER_SUITE_GCMP) ||
+ is_rsn_oui_present_in_wpa_ie(
+ pmpriv,
+ CIPHER_SUITE_GCMP_256) ||
+ is_rsn_oui_present_in_wpa_ie(
+ pmpriv,
+ CIPHER_SUITE_CCMP_256)) {
+ LEAVE();
+ return index;
+ } else {
+ LEAVE();
+ return -1;
+ }
+ }
+ LEAVE();
+ return index;
+ } else if (pmpriv->sec_info.wep_status ==
+ Wlan802_11WEPDisabled &&
+ !pmpriv->sec_info.wpa_enabled &&
+ !pmpriv->sec_info.wpa2_enabled &&
+ ((!pbss_desc->pwpa_ie) ||
+ ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id !=
+ WPA_IE)) &&
+ ((!pbss_desc->prsn_ie) ||
+ ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id !=
+ RSN_IE)) &&
+ pmpriv->sec_info.encryption_mode !=
+ MLAN_ENCRYPTION_MODE_NONE &&
+ pbss_desc->privacy) {
+ /* Dynamic WEP enabled */
+ pbss_desc->disable_11n = MTRUE;
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x rsn_ie=%#x EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ?
+ (*(pbss_desc->pwpa_ie))
+ .vend_hdr.element_id :
+ 0,
+ (pbss_desc->prsn_ie) ?
+ (*(pbss_desc->prsn_ie))
+ .ieee_hdr.element_id :
+ 0,
+ pmpriv->sec_info.encryption_mode,
+ pbss_desc->privacy);
+ LEAVE();
+ return index;
+ }
+ /* Security doesn't match */
+ PRINTM(MINFO,
+ "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ index,
+ (pbss_desc->pwpa_ie) ?
+ (*(pbss_desc->pwpa_ie)).vend_hdr.element_id :
+ 0,
+ (pbss_desc->prsn_ie) ?
+ (*(pbss_desc->prsn_ie)).ieee_hdr.element_id :
+ 0,
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled) ?
+ "e" :
+ "d",
+ (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
+ (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
+ pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
+ LEAVE();
+ return -1;
+ }
+ /* Mode doesn't match */
+ LEAVE();
+ return -1;
+}
+
+/**
+ * @brief Internal function used to flush the scan list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_flush_scan_table(pmlan_adapter pmadapter)
+{
+ t_u8 i = 0;
+ ENTER();
+
+ PRINTM(MINFO, "Flushing scan table\n");
+
+ memset(pmadapter, pmadapter->pscan_table, 0,
+ (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
+ pmadapter->num_in_scan_table = 0;
+
+ memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+
+ for (i = 0; i < pmadapter->num_in_chan_stats; i++)
+ pmadapter->pchan_stats[i].cca_scan_duration = 0;
+ pmadapter->idx_chan_stats = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param puser_scan_in Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return MLAN_STATUS_SUCCESS or < 0 if error
+ */
+mlan_status wlan_scan_networks(mlan_private *pmpriv, t_void *pioctl_buf,
+ wlan_user_scan_cfg *puser_scan_in)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
+ t_u32 buf_size;
+ ChanScanParamSet_t *pscan_chan_list;
+
+ t_u8 keep_previous_scan;
+ t_u8 filtered_scan;
+ t_u8 scan_current_chan_only;
+ t_u8 max_chan_per_scan;
+ t_u8 i;
+
+ ENTER();
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
+ (t_u8 **)&pscan_cfg_out);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
+ (t_u8 **)&pscan_chan_list);
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
+ PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pscan_cfg_out);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, pscan_chan_list, 0x00, buf_size);
+ memset(pmadapter, pscan_cfg_out, 0x00,
+ sizeof(wlan_scan_cmd_config_tlv));
+
+ keep_previous_scan = MFALSE;
+
+ ret = wlan_scan_setup_scan_config(pmpriv, puser_scan_in,
+ &pscan_cfg_out->config,
+ &pchan_list_out, pscan_chan_list,
+ &max_chan_per_scan, &filtered_scan,
+ &scan_current_chan_only);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to setup scan config\n");
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pscan_cfg_out);
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pscan_chan_list);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (puser_scan_in)
+ keep_previous_scan = puser_scan_in->keep_previous_scan;
+
+ if (keep_previous_scan == MFALSE) {
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ }
+ for (i = 0; i < pmadapter->num_in_chan_stats; i++)
+ pmadapter->pchan_stats[i].cca_scan_duration = 0;
+ pmadapter->idx_chan_stats = 0;
+
+ ret = wlan_scan_channel_list(pmpriv, pioctl_buf, max_chan_per_scan,
+ filtered_scan, &pscan_cfg_out->config,
+ pchan_list_out, pscan_chan_list);
+
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
+ pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->pscan_ioctl_req = pioctl_req;
+ pmadapter->scan_processing = MTRUE;
+ wlan_release_cmd_lock(pmadapter);
+ } else {
+ wlan_request_cmd_lock(pmadapter);
+ if (util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MNULL,
+ MNULL)) {
+ pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
+ pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MNULL,
+ MNULL);
+ pmadapter->pscan_ioctl_req = pioctl_req;
+ pmadapter->scan_processing = MTRUE;
+ wlan_insert_cmd_to_pending_q(pmadapter,
+ pcmd_node, MTRUE);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ }
+ }
+ if (pscan_cfg_out)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
+
+ if (pscan_chan_list)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pscan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_scan(mlan_private *pmpriv, HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
+ wlan_scan_cmd_config *pscan_cfg;
+
+ ENTER();
+
+ pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan_cmd->bss_mode = pscan_cfg->bss_mode;
+ memcpy_ext(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
+ sizeof(pscan_cmd->bssid), sizeof(pscan_cmd->bssid));
+ memcpy_ext(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
+ pscan_cfg->tlv_buf_len, pscan_cfg->tlv_buf_len);
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = (t_u16)wlan_cpu_to_le16(
+ (t_u16)(sizeof(pscan_cmd->bss_mode) + sizeof(pscan_cmd->bssid) +
+ pscan_cfg->tlv_buf_len + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Check if any hidden SSID found in passive scan channels
+ * and do specific SSID active scan for those channels
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MTRUE/MFALSE
+ */
+
+t_bool wlan_active_scan_req_for_passive_chan(mlan_private *pmpriv,
+ mlan_ioctl_req *pioctl_buf)
+{
+ t_bool ret = MFALSE;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_bool scan_reqd = MFALSE;
+ t_bool chan_listed = MFALSE;
+ t_u8 id = 0;
+ t_u32 bss_idx, i;
+ t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ wlan_user_scan_cfg *user_scan_cfg;
+ mlan_ds_scan *pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
+ mlan_scan_req *pscan_req = MNULL;
+ wlan_user_scan_cfg *puser_scan_in = MNULL;
+
+ ENTER();
+
+ if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
+ puser_scan_in = (wlan_user_scan_cfg *)
+ pscan->param.user_scan.scan_cfg_buf;
+ if (!puser_scan_in->ssid_filter)
+ goto done;
+ }
+
+ if (pmadapter->active_scan_triggered) {
+ pmadapter->active_scan_triggered = MFALSE;
+ goto done;
+ }
+
+ if ((pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
+ (t_u8 **)&user_scan_cfg) !=
+ MLAN_STATUS_SUCCESS) ||
+ !user_scan_cfg) {
+ PRINTM(MERROR, "Memory allocation for user_scan_cfg failed\n");
+ goto done;
+ }
+ memset(pmadapter, user_scan_cfg, 0, sizeof(wlan_user_scan_cfg));
+ for (bss_idx = 0; bss_idx < pmadapter->num_in_scan_table; bss_idx++) {
+ scan_reqd = MFALSE;
+ if (!memcmp(pmadapter,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ null_ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len)) {
+ if (puser_scan_in &&
+ puser_scan_in->chan_list[0].chan_number) {
+ for (i = 0;
+ i < WLAN_USER_SCAN_CHAN_MAX &&
+ puser_scan_in->chan_list[i].chan_number;
+ i++) {
+ if (puser_scan_in->chan_list[i]
+ .chan_number ==
+ pmadapter->pscan_table[bss_idx]
+ .channel) {
+ if (puser_scan_in->chan_list[i]
+ .scan_type ==
+ MLAN_SCAN_TYPE_PASSIVE)
+ scan_reqd = MTRUE;
+ break;
+ }
+ }
+ } else if (pmadapter->scan_type ==
+ MLAN_SCAN_TYPE_PASSIVE) {
+ scan_reqd = MTRUE;
+ } else {
+ if ((pmadapter->pscan_table[bss_idx].bss_band &
+ BAND_A) &&
+ wlan_11h_radar_detect_required(
+ pmpriv,
+ pmadapter->pscan_table[bss_idx]
+ .channel))
+ scan_reqd = MTRUE;
+ if (pmadapter->pscan_table[bss_idx].bss_band &
+ (BAND_B | BAND_G) &&
+ wlan_bg_scan_type_is_passive(
+ pmpriv,
+ pmadapter->pscan_table[bss_idx]
+ .channel))
+ scan_reqd = MTRUE;
+ }
+
+ if (scan_reqd) {
+ chan_listed = MFALSE;
+ for (i = 0; i < id; i++) {
+ if ((user_scan_cfg->chan_list[i]
+ .chan_number ==
+ pmadapter->pscan_table[bss_idx]
+ .channel) &&
+ (user_scan_cfg->chan_list[i]
+ .radio_type &
+ pmadapter->pscan_table[bss_idx]
+ .bss_band)) {
+ chan_listed = MTRUE;
+ break;
+ }
+ }
+ if (chan_listed == MTRUE)
+ continue;
+ user_scan_cfg->chan_list[id].chan_number =
+ pmadapter->pscan_table[bss_idx].channel;
+ if (pmadapter->pscan_table[bss_idx].bss_band &
+ (BAND_B | BAND_G))
+ user_scan_cfg->chan_list[id].radio_type =
+ BAND_2GHZ;
+ if (pmadapter->pscan_table[bss_idx].bss_band &
+ BAND_A)
+ user_scan_cfg->chan_list[id].radio_type =
+ BAND_5GHZ;
+ user_scan_cfg->chan_list[id].scan_type =
+ MLAN_SCAN_TYPE_ACTIVE;
+ id++;
+ }
+ }
+ }
+ if (id) {
+ pmadapter->active_scan_triggered = MTRUE;
+ if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
+ memcpy_ext(pmpriv->adapter, user_scan_cfg->ssid_list,
+ puser_scan_in->ssid_list,
+ sizeof(user_scan_cfg->ssid_list),
+ sizeof(user_scan_cfg->ssid_list));
+ } else {
+ pscan_req = &pscan->param.scan_req;
+ memcpy_ext(pmpriv->adapter,
+ user_scan_cfg->ssid_list[0].ssid,
+ pscan_req->scan_ssid.ssid,
+ pscan_req->scan_ssid.ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ }
+ user_scan_cfg->keep_previous_scan = MTRUE;
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_scan_networks(pmpriv, pioctl_buf, user_scan_cfg)) {
+ goto done;
+ }
+ ret = MTRUE;
+ }
+ if (user_scan_cfg)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)user_scan_cfg);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-------------------------------------------------------------.
+ * | Header (4 * sizeof(t_u16)): Standard command response hdr |
+ * .-------------------------------------------------------------.
+ * | BufSize (t_u16) : sizeof the BSS Description data |
+ * .-------------------------------------------------------------.
+ * | NumOfSet (t_u8) : Number of BSS Descs returned |
+ * .-------------------------------------------------------------.
+ * | BSSDescription data (variable, size given in BufSize) |
+ * .-------------------------------------------------------------.
+ * | TLV data (variable, size calculated using Header->Size, |
+ * | BufSize and sizeof the fixed fields above) |
+ * .-------------------------------------------------------------.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_scan(mlan_private *pmpriv, HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ MrvlIEtypes_Data_t *ptlv;
+ MrvlIEtypes_TsfTimestamp_t *ptsf_tlv = MNULL;
+ MrvlIEtypes_ChannelStats_t *pchanstats_tlv = MNULL;
+ t_u8 *pbss_info;
+ t_u32 scan_resp_size;
+ t_u32 bytes_left;
+ t_u32 num_in_table;
+ t_u32 bss_idx;
+ t_u32 idx;
+ t_u32 tlv_buf_size;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
+ ChanBandParamSet_t *pchan_band;
+ t_u8 band;
+ t_u8 is_bgscan_resp;
+ t_u32 age_ts_usec;
+ t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
+ t_u32 status_code = 0;
+ pmlan_ioctl_req pscan_ioctl_req = MNULL;
+
+ ENTER();
+ pcb = (pmlan_callbacks)&pmadapter->callbacks;
+
+ is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ if (is_bgscan_resp)
+ pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+ else
+ pscan_rsp = &resp->params.scan_resp;
+
+ if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR,
+ "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan_rsp->number_of_sets);
+ status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
+ PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
+
+ scan_resp_size = resp->size;
+
+ PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
+ pscan_rsp->number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
+
+ /*
+ * The size of the TLV buffer is equal to the entire command response
+ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bss_descript_size as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlv_buf_size = scan_resp_size -
+ (bytes_left + sizeof(pscan_rsp->bss_descript_size) +
+ sizeof(pscan_rsp->number_of_sets) + S_DS_GEN);
+ if (is_bgscan_resp)
+ tlv_buf_size -= sizeof(
+ resp->params.bg_scan_query_resp.report_condition);
+
+ ptlv = (MrvlIEtypes_Data_t *)(pscan_rsp->bss_desc_and_tlv_buffer +
+ bytes_left);
+
+ /*
+ * Search the TLV buffer space in the scan response
+ * for any valid TLVs
+ */
+ wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter, ptlv, tlv_buf_size,
+ TLV_TYPE_TSFTIMESTAMP,
+ (MrvlIEtypes_Data_t **)&ptsf_tlv);
+
+ /*
+ * Search the TLV buffer space in the scan response
+ * for any valid TLVs
+ */
+ wlan_ret_802_11_scan_get_tlv_ptrs(
+ pmadapter, ptlv, tlv_buf_size, TLV_TYPE_CHANNELBANDLIST,
+ (MrvlIEtypes_Data_t **)&pchan_band_tlv);
+ wlan_ret_802_11_scan_get_tlv_ptrs(
+ pmadapter, ptlv, tlv_buf_size, TLV_TYPE_CHANNEL_STATS,
+ (MrvlIEtypes_Data_t **)&pchanstats_tlv);
+
+ if (pchanstats_tlv)
+ wlan_update_chan_statistics(pmpriv, pchanstats_tlv);
+
+ /*
+ * Process each scan response returned (pscan_rsp->number_of_sets).
+ * Save the information in the bss_new_entry and then insert into
+ * the driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(
+ pmadapter, bss_new_entry, &pbss_info, &bytes_left,
+ MFALSE) == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "SCAN_RESP: BSSID = " MACSTR "\n",
+ MAC2STR(bss_new_entry->mac_address));
+
+ band = BAND_G;
+ if (pchan_band_tlv) {
+ pchan_band =
+ &pchan_band_tlv->chan_band_param[idx];
+ band = radio_type_to_band(
+ pchan_band->bandcfg.chanBand);
+ if (!bss_new_entry->channel)
+ bss_new_entry->channel =
+ pchan_band->chan_number;
+ }
+ /*
+ * Save the band designation for this entry
+ * for use in join
+ */
+ bss_new_entry->bss_band = band;
+
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, (t_u8)bss_new_entry->bss_band,
+ (t_u16)bss_new_entry->channel);
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Skip entry if on blacklisted channel */
+ if (cfp && cfp->dynamic.blacklist) {
+ PRINTM(MINFO,
+ "SCAN_RESP: dropping entry on blacklist channel.\n");
+ continue;
+ }
+
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter,
+ bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx]
+ .mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a
+ * duplicate of this entry. Keep the
+ * bss_idx set to this entry so we
+ * replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx]
+ .ssid.ssid_len) &&
+ (!memcmp(
+ pmadapter,
+ bss_new_entry->ssid.ssid,
+ pmadapter
+ ->pscan_table[bss_idx]
+ .ssid.ssid,
+ bss_new_entry->ssid
+ .ssid_len))) {
+ PRINTM(MINFO,
+ "SCAN_RESP: Duplicate of index: %d\n",
+ bss_idx);
+
+ break;
+ }
+ /*
+ * If the SSID is NULL for same BSSID
+ * keep the bss_idx set to this entry
+ * so we replace the old contents in
+ * the table
+ */
+ if (!memcmp(pmadapter,
+ pmadapter
+ ->pscan_table[bss_idx]
+ .ssid.ssid,
+ null_ssid,
+ pmadapter
+ ->pscan_table[bss_idx]
+ .ssid.ssid_len)) {
+ PRINTM(MINFO,
+ "SCAN_RESP: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries
+ * in the table, the new entry was not a duplicate;
+ * append it to the scan table
+ */
+ if (bss_idx == num_in_table) {
+ /*
+ * Range check the bss_idx, keep it limited
+ * to the last entry
+ */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST)
+ bss_idx--;
+ else
+ num_in_table++;
+ } else {
+ if ((bss_new_entry->channel !=
+ pmadapter->pscan_table[bss_idx].channel) &&
+ (bss_new_entry->rssi >
+ pmadapter->pscan_table[bss_idx].rssi)) {
+ PRINTM(MCMND,
+ "skip update the duplicate entry with low rssi\n");
+ continue;
+ }
+ }
+ /*
+ * Save the beacon/probe response returned for later
+ * application retrieval. Duplicate beacon/probe
+ * responses are updated if possible
+ */
+ wlan_ret_802_11_scan_store_beacon(
+ pmpriv, bss_idx, num_in_table, bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND,
+ "No space for beacon, drop this entry\n");
+ num_in_table--;
+ continue;
+ }
+ /*
+ * If the TSF TLV was appended to the scan results, save
+ * this entry's TSF value in the networkTSF field. The
+ * networkTSF is the firmware's TSF value at the time
+ * the beacon or probe response was received.
+ */
+ if (ptsf_tlv) {
+ memcpy_ext(
+ pmpriv->adapter, &tsf_val,
+ &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(tsf_val), sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy_ext(pmpriv->adapter,
+ &bss_new_entry->network_tsf,
+ &tsf_val,
+ sizeof(bss_new_entry->network_tsf),
+ sizeof(bss_new_entry->network_tsf));
+ }
+
+ /* Copy the locally created bss_new_entry to the scan
+ * table */
+ memcpy_ext(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry,
+ sizeof(pmadapter->pscan_table[bss_idx]),
+ sizeof(pmadapter->pscan_table[bss_idx]));
+
+ } else {
+ /* Error parsing/interpreting the scan response, skipped
+ */
+ PRINTM(MERROR,
+ "SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan_rsp->number_of_sets,
+ num_in_table - pmadapter->num_in_scan_table, num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &pmadapter->age_in_secs, &age_ts_usec);
+ if (is_bgscan_resp)
+ goto done;
+ wlan_request_cmd_lock(pmadapter);
+ if (!util_peek_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q,
+ MNULL, MNULL)) {
+ wlan_release_cmd_lock(pmadapter);
+ if (pmadapter->pscan_ioctl_req) {
+ if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_SPECIFIC_SSID ||
+ ((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_USER_CONFIG) {
+ if (wlan_active_scan_req_for_passive_chan(
+ pmpriv,
+ pmadapter->pscan_ioctl_req)) {
+ goto done;
+ }
+ }
+ }
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pscan_ioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ /* Need to indicate IOCTL complete */
+ if (pscan_ioctl_req) {
+ pscan_ioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ (pmlan_ioctl_req)pscan_ioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ pmadapter->bgscan_reported = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ wlan_release_cmd_lock(pmadapter);
+ status_code = MLAN_ERROR_FW_NOT_READY;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ * cmd_pending_q */
+ pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
+ pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MNULL, MNULL);
+ wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
+ MTRUE);
+ wlan_release_cmd_lock(pmadapter);
+ }
+ }
+
+done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
+ if (ret) {
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pscan_ioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ if (pscan_ioctl_req) {
+ pscan_ioctl_req->status_code = status_code;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pscan_ioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Prepare an extended scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN_EXT command
+ * struct to send to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure to be sent to
+ * firmware with the HostCmd_DS_802_11_SCAN_EXT structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_scan_ext(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan;
+ wlan_scan_cmd_config *pscan_cfg = MNULL;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
+
+ if (pmpriv->adapter->ext_scan_enh == MTRUE) {
+ if (pdata_buf) {
+ if (pmpriv->adapter->ext_scan_type == EXT_SCAN_ENHANCE)
+ pext_scan_cmd->ext_scan_type = EXT_SCAN_ENHANCE;
+ else
+ pext_scan_cmd->ext_scan_type = EXT_SCAN_DEFAULT;
+ } else {
+ pcmd->size = wlan_cpu_to_le16((t_u16)(
+ sizeof(pext_scan_cmd->ext_scan_type) +
+ (t_u16)(sizeof(pext_scan_cmd->reserved)) +
+ S_DS_GEN));
+ pext_scan_cmd->ext_scan_type = EXT_SCAN_CANCEL;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
+
+ memcpy_ext(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
+ pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len,
+ pscan_cfg->tlv_buf_len);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ pcmd->size = wlan_cpu_to_le16(
+ (t_u16)(sizeof(pext_scan_cmd->ext_scan_type) +
+ (t_u16)sizeof(pext_scan_cmd->reserved) +
+ pscan_cfg->tlv_buf_len + S_DS_GEN));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_scan_ext(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ t_void *pioctl_buf)
+{
+ HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &(resp->params.ext_scan);
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ MrvlIEtypes_ChannelStats_t *tlv_chanstats = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ t_u32 ext_scan_type;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ pmlan_ioctl_req pioctl_req = (pmlan_ioctl_req)pioctl_buf;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+
+ PRINTM(MINFO, "EXT scan returns successfully\n");
+ ext_scan_type = pext_scan_cmd->ext_scan_type;
+ if (ext_scan_type == EXT_SCAN_CANCEL) {
+ PRINTM(MCMND, "Cancel scan command completed!\n");
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
+ wlan_release_cmd_lock(pmadapter);
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_STATUS_SUCCESS;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ (pmlan_ioctl_req)pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ } else if (ext_scan_type == EXT_SCAN_ENHANCE) {
+ /* Setup the timer after scan command response */
+ pcb->moal_start_timer(pmpriv->adapter->pmoal_handle,
+ pmpriv->adapter->pmlan_cmd_timer, MFALSE,
+ MRVDRV_TIMER_10S * 2);
+ pmpriv->adapter->cmd_timer_is_set = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ tlv = (MrvlIEtypesHeader_t *)pext_scan_cmd->tlv_buffer;
+ tlv_buf_left = resp->size -
+ (sizeof(HostCmd_DS_802_11_SCAN_EXT) - 1 + S_DS_GEN);
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR, "Error processing scan gap TLV\n");
+ break;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_CHANNEL_STATS:
+ tlv_chanstats = (MrvlIEtypes_ChannelStats_t *)tlv;
+ wlan_update_chan_statistics(pmpriv, tlv_chanstats);
+ break;
+ default:
+ break;
+ }
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function add a new entry to scan_table
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bss_new_entry A pointer to the bss_new_entry
+ * @param num_in_tbl number of scan entry in scan_table
+ *
+ * @return N/A
+ */
+t_void wlan_add_new_entry_to_scan_table(mlan_private *pmpriv,
+ BSSDescriptor_t *bss_new_entry,
+ t_u32 *num_in_tbl)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u32 bss_idx;
+ t_u32 num_in_table = *num_in_tbl;
+ t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = {0};
+
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (!memcmp(pmadapter, bss_new_entry->mac_address,
+ pmadapter->pscan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ /*
+ * If the SSID matches as well, it is a
+ * duplicate of this entry. Keep the
+ * bss_idx set to this entry so we
+ * replace the old contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len ==
+ pmadapter->pscan_table[bss_idx].ssid.ssid_len) &&
+ (!memcmp(pmadapter, bss_new_entry->ssid.ssid,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ PRINTM(MINFO,
+ "EXT_SCAN: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ /*
+ * If the SSID is NULL for same BSSID
+ * keep the bss_idx set to this entry
+ * so we replace the old contents in
+ * the table
+ */
+ if (!memcmp(pmadapter,
+ pmadapter->pscan_table[bss_idx].ssid.ssid,
+ null_ssid,
+ pmadapter->pscan_table[bss_idx]
+ .ssid.ssid_len)) {
+ PRINTM(MINFO,
+ "EXT_SCAN: Duplicate of index: %d\n",
+ bss_idx);
+ break;
+ }
+ }
+ }
+ /* If the bss_idx is equal to the number of entries
+ * in the table, the new entry was not a duplicate;
+ * append it to the scan table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to the last entry */
+ if (bss_idx == MRVDRV_MAX_BSSID_LIST)
+ bss_idx--;
+ else
+ num_in_table++;
+ } else {
+ if ((bss_new_entry->channel !=
+ pmadapter->pscan_table[bss_idx].channel) &&
+ (bss_new_entry->rssi >
+ pmadapter->pscan_table[bss_idx].rssi)) {
+ PRINTM(MCMND,
+ "skip update the duplicate entry with low rssi\n");
+ return;
+ }
+ }
+ /*
+ * Save the beacon/probe response returned for later
+ * application retrieval. Duplicate beacon/probe
+ * responses are updated if possible
+ */
+ wlan_ret_802_11_scan_store_beacon(pmpriv, bss_idx, num_in_table,
+ bss_new_entry);
+ if (bss_new_entry->pbeacon_buf == MNULL) {
+ PRINTM(MCMND, "No space for beacon, drop this entry\n");
+ num_in_table--;
+ goto done;
+ } else {
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy_ext(pmadapter, &pmadapter->pscan_table[bss_idx],
+ bss_new_entry,
+ sizeof(pmadapter->pscan_table[bss_idx]),
+ sizeof(pmadapter->pscan_table[bss_idx]));
+ }
+done:
+ *num_in_tbl = num_in_table;
+ return;
+}
+
+/**
+ * @brief This function parse and store the extended scan results
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param number_of_sets Number of BSS
+ * @param pscan_resp A pointer to scan response buffer
+ * @param scan_resp_size Size of scan response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_parse_ext_scan_result(mlan_private *pmpriv,
+ t_u8 number_of_sets,
+ t_u8 *pscan_resp,
+ t_u16 scan_resp_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = MNULL;
+ BSSDescriptor_t *bss_new_entry = MNULL;
+ t_u8 *pbss_info;
+ t_u32 bytes_left;
+ t_u32 bytes_left_for_tlv;
+ t_u32 num_in_table;
+ t_u32 idx;
+ t_u64 tsf_val;
+ chan_freq_power_t *cfp;
+ t_u16 tlv_type, tlv_len;
+ MrvlIEtypes_Data_t *ptlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Rsp_t *pscan_rsp_tlv = MNULL;
+ MrvlIEtypes_Bss_Scan_Info_t *pscan_info_tlv = MNULL;
+ t_u8 band;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ pcb = (pmlan_callbacks)&pmadapter->callbacks;
+
+ if (number_of_sets > MRVDRV_MAX_BSSID_LIST) {
+ PRINTM(MERROR,
+ "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ number_of_sets);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bytes_left = scan_resp_size;
+ PRINTM(MINFO, "EXT_SCAN: bss_descript_size %d\n", scan_resp_size);
+ PRINTM(MINFO, "EXT_SCAN: returned %d APs before parsing\n",
+ number_of_sets);
+
+ num_in_table = pmadapter->num_in_scan_table;
+ ptlv = (MrvlIEtypes_Data_t *)pscan_resp;
+
+ /*
+ * Process each scan response returned number_of_sets. Save
+ * the information in the bss_new_entry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
+ MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
+
+ if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
+ PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ for (idx = 0;
+ idx < number_of_sets && bytes_left > sizeof(MrvlIEtypesHeader_t);
+ idx++) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR,
+ "EXT_SCAN: Error bytes left < TLV length\n");
+ break;
+ }
+ pscan_rsp_tlv = MNULL;
+ pscan_info_tlv = MNULL;
+ bytes_left_for_tlv = bytes_left;
+ /*
+ * BSS response TLV with beacon or probe response buffer
+ * at the initial position of each descriptor
+ */
+ if (tlv_type == TLV_TYPE_BSS_SCAN_RSP) {
+ pbss_info = (t_u8 *)ptlv;
+ pscan_rsp_tlv = (MrvlIEtypes_Bss_Scan_Rsp_t *)ptlv;
+ ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
+ bytes_left_for_tlv -=
+ (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ } else
+ break;
+
+ /* Process variable TLV */
+ while (bytes_left_for_tlv >= sizeof(MrvlIEtypesHeader_t) &&
+ wlan_le16_to_cpu(ptlv->header.type) !=
+ TLV_TYPE_BSS_SCAN_RSP) {
+ tlv_type = wlan_le16_to_cpu(ptlv->header.type);
+ tlv_len = wlan_le16_to_cpu(ptlv->header.len);
+ if (bytes_left_for_tlv <
+ sizeof(MrvlIEtypesHeader_t) + tlv_len) {
+ PRINTM(MERROR,
+ "EXT_SCAN: Error in processing TLV, "
+ "bytes left < TLV length\n");
+ pscan_rsp_tlv = MNULL;
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_BSS_SCAN_INFO:
+ pscan_info_tlv =
+ (MrvlIEtypes_Bss_Scan_Info_t *)ptlv;
+ if (tlv_len !=
+ sizeof(MrvlIEtypes_Bss_Scan_Info_t) -
+ sizeof(MrvlIEtypesHeader_t)) {
+ bytes_left_for_tlv = 0;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
+ bytes_left -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ bytes_left_for_tlv -=
+ (tlv_len + sizeof(MrvlIEtypesHeader_t));
+ }
+ /* No BSS response TLV */
+ if (pscan_rsp_tlv == MNULL)
+ break;
+
+ /*
+ * Advance pointer to the beacon buffer length and
+ * update the bytes count so that the function
+ * wlan_interpret_bss_desc_with_ie() can handle the
+ * scan buffer withut any change
+ */
+ pbss_info += sizeof(t_u16);
+ bytes_left -= sizeof(t_u16);
+
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if (wlan_interpret_bss_desc_with_ie(
+ pmadapter, bss_new_entry, &pbss_info, &bytes_left,
+ MTRUE) == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "EXT_SCAN: BSSID = " MACSTR "\n",
+ MAC2STR(bss_new_entry->mac_address));
+
+ band = BAND_G;
+ /*
+ * If the BSS info TLV was appended to the scan results,
+ * save this entry's TSF value in the networkTSF field.
+ * The networkTSF is the firmware's TSF value at the
+ * time the beacon or probe response was received.
+ */
+ if (pscan_info_tlv) {
+ /* RSSI is 2 byte long */
+ bss_new_entry->rssi = -(t_s32)(
+ wlan_le16_to_cpu(pscan_info_tlv->rssi));
+ PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n",
+ bss_new_entry->rssi);
+ memcpy_ext(pmpriv->adapter, &tsf_val,
+ &pscan_info_tlv->tsf,
+ sizeof(tsf_val), sizeof(tsf_val));
+ tsf_val = wlan_le64_to_cpu(tsf_val);
+ memcpy_ext(pmpriv->adapter,
+ &bss_new_entry->network_tsf,
+ &tsf_val,
+ sizeof(bss_new_entry->network_tsf),
+ sizeof(bss_new_entry->network_tsf));
+ band = radio_type_to_band(
+ pscan_info_tlv->bandcfg.chanBand);
+ if (!bss_new_entry->channel)
+ bss_new_entry->channel =
+ pscan_info_tlv->channel;
+ }
+ /* Save the band designation for this entry for use in
+ * join */
+ bss_new_entry->bss_band = band;
+
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, (t_u8)bss_new_entry->bss_band,
+ (t_u16)bss_new_entry->channel);
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Skip entry if on blacklisted channel */
+ if (cfp && cfp->dynamic.blacklist) {
+ PRINTM(MINFO,
+ "EXT_SCAN: dropping entry on blacklist channel.\n");
+ continue;
+ }
+ wlan_add_new_entry_to_scan_table(pmpriv, bss_new_entry,
+ &num_in_table);
+
+ } else {
+ /* Error parsing/interpreting the scan response, skipped
+ */
+ PRINTM(MERROR,
+ "EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
+ }
+ }
+
+ PRINTM(MCMND, "EXT_SCAN: Scanned %2d APs, %d valid, %d total\n",
+ number_of_sets, num_in_table - pmadapter->num_in_scan_table,
+ num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ pmadapter->num_in_scan_table = num_in_table;
+ /* Update the age_in_second */
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &pmadapter->age_in_secs, &age_ts_usec);
+
+done:
+ if (bss_new_entry)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the event extended scan report
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_handle_event_ext_scan_report(mlan_private *pmpriv,
+ mlan_buffer *pmbuf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = &pmadapter->callbacks;
+ mlan_ioctl_req *pioctl_req = MNULL;
+ cmd_ctrl_node *pcmd_node = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ mlan_event_scan_result *pevent_scan =
+ (pmlan_event_scan_result)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 *ptlv = (pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(mlan_event_scan_result));
+ t_u16 tlv_buf_left = wlan_le16_to_cpu(pevent_scan->buf_size);
+
+ DBG_HEXDUMP(MCMD_D, "EVENT EXT_SCAN", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set, ptlv,
+ tlv_buf_left);
+ if (!pevent_scan->more_event &&
+ (pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)) {
+ wlan_request_cmd_lock(pmadapter);
+ if (!util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MNULL, MNULL)) {
+ wlan_release_cmd_lock(pmadapter);
+ if (pmadapter->pscan_ioctl_req) {
+ if (((mlan_ds_scan *)
+ pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_SPECIFIC_SSID ||
+ ((mlan_ds_scan *)
+ pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_USER_CONFIG) {
+ if (wlan_active_scan_req_for_passive_chan(
+ pmpriv,
+ pmadapter->pscan_ioctl_req)) {
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ (pmlan_ioctl_req)pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_release_cmd_lock(pmadapter);
+
+ pmadapter->bgscan_reported = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT,
+ MNULL);
+ } else {
+ /* If firmware not ready, do not issue any more scan
+ * commands */
+ if (pmadapter->hw_status != WlanHardwareStatusReady) {
+ wlan_release_cmd_lock(pmadapter);
+ /* Flush all pending scan commands */
+ wlan_flush_scan_queue(pmadapter);
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ /* Indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code =
+ MLAN_ERROR_FW_NOT_READY;
+
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ (pmlan_ioctl_req)pioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ } else {
+ /* Get scan command from scan_pending_q and put
+ * to cmd_pending_q */
+ pcmd_node = (cmd_ctrl_node *)util_dequeue_list(
+ pmadapter->pmoal_handle,
+ &pmadapter->scan_pending_q, MNULL,
+ MNULL);
+ wlan_insert_cmd_to_pending_q(pmadapter,
+ pcmd_node, MTRUE);
+ wlan_release_cmd_lock(pmadapter);
+ }
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the event extended scan status
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pmbuf A pointer to mlan_buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_handle_event_ext_scan_status(mlan_private *pmpriv,
+ mlan_buffer *pmbuf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_event_scan_status *scan_event;
+ mlan_ioctl_req *pioctl_req;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+ t_u16 tlv_buf_left, tlv_len, tlv_type;
+ MrvlIEtypesHeader_t *tlv;
+ MrvlIEtypes_ChannelStats_t *tlv_chan_stats;
+ t_u8 status;
+
+ ENTER();
+
+ if (pmbuf->data_len < sizeof(mlan_event_scan_status)) {
+ PRINTM(MERROR, "Wrong ext scan status event data length\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan_event =
+ (pmlan_event_scan_status)(pmbuf->pbuf + pmbuf->data_offset);
+ DBG_HEXDUMP(MCMD_D, "EVENT: Ext_Scan_Status", scan_event,
+ pmbuf->data_len);
+ status = scan_event->scan_status;
+ PRINTM(MEVENT, "ext_scan_status: status %d (scan %s), buf_len %d\n",
+ status, status ? "cancelled" : "success", scan_event->buf_len);
+
+ tlv = (MrvlIEtypesHeader_t *)scan_event->event_buf;
+ tlv_buf_left = pmbuf->data_len - sizeof(mlan_event_scan_status);
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error process scan gap tlv: length %d type 0x%x\n",
+ tlv_len, tlv_type);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ switch (tlv_type) {
+ case TLV_TYPE_CHANNEL_STATS:
+ tlv_chan_stats = (MrvlIEtypes_ChannelStats_t *)tlv;
+ wlan_update_chan_statistics(pmpriv, tlv_chan_stats);
+ break;
+ default:
+ break;
+ }
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+done:
+ /* Now we got response from FW, cancel the command timer */
+ if (!pmadapter->curr_cmd && pmadapter->cmd_timer_is_set) {
+ /* Cancel command timeout timer */
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pmadapter->pmlan_cmd_timer);
+ /* Cancel command timeout timer */
+ pmadapter->cmd_timer_is_set = MFALSE;
+ }
+ if (pmadapter->pscan_ioctl_req) {
+ if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_SPECIFIC_SSID ||
+ ((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)
+ ->sub_command ==
+ MLAN_OID_SCAN_USER_CONFIG) {
+ if (wlan_active_scan_req_for_passive_chan(
+ pmpriv, pmadapter->pscan_ioctl_req)) {
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(pmpriv);
+ /** Complete scan ioctl */
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
+ pioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ /* Need to indicate IOCTL complete */
+ if (pioctl_req != MNULL) {
+ pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req,
+ MLAN_STATUS_SUCCESS);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ pmadapter->bgscan_reported = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_query.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_802_11_bg_scan_query(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) +
+ S_DS_GEN);
+
+ bg_query->flush = MTRUE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pbg_scan_in pointer to scan configuration parameters
+ * @param tlv_chan_list A pointer to structure
+ * MrvlIEtypes_ChanListParamSet_t
+ *
+ * @return channel number
+ */
+static t_u8
+wlan_bgscan_create_channel_list(mlan_private *pmpriv,
+ const wlan_bgscan_cfg *pbg_scan_in,
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ region_chan_t *pscan_region;
+ chan_freq_power_t *cfp;
+ t_u32 region_idx;
+ t_u32 chan_idx = 0;
+ t_u32 next_chan;
+ t_u8 scan_type;
+ t_u8 radio_type;
+ t_u8 band;
+
+ ENTER();
+
+ for (region_idx = 0; region_idx < NELEMENTS(pmadapter->region_channel);
+ region_idx++) {
+ if (wlan_11d_is_enabled(pmpriv) &&
+ pmpriv->media_connected != MTRUE) {
+ /* Scan all the supported chan for the first scan */
+ if (!pmadapter->universal_channel[region_idx].valid)
+ continue;
+ pscan_region =
+ &pmadapter->universal_channel[region_idx];
+ } else {
+ if (!pmadapter->region_channel[region_idx].valid)
+ continue;
+ pscan_region = &pmadapter->region_channel[region_idx];
+ }
+
+ if (pbg_scan_in && !pbg_scan_in->chan_list[0].chan_number &&
+ pbg_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
+ radio_type = pbg_scan_in->chan_list[0].radio_type &
+ ~BAND_SPECIFIED;
+ if (!radio_type && (pscan_region->band != BAND_B) &&
+ (pscan_region->band != BAND_G))
+ continue;
+ if (radio_type && (pscan_region->band != BAND_A))
+ continue;
+ }
+ if ((pbg_scan_in &&
+ (pbg_scan_in->bss_type == MLAN_SCAN_MODE_IBSS)) ||
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ band = pmadapter->adhoc_start_band;
+ else
+ band = pmpriv->config_bands;
+ if (!wlan_is_band_compatible(band, pscan_region->band))
+ continue;
+ for (next_chan = 0; next_chan < pscan_region->num_cfp;
+ next_chan++, chan_idx++) {
+ if (chan_idx >= WLAN_BG_SCAN_CHAN_MAX)
+ break;
+ /*
+ * Set the default scan type to ACTIVE SCAN type, will
+ * later be changed to passive on a per channel basis
+ * if restricted by regulatory requirements (11d or 11h)
+ */
+ scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ cfp = pscan_region->pcfp + next_chan;
+
+ switch (pscan_region->band) {
+ case BAND_A:
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .bandcfg.chanBand = BAND_5GHZ;
+ /* Passive scan on DFS channels */
+ if (wlan_11h_radar_detect_required(
+ pmpriv, (t_u8)cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ break;
+ case BAND_B:
+ case BAND_G:
+ if (wlan_bg_scan_type_is_passive(
+ pmpriv, (t_u8)cfp->channel))
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .bandcfg.chanBand = BAND_2GHZ;
+ break;
+ default:
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .bandcfg.chanBand = BAND_2GHZ;
+ break;
+ }
+
+ if (pbg_scan_in &&
+ pbg_scan_in->chan_list[0].scan_time) {
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .max_scan_time = wlan_cpu_to_le16(
+ (t_u16)pbg_scan_in->chan_list[0]
+ .scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .min_scan_time = wlan_cpu_to_le16(
+ (t_u16)pbg_scan_in->chan_list[0]
+ .scan_time);
+ } else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .max_scan_time = wlan_cpu_to_le16(
+ pmadapter->passive_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .min_scan_time = wlan_cpu_to_le16(
+ pmadapter->passive_scan_time);
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .max_scan_time = wlan_cpu_to_le16(
+ pmadapter->specific_scan_time);
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .min_scan_time = wlan_cpu_to_le16(
+ pmadapter->specific_scan_time);
+ }
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .chan_scan_mode.passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_idx]
+ .chan_scan_mode.passive_scan = MFALSE;
+ }
+
+ tlv_chan_list->chan_scan_param[chan_idx].chan_number =
+ (t_u8)cfp->channel;
+ }
+ }
+
+ LEAVE();
+ return chan_idx;
+}
+
+/**
+ * @brief This function prepares command of bg_scan_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_bgscan_config(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *pcmd, t_void *pdata_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
+ &pcmd->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_in = (wlan_bgscan_cfg *)pdata_buf;
+ t_u16 cmd_size = 0;
+ MrvlIEtypes_NumProbes_t *pnum_probes_tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_tlv = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
+ MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ MrvlIEtypes_StartLater_t *tlv_start_later = MNULL;
+ MrvlIEtypes_RepeatCount_t *tlv_repeat = MNULL;
+ MrvlIEtypes_EESParamSet_t *tlv_ees_cfg = MNULL;
+ MrvlIEtype_EESNetworkCfg_t *tlv_ees_net_cfg = MNULL;
+ MrvlIEtypes_Cipher_t *tlv_ees_cipher = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIETypes_HTCap_t *pht_cap = MNULL;
+ MrvlIETypes_VHTCap_t *pvht_cap = MNULL;
+ MrvlIEtypes_Extension_t *phe_cap = MNULL;
+ t_u16 len = 0;
+
+ t_u8 index;
+ t_u8 *tlv = MNULL;
+ t_u16 num_probes = 0;
+ t_u32 ssid_idx;
+ t_u32 ssid_len = 0;
+ t_u32 chan_idx;
+ t_u32 chan_num;
+ t_u8 radio_type;
+ t_u16 scan_dur;
+ t_u8 scan_type;
+ t_u8 band;
+ const t_u8 zero_mac[6] = {0, 0, 0, 0, 0, 0};
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+ bg_scan->action = wlan_cpu_to_le16(bg_scan_in->action);
+ bg_scan->enable = bg_scan_in->enable;
+ bg_scan->bss_type = bg_scan_in->bss_type;
+ cmd_size = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG) + S_DS_GEN;
+ if (bg_scan_in->scan_interval)
+ bg_scan->scan_interval =
+ wlan_cpu_to_le32(bg_scan_in->scan_interval);
+ else
+ bg_scan->scan_interval =
+ wlan_cpu_to_le32(DEFAULT_BGSCAN_INTERVAL);
+ bg_scan->report_condition =
+ wlan_cpu_to_le32(bg_scan_in->report_condition);
+
+ if ((bg_scan_in->action == BG_SCAN_ACT_GET) ||
+ (bg_scan_in->action == BG_SCAN_ACT_GET_PPS_UAPSD) ||
+ (!bg_scan->enable))
+ goto done;
+
+ tlv = (t_u8 *)bg_scan + sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
+ num_probes = (bg_scan_in->num_probes ? bg_scan_in->num_probes :
+ pmadapter->scan_probes);
+ if (num_probes) {
+ pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)tlv;
+ pnum_probes_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnum_probes_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(pnum_probes_tlv->num_probes));
+ pnum_probes_tlv->num_probes =
+ wlan_cpu_to_le16((t_u16)num_probes);
+ tlv += sizeof(MrvlIEtypes_NumProbes_t);
+ cmd_size += sizeof(MrvlIEtypes_NumProbes_t);
+ }
+ if (bg_scan_in->rssi_threshold) {
+ rssi_tlv = (MrvlIEtypes_BeaconLowRssiThreshold_t *)tlv;
+ rssi_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_tlv->value = bg_scan_in->rssi_threshold;
+ rssi_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (bg_scan_in->snr_threshold) {
+ snr_tlv = (MrvlIEtypes_BeaconLowSnrThreshold_t *)tlv;
+ snr_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_tlv->value = bg_scan_in->snr_threshold;
+ snr_tlv->frequency = 0;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (bg_scan_in->repeat_count) {
+ tlv_repeat = (MrvlIEtypes_RepeatCount_t *)tlv;
+ tlv_repeat->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
+ tlv_repeat->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_RepeatCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_repeat->repeat_count =
+ wlan_cpu_to_le16(bg_scan_in->repeat_count);
+ tlv += sizeof(MrvlIEtypes_RepeatCount_t);
+ cmd_size += sizeof(MrvlIEtypes_RepeatCount_t);
+ }
+ for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list)) &&
+ (*bg_scan_in->ssid_list[ssid_idx].ssid ||
+ bg_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+ ssid_len = wlan_strlen(
+ (char *)bg_scan_in->ssid_list[ssid_idx].ssid);
+ pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *)tlv;
+ pwildcard_ssid_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header.len = (t_u16)(
+ ssid_len + sizeof(pwildcard_ssid_tlv->max_ssid_length));
+ pwildcard_ssid_tlv->max_ssid_length =
+ bg_scan_in->ssid_list[ssid_idx].max_len;
+ memcpy_ext(pmadapter, pwildcard_ssid_tlv->ssid,
+ bg_scan_in->ssid_list[ssid_idx].ssid, ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ tlv += sizeof(pwildcard_ssid_tlv->header) +
+ pwildcard_ssid_tlv->header.len;
+ cmd_size += sizeof(pwildcard_ssid_tlv->header) +
+ pwildcard_ssid_tlv->header.len;
+ pwildcard_ssid_tlv->header.len =
+ wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
+ PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
+ pwildcard_ssid_tlv->ssid,
+ pwildcard_ssid_tlv->max_ssid_length);
+ }
+ if (bg_scan_in->chan_list[0].chan_number) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
+ PRINTM(MINFO, "Scan: Using supplied channel list\n");
+ chan_num = 0;
+ for (chan_idx = 0; chan_idx < WLAN_BG_SCAN_CHAN_MAX &&
+ bg_scan_in->chan_list[chan_idx].chan_number;
+ chan_idx++) {
+ radio_type = bg_scan_in->chan_list[chan_idx].radio_type;
+ if (bg_scan_in->bss_type == MLAN_SCAN_MODE_IBSS ||
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ band = pmadapter->adhoc_start_band;
+ else
+ band = pmpriv->config_bands;
+ if (!wlan_is_band_compatible(
+ band, radio_type_to_band(radio_type)))
+ continue;
+ scan_type = bg_scan_in->chan_list[chan_idx].scan_type;
+ /* Prevent active scanning on a radar controlled channel
+ */
+ if (radio_type == BAND_5GHZ) {
+ if (wlan_11h_radar_detect_required(
+ pmpriv,
+ bg_scan_in->chan_list[chan_idx]
+ .chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ if (radio_type == BAND_2GHZ) {
+ if (wlan_bg_scan_type_is_passive(
+ pmpriv,
+ bg_scan_in->chan_list[chan_idx]
+ .chan_number)) {
+ scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].chan_number =
+ bg_scan_in->chan_list[chan_idx].chan_number;
+ tlv_chan_list->chan_scan_param[chan_num]
+ .bandcfg.chanBand =
+ bg_scan_in->chan_list[chan_idx].radio_type;
+
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ tlv_chan_list->chan_scan_param[chan_num]
+ .chan_scan_mode.passive_scan = MTRUE;
+ } else {
+ tlv_chan_list->chan_scan_param[chan_num]
+ .chan_scan_mode.passive_scan = MFALSE;
+ }
+ if (bg_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur =
+ (t_u16)bg_scan_in->chan_list[chan_idx]
+ .scan_time;
+ } else {
+ if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
+ scan_dur = pmadapter->passive_scan_time;
+ } else {
+ scan_dur =
+ pmadapter->specific_scan_time;
+ }
+ }
+ tlv_chan_list->chan_scan_param[chan_num].min_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ tlv_chan_list->chan_scan_param[chan_num].max_scan_time =
+ wlan_cpu_to_le16(scan_dur);
+ chan_num++;
+ }
+ tlv_chan_list->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(ChanScanParamSet_t) * chan_num;
+ } else {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
+ chan_num = wlan_bgscan_create_channel_list(pmpriv, bg_scan_in,
+ tlv_chan_list);
+ tlv_chan_list->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len =
+ wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(ChanScanParamSet_t) * chan_num;
+ cmd_size += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(ChanScanParamSet_t) * chan_num;
+ }
+ if (bg_scan_in->chan_per_scan) {
+ bg_scan->chan_per_scan = bg_scan_in->chan_per_scan;
+ } else {
+ if (bg_scan_in->report_condition & BG_SCAN_WAIT_ALL_CHAN_DONE)
+ bg_scan->chan_per_scan = chan_num;
+ else
+ bg_scan->chan_per_scan =
+ MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ }
+ if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_GN ||
+ pmpriv->config_bands & BAND_AN)) {
+ pht_cap = (MrvlIETypes_HTCap_t *)tlv;
+ memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
+ pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ pht_cap->header.len = sizeof(HTCap_t);
+ wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands,
+ MTRUE);
+ DBG_HEXDUMP(MCMD_D, "BGSCAN: HT_CAPABILITIES IE",
+ (t_u8 *)pht_cap, sizeof(MrvlIETypes_HTCap_t));
+ tlv += sizeof(MrvlIETypes_HTCap_t);
+ cmd_size += sizeof(MrvlIETypes_HTCap_t);
+ pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
+ }
+ if (ISSUPP_11ACENABLED(pmpriv->adapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_AAC)) {
+ pvht_cap = (MrvlIETypes_VHTCap_t *)tlv;
+ memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
+ pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
+ pvht_cap->header.len = sizeof(VHT_capa_t);
+ wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pmpriv->config_bands,
+ MFALSE, MFALSE);
+ DBG_HEXDUMP(MCMD_D, "BGSCAN: VHT_CAPABILITIES IE",
+ (t_u8 *)pvht_cap, sizeof(MrvlIETypes_VHTCap_t));
+ tlv += sizeof(MrvlIETypes_VHTCap_t);
+ cmd_size += sizeof(MrvlIETypes_VHTCap_t);
+ pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
+ }
+
+ if (IS_FW_SUPPORT_11AX(pmadapter) &&
+ (pmpriv->config_bands & BAND_AAX)) {
+ phe_cap = (MrvlIEtypes_Extension_t *)tlv;
+ len = wlan_fill_he_cap_tlv(pmpriv, BAND_A, phe_cap, MFALSE);
+ DBG_HEXDUMP(MCMD_D, "BGSCAN: HE_CAPABILITIES IE",
+ (t_u8 *)phe_cap, len);
+ tlv += len;
+ cmd_size += len;
+ }
+ if (wlan_is_ext_capa_support(pmpriv)) {
+ wlan_add_ext_capa_info_ie(pmpriv, MNULL, &tlv);
+ cmd_size += sizeof(MrvlIETypes_ExtCap_t);
+ }
+ if (pmpriv->adapter->ecsa_enable) {
+ t_u8 bandwidth = BW_20MHZ;
+ t_u8 oper_class = 1;
+ t_u32 usr_dot_11n_dev_cap;
+ if (pmpriv->media_connected) {
+ if (pmpriv->config_bands & BAND_A)
+ usr_dot_11n_dev_cap =
+ pmpriv->usr_dot_11n_dev_cap_a;
+ else
+ usr_dot_11n_dev_cap =
+ pmpriv->usr_dot_11n_dev_cap_bg;
+ if (usr_dot_11n_dev_cap & MBIT(17)) {
+ bandwidth = BW_40MHZ;
+ if (ISSUPP_11ACENABLED(
+ pmadapter->fw_cap_info) &&
+ (pmpriv->config_bands & BAND_AAC))
+ bandwidth = BW_80MHZ;
+ }
+ wlan_get_curr_oper_class(
+ pmpriv,
+ pmpriv->curr_bss_params.bss_descriptor.channel,
+ bandwidth, &oper_class);
+ }
+ len = wlan_add_supported_oper_class_ie(pmpriv, &tlv,
+ oper_class);
+ cmd_size += len;
+ }
+
+ tlv_start_later = (MrvlIEtypes_StartLater_t *)tlv;
+ tlv_start_later->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
+ tlv_start_later->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_StartLater_t) - sizeof(MrvlIEtypesHeader_t));
+ tlv_start_later->value = wlan_cpu_to_le16(bg_scan_in->start_later);
+ tlv += sizeof(MrvlIEtypes_StartLater_t);
+ cmd_size += sizeof(MrvlIEtypes_StartLater_t);
+
+ if (bg_scan_in->config_ees) {
+ /* Fill EES configuration */
+ tlv_ees_cfg = (MrvlIEtypes_EESParamSet_t *)tlv;
+ tlv_ees_cfg->header.type = wlan_cpu_to_le16(TLV_TYPE_EES_CFG);
+ tlv_ees_cfg->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_EESParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_ees_cfg->ees_mode = wlan_cpu_to_le16(bg_scan_in->ees_mode);
+ tlv_ees_cfg->report_cond =
+ wlan_cpu_to_le16(bg_scan_in->report_cond);
+ tlv_ees_cfg->high_period =
+ wlan_cpu_to_le16(bg_scan_in->high_period);
+ tlv_ees_cfg->high_period_count =
+ wlan_cpu_to_le16(bg_scan_in->high_period_count);
+ tlv_ees_cfg->mid_period =
+ wlan_cpu_to_le16(bg_scan_in->mid_period);
+ tlv_ees_cfg->mid_period_count =
+ wlan_cpu_to_le16(bg_scan_in->mid_period_count);
+ tlv_ees_cfg->low_period =
+ wlan_cpu_to_le16(bg_scan_in->low_period);
+ tlv_ees_cfg->low_period_count =
+ wlan_cpu_to_le16(bg_scan_in->low_period_count);
+ tlv += sizeof(MrvlIEtypes_EESParamSet_t);
+ cmd_size += sizeof(MrvlIEtypes_EESParamSet_t);
+
+ if (bg_scan_in->network_count) {
+ /* Fill EES network configuration */
+ tlv_ees_net_cfg = (MrvlIEtype_EESNetworkCfg_t *)tlv;
+ tlv_ees_net_cfg->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_EES_NET_CFG);
+ tlv_ees_net_cfg->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtype_EESNetworkCfg_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_ees_net_cfg->network_count =
+ bg_scan_in->network_count;
+ tlv_ees_net_cfg->max_conn_count =
+ bg_scan_in->max_conn_count;
+ tlv_ees_net_cfg->black_list_exp =
+ bg_scan_in->black_list_exp;
+ tlv += sizeof(MrvlIEtype_EESNetworkCfg_t);
+ cmd_size += sizeof(MrvlIEtype_EESNetworkCfg_t);
+ for (index = 0; index < bg_scan_in->network_count;
+ index++) {
+ if (wlan_strlen((char *)bg_scan_in
+ ->ees_ssid_cfg[index]
+ .ssid)) {
+ /* Fill SSID settings */
+ tlv_ssid =
+ (MrvlIEtypes_SsIdParamSet_t *)
+ tlv;
+ tlv_ssid->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SSID);
+ tlv_ssid->header.len = wlan_cpu_to_le16(
+ (t_u16)bg_scan_in
+ ->ees_ssid_cfg[index]
+ .max_len);
+ memcpy_ext(
+ pmadapter, tlv_ssid->ssid,
+ bg_scan_in->ees_ssid_cfg[index]
+ .ssid,
+ bg_scan_in->ees_ssid_cfg[index]
+ .max_len,
+ MLAN_MAX_SSID_LENGTH);
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ tlv_ssid->header.len;
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) +
+ tlv_ssid->header.len;
+ } else {
+ /* Fill Wildcard SSID settings */
+ pwildcard_ssid_tlv =
+ (MrvlIEtypes_WildCardSsIdParamSet_t
+ *)tlv;
+ pwildcard_ssid_tlv->header.type =
+ wlan_cpu_to_le16(
+ TLV_TYPE_WILDCARDSSID);
+ pwildcard_ssid_tlv->header
+ .len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ pwildcard_ssid_tlv->max_ssid_length =
+ MLAN_MAX_SSID_LENGTH;
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(pwildcard_ssid_tlv
+ ->max_ssid_length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) +
+ sizeof(pwildcard_ssid_tlv
+ ->max_ssid_length);
+ }
+ /* Fill Cipher settings */
+ tlv_ees_cipher = (MrvlIEtypes_Cipher_t *)tlv;
+ tlv_ees_cipher->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CIPHER);
+ tlv_ees_cipher->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_Cipher_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_ees_cipher->pair_cipher =
+ bg_scan_in->ees_ssid_cfg[index]
+ .pair_cipher;
+ tlv_ees_cipher->group_cipher =
+ bg_scan_in->ees_ssid_cfg[index]
+ .group_cipher;
+ tlv += sizeof(MrvlIEtypes_Cipher_t);
+ cmd_size += sizeof(MrvlIEtypes_Cipher_t);
+ }
+ }
+ }
+
+ if (memcmp(pmadapter, bg_scan_in->random_mac, zero_mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ MrvlIEtypes_MacAddr_t *randomMacParam =
+ (MrvlIEtypes_MacAddr_t *)tlv;
+ memset(pmadapter, randomMacParam, 0,
+ sizeof(MrvlIEtypes_MacAddr_t));
+ randomMacParam->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_RANDOM_MAC);
+ randomMacParam->header.len =
+ wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmadapter, randomMacParam->mac,
+ bg_scan_in->random_mac, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ tlv += sizeof(MrvlIEtypes_MacAddr_t);
+ cmd_size += sizeof(MrvlIEtypes_MacAddr_t);
+ }
+done:
+ pcmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of extended scan
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_bgscan_config(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
+ &resp->params.bg_scan_config;
+ wlan_bgscan_cfg *bg_scan_out = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
+ bg_scan_out =
+ (wlan_bgscan_cfg *)pscan->param.user_scan.scan_cfg_buf;
+ bg_scan_out->action = wlan_le16_to_cpu(bg_scan->action);
+ if ((bg_scan_out->action == BG_SCAN_ACT_GET) ||
+ (bg_scan_out->action == BG_SCAN_ACT_GET_PPS_UAPSD)) {
+ bg_scan_out->enable = bg_scan->enable;
+ bg_scan_out->bss_type = bg_scan->bss_type;
+ bg_scan_out->chan_per_scan = bg_scan->chan_per_scan;
+ bg_scan_out->scan_interval =
+ wlan_le32_to_cpu(bg_scan->scan_interval);
+ bg_scan_out->report_condition =
+ wlan_le32_to_cpu(bg_scan->report_condition);
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_scan) + MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of bgscan_query
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_802_11_bgscan_query(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_scan *pscan = MNULL;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ ENTER();
+ wlan_ret_802_11_scan(pmpriv, resp, MNULL);
+ if (pioctl_buf) {
+ pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *)pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
+ pscan->param.scan_resp.pchan_stats =
+ (t_u8 *)pmadapter->pchan_stats;
+ pscan->param.scan_resp.num_in_chan_stats =
+ pmadapter->num_in_chan_stats;
+
+ pioctl_buf->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32 wlan_find_ssid_in_list(mlan_private *pmpriv, mlan_802_11_ssid *ssid,
+ t_u8 *bssid, t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1, j;
+ t_u8 best_rssi = 0;
+ t_u32 i;
+
+ ENTER();
+ PRINTM(MINFO, "Num of entries in scan table = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Loop through the table until the maximum is reached or until a match
+ * is found based on the bssid field comparison
+ */
+ for (i = 0;
+ i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
+ i++) {
+ if (!wlan_ssid_cmp(pmadapter, &pmadapter->pscan_table[i].ssid,
+ ssid) &&
+ (!bssid ||
+ !memcmp(pmadapter, pmadapter->pscan_table[i].mac_address,
+ bssid, MLAN_MAC_ADDR_LENGTH))) {
+ if ((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(
+ pmpriv->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ continue;
+
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ j = wlan_is_network_compatible(pmpriv, i, mode);
+
+ if (j >= 0) {
+ if (SCAN_RSSI(pmadapter->pscan_table[i]
+ .rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(
+ pmadapter
+ ->pscan_table[i]
+ .rssi);
+ net = i;
+ }
+ } else {
+ if (net == -1)
+ net = j;
+ }
+ break;
+ case MLAN_BSS_MODE_AUTO:
+ default:
+ /*
+ * Do not check compatibility if the mode
+ * requested is Auto/Unknown. Allows generic
+ * find to work without verifying against the
+ * Adapter security settings
+ */
+ if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(
+ pmadapter->pscan_table[i].rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list or < 0 if error
+ */
+t_s32 wlan_find_bssid_in_list(mlan_private *pmpriv, t_u8 *bssid, t_u32 mode)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_s32 net = -1;
+ t_u32 i;
+
+ ENTER();
+
+ if (!bssid) {
+ LEAVE();
+ return -1;
+ }
+
+ PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
+ pmadapter->num_in_scan_table);
+
+ /*
+ * Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
+ if (!memcmp(pmadapter, pmadapter->pscan_table[i].mac_address,
+ bssid, MLAN_MAC_ADDR_LENGTH)) {
+ if ((mode == MLAN_BSS_MODE_INFRA) &&
+ !wlan_is_band_compatible(
+ pmpriv->config_bands,
+ pmadapter->pscan_table[i].bss_band))
+ continue;
+ switch (mode) {
+ case MLAN_BSS_MODE_INFRA:
+ case MLAN_BSS_MODE_IBSS:
+ net = wlan_is_network_compatible(pmpriv, i,
+ mode);
+ break;
+ default:
+ net = i;
+ break;
+ }
+ }
+ }
+
+ LEAVE();
+ return net;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+t_s32 wlan_ssid_cmp(pmlan_adapter pmadapter, mlan_802_11_ssid *ssid1,
+ mlan_802_11_ssid *ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param preq_ssid_bssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status wlan_find_best_network(mlan_private *pmpriv,
+ mlan_ssid_bssid *preq_ssid_bssid)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ BSSDescriptor_t *preq_bss;
+ t_s32 i;
+
+ ENTER();
+
+ memset(pmadapter, preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ i = wlan_find_best_network_in_list(pmpriv);
+
+ if (i >= 0) {
+ preq_bss = &pmadapter->pscan_table[i];
+ memcpy_ext(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(preq_ssid_bssid->ssid));
+ memcpy_ext(pmadapter, (t_u8 *)&preq_ssid_bssid->bssid,
+ (t_u8 *)&preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Make sure we are in the right mode */
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
+ pmpriv->bss_mode = preq_bss->bss_mode;
+ preq_ssid_bssid->channel = (t_u16)preq_bss->channel;
+ if (preq_bss->pmd_ie &&
+ wlan_ft_akm_is_used(pmpriv, (t_u8 *)preq_bss->prsn_ie)) {
+ preq_ssid_bssid->ft_md = preq_bss->pmd_ie->mdid;
+ preq_ssid_bssid->ft_cap = preq_bss->pmd_ie->ft_cap;
+ }
+ preq_ssid_bssid->bss_band = preq_bss->bss_band;
+ preq_ssid_bssid->idx = i + 1;
+ }
+
+ if (!preq_ssid_bssid->ssid.ssid_len) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO,
+ "Best network found = [%s], "
+ "[" MACSTR "]\n",
+ preq_ssid_bssid->ssid.ssid, MAC2STR(preq_ssid_bssid->bssid));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param preq_ssid A pointer to AP's ssid returned
+ *
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+mlan_status wlan_scan_specific_ssid(mlan_private *pmpriv, t_void *pioctl_buf,
+ mlan_802_11_ssid *preq_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ wlan_user_scan_cfg *pscan_cfg;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ if (!preq_ssid) {
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
+
+ ret = pcb->moal_malloc(pmpriv->adapter->pmoal_handle,
+ sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
+ (t_u8 **)&pscan_cfg);
+
+ if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
+ PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
+
+ memcpy_ext(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
+ preq_ssid->ssid, preq_ssid->ssid_len, MLAN_MAX_SSID_LENGTH);
+ pscan_cfg->keep_previous_scan = MFALSE;
+
+ ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
+
+ if (pscan_cfg)
+ pcb->moal_mfree(pmpriv->adapter->pmoal_handle,
+ (t_u8 *)pscan_cfg);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Save a beacon buffer of the current bss descriptor
+ * Save the current beacon buffer to restore in the following cases that
+ * makes the bcn_buf not to contain the current ssid's beacon buffer.
+ * - the current ssid was not found somehow in the last scan.
+ * - the current ssid was the last entry of the scan table and overloaded.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_save_curr_bcn(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
+ BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmpriv->curr_bcn_buf_lock);
+ /* save the beacon buffer if it is not saved or updated */
+ if ((pmpriv->pcurr_bcn_buf == MNULL) ||
+ (pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
+ (memcmp(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
+ pcurr_bss->pbeacon_buf, pcurr_bss->beacon_buf_size))) {
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
+
+ if (pmpriv->curr_bcn_size) {
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ pcurr_bss->beacon_buf_size,
+ MLAN_MEM_DEF,
+ &pmpriv->pcurr_bcn_buf);
+
+ if ((ret == MLAN_STATUS_SUCCESS) &&
+ pmpriv->pcurr_bcn_buf) {
+ memcpy_ext(pmpriv->adapter,
+ pmpriv->pcurr_bcn_buf,
+ pcurr_bss->pbeacon_buf,
+ pcurr_bss->beacon_buf_size,
+ pcurr_bss->beacon_buf_size);
+ PRINTM(MINFO, "current beacon saved %d\n",
+ pmpriv->curr_bcn_size);
+ } else {
+ PRINTM(MERROR,
+ "Fail to allocate curr_bcn_buf\n");
+ }
+ }
+ }
+ wlan_update_curr_bcn(pmpriv);
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmpriv->curr_bcn_buf_lock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Free a beacon buffer of the current bss descriptor
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_free_curr_bcn(mlan_private *pmpriv)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
+
+ ENTER();
+ if (pmpriv->pcurr_bcn_buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
+ pmpriv->pcurr_bcn_buf = MNULL;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.c
new file mode 100644
index 000000000000..b88c4fdb3ad8
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.c
@@ -0,0 +1,3013 @@
+/** @file mlan_sdio.c
+ *
+ * @brief This file contains SDIO specific code
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_init.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_sdio.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function initialize the SDIO port
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_init_ioport(mlan_adapter *pmadapter)
+{
+ t_u32 reg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 host_int_rsr_reg = pmadapter->pcard_sd->reg->host_int_rsr_reg;
+ t_u8 host_int_rsr_mask = pmadapter->pcard_sd->reg->sdio_int_mask;
+ t_u8 card_misc_cfg_reg = pmadapter->pcard_sd->reg->card_misc_cfg_reg;
+ t_u8 card_config_2_1_reg =
+ pmadapter->pcard_sd->reg->card_config_2_1_reg;
+ t_u8 cmd_config_0 = pmadapter->pcard_sd->reg->cmd_config_0;
+ t_u8 cmd_config_1 = pmadapter->pcard_sd->reg->cmd_config_1;
+
+ ENTER();
+
+ pmadapter->pcard_sd->ioport = MEM_PORT;
+ PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n",
+ pmadapter->pcard_sd->ioport);
+
+ /* enable sdio cmd53 new mode */
+ if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
+ card_config_2_1_reg,
+ &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ card_config_2_1_reg, reg | CMD53_NEW_MODE);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* configure cmd port */
+ /* enable reading rx length from the register */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, cmd_config_0, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, cmd_config_0,
+ reg | CMD_PORT_RD_LEN_EN);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* enable Dnld/Upld ready auto reset for cmd port
+ * after cmd53 is completed */
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_read_reg(pmadapter->pmoal_handle, cmd_config_1, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, cmd_config_1,
+ reg | CMD_PORT_AUTO_EN);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+#if defined(SD8977) || defined(SD8978)
+ if (IS_SD8977(pmadapter->card_type) ||
+ IS_SD8978(pmadapter->card_type)) {
+ if ((pmadapter->init_para.int_mode == INT_MODE_GPIO) &&
+ (pmadapter->init_para.gpio_pin == GPIO_INT_NEW_MODE)) {
+ PRINTM(MMSG, "Enable GPIO-1 int mode\n");
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ SCRATCH_REG_32,
+ ENABLE_GPIO_1_INT_MODE);
+ }
+ }
+#endif
+ /* Set Host interrupt reset to read to clear */
+ if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
+ host_int_rsr_reg, &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, host_int_rsr_reg,
+ reg | host_int_rsr_mask);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Dnld/Upld ready set to auto reset */
+ if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
+ card_misc_cfg_reg,
+ &reg)) {
+ pcb->moal_write_reg(pmadapter->pmoal_handle, card_misc_cfg_reg,
+ reg | AUTO_RE_ENABLE_INT);
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * SDIO header)
+ * @param port Port
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_write_data_sync(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf, t_u32 port)
+{
+ t_u32 i = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ do {
+ ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf,
+ port, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ i++;
+ PRINTM(MERROR,
+ "host_to_card, write iomem (%d) failed: %d\n", i,
+ ret);
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ HOST_TERM_CMD53)) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ goto exit;
+ }
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets available SDIO port for reading cmd/data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_get_rd_port(mlan_adapter *pmadapter, t_u8 *pport)
+{
+ t_u32 rd_bitmap = pmadapter->pcard_sd->mp_rd_bitmap;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+ t_u8 max_ports = MAX_PORT;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_rd_port: mp_rd_bitmap=0x%08x\n", rd_bitmap);
+
+ if (!(rd_bitmap & reg->data_port_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (pmadapter->pcard_sd->mp_rd_bitmap &
+ (1 << pmadapter->pcard_sd->curr_rd_port)) {
+ pmadapter->pcard_sd->mp_rd_bitmap &=
+ (t_u32)(~(1 << pmadapter->pcard_sd->curr_rd_port));
+ *pport = pmadapter->pcard_sd->curr_rd_port;
+
+ /* hw rx wraps round only after port (MAX_PORT-1) */
+ if (++pmadapter->pcard_sd->curr_rd_port == max_ports)
+ pmadapter->pcard_sd->curr_rd_port = reg->start_rd_port;
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", *pport,
+ rd_bitmap, pmadapter->pcard_sd->mp_rd_bitmap);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function gets available SDIO port for writing data
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pport A pointer to port number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_get_wr_port_data(mlan_adapter *pmadapter, t_u8 *pport)
+{
+ t_u32 wr_bitmap = pmadapter->pcard_sd->mp_wr_bitmap;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+
+ ENTER();
+
+ PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n",
+ wr_bitmap);
+
+ if (!(wr_bitmap & pmadapter->pcard_sd->mp_data_port_mask)) {
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if (pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port)) {
+ pmadapter->pcard_sd->mp_wr_bitmap &=
+ (t_u32)(~(1 << pmadapter->pcard_sd->curr_wr_port));
+ *pport = pmadapter->pcard_sd->curr_wr_port;
+ if (++pmadapter->pcard_sd->curr_wr_port ==
+ pmadapter->pcard_sd->mp_end_port)
+ pmadapter->pcard_sd->curr_wr_port = reg->start_wr_port;
+ } else {
+ pmadapter->data_sent = MTRUE;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ PRINTM(MIF_D, "port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", *pport,
+ wr_bitmap, pmadapter->pcard_sd->mp_wr_bitmap);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function polls the card status register.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param bits the bit mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_poll_card_status(mlan_adapter *pmadapter,
+ t_u8 bits)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 tries;
+ t_u32 cs = 0;
+
+ ENTER();
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if (pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->poll_reg,
+ &cs) != MLAN_STATUS_SUCCESS)
+ break;
+ else if ((cs & bits) == bits) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ wlan_udelay(pmadapter, 10);
+ }
+
+ PRINTM(MERROR,
+ "wlan_sdio_poll_card_status failed, tries = %d, cs = 0x%x\n",
+ tries, cs);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function reads firmware status registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_read_fw_status(mlan_adapter *pmadapter, t_u16 *dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 fws0 = 0, fws1 = 0;
+
+ ENTER();
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->status_reg_0, &fws0)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->status_reg_1, &fws1)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *dat = (t_u16)((fws1 << 8) | fws0);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads firmware dnld offset registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_read_fw_dnld_offset(mlan_adapter *pmadapter,
+ t_u32 *dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 fw_dnld_offset_0 = 0;
+ t_u32 fw_dnld_offset_1 = 0;
+ t_u32 fw_dnld_offset_2 = 0;
+ t_u32 fw_dnld_offset_3 = 0;
+
+ ENTER();
+
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_offset_0_reg, &fw_dnld_offset_0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_offset_0 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_offset_0_reg, fw_dnld_offset_0);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_offset_1_reg, &fw_dnld_offset_1);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_offset_1 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_offset_1_reg, fw_dnld_offset_1);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_offset_2_reg, &fw_dnld_offset_2);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_offset_2 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_offset_2_reg, fw_dnld_offset_2);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_offset_3_reg, &fw_dnld_offset_3);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_offset_3 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_offset_3_reg, fw_dnld_offset_3);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ *dat = (t_u32)(((fw_dnld_offset_3 & 0xff) << 24) |
+ ((fw_dnld_offset_2 & 0xff) << 16) |
+ ((fw_dnld_offset_1 & 0xff) << 8) |
+ (fw_dnld_offset_0 & 0xff));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function reads firmware dnld status registers
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param dat A pointer to keep returned data
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_read_fw_dnld_status(mlan_adapter *pmadapter,
+ t_u16 *dat)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 fw_dnld_status_0 = 0;
+ t_u32 fw_dnld_status_1 = 0;
+
+ ENTER();
+
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_status_0_reg, &fw_dnld_status_0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_status_0 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_status_0_reg, fw_dnld_status_0);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ reg->fw_dnld_status_1_reg, &fw_dnld_status_1);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev fw_dnld_status_1 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
+ reg->fw_dnld_status_1_reg, fw_dnld_status_1);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ *dat = (t_u16)(((fw_dnld_status_1 & 0xff) << 8) |
+ (fw_dnld_status_0 & 0xff));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function disables the host interrupts mask.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter,
+ t_u8 mask)
+{
+ t_u32 host_int_mask = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Read back the host_int_mask register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->host_int_mask_reg,
+ &host_int_mask)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~mask;
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->host_int_mask_reg,
+ host_int_mask)) {
+ PRINTM(MWARN, "Disable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function enables the host interrupts mask
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mask the interrupt mask
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter,
+ t_u8 mask)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ /* Simply write the mask to the register */
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->host_int_mask_reg,
+ mask)) {
+ PRINTM(MWARN, "Enable host interrupt failed\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads data from the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type A pointer to keep type as data or command
+ * @param nb A pointer to keep the data/cmd length returned in buffer
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param npayload the length of data/cmd buffer
+ * @param ioport the SDIO ioport
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_card_to_host(mlan_adapter *pmadapter, t_u32 *type,
+ t_u32 *nb, pmlan_buffer pmbuf,
+ t_u32 npayload, t_u32 ioport)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u32 i = 0;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MWARN, "pmbuf is NULL!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ do {
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf,
+ ioport, 0);
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "wlan: cmd53 read failed: %d ioport=0x%x retry=%d\n",
+ ret, ioport, i);
+ i++;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ HOST_TERM_CMD53)) {
+ PRINTM(MERROR, "Set Term cmd53 failed\n");
+ }
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+ *nb = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
+ if (*nb > npayload) {
+ PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb,
+ npayload);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Rd", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(*nb, MAX_DATA_DUMP_LEN));
+
+ *type = wlan_le16_to_cpu(
+ *(t_u16 *)(pmbuf->pbuf + pmbuf->data_offset + 2));
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param firmware A pointer to firmware image
+ * @param firmwarelen firmware len
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_prog_fw_w_helper(pmlan_adapter pmadapter, t_u8 *fw,
+ t_u32 fw_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *firmware = fw;
+ t_u32 firmwarelen = fw_len;
+ t_u32 offset = 0;
+ t_u32 base0, base1;
+ t_void *tmpfwbuf = MNULL;
+ t_u32 tmpfwbufsz;
+ t_u8 *fwbuf;
+ mlan_buffer mbuf;
+ t_u16 len = 0;
+ t_u32 txlen = 0, tx_blocks = 0, tries = 0;
+ t_u32 i = 0;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+ t_u32 read_base_0_reg = reg->base_0_reg;
+ t_u32 read_base_1_reg = reg->base_1_reg;
+#if defined(SD9098)
+ t_u32 rev_id_reg = 0;
+ t_u32 revision_id = 0;
+#endif
+ t_u8 check_fw_status = MFALSE;
+ t_u16 fw_dnld_status = 0;
+ t_u32 fw_dnld_offset = 0;
+ t_u8 mic_retry = 0;
+
+ ENTER();
+
+ if (!firmware && !pcb->moal_get_fw_data) {
+ PRINTM(MMSG, "No firmware image found! Terminating download\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT);
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&tmpfwbuf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
+ PRINTM(MERROR,
+ "Unable to allocate buffer for firmware. Terminating download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz);
+ /* Ensure 8-byte aligned firmware buffer */
+ fwbuf = (t_u8 *)ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);
+#if defined(SD9098)
+ if (IS_SD9098(pmadapter->card_type)) {
+ rev_id_reg = pmadapter->pcard_sd->reg->card_revision_reg;
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle, rev_id_reg,
+ &revision_id);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Card Revision register read failed:"
+ "card_revision_reg=0x%x\n",
+ rev_id_reg);
+ goto done;
+ }
+ /* Skyhawk A0, need to check both CRC and MIC error */
+ if (revision_id >= CHIP_9098_REV_A0)
+ check_fw_status = MTRUE;
+ }
+#endif
+#if defined(SD9097)
+ if (IS_SD9097(pmadapter->card_type))
+ check_fw_status = MTRUE;
+#endif
+ /* Perform firmware data transfer */
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits
+ */
+ ret = wlan_sdio_poll_card_status(
+ pmadapter, CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL,
+ "WLAN: FW download with helper poll status timeout @ %d\n",
+ offset);
+ goto done;
+ }
+
+ /* More data */
+ if (firmwarelen && offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ read_base_0_reg, &base0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE0 register read failed:"
+ " base0=0x%04X(%d). Terminating download\n",
+ base0, base0);
+ goto done;
+ }
+ ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
+ read_base_1_reg, &base1);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Dev BASE1 register read failed:"
+ " base1=0x%04X(%d). Terminating download\n",
+ base1, base1);
+ goto done;
+ }
+ len = (t_u16)(((base1 & 0xff) << 8) | (base0 & 0xff));
+
+ if (len)
+ break;
+ wlan_udelay(pmadapter, 10);
+ }
+
+ if (!len)
+ break;
+ else if (len > WLAN_UPLD_SIZE) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Ignore CRC check before download the 1st packet */
+ if (offset == 0 && (len & MBIT(0)))
+ len &= ~MBIT(0);
+
+ txlen = len;
+
+ if (len & MBIT(0)) {
+ /* New fw download process, check CRC and MIC error */
+ if (check_fw_status) {
+ /* Get offset from fw dnld offset Register */
+ ret = wlan_sdio_read_fw_dnld_offset(
+ pmadapter, &fw_dnld_offset);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL,
+ "WLAN: FW download with helper read fw dnld offset failed @ %d\n",
+ offset);
+ goto done;
+ }
+ /* Get CRC MIC error from fw dnld status
+ * Register */
+ ret = wlan_sdio_read_fw_dnld_status(
+ pmadapter, &fw_dnld_status);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL,
+ "WLAN: FW download with helper read fw dnld status failed @ %d\n",
+ offset);
+ goto done;
+ }
+ PRINTM(MERROR,
+ "WLAN: FW download error: status=0x%x offset = 0x%x fw offset = 0x%x\n",
+ fw_dnld_status, offset, fw_dnld_offset);
+ }
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, over max retry count\n",
+ offset);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MERROR,
+ "WLAN: FW CRC error indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n",
+ len, txlen);
+ len &= ~MBIT(0);
+ if (fw_dnld_status & (MBIT(6) | MBIT(7))) {
+ offset = 0;
+ mic_retry++;
+ if (mic_retry > MAX_FW_RETRY) {
+ PRINTM(MFATAL,
+ "WLAN: FW download failure @ %d, over max mic retry count\n",
+ offset);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i,
+ offset);
+ DBG_HEXDUMP(MERROR, "WLAN: FW block:", fwbuf, len);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking
+ * for last block */
+ if (firmwarelen && firmwarelen - offset < txlen)
+ txlen = firmwarelen - offset;
+ PRINTM(MINFO, ".");
+
+ tx_blocks = (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD - 1) /
+ MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ if (firmware)
+ memmove(pmadapter, fwbuf, &firmware[offset],
+ txlen);
+ else
+ pcb->moal_get_fw_data(pmadapter->pmoal_handle,
+ offset, txlen, fwbuf);
+ }
+
+ /* Send data */
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)fwbuf;
+ mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
+
+ ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->pcard_sd->ioport, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "WLAN: FW download, write iomem (%d) failed @ %d\n",
+ i, offset);
+ if (pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ HOST_TERM_CMD53) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "write CFG reg failed\n");
+ }
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ offset += txlen;
+ } while (MTRUE);
+
+ PRINTM(MMSG, "Wlan: FW download over, firmwarelen=%d downloaded %d\n",
+ firmwarelen, offset);
+
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ if (tmpfwbuf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tmpfwbuf);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function disables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_disable_sdio_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+
+ ENTER();
+ ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function decodes the rx packet &
+ * calls corresponding handlers according to the packet type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param upld_typ Type of rx packet
+ * @param lock_flag flag for spin_lock.
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_decode_rx_packet(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf, t_u32 upld_typ,
+ t_u8 lock_flag)
+{
+ t_u8 *cmd_buf;
+ t_u32 event;
+
+ ENTER();
+
+ switch (upld_typ) {
+ case MLAN_TYPE_SPA_DATA:
+ PRINTM(MINFO, "--- Rx: SPA Data packet ---\n");
+ pmbuf->data_len = pmadapter->upld_len;
+ if (pmadapter->rx_work_flag) {
+ pmbuf->buf_type = MLAN_BUF_TYPE_SPA_DATA;
+ if (lock_flag)
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue,
+ (pmlan_linked_list)pmbuf, MNULL,
+ MNULL);
+ pmadapter->rx_pkts_queued++;
+ if (lock_flag)
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ } else {
+ wlan_decode_spa_buffer(pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ pmadapter->data_received = MTRUE;
+ break;
+ case MLAN_TYPE_DATA:
+ PRINTM(MINFO, "--- Rx: Data packet ---\n");
+ if (pmadapter->upld_len > pmbuf->data_len) {
+ PRINTM(MERROR,
+ "SDIO: Drop packet upld_len=%d data_len=%d \n",
+ pmadapter->upld_len, pmbuf->data_len);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ break;
+ }
+ pmbuf->data_len = (pmadapter->upld_len - SDIO_INTF_HEADER_LEN);
+ pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
+ if (pmadapter->rx_work_flag) {
+ if (lock_flag)
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue,
+ (pmlan_linked_list)pmbuf, MNULL,
+ MNULL);
+ pmadapter->rx_pkts_queued++;
+ if (lock_flag)
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ } else {
+ wlan_handle_rx_packet(pmadapter, pmbuf);
+ }
+ pmadapter->data_received = MTRUE;
+ break;
+
+ case MLAN_TYPE_CMD:
+ PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
+ /* take care of curr_cmd = NULL case */
+ if (!pmadapter->curr_cmd) {
+ cmd_buf = pmadapter->upld_buf;
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ wlan_process_sleep_confirm_resp(
+ pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset +
+ SDIO_INTF_HEADER_LEN,
+ pmadapter->upld_len -
+ SDIO_INTF_HEADER_LEN);
+ }
+ pmadapter->upld_len -= SDIO_INTF_HEADER_LEN;
+ memcpy_ext(pmadapter, cmd_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ SDIO_INTF_HEADER_LEN,
+ pmadapter->upld_len - SDIO_INTF_HEADER_LEN,
+ MRVDRV_SIZE_OF_CMD_BUFFER);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ pmadapter->cmd_resp_received = MTRUE;
+ pmadapter->upld_len -= SDIO_INTF_HEADER_LEN;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+ if (pmadapter->upld_len >= MRVDRV_SIZE_OF_CMD_BUFFER) {
+ PRINTM(MMSG, "Invalid CmdResp len=%d\n",
+ pmadapter->upld_len);
+ DBG_HEXDUMP(MERROR, "Invalid CmdResp",
+ pmbuf->pbuf + pmbuf->data_offset,
+ MAX_DATA_DUMP_LEN);
+ }
+ }
+ break;
+
+ case MLAN_TYPE_EVENT:
+ PRINTM(MINFO, "--- Rx: Event ---\n");
+ event = *(t_u32 *)&pmbuf->pbuf[pmbuf->data_offset +
+ SDIO_INTF_HEADER_LEN];
+ pmadapter->event_cause = wlan_le32_to_cpu(event);
+ if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
+ ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) <
+ MAX_EVENT_SIZE)) {
+ memcpy_ext(pmadapter, pmadapter->event_body,
+ pmbuf->pbuf + pmbuf->data_offset +
+ MLAN_EVENT_HEADER_LEN,
+ pmadapter->upld_len - MLAN_EVENT_HEADER_LEN,
+ MAX_EVENT_SIZE);
+ }
+
+ /* event cause has been saved to adapter->event_cause */
+ pmadapter->event_received = MTRUE;
+ pmbuf->data_len = pmadapter->upld_len;
+ pmadapter->pmlan_buffer_event = pmbuf;
+
+ /* remove SDIO header */
+ pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
+ pmbuf->data_len -= SDIO_INTF_HEADER_LEN;
+ break;
+
+ default:
+ PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function receives single packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_receive_single_packet(mlan_adapter *pmadapter)
+{
+ mlan_buffer *pmbuf;
+ t_u8 port;
+ t_u16 rx_len;
+ t_u32 pkt_type = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ pmbuf = pmadapter->pcard_sd->mpa_rx.mbuf_arr[0];
+ port = pmadapter->pcard_sd->mpa_rx.start_port;
+ rx_len = pmadapter->pcard_sd->mpa_rx.len_arr[0];
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(pmadapter, &pkt_type,
+ (t_u32 *)&pmadapter->upld_len, pmbuf, rx_len,
+ pmadapter->pcard_sd->ioport + port)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
+ PRINTM(MERROR,
+ "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
+ pkt_type, pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->pcard_sd->mpa_rx_count[0]++;
+ wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
+done:
+ if (ret != MLAN_STATUS_SUCCESS)
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function receives data from the card in aggregate mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_receive_mp_aggr_buf(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf_aggr;
+ mlan_buffer *mbuf_deaggr;
+ t_u32 pind = 0;
+ t_u32 pkt_len, pkt_type = 0;
+ t_u8 *curr_ptr;
+ t_u32 cmd53_port = 0;
+ t_u32 i = 0;
+ t_u32 port_count = 0;
+
+ /* do aggr RX now */
+ PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
+ pmadapter->pcard_sd->mpa_rx.pkt_cnt);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ if (pmadapter->pcard_sd->mpa_rx.pkt_cnt == 1)
+ return wlan_receive_single_packet(pmadapter);
+ if (!pmadapter->pcard_sd->mpa_rx.buf) {
+ mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_rx.buf_len;
+ mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
+ mbuf_aggr.use_count = 0;
+ for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
+ pind++) {
+ pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind]->data_len =
+ pmadapter->pcard_sd->mpa_rx.len_arr[pind];
+ wlan_link_buf_to_aggr(
+ &mbuf_aggr,
+ pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind]);
+ }
+ } else {
+ mbuf_aggr.pbuf = (t_u8 *)pmadapter->pcard_sd->mpa_rx.buf;
+ mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_rx.buf_len;
+ }
+
+ port_count = bitcount(pmadapter->pcard_sd->mpa_rx.ports) - 1;
+ /* port_count = pmadapter->mpa_rx.pkt_cnt - 1; */
+ cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) +
+ pmadapter->pcard_sd->mpa_rx.start_port;
+ do {
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle,
+ &mbuf_aggr, cmd53_port, 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "wlan: sdio mp cmd53 read failed: %d ioport=0x%x retry=%d\n",
+ ret, cmd53_port, i);
+ i++;
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ HOST_TERM_CMD53)) {
+ PRINTM(MERROR, "Set Term cmd53 failed\n");
+ }
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ } while (ret == MLAN_STATUS_FAILURE);
+ if (pmadapter->rx_work_flag)
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ if (!pmadapter->pcard_sd->mpa_rx.buf &&
+ pmadapter->pcard_sd->mpa_rx.pkt_cnt > 1) {
+ for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
+ pind++) {
+ mbuf_deaggr =
+ pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind];
+ pkt_len = wlan_le16_to_cpu(
+ *(t_u16 *)(mbuf_deaggr->pbuf +
+ mbuf_deaggr->data_offset));
+ pkt_type = wlan_le16_to_cpu(
+ *(t_u16 *)(mbuf_deaggr->pbuf +
+ mbuf_deaggr->data_offset + 2));
+ pmadapter->upld_len = pkt_len;
+ wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type,
+ MFALSE);
+ }
+ } else {
+ DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd",
+ pmadapter->pcard_sd->mpa_rx.buf,
+ MIN(pmadapter->pcard_sd->mpa_rx.buf_len,
+ MAX_DATA_DUMP_LEN));
+
+ curr_ptr = pmadapter->pcard_sd->mpa_rx.buf;
+
+ for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
+ pind++) {
+ /* get curr PKT len & type */
+ pkt_len = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[0]);
+ pkt_type = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[2]);
+
+ PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n",
+ pind, pkt_len, pkt_type);
+
+ /* copy pkt to deaggr buf */
+ mbuf_deaggr =
+ pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind];
+ if ((pkt_type == MLAN_TYPE_DATA ||
+ pkt_type == MLAN_TYPE_SPA_DATA) &&
+ (pkt_len <=
+ pmadapter->pcard_sd->mpa_rx.len_arr[pind])) {
+ memcpy_ext(pmadapter,
+ mbuf_deaggr->pbuf +
+ mbuf_deaggr->data_offset,
+ curr_ptr, pkt_len, pkt_len);
+ pmadapter->upld_len = pkt_len;
+ /* Process de-aggr packet */
+ wlan_decode_rx_packet(pmadapter, mbuf_deaggr,
+ pkt_type, MFALSE);
+ } else {
+ PRINTM(MERROR,
+ "Wrong aggr packet: type=%d, len=%d, max_len=%d\n",
+ pkt_type, pkt_len,
+ pmadapter->pcard_sd->mpa_rx
+ .len_arr[pind]);
+ wlan_free_mlan_buffer(pmadapter, mbuf_deaggr);
+ }
+ curr_ptr += pmadapter->pcard_sd->mpa_rx.len_arr[pind];
+ }
+ }
+ if (pmadapter->rx_work_flag)
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ pmadapter->pcard_sd
+ ->mpa_rx_count[pmadapter->pcard_sd->mpa_rx.pkt_cnt - 1]++;
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+done:
+ return ret;
+}
+
+/**
+ * @brief This function receives data from the card in aggregate mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO data/cmd buffer
+ * @param port Current port on which packet needs to be rxed
+ * @param rx_len Length of received packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_card_to_host_mp_aggr(mlan_adapter *pmadapter,
+ mlan_buffer *pmbuf, t_u8 port,
+ t_u16 rx_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_s32 f_do_rx_aggr = 0;
+ t_s32 f_do_rx_cur = 0;
+ t_s32 f_aggr_cur = 0;
+ t_s32 f_post_aggr_cur = 0;
+ t_u32 pind = 0;
+ t_u32 pkt_type = 0;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+
+ ENTER();
+
+ if (!pmadapter->pcard_sd->mpa_rx.enabled) {
+ PRINTM(MINFO,
+ "card_2_host_mp_aggr: rx aggregation disabled !\n");
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (pmadapter->pcard_sd->mp_rd_bitmap & reg->data_port_mask) {
+ /* Some more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_aggr = 1;
+ f_post_aggr_cur = 1;
+ }
+ } else {
+ /* Rx aggr not in progress */
+ f_aggr_cur = 1;
+ }
+
+ } else {
+ /* No more data RX pending */
+ PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ f_do_rx_aggr = 1;
+ if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_cur = 1;
+ }
+ } else {
+ f_do_rx_cur = 1;
+ }
+ }
+
+ if (f_aggr_cur) {
+ PRINTM(MINFO, "Current packet aggregation.\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
+
+ if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
+ MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MINFO,
+ "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
+ /* No more pkts allowed in Aggr buf, rx it */
+ f_do_rx_aggr = 1;
+ }
+ }
+
+ if (f_do_rx_aggr) {
+ /* do aggr RX now */
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_receive_mp_aggr_buf(pmadapter)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+rx_curr_single:
+ if (f_do_rx_cur) {
+ PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port,
+ rx_len);
+
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(
+ pmadapter, &pkt_type, (t_u32 *)&pmadapter->upld_len,
+ pmbuf, rx_len,
+ pmadapter->pcard_sd->ioport + port)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (pkt_type != MLAN_TYPE_DATA &&
+ pkt_type != MLAN_TYPE_SPA_DATA) {
+ PRINTM(MERROR,
+ "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
+ pkt_type, pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmadapter->pcard_sd->mpa_rx_count[0]++;
+
+ wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
+ }
+ if (f_post_aggr_cur) {
+ PRINTM(MINFO, "Current packet aggregation.\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
+ }
+done:
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* MP-A transfer failed - cleanup */
+ for (pind = 0;
+ pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
+ pind++) {
+ wlan_free_mlan_buffer(
+ pmadapter, pmadapter->pcard_sd->mpa_rx
+ .mbuf_arr[pind]);
+ }
+ MP_RX_AGGR_BUF_RESET(pmadapter);
+ }
+
+ if (f_do_rx_cur) {
+ /* Single Transfer pending */
+ /* Free curr buff also */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends aggr buf
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_send_mp_aggr_buf(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 cmd53_port = 0;
+ t_u32 port_count = 0;
+ mlan_buffer mbuf_aggr;
+ t_u8 i = 0;
+ t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ ENTER();
+
+ if (!pmadapter->pcard_sd->mpa_tx.pkt_cnt) {
+ LEAVE();
+ return ret;
+ }
+ PRINTM(MINFO,
+ "host_2_card_mp_aggr: Send aggregation buffer."
+ "%d %d\n",
+ pmadapter->pcard_sd->mpa_tx.start_port,
+ pmadapter->pcard_sd->mpa_tx.ports);
+
+ memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
+
+ if (!pmadapter->pcard_sd->mpa_tx.buf &&
+ pmadapter->pcard_sd->mpa_tx.pkt_cnt > 1) {
+ mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_tx.buf_len;
+ mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
+ mbuf_aggr.use_count = 0;
+ for (i = 0; i < pmadapter->pcard_sd->mpa_tx.pkt_cnt; i++)
+ wlan_link_buf_to_aggr(
+ &mbuf_aggr,
+ pmadapter->pcard_sd->mpa_tx.mbuf_arr[i]);
+ } else {
+ mbuf_aggr.pbuf = (t_u8 *)pmadapter->pcard_sd->mpa_tx.buf;
+ mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_tx.buf_len;
+ }
+
+ port_count = bitcount(pmadapter->pcard_sd->mpa_tx.ports) - 1;
+ cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) +
+ pmadapter->pcard_sd->mpa_tx.start_port;
+
+ if (pmadapter->pcard_sd->mpa_tx.pkt_cnt == 1)
+ cmd53_port = pmadapter->pcard_sd->ioport +
+ pmadapter->pcard_sd->mpa_tx.start_port;
+ /** only one packet */
+ if (!pmadapter->pcard_sd->mpa_tx.buf &&
+ pmadapter->pcard_sd->mpa_tx.pkt_cnt == 1)
+ ret = wlan_write_data_sync(
+ pmadapter, pmadapter->pcard_sd->mpa_tx.mbuf_arr[0],
+ cmd53_port);
+ else
+ ret = wlan_write_data_sync(pmadapter, &mbuf_aggr, cmd53_port);
+ if (!pmadapter->pcard_sd->mpa_tx.buf) {
+ /** free mlan buffer */
+ for (i = 0; i < pmadapter->pcard_sd->mpa_tx.pkt_cnt; i++) {
+ wlan_write_data_complete(
+ pmadapter,
+ pmadapter->pcard_sd->mpa_tx.mbuf_arr[i],
+ MLAN_STATUS_SUCCESS);
+ }
+ }
+ if (!(pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port)) &&
+ (pmadapter->pcard_sd->mpa_tx.pkt_cnt < mp_aggr_pkt_limit))
+ pmadapter->pcard_sd->mpa_sent_no_ports++;
+ pmadapter->pcard_sd
+ ->mpa_tx_count[pmadapter->pcard_sd->mpa_tx.pkt_cnt - 1]++;
+ pmadapter->pcard_sd
+ ->last_mp_wr_bitmap[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->mp_wr_bitmap;
+ pmadapter->pcard_sd
+ ->last_mp_wr_ports[pmadapter->pcard_sd->last_mp_index] =
+ cmd53_port;
+ pmadapter->pcard_sd->last_mp_wr_len[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->mpa_tx.buf_len;
+ pmadapter->pcard_sd
+ ->last_curr_wr_port[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->curr_wr_port;
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)&pmadapter->pcard_sd
+ ->last_mp_wr_info[pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit],
+ (t_u8 *)pmadapter->pcard_sd->mpa_tx.mp_wr_info,
+ mp_aggr_pkt_limit * sizeof(t_u16),
+ mp_aggr_pkt_limit * sizeof(t_u16));
+ pmadapter->pcard_sd->last_mp_index++;
+ if (pmadapter->pcard_sd->last_mp_index >= SDIO_MP_DBG_NUM)
+ pmadapter->pcard_sd->last_mp_index = 0;
+ MP_TX_AGGR_BUF_RESET(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card in SDIO aggregated mode.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mbuf A pointer to the SDIO data/cmd buffer
+ * @param port current port for aggregation
+ * @param next_pkt_len Length of next packet used for multiport aggregation
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_host_to_card_mp_aggr(mlan_adapter *pmadapter,
+ mlan_buffer *mbuf, t_u8 port,
+ t_u32 next_pkt_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_s32 f_send_aggr_buf = 0;
+ t_s32 f_send_cur_buf = 0;
+ t_s32 f_precopy_cur_buf = 0;
+ t_s32 f_postcopy_cur_buf = 0;
+ t_u8 aggr_sg = 0;
+ t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ ENTER();
+
+ PRINTM(MIF_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
+ next_pkt_len, port);
+
+ if (!pmadapter->pcard_sd->mpa_tx.enabled) {
+ PRINTM(MINFO,
+ "host_2_card_mp_aggr: tx aggregation disabled !\n");
+ f_send_cur_buf = 1;
+ goto tx_curr_single;
+ }
+
+ if (next_pkt_len) {
+ /* More pkt in TX queue */
+ PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+
+ if (!(pmadapter->pcard_sd->mp_wr_bitmap &
+ (1
+ << pmadapter->pcard_sd->curr_wr_port)) ||
+ !MP_TX_AGGR_BUF_HAS_ROOM(
+ pmadapter, mbuf,
+ mbuf->data_len + next_pkt_len)) {
+ f_send_aggr_buf = 1;
+ }
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+
+ if (!(pmadapter->pcard_sd->mp_wr_bitmap &
+ (1
+ << pmadapter->pcard_sd->curr_wr_port))) {
+ f_send_cur_buf = 1;
+ } else {
+ f_postcopy_cur_buf = 1;
+ }
+ }
+ } else {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ mbuf->data_len) &&
+ (pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port)))
+ f_precopy_cur_buf = 1;
+ else
+ f_send_cur_buf = 1;
+ }
+ } else {
+ /* Last pkt in TX queue */
+ PRINTM(MINFO,
+ "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
+
+ if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
+ /* some packs in Aggr buf already */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
+ mbuf->data_len)) {
+ f_precopy_cur_buf = 1;
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_cur_buf = 1;
+ }
+ } else {
+ f_send_cur_buf = 1;
+ }
+ pmadapter->pcard_sd->mpa_sent_last_pkt++;
+ }
+
+ if (f_precopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Precopy current buffer\n");
+ if (pmadapter->pcard_sd->mpa_buf)
+ memcpy_ext(
+ pmadapter,
+ pmadapter->pcard_sd->mpa_buf +
+ (pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit +
+ pmadapter->pcard_sd->mpa_tx.pkt_cnt) *
+ MLAN_SDIO_BLOCK_SIZE,
+ mbuf->pbuf + mbuf->data_offset,
+ MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
+ if (!pmadapter->pcard_sd->mpa_tx.buf) {
+ MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
+ aggr_sg = MTRUE;
+ } else {
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+ }
+ if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter)) {
+ PRINTM(MIF_D,
+ "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
+ /* No more pkts allowed in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+ }
+ }
+
+ if (f_send_aggr_buf)
+ ret = wlan_send_mp_aggr_buf(pmadapter);
+
+tx_curr_single:
+ if (f_send_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n",
+ port);
+ ret = wlan_write_data_sync(pmadapter, mbuf,
+ pmadapter->pcard_sd->ioport + port);
+ if (!(pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port)))
+ pmadapter->pcard_sd->mpa_sent_no_ports++;
+ pmadapter->pcard_sd
+ ->last_mp_wr_bitmap[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->mp_wr_bitmap;
+ pmadapter->pcard_sd
+ ->last_mp_wr_ports[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->ioport + port;
+ pmadapter->pcard_sd
+ ->last_mp_wr_len[pmadapter->pcard_sd->last_mp_index] =
+ mbuf->data_len;
+ memset(pmadapter,
+ (t_u8 *)&pmadapter->pcard_sd->last_mp_wr_info
+ [pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit],
+ 0, sizeof(t_u16) * mp_aggr_pkt_limit);
+ pmadapter->pcard_sd
+ ->last_mp_wr_info[pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit] =
+ *(t_u16 *)(mbuf->pbuf + mbuf->data_offset);
+ pmadapter->pcard_sd
+ ->last_curr_wr_port[pmadapter->pcard_sd->last_mp_index] =
+ pmadapter->pcard_sd->curr_wr_port;
+ if (pmadapter->pcard_sd->mpa_buf)
+ memcpy_ext(pmadapter,
+ pmadapter->pcard_sd->mpa_buf +
+ (pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit *
+ MLAN_SDIO_BLOCK_SIZE),
+ mbuf->pbuf + mbuf->data_offset,
+ MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
+ pmadapter->pcard_sd->last_mp_index++;
+ if (pmadapter->pcard_sd->last_mp_index >= SDIO_MP_DBG_NUM)
+ pmadapter->pcard_sd->last_mp_index = 0;
+ pmadapter->pcard_sd->mpa_tx_count[0]++;
+ }
+ if (f_postcopy_cur_buf) {
+ PRINTM(MINFO, "host_2_card_mp_aggr: Postcopy current buffer\n");
+ if (pmadapter->pcard_sd->mpa_buf)
+ memcpy_ext(
+ pmadapter,
+ pmadapter->pcard_sd->mpa_buf +
+ (pmadapter->pcard_sd->last_mp_index *
+ mp_aggr_pkt_limit +
+ pmadapter->pcard_sd->mpa_tx.pkt_cnt) *
+ MLAN_SDIO_BLOCK_SIZE,
+ mbuf->pbuf + mbuf->data_offset,
+ MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
+ if (!pmadapter->pcard_sd->mpa_tx.buf) {
+ MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
+ aggr_sg = MTRUE;
+ } else {
+ MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
+ }
+ }
+ /* Always return PENDING in SG mode */
+ if (aggr_sg)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function checks if the interface is ready to download
+ * or not while other download interface is present
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param val Winner status (0: winner)
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ *
+ */
+mlan_status wlan_sdio_check_winner_status(mlan_adapter *pmadapter, t_u32 *val)
+{
+ t_u32 winner = 0;
+ pmlan_callbacks pcb;
+ t_u8 card_winner_check_reg = pmadapter->pcard_sd->reg->winner_check_reg;
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ card_winner_check_reg,
+ &winner)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ *val = winner;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function checks if the firmware is ready to accept
+ * command or not.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pollnum Maximum polling number
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_check_fw_status(mlan_adapter *pmadapter, t_u32 pollnum)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 firmwarestat = 0;
+ t_u32 tries;
+
+ ENTER();
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < pollnum; tries++) {
+ ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat);
+ if (MLAN_STATUS_SUCCESS != ret)
+ continue;
+ if (firmwarestat == SDIO_FIRMWARE_READY) {
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ } else {
+ wlan_mdelay(pmadapter, 100);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (pollnum > 1)
+ PRINTM(MERROR,
+ "Fail to poll firmware status: firmwarestat=0x%x\n",
+ firmwarestat);
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function enables the host interrupts.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_enable_sdio_host_int(pmlan_adapter pmadapter)
+{
+ mlan_status ret;
+ t_u8 mask = pmadapter->pcard_sd->reg->host_int_enable;
+
+ ENTER();
+ ret = wlan_sdio_enable_host_int_mask(pmadapter, mask);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_dnld_fw(pmlan_adapter pmadapter, pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 poll_num = 1;
+ t_u32 winner = 0;
+
+ ENTER();
+
+ /*when using GPIO wakeup, don't run the below code.
+ *if using GPIO wakeup, host will do handshake with FW
+ *to check if FW wake up and pull up SDIO line, then reload driver.
+ *So when using GPIO wakeup, don't need driver to do check wakeup status
+ *again. when using SDIO interface wakeup, run the below code; if using
+ *SDIO interface wakeup, driver need to do check wakeup status with FW.
+ */
+
+ /* Card specific probing */
+ ret = wlan_sdio_probe(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "WLAN SDIO probe failed\n", ret);
+ LEAVE();
+ return ret;
+ }
+
+ /* Check if firmware is already running */
+ ret = wlan_sdio_check_fw_status(pmadapter, poll_num);
+ if (ret == MLAN_STATUS_SUCCESS) {
+#if defined(SDIO)
+ if (pmfw->fw_reload == FW_RELOAD_SDIO_INBAND_RESET) {
+ PRINTM(MMSG, "Try reset fw in mlan\n");
+ ret = wlan_reset_fw(pmadapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "FW reset failure!");
+ LEAVE();
+ return ret;
+ }
+ } else {
+#endif
+ PRINTM(MMSG,
+ "WLAN FW already running! Skip FW download\n");
+#if defined(SDIO)
+ pmadapter->ops.wakeup_card(pmadapter, MFALSE);
+#endif
+ goto done;
+#if defined(SDIO)
+ }
+#endif
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if other interface is downloading */
+ ret = wlan_sdio_check_winner_status(pmadapter, &winner);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MFATAL, "WLAN read winner status failed!\n");
+ goto done;
+ }
+ if (winner) {
+ PRINTM(MMSG,
+ "WLAN is not the winner (0x%x). Skip FW download\n",
+ winner);
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+
+ /* Download the firmware image via helper */
+ ret = wlan_sdio_prog_fw_w_helper(pmadapter, pmfw->pfw_buf,
+ pmfw->fw_len);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
+ LEAVE();
+ return ret;
+ }
+
+poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = wlan_sdio_check_fw_status(pmadapter, poll_num);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "FW failed to be active in time!\n");
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+done:
+
+ /* re-enable host interrupt for mlan after fw dnld is successful */
+ wlan_enable_sdio_host_int(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function probes the driver
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_probe(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 sdio_ireg = 0;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ /*
+ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+ * from the bootloader. If we don't do this we get a interrupt
+ * as soon as we register the irq.
+ */
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ pmadapter->pcard_sd->reg->host_int_status_reg,
+ &sdio_ireg);
+
+ /* Disable host interrupt mask register for SDIO */
+ ret = wlan_disable_sdio_host_int(pmadapter);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Get SDIO ioport */
+ ret = wlan_sdio_init_ioport(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function get sdio device from card type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_get_sdio_device(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 card_type = pmadapter->card_type;
+
+ ENTER();
+
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_sdio_card),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->pcard_sd);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_sd) {
+ PRINTM(MERROR, "Failed to allocate pcard_sd\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (card_type) {
+#ifdef SD8887
+ case CARD_TYPE_SD8887:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8887;
+ pmadapter->pcard_info = &mlan_card_info_sd8887;
+ break;
+#endif
+#ifdef SD8897
+ case CARD_TYPE_SD8897:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8897;
+ pmadapter->pcard_info = &mlan_card_info_sd8897;
+ break;
+#endif
+#if defined(SD8977) || defined(SD8978)
+ case CARD_TYPE_SD8977:
+ case CARD_TYPE_SD8978:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
+ pmadapter->pcard_info = &mlan_card_info_sd8977;
+ break;
+#endif
+#ifdef SD8997
+ case CARD_TYPE_SD8997:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
+ pmadapter->pcard_info = &mlan_card_info_sd8997;
+ break;
+#endif
+#ifdef SD8987
+ case CARD_TYPE_SD8987:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
+ pmadapter->pcard_info = &mlan_card_info_sd8987;
+ break;
+#endif
+#ifdef SD9098
+ case CARD_TYPE_SD9098:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
+ pmadapter->pcard_info = &mlan_card_info_sd9098;
+ break;
+#endif
+#ifdef SD9097
+ case CARD_TYPE_SD9097:
+ pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
+ pmadapter->pcard_info = &mlan_card_info_sd9097;
+ break;
+#endif
+ default:
+ PRINTM(MERROR, "can't get right card type \n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function gets interrupt status.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_sdio_interrupt(t_u16 msg_id, pmlan_adapter pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf;
+ t_u32 sdio_ireg = 0;
+ t_u8 offset = 0;
+ t_u8 max_mp_regs = pmadapter->pcard_sd->reg->max_mp_regs;
+ t_u8 host_int_status_reg =
+ pmadapter->pcard_sd->reg->host_int_status_reg;
+
+ ENTER();
+
+ while (max_mp_regs) {
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = pmadapter->pcard_sd->mp_regs + offset;
+ mbuf.data_len = MIN(max_mp_regs, MLAN_SDIO_BLOCK_SIZE);
+
+ if (MLAN_STATUS_SUCCESS !=
+ pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
+ (REG_PORT + offset) |
+ MLAN_SDIO_BYTE_MODE_MASK,
+ 0)) {
+ PRINTM(MERROR,
+ "moal_read_data_sync: read registers failed\n");
+ pmadapter->dbg.num_int_read_failure++;
+ goto done;
+ }
+ offset += mbuf.data_len;
+ max_mp_regs -= mbuf.data_len;
+ }
+
+ DBG_HEXDUMP(MIF_D, "SDIO MP Registers", pmadapter->pcard_sd->mp_regs,
+ max_mp_regs);
+ sdio_ireg = pmadapter->pcard_sd->mp_regs[host_int_status_reg];
+ pmadapter->dbg.last_int_status = pmadapter->ireg | sdio_ireg;
+ if (sdio_ireg) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
+ * Clear the interrupt status register
+ */
+ PRINTM(MINTR, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ pmadapter->pcard_sd->num_of_irq++;
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ pmadapter->ireg |= sdio_ireg;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pint_lock);
+ if (!pmadapter->pps_uapsd_mode &&
+ pmadapter->ps_state == PS_STATE_SLEEP) {
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ }
+ } else {
+ PRINTM(MMSG, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
+ }
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function try to read the packet when fail to alloc rx buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param port Current port on which packet needs to be rxed
+ * @param rx_len Length of received packet
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_sdio_card_to_host_recovery(mlan_adapter *pmadapter,
+ t_u8 port, t_u16 rx_len)
+{
+ mlan_buffer mbuf;
+ t_u32 pkt_type = 0;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ ENTER();
+
+ if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
+ PRINTM(MDATA, "Recovery:do Rx Aggr\n");
+ /* do aggr RX now */
+ wlan_receive_mp_aggr_buf(pmadapter);
+ }
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = pmadapter->pcard_sd->rx_buf;
+ mbuf.data_len = rx_len;
+
+ PRINTM(MDATA, "Recovery: Try read port=%d rx_len=%d\n", port, rx_len);
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(pmadapter, &pkt_type,
+ (t_u32 *)&pmadapter->upld_len, &mbuf, rx_len,
+ pmadapter->pcard_sd->ioport + port)) {
+ PRINTM(MERROR, "Recovery: Fail to do cmd53\n");
+ }
+ if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
+ PRINTM(MERROR,
+ "Recovery: Receive a wrong pkt: type=%d, len=%d\n",
+ pkt_type, pmadapter->upld_len);
+ goto done;
+ }
+ if (pkt_type == MLAN_TYPE_DATA) {
+ // TODO fill the hole in Rx reorder table
+ PRINTM(MDATA, "Recovery: Drop Data packet\n");
+ pmadapter->dbg.num_pkt_dropped++;
+ } else if (pkt_type == MLAN_TYPE_SPA_DATA) {
+ PRINTM(MDATA, "Recovery: SPA Data packet len=%d\n",
+ pmadapter->upld_len);
+ wlan_decode_spa_buffer(pmadapter, pmadapter->pcard_sd->rx_buf,
+ pmadapter->upld_len);
+ pmadapter->data_received = MTRUE;
+ }
+ PRINTM(MMSG, "wlan: Success handle rx port=%d, rx_len=%d \n", port,
+ rx_len);
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the interrupt status and handle it accordingly.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_sdio_int_status(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 sdio_ireg;
+ mlan_buffer *pmbuf = MNULL;
+
+ t_u8 port = 0;
+ t_u32 len_reg_l, len_reg_u;
+ t_u32 rx_blocks;
+ t_u8 bit_count = 0;
+ t_u32 ps_state = pmadapter->ps_state;
+ t_u16 rx_len;
+ t_u32 upld_typ = 0;
+ t_u32 cr = 0;
+ const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
+ t_u8 rd_len_p0_l = reg->rd_len_p0_l;
+ t_u8 rd_len_p0_u = reg->rd_len_p0_u;
+ t_u8 cmd_rd_len_0 = reg->cmd_rd_len_0;
+ t_u8 cmd_rd_len_1 = reg->cmd_rd_len_1;
+
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+ sdio_ireg = (t_u8)pmadapter->ireg;
+ pmadapter->ireg = 0;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
+
+ if (!sdio_ireg)
+ goto done;
+
+ /* check the command port */
+ if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS) {
+ if (pmadapter->cmd_sent)
+ pmadapter->cmd_sent = MFALSE;
+
+ PRINTM(MINFO, "cmd_sent=%d\n", pmadapter->cmd_sent);
+ }
+
+ if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) {
+ /* read the len of control packet */
+ rx_len = ((t_u16)pmadapter->pcard_sd->mp_regs[cmd_rd_len_1])
+ << 8;
+ rx_len |= (t_u16)pmadapter->pcard_sd->mp_regs[cmd_rd_len_0];
+ PRINTM(MINFO, "RX: cmd port rx_len=%u\n", rx_len);
+ rx_blocks = (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) /
+ MLAN_SDIO_BLOCK_SIZE;
+ if (rx_len <= SDIO_INTF_HEADER_LEN ||
+ (rx_blocks * MLAN_SDIO_BLOCK_SIZE) > ALLOC_BUF_SIZE) {
+ PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, rx_len, 0,
+ MOAL_MALLOC_BUFFER);
+ if (pmbuf == MNULL) {
+ PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MINFO, "cmd rx buffer rx_len = %d\n", rx_len);
+
+ /* Transfer data from card */
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host(
+ pmadapter, &upld_typ, (t_u32 *)&pmadapter->upld_len,
+ pmbuf, rx_len,
+ pmadapter->pcard_sd->ioport | CMD_PORT_SLCT)) {
+ pmadapter->dbg.num_cmdevt_card_to_host_failure++;
+ PRINTM(MERROR,
+ "Card-to-host cmd failed: int status=0x%x\n",
+ sdio_ireg);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ ret = MLAN_STATUS_FAILURE;
+ goto term_cmd53;
+ }
+
+ if ((upld_typ != MLAN_TYPE_CMD) &&
+ (upld_typ != MLAN_TYPE_EVENT))
+ PRINTM(MERROR,
+ "receive a wrong packet from CMD PORT. type =0x%x\n",
+ upld_typ);
+
+ wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ, MFALSE);
+
+ /* We might receive data/sleep_cfm at the same time */
+ /* reset data_receive flag to avoid ps_state change */
+ if ((ps_state == PS_STATE_SLEEP_CFM) &&
+ (pmadapter->ps_state == PS_STATE_SLEEP))
+ pmadapter->data_received = MFALSE;
+ }
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ if (pmadapter->pcard_sd->mp_wr_bitmap &
+ pmadapter->pcard_sd->mp_data_port_mask)
+ pmadapter->pcard_sd->mp_invalid_update++;
+ pmadapter->pcard_sd->mp_wr_bitmap =
+ (t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_l];
+ pmadapter->pcard_sd->mp_wr_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_u])
+ << 8;
+ pmadapter->pcard_sd->mp_wr_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_1l])
+ << 16;
+ pmadapter->pcard_sd->mp_wr_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_1u])
+ << 24;
+ bit_count = bitcount(pmadapter->pcard_sd->mp_wr_bitmap &
+ pmadapter->pcard_sd->mp_data_port_mask);
+ if (bit_count) {
+ pmadapter->pcard_sd->mp_update[bit_count - 1]++;
+ if (pmadapter->pcard_sd->mp_update[bit_count - 1] ==
+ 0xffffffff)
+ memset(pmadapter,
+ pmadapter->pcard_sd->mp_update, 0,
+ sizeof(pmadapter->pcard_sd->mp_update));
+ }
+
+ pmadapter->pcard_sd->last_recv_wr_bitmap =
+ pmadapter->pcard_sd->mp_wr_bitmap;
+ PRINTM(MINTR, "DNLD: wr_bitmap=0x%08x\n",
+ pmadapter->pcard_sd->mp_wr_bitmap);
+ if (pmadapter->data_sent &&
+ (pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port))) {
+ PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
+ pmadapter->data_sent = MFALSE;
+ }
+ }
+
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+ pmadapter->pcard_sd->mp_rd_bitmap =
+ (t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_l];
+ pmadapter->pcard_sd->mp_rd_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_u])
+ << 8;
+ pmadapter->pcard_sd->mp_rd_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_1l])
+ << 16;
+ pmadapter->pcard_sd->mp_rd_bitmap |=
+ ((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_1u])
+ << 24;
+ PRINTM(MINTR, "UPLD: rd_bitmap=0x%08x\n",
+ pmadapter->pcard_sd->mp_rd_bitmap);
+
+ while (MTRUE) {
+ ret = wlan_get_rd_port(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO,
+ "no more rd_port to be handled\n");
+ break;
+ }
+ len_reg_l = rd_len_p0_l + (port << 1);
+ len_reg_u = rd_len_p0_u + (port << 1);
+ rx_len =
+ ((t_u16)pmadapter->pcard_sd->mp_regs[len_reg_u])
+ << 8;
+ rx_len |=
+ (t_u16)pmadapter->pcard_sd->mp_regs[len_reg_l];
+ PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
+ rx_blocks = (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) /
+ MLAN_SDIO_BLOCK_SIZE;
+ if (rx_len <= SDIO_INTF_HEADER_LEN ||
+ (rx_blocks * MLAN_SDIO_BLOCK_SIZE) >
+ pmadapter->pcard_sd->mpa_rx.buf_size) {
+ PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
+ if (rx_len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE)
+ pmbuf = wlan_alloc_mlan_buffer(
+ pmadapter, rx_len, 0,
+ MOAL_MALLOC_BUFFER);
+ else
+ pmbuf = wlan_alloc_mlan_buffer(
+ pmadapter, rx_len, MLAN_RX_HEADER_LEN,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (pmbuf == MNULL) {
+ PRINTM(MERROR,
+ "Failed to allocate 'mlan_buffer'\n");
+ pmadapter->dbg.num_alloc_buffer_failure++;
+ if (MLAN_STATUS_SUCCESS ==
+ wlan_sdio_card_to_host_recovery(
+ pmadapter, port, rx_len))
+ continue;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MINFO, "rx_len = %d\n", rx_len);
+ if (MLAN_STATUS_SUCCESS !=
+ wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf,
+ port, rx_len)) {
+ pmadapter->dbg.num_rx_card_to_host_failure++;
+
+ PRINTM(MERROR,
+ "Card to host failed: int status=0x%x\n",
+ sdio_ireg);
+ ret = MLAN_STATUS_FAILURE;
+ goto term_cmd53;
+ }
+ }
+ /* We might receive data/sleep_cfm at the same time */
+ /* reset data_receive flag to avoid ps_state change */
+ if ((ps_state == PS_STATE_SLEEP_CFM) &&
+ (pmadapter->ps_state == PS_STATE_SLEEP))
+ pmadapter->data_received = MFALSE;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+
+term_cmd53:
+ /* terminate cmd53 */
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config Reg val = %d\n", cr);
+ if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ (cr | HOST_TERM_CMD53)))
+ PRINTM(MERROR, "write CFG reg failed\n");
+ PRINTM(MINFO, "write success\n");
+ if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ &cr))
+ PRINTM(MERROR, "read CFG reg failed\n");
+ PRINTM(MINFO, "Config reg val =%x\n", cr);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * SDIO header)
+ * @param tx_param A pointer to mlan_tx_param
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_host_to_card(mlan_adapter *pmadapter, t_u8 type,
+ mlan_buffer *pmbuf, mlan_tx_param *tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 buf_block_len;
+ t_u32 blksz;
+ t_u8 port = 0;
+ t_u32 cmd53_port = 0;
+ t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
+
+ ENTER();
+
+ /* Allocate buffer and copy payload */
+ blksz = MLAN_SDIO_BLOCK_SIZE;
+ buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
+ *(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
+ *(t_u16 *)&payload[2] = wlan_cpu_to_le16(type);
+
+ /*
+ * This is SDIO specific header
+ * t_u16 length,
+ * t_u16 type (MLAN_TYPE_DATA = 0,
+ * MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
+ */
+ if (type == MLAN_TYPE_DATA) {
+ ret = wlan_get_wr_port_data(pmadapter, &port);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "no wr_port available: wr_bitmap=0x%08x curr_wr_port=%d\n",
+ pmadapter->pcard_sd->mp_wr_bitmap,
+ pmadapter->pcard_sd->curr_wr_port);
+ goto exit;
+ }
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+
+ if (tx_param)
+ ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
+ tx_param->next_pkt_len);
+ else
+ ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
+ 0);
+ } else {
+ /*Type must be MLAN_TYPE_CMD*/
+ pmadapter->cmd_sent = MTRUE;
+ if (pmbuf->data_len <= SDIO_INTF_HEADER_LEN ||
+ pmbuf->data_len > WLAN_UPLD_SIZE)
+ PRINTM(MWARN,
+ "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
+ payload, pmbuf->data_len);
+ /* Transfer data to card */
+ pmbuf->data_len = buf_block_len * blksz;
+ cmd53_port = (pmadapter->pcard_sd->ioport) | CMD_PORT_SLCT;
+ ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
+ }
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
+ if (type == MLAN_TYPE_CMD)
+ pmadapter->cmd_sent = MFALSE;
+ if (type == MLAN_TYPE_DATA)
+ pmadapter->data_sent = MFALSE;
+ } else {
+ if (type == MLAN_TYPE_DATA) {
+ if (!(pmadapter->pcard_sd->mp_wr_bitmap &
+ (1 << pmadapter->pcard_sd->curr_wr_port)))
+ pmadapter->data_sent = MTRUE;
+ else
+ pmadapter->data_sent = MFALSE;
+ }
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Wr",
+ pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+ }
+exit:
+ LEAVE();
+ return ret;
+}
+
+#if (defined(SD9098) || defined(SD9097))
+/**
+ * @brief This function sends vdll data to the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * SDIO header)
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_send_vdll(mlan_adapter *pmadapter, mlan_buffer *pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 buf_block_len;
+ t_u32 blksz;
+ t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
+ t_u32 cmd53_port = 0;
+ ENTER();
+ blksz = MLAN_SDIO_BLOCK_SIZE;
+ buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
+
+ *(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
+ *(t_u16 *)&payload[2] = wlan_cpu_to_le16(MLAN_TYPE_VDLL);
+
+ pmbuf->data_len = buf_block_len * blksz;
+
+ if (pmbuf->data_len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ PRINTM(MERROR, "VDLL block is too big: %d\n", pmbuf->data_len);
+ return MLAN_STATUS_FAILURE;
+ }
+ cmd53_port = (pmadapter->pcard_sd->ioport) | CMD_PORT_SLCT;
+ pmadapter->cmd_sent = MTRUE;
+ ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
+ if (ret == MLAN_STATUS_FAILURE)
+ PRINTM(MERROR, "Send Vdll: host_to_card failed: 0x%X\n", ret);
+ else
+ DBG_HEXDUMP(MIF_D, "SDIO Blk Wr",
+ pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function sends data to the card.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * SDIO header)
+ * @param tx_param A pointer to mlan_tx_param
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_sdio_host_to_card_ext(pmlan_private pmpriv, t_u8 type,
+ mlan_buffer *pmbuf,
+ mlan_tx_param *tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+
+#if (defined(SD9098) || defined(SD9097))
+ if (type == MLAN_TYPE_VDLL)
+ return wlan_sdio_send_vdll(pmadapter, pmbuf);
+#endif
+ ret = wlan_sdio_host_to_card(pmadapter, type, pmbuf, tx_param);
+
+ if (type == MLAN_TYPE_DATA && ret == MLAN_STATUS_FAILURE)
+ pmadapter->data_sent = MFALSE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deaggregate single port aggregation packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param buf A pointer to aggregated data packet
+ * @param len
+ *
+ * @return N/A
+ */
+void wlan_decode_spa_buffer(mlan_adapter *pmadapter, t_u8 *buf, t_u32 len)
+{
+ int total_pkt_len;
+ t_u8 block_num = 0;
+ t_u16 block_size = 0;
+ t_u8 *data;
+ t_u32 pkt_len, pkt_type = 0;
+ mlan_buffer *mbuf_deaggr = MNULL;
+
+ ENTER();
+
+ data = (t_u8 *)buf;
+ total_pkt_len = len;
+ if (total_pkt_len < pmadapter->pcard_sd->sdio_rx_block_size) {
+ PRINTM(MERROR, "Invalid sp aggr packet size=%d\n",
+ total_pkt_len);
+ goto done;
+ }
+ while (total_pkt_len >=
+ (OFFSET_OF_SDIO_HEADER + SDIO_INTF_HEADER_LEN)) {
+ block_num = *(data + OFFSET_OF_BLOCK_NUMBER);
+ block_size =
+ pmadapter->pcard_sd->sdio_rx_block_size * block_num;
+ if (block_size > total_pkt_len) {
+ PRINTM(MERROR,
+ "Error in pkt, block_num=%d, pkt_len=%d\n",
+ block_num, total_pkt_len);
+ break;
+ }
+ pkt_len = wlan_le16_to_cpu(
+ *(t_u16 *)(data + OFFSET_OF_SDIO_HEADER));
+ pkt_type = wlan_le16_to_cpu(
+ *(t_u16 *)(data + OFFSET_OF_SDIO_HEADER + 2));
+ if ((pkt_len + OFFSET_OF_SDIO_HEADER) > block_size) {
+ PRINTM(MERROR,
+ "Error in pkt, pkt_len=%d, block_size=%d\n",
+ pkt_len, block_size);
+ break;
+ }
+ mbuf_deaggr = wlan_alloc_mlan_buffer(
+ pmadapter, pkt_len - SDIO_INTF_HEADER_LEN,
+ MLAN_RX_HEADER_LEN, MOAL_ALLOC_MLAN_BUFFER);
+ if (mbuf_deaggr == MNULL) {
+ PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
+ break;
+ }
+ memcpy_ext(pmadapter,
+ mbuf_deaggr->pbuf + mbuf_deaggr->data_offset,
+ data + OFFSET_OF_SDIO_HEADER + SDIO_INTF_HEADER_LEN,
+ pkt_len - SDIO_INTF_HEADER_LEN,
+ pkt_len - SDIO_INTF_HEADER_LEN);
+ mbuf_deaggr->data_len = pkt_len - SDIO_INTF_HEADER_LEN;
+ wlan_handle_rx_packet(pmadapter, mbuf_deaggr);
+ data += block_size;
+ total_pkt_len -= block_size;
+ if (total_pkt_len < pmadapter->pcard_sd->sdio_rx_block_size)
+ break;
+ }
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function deaggr rx pkt
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the SDIO mpa data
+ * @return N/A
+ */
+t_void wlan_sdio_deaggr_rx_pkt(pmlan_adapter pmadapter, mlan_buffer *pmbuf)
+{
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_SPA_DATA) {
+ wlan_decode_spa_buffer(pmadapter,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else
+ wlan_handle_rx_packet(pmadapter, pmbuf);
+}
+
+/**
+ * @brief This function allocates buffer for the SDIO aggregation buffer
+ * related members of adapter structure
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param mpa_tx_buf_size Tx buffer size to allocate
+ * @param mpa_rx_buf_size Rx buffer size to allocate
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_alloc_sdio_mpa_buffers(mlan_adapter *pmadapter,
+ t_u32 mpa_tx_buf_size,
+ t_u32 mpa_rx_buf_size)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ ENTER();
+
+ if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
+ (pmadapter->pcard_sd->max_seg_size <
+ pmadapter->pcard_sd->max_sp_tx_size)) {
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ mpa_tx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->mpa_tx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->mpa_tx.head_ptr) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for SDIO MP TX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->pcard_sd->mpa_tx.buf = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->mpa_tx.head_ptr, DMA_ALIGNMENT);
+ } else {
+ PRINTM(MMSG, "wlan: Enable TX SG mode\n");
+ pmadapter->pcard_sd->mpa_tx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_tx.buf = MNULL;
+ }
+ pmadapter->pcard_sd->mpa_tx.buf_size = mpa_tx_buf_size;
+
+ if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
+ (pmadapter->pcard_sd->max_seg_size <
+ pmadapter->pcard_sd->max_sp_rx_size)) {
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ mpa_rx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->mpa_rx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->mpa_rx.head_ptr) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for SDIO MP RX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->pcard_sd->mpa_rx.buf = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->mpa_rx.head_ptr, DMA_ALIGNMENT);
+ } else {
+ PRINTM(MMSG, "wlan: Enable RX SG mode\n");
+ pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf = MNULL;
+ }
+ pmadapter->pcard_sd->mpa_rx.buf_size = mpa_rx_buf_size;
+error:
+ if (ret != MLAN_STATUS_SUCCESS)
+ wlan_free_sdio_mpa_buffers(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees buffers for the SDIO aggregation
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_free_sdio_mpa_buffers(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ if (pmadapter->pcard_sd->mpa_tx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mpa_tx.head_ptr);
+ pmadapter->pcard_sd->mpa_tx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_tx.buf = MNULL;
+ pmadapter->pcard_sd->mpa_tx.buf_size = 0;
+ }
+
+ if (pmadapter->pcard_sd->mpa_rx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mpa_rx.head_ptr);
+ pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf_size = 0;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function re-allocate rx mpa buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_re_alloc_sdio_rx_mpa_buffer(mlan_adapter *pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+ t_u32 mpa_rx_buf_size = SDIO_MP_AGGR_BUF_SIZE_MAX;
+
+ if (pmadapter->pcard_sd->mpa_rx.buf) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->mpa_rx.head_ptr);
+ pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf_size = 0;
+ }
+ if (pmadapter->pcard_sd->sdio_rx_aggr_enable) {
+ mpa_rx_buf_size = MAX(mpa_rx_buf_size, SDIO_CMD53_MAX_SIZE);
+ /** reallocate rx buffer for recover when single port rx
+ * aggregation enabled */
+ if (pmadapter->pcard_sd->rx_buffer) {
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->pcard_sd->rx_buffer);
+ pmadapter->pcard_sd->rx_buffer = MNULL;
+ pmadapter->pcard_sd->rx_buf = MNULL;
+ }
+ ret = pmadapter->callbacks.moal_malloc(
+ pmadapter->pmoal_handle,
+ SDIO_CMD53_MAX_SIZE + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->rx_buffer);
+
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->rx_buffer) {
+ PRINTM(MERROR, "Failed to allocate receive buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->pcard_sd->rx_buf = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->rx_buffer, DMA_ALIGNMENT);
+ }
+ if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
+ (pmadapter->pcard_sd->max_seg_size <
+ pmadapter->pcard_sd->max_sp_rx_size)) {
+ ret = pcb->moal_malloc(
+ pmadapter->pmoal_handle,
+ mpa_rx_buf_size + DMA_ALIGNMENT,
+ MLAN_MEM_DEF | MLAN_MEM_DMA,
+ (t_u8 **)&pmadapter->pcard_sd->mpa_rx.head_ptr);
+ if (ret != MLAN_STATUS_SUCCESS ||
+ !pmadapter->pcard_sd->mpa_rx.head_ptr) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for SDIO MP RX aggr\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->pcard_sd->mpa_rx.buf = (t_u8 *)ALIGN_ADDR(
+ pmadapter->pcard_sd->mpa_rx.head_ptr, DMA_ALIGNMENT);
+ } else {
+ PRINTM(MMSG, "wlan: Enable RX SG mode\n");
+ pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
+ pmadapter->pcard_sd->mpa_rx.buf = MNULL;
+ }
+ pmadapter->pcard_sd->mpa_rx.buf_size = mpa_rx_buf_size;
+ PRINTM(MMSG, "mpa_rx_buf_size=%d\n", mpa_rx_buf_size);
+error:
+ return ret;
+}
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param timeout set timeout flag
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pm_sdio_wakeup_card(pmlan_adapter pmadapter, t_u8 timeout)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 age_ts_usec;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ PRINTM(MEVENT, "Wakeup device...\n");
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->pm_wakeup_in_secs,
+ &age_ts_usec);
+
+ if (timeout) {
+ pmadapter->callbacks.moal_start_timer(
+ pmadapter->pmoal_handle, pmadapter->pwakeup_fw_timer,
+ MFALSE, MRVDRV_TIMER_3S);
+ pmadapter->wakeup_fw_timer_is_set = MTRUE;
+ }
+
+ ret = pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, HOST_POWER_UP);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function resets the PM setting of the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pm_sdio_reset_card(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+
+ ret = pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, 0);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_set_sdio_gpio_int(pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = MNULL;
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_int_cfg;
+
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter = priv->adapter;
+
+ ENTER();
+
+ if (pmadapter->pcard_sd->int_mode == INT_MODE_GPIO) {
+ if (pmadapter->pcard_sd->gpio_pin != GPIO_INT_NEW_MODE) {
+ PRINTM(MINFO,
+ "SDIO_GPIO_INT_CONFIG: interrupt mode is GPIO\n");
+ sdio_int_cfg.action = HostCmd_ACT_GEN_SET;
+ sdio_int_cfg.gpio_pin = pmadapter->pcard_sd->gpio_pin;
+ sdio_int_cfg.gpio_int_edge = INT_FALLING_EDGE;
+ sdio_int_cfg.gpio_pulse_width = DELAY_1_US;
+ ret = wlan_prepare_cmd(priv,
+ HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &sdio_int_cfg);
+
+ if (ret) {
+ PRINTM(MERROR,
+ "SDIO_GPIO_INT_CONFIG: send command fail\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ } else {
+ PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is SDIO\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of SDIO GPIO interrupt
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_SDIO_GPIO_INT_CONFIG *psdio_gpio_int =
+ &cmd->params.sdio_gpio_int;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG)) +
+ S_DS_GEN);
+
+ memset(pmpriv->adapter, psdio_gpio_int, 0,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy_ext(pmpriv->adapter, psdio_gpio_int, pdata_buf,
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG),
+ sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
+ psdio_gpio_int->action =
+ wlan_cpu_to_le16(psdio_gpio_int->action);
+ psdio_gpio_int->gpio_pin =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_pin);
+ psdio_gpio_int->gpio_int_edge =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_int_edge);
+ psdio_gpio_int->gpio_pulse_width =
+ wlan_cpu_to_le16(psdio_gpio_int->gpio_pulse_width);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+mlan_status wlan_reset_fw(pmlan_adapter pmadapter)
+{
+ t_u32 tries = 0;
+ t_u32 value = 1;
+ t_u32 reset_reg = pmadapter->pcard_sd->reg->fw_reset_reg;
+ t_u8 reset_val = pmadapter->pcard_sd->reg->fw_reset_val;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ wlan_pm_sdio_wakeup_card(pmadapter, MFALSE);
+
+ /** wait SOC fully wake up */
+ for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
+ if (MLAN_STATUS_SUCCESS ==
+ pcb->moal_write_reg(pmadapter->pmoal_handle, reset_reg,
+ 0xba)) {
+ pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg,
+ &value);
+ if (value == 0xba) {
+ PRINTM(MMSG, "FW wake up\n");
+ break;
+ }
+ }
+ pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
+ }
+ /* Write register to notify FW */
+ if (MLAN_STATUS_FAILURE == pcb->moal_write_reg(pmadapter->pmoal_handle,
+ reset_reg, reset_val)) {
+ PRINTM(MERROR, "Failed to write register.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if defined(SD8997) || defined(SD8977) || defined(SD8987) || \
+ defined(SD9098) || defined(SD9097) || defined(SD8978)
+ if (MFALSE
+#ifdef SD8997
+ || IS_SD8997(pmadapter->card_type)
+#endif
+#ifdef SD8977
+ || IS_SD8977(pmadapter->card_type)
+#endif
+#ifdef SD8978
+ || IS_SD8978(pmadapter->card_type)
+#endif
+#ifdef SD8987
+ || IS_SD8987(pmadapter->card_type)
+#endif
+#ifdef SD9098
+ || IS_SD9098(pmadapter->card_type)
+#endif
+#ifdef SD9097
+ || IS_SD9097(pmadapter->card_type)
+#endif
+ ) {
+ pcb->moal_read_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG, &value);
+ pcb->moal_write_reg(pmadapter->pmoal_handle,
+ HOST_TO_CARD_EVENT_REG,
+ value | HOST_POWER_UP);
+ }
+#endif
+ /* Poll register around 100 ms */
+ for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
+ pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg, &value);
+ if (value == 0)
+ /* FW is ready */
+ break;
+ pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
+ }
+
+ if (value) {
+ PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
+ reset_reg, value);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MMSG, "FW Reset success\n");
+ ret = wlan_sdio_probe(pmadapter);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handle event/data/cmd complete
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return N/A
+ */
+mlan_status wlan_sdio_data_evt_complete(pmlan_adapter pmadapter,
+ mlan_buffer *pmbuf, mlan_status status)
+{
+ ENTER();
+
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle receive packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return
+ */
+mlan_status wlan_sdio_handle_rx_packet(mlan_adapter *pmadapter,
+ pmlan_buffer pmbuf)
+{
+ ENTER();
+
+ wlan_sdio_deaggr_rx_pkt(pmadapter, pmbuf);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+mlan_adapter_operations mlan_sdio_ops = {
+ .dnld_fw = wlan_sdio_dnld_fw,
+ .interrupt = wlan_sdio_interrupt,
+ .process_int_status = wlan_process_sdio_int_status,
+ .host_to_card = wlan_sdio_host_to_card_ext,
+ .wakeup_card = wlan_pm_sdio_wakeup_card,
+ .reset_card = wlan_pm_sdio_reset_card,
+ .event_complete = wlan_sdio_data_evt_complete,
+ .data_complete = wlan_sdio_data_evt_complete,
+ .cmdrsp_complete = wlan_sdio_data_evt_complete,
+ .handle_rx_packet = wlan_sdio_handle_rx_packet,
+
+ .intf_header_len = SDIO_INTF_HEADER_LEN,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.h
new file mode 100644
index 000000000000..6f653365a63a
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sdio.h
@@ -0,0 +1,550 @@
+/** @file mlan_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MLAN_SDIO_H
+#define _MLAN_SDIO_H
+
+/** Block mode */
+#ifndef BLOCK_MODE
+#define BLOCK_MODE 1
+#endif
+
+/** Fixed address mode */
+#ifndef FIXED_ADDRESS
+#define FIXED_ADDRESS 0
+#endif
+
+/* Host Control Registers */
+/** Host Control Registers : Host to Card Event */
+#define HOST_TO_CARD_EVENT_REG 0x00
+/** Host Control Registers : Host terminates Command 53 */
+#define HOST_TERM_CMD53 (0x1U << 2)
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+#define HOST_INT_RSR_MASK 0xFF
+
+/** Host Control Registers : Upload command port host interrupt status */
+#define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U)
+/** Host Control Registers : Download command port host interrupt status */
+#define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U)
+
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/** Host Control Registers : Cmd port upload interrupt mask */
+#define CMD_PORT_UPLD_INT_MASK (0x1U << 6)
+/** Host Control Registers : Cmd port download interrupt mask */
+#define CMD_PORT_DNLD_INT_MASK (0x1U << 7)
+/** Enable Host interrupt mask */
+#define HIM_ENABLE \
+ (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | CMD_PORT_UPLD_INT_MASK | \
+ CMD_PORT_DNLD_INT_MASK)
+/** Disable Host interrupt mask */
+#define HIM_DISABLE 0xff
+
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/** Host Control Registers : Download CRC error */
+#define DN_LD_CRC_ERR (0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/** Card Control Registers : Command port upload ready */
+#define UP_LD_CP_RDY (0x1U << 6)
+/** Card Control Registers : Command port download ready */
+#define DN_LD_CP_RDY (0x1U << 7)
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0 (0x1U)
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1 (0x1U)
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2 (0x1U)
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3 (0x1U)
+
+/** Port for registers */
+#define REG_PORT 0
+/** Port for memory */
+#define MEM_PORT 0x10000
+
+/** Card Control Registers : cmd53 new mode */
+#define CMD53_NEW_MODE (0x1U << 0)
+/** Card Control Registers : cmd53 tx len format 1 (0x10) */
+#define CMD53_TX_LEN_FORMAT_1 (0x1U << 4)
+/** Card Control Registers : cmd53 tx len format 2 (0x20)*/
+#define CMD53_TX_LEN_FORMAT_2 (0x1U << 5)
+/** Card Control Registers : cmd53 rx len format 1 (0x40) */
+#define CMD53_RX_LEN_FORMAT_1 (0x1U << 6)
+/** Card Control Registers : cmd53 rx len format 2 (0x80)*/
+#define CMD53_RX_LEN_FORMAT_2 (0x1U << 7)
+
+#define CMD_PORT_RD_LEN_EN (0x1U << 2)
+/* Card Control Registers : cmd port auto enable */
+#define CMD_PORT_AUTO_EN (0x1U << 0)
+
+/* Command port */
+#define CMD_PORT_SLCT 0x8000
+
+/** Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT MBIT(4)
+
+/** Enable GPIO-1 as a duplicated signal of interrupt as appear of SDIO_DAT1*/
+#define ENABLE_GPIO_1_INT_MODE 0x88
+/** Scratch reg 3 2 : Configure GPIO-1 INT*/
+#define SCRATCH_REG_32 0xEE
+
+/** Event header Len*/
+#define MLAN_EVENT_HEADER_LEN 8
+
+/** SDIO byte mode size */
+#define MAX_BYTE_MODE_SIZE 512
+
+/** The base address for packet with multiple ports aggregation */
+#define SDIO_MPA_ADDR_BASE 0x1000
+
+/** SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->pcard_sd->mpa_tx.pkt_cnt > 0)
+
+/** SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a, mbuf, len) \
+ (((a->pcard_sd->mpa_tx.buf_len) + len) <= \
+ (a->pcard_sd->mpa_tx.buf_size))
+
+/** Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, mbuf, port) \
+ do { \
+ pmadapter->callbacks.moal_memmove( \
+ a->pmoal_handle, \
+ &a->pcard_sd->mpa_tx.buf[a->pcard_sd->mpa_tx.buf_len], \
+ mbuf->pbuf + mbuf->data_offset, mbuf->data_len); \
+ a->pcard_sd->mpa_tx.buf_len += mbuf->data_len; \
+ a->pcard_sd->mpa_tx.mp_wr_info[a->pcard_sd->mpa_tx.pkt_cnt] = \
+ *(t_u16 *)(mbuf->pbuf + mbuf->data_offset); \
+ if (!a->pcard_sd->mpa_tx.pkt_cnt) { \
+ a->pcard_sd->mpa_tx.start_port = port; \
+ } \
+ a->pcard_sd->mpa_tx.ports |= (1 << port); \
+ a->pcard_sd->mpa_tx.pkt_cnt++; \
+ } while (0)
+
+#define MP_TX_AGGR_BUF_PUT_SG(a, mbuf, port) \
+ do { \
+ a->pcard_sd->mpa_tx.buf_len += mbuf->data_len; \
+ a->pcard_sd->mpa_tx.mp_wr_info[a->pcard_sd->mpa_tx.pkt_cnt] = \
+ *(t_u16 *)(mbuf->pbuf + mbuf->data_offset); \
+ a->pcard_sd->mpa_tx.mbuf_arr[a->pcard_sd->mpa_tx.pkt_cnt] = \
+ mbuf; \
+ if (!a->pcard_sd->mpa_tx.pkt_cnt) { \
+ a->pcard_sd->mpa_tx.start_port = port; \
+ } \
+ a->pcard_sd->mpa_tx.ports |= (1 << port); \
+ a->pcard_sd->mpa_tx.pkt_cnt++; \
+ } while (0)
+/** SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \
+ ((a->pcard_sd->mpa_tx.pkt_cnt) == (a->pcard_sd->mpa_tx.pkt_aggr_limit))
+
+/** Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) \
+ do { \
+ memset(a, a->pcard_sd->mpa_tx.mp_wr_info, 0, \
+ sizeof(a->pcard_sd->mpa_tx.mp_wr_info)); \
+ a->pcard_sd->mpa_tx.pkt_cnt = 0; \
+ a->pcard_sd->mpa_tx.buf_len = 0; \
+ a->pcard_sd->mpa_tx.ports = 0; \
+ a->pcard_sd->mpa_tx.start_port = 0; \
+ } while (0)
+
+/** SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \
+ (a->pcard_sd->mpa_rx.pkt_cnt == a->pcard_sd->mpa_rx.pkt_aggr_limit)
+
+/** SDIO Rx aggregation port limit ? */
+/** this is for test only, because port 0 is reserved for control port */
+/* #define MP_RX_AGGR_PORT_LIMIT_REACHED(a) (a->curr_rd_port == 1) */
+
+/* receive packets aggregated up to a half of mp_end_port */
+/* note: hw rx wraps round only after port (MAX_PORT-1) */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) \
+ (((a->pcard_sd->curr_rd_port < a->pcard_sd->mpa_rx.start_port) && \
+ (((MAX_PORT - a->pcard_sd->mpa_rx.start_port) + \
+ a->pcard_sd->curr_rd_port) >= (a->pcard_sd->mp_end_port >> 1))) || \
+ ((a->pcard_sd->curr_rd_port - a->pcard_sd->mpa_rx.start_port) >= \
+ (a->pcard_sd->mp_end_port >> 1)))
+
+/** SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->pcard_sd->mpa_rx.pkt_cnt > 0)
+
+/** SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \
+ ((a->pcard_sd->mpa_rx.buf_len + rx_len) <= a->pcard_sd->mpa_rx.buf_size)
+
+/** Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, mbuf, port, rx_len) \
+ do { \
+ a->pcard_sd->mpa_rx.buf_len += rx_len; \
+ if (!a->pcard_sd->mpa_rx.pkt_cnt) { \
+ a->pcard_sd->mpa_rx.start_port = port; \
+ } \
+ a->pcard_sd->mpa_rx.ports |= (1 << port); \
+ a->pcard_sd->mpa_rx.mbuf_arr[a->pcard_sd->mpa_rx.pkt_cnt] = \
+ mbuf; \
+ a->pcard_sd->mpa_rx.len_arr[a->pcard_sd->mpa_rx.pkt_cnt] = \
+ rx_len; \
+ a->pcard_sd->mpa_rx.pkt_cnt++; \
+ } while (0)
+
+/** Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) \
+ do { \
+ a->pcard_sd->mpa_rx.pkt_cnt = 0; \
+ a->pcard_sd->mpa_rx.buf_len = 0; \
+ a->pcard_sd->mpa_rx.ports = 0; \
+ a->pcard_sd->mpa_rx.start_port = 0; \
+ } while (0)
+
+/** aggr buf size 32k */
+#define SDIO_MP_AGGR_BUF_SIZE_32K (32768)
+/** max aggr buf size 64k-256 */
+#define SDIO_MP_AGGR_BUF_SIZE_MAX (65280)
+
+#ifdef SD8887
+static const struct _mlan_sdio_card_reg mlan_reg_sd8887 = {
+ .start_rd_port = 0,
+ .start_wr_port = 0,
+ .base_0_reg = 0x6C,
+ .base_1_reg = 0x6D,
+ .poll_reg = 0x5C,
+ .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
+ CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+ .host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
+ DN_LD_CMD_PORT_HOST_INT_STATUS |
+ UP_LD_CMD_PORT_HOST_INT_STATUS,
+ .status_reg_0 = 0x90,
+ .status_reg_1 = 0x91,
+ .sdio_int_mask = 0xff,
+ .data_port_mask = 0xffffffff,
+ .max_mp_regs = 196,
+ .rd_bitmap_l = 0x10,
+ .rd_bitmap_u = 0x11,
+ .rd_bitmap_1l = 0x12,
+ .rd_bitmap_1u = 0x13,
+ .wr_bitmap_l = 0x14,
+ .wr_bitmap_u = 0x15,
+ .wr_bitmap_1l = 0x16,
+ .wr_bitmap_1u = 0x17,
+ .rd_len_p0_l = 0x18,
+ .rd_len_p0_u = 0x19,
+ .card_config_2_1_reg = 0xD9,
+ .cmd_config_0 = 0xC4,
+ .cmd_config_1 = 0xC5,
+ .cmd_config_2 = 0xC6,
+ .cmd_config_3 = 0xC7,
+ .cmd_rd_len_0 = 0xC0,
+ .cmd_rd_len_1 = 0xC1,
+ .cmd_rd_len_2 = 0xC2,
+ .cmd_rd_len_3 = 0xC3,
+ .io_port_0_reg = 0xE4,
+ .io_port_1_reg = 0xE5,
+ .io_port_2_reg = 0xE6,
+ .host_int_rsr_reg = 0x04,
+ .host_int_mask_reg = 0x08,
+ .host_int_status_reg = 0x0C,
+ .host_restart_reg = 0x58,
+ .card_to_host_event_reg = 0x5C,
+ .host_interrupt_mask_reg = 0x60,
+ .card_interrupt_status_reg = 0x64,
+ .card_interrupt_rsr_reg = 0x68,
+ .card_revision_reg = 0xC8,
+ .card_ocr_0_reg = 0xD4,
+ .card_ocr_1_reg = 0xD5,
+ .card_ocr_3_reg = 0xD6,
+ .card_config_reg = 0xD7,
+ .card_misc_cfg_reg = 0xD8,
+ .debug_0_reg = 0xDC,
+ .debug_1_reg = 0xDD,
+ .debug_2_reg = 0xDE,
+ .debug_3_reg = 0xDF,
+ .fw_reset_reg = 0x0B6,
+ .fw_reset_val = 1,
+ .winner_check_reg = 0x90,
+};
+
+static const struct _mlan_card_info mlan_card_info_sd8887 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
+ .v16_fw_api = 0,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
+};
+#endif
+
+#ifdef SD8897
+static const struct _mlan_sdio_card_reg mlan_reg_sd8897 = {
+ .start_rd_port = 0,
+ .start_wr_port = 0,
+ .base_0_reg = 0x60,
+ .base_1_reg = 0x61,
+ .poll_reg = 0x50,
+ .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
+ CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+ .host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
+ DN_LD_CMD_PORT_HOST_INT_STATUS |
+ UP_LD_CMD_PORT_HOST_INT_STATUS,
+ .status_reg_0 = 0xC0,
+ .status_reg_1 = 0xC1,
+ .sdio_int_mask = 0xff,
+ .data_port_mask = 0xffffffff,
+ .max_mp_regs = 184,
+ .rd_bitmap_l = 0x04,
+ .rd_bitmap_u = 0x05,
+ .rd_bitmap_1l = 0x06,
+ .rd_bitmap_1u = 0x07,
+ .wr_bitmap_l = 0x08,
+ .wr_bitmap_u = 0x09,
+ .wr_bitmap_1l = 0x0A,
+ .wr_bitmap_1u = 0x0B,
+ .rd_len_p0_l = 0x0C,
+ .rd_len_p0_u = 0x0D,
+ .card_config_2_1_reg = 0xCD,
+ .cmd_config_0 = 0xB8,
+ .cmd_config_1 = 0xB9,
+ .cmd_config_2 = 0xBA,
+ .cmd_config_3 = 0xBB,
+ .cmd_rd_len_0 = 0xB4,
+ .cmd_rd_len_1 = 0xB5,
+ .cmd_rd_len_2 = 0xB6,
+ .cmd_rd_len_3 = 0xB7,
+ .io_port_0_reg = 0xD8,
+ .io_port_1_reg = 0xD9,
+ .io_port_2_reg = 0xDA,
+ .host_int_rsr_reg = 0x01,
+ .host_int_mask_reg = 0x02,
+ .host_int_status_reg = 0x03,
+ .host_restart_reg = 0x4C,
+ .card_to_host_event_reg = 0x50,
+ .host_interrupt_mask_reg = 0x54,
+ .card_interrupt_status_reg = 0x58,
+ .card_interrupt_rsr_reg = 0x5C,
+ .card_revision_reg = 0xBC,
+ .card_ocr_0_reg = 0xC8,
+ .card_ocr_1_reg = 0xC9,
+ .card_ocr_3_reg = 0xCA,
+ .card_config_reg = 0xCB,
+ .card_misc_cfg_reg = 0xCC,
+ .debug_0_reg = 0xD0,
+ .debug_1_reg = 0xD1,
+ .debug_2_reg = 0xD2,
+ .debug_3_reg = 0xD3,
+ .fw_reset_reg = 0x0E8,
+ .fw_reset_val = 1,
+ .winner_check_reg = 0xC0,
+};
+
+static const struct _mlan_card_info mlan_card_info_sd8897 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 0,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#if defined(SD8977) || defined(SD8997) || defined(SD8987) || \
+ defined(SD9098) || defined(SD9097) || defined(SD8978)
+static const struct _mlan_sdio_card_reg mlan_reg_sd8977_sd8997 = {
+ .start_rd_port = 0,
+ .start_wr_port = 0,
+ .base_0_reg = 0xf8,
+ .base_1_reg = 0xf9,
+ .poll_reg = 0x5C,
+ .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
+ CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+ .host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
+ DN_LD_CMD_PORT_HOST_INT_STATUS |
+ UP_LD_CMD_PORT_HOST_INT_STATUS,
+ .status_reg_0 = 0xe8,
+ .status_reg_1 = 0xe9,
+ .sdio_int_mask = 0xff,
+ .data_port_mask = 0xffffffff,
+ .max_mp_regs = 196,
+ .rd_bitmap_l = 0x10,
+ .rd_bitmap_u = 0x11,
+ .rd_bitmap_1l = 0x12,
+ .rd_bitmap_1u = 0x13,
+ .wr_bitmap_l = 0x14,
+ .wr_bitmap_u = 0x15,
+ .wr_bitmap_1l = 0x16,
+ .wr_bitmap_1u = 0x17,
+ .rd_len_p0_l = 0x18,
+ .rd_len_p0_u = 0x19,
+ .card_config_2_1_reg = 0xD9,
+ .cmd_config_0 = 0xC4,
+ .cmd_config_1 = 0xC5,
+ .cmd_config_2 = 0xC6,
+ .cmd_config_3 = 0xC7,
+ .cmd_rd_len_0 = 0xC0,
+ .cmd_rd_len_1 = 0xC1,
+ .cmd_rd_len_2 = 0xC2,
+ .cmd_rd_len_3 = 0xC3,
+ .io_port_0_reg = 0xE4,
+ .io_port_1_reg = 0xE5,
+ .io_port_2_reg = 0xE6,
+ .host_int_rsr_reg = 0x04,
+ .host_int_mask_reg = 0x08,
+ .host_int_status_reg = 0x0C,
+ .host_restart_reg = 0x58,
+ .card_to_host_event_reg = 0x5C,
+ .host_interrupt_mask_reg = 0x60,
+ .card_interrupt_status_reg = 0x64,
+ .card_interrupt_rsr_reg = 0x68,
+ .card_revision_reg = 0xC8,
+ .card_ocr_0_reg = 0xD4,
+ .card_ocr_1_reg = 0xD5,
+ .card_ocr_3_reg = 0xD6,
+ .card_config_reg = 0xD7,
+ .card_misc_cfg_reg = 0xD8,
+ .debug_0_reg = 0xDC,
+ .debug_1_reg = 0xDD,
+ .debug_2_reg = 0xDE,
+ .debug_3_reg = 0xDF,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .fw_dnld_offset_0_reg = 0xEC,
+ .fw_dnld_offset_1_reg = 0xED,
+ .fw_dnld_offset_2_reg = 0xEE,
+ .fw_dnld_offset_3_reg = 0xEF,
+ .fw_dnld_status_0_reg = 0xE8,
+ .fw_dnld_status_1_reg = 0xE9,
+ .winner_check_reg = 0xFC,
+};
+
+#ifdef SD8997
+static const struct _mlan_card_info mlan_card_info_sd8997 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef SD9097
+static const struct _mlan_card_info mlan_card_info_sd9097 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+#ifdef SD9098
+static const struct _mlan_card_info mlan_card_info_sd9098 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#if defined(SD8977) || defined(SD8978)
+static const struct _mlan_card_info mlan_card_info_sd8977 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
+};
+#endif
+
+#ifdef SD8987
+static const struct _mlan_card_info mlan_card_info_sd8987 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 0,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
+};
+#endif
+#endif
+
+/** Probe and initialization function */
+mlan_status wlan_sdio_probe(pmlan_adapter pmadapter);
+mlan_status wlan_get_sdio_device(pmlan_adapter pmadapter);
+
+mlan_status wlan_send_mp_aggr_buf(mlan_adapter *pmadapter);
+
+mlan_status wlan_re_alloc_sdio_rx_mpa_buffer(mlan_adapter *pmadapter);
+
+void wlan_decode_spa_buffer(mlan_adapter *pmadapter, t_u8 *buf, t_u32 len);
+t_void wlan_sdio_deaggr_rx_pkt(pmlan_adapter pmadapter, mlan_buffer *pmbuf);
+/** Transfer data to card */
+mlan_status wlan_sdio_host_to_card(mlan_adapter *pmadapter, t_u8 type,
+ mlan_buffer *mbuf, mlan_tx_param *tx_param);
+mlan_status wlan_set_sdio_gpio_int(pmlan_private priv);
+mlan_status wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf);
+mlan_status wlan_reset_fw(pmlan_adapter pmadapter);
+
+#endif /* _MLAN_SDIO_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c
new file mode 100644
index 000000000000..c5fc7f5085c7
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c
@@ -0,0 +1,1700 @@
+/** @file mlan_shim.c
+ *
+ * @brief This file contains APIs to MOAL module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif /* SDIO */
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+#ifdef UAP_SUPPORT
+#include "mlan_uap.h"
+#endif
+#include "mlan_11h.h"
+#include "mlan_11n_rxreorder.h"
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+#include "authenticator_api.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+#ifdef STA_SUPPORT
+mlan_operations mlan_sta_ops = {
+ /* init cmd handler */
+ wlan_ops_sta_init_cmd,
+ /* ioctl handler */
+ wlan_ops_sta_ioctl,
+ /* cmd handler */
+ wlan_ops_sta_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_sta_process_cmdresp,
+ /* rx handler */
+ wlan_ops_sta_process_rx_packet,
+ /* Event handler */
+ wlan_ops_sta_process_event,
+ /* txpd handler */
+ wlan_ops_sta_process_txpd,
+ /* BSS role: STA */
+ MLAN_BSS_ROLE_STA,
+};
+#endif
+#ifdef UAP_SUPPORT
+mlan_operations mlan_uap_ops = {
+ /* init cmd handler */
+ wlan_ops_uap_init_cmd,
+ /* ioctl handler */
+ wlan_ops_uap_ioctl,
+ /* cmd handler */
+ wlan_ops_uap_prepare_cmd,
+ /* cmdresp handler */
+ wlan_ops_uap_process_cmdresp,
+ /* rx handler */
+ wlan_ops_uap_process_rx_packet,
+ /* Event handler */
+ wlan_ops_uap_process_event,
+ /* txpd handler */
+ wlan_ops_uap_process_txpd,
+ /* BSS role: uAP */
+ MLAN_BSS_ROLE_UAP,
+};
+#endif
+
+/** mlan function table */
+mlan_operations *mlan_ops[] = {
+#ifdef STA_SUPPORT
+ &mlan_sta_ops,
+#endif
+#ifdef UAP_SUPPORT
+ &mlan_uap_ops,
+#endif
+ MNULL,
+};
+
+/** Global moal_assert callback */
+t_void (*assert_callback)(t_pvoid pmoal_handle, t_u32 cond) = MNULL;
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
+#endif
+
+/** Global moal_print callback */
+t_void (*print_callback)(t_pvoid pmoal_handle, t_u32 level, char *pformat,
+ IN...) = MNULL;
+
+/** Global moal_get_system_time callback */
+mlan_status (*get_sys_time_callback)(t_pvoid pmoal_handle, t_pu32 psec,
+ t_pu32 pusec) = MNULL;
+
+/** Global driver debug mit masks */
+t_u32 mlan_drvdbg = DEFAULT_DEBUG_MASK;
+#endif
+
+#ifdef USB
+extern mlan_status wlan_get_usb_device(pmlan_adapter pmadapter);
+#endif
+/********************************************************
+ Local Functions
+*******************************************************/
+/**
+ * @brief This function process pending ioctl
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ */
+void wlan_process_pending_ioctl(mlan_adapter *pmadapter)
+{
+ pmlan_ioctl_req pioctl_buf;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ pmlan_ds_bss bss = MNULL;
+#endif
+#ifdef STA_SUPPORT
+ pmlan_ds_misc_cfg misc = MNULL;
+#endif
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ while ((pioctl_buf = (pmlan_ioctl_req)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->ioctl_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+ switch (pioctl_buf->req_id) {
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case MLAN_IOCTL_BSS:
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_ROLE) {
+ PRINTM(MCMND, "Role switch ioctl: %d\n",
+ bss->param.bss_role);
+ status = wlan_bss_ioctl_bss_role(pmadapter,
+ pioctl_buf);
+ }
+ break;
+#endif
+#ifdef STA_SUPPORT
+ case MLAN_IOCTL_MISC_CFG:
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ if (misc->sub_command == MLAN_OID_MISC_WARM_RESET) {
+ PRINTM(MCMND, "Warm Reset ioctl\n");
+ status = wlan_misc_ioctl_warm_reset(pmadapter,
+ pioctl_buf);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ if (status != MLAN_STATUS_PENDING)
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ pioctl_buf, status);
+ }
+ LEAVE();
+}
+/********************************************************
+ Global Functions
+********************************************************/
+#ifdef USB
+extern mlan_adapter_operations mlan_usb_ops;
+#endif
+#ifdef PCIE
+extern mlan_adapter_operations mlan_pcie_ops;
+#endif
+#ifdef SDIO
+extern mlan_adapter_operations mlan_sdio_ops;
+#endif
+
+/**
+ * @brief This function registers MOAL to MLAN module.
+ *
+ * @param pmdevice A pointer to a mlan_device structure
+ * allocated in MOAL
+ * @param ppmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer as the context
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The registration succeeded.
+ * MLAN_STATUS_FAILURE
+ * The registration failed.
+ *
+ * mlan_status mlan_register(
+ * pmlan_device pmdevice,
+ * t_void **ppmlan_adapter
+ * );
+ *
+ * Comments
+ * MOAL constructs mlan_device data structure to pass moal_handle and
+ * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to
+ * the ppmlan_adapter buffer provided by MOAL.
+ * Headers:
+ * declared in mlan_decl.h
+ * See Also
+ * mlan_unregister
+ */
+mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = MNULL;
+ pmlan_callbacks pcb = MNULL;
+ t_u8 i = 0;
+ t_u32 j = 0;
+
+ if (!pmdevice || !ppmlan_adapter) {
+ return MLAN_STATUS_FAILURE;
+ }
+ MASSERT(ppmlan_adapter);
+ MASSERT(pmdevice->callbacks.moal_print);
+#ifdef DEBUG_LEVEL1
+ print_callback = pmdevice->callbacks.moal_print;
+ get_sys_time_callback = pmdevice->callbacks.moal_get_system_time;
+#endif
+ assert_callback = pmdevice->callbacks.moal_assert;
+
+ ENTER();
+
+ MASSERT(pmdevice->callbacks.moal_malloc);
+ MASSERT(pmdevice->callbacks.moal_mfree);
+ MASSERT(pmdevice->callbacks.moal_memset);
+ MASSERT(pmdevice->callbacks.moal_memmove);
+ MASSERT(pmdevice->callbacks.moal_udelay);
+ MASSERT(pmdevice->callbacks.moal_usleep_range);
+
+ if (!pmdevice->callbacks.moal_malloc ||
+ !pmdevice->callbacks.moal_mfree ||
+ !pmdevice->callbacks.moal_memset ||
+ !pmdevice->callbacks.moal_udelay ||
+ !pmdevice->callbacks.moal_usleep_range ||
+ !pmdevice->callbacks.moal_memmove) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate memory for adapter structure */
+ if (pmdevice->callbacks.moal_vmalloc && pmdevice->callbacks.moal_vfree)
+ ret = pmdevice->callbacks.moal_vmalloc(pmdevice->pmoal_handle,
+ sizeof(mlan_adapter),
+ (t_u8 **)&pmadapter);
+ else
+ ret = pmdevice->callbacks.moal_malloc(pmdevice->pmoal_handle,
+ sizeof(mlan_adapter),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmadapter) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit_register;
+ }
+
+ pmdevice->callbacks.moal_memset(pmdevice->pmoal_handle, pmadapter, 0,
+ sizeof(mlan_adapter));
+
+ pcb = &pmadapter->callbacks;
+
+ /* Save callback functions */
+ pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb,
+ &pmdevice->callbacks,
+ sizeof(mlan_callbacks));
+
+ /* Assertion for all callback functions */
+ MASSERT(pcb->moal_get_hw_spec_complete);
+ MASSERT(pcb->moal_init_fw_complete);
+ MASSERT(pcb->moal_shutdown_fw_complete);
+ MASSERT(pcb->moal_send_packet_complete);
+ MASSERT(pcb->moal_recv_packet);
+ MASSERT(pcb->moal_recv_event);
+ MASSERT(pcb->moal_ioctl_complete);
+
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ MASSERT(pcb->moal_write_reg);
+ MASSERT(pcb->moal_read_reg);
+ MASSERT(pcb->moal_alloc_mlan_buffer);
+ MASSERT(pcb->moal_free_mlan_buffer);
+ }
+#endif
+ MASSERT(pcb->moal_get_vdll_data);
+ MASSERT(pcb->moal_write_data_sync);
+ MASSERT(pcb->moal_read_data_sync);
+ MASSERT(pcb->moal_mfree);
+ MASSERT(pcb->moal_memcpy);
+ MASSERT(pcb->moal_memcpy_ext);
+ MASSERT(pcb->moal_memcmp);
+ MASSERT(pcb->moal_get_system_time);
+ MASSERT(pcb->moal_init_timer);
+ MASSERT(pcb->moal_free_timer);
+ MASSERT(pcb->moal_get_boot_ktime);
+ MASSERT(pcb->moal_start_timer);
+ MASSERT(pcb->moal_stop_timer);
+ MASSERT(pcb->moal_init_lock);
+ MASSERT(pcb->moal_free_lock);
+ MASSERT(pcb->moal_spin_lock);
+ MASSERT(pcb->moal_spin_unlock);
+ MASSERT(pcb->moal_hist_data_add);
+ /* Save pmoal_handle */
+ pmadapter->pmoal_handle = pmdevice->pmoal_handle;
+
+ pmadapter->feature_control = pmdevice->feature_control;
+
+ pmadapter->card_type = pmdevice->card_type;
+ pmadapter->card_rev = pmdevice->card_rev;
+ pmadapter->init_para.uap_max_sta = pmdevice->uap_max_sta;
+
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ PRINTM(MMSG,
+ "Attach mlan adapter operations.card_type is 0x%x.\n",
+ pmdevice->card_type);
+ memcpy_ext(pmadapter, &pmadapter->ops, &mlan_sdio_ops,
+ sizeof(mlan_adapter_operations),
+ sizeof(mlan_adapter_operations));
+ ret = wlan_get_sdio_device(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ if ((pmdevice->int_mode == INT_MODE_GPIO) &&
+ (pmdevice->gpio_pin == 0)) {
+ PRINTM(MERROR,
+ "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->init_para.int_mode = pmdevice->int_mode;
+ pmadapter->init_para.gpio_pin = pmdevice->gpio_pin;
+ /* card specific probing has been deferred until now .. */
+ ret = wlan_sdio_probe(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ pmadapter->pcard_sd->max_segs = pmdevice->max_segs;
+ pmadapter->pcard_sd->max_seg_size = pmdevice->max_seg_size;
+
+ pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg;
+ pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg;
+ pmadapter->pcard_sd->sdio_rx_aggr_enable =
+ pmdevice->sdio_rx_aggr_enable;
+ }
+#endif
+
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type)) {
+ MASSERT(pcb->moal_malloc_consistent);
+ MASSERT(pcb->moal_mfree_consistent);
+ MASSERT(pcb->moal_map_memory);
+ MASSERT(pcb->moal_unmap_memory);
+ PRINTM(MMSG,
+ "Attach mlan adapter operations.card_type is 0x%x.\n",
+ pmdevice->card_type);
+ memcpy_ext(pmadapter, &pmadapter->ops, &mlan_pcie_ops,
+ sizeof(mlan_adapter_operations),
+ sizeof(mlan_adapter_operations));
+ ret = wlan_get_pcie_device(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ }
+#endif
+
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ MASSERT(pcb->moal_write_data_async);
+ MASSERT(pcb->moal_recv_complete);
+ PRINTM(MMSG,
+ "Attach mlan adapter operations.card_type is 0x%x.\n",
+ pmdevice->card_type);
+ memcpy_ext(pmadapter, &pmadapter->ops, &mlan_usb_ops,
+ sizeof(mlan_adapter_operations),
+ sizeof(mlan_adapter_operations));
+ ret = wlan_get_usb_device(pmadapter);
+ if (MLAN_STATUS_SUCCESS != ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ }
+#endif
+
+#ifdef DEBUG_LEVEL1
+ mlan_drvdbg = pmdevice->drvdbg;
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+ pmadapter->init_para.mfg_mode = pmdevice->mfg_mode;
+#endif
+ pmadapter->init_para.auto_ds = pmdevice->auto_ds;
+ pmadapter->init_para.ps_mode = pmdevice->ps_mode;
+ if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_12K ||
+ pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K)
+ pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf;
+#ifdef STA_SUPPORT
+ pmadapter->init_para.cfg_11d = pmdevice->cfg_11d;
+#else
+ pmadapter->init_para.cfg_11d = 0;
+#endif
+ if (IS_DFS_SUPPORT(pmadapter->feature_control))
+ pmadapter->init_para.dfs_master_radar_det_en =
+ DFS_MASTER_RADAR_DETECT_EN;
+ pmadapter->init_para.dfs_slave_radar_det_en = DFS_SLAVE_RADAR_DETECT_EN;
+ pmadapter->init_para.dev_cap_mask = pmdevice->dev_cap_mask;
+ pmadapter->init_para.indrstcfg = pmdevice->indrstcfg;
+ pmadapter->rx_work_flag = pmdevice->rx_work;
+ pmadapter->init_para.passive_to_active_scan =
+ pmdevice->passive_to_active_scan;
+ pmadapter->fixed_beacon_buffer = pmdevice->fixed_beacon_buffer;
+
+ pmadapter->multiple_dtim = pmdevice->multi_dtim;
+ pmadapter->inact_tmo = pmdevice->inact_tmo;
+ pmadapter->init_para.fw_region = pmdevice->fw_region;
+ pmadapter->hs_wake_interval = pmdevice->hs_wake_interval;
+ if (pmdevice->indication_gpio != 0xff) {
+ pmadapter->ind_gpio = pmdevice->indication_gpio & 0x0f;
+ pmadapter->level = (pmdevice->indication_gpio & 0xf0) >> 4;
+ if (pmadapter->level != 0 && pmadapter->level != 1) {
+ PRINTM(MERROR,
+ "Indication GPIO level is wrong and will use default value 0.\n");
+ pmadapter->level = 0;
+ }
+ }
+ pmadapter->hs_mimo_switch = pmdevice->hs_mimo_switch;
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ pmadapter->tx_cmd_ep = pmdevice->tx_cmd_ep;
+ pmadapter->rx_cmd_ep = pmdevice->rx_cmd_ep;
+ pmadapter->tx_data_ep = pmdevice->tx_data_ep;
+ pmadapter->rx_data_ep = pmdevice->rx_data_ep;
+ }
+#endif
+ pmadapter->init_para.dfs53cfg = pmdevice->dfs53cfg;
+ pmadapter->priv_num = 0;
+ pmadapter->priv[0] = MNULL;
+
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ ret = pcb->moal_vmalloc(pmadapter->pmoal_handle,
+ sizeof(mlan_private),
+ (t_u8 **)&pmadapter->priv[0]);
+ else
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_private), MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->priv[0]);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->priv[0]) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ pmadapter->priv_num++;
+ memset(pmadapter, pmadapter->priv[0], 0, sizeof(mlan_private));
+
+ pmadapter->priv[0]->adapter = pmadapter;
+ pmadapter->priv[0]->bss_type = (t_u8)pmdevice->bss_attr[0].bss_type;
+ pmadapter->priv[0]->frame_type = (t_u8)pmdevice->bss_attr[0].frame_type;
+ pmadapter->priv[0]->bss_priority =
+ (t_u8)pmdevice->bss_attr[0].bss_priority;
+ if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_STA)
+ pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_STA;
+ else if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_UAP)
+ pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_UAP;
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_STA;
+ if (pmdevice->bss_attr[0].bss_virtual)
+ pmadapter->priv[0]->bss_virtual = MTRUE;
+ }
+#endif
+ /* Save bss_index and bss_num */
+ pmadapter->priv[0]->bss_index = 0;
+ pmadapter->priv[0]->bss_num = (t_u8)pmdevice->bss_attr[0].bss_num;
+
+ /* init function table */
+ for (j = 0; mlan_ops[j]; j++) {
+ if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmadapter->priv[0])) {
+ memcpy_ext(pmadapter, &pmadapter->priv[0]->ops,
+ mlan_ops[j], sizeof(mlan_operations),
+ sizeof(mlan_operations));
+ break;
+ }
+ }
+ /** back up bss_attr table */
+ memcpy_ext(pmadapter, pmadapter->bss_attr, pmdevice->bss_attr,
+ sizeof(pmadapter->bss_attr), sizeof(pmadapter->bss_attr));
+
+ /* Initialize lock variables */
+ if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /** init lock varible for first priv */
+ if (wlan_init_priv_lock_list(pmadapter, 0) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Allocate memory for member of adapter structure */
+ if (wlan_allocate_adapter(pmadapter)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+
+ /* Initialize timers */
+ if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ /* Return pointer of mlan_adapter to MOAL */
+ *ppmlan_adapter = pmadapter;
+
+ goto exit_register;
+
+error:
+ PRINTM(MINFO, "Leave mlan_register with error\n");
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (pmadapter->priv[i]) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->priv[i]);
+ else if (pcb->moal_mfree)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->priv[i]);
+ }
+ }
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
+ else if (pcb->moal_mfree)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
+
+exit_register:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function unregisters MOAL from MLAN module.
+ *
+ * @param pmlan_adapter A pointer to a mlan_device structure
+ * allocated in MOAL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The deregistration succeeded.
+ */
+mlan_status mlan_unregister(t_void *pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ MASSERT(pmlan_adapter);
+
+ ENTER();
+
+ pcb = &pmadapter->callbacks;
+
+ /* Free adapter structure */
+ wlan_free_adapter(pmadapter);
+
+ /* Free private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i]) {
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->priv[i]);
+ else if (pcb->moal_mfree)
+ pcb->moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)pmadapter->priv[i]);
+ }
+ }
+
+ /* Free mlan_adapter */
+ if (pcb->moal_vmalloc && pcb->moal_vfree)
+ pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
+ else if (pcb->moal_mfree)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware download succeeded.
+ * MLAN_STATUS_FAILURE
+ * The firmware download failed.
+ */
+mlan_status mlan_dnld_fw(t_void *pmlan_adapter, pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /* Download helper/firmware */
+ if (pmfw) {
+ ret = pmadapter->ops.dnld_fw(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
+ LEAVE();
+ return ret;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function pass init param to MLAN
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ * @param pparam A pointer to mlan_init_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ *
+ */
+mlan_status mlan_set_init_param(t_void *pmlan_adapter, pmlan_init_param pparam)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ /** Save DPD data in MLAN */
+ if ((pparam->pdpd_data_buf) || (pparam->dpd_data_len > 0)) {
+ pmadapter->pdpd_data = pparam->pdpd_data_buf;
+ pmadapter->dpd_data_len = pparam->dpd_data_len;
+ }
+ if (pparam->ptxpwr_data_buf && (pparam->txpwr_data_len > 0)) {
+ pmadapter->ptxpwr_data = pparam->ptxpwr_data_buf;
+ pmadapter->txpwr_data_len = pparam->txpwr_data_len;
+ }
+ /** Save cal data in MLAN */
+ if ((pparam->pcal_data_buf) && (pparam->cal_data_len > 0)) {
+ pmadapter->pcal_data = pparam->pcal_data_buf;
+ pmadapter->cal_data_len = pparam->cal_data_len;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes the firmware
+ *
+ * @param pmlan_adapter A pointer to a t_void pointer to store
+ * mlan_adapter structure pointer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware initialization succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware initialization is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware initialization failed.
+ */
+mlan_status mlan_init_fw(t_void *pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+
+ ENTER();
+ MASSERT(pmlan_adapter);
+
+ pmadapter->hw_status = WlanHardwareStatusGetHwSpec;
+
+ /* Initialize firmware, may return PENDING */
+ ret = wlan_init_fw(pmadapter);
+ PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Shutdown firmware
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ * The firmware shutdown call succeeded.
+ * MLAN_STATUS_PENDING
+ * The firmware shutdown call is pending.
+ * MLAN_STATUS_FAILURE
+ * The firmware shutdown call failed.
+ */
+mlan_status mlan_shutdown_fw(t_void *pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ pmlan_buffer pmbuf;
+ pmlan_ioctl_req pioctl_buf;
+ pmlan_callbacks pcb;
+ t_s32 i = 0;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter);
+ /* MLAN already shutdown */
+ if (pmadapter->hw_status == WlanHardwareStatusNotReady) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ pmadapter->hw_status = WlanHardwareStatusClosing;
+ /* Wait for mlan_process to complete */
+ if (pmadapter->mlan_processing) {
+ PRINTM(MWARN, "MLAN main processing is still running\n");
+ LEAVE();
+ return ret;
+ }
+
+ /* Shut down MLAN */
+ PRINTM(MINFO, "Shutdown MLAN...\n");
+
+ /* Cancel all pending commands and complete ioctls */
+ wlan_cancel_all_pending_cmd(pmadapter, MTRUE);
+
+ /* Clean up priv structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_free_priv(pmadapter->priv[i]);
+ }
+
+ pcb = &pmadapter->callbacks;
+ /** cancel pending ioctl */
+ while ((pioctl_buf = (pmlan_ioctl_req)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->ioctl_pending_q,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+ pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf,
+ MLAN_STATUS_FAILURE);
+ }
+
+ while ((pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->rx_data_queue,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+#ifdef USB
+ if (IS_USB(pmadapter->card_type))
+ pcb->moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->rx_data_ep,
+ MLAN_STATUS_FAILURE);
+#endif
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type))
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+#endif
+ }
+ pmadapter->rx_pkts_queued = 0;
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type) &&
+ wlan_set_drv_ready_reg(pmadapter, 0)) {
+ PRINTM(MERROR, "Failed to write driver not-ready signature\n");
+ }
+#endif
+
+ /* Notify completion */
+ ret = wlan_shutdown_fw_complete(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief queue main work
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+static t_void mlan_queue_main_work(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing) {
+ pmadapter->more_task_flag = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ } else {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief queue rx_work
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return N/A
+ */
+static t_void mlan_queue_rx_work(mlan_adapter *pmadapter)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_rx_processing) {
+ pmadapter->more_rx_task_flag = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ } else {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_DEFER_RX_WORK, MNULL);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief block main process
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param block MTRUE/MFALSE
+ *
+ * @return N/A
+ */
+void mlan_block_main_process(mlan_adapter *pmadapter, t_u8 block)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ if (!block) {
+ pmadapter->main_lock_flag = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ } else {
+ pmadapter->main_lock_flag = MTRUE;
+ if (pmadapter->mlan_processing) {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ PRINTM(MEVENT, "wlan: wait main work done...\n");
+ wlan_recv_event(
+ wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK, MNULL);
+ } else {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ }
+ }
+}
+
+/**
+ * @brief block rx process
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param block MTRUE/MFALSE;
+ *
+ * @return N/A
+ */
+void mlan_block_rx_process(mlan_adapter *pmadapter, t_u8 block)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
+ if (!block) {
+ pmadapter->rx_lock_flag = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ } else {
+ pmadapter->rx_lock_flag = MTRUE;
+ if (pmadapter->mlan_rx_processing) {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ PRINTM(MEVENT, "wlan: wait rx work done...\n");
+ wlan_recv_event(wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL);
+ } else {
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ }
+ }
+}
+
+/**
+ * @brief The receive process
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param rx_pkts A pointer to save receive pkts number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status mlan_rx_process(t_void *pmlan_adapter, t_u8 *rx_pkts)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ pmlan_callbacks pcb;
+ pmlan_buffer pmbuf;
+ t_u8 limit = 0;
+ t_u8 rx_num = 0;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter);
+ pcb = &pmadapter->callbacks;
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
+ if (pmadapter->mlan_rx_processing || pmadapter->rx_lock_flag) {
+ pmadapter->more_rx_task_flag = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ goto exit_rx_proc;
+ } else {
+ pmadapter->mlan_rx_processing = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ }
+ if (rx_pkts)
+ limit = *rx_pkts;
+
+rx_process_start:
+ /* Check for Rx data */
+ while (MTRUE) {
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (pmadapter->authenticator_priv) {
+ if (IsAuthenticatorEnabled(
+ pmadapter->authenticator_priv->psapriv)) {
+ AuthenticatorKeyMgmtInit(
+ pmadapter->authenticator_priv->psapriv,
+ pmadapter->authenticator_priv
+ ->curr_addr);
+ pmadapter->authenticator_priv = MNULL;
+ }
+ }
+#endif
+ if (pmadapter->flush_data) {
+ pmadapter->flush_data = MFALSE;
+ wlan_flush_rxreorder_tbl(pmadapter);
+ }
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->rx_data_queue,
+ MNULL, MNULL);
+ if (!pmbuf) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ break;
+ }
+ pmadapter->rx_pkts_queued--;
+ rx_num++;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+
+ // rx_trace 6
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf,
+ 6 /*RX_DROP_P2*/);
+ if (pmadapter->tp_state_drop_point == 6 /*RX_DROP_P2*/) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto rx_process_start;
+ }
+
+ if (pmadapter->delay_task_flag &&
+ (pmadapter->rx_pkts_queued < LOW_RX_PENDING)) {
+ PRINTM(MEVENT, "Run\n");
+ pmadapter->delay_task_flag = MFALSE;
+ mlan_queue_main_work(pmadapter);
+ }
+ pmadapter->ops.handle_rx_packet(pmadapter, pmbuf);
+ if (limit && rx_num >= limit)
+ break;
+ }
+ if (rx_pkts)
+ *rx_pkts = rx_num;
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
+ if (pmadapter->more_rx_task_flag) {
+ pmadapter->more_rx_task_flag = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+ goto rx_process_start;
+ }
+ pmadapter->mlan_rx_processing = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->prx_proc_lock);
+exit_rx_proc:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief The main process
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status mlan_main_process(t_void *pmlan_adapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter);
+
+ pcb = &pmadapter->callbacks;
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing || pmadapter->main_lock_flag) {
+ pmadapter->more_task_flag = MTRUE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ goto exit_main_proc;
+ } else {
+ pmadapter->mlan_processing = MTRUE;
+ pmadapter->main_process_cnt++;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ }
+process_start:
+ do {
+ /* Is MLAN shutting down or not ready? */
+ if ((pmadapter->hw_status == WlanHardwareStatusClosing) ||
+ (pmadapter->hw_status == WlanHardwareStatusNotReady))
+ break;
+ if (pmadapter->pending_ioctl) {
+ wlan_process_pending_ioctl(pmadapter);
+ pmadapter->pending_ioctl = MFALSE;
+ }
+ if (pmadapter->pending_disconnect_priv) {
+ PRINTM(MEVENT, "Reset connect state\n");
+ wlan_reset_connect_state(
+ pmadapter->pending_disconnect_priv, MTRUE);
+ pmadapter->pending_disconnect_priv = MNULL;
+ }
+#if defined(SDIO) || defined(PCIE)
+ if (!IS_USB(pmadapter->card_type)) {
+ if (pmadapter->rx_pkts_queued > HIGH_RX_PENDING) {
+ pcb->moal_tp_accounting_rx_param(
+ pmadapter->pmoal_handle, 2, 0);
+ PRINTM(MEVENT, "Pause\n");
+ pmadapter->delay_task_flag = MTRUE;
+ mlan_queue_rx_work(pmadapter);
+ break;
+ }
+ /* Handle pending interrupts if any */
+ if (pmadapter->ireg) {
+ if (pmadapter->hs_activated == MTRUE)
+ wlan_process_hs_config(pmadapter);
+ pmadapter->ops.process_int_status(pmadapter);
+ if (pmadapter->data_received)
+ mlan_queue_rx_work(pmadapter);
+ }
+ }
+#endif
+
+ /* Need to wake up the card ? */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP) &&
+ (pmadapter->pm_wakeup_card_req &&
+ !pmadapter->pm_wakeup_fw_try) &&
+ (wlan_is_cmd_pending(pmadapter) ||
+ !wlan_bypass_tx_list_empty(pmadapter) ||
+ !wlan_wmm_lists_empty(pmadapter))) {
+ pmadapter->ops.wakeup_card(pmadapter, MTRUE);
+ pmadapter->pm_wakeup_fw_try = MTRUE;
+ continue;
+ }
+ if (IS_CARD_RX_RCVD(pmadapter) ||
+ (!pmadapter->cmd_sent &&
+ pmadapter->vdll_ctrl.pending_block)) {
+ pmadapter->data_received = MFALSE;
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(
+ wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ if (pmadapter->ps_state == PS_STATE_SLEEP)
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ if (pmadapter->wakeup_fw_timer_is_set) {
+ pcb->moal_stop_timer(
+ pmadapter->pmoal_handle,
+ pmadapter->pwakeup_fw_timer);
+ pmadapter->wakeup_fw_timer_is_set = MFALSE;
+ }
+ } else {
+ /* We have tried to wakeup the card already */
+ if (pmadapter->pm_wakeup_fw_try)
+ break;
+ /* Check if we need to confirm Sleep Request received
+ * previously */
+ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
+ if (!pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd &&
+ !pmadapter->vdll_ctrl.pending_block)
+ wlan_check_ps_cond(pmadapter);
+ if (pmadapter->ps_state != PS_STATE_AWAKE ||
+ (pmadapter->tx_lock_flag == MTRUE))
+ break;
+
+ if (pmadapter->data_sent ||
+ (wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) ||
+ wlan_11h_radar_detected_tx_blocked(pmadapter)) {
+ if (pmadapter->cmd_sent ||
+ pmadapter->curr_cmd ||
+ !wlan_is_cmd_pending(pmadapter)) {
+ break;
+ }
+ }
+ }
+
+ /* Check for Cmd Resp */
+ if (pmadapter->cmd_resp_received) {
+ pmadapter->cmd_resp_received = MFALSE;
+ wlan_process_cmdresp(pmadapter);
+
+ /* call moal back when init_fw is done */
+ if (pmadapter->hw_status ==
+ WlanHardwareStatusInitdone) {
+ pmadapter->hw_status = WlanHardwareStatusReady;
+ wlan_init_fw_complete(pmadapter);
+ } else if (pmadapter->hw_status ==
+ WlanHardwareStatusGetHwSpecdone) {
+ pmadapter->hw_status =
+ WlanHardwareStatusInitializing;
+ wlan_get_hw_spec_complete(pmadapter);
+ }
+ }
+
+ /* Check for event */
+ if (pmadapter->event_received) {
+ pmadapter->event_received = MFALSE;
+ wlan_process_event(pmadapter);
+ }
+
+ /* Check if we need to confirm Sleep Request received previously
+ */
+ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd &&
+ !pmadapter->vdll_ctrl.pending_block)
+ wlan_check_ps_cond(pmadapter);
+
+ /*
+ * The ps_state may have been changed during processing of
+ * Sleep Request event.
+ */
+ if ((pmadapter->ps_state == PS_STATE_SLEEP) ||
+ (pmadapter->ps_state == PS_STATE_PRE_SLEEP) ||
+ (pmadapter->ps_state == PS_STATE_SLEEP_CFM) ||
+ (pmadapter->tx_lock_flag == MTRUE)) {
+ continue;
+ }
+
+ /* in a case of race condition, download the VDLL block here */
+ if (!pmadapter->cmd_sent &&
+ pmadapter->vdll_ctrl.pending_block) {
+ wlan_download_vdll_block(
+ pmadapter, pmadapter->vdll_ctrl.pending_block,
+ pmadapter->vdll_ctrl.pending_block_len);
+ pmadapter->vdll_ctrl.pending_block = MNULL;
+ }
+ if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) {
+ if (wlan_exec_next_cmd(pmadapter) ==
+ MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ }
+
+ if (!pmadapter->data_sent &&
+ !wlan_11h_radar_detected_tx_blocked(pmadapter) &&
+ !wlan_bypass_tx_list_empty(pmadapter)) {
+ PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n");
+ wlan_process_bypass_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(
+ wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+ if (!pmadapter->data_sent && !wlan_wmm_lists_empty(pmadapter) &&
+ !wlan_11h_radar_detected_tx_blocked(pmadapter)) {
+ wlan_wmm_process_tx(pmadapter);
+ if (pmadapter->hs_activated == MTRUE) {
+ pmadapter->is_hs_configured = MFALSE;
+ wlan_host_sleep_activated_event(
+ wlan_get_priv(pmadapter,
+ MLAN_BSS_ROLE_ANY),
+ MFALSE);
+ }
+ }
+
+#ifdef STA_SUPPORT
+ if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent &&
+ !pmadapter->curr_cmd && !wlan_is_cmd_pending(pmadapter) &&
+ wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) {
+ if (wlan_send_null_packet(
+ wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA),
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) ==
+ MLAN_STATUS_SUCCESS) {
+ pmadapter->delay_null_pkt = MFALSE;
+ }
+ break;
+ }
+#endif
+
+ } while (MTRUE);
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ if (pmadapter->more_task_flag == MTRUE) {
+ pmadapter->more_task_flag = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ goto process_start;
+ }
+ pmadapter->mlan_processing = MFALSE;
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+
+exit_main_proc:
+ if (pmadapter->hw_status == WlanHardwareStatusClosing)
+ mlan_shutdown_fw(pmadapter);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Function to send packet
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ *
+ * @return MLAN_STATUS_PENDING
+ */
+mlan_status mlan_send_packet(t_void *pmlan_adapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ mlan_private *pmpriv;
+ t_u16 eth_type = 0;
+
+ ENTER();
+ MASSERT(pmlan_adapter && pmbuf);
+
+ if (!pmlan_adapter || !pmbuf) {
+ return MLAN_STATUS_FAILURE;
+ }
+
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+ pmbuf->flags |= MLAN_BUF_FLAG_MOAL_TX_BUF;
+ pmpriv = pmadapter->priv[pmbuf->bss_index];
+
+ eth_type =
+ mlan_ntohs(*(t_u16 *)&pmbuf->pbuf[pmbuf->data_offset +
+ MLAN_ETHER_PKT_TYPE_OFFSET]);
+ if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) &&
+ ((eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) ||
+ (eth_type == MLAN_ETHER_PKT_TYPE_ARP) ||
+ (eth_type == MLAN_ETHER_PKT_TYPE_WAPI))) ||
+ (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)
+
+ ) {
+ if (eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) {
+ PRINTM_NETINTF(MMSG, pmpriv);
+ PRINTM(MMSG, "wlan: Send EAPOL pkt to " MACSTR "\n",
+ MAC2STR(pmbuf->pbuf + pmbuf->data_offset));
+ }
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf->pdesc, 2);
+ if (pmadapter->tp_state_drop_point == 2)
+ return 0;
+ else
+ wlan_add_buf_bypass_txqueue(pmadapter, pmbuf);
+ } else {
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf->pdesc, 2);
+ if (pmadapter->tp_state_drop_point == 2)
+ return 0;
+ else
+ /* Transmit the packet*/
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status mlan_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = (pmlan_adapter)adapter;
+ pmlan_private pmpriv = MNULL;
+
+ ENTER();
+
+ if (pioctl_req == MNULL) {
+ PRINTM(MMSG, "Cancel all pending cmd!\n");
+ wlan_cancel_all_pending_cmd(pmadapter, MFALSE);
+ goto exit;
+ }
+ if (pioctl_req->action == MLAN_ACT_CANCEL) {
+ wlan_cancel_pending_ioctl(pmadapter, pioctl_req);
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ ret = pmpriv->ops.ioctl(adapter, pioctl_req);
+exit:
+ LEAVE();
+ return ret;
+}
+
+#ifdef USB
+/**
+ * @brief Packet send completion callback
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param port Data port
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status mlan_write_data_async_complete(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf, t_u32 port,
+ mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+
+ ENTER();
+
+ if (port == pmadapter->tx_cmd_ep) {
+ pmadapter->cmd_sent = MFALSE;
+ PRINTM(MCMND, "mlan_write_data_async_complete: CMD\n");
+ /* pmbuf was allocated by MLAN */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ pmadapter->data_sent = MFALSE;
+ ret = wlan_write_data_complete(pmadapter, pmbuf, status);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive handler
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param port Data port
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or
+ * MLAN_STATUS_PENDING
+ */
+mlan_status mlan_recv(t_void *pmlan_adapter, pmlan_buffer pmbuf, t_u32 port)
+{
+ mlan_status ret = MLAN_STATUS_PENDING;
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ t_u8 *pbuf;
+ t_u32 len, recv_type;
+ t_u32 event_cause;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec, usec;
+#endif
+ t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE;
+
+ ENTER();
+
+ MASSERT(pmlan_adapter && pmbuf);
+
+ if (pmadapter->hs_activated == MTRUE)
+ wlan_process_hs_config(pmadapter);
+ pbuf = pmbuf->pbuf + pmbuf->data_offset;
+ len = pmbuf->data_len;
+
+ MASSERT(len >= MLAN_TYPE_LEN);
+ recv_type = *(t_u32 *)pbuf;
+ recv_type = wlan_le32_to_cpu(recv_type);
+ pbuf += MLAN_TYPE_LEN;
+ len -= MLAN_TYPE_LEN;
+
+ if (port == pmadapter->rx_cmd_ep) {
+ switch (recv_type) {
+ case MLAN_USB_TYPE_CMD:
+ PRINTM_GET_SYS_TIME(MCMND, &sec, &usec);
+ PRINTM(MCMND, "mlan_recv: CMD (%lu.%06lu)\n", sec,
+ usec);
+ if (len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ pmbuf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "mlan_recv: CMD too large\n");
+ } else if (!pmadapter->curr_cmd) {
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
+ pmbuf->data_offset += MLAN_TYPE_LEN;
+ pmbuf->data_len -= MLAN_TYPE_LEN;
+ wlan_process_sleep_confirm_resp(
+ pmadapter,
+ pmbuf->pbuf +
+ pmbuf->data_offset,
+ pmbuf->data_len);
+ pmbuf->flags |=
+ MLAN_BUF_FLAG_SLEEPCFM_RESP;
+ ret = MLAN_STATUS_SUCCESS;
+
+ } else {
+ pmbuf->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ PRINTM(MINFO, "mlan_recv: no curr_cmd\n");
+ } else {
+ pmadapter->upld_len = len;
+ pmbuf->data_offset += MLAN_TYPE_LEN;
+ pmbuf->data_len -= MLAN_TYPE_LEN;
+ pmadapter->curr_cmd->respbuf = pmbuf;
+ pmadapter->cmd_resp_received = MTRUE;
+ }
+ break;
+ case MLAN_USB_TYPE_EVENT:
+ MASSERT(len >= sizeof(t_u32));
+ memmove(pmadapter, &event_cause, pbuf, sizeof(t_u32));
+ pmadapter->event_cause = wlan_le32_to_cpu(event_cause);
+ PRINTM_GET_SYS_TIME(MEVENT, &sec, &usec);
+ PRINTM(MEVENT, "mlan_recv: EVENT 0x%x (%lu.%06lu)\n",
+ pmadapter->event_cause, sec, usec);
+ pbuf += sizeof(t_u32);
+ len -= sizeof(t_u32);
+ if ((len > 0) && (len < MAX_EVENT_SIZE))
+ memmove(pmadapter, pmadapter->event_body, pbuf,
+ len);
+ pmadapter->event_received = MTRUE;
+ pmadapter->pmlan_buffer_event = pmbuf;
+ /* remove 4 byte recv_type */
+ pmbuf->data_offset += MLAN_TYPE_LEN;
+ pmbuf->data_len -= MLAN_TYPE_LEN;
+ /* MOAL to call mlan_main_process for processing */
+ break;
+ default:
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "mlan_recv: unknown recv_type 0x%x\n",
+ recv_type);
+ break;
+ }
+ } else if (port == pmadapter->rx_data_ep) {
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM(MDATA, "mlan_recv: DATA (%lu.%06lu)\n", sec, usec);
+#if defined(USB)
+ if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable) {
+ max_rx_data_size = pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_max;
+ if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl
+ .aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
+ max_rx_data_size *=
+ MAX(MLAN_USB_MAX_PKT_SIZE,
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align);
+ max_rx_data_size = MAX(max_rx_data_size,
+ MLAN_RX_DATA_BUF_SIZE);
+ }
+ }
+#endif
+ if (len > max_rx_data_size) {
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "mlan_recv: DATA too large\n");
+ } else {
+ pmadapter->upld_len = len;
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &pmbuf->in_ts_sec,
+ &pmbuf->in_ts_usec);
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->rx_data_queue,
+ (pmlan_linked_list)pmbuf, MNULL,
+ MNULL);
+ pmadapter->rx_pkts_queued++;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ pmadapter->rx_data_queue.plock);
+ pmadapter->data_received = MTRUE;
+ mlan_queue_rx_work(pmadapter);
+ }
+ } else {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "mlan_recv: unknown port number 0x%x\n", port);
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* USB */
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status mlan_recv_packet_complete(t_void *pmlan_adapter, pmlan_buffer pmbuf,
+ mlan_status status)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+
+ ENTER();
+ wlan_recv_packet_complete(pmadapter, pmbuf, status);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmlan_adapter A pointer to mlan_adapter structure
+ * @param bss_num BSS number
+ * @param tid TID
+ *
+ * @return wmm queue priority (0 - 3)
+ */
+t_u8 mlan_select_wmm_queue(t_void *pmlan_adapter, t_u8 bss_num, t_u8 tid)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
+ pmlan_private pmpriv = pmadapter->priv[bss_num];
+ t_u8 ret;
+ ENTER();
+ ret = wlan_wmm_select_queue(pmpriv, tid);
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO) || defined(PCIE)
+/**
+ * @brief This function gets interrupt status.
+ * @param msg_id only used for PCIE
+ */
+/**
+ * @param msg_id A message id
+ * @param adapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_FAILURE -- if the intererupt is not for us
+ */
+mlan_status mlan_interrupt(t_u16 msg_id, t_void *adapter)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)adapter;
+ mlan_status ret;
+
+ ENTER();
+ ret = pmadapter->ops.interrupt(msg_id, pmadapter);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function wakeup firmware.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param keep_wakeup keep wake up flag
+ * @return N/A
+ */
+t_void mlan_pm_wakeup_card(t_void *adapter, t_u8 keep_wakeup)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)adapter;
+
+ ENTER();
+ if (keep_wakeup)
+ pmadapter->ops.wakeup_card(pmadapter, MFALSE);
+ pmadapter->keep_wakeup = keep_wakeup;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function check main_process status.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @return MTRUE/MFALSE
+ */
+t_u8 mlan_is_main_process_running(t_void *adapter)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 ret = MFALSE;
+ ENTER();
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+
+ /* Check if already processing */
+ if (pmadapter->mlan_processing) {
+ pmadapter->more_task_flag = MTRUE;
+ ret = MTRUE;
+ }
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pmadapter->pmain_proc_lock);
+ LEAVE();
+ return ret;
+}
+
+#ifdef PCIE
+/**
+ * @brief This function sets the PCIE interrupt mode.
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param int_mode PCIE interrupt type active
+ * @param func_num PCIE function num
+ * @return N/A
+ */
+t_void mlan_set_int_mode(t_void *adapter, t_u32 int_mode, t_u8 func_num)
+{
+ mlan_adapter *pmadapter = (mlan_adapter *)adapter;
+ ENTER();
+ pmadapter->pcard_pcie->pcie_int_mode = int_mode;
+ pmadapter->pcard_pcie->func_num = func_num;
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmd.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmd.c
new file mode 100644
index 000000000000..314e8fb7f3e4
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmd.c
@@ -0,0 +1,2950 @@
+/** @file mlan_sta_cmd.c
+ *
+ * @brief This file contains the handling of command.
+ * it prepares command and sends it to firmware when
+ * it is ready.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+ * Change log:
+ * 10/21/2008: initial version
+ ******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif /* SDIO */
+#include "mlan_meas.h"
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+
+/********************************************************
+ * Local Variables
+ ********************************************************/
+
+/********************************************************
+ * Global Variables
+ ********************************************************/
+
+/********************************************************
+ * Local Functions
+ ********************************************************/
+
+/**
+ * @brief This function prepares command of RSSI info.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_rssi_info(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action)
+{
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+ pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI_INFO) +
+ S_DS_GEN);
+ pcmd->params.rssi_info.action = wlan_cpu_to_le16(cmd_action);
+ pcmd->params.rssi_info.ndata =
+ wlan_cpu_to_le16(pmpriv->data_avg_factor);
+ pcmd->params.rssi_info.nbcn = wlan_cpu_to_le16(pmpriv->bcn_avg_factor);
+
+ /* Reset SNR/NF/RSSI values in private structure */
+ pmpriv->data_rssi_last = 0;
+ pmpriv->data_nf_last = 0;
+ pmpriv->data_rssi_avg = 0;
+ pmpriv->data_nf_avg = 0;
+ pmpriv->bcn_rssi_last = 0;
+ pmpriv->bcn_nf_last = 0;
+ pmpriv->bcn_rssi_avg = 0;
+ pmpriv->bcn_nf_avg = 0;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of RSSI info.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action Command action
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_rssi_info_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *pcmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_EXT *rssi_info_ext_cmd =
+ &pcmd->params.rssi_info_ext;
+ mlan_ds_get_info *info = (mlan_ds_get_info *)pdata_buf;
+ MrvlIEtypes_RSSI_EXT_t *signal_info_tlv = MNULL;
+ t_u8 *pos = MNULL;
+
+ ENTER();
+
+ pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_RSSI_INFO_EXT);
+ pcmd->size = sizeof(HostCmd_DS_802_11_RSSI_INFO_EXT) + S_DS_GEN;
+ rssi_info_ext_cmd->action = wlan_cpu_to_le16(cmd_action);
+ rssi_info_ext_cmd->ndata = 0;
+ rssi_info_ext_cmd->nbcn = 0;
+
+ if (info->param.path_id) {
+ pos = (t_u8 *)rssi_info_ext_cmd->tlv_buf;
+ signal_info_tlv = (MrvlIEtypes_RSSI_EXT_t *)pos;
+ signal_info_tlv->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_RSSI_EXT_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ signal_info_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_RSSI_INFO);
+ signal_info_tlv->path_id =
+ wlan_cpu_to_le16(info->param.path_id);
+ pcmd->size += sizeof(MrvlIEtypes_RSSI_EXT_t);
+ }
+ pcmd->size = wlan_cpu_to_le16(pcmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to command information buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_snmp_mib(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ t_u32 ul_temp;
+
+ ENTER();
+ PRINTM(MINFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(MAX_SNMP_BUF_SIZE);
+ cmd->size += MAX_SNMP_BUF_SIZE;
+ }
+
+ switch (cmd_oid) {
+ case DtimPeriod_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)DtimPeriod_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ ul_temp = *((t_u32 *)pdata_buf);
+ psnmp_mib->value[0] = (t_u8)ul_temp;
+ cmd->size += sizeof(t_u8);
+ }
+ break;
+ case FragThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)FragThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *)pdata_buf);
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case RtsThresh_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)RtsThresh_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *)pdata_buf);
+ *(t_u16 *)(psnmp_mib->value) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+
+ case ShortRetryLim_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)ShortRetryLim_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = (*(t_u32 *)pdata_buf);
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11D_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)Dot11D_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *)pdata_buf;
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)Dot11H_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *)pdata_buf;
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case WwsMode_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)WwsMode_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *((t_u32 *)pdata_buf);
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ }
+ break;
+ case Thermal_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)Thermal_i);
+ break;
+ case NullPktPeriod_i:
+ /** keep alive null data pkt interval in full power mode */
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)NullPktPeriod_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u32));
+ ul_temp = *((t_u32 *)pdata_buf);
+ ul_temp = wlan_cpu_to_le32(ul_temp);
+ memcpy_ext(pmpriv->adapter, psnmp_mib->value, &ul_temp,
+ sizeof(t_u32), sizeof(t_u32));
+ cmd->size += sizeof(t_u32);
+ }
+ break;
+ case ECSAEnable_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)ECSAEnable_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ psnmp_mib->value[0] = *((t_u8 *)pdata_buf);
+ cmd->size += sizeof(t_u8);
+ }
+ break;
+ case SignalextEnable_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)SignalextEnable_i);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ psnmp_mib->query_type =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ psnmp_mib->value[0] = *(t_u8 *)pdata_buf;
+ cmd->size += sizeof(t_u8);
+ }
+ break;
+ default:
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ PRINTM(MINFO,
+ "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, wlan_le16_to_cpu(psnmp_mib->buf_size),
+ wlan_le16_to_cpu(*(t_u16 *)psnmp_mib->value));
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of get_log.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_get_log(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of MFG Continuous Tx cmd.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_mfg_tx_cont(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 action,
+ t_void *pdata_buf)
+{
+ struct mfg_cmd_tx_cont *mcmd =
+ (struct mfg_cmd_tx_cont *)&cmd->params.mfg_tx_cont;
+ struct mfg_cmd_tx_cont *cfg = (struct mfg_cmd_tx_cont *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+ cmd->size = wlan_cpu_to_le16(sizeof(struct mfg_cmd_tx_cont) + S_DS_GEN);
+
+ mcmd->mfg_cmd = wlan_cpu_to_le32(cfg->mfg_cmd);
+ mcmd->action = wlan_cpu_to_le16(action);
+ if (action == HostCmd_ACT_GEN_SET) {
+ mcmd->enable_tx = wlan_cpu_to_le32(cfg->enable_tx);
+ mcmd->cw_mode = wlan_cpu_to_le32(cfg->cw_mode);
+ mcmd->payload_pattern = wlan_cpu_to_le32(cfg->payload_pattern);
+ mcmd->cs_mode = wlan_cpu_to_le32(cfg->cs_mode);
+ mcmd->act_sub_ch = wlan_cpu_to_le32(cfg->act_sub_ch);
+ mcmd->tx_rate = wlan_cpu_to_le32(cfg->tx_rate);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of MFG Tx frame.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_mfg_tx_frame(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 action,
+ t_void *pdata_buf)
+{
+ struct mfg_cmd_tx_frame2 *mcmd =
+ (struct mfg_cmd_tx_frame2 *)&cmd->params.mfg_tx_frame2;
+ struct mfg_cmd_tx_frame2 *cfg = (struct mfg_cmd_tx_frame2 *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(struct mfg_cmd_tx_frame2) + S_DS_GEN);
+
+ mcmd->mfg_cmd = wlan_cpu_to_le32(cfg->mfg_cmd);
+ mcmd->action = wlan_cpu_to_le16(action);
+ if (action == HostCmd_ACT_GEN_SET) {
+ mcmd->enable = wlan_cpu_to_le32(cfg->enable);
+ mcmd->data_rate = wlan_cpu_to_le32(cfg->data_rate);
+ mcmd->frame_pattern = wlan_cpu_to_le32(cfg->frame_pattern);
+ mcmd->frame_length = wlan_cpu_to_le32(cfg->frame_length);
+ mcmd->adjust_burst_sifs =
+ wlan_cpu_to_le16(cfg->adjust_burst_sifs);
+ mcmd->burst_sifs_in_us =
+ wlan_cpu_to_le32(cfg->burst_sifs_in_us);
+ mcmd->short_preamble = wlan_cpu_to_le32(cfg->short_preamble);
+ mcmd->act_sub_ch = wlan_cpu_to_le32(cfg->act_sub_ch);
+ mcmd->short_gi = wlan_cpu_to_le32(cfg->short_gi);
+ mcmd->tx_bf = wlan_cpu_to_le32(cfg->tx_bf);
+ mcmd->gf_mode = wlan_cpu_to_le32(cfg->gf_mode);
+ mcmd->stbc = wlan_cpu_to_le32(cfg->stbc);
+ memcpy_ext(pmpriv->adapter, mcmd->bssid, cfg->bssid,
+ MLAN_MAC_ADDR_LENGTH, sizeof(mcmd->bssid));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of MFG cmd.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 action, t_void *pdata_buf)
+{
+ struct mfg_cmd_generic_cfg *mcmd =
+ (struct mfg_cmd_generic_cfg *)&cmd->params.mfg_generic_cfg;
+ struct mfg_cmd_generic_cfg *cfg =
+ (struct mfg_cmd_generic_cfg *)pdata_buf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!mcmd || !cfg) {
+ ret = MLAN_STATUS_FAILURE;
+ goto cmd_mfg_done;
+ }
+ switch (cfg->mfg_cmd) {
+ case MFG_CMD_TX_CONT:
+ ret = wlan_cmd_mfg_tx_cont(pmpriv, cmd, action, pdata_buf);
+ goto cmd_mfg_done;
+ case MFG_CMD_TX_FRAME:
+ ret = wlan_cmd_mfg_tx_frame(pmpriv, cmd, action, pdata_buf);
+ goto cmd_mfg_done;
+ case MFG_CMD_SET_TEST_MODE:
+ case MFG_CMD_UNSET_TEST_MODE:
+ case MFG_CMD_TX_ANT:
+ case MFG_CMD_RX_ANT:
+ case MFG_CMD_RF_CHAN:
+ case MFG_CMD_CLR_RX_ERR:
+ case MFG_CMD_RF_BAND_AG:
+ case MFG_CMD_RF_CHANNELBW:
+ case MFG_CMD_RFPWR:
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ goto cmd_mfg_done;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(struct mfg_cmd_generic_cfg) + S_DS_GEN);
+
+ mcmd->mfg_cmd = wlan_cpu_to_le32(cfg->mfg_cmd);
+ mcmd->action = wlan_cpu_to_le16(action);
+ if (action == HostCmd_ACT_GEN_SET) {
+ mcmd->data1 = wlan_cpu_to_le32(cfg->data1);
+ mcmd->data2 = wlan_cpu_to_le32(cfg->data2);
+ mcmd->data3 = wlan_cpu_to_le32(cfg->data3);
+ }
+cmd_mfg_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of tx_power_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_tx_power_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp = MNULL;
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &cmd->params.txp_cfg;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TXPWR_CFG));
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ ptxp = (HostCmd_DS_TXPWR_CFG *)pdata_buf;
+ if (ptxp->mode) {
+ ppg_tlv = (MrvlTypes_Power_Group_t
+ *)((t_u8 *)pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t) +
+ ppg_tlv->length);
+
+ ppg_tlv = (MrvlTypes_Power_Group_t
+ *)((t_u8 *)ptxp_cfg +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ cmd->size += wlan_cpu_to_le16(
+ sizeof(MrvlTypes_Power_Group_t) +
+ ppg_tlv->length);
+ ppg_tlv->type = wlan_cpu_to_le16(ppg_tlv->type);
+ ppg_tlv->length = wlan_cpu_to_le16(ppg_tlv->length);
+ } else {
+ memmove(pmpriv->adapter, ptxp_cfg, pdata_buf,
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ }
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ ptxp_cfg->cfg_index = wlan_cpu_to_le16(ptxp_cfg->cfg_index);
+ ptxp_cfg->mode = wlan_cpu_to_le32(ptxp_cfg->mode);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ ptxp_cfg->action = wlan_cpu_to_le16(cmd_action);
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_tx_power.
+ *
+ * @param pmpriv A pointer to wlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_rf_tx_power(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_RF_TX_POWER *prtp = &cmd->params.txp;
+
+ ENTER();
+
+ cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER)) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
+ prtp->action = cmd_action;
+
+ PRINTM(MINFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n", cmd->size,
+ cmd->command, prtp->action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_GET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ prtp->current_level = 0;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ prtp->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ prtp->current_level = wlan_cpu_to_le16(*((t_s16 *)pdata_buf));
+ break;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Check if any p2p interface is conencted
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return MTRUE/MFALSE;
+ */
+static t_u8 wlan_is_p2p_connected(pmlan_adapter pmadapter)
+{
+ int j;
+ pmlan_private priv;
+
+ ENTER();
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ priv = pmadapter->priv[j];
+ if (priv) {
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if ((priv->bss_role == MLAN_BSS_ROLE_STA) &&
+ (priv->media_connected == MTRUE)) {
+ LEAVE();
+ return MTRUE;
+ }
+ if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
+ (priv->uap_bss_started == MTRUE)) {
+ LEAVE();
+ return MTRUE;
+ }
+ }
+ }
+ }
+ LEAVE();
+ return MFALSE;
+}
+#endif
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_hs_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ hs_config_param *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &cmd->params.opt_hs_cfg;
+ t_u16 hs_activate = MFALSE;
+ t_u8 *tlv = (t_u8 *)phs_cfg + sizeof(HostCmd_DS_802_11_HS_CFG_ENH);
+ MrvlIEtypes_HsWakeHoldoff_t *holdoff_tlv = MNULL;
+ MrvlIEtypes_PsParamsInHs_t *psparam_tlv = MNULL;
+ MrvlIEtypes_WakeupSourceGPIO_t *gpio_tlv = MNULL;
+ MrvlIEtypes_MgmtFrameFilter_t *mgmt_filter_tlv = MNULL;
+ MrvlIEtypes_WakeupExtend_t *ext_tlv = MNULL;
+ MrvlIEtypes_HS_Antmode_t *antmode_tlv = MNULL;
+
+ ENTER();
+
+ if (pdata_buf == MNULL) {
+ /* New Activate command */
+ hs_activate = MTRUE;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_802_11_HS_CFG_ENH);
+
+ if (hs_activate) {
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl =
+ wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (wlan_is_p2p_connected(pmadapter))
+ phs_cfg->params.hs_config.conditions = wlan_cpu_to_le32(
+ pdata_buf->conditions |
+ HOST_SLEEP_COND_MULTICAST_DATA);
+ else
+#endif
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ if (pmadapter->min_wake_holdoff) {
+ cmd->size += sizeof(MrvlIEtypes_HsWakeHoldoff_t);
+ holdoff_tlv = (MrvlIEtypes_HsWakeHoldoff_t *)tlv;
+ holdoff_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_HS_WAKE_HOLDOFF);
+ holdoff_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_HsWakeHoldoff_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ holdoff_tlv->min_wake_holdoff =
+ wlan_cpu_to_le16(pmadapter->min_wake_holdoff);
+ tlv += sizeof(MrvlIEtypes_HsWakeHoldoff_t);
+ PRINTM(MCMND, "min_wake_holdoff=%d\n",
+ pmadapter->min_wake_holdoff);
+ }
+ if (pmadapter->hs_wake_interval && pmpriv->media_connected &&
+ (pmpriv->bss_type == MLAN_BSS_TYPE_STA)) {
+ cmd->size += sizeof(MrvlIEtypes_PsParamsInHs_t);
+ psparam_tlv = (MrvlIEtypes_PsParamsInHs_t *)tlv;
+ psparam_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PS_PARAMS_IN_HS);
+ psparam_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_PsParamsInHs_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ psparam_tlv->hs_wake_interval =
+ wlan_cpu_to_le32(pmadapter->hs_wake_interval);
+ psparam_tlv->hs_inactivity_timeout = wlan_cpu_to_le32(
+ pmadapter->hs_inactivity_timeout);
+ tlv += sizeof(MrvlIEtypes_PsParamsInHs_t);
+ PRINTM(MCMND, "hs_wake_interval=%d\n",
+ pmadapter->hs_wake_interval);
+ PRINTM(MCMND, "hs_inactivity_timeout=%d\n",
+ pmadapter->hs_inactivity_timeout);
+ }
+ if (pmadapter->param_type_ind == 1) {
+ cmd->size += sizeof(MrvlIEtypes_WakeupSourceGPIO_t);
+ gpio_tlv = (MrvlIEtypes_WakeupSourceGPIO_t *)tlv;
+ gpio_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_HS_WAKEUP_SOURCE_GPIO);
+ gpio_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_WakeupSourceGPIO_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ gpio_tlv->ind_gpio = (t_u8)pmadapter->ind_gpio;
+ gpio_tlv->level = (t_u8)pmadapter->level;
+ tlv += sizeof(MrvlIEtypes_WakeupSourceGPIO_t);
+ }
+ if (pmadapter->param_type_ext == 2) {
+ cmd->size += sizeof(MrvlIEtypes_WakeupExtend_t);
+ ext_tlv = (MrvlIEtypes_WakeupExtend_t *)tlv;
+ ext_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WAKEUP_EXTEND);
+ ext_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_WakeupExtend_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ ext_tlv->event_force_ignore =
+ wlan_cpu_to_le32(pmadapter->event_force_ignore);
+ ext_tlv->event_use_ext_gap =
+ wlan_cpu_to_le32(pmadapter->event_use_ext_gap);
+ ext_tlv->ext_gap = pmadapter->ext_gap;
+ ext_tlv->gpio_wave = pmadapter->gpio_wave;
+ tlv += sizeof(MrvlIEtypes_WakeupExtend_t);
+ }
+ if (pmadapter->mgmt_filter[0].type) {
+ int i = 0;
+ mgmt_frame_filter mgmt_filter[MAX_MGMT_FRAME_FILTER];
+
+ memset(pmadapter, mgmt_filter, 0,
+ MAX_MGMT_FRAME_FILTER *
+ sizeof(mgmt_frame_filter));
+ mgmt_filter_tlv = (MrvlIEtypes_MgmtFrameFilter_t *)tlv;
+ mgmt_filter_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_MGMT_FRAME_WAKEUP);
+ tlv += sizeof(MrvlIEtypesHeader_t);
+ while (i < MAX_MGMT_FRAME_FILTER &&
+ pmadapter->mgmt_filter[i].type) {
+ mgmt_filter[i].action =
+ (t_u8)pmadapter->mgmt_filter[i].action;
+ mgmt_filter[i].type =
+ (t_u8)pmadapter->mgmt_filter[i].type;
+ mgmt_filter[i].frame_mask = wlan_cpu_to_le32(
+ pmadapter->mgmt_filter[i].frame_mask);
+ i++;
+ }
+ memcpy_ext(pmadapter, (t_u8 *)mgmt_filter_tlv->filter,
+ (t_u8 *)mgmt_filter,
+ i * sizeof(mgmt_frame_filter),
+ sizeof(mgmt_filter_tlv->filter));
+ tlv += i * sizeof(mgmt_frame_filter);
+ mgmt_filter_tlv->header.len =
+ wlan_cpu_to_le16(i * sizeof(mgmt_frame_filter));
+ cmd->size += i * sizeof(mgmt_frame_filter) +
+ sizeof(MrvlIEtypesHeader_t);
+ }
+ if (pmadapter->hs_mimo_switch) {
+ cmd->size += sizeof(MrvlIEtypes_HS_Antmode_t);
+ antmode_tlv = (MrvlIEtypes_HS_Antmode_t *)tlv;
+ antmode_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_HS_ANTMODE);
+ antmode_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_HS_Antmode_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ antmode_tlv->txpath_antmode = ANTMODE_FW_DECISION;
+ antmode_tlv->rxpath_antmode = ANTMODE_FW_DECISION;
+ tlv += sizeof(MrvlIEtypes_HS_Antmode_t);
+ PRINTM(MCMND, "hs_mimo_switch=%d\n",
+ pmadapter->hs_mimo_switch);
+ PRINTM(MCMND, "txpath_antmode=%d, rxpath_antmode=%d\n",
+ antmode_tlv->txpath_antmode,
+ antmode_tlv->rxpath_antmode);
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ PRINTM(MCMND, "HS_CFG_CMD: condition:0x%x gpio:0x%x\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio);
+ PRINTM(MCMND, "HS_CFG_CMD: gap:0x%x holdoff=%d\n",
+ phs_cfg->params.hs_config.gap,
+ pmadapter->min_wake_holdoff);
+ PRINTM(MCMND,
+ "HS_CFG_CMD: wake_interval=%d inactivity_timeout=%d\n",
+ pmadapter->hs_wake_interval,
+ pmadapter->hs_inactivity_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_period.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_sleep_period(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_u16 *pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &cmd->params.sleep_pd;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) +
+ S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ pcmd_sleep_pd->sleep_pd = wlan_cpu_to_le16(*(t_u16 *)pdata_buf);
+
+ pcmd_sleep_pd->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sleep_params.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_sleep_params(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_u16 *pdata_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *pcmd_sp = &cmd->params.sleep_param;
+ mlan_ds_sleep_params *psp = (mlan_ds_sleep_params *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PARAMS) +
+ S_DS_GEN);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pcmd_sp->reserved = (t_u16)psp->reserved;
+ pcmd_sp->error = (t_u16)psp->error;
+ pcmd_sp->offset = (t_u16)psp->offset;
+ pcmd_sp->stable_time = (t_u16)psp->stable_time;
+ pcmd_sp->cal_control = (t_u8)psp->cal_control;
+ pcmd_sp->external_sleep_clk = (t_u8)psp->ext_sleep_clk;
+
+ pcmd_sp->reserved = wlan_cpu_to_le16(pcmd_sp->reserved);
+ pcmd_sp->error = wlan_cpu_to_le16(pcmd_sp->error);
+ pcmd_sp->offset = wlan_cpu_to_le16(pcmd_sp->offset);
+ pcmd_sp->stable_time = wlan_cpu_to_le16(pcmd_sp->stable_time);
+ }
+ pcmd_sp->action = wlan_cpu_to_le16(cmd_action);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mac_multicast_adr.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_mac_multicast_adr(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ mlan_multicast_list *pmcast_list = (mlan_multicast_list *)pdata_buf;
+ HostCmd_DS_MAC_MULTICAST_ADR *pmc_addr = &cmd->params.mc_addr;
+
+ ENTER();
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+ pmc_addr->action = wlan_cpu_to_le16(cmd_action);
+ pmc_addr->num_of_adrs =
+ wlan_cpu_to_le16((t_u16)pmcast_list->num_multicast_addr);
+ memcpy_ext(pmpriv->adapter, pmc_addr->mac_list, pmcast_list->mac_list,
+ pmcast_list->num_multicast_addr * MLAN_MAC_ADDR_LENGTH,
+ sizeof(pmc_addr->mac_list));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauthenticate/disassociate.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_deauthenticate(pmlan_private pmpriv,
+ t_u16 cmd_no,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_DEAUTHENTICATE *pdeauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(cmd_no);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) +
+ S_DS_GEN);
+
+ /* Set AP MAC address */
+ memcpy_ext(pmpriv->adapter, pdeauth, (t_u8 *)pdata_buf,
+ sizeof(*pdeauth), sizeof(*pdeauth));
+ if (cmd_no == HostCmd_CMD_802_11_DEAUTHENTICATE)
+ PRINTM(MCMND, "Deauth: " MACSTR "\n",
+ MAC2STR(pdeauth->mac_addr));
+ else
+ PRINTM(MCMND, "Disassociate: " MACSTR "\n",
+ MAC2STR(pdeauth->mac_addr));
+
+ if (pmpriv->adapter->state_11h.recvd_chanswann_event) {
+/** Reason code 36 = Requested from peer station as it is leaving the BSS */
+#define REASON_CODE_PEER_STA_LEAVING 36
+ pdeauth->reason_code =
+ wlan_cpu_to_le16(REASON_CODE_PEER_STA_LEAVING);
+ } else {
+ pdeauth->reason_code = wlan_cpu_to_le16(pdeauth->reason_code);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ad_hoc_stop.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_ad_hoc_stop(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd)
+{
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN);
+
+ if (wlan_11h_is_active(pmpriv))
+ wlan_11h_activate(pmpriv, MNULL, MFALSE);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of key_material.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_cmd_802_11_key_material(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material =
+ &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *)pdata_buf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (!pkey) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ PRINTM(MCMND, "GET Key\n");
+ pkey_material->key_param_set.key_idx =
+ pkey->key_index & KEY_INDEX_MASK;
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.mac_addr,
+ pkey->mac_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_UCAST_KEY;
+ if (pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)
+ pkey_material->key_param_set.key_info =
+ KEY_INFO_CMAC_AES_KEY;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(pkey_material->action));
+ goto done;
+ }
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSetV2_t));
+ if (pkey->key_flags & KEY_FLAG_REMOVE_KEY) {
+ pkey_material->action =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+ pkey_material->key_param_set.key_idx =
+ pkey->key_index & KEY_INDEX_MASK;
+ pkey_material->key_param_set.key_info = wlan_cpu_to_le16(
+ KEY_INFO_MCAST_KEY | KEY_INFO_UCAST_KEY);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.mac_addr,
+ pkey->mac_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Remove Key\n");
+ goto done;
+ }
+ pkey_material->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ pkey_material->key_param_set.key_idx = pkey->key_index & KEY_INDEX_MASK;
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ pkey_material->key_param_set.key_info = KEY_INFO_ENABLE_KEY;
+ memcpy_ext(pmpriv->adapter, pkey_material->key_param_set.mac_addr,
+ pkey->mac_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ if (pkey->key_len <= MAX_WEP_KEY_SIZE) {
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(wep_param_t));
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_WEP;
+ if (pkey->is_current_wep_key) {
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_MCAST_KEY | KEY_INFO_UCAST_KEY;
+ if (pkey_material->key_param_set.key_idx ==
+ (pmpriv->wep_key_curr_index & KEY_INDEX_MASK))
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_DEFAULT_KEY;
+ } else {
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_UCAST_KEY;
+ }
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ pkey_material->key_param_set.key_params.wep.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wep.key,
+ pkey->key_material, pkey->key_len, MAX_WEP_KEY_SIZE);
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(wep_param_t) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set WEP Key\n");
+ goto done;
+ }
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |= KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_UCAST_KEY;
+ if (pkey->key_flags & KEY_FLAG_SET_TX_KEY)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_TX_KEY | KEY_INFO_RX_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_RX_KEY;
+ if (pkey->is_wapi_key) {
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_WAPI;
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wapi.pn,
+ pkey->pn, PN_SIZE, PN_SIZE);
+ pkey_material->key_param_set.key_params.wapi.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wapi.key,
+ pkey->key_material, pkey->key_len, WAPI_KEY_SIZE);
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_DEFAULT_KEY;
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(wapi_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(wapi_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set WAPI Key\n");
+ goto done;
+ }
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ /* Enable default key for WPA/WPA2 */
+ if (!pmpriv->wpa_is_gtk_set)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_DEFAULT_KEY;
+ } else {
+ pkey_material->key_param_set.key_info |= KEY_INFO_DEFAULT_KEY;
+ /* Enable unicast bit for WPA-NONE/ADHOC_AES */
+ if ((!pmpriv->sec_info.wpa2_enabled) &&
+ (pkey->key_flags & KEY_FLAG_SET_TX_KEY))
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_UCAST_KEY;
+ }
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ if (pkey->key_flags & KEY_FLAG_GCMP ||
+ pkey->key_flags & KEY_FLAG_GCMP_256) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID)) {
+ memcpy_ext(
+ pmpriv->adapter,
+ pkey_material->key_param_set.key_params.gcmp.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ }
+ if (pkey->key_flags & KEY_FLAG_GCMP)
+ pkey_material->key_param_set.key_type =
+ KEY_TYPE_ID_GCMP;
+ else
+ pkey_material->key_param_set.key_type =
+ KEY_TYPE_ID_GCMP_256;
+ pkey_material->key_param_set.key_params.gcmp.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.gcmp.key,
+ pkey->key_material, pkey->key_len, WPA_GCMP_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(gcmp_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(gcmp_param) +
+ sizeof(pkey_material->action));
+
+ goto done;
+ }
+ if (pkey->key_flags & KEY_FLAG_CCMP_256) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID)) {
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params
+ .ccmp256.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ }
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_CCMP_256;
+ pkey_material->key_param_set.key_params.ccmp256.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.ccmp256.key,
+ pkey->key_material, pkey->key_len,
+ WPA_CCMP_256_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(ccmp_256_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(ccmp_256_param) +
+ sizeof(pkey_material->action));
+
+ goto done;
+ }
+ if (pkey->key_len == WPA_AES_KEY_LEN &&
+ !(pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(
+ pmpriv->adapter,
+ pkey_material->key_param_set.key_params.aes.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_AES;
+ pkey_material->key_param_set.key_params.aes.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.aes.key,
+ pkey->key_material, pkey->key_len, WPA_AES_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(aes_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(aes_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set AES Key\n");
+ goto done;
+ }
+ if (pkey->key_len == WPA_IGTK_KEY_LEN &&
+ (pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params
+ .cmac_aes.ipn,
+ pkey->pn, SEQ_MAX_SIZE, IGTK_PN_SIZE);
+ pkey_material->key_param_set.key_info &=
+ ~(wlan_cpu_to_le16(KEY_INFO_MCAST_KEY));
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST_IGTK);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC;
+ pkey_material->key_param_set.key_params.cmac_aes.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.cmac_aes.key,
+ pkey->key_material, pkey->key_len, CMAC_AES_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(cmac_aes_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(cmac_aes_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set CMAC AES Key\n");
+ goto done;
+ }
+ if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(
+ pmpriv->adapter,
+ pkey_material->key_param_set.key_params.tkip.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_TKIP;
+ pkey_material->key_param_set.key_params.tkip.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.tkip.key,
+ pkey->key_material, pkey->key_len, WPA_TKIP_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(tkip_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(tkip_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set TKIP Key\n");
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of gtk rekey offload
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_cmd_gtk_rekey_offload(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_GTK_REKEY_PARAMS *rekey = &cmd->params.gtk_rekey;
+ mlan_ds_misc_gtk_rekey_data *data =
+ (mlan_ds_misc_gtk_rekey_data *)pdata_buf;
+ t_u64 rekey_ctr;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(*rekey) + S_DS_GEN);
+
+ rekey->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy_ext(pmpriv->adapter, rekey->kek, data->kek, MLAN_KEK_LEN,
+ MLAN_KEK_LEN);
+ memcpy_ext(pmpriv->adapter, rekey->kck, data->kck, MLAN_KCK_LEN,
+ MLAN_KCK_LEN);
+ rekey_ctr = wlan_le64_to_cpu(
+ swap_byte_64(*(t_u64 *)data->replay_ctr));
+ rekey->replay_ctr_low = wlan_cpu_to_le32((t_u32)rekey_ctr);
+ rekey->replay_ctr_high =
+ wlan_cpu_to_le32((t_u64)rekey_ctr >> 32);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function send eapol pkt to FW
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_eapol_pkt(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_EAPOL_PKT *eapol_pkt = &cmd->params.eapol_pkt;
+ mlan_buffer *pmbuf = (mlan_buffer *)pdata_buf;
+
+ ENTER();
+ eapol_pkt->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ cmd->size = sizeof(HostCmd_DS_EAPOL_PKT) + S_DS_GEN;
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+
+ eapol_pkt->tlv_eapol.header.type = wlan_cpu_to_le16(TLV_TYPE_EAPOL_PKT);
+ eapol_pkt->tlv_eapol.header.len = wlan_cpu_to_le16(pmbuf->data_len);
+ memcpy_ext(pmpriv->adapter, eapol_pkt->tlv_eapol.pkt_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len,
+ pmbuf->data_len);
+ cmd->size += pmbuf->data_len;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_supplicant_profile(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *sup_profile =
+ (HostCmd_DS_802_11_SUPPLICANT_PROFILE *)&(
+ cmd->params.esupplicant_profile);
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ t_u8 *ptlv_buffer = (t_u8 *)sup_profile->tlv_buf;
+ mlan_ds_esupp_mode *esupp = MNULL;
+
+ ENTER();
+
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_SUPPLICANT_PROFILE) + S_DS_GEN - 1);
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PROFILE);
+ sup_profile->action = wlan_cpu_to_le16(cmd_action);
+ if ((cmd_action == HostCmd_ACT_GEN_SET) && pdata_buf) {
+ esupp = (mlan_ds_esupp_mode *)pdata_buf;
+ if (esupp->rsn_mode) {
+ encr_proto_tlv = (MrvlIEtypes_EncrProto_t *)ptlv_buffer;
+ encr_proto_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_ENCRYPTION_PROTO);
+ encr_proto_tlv->header.len =
+ (t_u16)sizeof(encr_proto_tlv->rsn_mode);
+ encr_proto_tlv->rsn_mode =
+ wlan_cpu_to_le16(esupp->rsn_mode);
+ ptlv_buffer += (encr_proto_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (encr_proto_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ encr_proto_tlv->header.len =
+ wlan_cpu_to_le16(encr_proto_tlv->header.len);
+ }
+ if (esupp->act_paircipher || esupp->act_groupcipher) {
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *)ptlv_buffer;
+ pcipher_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CIPHER);
+ pcipher_tlv->header.len =
+ (t_u16)(sizeof(pcipher_tlv->pair_cipher) +
+ sizeof(pcipher_tlv->group_cipher));
+ if (esupp->act_paircipher) {
+ pcipher_tlv->pair_cipher =
+ esupp->act_paircipher & 0xff;
+ }
+ if (esupp->act_groupcipher) {
+ pcipher_tlv->group_cipher =
+ esupp->act_groupcipher & 0xff;
+ }
+ ptlv_buffer += (pcipher_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ cmd->size += (pcipher_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ pcipher_tlv->header.len =
+ wlan_cpu_to_le16(pcipher_tlv->header.len);
+ }
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of rf_channel.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_802_11_rf_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_chan = &cmd->params.rf_channel;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL) +
+ S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->adhoc_start_band & BAND_A))
+ prf_chan->rf_type.bandcfg.chanBand = BAND_5GHZ;
+ prf_chan->rf_type.bandcfg.chanWidth =
+ pmpriv->adapter->chan_bandwidth;
+ prf_chan->current_channel =
+ wlan_cpu_to_le16(*((t_u16 *)pdata_buf));
+ }
+ prf_chan->action = wlan_cpu_to_le16(cmd_action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of ibss_coalescing_status.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer or MNULL
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_ibss_coalescing_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal =
+ &(cmd->params.ibss_coalescing);
+ t_u16 enable = 0;
+
+ ENTER();
+
+ cmd->command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_STATUS) +
+ S_DS_GEN);
+ cmd->result = 0;
+ pibss_coal->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ if (pdata_buf != MNULL)
+ enable = *(t_u16 *)pdata_buf;
+ pibss_coal->enable = wlan_cpu_to_le16(enable);
+ break;
+
+ /* In other case.. Nothing to do */
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of mgmt IE list.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_mgmt_ie_list(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list =
+ &(cmd->params.mgmt_ie_list);
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MGMT_IE_LIST);
+ cmd->size = sizeof(HostCmd_DS_MGMT_IE_LIST_CFG) + S_DS_GEN;
+ cmd->result = 0;
+ pmgmt_ie_list->action = wlan_cpu_to_le16(cmd_action);
+
+ cust_ie = (mlan_ds_misc_custom_ie *)pdata_buf;
+ pmgmt_ie_list->ds_mgmt_ie.type = wlan_cpu_to_le16(cust_ie->type);
+ pmgmt_ie_list->ds_mgmt_ie.len = wlan_cpu_to_le16(cust_ie->len);
+
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(cust_ie->ie_data_list[0].ie_index);
+
+ while (req_len > sizeof(t_u16)) {
+ cptr = (custom_ie *)(((t_u8 *)cust_ie->ie_data_list) +
+ travel_len);
+ travel_len += cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ req_len -= cptr->ie_length + sizeof(custom_ie) - MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(cptr->ie_length);
+ }
+ if (cust_ie->len)
+ memcpy_ext(pmpriv->adapter,
+ pmgmt_ie_list->ds_mgmt_ie.ie_data_list,
+ cust_ie->ie_data_list, cust_ie->len,
+ sizeof(pmgmt_ie_list->ds_mgmt_ie.ie_data_list));
+
+ cmd->size -= (MAX_MGMT_IE_INDEX_TO_FW * sizeof(custom_ie)) +
+ sizeof(tlvbuf_max_mgmt_ie);
+ cmd->size += cust_ie->len;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares system clock cfg command
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_sysclock_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *cfg = &cmd->params.sys_clock_cfg;
+ mlan_ds_misc_sys_clock *clk_cfg = (mlan_ds_misc_sys_clock *)pdata_buf;
+ int i = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG) + S_DS_GEN);
+
+ cfg->action = wlan_cpu_to_le16(cmd_action);
+ cfg->cur_sys_clk = wlan_cpu_to_le16(clk_cfg->cur_sys_clk);
+ cfg->sys_clk_type = wlan_cpu_to_le16(clk_cfg->sys_clk_type);
+ cfg->sys_clk_len =
+ wlan_cpu_to_le16(clk_cfg->sys_clk_num) * sizeof(t_u16);
+ for (i = 0; i < clk_cfg->sys_clk_num; i++)
+ cfg->sys_clk[i] = wlan_cpu_to_le16(clk_cfg->sys_clk[i]);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of subscribe event.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_subscribe_event(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ mlan_ds_subscribe_evt *sub_evt = (mlan_ds_subscribe_evt *)pdata_buf;
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *)&cmd->params.subscribe_event;
+ t_u16 cmd_size = 0;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_low = MNULL;
+ MrvlIEtypes_BeaconLowSnrThreshold_t *snr_low = MNULL;
+ MrvlIEtypes_FailureCount_t *fail_count = MNULL;
+ MrvlIEtypes_BeaconsMissed_t *beacon_missed = MNULL;
+ MrvlIEtypes_BeaconHighRssiThreshold_t *rssi_high = MNULL;
+ MrvlIEtypes_BeaconHighSnrThreshold_t *snr_high = MNULL;
+ MrvlIEtypes_DataLowRssiThreshold_t *data_rssi_low = MNULL;
+ MrvlIEtypes_DataLowSnrThreshold_t *data_snr_low = MNULL;
+ MrvlIEtypes_DataHighRssiThreshold_t *data_rssi_high = MNULL;
+ MrvlIEtypes_DataHighSnrThreshold_t *data_snr_high = MNULL;
+ MrvlIEtypes_LinkQualityThreshold_t *link_quality = MNULL;
+ MrvlIETypes_PreBeaconMissed_t *pre_bcn_missed = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT);
+ evt->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SUBSCRIBE_EVENT) + S_DS_GEN;
+ if (cmd_action == HostCmd_ACT_GEN_GET)
+ goto done;
+ evt->action = wlan_cpu_to_le16(sub_evt->evt_action);
+ evt->event_bitmap = wlan_cpu_to_le16(sub_evt->evt_bitmap);
+ tlv = (t_u8 *)cmd + cmd_size;
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_LOW) {
+ rssi_low = (MrvlIEtypes_BeaconLowRssiThreshold_t *)tlv;
+ rssi_low->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
+ rssi_low->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_low->value = sub_evt->low_rssi;
+ rssi_low->frequency = sub_evt->low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_LOW) {
+ snr_low = (MrvlIEtypes_BeaconLowSnrThreshold_t *)tlv;
+ snr_low->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_low->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_low->value = sub_evt->low_snr;
+ snr_low->frequency = sub_evt->low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_MAX_FAIL) {
+ fail_count = (MrvlIEtypes_FailureCount_t *)tlv;
+ fail_count->header.type = wlan_cpu_to_le16(TLV_TYPE_FAILCOUNT);
+ fail_count->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_FailureCount_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ fail_count->value = sub_evt->failure_count;
+ fail_count->frequency = sub_evt->failure_count_freq;
+ tlv += sizeof(MrvlIEtypes_FailureCount_t);
+ cmd_size += sizeof(MrvlIEtypes_FailureCount_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_BEACON_MISSED) {
+ beacon_missed = (MrvlIEtypes_BeaconsMissed_t *)tlv;
+ beacon_missed->header.type = wlan_cpu_to_le16(TLV_TYPE_BCNMISS);
+ beacon_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_BeaconsMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ beacon_missed->value = sub_evt->beacon_miss;
+ beacon_missed->frequency = sub_evt->beacon_miss_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconsMissed_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_RSSI_HIGH) {
+ rssi_high = (MrvlIEtypes_BeaconHighRssiThreshold_t *)tlv;
+ rssi_high->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+ rssi_high->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ rssi_high->value = sub_evt->high_rssi;
+ rssi_high->frequency = sub_evt->high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_SNR_HIGH) {
+ snr_high = (MrvlIEtypes_BeaconHighSnrThreshold_t *)tlv;
+ snr_high->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH);
+ snr_high->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ snr_high->value = sub_evt->high_snr;
+ snr_high->frequency = sub_evt->high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_BeaconHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_LOW) {
+ data_rssi_low = (MrvlIEtypes_DataLowRssiThreshold_t *)tlv;
+ data_rssi_low->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW_DATA);
+ data_rssi_low->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_DataLowRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_low->value = sub_evt->data_low_rssi;
+ data_rssi_low->frequency = sub_evt->data_low_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_LOW) {
+ data_snr_low = (MrvlIEtypes_DataLowSnrThreshold_t *)tlv;
+ data_snr_low->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SNR_LOW_DATA);
+ data_snr_low->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_DataLowSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_low->value = sub_evt->data_low_snr;
+ data_snr_low->frequency = sub_evt->data_low_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataLowSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_RSSI_HIGH) {
+ data_rssi_high = (MrvlIEtypes_DataHighRssiThreshold_t *)tlv;
+ data_rssi_high->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_RSSI_HIGH_DATA);
+ data_rssi_high->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_DataHighRssiThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_rssi_high->value = sub_evt->data_high_rssi;
+ data_rssi_high->frequency = sub_evt->data_high_rssi_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighRssiThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_DATA_SNR_HIGH) {
+ data_snr_high = (MrvlIEtypes_DataHighSnrThreshold_t *)tlv;
+ data_snr_high->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_SNR_HIGH_DATA);
+ data_snr_high->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_DataHighSnrThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ data_snr_high->value = sub_evt->data_high_snr;
+ data_snr_high->frequency = sub_evt->data_high_snr_freq;
+ tlv += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_DataHighSnrThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_LINK_QUALITY) {
+ link_quality = (MrvlIEtypes_LinkQualityThreshold_t *)tlv;
+ link_quality->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_LINK_QUALITY);
+ link_quality->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_LinkQualityThreshold_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ link_quality->link_snr = wlan_cpu_to_le16(sub_evt->link_snr);
+ link_quality->link_snr_freq =
+ wlan_cpu_to_le16(sub_evt->link_snr_freq);
+ link_quality->link_rate = wlan_cpu_to_le16(sub_evt->link_rate);
+ link_quality->link_rate_freq =
+ wlan_cpu_to_le16(sub_evt->link_rate_freq);
+ link_quality->link_tx_latency =
+ wlan_cpu_to_le16(sub_evt->link_tx_latency);
+ link_quality->link_tx_lantency_freq =
+ wlan_cpu_to_le16(sub_evt->link_tx_lantency_freq);
+ tlv += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ cmd_size += sizeof(MrvlIEtypes_LinkQualityThreshold_t);
+ }
+ if (sub_evt->evt_bitmap & SUBSCRIBE_EVT_PRE_BEACON_LOST) {
+ pre_bcn_missed = (MrvlIETypes_PreBeaconMissed_t *)tlv;
+ pre_bcn_missed->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PRE_BCNMISS);
+ pre_bcn_missed->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIETypes_PreBeaconMissed_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ pre_bcn_missed->value = sub_evt->pre_beacon_miss;
+ pre_bcn_missed->frequency = 0;
+ tlv += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ cmd_size += sizeof(MrvlIETypes_PreBeaconMissed_t);
+ }
+done:
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of OTP user data.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_otp_user_data(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ mlan_ds_misc_otp_user_data *user_data =
+ (mlan_ds_misc_otp_user_data *)pdata_buf;
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *)&cmd->params.otp_user_data;
+ t_u16 cmd_size = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_OTP_READ_USER_DATA);
+ cmd_size = sizeof(HostCmd_DS_OTP_USER_DATA) + S_DS_GEN - 1;
+
+ cmd_user_data->action = wlan_cpu_to_le16(cmd_action);
+ cmd_user_data->reserved = 0;
+ cmd_user_data->user_data_length =
+ wlan_cpu_to_le16(user_data->user_data_length);
+ cmd_size += user_data->user_data_length;
+ cmd->size = wlan_cpu_to_le16(cmd_size);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef USB
+/**
+ * @brief This function prepares command of packet aggragation
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status
+wlan_cmd_packet_aggr_over_host_interface(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE *packet_aggr =
+ &cmd->params.packet_aggr;
+ MrvlIETypes_USBAggrParam_t *usb_aggr_param_tlv = MNULL;
+ mlan_ds_misc_usb_aggr_ctrl *usb_aggr_ctrl =
+ (mlan_ds_misc_usb_aggr_ctrl *)pdata_buf;
+ t_u8 *ptlv_buffer = (t_u8 *)packet_aggr->tlv_buf;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ usb_aggr_param_tlv = (MrvlIETypes_USBAggrParam_t *)ptlv_buffer;
+
+ cmd->command =
+ wlan_cpu_to_le16(HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE);
+ packet_aggr->action = wlan_cpu_to_le16(cmd_action);
+ memset(pmadapter, usb_aggr_param_tlv, 0,
+ MRVL_USB_AGGR_PARAM_TLV_LEN + sizeof(MrvlIEtypesHeader_t));
+ usb_aggr_param_tlv->header.type =
+ wlan_cpu_to_le16(MRVL_USB_AGGR_PARAM_TLV_ID);
+ usb_aggr_param_tlv->header.len =
+ wlan_cpu_to_le16(MRVL_USB_AGGR_PARAM_TLV_LEN);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE) + S_DS_GEN +
+ MRVL_USB_AGGR_PARAM_TLV_LEN + sizeof(MrvlIEtypesHeader_t) - 1);
+
+ if (pmadapter->data_sent || (!wlan_bypass_tx_list_empty(pmadapter)) ||
+ (!wlan_wmm_lists_empty(pmadapter))) {
+ /* Make sure this is not issued during traffic */
+ PRINTM(MERROR,
+ "USB aggregation parameters cannot be accessed during traffic.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ usb_aggr_param_tlv->enable = 0;
+ if (usb_aggr_ctrl->tx_aggr_ctrl.enable)
+ usb_aggr_param_tlv->enable |= MBIT(1);
+ usb_aggr_param_tlv->tx_aggr_align = wlan_cpu_to_le16(
+ usb_aggr_ctrl->tx_aggr_ctrl.aggr_align);
+ if (usb_aggr_ctrl->rx_deaggr_ctrl.enable)
+ usb_aggr_param_tlv->enable |= MBIT(0);
+ usb_aggr_param_tlv->rx_aggr_mode = wlan_cpu_to_le16(
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_mode);
+ usb_aggr_param_tlv->rx_aggr_align = wlan_cpu_to_le16(
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_align);
+ usb_aggr_param_tlv->rx_aggr_max = wlan_cpu_to_le16(
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_max);
+ usb_aggr_param_tlv->rx_aggr_tmo = wlan_cpu_to_le16(
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_tmo);
+ usb_aggr_param_tlv->enable =
+ wlan_cpu_to_le16(usb_aggr_param_tlv->enable);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function prepares inactivity timeout command
+ *
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_inactivity_timeout(HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ pmlan_ds_inactivity_to inac_to;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to =
+ &cmd->params.inactivity_to;
+
+ ENTER();
+
+ inac_to = (mlan_ds_inactivity_to *)pdata_buf;
+
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_INACTIVITY_TIMEOUT_EXT) +
+ S_DS_GEN);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_inac_to->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cmd_inac_to->timeout_unit =
+ wlan_cpu_to_le16((t_u16)inac_to->timeout_unit);
+ cmd_inac_to->unicast_timeout =
+ wlan_cpu_to_le16((t_u16)inac_to->unicast_timeout);
+ cmd_inac_to->mcast_timeout =
+ wlan_cpu_to_le16((t_u16)inac_to->mcast_timeout);
+ cmd_inac_to->ps_entry_timeout =
+ wlan_cpu_to_le16((t_u16)inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares Low Power Mode
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_low_pwr_mode(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_CONFIG_LOW_PWR_MODE *cmd_lpm_cfg =
+ &cmd->params.low_pwr_mode_cfg;
+ t_u8 *enable;
+
+ ENTER();
+
+ cmd->size = S_DS_GEN + sizeof(HostCmd_CONFIG_LOW_PWR_MODE);
+
+ enable = (t_u8 *)pdata_buf;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_lpm_cfg->enable = *enable;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares DFS repeater mode configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_cmd_dfs_repeater_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ mlan_ds_misc_dfs_repeater *dfs_repeater = MNULL;
+ HostCmd_DS_DFS_REPEATER_MODE *cmd_dfs_repeater =
+ &cmd->params.dfs_repeater;
+
+ ENTER();
+
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_DFS_REPEATER_MODE);
+
+ dfs_repeater = (mlan_ds_misc_dfs_repeater *)pdata_buf;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ cmd->command = wlan_cpu_to_le16(cmd->command);
+ cmd_dfs_repeater->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ cmd_dfs_repeater->mode = wlan_cpu_to_le16(dfs_repeater->mode);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of coalesce_config.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_coalesce_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_COALESCE_CONFIG *coalesce_config =
+ &cmd->params.coalesce_config;
+ mlan_ds_coalesce_cfg *cfg = (mlan_ds_coalesce_cfg *)pdata_buf;
+ t_u16 cnt, idx, length;
+ struct coalesce_filt_field_param *param;
+ struct coalesce_receive_filt_rule *rule;
+
+ ENTER();
+
+ cmd->size = sizeof(HostCmd_DS_COALESCE_CONFIG) + S_DS_GEN;
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_COALESCE_CFG);
+ coalesce_config->action = wlan_cpu_to_le16(cmd_action);
+ coalesce_config->num_of_rules = wlan_cpu_to_le16(cfg->num_of_rules);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ rule = coalesce_config->rule;
+ for (cnt = 0; cnt < cfg->num_of_rules; cnt++) {
+ rule->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_COALESCE_RULE);
+ rule->max_coalescing_delay = wlan_cpu_to_le16(
+ cfg->rule[cnt].max_coalescing_delay);
+ rule->pkt_type = cfg->rule[cnt].pkt_type;
+ rule->num_of_fields = cfg->rule[cnt].num_of_fields;
+
+ length = 0;
+
+ param = rule->params;
+ for (idx = 0; idx < cfg->rule[cnt].num_of_fields;
+ idx++) {
+ param->operation =
+ cfg->rule[cnt].params[idx].operation;
+ param->operand_len =
+ cfg->rule[cnt].params[idx].operand_len;
+ param->offset = wlan_cpu_to_le16(
+ cfg->rule[cnt].params[idx].offset);
+ memcpy_ext(pmpriv->adapter,
+ param->operand_byte_stream,
+ cfg->rule[cnt]
+ .params[idx]
+ .operand_byte_stream,
+ param->operand_len,
+ sizeof(param->operand_byte_stream));
+
+ length += sizeof(
+ struct coalesce_filt_field_param);
+
+ param++;
+ }
+
+ /* Total rule length is sizeof
+ * max_coalescing_delay(t_u16), num_of_fields(t_u8),
+ * pkt_type(t_u8) and total length of the all params
+ */
+ rule->header.len =
+ wlan_cpu_to_le16(length + sizeof(t_u16) +
+ sizeof(t_u8) + sizeof(t_u8));
+
+ /* Add the rule length to the command size*/
+ cmd->size += wlan_le16_to_cpu(rule->header.len) +
+ sizeof(MrvlIEtypesHeader_t);
+
+ rule = (void *)((t_u8 *)rule->params + length);
+ }
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ * Global Functions
+ ********************************************************/
+
+static mlan_status wlan_cmd_get_sensor_temp(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action)
+{
+ ENTER();
+
+ if (cmd_action != HostCmd_ACT_GEN_GET) {
+ PRINTM(MERROR, "wlan_cmd_get_sensor_temp: support GET only.\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_DS_GET_SENSOR_TEMP);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + 4);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of arb cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_arb_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_ARB_CONFIG *cfg_cmd =
+ (HostCmd_DS_CMD_ARB_CONFIG *)&cmd->params.arb_cfg;
+ mlan_ds_misc_arb_cfg *misc_cfg = (mlan_ds_misc_arb_cfg *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ARB_CONFIG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_ARB_CONFIG) + S_DS_GEN);
+ cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ cfg_cmd->arb_mode = wlan_cpu_to_le32(misc_cfg->arb_mode);
+ if (misc_cfg->arb_mode == 3) {
+#define DEF_ARB_TX_WIN 4
+#define DEF_ARB_TIMEOUT 0
+ pmpriv->add_ba_param.timeout = DEF_ARB_TIMEOUT;
+ pmpriv->add_ba_param.tx_win_size = DEF_ARB_TX_WIN;
+ } else {
+ pmpriv->add_ba_param.timeout =
+ MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ pmpriv->add_ba_param.tx_win_size =
+ MLAN_STA_AMPDU_DEF_TXWINSIZE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function sends get sta band channel command to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd Hostcmd ID
+ * @return N/A
+ */
+static mlan_status wlan_cmd_sta_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ mlan_ioctl_req *pioctl_buf,
+ t_void *pdata_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_STA_CONFIGURE *sta_cfg_cmd = &cmd->params.sta_cfg;
+ MrvlIEtypes_channel_band_t *tlv_band_channel = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (!pioctl_buf)
+ return ret;
+
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ if ((bss->sub_command == MLAN_OID_BSS_CHAN_INFO) &&
+ (cmd_action == HostCmd_ACT_GEN_GET)) {
+ cmd->command =
+ wlan_cpu_to_le16(HostCmd_CMD_STA_CONFIGURE);
+ cmd->size = wlan_cpu_to_le16(
+ S_DS_GEN + sizeof(HostCmd_DS_STA_CONFIGURE) +
+ sizeof(*tlv_band_channel));
+ sta_cfg_cmd->action = wlan_cpu_to_le16(cmd_action);
+ tlv_band_channel = (MrvlIEtypes_channel_band_t *)
+ sta_cfg_cmd->tlv_buffer;
+ memset(pmpriv->adapter, tlv_band_channel, 0x00,
+ sizeof(*tlv_band_channel));
+ tlv_band_channel->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
+ tlv_band_channel->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends set and get auto tx command to firmware.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd Hostcmd ID
+ * @param cmd_action Command action
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pdata_buf A void pointer to information buffer
+ * @return N/A
+ */
+static mlan_status wlan_cmd_auto_tx(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
+ t_u32 cmd_oid, t_void *pdata_buf)
+{
+ HostCmd_DS_AUTO_TX *auto_tx_cmd = &cmd->params.auto_tx;
+ t_u8 *pos = (t_u8 *)auto_tx_cmd->tlv_buffer;
+ t_u16 len = 0;
+ MrvlIEtypes_Cloud_Keep_Alive_t *keep_alive_tlv = MNULL;
+ MrvlIEtypes_Keep_Alive_Ctrl_t *ctrl_tlv = MNULL;
+ MrvlIEtypes_Keep_Alive_Pkt_t *pkt_tlv = MNULL;
+ mlan_ds_misc_keep_alive *misc_keep_alive = MNULL;
+ t_u8 eth_ip[] = {0x08, 0x00};
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_AUTO_TX);
+ cmd->size = S_DS_GEN + sizeof(HostCmd_DS_AUTO_TX);
+ auto_tx_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ switch (cmd_oid) {
+ case OID_CLOUD_KEEP_ALIVE:
+ misc_keep_alive = (mlan_ds_misc_keep_alive *)pdata_buf;
+ keep_alive_tlv = (MrvlIEtypes_Cloud_Keep_Alive_t *)pos;
+
+ keep_alive_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CLOUD_KEEP_ALIVE);
+ keep_alive_tlv->keep_alive_id = misc_keep_alive->mkeep_alive_id;
+ keep_alive_tlv->enable = misc_keep_alive->enable;
+ len = len + sizeof(keep_alive_tlv->keep_alive_id) +
+ sizeof(keep_alive_tlv->enable);
+ pos = pos + len + sizeof(MrvlIEtypesHeader_t);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if (misc_keep_alive->enable) {
+ ctrl_tlv = (MrvlIEtypes_Keep_Alive_Ctrl_t *)pos;
+ ctrl_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_KEEP_ALIVE_CTRL);
+ ctrl_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_Keep_Alive_Ctrl_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ ctrl_tlv->snd_interval = wlan_cpu_to_le32(
+ misc_keep_alive->send_interval);
+ ctrl_tlv->retry_interval = wlan_cpu_to_le16(
+ misc_keep_alive->retry_interval);
+ ctrl_tlv->retry_count = wlan_cpu_to_le16(
+ misc_keep_alive->retry_count);
+ len = len +
+ sizeof(MrvlIEtypes_Keep_Alive_Ctrl_t);
+
+ pos = pos +
+ sizeof(MrvlIEtypes_Keep_Alive_Ctrl_t);
+ pkt_tlv = (MrvlIEtypes_Keep_Alive_Pkt_t *)pos;
+ pkt_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_KEEP_ALIVE_PKT);
+ memcpy_ext(pmpriv->adapter,
+ pkt_tlv->eth_header.dest_addr,
+ misc_keep_alive->dst_mac,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmpriv->adapter,
+ pkt_tlv->eth_header.src_addr,
+ misc_keep_alive->src_mac,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(
+ pmpriv->adapter,
+ (t_u8 *)&pkt_tlv->eth_header.h803_len,
+ eth_ip, sizeof(t_u16), sizeof(t_u16));
+ if (misc_keep_alive->ether_type)
+ pkt_tlv->eth_header
+ .h803_len = mlan_htons(
+ misc_keep_alive->ether_type);
+ else
+ memcpy_ext(pmpriv->adapter,
+ (t_u8 *)&pkt_tlv->eth_header
+ .h803_len,
+ eth_ip, sizeof(t_u16),
+ sizeof(t_u16));
+ pkt_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(Eth803Hdr_t) +
+ misc_keep_alive->pkt_len);
+ len = len + sizeof(MrvlIEtypesHeader_t) +
+ sizeof(Eth803Hdr_t) +
+ misc_keep_alive->pkt_len;
+ } else {
+ pkt_tlv = (MrvlIEtypes_Keep_Alive_Pkt_t *)pos;
+ pkt_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_KEEP_ALIVE_PKT);
+ pkt_tlv->header.len = 0;
+ len = len + sizeof(MrvlIEtypesHeader_t);
+ }
+ }
+ if (cmd_action == HostCmd_ACT_GEN_RESET) {
+ pkt_tlv = (MrvlIEtypes_Keep_Alive_Pkt_t *)pos;
+ pkt_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEEP_ALIVE_PKT);
+ pkt_tlv->header.len = 0;
+ len = len + sizeof(MrvlIEtypesHeader_t);
+ }
+ keep_alive_tlv->header.len = wlan_cpu_to_le16(len);
+
+ cmd->size = cmd->size + len + sizeof(MrvlIEtypesHeader_t);
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function check if the command is supported by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_is_cmd_allowed(mlan_private *priv, t_u16 cmd_no)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (priv->adapter->pcard_info->v16_fw_api) {
+ if (!IS_FW_SUPPORT_ADHOC(priv->adapter)) {
+ switch (cmd_no) {
+ case HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON:
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_sta_prepare_cmd(t_void *priv, t_u16 cmd_no,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pioctl_buf, t_void *pdata_buf,
+ t_void *pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *)pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wlan_is_cmd_allowed(pmpriv, cmd_no)) {
+ PRINTM(MERROR, "FW don't support the command 0x%x\n", cmd_no);
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ ret = wlan_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_cmd_mac_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_cmd_802_11_mac_address(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = wlan_cmd_mac_multicast_adr(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_CW_MODE_CTRL:
+ ret = wlan_cmd_cw_mode_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_cmd_tx_power_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_cmd_802_11_rf_tx_power(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16)cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *)pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ROBUSTCOEX:
+ ret = wlan_cmd_robustcoex(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_DMCS_CONFIG:
+ ret = wlan_cmd_dmcs_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#if defined(PCIE)
+ case HostCmd_CMD_SSU:
+ ret = wlan_cmd_ssu(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HOST_CMD_PMIC_CONFIGURE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_cmd_802_11_sleep_period(pmpriv, cmd_ptr, cmd_action,
+ (t_u16 *)pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_cmd_802_11_sleep_params(pmpriv, cmd_ptr, cmd_action,
+ (t_u16 *)pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_cmd_802_11_scan(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_cmd_bgscan_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_cmd_802_11_bg_scan_query(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_cmd_802_11_associate(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ case HostCmd_CMD_802_11_DISASSOCIATE:
+ ret = wlan_cmd_802_11_deauthenticate(pmpriv, cmd_no, cmd_ptr,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ ret = wlan_cmd_802_11_ad_hoc_start(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_cmd_802_11_ad_hoc_join(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_cmd_802_11_ad_hoc_stop(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_cmd_802_11_get_log(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_LINK_STATS:
+ ret = wlan_cmd_802_11_link_statistic(pmpriv, cmd_ptr,
+ cmd_action, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_cmd_802_11_rssi_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_RSSI_INFO_EXT:
+ ret = wlan_cmd_802_11_rssi_info_ext(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_cmd_802_11_snmp_mib(pmpriv, cmd_ptr, cmd_action,
+ cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) +
+ S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8)(*((t_u32 *)pdata_buf));
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action =
+ wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ wlan_cpu_to_le32((t_u32)(*((t_u32 *)pdata_buf)));
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_RX_MGMT_IND) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = wlan_cmd_802_11_rf_channel(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status =
+ WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_SOFT_RESET:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_cmd_802_11_key_material(pmpriv, cmd_ptr, cmd_action,
+ cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:
+ ret = wlan_cmd_gtk_rekey_offload(pmpriv, cmd_ptr, cmd_action,
+ cmd_oid, pdata_buf);
+ break;
+
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_cmd_802_11_supplicant_pmk(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_EAPOL_PKT:
+ ret = wlan_cmd_eapol_pkt(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_cmd_802_11_supplicant_profile(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_cmd_11n_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = wlan_cmd_11ac_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#if 0
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmd sent\n");
+ cmd_ptr->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_cmd_wmm_addts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_cmd_wmm_delts_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_cmd_wmm_queue_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_cmd_wmm_queue_stats(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_cmd_wmm_ts_status(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_PARAM_CONFIG:
+ ret = wlan_cmd_wmm_param_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = wlan_cmd_ibss_coalescing_status(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_cmd_mgmt_ie_list(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_cmd_802_11_scan_ext(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_cmd_sysclock_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_TARGET_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ case HostCmd_CMD_BCA_REG_ACCESS:
+ ret = wlan_cmd_reg_access(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_cmd_mem_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_cmd_inactivity_timeout(cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_GET_TSF:
+ ret = wlan_cmd_get_tsf(pmpriv, cmd_ptr, cmd_action);
+ break;
+#if defined(SDIO)
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (pdata_buf) {
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *)pdata_buf;
+ } else
+#endif
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ cmd_ptr->params.bss_mode.con_type =
+ CONNECTION_TYPE_ADHOC;
+ else if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ cmd_ptr->params.bss_mode.con_type =
+ CONNECTION_TYPE_INFRA;
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+#if defined(PCIE)
+#if defined(PCIE8997) || defined(PCIE8897)
+ case HostCmd_CMD_PCIE_HOST_BUF_DETAILS:
+ ret = wlan_cmd_pcie_host_buf_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+#endif
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_cmd_subscribe_event(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_cmd_otp_user_data(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_HS_WAKEUP_REASON:
+ ret = wlan_cmd_hs_wakeup_reason(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_REJECT_ADDBA_REQ:
+ ret = wlan_cmd_reject_addba_req(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+ ret = wlan_cmd_packet_aggr_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#ifdef USB
+ case HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE:
+ ret = wlan_cmd_packet_aggr_over_host_interface(
+ pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+#ifdef RX_PACKET_COALESCE
+ case HostCmd_CMD_RX_PKT_COALESCE_CFG:
+ ret = wlan_cmd_rx_pkt_coalesce_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCMD_CONFIG_LOW_POWER_MODE:
+ ret = wlan_cmd_low_pwr_mode(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_DFS_REPEATER_MODE:
+ ret = wlan_cmd_dfs_repeater_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_COALESCE_CFG:
+ ret = wlan_cmd_coalesce_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_DS_GET_SENSOR_TEMP:
+ ret = wlan_cmd_get_sensor_temp(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_MIMO_SWITCH:
+ ret = wlan_cmd_802_11_mimo_switch(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_STA_CONFIGURE:
+ ret = wlan_cmd_sta_config(pmpriv, cmd_ptr, cmd_action,
+ pioctl_buf, pdata_buf);
+ break;
+
+ case HostCmd_CMD_INDEPENDENT_RESET_CFG:
+ ret = wlan_cmd_ind_rst_cfg(cmd_ptr, cmd_action, pdata_buf);
+ break;
+
+ case HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT:
+ ret = wlan_cmd_ps_inactivity_timeout(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_CHAN_REGION_CFG) + S_DS_GEN);
+ cmd_ptr->params.reg_cfg.action = wlan_cpu_to_le16(cmd_action);
+ break;
+ case HostCmd_CMD_AUTO_TX:
+ ret = wlan_cmd_auto_tx(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HOST_CMD_TX_RX_PKT_STATS:
+ ret = wlan_cmd_tx_rx_pkt_stats(pmpriv, cmd_ptr,
+ (pmlan_ioctl_req)pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_DYN_BW:
+ ret = wlan_cmd_config_dyn_bw(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_BOOT_SLEEP:
+ ret = wlan_cmd_boot_sleep(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_FW_DUMP_EVENT:
+ ret = wlan_cmd_fw_dump_event(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#if defined(DRV_EMBEDDED_SUPPLICANT)
+ case HostCmd_CMD_CRYPTO:
+ ret = wlan_cmd_crypto(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_11AX_CFG:
+ ret = wlan_cmd_11ax_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11AX_CMD:
+ ret = wlan_cmd_11ax_cmd(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_RANGE_EXT:
+ ret = wlan_cmd_range_ext(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TWT_CFG:
+ ret = wlan_cmd_twt_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG:
+ ret = wlan_cmd_rxabortcfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG_EXT:
+ ret = wlan_cmd_rxabortcfg_ext(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_ARB_CONFIG:
+ ret = wlan_cmd_arb_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_TX_AMPDU_PROT_MODE:
+ ret = wlan_cmd_tx_ampdu_prot_mode(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG:
+ ret = wlan_cmd_dot11mc_unassoc_ftm_cfg(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_RATE_ADAPT_CFG:
+ ret = wlan_cmd_rate_adapt_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_CCK_DESENSE_CFG:
+ ret = wlan_cmd_cck_desense_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CHANNEL_TRPC_CONFIG:
+ ret = wlan_cmd_get_chan_trpc_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_LOW_POWER_MODE_CFG:
+ ret = wlan_cmd_set_get_low_power_mode_cfg(
+ pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_MFG_COMMAND:
+ ret = wlan_cmd_mfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_sta_init_cmd(t_void *priv, t_u8 first_bss)
+{
+ pmlan_private pmpriv = (pmlan_private)priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+
+ ENTER();
+
+ if (!pmpriv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (first_bss == MTRUE) {
+ ret = wlan_adapter_init_cmd(pmpriv->adapter);
+ if (ret == MLAN_STATUS_FAILURE)
+ goto done;
+ }
+
+ /* get tx rate */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->data_rate = 0;
+
+ /* get tx power */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_TX_POWER,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, &amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+ amsdu_aggr_ctrl.enable = MLAN_ACT_ENABLE;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ (t_void *)&amsdu_aggr_ctrl);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* MAC Control must be the last command in init_fw */
+ /* set MAC Control */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /** set last_init_cmd */
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_MAC_CONTROL;
+
+ if (first_bss == MFALSE) {
+ /* Get MAC address */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmpriv->adapter->last_init_cmd = HostCmd_CMD_802_11_MAC_ADDRESS;
+ }
+
+ ret = MLAN_STATUS_PENDING;
+done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmdresp.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmdresp.c
new file mode 100644
index 000000000000..a7fee3788925
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_cmdresp.c
@@ -0,0 +1,2749 @@
+/** @file mlan_sta_cmdresp.c
+ *
+ * @brief This file contains the handling of command
+ * responses generated by firmware.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+ * Change log:
+ * 10/21/2008: initial version
+ ******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#include "mlan_meas.h"
+
+/********************************************************
+ * Local Variables
+ ********************************************************/
+
+/********************************************************
+ * Global Variables
+ ********************************************************/
+
+/********************************************************
+ * Local Functions
+ ********************************************************/
+
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static mlan_status wlan_process_cmdresp_error(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ pmlan_ioctl_req pscan_ioctl_req = MNULL;
+ mlan_callbacks *pcb = MNULL;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (resp->command != HostCmd_CMD_WMM_PARAM_CONFIG &&
+ resp->command != HostCmd_CMD_CHAN_REGION_CFG)
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
+
+ switch (resp->command) {
+ case HostCmd_CMD_802_11_PS_MODE_ENH: {
+ HostCmd_DS_802_11_PS_MODE_ENH *pm = &resp->params.psmode_enh;
+ PRINTM(MERROR,
+ "PS_MODE_ENH command failed: result=0x%x action=0x%X\n",
+ resp->result, wlan_le16_to_cpu(pm->action));
+ /*
+ * We do not re-try enter-ps command in ad-hoc mode.
+ */
+ if (wlan_le16_to_cpu(pm->action) == EN_AUTO_PS &&
+ (wlan_le16_to_cpu(pm->params.auto_ps.ps_bitmap) &
+ BITMAP_STA_PS) &&
+ pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ } break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ case HostCmd_CMD_802_11_SCAN:
+ /* Cancel all pending scan command */
+ wlan_flush_scan_queue(pmadapter);
+
+ pcb = (pmlan_callbacks)&pmadapter->callbacks;
+
+ wlan_request_cmd_lock(pmadapter);
+ pmadapter->scan_processing = MFALSE;
+ pscan_ioctl_req = pmadapter->pscan_ioctl_req;
+ pmadapter->pscan_ioctl_req = MNULL;
+ /* Need to indicate IOCTL complete */
+ if (pscan_ioctl_req) {
+ pscan_ioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
+ /* Indicate ioctl complete */
+ pcb->moal_ioctl_complete(
+ pmadapter->pmoal_handle,
+ (pmlan_ioctl_req)pscan_ioctl_req,
+ MLAN_STATUS_FAILURE);
+ }
+ wlan_release_cmd_lock(pmadapter);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
+ break;
+
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++)
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.enable = MFALSE;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable =
+ MFALSE;
+ }
+#endif
+ break;
+#ifdef USB
+ case HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE:
+ pmadapter->pcard_usb->fw_usb_aggr = MFALSE;
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++)
+ pmadapter->pcard_usb->usb_tx_aggr[i].aggr_ctrl.enable =
+ MFALSE;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable = MFALSE;
+ break;
+#endif
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ break;
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ pmadapter->pcard_sd->sdio_rx_aggr_enable = MFALSE;
+ PRINTM(MMSG, "FW don't support SDIO single port rx aggr\n");
+ break;
+#endif
+
+ case HostCmd_CMD_MGMT_IE_LIST: {
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list =
+ &(resp->params.mgmt_ie_list);
+ t_u16 resp_len = 0, travel_len = 0, index;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ custom_ie *cptr;
+
+ if (wlan_le16_to_cpu(pmgmt_ie_list->action) ==
+ HostCmd_ACT_GEN_GET)
+ break;
+
+ cust_ie = (mlan_ds_misc_custom_ie *)&pmgmt_ie_list->ds_mgmt_ie;
+ if (cust_ie) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len =
+ wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0]
+ .ie_index = wlan_cpu_to_le16(
+ cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr = (custom_ie *)(((t_u8 *)cust_ie
+ ->ie_data_list) +
+ travel_len);
+ index = cptr->ie_index =
+ wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_le16_to_cpu(
+ cptr->mgmt_subtype_mask);
+ cptr->ie_length =
+ wlan_le16_to_cpu(cptr->ie_length);
+ travel_len += cptr->ie_length +
+ sizeof(custom_ie) - MAX_IE_SIZE;
+ resp_len -= cptr->ie_length +
+ sizeof(custom_ie) - MAX_IE_SIZE;
+ if ((pmpriv->mgmt_ie[index].mgmt_subtype_mask ==
+ cptr->mgmt_subtype_mask) &&
+ (pmpriv->mgmt_ie[index].ie_length ==
+ cptr->ie_length) &&
+ !memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index].ie_buffer,
+ cptr->ie_buffer, cptr->ie_length)) {
+ PRINTM(MERROR,
+ "set custom ie fail, remove ie index :%d\n",
+ index);
+ memset(pmadapter,
+ &pmpriv->mgmt_ie[index], 0,
+ sizeof(custom_ie));
+ }
+ }
+ }
+ } break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = MLAN_STATUS_SUCCESS;
+ PRINTM(MCMND, "FW don't support chan region cfg command!\n");
+ break;
+#if defined(DRV_EMBEDDED_SUPPLICANT)
+ case HostCmd_CMD_CRYPTO:
+ PRINTM(MCMND, "crypto cmd result=0x%x!\n", resp->result);
+ ret = wlan_ret_crypto(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ default:
+ break;
+ }
+ /*
+ * Handling errors here
+ */
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of RSSI info
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_rssi_info_ext(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_EXT *prssi_info_rsp =
+ &resp->params.rssi_info_ext;
+ mlan_ds_get_signal *signal = MNULL;
+ mlan_ds_get_info *info = MNULL;
+ MrvlIEtypes_RSSI_EXT_t *signal_info_tlv = MNULL;
+ t_u16 tlv_left_len = 0, tlv_num = 0;
+ t_u16 tlv_id, tlv_len;
+
+ ENTER();
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_buf != MNULL) {
+ info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ signal_info_tlv =
+ (MrvlIEtypes_RSSI_EXT_t *)(prssi_info_rsp->tlv_buf);
+ tlv_left_len =
+ resp->size -
+ (sizeof(HostCmd_DS_802_11_RSSI_INFO_EXT) + S_DS_GEN);
+
+ while (tlv_left_len >= sizeof(MrvlIEtypes_RSSI_EXT_t)) {
+ tlv_id = wlan_le16_to_cpu(signal_info_tlv->header.type);
+ tlv_len = wlan_le16_to_cpu(signal_info_tlv->header.len);
+ if ((tlv_id != TLV_TYPE_RSSI_INFO) ||
+ (tlv_len != sizeof(MrvlIEtypes_RSSI_EXT_t) -
+ sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Invalid RSSI INFO TLV, type=%d, len=%d\n",
+ tlv_id, tlv_len);
+ break;
+ }
+
+ signal = (mlan_ds_get_signal *)&info->param
+ .signal_ext[tlv_num];
+ /* PATH ID */
+ signal->selector =
+ wlan_le16_to_cpu(signal_info_tlv->path_id);
+
+ /* RSSI */
+ signal->bcn_rssi_last = wlan_le16_to_cpu(
+ signal_info_tlv->bcn_rssi_last);
+ signal->bcn_rssi_avg =
+ wlan_le16_to_cpu(signal_info_tlv->bcn_rssi_avg);
+ signal->data_rssi_last = wlan_le16_to_cpu(
+ signal_info_tlv->data_rssi_last);
+ signal->data_rssi_avg = wlan_le16_to_cpu(
+ signal_info_tlv->data_rssi_avg);
+
+ /* SNR */
+ signal->bcn_snr_last = CAL_SNR(
+ wlan_le16_to_cpu(
+ signal_info_tlv->bcn_rssi_last),
+ wlan_le16_to_cpu(signal_info_tlv->bcn_nf_last));
+ signal->bcn_snr_avg = CAL_SNR(
+ wlan_le16_to_cpu(signal_info_tlv->bcn_rssi_avg),
+ wlan_le16_to_cpu(signal_info_tlv->bcn_nf_avg));
+ signal->data_snr_last = CAL_SNR(
+ wlan_le16_to_cpu(
+ signal_info_tlv->data_rssi_last),
+ wlan_le16_to_cpu(
+ signal_info_tlv->data_nf_last));
+ signal->data_snr_avg = CAL_SNR(
+ wlan_le16_to_cpu(
+ signal_info_tlv->data_rssi_avg),
+ wlan_le16_to_cpu(signal_info_tlv->data_nf_avg));
+
+ /* NF */
+ signal->bcn_nf_last =
+ wlan_le16_to_cpu(signal_info_tlv->bcn_nf_last);
+ signal->bcn_nf_avg =
+ wlan_le16_to_cpu(signal_info_tlv->bcn_nf_avg);
+ signal->data_nf_last =
+ wlan_le16_to_cpu(signal_info_tlv->data_nf_last);
+ signal->data_nf_avg =
+ wlan_le16_to_cpu(signal_info_tlv->data_nf_avg);
+
+ tlv_left_len -= sizeof(MrvlIEtypes_RSSI_EXT_t);
+ signal_info_tlv++;
+ tlv_num++;
+ if (tlv_num > MAX_PATH_NUM)
+ break;
+ }
+
+ pioctl_buf->data_read_written =
+ tlv_num * sizeof(mlan_ds_get_signal) + sizeof(t_u32);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of RSSI info
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_rssi_info(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RSSI_INFO_RSP *prssi_info_rsp =
+ &resp->params.rssi_info_rsp;
+ mlan_ds_get_info *pget_info = MNULL;
+ BSSDescriptor_t *pbss_desc;
+ t_s32 tbl_idx = 0;
+
+ ENTER();
+
+ pmpriv->data_rssi_last =
+ wlan_le16_to_cpu(prssi_info_rsp->data_rssi_last);
+ pmpriv->data_nf_last = wlan_le16_to_cpu(prssi_info_rsp->data_nf_last);
+
+ pmpriv->data_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->data_rssi_avg);
+ pmpriv->data_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->data_nf_avg);
+
+ pmpriv->bcn_rssi_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_last);
+ pmpriv->bcn_nf_last = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_last);
+
+ pmpriv->bcn_rssi_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_rssi_avg);
+ pmpriv->bcn_nf_avg = wlan_le16_to_cpu(prssi_info_rsp->bcn_nf_avg);
+
+ /* Get current BSS info */
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ pbss_desc->rssi = -pmpriv->bcn_rssi_avg;
+ tbl_idx = wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
+ pbss_desc->mac_address,
+ pmpriv->bss_mode);
+ if (tbl_idx >= 0) {
+ pbss_desc = &pmpriv->adapter->pscan_table[tbl_idx];
+ pbss_desc->rssi = -pmpriv->bcn_rssi_avg;
+ }
+
+ /* Need to indicate IOCTL complete */
+ if (pioctl_buf != MNULL) {
+ pget_info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+
+ memset(pmpriv->adapter, &pget_info->param.signal, 0,
+ sizeof(mlan_ds_get_signal));
+
+ pget_info->param.signal.selector = ALL_RSSI_INFO_MASK;
+
+ /* RSSI */
+ pget_info->param.signal.bcn_rssi_last = pmpriv->bcn_rssi_last;
+ pget_info->param.signal.bcn_rssi_avg = pmpriv->bcn_rssi_avg;
+ pget_info->param.signal.data_rssi_last = pmpriv->data_rssi_last;
+ pget_info->param.signal.data_rssi_avg = pmpriv->data_rssi_avg;
+
+ /* SNR */
+ pget_info->param.signal.bcn_snr_last =
+ CAL_SNR(pmpriv->bcn_rssi_last, pmpriv->bcn_nf_last);
+ pget_info->param.signal.bcn_snr_avg =
+ CAL_SNR(pmpriv->bcn_rssi_avg, pmpriv->bcn_nf_avg);
+ pget_info->param.signal.data_snr_last =
+ CAL_SNR(pmpriv->data_rssi_last, pmpriv->data_nf_last);
+ pget_info->param.signal.data_snr_avg =
+ CAL_SNR(pmpriv->data_rssi_avg, pmpriv->data_nf_avg);
+
+ /* NF */
+ pget_info->param.signal.bcn_nf_last = pmpriv->bcn_nf_last;
+ pget_info->param.signal.bcn_nf_avg = pmpriv->bcn_nf_avg;
+ pget_info->param.signal.data_nf_last = pmpriv->data_nf_last;
+ pget_info->param.signal.data_nf_avg = pmpriv->data_nf_avg;
+
+ pioctl_buf->data_read_written = sizeof(mlan_ds_get_info);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_snmp_mib(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psmib = &resp->params.smib;
+ t_u16 oid = wlan_le16_to_cpu(psmib->oid);
+ t_u16 query_type = wlan_le16_to_cpu(psmib->query_type);
+ t_u32 ul_temp;
+ mlan_ds_snmp_mib *mib = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf)
+ mib = (mlan_ds_snmp_mib *)pioctl_buf->pbuf;
+
+ PRINTM(MINFO, "SNMP_RESP: value of the oid = 0x%x, query_type=0x%x\n",
+ oid, query_type);
+ PRINTM(MINFO, "SNMP_RESP: Buf size = 0x%x\n",
+ wlan_le16_to_cpu(psmib->buf_size));
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ switch (oid) {
+ case DtimPeriod_i:
+ ul_temp = psmib->value[0];
+ PRINTM(MINFO, "SNMP_RESP: DTIM Period =%u\n", ul_temp);
+ if (mib)
+ mib->param.dtim_period = ul_temp;
+ break;
+ case FragThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: FragThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.frag_threshold = ul_temp;
+ break;
+
+ case RtsThresh_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ if (mib)
+ mib->param.rts_threshold = ul_temp;
+ break;
+
+ case ShortRetryLim_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ if (mib)
+ mib->param.retry_count = ul_temp;
+ break;
+ case WwsMode_i:
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: WWSCfg =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *)pioctl_buf->pbuf)
+ ->param.wws_cfg = ul_temp;
+ break;
+ case Thermal_i:
+ ul_temp = wlan_le32_to_cpu(*((t_u32 *)(psmib->value)));
+ PRINTM(MINFO, "SNMP_RESP: Thermal =%u\n", ul_temp);
+ if (pioctl_buf)
+ ((mlan_ds_misc_cfg *)pioctl_buf->pbuf)
+ ->param.thermal = ul_temp;
+ break;
+ case NullPktPeriod_i:
+ ul_temp = psmib->value[0];
+ PRINTM(MINFO, "SNMP_RESP: Auto NULL Pkt Period =%u\n",
+ ul_temp);
+ break;
+ default:
+ break;
+ }
+ } else { /* (query_type == HostCmd_ACT_GEN_SET) */
+ /* Update state for 11d */
+ if (oid == Dot11D_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = ul_temp;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = ul_temp;
+ }
+ /* Update state for 11h */
+ if (oid == Dot11H_i) {
+ ul_temp = wlan_le16_to_cpu(*((t_u16 *)(psmib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active =
+ (ul_temp & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active =
+ (ul_temp & MASTER_RADAR_DET_MASK) ? MTRUE :
+ MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active =
+ (ul_temp & SLAVE_RADAR_DET_MASK) ? MTRUE :
+ MFALSE;
+ }
+ }
+
+ if (pioctl_buf) {
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written = sizeof(mlan_ds_snmp_mib);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_log
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_get_log(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_GET_LOG *pget_log =
+ (HostCmd_DS_802_11_GET_LOG *)&resp->params.get_log;
+ mlan_ds_get_info *pget_info = MNULL;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pget_info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ pget_info->param.stats.mcast_tx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_tx_frame);
+ pget_info->param.stats.failed =
+ wlan_le32_to_cpu(pget_log->failed);
+ pget_info->param.stats.retry =
+ wlan_le32_to_cpu(pget_log->retry);
+ pget_info->param.stats.multi_retry =
+ wlan_le32_to_cpu(pget_log->multiretry);
+ pget_info->param.stats.frame_dup =
+ wlan_le32_to_cpu(pget_log->frame_dup);
+ pget_info->param.stats.rts_success =
+ wlan_le32_to_cpu(pget_log->rts_success);
+ pget_info->param.stats.rts_failure =
+ wlan_le32_to_cpu(pget_log->rts_failure);
+ pget_info->param.stats.ack_failure =
+ wlan_le32_to_cpu(pget_log->ack_failure);
+ pget_info->param.stats.rx_frag =
+ wlan_le32_to_cpu(pget_log->rx_frag);
+ pget_info->param.stats.mcast_rx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_rx_frame);
+ pget_info->param.stats.fcs_error =
+ wlan_le32_to_cpu(pget_log->fcs_error);
+ pget_info->param.stats.tx_frame =
+ wlan_le32_to_cpu(pget_log->tx_frame);
+ pget_info->param.stats.wep_icv_error[0] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[0]);
+ pget_info->param.stats.wep_icv_error[1] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[1]);
+ pget_info->param.stats.wep_icv_error[2] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[2]);
+ pget_info->param.stats.wep_icv_error[3] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[3]);
+ pget_info->param.stats.bcn_rcv_cnt =
+ wlan_le32_to_cpu(pget_log->bcn_rcv_cnt);
+ pget_info->param.stats.bcn_miss_cnt =
+ wlan_le32_to_cpu(pget_log->bcn_miss_cnt);
+ pget_info->param.stats.amsdu_rx_cnt = pmpriv->amsdu_rx_cnt;
+ pget_info->param.stats.msdu_in_rx_amsdu_cnt =
+ pmpriv->msdu_in_rx_amsdu_cnt;
+ pget_info->param.stats.amsdu_tx_cnt = pmpriv->amsdu_tx_cnt;
+ pget_info->param.stats.msdu_in_tx_amsdu_cnt =
+ pmpriv->msdu_in_tx_amsdu_cnt;
+ pget_info->param.stats.rx_stuck_issue_cnt[0] =
+ wlan_le32_to_cpu(pget_log->rx_stuck_issue_cnt[0]);
+ pget_info->param.stats.rx_stuck_issue_cnt[1] =
+ wlan_le32_to_cpu(pget_log->rx_stuck_issue_cnt[1]);
+ pget_info->param.stats.rx_stuck_recovery_cnt =
+ wlan_le32_to_cpu(pget_log->rx_stuck_recovery_cnt);
+ pget_info->param.stats.rx_stuck_tsf[0] =
+ wlan_le64_to_cpu(pget_log->rx_stuck_tsf[0]);
+ pget_info->param.stats.rx_stuck_tsf[1] =
+ wlan_le64_to_cpu(pget_log->rx_stuck_tsf[1]);
+ pget_info->param.stats.tx_watchdog_recovery_cnt =
+ wlan_le32_to_cpu(pget_log->tx_watchdog_recovery_cnt);
+ pget_info->param.stats.tx_watchdog_tsf[0] =
+ wlan_le64_to_cpu(pget_log->tx_watchdog_tsf[0]);
+ pget_info->param.stats.tx_watchdog_tsf[1] =
+ wlan_le64_to_cpu(pget_log->tx_watchdog_tsf[1]);
+ pget_info->param.stats.channel_switch_ann_sent =
+ wlan_le32_to_cpu(pget_log->channel_switch_ann_sent);
+ pget_info->param.stats.channel_switch_state =
+ wlan_le32_to_cpu(pget_log->channel_switch_state);
+ pget_info->param.stats.reg_class =
+ wlan_le32_to_cpu(pget_log->reg_class);
+ pget_info->param.stats.channel_number =
+ wlan_le32_to_cpu(pget_log->channel_number);
+ pget_info->param.stats.channel_switch_mode =
+ wlan_le32_to_cpu(pget_log->channel_switch_mode);
+ if (pmpriv->adapter->getlog_enable) {
+ pget_info->param.stats.tx_frag_cnt =
+ wlan_le32_to_cpu(pget_log->tx_frag_cnt);
+ for (i = 0; i < 8; i++) {
+ pget_info->param.stats.qos_tx_frag_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_tx_frag_cnt[i]);
+ pget_info->param.stats.qos_failed_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_failed_cnt[i]);
+ pget_info->param.stats.qos_retry_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_retry_cnt[i]);
+ pget_info->param.stats.qos_multi_retry_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_multi_retry_cnt[i]);
+ pget_info->param.stats.qos_frm_dup_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_frm_dup_cnt[i]);
+ pget_info->param.stats.qos_rts_suc_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rts_suc_cnt[i]);
+ pget_info->param.stats.qos_rts_failure_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rts_failure_cnt[i]);
+ pget_info->param.stats.qos_ack_failure_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_ack_failure_cnt[i]);
+ pget_info->param.stats.qos_rx_frag_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rx_frag_cnt[i]);
+ pget_info->param.stats.qos_tx_frm_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_tx_frm_cnt[i]);
+ pget_info->param.stats.qos_discarded_frm_cnt
+ [i] = wlan_le32_to_cpu(
+ pget_log->qos_discarded_frm_cnt[i]);
+ pget_info->param.stats.qos_mpdus_rx_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_mpdus_rx_cnt[i]);
+ pget_info->param.stats.qos_retries_rx_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_retries_rx_cnt[i]);
+ }
+ pget_info->param.stats.cmacicv_errors =
+ wlan_le32_to_cpu(pget_log->cmacicv_errors);
+ pget_info->param.stats.cmac_replays =
+ wlan_le32_to_cpu(pget_log->cmac_replays);
+ pget_info->param.stats.mgmt_ccmp_replays =
+ wlan_le32_to_cpu(pget_log->mgmt_ccmp_replays);
+ pget_info->param.stats.tkipicv_errors =
+ wlan_le32_to_cpu(pget_log->tkipicv_errors);
+ pget_info->param.stats.tkip_replays =
+ wlan_le32_to_cpu(pget_log->tkip_replays);
+ pget_info->param.stats.ccmp_decrypt_errors =
+ wlan_le32_to_cpu(pget_log->ccmp_decrypt_errors);
+ pget_info->param.stats.ccmp_replays =
+ wlan_le32_to_cpu(pget_log->ccmp_replays);
+ pget_info->param.stats.tx_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->tx_amsdu_cnt);
+ pget_info->param.stats.failed_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->failed_amsdu_cnt);
+ pget_info->param.stats.retry_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->retry_amsdu_cnt);
+ pget_info->param.stats.multi_retry_amsdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->multi_retry_amsdu_cnt);
+ pget_info->param.stats.tx_octets_in_amsdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->tx_octets_in_amsdu_cnt);
+ pget_info->param.stats.amsdu_ack_failure_cnt =
+ wlan_le32_to_cpu(
+ pget_log->amsdu_ack_failure_cnt);
+ pget_info->param.stats.rx_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->rx_amsdu_cnt);
+ pget_info->param.stats.rx_octets_in_amsdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->rx_octets_in_amsdu_cnt);
+ pget_info->param.stats.tx_ampdu_cnt =
+ wlan_le32_to_cpu(pget_log->tx_ampdu_cnt);
+ pget_info->param.stats.tx_mpdus_in_ampdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->tx_mpdus_in_ampdu_cnt);
+ pget_info->param.stats.tx_octets_in_ampdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->tx_octets_in_ampdu_cnt);
+ pget_info->param.stats.ampdu_rx_cnt =
+ wlan_le32_to_cpu(pget_log->ampdu_rx_cnt);
+ pget_info->param.stats.mpdu_in_rx_ampdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->mpdu_in_rx_ampdu_cnt);
+ pget_info->param.stats.rx_octets_in_ampdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->rx_octets_in_ampdu_cnt);
+ pget_info->param.stats.ampdu_delimiter_crc_error_cnt =
+ wlan_le32_to_cpu(
+ pget_log->ampdu_delimiter_crc_error_cnt);
+
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_get_info);
+ } else
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_get_stats_org) +
+ sizeof(pget_info->sub_command);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Get power level and rate index
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pdata_buf Pointer to the data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_get_power_level(pmlan_private pmpriv, void *pdata_buf)
+{
+ t_u16 length = 0;
+ t_s8 max_power = -1, min_power = -1;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+
+ ENTER();
+
+ if (pdata_buf) {
+ ppg_tlv = (MrvlTypes_Power_Group_t
+ *)((t_u8 *)pdata_buf +
+ sizeof(HostCmd_DS_TXPWR_CFG));
+ pg = (Power_Group_t *)((t_u8 *)ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+ length = ppg_tlv->length;
+ if (length > 0) {
+ max_power = pg->power_max;
+ min_power = pg->power_min;
+ length -= sizeof(Power_Group_t);
+ }
+ while (length) {
+ pg++;
+ if (max_power < pg->power_max)
+ max_power = pg->power_max;
+ if (min_power > pg->power_min)
+ min_power = pg->power_min;
+ length -= sizeof(Power_Group_t);
+ }
+ if (ppg_tlv->length > 0) {
+ pmpriv->min_tx_power_level = min_power;
+ pmpriv->max_tx_power_level = max_power;
+ }
+ } else {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of tx_power_cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_tx_power_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_TXPWR_CFG *ptxp_cfg = &resp->params.txp_cfg;
+ MrvlTypes_Power_Group_t *ppg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ t_u16 action = wlan_le16_to_cpu(ptxp_cfg->action);
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_power_group *pwr_grp = MNULL;
+ t_u8 i = 0;
+
+ ENTER();
+
+ ppg_tlv = (MrvlTypes_Power_Group_t *)(ptxp_cfg->tlv_buf);
+ pg = (Power_Group_t *)((t_u8 *)ppg_tlv +
+ sizeof(MrvlTypes_Power_Group_t));
+
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ ppg_tlv->length = wlan_le16_to_cpu(ppg_tlv->length);
+ if (pmpriv->adapter->hw_status ==
+ WlanHardwareStatusInitializing)
+ wlan_get_power_level(pmpriv, ptxp_cfg);
+ pmpriv->tx_power_level = (t_s16)pg->power_min;
+ break;
+
+ case HostCmd_ACT_GEN_SET:
+ if (wlan_le32_to_cpu(ptxp_cfg->mode)) {
+ if (pg->power_max == pg->power_min)
+ pmpriv->tx_power_level = (t_s16)pg->power_min;
+ }
+ break;
+
+ default:
+ PRINTM(MERROR, "CMD_RESP: unknown command action %d\n", action);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level, pmpriv->max_tx_power_level,
+ pmpriv->min_tx_power_level);
+
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *)pioctl_buf->pbuf;
+ if (action == HostCmd_ACT_GEN_GET) {
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_power_cfg_t) +
+ MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level =
+ pmpriv->tx_power_level;
+ if (wlan_le32_to_cpu(ptxp_cfg->mode))
+ power->param.power_cfg.is_power_auto =
+ 0;
+ else
+ power->param.power_cfg.is_power_auto =
+ 1;
+ } else {
+ power->param.power_ext.num_pwr_grp = 0;
+ i = 0;
+ while ((ppg_tlv->length) &&
+ (i < MAX_POWER_GROUP)) {
+ pwr_grp = (mlan_power_group *)&power
+ ->param.power_ext
+ .power_group[i];
+ pwr_grp->first_rate_ind = 0;
+ pwr_grp->last_rate_ind = 0;
+ if (pg->modulation_class ==
+ MOD_CLASS_HR_DSSS) {
+ pwr_grp->rate_format =
+ MLAN_RATE_FORMAT_LG;
+ pwr_grp->first_rate_ind =
+ pg->first_rate_code;
+ pwr_grp->last_rate_ind =
+ pg->last_rate_code;
+ } else if (pg->modulation_class ==
+ MOD_CLASS_OFDM) {
+ pwr_grp->rate_format =
+ MLAN_RATE_FORMAT_LG;
+ pwr_grp->first_rate_ind =
+ MLAN_RATE_INDEX_OFDM0 +
+ pg->first_rate_code;
+ pwr_grp->last_rate_ind =
+ MLAN_RATE_INDEX_OFDM0 +
+ pg->last_rate_code;
+ } else if (pg->modulation_class ==
+ MOD_CLASS_HT) {
+ pwr_grp->rate_format =
+ MLAN_RATE_FORMAT_HT;
+ pwr_grp->first_rate_ind =
+ pg->first_rate_code;
+ pwr_grp->last_rate_ind =
+ pg->last_rate_code;
+ } else if (pg->modulation_class ==
+ MOD_CLASS_VHT) {
+ pwr_grp->rate_format =
+ MLAN_RATE_FORMAT_VHT;
+ pwr_grp->first_rate_ind =
+ (pg->first_rate_code) &
+ 0xF;
+ pwr_grp->last_rate_ind =
+ (pg->last_rate_code) &
+ 0xF;
+ // pwr_grp->nss = 1 +
+ // (pg->first_rate_code >> 4);
+ pwr_grp->nss =
+ 1 +
+ (pg->last_rate_code >>
+ 4);
+ }
+ pwr_grp->bandwidth = pg->ht_bandwidth;
+ pwr_grp->power_min = pg->power_min;
+ pwr_grp->power_max = pg->power_max;
+ pwr_grp->power_step = pg->power_step;
+ ppg_tlv->length -=
+ sizeof(Power_Group_t);
+ pg++;
+ i++;
+ }
+ power->param.power_ext.num_pwr_grp = i;
+ pioctl_buf->data_read_written =
+ sizeof(mlan_power_cfg_ext) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_tx_power
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_rf_tx_power(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
+ t_u16 action = wlan_le16_to_cpu(rtp->action);
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ pmpriv->tx_power_level = wlan_le16_to_cpu(rtp->current_level);
+
+ if (action == HostCmd_ACT_GEN_GET) {
+ pmpriv->max_tx_power_level = rtp->max_power;
+ pmpriv->min_tx_power_level = rtp->min_power;
+ if (pioctl_buf) {
+ power = (mlan_ds_power_cfg *)pioctl_buf->pbuf;
+ if (power->sub_command == MLAN_OID_POWER_CFG) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_power_cfg_t) +
+ MLAN_SUB_COMMAND_SIZE;
+ power->param.power_cfg.power_level =
+ pmpriv->tx_power_level;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+ pmpriv->tx_power_level, pmpriv->max_tx_power_level,
+ pmpriv->min_tx_power_level);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_period
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_sleep_period(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PERIOD *pcmd_sleep_pd = &resp->params.sleep_pd;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 sleep_pd = 0;
+
+ ENTER();
+
+ sleep_pd = wlan_le16_to_cpu(pcmd_sleep_pd->sleep_pd);
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf;
+ pm_cfg->param.sleep_period = (t_u32)sleep_pd;
+ pioctl_buf->data_read_written =
+ sizeof(pm_cfg->param.sleep_period) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
+ pmpriv->adapter->sleep_period.period = sleep_pd;
+
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ if ((pmpriv->adapter->sleep_period.period != 0) &&
+ (pmpriv->adapter->sleep_period.period !=
+ SLEEP_PERIOD_RESERVED_FF)) {
+ pmpriv->adapter->gen_null_pkt = MTRUE;
+ } else {
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+ pmpriv->adapter->gen_null_pkt = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sleep_params
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_sleep_params(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_SLEEP_PARAMS *presp_sp = &resp->params.sleep_param;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ mlan_ds_sleep_params *psp = MNULL;
+ sleep_params_t *psleep_params = &pmpriv->adapter->sleep_params;
+
+ ENTER();
+
+ psleep_params->sp_reserved = wlan_le16_to_cpu(presp_sp->reserved);
+ psleep_params->sp_error = wlan_le16_to_cpu(presp_sp->error);
+ psleep_params->sp_offset = wlan_le16_to_cpu(presp_sp->offset);
+ psleep_params->sp_stable_time = wlan_le16_to_cpu(presp_sp->stable_time);
+ psleep_params->sp_cal_control = presp_sp->cal_control;
+ psleep_params->sp_ext_sleep_clk = presp_sp->external_sleep_clk;
+
+ if (pioctl_buf) {
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf;
+ psp = (mlan_ds_sleep_params *)&pm_cfg->param.sleep_params;
+
+ psp->error = (t_u32)psleep_params->sp_error;
+ psp->offset = (t_u32)psleep_params->sp_offset;
+ psp->stable_time = (t_u32)psleep_params->sp_stable_time;
+ psp->cal_control = (t_u32)psleep_params->sp_cal_control;
+ psp->ext_sleep_clk = (t_u32)psleep_params->sp_ext_sleep_clk;
+ psp->reserved = (t_u32)psleep_params->sp_reserved;
+
+ pioctl_buf->data_read_written =
+ sizeof(pm_cfg->param.sleep_params) +
+ MLAN_SUB_COMMAND_SIZE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of multicast_address
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_mac_multicast_adr(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ ENTER();
+ if (pioctl_buf) {
+ pioctl_buf->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of deauthenticate
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_deauthenticate(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u8 event_buf[32];
+ mlan_event *pevent = (mlan_event *)event_buf;
+ ENTER();
+
+ pmadapter->dbg.num_cmd_deauth++;
+
+ if (!memcmp(pmadapter, resp->params.deauth.mac_addr,
+ &pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(resp->params.deauth.mac_addr))) {
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ }
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *)pmpriv);
+ memset(pmadapter, event_buf, 0, sizeof(event_buf));
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER;
+ pevent->event_len = sizeof(resp->params.deauth.reason_code);
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
+ &resp->params.deauth.reason_code, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER, pevent);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ad_hoc_stop
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_ad_hoc_stop(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ ENTER();
+
+ wlan_reset_connect_state(pmpriv, MTRUE);
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *)pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of key_material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_key_material(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey = &resp->params.key_material;
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 zero_kek[MLAN_KEK_LEN] = {0};
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pkey->action) == HostCmd_ACT_GEN_SET) {
+ if ((wlan_le16_to_cpu(pkey->key_param_set.key_info) &
+ KEY_INFO_TKIP_MCAST)) {
+ PRINTM(MINFO, "key: GTK is set\n");
+ pmpriv->wpa_is_gtk_set = MTRUE;
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ /* GTK is set, open the port */
+ PRINTM(MINFO,
+ "GTK_SET: Open port: WPA/WPA2 h-supp mode\n");
+ pmpriv->port_open = MTRUE;
+ }
+ if (memcmp(pmpriv->adapter, pmpriv->gtk_rekey.kek,
+ zero_kek, sizeof(zero_kek)) != 0) {
+ wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->gtk_rekey);
+ memset(pmpriv->adapter, &pmpriv->gtk_rekey, 0,
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+ }
+ pmpriv->adapter->scan_block = MFALSE;
+ }
+ } else if (wlan_le16_to_cpu(pkey->action) == HostCmd_ACT_GEN_GET) {
+ if (pioctl_buf && (wlan_le16_to_cpu(pkey->key_param_set.type) ==
+ TLV_TYPE_KEY_PARAM_V2)) {
+ sec = (mlan_ds_sec_cfg *)pioctl_buf->pbuf;
+ memcpy_ext(pmpriv->adapter,
+ sec->param.encrypt_key.mac_addr,
+ pkey->key_param_set.mac_addr,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(sec->param.encrypt_key.mac_addr));
+ sec->param.encrypt_key.key_index =
+ pkey->key_param_set.key_idx;
+ PRINTM(MIOCTL,
+ "key_type=%d, key_index=%d, key_info=0x%x " MACSTR
+ "\n",
+ pkey->key_param_set.key_type,
+ pkey->key_param_set.key_idx,
+ wlan_le16_to_cpu(pkey->key_param_set.key_info),
+ MAC2STR(sec->param.encrypt_key.mac_addr));
+ switch (pkey->key_param_set.key_type) {
+ case KEY_TYPE_ID_WAPI:
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(
+ pkey->key_param_set.key_params
+ .wapi.key_len);
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key_params.wapi.key,
+ sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key
+ .key_material));
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.pn,
+ pkey->key_param_set.key_params.wapi.pn,
+ PN_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ break;
+ case KEY_TYPE_ID_TKIP:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(
+ pkey->key_param_set.key_params
+ .tkip.key_len);
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key_params.tkip.key,
+ sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key
+ .key_material));
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.pn,
+ pkey->key_param_set.key_params.tkip.pn,
+ WPA_PN_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ break;
+ case KEY_TYPE_ID_AES:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(
+ pkey->key_param_set.key_params
+ .aes.key_len);
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key_params.aes.key,
+ sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key
+ .key_material));
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.pn,
+ pkey->key_param_set.key_params.aes.pn,
+ WPA_PN_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ break;
+ case KEY_TYPE_ID_AES_CMAC:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(
+ pkey->key_param_set.key_params
+ .cmac_aes.key_len);
+ memcpy_ext(pmpriv->adapter,
+ sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key_params
+ .cmac_aes.key,
+ sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key
+ .key_material));
+ memcpy_ext(pmpriv->adapter,
+ sec->param.encrypt_key.pn,
+ pkey->key_param_set.key_params
+ .cmac_aes.ipn,
+ IGTK_PN_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ break;
+ case KEY_TYPE_ID_WEP:
+ sec->param.encrypt_key.key_len =
+ wlan_le16_to_cpu(
+ pkey->key_param_set.key_params
+ .wep.key_len);
+ memcpy_ext(
+ pmpriv->adapter,
+ sec->param.encrypt_key.key_material,
+ pkey->key_param_set.key_params.wep.key,
+ sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key
+ .key_material));
+ break;
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the supplicant profile response
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_802_11_supplicant_profile(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_SUPPLICANT_PROFILE *psup_profile =
+ &resp->params.esupplicant_profile;
+ MrvlIEtypesHeader_t *head;
+ MrvlIEtypes_EncrProto_t *encr_proto_tlv = MNULL;
+ MrvlIEtypes_Cipher_t *pcipher_tlv = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ t_u8 *tlv;
+ int len;
+
+ ENTER();
+
+ len = resp->size - S_DS_GEN - sizeof(t_u16);
+ tlv = psup_profile->tlv_buf;
+ if (pioctl_buf) {
+ sec = (mlan_ds_sec_cfg *)pioctl_buf->pbuf;
+ while (len > 0) {
+ head = (MrvlIEtypesHeader_t *)tlv;
+ head->type = wlan_le16_to_cpu(head->type);
+ head->len = wlan_le16_to_cpu(head->len);
+ switch (head->type) {
+ case TLV_TYPE_ENCRYPTION_PROTO:
+ encr_proto_tlv =
+ (MrvlIEtypes_EncrProto_t *)head;
+ sec->param.esupp_mode.rsn_mode =
+ wlan_le16_to_cpu(
+ encr_proto_tlv->rsn_mode);
+ PRINTM(MINFO, "rsn_mode=0x%x\n",
+ sec->param.esupp_mode.rsn_mode);
+ break;
+ case TLV_TYPE_CIPHER:
+ pcipher_tlv = (MrvlIEtypes_Cipher_t *)head;
+ sec->param.esupp_mode.act_paircipher =
+ pcipher_tlv->pair_cipher;
+ sec->param.esupp_mode.act_groupcipher =
+ pcipher_tlv->group_cipher;
+ PRINTM(MINFO,
+ "paircipher=0x%x, groupcipher=0x%x\n",
+ sec->param.esupp_mode.act_paircipher,
+ sec->param.esupp_mode.act_groupcipher);
+ break;
+ }
+ len -= (head->len - sizeof(MrvlIEtypesHeader_t));
+ tlv = tlv + (head->len + sizeof(MrvlIEtypesHeader_t));
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of rf_channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_802_11_rf_channel(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_RF_CHANNEL *prf_channel = &resp->params.rf_channel;
+ t_u16 new_channel = wlan_le16_to_cpu(prf_channel->current_channel);
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+ if (pmpriv->curr_bss_params.bss_descriptor.channel != new_channel) {
+ PRINTM(MINFO, "Channel Switch: %d to %d\n",
+ pmpriv->curr_bss_params.bss_descriptor.channel,
+ new_channel);
+ /* Update the channel again */
+ pmpriv->curr_bss_params.bss_descriptor.channel = new_channel;
+ }
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ bss->param.bss_chan.channel = new_channel;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Handle the ibss_coalescing_status resp
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_ibss_coalescing_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp)
+{
+ HostCmd_DS_802_11_IBSS_STATUS *pibss_coal_resp =
+ &(resp->params.ibss_coalescing);
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pibss_coal_resp->action) == HostCmd_ACT_GEN_SET) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ PRINTM(MINFO, "New BSSID " MACSTR "\n",
+ MAC2STR(pibss_coal_resp->bssid));
+
+ /* If rsp has MNULL BSSID, Just return..... No Action */
+ if (!memcmp(pmpriv->adapter, pibss_coal_resp->bssid, zero_mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG, "New BSSID is MNULL\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ /* If BSSID is diff, modify current BSS parameters */
+ if (memcmp(pmpriv->adapter,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH)) {
+ /* BSSID */
+ memcpy_ext(pmpriv->adapter,
+ pmpriv->curr_bss_params.bss_descriptor.mac_address,
+ pibss_coal_resp->bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(pmpriv->curr_bss_params.bss_descriptor
+ .mac_address));
+
+ /* Beacon Interval and ATIM window */
+ pmpriv->curr_bss_params.bss_descriptor.beacon_period =
+ wlan_le16_to_cpu(pibss_coal_resp->beacon_interval);
+ pmpriv->curr_bss_params.bss_descriptor.atim_window =
+ wlan_le16_to_cpu(pibss_coal_resp->atim_window);
+
+ /* ERP Information */
+ pmpriv->curr_bss_params.bss_descriptor.erp_flags =
+ (t_u8)wlan_le16_to_cpu(
+ pibss_coal_resp->use_g_rate_protect);
+
+ pmpriv->adhoc_state = ADHOC_COALESCED;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of MGMT_IE_LIST
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_mgmt_ie_list(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ t_u16 resp_len = 0, travel_len = 0;
+ int i = 0;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ custom_ie *cptr;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ HostCmd_DS_MGMT_IE_LIST_CFG *pmgmt_ie_list =
+ &(resp->params.mgmt_ie_list);
+
+ ENTER();
+
+ if (wlan_le16_to_cpu(pmgmt_ie_list->action) == HostCmd_ACT_GEN_SET) {
+ if ((pmpriv->adapter->state_rdh.stage == RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage == RDH_REM_CUSTOM_IE))
+ if (!pmpriv->adapter->ecsa_enable)
+ wlan_11h_radar_detected_callback(
+ (t_void *)pmpriv);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *)&pmgmt_ie_list->ds_mgmt_ie;
+ if (cust_ie) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len = wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index = wlan_cpu_to_le16(
+ cust_ie->ie_data_list[0].ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr = (custom_ie *)(((t_u8 *)cust_ie->ie_data_list) +
+ travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_le16_to_cpu(cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(cptr->ie_length);
+ travel_len += cptr->ie_length + sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ resp_len -= cptr->ie_length + sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ }
+ memcpy_ext(pmpriv->adapter, &misc->param.cust_ie, cust_ie,
+ (cust_ie->len + sizeof(MrvlIEtypesHeader_t)),
+ sizeof(misc->param.cust_ie));
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie *)((t_u8 *)cust_ie + cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(max_mgmt_ie->type);
+ if (max_mgmt_ie->type == TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len =
+ wlan_le16_to_cpu(max_mgmt_ie->len);
+ max_mgmt_ie->count =
+ wlan_le16_to_cpu(max_mgmt_ie->count);
+ for (i = 0; i < max_mgmt_ie->count; i++) {
+ max_mgmt_ie->info[i]
+ .buf_size = wlan_le16_to_cpu(
+ max_mgmt_ie->info[i].buf_size);
+ max_mgmt_ie->info[i]
+ .buf_count = wlan_le16_to_cpu(
+ max_mgmt_ie->info[i].buf_count);
+ }
+ /* Append max_mgmt_ie TLV after custom_ie */
+ memcpy_ext(
+ pmpriv->adapter,
+ (t_u8 *)&misc->param.cust_ie +
+ (cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t)),
+ max_mgmt_ie,
+ max_mgmt_ie->len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(misc->param.cust_ie) -
+ (cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t)));
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sysclock
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_sysclock_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *mis_ccfg = MNULL;
+ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *clk_cfg =
+ &resp->params.sys_clock_cfg;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ mis_ccfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ mis_ccfg->param.sys_clock.cur_sys_clk =
+ wlan_le16_to_cpu(clk_cfg->cur_sys_clk);
+ mis_ccfg->param.sys_clock.sys_clk_type =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_type);
+ mis_ccfg->param.sys_clock.sys_clk_num =
+ wlan_le16_to_cpu(clk_cfg->sys_clk_len) / sizeof(t_u16);
+ for (i = 0; i < mis_ccfg->param.sys_clock.sys_clk_num; i++)
+ mis_ccfg->param.sys_clock.sys_clk[i] =
+ wlan_le16_to_cpu(clk_cfg->sys_clk[i]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of inactivity timeout
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_inactivity_timeout(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_ds_inactivity_to *inac_to = MNULL;
+ HostCmd_DS_INACTIVITY_TIMEOUT_EXT *cmd_inac_to =
+ (HostCmd_DS_INACTIVITY_TIMEOUT_EXT *)&resp->params.inactivity_to;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pmcfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ inac_to->timeout_unit =
+ wlan_le16_to_cpu(cmd_inac_to->timeout_unit);
+ inac_to->unicast_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->unicast_timeout);
+ inac_to->mcast_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->mcast_timeout);
+ inac_to->ps_entry_timeout =
+ wlan_le16_to_cpu(cmd_inac_to->ps_entry_timeout);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * subscribe event
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_subscribe_event(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_SUBSCRIBE_EVENT *evt =
+ (HostCmd_DS_SUBSCRIBE_EVENT *)&resp->params.subscribe_event;
+ mlan_ds_subscribe_evt *sub_evt = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ sub_evt = &misc->param.subscribe_event;
+ sub_evt->evt_bitmap = wlan_le16_to_cpu(evt->event_bitmap);
+ pioctl_buf->data_read_written = sizeof(mlan_ds_misc_cfg);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of
+ * OTP user data
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_otp_user_data(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_OTP_USER_DATA *cmd_user_data =
+ (HostCmd_DS_OTP_USER_DATA *)&resp->params.otp_user_data;
+ mlan_ds_misc_otp_user_data *user_data = MNULL;
+
+ ENTER();
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ user_data = (mlan_ds_misc_otp_user_data *)pioctl_buf->pbuf;
+ user_data->user_data_length =
+ MIN(MAX_OTP_USER_DATA_LEN,
+ wlan_le16_to_cpu(cmd_user_data->user_data_length));
+ memcpy_ext(pmpriv->adapter, user_data->user_data,
+ cmd_user_data->user_data,
+ user_data->user_data_length,
+ sizeof(user_data->user_data));
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_misc_otp_user_data) +
+ user_data->user_data_length;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef USB
+/**
+ * @brief This function handles the command response of
+ * packet aggregation
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_ret_packet_aggr_over_host_interface(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE *packet_aggr =
+ (HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE *)&resp->params
+ .packet_aggr;
+ MrvlIETypes_USBAggrParam_t *usb_aggr_param_tlv = MNULL;
+ mlan_ds_misc_usb_aggr_ctrl *usb_aggr_ctrl = MNULL;
+ t_u8 *ptlv_buffer = (t_u8 *)packet_aggr->tlv_buf;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ t_u16 tlv = 0;
+ int tlv_buf_len = 0;
+ t_u8 changed = 0;
+#if defined(USB)
+ t_s32 i = 0;
+#endif
+
+ ENTER();
+
+ tlv_buf_len =
+ resp->size -
+ (sizeof(HostCmd_DS_PACKET_AGGR_OVER_HOST_INTERFACE) + S_DS_GEN);
+
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ while (tlv_buf_len > 0) {
+ changed = 0;
+ tlv = (*ptlv_buffer) | (*(ptlv_buffer + 1) << 8);
+ switch (tlv) {
+ case MRVL_USB_AGGR_PARAM_TLV_ID:
+ usb_aggr_param_tlv =
+ (MrvlIETypes_USBAggrParam_t *)ptlv_buffer;
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ usb_aggr_ctrl = (mlan_ds_misc_usb_aggr_ctrl *)&(
+ misc->param.usb_aggr_params);
+ usb_aggr_param_tlv->header.len = wlan_le16_to_cpu(
+ usb_aggr_param_tlv->header.len);
+ usb_aggr_param_tlv->enable =
+ wlan_le16_to_cpu(usb_aggr_param_tlv->enable);
+#if defined(USB)
+ if (pioctl_buf->action == MLAN_ACT_SET) {
+ /* Update the Tx aggregation values in
+ * MLAN */
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++) {
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.enable =
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .enable;
+ if (pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_mode !=
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .aggr_mode) {
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_mode =
+ usb_aggr_ctrl
+ ->tx_aggr_ctrl
+ .aggr_mode;
+ changed = 1;
+ }
+ if (pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_align !=
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .aggr_align) {
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_align =
+ usb_aggr_ctrl
+ ->tx_aggr_ctrl
+ .aggr_align;
+ changed = 1;
+ }
+ if (pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_max !=
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .aggr_max) {
+ pmadapter->pcard_usb
+ ->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_max =
+ usb_aggr_ctrl
+ ->tx_aggr_ctrl
+ .aggr_max;
+ changed = 1;
+ }
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.aggr_tmo =
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .aggr_tmo;
+ }
+ } else {
+ if (usb_aggr_param_tlv->enable & MBIT(1))
+ usb_aggr_ctrl->tx_aggr_ctrl.enable =
+ MTRUE;
+ else
+ usb_aggr_ctrl->tx_aggr_ctrl.enable =
+ MFALSE;
+ usb_aggr_ctrl->tx_aggr_ctrl
+ .aggr_align = wlan_le16_to_cpu(
+ usb_aggr_param_tlv->tx_aggr_align);
+ usb_aggr_ctrl->tx_aggr_ctrl.aggr_mode =
+ pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.aggr_mode;
+ usb_aggr_ctrl->tx_aggr_ctrl.aggr_max =
+ pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.aggr_max;
+ usb_aggr_ctrl->tx_aggr_ctrl.aggr_tmo =
+ pmadapter->pcard_usb->usb_tx_aggr[0]
+ .aggr_ctrl.aggr_tmo;
+ }
+ if (changed)
+ wlan_reset_usb_tx_aggr(pmadapter);
+#endif
+
+#if defined(USB)
+ if (pioctl_buf->action == MLAN_ACT_SET) {
+ /* Update the Rx deaggregation values in
+ * MLAN */
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl
+ .enable =
+ usb_aggr_ctrl->rx_deaggr_ctrl.enable;
+ if (pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_mode !=
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_mode)
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_mode =
+ usb_aggr_ctrl->rx_deaggr_ctrl
+ .aggr_mode;
+ if (pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align !=
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_align)
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align =
+ usb_aggr_ctrl->rx_deaggr_ctrl
+ .aggr_align;
+ if (pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_max !=
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_max)
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_max =
+ usb_aggr_ctrl->rx_deaggr_ctrl
+ .aggr_max;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl
+ .aggr_tmo =
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_tmo;
+ } else {
+ if (usb_aggr_param_tlv->enable & MBIT(0))
+ usb_aggr_ctrl->rx_deaggr_ctrl.enable =
+ MTRUE;
+ else
+ usb_aggr_ctrl->rx_deaggr_ctrl.enable =
+ MFALSE;
+ usb_aggr_ctrl->rx_deaggr_ctrl
+ .aggr_mode = wlan_le16_to_cpu(
+ usb_aggr_param_tlv->rx_aggr_mode);
+ usb_aggr_ctrl->rx_deaggr_ctrl
+ .aggr_align = wlan_le16_to_cpu(
+ usb_aggr_param_tlv->rx_aggr_align);
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_max =
+ wlan_le16_to_cpu(
+ usb_aggr_param_tlv->rx_aggr_max);
+ usb_aggr_ctrl->rx_deaggr_ctrl.aggr_tmo =
+ wlan_le16_to_cpu(
+ usb_aggr_param_tlv->rx_aggr_tmo);
+ }
+#endif
+ ptlv_buffer += usb_aggr_param_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_buf_len -= (usb_aggr_param_tlv->header.len +
+ sizeof(MrvlIEtypesHeader_t));
+ break;
+ default:
+ break;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * @brief This function handles the command response of
+ * DFS Repeater mode configuration
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_dfs_repeater_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_DFS_REPEATER_MODE *cmd_dfs_repeater =
+ &resp->params.dfs_repeater;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_misc_dfs_repeater *dfs_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_GET)) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ dfs_cfg =
+ (mlan_ds_misc_dfs_repeater *)&misc->param.dfs_repeater;
+ dfs_cfg->mode = wlan_le16_to_cpu(cmd_dfs_repeater->mode);
+ }
+ if (pioctl_buf && (pioctl_buf->action == MLAN_ACT_SET)) {
+ if (wlan_le16_to_cpu(cmd_dfs_repeater->mode) == 1) {
+ /* Set dfs_repeater mode to true/enabled
+ * for futher references.
+ */
+ pmpriv->adapter->dfs_repeater = MTRUE;
+ } else {
+ pmpriv->adapter->dfs_repeater = MFALSE;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of coalesce config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_coalesce_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ ENTER();
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+mlan_status wlan_ret_get_sensor_temp(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *pcfg = MNULL;
+ const HostCmd_DS_SENSOR_TEMP *pSensorT = &resp->params.temp_sensor;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ pcfg->param.sensor_temp.temperature =
+ wlan_le32_to_cpu(pSensorT->temperature);
+ PRINTM(MCMND, "get SOC temperature %u C \n",
+ pSensorT->temperature);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of arb Cfg
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_arb_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_ARB_CONFIG *cfg_cmd =
+ (HostCmd_DS_CMD_ARB_CONFIG *)&resp->params.arb_cfg;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.arb_cfg.arb_mode =
+ wlan_le32_to_cpu(cfg_cmd->arb_mode);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sta get band and
+ * channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_sta_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_STA_CONFIGURE *cmdrsp_sta_cfg =
+ (HostCmd_DS_STA_CONFIGURE *)&resp->params.sta_cfg;
+ mlan_ds_bss *bss = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_band_channel = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_CHAN_INFO) {
+ tlv_band_channel =
+ (MrvlIEtypes_channel_band_t *)
+ cmdrsp_sta_cfg->tlv_buffer;
+ bss->param.sta_channel.bandcfg =
+ tlv_band_channel->bandcfg;
+ bss->param.sta_channel.channel =
+ tlv_band_channel->channel;
+ bss->param.sta_channel.is_11n_enabled =
+ IS_11N_ENABLED(pmpriv);
+ if (bss->param.sta_channel.bandcfg.chanWidth ==
+ CHAN_BW_80MHZ)
+ bss->param.sta_channel.center_chan =
+ wlan_get_center_freq_idx(
+ pmpriv, BAND_AAC,
+ bss->param.sta_channel
+ .channel,
+ CHANNEL_BW_80MHZ);
+ PRINTM(MCMND,
+ "Get STA channel, band=0x%x, channel=%d, is_11n_enabled=%d center_chan=%d\n",
+ bss->param.sta_channel.bandcfg,
+ bss->param.sta_channel.channel,
+ bss->param.sta_channel.is_11n_enabled,
+ bss->param.sta_channel.center_chan);
+
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_bss);
+ }
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of set/get auto tx
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_auto_tx(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_AUTO_TX *cmdrsp_auto_tx =
+ (HostCmd_DS_AUTO_TX *)&resp->params.auto_tx;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ MrvlIEtypesHeader_t *header = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 action;
+ t_u16 len = 0;
+ MrvlIEtypes_Cloud_Keep_Alive_t *keep_alive_tlv = MNULL;
+ MrvlIEtypes_Keep_Alive_Pkt_t *pkt_tlv = MNULL;
+ mlan_ds_misc_keep_alive *misc_keep_alive = MNULL;
+
+ ENTER();
+
+ action = wlan_le16_to_cpu(cmdrsp_auto_tx->action);
+ if (!pioctl_buf) {
+ PRINTM(MERROR, "ioctl is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ if (!misc) {
+ PRINTM(MERROR, "misc is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (resp->result == HostCmd_RESULT_OK) {
+ header = (MrvlIEtypesHeader_t *)cmdrsp_auto_tx->tlv_buffer;
+ header->type = wlan_le16_to_cpu(header->type);
+ len = wlan_le16_to_cpu(header->len);
+ if (header->type == TLV_TYPE_CLOUD_KEEP_ALIVE) {
+ keep_alive_tlv = (MrvlIEtypes_Cloud_Keep_Alive_t *)
+ cmdrsp_auto_tx->tlv_buffer;
+ misc_keep_alive = (mlan_ds_misc_keep_alive *)&misc
+ ->param.keep_alive;
+ misc_keep_alive->mkeep_alive_id =
+ keep_alive_tlv->keep_alive_id;
+ misc_keep_alive->enable = keep_alive_tlv->enable;
+ if (((action == HostCmd_ACT_GEN_SET) ||
+ (action == HostCmd_ACT_GEN_RESET)) &&
+ !keep_alive_tlv->enable) {
+ len = len -
+ sizeof(keep_alive_tlv->keep_alive_id) -
+ sizeof(keep_alive_tlv->enable);
+ if (len > sizeof(MrvlIEtypesHeader_t)) {
+ header = (MrvlIEtypesHeader_t *)
+ keep_alive_tlv->tlv;
+ header->type =
+ wlan_le16_to_cpu(header->type);
+ len = wlan_le16_to_cpu(header->len) -
+ sizeof(Eth803Hdr_t);
+ if (header->type ==
+ TLV_TYPE_KEEP_ALIVE_PKT) {
+ pkt_tlv =
+ (MrvlIEtypes_Keep_Alive_Pkt_t
+ *)keep_alive_tlv
+ ->tlv;
+ memcpy_ext(
+ pmpriv->adapter,
+ misc_keep_alive->dst_mac,
+ pkt_tlv->eth_header
+ .dest_addr,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(misc_keep_alive
+ ->dst_mac));
+ memcpy_ext(
+ pmpriv->adapter,
+ misc_keep_alive->src_mac,
+ pkt_tlv->eth_header
+ .src_addr,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(misc_keep_alive
+ ->src_mac));
+ memcpy_ext(
+ pmpriv->adapter,
+ misc_keep_alive->packet,
+ pkt_tlv->ip_packet, len,
+ sizeof(misc_keep_alive
+ ->packet));
+ misc_keep_alive->pkt_len = len;
+ }
+ }
+ }
+ }
+ }
+
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function prepares command resp of MFG Continuous Tx
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_mfg_tx_cont(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ struct mfg_cmd_tx_cont *mcmd =
+ (struct mfg_cmd_tx_cont *)&resp->params.mfg_tx_cont;
+ struct mfg_cmd_tx_cont *cfg = MNULL;
+
+ ENTER();
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cfg = (struct mfg_cmd_tx_cont *)&misc->param.mfg_tx_cont;
+
+ cfg->error = wlan_le32_to_cpu(mcmd->error);
+ cfg->enable_tx = wlan_le32_to_cpu(mcmd->enable_tx);
+ cfg->cw_mode = wlan_le32_to_cpu(mcmd->cw_mode);
+ cfg->payload_pattern = wlan_le32_to_cpu(mcmd->payload_pattern);
+ cfg->cs_mode = wlan_le32_to_cpu(mcmd->cs_mode);
+ cfg->act_sub_ch = wlan_le32_to_cpu(mcmd->act_sub_ch);
+ cfg->tx_rate = wlan_le32_to_cpu(mcmd->tx_rate);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command resp of MFG Tx frame
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_ret_mfg_tx_frame(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ struct mfg_cmd_tx_frame2 *mcmd =
+ (struct mfg_cmd_tx_frame2 *)&resp->params.mfg_tx_frame2;
+ struct mfg_cmd_tx_frame2 *cfg = MNULL;
+
+ ENTER();
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cfg = (struct mfg_cmd_tx_frame2 *)&misc->param.mfg_tx_frame2;
+
+ cfg->error = wlan_le32_to_cpu(mcmd->error);
+ cfg->enable = wlan_le32_to_cpu(mcmd->enable);
+ cfg->data_rate = wlan_le32_to_cpu(mcmd->data_rate);
+ cfg->frame_pattern = wlan_le32_to_cpu(mcmd->frame_pattern);
+ cfg->frame_length = wlan_le32_to_cpu(mcmd->frame_length);
+ cfg->adjust_burst_sifs = wlan_le16_to_cpu(mcmd->adjust_burst_sifs);
+ cfg->burst_sifs_in_us = wlan_le32_to_cpu(mcmd->burst_sifs_in_us);
+ cfg->short_preamble = wlan_le32_to_cpu(mcmd->short_preamble);
+ cfg->act_sub_ch = wlan_le32_to_cpu(mcmd->act_sub_ch);
+ cfg->short_gi = wlan_le32_to_cpu(mcmd->short_gi);
+ cfg->tx_bf = wlan_le32_to_cpu(mcmd->tx_bf);
+ cfg->gf_mode = wlan_le32_to_cpu(mcmd->gf_mode);
+ cfg->stbc = wlan_le32_to_cpu(mcmd->stbc);
+ memcpy_ext(pmpriv->adapter, cfg->bssid, mcmd->bssid,
+ MLAN_MAC_ADDR_LENGTH, sizeof(cfg->bssid));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command resp of MFG Cmd
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_mfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ struct mfg_cmd_generic_cfg *mcmd =
+ (struct mfg_cmd_generic_cfg *)&resp->params.mfg_generic_cfg;
+ struct mfg_cmd_generic_cfg *cfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ switch (wlan_le32_to_cpu(mcmd->mfg_cmd)) {
+ case MFG_CMD_TX_CONT:
+ ret = wlan_ret_mfg_tx_cont(pmpriv, resp, pioctl_buf);
+ goto cmd_mfg_done;
+ case MFG_CMD_TX_FRAME:
+ ret = wlan_ret_mfg_tx_frame(pmpriv, resp, pioctl_buf);
+ goto cmd_mfg_done;
+ case MFG_CMD_SET_TEST_MODE:
+ case MFG_CMD_UNSET_TEST_MODE:
+ case MFG_CMD_TX_ANT:
+ case MFG_CMD_RX_ANT:
+ case MFG_CMD_RF_CHAN:
+ case MFG_CMD_CLR_RX_ERR:
+ case MFG_CMD_RF_BAND_AG:
+ case MFG_CMD_RF_CHANNELBW:
+ case MFG_CMD_RFPWR:
+ break;
+ default:
+ ret = MLAN_STATUS_FAILURE;
+ goto cmd_mfg_done;
+ }
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cfg = (struct mfg_cmd_generic_cfg *)&misc->param.mfg_generic_cfg;
+
+ cfg->error = wlan_le32_to_cpu(mcmd->error);
+ cfg->data1 = wlan_le32_to_cpu(mcmd->data1);
+ cfg->data2 = wlan_le32_to_cpu(mcmd->data2);
+ cfg->data3 = wlan_le32_to_cpu(mcmd->data3);
+cmd_mfg_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the station command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_sta_process_cmdresp(t_void *priv, t_u16 cmdresp_no,
+ t_void *pcmd_buf, t_void *pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *)pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *)pioctl;
+
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#ifdef SDIO
+ int ctr;
+#endif
+
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if ((resp->result != HostCmd_RESULT_OK)) {
+ ret = wlan_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return ret;
+ }
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ ret = wlan_ret_sdio_rx_aggr_cfg(pmpriv, resp);
+ break;
+#endif
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_ret_mac_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = wlan_ret_802_11_mac_address(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = wlan_ret_mac_multicast_adr(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = wlan_ret_802_11_scan(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_SCAN_EXT:
+ ret = wlan_ret_802_11_scan_ext(pmpriv, resp, pioctl_buf);
+ pioctl_buf = MNULL;
+ pmadapter->curr_cmd->pioctl_buf = MNULL;
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+ ret = wlan_ret_bgscan_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = wlan_ret_802_11_bgscan_query(pmpriv, resp, pioctl_buf);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_BGSCAN_RESULT, MNULL);
+ PRINTM(MINFO, "CMD_RESP: BG_SCAN result is ready!\n");
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = wlan_ret_tx_power_cfg(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_RF_TX_POWER:
+ ret = wlan_ret_802_11_rf_tx_power(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PERIOD:
+ ret = wlan_ret_802_11_sleep_period(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SLEEP_PARAMS:
+ ret = wlan_ret_802_11_sleep_params(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_ROBUSTCOEX:
+ break;
+ case HostCmd_CMD_DMCS_CONFIG:
+ ret = wlan_ret_dmcs_config(pmpriv, resp, pioctl_buf);
+ break;
+#if defined(PCIE)
+ case HostCmd_CMD_SSU:
+ PRINTM(MCMND,
+ "SSU cmdresp:number_of_buffers %d, buffer_size %d rec_len %d\n",
+ resp->params.ssu_params.number_of_buffers,
+ resp->params.ssu_params.buffer_size,
+ resp->params.ssu_params.rec_len);
+ break;
+#endif
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = wlan_ret_802_11_associate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ case HostCmd_CMD_802_11_DISASSOCIATE:
+ ret = wlan_ret_802_11_deauthenticate(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = wlan_ret_802_11_ad_hoc(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = wlan_ret_802_11_ad_hoc_stop(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_ret_get_log(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_LINK_STATS:
+ ret = wlan_ret_get_link_statistic(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO_EXT:
+ ret = wlan_ret_802_11_rssi_info_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = wlan_ret_802_11_rssi_info(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_ret_802_11_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = wlan_ret_802_11_rf_channel(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CW_MODE_CTRL:
+ ret = wlan_ret_cw_mode_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_ret_802_11_key_material(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:
+ break;
+ case HostCmd_CMD_SUPPLICANT_PMK:
+ ret = wlan_ret_802_11_supplicant_pmk(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_SUPPLICANT_PROFILE:
+ ret = wlan_ret_802_11_supplicant_profile(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_EAPOL_PKT:
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+ case HostCmd_CMD_802_11_TPC_INFO:
+ case HostCmd_CMD_802_11_CHAN_SW_ANN:
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ wlan_set_tx_pause_flag(pmpriv, MFALSE);
+
+ pmadapter->tx_buf_size =
+ (t_u16)wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ pmadapter->tx_buf_size = (pmadapter->tx_buf_size /
+ MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->pcard_sd->mp_end_port = wlan_le16_to_cpu(
+ resp->params.tx_buf.mp_end_port);
+ pmadapter->pcard_sd->mp_data_port_mask =
+ pmadapter->pcard_sd->reg->data_port_mask;
+
+ for (ctr = 1;
+ ctr <= MAX_PORT - pmadapter->pcard_sd->mp_end_port;
+ ctr++) {
+ pmadapter->pcard_sd->mp_data_port_mask &=
+ ~(1 << (MAX_PORT - ctr));
+ }
+
+ pmadapter->pcard_sd->curr_wr_port = 0;
+ pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit =
+ MIN(SDIO_MP_AGGR_DEF_PKT_LIMIT,
+ (pmadapter->pcard_sd->mp_end_port >> 1));
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(
+ resp->params.tx_buf.mp_end_port),
+ pmadapter->pcard_sd->mp_data_port_mask);
+ }
+#endif
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ ret = wlan_ret_wmm_get_status(
+ pmpriv, resp->params.get_wmm_status.queue_status_tlv,
+ resp->size - S_DS_GEN);
+ break;
+ case HostCmd_CMD_WMM_ADDTS_REQ:
+ ret = wlan_ret_wmm_addts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_DELTS_REQ:
+ ret = wlan_ret_wmm_delts_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_ret_wmm_queue_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_STATS:
+ ret = wlan_ret_wmm_queue_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_TS_STATUS:
+ ret = wlan_ret_wmm_ts_status(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_PARAM_CONFIG:
+ ret = wlan_ret_wmm_param_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = wlan_ret_ibss_coalescing_status(pmpriv, resp);
+ break;
+ case HostCmd_CMD_MGMT_IE_LIST:
+ ret = wlan_ret_mgmt_ie_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_ret_11n_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = wlan_ret_11ac_cfg(pmpriv, resp, pioctl_buf);
+ break;
+#if 0
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ pmadapter->tx_buf_size = (t_u16)wlan_le16_to_cpu(resp->params.
+ tx_buf.buff_size);
+ break;
+#endif
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+ ret = wlan_ret_sysclock_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_TARGET_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ case HostCmd_CMD_BCA_REG_ACCESS:
+ ret = wlan_ret_reg_access(pmpriv->adapter, cmdresp_no, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_ret_mem_access(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_INACTIVITY_TIMEOUT_EXT:
+ ret = wlan_ret_inactivity_timeout(pmpriv, resp, pioctl_buf);
+ break;
+#if defined(SDIO)
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+#endif
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_MEASUREMENT_REQUEST:
+ case HostCmd_CMD_MEASUREMENT_REPORT:
+ ret = wlan_meas_cmdresp_process(pmpriv, resp);
+ break;
+#if defined(PCIE)
+#if defined(PCIE8997) || defined(PCIE8897)
+ case HostCmd_CMD_PCIE_HOST_BUF_DETAILS:
+ PRINTM(MINFO, "PCIE host buffer configuration successful.\n");
+ break;
+#endif
+#endif
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
+ ret = wlan_ret_subscribe_event(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_OTP_READ_USER_DATA:
+ ret = wlan_ret_otp_user_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_HS_WAKEUP_REASON:
+ ret = wlan_ret_hs_wakeup_reason(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_REJECT_ADDBA_REQ:
+ ret = wlan_ret_reject_addba_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+ ret = wlan_ret_packet_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef USB
+ case HostCmd_CMD_PACKET_AGGR_OVER_HOST_INTERFACE:
+ ret = wlan_ret_packet_aggr_over_host_interface(pmpriv, resp,
+ pioctl_buf);
+ break;
+#endif
+#ifdef RX_PACKET_COALESCE
+ case HostCmd_CMD_RX_PKT_COALESCE_CFG:
+ ret = wlan_ret_rx_pkt_coalesce_cfg(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCMD_CONFIG_LOW_POWER_MODE:
+ break;
+ case HostCmd_DFS_REPEATER_MODE:
+ ret = wlan_ret_dfs_repeater_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_COALESCE_CFG:
+ ret = wlan_ret_coalesce_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MEF_CFG:
+ break;
+ case HostCmd_DS_GET_SENSOR_TEMP:
+ ret = wlan_ret_get_sensor_temp(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MIMO_SWITCH:
+ break;
+ case HostCmd_CMD_STA_CONFIGURE:
+ ret = wlan_ret_sta_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_PMIC_CONFIGURE:
+ break;
+ case HostCmd_CMD_INDEPENDENT_RESET_CFG:
+ ret = wlan_ret_ind_rst_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT:
+ break;
+ case HostCmd_CMD_GET_TSF:
+ ret = wlan_ret_get_tsf(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = wlan_ret_chan_region_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_AUTO_TX:
+ ret = wlan_ret_auto_tx(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_TX_RX_PKT_STATS:
+ ret = wlan_ret_tx_rx_pkt_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_DYN_BW:
+ ret = wlan_ret_dyn_bw(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_BOOT_SLEEP:
+ ret = wlan_ret_boot_sleep(pmpriv, resp, pioctl_buf);
+ break;
+#if defined(DRV_EMBEDDED_SUPPLICANT)
+ case HostCmd_CMD_CRYPTO:
+ ret = wlan_ret_crypto(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_11AX_CFG:
+ ret = wlan_ret_11ax_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11AX_CMD:
+ ret = wlan_ret_11ax_cmd(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RANGE_EXT:
+ ret = wlan_ret_range_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TWT_CFG:
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG:
+ ret = wlan_ret_rxabortcfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG_EXT:
+ ret = wlan_ret_rxabortcfg_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ARB_CONFIG:
+ ret = wlan_ret_arb_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_AMPDU_PROT_MODE:
+ ret = wlan_ret_tx_ampdu_prot_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG:
+ ret = wlan_ret_dot11mc_unassoc_ftm_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_RATE_ADAPT_CFG:
+ ret = wlan_ret_rate_adapt_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CCK_DESENSE_CFG:
+ ret = wlan_ret_cck_desense_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CHANNEL_TRPC_CONFIG:
+ ret = wlan_ret_get_chan_trpc_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_LOW_POWER_MODE_CFG:
+ ret = wlan_ret_set_get_low_power_mode_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_MFG_COMMAND:
+ ret = wlan_ret_mfg(pmpriv, resp, pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_event.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_event.c
new file mode 100644
index 000000000000..cc96e9ac7e12
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_event.c
@@ -0,0 +1,1026 @@
+/** @file mlan_sta_event.c
+ *
+ * @brief This file contains MLAN event handling.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/13/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#ifdef DRV_EMBEDDED_SUPPLICANT
+#include "authenticator_api.h"
+#endif
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function handles link lost, deauth and
+ * disassoc events.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @return N/A
+ */
+static t_void wlan_handle_disconnect_event(pmlan_private pmpriv)
+{
+ ENTER();
+
+ if (pmpriv->media_connected == MTRUE)
+ wlan_reset_connect_state(pmpriv, MTRUE);
+
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles disconnect event, reports disconnect
+ * to upper layer, cleans tx/rx packets,
+ * resets link state etc.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param drv_disconnect Flag indicating the driver should disconnect
+ * and flush pending packets.
+ *
+ * @return N/A
+ */
+t_void wlan_reset_connect_state(pmlan_private priv, t_u8 drv_disconnect)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ state_11d_t enable;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *)event_buf;
+
+ ENTER();
+
+ PRINTM(MINFO, "Handles disconnect event.\n");
+
+#ifdef UAP_SUPPORT
+ /* If DFS repeater mode is enabled and station interface disconnects
+ * then make sure that all uAPs are stopped.
+ */
+ if (pmadapter->dfs_repeater)
+ wlan_dfs_rep_disconnect(pmadapter);
+#endif
+
+ if (drv_disconnect) {
+ priv->media_connected = MFALSE;
+ pmadapter->state_rdh.tx_block = MFALSE;
+ wlan_11h_check_update_radar_det_state(priv);
+ }
+
+ if (priv->port_ctrl_mode == MTRUE) {
+ /* Close the port on Disconnect */
+ PRINTM(MINFO, "DISC: port_status = CLOSED\n");
+ priv->port_open = MFALSE;
+ }
+ memset(pmadapter, &priv->gtk_rekey, 0,
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+ priv->tx_pause = MFALSE;
+ pmadapter->scan_block = MFALSE;
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_rate_info = 0;
+ priv->max_amsdu = 0;
+ priv->amsdu_disable = MFALSE;
+ wlan_coex_ampdu_rxwinsize(pmadapter);
+
+ priv->sec_info.ewpa_enabled = MFALSE;
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ priv->wpa_ie_len = 0;
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ supplicantStopSessionTimer(priv->psapriv);
+ supplicantClrEncryptKey(priv->psapriv);
+ supplicantDisable(priv->psapriv);
+#endif
+
+ priv->sec_info.wapi_enabled = MFALSE;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = MFALSE;
+
+ priv->wps.session_enable = MFALSE;
+ memset(priv->adapter, (t_u8 *)&priv->wps.wps_ie, 0x00,
+ sizeof(priv->wps.wps_ie));
+ priv->sec_info.osen_enabled = MFALSE;
+ priv->osen_ie_len = 0;
+
+ priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE;
+
+ /*Enable auto data rate */
+ priv->is_data_rate_auto = MTRUE;
+ priv->data_rate = 0;
+
+ if (priv->bss_mode == MLAN_BSS_MODE_IBSS) {
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->adhoc_is_link_sensed = MFALSE;
+ priv->intf_state_11h.adhoc_auto_sel_chan = MTRUE;
+ }
+
+ if (drv_disconnect) {
+ /* Free Tx and Rx packets, report disconnect to upper layer */
+ wlan_clean_txrx(priv);
+
+ /* Need to erase the current SSID and BSSID info */
+ memset(pmadapter, &priv->curr_bss_params, 0x00,
+ sizeof(priv->curr_bss_params));
+ }
+ pmadapter->tx_lock_flag = MFALSE;
+ pmadapter->pps_uapsd_mode = MFALSE;
+ pmadapter->delay_null_pkt = MFALSE;
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ pmadapter->hs_wake_interval = 0;
+
+ if ((wlan_fw_11d_is_enabled(priv)) &&
+ (priv->state_11d.user_enable_11d == DISABLE_11D)) {
+ priv->state_11d.enable_11d = DISABLE_11D;
+ enable = DISABLE_11D;
+
+ /* Send cmd to FW to enable/disable 11D function */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, Dot11D_i, MNULL,
+ &enable);
+ if (ret)
+ PRINTM(MERROR, "11D: Failed to enable 11D\n");
+ }
+ if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd &&
+ (pmadapter->cmd_timer_is_set == MFALSE)) {
+ LEAVE();
+ return;
+ }
+
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_DISCONNECTED;
+ pevent->event_len = sizeof(priv->disconnect_reason_code);
+ memcpy_ext(priv->adapter, pevent->event_buf,
+ &priv->disconnect_reason_code, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, pevent);
+ priv->disconnect_reason_code = 0;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function sends the OBSS scan parameters to the application
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+t_void wlan_2040_coex_event(pmlan_private pmpriv)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *)event_buf;
+ t_u8 ele_len;
+
+ ENTER();
+
+ if (pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param &&
+ pmpriv->curr_bss_params.bss_descriptor.poverlap_bss_scan_param
+ ->ieee_hdr.element_id == OVERLAPBSSSCANPARAM) {
+ ele_len = pmpriv->curr_bss_params.bss_descriptor
+ .poverlap_bss_scan_param->ieee_hdr.len;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM;
+ pevent->event_len = ele_len;
+ /* Copy OBSS scan parameters */
+ memcpy_ext(pmpriv->adapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)&pmpriv->curr_bss_params.bss_descriptor
+ .poverlap_bss_scan_param->obss_scan_param,
+ ele_len, pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM,
+ pevent);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will process tx pause event
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void wlan_process_sta_tx_pause_event(pmlan_private priv,
+ pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - sizeof(t_u32);
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
+ sizeof(t_u32));
+ MrvlIEtypes_tx_pause_t *tx_pause_tlv;
+ t_u8 *bssid = MNULL;
+ ENTER();
+ if (priv->media_connected)
+ bssid = priv->curr_bss_params.bss_descriptor.mac_address;
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_TX_PAUSE) {
+ tx_pause_tlv = (MrvlIEtypes_tx_pause_t *)tlv;
+ PRINTM(MCMND, "TxPause: " MACSTR " pause=%d, pkts=%d\n",
+ MAC2STR(tx_pause_tlv->peermac),
+ tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt);
+
+ if (bssid &&
+ !memcmp(priv->adapter, bssid, tx_pause_tlv->peermac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ if (tx_pause_tlv->tx_pause)
+ priv->tx_pause = MTRUE;
+ else
+ priv->tx_pause = MFALSE;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function will print diconnect reason code according
+ * to IEEE 802.11 spec
+ *
+ * @param reason_code reason code for the deauth/disaccoc
+ * received from firmware
+ * @return N/A
+ */
+static void wlan_print_disconnect_reason(t_u16 reason_code)
+{
+ ENTER();
+
+ switch (reason_code) {
+ case MLAN_REASON_UNSPECIFIED:
+ PRINTM(MMSG, "wlan: REASON: Unspecified reason\n");
+ break;
+ case MLAN_REASON_PREV_AUTH_NOT_VALID:
+ PRINTM(MMSG,
+ "wlan: REASON: Previous authentication no longer valid\n");
+ break;
+ case MLAN_REASON_DEAUTH_LEAVING:
+ PRINTM(MMSG,
+ "wlan: REASON: (Deauth) Sending STA is leaving (or has left) IBSS or ESS\n");
+ break;
+ case MLAN_REASON_DISASSOC_DUE_TO_INACTIVITY:
+ PRINTM(MMSG,
+ "wlan: REASON: Disassociated due to inactivity \n");
+ break;
+ case MLAN_REASON_DISASSOC_AP_BUSY:
+ PRINTM(MMSG,
+ "wlan: REASON: (Disassociated) AP unable to handle all connected STAs\n");
+ break;
+ case MLAN_REASON_CLASS2_FRAME_FROM_NOAUTH_STA:
+ PRINTM(MMSG,
+ "wlan: REASON: Class 2 frame was received from nonauthenticated STA\n");
+ break;
+ case MLAN_REASON_CLASS3_FRAME_FROM_NOASSOC_STA:
+ PRINTM(MMSG,
+ "wlan: REASON: Class 3 frame was received from nonassociated STA\n");
+ break;
+ case MLAN_REASON_DISASSOC_STA_HAS_LEFT:
+ PRINTM(MMSG,
+ "wlan: REASON: (Disassocated) Sending STA is leaving (or has left) BSS\n");
+ break;
+ case MLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
+ PRINTM(MMSG,
+ "wlan: REASON: STA requesting (re)assoc is not authenticated with responding STA\n");
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_sta_process_event(t_void *priv)
+{
+ pmlan_private pmpriv = (pmlan_private)priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ t_u8 *event_buf = MNULL;
+ t_u8 *evt_buf = MNULL;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u16 reason_code;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_event *pevent = MNULL;
+ chan_band_info *pchan_band_info = MNULL;
+ t_u8 radar_chan;
+ t_u16 enable = 0;
+
+ ENTER();
+
+ if (!pmbuf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Event length check */
+ if ((pmbuf->data_len - sizeof(eventcause)) > MAX_EVENT_SIZE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate memory for event buffer */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MAX_EVENT_SIZE + sizeof(mlan_event),
+ MLAN_MEM_DEF, &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ if (pmbuf)
+ pmbuf->status_code = MLAN_ERROR_NO_MEM;
+ goto done;
+ }
+ pevent = (pmlan_event)event_buf;
+ memset(pmadapter, event_buf, 0, MAX_EVENT_SIZE);
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+ PRINTM(MERROR,
+ "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
+ break;
+ case EVENT_LINK_SENSED:
+ PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
+ pmpriv->adhoc_is_link_sensed = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
+ MNULL);
+ break;
+
+ case EVENT_DEAUTHENTICATED:
+ if (pmpriv->wps.session_enable) {
+ PRINTM(MMSG,
+ "wlan: Receive deauth event in wps session\n");
+ break;
+ }
+ reason_code = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause)));
+ PRINTM(MMSG, "wlan: EVENT: Deauthenticated (reason 0x%x)\n",
+ reason_code);
+ wlan_print_disconnect_reason(reason_code);
+ pmpriv->disconnect_reason_code = reason_code;
+ pmadapter->dbg.num_event_deauth++;
+ wlan_handle_disconnect_event(pmpriv);
+
+ break;
+
+ case EVENT_DISASSOCIATED:
+ if (pmpriv->wps.session_enable) {
+ PRINTM(MMSG,
+ "wlan: Receive disassociate event in wps session\n");
+ break;
+ }
+ reason_code = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause)));
+ PRINTM(MMSG, "wlan: EVENT: Disassociated (reason 0x%x)\n",
+ reason_code);
+ wlan_print_disconnect_reason(reason_code);
+ pmpriv->disconnect_reason_code = reason_code;
+ pmadapter->dbg.num_event_disassoc++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_LINK_LOST:
+ reason_code = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause)));
+ PRINTM(MMSG, "wlan: EVENT: Link lost (reason 0x%x)\n",
+ reason_code);
+ pmpriv->disconnect_reason_code = reason_code;
+ pmadapter->dbg.num_event_link_lost++;
+ wlan_handle_disconnect_event(pmpriv);
+ break;
+
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "_");
+
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ wlan_check_ps_cond(pmadapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE\n");
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "|");
+ if (!pmadapter->pps_uapsd_mode && pmpriv->media_connected &&
+ (pmpriv->port_open || !pmpriv->port_ctrl_mode) &&
+ pmadapter->sleep_period.period) {
+ pmadapter->pps_uapsd_mode = MTRUE;
+ PRINTM(MEVENT, "PPS/UAPSD mode activated\n");
+ }
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->tx_lock_flag = MFALSE;
+ if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) {
+ if (MTRUE ==
+ wlan_check_last_packet_indication(pmpriv)) {
+ if (!pmadapter->data_sent) {
+ if (wlan_send_null_packet(
+ pmpriv,
+ MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) ==
+ MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ break;
+
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, 0,
+ 0, MNULL, MNULL);
+ break;
+ case EVENT_MIC_ERR_UNICAST:
+ PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
+ break;
+
+ case EVENT_MIC_ERR_MULTICAST:
+ PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
+ break;
+ case EVENT_MIB_CHANGED:
+ case EVENT_INIT_DONE:
+ break;
+
+ case EVENT_ADHOC_BCN_LOST:
+ PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
+ MNULL);
+ break;
+
+ case EVENT_FW_DEBUG_INFO:
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_DEBUG_INFO;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ pevent->event_len, pevent->event_len);
+ PRINTM(MEVENT, "EVENT: FW Debug Info %s\n",
+ (t_u8 *)pevent->event_buf);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+
+ case EVENT_BG_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
+ pmadapter->bgscan_reported = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
+ break;
+ case EVENT_BG_SCAN_STOPPED:
+ PRINTM(MEVENT, "EVENT: BGS_STOPPED\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN_STOPPED,
+ MNULL);
+ break;
+
+ case EVENT_PORT_RELEASE:
+ PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
+ /* Open the port for e-supp mode */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
+ pmpriv->port_open = MTRUE;
+ }
+ pmadapter->scan_block = MFALSE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
+ break;
+
+ case EVENT_STOP_TX:
+ PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
+ wlan_11h_tx_disable(pmpriv); /* this fn will send event up to
+ MOAL */
+ break;
+ case EVENT_START_TX:
+ PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
+ wlan_11h_tx_enable(pmpriv); /* this fn will send event up to
+ MOAL */
+ break;
+ case EVENT_CHANNEL_SWITCH:
+ PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
+ if (pmadapter->ecsa_enable) {
+ MrvlIEtypes_channel_band_t *pchan_info =
+ (MrvlIEtypes_channel_band_t
+ *)(pmadapter->event_body);
+ t_u8 channel = pchan_info->channel;
+ chan_freq_power_t *cfp = MNULL;
+ DBG_HEXDUMP(MCMD_D, "chan band config",
+ (t_u8 *)pchan_info,
+ sizeof(MrvlIEtypes_channel_band_t));
+ PRINTM(MEVENT, "Switch to channel %d success!\n",
+ channel);
+#define MAX_CHANNEL_BAND_B 14
+ if (channel <= MAX_CHANNEL_BAND_B)
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, BAND_B, channel);
+ else
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, BAND_A, channel);
+ pmpriv->curr_bss_params.bss_descriptor.channel =
+ channel;
+ if (cfp)
+ pmpriv->curr_bss_params.bss_descriptor.freq =
+ cfp->freq;
+ else
+ pmpriv->curr_bss_params.bss_descriptor.freq = 0;
+ if (pmpriv->adapter->state_rdh.stage ==
+ RDH_SET_CUSTOM_IE) {
+ pmadapter->state_rdh.stage =
+ RDH_RESTART_TRAFFIC;
+ wlan_11h_radar_detected_handling(pmadapter,
+ pmpriv);
+ }
+ pmadapter->state_rdh.tx_block = MFALSE;
+ /* Setup event buffer */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id =
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE;
+ pevent->event_len = sizeof(chan_band_info);
+ pchan_band_info = (chan_band_info *)pevent->event_buf;
+ /* Copy event data */
+ memcpy_ext(pmadapter, (t_u8 *)&pchan_band_info->bandcfg,
+ (t_u8 *)&pchan_info->bandcfg,
+ sizeof(pchan_info->bandcfg),
+ sizeof(pchan_band_info->bandcfg));
+ pchan_band_info->channel = pchan_info->channel;
+ if (pchan_band_info->bandcfg.chanWidth == CHAN_BW_80MHZ)
+ pchan_band_info->center_chan =
+ wlan_get_center_freq_idx(
+ priv, BAND_AAC,
+ pchan_info->channel,
+ CHANNEL_BW_80MHZ);
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE,
+ pevent);
+ }
+ break;
+ case EVENT_CHANNEL_SWITCH_ANN:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n");
+ /* Here, pass up event first, as handling will send deauth */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN,
+ MNULL);
+ wlan_11h_handle_event_chanswann(pmpriv);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+
+ /* Send as passthru first, this event can cause other events */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter, pmpriv);
+ } else {
+ PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+
+ break;
+
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ pevent->event_len, pevent->event_len);
+ /* Handle / pass event data */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent,
+ &radar_chan);
+ /* Also send this event as passthru */
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
+ break;
+ case EVENT_EXT_SCAN_REPORT:
+ PRINTM(MEVENT, "EVENT: EXT_SCAN Report (%d)\n",
+ pmbuf->data_len);
+ if (pmadapter->pscan_ioctl_req && pmadapter->ext_scan)
+ ret = wlan_handle_event_ext_scan_report(priv, pmbuf);
+ break;
+ case EVENT_EXT_SCAN_STATUS_REPORT:
+ PRINTM(MEVENT, "EVENT: EXT_SCAN status report (%d)\n",
+ pmbuf->data_len);
+ pmadapter->ext_scan_timeout = MFALSE;
+ ret = wlan_handle_event_ext_scan_status(priv, pmbuf);
+ break;
+ case EVENT_MEAS_REPORT_RDY:
+ PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n",
+ eventcause);
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
+ HostCmd_ACT_GEN_SET, 0, 0, MNULL);
+ break;
+ case EVENT_WMM_STATUS_CHANGE:
+ if (pmbuf &&
+ pmbuf->data_len >
+ sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) {
+ PRINTM(MEVENT, "EVENT: WMM status changed: %d\n",
+ pmbuf->data_len);
+
+ evt_buf = (pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause));
+
+ wlan_ret_wmm_get_status(pmpriv, evt_buf,
+ pmbuf->data_len -
+ sizeof(eventcause));
+ } else {
+ PRINTM(MEVENT, "EVENT: WMM status changed\n");
+ ret = wlan_cmd_wmm_status_change(pmpriv);
+ }
+ break;
+
+ case EVENT_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_BCN_RSSI_LOW;
+ pevent->event_len = sizeof(t_u16);
+ /** Fw send bcnRssi low value in event reason field*/
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)&pmadapter->event_body, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+ case EVENT_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
+ break;
+ case EVENT_MAX_FAIL:
+ PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
+ break;
+ case EVENT_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_BCN_RSSI_HIGH;
+ pevent->event_len = sizeof(t_u16);
+ /** Fw send bcnRssi high value in event reason field*/
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ (t_u8 *)&pmadapter->event_body, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+ case EVENT_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
+ break;
+ case EVENT_DATA_RSSI_LOW:
+ PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
+ break;
+ case EVENT_DATA_SNR_LOW:
+ PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
+ break;
+ case EVENT_DATA_RSSI_HIGH:
+ PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
+ break;
+ case EVENT_DATA_SNR_HIGH:
+ PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
+ break;
+ case EVENT_LINK_QUALITY:
+ PRINTM(MEVENT, "EVENT: Link Quality\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
+ break;
+ case EVENT_PRE_BEACON_LOST:
+ PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
+ break;
+ case EVENT_IBSS_COALESCED:
+ PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
+ ret = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ if (pmpriv->media_connected == MTRUE)
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore ADDBA Request event in disconnected state\n");
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ if (pmpriv->media_connected == MTRUE)
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore DELBA Request event in disconnected state\n");
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ if (pmpriv->media_connected == MTRUE)
+ wlan_11n_ba_stream_timeout(
+ pmpriv, (HostCmd_DS_11N_BATIMEOUT *)
+ pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore BA Stream timeout event in disconnected state\n");
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *)pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *)pmadapter->event_body));
+ if (pmbuf->data_len == sizeof(eventcause) + sizeof(t_u32)) {
+ enable = wlan_le16_to_cpu(
+ *(t_u16 *)(pmadapter->event_body +
+ sizeof(t_u16)));
+ if (enable)
+ pmpriv->amsdu_disable = MFALSE;
+ else
+ pmpriv->amsdu_disable = MTRUE;
+ PRINTM(MEVENT, "amsdu_disable=%d\n",
+ pmpriv->amsdu_disable);
+ }
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+
+ case EVENT_WEP_ICV_ERR:
+ PRINTM(MEVENT, "EVENT: WEP ICV error\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
+ pevent->event_len = sizeof(Event_WEP_ICV_ERR);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmadapter->event_body, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
+ break;
+
+ case EVENT_BW_CHANGE:
+ PRINTM(MEVENT, "EVENT: BW Change\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
+ pevent->event_len = sizeof(t_u8);
+ /* Copy event body from the event buffer */
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmadapter->event_body, pevent->event_len,
+ pevent->event_len);
+#ifdef UAP_SUPPORT
+ if (pmadapter->dfs_repeater)
+ wlan_dfs_rep_bw_change(pmadapter);
+#endif
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
+ break;
+
+#ifdef WIFI_DIRECT_SUPPORT
+ case EVENT_WIFIDIRECT_GENERIC_EVENT:
+ PRINTM(MEVENT, "EVENT: WIFIDIRECT event %d\n", eventcause);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+ case EVENT_WIFIDIRECT_SERVICE_DISCOVERY:
+ PRINTM(MEVENT, "EVENT: WIFIDIRECT service discovery event %d\n",
+ eventcause);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *)pmadapter->event_body);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
+ MNULL);
+ break;
+
+ case EVENT_TX_DATA_PAUSE:
+ PRINTM(MEVENT, "EVENT: TX_DATA_PAUSE\n");
+ wlan_process_sta_tx_pause_event(priv, pmbuf);
+ break;
+
+ case EVENT_IBSS_STATION_CONNECT:
+ break;
+ case EVENT_IBSS_STATION_DISCONNECT:
+ break;
+ case EVENT_SAD_REPORT: {
+#ifdef DEBUG_LEVEL1
+ t_u8 *pevt_dat =
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(t_u32);
+#endif
+ PRINTM(MEVENT,
+ "EVENT: Antenna Diversity %d (%d, %d, %d, %d)\n",
+ eventcause, pevt_dat[0] + 1, pevt_dat[1] + 1,
+ pevt_dat[2], pevt_dat[3]);
+ } break;
+
+ case EVENT_FW_DUMP_INFO:
+ PRINTM(MINFO, "EVENT: Dump FW info\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_DUMP_INFO;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+ case EVENT_TX_STATUS_REPORT:
+ PRINTM(MINFO, "EVENT: TX_STATUS\n");
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_TX_STATUS;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ PRINTM(MEVENT, "EVENT: BT coex wlan param update\n");
+ wlan_bt_coex_wlan_param_update_event(pmpriv, pmbuf);
+ break;
+
+#if defined(PCIE)
+ case EVENT_SSU_DUMP_DMA:
+ PRINTM(MEVENT, "EVENT: EVENT_SSU_DUMP_DMA\n");
+ if (!pmadapter->ssu_buf || !pmadapter->ssu_buf->pbuf)
+ break;
+
+ /* If ADMA is supported, SSU header could not be received with
+ * SSU data. Instead, SSU header is received through this event.
+ * So, copy the header into the buffer before passing the buffer
+ * to upper layer for file writting
+ */
+ memcpy_ext(pmadapter,
+ (t_u8 *)pmadapter->ssu_buf->pbuf +
+ pmadapter->ssu_buf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ (pmbuf->data_len - sizeof(eventcause)),
+ (pmbuf->data_len - sizeof(eventcause)));
+
+ DBG_HEXDUMP(MEVT_D, "SSU data",
+ (t_u8 *)pmadapter->ssu_buf->pbuf +
+ pmadapter->ssu_buf->data_offset,
+ 512);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_SSU_DUMP_FILE;
+ pevent->event_len = MLAN_SSU_BUF_SIZE;
+ *(t_ptr *)pevent->event_buf = (t_ptr)pmadapter->ssu_buf->pbuf +
+ pmadapter->ssu_buf->data_offset;
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ wlan_free_ssu_pcie_buf(pmadapter);
+ break;
+#endif
+ case EVENT_MEF_HOST_WAKEUP:
+ PRINTM(MEVENT, "EVENT: EVENT_MEF_HOST_WAKEUP len=%d\n",
+ pmbuf->data_len);
+ break;
+ case EVENT_MANAGEMENT_FRAME_WAKEUP:
+ PRINTM(MEVENT, "EVENT: EVENT_MANAGEMENT_FRAME_WAKEUP HOST\n");
+ break;
+ case EVENT_CLOUD_KEEP_ALIVE_RETRY_FAIL:
+ break;
+ case EVENT_VDLL_IND:
+ wlan_process_vdll_event(pmpriv, pmbuf);
+ break;
+ case EVENT_FW_HANG_REPORT:
+ if (pmbuf->data_len < (sizeof(eventcause) + sizeof(t_u16))) {
+ PRINTM(MEVENT,
+ "EVENT: EVENT_FW_HANG_REPORT skip for len too short: %d\n",
+ pmbuf->data_len);
+ break;
+ }
+ PRINTM(MEVENT, "EVENT: EVENT_FW_HANG_REPORT reasoncode=%d\n",
+ wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause))));
+ pmadapter->fw_hang_report = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ break;
+ default:
+ PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
+ break;
+ }
+done:
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_ioctl.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_ioctl.c
new file mode 100644
index 000000000000..c565144f04ac
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_ioctl.c
@@ -0,0 +1,5615 @@
+/** @file mlan_sta_ioctl.c
+ *
+ * @brief This file contains the functions for station ioctl.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/21/2008: initial version
+******************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#include "mlan_11h.h"
+#ifdef DRV_EMBEDDED_SUPPLICANT
+#include "authenticator_api.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Get signal information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_get_info_signal(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_signal)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_signal);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Signal info can be obtained only if connected */
+ if (pmpriv->media_connected == MFALSE) {
+ PRINTM(MINFO, "Can not get signal in disconnected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_get_info_signal_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info = MNULL;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ info = (mlan_ds_get_info *)pioctl_req->pbuf;
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_info)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_info);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RSSI_INFO_EXT,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ (t_void *)info);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get statistics information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_get_info_stats(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get sta channel information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_get_chan_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(chan_band_info)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(chan_band_info);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_STA_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_get_info_bss_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+ BSSDescriptor_t *pbss_desc;
+ t_s32 tbl_idx = 0;
+
+ ENTER();
+
+ /* Get current BSS info */
+ pbss_desc = &pmpriv->curr_bss_params.bss_descriptor;
+ info = (mlan_ds_get_info *)pioctl_req->pbuf;
+
+ /* BSS mode */
+ info->param.bss_info.bss_mode = pmpriv->bss_mode;
+
+ /* SSID */
+ memcpy_ext(pmadapter, &info->param.bss_info.ssid, &pbss_desc->ssid,
+ sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
+
+ /* BSSID */
+ memcpy_ext(pmadapter, &info->param.bss_info.bssid,
+ &pbss_desc->mac_address, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ /* Channel */
+ info->param.bss_info.bss_chan = pbss_desc->channel;
+
+ /* Beacon interval */
+ info->param.bss_info.beacon_interval = pbss_desc->beacon_period;
+
+ /* Band */
+ info->param.bss_info.bss_band = (t_u8)pbss_desc->bss_band;
+
+ /* Region code */
+ info->param.bss_info.region_code = pmadapter->region_code;
+
+ /* Scan table index if connected */
+ info->param.bss_info.scan_table_idx = 0;
+ info->param.bss_info.scan_block = pmadapter->scan_block;
+ if (pmpriv->media_connected == MTRUE) {
+ tbl_idx = wlan_find_ssid_in_list(pmpriv, &pbss_desc->ssid,
+ pbss_desc->mac_address,
+ pmpriv->bss_mode);
+ if (tbl_idx >= 0)
+ info->param.bss_info.scan_table_idx = tbl_idx;
+ }
+
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* Tx power information */
+ info->param.bss_info.max_power_level = pmpriv->max_tx_power_level;
+ info->param.bss_info.min_power_level = pmpriv->min_tx_power_level;
+
+ /* AdHoc state */
+ info->param.bss_info.adhoc_state = pmpriv->adhoc_state;
+
+ /* Last beacon NF */
+ info->param.bss_info.bcn_nf_last = pmpriv->bcn_nf_last;
+
+ /* wep status */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ info->param.bss_info.wep_status = MTRUE;
+ else
+ info->param.bss_info.wep_status = MFALSE;
+
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.bss_info.is_deep_sleep = pmadapter->is_deep_sleep;
+
+ /* Capability Info */
+ info->param.bss_info.capability_info = 0;
+ memcpy_ext(pmadapter, &info->param.bss_info.capability_info,
+ &pbss_desc->cap_info,
+ sizeof(info->param.bss_info.capability_info),
+ sizeof(info->param.bss_info.capability_info));
+
+ memset(pmadapter, &info->param.bss_info.ext_cap, 0, sizeof(ExtCap_t));
+ if (pbss_desc->pext_cap) {
+ memcpy_ext(pmadapter, &info->param.bss_info.ext_cap,
+ (t_u8 *)pbss_desc->pext_cap +
+ sizeof(IEEEtypes_Header_t),
+ pbss_desc->pext_cap->ieee_hdr.len,
+ sizeof(info->param.bss_info.ext_cap));
+ }
+
+ /* Listen Interval */
+ info->param.bss_info.listen_interval = pmpriv->listen_interval;
+
+ /* Association ID */
+ if (pmpriv->assoc_rsp_buf)
+ info->param.bss_info.assoc_id =
+ (t_u16)((IEEEtypes_AssocRsp_t *)pmpriv->assoc_rsp_buf)
+ ->a_id;
+ else
+ info->param.bss_info.assoc_id = 0;
+
+ /* AP/Peer supported rates */
+ memset(pmadapter, info->param.bss_info.peer_supp_rates, 0,
+ sizeof(info->param.bss_info.peer_supp_rates));
+ memcpy_ext(pmadapter, info->param.bss_info.peer_supp_rates,
+ pbss_desc->supported_rates,
+ sizeof(pbss_desc->supported_rates),
+ sizeof(info->param.bss_info.peer_supp_rates));
+ if (pbss_desc->pmd_ie) {
+ info->param.bss_info.mdid = pbss_desc->pmd_ie->mdid;
+ info->param.bss_info.ft_cap = pbss_desc->pmd_ie->ft_cap;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get information handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_get_info_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ pget_info = (mlan_ds_get_info *)pioctl_req->pbuf;
+
+ switch (pget_info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ status = wlan_get_info_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ status = wlan_get_info_signal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_SIGNAL_EXT:
+ status = wlan_get_info_signal_ext(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_FW_INFO:
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ pget_info->param.fw_info.fw_ver = pmadapter->fw_release_number;
+ memcpy_ext(pmadapter, &pget_info->param.fw_info.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.region_code = pmadapter->region_code;
+ if (pmadapter->otp_region && pmadapter->otp_region->force_reg)
+ pget_info->param.fw_info.force_reg = MTRUE;
+ else
+ pget_info->param.fw_info.force_reg = MFALSE;
+ pget_info->param.fw_info.ecsa_enable = pmadapter->ecsa_enable;
+ pget_info->param.fw_info.getlog_enable =
+ pmadapter->getlog_enable;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ pget_info->param.fw_info.hw_dot_11n_dev_cap =
+ pmadapter->hw_dot_11n_dev_cap;
+ pget_info->param.fw_info.usr_dev_mcs_support =
+ pmpriv->usr_dev_mcs_support;
+ if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
+ pget_info->param.fw_info.prohibit_80mhz = MTRUE;
+ else
+ pget_info->param.fw_info.prohibit_80mhz = MFALSE;
+ pget_info->param.fw_info.hw_dot_11ac_mcs_support =
+ pmadapter->hw_dot_11ac_mcs_support;
+ pget_info->param.fw_info.hw_dot_11ac_dev_cap =
+ pmadapter->hw_dot_11ac_dev_cap;
+ pget_info->param.fw_info.usr_dot_11ac_dev_cap_bg =
+ pmpriv->usr_dot_11ac_dev_cap_bg;
+ pget_info->param.fw_info.usr_dot_11ac_mcs_support =
+ pmpriv->usr_dot_11ac_mcs_support;
+ pget_info->param.fw_info.usr_dot_11ac_dev_cap_a =
+ pmpriv->usr_dot_11ac_dev_cap_a;
+ pget_info->param.fw_info.hw_hecap_len = pmadapter->hw_hecap_len;
+ pget_info->param.fw_info.hw_2g_hecap_len =
+ pmadapter->hw_2g_hecap_len;
+ memcpy_ext(pmadapter, pget_info->param.fw_info.hw_he_cap,
+ pmadapter->hw_he_cap, pmadapter->hw_hecap_len,
+ sizeof(pget_info->param.fw_info.hw_he_cap));
+ memcpy_ext(pmadapter, pget_info->param.fw_info.hw_2g_he_cap,
+ pmadapter->hw_2g_he_cap, pmadapter->hw_2g_hecap_len,
+ sizeof(pget_info->param.fw_info.hw_2g_he_cap));
+ pget_info->param.fw_info.fw_supplicant_support =
+ IS_FW_SUPPORT_SUPPLICANT(pmadapter) ? 0x01 : 0x00;
+ pget_info->param.fw_info.antinfo = pmadapter->antinfo;
+ pget_info->param.fw_info.max_ap_assoc_sta =
+ pmadapter->max_sta_conn;
+ break;
+ case MLAN_OID_GET_BSS_INFO:
+ status = wlan_get_info_bss_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DEBUG_INFO:
+ status = wlan_get_info_debug_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_VER_EXT:
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_LINK_STATS:
+ status = wlan_ioctl_link_statistic(pmpriv, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get SNMP MIB handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_snmp_mib_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u16 cmd_oid = 0;
+ mlan_ds_snmp_mib *mib = MNULL;
+ t_u32 value = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ mib = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ switch (mib->sub_command) {
+ case MLAN_OID_SNMP_MIB_RTS_THRESHOLD:
+ value = mib->param.rts_threshold;
+ cmd_oid = RtsThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_FRAG_THRESHOLD:
+ value = mib->param.frag_threshold;
+ cmd_oid = FragThresh_i;
+ break;
+ case MLAN_OID_SNMP_MIB_RETRY_COUNT:
+ value = mib->param.retry_count;
+ cmd_oid = ShortRetryLim_i;
+ break;
+ case MLAN_OID_SNMP_MIB_DTIM_PERIOD:
+ value = mib->param.dtim_period;
+ cmd_oid = DtimPeriod_i;
+ break;
+ case MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE:
+ value = mib->param.signalext_enable;
+ cmd_oid = SignalextEnable_i;
+ break;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, cmd_action,
+ cmd_oid, (t_void *)pioctl_req, &value);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Radio command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_radio_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_radio_cfg *radio_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_radio_cfg)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_radio_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ switch (radio_cfg->sub_command) {
+ case MLAN_OID_RADIO_CTRL:
+ status = wlan_radio_ioctl_radio_ctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BAND_CFG:
+ status = wlan_radio_ioctl_band_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_ANT_CFG:
+ status = wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_REMAIN_CHAN_CFG:
+ status =
+ wlan_radio_ioctl_remain_chan_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MIMO_SWITCH:
+ status =
+ wlan_radio_ioctl_mimo_switch_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_mac_address(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ t_u16 cmd_action;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ memcpy_ext(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_MAC_ADDRESS,
+ cmd_action, 0, (t_void *)pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set multicast list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_set_multicast_list(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 old_pkt_filter;
+
+ ENTER();
+
+ old_pkt_filter = pmpriv->curr_pkt_filter;
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_multicast_list) + MLAN_SUB_COMMAND_SIZE;
+ if (bss->param.multicast_list.mode == MLAN_PROMISC_MODE) {
+ PRINTM(MINFO, "Enable Promiscuous mode\n");
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ pmpriv->curr_pkt_filter &=
+ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ /* Multicast */
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ if (bss->param.multicast_list.mode == MLAN_ALL_MULTI_MODE) {
+ PRINTM(MINFO, "Enabling All Multicast!\n");
+ pmpriv->curr_pkt_filter |=
+ HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ pmpriv->curr_pkt_filter &=
+ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ if (bss->param.multicast_list.num_multicast_addr) {
+ PRINTM(MINFO, "Set multicast list=%d\n",
+ bss->param.multicast_list
+ .num_multicast_addr);
+ /* Set multicast addresses to firmware */
+ if (old_pkt_filter == pmpriv->curr_pkt_filter) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ &bss->param.multicast_list);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &bss->param.multicast_list);
+ }
+ if (ret)
+ goto exit;
+ }
+ }
+ }
+ PRINTM(MINFO, "old_pkt_filter=0x%x, curr_pkt_filter=0x%x\n",
+ old_pkt_filter, pmpriv->curr_pkt_filter);
+ if (old_pkt_filter != pmpriv->curr_pkt_filter) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ &pmpriv->curr_pkt_filter);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_get_channel_list(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp;
+ t_u32 i, j;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((wlan_11d_is_enabled(pmpriv) && pmpriv->media_connected == MTRUE) &&
+ ((pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) ||
+ (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS &&
+ pmpriv->adhoc_state != ADHOC_STARTED))) {
+ t_u8 chan_no;
+ t_u8 band;
+
+ parsed_region_chan_11d_t *parsed_region_chan = MNULL;
+ parsed_region_chan_11d_t region_chan;
+
+ BSSDescriptor_t *pbss_desc =
+ &pmpriv->curr_bss_params.bss_descriptor;
+
+ memset(pmadapter, &region_chan, 0,
+ sizeof(parsed_region_chan_11d_t));
+
+ /*If country IE is present in the associated AP then return the
+ channel list from country IE
+ else return it from the learning table*/
+
+ if (wlan_11d_parse_domain_info(
+ pmadapter, &pbss_desc->country_info,
+ (t_u8)pbss_desc->bss_band,
+ &region_chan) == MLAN_STATUS_SUCCESS) {
+ parsed_region_chan = &region_chan;
+ } else {
+ parsed_region_chan = &pmadapter->parsed_region_chan;
+ }
+
+ PRINTM(MINFO, "no_of_chan=%d\n",
+ parsed_region_chan->no_of_chan);
+
+ for (i = 0;
+ (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM) &&
+ (i < parsed_region_chan->no_of_chan);
+ i++) {
+ chan_no = parsed_region_chan->chan_pwr[i].chan;
+ band = parsed_region_chan->chan_pwr[i].band;
+ PRINTM(MINFO, "band=%d, chan_no=%d\n", band, chan_no);
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan]
+ .channel = (t_u32)chan_no;
+ bss->param.chanlist.cf[bss->param.chanlist.num_of_chan]
+ .freq = (t_u32)wlan_11d_chan_2_freq(
+ pmadapter, chan_no, band);
+ bss->param.chanlist.num_of_chan++;
+ }
+ } else {
+ for (j = 0;
+ (bss->param.chanlist.num_of_chan < MLAN_MAX_CHANNEL_NUM) &&
+ (j < MAX_REGION_CHANNEL_NUM);
+ j++) {
+ cfp = pmadapter->region_channel[j].pcfp;
+ for (i = 0; (bss->param.chanlist.num_of_chan <
+ MLAN_MAX_CHANNEL_NUM) &&
+ pmadapter->region_channel[j].valid && cfp &&
+ (i < pmadapter->region_channel[j].num_cfp);
+ i++) {
+ bss->param.chanlist
+ .cf[bss->param.chanlist.num_of_chan]
+ .channel = (t_u32)cfp->channel;
+ bss->param.chanlist
+ .cf[bss->param.chanlist.num_of_chan]
+ .freq = (t_u32)cfp->freq;
+ bss->param.chanlist.num_of_chan++;
+ cfp++;
+ }
+ }
+ }
+
+ PRINTM(MINFO, "num of channel=%d\n", bss->param.chanlist.num_of_chan);
+
+ LEAVE();
+ return ret;
+}
+
+/** Highest channel used in 2.4GHz band */
+#define MAX_CHANNEL_BAND_B (14)
+
+/** Highest frequency used in 2.4GHz band */
+#define MAX_FREQUENCY_BAND_B (2484)
+
+/**
+ * @brief Set/Get BSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_channel(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = MNULL;
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ chan_freq_power_t *cfp = MNULL;
+ ENTER();
+
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, pmpriv->curr_bss_params.band,
+ (t_u16)pmpriv->curr_bss_params.bss_descriptor.channel);
+ if (cfp) {
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(chan_freq) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+ }
+ if (!bss->param.bss_chan.channel && !bss->param.bss_chan.freq) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pmadapter->adhoc_start_band & BAND_A)
+ pmadapter->adhoc_start_band = BAND_G | BAND_B;
+ if (bss->param.bss_chan.channel) {
+ if (bss->param.bss_chan.channel <= MAX_CHANNEL_BAND_B)
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, BAND_B,
+ (t_u16)bss->param.bss_chan.channel);
+ if (!cfp) {
+ cfp = wlan_find_cfp_by_band_and_channel(
+ pmadapter, BAND_A,
+ (t_u16)bss->param.bss_chan.channel);
+ if (cfp) {
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ } else {
+ if (bss->param.bss_chan.freq <= MAX_FREQUENCY_BAND_B)
+ cfp = wlan_find_cfp_by_band_and_freq(
+ pmadapter, BAND_B, bss->param.bss_chan.freq);
+ if (!cfp) {
+ cfp = wlan_find_cfp_by_band_and_freq(
+ pmadapter, BAND_A, bss->param.bss_chan.freq);
+ if (cfp) {
+ pmadapter->adhoc_start_band = BAND_A;
+ }
+ }
+ }
+ if (!cfp || !cfp->channel) {
+ PRINTM(MERROR, "Invalid channel/freq\n");
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmpriv->adhoc_channel = (t_u8)cfp->channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ bss->param.bss_chan.channel = cfp->channel;
+ bss->param.bss_chan.freq = cfp->freq;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get BSS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bss_mode = pmpriv->bss_mode;
+ pioctl_req->data_read_written =
+ sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ goto exit;
+ }
+
+ if ((pmpriv->bss_mode == bss->param.bss_mode) ||
+ (bss->param.bss_mode == MLAN_BSS_MODE_AUTO)) {
+ PRINTM(MINFO, "Already set to required mode! No change!\n");
+ pmpriv->bss_mode = bss->param.bss_mode;
+ goto exit;
+ }
+
+ if (pmpriv->bss_mode != MLAN_BSS_MODE_AUTO)
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ else
+ ret = wlan_disconnect(pmpriv, pioctl_req, MNULL);
+
+ if (pmpriv->sec_info.authentication_mode != MLAN_AUTH_MODE_AUTO)
+ pmpriv->sec_info.authentication_mode = MLAN_AUTH_MODE_OPEN;
+ pmpriv->bss_mode = bss->param.bss_mode;
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
+ pmpriv->port_ctrl_mode = MTRUE;
+ else
+ pmpriv->port_ctrl_mode = MFALSE;
+ if (pmpriv->bss_mode != MLAN_BSS_MODE_AUTO) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_start(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ t_s32 i = -1;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+
+ ENTER();
+
+ /* Before ASSOC REQ, If "port ctrl" mode is enabled,
+ * move the port to CLOSED state */
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ PRINTM(MINFO, "bss_ioctl_start(): port_state=CLOSED\n");
+ pmpriv->prior_port_status = pmpriv->port_open;
+ pmpriv->port_open = MFALSE;
+ }
+ pmadapter->scan_block = MFALSE;
+
+ if (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA) {
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested SSID in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ if (memcmp(pmadapter,
+ &bss->param.ssid_bssid.bssid,
+ zero_mac, sizeof(zero_mac)))
+ i = wlan_find_ssid_in_list(
+ pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ (t_u8 *)&bss->param.ssid_bssid
+ .bssid,
+ MLAN_BSS_MODE_INFRA);
+ else
+ i = wlan_find_ssid_in_list(
+ pmpriv,
+ &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_INFRA);
+ } else {
+ i = wlan_find_bssid_in_list(
+ pmpriv,
+ (t_u8 *)&bss->param.ssid_bssid.bssid,
+ MLAN_BSS_MODE_INFRA);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(
+ pmpriv, bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+ if (i >= 0) {
+ /* block if upper-layer tries to reconnect before new
+ * scan */
+ if (wlan_11h_get_csa_closed_channel(pmpriv) ==
+ (t_u8)pmadapter->pscan_table[i].channel) {
+ PRINTM(MINFO,
+ "Attempt to reconnect on csa_closed_chan(%d)\n",
+ pmadapter->pscan_table[i].channel);
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto start_ssid_done;
+ }
+ PRINTM(MINFO,
+ "SSID found in scan list ... associating...\n");
+ pmpriv->curr_bss_params.host_mlme =
+ bss->param.ssid_bssid.host_mlme;
+ /* Clear any past association response stored for
+ * application retrieval */
+ pmpriv->assoc_rsp_size = 0;
+ pmpriv->curr_chan_flags =
+ bss->param.ssid_bssid.channel_flags;
+ if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
+ pmpriv->curr_chan_flags |= CHAN_FLAGS_NO_80MHZ;
+ ret = wlan_associate(pmpriv, pioctl_req,
+ &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ PRINTM(MERROR,
+ "SSID not found in scan list: ssid=%s, " MACSTR
+ ", idx=%d\n",
+ bss->param.ssid_bssid.ssid.ssid,
+ MAC2STR(bss->param.ssid_bssid.bssid),
+ (int)bss->param.ssid_bssid.idx);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto start_ssid_done;
+ }
+ } else {
+ /* Adhoc mode */
+ /* If the requested SSID matches current SSID, return */
+ if (bss->param.ssid_bssid.ssid.ssid_len &&
+ (!wlan_ssid_cmp(pmadapter,
+ &pmpriv->curr_bss_params.bss_descriptor.ssid,
+ &bss->param.ssid_bssid.ssid))) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto start_ssid_done;
+ }
+
+ /* Exit Adhoc mode first */
+ PRINTM(MINFO, "Sending Adhoc Stop\n");
+ ret = wlan_disconnect(pmpriv, MNULL, MNULL);
+ if (ret)
+ goto start_ssid_done;
+
+ pmpriv->adhoc_is_link_sensed = MFALSE;
+
+ if (!bss->param.ssid_bssid.idx ||
+ bss->param.ssid_bssid.idx > pmadapter->num_in_scan_table) {
+ /* Search for the requested network in the scan table */
+ if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(
+ pmpriv, &bss->param.ssid_bssid.ssid,
+ MNULL, MLAN_BSS_MODE_IBSS);
+ } else {
+ i = wlan_find_bssid_in_list(
+ pmpriv,
+ (t_u8 *)&bss->param.ssid_bssid.bssid,
+ MLAN_BSS_MODE_IBSS);
+ }
+ } else {
+ /* use bsslist index number to assoicate */
+ i = wlan_is_network_compatible(
+ pmpriv, bss->param.ssid_bssid.idx - 1,
+ pmpriv->bss_mode);
+ }
+
+ if (i >= 0) {
+ PRINTM(MINFO,
+ "Network found in scan list ... joining ...\n");
+ pmpriv->curr_chan_flags =
+ bss->param.ssid_bssid.channel_flags;
+ ret = wlan_adhoc_join(pmpriv, pioctl_req,
+ &pmadapter->pscan_table[i]);
+ if (ret)
+ goto start_ssid_done;
+ } else { /* i >= 0 */
+ PRINTM(MINFO,
+ "Network not found in the list, "
+ "creating adhoc with ssid = %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ pmpriv->curr_chan_flags =
+ bss->param.ssid_bssid.channel_flags;
+ ret = wlan_adhoc_start(pmpriv, pioctl_req,
+ &bss->param.ssid_bssid.ssid);
+ if (ret)
+ goto start_ssid_done;
+ }
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+start_ssid_done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_stop(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = (mlan_ds_bss *)pioctl_req->pbuf;
+
+ ENTER();
+
+ ret = wlan_disconnect(pmpriv, pioctl_req, &bss->param.deauth_param);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IBSS channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_ibss_channel(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->media_connected == MFALSE) {
+ bss->param.bss_chan.channel = pmpriv->adhoc_channel;
+ goto exit;
+ }
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ pmpriv->adhoc_channel = (t_u8)bss->param.bss_chan.channel;
+ pmpriv->intf_state_11h.adhoc_auto_sel_chan = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_CHANNEL,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &bss->param.bss_chan.channel);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Listen Interval
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_bss_ioctl_listen_interval(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ bss->param.listen_interval = pmpriv->listen_interval;
+ else
+ pmpriv->listen_interval = bss->param.listen_interval;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/*
+ * @brief Set/Get beacon interval
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_bss_ioctl_beacon_interval(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.bcn_interval = pmpriv->beacon_period;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.bcn_interval =
+ pmpriv->curr_bss_params.bss_descriptor
+ .beacon_period;
+ } else
+ pmpriv->beacon_period = (t_u16)bss->param.bcn_interval;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ATIM window
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_bss_ioctl_atim_window(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ bss->param.atim_window = pmpriv->atim_window;
+ if (pmpriv->media_connected == MTRUE)
+ bss->param.atim_window =
+ pmpriv->curr_bss_params.bss_descriptor
+ .atim_window;
+ } else
+ pmpriv->atim_window = (t_u16)bss->param.atim_window;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Query embe
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+static mlan_status wlan_query_passphrase(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ssid_bssid *ssid_bssid = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_ds_passphrase *sec_pp;
+ int i = 0;
+ BSSDescriptor_t *pbss_desc;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ ssid_bssid = &bss->param.ssid_bssid;
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_ds_sec_cfg),
+ MLAN_MEM_DEF, (t_u8 **)&sec);
+ if (ret || !sec) {
+ PRINTM(MERROR, "Could not allocate sec!\n");
+ LEAVE();
+ return ret;
+ }
+ memset(pmadapter, sec, 0, sizeof(mlan_ds_sec_cfg));
+ sec_pp = (mlan_ds_passphrase *)&sec->param.passphrase;
+ sec_pp->psk_type = MLAN_PSK_QUERY;
+ if (ssid_bssid->ssid.ssid_len == 0) {
+ i = wlan_find_bssid_in_list(priv, (t_u8 *)&ssid_bssid->bssid,
+ MLAN_BSS_MODE_AUTO);
+ if (i >= 0) {
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy_ext(pmadapter, (t_u8 *)&sec_pp->ssid,
+ &pbss_desc->ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ } else
+ memcpy_ext(pmadapter, (t_u8 *)&sec_pp->bssid,
+ &ssid_bssid->bssid, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ memcpy_ext(pmadapter, (t_u8 *)&sec_pp->ssid, &ssid_bssid->ssid,
+ sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_SUPPLICANT_PMK,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ (t_void *)sec);
+ if (sec)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)sec);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_bss_ioctl_find_bss(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ mlan_ds_bss *bss = MNULL;
+ mlan_ssid_bssid *ssid_bssid = MNULL;
+#endif
+
+ ENTER();
+
+ if (pmpriv->ewpa_query) {
+ if (wlan_query_passphrase(pmpriv, pioctl_req) ==
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "Find BSS ioctl: query passphrase\n");
+ LEAVE();
+ return MLAN_STATUS_PENDING;
+ }
+ }
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ if (!IS_FW_SUPPORT_SUPPLICANT(pmpriv->adapter)) {
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ ssid_bssid = &bss->param.ssid_bssid;
+ supplicantQueryPassphraseAndEnable(pmpriv->psapriv,
+ (t_u8 *)ssid_bssid);
+ }
+#endif
+
+ ret = wlan_find_bss(pmpriv, pioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_bss_ioctl_find_bssid(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int i = 0;
+
+ ENTER();
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ i = wlan_find_bssid_in_list(pmpriv, (t_u8 *)&bss->param.bssid,
+ MLAN_BSS_MODE_AUTO);
+ if (i < 0) {
+ PRINTM(MCMND, "Can not find bssid " MACSTR "\n",
+ MAC2STR((t_u8 *)&bss->param.bssid));
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ PRINTM(MCMND, "Find bssid " MACSTR "\n",
+ MAC2STR((t_u8 *)&bss->param.bssid));
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check if BSS channel is valid for Station's region
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_bss_ioctl_bss_11d_check_channel(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ssid_bssid *ssid_bssid = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ ssid_bssid = &bss->param.ssid_bssid;
+
+ PRINTM(MINFO, "ssid: %s idx:%d\n", ssid_bssid->ssid.ssid,
+ ssid_bssid->idx);
+ PRINTM(MINFO, "band:%d channel:%d\n", (t_u8)ssid_bssid->bss_band,
+ (t_u32)ssid_bssid->channel);
+
+ /* check if this channel is supported in the region */
+ if (!wlan_find_cfp_by_band_and_channel(pmadapter,
+ (t_u8)ssid_bssid->bss_band,
+ (t_u32)ssid_bssid->channel)) {
+ PRINTM(MERROR, "Unsupported Channel for region 0x%x\n",
+ pmadapter->region_code);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief BSS command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_bss_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_bss)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_bss);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_START:
+ status = wlan_bss_ioctl_start(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_STOP:
+ status = wlan_bss_ioctl_stop(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MODE:
+ status = wlan_bss_ioctl_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL:
+ status = wlan_bss_ioctl_channel(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHANNEL_LIST:
+ status = wlan_bss_ioctl_get_channel_list(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MAC_ADDR:
+ status = wlan_bss_ioctl_mac_address(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_MULTICAST_LIST:
+ status = wlan_bss_ioctl_set_multicast_list(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_BSS_FIND_BSS:
+ status = wlan_bss_ioctl_find_bss(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_FIND_BSSID:
+ status = wlan_bss_ioctl_find_bssid(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_BCN_INTERVAL:
+ status = wlan_bss_ioctl_beacon_interval(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_ATIM_WINDOW:
+ status = wlan_bss_ioctl_atim_window(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_IBSS_CHANNEL:
+ status = wlan_bss_ioctl_ibss_channel(pmadapter, pioctl_req);
+ break;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case MLAN_OID_BSS_ROLE:
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->ioctl_pending_q,
+ (pmlan_linked_list)pioctl_req,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pmadapter->pending_ioctl = MTRUE;
+ status = MLAN_STATUS_PENDING;
+ break;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ case MLAN_OID_WIFI_DIRECT_MODE:
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_BSS_LISTEN_INTERVAL:
+ status = wlan_bss_ioctl_listen_interval(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_BSS_REMOVE:
+ status = wlan_bss_ioctl_bss_remove(pmadapter, pioctl_req);
+ break;
+
+ case MLAN_OID_BSS_11D_CHECK_CHANNEL:
+ status = wlan_bss_ioctl_bss_11d_check_channel(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_BSS_CHAN_INFO:
+ status = wlan_bss_ioctl_get_chan_info(pmadapter, pioctl_req);
+ break;
+ default:
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get supported rates
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status
+wlan_rate_ioctl_get_supported_rate(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_rate *rate = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (pioctl_req->action != MLAN_ACT_GET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ if (rate->param.rate_band_cfg.config_bands &&
+ rate->param.rate_band_cfg.bss_mode)
+ wlan_get_active_data_rates(
+ pmpriv, rate->param.rate_band_cfg.bss_mode,
+ rate->param.rate_band_cfg.config_bands,
+ rate->param.rates);
+ else
+ wlan_get_active_data_rates(pmpriv, pmpriv->bss_mode,
+ (pmpriv->bss_mode ==
+ MLAN_BSS_MODE_INFRA) ?
+ pmpriv->config_bands :
+ pmadapter->adhoc_start_band,
+ rate->param.rates);
+ pioctl_req->data_read_written =
+ MLAN_SUPPORTED_RATES + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Rate command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_rate_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_rate)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_rate);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ switch (rate->sub_command) {
+ case MLAN_OID_RATE_CFG:
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_GET_DATA_RATE:
+ status = wlan_rate_ioctl_get_data_rate(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SUPPORTED_RATES:
+ status = wlan_rate_ioctl_get_supported_rate(pmadapter,
+ pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param cmd_no Firmware command number used to retrieve power values
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_power_ioctl_get_power(pmlan_adapter pmadapter,
+ t_u16 cmd_no,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, cmd_no, HostCmd_ACT_GEN_GET, 0,
+ (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_power_ioctl_set_power(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ t_s8 dbm = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
+ if (!power->param.power_cfg.is_power_auto) {
+ dbm = (t_s8)power->param.power_cfg.power_level;
+ if ((dbm < pmpriv->min_tx_power_level) ||
+ (dbm > pmpriv->max_tx_power_level)) {
+ PRINTM(MERROR,
+ "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ dbm, pmpriv->min_tx_power_level,
+ pmpriv->max_tx_power_level);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *)buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ if (!power->param.power_cfg.is_power_auto) {
+ txp_cfg->mode = 1;
+ pg_tlv = (MrvlTypes_Power_Group_t
+ *)(buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = 4 * sizeof(Power_Group_t);
+ pg = (Power_Group_t *)(buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ /* Power group for modulation class HR/DSSS */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x03;
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ pg->power_step = 0;
+ pg->power_min = (t_s8)dbm;
+ pg->power_max = (t_s8)dbm;
+ pg++;
+ /* Power group for modulation class OFDM */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x07;
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pg->power_step = 0;
+ pg->power_min = (t_s8)dbm;
+ pg->power_max = (t_s8)dbm;
+ pg++;
+ /* Power group for modulation class HTBW20 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8)dbm;
+ pg->power_max = (t_s8)dbm;
+ pg->ht_bandwidth = HT_BW_20;
+ pg++;
+ /* Power group for modulation class HTBW40 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (t_s8)dbm;
+ pg->power_max = (t_s8)dbm;
+ pg->ht_bandwidth = HT_BW_40;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ buf);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set extended power configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_power_ioctl_set_power_ext(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_power_cfg *power = MNULL;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *buf = MNULL;
+ HostCmd_DS_TXPWR_CFG *txp_cfg = MNULL;
+ MrvlTypes_Power_Group_t *pg_tlv = MNULL;
+ Power_Group_t *pg = MNULL;
+ mlan_power_group *pwr_grp = MNULL;
+
+ ENTER();
+
+ power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MRVDRV_SIZE_OF_CMD_BUFFER, MLAN_MEM_DEF, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || buf == MNULL) {
+ PRINTM(MERROR,
+ "ALLOC_CMD_BUF: Failed to allocate command buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ txp_cfg = (HostCmd_DS_TXPWR_CFG *)buf;
+ txp_cfg->action = HostCmd_ACT_GEN_SET;
+ pwr_grp = &power->param.power_ext.power_group[0];
+ if (pwr_grp->rate_format == TX_PWR_CFG_AUTO_CTRL_OFF)
+ txp_cfg->mode = 0;
+ else {
+ txp_cfg->mode = 1;
+
+ pg_tlv = (MrvlTypes_Power_Group_t
+ *)(buf + sizeof(HostCmd_DS_TXPWR_CFG));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = sizeof(Power_Group_t);
+ pg = (Power_Group_t *)(buf + sizeof(HostCmd_DS_TXPWR_CFG) +
+ sizeof(MrvlTypes_Power_Group_t));
+ pg->ht_bandwidth = pwr_grp->bandwidth;
+ pg->power_min = (t_s8)pwr_grp->power_min;
+ pg->power_max = (t_s8)pwr_grp->power_max;
+ pg->power_step = (t_s8)pwr_grp->power_step;
+
+ if (pwr_grp->rate_format == MLAN_RATE_FORMAT_LG) {
+ if (pwr_grp->first_rate_ind <=
+ MLAN_RATE_INDEX_HRDSSS3) {
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ } else {
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pwr_grp->first_rate_ind -=
+ MLAN_RATE_INDEX_OFDM0;
+ pwr_grp->last_rate_ind -= MLAN_RATE_INDEX_OFDM0;
+ }
+ pg->first_rate_code = (t_u8)pwr_grp->first_rate_ind;
+ pg->last_rate_code = (t_u8)pwr_grp->last_rate_ind;
+ } else if (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT) {
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->first_rate_code = (t_u8)pwr_grp->first_rate_ind;
+ pg->last_rate_code = (t_u8)pwr_grp->last_rate_ind;
+ } else if (pwr_grp->rate_format == MLAN_RATE_FORMAT_VHT) {
+ pg->modulation_class = MOD_CLASS_VHT;
+ pg->first_rate_code =
+ (t_u8)((pwr_grp->first_rate_ind & 0xF) |
+ ((pwr_grp->nss - 1) << 4));
+ pg->last_rate_code =
+ (t_u8)((pwr_grp->last_rate_ind & 0xF) |
+ ((pwr_grp->nss - 1) << 4));
+ } else {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ if (ret == MLAN_STATUS_FAILURE) {
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ buf);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ if (buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, buf);
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power configuration command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_power_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_power_cfg *power = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_power_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_power_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
+ switch (power->sub_command) {
+ case MLAN_OID_POWER_CFG:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(
+ pmadapter, HostCmd_CMD_TXPWR_CFG, pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power(pmadapter,
+ pioctl_req);
+ break;
+
+ case MLAN_OID_POWER_CFG_EXT:
+ if (pioctl_req->action == MLAN_ACT_GET)
+ status = wlan_power_ioctl_get_power(
+ pmadapter, HostCmd_CMD_TXPWR_CFG, pioctl_req);
+ else
+ status = wlan_power_ioctl_set_power_ext(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_POWER_LOW_POWER_MODE:
+ status = wlan_power_ioctl_set_get_lpm(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set power save configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ps_mode Power save mode
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_pm_ioctl_ps_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req,
+ t_u16 ps_mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 sub_cmd;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ sub_cmd = (pmadapter->ps_mode == Wlan802_11PowerModePSP) ?
+ EN_AUTO_PS :
+ DIS_AUTO_PS;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ sub_cmd, BITMAP_STA_PS,
+ (t_void *)pioctl_req, MNULL);
+ if ((ret == MLAN_STATUS_SUCCESS) && (sub_cmd == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ GET_PS, 0, MNULL, MNULL);
+ }
+ } else {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ GET_PS, 0, (t_void *)pioctl_req, MNULL);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Inactivity timeout extend
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_pm_ioctl_inactivity_timeout(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pmcfg = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pmcfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_INACTIVITY_TIMEOUT_EXT,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (t_void *)&pmcfg->param.inactivity_to);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable Auto Deep Sleep
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_set_auto_deep_sleep(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv =
+ (pmlan_private)pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (((mlan_ds_pm_cfg *)pioctl_req->pbuf)
+ ->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ mode = EN_AUTO_PS;
+ } else {
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ mode = DIS_AUTO_PS;
+ }
+ if (((mlan_ds_pm_cfg *)pioctl_req->pbuf)->param.auto_deep_sleep.idletime)
+ auto_ds.idletime = ((mlan_ds_pm_cfg *)pioctl_req->pbuf)
+ ->param.auto_deep_sleep.idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ /* note: the command could be queued and executed
+ later if there is command in progress. */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16)mode, BITMAP_AUTO_DS,
+ (t_void *)pioctl_req, &auto_ds);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_set_get_sleep_pd(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0, sleep_pd = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ sleep_pd = (t_u16)pm_cfg->param.sleep_period;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+ cmd_action, 0, (t_void *)pioctl_req, &sleep_pd);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_set_get_ps_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32)pmadapter->null_pkt_interval;
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32)pmadapter->multiple_dtim;
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32)pmadapter->local_listen_interval;
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32)pmadapter->bcn_miss_time_out;
+ pm_cfg->param.ps_cfg.delay_to_ps =
+ (t_u32)pmadapter->delay_to_ps;
+ pm_cfg->param.ps_cfg.ps_mode =
+ (t_u32)pmadapter->enhanced_ps_mode;
+ } else {
+ if (pm_cfg->param.ps_cfg.ps_null_interval)
+ pmadapter->null_pkt_interval =
+ (t_u16)pm_cfg->param.ps_cfg.ps_null_interval;
+ else
+ pm_cfg->param.ps_cfg.ps_null_interval =
+ (t_u32)pmadapter->null_pkt_interval;
+ if (pm_cfg->param.ps_cfg.multiple_dtim_interval)
+ pmadapter->multiple_dtim =
+ (t_u16)pm_cfg->param.ps_cfg
+ .multiple_dtim_interval;
+ else
+ pm_cfg->param.ps_cfg.multiple_dtim_interval =
+ (t_u32)pmadapter->multiple_dtim;
+ if (((t_s32)pm_cfg->param.ps_cfg.listen_interval) ==
+ MRVDRV_LISTEN_INTERVAL_DISABLE)
+ pmadapter->local_listen_interval = 0;
+ else if (pm_cfg->param.ps_cfg.listen_interval)
+ pmadapter->local_listen_interval =
+ (t_u16)pm_cfg->param.ps_cfg.listen_interval;
+ else
+ pm_cfg->param.ps_cfg.listen_interval =
+ (t_u32)pmadapter->local_listen_interval;
+ if (pm_cfg->param.ps_cfg.bcn_miss_timeout)
+ pmadapter->bcn_miss_time_out =
+ (t_u16)pm_cfg->param.ps_cfg.bcn_miss_timeout;
+ else
+ pm_cfg->param.ps_cfg.bcn_miss_timeout =
+ (t_u32)pmadapter->bcn_miss_time_out;
+ if (pm_cfg->param.ps_cfg.delay_to_ps != DELAY_TO_PS_UNCHANGED)
+ pmadapter->delay_to_ps =
+ (t_u16)pm_cfg->param.ps_cfg.delay_to_ps;
+ else
+ pm_cfg->param.ps_cfg.delay_to_ps =
+ (t_u32)pmadapter->delay_to_ps;
+ if (pm_cfg->param.ps_cfg.ps_mode)
+ pmadapter->enhanced_ps_mode =
+ (t_u16)pm_cfg->param.ps_cfg.ps_mode;
+ else
+ pm_cfg->param.ps_cfg.ps_mode =
+ (t_u32)pmadapter->enhanced_ps_mode;
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get PS configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_set_get_bcn_timeout(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_BCN_TMO, (t_void *)pioctl_req,
+ &pm_cfg->param.bcn_timeout);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set the sleep parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_set_get_sleep_params(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ cmd_action = HostCmd_ACT_GEN_GET;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &pm_cfg->param.sleep_params);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief config management frame wakeup filter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_config_mgmt_filter(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = MNULL;
+ int i = 0;
+
+ ENTER();
+
+ memset(pmadapter, pmadapter->mgmt_filter, 0,
+ sizeof(mlan_mgmt_frame_wakeup) * MAX_MGMT_FRAME_FILTER);
+ pm_cfg = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ for (i = 0; i < MAX_MGMT_FRAME_FILTER; i++)
+ if (!pm_cfg->param.mgmt_filter[i].type)
+ break;
+ memcpy_ext(pmadapter, (t_u8 *)pmadapter->mgmt_filter,
+ (t_u8 *)pm_cfg->param.mgmt_filter,
+ (i + 1) * sizeof(mlan_mgmt_frame_wakeup),
+ sizeof(pmadapter->mgmt_filter));
+ } else if (pioctl_req->action == MLAN_ACT_GET)
+ PRINTM(MERROR, "Get not support\n");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Power save command handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_pm_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ switch (pm->sub_command) {
+ case MLAN_OID_PM_CFG_IEEE_PS:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ /**Block ieee power save disable command when bt coex
+ * enable*/
+ if (pmadapter->coex_scan && !pm->param.ps_mode)
+ break;
+ if (pm->param.ps_mode)
+ pmadapter->ps_mode = Wlan802_11PowerModePSP;
+ else
+ pmadapter->ps_mode = Wlan802_11PowerModeCAM;
+ status = wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ case MLAN_ACT_GET:
+ status = wlan_pm_ioctl_ps_mode(pmadapter, pioctl_req,
+ pmadapter->ps_mode);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_HS_CFG:
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_INACTIVITY_TO:
+ status =
+ wlan_pm_ioctl_inactivity_timeout(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_DEEP_SLEEP:
+ switch (pioctl_req->action) {
+ case MLAN_ACT_SET:
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds ==
+ DEEP_SLEEP_ON) {
+ PRINTM(MMSG,
+ "Station already in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ } else if (!pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds ==
+ DEEP_SLEEP_OFF) {
+ PRINTM(MMSG,
+ "Station already not in enhanced deep sleep mode\n");
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ status =
+ wlan_set_auto_deep_sleep(pmadapter, pioctl_req);
+ break;
+ case MLAN_ACT_GET:
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds =
+ DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime =
+ pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds =
+ DEEP_SLEEP_OFF;
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ break;
+ case MLAN_OID_PM_CFG_PS_CFG:
+ status = wlan_set_get_ps_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PD:
+ status = wlan_set_get_sleep_pd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_SLEEP_PARAMS:
+ status = wlan_set_get_sleep_params(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_INFO:
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_HS_WAKEUP_REASON:
+ status = wlan_get_hs_wakeup_reason(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_MGMT_FILTER:
+ status = wlan_config_mgmt_filter(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_PM_CFG_BCN_TIMEOUT:
+ status = wlan_set_get_bcn_timeout(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_set_wpa_ie_helper(mlan_private *priv, t_u8 *ie_data_ptr,
+ t_u16 ie_len)
+{
+ ENTER();
+
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wpa_ie)) {
+ PRINTM(MERROR, "failed to copy, WPA IE is too big\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy_ext(priv->adapter, priv->wpa_ie, ie_data_ptr, ie_len,
+ sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = (t_u8)ie_len;
+ PRINTM(MIOCTL, "Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "Wpa_ie", priv->wpa_ie, priv->wpa_ie_len);
+ if (priv->wpa_ie[0] == WPA_IE) {
+ priv->sec_info.wpa_enabled = MTRUE;
+ } else if (priv->wpa_ie[0] == RSN_IE) {
+ priv->sec_info.wpa2_enabled = MTRUE;
+ } else {
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+ } else {
+ memset(priv->adapter, priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ PRINTM(MINFO, "Reset Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len,
+ priv->wpa_ie[0]);
+ priv->sec_info.wpa_enabled = MFALSE;
+ priv->sec_info.wpa2_enabled = MFALSE;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set OSEN IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_set_osen_ie(mlan_private *priv, t_u8 *ie_data_ptr,
+ t_u16 ie_len)
+{
+ ENTER();
+ if (ie_len) {
+ if (ie_len > sizeof(priv->osen_ie)) {
+ PRINTM(MWARN, "failed to copy, WAPI IE is too big\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy_ext(priv->adapter, priv->osen_ie, ie_data_ptr, ie_len,
+ sizeof(priv->osen_ie));
+ priv->osen_ie_len = (t_u8)ie_len;
+ PRINTM(MIOCTL, "Set osen_ie_len=%d IE=%#x\n", priv->osen_ie_len,
+ priv->osen_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "osen_ie", priv->osen_ie,
+ priv->osen_ie_len);
+ priv->sec_info.osen_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->osen_ie, 0, sizeof(priv->osen_ie));
+ priv->osen_ie_len = (t_u8)ie_len;
+ PRINTM(MINFO, "Reset osen_ie_len=%d IE=%#x\n",
+ priv->osen_ie_len, priv->osen_ie[0]);
+ priv->sec_info.osen_enabled = MFALSE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to IE
+ * @param ie_len Length of the IE
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_set_wapi_ie(mlan_private *priv, t_u8 *ie_data_ptr,
+ t_u16 ie_len)
+{
+ ENTER();
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy, WAPI IE is too big\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy_ext(priv->adapter, priv->wapi_ie, ie_data_ptr, ie_len,
+ sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = (t_u8)ie_len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie,
+ priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = (t_u8)ie_len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_sec_ioctl_wapi_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE)
+ wlan_set_wapi_ie(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_set_wapi_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ (t_void *)pioctl_req, &sec->param.encrypt_key);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_port_ctrl_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->port_ctrl_mode)
+ sec->param.port_ctrl_enabled = MTRUE;
+ else
+ sec->param.port_ctrl_enabled = MFALSE;
+ } else {
+ if (sec->param.port_ctrl_enabled) {
+ pmpriv->port_ctrl_mode = MTRUE;
+ pmpriv->port_open = MFALSE;
+ } else {
+ if (pmpriv->port_ctrl_mode == MTRUE) {
+ pmpriv->port_ctrl_mode = MFALSE;
+ /* Cleanup the bypass TX queue */
+ wlan_cleanup_bypass_txq(pmpriv);
+ }
+ }
+ }
+ PRINTM(MINFO, "port_ctrl: port_ctrl_mode=%d port_open=%d\n",
+ pmpriv->port_ctrl_mode, pmpriv->port_open);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get authentication mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_sec_ioctl_auth_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.auth_mode = pmpriv->sec_info.authentication_mode;
+ else
+ pmpriv->sec_info.authentication_mode = sec->param.auth_mode;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get encryption mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_sec_ioctl_encrypt_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ sec->param.encrypt_mode = pmpriv->sec_info.encryption_mode;
+ else
+ pmpriv->sec_info.encryption_mode = sec->param.encrypt_mode;
+
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Random charactor
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ *
+ * @return random charactor
+ */
+t_u8 wlan_get_random_charactor(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+ t_u8 ch = 0;
+
+ ENTER();
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+ ch = (((sec << 16) + usec) % 26) + 'a';
+ LEAVE();
+ return ch;
+}
+
+/**
+ * @brief Set/Get WPA status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_sec_ioctl_wpa_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wpa_ie_len)
+ sec->param.wpa_enabled = MTRUE;
+ else
+ sec->param.wpa_enabled = MFALSE;
+ } else {
+ if (sec->param.wpa_enabled == MFALSE)
+ wlan_set_wpa_ie_helper(pmpriv, MNULL, 0);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WEP keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_set_wep_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ mrvl_wep_key_t *pwep_key = MNULL;
+ int index;
+ int i = 0;
+
+ ENTER();
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+ pwep_key = &pmpriv->wep_key[pmpriv->wep_key_curr_index];
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ index = pmpriv->wep_key_curr_index;
+ sec->param.encrypt_key.key_index = index;
+ } else {
+ if (sec->param.encrypt_key.key_index >= MRVL_NUM_WEP_KEY) {
+ if ((sec->param.encrypt_key.key_remove == MTRUE) &&
+ (sec->param.encrypt_key.key_index <= 5)) {
+ /* call firmware remove key */
+ ret = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ &sec->param.encrypt_key);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ goto exit;
+ }
+ PRINTM(MERROR, "Key_index is invalid\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ index = sec->param.encrypt_key.key_index;
+ }
+
+ if ((sec->param.encrypt_key.key_disable == MTRUE) ||
+ (sec->param.encrypt_key.key_remove == MTRUE)) {
+ pmpriv->sec_info.wep_status = Wlan802_11WEPDisabled;
+ /* remove key */
+ if (sec->param.encrypt_key.key_remove == MTRUE) {
+ memset(pmadapter, &pmpriv->wep_key[index], 0,
+ sizeof(mrvl_wep_key_t));
+ /* call firmware remove key */
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &sec->param.encrypt_key);
+ if (ret)
+ goto exit;
+ }
+ } else {
+ if (sec->param.encrypt_key.key_len) {
+ if ((sec->param.encrypt_key.key_len !=
+ WEP_104_BIT_LEN) &&
+ (sec->param.encrypt_key.key_len !=
+ WEP_40_BIT_LEN)) {
+ PRINTM(MERROR, "Invalid wep key len=%d\n",
+ sec->param.encrypt_key.key_len);
+ /* We will use random key to clear the key
+ * buffer in FW */
+ if (sec->param.encrypt_key.key_len <
+ WEP_40_BIT_LEN)
+ sec->param.encrypt_key.key_len =
+ WEP_40_BIT_LEN;
+ else
+ sec->param.encrypt_key.key_len =
+ WEP_104_BIT_LEN;
+ for (i = 0; i < sec->param.encrypt_key.key_len;
+ i++)
+ sec->param.encrypt_key.key_material[i] =
+ wlan_get_random_charactor(
+ pmadapter);
+ }
+ pwep_key = &pmpriv->wep_key[index];
+ /* Cleanup */
+ memset(pmadapter, pwep_key, 0, sizeof(mrvl_wep_key_t));
+ /* Copy the key in the driver */
+
+ memcpy_ext(pmadapter, pwep_key->key_material,
+ sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len,
+ MRVL_KEY_BUFFER_SIZE_IN_BYTE);
+ pwep_key->key_index = index;
+ pwep_key->key_length = sec->param.encrypt_key.key_len;
+ if (pmpriv->sec_info.wep_status !=
+ Wlan802_11WEPEnabled) {
+ /*
+ * The status is set as Key Absent
+ * so as to make sure we display the
+ * keys when iwlist mlanX key is used
+ */
+ pmpriv->sec_info.wep_status =
+ Wlan802_11WEPKeyAbsent;
+ }
+ }
+ if (sec->param.encrypt_key.is_current_wep_key == MTRUE) {
+ /* Copy the required key as the current key */
+ pwep_key = &pmpriv->wep_key[index];
+ if (!pwep_key->key_length) {
+ if (&pmpriv->sec_info.wpa_enabled ||
+ &pmpriv->sec_info.wpa2_enabled ||
+ &pmpriv->sec_info.wapi_enabled) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto exit;
+ }
+ PRINTM(MERROR,
+ "Key %d not set,so cannot enable it\n",
+ index);
+ pioctl_req->status_code =
+ MLAN_ERROR_CMD_RESP_FAIL;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ pmpriv->wep_key_curr_index = (t_u16)index;
+ pmpriv->sec_info.wep_status = Wlan802_11WEPEnabled;
+ }
+ if (sec->param.encrypt_key.key_flags && pwep_key->key_length) {
+ pmpriv->wep_key_curr_index = (t_u16)index;
+ // Only do this if the key is an xmit key. If the key
+ // is a group key, we might be in wpa/wep mixed mode in
+ // which case we don't want to set wep_status =
+ // Wlan802_11WEPEnabled because that enables WEP at the
+ // MAC controller level and WPA stops working properly.
+ if (sec->param.encrypt_key.key_flags &
+ KEY_FLAG_SET_TX_KEY) {
+ pmpriv->sec_info.wep_status =
+ Wlan802_11WEPEnabled;
+ }
+ }
+ }
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)
+ pmpriv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ pmpriv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ /* Send request to firmware */
+ if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled &&
+ pwep_key->key_length) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &pmpriv->curr_pkt_filter);
+ if (ret)
+ goto exit;
+ if (!sec->param.encrypt_key.key_len) {
+ sec->param.encrypt_key.key_index = pwep_key->key_index;
+ sec->param.encrypt_key.key_len = pwep_key->key_length;
+ memcpy_ext(pmadapter,
+ sec->param.encrypt_key.key_material,
+ pwep_key->key_material,
+ sec->param.encrypt_key.key_len,
+ MLAN_MAX_KEY_LENGTH);
+ }
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ &sec->param.encrypt_key);
+ } else {
+ if (pwep_key->key_length) {
+ if (!sec->param.encrypt_key.key_len) {
+ sec->param.encrypt_key.key_index =
+ pwep_key->key_index;
+ sec->param.encrypt_key.key_len =
+ pwep_key->key_length;
+ memcpy_ext(pmadapter,
+ sec->param.encrypt_key.key_material,
+ pwep_key->key_material,
+ sec->param.encrypt_key.key_len,
+ MLAN_MAX_KEY_LENGTH);
+ }
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &sec->param.encrypt_key);
+ if (ret)
+ goto exit;
+ }
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req,
+ &pmpriv->curr_pkt_filter);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_set_wpa_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ /* Current driver only supports key length of up to 32 bytes */
+ if (sec->param.encrypt_key.key_len > MLAN_MAX_KEY_LENGTH) {
+ PRINTM(MERROR, "Key length is incorrect\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ &sec->param.encrypt_key);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get security keys
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_get_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ int index;
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+
+ if (pmpriv->wep_key_curr_index >= MRVL_NUM_WEP_KEY)
+ pmpriv->wep_key_curr_index = 0;
+
+ if ((pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled) ||
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPKeyAbsent) ||
+ pmpriv->sec_info.ewpa_enabled || pmpriv->sec_info.wpa_enabled ||
+ pmpriv->sec_info.wpa2_enabled) {
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ if (sec->param.encrypt_key.key_index == MLAN_KEY_INDEX_DEFAULT) {
+ if ((pmpriv->wep_key[pmpriv->wep_key_curr_index].key_length) &&
+ (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled)) {
+ index = pmpriv->wep_key_curr_index;
+ sec->param.encrypt_key.key_index =
+ pmpriv->wep_key[index].key_index;
+ memcpy_ext(pmadapter,
+ sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material,
+ pmpriv->wep_key[index].key_length,
+ MLAN_MAX_KEY_LENGTH);
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled) ||
+ (pmpriv->sec_info.ewpa_enabled) ||
+ (pmpriv->sec_info.wpa2_enabled) ||
+ (pmpriv->sec_info.wapi_enabled)) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ memcpy_ext(pmadapter,
+ sec->param.encrypt_key.key_material,
+ pmpriv->aes_key.key_material,
+ pmpriv->aes_key.key_len,
+ MLAN_MAX_KEY_LENGTH);
+ sec->param.encrypt_key.key_len = MIN(
+ MLAN_MAX_KEY_LENGTH, pmpriv->aes_key.key_len);
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ } else {
+ index = sec->param.encrypt_key.key_index;
+ if (pmpriv->wep_key[index].key_length) {
+ sec->param.encrypt_key.key_index =
+ pmpriv->wep_key[index].key_index;
+ memcpy_ext(pmadapter,
+ sec->param.encrypt_key.key_material,
+ pmpriv->wep_key[index].key_material,
+ pmpriv->wep_key[index].key_length,
+ MLAN_MAX_KEY_LENGTH);
+ sec->param.encrypt_key.key_len =
+ MIN(MLAN_MAX_KEY_LENGTH,
+ pmpriv->wep_key[index].key_length);
+ } else if ((pmpriv->sec_info.wpa_enabled) ||
+ (pmpriv->sec_info.ewpa_enabled) ||
+ (pmpriv->sec_info.wpa2_enabled) ||
+ (pmpriv->sec_info.wapi_enabled)) {
+ /* Return WPA enabled */
+ sec->param.encrypt_key.key_disable = MFALSE;
+ } else {
+ sec->param.encrypt_key.key_disable = MTRUE;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set security key(s)
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_encrypt_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (sec->param.encrypt_key.is_wapi_key)
+ status = wlan_sec_ioctl_set_wapi_key(pmadapter,
+ pioctl_req);
+ else if (sec->param.encrypt_key.key_len > MAX_WEP_KEY_SIZE)
+ status = wlan_sec_ioctl_set_wpa_key(pmadapter,
+ pioctl_req);
+ else
+ status = wlan_sec_ioctl_set_wep_key(pmadapter,
+ pioctl_req);
+ } else {
+ status = wlan_sec_ioctl_get_key(pmadapter, pioctl_req);
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Query Encrpyt key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_query_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ /* Current driver only supports get PTK/GTK */
+ if (pmpriv->port_open &&
+ (pmpriv->sec_info.wpa_enabled || pmpriv->sec_info.wpa2_enabled ||
+ pmpriv->sec_info.wapi_enabled)) {
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_GET, KEY_INFO_ENABLED,
+ (t_void *)pioctl_req,
+ &sec->param.encrypt_key);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get esupplicant status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_sec_ioctl_ewpa_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ sec->param.ewpa_enabled = pmpriv->sec_info.ewpa_enabled;
+ } else {
+ pmpriv->sec_info.ewpa_enabled = (t_u8)sec->param.ewpa_enabled;
+ PRINTM(MINFO, "Set: ewpa_enabled = %d\n",
+ (int)pmpriv->sec_info.ewpa_enabled);
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupplicant mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_sec_ioctl_esupp_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u16 cmd_action = 0;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MERROR,
+ "Cannot set esupplicant mode configuration while connected.\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.rsn_mode ||
+ (sec->param.esupp_mode.rsn_mode & RSN_TYPE_VALID_BITS) !=
+ sec->param.esupp_mode.rsn_mode) {
+ PRINTM(MERROR, "Invalid RSN mode\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_paircipher ||
+ (sec->param.esupp_mode.act_paircipher &
+ EMBED_CIPHER_VALID_BITS) !=
+ sec->param.esupp_mode.act_paircipher) {
+ PRINTM(MERROR, "Invalid pairwise cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ if (!sec->param.esupp_mode.act_groupcipher ||
+ (sec->param.esupp_mode.act_groupcipher &
+ EMBED_CIPHER_VALID_BITS) !=
+ sec->param.esupp_mode.act_groupcipher) {
+ PRINTM(MERROR, "Invalid group cipher\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET_CURRENT;
+ }
+
+ /* Send request to firmware */
+ if (sec) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &sec->param.esupp_mode);
+ } else {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SUPPLICANT_PROFILE,
+ cmd_action, 0, (t_void *)pioctl_req,
+ MNULL);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Security configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_sec_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_sec_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_sec_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ switch (sec->sub_command) {
+ case MLAN_OID_SEC_CFG_AUTH_MODE:
+ status = wlan_sec_ioctl_auth_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_MODE:
+ status = wlan_sec_ioctl_encrypt_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WPA_ENABLED:
+ status = wlan_sec_ioctl_wpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_WAPI_ENABLED:
+ status = wlan_sec_ioctl_wapi_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED:
+ status = wlan_sec_ioctl_port_ctrl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ENCRYPT_KEY:
+ status = wlan_sec_ioctl_encrypt_key(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_QUERY_KEY:
+ status = wlan_sec_ioctl_query_key(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_PASSPHRASE:
+ status = wlan_sec_ioctl_passphrase(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_EWPA_ENABLED:
+ status = wlan_sec_ioctl_ewpa_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_SEC_CFG_ESUPP_MODE:
+ status = wlan_sec_ioctl_esupp_mode(pmadapter, pioctl_req);
+ break;
+
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Append/Reset IE buffer.
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command. This function is the main body
+ * for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ * Data is appended to an existing buffer and then wrapped in a passthrough
+ * TLV in the command API to the firmware. The firmware treats the data
+ * as a transparent passthrough to the transmitted management frame.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param ie_data_ptr A pointer to iwreq structure
+ * @param ie_len Length of the IE or IE block passed in ie_data_ptr
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int wlan_set_gen_ie_helper(mlan_private *priv, t_u8 *ie_data_ptr,
+ t_u16 ie_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_VendorHeader_t *pvendor_ie;
+ const t_u8 wpa_oui[] = {0x00, 0x50, 0xf2, 0x01};
+ const t_u8 wps_oui[] = {0x00, 0x50, 0xf2, 0x04};
+ const t_u8 osen_oui[] = {0x50, 0x6f, 0x9a, 0x12};
+ t_u8 i = 0, temp[12] = {0};
+
+ ENTER();
+
+ /* If the passed length is zero, reset the buffer */
+ if (!ie_len) {
+ priv->gen_ie_buf_len = 0;
+ priv->wps.session_enable = MFALSE;
+ wlan_set_wpa_ie_helper(priv, MNULL, 0);
+ wlan_set_wapi_ie(priv, MNULL, 0);
+ wlan_set_osen_ie(priv, MNULL, 0);
+ } else if (!ie_data_ptr) {
+ /* MNULL check */
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ pvendor_ie = (IEEEtypes_VendorHeader_t *)ie_data_ptr;
+ if (pvendor_ie->element_id == EXT_CAPABILITY) {
+ memcpy_ext(priv->adapter, temp, &priv->ext_cap,
+ sizeof(priv->ext_cap), sizeof(temp));
+ for (i = 0;
+ i < MIN(sizeof(priv->ext_cap), pvendor_ie->len);
+ i++)
+ temp[i] |= ie_data_ptr[2 + i];
+ memcpy_ext(priv->adapter, &priv->ext_cap, temp,
+ sizeof(temp), sizeof(priv->ext_cap));
+ } else
+ /* Test to see if it is a WPA IE, if not, then it is a
+ gen IE*/
+ if (((pvendor_ie->element_id == WPA_IE) &&
+ (!memcmp(priv->adapter, pvendor_ie->oui, wpa_oui,
+ sizeof(wpa_oui)))) ||
+ (pvendor_ie->element_id == RSN_IE)) {
+ /* IE is a WPA/WPA2 IE so call set_wpa function */
+ ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+ priv->wps.session_enable = MFALSE;
+ } else if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_set_wapi_ie(priv, ie_data_ptr, ie_len);
+ } else if ((pvendor_ie->element_id == VENDOR_SPECIFIC_221) &&
+ (!memcmp(priv->adapter, pvendor_ie->oui, osen_oui,
+ sizeof(osen_oui)))) {
+ /* IE is a OSEN IE so call set_osen function */
+ ret = wlan_set_osen_ie(priv, ie_data_ptr, ie_len);
+
+ } else if ((pvendor_ie->element_id == WPS_IE) &&
+ (priv->wps.session_enable == MFALSE) &&
+ (!memcmp(priv->adapter, pvendor_ie->oui, wps_oui,
+ sizeof(wps_oui)))) {
+ /*
+ * Discard first two byte (Element ID and Length)
+ * because they are not needed in the case of setting
+ * WPS_IE
+ */
+ if (pvendor_ie->len > 4) {
+ memcpy_ext(priv->adapter,
+ (t_u8 *)&priv->wps.wps_ie,
+ ie_data_ptr, ie_len,
+ sizeof(IEEEtypes_VendorSpecific_t));
+ HEXDUMP("wps_ie", (t_u8 *)&priv->wps.wps_ie,
+ priv->wps.wps_ie.vend_hdr.len + 2);
+ } else {
+ /* Only wps oui exist, reset driver wps buffer
+ */
+ memset(priv->adapter, (t_u8 *)&priv->wps.wps_ie,
+ 0x00, sizeof(priv->wps.wps_ie));
+ PRINTM(MINFO, "wps_ie cleared\n");
+ }
+ } else {
+ /*
+ * Verify that the passed length is not larger than
+ * the available space remaining in the buffer
+ */
+ if (ie_len <
+ (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+ /* Test to see if it is a WPS IE, if so, enable
+ * wps session flag */
+ pvendor_ie =
+ (IEEEtypes_VendorHeader_t *)ie_data_ptr;
+ if ((pvendor_ie->element_id == WPS_IE) &&
+ (!memcmp(priv->adapter, pvendor_ie->oui,
+ wps_oui, sizeof(wps_oui)))) {
+ priv->wps.session_enable = MTRUE;
+ PRINTM(MINFO, "WPS Session Enabled.\n");
+ }
+
+ /* Append the passed data to the end of
+ * the genIeBuffer */
+ memcpy_ext(priv->adapter,
+ priv->gen_ie_buf +
+ priv->gen_ie_buf_len,
+ ie_data_ptr, ie_len,
+ MRVDRV_GENIE_BUF_SIZE -
+ priv->gen_ie_buf_len);
+ /* Increment the stored buffer length by
+ * the size passed */
+ priv->gen_ie_buf_len += ie_len;
+ } else {
+ /* Passed data does not fit in the
+ * remaining buffer space */
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+
+ /* Return MLAN_STATUS_SUCCESS, or MLAN_STATUS_FAILURE for error case */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_misc_ioctl_wws_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ t_u32 enable = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ enable = misc_cfg->param.wws_cfg;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, cmd_action,
+ WwsMode_i, (t_void *)pioctl_req, &enable);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11D status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_11d_cfg_ioctl_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ pcfg_11d = (mlan_ds_11d_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while interface is active.\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MINFO, "11D: 11dcfg SET=%d\n",
+ pcfg_11d->param.enable_11d);
+
+ /* Compare with current settings */
+ if (pmpriv->state_11d.user_enable_11d !=
+ pcfg_11d->param.enable_11d) {
+ ret = wlan_11d_enable(
+ pmpriv, pioctl_req,
+ (state_11d_t)pcfg_11d->param.enable_11d);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ PRINTM(MINFO,
+ "11D: same as current setting, do nothing\n");
+ }
+ } else {
+ pcfg_11d->param.enable_11d =
+ (t_u32)pmpriv->state_11d.user_enable_11d;
+ pioctl_req->data_read_written =
+ sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ PRINTM(MINFO, "11D: 11dcfg GET=%d\n",
+ pcfg_11d->param.enable_11d);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Clear 11D chan table
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_11d_clr_chan_table(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "11D: 11dclrtbl SET\n");
+
+ if (wlan_11d_clear_parsedtable(pmpriv) == MLAN_STATUS_SUCCESS)
+ PRINTM(MINFO,
+ "11D: cleared parsed_region_chan (now no_of_chan=%d)\n",
+ pmadapter->parsed_region_chan.no_of_chan);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 11D configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_11d_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11d_cfg *pcfg_11d = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ status = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *)pioctl_req->pbuf;
+ switch (pcfg_11d->sub_command) {
+ case MLAN_OID_11D_CFG_ENABLE:
+ status = wlan_11d_cfg_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_CLR_CHAN_TABLE:
+ status = wlan_11d_clr_chan_table(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11D_DOMAIN_INFO_EXT:
+ status = wlan_11d_cfg_domain_info(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+exit:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief WPS configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_wps_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wps_cfg *pwps = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wps_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wps_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ pwps = (mlan_ds_wps_cfg *)pioctl_req->pbuf;
+ switch (pwps->sub_command) {
+ case MLAN_OID_WPS_CFG_SESSION:
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pwps->param.wps_session ==
+ MLAN_WPS_CFG_SESSION_START)
+ pmpriv->wps.session_enable = MTRUE;
+ else
+ pmpriv->wps.session_enable = MFALSE;
+ } else {
+ pwps->param.wps_session =
+ (t_u32)pmpriv->wps.session_enable;
+ pioctl_req->data_read_written = sizeof(t_u32);
+ PRINTM(MINFO, "wpscfg GET=%d\n",
+ pwps->param.wps_session);
+ }
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief register memory access handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_reg_mem_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_reg_mem *reg_mem = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_reg_mem)) {
+ PRINTM(MWARN, "MLAN REG_MEM IOCTL length is too short\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_reg_mem);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
+ switch (reg_mem->sub_command) {
+ case MLAN_OID_REG_RW:
+ status = wlan_reg_mem_ioctl_reg_rw(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_EEPROM_RD:
+ status = wlan_reg_mem_ioctl_read_eeprom(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MEM_RW:
+ status = wlan_reg_mem_ioctl_mem_rw(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief 802.11h ad-hoc start channel check
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_11h_channel_check_req(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 chan_width = CHAN_BW_20MHZ;
+ Band_Config_t bandcfg;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmadapter, &bandcfg, 0, sizeof(Band_Config_t));
+ pmpriv->adhoc_state = ADHOC_STARTING;
+
+ if ((pmadapter->adhoc_start_band & BAND_A)) {
+ if (pmpriv->intf_state_11h.adhoc_auto_sel_chan)
+ pmpriv->adhoc_channel =
+ wlan_11h_get_adhoc_start_channel(pmpriv);
+
+ /*
+ * Check if the region and channel requires a channel
+ * availability check.
+ */
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pmpriv->adhoc_channel) &&
+ !wlan_11h_is_channel_under_nop(pmadapter,
+ pmpriv->adhoc_channel)) {
+ /*
+ * Radar detection is required for this channel, make
+ * sure 11h is activated in the firmware
+ */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+
+ /* Check for radar on the channel */
+ if ((pmadapter->chan_bandwidth ==
+ CHANNEL_BW_40MHZ_ABOVE) ||
+ (pmadapter->chan_bandwidth ==
+ CHANNEL_BW_40MHZ_BELOW)) {
+ chan_width = CHAN_BW_40MHZ;
+ if (pmadapter->chanrpt_param_bandcfg) {
+ bandcfg.chan2Offset =
+ pmadapter->chan_bandwidth;
+ }
+ } else if (pmadapter->chan_bandwidth ==
+ CHANNEL_BW_80MHZ)
+ chan_width = CHAN_BW_80MHZ;
+ if (pmadapter->chanrpt_param_bandcfg) {
+ bandcfg.chanWidth = chan_width;
+ bandcfg.chanBand = BAND_5GHZ;
+ } else {
+ *((t_u8 *)&bandcfg) = chan_width;
+ }
+
+ ret = wlan_11h_issue_radar_detect(pmpriv, pioctl_req,
+ pmpriv->adhoc_channel,
+ bandcfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h set/get local power constraint
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status
+wlan_11h_ioctl_local_power_constraint(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+ t_s8 *plocalpower = &pmadapter->state_11h.usr_def_power_constraint;
+
+ ENTER();
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ ds_11hcfg->param.usr_local_power_constraint = *plocalpower;
+ else
+ *plocalpower = ds_11hcfg->param.usr_local_power_constraint;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief 11h configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_11h_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_11h_cfg *ds_11hcfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11H IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+
+ switch (ds_11hcfg->sub_command) {
+ case MLAN_OID_11H_CHANNEL_CHECK:
+ status = wlan_11h_channel_check_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11H_LOCAL_POWER_CONSTRAINT:
+ status = wlan_11h_ioctl_local_power_constraint(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_11H_DFS_TESTING:
+ status = wlan_11h_ioctl_dfs_testing(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_11H_DFS_W53_CFG:
+ status = wlan_11h_ioctl_dfs_w53_cfg(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_misc_ioctl_gen_ie(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ switch (misc->param.gen_ie.type) {
+ case MLAN_IE_TYPE_GEN_IE:
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ misc->param.gen_ie.len = pmpriv->wpa_ie_len;
+ memcpy_ext(pmadapter, misc->param.gen_ie.ie_data,
+ pmpriv->wpa_ie, misc->param.gen_ie.len,
+ MAX_IE_SIZE);
+ } else {
+ wlan_set_gen_ie_helper(pmpriv,
+ misc->param.gen_ie.ie_data,
+ (t_u16)misc->param.gen_ie.len);
+ }
+ break;
+ default:
+ PRINTM(MERROR, "Invalid IE type\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pioctl_req->data_read_written =
+ sizeof(mlan_ds_misc_gen_ie) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Perform warm reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_warm_reset(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pmlan_buffer pmbuf;
+ t_s32 i = 0;
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ENTER();
+ mlan_block_rx_process(pmadapter, MTRUE);
+
+ /* Cancel all pending commands and complete ioctls */
+ if (misc->param.fw_reload)
+ wlan_cancel_all_pending_cmd(pmadapter, MTRUE);
+
+ /** Init all the head nodes and free all the locks here */
+ for (i = 0; i < pmadapter->priv_num; i++)
+ wlan_free_priv(pmadapter->priv[i]);
+
+ while ((pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle, &pmadapter->rx_data_queue,
+ pcb->moal_spin_lock, pcb->moal_spin_unlock))) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ }
+ pmadapter->rx_pkts_queued = 0;
+
+ /* Initialize adapter structure */
+ wlan_init_adapter(pmadapter);
+ pmadapter->hw_status = WlanHardwareStatusInitializing;
+
+ /* Initialize private structures */
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ if (pmadapter->priv[i])
+ wlan_init_priv(pmadapter->priv[i]);
+ }
+ mlan_block_rx_process(pmadapter, MFALSE);
+
+ if (misc->param.fw_reload != MTRUE) {
+ /* Restart the firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_FUNC_SHUTDOWN,
+ HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
+ if (ret)
+ goto done;
+ }
+
+ /* Issue firmware initialize commands for first BSS,
+ * for other interfaces it will be called after getting
+ * the last init command response of previous interface
+ */
+ pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (!pmpriv) {
+ ret = MLAN_STATUS_FAILURE;
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_adapter_get_hw_spec(pmpriv->adapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ LEAVE();
+ return ret;
+ }
+ ret = pmpriv->ops.init_cmd(pmpriv, MTRUE);
+ if (ret == MLAN_STATUS_FAILURE) {
+ LEAVE();
+ return ret;
+ }
+ if (ret == MLAN_STATUS_PENDING)
+ pmadapter->pwarm_reset_ioctl_req = pioctl_req;
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief Reconfigure SDIO multiport aggregation parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static mlan_status wlan_misc_ioctl_sdio_mpa_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_ds_misc_sdio_mpa_ctrl *mpa_ctrl = MNULL;
+
+ ENTER();
+
+ mpa_ctrl = &misc->param.mpa_ctrl;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmpriv->media_connected == MTRUE) {
+ PRINTM(MMSG,
+ "SDIO MPA CTRL: not allowed in connected state\n");
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_enable > 1) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->rx_max_ports > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ if (mpa_ctrl->tx_buf_size || mpa_ctrl->rx_buf_size) {
+ wlan_free_sdio_mpa_buffers(pmadapter);
+
+ if (mpa_ctrl->tx_buf_size > 0)
+ pmadapter->pcard_sd->mpa_tx.buf_size =
+ mpa_ctrl->tx_buf_size;
+
+ if (mpa_ctrl->rx_buf_size > 0)
+ pmadapter->pcard_sd->mpa_rx.buf_size =
+ mpa_ctrl->rx_buf_size;
+
+ if (wlan_alloc_sdio_mpa_buffers(
+ pmadapter,
+ pmadapter->pcard_sd->mpa_tx.buf_size,
+ pmadapter->pcard_sd->mpa_rx.buf_size) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to allocate sdio mp-a buffers\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ }
+
+ if (mpa_ctrl->tx_max_ports > 0)
+ pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit =
+ mpa_ctrl->tx_max_ports;
+ if (mpa_ctrl->rx_max_ports > 0)
+ pmadapter->pcard_sd->mpa_rx.pkt_aggr_limit =
+ mpa_ctrl->rx_max_ports;
+
+ pmadapter->pcard_sd->mpa_tx.enabled = (t_u8)mpa_ctrl->tx_enable;
+ pmadapter->pcard_sd->mpa_rx.enabled = (t_u8)mpa_ctrl->rx_enable;
+
+ } else {
+ mpa_ctrl->tx_enable =
+ (t_u16)pmadapter->pcard_sd->mpa_tx.enabled;
+ mpa_ctrl->rx_enable =
+ (t_u16)pmadapter->pcard_sd->mpa_rx.enabled;
+ mpa_ctrl->tx_buf_size =
+ (t_u16)pmadapter->pcard_sd->mpa_tx.buf_size;
+ mpa_ctrl->rx_buf_size =
+ (t_u16)pmadapter->pcard_sd->mpa_rx.buf_size;
+ mpa_ctrl->tx_max_ports =
+ (t_u16)pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit;
+ mpa_ctrl->rx_max_ports =
+ (t_u16)pmadapter->pcard_sd->mpa_rx.pkt_aggr_limit;
+ }
+
+exit:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get system clock configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_misc_ioctl_sysclock(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else
+ cmd_action = HostCmd_ACT_GEN_SET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (t_void *)&misc->param.sys_clock);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the associate response
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_misc_ioctl_get_assoc_rsp(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if ((pioctl_req->action == MLAN_ACT_GET) && pmpriv->assoc_rsp_size) {
+ memcpy_ext(pmadapter, misc->param.assoc_resp.assoc_resp_buf,
+ pmpriv->assoc_rsp_buf, pmpriv->assoc_rsp_size,
+ ASSOC_RSP_BUF_SIZE);
+ misc->param.assoc_resp.assoc_resp_len =
+ MIN(ASSOC_RSP_BUF_SIZE, pmpriv->assoc_rsp_size);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send function softreset command to firmware
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_misc_ioctl_soft_reset(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the thermal reading
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_thermal(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Thermal reading setting is not allowed!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, cmd_action,
+ Thermal_i, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set subscribe event
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_subscribe_evt(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &misc->param.subscribe_event);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+#define FLTR_BUF_IP_OFFSET 24
+#define FLTR_BUF_IP_OFFSET_2_IP_1 9
+#define FLTR_BUF_IP_OFFSET_2_IP_2 26
+
+/**
+ * @brief Enable/Disable Auto ARP resonse
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param ipv4_addr ipv4 Address
+ * @param num_ipv4 Number of ipv4 Addresses
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_ipaddr_auto_arp_resp(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req,
+ t_u32 *ipv4_addr, t_u8 num_ipv4)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_ds_misc_cmd *hostcmd;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+
+ t_u8 fltr_buf[] = {0x01, 0x10, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x08, 0x06, 0x02, 0x02, 0x14, 0x00, 0x00,
+ 0x00, 0x01, 0x41, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0xc0, 0xa8, 0x01, 0x6d, 0x04, 0x02, 0x2e, 0x00,
+ 0x00, 0x00, 0x01, 0x41, 0x44};
+ t_u8 fltr_buf_2_ip[] = {0x01, 0x10, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0xc0, 0xa8, 0x01, 0x6d, 0x04, 0x02, 0x2e,
+ 0x00, 0x00, 0x00, 0x01, 0x41, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0xc0, 0xa8, 0x02, 0x6d, 0x04, 0x02,
+ 0x2e, 0x00, 0x00, 0x00, 0x01, 0x41, 0x45, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x02, 0x02,
+ 0x14, 0x00, 0x00, 0x00, 0x01, 0x41, 0x44};
+
+ ENTER();
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF,
+ (t_u8 **)&hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *)(buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *)(buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ if (!ipv4_addr) {
+ PRINTM(MINFO, "Disable Auto ARP Response\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ } else {
+ /* Event bit (bit2) of HS conditions should be masked out */
+ mefcmd->criteria = wlan_cpu_to_le32(
+ pmpriv->adapter->hs_cfg.conditions & ~MBIT(2));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ if (num_ipv4 == 1) {
+ memcpy_ext(pmpriv->adapter, filter, fltr_buf,
+ sizeof(fltr_buf), sizeof(fltr_buf));
+ memcpy_ext(pmpriv->adapter, &filter[FLTR_BUF_IP_OFFSET],
+ &ipv4_addr[0], sizeof(t_u32), sizeof(t_u32));
+ buf_len += sizeof(fltr_buf);
+ } else if (num_ipv4 >= 2) {
+ memcpy_ext(pmpriv->adapter, filter, fltr_buf_2_ip,
+ sizeof(fltr_buf_2_ip),
+ sizeof(fltr_buf_2_ip));
+ memcpy_ext(pmpriv->adapter,
+ &filter[FLTR_BUF_IP_OFFSET_2_IP_1],
+ &ipv4_addr[0], sizeof(t_u32), sizeof(t_u32));
+ memcpy_ext(pmpriv->adapter,
+ &filter[FLTR_BUF_IP_OFFSET_2_IP_2],
+ &ipv4_addr[1], sizeof(t_u32), sizeof(t_u32));
+ buf_len += sizeof(fltr_buf_2_ip);
+ }
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req,
+ (t_void *)hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MEF configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_mef_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_mef_cfg *mef_cfg =
+ &((mlan_ds_misc_cfg *)pioctl_req->pbuf)->param.mef_cfg;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ HostCmd_DS_GEN *hostcmd_hdr;
+ HostCmd_DS_MEF_CFG *mefcmd;
+ mlan_ds_misc_cmd *hostcmd = MNULL;
+ t_u32 buf_len = 0;
+ t_u8 *buf, *filter;
+ t_u8 fltr_buf[] = {0x02, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x5e, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x41, 0x06, 0x00, 0x00, 0x00, 0x01, 0xff, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x45, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x33, 0x33, 0x02, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x41, 0x45};
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ /* TODO: need to store for get operation */
+ goto done;
+ }
+
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF,
+ (t_u8 **)&hostcmd);
+
+ if (ret != MLAN_STATUS_SUCCESS || hostcmd == MNULL) {
+ PRINTM(MERROR, "Failed to allocate hostcmd buffer\n");
+ pioctl_req->status_code = MLAN_ERROR_NO_MEM;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(pmpriv->adapter, hostcmd, 0, sizeof(mlan_ds_misc_cmd));
+ buf = hostcmd->cmd;
+
+ /* Prepare hostcmd buffer */
+ hostcmd_hdr = (HostCmd_DS_GEN *)(buf);
+ hostcmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_MEF_CFG);
+ mefcmd = (HostCmd_DS_MEF_CFG *)(buf + S_DS_GEN);
+ buf_len = S_DS_GEN;
+
+ switch (mef_cfg->sub_id) {
+ case MEF_CFG_DISABLE:
+ PRINTM(MINFO, "Disable MEF\n");
+ mefcmd->criteria = wlan_cpu_to_le32(0);
+ mefcmd->nentries = wlan_cpu_to_le16(0);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ break;
+ case MEF_CFG_RX_FILTER_ENABLE:
+ PRINTM(MINFO, "Enable Rx filter\n");
+ mefcmd->criteria = wlan_cpu_to_le32((MBIT(3) | MBIT(0)));
+ mefcmd->nentries = wlan_cpu_to_le16(1);
+ buf_len += sizeof(HostCmd_DS_MEF_CFG);
+ filter = buf + buf_len;
+ memcpy_ext(pmpriv->adapter, filter, fltr_buf, sizeof(fltr_buf),
+ MRVDRV_SIZE_OF_CMD_BUFFER - buf_len);
+ buf_len += sizeof(fltr_buf);
+ break;
+ case MEF_CFG_AUTO_ARP_RESP:
+ PRINTM(MINFO, "Enable auto ARP response\n");
+ /* TODO */
+ break;
+ case MEF_CFG_HOSTCMD:
+ PRINTM(MINFO, "MEF hostcmd from MOAL\n");
+ filter = buf + buf_len;
+ memcpy_ext(pmpriv->adapter, filter, mef_cfg->param.cmd_buf.cmd,
+ mef_cfg->param.cmd_buf.len,
+ MRVDRV_SIZE_OF_CMD_BUFFER - buf_len);
+ buf_len += mef_cfg->param.cmd_buf.len;
+ break;
+ default:
+ PRINTM(MERROR, "Invalid sub ID parameter\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ break;
+ }
+ hostcmd_hdr->size = wlan_cpu_to_le16(buf_len);
+ hostcmd->len = buf_len;
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, (t_void *)pioctl_req,
+ (t_void *)hostcmd);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+done:
+ if (hostcmd)
+ pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ipaddr configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_ipaddr_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 ipv4_addr[MAX_IPADDR] = {0};
+ int i = 0;
+
+ ENTER();
+
+ /* GET operation */
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ memcpy_ext(pmadapter, misc->param.ipaddr_cfg.ip_addr,
+ pmpriv->ip_addr, IPADDR_LEN, IPADDR_LEN);
+ misc->param.ipaddr_cfg.op_code = pmpriv->op_code;
+ goto done;
+ }
+ /* only one IP is supported in current firmware */
+ for (i = 0; i < misc->param.ipaddr_cfg.ip_addr_num; i++) {
+ memcpy_ext(pmadapter, &ipv4_addr[i],
+ misc->param.ipaddr_cfg.ip_addr[i], sizeof(t_u32),
+ sizeof(t_u32));
+ }
+
+ if (misc->param.ipaddr_cfg.op_code != MLAN_IPADDR_OP_IP_REMOVE &&
+ !misc->param.ipaddr_cfg.ip_addr_num) {
+ PRINTM(MERROR, "Invalid IPv4 address\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Save the values in MLAN */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmpriv->op_code = misc->param.ipaddr_cfg.op_code;
+ memcpy_ext(pmadapter, pmpriv->ip_addr,
+ misc->param.ipaddr_cfg.ip_addr, IPADDR_LEN,
+ IPADDR_LEN);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief CFP code configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_cfp_code_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_ds_misc_cfp_code *cfp_code = MNULL;
+ t_u32 region_bg = 0;
+ t_u32 region_a = 0;
+ int i;
+
+ ENTER();
+
+ cfp_code = &misc->param.cfp_code;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
+ PRINTM(MERROR,
+ "ForceRegionRule is set in the on-chip OTP"
+ "memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Save the values in MLAN */
+ if (!cfp_code->cfp_code_bg)
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_bg == region_code_index[i]) {
+ region_bg = cfp_code->cfp_code_bg;
+ break;
+ }
+ }
+ if (!cfp_code->cfp_code_a)
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* Use the region code to search for the index */
+ if (cfp_code->cfp_code_a == region_code_index[i]) {
+ region_a = cfp_code->cfp_code_a;
+ break;
+ }
+ }
+ if (!region_a) {
+ for (i = 0; i < MRVDRV_MAX_CFP_CODE_A; i++) {
+ /* Use the CFP code to search for the index */
+ if (cfp_code->cfp_code_a == cfp_code_index_a[i])
+ break;
+ }
+ if (i >= MRVDRV_MAX_CFP_CODE_A) {
+ PRINTM(MERROR,
+ "CFP Code not identified for A\n");
+ pioctl_req->status_code =
+ MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ pmadapter->cfp_code_bg = (t_u8)cfp_code->cfp_code_bg;
+ pmadapter->cfp_code_a = (t_u8)cfp_code->cfp_code_a;
+ if (region_bg && region_a && (region_bg == region_a))
+ pmadapter->region_code = pmadapter->cfp_code_a;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code,
+ pmadapter->config_bands |
+ pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+ /* GET operation */
+ cfp_code->cfp_code_bg = pmadapter->cfp_code_bg;
+ cfp_code->cfp_code_a = pmadapter->cfp_code_a;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets up country code and downloads CMD to FW
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_ioctl_country_code(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_country_code *country_code = MNULL;
+ mlan_ds_misc_cfg *cfg_misc = MNULL;
+ t_u8 cfp_bg = 0, cfp_a = 0;
+
+ ENTER();
+
+ cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ country_code = &cfg_misc->param.country_code;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pmadapter->otp_region && pmadapter->otp_region->force_reg) {
+ PRINTM(MERROR,
+ "ForceRegionRule is set in the on-chip OTP"
+ "memory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Update region code and table based on country code */
+ if (wlan_misc_country_2_cfp_table_code(
+ pmadapter, country_code->country_code, &cfp_bg,
+ &cfp_a)) {
+ PRINTM(MERROR, "Country code not found!\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmadapter->cfp_code_bg = cfp_bg;
+ pmadapter->cfp_code_a = cfp_a;
+ if (cfp_a)
+ pmadapter->region_code = cfp_a;
+ else if (cfp_bg)
+ pmadapter->region_code = cfp_bg;
+ else
+ pmadapter->region_code = 0;
+ if (wlan_set_regiontable(pmpriv, pmadapter->region_code,
+ pmadapter->config_bands |
+ pmadapter->adhoc_start_band)) {
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy_ext(pmadapter, pmadapter->country_code,
+ country_code->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ } else {
+ /* GET operation */
+ memcpy_ext(pmadapter, country_code->country_code,
+ pmadapter->country_code, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure MFPC and MFPR for management frame protection
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_pmfcfg(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *cfg_misc = MNULL;
+ mlan_ds_misc_pmfcfg *pmfcfg;
+
+ cfg_misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ pmfcfg = &cfg_misc->param.pmfcfg;
+
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ pmpriv->pmfcfg.mfpc = pmfcfg->mfpc;
+ pmpriv->pmfcfg.mfpr = pmfcfg->mfpr;
+ } else {
+ /* GET operation */
+ pmfcfg->mfpc = pmpriv->pmfcfg.mfpc;
+ pmfcfg->mfpr = pmpriv->pmfcfg.mfpr;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief HW ARB Cfg
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_arb_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_ARB_CONFIG, cmd_action, 0,
+ (t_void *)pioctl_req, &(pmisc->param.arb_cfg));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Save tp accounting command configurations.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_tp_state(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ pmadapter->tp_state_on = pmisc->param.tp_state.on;
+ pmadapter->tp_state_drop_point = pmisc->param.tp_state.drop_point;
+
+ LEAVE();
+ return ret;
+}
+
+mlan_status wlan_misc_ioctl_get_sensor_temp(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ cmd_action = HostCmd_ACT_GEN_GET;
+ else {
+ PRINTM(MERROR, " sensor temp only support get operation \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_DS_GET_SENSOR_TEMP, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Gtk Rekey Offload
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_misc_ioctl_gtk_rekey_offload(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_CLEAR)
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ if (!pmpriv->wpa_is_gtk_set) {
+ /* Store the gtk rekey data if it has already set gtk */
+ memcpy_ext(pmadapter, &pmpriv->gtk_rekey,
+ &misc_cfg->param.gtk_rekey,
+ sizeof(mlan_ds_misc_gtk_rekey_data),
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+ LEAVE();
+ return ret;
+ }
+ /* Send request to firmware if it hasn't set gtk yet */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &misc_cfg->param.gtk_rekey);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief cloud keep alive
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req Pointer to the IOCTL request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_misc_cloud_keep_alive(pmlan_adapter pmadapter,
+ mlan_ioctl_req *pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ t_u16 cmd_action = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else if (pioctl_req->action == MLAN_ACT_GET) {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ } else if (pioctl_req->action == MLAN_ACT_RESET) {
+ cmd_action = HostCmd_ACT_GEN_RESET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_REMOVE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_AUTO_TX, cmd_action,
+ OID_CLOUD_KEEP_ALIVE, (t_void *)pioctl_req,
+ &misc->param.keep_alive);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Miscellaneous configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_misc_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = MNULL;
+
+ ENTER();
+
+ if ((pioctl_req == MNULL) || (pioctl_req->pbuf == MNULL)) {
+ PRINTM(MERROR, "Request buffer not found!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (pioctl_req->buf_len < sizeof(mlan_ds_misc_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_misc_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ switch (misc->sub_command) {
+ case MLAN_OID_MISC_GEN_IE:
+ status = wlan_misc_ioctl_gen_ie(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_REGION:
+ status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WARM_RESET:
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &pmadapter->ioctl_pending_q,
+ (pmlan_linked_list)pioctl_req,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pmadapter->pending_ioctl = MTRUE;
+ status = MLAN_STATUS_PENDING;
+ break;
+#ifdef SDIO
+ case MLAN_OID_MISC_SDIO_MPA_CTRL:
+ status = wlan_misc_ioctl_sdio_mpa_ctrl(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_HOST_CMD:
+ status = wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SYS_CLOCK:
+ status = wlan_misc_ioctl_sysclock(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_WWS:
+ status = wlan_misc_ioctl_wws_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_ASSOC_RSP:
+ status = wlan_misc_ioctl_get_assoc_rsp(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_INIT_SHUTDOWN:
+ status = wlan_misc_ioctl_init_shutdown(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SOFT_RESET:
+ status = wlan_misc_ioctl_soft_reset(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CUSTOM_IE:
+ status = wlan_misc_ioctl_custom_ie_list(pmadapter, pioctl_req,
+ MTRUE);
+ break;
+
+ case MLAN_OID_MISC_MAC_CONTROL:
+ status = wlan_misc_ioctl_mac_control(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_MEF_CFG:
+ status = wlan_misc_ioctl_mef_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RX_MGMT_IND:
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+ break;
+#ifdef DEBUG_LEVEL1
+ case MLAN_OID_MISC_DRVDBG:
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_IP_ADDR:
+ status = wlan_misc_ioctl_ipaddr_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CFP_CODE:
+ status = wlan_misc_ioctl_cfp_code_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_COUNTRY_CODE:
+ status = wlan_misc_ioctl_country_code(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_THERMAL:
+ status = wlan_misc_ioctl_thermal(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_SUBSCRIBE_EVENT:
+ status = wlan_misc_ioctl_subscribe_evt(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_HOTSPOT_CFG:
+ status = wlan_misc_hotspot_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_OTP_USER_DATA:
+ status = wlan_misc_otp_user_data(pmadapter, pioctl_req);
+ break;
+#ifdef USB
+ case MLAN_OID_MISC_USB_AGGR_CTRL:
+ status = wlan_misc_ioctl_usb_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_AGGR_CTRL:
+ status = wlan_misc_ioctl_aggr_ctrl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_TXCONTROL:
+ status = wlan_misc_ioctl_txcontrol(pmadapter, pioctl_req);
+ break;
+#ifdef STA_SUPPORT
+ case MLAN_OID_MISC_EXT_CAP_CFG:
+ status = wlan_misc_ext_capa_cfg(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_PMFCFG:
+ status = wlan_misc_pmfcfg(pmadapter, pioctl_req);
+ break;
+#ifdef RX_PACKET_COALESCE
+ case MLAN_OID_MISC_RX_PACKET_COALESCE:
+ status = wlan_misc_ioctl_rx_pkt_coalesce_config(pmadapter,
+ pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_LOW_PWR_MODE:
+ status = wlan_misc_ioctl_low_pwr_mode(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_PMIC_CFG:
+ status = wlan_misc_ioctl_pmic_configure(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CWMODE_CTRL:
+ status = wlan_misc_ioctl_cwmode_ctrl(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_MEF_FLT_CFG:
+ status = wlan_misc_ioctl_mef_flt_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_DFS_REAPTER_MODE:
+ status =
+ wlan_misc_ioctl_dfs_repeater_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_COALESCE_CFG:
+ status = wlan_misc_ioctl_coalesce_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_SENSOR_TEMP:
+ status = wlan_misc_ioctl_get_sensor_temp(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_OPER_CLASS:
+ status = wlan_misc_ioctl_oper_class(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_OPER_CLASS_CHECK:
+ status = wlan_misc_ioctl_operclass_validation(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_MISC_GTK_REKEY_OFFLOAD:
+ status = wlan_misc_ioctl_gtk_rekey_offload(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_MISC_IND_RST_CFG:
+ status = wlan_misc_ioctl_ind_rst_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_TSF:
+ status = wlan_misc_ioctl_get_tsf(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_CHAN_REGION_CFG:
+ status = wlan_misc_chan_reg_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CLOUD_KEEP_ALIVE:
+ status = wlan_misc_cloud_keep_alive(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_DYN_BW:
+ status = wlan_misc_ioctl_dyn_bw(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_FW_DUMP_EVENT:
+ status = wlan_misc_ioctl_fw_dump_event(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_PER_PKT_CFG:
+ status = wlan_misc_per_pkt_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_ROBUSTCOEX:
+ status = wlan_misc_robustcoex(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_DMCS_CONFIG:
+ status = wlan_misc_dmcs_config(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_TX_RX_HISTOGRAM:
+ status = wlan_get_tx_rx_histogram(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_BOOT_SLEEP:
+ status = wlan_misc_bootsleep(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CFP_INFO:
+ status = wlan_get_cfpinfo(pmadapter, pioctl_req);
+ break;
+#if defined(PCIE)
+ case MLAN_OID_MISC_SSU:
+ if (pmadapter->ssu_buf)
+ status = MLAN_STATUS_FAILURE;
+ else
+ status = wlan_misc_ssu(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_MISC_RX_ABORT_CFG:
+ status = wlan_misc_ioctl_rxabortcfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RX_ABORT_CFG_EXT:
+ status = wlan_misc_ioctl_rxabortcfg_ext(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_TX_AMPDU_PROT_MODE:
+ status = wlan_misc_ioctl_tx_ampdu_prot_mode(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG:
+ status = wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_MISC_RATE_ADAPT_CFG:
+ status = wlan_misc_ioctl_rate_adapt_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_CCK_DESENSE_CFG:
+ status = wlan_misc_ioctl_cck_desense_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_REGIONPWR_CFG:
+ status = wlan_get_rgchnpwr_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_GET_CHAN_TRPC_CFG:
+ status = wlan_get_chan_trpc_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RF_TEST_GENERIC:
+ case MLAN_OID_MISC_RF_TEST_TX_CONT:
+ case MLAN_OID_MISC_RF_TEST_TX_FRAME:
+ status = wlan_misc_ioctl_rf_test_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_ARB_CONFIG:
+ status = wlan_misc_ioctl_arb_cfg(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_RANGE_EXT:
+ status = wlan_misc_ioctl_range_ext(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_MISC_TP_STATE:
+ status = wlan_misc_ioctl_tp_state(pmadapter, pioctl_req);
+ break;
+ default:
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get scan configuration parameter
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ * @param action Set/Get
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_set_get_scan_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req,
+ t_u32 action)
+{
+ mlan_ds_scan *scan = MNULL;
+
+ ENTER();
+
+ scan = (mlan_ds_scan *)pioctl_req->pbuf;
+ if (action == MLAN_ACT_SET) {
+ if (scan->param.scan_cfg.scan_type)
+ pmadapter->scan_type =
+ (t_u8)scan->param.scan_cfg.scan_type;
+ if (scan->param.scan_cfg.scan_mode)
+ pmadapter->scan_mode = scan->param.scan_cfg.scan_mode;
+ if (scan->param.scan_cfg.scan_probe)
+ pmadapter->scan_probes =
+ (t_u16)scan->param.scan_cfg.scan_probe;
+ if (scan->param.scan_cfg.scan_time.specific_scan_time)
+ pmadapter->specific_scan_time =
+ (t_u16)scan->param.scan_cfg.scan_time
+ .specific_scan_time;
+ if (scan->param.scan_cfg.scan_time.active_scan_time)
+ pmadapter->active_scan_time =
+ (t_u16)scan->param.scan_cfg.scan_time
+ .active_scan_time;
+ if (scan->param.scan_cfg.scan_time.passive_scan_time)
+ pmadapter->passive_scan_time =
+ (t_u16)scan->param.scan_cfg.scan_time
+ .passive_scan_time;
+ if (scan->param.scan_cfg.passive_to_active_scan)
+ pmadapter->passive_to_active_scan =
+ scan->param.scan_cfg.passive_to_active_scan;
+ if (scan->param.scan_cfg.ext_scan)
+ pmadapter->ext_scan = scan->param.scan_cfg.ext_scan - 1;
+ pmadapter->scan_chan_gap = scan->param.scan_cfg.scan_chan_gap;
+ }
+ scan->param.scan_cfg.scan_type = (t_u32)pmadapter->scan_type;
+ scan->param.scan_cfg.scan_mode = pmadapter->scan_mode;
+ scan->param.scan_cfg.scan_probe = (t_u32)pmadapter->scan_probes;
+ scan->param.scan_cfg.scan_time.specific_scan_time =
+ (t_u32)pmadapter->specific_scan_time;
+ scan->param.scan_cfg.scan_time.active_scan_time =
+ (t_u32)pmadapter->active_scan_time;
+ scan->param.scan_cfg.scan_time.passive_scan_time =
+ (t_u32)pmadapter->passive_scan_time;
+ scan->param.scan_cfg.passive_to_active_scan =
+ pmadapter->passive_to_active_scan;
+ scan->param.scan_cfg.ext_scan = pmadapter->ext_scan + 1;
+ scan->param.scan_cfg.scan_chan_gap = pmadapter->scan_chan_gap;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get scan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_scan_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *pscan;
+
+ ENTER();
+
+ pscan = (mlan_ds_scan *)pioctl_req->pbuf;
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG ||
+ pscan->sub_command == MLAN_OID_SCAN_BGSCAN_CONFIG)
+ goto start_config;
+ if (pmadapter->scan_processing && pioctl_req->action == MLAN_ACT_SET &&
+ pscan->sub_command != MLAN_OID_SCAN_CANCEL) {
+ PRINTM(MINFO, "Scan already in process...\n");
+ LEAVE();
+ return status;
+ }
+
+ if (pmadapter->scan_block && pioctl_req->action == MLAN_ACT_SET) {
+ PRINTM(MERROR, "Scan is blocked during association...\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+start_config:
+ /* Set scan */
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ switch (pscan->sub_command) {
+ case MLAN_OID_SCAN_NORMAL:
+ status = wlan_scan_networks(pmpriv, pioctl_req, MNULL);
+ break;
+ case MLAN_OID_SCAN_SPECIFIC_SSID:
+ status = wlan_scan_specific_ssid(
+ pmpriv, pioctl_req,
+ &pscan->param.scan_req.scan_ssid);
+ break;
+ case MLAN_OID_SCAN_USER_CONFIG:
+ status = wlan_scan_networks(
+ pmpriv, pioctl_req,
+ (wlan_user_scan_cfg *)
+ pscan->param.user_scan.scan_cfg_buf);
+ break;
+ case MLAN_OID_SCAN_CONFIG:
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req,
+ MLAN_ACT_SET);
+ break;
+ case MLAN_OID_SCAN_CANCEL:
+ status = wlan_cancel_pending_scan_cmd(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_OID_SCAN_TABLE_FLUSH:
+ status = wlan_flush_scan_table(pmadapter);
+ break;
+ case MLAN_OID_SCAN_BGSCAN_CONFIG:
+ /* Send request to firmware */
+ status = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ pscan->param.user_scan.scan_cfg_buf);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pscan->sub_command != MLAN_OID_SCAN_TABLE_FLUSH) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CANCEL) &&
+ (pscan->sub_command != MLAN_OID_SCAN_CONFIG)) {
+ PRINTM(MINFO,
+ "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ }
+ /* Get scan */
+ else {
+ if (pscan->sub_command == MLAN_OID_SCAN_CONFIG) {
+ status = wlan_set_get_scan_cfg(pmadapter, pioctl_req,
+ MLAN_ACT_GET);
+ } else if (pscan->sub_command ==
+ MLAN_OID_SCAN_GET_CURRENT_BSS) {
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *)&pmpriv->curr_bss_params.bss_descriptor;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ } else {
+ if (pmadapter->bgscan_reported) {
+ pmadapter->bgscan_reported = MFALSE;
+ /* Clear the previous scan result */
+ memset(pmadapter, pmadapter->pscan_table, 0x00,
+ sizeof(BSSDescriptor_t) *
+ MRVDRV_MAX_BSSID_LIST);
+ pmadapter->num_in_scan_table = 0;
+ pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
+ status = wlan_prepare_cmd(
+ pmpriv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET, 0,
+ (t_void *)pioctl_req, MNULL);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO,
+ "wlan_scan_ioctl: return MLAN_STATUS_PENDING\n");
+ status = MLAN_STATUS_PENDING;
+ }
+ } else {
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *)pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs =
+ pmadapter->age_in_secs;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) +
+ MLAN_SUB_COMMAND_SIZE;
+ pscan->param.scan_resp.pchan_stats =
+ (t_u8 *)pmadapter->pchan_stats;
+ pscan->param.scan_resp.num_in_chan_stats =
+ pmadapter->num_in_chan_stats;
+ }
+ }
+ }
+
+ LEAVE();
+ return status;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param psec_pp A pointer to mlan_ds_passphrase structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_set_ewpa_mode(mlan_private *priv, mlan_ds_passphrase *psec_pp)
+{
+ ENTER();
+
+ if ((psec_pp->psk_type == MLAN_PSK_PASSPHRASE &&
+ psec_pp->psk.passphrase.passphrase_len > 0) ||
+ (psec_pp->psk_type == MLAN_PSK_PMK))
+ priv->sec_info.ewpa_enabled = MTRUE;
+ else
+ priv->sec_info.ewpa_enabled = MFALSE;
+
+ PRINTM(MINFO, "Set ewpa mode = %d\n", priv->sec_info.ewpa_enabled);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Search for a BSS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise
+ * fail
+ */
+mlan_status wlan_find_bss(mlan_private *pmpriv, pmlan_ioctl_req pioctl_req)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ t_u8 mac[MLAN_MAC_ADDR_LENGTH];
+ int i = 0;
+ BSSDescriptor_t *pbss_desc = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+
+ if (memcmp(pmadapter, &bss->param.ssid_bssid.bssid, zero_mac,
+ sizeof(zero_mac))) {
+ if (bss->param.ssid_bssid.ssid.ssid_len) /* ssid & bssid */
+ i = wlan_find_ssid_in_list(
+ pmpriv, &bss->param.ssid_bssid.ssid,
+ (t_u8 *)&bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ else
+ i = wlan_find_bssid_in_list(
+ pmpriv, (t_u8 *)&bss->param.ssid_bssid.bssid,
+ pmpriv->bss_mode);
+ if (i < 0) {
+ memcpy_ext(pmadapter, mac, &bss->param.ssid_bssid.bssid,
+ sizeof(mac), MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MIOCTL, "Can not find bssid " MACSTR "\n",
+ MAC2STR(mac));
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy_ext(pmadapter, &bss->param.ssid_bssid.ssid,
+ &pbss_desc->ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ bss->param.ssid_bssid.rssi = pbss_desc->rssi;
+ bss->param.ssid_bssid.channel = (t_u16)pbss_desc->channel;
+
+ bss->param.ssid_bssid.bss_band = pbss_desc->bss_band;
+ /* index in bss list,start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else if (bss->param.ssid_bssid.ssid.ssid_len) {
+ i = wlan_find_ssid_in_list(pmpriv, &bss->param.ssid_bssid.ssid,
+ MNULL, pmpriv->bss_mode);
+ if (i < 0) {
+ PRINTM(MIOCTL, "Can not find ssid %s\n",
+ bss->param.ssid_bssid.ssid.ssid);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pbss_desc = &pmadapter->pscan_table[i];
+ memcpy_ext(pmadapter, (t_u8 *)&bss->param.ssid_bssid.bssid,
+ (t_u8 *)&pbss_desc->mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ bss->param.ssid_bssid.rssi = pbss_desc->rssi;
+ bss->param.ssid_bssid.channel = (t_u16)pbss_desc->channel;
+
+ bss->param.ssid_bssid.bss_band = pbss_desc->bss_band;
+ /* index in bss list, start from 1 */
+ bss->param.ssid_bssid.idx = i + 1;
+ } else {
+ ret = wlan_find_best_network(pmpriv, &bss->param.ssid_bssid);
+ }
+
+ if (pbss_desc) {
+ /**if rsn do not have ft akm, don't set ft cap and ft md*/
+ if (pbss_desc->pmd_ie &&
+ wlan_ft_akm_is_used(pmpriv, (t_u8 *)pbss_desc->prsn_ie)) {
+ bss->param.ssid_bssid.ft_md = pbss_desc->pmd_ie->mdid;
+ bss->param.ssid_bssid.ft_cap =
+ pbss_desc->pmd_ie->ft_cap;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN station ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+mlan_status wlan_ops_sta_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter)adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ status = wlan_scan_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_BSS:
+ status = wlan_bss_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ status = wlan_radio_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ status = wlan_snmp_mib_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_GET_INFO:
+ status = wlan_get_info_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ status = wlan_sec_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ status = wlan_rate_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_POWER_CFG:
+ status = wlan_power_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ status = wlan_pm_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WMM_CFG:
+ status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_WPS_CFG:
+ status = wlan_wps_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ status = wlan_11d_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_REG_MEM:
+ status = wlan_reg_mem_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ status = wlan_misc_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ status = wlan_11h_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11AC_CFG:
+ status = wlan_11ac_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11AX_CFG:
+ status = wlan_11ax_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_rx.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_rx.c
new file mode 100644
index 000000000000..af9a143e9adf
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_rx.c
@@ -0,0 +1,488 @@
+/** @file mlan_sta_rx.c
+ *
+ * @brief This file contains the handling of RX in MLAN
+ * module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#ifdef DRV_EMBEDDED_SUPPLICANT
+#include "authenticator_api.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Ethernet II header */
+typedef struct {
+ /** Ethernet II header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header length */
+ t_u16 ethertype;
+
+} EthII_Hdr_t;
+
+/** IPv4 ARP request header */
+typedef MLAN_PACK_START struct {
+ /** Hardware type */
+ t_u16 Htype;
+ /** Protocol type */
+ t_u16 Ptype;
+ /** Hardware address length */
+ t_u8 addr_len;
+ /** Protocol address length */
+ t_u8 proto_len;
+ /** Operation code */
+ t_u16 op_code;
+ /** Source mac address */
+ t_u8 src_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Sender IP address */
+ t_u8 src_ip[4];
+ /** Destination mac address */
+ t_u8 dst_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Destination IP address */
+ t_u8 dst_ip[4];
+} MLAN_PACK_END IPv4_ARP_t;
+
+/** IPv6 Nadv packet header */
+typedef MLAN_PACK_START struct {
+ /** IP protocol version */
+ t_u8 version;
+ /** flow label */
+ t_u8 flow_lab[3];
+ /** Payload length */
+ t_u16 payload_len;
+ /** Next header type */
+ t_u8 next_hdr;
+ /** Hot limit */
+ t_u8 hop_limit;
+ /** Source address */
+ t_u8 src_addr[16];
+ /** Destination address */
+ t_u8 dst_addr[16];
+ /** ICMP type */
+ t_u8 icmp_type;
+ /** IPv6 Code */
+ t_u8 ipv6_code;
+ /** IPv6 Checksum */
+ t_u16 ipv6_checksum;
+ /** Flags */
+ t_u32 flags;
+ /** Target address */
+ t_u8 taget_addr[16];
+ /** Reserved */
+ t_u8 rev[8];
+} MLAN_PACK_END IPv6_Nadv_t;
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function check and discard IPv4 and IPv6 gratuitous broadcast
+ * packets
+ *
+ * @param prx_pkt A pointer to RxPacketHdr_t structure of received packet
+ * @param pmadapter A pointer to pmlan_adapter structure
+ * @return TRUE if found such type of packets, FALSE not found
+ */
+static t_u8 discard_gratuitous_ARP_msg(RxPacketHdr_t *prx_pkt,
+ pmlan_adapter pmadapter)
+{
+ t_u8 proto_ARP_type[] = {0x08, 0x06};
+ t_u8 proto_ARP_type_v6[] = {0x86, 0xDD};
+ IPv4_ARP_t *parp_hdr;
+ IPv6_Nadv_t *pNadv_hdr;
+ t_u8 ret = MFALSE;
+
+ /* IPV4 pkt check
+ * A gratuitous ARP is an ARP packet
+ * where the source and destination IP are both set to
+ * the IP of the machine issuing the packet.
+ */
+ if (memcmp(pmadapter, proto_ARP_type, &prx_pkt->eth803_hdr.h803_len,
+ sizeof(proto_ARP_type)) == 0) {
+ parp_hdr = (IPv4_ARP_t *)(&prx_pkt->rfc1042_hdr);
+ /* Graguitous ARP can be ARP request or ARP reply*/
+ if ((parp_hdr->op_code == mlan_htons(0x01)) ||
+ (parp_hdr->op_code == mlan_htons(0x02)))
+ if (memcmp(pmadapter, parp_hdr->src_ip,
+ parp_hdr->dst_ip, 4) == 0)
+ ret = MTRUE;
+ }
+
+ /* IPV6 pkt check
+ * An unsolicited Neighbor Advertisement pkt is
+ * marked by a cleared Solicited Flag
+ */
+ if (memcmp(pmadapter, proto_ARP_type_v6, &prx_pkt->eth803_hdr.h803_len,
+ sizeof(proto_ARP_type_v6)) == 0) {
+ pNadv_hdr = (IPv6_Nadv_t *)(&prx_pkt->rfc1042_hdr);
+ /* Check Nadv type: next header is ICMPv6 and
+ * icmp type is Nadv */
+ if (pNadv_hdr->next_hdr == 0x3A && pNadv_hdr->icmp_type == 0x88)
+ if ((pNadv_hdr->flags & mlan_htonl(0x40000000)) == 0)
+ ret = MTRUE;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ RxPacketHdr_t *prx_pkt;
+ RxPD *prx_pd;
+ int hdr_chop;
+ EthII_Hdr_t *peth_hdr;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = {0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0x00};
+ t_u8 snap_oui_802_h[MLAN_MAC_ADDR_LENGTH] = {0xaa, 0xaa, 0x03,
+ 0x00, 0x00, 0xf8};
+ t_u8 appletalk_aarp_type[2] = {0x80, 0xf3};
+ t_u8 ipx_snap_type[2] = {0x81, 0x37};
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ t_u8 eapol_type[2] = {0x88, 0x8e};
+#endif
+ t_u8 ext_rate_info = 0;
+
+ ENTER();
+
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *)((t_u8 *)prx_pd + prx_pd->rx_pkt_offset);
+
+/** Small debug type */
+#define DBG_TYPE_SMALL 2
+/** Size of debugging structure */
+#define SIZE_OF_DBG_STRUCT 4
+ if (prx_pd->rx_pkt_type == PKT_TYPE_DEBUG) {
+ t_u8 dbg_type;
+ dbg_type = *(t_u8 *)&prx_pkt->eth803_hdr;
+ if (dbg_type == DBG_TYPE_SMALL) {
+ PRINTM(MFW_D, "\n");
+ DBG_HEXDUMP(MFW_D, "FWDBG",
+ (char *)((t_u8 *)&prx_pkt->eth803_hdr +
+ SIZE_OF_DBG_STRUCT),
+ prx_pd->rx_pkt_length);
+ PRINTM(MFW_D, "FWDBG::\n");
+ }
+ goto done;
+ }
+
+ PRINTM(MINFO,
+ "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ HEXDUMP("RX Data: Dest", prx_pkt->eth803_hdr.dest_addr,
+ sizeof(prx_pkt->eth803_hdr.dest_addr));
+ HEXDUMP("RX Data: Src", prx_pkt->eth803_hdr.src_addr,
+ sizeof(prx_pkt->eth803_hdr.src_addr));
+
+ if ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr, snap_oui_802_h,
+ sizeof(snap_oui_802_h)) == 0) ||
+ ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr, rfc1042_eth_hdr,
+ sizeof(rfc1042_eth_hdr)) == 0) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ appletalk_aarp_type, sizeof(appletalk_aarp_type)) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type, ipx_snap_type,
+ sizeof(ipx_snap_type)))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type
+ * (ethertype). The firmware only passes up SNAP frames
+ * converting all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address
+ * right before the snap_type.
+ */
+ peth_hdr =
+ (EthII_Hdr_t *)((t_u8 *)&prx_pkt->eth803_hdr +
+ sizeof(prx_pkt->eth803_hdr) +
+ sizeof(prx_pkt->rfc1042_hdr) -
+ sizeof(prx_pkt->eth803_hdr.dest_addr) -
+ sizeof(prx_pkt->eth803_hdr.src_addr) -
+ sizeof(prx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy_ext(pmadapter, peth_hdr->src_addr,
+ prx_pkt->eth803_hdr.src_addr,
+ sizeof(peth_hdr->src_addr),
+ sizeof(peth_hdr->src_addr));
+ memcpy_ext(pmadapter, peth_hdr->dest_addr,
+ prx_pkt->eth803_hdr.dest_addr,
+ sizeof(peth_hdr->dest_addr),
+ sizeof(peth_hdr->dest_addr));
+
+ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap
+ * header that was removed.
+ */
+ hdr_chop = (t_u32)((t_ptr)peth_hdr - (t_ptr)prx_pd);
+ } else {
+ HEXDUMP("RX Data: LLC/SNAP", (t_u8 *)&prx_pkt->rfc1042_hdr,
+ sizeof(prx_pkt->rfc1042_hdr));
+ if ((priv->hotspot_cfg & HOTSPOT_ENABLED) &&
+ discard_gratuitous_ARP_msg(prx_pkt, pmadapter)) {
+ ret = MLAN_STATUS_SUCCESS;
+ PRINTM(MDATA,
+ "Bypass sending Gratuitous ARP frame to Kernel.\n");
+ goto done;
+ }
+ /* Chop off the RxPD */
+ hdr_chop = (t_u32)((t_ptr)&prx_pkt->eth803_hdr - (t_ptr)prx_pd);
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ * either the reconstructed EthII frame or the 802.2/llc/snap frame
+ */
+ pmbuf->data_len -= hdr_chop;
+ pmbuf->data_offset += hdr_chop;
+ pmbuf->pparent = MNULL;
+ DBG_HEXDUMP(MDAT_D, "RxPD", (t_u8 *)prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "Rx Payload",
+ ((t_u8 *)prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ priv->rxpd_rate = prx_pd->rx_rate;
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+
+#ifdef DRV_EMBEDDED_SUPPLICANT
+ if (supplicantIsEnabled(priv->psapriv) &&
+ (!memcmp(pmadapter, &prx_pkt->eth803_hdr.h803_len, eapol_type,
+ sizeof(eapol_type)))) {
+ // BML_SET_OFFSET(bufDesc, offset);
+ if (ProcessEAPoLPkt(priv->psapriv, pmbuf)) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ ret = MLAN_STATUS_SUCCESS;
+ PRINTM(MMSG,
+ "host supplicant eapol pkt process done.\n");
+
+ LEAVE();
+ return ret;
+ }
+ }
+#endif
+
+ if (MFALSE || priv->rx_pkt_info) {
+ ext_rate_info = (t_u8)(prx_pd->rx_info >> 16);
+ pmbuf->u.rx_info.data_rate =
+ wlan_index_to_data_rate(priv->adapter, prx_pd->rx_rate,
+ prx_pd->rate_info,
+ ext_rate_info);
+
+ pmbuf->u.rx_info.channel =
+ (prx_pd->rx_info & RXPD_CHAN_MASK) >> 5;
+ pmbuf->u.rx_info.antenna = prx_pd->antenna;
+ pmbuf->u.rx_info.rssi = prx_pd->snr - prx_pd->nf;
+ }
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ PRINTM(MERROR,
+ "STA Rx Error: moal_recv_packet returned error\n");
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+#ifdef USB
+ else if (IS_USB(pmadapter->card_type))
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ MNULL, MLAN_USB_EP_DATA,
+ MLAN_STATUS_SUCCESS);
+#endif
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_sta_process_rx_packet(t_void *adapter, pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter)adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
+
+ sta_node *sta_ptr = MNULL;
+ t_u16 adj_rx_rate = 0;
+ t_u8 antenna = 0;
+ ENTER();
+
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *)((t_u8 *)prx_pd + prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) !=
+ (t_u16)pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to
+ * forwarded to app as an event
+ */
+ pmgmt_pkt_hdr = (wlan_mgmt_pkt *)((t_u8 *)prx_pd +
+ prx_pd->rx_pkt_offset);
+ pmgmt_pkt_hdr->frm_len =
+ wlan_le16_to_cpu(pmgmt_pkt_hdr->frm_len);
+
+ if ((pmgmt_pkt_hdr->wlan_header.frm_ctl &
+ IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(
+ pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *)&pmgmt_pkt_hdr->wlan_header,
+ pmgmt_pkt_hdr->frm_len + sizeof(wlan_mgmt_pkt) -
+ sizeof(pmgmt_pkt_hdr->frm_len),
+ prx_pd);
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ if (rx_pkt_type != PKT_TYPE_BAR) {
+ priv->rxpd_rate_info = prx_pd->rate_info;
+ priv->rxpd_rate = prx_pd->rx_rate;
+ priv->rxpd_rx_info = (t_u8)(prx_pd->rx_info >> 16);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ antenna = wlan_adjust_antenna(priv, prx_pd);
+ adj_rx_rate = wlan_adjust_data_rate(
+ priv, priv->rxpd_rate, priv->rxpd_rate_info);
+ pmadapter->callbacks.moal_hist_data_add(
+ pmadapter->pmoal_handle, pmbuf->bss_index,
+ adj_rx_rate, prx_pd->snr, prx_pd->nf, antenna);
+ }
+ }
+
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if ((!IS_11N_ENABLED(priv)) ||
+ memcmp(priv->adapter, priv->curr_addr,
+ prx_pkt->eth803_hdr.dest_addr, MLAN_MAC_ADDR_LENGTH)) {
+ priv->snr = prx_pd->snr;
+ priv->nf = prx_pd->nf;
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+
+ if (queuing_ra_based(priv)) {
+ memcpy_ext(pmadapter, ta, prx_pkt->eth803_hdr.src_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ if (prx_pd->priority < MAX_NUM_TID) {
+ PRINTM(MDATA, "adhoc/tdls packet %p " MACSTR "\n",
+ pmbuf, MAC2STR(ta));
+ sta_ptr = wlan_get_station_entry(priv, ta);
+ if (sta_ptr) {
+ sta_ptr->rx_seq[prx_pd->priority] =
+ prx_pd->seq_num;
+ sta_ptr->snr = prx_pd->snr;
+ sta_ptr->nf = prx_pd->nf;
+ }
+ if (!sta_ptr || !sta_ptr->is_11n_enabled) {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+ }
+ } else {
+ priv->snr = prx_pd->snr;
+ priv->nf = prx_pd->nf;
+ if ((rx_pkt_type != PKT_TYPE_BAR) &&
+ (prx_pd->priority < MAX_NUM_TID))
+ priv->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ memcpy_ext(pmadapter, ta,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ }
+ if ((priv->port_ctrl_mode == MTRUE && priv->port_open == MFALSE) &&
+ (rx_pkt_type != PKT_TYPE_BAR)) {
+ mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num, prx_pd->priority,
+ ta, (t_u8)prx_pd->rx_pkt_type,
+ (t_void *)RX_PKT_DROPPED_IN_FW);
+ if (rx_pkt_type == PKT_TYPE_AMSDU) {
+ pmbuf->data_len = prx_pd->rx_pkt_length;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ wlan_11n_deaggregate_pkt(priv, pmbuf);
+ } else {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ }
+ goto done;
+ }
+ /* Reorder and send to OS */
+ ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num, prx_pd->priority,
+ ta, (t_u8)prx_pd->rx_pkt_type,
+ (void *)pmbuf);
+ if (ret || (rx_pkt_type == PKT_TYPE_BAR))
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+
+done:
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_tx.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_tx.c
new file mode 100644
index 000000000000..737f2baca4ee
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_sta_tx.c
@@ -0,0 +1,326 @@
+/** @file mlan_sta_tx.c
+ *
+ * @brief This file contains the handling of data packet
+ * transmission in MLAN module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *wlan_ops_sta_process_txpd(t_void *priv, pmlan_buffer pmbuf)
+{
+ mlan_private *pmpriv = (mlan_private *)priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ TxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy_ext(pmpriv->adapter, &pkt_type,
+ pmbuf->pbuf + pmbuf->data_offset, sizeof(pkt_type),
+ sizeof(pkt_type));
+ memcpy_ext(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control), sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+
+ if (pmbuf->data_offset <
+ (sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT)) {
+ PRINTM(MERROR,
+ "not enough space for TxPD: headroom=%d pkt_len=%d, required=%d\n",
+ pmbuf->data_offset, pmbuf->data_len,
+ sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr = pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) -
+ pmpriv->intf_hr_len;
+ head_ptr = (t_u8 *)((t_ptr)head_ptr & ~((t_ptr)(DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (TxPD *)(head_ptr + pmpriv->intf_hr_len);
+ memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD));
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+ plocal_tx_pd->tx_pkt_length = (t_u16)pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8)pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority <
+ NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control =
+ pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+ if (pmadapter->pps_uapsd_mode) {
+ if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
+ pmadapter->tx_lock_flag = MTRUE;
+ plocal_tx_pd->flags =
+ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset = (t_u16)(
+ (t_ptr)pmbuf->pbuf + pmbuf->data_offset - (t_ptr)plocal_tx_pd);
+
+ if (!plocal_tx_pd->tx_control) {
+ /* TxCtrl set by user or default */
+ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
+ }
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16)pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+
+ if (pmbuf->flags & MLAN_BUF_FLAG_TX_STATUS) {
+ plocal_tx_pd->tx_control_1 |= pmbuf->tx_seq_num << 8;
+ plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS;
+ }
+ if (pmbuf->flags & MLAN_BUF_FLAG_TX_CTRL) {
+ if (pmbuf->u.tx_info.data_rate) {
+ plocal_tx_pd->tx_control |=
+ (wlan_ieee_rateid_to_mrvl_rateid(
+ pmpriv, pmbuf->u.tx_info.data_rate,
+ MNULL)
+ << 16);
+ plocal_tx_pd->tx_control |= TXPD_TXRATE_ENABLE;
+ }
+ plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.channel << 21;
+ if (pmbuf->u.tx_info.bw) {
+ plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.bw << 16;
+ plocal_tx_pd->tx_control_1 |= TXPD_BW_ENABLE;
+ }
+ if (pmbuf->u.tx_info.tx_power.tp.hostctl)
+ plocal_tx_pd->tx_control |=
+ (t_u32)pmbuf->u.tx_info.tx_power.val;
+ if (pmbuf->u.tx_info.retry_limit) {
+ plocal_tx_pd->tx_control |= pmbuf->u.tx_info.retry_limit
+ << 8;
+ plocal_tx_pd->tx_control |= TXPD_RETRY_ENABLE;
+ }
+ }
+ endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32)(head_ptr - pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function tells firmware to send a NULL data packet.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param flags Transmit Pkt Flags
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
+ * failure
+ */
+mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags)
+{
+ pmlan_adapter pmadapter = MNULL;
+ TxPD *ptx_pd;
+/* sizeof(TxPD) + Interface specific header */
+#define NULL_PACKET_HDR 256
+ t_u32 data_len = NULL_PACKET_HDR;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 *ptr;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pmadapter = priv->adapter;
+
+ if (pmadapter->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (pmadapter->data_sent == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0,
+ MOAL_MALLOC_BUFFER);
+ if (!pmbuf) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memset(pmadapter, pmbuf->pbuf, 0, data_len);
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ pmbuf->flags |= MLAN_BUF_FLAG_NULL_PKT;
+ ptr = pmbuf->pbuf + pmbuf->data_offset;
+ pmbuf->data_len = sizeof(TxPD) + priv->intf_hr_len;
+ ptx_pd = (TxPD *)(ptr + priv->intf_hr_len);
+ ptx_pd->tx_control = priv->pkt_tx_ctrl;
+ ptx_pd->flags = flags;
+ ptx_pd->priority = WMM_HIGHEST_PRIORITY;
+ ptx_pd->tx_pkt_offset = sizeof(TxPD);
+ /* Set the BSS number to TxPD */
+ ptx_pd->bss_num = GET_BSS_NUM(priv);
+ ptx_pd->bss_type = priv->bss_type;
+
+ endian_convert_TxPD(ptx_pd);
+
+ ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf, MNULL);
+
+ switch (ret) {
+#ifdef USB
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ break;
+#endif
+ case MLAN_STATUS_RESOURCE:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ goto done;
+ case MLAN_STATUS_FAILURE:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ goto done;
+ case MLAN_STATUS_SUCCESS:
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n");
+ pmadapter->tx_lock_flag = MTRUE;
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->tx_lock_flag = MTRUE;
+ break;
+ default:
+ break;
+ }
+
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
+ DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + priv->intf_hr_len);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks if we need to send last packet indication.
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MTRUE or MFALSE
+ */
+t_u8 wlan_check_last_packet_indication(pmlan_private priv)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 ret = MFALSE;
+ t_u8 prop_ps = MTRUE;
+
+ ENTER();
+
+ if (!pmadapter->sleep_period.period) {
+ LEAVE();
+ return ret;
+ }
+ if (wlan_bypass_tx_list_empty(pmadapter) &&
+ wlan_wmm_lists_empty(pmadapter)) {
+ if (((priv->curr_bss_params.wmm_uapsd_enabled == MTRUE) &&
+ priv->wmm_qosinfo) ||
+ prop_ps)
+
+ ret = MTRUE;
+ }
+ if (ret && !pmadapter->cmd_sent && !pmadapter->curr_cmd &&
+ !wlan_is_cmd_pending(pmadapter)) {
+ pmadapter->delay_null_pkt = MFALSE;
+ ret = MTRUE;
+ } else {
+ ret = MFALSE;
+ pmadapter->delay_null_pkt = MTRUE;
+ }
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_txrx.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_txrx.c
new file mode 100644
index 000000000000..a8c93d5322db
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_txrx.c
@@ -0,0 +1,424 @@
+/**
+ * @file mlan_txrx.c
+ *
+ * @brief This file contains the handling of TX/RX in MLAN
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/*************************************************************
+Change Log:
+ 05/11/2009: initial version
+************************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = MNULL;
+ RxPD *prx_pd;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+
+ ENTER();
+
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+ /* Get the BSS number from RxPD, get corresponding priv */
+ priv = wlan_get_priv_by_id(pmadapter, prx_pd->bss_num & BSS_NUM_MASK,
+ prx_pd->bss_type);
+ if (!priv)
+ priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pmbuf->bss_index = priv->bss_index;
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
+ ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to device
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ * @param tx_param A pointer to mlan_tx_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
+ * failure
+ */
+mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
+ mlan_tx_param *tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u8 *head_ptr = MNULL;
+#ifdef DEBUG_LEVEL1
+ t_u32 sec = 0, usec = 0;
+#endif
+#ifdef STA_SUPPORT
+ PTxPD plocal_tx_pd = MNULL;
+#endif
+
+ ENTER();
+ head_ptr = (t_u8 *)priv->ops.process_txpd(priv, pmbuf);
+ if (!head_ptr) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ plocal_tx_pd = (TxPD *)(head_ptr + priv->intf_hr_len);
+#endif
+ if (pmadapter->tp_state_on)
+ pmadapter->callbacks.moal_tp_accounting(pmadapter->pmoal_handle,
+ pmbuf, 4);
+ if (pmadapter->tp_state_drop_point == 4)
+ goto done;
+ else {
+ ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf,
+ tx_param);
+ }
+done:
+ switch (ret) {
+#ifdef USB
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
+ MIN(pmbuf->data_len + sizeof(TxPD),
+ MAX_DATA_DUMP_LEN));
+ break;
+#endif
+ case MLAN_STATUS_RESOURCE:
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ pmadapter->pps_uapsd_mode &&
+ (pmadapter->tx_lock_flag == MTRUE)) {
+ pmadapter->tx_lock_flag = MFALSE;
+ if (plocal_tx_pd != MNULL)
+ plocal_tx_pd->flags = 0;
+ }
+#endif
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
+ MIN(pmbuf->data_len + sizeof(TxPD),
+ MAX_DATA_DUMP_LEN));
+ break;
+ case MLAN_STATUS_SUCCESS:
+ DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
+ MIN(pmbuf->data_len + sizeof(TxPD),
+ MAX_DATA_DUMP_LEN));
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ default:
+ break;
+ }
+
+ if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
+ PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet send completion handling
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_write_data_complete(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf, mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+ if (!pmadapter || !pmbuf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcb = &pmadapter->callbacks;
+
+ if ((pmbuf->buf_type == MLAN_BUF_TYPE_DATA) ||
+ (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)) {
+ PRINTM(MINFO, "wlan_write_data_complete: DATA %p\n", pmbuf);
+#if defined(USB)
+ if ((pmbuf->flags & MLAN_BUF_FLAG_USB_TX_AGGR) &&
+ pmbuf->use_count) {
+ pmlan_buffer pmbuf_next;
+ t_u32 i, use_count = pmbuf->use_count;
+ for (i = 0; i <= use_count; i++) {
+ pmbuf_next = pmbuf->pnext;
+ if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF)
+ pcb->moal_send_packet_complete(
+ pmadapter->pmoal_handle, pmbuf,
+ status);
+ else
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ pmbuf = pmbuf_next;
+ }
+ } else {
+#endif
+ if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF) {
+ /* pmbuf was allocated by MOAL */
+ pcb->moal_send_packet_complete(
+ pmadapter->pmoal_handle, pmbuf, status);
+ } else {
+ /* pmbuf was allocated by MLAN */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+#if defined(USB)
+ }
+#endif
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Packet receive completion callback handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to mlan_buffer structure
+ * @param status Callback status
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf, mlan_status status)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb;
+
+ ENTER();
+
+ MASSERT(pmadapter && pmbuf);
+ if (!pmadapter || !pmbuf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ pcb = &pmadapter->callbacks;
+ MASSERT(pmbuf->bss_index < pmadapter->priv_num);
+
+ if (pmbuf->pparent) {
+ /** we will free the pparaent at the end of deaggr */
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ } else {
+ pmadapter->ops.data_complete(pmadapter, pmbuf, status);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add packet to Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void wlan_add_buf_bypass_txqueue(mlan_adapter *pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ ENTER();
+
+ if (pmbuf->buf_type != MLAN_BUF_TYPE_RAW_DATA)
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ pmadapter->bypass_pkt_count++;
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->bypass_txq,
+ (pmlan_linked_list)pmbuf, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ LEAVE();
+}
+
+/**
+ * @brief Check if packets are available in Bypass TX queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+INLINE t_u8 wlan_bypass_tx_list_empty(mlan_adapter *pmadapter)
+{
+ return (pmadapter->bypass_pkt_count) ? MFALSE : MTRUE;
+}
+
+/**
+ * @brief Clean up the By-pass TX queue
+ *
+ * @param priv Pointer to the mlan_private data struct
+ *
+ * @return N/A
+ */
+t_void wlan_cleanup_bypass_txq(mlan_private *priv)
+{
+ pmlan_buffer pmbuf;
+ mlan_adapter *pmadapter = priv->adapter;
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
+ &priv->bypass_txq, MNULL,
+ MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &priv->bypass_txq,
+ (pmlan_linked_list)pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ pmadapter->bypass_pkt_count--;
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ LEAVE();
+}
+
+/**
+ * @brief Transmit the By-passed packet awaiting in by-pass queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+t_void wlan_process_bypass_tx(pmlan_adapter pmadapter)
+{
+ pmlan_buffer pmbuf;
+ mlan_tx_param tx_param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_private priv;
+ int j = 0;
+ ENTER();
+ do {
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ priv = pmadapter->priv[j];
+ if (priv) {
+ pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle,
+ &priv->bypass_txq,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ if (pmbuf) {
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ pmadapter->bypass_pkt_count--;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ PRINTM(MINFO,
+ "Dequeuing bypassed packet %p\n",
+ pmbuf);
+ if (wlan_bypass_tx_list_empty(
+ pmadapter))
+ tx_param.next_pkt_len = 0;
+ else
+ tx_param.next_pkt_len =
+ pmbuf->data_len;
+ status = wlan_process_tx(
+ pmadapter->priv[pmbuf->bss_index],
+ pmbuf, &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /* Queue the packet again so
+ * that it will be TX'ed later
+ */
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ pmadapter->bypass_pkt_count++;
+ util_enqueue_list_head(
+ pmadapter->pmoal_handle,
+ &priv->bypass_txq,
+ (pmlan_linked_list)pmbuf,
+ pmadapter->callbacks
+ .moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->bypass_txq.plock);
+ }
+ break;
+ } else {
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+ }
+ }
+ } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag &&
+ !wlan_bypass_tx_list_empty(pmadapter));
+ LEAVE();
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap.h
new file mode 100644
index 000000000000..f6f85b851591
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap.h
@@ -0,0 +1,57 @@
+/** @file mlan_uap.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of uap functionalities
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#ifndef _MLAN_UAP_H_
+#define _MLAN_UAP_H_
+
+mlan_status wlan_uap_get_channel(pmlan_private pmpriv);
+
+mlan_status wlan_uap_set_channel(pmlan_private pmpriv,
+ Band_Config_t uap_band_cfg, t_u8 channel);
+
+mlan_status wlan_uap_get_beacon_dtim(pmlan_private pmpriv);
+
+mlan_status wlan_ops_uap_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req);
+
+mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pioctl_buf, t_void *pdata_buf,
+ t_void *pcmd_buf);
+
+mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no,
+ t_void *pcmd_buf, t_void *pioctl);
+
+mlan_status wlan_ops_uap_process_rx_packet(t_void *adapter, pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_process_event(t_void *priv);
+
+t_void *wlan_ops_uap_process_txpd(t_void *priv, pmlan_buffer pmbuf);
+
+mlan_status wlan_ops_uap_init_cmd(t_void *priv, t_u8 first_bss);
+
+#endif /* _MLAN_UAP_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_cmdevent.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_cmdevent.c
new file mode 100644
index 000000000000..1f905eb56b33
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_cmdevent.c
@@ -0,0 +1,5587 @@
+/** @file mlan_uap_cmdevent.c
+ *
+ * @brief This file contains the handling of AP mode command and event
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif /* SDIO */
+#include "mlan_11n.h"
+#include "mlan_11h.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+#include "authenticator_api.h"
+#endif
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function prepares command of BAND_STEERING_CFG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_set_get_band_steering_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ t_void *pdata_buf)
+{
+ mlan_ds_band_steer_cfg *pband_steer_cfg =
+ (mlan_ds_band_steer_cfg *)pdata_buf;
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BAND_STEERING);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_BAND_STEERING) + S_DS_GEN);
+ cmd->params.band_steer_info.state = pband_steer_cfg->state;
+ cmd->params.band_steer_info.block_2g_prb_req =
+ pband_steer_cfg->block_2g_prb_req;
+ cmd->params.band_steer_info.max_btm_req_allowed =
+ pband_steer_cfg->max_btm_req_allowed;
+ cmd->params.band_steer_info.action = cmd_action;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of HostCmd_CMD_802_11_BAND_STEERING
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_set_get_band_steering_cfg(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_BAND_STEERING *pband_steer_info =
+ &resp->params.band_steer_info;
+ mlan_ds_misc_cfg *pband_steer;
+
+ ENTER();
+
+ pband_steer = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ pband_steer->param.band_steer_cfg.action = pband_steer_info->action;
+ pband_steer->param.band_steer_cfg.state = pband_steer_info->state;
+ pband_steer->param.band_steer_cfg.block_2g_prb_req =
+ pband_steer_info->block_2g_prb_req;
+ pband_steer->param.band_steer_cfg.max_btm_req_allowed =
+ pband_steer_info->max_btm_req_allowed;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of BEACON_STUCK_CFG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_set_get_beacon_stuck_cfg(IN pmlan_private pmpriv,
+ IN HostCmd_DS_COMMAND *cmd,
+ IN t_u16 cmd_action,
+ IN t_void *pdata_buf)
+{
+ HostCmd_DS_BEACON_STUCK_CFG *pbeacon_stuck_param_cfg =
+ (HostCmd_DS_BEACON_STUCK_CFG *)(pdata_buf + sizeof(t_u32));
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_UAP_BEACON_STUCK_CFG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_BEACON_STUCK_CFG) +
+ S_DS_GEN);
+ cmd->params.beacon_stuck_cfg.beacon_stuck_detect_count =
+ pbeacon_stuck_param_cfg->beacon_stuck_detect_count;
+ cmd->params.beacon_stuck_cfg.recovery_confirm_count =
+ pbeacon_stuck_param_cfg->recovery_confirm_count;
+ cmd->params.beacon_stuck_cfg.action = cmd_action;
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle response of HostCmd_CMD_UAP_BEACON_STUCK_CFG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp Pointer to command response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ret_set_get_beacon_stuck_cfg(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ HostCmd_DS_BEACON_STUCK_CFG *pbeacon_stuck_param_cfg =
+ &resp->params.beacon_stuck_cfg;
+ mlan_ds_misc_cfg *pbeacon_stuck;
+
+ ENTER();
+
+ pbeacon_stuck = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+
+ pbeacon_stuck->param.beacon_stuck_cfg.action =
+ pbeacon_stuck_param_cfg->action;
+ pbeacon_stuck->param.beacon_stuck_cfg.beacon_stuck_detect_count =
+ pbeacon_stuck_param_cfg->beacon_stuck_detect_count;
+ pbeacon_stuck->param.beacon_stuck_cfg.recovery_confirm_count =
+ pbeacon_stuck_param_cfg->recovery_confirm_count;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response error
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to command buffer
+ *
+ * @return N/A
+ */
+static mlan_status uap_process_cmdresp_error(mlan_private *pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#if defined(USB)
+ t_u8 i;
+#endif
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ if (resp->command != HostCmd_CMD_WMM_PARAM_CONFIG ||
+ resp->command != HostCmd_CMD_CHAN_REGION_CFG)
+ PRINTM(MERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
+ if (pioctl_buf)
+ pioctl_buf->status_code = resp->result;
+ /*
+ * Handling errors here
+ */
+ switch (resp->command) {
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ pmadapter->pcard_sd->sdio_rx_aggr_enable = MFALSE;
+ PRINTM(MMSG, "FW don't support SDIO single port rx aggr\n");
+ break;
+#endif
+
+ case HOST_CMD_APCMD_SYS_CONFIGURE: {
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *)&resp->params.sys_config;
+ t_u16 resp_len = 0, travel_len = 0, index;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ custom_ie *cptr;
+
+ if (!pioctl_buf || (pioctl_buf->req_id != MLAN_IOCTL_MISC_CFG))
+ break;
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ if ((pioctl_buf->action == MLAN_ACT_SET) &&
+ (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)) {
+ cust_ie = (mlan_ds_misc_custom_ie *)
+ sys_config->tlv_buffer;
+ if (cust_ie) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len =
+ wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(
+ cust_ie->ie_data_list[0]
+ .ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr = (custom_ie
+ *)(((t_u8 *)cust_ie
+ ->ie_data_list) +
+ travel_len);
+ index = cptr->ie_index =
+ wlan_le16_to_cpu(
+ cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_le16_to_cpu(
+ cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(
+ cptr->ie_length);
+ travel_len += cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ resp_len -= cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ if ((pmpriv->mgmt_ie[index]
+ .mgmt_subtype_mask ==
+ cptr->mgmt_subtype_mask) &&
+ (pmpriv->mgmt_ie[index].ie_length ==
+ cptr->ie_length) &&
+ !memcmp(pmpriv->adapter,
+ pmpriv->mgmt_ie[index]
+ .ie_buffer,
+ cptr->ie_buffer,
+ cptr->ie_length)) {
+ PRINTM(MERROR,
+ "set custom ie fail, remove ie index :%d\n",
+ index);
+ memset(pmadapter,
+ &pmpriv->mgmt_ie[index],
+ 0, sizeof(custom_ie));
+ }
+ }
+ }
+ }
+ } break;
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ for (i = 0; i < MAX_USB_TX_PORT_NUM; i++)
+ pmadapter->pcard_usb->usb_tx_aggr[i]
+ .aggr_ctrl.enable = MFALSE;
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable =
+ MFALSE;
+ }
+#endif
+ break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = MLAN_STATUS_SUCCESS;
+ PRINTM(MCMND, "FW don't support chan region cfg command!\n");
+ break;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR)
+ case HostCmd_CMD_CRYPTO:
+ PRINTM(MCMND, "crypto cmd result=0x%x!\n", resp->result);
+ ret = wlan_ret_crypto(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ wlan_request_cmd_lock(pmadapter);
+ wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
+ pmadapter->curr_cmd = MNULL;
+ wlan_release_cmd_lock(pmadapter);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will return the pointer to station entry in station
+ * list table which matches the give mac address
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return A pointer to structure sta_node
+ */
+void wlan_notify_station_deauth(mlan_private *priv)
+{
+ sta_node *sta_ptr;
+ t_u8 event_buf[100];
+ mlan_event *pevent = (mlan_event *)event_buf;
+ t_u8 *pbuf;
+
+ ENTER();
+ sta_ptr = (sta_node *)util_peek_list(
+ priv->adapter->pmoal_handle, &priv->sta_list,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+ if (!sta_ptr) {
+ LEAVE();
+ return;
+ }
+ while (sta_ptr != (sta_node *)&priv->sta_list) {
+ memset(priv->adapter, event_buf, 0, sizeof(event_buf));
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH + 2;
+ pbuf = (t_u8 *)pevent->event_buf;
+ /* reason field set to 0, Unspecified */
+ memcpy_ext(priv->adapter, pbuf + 2, sta_ptr->mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ wlan_recv_event(priv, pevent->event_id, pevent);
+ sta_ptr = sta_ptr->pnext;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command of hs_cfg.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_802_11_hs_cfg(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ hs_config_param *pdata_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg =
+ (HostCmd_DS_802_11_HS_CFG_ENH *)&(cmd->params.opt_hs_cfg);
+ t_u8 *tlv = (t_u8 *)phs_cfg + sizeof(HostCmd_DS_802_11_HS_CFG_ENH);
+ MrvlIEtypes_HsWakeHoldoff_t *holdoff_tlv = MNULL;
+ MrvlIEtypes_HS_Antmode_t *antmode_tlv = MNULL;
+ MrvlIEtypes_WakeupSourceGPIO_t *gpio_tlv = MNULL;
+ MrvlIEtypes_MgmtFrameFilter_t *mgmt_filter_tlv = MNULL;
+ MrvlIEtypes_WakeupExtend_t *ext_tlv = MNULL;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN +
+ sizeof(HostCmd_DS_802_11_HS_CFG_ENH));
+
+ if (pdata_buf == MNULL) {
+ phs_cfg->action = wlan_cpu_to_le16(HS_ACTIVATE);
+ phs_cfg->params.hs_activate.resp_ctrl =
+ wlan_cpu_to_le16(RESP_NEEDED);
+ } else {
+ phs_cfg->action = wlan_cpu_to_le16(HS_CONFIGURE);
+ phs_cfg->params.hs_config.conditions =
+ wlan_cpu_to_le32(pdata_buf->conditions);
+ phs_cfg->params.hs_config.gpio = pdata_buf->gpio;
+ phs_cfg->params.hs_config.gap = pdata_buf->gap;
+ if (pmpriv->adapter->min_wake_holdoff) {
+ cmd->size = wlan_cpu_to_le16(
+ S_DS_GEN +
+ sizeof(HostCmd_DS_802_11_HS_CFG_ENH) +
+ sizeof(MrvlIEtypes_HsWakeHoldoff_t));
+ holdoff_tlv = (MrvlIEtypes_HsWakeHoldoff_t *)tlv;
+ holdoff_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_HS_WAKE_HOLDOFF);
+ holdoff_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_HsWakeHoldoff_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ holdoff_tlv->min_wake_holdoff = wlan_cpu_to_le16(
+ pmpriv->adapter->min_wake_holdoff);
+ tlv += sizeof(MrvlIEtypes_HsWakeHoldoff_t);
+ }
+ PRINTM(MCMND,
+ "HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x holdoff=%d\n",
+ phs_cfg->params.hs_config.conditions,
+ phs_cfg->params.hs_config.gpio,
+ phs_cfg->params.hs_config.gap,
+ pmpriv->adapter->min_wake_holdoff);
+
+ if (pmadapter->param_type_ind == 1) {
+ cmd->size += sizeof(MrvlIEtypes_WakeupSourceGPIO_t);
+ gpio_tlv = (MrvlIEtypes_WakeupSourceGPIO_t *)tlv;
+ gpio_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_HS_WAKEUP_SOURCE_GPIO);
+ gpio_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_WakeupSourceGPIO_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ gpio_tlv->ind_gpio = (t_u8)pmadapter->ind_gpio;
+ gpio_tlv->level = (t_u8)pmadapter->level;
+ tlv += sizeof(MrvlIEtypes_WakeupSourceGPIO_t);
+ }
+ if (pmadapter->param_type_ext == 2) {
+ cmd->size += sizeof(MrvlIEtypes_WakeupExtend_t);
+ ext_tlv = (MrvlIEtypes_WakeupExtend_t *)tlv;
+ ext_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_WAKEUP_EXTEND);
+ ext_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_WakeupExtend_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ ext_tlv->event_force_ignore =
+ wlan_cpu_to_le32(pmadapter->event_force_ignore);
+ ext_tlv->event_use_ext_gap =
+ wlan_cpu_to_le32(pmadapter->event_use_ext_gap);
+ ext_tlv->ext_gap = pmadapter->ext_gap;
+ ext_tlv->gpio_wave = pmadapter->gpio_wave;
+ tlv += sizeof(MrvlIEtypes_WakeupExtend_t);
+ }
+ if (pmadapter->mgmt_filter[0].type) {
+ int i = 0;
+ mgmt_frame_filter mgmt_filter[MAX_MGMT_FRAME_FILTER];
+ memset(pmadapter, mgmt_filter, 0,
+ MAX_MGMT_FRAME_FILTER *
+ sizeof(mgmt_frame_filter));
+ mgmt_filter_tlv = (MrvlIEtypes_MgmtFrameFilter_t *)tlv;
+ mgmt_filter_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_MGMT_FRAME_WAKEUP);
+ tlv += sizeof(MrvlIEtypesHeader_t);
+ while (i < MAX_MGMT_FRAME_FILTER &&
+ pmadapter->mgmt_filter[i].type) {
+ mgmt_filter[i].action =
+ (t_u8)pmadapter->mgmt_filter[i].action;
+ mgmt_filter[i].type =
+ (t_u8)pmadapter->mgmt_filter[i].type;
+ mgmt_filter[i].frame_mask = wlan_cpu_to_le32(
+ pmadapter->mgmt_filter[i].frame_mask);
+ i++;
+ }
+ memcpy_ext(pmadapter, (t_u8 *)mgmt_filter_tlv->filter,
+ (t_u8 *)mgmt_filter,
+ i * sizeof(mgmt_frame_filter),
+ sizeof(mgmt_filter_tlv->filter));
+ tlv += i * sizeof(mgmt_frame_filter);
+ mgmt_filter_tlv->header.len =
+ wlan_cpu_to_le16(i * sizeof(mgmt_frame_filter));
+ cmd->size += i * sizeof(mgmt_frame_filter) +
+ sizeof(MrvlIEtypesHeader_t);
+ }
+ if (pmadapter->hs_mimo_switch) {
+ cmd->size += sizeof(MrvlIEtypes_HS_Antmode_t);
+ antmode_tlv = (MrvlIEtypes_HS_Antmode_t *)tlv;
+ antmode_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_HS_ANTMODE);
+ antmode_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_HS_Antmode_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ antmode_tlv->txpath_antmode = ANTMODE_FW_DECISION;
+ antmode_tlv->rxpath_antmode = ANTMODE_FW_DECISION;
+ tlv += sizeof(MrvlIEtypes_HS_Antmode_t);
+ PRINTM(MCMND,
+ "hs_mimo_switch=%d, txpath_antmode=%d, rxpath_antmode=%d\n",
+ pmadapter->hs_mimo_switch,
+ antmode_tlv->txpath_antmode,
+ antmode_tlv->rxpath_antmode);
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of Tx data pause
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_txdatapause(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *)&cmd->params.tx_data_pause;
+ mlan_ds_misc_tx_datapause *data_pause =
+ (mlan_ds_misc_tx_datapause *)pdata_buf;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CFG_TX_DATA_PAUSE);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_TX_DATA_PAUSE) +
+ S_DS_GEN);
+ pause_cmd->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ pause_cmd->enable_tx_pause = (t_u8)data_pause->tx_pause;
+ pause_cmd->pause_tx_count = (t_u8)data_pause->tx_buf_cnt;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of Tx data pause
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_txdatapause(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_CMD_TX_DATA_PAUSE *pause_cmd =
+ (HostCmd_DS_CMD_TX_DATA_PAUSE *)&resp->params.tx_data_pause;
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ misc_cfg->param.tx_datapause.tx_pause =
+ pause_cmd->enable_tx_pause;
+ misc_cfg->param.tx_datapause.tx_buf_cnt =
+ pause_cmd->pause_tx_count;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function will process tx pause event
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void wlan_process_tx_pause_event(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - sizeof(t_u32);
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
+ sizeof(t_u32));
+ MrvlIEtypes_tx_pause_t *tx_pause_tlv;
+ sta_node *sta_ptr = MNULL;
+ t_u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ t_u32 total_pkts_queued;
+ t_u16 tx_pkts_queued = 0;
+ ;
+
+ ENTER();
+
+ total_pkts_queued =
+ util_scalar_read(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_TX_PAUSE) {
+ tx_pause_tlv = (MrvlIEtypes_tx_pause_t *)tlv;
+
+ if (!memcmp(priv->adapter, bc_mac,
+ tx_pause_tlv->peermac,
+ MLAN_MAC_ADDR_LENGTH))
+ tx_pkts_queued = wlan_update_ralist_tx_pause(
+ priv, tx_pause_tlv->peermac,
+ tx_pause_tlv->tx_pause);
+ else if (!memcmp(priv->adapter, priv->curr_addr,
+ tx_pause_tlv->peermac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ if (tx_pause_tlv->tx_pause)
+ priv->tx_pause = MTRUE;
+ else
+ priv->tx_pause = MFALSE;
+ } else {
+ sta_ptr = wlan_get_station_entry(
+ priv, tx_pause_tlv->peermac);
+ if (sta_ptr) {
+ if (sta_ptr->tx_pause !=
+ tx_pause_tlv->tx_pause) {
+ sta_ptr->tx_pause =
+ tx_pause_tlv->tx_pause;
+ tx_pkts_queued =
+ wlan_update_ralist_tx_pause(
+ priv,
+ tx_pause_tlv
+ ->peermac,
+ tx_pause_tlv
+ ->tx_pause);
+ }
+ }
+ }
+ if (!tx_pause_tlv->tx_pause)
+ total_pkts_queued += tx_pkts_queued;
+ PRINTM(MCMND,
+ "TxPause: " MACSTR
+ " pause=%d, pkts=%d pending=%d total=%d\n",
+ MAC2STR(tx_pause_tlv->peermac),
+ tx_pause_tlv->tx_pause, tx_pause_tlv->pkt_cnt,
+ tx_pkts_queued, total_pkts_queued);
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function prepares command for config uap settings
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_uap_cmd_ap_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ pmlan_ioctl_req pioctl_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *)&cmd->params.sys_config;
+ t_u8 *tlv = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+ MrvlIEtypes_preamble_t *tlv_preamble = MNULL;
+
+ t_u32 cmd_size = 0;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ t_u16 i;
+ t_u16 ac;
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ int rx_mcs_supp = 0;
+#endif
+
+ ENTER();
+ if (pioctl_buf == MNULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd_size = sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN;
+
+ tlv = (t_u8 *)sys_config->tlv_buffer;
+ if (memcmp(pmpriv->adapter, zero_mac, &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ tlv_mac = (MrvlIEtypes_MacAddr_t *)tlv;
+ tlv_mac->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ tlv_mac->header.len = wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ memcpy_ext(pmpriv->adapter, tlv_mac->mac,
+ &bss->param.bss_config.mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ cmd_size += sizeof(MrvlIEtypes_MacAddr_t);
+ tlv += sizeof(MrvlIEtypes_MacAddr_t);
+ }
+
+ if (bss->param.bss_config.bandcfg.scanMode == SCAN_MODE_ACS) {
+ /* ACS is not allowed when DFS repeater mode is on */
+ if (pmpriv->adapter->dfs_repeater) {
+ PRINTM(MERROR, "ACS is not allowed when"
+ "DFS repeater mode is on.\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+
+ if (bss->param.bss_config.ssid.ssid_len) {
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *)tlv;
+ tlv_ssid->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+ tlv_ssid->header.len = wlan_cpu_to_le16(
+ (t_u16)bss->param.bss_config.ssid.ssid_len);
+ memcpy_ext(pmpriv->adapter, tlv_ssid->ssid,
+ bss->param.bss_config.ssid.ssid,
+ bss->param.bss_config.ssid.ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.ssid.ssid_len;
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.ssid.ssid_len;
+ }
+
+ if ((bss->param.bss_config.beacon_period >= MIN_BEACON_PERIOD) &&
+ (bss->param.bss_config.beacon_period <= MAX_BEACON_PERIOD)) {
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *)tlv;
+ tlv_beacon_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ tlv_beacon_period->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_beacon_period->beacon_period =
+ wlan_cpu_to_le16(bss->param.bss_config.beacon_period);
+ cmd_size += sizeof(MrvlIEtypes_beacon_period_t);
+ tlv += sizeof(MrvlIEtypes_beacon_period_t);
+ }
+
+ if ((bss->param.bss_config.dtim_period >= MIN_DTIM_PERIOD) &&
+ (bss->param.bss_config.dtim_period <= MAX_DTIM_PERIOD)) {
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *)tlv;
+ tlv_dtim_period->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ tlv_dtim_period->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_dtim_period->dtim_period =
+ bss->param.bss_config.dtim_period;
+ cmd_size += sizeof(MrvlIEtypes_dtim_period_t);
+ tlv += sizeof(MrvlIEtypes_dtim_period_t);
+ }
+
+ if (bss->param.bss_config.rates[0]) {
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *)tlv;
+ tlv_rates->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+ for (i = 0;
+ i < MAX_DATA_RATES && bss->param.bss_config.rates[i];
+ i++) {
+ tlv_rates->rates[i] = bss->param.bss_config.rates[i];
+ }
+ tlv_rates->header.len = wlan_cpu_to_le16(i);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + i;
+ tlv += sizeof(MrvlIEtypesHeader_t) + i;
+ }
+
+ if (bss->param.bss_config.tx_data_rate <= DATA_RATE_54M) {
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *)tlv;
+ tlv_txrate->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_TX_DATA_RATE);
+ tlv_txrate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_txrate->tx_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.tx_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_tx_rate_t);
+ tlv += sizeof(MrvlIEtypes_tx_rate_t);
+ }
+
+ if (bss->param.bss_config.tx_beacon_rate <= DATA_RATE_54M) {
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *)tlv;
+ tlv_txrate->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_TX_BEACON_RATE);
+ tlv_txrate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_txrate->tx_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.tx_beacon_rate);
+ cmd_size += sizeof(MrvlIEtypes_tx_rate_t);
+ tlv += sizeof(MrvlIEtypes_tx_rate_t);
+ }
+
+ if (bss->param.bss_config.mcbc_data_rate <= DATA_RATE_54M) {
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *)tlv;
+ tlv_mcbc_rate->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MCBC_DATA_RATE);
+ tlv_mcbc_rate->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_mcbc_rate->mcbc_data_rate =
+ wlan_cpu_to_le16(bss->param.bss_config.mcbc_data_rate);
+ cmd_size += sizeof(MrvlIEtypes_mcbc_rate_t);
+ tlv += sizeof(MrvlIEtypes_mcbc_rate_t);
+ }
+
+ if (bss->param.bss_config.tx_power_level <= MAX_TX_POWER) {
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *)tlv;
+ tlv_tx_power->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_TX_POWER);
+ tlv_tx_power->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_tx_power->tx_power = bss->param.bss_config.tx_power_level;
+ cmd_size += sizeof(MrvlIEtypes_tx_power_t);
+ tlv += sizeof(MrvlIEtypes_tx_power_t);
+ }
+
+ if (bss->param.bss_config.bcast_ssid_ctl <= MAX_BCAST_SSID_CTL) {
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *)tlv;
+ tlv_bcast_ssid->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID_CTL);
+ tlv_bcast_ssid->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_bcast_ssid->bcast_ssid_ctl =
+ bss->param.bss_config.bcast_ssid_ctl;
+ cmd_size += sizeof(MrvlIEtypes_bcast_ssid_t);
+ tlv += sizeof(MrvlIEtypes_bcast_ssid_t);
+ }
+
+ if ((bss->param.bss_config.tx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.tx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *)tlv;
+ tlv_antenna->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = TX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.tx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if ((bss->param.bss_config.rx_antenna == ANTENNA_MODE_A) ||
+ (bss->param.bss_config.rx_antenna == ANTENNA_MODE_B)) {
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *)tlv;
+ tlv_antenna->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_ANTENNA_CTL);
+ tlv_antenna->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_antenna->which_antenna = RX_ANTENNA;
+ tlv_antenna->antenna_mode = bss->param.bss_config.rx_antenna;
+ cmd_size += sizeof(MrvlIEtypes_antenna_mode_t);
+ tlv += sizeof(MrvlIEtypes_antenna_mode_t);
+ }
+
+ if (bss->param.bss_config.pkt_forward_ctl <= MAX_PKT_FWD_CTRL) {
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *)tlv;
+ tlv_pkt_forward->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PKT_FWD_CTL);
+ tlv_pkt_forward->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_pkt_forward->pkt_forward_ctl =
+ bss->param.bss_config.pkt_forward_ctl;
+ cmd_size += sizeof(MrvlIEtypes_pkt_forward_t);
+ tlv += sizeof(MrvlIEtypes_pkt_forward_t);
+ }
+
+ if (bss->param.bss_config.max_sta_count <= MAX_STA_COUNT) {
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *)tlv;
+ tlv_sta_count->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MAX_STA_CNT);
+ tlv_sta_count->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_sta_count->max_sta_count =
+ wlan_cpu_to_le16(bss->param.bss_config.max_sta_count);
+ cmd_size += sizeof(MrvlIEtypes_max_sta_count_t);
+ tlv += sizeof(MrvlIEtypes_max_sta_count_t);
+ }
+
+ if (((bss->param.bss_config.sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.sta_ageout_timer <= MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.sta_ageout_timer == 0)) {
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *)tlv;
+ tlv_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_AGEOUT_TIMER);
+ tlv_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_sta_ageout->sta_ageout_timer = wlan_cpu_to_le32(
+ bss->param.bss_config.sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_sta_ageout_t);
+ }
+
+ if (((bss->param.bss_config.ps_sta_ageout_timer >= MIN_STAGE_OUT_TIME) &&
+ (bss->param.bss_config.ps_sta_ageout_timer <=
+ MAX_STAGE_OUT_TIME)) ||
+ (bss->param.bss_config.ps_sta_ageout_timer == 0)) {
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *)tlv;
+ tlv_ps_sta_ageout->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER);
+ tlv_ps_sta_ageout->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_ps_sta_ageout->ps_sta_ageout_timer = wlan_cpu_to_le32(
+ bss->param.bss_config.ps_sta_ageout_timer);
+ cmd_size += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ tlv += sizeof(MrvlIEtypes_ps_sta_ageout_t);
+ }
+ if (bss->param.bss_config.rts_threshold <= MAX_RTS_THRESHOLD) {
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *)tlv;
+ tlv_rts_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
+ tlv_rts_threshold->header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_rts_threshold->rts_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.rts_threshold);
+ cmd_size += sizeof(MrvlIEtypes_rts_threshold_t);
+ tlv += sizeof(MrvlIEtypes_rts_threshold_t);
+ }
+
+ if ((bss->param.bss_config.frag_threshold >= MIN_FRAG_THRESHOLD) &&
+ (bss->param.bss_config.frag_threshold <= MAX_FRAG_THRESHOLD)) {
+ tlv_frag_threshold = (MrvlIEtypes_frag_threshold_t *)tlv;
+ tlv_frag_threshold->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
+ tlv_frag_threshold->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_frag_threshold->frag_threshold =
+ wlan_cpu_to_le16(bss->param.bss_config.frag_threshold);
+ cmd_size += sizeof(MrvlIEtypes_frag_threshold_t);
+ tlv += sizeof(MrvlIEtypes_frag_threshold_t);
+ }
+
+ if (bss->param.bss_config.retry_limit <= MAX_RETRY_LIMIT) {
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *)tlv;
+ tlv_retry_limit->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
+ tlv_retry_limit->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_retry_limit->retry_limit =
+ (t_u8)bss->param.bss_config.retry_limit;
+ cmd_size += sizeof(MrvlIEtypes_retry_limit_t);
+ tlv += sizeof(MrvlIEtypes_retry_limit_t);
+ }
+
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IS_FW_SUPPORT_AUTHENTICATOR(pmpriv->adapter)) {
+#endif
+ if (bss->param.bss_config.pairwise_update_timeout <
+ (MAX_VALID_DWORD)) {
+ tlv_pairwise_timeout =
+ (MrvlIEtypes_eapol_pwk_hsk_timeout_t *)tlv;
+ tlv_pairwise_timeout->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT);
+ tlv_pairwise_timeout->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_timeout
+ ->pairwise_update_timeout = wlan_cpu_to_le32(
+ bss->param.bss_config.pairwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.pwk_retries < (MAX_VALID_DWORD)) {
+ tlv_pairwise_retries =
+ (MrvlIEtypes_eapol_pwk_hsk_retries_t *)tlv;
+ tlv_pairwise_retries->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES);
+ tlv_pairwise_retries->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_pairwise_retries->pwk_retries = wlan_cpu_to_le32(
+ bss->param.bss_config.pwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_pwk_hsk_retries_t);
+ }
+
+ if (bss->param.bss_config.groupwise_update_timeout <
+ (MAX_VALID_DWORD)) {
+ tlv_groupwise_timeout =
+ (MrvlIEtypes_eapol_gwk_hsk_timeout_t *)tlv;
+ tlv_groupwise_timeout->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT);
+ tlv_groupwise_timeout->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_timeout
+ ->groupwise_update_timeout = wlan_cpu_to_le32(
+ bss->param.bss_config.groupwise_update_timeout);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_timeout_t);
+ }
+
+ if (bss->param.bss_config.gwk_retries < (MAX_VALID_DWORD)) {
+ tlv_groupwise_retries =
+ (MrvlIEtypes_eapol_gwk_hsk_retries_t *)tlv;
+ tlv_groupwise_retries->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES);
+ tlv_groupwise_retries->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_groupwise_retries->gwk_retries = wlan_cpu_to_le32(
+ bss->param.bss_config.gwk_retries);
+ cmd_size += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ tlv += sizeof(MrvlIEtypes_eapol_gwk_hsk_retries_t);
+ }
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ }
+#endif
+ if ((bss->param.bss_config.filter.filter_mode <=
+ MAC_FILTER_MODE_BLOCK_MAC) &&
+ (bss->param.bss_config.filter.mac_count <= MAX_MAC_FILTER_NUM)) {
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *)tlv;
+ tlv_mac_filter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_STA_MAC_ADDR_FILTER);
+ tlv_mac_filter->header.len = wlan_cpu_to_le16(
+ 2 + MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count);
+ tlv_mac_filter->count =
+ (t_u8)bss->param.bss_config.filter.mac_count;
+ tlv_mac_filter->filter_mode =
+ (t_u8)bss->param.bss_config.filter.filter_mode;
+ memcpy_ext(pmpriv->adapter, tlv_mac_filter->mac_address,
+ (t_u8 *)bss->param.bss_config.filter.mac_list,
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count,
+ MLAN_MAC_ADDR_LENGTH * MAX_MAC_FILTER_NUM);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count;
+ tlv += sizeof(MrvlIEtypesHeader_t) + 2 +
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count;
+ }
+
+ if (((bss->param.bss_config.bandcfg.scanMode == SCAN_MODE_MANUAL) &&
+ (bss->param.bss_config.channel > 0) &&
+ (bss->param.bss_config.channel <= MLAN_MAX_CHANNEL)) ||
+ (bss->param.bss_config.bandcfg.scanMode == SCAN_MODE_ACS)) {
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *)tlv;
+ tlv_chan_band->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ tlv_chan_band->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_chan_band->bandcfg = bss->param.bss_config.bandcfg;
+ tlv_chan_band->channel = bss->param.bss_config.channel;
+ cmd_size += sizeof(MrvlIEtypes_channel_band_t);
+ tlv += sizeof(MrvlIEtypes_channel_band_t);
+ }
+
+ if ((bss->param.bss_config.num_of_chan) &&
+ (bss->param.bss_config.num_of_chan <= MLAN_MAX_CHANNEL)) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
+ tlv_chan_list->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ tlv_chan_list->header.len = wlan_cpu_to_le16(
+ (t_u16)(sizeof(ChanScanParamSet_t) *
+ bss->param.bss_config.num_of_chan));
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan; i++) {
+ pscan_chan->chan_number =
+ bss->param.bss_config.chan_list[i].chan_number;
+ pscan_chan->bandcfg =
+ bss->param.bss_config.chan_list[i].bandcfg;
+ pscan_chan++;
+ }
+ cmd_size += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) *
+ bss->param.bss_config.num_of_chan);
+ tlv += sizeof(tlv_chan_list->header) +
+ (sizeof(ChanScanParamSet_t) *
+ bss->param.bss_config.num_of_chan);
+ }
+
+ if ((bss->param.bss_config.auth_mode <= MLAN_AUTH_MODE_SHARED) ||
+ (bss->param.bss_config.auth_mode == MLAN_AUTH_MODE_AUTO)) {
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *)tlv;
+ tlv_auth_type->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ tlv_auth_type->header.len = wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_auth_type->auth_type =
+ (t_u8)bss->param.bss_config.auth_mode;
+ cmd_size += sizeof(MrvlIEtypes_auth_type_t);
+ tlv += sizeof(MrvlIEtypes_auth_type_t);
+ }
+
+ if (bss->param.bss_config.protocol) {
+ tlv_encrypt_protocol = (MrvlIEtypes_encrypt_protocol_t *)tlv;
+ tlv_encrypt_protocol->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_ENCRYPT_PROTOCOL);
+ tlv_encrypt_protocol->header.len =
+ wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_encrypt_protocol->protocol =
+ wlan_cpu_to_le16(bss->param.bss_config.protocol);
+ cmd_size += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ tlv += sizeof(MrvlIEtypes_encrypt_protocol_t);
+ }
+
+ if ((bss->param.bss_config.protocol & PROTOCOL_WPA) ||
+ (bss->param.bss_config.protocol & PROTOCOL_WPA2) ||
+ (bss->param.bss_config.protocol & PROTOCOL_EAP)) {
+ tlv_akmp = (MrvlIEtypes_akmp_t *)tlv;
+ tlv_akmp->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_AKMP);
+ tlv_akmp->key_mgmt =
+ wlan_cpu_to_le16(bss->param.bss_config.key_mgmt);
+ tlv_akmp->header.len = sizeof(t_u16);
+ tlv_akmp->key_mgmt_operation = wlan_cpu_to_le16(
+ bss->param.bss_config.key_mgmt_operation);
+ tlv_akmp->header.len += sizeof(t_u16);
+ tlv_akmp->header.len = wlan_cpu_to_le16(tlv_akmp->header.len);
+ cmd_size += sizeof(MrvlIEtypes_akmp_t);
+ tlv += sizeof(MrvlIEtypes_akmp_t);
+
+ if (bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa &
+ VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *)tlv;
+ tlv_pwk_cipher->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len = wlan_cpu_to_le16(
+ sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol =
+ wlan_cpu_to_le16(PROTOCOL_WPA);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg
+ .pairwise_cipher_wpa;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.pairwise_cipher_wpa2 &
+ VALID_CIPHER_BITMAP) {
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *)tlv;
+ tlv_pwk_cipher->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ tlv_pwk_cipher->header.len = wlan_cpu_to_le16(
+ sizeof(t_u16) + sizeof(t_u8) + sizeof(t_u8));
+ tlv_pwk_cipher->protocol =
+ wlan_cpu_to_le16(PROTOCOL_WPA2);
+ tlv_pwk_cipher->pairwise_cipher =
+ bss->param.bss_config.wpa_cfg
+ .pairwise_cipher_wpa2;
+ cmd_size += sizeof(MrvlIEtypes_pwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_pwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.group_cipher &
+ VALID_CIPHER_BITMAP) {
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *)tlv;
+ tlv_gwk_cipher->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+ tlv_gwk_cipher->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8) + sizeof(t_u8));
+ tlv_gwk_cipher->group_cipher =
+ bss->param.bss_config.wpa_cfg.group_cipher;
+ cmd_size += sizeof(MrvlIEtypes_gwk_cipher_t);
+ tlv += sizeof(MrvlIEtypes_gwk_cipher_t);
+ }
+
+ if (bss->param.bss_config.wpa_cfg.rsn_protection <= MTRUE) {
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *)tlv;
+ tlv_rsn_prot->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_RSN_REPLAY_PROTECT);
+ tlv_rsn_prot->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_rsn_prot->rsn_replay_prot =
+ bss->param.bss_config.wpa_cfg.rsn_protection;
+ cmd_size += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ tlv += sizeof(MrvlIEtypes_rsn_replay_prot_t);
+ }
+
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IS_FW_SUPPORT_AUTHENTICATOR(pmpriv->adapter)) {
+#endif
+ if (bss->param.bss_config.wpa_cfg.length) {
+ tlv_passphrase =
+ (MrvlIEtypes_passphrase_t *)tlv;
+ tlv_passphrase->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_WPA_PASSPHRASE);
+ tlv_passphrase->header
+ .len = (t_u16)wlan_cpu_to_le16(
+ bss->param.bss_config.wpa_cfg.length);
+ memcpy_ext(
+ pmpriv->adapter,
+ tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.passphrase,
+ bss->param.bss_config.wpa_cfg.length,
+ bss->param.bss_config.wpa_cfg.length);
+ cmd_size +=
+ sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ tlv += sizeof(MrvlIEtypesHeader_t) +
+ bss->param.bss_config.wpa_cfg.length;
+ }
+
+ if (bss->param.bss_config.wpa_cfg.gk_rekey_time <
+ MAX_GRP_TIMER) {
+ tlv_rekey_time =
+ (MrvlIEtypes_group_rekey_time_t *)tlv;
+ tlv_rekey_time->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_GRP_REKEY_TIME);
+ tlv_rekey_time->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ tlv_rekey_time->gk_rekey_time =
+ wlan_cpu_to_le32(
+ bss->param.bss_config.wpa_cfg
+ .gk_rekey_time);
+ cmd_size +=
+ sizeof(MrvlIEtypes_group_rekey_time_t);
+ tlv += sizeof(MrvlIEtypes_group_rekey_time_t);
+ }
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ }
+#endif
+ } else {
+ if ((bss->param.bss_config.wep_cfg.key0.length) &&
+ ((bss->param.bss_config.wep_cfg.key0.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key0.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *)tlv;
+ tlv_wep_key->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len = wlan_cpu_to_le16(
+ 2 + bss->param.bss_config.wep_cfg.key0.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key0.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key0.is_default;
+ memcpy_ext(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key0.key,
+ bss->param.bss_config.wep_cfg.key0.length,
+ bss->param.bss_config.wep_cfg.key0.length);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ tlv += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key0.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key1.length) &&
+ ((bss->param.bss_config.wep_cfg.key1.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key1.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *)tlv;
+ tlv_wep_key->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len = wlan_cpu_to_le16(
+ 2 + bss->param.bss_config.wep_cfg.key1.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key1.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key1.is_default;
+ memcpy_ext(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key1.key,
+ bss->param.bss_config.wep_cfg.key1.length,
+ bss->param.bss_config.wep_cfg.key1.length);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ tlv += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key1.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key2.length) &&
+ ((bss->param.bss_config.wep_cfg.key2.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key2.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *)tlv;
+ tlv_wep_key->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len = wlan_cpu_to_le16(
+ 2 + bss->param.bss_config.wep_cfg.key2.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key2.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key2.is_default;
+ memcpy_ext(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key2.key,
+ bss->param.bss_config.wep_cfg.key2.length,
+ bss->param.bss_config.wep_cfg.key2.length);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ tlv += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key2.length;
+ }
+
+ if ((bss->param.bss_config.wep_cfg.key3.length) &&
+ ((bss->param.bss_config.wep_cfg.key3.length == 5) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 10) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 13) ||
+ (bss->param.bss_config.wep_cfg.key3.length == 26))) {
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *)tlv;
+ tlv_wep_key->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+ tlv_wep_key->header.len = wlan_cpu_to_le16(
+ 2 + bss->param.bss_config.wep_cfg.key3.length);
+ tlv_wep_key->key_index =
+ bss->param.bss_config.wep_cfg.key3.key_index;
+ tlv_wep_key->is_default =
+ bss->param.bss_config.wep_cfg.key3.is_default;
+ memcpy_ext(pmpriv->adapter, tlv_wep_key->key,
+ bss->param.bss_config.wep_cfg.key3.key,
+ bss->param.bss_config.wep_cfg.key3.length,
+ bss->param.bss_config.wep_cfg.key3.length);
+ cmd_size += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ tlv += sizeof(MrvlIEtypesHeader_t) + 2 +
+ bss->param.bss_config.wep_cfg.key3.length;
+ }
+ }
+ if (bss->param.bss_config.ht_cap_info) {
+ tlv_htcap = (MrvlIETypes_HTCap_t *)tlv;
+ tlv_htcap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
+ tlv_htcap->header.len = wlan_cpu_to_le16(sizeof(HTCap_t));
+ tlv_htcap->ht_cap.ht_cap_info =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_cap_info);
+ tlv_htcap->ht_cap.ampdu_param =
+ bss->param.bss_config.ampdu_param;
+ memcpy_ext(pmpriv->adapter, tlv_htcap->ht_cap.supported_mcs_set,
+ bss->param.bss_config.supported_mcs_set, 16,
+ sizeof(tlv_htcap->ht_cap.supported_mcs_set));
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(SD9097) || defined(USB9097)
+ if (IS_CARD9098(pmpriv->adapter->card_type) ||
+ IS_CARD9097(pmpriv->adapter->card_type)) {
+ if (bss->param.bss_config.supported_mcs_set[0]) {
+ if (bss->param.bss_config.bandcfg.chanBand ==
+ BAND_5GHZ)
+ rx_mcs_supp = GET_RXMCSSUPP(
+ pmpriv->adapter->user_htstream >>
+ 8);
+ else
+ rx_mcs_supp = GET_RXMCSSUPP(
+ pmpriv->adapter->user_htstream);
+
+ if (rx_mcs_supp == 0x1) {
+ tlv_htcap->ht_cap.supported_mcs_set[0] =
+ 0xFF;
+ tlv_htcap->ht_cap.supported_mcs_set[1] =
+ 0;
+ } else if (rx_mcs_supp == 0x2) {
+ tlv_htcap->ht_cap.supported_mcs_set[0] =
+ 0xFF;
+ tlv_htcap->ht_cap.supported_mcs_set[1] =
+ 0xFF;
+ }
+ }
+ }
+#endif
+ tlv_htcap->ht_cap.ht_ext_cap =
+ wlan_cpu_to_le16(bss->param.bss_config.ht_ext_cap);
+ tlv_htcap->ht_cap.tx_bf_cap =
+ wlan_cpu_to_le32(bss->param.bss_config.tx_bf_cap);
+ tlv_htcap->ht_cap.asel = bss->param.bss_config.asel;
+ cmd_size += sizeof(MrvlIETypes_HTCap_t);
+ tlv += sizeof(MrvlIETypes_HTCap_t);
+ }
+ if (bss->param.bss_config.mgmt_ie_passthru_mask < (MAX_VALID_DWORD)) {
+ tlv_mgmt_ie_passthru = (MrvlIEtypes_mgmt_ie_passthru_t *)tlv;
+ tlv_mgmt_ie_passthru->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK);
+ tlv_mgmt_ie_passthru->header.len =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ /* keep copy in private data */
+ pmpriv->mgmt_frame_passthru_mask =
+ bss->param.bss_config.mgmt_ie_passthru_mask;
+ tlv_mgmt_ie_passthru->mgmt_ie_mask = wlan_cpu_to_le32(
+ bss->param.bss_config.mgmt_ie_passthru_mask);
+ cmd_size += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ tlv += sizeof(MrvlIEtypes_mgmt_ie_passthru_t);
+ }
+ if ((bss->param.bss_config.enable_2040coex == 0) ||
+ (bss->param.bss_config.enable_2040coex == 1)) {
+ tlv_2040_coex_enable = (MrvlIEtypes_2040_coex_enable_t *)tlv;
+ tlv_2040_coex_enable->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_2040_BSS_COEX_CONTROL);
+ tlv_2040_coex_enable->header.len =
+ wlan_cpu_to_le16(sizeof(t_u8));
+ tlv_2040_coex_enable->enable_2040coex =
+ bss->param.bss_config.enable_2040coex;
+ cmd_size += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ tlv += sizeof(MrvlIEtypes_2040_coex_enable_t);
+ }
+ if ((bss->param.bss_config.uap_host_based_config == MTRUE) ||
+ (bss->param.bss_config.wmm_para.qos_info & 0x80 ||
+ bss->param.bss_config.wmm_para.qos_info == 0x00)) {
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *)tlv;
+ tlv_wmm_parameter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_VENDOR_SPECIFIC_IE);
+ tlv_wmm_parameter->header.len = wlan_cpu_to_le16(
+ sizeof(bss->param.bss_config.wmm_para));
+ memcpy_ext(pmpriv->adapter, tlv_wmm_parameter->wmm_para.ouitype,
+ bss->param.bss_config.wmm_para.ouitype,
+ sizeof(tlv_wmm_parameter->wmm_para.ouitype),
+ sizeof(tlv_wmm_parameter->wmm_para.ouitype));
+ tlv_wmm_parameter->wmm_para.ouisubtype =
+ bss->param.bss_config.wmm_para.ouisubtype;
+ tlv_wmm_parameter->wmm_para.version =
+ bss->param.bss_config.wmm_para.version;
+ tlv_wmm_parameter->wmm_para.qos_info =
+ bss->param.bss_config.wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ tlv_wmm_parameter->wmm_para.ac_params[ac]
+ .aci_aifsn.aifsn =
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .aci_aifsn.aifsn;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].aci_aifsn.aci =
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .aci_aifsn.aci;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_max =
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .ecw.ecw_max;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].ecw.ecw_min =
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .ecw.ecw_min;
+ tlv_wmm_parameter->wmm_para.ac_params[ac].tx_op_limit =
+ wlan_cpu_to_le16(bss->param.bss_config.wmm_para
+ .ac_params[ac]
+ .tx_op_limit);
+ }
+ cmd_size += sizeof(MrvlIEtypes_wmm_parameter_t);
+ tlv += sizeof(MrvlIEtypes_wmm_parameter_t);
+ }
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (!IS_FW_SUPPORT_AUTHENTICATOR(pmpriv->adapter))
+ AuthenticatorBssConfig(pmpriv->psapriv,
+ (t_u8 *)&bss->param.bss_config, 0, 0, 0);
+#endif
+ if (pmpriv->adapter->pcard_info->v17_fw_api &&
+ bss->param.bss_config.preamble_type) {
+ tlv_preamble = (MrvlIEtypes_preamble_t *)tlv;
+ tlv_preamble->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_PREAMBLE_CTL);
+ tlv_preamble->header.len =
+ wlan_cpu_to_le16(sizeof(MrvlIEtypes_preamble_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ tlv_preamble->preamble_type =
+ wlan_cpu_to_le16(bss->param.bss_config.preamble_type);
+
+ cmd_size += sizeof(MrvlIEtypes_preamble_t);
+ tlv += sizeof(MrvlIEtypes_preamble_t);
+ }
+
+ cmd->size = (t_u16)wlan_cpu_to_le16(cmd_size);
+ PRINTM(MCMND, "AP config: cmd_size=%d\n", cmd_size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_uap_cmd_sys_configure(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ pmlan_ioctl_req pioctl_buf,
+ t_void *pdata_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *)&cmd->params.sys_config;
+ MrvlIEtypes_MacAddr_t *mac_tlv = MNULL;
+ MrvlIEtypes_channel_band_t *pdat_tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *bcn_pd_tlv = MNULL,
+ *pdat_tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *dtim_pd_tlv = MNULL,
+ *pdat_tlv_dtimpd = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_channel_band_t *chan_band_tlv = MNULL;
+ MrvlIEtypes_chan_bw_oper_t *poper_class_tlv = MNULL;
+ t_u8 length = 0;
+ t_u8 curr_oper_class = 1;
+ t_u8 *oper_class_ie = (t_u8 *)sys_config->tlv_buffer;
+ t_u16 i = 0;
+ t_u8 ac = 0;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypesHeader_t *ie_header =
+ (MrvlIEtypesHeader_t *)sys_config->tlv_buffer;
+ MrvlIEtypesHeader_t *pdata_header = (MrvlIEtypesHeader_t *)pdata_buf;
+ t_u8 *ie = (t_u8 *)sys_config->tlv_buffer + sizeof(MrvlIEtypesHeader_t);
+ t_u16 req_len = 0, travel_len = 0;
+ custom_ie *cptr = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
+ sys_config->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+ if (pioctl_buf == MNULL) {
+ if (pdata_buf) {
+ switch (pdata_header->type) {
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ pdat_tlv_cb =
+ (MrvlIEtypes_channel_band_t *)pdata_buf;
+ chan_band_tlv = (MrvlIEtypes_channel_band_t *)
+ sys_config->tlv_buffer;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_channel_band_t));
+ chan_band_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ chan_band_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ chan_band_tlv->bandcfg =
+ pdat_tlv_cb->bandcfg;
+ chan_band_tlv->channel =
+ pdat_tlv_cb->channel;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ pdat_tlv_bcnpd = (MrvlIEtypes_beacon_period_t *)
+ pdata_buf;
+ bcn_pd_tlv = (MrvlIEtypes_beacon_period_t *)
+ sys_config->tlv_buffer;
+ cmd->size = sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_beacon_period_t);
+ bcn_pd_tlv->header.type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_BEACON_PERIOD);
+ bcn_pd_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_beacon_period_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ bcn_pd_tlv->beacon_period =
+ wlan_cpu_to_le16(
+ pdat_tlv_bcnpd
+ ->beacon_period);
+ }
+ /* Add TLV_UAP_DTIM_PERIOD if it follws in
+ * pdata_buf */
+ pdat_tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t
+ *)(((t_u8 *)pdata_buf) +
+ sizeof(MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD ==
+ pdat_tlv_dtimpd->header.type) {
+ dtim_pd_tlv =
+ (MrvlIEtypes_dtim_period_t
+ *)(sys_config
+ ->tlv_buffer +
+ sizeof(MrvlIEtypes_beacon_period_t));
+ cmd->size += sizeof(
+ MrvlIEtypes_dtim_period_t);
+ dtim_pd_tlv->header
+ .type = wlan_cpu_to_le16(
+ TLV_TYPE_UAP_DTIM_PERIOD);
+ dtim_pd_tlv->header
+ .len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_dtim_period_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action) {
+ dtim_pd_tlv->dtim_period =
+ pdat_tlv_dtimpd
+ ->dtim_period;
+ }
+ }
+ /* Finalize cmd size */
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case TLV_TYPE_MGMT_IE:
+ cust_ie = (mlan_ds_misc_custom_ie *)pdata_buf;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN + sizeof(MrvlIEtypesHeader_t) +
+ cust_ie->len);
+ ie_header->type =
+ wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len = wlan_cpu_to_le16(cust_ie->len);
+
+ if (ie) {
+ req_len = cust_ie->len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0]
+ .ie_index = wlan_cpu_to_le16(
+ cust_ie->ie_data_list[0]
+ .ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr = (custom_ie
+ *)(((t_u8 *)&cust_ie
+ ->ie_data_list) +
+ travel_len);
+ travel_len +=
+ cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ req_len -= cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ cptr->ie_index =
+ wlan_cpu_to_le16(
+ cptr->ie_index);
+ cptr->mgmt_subtype_mask = wlan_cpu_to_le16(
+ cptr->mgmt_subtype_mask);
+ cptr->ie_length =
+ wlan_cpu_to_le16(
+ cptr->ie_length);
+ }
+ memcpy_ext(pmpriv->adapter, ie,
+ cust_ie->ie_data_list,
+ cust_ie->len, cust_ie->len);
+ }
+ break;
+ case REGULATORY_CLASS:
+ poper_class_tlv =
+ (MrvlIEtypes_chan_bw_oper_t *)pdata_buf;
+ ret = wlan_get_curr_oper_class(
+ pmpriv,
+ poper_class_tlv->ds_chan_bw_oper.channel,
+ poper_class_tlv->ds_chan_bw_oper
+ .bandwidth,
+ &curr_oper_class);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Can not get current oper class! bandwidth = %d, channel = %d\n",
+ poper_class_tlv->ds_chan_bw_oper
+ .bandwidth,
+ poper_class_tlv->ds_chan_bw_oper
+ .channel);
+ }
+
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ length =
+ wlan_add_supported_oper_class_ie(
+ pmpriv, &oper_class_ie,
+ curr_oper_class);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN + length);
+ break;
+ case TLV_TYPE_UAP_MAX_STA_CNT_PER_CHIP:
+ memcpy_ext(
+ pmpriv->adapter, sys_config->tlv_buffer,
+ pdata_buf,
+ sizeof(MrvlIEtypes_uap_max_sta_cnt_t),
+ sizeof(MrvlIEtypes_uap_max_sta_cnt_t));
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_uap_max_sta_cnt_t));
+ break;
+ default:
+ PRINTM(MERROR,
+ "Wrong data, or missing TLV_TYPE 0x%04x handler.\n",
+ *(t_u16 *)pdata_buf);
+ break;
+ }
+ goto done;
+ } else {
+ mac_tlv =
+ (MrvlIEtypes_MacAddr_t *)sys_config->tlv_buffer;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len =
+ wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ mac_tlv =
+ (MrvlIEtypes_MacAddr_t *)sys_config->tlv_buffer;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_MacAddr_t));
+ mac_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len =
+ wlan_cpu_to_le16(MLAN_MAC_ADDR_LENGTH);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy_ext(pmpriv->adapter, mac_tlv->mac,
+ &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ } else if (bss->sub_command == MLAN_OID_UAP_CFG_WMM_PARAM) {
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *)
+ sys_config->tlv_buffer;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_wmm_parameter_t));
+ tlv_wmm_parameter->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_AP_WMM_PARAM);
+ tlv_wmm_parameter->header.len = wlan_cpu_to_le16(
+ sizeof(bss->param.ap_wmm_para));
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ for (ac = 0; ac < 4; ac++) {
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aifsn =
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aifsn;
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aci =
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aci;
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .ecw.ecw_max =
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .ecw.ecw_max;
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .ecw.ecw_min =
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .ecw.ecw_min;
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .tx_op_limit = wlan_cpu_to_le16(
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .tx_op_limit);
+ }
+ }
+ } else if (bss->sub_command == MLAN_OID_UAP_SCAN_CHANNELS) {
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)
+ sys_config->tlv_buffer;
+ tlv_chan_list->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+ if (bss->param.ap_scan_channels.num_of_chan &&
+ bss->param.ap_scan_channels.num_of_chan <=
+ MLAN_MAX_CHANNEL) {
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(tlv_chan_list->header) +
+ sizeof(ChanScanParamSet_t) *
+ bss->param.ap_scan_channels
+ .num_of_chan);
+ tlv_chan_list->header.len = wlan_cpu_to_le16(
+ (t_u16)(sizeof(ChanScanParamSet_t) *
+ bss->param.ap_scan_channels
+ .num_of_chan));
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0;
+ i <
+ bss->param.ap_scan_channels.num_of_chan;
+ i++) {
+ pscan_chan->chan_number =
+ bss->param.ap_scan_channels
+ .chan_list[i]
+ .chan_number;
+ pscan_chan->bandcfg =
+ bss->param.ap_scan_channels
+ .chan_list[i]
+ .bandcfg;
+ pscan_chan++;
+ }
+ PRINTM(MCMND,
+ "Set AP scan channel list = %d\n",
+ bss->param.ap_scan_channels.num_of_chan);
+ } else {
+ tlv_chan_list->header.len = wlan_cpu_to_le16(
+ (t_u16)(sizeof(ChanScanParamSet_t) *
+ MLAN_MAX_CHANNEL));
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 +
+ S_DS_GEN +
+ sizeof(MrvlIEtypes_ChanListParamSet_t) +
+ sizeof(ChanScanParamSet_t) *
+ MLAN_MAX_CHANNEL);
+ }
+ } else if (bss->sub_command == MLAN_OID_UAP_CHANNEL) {
+ chan_band_tlv = (MrvlIEtypes_channel_band_t *)
+ sys_config->tlv_buffer;
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypes_channel_band_t));
+ chan_band_tlv->header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ chan_band_tlv->header.len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ chan_band_tlv->bandcfg =
+ bss->param.ap_channel.bandcfg;
+ chan_band_tlv->channel =
+ bss->param.ap_channel.channel;
+ PRINTM(MCMND,
+ "Set AP channel, band=%d, channel=%d\n",
+ bss->param.ap_channel.bandcfg,
+ bss->param.ap_channel.channel);
+ }
+ } else if ((bss->sub_command == MLAN_OID_UAP_BSS_CONFIG) &&
+ (cmd_action == HostCmd_ACT_GEN_SET)) {
+ ret = wlan_uap_cmd_ap_config(pmpriv, cmd, cmd_action,
+ pioctl_buf);
+ goto done;
+ }
+ } else if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ if ((misc->sub_command == MLAN_OID_MISC_GEN_IE) &&
+ (misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE)) {
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.gen_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header->len =
+ wlan_cpu_to_le16(misc->param.gen_ie.len);
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy_ext(pmpriv->adapter, ie,
+ misc->param.gen_ie.ie_data,
+ misc->param.gen_ie.len,
+ misc->param.gen_ie.len);
+ }
+ if ((misc->sub_command == MLAN_OID_MISC_CUSTOM_IE) &&
+ (misc->param.cust_ie.type == TLV_TYPE_MGMT_IE)) {
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN +
+ sizeof(MrvlIEtypesHeader_t) +
+ misc->param.cust_ie.len);
+ ie_header->type = wlan_cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header->len =
+ wlan_cpu_to_le16(misc->param.cust_ie.len);
+
+ if (ie) {
+ req_len = misc->param.cust_ie.len;
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (req_len == sizeof(t_u16))
+ misc->param.cust_ie.ie_data_list[0]
+ .ie_index = wlan_cpu_to_le16(
+ misc->param.cust_ie
+ .ie_data_list[0]
+ .ie_index);
+ while (req_len > sizeof(t_u16)) {
+ cptr = (custom_ie
+ *)(((t_u8 *)&misc->param
+ .cust_ie
+ .ie_data_list) +
+ travel_len);
+ travel_len += cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ req_len -= cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ cptr->ie_index = wlan_cpu_to_le16(
+ cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_cpu_to_le16(
+ cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_cpu_to_le16(
+ cptr->ie_length);
+ }
+ if (misc->param.cust_ie.len)
+ memcpy_ext(
+ pmpriv->adapter, ie,
+ misc->param.cust_ie.ie_data_list,
+ misc->param.cust_ie.len,
+ misc->param.cust_ie.len);
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles command resp for get uap settings
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_cmd_ap_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *)&resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ MrvlIEtypesHeader_t *tlv = MNULL;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 tlv_len = 0;
+ MrvlIEtypes_MacAddr_t *tlv_mac = MNULL;
+ MrvlIEtypes_SsIdParamSet_t *tlv_ssid = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_beacon_period = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtim_period = MNULL;
+ MrvlIEtypes_RatesParamSet_t *tlv_rates = MNULL;
+ MrvlIEtypes_tx_rate_t *tlv_txrate = MNULL;
+ MrvlIEtypes_mcbc_rate_t *tlv_mcbc_rate = MNULL;
+ MrvlIEtypes_tx_power_t *tlv_tx_power = MNULL;
+ MrvlIEtypes_bcast_ssid_t *tlv_bcast_ssid = MNULL;
+ MrvlIEtypes_antenna_mode_t *tlv_antenna = MNULL;
+ MrvlIEtypes_pkt_forward_t *tlv_pkt_forward = MNULL;
+ MrvlIEtypes_max_sta_count_t *tlv_sta_count = MNULL;
+ MrvlIEtypes_sta_ageout_t *tlv_sta_ageout = MNULL;
+ MrvlIEtypes_ps_sta_ageout_t *tlv_ps_sta_ageout = MNULL;
+ MrvlIEtypes_rts_threshold_t *tlv_rts_threshold = MNULL;
+ MrvlIEtypes_frag_threshold_t *tlv_frag_threshold = MNULL;
+ MrvlIEtypes_retry_limit_t *tlv_retry_limit = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_timeout_t *tlv_pairwise_timeout = MNULL;
+ MrvlIEtypes_eapol_pwk_hsk_retries_t *tlv_pairwise_retries = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_timeout_t *tlv_groupwise_timeout = MNULL;
+ MrvlIEtypes_eapol_gwk_hsk_retries_t *tlv_groupwise_retries = MNULL;
+ MrvlIEtypes_mgmt_ie_passthru_t *tlv_mgmt_ie_passthru = MNULL;
+ MrvlIEtypes_2040_coex_enable_t *tlv_2040_coex_enable = MNULL;
+ MrvlIEtypes_mac_filter_t *tlv_mac_filter = MNULL;
+ MrvlIEtypes_channel_band_t *tlv_chan_band = MNULL;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ MrvlIEtypes_auth_type_t *tlv_auth_type = MNULL;
+ MrvlIEtypes_encrypt_protocol_t *tlv_encrypt_protocol = MNULL;
+ MrvlIEtypes_akmp_t *tlv_akmp = MNULL;
+ MrvlIEtypes_pwk_cipher_t *tlv_pwk_cipher = MNULL;
+ MrvlIEtypes_gwk_cipher_t *tlv_gwk_cipher = MNULL;
+ MrvlIEtypes_rsn_replay_prot_t *tlv_rsn_prot = MNULL;
+ MrvlIEtypes_passphrase_t *tlv_passphrase = MNULL;
+#ifdef WIFI_DIRECT_SUPPORT
+ MrvlIEtypes_psk_t *tlv_psk = MNULL;
+#endif /* WIFI_DIRECT_SUPPORT */
+ MrvlIEtypes_group_rekey_time_t *tlv_rekey_time = MNULL;
+ MrvlIEtypes_wep_key_t *tlv_wep_key = MNULL;
+ MrvlIEtypes_preamble_t *tlv_preamble = MNULL;
+ MrvlIEtypes_bss_status_t *tlv_bss_status = MNULL;
+ MrvlIETypes_HTCap_t *tlv_htcap = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter = MNULL;
+
+ wep_key *pkey = MNULL;
+ t_u16 i;
+ t_u16 ac;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ tlv = (MrvlIEtypesHeader_t *)sys_config->tlv_buffer;
+ tlv_buf_left =
+ resp->size - (sizeof(HostCmd_DS_SYS_CONFIG) - 1 + S_DS_GEN);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+
+ if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
+ PRINTM(MERROR,
+ "Error processing uAP sys config TLVs, bytes left < TLV length\n");
+ break;
+ }
+
+ switch (tlv_type) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ tlv_mac = (MrvlIEtypes_MacAddr_t *)tlv;
+ memcpy_ext(pmpriv->adapter,
+ &bss->param.bss_config.mac_addr,
+ tlv_mac->mac, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_SSID:
+ tlv_ssid = (MrvlIEtypes_SsIdParamSet_t *)tlv;
+ bss->param.bss_config.ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, tlv_len);
+ memcpy_ext(pmpriv->adapter,
+ bss->param.bss_config.ssid.ssid,
+ tlv_ssid->ssid, tlv_len,
+ MLAN_MAX_SSID_LENGTH);
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_beacon_period = (MrvlIEtypes_beacon_period_t *)tlv;
+ bss->param.bss_config.beacon_period = wlan_le16_to_cpu(
+ tlv_beacon_period->beacon_period);
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(
+ tlv_beacon_period->beacon_period);
+ break;
+ case TLV_TYPE_UAP_DTIM_PERIOD:
+ tlv_dtim_period = (MrvlIEtypes_dtim_period_t *)tlv;
+ bss->param.bss_config.dtim_period =
+ tlv_dtim_period->dtim_period;
+ pmpriv->uap_state_chan_cb.dtim_period =
+ tlv_dtim_period->dtim_period;
+ break;
+ case TLV_TYPE_RATES:
+ tlv_rates = (MrvlIEtypes_RatesParamSet_t *)tlv;
+ memcpy_ext(pmpriv->adapter, bss->param.bss_config.rates,
+ tlv_rates->rates, tlv_len, MAX_DATA_RATES);
+ break;
+ case TLV_TYPE_UAP_TX_DATA_RATE:
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *)tlv;
+ bss->param.bss_config.tx_data_rate =
+ wlan_le16_to_cpu(tlv_txrate->tx_data_rate);
+ break;
+ case TLV_TYPE_UAP_TX_BEACON_RATE:
+ tlv_txrate = (MrvlIEtypes_tx_rate_t *)tlv;
+ bss->param.bss_config.tx_beacon_rate =
+ wlan_le16_to_cpu(tlv_txrate->tx_data_rate);
+ break;
+ case TLV_TYPE_UAP_MCBC_DATA_RATE:
+ tlv_mcbc_rate = (MrvlIEtypes_mcbc_rate_t *)tlv;
+ bss->param.bss_config.mcbc_data_rate =
+ wlan_le16_to_cpu(tlv_mcbc_rate->mcbc_data_rate);
+ break;
+ case TLV_TYPE_UAP_TX_POWER:
+ tlv_tx_power = (MrvlIEtypes_tx_power_t *)tlv;
+ bss->param.bss_config.tx_power_level =
+ tlv_tx_power->tx_power;
+ break;
+ case TLV_TYPE_UAP_BCAST_SSID_CTL:
+ tlv_bcast_ssid = (MrvlIEtypes_bcast_ssid_t *)tlv;
+ bss->param.bss_config.bcast_ssid_ctl =
+ tlv_bcast_ssid->bcast_ssid_ctl;
+ break;
+ case TLV_TYPE_UAP_ANTENNA_CTL:
+ tlv_antenna = (MrvlIEtypes_antenna_mode_t *)tlv;
+ if (tlv_antenna->which_antenna == TX_ANTENNA)
+ bss->param.bss_config.tx_antenna =
+ tlv_antenna->antenna_mode;
+ else if (tlv_antenna->which_antenna == RX_ANTENNA)
+ bss->param.bss_config.rx_antenna =
+ tlv_antenna->antenna_mode;
+ break;
+ case TLV_TYPE_UAP_PKT_FWD_CTL:
+ tlv_pkt_forward = (MrvlIEtypes_pkt_forward_t *)tlv;
+ bss->param.bss_config.pkt_forward_ctl =
+ tlv_pkt_forward->pkt_forward_ctl;
+ break;
+ case TLV_TYPE_UAP_MAX_STA_CNT:
+ tlv_sta_count = (MrvlIEtypes_max_sta_count_t *)tlv;
+ bss->param.bss_config.max_sta_count =
+ wlan_le16_to_cpu(tlv_sta_count->max_sta_count);
+ break;
+ case TLV_TYPE_UAP_STA_AGEOUT_TIMER:
+ tlv_sta_ageout = (MrvlIEtypes_sta_ageout_t *)tlv;
+ bss->param.bss_config.sta_ageout_timer =
+ wlan_le32_to_cpu(
+ tlv_sta_ageout->sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_PS_STA_AGEOUT_TIMER:
+ tlv_ps_sta_ageout = (MrvlIEtypes_ps_sta_ageout_t *)tlv;
+ bss->param.bss_config.ps_sta_ageout_timer =
+ wlan_le32_to_cpu(
+ tlv_ps_sta_ageout->ps_sta_ageout_timer);
+ break;
+ case TLV_TYPE_UAP_RTS_THRESHOLD:
+ tlv_rts_threshold = (MrvlIEtypes_rts_threshold_t *)tlv;
+ bss->param.bss_config.rts_threshold = wlan_le16_to_cpu(
+ tlv_rts_threshold->rts_threshold);
+ break;
+ case TLV_TYPE_UAP_FRAG_THRESHOLD:
+ tlv_frag_threshold =
+ (MrvlIEtypes_frag_threshold_t *)tlv;
+ bss->param.bss_config.frag_threshold = wlan_le16_to_cpu(
+ tlv_frag_threshold->frag_threshold);
+ break;
+ case TLV_TYPE_UAP_RETRY_LIMIT:
+ tlv_retry_limit = (MrvlIEtypes_retry_limit_t *)tlv;
+ bss->param.bss_config.retry_limit =
+ tlv_retry_limit->retry_limit;
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_TIMEOUT:
+ tlv_pairwise_timeout =
+ (MrvlIEtypes_eapol_pwk_hsk_timeout_t *)tlv;
+ bss->param.bss_config
+ .pairwise_update_timeout = wlan_le32_to_cpu(
+ tlv_pairwise_timeout->pairwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_PWK_HSK_RETRIES:
+ tlv_pairwise_retries =
+ (MrvlIEtypes_eapol_pwk_hsk_retries_t *)tlv;
+ bss->param.bss_config.pwk_retries = wlan_le32_to_cpu(
+ tlv_pairwise_retries->pwk_retries);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_TIMEOUT:
+ tlv_groupwise_timeout =
+ (MrvlIEtypes_eapol_gwk_hsk_timeout_t *)tlv;
+ bss->param.bss_config.groupwise_update_timeout =
+ wlan_le32_to_cpu(
+ tlv_groupwise_timeout
+ ->groupwise_update_timeout);
+ break;
+ case TLV_TYPE_UAP_EAPOL_GWK_HSK_RETRIES:
+ tlv_groupwise_retries =
+ (MrvlIEtypes_eapol_gwk_hsk_retries_t *)tlv;
+ bss->param.bss_config.gwk_retries = wlan_le32_to_cpu(
+ tlv_groupwise_retries->gwk_retries);
+ break;
+ case TLV_TYPE_UAP_MGMT_IE_PASSTHRU_MASK:
+ tlv_mgmt_ie_passthru =
+ (MrvlIEtypes_mgmt_ie_passthru_t *)tlv;
+ bss->param.bss_config.mgmt_ie_passthru_mask =
+ wlan_le32_to_cpu(
+ tlv_mgmt_ie_passthru->mgmt_ie_mask);
+ break;
+ case TLV_TYPE_2040_BSS_COEX_CONTROL:
+ tlv_2040_coex_enable =
+ (MrvlIEtypes_2040_coex_enable_t *)tlv;
+ bss->param.bss_config.enable_2040coex =
+ tlv_2040_coex_enable->enable_2040coex;
+ break;
+ case TLV_TYPE_UAP_STA_MAC_ADDR_FILTER:
+ tlv_mac_filter = (MrvlIEtypes_mac_filter_t *)tlv;
+ bss->param.bss_config.filter.mac_count =
+ MIN(MAX_MAC_FILTER_NUM, tlv_mac_filter->count);
+ bss->param.bss_config.filter.filter_mode =
+ tlv_mac_filter->filter_mode;
+ memcpy_ext(
+ pmpriv->adapter,
+ (t_u8 *)bss->param.bss_config.filter.mac_list,
+ tlv_mac_filter->mac_address,
+ MLAN_MAC_ADDR_LENGTH *
+ bss->param.bss_config.filter.mac_count,
+ sizeof(bss->param.bss_config.filter.mac_list));
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_chan_band = (MrvlIEtypes_channel_band_t *)tlv;
+ bss->param.bss_config.bandcfg = tlv_chan_band->bandcfg;
+ bss->param.bss_config.channel = tlv_chan_band->channel;
+ pmpriv->uap_state_chan_cb.bandcfg =
+ tlv_chan_band->bandcfg;
+ pmpriv->uap_state_chan_cb.channel =
+ tlv_chan_band->channel;
+ break;
+ case TLV_TYPE_CHANLIST:
+ tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
+ bss->param.bss_config.num_of_chan =
+ tlv_len / sizeof(ChanScanParamSet_t);
+ pscan_chan = tlv_chan_list->chan_scan_param;
+ for (i = 0; i < bss->param.bss_config.num_of_chan;
+ i++) {
+ bss->param.bss_config.chan_list[i].chan_number =
+ pscan_chan->chan_number;
+ bss->param.bss_config.chan_list[i].bandcfg =
+ pscan_chan->bandcfg;
+ pscan_chan++;
+ }
+ break;
+ case TLV_TYPE_AUTH_TYPE:
+ tlv_auth_type = (MrvlIEtypes_auth_type_t *)tlv;
+ bss->param.bss_config.auth_mode =
+ tlv_auth_type->auth_type;
+ break;
+ case TLV_TYPE_UAP_ENCRYPT_PROTOCOL:
+ tlv_encrypt_protocol =
+ (MrvlIEtypes_encrypt_protocol_t *)tlv;
+ bss->param.bss_config.protocol = wlan_le16_to_cpu(
+ tlv_encrypt_protocol->protocol);
+ break;
+ case TLV_TYPE_UAP_AKMP:
+ tlv_akmp = (MrvlIEtypes_akmp_t *)tlv;
+ bss->param.bss_config.key_mgmt =
+ wlan_le16_to_cpu(tlv_akmp->key_mgmt);
+ if (tlv_len > sizeof(t_u16))
+ bss->param.bss_config.key_mgmt_operation =
+ wlan_le16_to_cpu(
+ tlv_akmp->key_mgmt_operation);
+ break;
+ case TLV_TYPE_PWK_CIPHER:
+ tlv_pwk_cipher = (MrvlIEtypes_pwk_cipher_t *)tlv;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) &
+ PROTOCOL_WPA)
+ bss->param.bss_config.wpa_cfg
+ .pairwise_cipher_wpa =
+ tlv_pwk_cipher->pairwise_cipher;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) &
+ PROTOCOL_WPA2)
+ bss->param.bss_config.wpa_cfg
+ .pairwise_cipher_wpa2 =
+ tlv_pwk_cipher->pairwise_cipher;
+ if (wlan_le16_to_cpu(tlv_pwk_cipher->protocol) &
+ PROTOCOL_WPA3_SAE)
+ bss->param.bss_config.wpa_cfg
+ .pairwise_cipher_wpa2 =
+ tlv_pwk_cipher->pairwise_cipher;
+ break;
+ case TLV_TYPE_GWK_CIPHER:
+ tlv_gwk_cipher = (MrvlIEtypes_gwk_cipher_t *)tlv;
+ bss->param.bss_config.wpa_cfg.group_cipher =
+ tlv_gwk_cipher->group_cipher;
+ break;
+ case TLV_TYPE_UAP_RSN_REPLAY_PROTECT:
+ tlv_rsn_prot = (MrvlIEtypes_rsn_replay_prot_t *)tlv;
+ bss->param.bss_config.wpa_cfg.rsn_protection =
+ tlv_rsn_prot->rsn_replay_prot;
+ break;
+ case TLV_TYPE_UAP_WPA_PASSPHRASE:
+ tlv_passphrase = (MrvlIEtypes_passphrase_t *)tlv;
+ bss->param.bss_config.wpa_cfg.length =
+ MIN(MLAN_PMK_HEXSTR_LENGTH, tlv_len);
+ memcpy_ext(pmpriv->adapter,
+ bss->param.bss_config.wpa_cfg.passphrase,
+ tlv_passphrase->passphrase,
+ bss->param.bss_config.wpa_cfg.length,
+ sizeof(bss->param.bss_config.wpa_cfg
+ .passphrase));
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case TLV_TYPE_UAP_PSK:
+ tlv_psk = (MrvlIEtypes_psk_t *)tlv;
+ memcpy_ext(pmpriv->adapter, bss->param.bss_config.psk,
+ tlv_psk->psk, tlv_len, MLAN_MAX_KEY_LENGTH);
+ break;
+#endif /* WIFI_DIRECT_SUPPORT */
+ case TLV_TYPE_UAP_GRP_REKEY_TIME:
+ tlv_rekey_time = (MrvlIEtypes_group_rekey_time_t *)tlv;
+ bss->param.bss_config.wpa_cfg.gk_rekey_time =
+ wlan_le32_to_cpu(tlv_rekey_time->gk_rekey_time);
+ break;
+ case TLV_TYPE_UAP_WEP_KEY:
+ tlv_wep_key = (MrvlIEtypes_wep_key_t *)tlv;
+ pkey = MNULL;
+ if (tlv_wep_key->key_index == 0)
+ pkey = &bss->param.bss_config.wep_cfg.key0;
+ else if (tlv_wep_key->key_index == 1)
+ pkey = &bss->param.bss_config.wep_cfg.key1;
+ else if (tlv_wep_key->key_index == 2)
+ pkey = &bss->param.bss_config.wep_cfg.key2;
+ else if (tlv_wep_key->key_index == 3)
+ pkey = &bss->param.bss_config.wep_cfg.key3;
+ if (pkey) {
+ pkey->key_index = tlv_wep_key->key_index;
+ pkey->is_default = tlv_wep_key->is_default;
+ pkey->length =
+ MIN(MAX_WEP_KEY_SIZE, (tlv_len - 2));
+ memcpy_ext(pmpriv->adapter, pkey->key,
+ tlv_wep_key->key, pkey->length,
+ pkey->length);
+ }
+ break;
+ case TLV_TYPE_UAP_PREAMBLE_CTL:
+ tlv_preamble = (MrvlIEtypes_preamble_t *)tlv;
+ bss->param.bss_config.preamble_type =
+ tlv_preamble->preamble_type;
+ break;
+ case TLV_TYPE_BSS_STATUS:
+ tlv_bss_status = (MrvlIEtypes_bss_status_t *)tlv;
+ bss->param.bss_config.bss_status =
+ wlan_le16_to_cpu(tlv_bss_status->bss_status);
+ pmpriv->uap_bss_started =
+ (bss->param.bss_config.bss_status) ? MTRUE :
+ MFALSE;
+ break;
+ case TLV_TYPE_HT_CAPABILITY:
+ tlv_htcap = (MrvlIETypes_HTCap_t *)tlv;
+ bss->param.bss_config.ht_cap_info =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_cap_info);
+ bss->param.bss_config.ampdu_param =
+ tlv_htcap->ht_cap.ampdu_param;
+ memcpy_ext(
+ pmpriv->adapter,
+ bss->param.bss_config.supported_mcs_set,
+ tlv_htcap->ht_cap.supported_mcs_set, 16,
+ sizeof(bss->param.bss_config.supported_mcs_set));
+ bss->param.bss_config.ht_ext_cap =
+ wlan_le16_to_cpu(tlv_htcap->ht_cap.ht_ext_cap);
+ bss->param.bss_config.tx_bf_cap =
+ wlan_le32_to_cpu(tlv_htcap->ht_cap.tx_bf_cap);
+ bss->param.bss_config.asel = tlv_htcap->ht_cap.asel;
+ break;
+ case TLV_TYPE_VENDOR_SPECIFIC_IE:
+ tlv_wmm_parameter = (MrvlIEtypes_wmm_parameter_t *)tlv;
+ bss->param.bss_config.wmm_para.qos_info =
+ tlv_wmm_parameter->wmm_para.qos_info;
+ for (ac = 0; ac < 4; ac++) {
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .aci_aifsn.aifsn =
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aifsn;
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .aci_aifsn.aci =
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aci;
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .ecw.ecw_max =
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .ecw.ecw_max;
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .ecw.ecw_min =
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .ecw.ecw_min;
+ bss->param.bss_config.wmm_para.ac_params[ac]
+ .tx_op_limit = wlan_le16_to_cpu(
+ tlv_wmm_parameter->wmm_para
+ .ac_params[ac]
+ .tx_op_limit);
+ }
+ break;
+ }
+
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (!IS_FW_SUPPORT_AUTHENTICATOR(pmpriv->adapter))
+ AuthenticatorBssConfig(pmpriv->psapriv,
+ (t_u8 *)&bss->param.bss_config, 0, 0, 1);
+#endif
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_reset
+ * Clear various private state variables used by DFS.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_sys_reset(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ ENTER();
+
+ memset(pmpriv->adapter, &(pmpriv->uap_state_chan_cb.bandcfg), 0,
+ sizeof(pmpriv->uap_state_chan_cb.bandcfg));
+ pmpriv->uap_state_chan_cb.channel = 0;
+ pmpriv->uap_state_chan_cb.beacon_period = 0;
+ pmpriv->uap_state_chan_cb.dtim_period = 0;
+
+ /* assume default 11d/11h states are off, should check with FW */
+ /* currently don't clear domain_info... global, could be from STA */
+ wlan_11d_priv_init(pmpriv);
+ wlan_11h_priv_init(pmpriv);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_sys_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ int resp_len = 0, travel_len = 0;
+ int i = 0;
+ custom_ie *cptr;
+ HostCmd_DS_SYS_CONFIG *sys_config =
+ (HostCmd_DS_SYS_CONFIG *)&resp->params.sys_config;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ MrvlIEtypes_MacAddr_t *tlv =
+ (MrvlIEtypes_MacAddr_t *)sys_config->tlv_buffer;
+ mlan_ds_misc_custom_ie *cust_ie = MNULL;
+ tlvbuf_max_mgmt_ie *max_mgmt_ie = MNULL;
+ MrvlIEtypes_wmm_parameter_t *tlv_wmm_parameter =
+ (MrvlIEtypes_wmm_parameter_t *)sys_config->tlv_buffer;
+ MrvlIEtypes_ChanListParamSet_t *tlv_chan_list =
+ (MrvlIEtypes_ChanListParamSet_t *)sys_config->tlv_buffer;
+ MrvlIEtypes_channel_band_t *chan_band_tlv =
+ (MrvlIEtypes_channel_band_t *)sys_config->tlv_buffer;
+ ChanScanParamSet_t *pscan_chan = MNULL;
+ t_u8 ac = 0;
+ MrvlIEtypes_channel_band_t *tlv_cb = MNULL;
+ MrvlIEtypes_beacon_period_t *tlv_bcnpd = MNULL;
+ MrvlIEtypes_dtim_period_t *tlv_dtimpd = MNULL;
+ MrvlIEtypes_uap_max_sta_cnt_t *tlv_uap_max_sta = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ if (pioctl_buf->req_id == MLAN_IOCTL_BSS) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR) {
+ if (TLV_TYPE_UAP_MAC_ADDRESS ==
+ wlan_le16_to_cpu(tlv->header.type)) {
+ memcpy_ext(pmpriv->adapter,
+ &bss->param.mac_addr,
+ tlv->mac,
+ MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+ } else if (bss->sub_command ==
+ MLAN_OID_UAP_CFG_WMM_PARAM) {
+ if (TLV_TYPE_AP_WMM_PARAM ==
+ wlan_le16_to_cpu(
+ tlv_wmm_parameter->header.type)) {
+ if (wlan_le16_to_cpu(
+ tlv_wmm_parameter->header
+ .len) <
+ sizeof(bss->param.ap_wmm_para)) {
+ PRINTM(MCMND,
+ "FW don't support AP WMM PARAM\n");
+ } else {
+ bss->param.ap_wmm_para.reserved =
+ MLAN_STATUS_COMPLETE;
+ for (ac = 0; ac < 4; ac++) {
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .aci_aifsn
+ .aifsn =
+ tlv_wmm_parameter
+ ->wmm_para
+ .ac_params
+ [ac]
+ .aci_aifsn
+ .aifsn;
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .aci_aifsn.aci =
+ tlv_wmm_parameter
+ ->wmm_para
+ .ac_params
+ [ac]
+ .aci_aifsn
+ .aci;
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .ecw.ecw_max =
+ tlv_wmm_parameter
+ ->wmm_para
+ .ac_params
+ [ac]
+ .ecw
+ .ecw_max;
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .ecw.ecw_min =
+ tlv_wmm_parameter
+ ->wmm_para
+ .ac_params
+ [ac]
+ .ecw
+ .ecw_min;
+ bss->param.ap_wmm_para
+ .ac_params[ac]
+ .tx_op_limit = wlan_le16_to_cpu(
+ tlv_wmm_parameter
+ ->wmm_para
+ .ac_params
+ [ac]
+ .tx_op_limit);
+ PRINTM(MCMND,
+ "ac=%d, aifsn=%d, aci=%d, ecw_max=%d, ecw_min=%d, tx_op=%d\n",
+ ac,
+ bss->param
+ .ap_wmm_para
+ .ac_params
+ [ac]
+ .aci_aifsn
+ .aifsn,
+ bss->param
+ .ap_wmm_para
+ .ac_params
+ [ac]
+ .aci_aifsn
+ .aci,
+ bss->param
+ .ap_wmm_para
+ .ac_params
+ [ac]
+ .ecw
+ .ecw_max,
+ bss->param
+ .ap_wmm_para
+ .ac_params
+ [ac]
+ .ecw
+ .ecw_min,
+ bss->param
+ .ap_wmm_para
+ .ac_params
+ [ac]
+ .tx_op_limit);
+ }
+ }
+ }
+ } else if (bss->sub_command ==
+ MLAN_OID_UAP_SCAN_CHANNELS) {
+ if (TLV_TYPE_CHANLIST ==
+ wlan_le16_to_cpu(
+ tlv_chan_list->header.type)) {
+ pscan_chan =
+ tlv_chan_list->chan_scan_param;
+ bss->param.ap_scan_channels.num_of_chan =
+ 0;
+ for (i = 0;
+ i <
+ wlan_le16_to_cpu(
+ tlv_chan_list->header.len) /
+ sizeof(ChanScanParamSet_t);
+ i++) {
+ if (bss->param.ap_scan_channels
+ .remove_nop_channel &&
+ wlan_11h_is_channel_under_nop(
+ pmpriv->adapter,
+ pscan_chan
+ ->chan_number)) {
+ bss->param
+ .ap_scan_channels
+ .num_remvoed_channel++;
+ PRINTM(MCMND,
+ "Remove nop channel=%d\n",
+ pscan_chan
+ ->chan_number);
+ pscan_chan++;
+ continue;
+ }
+ bss->param.ap_scan_channels
+ .chan_list
+ [bss->param
+ .ap_scan_channels
+ .num_of_chan]
+ .chan_number =
+ pscan_chan->chan_number;
+ bss->param.ap_scan_channels
+ .chan_list
+ [bss->param
+ .ap_scan_channels
+ .num_of_chan]
+ .bandcfg =
+ pscan_chan->bandcfg;
+ bss->param.ap_scan_channels
+ .num_of_chan++;
+ pscan_chan++;
+ }
+ PRINTM(MCMND,
+ "AP scan channel list=%d\n",
+ bss->param.ap_scan_channels
+ .num_of_chan);
+ }
+ } else if (bss->sub_command == MLAN_OID_UAP_CHANNEL) {
+ if (TLV_TYPE_UAP_CHAN_BAND_CONFIG ==
+ wlan_le16_to_cpu(
+ chan_band_tlv->header.type)) {
+ bss->param.ap_channel.bandcfg =
+ chan_band_tlv->bandcfg;
+ bss->param.ap_channel.channel =
+ chan_band_tlv->channel;
+ bss->param.ap_channel.is_11n_enabled =
+ pmpriv->is_11n_enabled;
+ bss->param.ap_channel.is_dfs_chan =
+ wlan_11h_radar_detect_required(
+ pmpriv,
+ bss->param.ap_channel
+ .channel);
+ if (chan_band_tlv->bandcfg.chanWidth ==
+ CHAN_BW_80MHZ)
+ bss->param.ap_channel
+ .center_chan =
+ wlan_get_center_freq_idx(
+ pmpriv,
+ BAND_AAC,
+ chan_band_tlv
+ ->channel,
+ CHANNEL_BW_80MHZ);
+ PRINTM(MCMND,
+ "AP channel, band=0x%x, channel=%d, is_11n_enabled=%d center_chan=%d\n",
+ bss->param.ap_channel.bandcfg,
+ bss->param.ap_channel.channel,
+ bss->param.ap_channel
+ .is_11n_enabled,
+ bss->param.ap_channel
+ .center_chan);
+ }
+ } else if ((bss->sub_command ==
+ MLAN_OID_UAP_BSS_CONFIG) &&
+ (pioctl_buf->action == MLAN_ACT_GET)) {
+ wlan_uap_ret_cmd_ap_config(pmpriv, resp,
+ pioctl_buf);
+ }
+ }
+ if (pioctl_buf->req_id == MLAN_IOCTL_MISC_CFG) {
+ misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf;
+ cust_ie = (mlan_ds_misc_custom_ie *)
+ sys_config->tlv_buffer;
+ if ((pioctl_buf->action == MLAN_ACT_GET ||
+ pioctl_buf->action == MLAN_ACT_SET) &&
+ (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)) {
+ cust_ie->type = wlan_le16_to_cpu(cust_ie->type);
+ resp_len = cust_ie->len =
+ wlan_le16_to_cpu(cust_ie->len);
+ travel_len = 0;
+ /* conversion for index, mask, len */
+ if (resp_len == sizeof(t_u16))
+ cust_ie->ie_data_list[0].ie_index =
+ wlan_cpu_to_le16(
+ cust_ie->ie_data_list[0]
+ .ie_index);
+
+ while (resp_len > sizeof(t_u16)) {
+ cptr = (custom_ie
+ *)(((t_u8 *)cust_ie
+ ->ie_data_list) +
+ travel_len);
+ cptr->ie_index = wlan_le16_to_cpu(
+ cptr->ie_index);
+ cptr->mgmt_subtype_mask =
+ wlan_le16_to_cpu(
+ cptr->mgmt_subtype_mask);
+ cptr->ie_length = wlan_le16_to_cpu(
+ cptr->ie_length);
+ travel_len += cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ resp_len -= cptr->ie_length +
+ sizeof(custom_ie) -
+ MAX_IE_SIZE;
+ }
+ memcpy_ext(pmpriv->adapter,
+ &misc->param.cust_ie, cust_ie,
+ cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(mlan_ds_misc_custom_ie) -
+ sizeof(tlvbuf_max_mgmt_ie));
+ max_mgmt_ie =
+ (tlvbuf_max_mgmt_ie
+ *)(sys_config->tlv_buffer +
+ cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t));
+ if (max_mgmt_ie) {
+ max_mgmt_ie->type = wlan_le16_to_cpu(
+ max_mgmt_ie->type);
+ if (max_mgmt_ie->type ==
+ TLV_TYPE_MAX_MGMT_IE) {
+ max_mgmt_ie->len =
+ wlan_le16_to_cpu(
+ max_mgmt_ie
+ ->len);
+ max_mgmt_ie->count =
+ wlan_le16_to_cpu(
+ max_mgmt_ie
+ ->count);
+ for (i = 0;
+ i < max_mgmt_ie->count;
+ i++) {
+ max_mgmt_ie->info[i]
+ .buf_size = wlan_le16_to_cpu(
+ max_mgmt_ie
+ ->info[i]
+ .buf_size);
+ max_mgmt_ie->info[i]
+ .buf_count = wlan_le16_to_cpu(
+ max_mgmt_ie
+ ->info[i]
+ .buf_count);
+ }
+ /* Append max_mgmt_ie TLV after
+ * custom_ie */
+ memcpy_ext(
+ pmpriv->adapter,
+ (t_u8 *)&misc->param
+ .cust_ie +
+ (cust_ie->len +
+ sizeof(MrvlIEtypesHeader_t)),
+ max_mgmt_ie,
+ max_mgmt_ie->len +
+ sizeof(MrvlIEtypesHeader_t),
+ sizeof(tlvbuf_max_mgmt_ie));
+ }
+ }
+ }
+ }
+ } else { /* no ioctl: driver generated get/set */
+ switch (wlan_le16_to_cpu(tlv->header.type)) {
+ case TLV_TYPE_UAP_MAC_ADDRESS:
+ memcpy_ext(pmpriv->adapter, pmpriv->curr_addr, tlv->mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ break;
+ case TLV_TYPE_UAP_MAX_STA_CNT_PER_CHIP:
+ tlv_uap_max_sta = (MrvlIEtypes_uap_max_sta_cnt_t *)tlv;
+ pmpriv->adapter->max_sta_conn =
+ wlan_le16_to_cpu(tlv_uap_max_sta->uap_max_sta);
+ PRINTM(MCMND, "Uap max_sta per chip=%d\n",
+ wlan_le16_to_cpu(tlv_uap_max_sta->uap_max_sta));
+ break;
+ case TLV_TYPE_UAP_CHAN_BAND_CONFIG:
+ tlv_cb = (MrvlIEtypes_channel_band_t *)tlv;
+ pmpriv->uap_state_chan_cb.bandcfg = tlv_cb->bandcfg;
+ pmpriv->uap_state_chan_cb.channel = tlv_cb->channel;
+ /* call callback waiting for channel info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(
+ pmpriv);
+ break;
+ case TLV_TYPE_UAP_BEACON_PERIOD:
+ tlv_bcnpd = (MrvlIEtypes_beacon_period_t *)tlv;
+ pmpriv->uap_state_chan_cb.beacon_period =
+ wlan_le16_to_cpu(tlv_bcnpd->beacon_period);
+ /* copy dtim_period as well if it follows */
+ tlv_dtimpd =
+ (MrvlIEtypes_dtim_period_t
+ *)(((t_u8 *)tlv) +
+ sizeof(MrvlIEtypes_beacon_period_t));
+ if (TLV_TYPE_UAP_DTIM_PERIOD ==
+ wlan_le16_to_cpu(tlv_dtimpd->header.type))
+ pmpriv->uap_state_chan_cb.dtim_period =
+ tlv_dtimpd->dtim_period;
+ /* call callback waiting for beacon/dtim info */
+ if (pmpriv->uap_state_chan_cb.get_chan_callback)
+ pmpriv->uap_state_chan_cb.get_chan_callback(
+ pmpriv);
+ break;
+ case TLV_TYPE_MGMT_IE:
+ if ((pmpriv->adapter->state_rdh.stage ==
+ RDH_SET_CUSTOM_IE) ||
+ (pmpriv->adapter->state_rdh.stage ==
+ RDH_REM_CUSTOM_IE)) {
+ if (!pmpriv->adapter->ecsa_enable)
+ wlan_11h_radar_detected_callback(
+ (t_void *)pmpriv);
+ }
+ break;
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @param pdata_buf A pointer to information buffer
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_uap_cmd_snmp_mib(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ pmlan_ioctl_req pioctl_buf,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib = &cmd->params.smib;
+ HostCmd_DS_UAP_802_11_SNMP_MIB *puap_snmp_mib = &cmd->params.uap_smib;
+
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 ul_temp;
+ t_u8 i;
+
+ t_u8 snmp_oids[] = {
+ tkip_mic_failures,
+ ccmp_decrypt_errors,
+ wep_undecryptable_count,
+ wep_icv_error_count,
+ decrypt_failure_count,
+ dot11_mcast_tx_count,
+ dot11_failed_count,
+ dot11_retry_count,
+ dot11_multi_retry_count,
+ dot11_frame_dup_count,
+ dot11_rts_success_count,
+ dot11_rts_failure_count,
+ dot11_ack_failure_count,
+ dot11_rx_fragment_count,
+ dot11_mcast_rx_frame_count,
+ dot11_fcs_error_count,
+ dot11_tx_frame_count,
+ dot11_rsna_tkip_cm_invoked,
+ dot11_rsna_4way_hshk_failures,
+ };
+
+ ENTER();
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+ if (cmd_oid == StopDeauth_i) {
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)StopDeauth_i);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_802_11_SNMP_MIB) + S_DS_GEN);
+ } else {
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(t_u16) + S_DS_GEN +
+ sizeof(snmp_oids) *
+ sizeof(MrvlIEtypes_snmp_oid_t));
+ psnmp_oid = (t_u8 *)&puap_snmp_mib->snmp_data;
+ for (i = 0; i < sizeof(snmp_oids); i++) {
+ /* SNMP OID header type */
+ *(t_u16 *)psnmp_oid =
+ wlan_cpu_to_le16(snmp_oids[i]);
+ psnmp_oid += sizeof(t_u16);
+ /* SNMP OID header length */
+ *(t_u16 *)psnmp_oid =
+ wlan_cpu_to_le16(sizeof(t_u32));
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u32);
+ }
+ }
+ } else { /* cmd_action == ACT_SET */
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = sizeof(HostCmd_DS_802_11_SNMP_MIB) - 1 + S_DS_GEN;
+ psnmp_mib->query_type = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+
+ switch (cmd_oid) {
+ case Dot11D_i:
+ case Dot11H_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)cmd_oid);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u16));
+ ul_temp = *(t_u32 *)pdata_buf;
+ *((t_u16 *)(psnmp_mib->value)) =
+ wlan_cpu_to_le16((t_u16)ul_temp);
+ cmd->size += sizeof(t_u16);
+ break;
+ case ECSAEnable_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)cmd_oid);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ psnmp_mib->value[0] = *((t_u8 *)pdata_buf);
+ cmd->size += sizeof(t_u8);
+ break;
+ case StopDeauth_i:
+ psnmp_mib->oid = wlan_cpu_to_le16((t_u16)cmd_oid);
+ psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u8));
+ psnmp_mib->value[0] = *((t_u8 *)pdata_buf);
+ cmd->size += sizeof(t_u8);
+ break;
+ default:
+ PRINTM(MERROR, "Unsupported OID.\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of get_log.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_802_11_get_log(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd)
+{
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of bss_start.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_bss_start(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd)
+{
+ MrvlIEtypes_HostMlme_t *tlv;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_BSS_START);
+ cmd->size = S_DS_GEN;
+ if (pmpriv->uap_host_based & UAP_FLAG_HOST_MLME) {
+ tlv = (MrvlIEtypes_HostMlme_t *)((t_u8 *)cmd + cmd->size);
+ tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_HOST_MLME);
+ tlv->header.len = wlan_cpu_to_le16(sizeof(tlv->host_mlme));
+ tlv->host_mlme = MTRUE;
+ cmd->size += sizeof(MrvlIEtypes_HostMlme_t);
+ }
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of snmp_mib
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_snmp_mib(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ HostCmd_DS_802_11_SNMP_MIB *psnmp_mib =
+ (HostCmd_DS_802_11_SNMP_MIB *)&resp->params.smib;
+ mlan_ds_get_info *info;
+ mlan_ds_snmp_mib *mib = MNULL;
+ t_u16 oid = wlan_le16_to_cpu(psnmp_mib->oid);
+ t_u8 *psnmp_oid = MNULL;
+ t_u32 data;
+ t_u16 tlv_buf_left = 0;
+ t_u16 tlv_type = 0;
+ t_u16 query_type = wlan_le16_to_cpu(psnmp_mib->query_type);
+
+ ENTER();
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (oid == StopDeauth_i) {
+ mib = (mlan_ds_snmp_mib *)pioctl_buf->pbuf;
+ if (mib)
+ mib->param.deauthctrl = psnmp_mib->value[0];
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ tlv_buf_left = resp->size - (sizeof(t_u16) + S_DS_GEN);
+ psnmp_oid = (t_u8 *)&psnmp_mib->oid;
+ while (tlv_buf_left >= sizeof(MrvlIEtypes_snmp_oid_t)) {
+ tlv_type = wlan_le16_to_cpu(*(t_u16 *)psnmp_oid);
+ psnmp_oid += sizeof(t_u16) + sizeof(t_u16);
+ memcpy_ext(pmadapter, &data, psnmp_oid, sizeof(t_u32),
+ sizeof(t_u32));
+ switch (tlv_type) {
+ case tkip_mic_failures:
+ info->param.ustats.tkip_mic_failures =
+ wlan_le32_to_cpu(data);
+ break;
+ case ccmp_decrypt_errors:
+ info->param.ustats.ccmp_decrypt_errors =
+ wlan_le32_to_cpu(data);
+ break;
+ case wep_undecryptable_count:
+ info->param.ustats.wep_undecryptable_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case wep_icv_error_count:
+ info->param.ustats.wep_icv_error_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case decrypt_failure_count:
+ info->param.ustats.decrypt_failure_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_tx_count:
+ info->param.ustats.mcast_tx_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_failed_count:
+ info->param.ustats.failed_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_retry_count:
+ info->param.ustats.retry_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_multi_retry_count:
+ info->param.ustats.multi_retry_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_frame_dup_count:
+ info->param.ustats.frame_dup_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_success_count:
+ info->param.ustats.rts_success_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rts_failure_count:
+ info->param.ustats.rts_failure_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_ack_failure_count:
+ info->param.ustats.ack_failure_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rx_fragment_count:
+ info->param.ustats.rx_fragment_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_mcast_rx_frame_count:
+ info->param.ustats.mcast_rx_frame_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_fcs_error_count:
+ info->param.ustats.fcs_error_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_tx_frame_count:
+ info->param.ustats.tx_frame_count =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_tkip_cm_invoked:
+ info->param.ustats.rsna_tkip_cm_invoked =
+ wlan_le32_to_cpu(data);
+ break;
+ case dot11_rsna_4way_hshk_failures:
+ info->param.ustats.rsna_4way_hshk_failures =
+ wlan_le32_to_cpu(data);
+ break;
+ }
+ tlv_buf_left -= sizeof(MrvlIEtypes_snmp_oid_t);
+ psnmp_oid += sizeof(t_u32);
+ }
+ } else { /* ACT_SET */
+ switch (wlan_le16_to_cpu(psnmp_mib->oid)) {
+ case Dot11D_i:
+ data = wlan_le16_to_cpu(*((t_u16 *)(psnmp_mib->value)));
+ /* Set 11d state to private */
+ pmpriv->state_11d.enable_11d = data;
+ /* Set user enable flag if called from ioctl */
+ if (pioctl_buf)
+ pmpriv->state_11d.user_enable_11d = data;
+ break;
+ case Dot11H_i:
+ data = wlan_le16_to_cpu(*((t_u16 *)(psnmp_mib->value)));
+ /* Set 11h state to priv */
+ pmpriv->intf_state_11h.is_11h_active =
+ (data & ENABLE_11H_MASK);
+ /* Set radar_det state to adapter */
+ pmpriv->adapter->state_11h.is_master_radar_det_active =
+ (data & MASTER_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ pmpriv->adapter->state_11h.is_slave_radar_det_active =
+ (data & SLAVE_RADAR_DET_MASK) ? MTRUE : MFALSE;
+ break;
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of get_log
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_get_log(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_802_11_GET_LOG *pget_log =
+ (HostCmd_DS_802_11_GET_LOG *)&resp->params.get_log;
+ mlan_ds_get_info *pget_info = MNULL;
+ int i = 0;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pget_info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ pget_info->param.stats.mcast_tx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_tx_frame);
+ pget_info->param.stats.failed =
+ wlan_le32_to_cpu(pget_log->failed);
+ pget_info->param.stats.retry =
+ wlan_le32_to_cpu(pget_log->retry);
+ pget_info->param.stats.multi_retry =
+ wlan_le32_to_cpu(pget_log->multiretry);
+ pget_info->param.stats.frame_dup =
+ wlan_le32_to_cpu(pget_log->frame_dup);
+ pget_info->param.stats.rts_success =
+ wlan_le32_to_cpu(pget_log->rts_success);
+ pget_info->param.stats.rts_failure =
+ wlan_le32_to_cpu(pget_log->rts_failure);
+ pget_info->param.stats.ack_failure =
+ wlan_le32_to_cpu(pget_log->ack_failure);
+ pget_info->param.stats.rx_frag =
+ wlan_le32_to_cpu(pget_log->rx_frag);
+ pget_info->param.stats.mcast_rx_frame =
+ wlan_le32_to_cpu(pget_log->mcast_rx_frame);
+ pget_info->param.stats.fcs_error =
+ wlan_le32_to_cpu(pget_log->fcs_error);
+ pget_info->param.stats.tx_frame =
+ wlan_le32_to_cpu(pget_log->tx_frame);
+ pget_info->param.stats.wep_icv_error[0] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[0]);
+ pget_info->param.stats.wep_icv_error[1] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[1]);
+ pget_info->param.stats.wep_icv_error[2] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[2]);
+ pget_info->param.stats.wep_icv_error[3] =
+ wlan_le32_to_cpu(pget_log->wep_icv_err_cnt[3]);
+ pget_info->param.stats.bcn_rcv_cnt =
+ wlan_le32_to_cpu(pget_log->bcn_rcv_cnt);
+ pget_info->param.stats.bcn_miss_cnt =
+ wlan_le32_to_cpu(pget_log->bcn_miss_cnt);
+ pget_info->param.stats.amsdu_rx_cnt = pmpriv->amsdu_rx_cnt;
+ pget_info->param.stats.msdu_in_rx_amsdu_cnt =
+ pmpriv->msdu_in_rx_amsdu_cnt;
+ pget_info->param.stats.amsdu_tx_cnt = pmpriv->amsdu_tx_cnt;
+ pget_info->param.stats.msdu_in_tx_amsdu_cnt =
+ pmpriv->msdu_in_tx_amsdu_cnt;
+ pget_info->param.stats.rx_stuck_issue_cnt[0] =
+ wlan_le32_to_cpu(pget_log->rx_stuck_issue_cnt[0]);
+ pget_info->param.stats.rx_stuck_issue_cnt[1] =
+ wlan_le32_to_cpu(pget_log->rx_stuck_issue_cnt[1]);
+ pget_info->param.stats.rx_stuck_recovery_cnt =
+ wlan_le32_to_cpu(pget_log->rx_stuck_recovery_cnt);
+ pget_info->param.stats.rx_stuck_tsf[0] =
+ wlan_le64_to_cpu(pget_log->rx_stuck_tsf[0]);
+ pget_info->param.stats.rx_stuck_tsf[1] =
+ wlan_le64_to_cpu(pget_log->rx_stuck_tsf[1]);
+ pget_info->param.stats.tx_watchdog_recovery_cnt =
+ wlan_le32_to_cpu(pget_log->tx_watchdog_recovery_cnt);
+ pget_info->param.stats.tx_watchdog_tsf[0] =
+ wlan_le64_to_cpu(pget_log->tx_watchdog_tsf[0]);
+ pget_info->param.stats.tx_watchdog_tsf[1] =
+ wlan_le64_to_cpu(pget_log->tx_watchdog_tsf[1]);
+ pget_info->param.stats.channel_switch_ann_sent =
+ wlan_le32_to_cpu(pget_log->channel_switch_ann_sent);
+ pget_info->param.stats.channel_switch_state =
+ wlan_le32_to_cpu(pget_log->channel_switch_state);
+ pget_info->param.stats.reg_class =
+ wlan_le32_to_cpu(pget_log->reg_class);
+ pget_info->param.stats.channel_number =
+ wlan_le32_to_cpu(pget_log->channel_number);
+ pget_info->param.stats.channel_switch_mode =
+ wlan_le32_to_cpu(pget_log->channel_switch_mode);
+ if (pmpriv->adapter->getlog_enable) {
+ pget_info->param.stats.tx_frag_cnt =
+ wlan_le32_to_cpu(pget_log->tx_frag_cnt);
+ for (i = 0; i < 8; i++) {
+ pget_info->param.stats.qos_tx_frag_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_tx_frag_cnt[i]);
+ pget_info->param.stats.qos_failed_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_failed_cnt[i]);
+ pget_info->param.stats.qos_retry_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_retry_cnt[i]);
+ pget_info->param.stats.qos_multi_retry_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_multi_retry_cnt[i]);
+ pget_info->param.stats.qos_frm_dup_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_frm_dup_cnt[i]);
+ pget_info->param.stats.qos_rts_suc_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rts_suc_cnt[i]);
+ pget_info->param.stats.qos_rts_failure_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rts_failure_cnt[i]);
+ pget_info->param.stats.qos_ack_failure_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_ack_failure_cnt[i]);
+ pget_info->param.stats.qos_rx_frag_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_rx_frag_cnt[i]);
+ pget_info->param.stats.qos_tx_frm_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_tx_frm_cnt[i]);
+ pget_info->param.stats.qos_discarded_frm_cnt
+ [i] = wlan_le32_to_cpu(
+ pget_log->qos_discarded_frm_cnt[i]);
+ pget_info->param.stats.qos_mpdus_rx_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_mpdus_rx_cnt[i]);
+ pget_info->param.stats.qos_retries_rx_cnt[i] =
+ wlan_le32_to_cpu(
+ pget_log->qos_retries_rx_cnt[i]);
+ }
+ pget_info->param.stats.mgmt_ccmp_replays =
+ wlan_le32_to_cpu(pget_log->mgmt_ccmp_replays);
+ pget_info->param.stats.tx_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->tx_amsdu_cnt);
+ pget_info->param.stats.failed_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->failed_amsdu_cnt);
+ pget_info->param.stats.retry_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->retry_amsdu_cnt);
+ pget_info->param.stats.multi_retry_amsdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->multi_retry_amsdu_cnt);
+ pget_info->param.stats.tx_octets_in_amsdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->tx_octets_in_amsdu_cnt);
+ pget_info->param.stats.amsdu_ack_failure_cnt =
+ wlan_le32_to_cpu(
+ pget_log->amsdu_ack_failure_cnt);
+ pget_info->param.stats.rx_amsdu_cnt =
+ wlan_le32_to_cpu(pget_log->rx_amsdu_cnt);
+ pget_info->param.stats.rx_octets_in_amsdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->rx_octets_in_amsdu_cnt);
+ pget_info->param.stats.tx_ampdu_cnt =
+ wlan_le32_to_cpu(pget_log->tx_ampdu_cnt);
+ pget_info->param.stats.tx_mpdus_in_ampdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->tx_mpdus_in_ampdu_cnt);
+ pget_info->param.stats.tx_octets_in_ampdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->tx_octets_in_ampdu_cnt);
+ pget_info->param.stats.ampdu_rx_cnt =
+ wlan_le32_to_cpu(pget_log->ampdu_rx_cnt);
+ pget_info->param.stats.mpdu_in_rx_ampdu_cnt =
+ wlan_le32_to_cpu(
+ pget_log->mpdu_in_rx_ampdu_cnt);
+ pget_info->param.stats.rx_octets_in_ampdu_cnt =
+ wlan_le64_to_cpu(
+ pget_log->rx_octets_in_ampdu_cnt);
+ pget_info->param.stats.ampdu_delimiter_crc_error_cnt =
+ wlan_le32_to_cpu(
+ pget_log->ampdu_delimiter_crc_error_cnt);
+
+ /* Indicate ioctl complete */
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_get_info);
+ } else
+ pioctl_buf->data_read_written =
+ sizeof(mlan_ds_get_stats_org) +
+ sizeof(pget_info->sub_command);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of deauth station
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_sta_deauth(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_STA_DEAUTH *pcmd_sta_deauth =
+ (HostCmd_DS_STA_DEAUTH *)&cmd->params.sta_deauth;
+ mlan_deauth_param *deauth = (mlan_deauth_param *)pdata_buf;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_STA_DEAUTH);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_STA_DEAUTH));
+ memcpy_ext(pmpriv->adapter, pcmd_sta_deauth->mac, deauth->mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ pcmd_sta_deauth->reason = wlan_cpu_to_le16(deauth->reason_code);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of report mic_err
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_report_mic(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_REPORT_MIC *pcmd_report_mic =
+ (HostCmd_DS_REPORT_MIC *)&cmd->params.report_mic;
+
+ ENTER();
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_REPORT_MIC);
+ cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_REPORT_MIC));
+ memcpy_ext(pmpriv->adapter, pcmd_report_mic->mac, pdata_buf,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of key material
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action The action: GET or SET
+ * @param cmd_oid OID: ENABLE or DISABLE
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_key_material(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_u16 cmd_oid,
+ t_void *pdata_buf)
+{
+ HostCmd_DS_802_11_KEY_MATERIAL *pkey_material =
+ &cmd->params.key_material;
+ mlan_ds_encrypt_key *pkey = (mlan_ds_encrypt_key *)pdata_buf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+ if (!pkey) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ pkey_material->action = wlan_cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = wlan_cpu_to_le16(sizeof(pkey_material->action) +
+ S_DS_GEN);
+ goto done;
+ }
+ memset(pmpriv->adapter, &pkey_material->key_param_set, 0,
+ sizeof(MrvlIEtype_KeyParamSetV2_t));
+ if (pkey->key_flags & KEY_FLAG_REMOVE_KEY) {
+ pkey_material->action =
+ wlan_cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ pkey_material->key_param_set.length =
+ wlan_cpu_to_le16(KEY_PARAMS_FIXED_LEN);
+ pkey_material->key_param_set.key_idx =
+ pkey->key_index & KEY_INDEX_MASK;
+ pkey_material->key_param_set.key_info = wlan_cpu_to_le16(
+ KEY_INFO_MCAST_KEY | KEY_INFO_UCAST_KEY);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.mac_addr,
+ pkey->mac_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Remove Key\n");
+ goto done;
+ }
+ pkey_material->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+ pkey_material->key_param_set.key_idx = pkey->key_index & KEY_INDEX_MASK;
+ pkey_material->key_param_set.type =
+ wlan_cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
+ pkey_material->key_param_set.key_info = KEY_INFO_ENABLE_KEY;
+ memcpy_ext(pmpriv->adapter, pkey_material->key_param_set.mac_addr,
+ pkey->mac_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ if (pkey->key_len <= MAX_WEP_KEY_SIZE) {
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(wep_param_t));
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_WEP;
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_MCAST_KEY | KEY_INFO_UCAST_KEY;
+ if (pkey_material->key_param_set.key_idx ==
+ (pmpriv->wep_key_curr_index & KEY_INDEX_MASK))
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_DEFAULT_KEY;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ pkey_material->key_param_set.key_params.wep.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wep.key,
+ pkey->key_material, pkey->key_len, MAX_WEP_KEY_SIZE);
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(wep_param_t) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set WEP Key\n");
+ goto done;
+ }
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY)
+ pkey_material->key_param_set.key_info |= KEY_INFO_MCAST_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_UCAST_KEY;
+ if (pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)
+ pkey_material->key_param_set.key_info = KEY_INFO_CMAC_AES_KEY;
+ if (pkey->key_flags & KEY_FLAG_SET_TX_KEY)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_TX_KEY | KEY_INFO_RX_KEY;
+ else
+ pkey_material->key_param_set.key_info |= KEY_INFO_TX_KEY;
+ if (pkey->is_wapi_key) {
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_WAPI;
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wapi.pn,
+ pkey->pn, PN_SIZE, PN_SIZE);
+ pkey_material->key_param_set.key_params.wapi.key_len =
+ wlan_cpu_to_le16(MIN(WAPI_KEY_SIZE, pkey->key_len));
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.wapi.key,
+ pkey->key_material, pkey->key_len, WAPI_KEY_SIZE);
+ if (!pmpriv->sec_info.wapi_key_on)
+ pkey_material->key_param_set.key_info |=
+ KEY_INFO_DEFAULT_KEY;
+ if (pkey->key_flags & KEY_FLAG_GROUP_KEY) {
+ pmpriv->sec_info.wapi_key_on = MTRUE;
+ } else {
+ /* WAPI pairwise key: unicast */
+ sta_ptr =
+ wlan_add_station_entry(pmpriv, pkey->mac_addr);
+ if (sta_ptr) {
+ PRINTM(MCMND, "station: wapi_key_on\n");
+ sta_ptr->wapi_key_on = MTRUE;
+ }
+ }
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(wapi_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(wapi_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set WAPI Key\n");
+ goto done;
+ }
+ pkey_material->key_param_set.key_info |= KEY_INFO_DEFAULT_KEY;
+ pkey_material->key_param_set.key_info =
+ wlan_cpu_to_le16(pkey_material->key_param_set.key_info);
+ if (pkey->key_len == WPA_AES_KEY_LEN &&
+ !(pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(
+ pmpriv->adapter,
+ pkey_material->key_param_set.key_params.aes.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_AES;
+ pkey_material->key_param_set.key_params.aes.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.aes.key,
+ pkey->key_material, pkey->key_len, WPA_AES_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(aes_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(aes_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set AES Key\n");
+ goto done;
+ }
+ if (pkey->key_len == WPA_IGTK_KEY_LEN &&
+ (pkey->key_flags & KEY_FLAG_AES_MCAST_IGTK)) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params
+ .cmac_aes.ipn,
+ pkey->pn, SEQ_MAX_SIZE, IGTK_PN_SIZE);
+ pkey_material->key_param_set.key_info &=
+ ~(wlan_cpu_to_le16(KEY_INFO_MCAST_KEY));
+ pkey_material->key_param_set.key_info |=
+ wlan_cpu_to_le16(KEY_INFO_AES_MCAST_IGTK);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC;
+ pkey_material->key_param_set.key_params.cmac_aes.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.cmac_aes.key,
+ pkey->key_material, pkey->key_len, CMAC_AES_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(cmac_aes_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(cmac_aes_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set CMAC AES Key\n");
+ goto done;
+ }
+ if (pkey->key_len == WPA_TKIP_KEY_LEN) {
+ if (pkey->key_flags &
+ (KEY_FLAG_RX_SEQ_VALID | KEY_FLAG_TX_SEQ_VALID))
+ memcpy_ext(
+ pmpriv->adapter,
+ pkey_material->key_param_set.key_params.tkip.pn,
+ pkey->pn, SEQ_MAX_SIZE, WPA_PN_SIZE);
+ pkey_material->key_param_set.key_type = KEY_TYPE_ID_TKIP;
+ pkey_material->key_param_set.key_params.tkip.key_len =
+ wlan_cpu_to_le16(pkey->key_len);
+ memcpy_ext(pmpriv->adapter,
+ pkey_material->key_param_set.key_params.tkip.key,
+ pkey->key_material, pkey->key_len, WPA_TKIP_KEY_LEN);
+ pkey_material->key_param_set.length = wlan_cpu_to_le16(
+ KEY_PARAMS_FIXED_LEN + sizeof(tkip_param));
+ cmd->size = wlan_cpu_to_le16(sizeof(MrvlIEtypesHeader_t) +
+ S_DS_GEN + KEY_PARAMS_FIXED_LEN +
+ sizeof(tkip_param) +
+ sizeof(pkey_material->action));
+ PRINTM(MCMND, "Set TKIP Key\n");
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the command response of sta_list
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_sta_list(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_STA_LIST *sta_list =
+ (HostCmd_DS_STA_LIST *)&resp->params.sta_list;
+ mlan_ds_get_info *info;
+ MrvlIEtypes_sta_info_t *tlv = MNULL;
+ t_u8 i = 0;
+ sta_node *sta_ptr;
+ t_u8 tlv_len = 0;
+ t_u8 *buf = MNULL;
+
+ ENTER();
+ if (pioctl_buf) {
+ info = (mlan_ds_get_info *)pioctl_buf->pbuf;
+ info->param.sta_list.sta_count =
+ wlan_le16_to_cpu(sta_list->sta_count);
+ buf = sta_list->tlv_buf;
+ tlv = (MrvlIEtypes_sta_info_t *)buf;
+ info->param.sta_list.sta_count =
+ MIN(info->param.sta_list.sta_count, MAX_NUM_CLIENTS);
+ pioctl_buf->data_read_written =
+ sizeof(info->param.sta_list.sta_count);
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ tlv_len = wlan_le16_to_cpu(tlv->header.len);
+ memcpy_ext(pmpriv->adapter,
+ info->param.sta_list.info[i].mac_address,
+ tlv->mac_address, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ info->param.sta_list.info[i].ie_len =
+ tlv_len + sizeof(MrvlIEtypesHeader_t) -
+ sizeof(MrvlIEtypes_sta_info_t);
+ if (info->param.sta_list.info[i].ie_len)
+ memcpy_ext(pmpriv->adapter,
+ info->param.sta_list.info[i].ie_buf,
+ tlv->ie_buf,
+ info->param.sta_list.info[i].ie_len,
+ info->param.sta_list.info[i].ie_len);
+ info->param.sta_list.info[i].power_mgmt_status =
+ tlv->power_mgmt_status;
+ info->param.sta_list.info[i].rssi = tlv->rssi;
+ sta_ptr = wlan_get_station_entry(pmpriv,
+ tlv->mac_address);
+ if (sta_ptr) {
+ info->param.sta_list.info[i].bandmode =
+ sta_ptr->bandmode;
+ memcpy_ext(
+ pmpriv->adapter,
+ &(info->param.sta_list.info[i].stats),
+ &(sta_ptr->stats), sizeof(sta_stats),
+ sizeof(sta_stats));
+ } else
+ info->param.sta_list.info[i].bandmode = 0xFF;
+ pioctl_buf->data_read_written +=
+ sizeof(sta_info) +
+ info->param.sta_list.info[i].ie_len;
+ buf += sizeof(MrvlIEtypes_sta_info_t) +
+ info->param.sta_list.info[i].ie_len;
+ tlv = (MrvlIEtypes_sta_info_t *)buf;
+ }
+ PRINTM(MCMND, "Total sta_list size=%d\n",
+ pioctl_buf->data_read_written);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Fixed size of bss start event */
+#define BSS_START_EVENT_FIX_SIZE 12
+
+/**
+ * @brief This function will search for the specific ie
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return N/A
+ */
+static void wlan_check_uap_capability(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u16 tlv_type, tlv_len;
+ int tlv_buf_left = pevent->data_len - BSS_START_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
+ BSS_START_EVENT_FIX_SIZE);
+
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+ IEEEtypes_WmmParameter_t wmm_param_ie;
+ MrvlIEtypes_channel_band_t *pchan_info;
+ t_u8 event_buf[100];
+ mlan_event *event = (mlan_event *)event_buf;
+ chan_band_info *pchan_band_info = (chan_band_info *)event->event_buf;
+ MrvlIEtypes_He_cap_t *pext_tlv = MNULL;
+
+ ENTER();
+ priv->wmm_enabled = MFALSE;
+ priv->pkt_fwd = MFALSE;
+ priv->is_11n_enabled = MFALSE;
+ priv->is_11ac_enabled = MFALSE;
+ priv->is_11ax_enabled = MFALSE;
+
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == HT_CAPABILITY) {
+ DBG_HEXDUMP(MCMD_D, "HT_CAP tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->is_11n_enabled = MTRUE;
+ }
+ if (tlv_type == VHT_CAPABILITY) {
+ DBG_HEXDUMP(MCMD_D, "VHT_CAP tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->is_11ac_enabled = MTRUE;
+ }
+ if (tlv_type == EXTENSION) {
+ pext_tlv = (MrvlIEtypes_He_cap_t *)tlv;
+ if (pext_tlv->ext_id == HE_CAPABILITY) {
+ DBG_HEXDUMP(
+ MCMD_D, "HE_CAP tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->is_11ax_enabled = MTRUE;
+ }
+ }
+
+ if (tlv_type == VENDOR_SPECIFIC_221) {
+ if (!memcmp(priv->adapter,
+ (t_u8 *)tlv + sizeof(MrvlIEtypesHeader_t),
+ wmm_oui, sizeof(wmm_oui))) {
+ DBG_HEXDUMP(
+ MCMD_D, "wmm ie tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->wmm_enabled = MFALSE;
+ wlan_wmm_setup_ac_downgrade(priv);
+ priv->wmm_enabled = MTRUE;
+ memcpy_ext(priv->adapter, &wmm_param_ie,
+ ((t_u8 *)tlv + 2),
+ sizeof(IEEEtypes_WmmParameter_t),
+ sizeof(IEEEtypes_WmmParameter_t));
+ wmm_param_ie.vend_hdr.len = (t_u8)tlv_len;
+ wmm_param_ie.vend_hdr.element_id = WMM_IE;
+ wlan_wmm_setup_queue_priorities(priv,
+ &wmm_param_ie);
+ }
+ }
+ if (tlv_type == TLV_TYPE_UAP_PKT_FWD_CTL) {
+ DBG_HEXDUMP(MCMD_D, "pkt_fwd tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ priv->pkt_fwd =
+ *((t_u8 *)tlv + sizeof(MrvlIEtypesHeader_t));
+ PRINTM(MCMND, "pkt_fwd FW: 0x%x\n", priv->pkt_fwd);
+ if (priv->pkt_fwd & PKT_FWD_FW_BIT)
+ priv->pkt_fwd = MFALSE;
+ else
+ priv->pkt_fwd |= PKT_FWD_ENABLE_BIT;
+ PRINTM(MCMND, "pkt_fwd DRV: 0x%x\n", priv->pkt_fwd);
+ }
+ if (tlv_type == TLV_TYPE_UAP_CHAN_BAND_CONFIG) {
+ DBG_HEXDUMP(MCMD_D, "chan_band_config tlv", tlv,
+ tlv_len + sizeof(MrvlIEtypesHeader_t));
+ pchan_info = (MrvlIEtypes_channel_band_t *)tlv;
+ priv->uap_channel = pchan_info->channel;
+ PRINTM(MCMND, "uap_channel FW: 0x%x\n",
+ priv->uap_channel);
+ event->bss_index = priv->bss_index;
+ event->event_id = MLAN_EVENT_ID_DRV_UAP_CHAN_INFO;
+ event->event_len = sizeof(chan_band_info);
+ memcpy_ext(priv->adapter,
+ (t_u8 *)&pchan_band_info->bandcfg,
+ (t_u8 *)&pchan_info->bandcfg, tlv_len,
+ tlv_len);
+ if (pchan_band_info->bandcfg.chanWidth == CHAN_BW_80MHZ)
+ pchan_band_info->center_chan =
+ wlan_get_center_freq_idx(
+ priv, BAND_AAC,
+ pchan_info->channel,
+ CHANNEL_BW_80MHZ);
+ if (priv->adapter->ecsa_enable) {
+ int ret;
+ t_u8 bandwidth = BW_20MHZ;
+
+ MrvlIEtypes_chan_bw_oper_t chan_bw_oper;
+ chan_bw_oper.header.type = REGULATORY_CLASS;
+ chan_bw_oper.header.len =
+ sizeof(MrvlIEtypes_chan_bw_oper_t);
+ chan_bw_oper.ds_chan_bw_oper.channel =
+ pchan_info->channel;
+
+ if (pchan_band_info->bandcfg.chanWidth ==
+ CHAN_BW_40MHZ)
+ bandwidth = BW_40MHZ;
+ else if (pchan_band_info->bandcfg.chanWidth ==
+ CHAN_BW_80MHZ)
+ bandwidth = BW_80MHZ;
+ chan_bw_oper.ds_chan_bw_oper.bandwidth =
+ bandwidth;
+
+ ret = wlan_prepare_cmd(
+ priv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ &chan_bw_oper);
+ if (ret != MLAN_STATUS_SUCCESS &&
+ ret != MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "%s(): Could not set supported operating class IE for priv=%p [priv_bss_idx=%d]!\n",
+ __func__, priv, priv->bss_index);
+ }
+ }
+ }
+
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ if (priv->wmm_enabled == MFALSE) {
+ /* Since WMM is not enabled, setup the queues with the defaults
+ */
+ wlan_wmm_setup_queues(priv);
+ }
+ if (event->event_id == MLAN_EVENT_ID_DRV_UAP_CHAN_INFO) {
+ pchan_band_info->is_11n_enabled = priv->is_11n_enabled;
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_UAP_CHAN_INFO, event);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function will update WAPI PN in statation assoc event
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to event buf
+ *
+ * @return MFALSE
+ */
+static t_u32 wlan_update_wapi_info_tlv(pmlan_private priv, pmlan_buffer pevent)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u32 tx_pn[4];
+ t_u32 i = 0;
+ int tlv_buf_left = pevent->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pevent->pbuf + pevent->data_offset +
+ ASSOC_EVENT_FIX_SIZE);
+ MrvlIEtypes_wapi_info_t *wapi_tlv = MNULL;
+
+ ENTER();
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_AP_WAPI_INFO) {
+ wapi_tlv = (MrvlIEtypes_wapi_info_t *)tlv;
+ DBG_HEXDUMP(MCMD_D, "Fw:multicast_PN",
+ wapi_tlv->multicast_PN, PN_SIZE);
+ memcpy_ext(priv->adapter, (t_u8 *)tx_pn,
+ wapi_tlv->multicast_PN, PN_SIZE,
+ sizeof(tx_pn));
+ for (i = 0; i < 4; i++)
+ tx_pn[i] = mlan_ntohl(tx_pn[i]);
+ memcpy_ext(priv->adapter, wapi_tlv->multicast_PN,
+ (t_u8 *)tx_pn, PN_SIZE,
+ sizeof(wapi_tlv->multicast_PN));
+ DBG_HEXDUMP(MCMD_D, "Host:multicast_PN",
+ wapi_tlv->multicast_PN, PN_SIZE);
+ break;
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function send sta_assoc_event to moal
+ * payload with sta mac address and assoc ie.
+ *
+ * @param priv A pointer to mlan_private
+ * @param pevent A pointer to mlan_event buffer
+ * @param pbuf A pointer to mlan_buffer which has event content.
+ *
+ * @return MFALSE
+ */
+static t_u32 wlan_process_sta_assoc_event(pmlan_private priv,
+ mlan_event *pevent,
+ pmlan_buffer pmbuf)
+{
+ t_u32 ret = MFALSE;
+ t_u16 tlv_type, tlv_len;
+ t_u16 frame_control, frame_sub_type = 0;
+ t_u8 *assoc_req_ie = MNULL;
+ t_u8 ie_len = 0, assoc_ie_len = 0;
+ int tlv_buf_left = pmbuf->data_len - ASSOC_EVENT_FIX_SIZE;
+ MrvlIEtypesHeader_t *tlv =
+ (MrvlIEtypesHeader_t *)(pmbuf->pbuf + pmbuf->data_offset +
+ ASSOC_EVENT_FIX_SIZE);
+ MrvlIETypes_MgmtFrameSet_t *mgmt_tlv = MNULL;
+
+ ENTER();
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_CONNECT;
+ pevent->bss_index = priv->bss_index;
+ pevent->event_len = MLAN_MAC_ADDR_LENGTH;
+ memcpy_ext(priv->adapter, pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 6, pevent->event_len,
+ pevent->event_len);
+ while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) {
+ tlv_type = wlan_le16_to_cpu(tlv->type);
+ tlv_len = wlan_le16_to_cpu(tlv->len);
+ if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) >
+ (unsigned int)tlv_buf_left) {
+ PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n",
+ tlv_len, tlv_buf_left);
+ break;
+ }
+ if (tlv_type == TLV_TYPE_MGMT_FRAME) {
+ mgmt_tlv = (MrvlIETypes_MgmtFrameSet_t *)tlv;
+ memcpy_ext(priv->adapter, &frame_control,
+ (t_u8 *)&(mgmt_tlv->frame_control),
+ sizeof(frame_control),
+ sizeof(frame_control));
+ frame_sub_type = IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(
+ frame_control);
+ if ((mgmt_tlv->frame_control.type == 0) &&
+ ((frame_sub_type == SUBTYPE_ASSOC_REQUEST) ||
+ (frame_sub_type == SUBTYPE_REASSOC_REQUEST))) {
+ if (frame_sub_type == SUBTYPE_ASSOC_REQUEST)
+ assoc_ie_len =
+ sizeof(IEEEtypes_AssocRqst_t);
+ else if (frame_sub_type ==
+ SUBTYPE_REASSOC_REQUEST)
+ assoc_ie_len =
+ sizeof(IEEEtypes_ReAssocRqst_t);
+
+ ie_len = tlv_len -
+ sizeof(IEEEtypes_FrameCtl_t) -
+ assoc_ie_len;
+ assoc_req_ie =
+ (t_u8 *)tlv +
+ sizeof(MrvlIETypes_MgmtFrameSet_t) +
+ assoc_ie_len;
+ memcpy_ext(priv->adapter,
+ pevent->event_buf +
+ pevent->event_len,
+ assoc_req_ie, ie_len, ie_len);
+ pevent->event_len += ie_len;
+ break;
+ }
+ }
+ tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
+ sizeof(MrvlIEtypesHeader_t));
+ }
+ PRINTM(MEVENT, "STA assoc event len=%d\n", pevent->event_len);
+ DBG_HEXDUMP(MCMD_D, "STA assoc event", pevent->event_buf,
+ pevent->event_len);
+ wlan_recv_event(priv, pevent->event_id, pevent);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles repsonse of acs_scan.
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param pcmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_cmd_uap_acs_scan(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCMD_DS_APCMD_ACS_SCAN *acs_scan =
+ (HostCMD_DS_APCMD_ACS_SCAN *)&resp->params.acs_scan;
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+ PRINTM(MCMND, "ACS scan done: bandcfg=%x, channel=%d\n",
+ acs_scan->bandcfg, acs_scan->chan);
+ if (pioctl_buf) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ bss->param.ap_acs_scan.chan = acs_scan->chan;
+ bss->param.ap_acs_scan.bandcfg = acs_scan->bandcfg;
+ pioctl_buf->data_read_written = sizeof(mlan_ds_bss);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares command of uap operation control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action the action: GET or SET
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_cmd_oper_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action, t_void *pdata_buf)
+{
+ HostCmd_DS_UAP_OPER_CTRL *poper_ctl =
+ (HostCmd_DS_UAP_OPER_CTRL *)&cmd->params.uap_oper_ctrl;
+ mlan_ds_bss *bss = (mlan_ds_bss *)pdata_buf;
+ mlan_uap_oper_ctrl *uap_oper_ctrl = &bss->param.ap_oper_ctrl;
+ Band_Config_t *bandcfg = MNULL;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HOST_CMD_APCMD_OPER_CTRL);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_UAP_OPER_CTRL) + S_DS_GEN);
+ poper_ctl->action = wlan_cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ poper_ctl->ctrl = wlan_cpu_to_le16(uap_oper_ctrl->ctrl_value);
+ if (uap_oper_ctrl->ctrl_value == 2) {
+ poper_ctl->chan_opt =
+ wlan_cpu_to_le16(uap_oper_ctrl->chan_opt);
+ if (uap_oper_ctrl->chan_opt == 3) {
+ poper_ctl->channel_band.header.type =
+ wlan_cpu_to_le16(
+ TLV_TYPE_UAP_CHAN_BAND_CONFIG);
+ poper_ctl->channel_band.header
+ .len = wlan_cpu_to_le16(
+ sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t));
+ bandcfg = &poper_ctl->channel_band.bandcfg;
+ if (uap_oper_ctrl->channel > 14)
+ bandcfg->chanBand = BAND_5GHZ;
+ bandcfg->chanWidth = uap_oper_ctrl->band_cfg;
+ if (bandcfg->chanWidth)
+ bandcfg->chan2Offset =
+ wlan_get_second_channel_offset(
+ uap_oper_ctrl->channel);
+ bandcfg->scanMode = SCAN_MODE_MANUAL;
+ poper_ctl->channel_band.channel =
+ uap_oper_ctrl->channel;
+ }
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of uap operation control
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static mlan_status wlan_uap_ret_oper_ctrl(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ HostCmd_DS_UAP_OPER_CTRL *poper_ctl =
+ (HostCmd_DS_UAP_OPER_CTRL *)&resp->params.uap_oper_ctrl;
+ mlan_ds_bss *bss = MNULL;
+ mlan_uap_oper_ctrl *uap_oper_ctrl = MNULL;
+ Band_Config_t *bandcfg = MNULL;
+
+ ENTER();
+
+ if (pioctl_buf && pioctl_buf->action == MLAN_ACT_GET) {
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ uap_oper_ctrl = (mlan_uap_oper_ctrl *)&bss->param.ap_oper_ctrl;
+ uap_oper_ctrl->ctrl_value = wlan_le16_to_cpu(poper_ctl->ctrl);
+ uap_oper_ctrl->chan_opt = wlan_le16_to_cpu(poper_ctl->chan_opt);
+ uap_oper_ctrl->channel = poper_ctl->channel_band.channel;
+ bandcfg = &poper_ctl->channel_band.bandcfg;
+ uap_oper_ctrl->band_cfg = bandcfg->chanWidth;
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Check 11B support Rates
+ *
+ *
+ * @param pmadapter Private mlan adapter structure
+ *
+ * @return MTRUE/MFALSE
+ *
+ */
+t_u8 wlan_check_11B_support_rates(MrvlIEtypes_RatesParamSet_t *prates_tlv)
+{
+ int i;
+ t_u8 rate;
+ t_u8 ret = MTRUE;
+ for (i = 0; i < prates_tlv->header.len; i++) {
+ rate = prates_tlv->rates[i] & 0x7f;
+ if ((rate != 0x02) && (rate != 0x04) && (rate != 0x0b) &&
+ (rate != 0x16)) {
+ ret = MFALSE;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of sys_config
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action cmd action
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_uap_cmd_add_station(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_u16 cmd_action,
+ pmlan_ioctl_req pioctl_buf)
+{
+ mlan_ds_bss *bss = MNULL;
+ HostCmd_DS_ADD_STATION *new_sta =
+ (HostCmd_DS_ADD_STATION *)&cmd->params.sta_info;
+ sta_node *sta_ptr = MNULL;
+ t_u16 tlv_buf_left;
+ t_u8 *pos = MNULL;
+ t_u8 *tlv_buf = MNULL;
+ t_u16 travel_len = 0;
+ MrvlIEtypesHeader_t *tlv;
+ t_u16 tlv_len = 0;
+ t_u8 b_only = MFALSE;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+ MrvlIETypes_HTCap_t *phtcap;
+ MrvlIETypes_VHTCap_t *pvhtcap;
+ MrvlIEtypes_Extension_t *pext_tlv;
+ MrvlIEtypes_StaFlag_t *pstaflag;
+ int i;
+
+ ENTER();
+
+ if (!pioctl_buf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ bss = (mlan_ds_bss *)pioctl_buf->pbuf;
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_ADD_NEW_STATION);
+ new_sta->action = wlan_cpu_to_le16(cmd_action);
+ cmd->size = sizeof(HostCmd_DS_ADD_STATION) + S_DS_GEN;
+ if (cmd_action == HostCmd_ACT_ADD_STA) {
+ sta_ptr = wlan_get_station_entry(pmpriv,
+ bss->param.sta_info.peer_mac);
+ if (!sta_ptr)
+ sta_ptr = wlan_add_station_entry(
+ pmpriv, bss->param.sta_info.peer_mac);
+ } else {
+ sta_ptr = wlan_add_station_entry(pmpriv,
+ bss->param.sta_info.peer_mac);
+ }
+ if (!sta_ptr) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy_ext(pmadapter, new_sta->peer_mac, bss->param.sta_info.peer_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ if (cmd_action != HostCmd_ACT_ADD_STA)
+ goto done;
+ new_sta->aid = wlan_cpu_to_le16(bss->param.sta_info.aid);
+ new_sta->listen_interval =
+ wlan_cpu_to_le32(bss->param.sta_info.listen_interval);
+ if (bss->param.sta_info.cap_info)
+ new_sta->cap_info =
+ wlan_cpu_to_le16(bss->param.sta_info.cap_info);
+ else
+ new_sta->cap_info = wlan_cpu_to_le16(sta_ptr->capability);
+ tlv_buf_left = bss->param.sta_info.tlv_len;
+ pos = new_sta->tlv;
+ tlv_buf = bss->param.sta_info.tlv;
+ tlv = (MrvlIEtypesHeader_t *)tlv_buf;
+ if (bss->param.sta_info.sta_flags & STA_FLAG_WME) {
+ PRINTM(MCMND, "STA flags supports wmm \n");
+ sta_ptr->is_wmm_enabled = MTRUE;
+ }
+ // append sta_flag_flags.
+ pstaflag = (MrvlIEtypes_StaFlag_t *)pos;
+ pstaflag->header.type = wlan_cpu_to_le16(TLV_TYPE_UAP_STA_FLAGS);
+ pstaflag->header.len = wlan_cpu_to_le16(sizeof(t_u32));
+ pstaflag->sta_flags = wlan_cpu_to_le32(bss->param.sta_info.sta_flags);
+ pos += sizeof(MrvlIEtypes_StaFlag_t);
+ cmd->size += sizeof(MrvlIEtypes_StaFlag_t);
+
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
+ if (tlv_buf_left < (sizeof(MrvlIEtypesHeader_t) + tlv->len))
+ break;
+ switch (tlv->type) {
+ case EXT_CAPABILITY:
+ break;
+ case SUPPORTED_RATES:
+ b_only = wlan_check_11B_support_rates(
+ (MrvlIEtypes_RatesParamSet_t *)tlv);
+ break;
+ case QOS_INFO:
+ PRINTM(MCMND, "STA supports wmm\n");
+ sta_ptr->is_wmm_enabled = MTRUE;
+ break;
+ case HT_CAPABILITY:
+ PRINTM(MCMND, "STA supports 11n\n");
+ sta_ptr->is_11n_enabled = MTRUE;
+ phtcap = (MrvlIETypes_HTCap_t *)tlv;
+ if (sta_ptr->HTcap.ieee_hdr.element_id ==
+ HT_CAPABILITY) {
+ if (GETHT_40MHZ_INTOLARANT(
+ sta_ptr->HTcap.ht_cap.ht_cap_info)) {
+ PRINTM(MCMND,
+ "SETHT_40MHZ_INTOLARANT\n");
+ SETHT_40MHZ_INTOLARANT(
+ phtcap->ht_cap.ht_cap_info);
+ }
+ }
+ if (GETHT_MAXAMSDU(phtcap->ht_cap.ht_cap_info))
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ break;
+ case VHT_CAPABILITY:
+ PRINTM(MCMND, "STA supports 11ac\n");
+ sta_ptr->is_11ac_enabled = MTRUE;
+ pvhtcap = (MrvlIETypes_VHTCap_t *)tlv;
+ if (GET_VHTCAP_MAXMPDULEN(
+ pvhtcap->vht_cap.vht_cap_info) == 2)
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_12K;
+ else if (GET_VHTCAP_MAXMPDULEN(
+ pvhtcap->vht_cap.vht_cap_info) == 1)
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_8K;
+ else
+ sta_ptr->max_amsdu = MLAN_TX_DATA_BUF_SIZE_4K;
+ break;
+ case OPER_MODE_NTF:
+ break;
+ case EXTENSION:
+ pext_tlv = (MrvlIEtypes_Extension_t *)tlv;
+ if (pext_tlv->ext_id == HE_CAPABILITY) {
+ sta_ptr->is_11ax_enabled = MTRUE;
+ PRINTM(MCMND, "STA supports 11ax\n");
+ }
+ break;
+ default:
+ break;
+ }
+ tlv_len = tlv->len;
+ tlv->type = wlan_cpu_to_le16(tlv->type);
+ tlv->len = wlan_cpu_to_le16(tlv->len);
+ memcpy_ext(pmadapter, pos, (t_u8 *)tlv,
+ sizeof(MrvlIEtypesHeader_t) + tlv_len,
+ sizeof(MrvlIEtypesHeader_t) + tlv_len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv_len;
+ tlv_buf += sizeof(MrvlIEtypesHeader_t) + tlv_len;
+ tlv = (MrvlIEtypesHeader_t *)tlv_buf;
+ travel_len += sizeof(MrvlIEtypesHeader_t) + tlv_len;
+ tlv_buf_left -= sizeof(MrvlIEtypesHeader_t) + tlv_len;
+ }
+
+ if (sta_ptr->is_11n_enabled) {
+ if (pmpriv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GN;
+ else
+ sta_ptr->bandmode = BAND_AN;
+ } else if (!b_only) {
+ if (pmpriv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_G;
+ else
+ sta_ptr->bandmode = BAND_A;
+ } else
+ sta_ptr->bandmode = BAND_B;
+ if (sta_ptr->is_11ac_enabled) {
+ if (pmpriv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GAC;
+ else
+ sta_ptr->bandmode = BAND_AAC;
+ }
+ if (sta_ptr->is_11ax_enabled) {
+ if (pmpriv->uap_channel <= 14)
+ sta_ptr->bandmode = BAND_GAX;
+ else
+ sta_ptr->bandmode = BAND_AAX;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (sta_ptr->is_11n_enabled)
+ sta_ptr->ampdu_sta[i] =
+ pmpriv->aggr_prio_tbl[i].ampdu_user;
+ else
+ sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+ }
+ memset(pmadapter, sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
+done:
+ cmd->size += travel_len;
+ cmd->size = wlan_cpu_to_le16(cmd->size);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function prepare the command before sending to firmware.
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmd_no Command number
+ * @param cmd_action Command action: GET or SET
+ * @param cmd_oid Cmd oid: treated as sub command
+ * @param pioctl_buf A pointer to MLAN IOCTL Request buffer
+ * @param pdata_buf A pointer to information buffer
+ * @param pcmd_buf A pointer to cmd buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_uap_prepare_cmd(t_void *priv, t_u16 cmd_no,
+ t_u16 cmd_action, t_u32 cmd_oid,
+ t_void *pioctl_buf, t_void *pdata_buf,
+ t_void *pcmd_buf)
+{
+ HostCmd_DS_COMMAND *cmd_ptr = (HostCmd_DS_COMMAND *)pcmd_buf;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
+
+ ENTER();
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCMD_APCMD_ACS_SCAN:
+ case HostCmd_CMD_SOFT_RESET:
+ case HOST_CMD_APCMD_BSS_STOP:
+ case HOST_CMD_APCMD_SYS_INFO:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HOST_CMD_APCMD_BSS_START:
+ ret = wlan_uap_cmd_bss_start(pmpriv, cmd_ptr);
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IsAuthenticatorEnabled(pmpriv->psapriv))
+ AuthenticatorBssConfig(pmpriv->psapriv, MNULL, 1, 0, 0);
+#endif
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_cmd_sys_configure(pmpriv, cmd_ptr, cmd_action,
+ (pmlan_ioctl_req)pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_cmd_enh_power_mode(pmpriv, cmd_ptr, cmd_action,
+ (t_u16)cmd_oid, pdata_buf);
+ break;
+#if defined(SDIO)
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ ret = wlan_cmd_sdio_gpio_int(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_FUNC_INIT:
+ if (pmpriv->adapter->hw_status == WlanHardwareStatusReset)
+ pmpriv->adapter->hw_status =
+ WlanHardwareStatusInitializing;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ pmpriv->adapter->hw_status = WlanHardwareStatusReset;
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_cmd_cfg_data(pmpriv, cmd_ptr, cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_cmd_mac_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_cmd_snmp_mib(pmpriv, cmd_ptr, cmd_action,
+ cmd_oid,
+ (pmlan_ioctl_req)pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_uap_cmd_802_11_get_log(pmpriv, cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_cmd_802_11d_domain_info(pmpriv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmd_process(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ ret = wlan_uap_cmd_sta_deauth(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HOST_CMD_APCMD_REPORT_MIC:
+ ret = wlan_uap_cmd_report_mic(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = wlan_uap_cmd_key_material(pmpriv, cmd_ptr, cmd_action,
+ cmd_oid, pdata_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_cmd_get_hw_spec(pmpriv, cmd_ptr);
+ break;
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ ret = wlan_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_uap_cmd_802_11_hs_cfg(pmpriv, cmd_ptr, cmd_action,
+ (hs_config_param *)pdata_buf);
+ break;
+ case HostCmd_CMD_HS_WAKEUP_REASON:
+ ret = wlan_cmd_hs_wakeup_reason(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_ROBUSTCOEX:
+ ret = wlan_cmd_robustcoex(pmpriv, cmd_ptr, cmd_action,
+ (t_u16 *)pdata_buf);
+ break;
+ case HostCmd_CMD_DMCS_CONFIG:
+ ret = wlan_cmd_dmcs_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = wlan_cmd_recfg_tx_buf(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_cmd_amsdu_aggr_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_cmd_11n_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_cmd_11n_addba_req(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_cmd_11n_delba(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_cmd_11n_addba_rspgen(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_REJECT_ADDBA_REQ:
+ ret = wlan_cmd_reject_addba_req(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_cmd_tx_bf_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#if defined(WIFI_DIRECT_SUPPORT)
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ if (pdata_buf)
+ cmd_ptr->params.bss_mode.con_type = *(t_u8 *)pdata_buf;
+ else
+ cmd_ptr->params.bss_mode.con_type =
+ BSS_MODE_WIFIDIRECT_GO;
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_SET_BSS_MODE) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+#endif
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (t_u8)(*((t_u32 *)pdata_buf));
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_VERSION_EXT) + S_DS_GEN);
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->params.rx_mgmt_ind.action =
+ wlan_cpu_to_le16(cmd_action);
+ cmd_ptr->params.rx_mgmt_ind.mgmt_subtype_mask =
+ (t_u32)(*((t_u32 *)pdata_buf));
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_RX_MGMT_IND) + S_DS_GEN);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_cmd_txdatapause(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_cmd_802_11_radio_control(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_cmd_tx_rate_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command =
+ wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size = wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) +
+ S_DS_GEN);
+ pmpriv->tx_rate = 0;
+ ret = MLAN_STATUS_SUCCESS;
+ break;
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_cmd_remain_on_channel(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_cmd_wifi_direct_mode(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HOST_CMD_P2P_PARAMS_CONFIG:
+ ret = wlan_cmd_p2p_params_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_cmd_802_11_rf_antenna(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_MIMO_SWITCH:
+ ret = wlan_cmd_802_11_mimo_switch(pmpriv, cmd_ptr, pdata_buf);
+ break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = wlan_cmd_11ac_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_DYN_BW:
+ ret = wlan_cmd_config_dyn_bw(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_TARGET_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ case HostCmd_CMD_BCA_REG_ACCESS:
+ ret = wlan_cmd_reg_access(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_cmd_mem_access(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_cmd_wmm_queue_config(pmpriv, cmd_ptr, pdata_buf);
+ break;
+#ifdef RX_PACKET_COALESCE
+ case HostCmd_CMD_RX_PKT_COALESCE_CFG:
+ ret = wlan_cmd_rx_pkt_coalesce_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+ case HOST_CMD_APCMD_OPER_CTRL:
+ ret = wlan_uap_cmd_oper_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+
+ case HostCmd_CMD_INDEPENDENT_RESET_CFG:
+ ret = wlan_cmd_ind_rst_cfg(cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_GET_TSF:
+ ret = wlan_cmd_get_tsf(pmpriv, cmd_ptr, cmd_action);
+ break;
+
+ case HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT:
+ ret = wlan_cmd_ps_inactivity_timeout(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ cmd_ptr->command = wlan_cpu_to_le16(cmd_no);
+ cmd_ptr->size = wlan_cpu_to_le16(
+ sizeof(HostCmd_DS_CHAN_REGION_CFG) + S_DS_GEN);
+ cmd_ptr->params.reg_cfg.action = wlan_cpu_to_le16(cmd_action);
+ break;
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+ ret = wlan_cmd_packet_aggr_ctrl(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#if defined(PCIE)
+#if defined(PCIE8997) || defined(PCIE8897)
+ case HostCmd_CMD_PCIE_HOST_BUF_DETAILS:
+ ret = wlan_cmd_pcie_host_buf_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#endif
+#endif
+ case HOST_CMD_TX_RX_PKT_STATS:
+ ret = wlan_cmd_tx_rx_pkt_stats(pmpriv, cmd_ptr,
+ (pmlan_ioctl_req)pioctl_buf,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_FW_DUMP_EVENT:
+ ret = wlan_cmd_fw_dump_event(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_LINK_STATS:
+ ret = wlan_cmd_802_11_link_statistic(pmpriv, cmd_ptr,
+ cmd_action, pioctl_buf);
+ break;
+ case HostCmd_CMD_ADD_NEW_STATION:
+ ret = wlan_uap_cmd_add_station(pmpriv, cmd_ptr, cmd_action,
+ (pmlan_ioctl_req)pioctl_buf);
+ break;
+ case HostCmd_CMD_BOOT_SLEEP:
+ ret = wlan_cmd_boot_sleep(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR)
+ case HostCmd_CMD_CRYPTO:
+ ret = wlan_cmd_crypto(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+#endif
+ case HostCmd_CMD_11AX_CFG:
+ ret = wlan_cmd_11ax_cfg(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_11AX_CMD:
+ ret = wlan_cmd_11ax_cmd(pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_RANGE_EXT:
+ ret = wlan_cmd_range_ext(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG:
+ ret = wlan_cmd_rxabortcfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG_EXT:
+ ret = wlan_cmd_rxabortcfg_ext(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_TX_AMPDU_PROT_MODE:
+ ret = wlan_cmd_tx_ampdu_prot_mode(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG:
+ ret = wlan_cmd_dot11mc_unassoc_ftm_cfg(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_RATE_ADAPT_CFG:
+ ret = wlan_cmd_rate_adapt_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_CCK_DESENSE_CFG:
+ ret = wlan_cmd_cck_desense_cfg(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CHANNEL_TRPC_CONFIG:
+ ret = wlan_cmd_get_chan_trpc_config(pmpriv, cmd_ptr, cmd_action,
+ pdata_buf);
+ break;
+ case HostCmd_CMD_LOW_POWER_MODE_CFG:
+ ret = wlan_cmd_set_get_low_power_mode_cfg(
+ pmpriv, cmd_ptr, cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_802_11_BAND_STEERING:
+ ret = wlan_cmd_set_get_band_steering_cfg(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ case HostCmd_CMD_UAP_BEACON_STUCK_CFG:
+ ret = wlan_cmd_set_get_beacon_stuck_cfg(pmpriv, cmd_ptr,
+ cmd_action, pdata_buf);
+ break;
+ default:
+ PRINTM(MERROR, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ if (pioctl_req)
+ pioctl_req->status_code = MLAN_ERROR_CMD_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles the AP mode command response
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param cmdresp_no cmd no
+ * @param pcmd_buf cmdresp buf
+ * @param pioctl A pointer to ioctl buf
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_uap_process_cmdresp(t_void *priv, t_u16 cmdresp_no,
+ t_void *pcmd_buf, t_void *pioctl)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ HostCmd_DS_COMMAND *resp = (HostCmd_DS_COMMAND *)pcmd_buf;
+ mlan_ioctl_req *pioctl_buf = (mlan_ioctl_req *)pioctl;
+ mlan_adapter *pmadapter = pmpriv->adapter;
+#ifdef SDIO
+ int ctr;
+#endif
+ wlan_dfs_device_state_t *pstate_dfs =
+ (wlan_dfs_device_state_t *)&pmpriv->adapter->state_dfs;
+ t_u32 sec, usec;
+ ENTER();
+
+ /* If the command is not successful, cleanup and return failure */
+ if (resp->result != HostCmd_RESULT_OK) {
+ ret = uap_process_cmdresp_error(pmpriv, resp, pioctl_buf);
+ LEAVE();
+ return ret;
+ }
+
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HOST_CMD_APCMD_BSS_STOP:
+ pmpriv->uap_bss_started = MFALSE;
+ /* Timestamp update is required because bss_start after skip_cac
+ * enabled should not select non-current channel just because
+ * timestamp got expired
+ */
+ if (!pmpriv->intf_state_11h.is_11h_host &&
+ !pstate_dfs->dfs_check_pending &&
+ pstate_dfs->dfs_check_channel) {
+ pmpriv->adapter->callbacks.moal_get_system_time(
+ pmpriv->adapter->pmoal_handle, &sec, &usec);
+ pstate_dfs->dfs_report_time_sec = sec;
+ }
+ if (pmpriv->intf_state_11h.is_11h_host)
+ pmpriv->intf_state_11h.tx_disabled = MFALSE;
+ else {
+ if (pmpriv->adapter->ecsa_enable)
+ wlan_11h_remove_custom_ie(pmpriv->adapter,
+ pmpriv);
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+
+ if (pmpriv->adapter->state_rdh.stage == RDH_STOP_INTFS)
+ wlan_11h_radar_detected_callback((t_void *)pmpriv);
+ wlan_coex_ampdu_rxwinsize(pmadapter);
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IsAuthenticatorEnabled(pmpriv->psapriv)) {
+ AuthenticatorBssConfig(pmpriv->psapriv, MNULL, 0, 1, 0);
+ AuthenticatorkeyClear(pmpriv->psapriv);
+ }
+#endif
+ pmpriv->uap_host_based = 0;
+ break;
+ case HOST_CMD_APCMD_BSS_START:
+ if (!pmpriv->intf_state_11h.is_11h_host &&
+ pmpriv->adapter->state_rdh.stage == RDH_RESTART_INTFS)
+ wlan_11h_radar_detected_callback((t_void *)pmpriv);
+ /* Stop pps_uapsd_mode once bss_start */
+ pmpriv->adapter->tx_lock_flag = MFALSE;
+ pmpriv->adapter->pps_uapsd_mode = MFALSE;
+ pmpriv->adapter->delay_null_pkt = MFALSE;
+ /* Clear AMSDU statistics*/
+ pmpriv->amsdu_rx_cnt = 0;
+ pmpriv->amsdu_tx_cnt = 0;
+ pmpriv->msdu_in_rx_amsdu_cnt = 0;
+ pmpriv->msdu_in_tx_amsdu_cnt = 0;
+ break;
+ case HOST_CMD_APCMD_SYS_RESET:
+ pmpriv->uap_bss_started = MFALSE;
+ pmpriv->uap_host_based = 0;
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ AuthenitcatorInitBssConfig(pmpriv->psapriv);
+#endif
+ ret = wlan_uap_ret_sys_reset(pmpriv, resp, pioctl_buf);
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ wlan_coex_ampdu_rxwinsize(pmadapter);
+ break;
+ case HOST_CMD_APCMD_SYS_INFO:
+ break;
+ case HOST_CMD_APCMD_SYS_CONFIGURE:
+ ret = wlan_uap_ret_sys_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = wlan_ret_enh_power_mode(pmpriv, resp, pioctl_buf);
+ break;
+#if defined(SDIO)
+ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
+ break;
+#endif
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = wlan_uap_ret_snmp_mib(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = wlan_uap_ret_get_log(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = wlan_ret_802_11d_domain_info(pmpriv, resp);
+ break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = wlan_11h_cmdresp_process(pmpriv, resp);
+ break;
+ case HOST_CMD_APCMD_STA_DEAUTH:
+ break;
+ case HOST_CMD_APCMD_REPORT_MIC:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ break;
+ case HOST_CMD_APCMD_STA_LIST:
+ ret = wlan_uap_ret_sta_list(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = wlan_ret_get_hw_spec(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef SDIO
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ ret = wlan_ret_sdio_rx_aggr_cfg(pmpriv, resp);
+ break;
+#endif
+ case HostCmd_CMD_CFG_DATA:
+ ret = wlan_ret_cfg_data(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = wlan_ret_mac_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_HS_WAKEUP_REASON:
+ ret = wlan_ret_hs_wakeup_reason(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_ROBUSTCOEX:
+ break;
+ case HostCmd_CMD_DMCS_CONFIG:
+ ret = wlan_ret_dmcs_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = wlan_ret_11n_addba_req(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = wlan_ret_11n_delba(pmpriv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = wlan_ret_11n_addba_resp(pmpriv, resp);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ wlan_set_tx_pause_flag(pmpriv, MFALSE);
+
+ pmadapter->tx_buf_size =
+ (t_u16)wlan_le16_to_cpu(resp->params.tx_buf.buff_size);
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ pmadapter->tx_buf_size = (pmadapter->tx_buf_size /
+ MLAN_SDIO_BLOCK_SIZE) *
+ MLAN_SDIO_BLOCK_SIZE;
+ pmadapter->pcard_sd->mp_end_port = wlan_le16_to_cpu(
+ resp->params.tx_buf.mp_end_port);
+ pmadapter->pcard_sd->mp_data_port_mask =
+ pmadapter->pcard_sd->reg->data_port_mask;
+
+ for (ctr = 1;
+ ctr <= MAX_PORT - pmadapter->pcard_sd->mp_end_port;
+ ctr++) {
+ pmadapter->pcard_sd->mp_data_port_mask &=
+ ~(1 << (MAX_PORT - ctr));
+ }
+
+ pmadapter->pcard_sd->curr_wr_port = 0;
+ pmadapter->pcard_sd->mpa_tx.pkt_aggr_limit =
+ MIN(SDIO_MP_AGGR_DEF_PKT_LIMIT,
+ (pmadapter->pcard_sd->mp_end_port >> 1));
+ PRINTM(MCMND, "end port %d, data port mask %x\n",
+ wlan_le16_to_cpu(
+ resp->params.tx_buf.mp_end_port),
+ pmadapter->pcard_sd->mp_data_port_mask);
+ }
+#endif
+ pmadapter->curr_tx_buf_size = pmadapter->tx_buf_size;
+ PRINTM(MCMND, "max_tx_buf_size=%d, tx_buf_size=%d\n",
+ pmadapter->max_tx_buf_size, pmadapter->tx_buf_size);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = wlan_ret_amsdu_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = wlan_ret_11n_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_REJECT_ADDBA_REQ:
+ ret = wlan_ret_reject_addba_req(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_BF_CFG:
+ ret = wlan_ret_tx_bf_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = wlan_ret_ver_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_MGMT_IND:
+ ret = wlan_ret_rx_mgmt_ind(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CFG_TX_DATA_PAUSE:
+ ret = wlan_uap_ret_txdatapause(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_RADIO_CONTROL:
+ ret = wlan_ret_802_11_radio_control(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = wlan_ret_tx_rate_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = wlan_ret_802_11_tx_rate_query(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL:
+ ret = wlan_ret_remain_on_channel(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+ case HOST_CMD_WIFI_DIRECT_MODE_CONFIG:
+ ret = wlan_ret_wifi_direct_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_P2P_PARAMS_CONFIG:
+ ret = wlan_ret_p2p_params_config(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_802_11_RF_ANTENNA:
+ ret = wlan_ret_802_11_rf_antenna(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_MIMO_SWITCH:
+ break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = wlan_ret_11ac_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_DYN_BW:
+ ret = wlan_ret_dyn_bw(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_TARGET_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ case HostCmd_CMD_BCA_REG_ACCESS:
+ ret = wlan_ret_reg_access(pmpriv->adapter, cmdresp_no, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = wlan_ret_mem_access(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_WMM_QUEUE_CONFIG:
+ ret = wlan_ret_wmm_queue_config(pmpriv, resp, pioctl_buf);
+ break;
+#ifdef RX_PACKET_COALESCE
+ case HostCmd_CMD_RX_PKT_COALESCE_CFG:
+ ret = wlan_ret_rx_pkt_coalesce_cfg(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCMD_APCMD_ACS_SCAN:
+ ret = wlan_ret_cmd_uap_acs_scan(pmpriv, resp, pioctl_buf);
+ break;
+ case HOST_CMD_APCMD_OPER_CTRL:
+ ret = wlan_uap_ret_oper_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_INDEPENDENT_RESET_CFG:
+ ret = wlan_ret_ind_rst_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT:
+ break;
+ case HostCmd_CMD_GET_TSF:
+ ret = wlan_ret_get_tsf(pmpriv, resp, pioctl_buf);
+ break;
+
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = wlan_ret_chan_region_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_PACKET_AGGR_CTRL:
+ ret = wlan_ret_packet_aggr_ctrl(pmpriv, resp, pioctl_buf);
+ break;
+#if defined(PCIE)
+#if defined(PCIE8997) || defined(PCIE8897)
+ case HostCmd_CMD_PCIE_HOST_BUF_DETAILS:
+ PRINTM(MINFO, "PCIE host buffer configuration successful.\n");
+ break;
+#endif
+#endif
+ case HOST_CMD_TX_RX_PKT_STATS:
+ ret = wlan_ret_tx_rx_pkt_stats(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_LINK_STATS:
+ ret = wlan_ret_get_link_statistic(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_BOOT_SLEEP:
+ ret = wlan_ret_boot_sleep(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_ADD_NEW_STATION:
+ break;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR)
+ case HostCmd_CMD_CRYPTO:
+ ret = wlan_ret_crypto(pmpriv, resp, pioctl_buf);
+ break;
+#endif
+ case HostCmd_CMD_11AX_CFG:
+ ret = wlan_ret_11ax_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_11AX_CMD:
+ ret = wlan_ret_11ax_cmd(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RANGE_EXT:
+ ret = wlan_ret_range_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG:
+ ret = wlan_ret_rxabortcfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_RX_ABORT_CFG_EXT:
+ ret = wlan_ret_rxabortcfg_ext(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_TX_AMPDU_PROT_MODE:
+ ret = wlan_ret_tx_ampdu_prot_mode(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG:
+ ret = wlan_ret_dot11mc_unassoc_ftm_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_RATE_ADAPT_CFG:
+ ret = wlan_ret_rate_adapt_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_CCK_DESENSE_CFG:
+ ret = wlan_ret_cck_desense_cfg(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CHANNEL_TRPC_CONFIG:
+ ret = wlan_ret_get_chan_trpc_config(pmpriv, resp, pioctl_buf);
+ break;
+ case HostCmd_CMD_LOW_POWER_MODE_CFG:
+ ret = wlan_ret_set_get_low_power_mode_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_802_11_BAND_STEERING:
+ ret = wlan_ret_set_get_band_steering_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ case HostCmd_CMD_UAP_BEACON_STUCK_CFG:
+ ret = wlan_ret_set_get_beacon_stuck_cfg(pmpriv, resp,
+ pioctl_buf);
+ break;
+ default:
+ PRINTM(MERROR, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ if (pioctl_buf)
+ pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_uap_process_event(t_void *priv)
+{
+ pmlan_private pmpriv = (pmlan_private)priv;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 eventcause = pmadapter->event_cause;
+ pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
+ t_u8 *event_buf = MNULL;
+ mlan_event *pevent = MNULL;
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ sta_node *sta_ptr = MNULL;
+ t_u8 i = 0;
+ t_u8 channel = 0;
+ MrvlIEtypes_channel_band_t *pchan_info = MNULL;
+ chan_band_info *pchan_band_info = MNULL;
+ event_exceed_max_p2p_conn *event_excd_p2p = MNULL;
+ t_u16 enable;
+
+ ENTER();
+
+ if (!pmbuf) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Event length check */
+ if (pmbuf && (pmbuf->data_len - sizeof(eventcause)) > MAX_EVENT_SIZE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate memory for event buffer */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle,
+ MAX_EVENT_SIZE + sizeof(mlan_event),
+ MLAN_MEM_DEF, &event_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !event_buf) {
+ PRINTM(MERROR, "Could not allocate buffer for event buf\n");
+ if (pmbuf)
+ pmbuf->status_code = MLAN_ERROR_NO_MEM;
+ goto done;
+ }
+ pevent = (pmlan_event)event_buf;
+ memset(pmadapter, &pevent->event_id, 0, sizeof(pevent->event_id));
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
+ pmbuf->data_len > sizeof(eventcause))
+ DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+
+ switch (eventcause) {
+ case EVENT_MICRO_AP_BSS_START:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_START\n");
+ pmpriv->uap_bss_started = MTRUE;
+ pmpriv->is_data_rate_auto = MTRUE;
+ memcpy_ext(pmadapter, pmpriv->curr_addr,
+ pmadapter->event_body + 2, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_START;
+ wlan_check_uap_capability(pmpriv, pmbuf);
+ wlan_coex_ampdu_rxwinsize(pmadapter);
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ if (IsAuthenticatorEnabled(pmpriv->psapriv)) {
+ pmadapter->authenticator_priv = pmpriv;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DEFER_RX_WORK,
+ MNULL);
+ }
+#endif
+ break;
+ case EVENT_MICRO_AP_BSS_ACTIVE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_ACTIVE\n");
+ pmpriv->media_connected = MTRUE;
+ pmpriv->port_open = MTRUE;
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE;
+ break;
+ case EVENT_MICRO_AP_BSS_IDLE:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_BSS_IDLE\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_BSS_IDLE;
+ pmpriv->media_connected = MFALSE;
+ wlan_clean_txrx(pmpriv);
+ wlan_notify_station_deauth(pmpriv);
+ wlan_delete_station_list(pmpriv);
+ pmpriv->port_open = MFALSE;
+ pmpriv->amsdu_disable = MFALSE;
+ pmpriv->tx_pause = MFALSE;
+ break;
+ case EVENT_MICRO_AP_MIC_COUNTERMEASURES:
+ PRINTM(MEVENT, "EVENT: MICRO_AP_MIC_COUNTERMEASURES\n");
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_MIC_COUNTERMEASURES;
+ break;
+ case EVENT_PS_AWAKE:
+ PRINTM(MINFO, "EVENT: AWAKE\n");
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "||");
+ /* Handle unexpected PS AWAKE event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->ps_state = PS_STATE_AWAKE;
+
+ break;
+ case EVENT_PS_SLEEP:
+ PRINTM(MINFO, "EVENT: SLEEP\n");
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "__");
+ /* Handle unexpected PS SLEEP event */
+ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
+ break;
+ pmadapter->ps_state = PS_STATE_PRE_SLEEP;
+ wlan_check_ps_cond(pmadapter);
+ break;
+ case EVENT_MICRO_AP_STA_ASSOC:
+ wlan_process_sta_assoc_event(pmpriv, pevent, pmbuf);
+ memcpy_ext(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ sta_ptr = wlan_add_station_entry(pmpriv, sta_addr);
+ PRINTM_NETINTF(MMSG, pmpriv);
+ PRINTM(MMSG, "wlan: EVENT: MICRO_AP_STA_ASSOC " MACSTR "\n",
+ MAC2STR(sta_addr));
+ if (!sta_ptr)
+ break;
+ if (pmpriv->is_11n_enabled
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ || IsAuthenticatorEnabled(pmpriv->psapriv)
+#endif
+ ) {
+ wlan_check_sta_capability(pmpriv, pmbuf, sta_ptr);
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (sta_ptr->is_11n_enabled)
+ sta_ptr->ampdu_sta[i] =
+ pmpriv->aggr_prio_tbl[i]
+ .ampdu_user;
+ else
+ sta_ptr->ampdu_sta[i] =
+ BA_STREAM_NOT_ALLOWED;
+ }
+ memset(pmadapter, sta_ptr->rx_seq, 0xff,
+ sizeof(sta_ptr->rx_seq));
+ }
+ if (pmpriv->sec_info.wapi_enabled)
+ wlan_update_wapi_info_tlv(pmpriv, pmbuf);
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ /**enter authenticator*/
+ if (IsAuthenticatorEnabled(pmpriv->psapriv))
+ AuthenticatorSendEapolPacket(
+ pmpriv->psapriv, sta_ptr->cm_connectioninfo);
+#endif
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_MICRO_AP_STA_DEAUTH:
+ pevent->event_id = MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT;
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len - 4;
+ /* skip event length field */
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset + 4,
+ pevent->event_len, pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ memcpy_ext(pmadapter, sta_addr, pmadapter->event_body + 2,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ PRINTM_NETINTF(MMSG, pmpriv);
+ PRINTM(MMSG, "wlan: EVENT: MICRO_AP_STA_DEAUTH " MACSTR "\n",
+ MAC2STR(sta_addr));
+ if (pmpriv->is_11n_enabled) {
+ wlan_cleanup_reorder_tbl(pmpriv, sta_addr);
+ wlan_11n_cleanup_txbastream_tbl(pmpriv, sta_addr);
+ }
+ wlan_wmm_delete_peer_ralist(pmpriv, sta_addr);
+ wlan_delete_station_entry(pmpriv, sta_addr);
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_HS_ACT_REQ:
+ PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_HS_CFG_ENH, 0,
+ 0, MNULL, MNULL);
+ break;
+ case EVENT_ADDBA:
+ PRINTM(MEVENT, "EVENT: ADDBA Request\n");
+ if (pmpriv->media_connected == MTRUE)
+ ret = wlan_prepare_cmd(pmpriv,
+ HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0, MNULL,
+ pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore ADDBA Request event in BSS idle state\n");
+ break;
+ case EVENT_DELBA:
+ PRINTM(MEVENT, "EVENT: DELBA Request\n");
+ if (pmpriv->media_connected == MTRUE)
+ wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore DELBA Request event in BSS idle state\n");
+ break;
+ case EVENT_BA_STREAM_TIMEOUT:
+ PRINTM(MEVENT, "EVENT: BA Stream timeout\n");
+ if (pmpriv->media_connected == MTRUE)
+ wlan_11n_ba_stream_timeout(
+ pmpriv, (HostCmd_DS_11N_BATIMEOUT *)
+ pmadapter->event_body);
+ else
+ PRINTM(MERROR,
+ "Ignore BA Stream timeout event in BSS idle state\n");
+ break;
+ case EVENT_RXBA_SYNC:
+ PRINTM(MEVENT, "EVENT: RXBA_SYNC\n");
+ wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
+ pmbuf->data_len - sizeof(eventcause));
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n",
+ *(t_u16 *)pmadapter->event_body);
+ pmadapter->tx_buf_size =
+ MIN(pmadapter->curr_tx_buf_size,
+ wlan_le16_to_cpu(*(t_u16 *)pmadapter->event_body));
+ if (pmbuf->data_len == sizeof(eventcause) + sizeof(t_u32)) {
+ enable = wlan_le16_to_cpu(
+ *(t_u16 *)(pmadapter->event_body +
+ sizeof(t_u16)));
+ if (enable)
+ pmpriv->amsdu_disable = MFALSE;
+ else
+ pmpriv->amsdu_disable = MTRUE;
+ PRINTM(MEVENT, "amsdu_disable=%d\n",
+ pmpriv->amsdu_disable);
+ }
+ PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
+ break;
+ case EVENT_TX_DATA_PAUSE:
+ PRINTM(MEVENT, "EVENT: TX_DATA_PAUSE\n");
+ wlan_process_tx_pause_event(priv, pmbuf);
+ break;
+ case EVENT_RADAR_DETECTED:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: Radar Detected\n");
+ if (pmpriv->adapter->dfs_test_params.cac_restart &&
+ pmpriv->adapter->state_dfs.dfs_check_pending) {
+ wlan_11h_cancel_radar_detect(pmpriv);
+ wlan_11h_issue_radar_detect(
+ pmpriv, MNULL,
+ pmpriv->adapter->dfs_test_params.chan,
+ pmpriv->adapter->dfs_test_params.bandcfg);
+ pevent->event_id = 0;
+ break;
+ }
+ /* Send as passthru first, this event can cause other events */
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pevent->event_id = 0; /* clear to avoid resending at end of fcn
+ */
+
+ /* Print event data */
+ pevent->event_id = MLAN_EVENT_ID_FW_RADAR_DETECTED;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ pevent->event_len, pevent->event_len);
+ wlan_11h_print_event_radar_detected(pmpriv, pevent, &channel);
+ *((t_u8 *)pevent->event_buf) = channel;
+ if (!pmpriv->intf_state_11h.is_11h_host) {
+ if (pmadapter->state_rdh.stage == RDH_OFF) {
+ pmadapter->state_rdh.stage = RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(pmadapter,
+ pmpriv);
+ if (pmpriv->uap_host_based)
+ wlan_recv_event(
+ priv,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ pevent);
+ } else {
+ PRINTM(MEVENT,
+ "Ignore Event Radar Detected - handling"
+ " already in progress.\n");
+ }
+ } else {
+ if (pmpriv->adapter->dfs_test_params
+ .no_channel_change_on_radar ||
+ pmpriv->adapter->dfs_test_params
+ .fixed_new_channel_on_radar) {
+ if (pmadapter->state_rdh.stage == RDH_OFF ||
+ pmadapter->state_rdh.stage ==
+ RDH_SET_CUSTOM_IE) {
+ pmadapter->state_rdh.stage =
+ RDH_CHK_INTFS;
+ wlan_11h_radar_detected_handling(
+ pmadapter, pmpriv);
+ } else
+ PRINTM(MEVENT,
+ "Ignore Event Radar Detected - handling already in progress.\n");
+ } else {
+ pmpriv->intf_state_11h.tx_disabled = MTRUE;
+ wlan_recv_event(priv,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED,
+ pevent);
+ }
+ }
+
+ pevent->event_id = 0; /* clear to avoid resending at end of fcn
+ */
+ break;
+ case EVENT_CHANNEL_REPORT_RDY:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
+ pmpriv->adapter->dfs_test_params.cac_restart = MFALSE;
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ /* Copy event data */
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ pevent->event_len, pevent->event_len);
+ /* Handle / pass event data, and free buffer */
+ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent,
+ &channel);
+ if (pmpriv->intf_state_11h.is_11h_host) {
+ *((t_u8 *)pevent->event_buf) =
+ pmpriv->adapter->state_dfs.dfs_radar_found;
+ *((t_u8 *)pevent->event_buf + 1) = channel;
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY,
+ pevent);
+ } else {
+ /* Send up this Event to unblock MOAL waitqueue */
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT,
+ MNULL);
+ }
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_CHANNEL_SWITCH:
+ pchan_info =
+ (MrvlIEtypes_channel_band_t *)(pmadapter->event_body);
+ channel = pchan_info->channel;
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: CHANNEL_SWITCH new channel %d\n",
+ channel);
+ pmpriv->uap_channel = channel;
+ pmpriv->uap_state_chan_cb.channel = pchan_info->channel;
+ pmpriv->uap_state_chan_cb.bandcfg = pchan_info->bandcfg;
+ if (wlan_11h_radar_detect_required(pmpriv,
+ pchan_info->channel)) {
+ if (!wlan_11h_is_active(pmpriv)) {
+ /* active 11h extention in Fw */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv,
+ MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(
+ pmpriv);
+ }
+ if (pmpriv->uap_host_based)
+ pmpriv->intf_state_11h.is_11h_host = MTRUE;
+ wlan_11h_set_dfs_check_chan(pmpriv,
+ pchan_info->channel);
+ }
+ if ((pmpriv->adapter->state_rdh.stage != RDH_OFF &&
+ !pmpriv->intf_state_11h.is_11h_host) ||
+ pmpriv->adapter->dfs_test_params.no_channel_change_on_radar ||
+ pmpriv->adapter->dfs_test_params.fixed_new_channel_on_radar) {
+ /* Handle embedded DFS */
+ if (pmpriv->adapter->state_rdh.stage ==
+ RDH_SET_CUSTOM_IE) {
+ pmadapter->state_rdh.stage =
+ RDH_RESTART_TRAFFIC;
+ wlan_11h_radar_detected_handling(pmadapter,
+ pmpriv);
+ }
+
+ } else {
+ /* Handle Host-based DFS and non-DFS(normal uap) case */
+ pmpriv->intf_state_11h.tx_disabled = MFALSE;
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ /* Setup event buffer */
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id =
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE;
+ pevent->event_len = sizeof(chan_band_info);
+ pchan_band_info = (chan_band_info *)pevent->event_buf;
+ /* Copy event data */
+ memcpy_ext(pmadapter, (t_u8 *)&pchan_band_info->bandcfg,
+ (t_u8 *)&pchan_info->bandcfg,
+ sizeof(pchan_info->bandcfg),
+ sizeof(pchan_info->bandcfg));
+ pchan_band_info->channel = pchan_info->channel;
+ if (pchan_band_info->bandcfg.chanWidth == CHAN_BW_80MHZ)
+ pchan_band_info->center_chan =
+ wlan_get_center_freq_idx(
+ priv, BAND_AAC,
+ pchan_info->channel,
+ CHANNEL_BW_80MHZ);
+ pchan_band_info->is_11n_enabled =
+ pmpriv->is_11n_enabled;
+ wlan_recv_event(pmpriv,
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE,
+ pevent);
+ pevent->event_id = 0;
+ }
+ break;
+ case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
+ PRINTM_NETINTF(MEVENT, pmpriv);
+ PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
+ *(t_u16 *)pmadapter->event_body);
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL);
+ pevent->event_id = MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED;
+ break;
+
+ case EVENT_FW_DEBUG_INFO:
+ memset(pmadapter, event_buf, 0x00, MAX_EVENT_SIZE);
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_FW_DEBUG_INFO;
+ pevent->event_len = pmbuf->data_len - sizeof(eventcause);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ pevent->event_len, pevent->event_len);
+ PRINTM(MEVENT, "EVENT: FW Debug Info %s\n",
+ (t_u8 *)pevent->event_buf);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ pevent->event_id = 0; /* clear to avoid resending at end of fcn
+ */
+ break;
+ case EVENT_TX_STATUS_REPORT:
+ PRINTM(MINFO, "EVENT: TX_STATUS\n");
+ pevent->event_id = MLAN_EVENT_ID_FW_TX_STATUS;
+ break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ PRINTM(MEVENT, "EVENT: BT coex wlan param update\n");
+ wlan_bt_coex_wlan_param_update_event(pmpriv, pmbuf);
+ break;
+ case EVENT_EXCEED_MAX_P2P_CONN:
+ event_excd_p2p =
+ (event_exceed_max_p2p_conn *)(pmbuf->pbuf +
+ pmbuf->data_offset);
+ PRINTM(MEVENT, "EVENT: EXCEED MAX P2P CONNECTION\n");
+ PRINTM(MEVENT, "REQUEST P2P MAC: " MACSTR "\n",
+ MAC2STR(event_excd_p2p->peer_mac_addr));
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ case EVENT_VDLL_IND:
+ wlan_process_vdll_event(pmpriv, pmbuf);
+ break;
+
+ case EVENT_FW_HANG_REPORT:
+ if (pmbuf->data_len < (sizeof(eventcause) + sizeof(t_u16))) {
+ PRINTM(MEVENT,
+ "EVENT: EVENT_FW_HANG_REPORT skip for len too short: %d\n",
+ pmbuf->data_len);
+ break;
+ }
+ PRINTM(MEVENT, "EVENT: EVENT_FW_HANG_REPORT reasoncode=%d\n",
+ wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause))));
+ pmadapter->fw_hang_report = MTRUE;
+ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL);
+ break;
+ case EVENT_WATCHDOG_TMOUT:
+ PRINTM(MEVENT, "EVENT: EVENT_WATCHDOG_TMOUT reasoncode=%d\n",
+ wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf +
+ pmbuf->data_offset +
+ sizeof(eventcause))));
+ pevent->event_id = MLAN_EVENT_ID_DRV_WIFI_STATUS;
+ pevent->event_len = sizeof(pevent->event_id) + sizeof(t_u16);
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset +
+ sizeof(eventcause),
+ sizeof(t_u16), sizeof(t_u16));
+ break;
+ default:
+ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
+ break;
+ }
+
+ if (pevent->event_id) {
+ pevent->bss_index = pmpriv->bss_index;
+ pevent->event_len = pmbuf->data_len;
+ memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf,
+ pmbuf->pbuf + pmbuf->data_offset, pevent->event_len,
+ pevent->event_len);
+ wlan_recv_event(pmpriv, pevent->event_id, pevent);
+ }
+done:
+ if (event_buf)
+ pcb->moal_mfree(pmadapter->pmoal_handle, event_buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to set uap max sta number
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param uap_max_sta Max station number uAP can supported (per chip)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_uap_set_uap_max_sta(pmlan_private pmpriv, t_u8 uap_max_sta)
+{
+ MrvlIEtypes_uap_max_sta_cnt_t tlv_uap_max_sta;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_uap_max_sta, 0, sizeof(tlv_uap_max_sta));
+ tlv_uap_max_sta.header.type =
+ wlan_cpu_to_le16(TLV_TYPE_UAP_MAX_STA_CNT_PER_CHIP);
+ tlv_uap_max_sta.header.len = wlan_cpu_to_le16(sizeof(t_u16));
+ tlv_uap_max_sta.uap_max_sta = wlan_cpu_to_le16(uap_max_sta);
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &tlv_uap_max_sta);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function issues commands to initialize firmware
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param first_bss flag for first BSS
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_uap_init_cmd(t_void *priv, t_u8 first_bss)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = (pmlan_private)priv;
+ t_u16 last_cmd = 0;
+
+ ENTER();
+ if (!pmpriv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (first_bss) {
+ if (wlan_adapter_init_cmd(pmpriv->adapter) ==
+ MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (pmpriv->adapter->init_para.uap_max_sta &&
+ (pmpriv->adapter->init_para.uap_max_sta <= MAX_STA_COUNT))
+ wlan_uap_set_uap_max_sta(
+ pmpriv, pmpriv->adapter->init_para.uap_max_sta);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
+ if (ret) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ last_cmd = HOST_CMD_APCMD_SYS_CONFIGURE;
+ /** set last_init_cmd */
+ if (last_cmd) {
+ pmpriv->adapter->last_init_cmd = last_cmd;
+ ret = MLAN_STATUS_PENDING;
+ }
+done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_ioctl.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_ioctl.c
new file mode 100644
index 000000000000..2610627c123b
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_ioctl.c
@@ -0,0 +1,2240 @@
+/** @file mlan_uap_ioctl.c
+ *
+ * @brief This file contains the handling of AP mode ioctls
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_11n.h"
+#include "mlan_fw.h"
+#include "mlan_11h.h"
+#include "mlan_11ac.h"
+#include "mlan_11ax.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+extern t_u8 tos_to_tid_inv[];
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Stop BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_stop(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+static t_bool wlan_can_radar_det_skip(mlan_private *priv)
+{
+ mlan_private *priv_list[MLAN_MAX_BSS_NUM];
+ mlan_private *pmpriv;
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 pcount, i;
+
+ /* In MBSS environment, if one of the BSS is already beaconing and DRCS
+ * is off then 11n_radar detection is not required for subsequent BSSes
+ * since they will follow the primary bss.
+ */
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)) {
+ memset(pmadapter, priv_list, 0x00, sizeof(priv_list));
+ pcount = wlan_get_privs_by_cond(pmadapter, wlan_is_intf_active,
+ priv_list);
+ for (i = 0; i < pcount; i++) {
+ pmpriv = priv_list[i];
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
+ return MTRUE;
+ }
+ }
+ return MFALSE;
+}
+/**
+ * @brief Callback to finish BSS IOCTL START
+ * Not to be called directly to initiate bss_start
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_bss_ioctl_start
+ */
+static mlan_status wlan_uap_callback_bss_ioctl_start(t_void *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ t_u8 old_channel;
+ t_bool under_nop = MFALSE;
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ /*
+ * Check if the region and channel requires we check for radar.
+ */
+ if ((puap_state_chan_cb->bandcfg.chanBand == BAND_5GHZ) &&
+ !wlan_can_radar_det_skip(pmpriv) &&
+ wlan_11h_radar_detect_required(pmpriv,
+ puap_state_chan_cb->channel)) {
+ /* If DFS repeater mode is on then before starting the uAP
+ * make sure that mlan0 is connected to some external AP
+ * for DFS channel operations.
+ */
+ if (pmpriv->adapter->dfs_repeater) {
+ pmlan_private tmpriv = MNULL;
+ tmpriv = wlan_get_priv(pmpriv->adapter,
+ MLAN_BSS_ROLE_STA);
+
+ if (tmpriv && !tmpriv->media_connected) {
+ PRINTM(MERROR,
+ "BSS start is blocked when DFS-repeater\n"
+ "mode is on and STA is not connected\n");
+ pcb->moal_ioctl_complete(
+ pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ } else {
+ /* STA is connected.
+ * Skip DFS check for bss_start since its a
+ * repeater mode
+ */
+ goto prep_bss_start;
+ }
+ }
+
+ /* first check if channel is under NOP */
+ if (wlan_11h_is_channel_under_nop(
+ pmpriv->adapter, puap_state_chan_cb->channel)) {
+ /* recently we've seen radar on this channel */
+ ret = MLAN_STATUS_FAILURE;
+ under_nop = MTRUE;
+ }
+
+ /* Check cached radar check on the channel */
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = wlan_11h_check_chan_report(
+ pmpriv, puap_state_chan_cb->channel);
+
+ /* Found radar: try to switch to a non-dfs channel */
+ if (ret != MLAN_STATUS_SUCCESS) {
+ old_channel = puap_state_chan_cb->channel;
+ ret = wlan_11h_switch_non_dfs_chan(
+ pmpriv, &puap_state_chan_cb->channel);
+
+ if (ret == MLAN_STATUS_SUCCESS) {
+ wlan_11h_update_bandcfg(
+ &pmpriv->uap_state_chan_cb.bandcfg,
+ puap_state_chan_cb->channel);
+ PRINTM(MCMD_D,
+ "NOP: uap band config:0x%x channel=%d\n",
+ pmpriv->uap_state_chan_cb.bandcfg,
+ puap_state_chan_cb->channel);
+
+ ret = wlan_uap_set_channel(
+ pmpriv,
+ pmpriv->uap_state_chan_cb.bandcfg,
+ puap_state_chan_cb->channel);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (under_nop) {
+ PRINTM(MMSG,
+ "Channel %d under NOP,"
+ " switched to new channel %d successfully.\n",
+ old_channel,
+ puap_state_chan_cb
+ ->channel);
+ } else {
+ PRINTM(MMSG,
+ "Radar found on channel %d,"
+ " switched to new channel %d successfully.\n",
+ old_channel,
+ puap_state_chan_cb
+ ->channel);
+ }
+ } else {
+ if (under_nop) {
+ PRINTM(MMSG,
+ "Channel %d under NOP,"
+ " switch to new channel %d failed.\n",
+ old_channel,
+ puap_state_chan_cb
+ ->channel);
+ } else {
+ PRINTM(MMSG,
+ "Radar found on channel %d,"
+ " switch to new channel %d failed.\n",
+ old_channel,
+ puap_state_chan_cb
+ ->channel);
+ }
+ pcb->moal_ioctl_complete(
+ pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb
+ ->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ if (under_nop) {
+ PRINTM(MMSG,
+ "Channel %d under NOP, no switch channel available.\n",
+ old_channel);
+ } else {
+ PRINTM(MMSG,
+ "Radar found on channel %d, no switch channel available.\n",
+ old_channel);
+ }
+ /* No command sent with the ioctl, need manually
+ * signal completion */
+ pcb->moal_ioctl_complete(
+ pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ goto done;
+ }
+ } else {
+ PRINTM(MINFO, "No Radar found on channel %d\n",
+ puap_state_chan_cb->channel);
+ }
+ }
+
+prep_bss_start:
+ /* else okay to send command: not DFS channel or no radar */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)puap_state_chan_cb->pioctl_req_curr,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+done:
+ puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+/**
+ * @sa wlan_uap_callback_bss_ioctl_start
+ */
+static mlan_status wlan_uap_bss_ioctl_start(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ pmpriv->uap_host_based = bss->param.host_based;
+ if (!pmpriv->intf_state_11h.is_11h_host &&
+ pmpriv->intf_state_11h.is_11h_active) {
+ /* if FW supports ACS+DFS then sequence is different */
+
+ /* First check channel report, defer BSS_START CMD to callback.
+ */
+ /* store params, issue command to get UAP channel, whose
+ * CMD_RESP will callback remainder of bss_start handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_bss_ioctl_start;
+ pmpriv->intf_state_11h.is_11h_host = MFALSE;
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
+ HostCmd_ACT_GEN_SET, 0,
+ (t_void *)pioctl_req, MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset BSS
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_reset(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ t_u8 i = 0;
+
+ ENTER();
+
+ /*
+ * Reset any uap private parameters here
+ */
+ for (i = 0; i < pmadapter->max_mgmt_ie_index; i++)
+ memset(pmadapter, &pmpriv->mgmt_ie[i], 0, sizeof(custom_ie));
+ pmpriv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+ pmpriv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ pmpriv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ pmpriv->user_rxwinsize = pmpriv->add_ba_param.rx_win_size;
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ pmpriv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ pmpriv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
+ pmpriv->addba_reject[i] = ADDBA_RSP_STATUS_ACCEPT;
+ }
+ pmpriv->aggr_prio_tbl[6].ampdu_user =
+ pmpriv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
+ pmpriv->addba_reject[6] = pmpriv->addba_reject[7] =
+ ADDBA_RSP_STATUS_REJECT;
+
+ /* hs_configured, hs_activated are reset by main loop */
+ pmadapter->hs_cfg.conditions = HOST_SLEEP_DEF_COND;
+ pmadapter->hs_cfg.gpio = HOST_SLEEP_DEF_GPIO;
+ pmadapter->hs_cfg.gap = HOST_SLEEP_DEF_GAP;
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function to process add station.
+ *
+ * @param pmadapter A pointer to pmadapter.
+ *
+ * @param pioctl_req A pointer to pioctl_req
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_uap_bss_ioctl_add_station(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_ADD_NEW_STATION,
+ HostCmd_ACT_ADD_STA, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get MAC address
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_mac_address(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ memcpy_ext(pmadapter, pmpriv->curr_addr, &bss->param.mac_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get wmm param
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_uap_wmm_param(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get scan channels
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_bss_ioctl_uap_scan_channels(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get UAP channel
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_uap_channel(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get UAP operation control vaule
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_uap_oper_ctrl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pmadapter->fw_ver == HOST_API_VERSION_V15 &&
+ pmadapter->fw_min_ver >= FW_MINOR_VERSION_1) {
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_OPER_CTRL,
+ cmd_action, 0, (t_void *)pioctl_req,
+ (t_void *)pioctl_req->pbuf);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ PRINTM(MMSG, "FW don't support uap oper ctrl\n");
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Uap statistics
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_get_stats(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Uap MIB counters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_get_stats_log(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (pioctl_req != MNULL) {
+ pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ } else {
+ PRINTM(MERROR, "MLAN IOCTL information is not present\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Check information buffer length of MLAN IOCTL */
+ if (pioctl_req->buf_len < sizeof(mlan_ds_get_stats)) {
+ PRINTM(MWARN,
+ "MLAN IOCTL information buffer length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_get_stats);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ ret = MLAN_STATUS_RESOURCE;
+ goto exit;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get AP config
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE, cmd_action,
+ 0, (t_void *)pioctl_req, MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief deauth sta
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_deauth_sta(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_bss *bss = MNULL;
+ const t_u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ sta_node *sta_ptr = MNULL;
+
+ ENTER();
+
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (pmpriv->uap_host_based & UAP_FLAG_HOST_MLME) {
+ if (memcmp(pmpriv->adapter, bss->param.deauth_param.mac_addr,
+ bc_mac, MLAN_MAC_ADDR_LENGTH)) {
+ sta_ptr = wlan_get_station_entry(
+ pmpriv, bss->param.deauth_param.mac_addr);
+ if (!sta_ptr) {
+ PRINTM(MCMND,
+ "Skip deauth to station " MACSTR "\n",
+ MAC2STR(bss->param.deauth_param
+ .mac_addr));
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)&bss->param.deauth_param);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get station list
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_get_sta_list(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_STA_LIST,
+ HostCmd_ACT_GEN_GET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief soft_reset
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_misc_ioctl_soft_reset(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_SOFT_RESET,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Tx data pause
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_misc_ioctl_txdatapause(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pmisc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ if (pioctl_req->action == MLAN_ACT_SET)
+ cmd_action = HostCmd_ACT_GEN_SET;
+ else
+ cmd_action = HostCmd_ACT_GEN_GET;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_CFG_TX_DATA_PAUSE,
+ cmd_action, 0, (t_void *)pioctl_req,
+ &(pmisc->param.tx_datapause));
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Power mode
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_pm_ioctl_mode(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 cmd_action = 0;
+ t_u32 cmd_oid = 0;
+
+ ENTER();
+
+ pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ if (pm->param.ps_mgmt.ps_mode == PS_MODE_INACTIVITY) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS;
+ } else if (pm->param.ps_mgmt.ps_mode == PS_MODE_PERIODIC_DTIM) {
+ cmd_action = EN_AUTO_PS;
+ cmd_oid = BITMAP_UAP_DTIM_PS;
+ } else {
+ cmd_action = DIS_AUTO_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ } else {
+ cmd_action = GET_PS;
+ cmd_oid = BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS;
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ cmd_action, cmd_oid, (t_void *)pioctl_req,
+ (t_void *)&pm->param.ps_mgmt);
+ if ((ret == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_SET) &&
+ (cmd_action == DIS_AUTO_PS)) {
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ GET_PS, 0, MNULL, MNULL);
+ }
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WAPI IE
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_set_wapi_ie(mlan_private *priv,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (misc->param.gen_ie.len) {
+ if (misc->param.gen_ie.len > sizeof(priv->wapi_ie)) {
+ PRINTM(MWARN, "failed to copy WAPI IE, too big\n");
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ memcpy_ext(priv->adapter, priv->wapi_ie,
+ misc->param.gen_ie.ie_data, misc->param.gen_ie.len,
+ sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MIOCTL, "Set wapi_ie_len=%d IE=%#x\n", priv->wapi_ie_len,
+ priv->wapi_ie[0]);
+ DBG_HEXDUMP(MCMD_D, "wapi_ie", priv->wapi_ie,
+ priv->wapi_ie_len);
+ if (priv->wapi_ie[0] == WAPI_IE)
+ priv->sec_info.wapi_enabled = MTRUE;
+ } else {
+ memset(priv->adapter, priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = misc->param.gen_ie.len;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = MFALSE;
+ }
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(priv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set generic IE
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_uap_misc_ioctl_gen_ie(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *misc = MNULL;
+ IEEEtypes_VendorHeader_t *pvendor_ie = MNULL;
+
+ ENTER();
+
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ if ((misc->param.gen_ie.type == MLAN_IE_TYPE_GEN_IE) &&
+ (pioctl_req->action == MLAN_ACT_SET)) {
+ if (misc->param.gen_ie.len) {
+ pvendor_ie = (IEEEtypes_VendorHeader_t *)
+ misc->param.gen_ie.ie_data;
+ if (pvendor_ie->element_id == WAPI_IE) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ } else {
+ /* clear WAPI IE */
+ ret = wlan_uap_set_wapi_ie(pmpriv, pioctl_req);
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WAPI status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_uap_sec_ioctl_wapi_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmpriv->wapi_ie_len)
+ sec->param.wapi_enabled = MTRUE;
+ else
+ sec->param.wapi_enabled = MFALSE;
+ } else {
+ if (sec->param.wapi_enabled == MFALSE) {
+ memset(pmpriv->adapter, pmpriv->wapi_ie, 0,
+ sizeof(pmpriv->wapi_ie));
+ pmpriv->wapi_ie_len = 0;
+ PRINTM(MINFO, "Reset wapi_ie_len=%d IE=%#x\n",
+ pmpriv->wapi_ie_len, pmpriv->wapi_ie[0]);
+ pmpriv->sec_info.wapi_enabled = MFALSE;
+ }
+ }
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief report mic error
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status
+wlan_uap_sec_ioctl_report_mic_error(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_REPORT_MIC,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)sec->param.sta_mac);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encrypt key
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status
+wlan_uap_sec_ioctl_set_encrypt_key(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_sec_cfg *sec = MNULL;
+
+ ENTER();
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action != MLAN_ACT_SET) {
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!sec->param.encrypt_key.key_remove &&
+ !sec->param.encrypt_key.key_len) {
+ PRINTM(MCMND, "Skip set key with key_len = 0\n");
+ LEAVE();
+ return ret;
+ }
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ (t_void *)pioctl_req, &sec->param.encrypt_key);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get BSS information
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_uap_get_bss_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_info *info;
+
+ ENTER();
+
+ info = (mlan_ds_get_info *)pioctl_req->pbuf;
+ /* Connection status */
+ info->param.bss_info.media_connected = pmpriv->media_connected;
+
+ /* Radio status */
+ info->param.bss_info.radio_on = pmadapter->radio_on;
+
+ /* BSSID */
+ memcpy_ext(pmadapter, &info->param.bss_info.bssid, pmpriv->curr_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ info->param.bss_info.scan_block = pmadapter->scan_block;
+
+ info->param.bss_info.is_hs_configured = pmadapter->is_hs_configured;
+ info->param.bss_info.is_11h_active =
+ pmpriv->intf_state_11h.is_11h_active;
+ info->param.bss_info.dfs_check_channel =
+ pmpriv->adapter->state_dfs.dfs_check_channel;
+ pioctl_req->data_read_written =
+ sizeof(mlan_bss_info) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_uap_pm_ioctl_deepsleep(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_ds_auto_ds auto_ds;
+ t_u32 mode;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_pm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_pm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET) {
+ if (pmadapter->is_deep_sleep) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime =
+ pmadapter->idle_time;
+ } else
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ } else {
+ if (pmadapter->is_deep_sleep &&
+ pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ PRINTM(MMSG, "uAP already in deep sleep mode\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (((mlan_ds_pm_cfg *)pioctl_req->pbuf)
+ ->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) {
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ mode = EN_AUTO_PS;
+ PRINTM(MINFO, "Auto Deep Sleep: on\n");
+ } else {
+ mode = DIS_AUTO_PS;
+ auto_ds.auto_ds = DEEP_SLEEP_OFF;
+ PRINTM(MINFO, "Auto Deep Sleep: off\n");
+ }
+ if (((mlan_ds_pm_cfg *)pioctl_req->pbuf)
+ ->param.auto_deep_sleep.idletime)
+ auto_ds.idletime =
+ ((mlan_ds_pm_cfg *)pioctl_req->pbuf)
+ ->param.auto_deep_sleep.idletime;
+ else
+ auto_ds.idletime = pmadapter->idle_time;
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ (t_u16)mode, BITMAP_AUTO_DS,
+ (t_void *)pioctl_req, &auto_ds);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Band Steering configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_misc_band_steering_cfg(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_band_steer_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_band_steer_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_BAND_STEERING,
+ (t_u16)pm->param.band_steer_cfg.action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&pm->param.band_steer_cfg);
+ LEAVE();
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ return ret;
+}
+
+/**
+ * @brief Set Beacon Stuck Detect Mechanism Configurations
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCES/MLAN_STATUS_PENDING --success,
+ * otherwise fail
+ */
+static mlan_status wlan_misc_beacon_stuck_cfg(IN pmlan_adapter pmadapter,
+ IN pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_misc_cfg *pm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_beacon_stuck_param_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed =
+ sizeof(mlan_ds_beacon_stuck_param_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ pm = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_UAP_BEACON_STUCK_CFG,
+ (t_u16)pm->param.beacon_stuck_cfg.action, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&pm->param.beacon_stuck_cfg);
+
+ LEAVE();
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11D
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_snmp_mib_11d(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_snmp_mib *snmp = MNULL;
+ state_11d_t flag;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "11D setting cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ snmp = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ flag = (snmp->param.oid_value) ? ENABLE_11D : DISABLE_11D;
+
+ ret = wlan_11d_enable(pmpriv, (t_void *)pioctl_req, flag);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish domain_info handling
+ * Not to be called directly to initiate domain_info setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_domain_info
+ */
+static mlan_status wlan_uap_callback_domain_info(t_void *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_ds_11d_cfg *cfg11d;
+ t_u8 band;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ if (!puap_state_chan_cb->pioctl_req_curr) {
+ PRINTM(MERROR, "pioctl_req_curr is null\n");
+ LEAVE();
+ return ret;
+ }
+ cfg11d = (mlan_ds_11d_cfg *)puap_state_chan_cb->pioctl_req_curr->pbuf;
+ band = (puap_state_chan_cb->bandcfg.chanBand == BAND_5GHZ) ? BAND_A :
+ BAND_B;
+
+ ret = wlan_11d_handle_uap_domain_info(
+ pmpriv, band, cfg11d->param.domain_tlv,
+ puap_state_chan_cb->pioctl_req_curr);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ else {
+ puap_state_chan_cb->pioctl_req_curr->status_code =
+ MLAN_STATUS_FAILURE;
+ pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_FAILURE);
+ }
+
+ puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Domain Info for 11D
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_domain_info
+ */
+static mlan_status wlan_uap_domain_info(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11d_cfg)) {
+ PRINTM(MWARN, "MLAN 11d_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11d_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+
+ if ((pioctl_req->action == MLAN_ACT_SET) && pmpriv->uap_bss_started) {
+ PRINTM(MIOCTL,
+ "Domain_info cannot be changed while UAP bss is started.\n");
+ pioctl_req->data_read_written = 0;
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ * callback remainder of domain_info handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_domain_info;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H channel check handling.
+ * Not to be called directly to initiate channel check.
+ *
+ * @param priv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_SUCCESS/PENDING --success, otherwise fail
+ * @sa wlan_uap_11h_channel_check_req
+ */
+static mlan_status wlan_uap_callback_11h_channel_check_req(t_void *priv)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ Band_Config_t *pband_cfg = &puap_state_chan_cb->bandcfg;
+ /* keep copy as local variable */
+ pmlan_ioctl_req pioctl = puap_state_chan_cb->pioctl_req_curr;
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+ /* clear early to avoid race condition */
+ puap_state_chan_cb->pioctl_req_curr = MNULL;
+
+ /*
+ * Check if the region and channel requires a channel availability
+ * check.
+ */
+ if ((puap_state_chan_cb->bandcfg.chanBand == BAND_5GHZ) &&
+ !wlan_can_radar_det_skip(pmpriv) &&
+ wlan_11h_radar_detect_required(pmpriv,
+ puap_state_chan_cb->channel) &&
+ !wlan_11h_is_channel_under_nop(pmpriv->adapter,
+ puap_state_chan_cb->channel)) {
+ /*
+ * Radar detection is required for this channel, make sure
+ * 11h is activated in the firmware
+ */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+
+ /* Check for radar on the channel */
+ ret = wlan_11h_issue_radar_detect(pmpriv, pioctl,
+ puap_state_chan_cb->channel,
+ *pband_cfg);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ /* No command sent with the ioctl, need manually signal
+ * completion */
+ pcb->moal_ioctl_complete(pmpriv->adapter->pmoal_handle, pioctl,
+ MLAN_STATUS_COMPLETE);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief 802.11h uap start channel check
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_11h_channel_check_req
+ */
+static mlan_status wlan_uap_11h_channel_check_req(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_11h_cfg *p11h_cfg;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_11h_cfg)) {
+ PRINTM(MWARN, "MLAN 11h_cfg IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_11h_cfg);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ p11h_cfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ pmpriv->intf_state_11h.is_11h_host =
+ p11h_cfg->param.chan_rpt_req.host_based;
+
+ if (!pmpriv->intf_state_11h.is_11h_host) {
+ /* store params, issue command to get UAP channel, whose
+ * CMD_RESP will callback remainder of 11H channel check
+ * handling */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_11h_channel_check_req;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ } else {
+ if (!wlan_11h_is_active(pmpriv)) {
+ /* active 11h extention in Fw */
+ ret = wlan_11h_activate(pmpriv, MNULL, MTRUE);
+ ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ ret = wlan_11h_check_update_radar_det_state(pmpriv);
+ }
+ if (p11h_cfg->param.chan_rpt_req.millisec_dwell_time) {
+ if (pmpriv->adapter->dfs_test_params
+ .user_cac_period_msec) {
+ PRINTM(MCMD_D,
+ "cfg80211 dfs_testing - user CAC period=%d (msec)\n",
+ pmpriv->adapter->dfs_test_params
+ .user_cac_period_msec);
+ p11h_cfg->param.chan_rpt_req
+ .millisec_dwell_time =
+ pmpriv->adapter->dfs_test_params
+ .user_cac_period_msec;
+ }
+ ret = wlan_prepare_cmd(
+ pmpriv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ (t_void *)&p11h_cfg->param.chan_rpt_req);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Callback to finish 11H handling
+ * Not to be called directly to initiate 11H setting.
+ *
+ * @param pmpriv A pointer to mlan_private structure (cast from t_void*)
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_snmp_mib_11h
+ */
+static mlan_status wlan_uap_callback_snmp_mib_11h(t_void *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = (mlan_private *)priv;
+ wlan_uap_get_info_cb_t *puap_state_chan_cb = &pmpriv->uap_state_chan_cb;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
+ mlan_ds_snmp_mib *snmp;
+ t_bool enable_11h;
+
+ ENTER();
+ /* clear callback now that we're here */
+ puap_state_chan_cb->get_chan_callback = MNULL;
+
+ snmp = (mlan_ds_snmp_mib *)puap_state_chan_cb->pioctl_req_curr->pbuf;
+ enable_11h = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable_11h) {
+ if ((puap_state_chan_cb->bandcfg.chanBand == BAND_5GHZ) &&
+ !wlan_can_radar_det_skip(pmpriv) &&
+ wlan_11h_radar_detect_required(
+ pmpriv, puap_state_chan_cb->channel)) {
+ if (!wlan_11h_is_master_radar_det_active(pmpriv))
+ wlan_11h_config_master_radar_det(pmpriv, MTRUE);
+ } else {
+ puap_state_chan_cb->pioctl_req_curr->status_code =
+ MLAN_STATUS_SUCCESS;
+ pcb->moal_ioctl_complete(
+ pmpriv->adapter->pmoal_handle,
+ puap_state_chan_cb->pioctl_req_curr,
+ MLAN_STATUS_SUCCESS);
+ goto done;
+ }
+ }
+
+ ret = wlan_11h_activate(pmpriv,
+ (t_void *)puap_state_chan_cb->pioctl_req_curr,
+ enable_11h);
+ wlan_11h_check_update_radar_det_state(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+done:
+ puap_state_chan_cb->pioctl_req_curr = MNULL; /* prevent re-use */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set SNMP MIB for 11H
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ * @sa wlan_uap_callback_snmp_mib_11h
+ */
+static mlan_status wlan_uap_snmp_mib_11h(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_snmp_mib *snmp = MNULL;
+ t_bool enable;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_snmp_mib)) {
+ PRINTM(MWARN, "MLAN snmp_mib IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_snmp_mib);
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ snmp = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ enable = (snmp->param.oid_value) ? MTRUE : MFALSE;
+
+ if (enable) {
+ /* first enable 11D if it is not enabled */
+ if (!wlan_fw_11d_is_enabled(pmpriv)) {
+ ret = wlan_11d_enable(pmpriv, MNULL, ENABLE_11D);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Failed to first enable 11D before enabling 11H.\n");
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+
+ /* store params, issue command to get UAP channel, whose CMD_RESP will
+ * callback remainder of 11H handling (and radar detect if DFS chan) */
+ pmpriv->uap_state_chan_cb.pioctl_req_curr = pioctl_req;
+ pmpriv->uap_state_chan_cb.get_chan_callback =
+ wlan_uap_callback_snmp_mib_11h;
+
+ ret = wlan_uap_get_channel(pmpriv);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ACS scan
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_uap_bss_ioctl_acs_scan(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (pmadapter->uap_fw_ver < UAP_FW_VERSION_2) {
+ PRINTM(MIOCTL, "FW don't support ACS SCAN API\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCMD_APCMD_ACS_SCAN,
+ HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_req,
+ MNULL);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Issue CMD to UAP firmware to get current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_uap_get_channel(pmlan_private pmpriv)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to set current channel
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param uap_band_cfg UAP band configuration
+ * @param channel New channel
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_uap_set_channel(pmlan_private pmpriv,
+ Band_Config_t uap_band_cfg, t_u8 channel)
+{
+ MrvlIEtypes_channel_band_t tlv_chan_band;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(pmpriv->adapter, &tlv_chan_band, 0, sizeof(tlv_chan_band));
+ tlv_chan_band.header.type = TLV_TYPE_UAP_CHAN_BAND_CONFIG;
+ tlv_chan_band.header.len = sizeof(MrvlIEtypes_channel_band_t) -
+ sizeof(MrvlIEtypesHeader_t);
+ tlv_chan_band.bandcfg = uap_band_cfg;
+ tlv_chan_band.channel = channel;
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_SET, 0, MNULL, &tlv_chan_band);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue CMD to UAP firmware to get current beacon and dtim periods
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_uap_get_beacon_dtim(pmlan_private pmpriv)
+{
+ t_u8 tlv_buffer[sizeof(MrvlIEtypes_beacon_period_t) +
+ sizeof(MrvlIEtypes_dtim_period_t)];
+ MrvlIEtypes_beacon_period_t *ptlv_beacon_pd;
+ MrvlIEtypes_dtim_period_t *ptlv_dtim_pd;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(pmpriv->adapter, &tlv_buffer, 0, sizeof(tlv_buffer));
+ ptlv_beacon_pd = (MrvlIEtypes_beacon_period_t *)tlv_buffer;
+ ptlv_beacon_pd->header.type = TLV_TYPE_UAP_BEACON_PERIOD;
+ ptlv_beacon_pd->header.len = sizeof(MrvlIEtypes_beacon_period_t) -
+ sizeof(MrvlIEtypesHeader_t);
+
+ ptlv_dtim_pd =
+ (MrvlIEtypes_dtim_period_t
+ *)(tlv_buffer + sizeof(MrvlIEtypes_beacon_period_t));
+ ptlv_dtim_pd->header.type = TLV_TYPE_UAP_DTIM_PERIOD;
+ ptlv_dtim_pd->header.len =
+ sizeof(MrvlIEtypes_dtim_period_t) - sizeof(MrvlIEtypesHeader_t);
+
+ ret = wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_SYS_CONFIGURE,
+ HostCmd_ACT_GEN_GET, 0, MNULL, tlv_buffer);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get deauth control.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+mlan_status wlan_uap_snmp_mib_ctrl_deauth(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_snmp_mib *mib = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ t_u16 cmd_action = 0;
+
+ ENTER();
+
+ mib = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_SET) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ }
+
+ /* Send command to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, cmd_action,
+ StopDeauth_i, (t_void *)pioctl_req,
+ &mib->param.deauthctrl);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief MLAN uap ioctl handler
+ *
+ * @param adapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_ops_uap_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter)adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = MNULL;
+ mlan_ds_get_info *pget_info = MNULL;
+ mlan_ds_misc_cfg *misc = MNULL;
+ mlan_ds_sec_cfg *sec = MNULL;
+ mlan_ds_power_cfg *power = MNULL;
+ mlan_ds_pm_cfg *pm = MNULL;
+ mlan_ds_11d_cfg *cfg11d = MNULL;
+ mlan_ds_snmp_mib *snmp = MNULL;
+ mlan_ds_11h_cfg *cfg11h = MNULL;
+ mlan_ds_radio_cfg *radiocfg = MNULL;
+ mlan_ds_rate *rate = MNULL;
+ mlan_ds_reg_mem *reg_mem = MNULL;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ pmlan_ds_scan pscan;
+#endif
+
+ ENTER();
+ switch (pioctl_req->req_id) {
+ case MLAN_IOCTL_BSS:
+ bss = (mlan_ds_bss *)pioctl_req->pbuf;
+ if (bss->sub_command == MLAN_OID_BSS_MAC_ADDR)
+ status = wlan_uap_bss_ioctl_mac_address(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_STOP)
+ status = wlan_uap_bss_ioctl_stop(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_BSS_START)
+ status =
+ wlan_uap_bss_ioctl_start(pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_CONFIG)
+ status = wlan_uap_bss_ioctl_config(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_DEAUTH_STA)
+ status = wlan_uap_bss_ioctl_deauth_sta(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_BSS_RESET)
+ status =
+ wlan_uap_bss_ioctl_reset(pmadapter, pioctl_req);
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ else if (bss->sub_command == MLAN_OID_BSS_ROLE) {
+ util_enqueue_list_tail(
+ pmadapter->pmoal_handle,
+ &pmadapter->ioctl_pending_q,
+ (pmlan_linked_list)pioctl_req,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ pmadapter->pending_ioctl = MTRUE;
+ status = MLAN_STATUS_PENDING;
+ }
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (bss->sub_command == MLAN_OID_WIFI_DIRECT_MODE)
+ status = wlan_bss_ioctl_wifi_direct_mode(pmadapter,
+ pioctl_req);
+#endif
+ else if (bss->sub_command == MLAN_OID_BSS_REMOVE)
+ status = wlan_bss_ioctl_bss_remove(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_CFG_WMM_PARAM)
+ status = wlan_uap_bss_ioctl_uap_wmm_param(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_SCAN_CHANNELS)
+ status = wlan_uap_bss_ioctl_uap_scan_channels(
+ pmadapter, pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_CHANNEL)
+ status = wlan_uap_bss_ioctl_uap_channel(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_ACS_SCAN)
+ status = wlan_uap_bss_ioctl_acs_scan(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_OPER_CTRL)
+ status = wlan_uap_bss_ioctl_uap_oper_ctrl(pmadapter,
+ pioctl_req);
+ else if (bss->sub_command == MLAN_OID_UAP_ADD_STATION)
+ status = wlan_uap_bss_ioctl_add_station(pmadapter,
+ pioctl_req);
+ break;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case MLAN_IOCTL_SCAN:
+ pscan = (mlan_ds_scan *)pioctl_req->pbuf;
+ if ((pscan->sub_command == MLAN_OID_SCAN_NORMAL) &&
+ (pioctl_req->action == MLAN_ACT_GET)) {
+ PRINTM(MIOCTL, "Get scan table in uap\n");
+ pscan->param.scan_resp.pscan_table =
+ (t_u8 *)pmadapter->pscan_table;
+ pscan->param.scan_resp.num_in_scan_table =
+ pmadapter->num_in_scan_table;
+ pscan->param.scan_resp.age_in_secs =
+ pmadapter->age_in_secs;
+ pioctl_req->data_read_written =
+ sizeof(mlan_scan_resp) + MLAN_SUB_COMMAND_SIZE;
+ pscan->param.scan_resp.pchan_stats =
+ (t_u8 *)pmadapter->pchan_stats;
+ pscan->param.scan_resp.num_in_chan_stats =
+ pmadapter->num_in_chan_stats;
+ }
+ break;
+#endif
+ case MLAN_IOCTL_GET_INFO:
+ pget_info = (mlan_ds_get_info *)pioctl_req->pbuf;
+ if (pget_info->sub_command == MLAN_OID_GET_VER_EXT)
+ status = wlan_get_info_ver_ext(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_DEBUG_INFO)
+ status =
+ wlan_get_info_debug_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_STATS)
+ status = wlan_uap_get_stats(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_UAP_STATS_LOG)
+ status = wlan_uap_get_stats_log(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_UAP_STA_LIST)
+ status = wlan_uap_get_sta_list(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_BSS_INFO)
+ status = wlan_uap_get_bss_info(pmadapter, pioctl_req);
+ else if (pget_info->sub_command == MLAN_OID_GET_FW_INFO) {
+ pioctl_req->data_read_written =
+ sizeof(mlan_fw_info) + MLAN_SUB_COMMAND_SIZE;
+ memcpy_ext(pmadapter,
+ &pget_info->param.fw_info.mac_addr,
+ pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ pget_info->param.fw_info.fw_ver =
+ pmadapter->fw_release_number;
+ pget_info->param.fw_info.fw_bands = pmadapter->fw_bands;
+ pget_info->param.fw_info.ecsa_enable =
+ pmadapter->ecsa_enable;
+ pget_info->param.fw_info.getlog_enable =
+ pmadapter->getlog_enable;
+ pget_info->param.fw_info.hw_dev_mcs_support =
+ pmadapter->hw_dev_mcs_support;
+ pget_info->param.fw_info.hw_dot_11n_dev_cap =
+ pmadapter->hw_dot_11n_dev_cap;
+ pget_info->param.fw_info.usr_dev_mcs_support =
+ pmpriv->usr_dev_mcs_support;
+ if (IS_FW_SUPPORT_NO_80MHZ(pmadapter))
+ pget_info->param.fw_info.prohibit_80mhz = MTRUE;
+ else
+ pget_info->param.fw_info.prohibit_80mhz =
+ MFALSE;
+ pget_info->param.fw_info.hw_dot_11ac_mcs_support =
+ pmadapter->hw_dot_11ac_mcs_support;
+ pget_info->param.fw_info.hw_dot_11ac_dev_cap =
+ pmadapter->hw_dot_11ac_dev_cap;
+ pget_info->param.fw_info.usr_dot_11ac_dev_cap_bg =
+ pmpriv->usr_dot_11ac_dev_cap_bg;
+ pget_info->param.fw_info.usr_dot_11ac_mcs_support =
+ pmpriv->usr_dot_11ac_mcs_support;
+ pget_info->param.fw_info.usr_dot_11ac_dev_cap_a =
+ pmpriv->usr_dot_11ac_dev_cap_a;
+ pget_info->param.fw_info.hw_hecap_len =
+ pmadapter->hw_hecap_len;
+ pget_info->param.fw_info.hw_2g_hecap_len =
+ pmadapter->hw_2g_hecap_len;
+ memcpy_ext(pmadapter,
+ pget_info->param.fw_info.hw_he_cap,
+ pmadapter->hw_he_cap,
+ pmadapter->hw_hecap_len,
+ sizeof(pget_info->param.fw_info.hw_he_cap));
+ memcpy_ext(
+ pmadapter,
+ pget_info->param.fw_info.hw_2g_he_cap,
+ pmadapter->hw_2g_he_cap,
+ pmadapter->hw_2g_hecap_len,
+ sizeof(pget_info->param.fw_info.hw_2g_he_cap));
+ pget_info->param.fw_info.region_code =
+ pmadapter->region_code;
+ if (pmadapter->otp_region &&
+ pmadapter->otp_region->force_reg)
+ pget_info->param.fw_info.force_reg = MTRUE;
+ else
+ pget_info->param.fw_info.force_reg = MFALSE;
+ pget_info->param.fw_info.fw_supplicant_support =
+ IS_FW_SUPPORT_SUPPLICANT(pmadapter) ? 0x01 :
+ 0x00;
+ pget_info->param.fw_info.antinfo = pmadapter->antinfo;
+ pget_info->param.fw_info.max_ap_assoc_sta =
+ pmadapter->max_sta_conn;
+ } else if (pget_info->sub_command == MLAN_OID_LINK_STATS)
+ status = wlan_ioctl_link_statistic(pmpriv, pioctl_req);
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ misc = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ if (misc->sub_command == MLAN_OID_MISC_INIT_SHUTDOWN)
+ status = wlan_misc_ioctl_init_shutdown(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_SOFT_RESET)
+ status = wlan_uap_misc_ioctl_soft_reset(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_HOST_CMD)
+ status =
+ wlan_misc_ioctl_host_cmd(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_REGION)
+ status = wlan_misc_ioctl_region(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GEN_IE)
+ status = wlan_uap_misc_ioctl_gen_ie(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CUSTOM_IE)
+ status = wlan_misc_ioctl_custom_ie_list(
+ pmadapter, pioctl_req, MTRUE);
+ if (misc->sub_command == MLAN_OID_MISC_TX_DATAPAUSE)
+ status = wlan_uap_misc_ioctl_txdatapause(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RX_MGMT_IND)
+ status = wlan_reg_rx_mgmt_ind(pmadapter, pioctl_req);
+#ifdef DEBUG_LEVEL1
+ if (misc->sub_command == MLAN_OID_MISC_DRVDBG)
+ status = wlan_set_drvdbg(pmadapter, pioctl_req);
+#endif
+
+ if (misc->sub_command == MLAN_OID_MISC_TXCONTROL)
+ status = wlan_misc_ioctl_txcontrol(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_MAC_CONTROL)
+ status = wlan_misc_ioctl_mac_control(pmadapter,
+ pioctl_req);
+#ifdef RX_PACKET_COALESCE
+ if (misc->sub_command == MLAN_OID_MISC_RX_PACKET_COALESCE)
+ status = wlan_misc_ioctl_rx_pkt_coalesce_config(
+ pmadapter, pioctl_req);
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (misc->sub_command == MLAN_OID_MISC_WIFI_DIRECT_CONFIG)
+ status = wlan_misc_p2p_config(pmadapter, pioctl_req);
+#endif
+
+ if (misc->sub_command == MLAN_OID_MISC_DFS_REAPTER_MODE) {
+ mlan_ds_misc_cfg *misc_cfg = MNULL;
+
+ misc_cfg = (mlan_ds_misc_cfg *)pioctl_req->pbuf;
+ misc_cfg->param.dfs_repeater.mode =
+ pmadapter->dfs_repeater;
+ pioctl_req->data_read_written =
+ sizeof(mlan_ds_misc_dfs_repeater);
+
+ status = MLAN_STATUS_SUCCESS;
+ }
+ if (misc->sub_command == MLAN_OID_MISC_IND_RST_CFG)
+ status = wlan_misc_ioctl_ind_rst_cfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GET_TSF)
+ status = wlan_misc_ioctl_get_tsf(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GET_CHAN_REGION_CFG)
+ status = wlan_misc_chan_reg_cfg(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_OPER_CLASS_CHECK)
+ status = wlan_misc_ioctl_operclass_validation(
+ pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_OPER_CLASS)
+ status = wlan_misc_ioctl_oper_class(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_AGGR_CTRL)
+ status = wlan_misc_ioctl_aggr_ctrl(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_PER_PKT_CFG)
+ status = wlan_misc_per_pkt_cfg(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_FW_DUMP_EVENT)
+ status = wlan_misc_ioctl_fw_dump_event(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RX_ABORT_CFG)
+ status = wlan_misc_ioctl_rxabortcfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RX_ABORT_CFG_EXT)
+ status = wlan_misc_ioctl_rxabortcfg_ext(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_TX_AMPDU_PROT_MODE)
+ status = wlan_misc_ioctl_tx_ampdu_prot_mode(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG)
+ status = wlan_misc_ioctl_dot11mc_unassoc_ftm_cfg(
+ pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RATE_ADAPT_CFG)
+ status = wlan_misc_ioctl_rate_adapt_cfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CCK_DESENSE_CFG)
+ status = wlan_misc_ioctl_cck_desense_cfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_ROBUSTCOEX)
+ status = wlan_misc_robustcoex(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_DMCS_CONFIG)
+ status = wlan_misc_dmcs_config(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GET_TX_RX_HISTOGRAM)
+ status =
+ wlan_get_tx_rx_histogram(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CFP_INFO)
+ status = wlan_get_cfpinfo(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_BOOT_SLEEP)
+ status = wlan_misc_bootsleep(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_DYN_BW)
+ status = wlan_misc_ioctl_dyn_bw(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GET_CHAN_TRPC_CFG)
+ status = wlan_get_chan_trpc_cfg(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_BAND_STEERING)
+ status = wlan_misc_band_steering_cfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_BEACON_STUCK)
+ status = wlan_misc_beacon_stuck_cfg(pmadapter,
+ pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_GET_REGIONPWR_CFG)
+ status = wlan_get_rgchnpwr_cfg(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_CFP_TABLE)
+ status = wlan_get_cfp_table(pmadapter, pioctl_req);
+ if (misc->sub_command == MLAN_OID_MISC_RANGE_EXT)
+ status = wlan_misc_ioctl_range_ext(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_POWER_CFG:
+ power = (mlan_ds_power_cfg *)pioctl_req->pbuf;
+ if (power->sub_command == MLAN_OID_POWER_LOW_POWER_MODE)
+ status = wlan_power_ioctl_set_get_lpm(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_PM_CFG:
+ pm = (mlan_ds_pm_cfg *)pioctl_req->pbuf;
+ if (pm->sub_command == MLAN_OID_PM_CFG_PS_MODE)
+ status = wlan_uap_pm_ioctl_mode(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_DEEP_SLEEP)
+ status = wlan_uap_pm_ioctl_deepsleep(pmadapter,
+ pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_CFG_HS_CFG)
+ status = wlan_pm_ioctl_hscfg(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_HS_WAKEUP_REASON)
+ status = wlan_get_hs_wakeup_reason(pmadapter,
+ pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_MGMT_FILTER)
+ status = wlan_config_mgmt_filter(pmadapter, pioctl_req);
+ if (pm->sub_command == MLAN_OID_PM_INFO)
+ status = wlan_get_pm_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ snmp = (mlan_ds_snmp_mib *)pioctl_req->pbuf;
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_CTRL_DEAUTH)
+ status = wlan_uap_snmp_mib_ctrl_deauth(pmadapter,
+ pioctl_req);
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11D)
+ status = wlan_uap_snmp_mib_11d(pmadapter, pioctl_req);
+ if (snmp->sub_command == MLAN_OID_SNMP_MIB_DOT11H)
+ status = wlan_uap_snmp_mib_11h(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_SEC_CFG:
+ sec = (mlan_ds_sec_cfg *)pioctl_req->pbuf;
+ if (sec->sub_command == MLAN_OID_SEC_CFG_ENCRYPT_KEY)
+ status = wlan_uap_sec_ioctl_set_encrypt_key(pmadapter,
+ pioctl_req);
+ if (sec->sub_command == MLAN_OID_SEC_CFG_WAPI_ENABLED)
+ status = wlan_uap_sec_ioctl_wapi_enable(pmadapter,
+ pioctl_req);
+ if (sec->sub_command == MLAN_OID_SEC_CFG_REPORT_MIC_ERR)
+ status = wlan_uap_sec_ioctl_report_mic_error(
+ pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11N_CFG:
+ status = wlan_11n_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11D_CFG:
+ cfg11d = (mlan_ds_11d_cfg *)pioctl_req->pbuf;
+ if (cfg11d->sub_command == MLAN_OID_11D_DOMAIN_INFO)
+ status = wlan_uap_domain_info(pmadapter, pioctl_req);
+ else if (cfg11d->sub_command == MLAN_OID_11D_DOMAIN_INFO_EXT)
+ status =
+ wlan_11d_cfg_domain_info(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ cfg11h = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
+ if (cfg11h->sub_command == MLAN_OID_11H_CHANNEL_CHECK)
+ status = wlan_uap_11h_channel_check_req(pmadapter,
+ pioctl_req);
+ if (cfg11h->sub_command == MLAN_OID_11H_DFS_TESTING)
+ status = wlan_11h_ioctl_dfs_testing(pmadapter,
+ pioctl_req);
+ if (cfg11h->sub_command == MLAN_OID_11H_CHAN_NOP_INFO)
+ status = wlan_11h_ioctl_get_channel_nop_info(
+ pmadapter, pioctl_req);
+ if (cfg11h->sub_command == MLAN_OID_11H_CHAN_REPORT_REQUEST)
+ status = wlan_11h_ioctl_dfs_chan_report(pmpriv,
+ pioctl_req);
+ if (cfg11h->sub_command == MLAN_OID_11H_CHAN_SWITCH_COUNT)
+ status = wlan_11h_ioctl_chan_switch_count(pmadapter,
+ pioctl_req);
+ if (cfg11h->sub_command == MLAN_OID_11H_DFS_W53_CFG)
+ status = wlan_11h_ioctl_dfs_w53_cfg(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ radiocfg = (mlan_ds_radio_cfg *)pioctl_req->pbuf;
+ if (radiocfg->sub_command == MLAN_OID_MIMO_SWITCH)
+ status = wlan_radio_ioctl_mimo_switch_cfg(pmadapter,
+ pioctl_req);
+ if (radiocfg->sub_command == MLAN_OID_RADIO_CTRL)
+ status = wlan_radio_ioctl_radio_ctl(pmadapter,
+ pioctl_req);
+ if (radiocfg->sub_command == MLAN_OID_REMAIN_CHAN_CFG)
+ status = wlan_radio_ioctl_remain_chan_cfg(pmadapter,
+ pioctl_req);
+ if (radiocfg->sub_command == MLAN_OID_ANT_CFG)
+ status =
+ wlan_radio_ioctl_ant_cfg(pmadapter, pioctl_req);
+ if (radiocfg->sub_command == MLAN_OID_BAND_CFG)
+ status = wlan_radio_ioctl_band_cfg(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_RATE:
+ rate = (mlan_ds_rate *)pioctl_req->pbuf;
+ if (rate->sub_command == MLAN_OID_RATE_CFG)
+ status = wlan_rate_ioctl_cfg(pmadapter, pioctl_req);
+ else if (rate->sub_command == MLAN_OID_GET_DATA_RATE)
+ status = wlan_rate_ioctl_get_data_rate(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_11AC_CFG:
+ status = wlan_11ac_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_11AX_CFG:
+ status = wlan_11ax_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ case MLAN_IOCTL_REG_MEM:
+ reg_mem = (mlan_ds_reg_mem *)pioctl_req->pbuf;
+ if (reg_mem->sub_command == MLAN_OID_REG_RW)
+ status = wlan_reg_mem_ioctl_reg_rw(pmadapter,
+ pioctl_req);
+ else if (reg_mem->sub_command == MLAN_OID_EEPROM_RD)
+ status = wlan_reg_mem_ioctl_read_eeprom(pmadapter,
+ pioctl_req);
+ else if (reg_mem->sub_command == MLAN_OID_MEM_RW)
+ status = wlan_reg_mem_ioctl_mem_rw(pmadapter,
+ pioctl_req);
+ break;
+ case MLAN_IOCTL_WMM_CFG:
+ status = wlan_wmm_cfg_ioctl(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ break;
+ }
+ LEAVE();
+ return status;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_txrx.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_txrx.c
new file mode 100644
index 000000000000..5ea637fa26d8
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_uap_txrx.c
@@ -0,0 +1,820 @@
+/** @file mlan_uap_txrx.c
+ *
+ * @brief This file contains AP mode transmit and receive functions
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/05/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_main.h"
+#include "mlan_uap.h"
+#include "mlan_wmm.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+#include "authenticator_api.h"
+#endif
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_upload_uap_rx_packet(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef DEBUG_LEVEL1
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+#endif
+ PRxPD prx_pd;
+ ENTER();
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", (t_u8 *)prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *)prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING)
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+#ifdef USB
+ else if (IS_USB(pmadapter->card_type))
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ MNULL,
+ pmadapter->rx_data_ep,
+ ret);
+#endif
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function will check if unicast packet need be dropped
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac mac address to find in station list table
+ *
+ * @return MLAN_STATUS_FAILURE -- drop packet, otherwise forward to
+ * network stack
+ */
+static mlan_status wlan_check_unicast_packet(mlan_private *priv, t_u8 *mac)
+{
+ int j;
+ sta_node *sta_ptr = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_private pmpriv = MNULL;
+ t_u8 pkt_type = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ for (j = 0; j < MLAN_MAX_BSS_NUM; ++j) {
+ pmpriv = pmadapter->priv[j];
+ if (pmpriv) {
+ if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
+ continue;
+ sta_ptr = wlan_get_station_entry(pmpriv, mac);
+ if (sta_ptr) {
+ if (pmpriv == priv)
+ pkt_type = PKT_INTRA_UCAST;
+ else
+ pkt_type = PKT_INTER_UCAST;
+ break;
+ }
+ }
+ }
+ if ((pkt_type == PKT_INTRA_UCAST) &&
+ (priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) {
+ PRINTM(MDATA, "Drop INTRA_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ } else if ((pkt_type == PKT_INTER_UCAST) &&
+ (priv->pkt_fwd & PKT_FWD_INTER_UCAST)) {
+ PRINTM(MDATA, "Drop INTER_UCAST packet\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function fill the txpd for tx packet
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param pmbuf A pointer to the mlan_buffer for process
+ *
+ * @return headptr or MNULL
+ */
+t_void *wlan_ops_uap_process_txpd(t_void *priv, pmlan_buffer pmbuf)
+{
+ pmlan_private pmpriv = (pmlan_private)priv;
+ TxPD *plocal_tx_pd;
+ t_u8 *head_ptr = MNULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+ t_u8 dst_mac[MLAN_MAC_ADDR_LENGTH];
+
+ ENTER();
+
+ if (!pmbuf->data_len) {
+ PRINTM(MERROR, "uAP Tx Error: Invalid packet length: %d\n",
+ pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ memcpy_ext(pmpriv->adapter, &pkt_type,
+ pmbuf->pbuf + pmbuf->data_offset, sizeof(pkt_type),
+ sizeof(pkt_type));
+ memcpy_ext(pmpriv->adapter, &tx_control,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ sizeof(tx_control), sizeof(tx_control));
+ pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
+ pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
+ }
+ if (pmbuf->data_offset <
+ (sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT)) {
+ PRINTM(MERROR,
+ "not enough space for TxPD: headroom=%d pkt_len=%d, required=%d\n",
+ pmbuf->data_offset, pmbuf->data_len,
+ sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT);
+ DBG_HEXDUMP(MDAT_D, "drop pkt",
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ goto done;
+ }
+
+ /* head_ptr should be aligned */
+ head_ptr = pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) -
+ pmpriv->intf_hr_len;
+ head_ptr = (t_u8 *)((t_ptr)head_ptr & ~((t_ptr)(DMA_ALIGNMENT - 1)));
+
+ plocal_tx_pd = (TxPD *)(head_ptr + pmpriv->intf_hr_len);
+ memset(pmpriv->adapter, plocal_tx_pd, 0, sizeof(TxPD));
+
+ /* Set the BSS number to TxPD */
+ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
+ plocal_tx_pd->bss_type = pmpriv->bss_type;
+
+ plocal_tx_pd->tx_pkt_length = (t_u16)pmbuf->data_len;
+
+ plocal_tx_pd->priority = (t_u8)pmbuf->priority;
+ plocal_tx_pd->pkt_delay_2ms =
+ wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
+
+ if (plocal_tx_pd->priority <
+ NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ plocal_tx_pd->tx_control =
+ pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
+
+ if (pmbuf->flags & MLAN_BUF_FLAG_TX_STATUS) {
+ plocal_tx_pd->tx_control_1 |= pmbuf->tx_seq_num << 8;
+ plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS;
+ }
+
+ /* Offset of actual data */
+ plocal_tx_pd->tx_pkt_offset = (t_u16)(
+ (t_ptr)pmbuf->pbuf + pmbuf->data_offset - (t_ptr)plocal_tx_pd);
+
+ if (!plocal_tx_pd->tx_control) {
+ /* TxCtrl set by user or default */
+ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
+ }
+
+ if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ plocal_tx_pd->tx_pkt_type = (t_u16)pkt_type;
+ plocal_tx_pd->tx_control = tx_control;
+ }
+ if (pmbuf->flags & MLAN_BUF_FLAG_TX_CTRL) {
+ if (pmbuf->u.tx_info.data_rate) {
+ memcpy_ext(pmpriv->adapter, dst_mac,
+ pmbuf->pbuf + pmbuf->data_offset,
+ sizeof(dst_mac), sizeof(dst_mac));
+ plocal_tx_pd->tx_control |=
+ (wlan_ieee_rateid_to_mrvl_rateid(
+ pmpriv, pmbuf->u.tx_info.data_rate,
+ dst_mac)
+ << 16);
+ plocal_tx_pd->tx_control |= TXPD_TXRATE_ENABLE;
+ }
+ plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.channel << 21;
+ if (pmbuf->u.tx_info.bw) {
+ plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.bw << 16;
+ plocal_tx_pd->tx_control_1 |= TXPD_BW_ENABLE;
+ }
+ if (pmbuf->u.tx_info.tx_power.tp.hostctl)
+ plocal_tx_pd->tx_control |=
+ (t_u32)pmbuf->u.tx_info.tx_power.val;
+ if (pmbuf->u.tx_info.retry_limit) {
+ plocal_tx_pd->tx_control |= pmbuf->u.tx_info.retry_limit
+ << 8;
+ plocal_tx_pd->tx_control |= TXPD_RETRY_ENABLE;
+ }
+ }
+
+ endian_convert_TxPD(plocal_tx_pd);
+
+ /* Adjust the data offset and length to include TxPD in pmbuf */
+ pmbuf->data_len += pmbuf->data_offset;
+ pmbuf->data_offset = (t_u32)((t_ptr)head_ptr - (t_ptr)pmbuf->pbuf);
+ pmbuf->data_len -= pmbuf->data_offset;
+
+done:
+ LEAVE();
+ return head_ptr;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_ops_uap_process_rx_packet(t_void *adapter, pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter)adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ wlan_mgmt_pkt *puap_pkt_hdr = MNULL;
+
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ sta_node *sta_ptr = MNULL;
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ t_u8 eapol_type[2] = {0x88, 0x8e};
+#endif
+ t_u16 adj_rx_rate = 0;
+ t_u8 antenna = 0;
+
+ t_u32 last_rx_sec = 0;
+ t_u32 last_rx_usec = 0;
+ t_u8 ext_rate_info = 0;
+
+ ENTER();
+
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+
+ if (priv->rx_pkt_info) {
+ ext_rate_info = (t_u8)(prx_pd->rx_info >> 16);
+ pmbuf->u.rx_info.data_rate =
+ wlan_index_to_data_rate(priv->adapter, prx_pd->rx_rate,
+ prx_pd->rate_info,
+ ext_rate_info);
+ pmbuf->u.rx_info.channel =
+ (prx_pd->rx_info & RXPD_CHAN_MASK) >> 5;
+ pmbuf->u.rx_info.antenna = prx_pd->antenna;
+ pmbuf->u.rx_info.rssi = prx_pd->snr - prx_pd->nf;
+ }
+
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *)((t_u8 *)prx_pd + prx_pd->rx_pkt_offset);
+
+ PRINTM(MINFO,
+ "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) !=
+ (t_u16)pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to
+ * forwarded to app as an event
+ */
+ puap_pkt_hdr = (wlan_mgmt_pkt *)((t_u8 *)prx_pd +
+ prx_pd->rx_pkt_offset);
+ puap_pkt_hdr->frm_len = wlan_le16_to_cpu(puap_pkt_hdr->frm_len);
+ if ((puap_pkt_hdr->wlan_header.frm_ctl &
+ IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(
+ pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *)&puap_pkt_hdr->wlan_header,
+ puap_pkt_hdr->frm_len + sizeof(wlan_mgmt_pkt) -
+ sizeof(puap_pkt_hdr->frm_len),
+ (RxPD *)prx_pd);
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ if (rx_pkt_type != PKT_TYPE_BAR) {
+ priv->rxpd_rate = prx_pd->rx_rate;
+ priv->rxpd_rate_info = prx_pd->rate_info;
+ priv->rxpd_rx_info = (t_u8)(prx_pd->rx_info >> 16);
+
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ antenna = wlan_adjust_antenna(priv, (RxPD *)prx_pd);
+ adj_rx_rate = wlan_adjust_data_rate(
+ priv, priv->rxpd_rate, priv->rxpd_rate_info);
+ pmadapter->callbacks.moal_hist_data_add(
+ pmadapter->pmoal_handle, pmbuf->bss_index,
+ adj_rx_rate, prx_pd->snr, prx_pd->nf, antenna);
+ }
+ }
+
+ sta_ptr = wlan_get_station_entry(priv, prx_pkt->eth803_hdr.src_addr);
+ if (sta_ptr) {
+ sta_ptr->snr = prx_pd->snr;
+ sta_ptr->nf = prx_pd->nf;
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &last_rx_sec, &last_rx_usec);
+ sta_ptr->stats.last_rx_in_msec =
+ (t_u64)last_rx_sec * 1000 + (t_u64)last_rx_usec / 1000;
+ }
+
+#ifdef DRV_EMBEDDED_AUTHENTICATOR
+ /**process eapol packet for uap*/
+ if (IsAuthenticatorEnabled(priv->psapriv) &&
+ (!memcmp(pmadapter, &prx_pkt->eth803_hdr.h803_len, eapol_type,
+ sizeof(eapol_type)))) {
+ ret = AuthenticatorProcessEapolPacket(
+ priv->psapriv, ((t_u8 *)prx_pd + prx_pd->rx_pkt_offset),
+ prx_pd->rx_pkt_length);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ }
+#endif
+
+ pmbuf->priority = prx_pd->priority;
+ memcpy_ext(pmadapter, ta, prx_pkt->eth803_hdr.src_addr,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID)) {
+ sta_ptr = wlan_get_station_entry(priv, ta);
+ if (sta_ptr) {
+ sta_ptr->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ sta_ptr->snr = prx_pd->snr;
+ sta_ptr->nf = prx_pd->nf;
+ }
+ }
+ /* check if UAP enable 11n */
+ if (!priv->is_11n_enabled ||
+ (!wlan_11n_get_rxreorder_tbl((mlan_private *)priv, prx_pd->priority,
+ ta) &&
+ (prx_pd->rx_pkt_type != PKT_TYPE_AMSDU))) {
+ if (priv->pkt_fwd)
+ wlan_process_uap_rx_packet(priv, pmbuf);
+ else
+ wlan_upload_uap_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+ /* Reorder and send to OS */
+ ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num, prx_pd->priority,
+ ta, (t_u8)prx_pd->rx_pkt_type,
+ (void *)pmbuf);
+ if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_uap_recv_packet(mlan_private *priv, pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pkt = (RxPacketHdr_t *)((t_u8 *)pmbuf->pbuf + pmbuf->data_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uap_recv_packet", pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MDATA, "AMSDU dest " MACSTR "\n",
+ MAC2STR(prx_pkt->eth803_hdr.dest_addr));
+
+ /* don't do packet forwarding in disconnected state */
+ if ((priv->media_connected == MFALSE) ||
+ (pmbuf->data_len > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ newbuf =
+ wlan_alloc_mlan_buffer(pmadapter,
+ MLAN_TX_DATA_BUF_SIZE_2K,
+ 0, MOAL_MALLOC_BUFFER);
+ if (newbuf) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(TxPD) + priv->intf_hr_len +
+ DMA_ALIGNMENT);
+ util_scalar_increment(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy_ext(pmadapter,
+ (t_u8 *)newbuf->pbuf +
+ newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len,
+ MLAN_TX_DATA_BUF_SIZE_2K);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock) >
+ RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv,
+ prx_pkt->eth803_hdr.dest_addr))) {
+ /* Intra BSS packet */
+ newbuf =
+ wlan_alloc_mlan_buffer(pmadapter,
+ MLAN_TX_DATA_BUF_SIZE_2K,
+ 0, MOAL_MALLOC_BUFFER);
+ if (newbuf) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(TxPD) + priv->intf_hr_len +
+ DMA_ALIGNMENT);
+ util_scalar_increment(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data */
+ memcpy_ext(pmadapter,
+ (t_u8 *)newbuf->pbuf +
+ newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len,
+ MLAN_TX_DATA_BUF_SIZE_2K);
+ newbuf->data_len = pmbuf->data_len;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock) >
+ RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(
+ priv, prx_pkt->eth803_hdr.dest_addr)) {
+ /* drop packet */
+ PRINTM(MDATA, "Drop AMSDU dest " MACSTR "\n",
+ MAC2STR(prx_pkt->eth803_hdr.dest_addr));
+ goto done;
+ }
+ }
+upload:
+ /** send packet to moal */
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ pmbuf);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer or send back to firmware
+ *
+ * @param priv A pointer to mlan_private
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_process_uap_rx_packet(mlan_private *priv, pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_buffer newbuf = MNULL;
+
+ ENTER();
+
+ prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *)((t_u8 *)prx_pd + prx_pd->rx_pkt_offset);
+
+ DBG_HEXDUMP(MDAT_D, "uAP RxPD", prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
+ ((t_u8 *)prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ PRINTM(MINFO,
+ "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+ PRINTM(MDATA, "Rx dest " MACSTR "\n",
+ MAC2STR(prx_pkt->eth803_hdr.dest_addr));
+
+ /* don't do packet forwarding in disconnected state */
+ /* don't do packet forwarding when packet > 1514 */
+ if ((priv->media_connected == MFALSE) ||
+ ((pmbuf->data_len - prx_pd->rx_pkt_offset) > MV_ETH_FRAME_LEN))
+ goto upload;
+
+ if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
+ if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
+ /* Multicast pkt */
+ newbuf =
+ wlan_alloc_mlan_buffer(pmadapter,
+ MLAN_TX_DATA_BUF_SIZE_2K,
+ 0, MOAL_MALLOC_BUFFER);
+ if (newbuf) {
+ newbuf->bss_index = pmbuf->bss_index;
+ newbuf->buf_type = pmbuf->buf_type;
+ newbuf->priority = pmbuf->priority;
+ newbuf->in_ts_sec = pmbuf->in_ts_sec;
+ newbuf->in_ts_usec = pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(TxPD) + priv->intf_hr_len +
+ DMA_ALIGNMENT);
+ util_scalar_increment(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data, skip rxpd */
+ memcpy_ext(pmadapter,
+ (t_u8 *)newbuf->pbuf +
+ newbuf->data_offset,
+ pmbuf->pbuf + pmbuf->data_offset +
+ prx_pd->rx_pkt_offset,
+ pmbuf->data_len -
+ prx_pd->rx_pkt_offset,
+ MLAN_TX_DATA_BUF_SIZE_2K);
+ newbuf->data_len =
+ pmbuf->data_len - prx_pd->rx_pkt_offset;
+ wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock) >
+ RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ wlan_recv_event(
+ priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ }
+ } else {
+ if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
+ (wlan_get_station_entry(priv,
+ prx_pkt->eth803_hdr.dest_addr))) {
+ /* Forwarding Intra-BSS packet */
+#ifdef USB
+ if (IS_USB(pmadapter->card_type)) {
+ if (pmbuf->flags & MLAN_BUF_FLAG_RX_DEAGGR) {
+ newbuf = wlan_alloc_mlan_buffer(
+ pmadapter,
+ MLAN_TX_DATA_BUF_SIZE_2K, 0,
+ MOAL_MALLOC_BUFFER);
+ if (newbuf) {
+ newbuf->bss_index =
+ pmbuf->bss_index;
+ newbuf->buf_type =
+ pmbuf->buf_type;
+ newbuf->priority =
+ pmbuf->priority;
+ newbuf->in_ts_sec =
+ pmbuf->in_ts_sec;
+ newbuf->in_ts_usec =
+ pmbuf->in_ts_usec;
+ newbuf->data_offset =
+ (sizeof(TxPD) +
+ priv->intf_hr_len +
+ DMA_ALIGNMENT);
+ util_scalar_increment(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks
+ .moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock);
+ newbuf->flags |=
+ MLAN_BUF_FLAG_BRIDGE_BUF;
+
+ /* copy the data, skip rxpd */
+ memcpy_ext(
+ pmadapter,
+ (t_u8 *)newbuf->pbuf +
+ newbuf->data_offset,
+ pmbuf->pbuf +
+ pmbuf->data_offset +
+ prx_pd->rx_pkt_offset,
+ pmbuf->data_len -
+ prx_pd->rx_pkt_offset,
+ pmbuf->data_len -
+ prx_pd->rx_pkt_offset);
+ newbuf->data_len =
+ pmbuf->data_len -
+ prx_pd->rx_pkt_offset;
+ wlan_wmm_add_buf_txqueue(
+ pmadapter, newbuf);
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks
+ .moal_spin_lock,
+ pmadapter->callbacks
+ .moal_spin_unlock) >
+ RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ wlan_recv_event(
+ priv,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ }
+ pmadapter->callbacks.moal_recv_complete(
+ pmadapter->pmoal_handle, pmbuf,
+ pmadapter->rx_data_ep, ret);
+ goto done;
+ }
+ }
+#endif
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
+ util_scalar_increment(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock);
+ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &pmadapter->pending_bridge_pkts,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock) >
+ RX_HIGH_THRESHOLD)
+ wlan_drop_tx_pkts(priv);
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
+ MNULL);
+ goto done;
+ } else if (MLAN_STATUS_FAILURE ==
+ wlan_check_unicast_packet(
+ priv, prx_pkt->eth803_hdr.dest_addr)) {
+ PRINTM(MDATA, "Drop Pkts: Rx dest " MACSTR "\n",
+ MAC2STR(prx_pkt->eth803_hdr.dest_addr));
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+ goto done;
+ }
+ }
+
+upload:
+ /* Chop off RxPD */
+ pmbuf->data_len -= prx_pd->rx_pkt_offset;
+ pmbuf->data_offset += prx_pd->rx_pkt_offset;
+ pmbuf->pparent = MNULL;
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
+ pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "uAP Rx Error: moal_recv_packet returned error\n");
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ }
+
+ if (ret != MLAN_STATUS_PENDING)
+ pmadapter->ops.data_complete(pmadapter, pmbuf, ret);
+#ifdef USB
+ else if (IS_USB(pmadapter->card_type))
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
+ MNULL,
+ pmadapter->rx_data_ep,
+ ret);
+#endif
+done:
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_usb.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_usb.c
new file mode 100644
index 000000000000..5a5f2d8aa71e
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_usb.c
@@ -0,0 +1,1264 @@
+/** @file mlan_usb.c
+ *
+ * @brief This file contains USB specific code
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 04/21/2009: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_init.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef USB8897
+static const struct _mlan_card_info mlan_card_info_usb8897 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 0,
+ .supp_ps_handshake = 1,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef USB8997
+static const struct _mlan_card_info mlan_card_info_usb8997 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 1,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef USB8978
+static const struct _mlan_card_info mlan_card_info_usb8978 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .supp_ps_handshake = 1,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef USB9098
+static const struct _mlan_card_info mlan_card_info_usb9098 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .supp_ps_handshake = 1,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+#ifdef USB9097
+static const struct _mlan_card_info mlan_card_info_usb9097 = {
+ .max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .supp_ps_handshake = 1,
+ .default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
+};
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+#if defined(USB9098)
+/**
+ * @This function checks the chip revision id
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param rev_id A pointer to chip revision id
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_usb_check_revision(mlan_adapter *pmadapter, t_u32 *rev_id)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ mlan_buffer mbuf;
+ t_u8 *tx_buff = MNULL;
+ t_u8 *recv_buff = MNULL;
+ t_u8 tx_size = 16;
+ FWSyncPkt syncpkt;
+
+ ENTER();
+ /* Allocate memory for transmit */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_TX_BUF_SIZE,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&tx_buff);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tx_buff) {
+ PRINTM(MERROR, "Could not allocate buffer for FW download\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Allocate memory for receive */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_RX_BUF_SIZE,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, &recv_buff);
+ if ((ret != MLAN_STATUS_SUCCESS) || !recv_buff) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for FW download response\n");
+ goto cleanup;
+ }
+ memset(pmadapter, &syncpkt, 0, sizeof(FWSyncPkt));
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)tx_buff;
+ mbuf.data_len = tx_size;
+ ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->tx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "check revision: write_data failed, ret %d\n",
+ ret);
+ goto cleanup;
+ }
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)recv_buff;
+ mbuf.data_len = 2048;
+ ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
+ pmadapter->rx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "check revision: read_data failed, ret %d\n",
+ ret);
+ goto cleanup;
+ }
+ memcpy_ext(pmadapter, &syncpkt, recv_buff, sizeof(syncpkt),
+ sizeof(syncpkt));
+ syncpkt.chip_rev = wlan_le32_to_cpu(syncpkt.chip_rev);
+ *rev_id = syncpkt.chip_rev & 0x000000ff;
+ PRINTM(MERROR, "chip_revision_id = %d\n", syncpkt.chip_rev);
+cleanup:
+ if (recv_buff)
+ pcb->moal_mfree(pmadapter->pmoal_handle, recv_buff);
+ if (tx_buff)
+ pcb->moal_mfree(pmadapter->pmoal_handle, tx_buff);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function downloads FW blocks to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter,
+ pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ t_u8 *firmware = pmfw->pfw_buf, *RecvBuff;
+ t_u32 retries = MAX_FW_RETRY, DataLength;
+ t_u32 FWSeqNum = 0, TotalBytes = 0, DnldCmd = 0;
+ t_u8 *TxBuff = MNULL;
+ FWData *fwdata = MNULL;
+ FWSyncHeader SyncFWHeader;
+ t_u8 check_winner = 1;
+ t_u8 check_fw_status = MFALSE;
+ t_u8 mic_retry = MAX_FW_RETRY;
+#if defined(USB9098)
+ t_u32 revision_id = 0;
+#endif
+
+ ENTER();
+
+ if (!firmware && !pcb->moal_get_fw_data) {
+ PRINTM(MMSG, "No firmware image found! Terminating download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto fw_exit;
+ }
+
+ /* Allocate memory for transmit */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_TX_BUF_SIZE,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&TxBuff);
+ if ((ret != MLAN_STATUS_SUCCESS) || !TxBuff) {
+ PRINTM(MERROR, "Could not allocate buffer for FW download\n");
+ goto fw_exit;
+ }
+ fwdata = (FWData *)TxBuff;
+
+ /* Allocate memory for receive */
+ ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_RX_BUF_SIZE,
+ MLAN_MEM_DEF | MLAN_MEM_DMA, &RecvBuff);
+ if ((ret != MLAN_STATUS_SUCCESS) || !RecvBuff) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for FW download response\n");
+ goto cleanup;
+ }
+
+ if (!IS_USB_NEW_INIT(pmadapter->feature_control))
+ check_winner = 0;
+#if defined(USB9098)
+ if (IS_USB9098(pmadapter->card_type)) {
+ ret = wlan_usb_check_revision(pmadapter, &revision_id);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to get USB chip revision ID\n");
+ goto cleanup;
+ }
+ /* Skyhawk A0, need to check both CRC and MIC error */
+ if (revision_id >= CHIP_9098_REV_A0)
+ check_fw_status = MTRUE;
+ }
+#endif
+#if defined(USB9097)
+ if (IS_USB9097(pmadapter->card_type))
+ check_fw_status = MTRUE;
+#endif
+ do {
+ /* Send pseudo data to check winner status first */
+ if (check_winner) {
+ memset(pmadapter, &fwdata->fw_header, 0,
+ sizeof(FWHeader));
+ DataLength = 0;
+ } else {
+ /* Copy the header of the firmware data to get the
+ * length */
+ if (firmware)
+ memcpy_ext(pmadapter, &fwdata->fw_header,
+ &firmware[TotalBytes],
+ sizeof(FWHeader),
+ sizeof(fwdata->fw_header));
+ else
+ pcb->moal_get_fw_data(
+ pmadapter->pmoal_handle, TotalBytes,
+ sizeof(FWHeader),
+ (t_u8 *)&fwdata->fw_header);
+
+ DataLength =
+ wlan_le32_to_cpu(fwdata->fw_header.data_length);
+ DnldCmd = wlan_le32_to_cpu(fwdata->fw_header.dnld_cmd);
+ TotalBytes += sizeof(FWHeader);
+
+ /** CMD 7 don't have data_length field */
+ if (DnldCmd == FW_CMD_4 || DnldCmd == FW_CMD_6 ||
+ DnldCmd == FW_CMD_7 || DnldCmd == FW_CMD_10)
+ DataLength = 0;
+
+ if (DataLength >
+ (FW_DNLD_TX_BUF_SIZE - sizeof(FWHeader))) {
+ PRINTM(MERROR,
+ "Invalid Data Legth read from FW\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ /* Copy the firmware data */
+ if (firmware)
+ memcpy_ext(pmadapter, fwdata->data,
+ &firmware[TotalBytes], DataLength,
+ DataLength);
+ else
+ pcb->moal_get_fw_data(pmadapter->pmoal_handle,
+ TotalBytes, DataLength,
+ (t_u8 *)fwdata->data);
+
+ fwdata->seq_num = wlan_cpu_to_le32(FWSeqNum);
+ TotalBytes += DataLength;
+ }
+ /* If the send/receive fails or CRC occurs then retry */
+ while (retries) {
+ mlan_buffer mbuf;
+ int length = FW_DATA_XMIT_SIZE;
+ retries--;
+
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)fwdata;
+ mbuf.data_len = length;
+ /* Send the firmware block */
+ ret = pcb->moal_write_data_sync(
+ pmadapter->pmoal_handle, &mbuf,
+ pmadapter->tx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "fw_dnld: write_data failed, ret %d\n",
+ ret);
+ continue;
+ }
+
+ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = RecvBuff;
+ mbuf.data_len = FW_DNLD_RX_BUF_SIZE;
+
+ /* Receive the firmware block response */
+ ret = pcb->moal_read_data_sync(
+ pmadapter->pmoal_handle, &mbuf,
+ pmadapter->rx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "fw_dnld: read_data failed, ret %d\n",
+ ret);
+ continue;
+ }
+ memcpy_ext(pmadapter, &SyncFWHeader, RecvBuff,
+ sizeof(FWSyncHeader), sizeof(SyncFWHeader));
+ endian_convert_syncfwheader(&SyncFWHeader);
+ /* Check the first firmware block response for highest
+ * bit set */
+ if (check_winner) {
+ if (SyncFWHeader.cmd & 0x80000000) {
+ PRINTM(MMSG,
+ "USB is not the winner 0x%x, returning success\n",
+ SyncFWHeader.cmd);
+ ret = MLAN_STATUS_SUCCESS;
+ goto cleanup;
+ }
+ PRINTM(MINFO,
+ "USB is the winner, start to download FW\n");
+ check_winner = 0;
+ break;
+ }
+
+ /* Check the firmware block response for CRC errors */
+ if (SyncFWHeader.cmd) {
+ /* Check firmware block response for CRC and MIC
+ * errors */
+ if (check_fw_status) {
+ if (SyncFWHeader.status & MBIT(0)) {
+ PRINTM(MERROR,
+ "FW received Blk with CRC error 0x%x offset=%d\n",
+ SyncFWHeader.status,
+ SyncFWHeader.offset);
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+ if (SyncFWHeader.status &
+ (MBIT(6) | MBIT(7))) {
+ PRINTM(MERROR,
+ "FW received Blk with MIC error 0x%x offset\n",
+ SyncFWHeader.status,
+ SyncFWHeader.offset);
+ mic_retry--;
+ FWSeqNum = 0;
+ TotalBytes = 0;
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+ } else {
+ PRINTM(MERROR,
+ "FW received Blk with CRC error 0x%x\n",
+ SyncFWHeader.cmd);
+ ret = MLAN_STATUS_FAILURE;
+ continue;
+ }
+ }
+
+ retries = MAX_FW_RETRY;
+ break;
+ }
+
+ FWSeqNum++;
+ PRINTM(MINFO, ".\n");
+
+ } while ((DnldCmd != FW_HAS_LAST_BLOCK) && retries && mic_retry);
+
+cleanup:
+ PRINTM(MMSG, "fw_dnld: %d bytes downloaded\n", TotalBytes);
+
+ if (RecvBuff)
+ pcb->moal_mfree(pmadapter->pmoal_handle, RecvBuff);
+ if (TxBuff)
+ pcb->moal_mfree(pmadapter->pmoal_handle, TxBuff);
+ if (retries && mic_retry) {
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+fw_exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get number of packets when deaggregated
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pdata A pointer to packet data
+ * @param aggr_pkt_len Aggregate packet length
+ *
+ * @return Number of packets
+ */
+static int wlan_usb_deaggr_rx_num_pkts(pmlan_adapter pmadapter, t_u8 *pdata,
+ int aggr_pkt_len)
+{
+ int pkt_count = 0, pkt_len;
+ RxPD *prx_pd;
+
+ ENTER();
+ while (aggr_pkt_len >= sizeof(RxPD)) {
+ prx_pd = (RxPD *)pdata;
+ pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
+ wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
+ if (pkt_len == 0) /* blank RxPD can be at the end */
+ break;
+
+ ++pkt_count;
+ if (aggr_pkt_len == pkt_len) /* last packet has no padding */
+ break;
+
+ /* skip padding and goto next */
+ if (pkt_len %
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_align)
+ pkt_len +=
+ (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl
+ .aggr_align -
+ (pkt_len % pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align));
+ aggr_pkt_len -= pkt_len;
+ pdata += pkt_len;
+ }
+ LEAVE();
+ return pkt_count;
+}
+
+static inline t_u32 usb_tx_aggr_pad_len(t_u32 len,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ return (len % pusb_tx_aggr->aggr_ctrl.aggr_align) ?
+ (len + (pusb_tx_aggr->aggr_ctrl.aggr_align -
+ (len % pusb_tx_aggr->aggr_ctrl.aggr_align))) :
+ len;
+}
+
+/**
+ * @brief Copy pmbuf to aggregation buffer
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param pmbuf_aggr Pointer to aggregation buffer
+ * @param pmbuf Pointer to buffer to copy
+ * @param pusb_tx_aggr Pointer to usb_tx_aggr_params
+ *
+ * @return N/A
+ */
+static inline t_void
+wlan_usb_tx_copy_buf_to_aggr(pmlan_adapter pmadapter, pmlan_buffer pmbuf_aggr,
+ pmlan_buffer pmbuf,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ ENTER();
+ pmbuf_aggr->data_len =
+ usb_tx_aggr_pad_len(pmbuf_aggr->data_len, pusb_tx_aggr);
+ memcpy_ext(pmadapter,
+ pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
+ pmbuf_aggr->data_len,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len,
+ pmbuf->data_len);
+ pmbuf_aggr->data_len += pmbuf->data_len;
+ LEAVE();
+}
+
+#define MLAN_TYPE_AGGR_DATA_V2 11
+/**
+ * @brief Copy pmbuf to aggregation buffer
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param pmbuf_aggr Pointer to aggregation buffer
+ * @param pmbuf Pointer to buffer to copy
+ * @param last last packet flag
+ * @param pusb_tx_aggr Pointer to usb_tx_aggr_params
+ *
+ * @return N/A
+ */
+static inline t_void
+wlan_usb_tx_copy_buf_to_aggr_v2(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf_aggr, pmlan_buffer pmbuf,
+ t_u8 last, usb_tx_aggr_params *pusb_tx_aggr)
+{
+ t_u8 *payload;
+ t_u16 offset;
+
+ ENTER();
+ pmbuf_aggr->data_len =
+ usb_tx_aggr_pad_len(pmbuf_aggr->data_len, pusb_tx_aggr);
+ memcpy_ext(pmadapter,
+ pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
+ pmbuf_aggr->data_len,
+ pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len,
+ pmbuf->data_len);
+ payload = pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
+ pmbuf_aggr->data_len;
+ if (last) {
+ offset = pmbuf->data_len;
+ *(t_u16 *)&payload[2] =
+ wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2 | 0x80);
+ } else {
+ offset = usb_tx_aggr_pad_len(pmbuf->data_len, pusb_tx_aggr);
+ *(t_u16 *)&payload[2] =
+ wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2);
+ }
+ *(t_u16 *)&payload[0] = wlan_cpu_to_le16(offset);
+ pmbuf_aggr->data_len += pmbuf->data_len;
+ PRINTM(MIF_D, "offset=%d len=%d\n", offset, pmbuf->data_len);
+ LEAVE();
+}
+
+/**
+ * @brief Allocate Aggregation buffer and copy pending buffers to it.
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param pusb_tx_aggr Pointer to usb_tx_aggr_params
+ *
+ * @return Aggregation buffer
+ */
+static inline pmlan_buffer
+wlan_usb_copy_buf_to_aggr(pmlan_adapter pmadapter,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ pmlan_buffer pmbuf_aggr = MNULL;
+ t_u8 i, use_count;
+ pmlan_buffer pmbuf_curr, pmbuf_next;
+ pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pusb_tx_aggr->aggr_len,
+ 0, MOAL_MALLOC_BUFFER);
+ if (pmbuf_aggr) {
+ pmbuf_curr = pusb_tx_aggr->pmbuf_aggr;
+ pmbuf_aggr->bss_index = pmbuf_curr->bss_index;
+ pmbuf_aggr->buf_type = pmbuf_curr->buf_type;
+ pmbuf_aggr->priority = pmbuf_curr->priority;
+ pmbuf_aggr->data_len = 0;
+ PRINTM(MIF_D, "use_count=%d,aggr_len=%d\n",
+ pmbuf_curr->use_count, pusb_tx_aggr->aggr_len);
+ use_count = pmbuf_curr->use_count;
+ for (i = 0; i <= use_count; i++) {
+ pmbuf_next = pmbuf_curr->pnext;
+ if (pusb_tx_aggr->aggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_LEN_V2) {
+ if (i == use_count)
+ wlan_usb_tx_copy_buf_to_aggr_v2(
+ pmadapter, pmbuf_aggr,
+ pmbuf_curr, MTRUE,
+ pusb_tx_aggr);
+ else
+ wlan_usb_tx_copy_buf_to_aggr_v2(
+ pmadapter, pmbuf_aggr,
+ pmbuf_curr, MFALSE,
+ pusb_tx_aggr);
+ } else
+ wlan_usb_tx_copy_buf_to_aggr(pmadapter,
+ pmbuf_aggr,
+ pmbuf_curr,
+ pusb_tx_aggr);
+ pmbuf_curr = pmbuf_next;
+ }
+ DBG_HEXDUMP(MIF_D, "USB AggrTx",
+ pmbuf_aggr->pbuf + pmbuf_aggr->data_offset,
+ pmbuf_aggr->data_len);
+ }
+ return pmbuf_aggr;
+}
+
+/**
+ * @brief Link buffer into aggregate head buffer
+ *
+ * @param pmbuf_aggr Pointer to aggregation buffer
+ * @param pmbuf Pointer to buffer to add to the buffer list
+ * @param pusb_tx_aggr Pointer to usb_tx_aggr_params
+ */
+static inline t_void
+wlan_usb_tx_link_buf_to_aggr(pmlan_buffer pmbuf_aggr, pmlan_buffer pmbuf,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ /* link new buf at end of list */
+ pmbuf->pnext = pmbuf_aggr;
+ pmbuf->pprev = pmbuf_aggr->pprev;
+ pmbuf->pparent = pmbuf_aggr;
+ pmbuf_aggr->pprev->pnext = pmbuf;
+ pmbuf_aggr->pprev = pmbuf;
+ pmbuf_aggr->use_count++;
+ pusb_tx_aggr->aggr_len =
+ usb_tx_aggr_pad_len(pusb_tx_aggr->aggr_len, pusb_tx_aggr);
+ pusb_tx_aggr->aggr_len += pmbuf->data_len;
+}
+
+/**
+ * @brief Send aggregated buffer
+ *
+ * @param pmadapter Pointer to mlan_adapter structure
+ * @param pusb_tx_aggr Pointer to usb_tx_aggr_params
+ */
+static inline t_void wlan_usb_tx_send_aggr(pmlan_adapter pmadapter,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ mlan_status ret;
+ pmlan_buffer pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr;
+ ENTER();
+ if (!pusb_tx_aggr->pmbuf_aggr) {
+ LEAVE();
+ return;
+ }
+
+ if (pusb_tx_aggr->pmbuf_aggr->use_count) {
+ pmbuf_aggr = wlan_usb_copy_buf_to_aggr(pmadapter, pusb_tx_aggr);
+ /* allocate new buffer for aggregation if not exist */
+ if (!pmbuf_aggr) {
+ PRINTM(MERROR,
+ "Error allocating [usb_tx] aggr mlan_buffer.\n");
+ pmadapter->dbg.num_tx_host_to_card_failure +=
+ pusb_tx_aggr->pmbuf_aggr->use_count;
+ wlan_write_data_complete(pmadapter,
+ pusb_tx_aggr->pmbuf_aggr,
+ MLAN_STATUS_FAILURE);
+ pusb_tx_aggr->pmbuf_aggr = MNULL;
+ pusb_tx_aggr->aggr_len = 0;
+ LEAVE();
+ return;
+ } else {
+ wlan_write_data_complete(pmadapter,
+ pusb_tx_aggr->pmbuf_aggr,
+ MLAN_STATUS_SUCCESS);
+ pusb_tx_aggr->pmbuf_aggr = MNULL;
+ pusb_tx_aggr->aggr_len = 0;
+ }
+ } else if (pusb_tx_aggr->aggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_LEN_V2) {
+ t_u8 *payload = pmbuf_aggr->pbuf + pmbuf_aggr->data_offset;
+ *(t_u16 *)&payload[0] = wlan_cpu_to_le16(pmbuf_aggr->data_len);
+ *(t_u16 *)&payload[2] =
+ wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2 | 0x80);
+ PRINTM(MIF_D, "USB Send single packet len=%d\n",
+ pmbuf_aggr->data_len);
+ DBG_HEXDUMP(MIF_D, "USB Tx",
+ pmbuf_aggr->pbuf + pmbuf_aggr->data_offset,
+ pmbuf_aggr->data_len);
+ }
+
+ if (pmbuf_aggr && pmbuf_aggr->data_len) {
+ pmadapter->data_sent = MTRUE;
+ ret = pmadapter->callbacks.moal_write_data_async(
+ pmadapter->pmoal_handle, pmbuf_aggr,
+ pusb_tx_aggr->port);
+ switch (ret) {
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_RESOURCE:
+ /* Shouldn't reach here due to next condition. */
+ /* TODO: (maybe) How to requeue the aggregate? */
+ /* It may occur when the pending tx urbs reach the high
+ * mark */
+ /* Thus, block further pkts for a bit */
+ PRINTM(MERROR,
+ "Error: moal_write_data_async failed: 0x%X\n",
+ ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ PRINTM(MERROR,
+ "Error: moal_write_data_async failed: 0x%X\n",
+ ret);
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
+ break;
+ default:
+ break;
+ }
+
+ /* aggr_buf now sent to bus, prevent others from using it */
+ pusb_tx_aggr->pmbuf_aggr = MNULL;
+ pusb_tx_aggr->aggr_len = 0;
+ }
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function get pcie device from card type
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_get_usb_device(pmlan_adapter pmadapter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u16 card_type = pmadapter->card_type;
+
+ ENTER();
+
+ ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(mlan_usb_card),
+ MLAN_MEM_DEF,
+ (t_u8 **)&pmadapter->pcard_usb);
+ if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_usb) {
+ PRINTM(MERROR, "Failed to allocate pcard_usb\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ switch (card_type) {
+#ifdef USB8897
+ case CARD_TYPE_USB8897:
+ pmadapter->pcard_info = &mlan_card_info_usb8897;
+ break;
+#endif
+#ifdef USB8997
+ case CARD_TYPE_USB8997:
+ pmadapter->pcard_info = &mlan_card_info_usb8997;
+ break;
+#endif
+#ifdef USB8978
+ case CARD_TYPE_USB8978:
+ pmadapter->pcard_info = &mlan_card_info_usb8978;
+ break;
+#endif
+#ifdef USB9098
+ case CARD_TYPE_USB9098:
+ pmadapter->pcard_info = &mlan_card_info_usb9098;
+ break;
+#endif
+#ifdef USB9097
+ case CARD_TYPE_USB9097:
+ pmadapter->pcard_info = &mlan_card_info_usb9097;
+ break;
+#endif
+ default:
+ PRINTM(MERROR, "can't get right USB card type \n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware to card
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmfw A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_usb_dnld_fw(pmlan_adapter pmadapter, pmlan_fw_image pmfw)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_usb_prog_fw_w_helper(pmadapter, pmfw);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function deaggregates USB RX Data Packet from device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_usb_deaggr_rx_pkt(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ const t_u8 zero_rx_pd[sizeof(RxPD)] = {0};
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 curr_pkt_len;
+ RxPD *prx_pd;
+ t_u8 *pdata;
+ t_s32 aggr_len;
+ pmlan_buffer pdeaggr_buf;
+
+ ENTER();
+
+ pdata = pmbuf->pbuf + pmbuf->data_offset;
+ prx_pd = (RxPD *)pdata;
+ curr_pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
+ wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
+ /* if non-aggregate, just send through, don’t process here */
+ aggr_len = pmbuf->data_len;
+ if ((aggr_len == curr_pkt_len) ||
+ (wlan_usb_deaggr_rx_num_pkts(pmadapter, pdata, aggr_len) == 1) ||
+ (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable != MTRUE)) {
+ ret = wlan_handle_rx_packet(pmadapter, pmbuf);
+ LEAVE();
+ return ret;
+ }
+
+ while (aggr_len >= sizeof(RxPD)) {
+ /* check for (all-zeroes) termination RxPD */
+ if (!memcmp(pmadapter, pdata, zero_rx_pd, sizeof(RxPD))) {
+ break;
+ }
+
+ /* make new buffer and copy packet to it (including RxPD).
+ * Also, reserve headroom so that there must have space
+ * to change RxPD to TxPD for bridge packet in uAP mode */
+ pdeaggr_buf = wlan_alloc_mlan_buffer(pmadapter, curr_pkt_len,
+ MLAN_RX_HEADER_LEN,
+ MOAL_ALLOC_MLAN_BUFFER);
+ if (pdeaggr_buf == MNULL) {
+ PRINTM(MERROR,
+ "Error allocating [usb_rx] deaggr mlan_buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+ pdeaggr_buf->bss_index = pmbuf->bss_index;
+ pdeaggr_buf->buf_type = pmbuf->buf_type;
+ pdeaggr_buf->data_len = curr_pkt_len;
+ pdeaggr_buf->in_ts_sec = pmbuf->in_ts_sec;
+ pdeaggr_buf->in_ts_usec = pmbuf->in_ts_usec;
+ pdeaggr_buf->priority = pmbuf->priority;
+ memcpy_ext(pmadapter,
+ pdeaggr_buf->pbuf + pdeaggr_buf->data_offset, pdata,
+ curr_pkt_len, pdeaggr_buf->data_len);
+
+ /* send new packet to processing */
+ ret = wlan_handle_rx_packet(pmadapter, pdeaggr_buf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ break;
+ }
+ /* last block has no padding bytes */
+ if (aggr_len == curr_pkt_len) {
+ break;
+ }
+
+ /* round up to next block boundary */
+ if (curr_pkt_len %
+ pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_align)
+ curr_pkt_len += (pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align -
+ (curr_pkt_len %
+ pmadapter->pcard_usb->usb_rx_deaggr
+ .aggr_ctrl.aggr_align));
+ /* point to next packet */
+ aggr_len -= curr_pkt_len;
+ pdata += curr_pkt_len;
+ prx_pd = (RxPD *)pdata;
+ curr_pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
+ wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
+ }
+
+ /* free original pmbuf (since not sent for processing) */
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->rx_data_ep, ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function restore tx_pause flag
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pusb_tx_aggr A pointer to usb_tx_aggr_params
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 wlan_is_port_tx_paused(pmlan_adapter pmadapter,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ mlan_private *pmpriv = MNULL;
+ t_u8 i;
+ t_u8 ret = MFALSE;
+ for (i = 0; i < pmadapter->priv_num; i++) {
+ pmpriv = pmadapter->priv[i];
+ if (pmpriv && pmpriv->tx_pause &&
+ (pmpriv->port == pusb_tx_aggr->port)) {
+ ret = MTRUE;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief This function handles the timeout of usb tx aggregation.
+ * It will send the aggregate buffer being held.
+ *
+ * @param function_context A pointer to function_context
+ * @return N/A
+ */
+t_void wlan_usb_tx_aggr_timeout_func(t_void *function_context)
+{
+ usb_tx_aggr_params *pusb_tx_aggr =
+ (usb_tx_aggr_params *)function_context;
+ pmlan_adapter pmadapter = (mlan_adapter *)pusb_tx_aggr->phandle;
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+
+ ENTER();
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pusb_tx_aggr->paggr_lock);
+ pusb_tx_aggr->aggr_hold_timer_is_set = MFALSE;
+ if (pusb_tx_aggr->pmbuf_aggr && !pmadapter->data_sent &&
+ !wlan_is_port_tx_paused(pmadapter, pusb_tx_aggr))
+ wlan_usb_tx_send_aggr(pmadapter, pusb_tx_aggr);
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pusb_tx_aggr->paggr_lock);
+ LEAVE();
+}
+
+/**
+ * @brief This function aggregates USB TX Data Packet to send to device
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the transmit buffer
+ * @param tx_param A pointer to mlan_tx_param
+ * @param pusb_tx_aggr A pointer to usb_tx_aggr_params
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
+ */
+/*
+ * Non Scatter-Gather code creates a new large buffer where each incoming
+ * buffer's data contents are copied to (aligned to USB boundaries).
+ * The individual buffers are ALSO linked to the large buffer,
+ * in order to handle complete AFTER the aggregate is sent.
+ * pmbuf_aggr->data_len is used to keep track of bytes aggregated so far.
+ */
+mlan_status wlan_usb_host_to_card_aggr(pmlan_adapter pmadapter,
+ pmlan_buffer pmbuf,
+ mlan_tx_param *tx_param,
+ usb_tx_aggr_params *pusb_tx_aggr)
+{
+ pmlan_callbacks pcb = &pmadapter->callbacks;
+ pmlan_buffer pmbuf_aggr;
+ mlan_status ret = MLAN_STATUS_PENDING;
+ t_u32 next_pkt_len = (tx_param) ? tx_param->next_pkt_len : 0;
+ t_u32 aggr_len_counter = 0;
+ /* indicators */
+ t_u8 f_precopy_cur_buf = 0;
+ t_u8 f_send_aggr_buf = 0;
+ t_u8 f_postcopy_cur_buf = 0;
+ t_u32 max_aggr_size = 0, max_aggr_num = 0;
+
+ ENTER();
+
+ pcb->moal_spin_lock(pmadapter->pmoal_handle, pusb_tx_aggr->paggr_lock);
+
+ /* stop timer while we process */
+ if (pusb_tx_aggr->aggr_hold_timer_is_set) {
+ pcb->moal_stop_timer(pmadapter->pmoal_handle,
+ pusb_tx_aggr->paggr_hold_timer);
+ pusb_tx_aggr->aggr_hold_timer_is_set = MFALSE;
+ }
+
+ pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr;
+
+ if (pusb_tx_aggr->aggr_ctrl.aggr_tmo == MLAN_USB_TX_AGGR_TIMEOUT_DYN) {
+ if (!pmbuf_aggr) {
+ /* Start aggr from min timeout value in micro sec */
+ pusb_tx_aggr->hold_timeout_msec =
+ MLAN_USB_TX_MIN_AGGR_TIMEOUT;
+ } else {
+ /* Increase timeout in milisecond if pkts are
+ * consecutive */
+ if (pusb_tx_aggr->hold_timeout_msec <
+ MLAN_USB_TX_MAX_AGGR_TIMEOUT)
+ pusb_tx_aggr->hold_timeout_msec++;
+ }
+ } else {
+ if (pusb_tx_aggr->aggr_ctrl.aggr_tmo)
+ pusb_tx_aggr->hold_timeout_msec =
+ pusb_tx_aggr->aggr_ctrl.aggr_tmo / 1000;
+ }
+
+ max_aggr_size = max_aggr_num = pusb_tx_aggr->aggr_ctrl.aggr_max;
+ if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
+ max_aggr_size *= MAX(MLAN_USB_MAX_PKT_SIZE,
+ pusb_tx_aggr->aggr_ctrl.aggr_align);
+ }
+ if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_LEN)
+ max_aggr_num /= pusb_tx_aggr->aggr_ctrl.aggr_align;
+ else if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_LEN_V2)
+ max_aggr_num = MLAN_USB_TX_AGGR_MAX_NUM;
+ if (!pmbuf_aggr) {
+ /* use this buf to start linked list, that's it */
+ pmbuf->pnext = pmbuf->pprev = pmbuf;
+ pmbuf_aggr = pmbuf;
+ pusb_tx_aggr->pmbuf_aggr = pmbuf_aggr;
+ pusb_tx_aggr->aggr_len = pmbuf->data_len;
+ pmbuf->flags |= MLAN_BUF_FLAG_USB_TX_AGGR;
+
+ } else {
+ /* DECIDE what to do */
+ aggr_len_counter = usb_tx_aggr_pad_len(pusb_tx_aggr->aggr_len,
+ pusb_tx_aggr);
+
+ if ((aggr_len_counter + pmbuf->data_len) < max_aggr_size) {
+ f_precopy_cur_buf = 1; /* can fit current packet in aggr
+ */
+ if (next_pkt_len) {
+ aggr_len_counter += usb_tx_aggr_pad_len(
+ pmbuf->data_len, pusb_tx_aggr);
+ if ((aggr_len_counter + next_pkt_len) >=
+ max_aggr_size)
+ f_send_aggr_buf = 1; /* can't fit next
+ packet, send now
+ */
+ }
+ } else {
+ /* can't fit current packet */
+ if (pusb_tx_aggr->aggr_len)
+ f_send_aggr_buf = 1; /* send aggr first */
+ f_postcopy_cur_buf = 1; /* then copy into new aggr_buf
+ */
+ }
+ }
+
+ /* For zero timeout and zero next packet length send pkt now */
+ if (!pusb_tx_aggr->aggr_ctrl.aggr_tmo && !next_pkt_len)
+ f_send_aggr_buf = 1;
+
+ /* PERFORM ACTIONS as decided */
+ if (f_precopy_cur_buf) {
+ PRINTM(MIF_D, "%s: Precopy current buffer.\n", __FUNCTION__);
+ wlan_usb_tx_link_buf_to_aggr(pmbuf_aggr, pmbuf, pusb_tx_aggr);
+ }
+ if (pmbuf_aggr->use_count + 1 >= max_aggr_num)
+ f_send_aggr_buf = 1;
+
+ if (pmbuf->flags & MLAN_BUF_FLAG_NULL_PKT ||
+ pmbuf->flags & MLAN_BUF_FLAG_TCP_ACK)
+ f_send_aggr_buf = 1;
+
+ if (f_send_aggr_buf) {
+ PRINTM(MIF_D, "%s: Send aggregate buffer.\n", __FUNCTION__);
+ wlan_usb_tx_send_aggr(pmadapter, pusb_tx_aggr);
+ pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr; /* update ptr */
+ }
+
+ if (f_postcopy_cur_buf) {
+ PRINTM(MIF_D, "%s: Postcopy current buffer.\n", __FUNCTION__);
+ if (!pmbuf_aggr) { /* this is possible if just sent (above) */
+ /* use this buf to start linked list */
+ pmbuf->pnext = pmbuf->pprev = pmbuf;
+ pmbuf_aggr = pmbuf;
+ pusb_tx_aggr->pmbuf_aggr = pmbuf_aggr;
+ pusb_tx_aggr->aggr_len = pmbuf->data_len;
+ pmbuf->flags |= MLAN_BUF_FLAG_USB_TX_AGGR;
+ }
+ }
+ /* (re)start timer if there is something in the aggregation buffer */
+ if (pmbuf_aggr && pmbuf_aggr->data_len) {
+ if (pusb_tx_aggr->aggr_ctrl.aggr_tmo) {
+ pcb->moal_start_timer(pmadapter->pmoal_handle,
+ pusb_tx_aggr->paggr_hold_timer,
+ MFALSE,
+ pusb_tx_aggr->hold_timeout_msec);
+ pusb_tx_aggr->aggr_hold_timer_is_set = MTRUE;
+ }
+ }
+
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ pusb_tx_aggr->paggr_lock);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function wakes up the card.
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param timeout set timeout flag
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_pm_usb_wakeup_card(pmlan_adapter pmadapter, t_u8 timeout)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 age_ts_usec;
+
+ ENTER();
+ PRINTM(MEVENT, "Wakeup device...\n");
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmadapter->pm_wakeup_in_secs,
+ &age_ts_usec);
+
+ /* Simulation of HS_AWAKE event */
+ pmadapter->pm_wakeup_fw_try = MFALSE;
+ pmadapter->pm_wakeup_card_req = MFALSE;
+ /* TODO USB suspend/resume */
+ pmadapter->ps_state = PS_STATE_AWAKE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card
+ * by this function. This function adds the PCIE specific header
+ * to the front of the buffer before transferring. The header
+ * contains the length of the packet and the type. The firmware
+ * handles the packets based upon this set type.
+ *
+ * @param pmpriv A pointer to pmlan_private structure
+ * @param type data or command
+ * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
+ * PCIE header)
+ * @param tx_param A pointer to mlan_tx_param (can be MNULL if type is
+ * command)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_usb_host_to_card(pmlan_private pmpriv, t_u8 type,
+ mlan_buffer *pmbuf, mlan_tx_param *tx_param)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ usb_tx_aggr_params *pusb_tx_aggr = MNULL;
+ pmlan_adapter pmadapter = pmpriv->adapter;
+
+ ENTER();
+
+ if (!pmbuf) {
+ PRINTM(MERROR, "Passed NULL pmbuf to %s\n", __FUNCTION__);
+ return MLAN_STATUS_FAILURE;
+ }
+ if (type == MLAN_TYPE_CMD
+#if (defined(USB9098) || defined(USB9097))
+ || type == MLAN_TYPE_VDLL
+#endif
+ ) {
+ pmadapter->cmd_sent = MTRUE;
+ ret = pmadapter->callbacks.moal_write_data_async(
+ pmadapter->pmoal_handle, pmbuf, pmadapter->tx_cmd_ep);
+ if (ret == MLAN_STATUS_FAILURE)
+ pmadapter->cmd_sent = MFALSE;
+ LEAVE();
+ return ret;
+ }
+ pusb_tx_aggr = wlan_get_usb_tx_aggr_params(pmadapter, pmpriv->port);
+ if (pusb_tx_aggr) {
+ ret = wlan_usb_host_to_card_aggr(pmadapter, pmbuf, tx_param,
+ pusb_tx_aggr);
+ } else {
+ pmadapter->data_sent = MTRUE;
+ ret = pmadapter->callbacks.moal_write_data_async(
+ pmadapter->pmoal_handle, pmbuf, pmpriv->port);
+ switch (ret) {
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ break;
+ case MLAN_STATUS_RESOURCE:
+
+ break;
+ case MLAN_STATUS_FAILURE:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_PENDING:
+ pmadapter->data_sent = MFALSE;
+ break;
+ case MLAN_STATUS_SUCCESS:
+ break;
+ default:
+ break;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handle event/cmd complete
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return N/A
+ */
+mlan_status wlan_usb_cmdevt_complete(pmlan_adapter pmadapter,
+ mlan_buffer *pmbuf, mlan_status status)
+{
+ ENTER();
+
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->rx_cmd_ep, status);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle data complete
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return N/A
+ */
+mlan_status wlan_usb_data_complete(pmlan_adapter pmadapter, mlan_buffer *pmbuf,
+ mlan_status status)
+{
+ ENTER();
+
+ pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
+ pmadapter->rx_data_ep, status);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handle receive packet
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pmbuf A pointer to the mlan_buffer
+ * @return
+ */
+mlan_status wlan_usb_handle_rx_packet(mlan_adapter *pmadapter,
+ pmlan_buffer pmbuf)
+{
+ ENTER();
+
+ if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable == MTRUE)
+ return wlan_usb_deaggr_rx_pkt(pmadapter, pmbuf);
+ else
+ return wlan_handle_rx_packet(pmadapter, pmbuf);
+
+ LEAVE();
+}
+
+mlan_adapter_operations mlan_usb_ops = {
+ .dnld_fw = wlan_usb_dnld_fw,
+ .host_to_card = wlan_usb_host_to_card,
+ .wakeup_card = wlan_pm_usb_wakeup_card,
+ .event_complete = wlan_usb_cmdevt_complete,
+ .data_complete = wlan_usb_data_complete,
+ .cmdrsp_complete = wlan_usb_cmdevt_complete,
+ .handle_rx_packet = wlan_usb_handle_rx_packet,
+
+ .intf_header_len = USB_INTF_HEADER_LEN,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_util.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_util.h
new file mode 100644
index 000000000000..c86269e2b155
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_util.h
@@ -0,0 +1,492 @@
+/** @file mlan_util.h
+ *
+ * @brief This file contains wrappers for linked-list,
+ * spinlock and timer defines.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/28/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_UTIL_H_
+#define _MLAN_UTIL_H_
+
+/** Circular doubly linked list */
+typedef struct _mlan_linked_list {
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+} mlan_linked_list, *pmlan_linked_list;
+
+/** List head */
+typedef struct _mlan_list_head {
+ /** Pointer to previous node */
+ struct _mlan_linked_list *pprev;
+ /** Pointer to next node */
+ struct _mlan_linked_list *pnext;
+ /** Pointer to lock */
+ t_void *plock;
+} mlan_list_head, *pmlan_list_head;
+
+/**
+ * @brief This function initializes a list without locking
+ *
+ * @param phead List head
+ *
+ * @return N/A
+ */
+static INLINE t_void util_init_list(pmlan_linked_list phead)
+{
+ /* Both next and prev point to self */
+ phead->pprev = phead->pnext = (pmlan_linked_list)phead;
+}
+
+/**
+ * @brief This function initializes a list
+ *
+ * @param phead List head
+ * @param lock_required A flag for spinlock requirement
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_init_list_head(
+ t_void *pmoal_handle, pmlan_list_head phead, t_u8 lock_required,
+ mlan_status (*moal_init_lock)(t_void *handle, t_void **pplock))
+{
+ /* Both next and prev point to self */
+ util_init_list((pmlan_linked_list)phead);
+ if (lock_required)
+ moal_init_lock(pmoal_handle, &phead->plock);
+ else
+ phead->plock = 0;
+}
+
+/**
+ * @brief This function frees a list
+ *
+ * @param phead List head
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_free_list_head(
+ t_void *pmoal_handle, pmlan_list_head phead,
+ mlan_status (*moal_free_lock)(t_void *handle, t_void *plock))
+{
+ phead->pprev = phead->pnext = 0;
+ if (phead->plock)
+ moal_free_lock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function peeks into a list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list
+util_peek_list(t_void *pmoal_handle, pmlan_list_head phead,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ pmlan_linked_list pnode = 0;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ if (phead->pnext != (pmlan_linked_list)phead)
+ pnode = phead->pnext;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/**
+ * @brief This function queues a node at the list tail
+ *
+ * @param phead List head
+ * @param pnode List node to queue
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_enqueue_list_tail(
+ t_void *pmoal_handle, pmlan_list_head phead, pmlan_linked_list pnode,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ pmlan_linked_list pold_last;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_last = phead->pprev;
+ pnode->pprev = pold_last;
+ pnode->pnext = (pmlan_linked_list)phead;
+
+ phead->pprev = pold_last->pnext = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function adds a node at the list head
+ *
+ * @param phead List head
+ * @param pnode List node to add
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_enqueue_list_head(
+ t_void *pmoal_handle, pmlan_list_head phead, pmlan_linked_list pnode,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ pmlan_linked_list pold_first;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pold_first = phead->pnext;
+ pnode->pprev = (pmlan_linked_list)phead;
+ pnode->pnext = pold_first;
+
+ phead->pnext = pold_first->pprev = pnode;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function removes a node from the list
+ *
+ * @param phead List head
+ * @param pnode List node to remove
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_unlink_list(
+ t_void *pmoal_handle, pmlan_list_head phead, pmlan_linked_list pnode,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ pmlan_linked_list pmy_prev;
+ pmlan_linked_list pmy_next;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pmy_prev = pnode->pprev;
+ pmy_next = pnode->pnext;
+ pmy_next->pprev = pmy_prev;
+ pmy_prev->pnext = pmy_next;
+
+ pnode->pnext = pnode->pprev = 0;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+}
+
+/**
+ * @brief This function dequeues a node from the list
+ *
+ * @param phead List head
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return List node
+ */
+static INLINE pmlan_linked_list util_dequeue_list(
+ t_void *pmoal_handle, pmlan_list_head phead,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ pmlan_linked_list pnode;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, phead->plock);
+ pnode = phead->pnext;
+ if (pnode && (pnode != (pmlan_linked_list)phead))
+ util_unlink_list(pmoal_handle, phead, pnode, 0, 0);
+ else
+ pnode = 0;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, phead->plock);
+ return pnode;
+}
+
+/** Access controlled scalar variable */
+typedef struct _mlan_scalar {
+ /** Value */
+ t_s32 value;
+ /** Pointer to lock */
+ t_void *plock;
+ /** Control flags */
+ t_u32 flags;
+} mlan_scalar, *pmlan_scalar;
+
+/** Flag to scalar lock acquired */
+#define MLAN_SCALAR_FLAG_UNIQUE_LOCK MBIT(16)
+
+/** scalar conditional value list */
+typedef enum _MLAN_SCALAR_CONDITIONAL {
+ MLAN_SCALAR_COND_EQUAL,
+ MLAN_SCALAR_COND_NOT_EQUAL,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ MLAN_SCALAR_COND_GREATER_OR_EQUAL,
+ MLAN_SCALAR_COND_LESS_THAN,
+ MLAN_SCALAR_COND_LESS_OR_EQUAL
+} MLAN_SCALAR_CONDITIONAL;
+
+/**
+ * @brief This function initializes a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Initial scalar value
+ * @param plock_to_use A new lock is created if NULL, else lock to use
+ * @param moal_init_lock A pointer to init lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_init(t_void *pmoal_handle, pmlan_scalar pscalar, t_s32 val,
+ t_void *plock_to_use,
+ mlan_status (*moal_init_lock)(t_void *handle, t_void **pplock))
+{
+ pscalar->value = val;
+ pscalar->flags = 0;
+ if (plock_to_use) {
+ pscalar->flags &= ~MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ pscalar->plock = plock_to_use;
+ } else {
+ pscalar->flags |= MLAN_SCALAR_FLAG_UNIQUE_LOCK;
+ moal_init_lock(pmoal_handle, &pscalar->plock);
+ }
+}
+
+/**
+ * @brief This function frees a scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_free_lock A pointer to free lock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void
+util_scalar_free(t_void *pmoal_handle, pmlan_scalar pscalar,
+ mlan_status (*moal_free_lock)(t_void *handle, t_void *plock))
+{
+ if (pscalar->flags & MLAN_SCALAR_FLAG_UNIQUE_LOCK)
+ moal_free_lock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function reads value from scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Stored value
+ */
+static INLINE t_s32
+util_scalar_read(t_void *pmoal_handle, pmlan_scalar pscalar,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ t_s32 val;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ val = pscalar->value;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return val;
+}
+
+/**
+ * @brief This function writes value to scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param val Value to write
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_scalar_write(
+ t_void *pmoal_handle, pmlan_scalar pscalar, t_s32 val,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value = val;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function increments the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_scalar_increment(
+ t_void *pmoal_handle, pmlan_scalar pscalar,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value++;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function decrements the value in scalar
+ *
+ * @param pscalar Pointer to scalar
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return N/A
+ */
+static INLINE t_void util_scalar_decrement(
+ t_void *pmoal_handle, pmlan_scalar pscalar,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ pscalar->value--;
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+}
+
+/**
+ * @brief This function adds an offset to the value in scalar,
+ * and returns the new value
+ *
+ * @param pscalar Pointer to scalar
+ * @param offset Offset value (can be negative)
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Value after offset
+ */
+static INLINE t_s32 util_scalar_offset(
+ t_void *pmoal_handle, pmlan_scalar pscalar, t_s32 offset,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ t_s32 newval;
+
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+ newval = (pscalar->value += offset);
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+
+ return newval;
+}
+
+/**
+ * @brief This function writes the value to the scalar
+ * if existing value compared with other value is true.
+ *
+ * @param pscalar Pointer to scalar
+ * @param condition Condition to check
+ * @param val_compare Value to compare against current value
+ * ((A X B), where B = val_compare)
+ * @param val_to_set Value to set if comparison is true
+ * @param moal_spin_lock A pointer to spin lock handler
+ * @param moal_spin_unlock A pointer to spin unlock handler
+ *
+ * @return Comparison result (MTRUE or MFALSE)
+ */
+static INLINE t_u8 util_scalar_conditional_write(
+ t_void *pmoal_handle, pmlan_scalar pscalar,
+ MLAN_SCALAR_CONDITIONAL condition, t_s32 val_compare, t_s32 val_to_set,
+ mlan_status (*moal_spin_lock)(t_void *handle, t_void *plock),
+ mlan_status (*moal_spin_unlock)(t_void *handle, t_void *plock))
+{
+ t_u8 update;
+ if (moal_spin_lock)
+ moal_spin_lock(pmoal_handle, pscalar->plock);
+
+ switch (condition) {
+ case MLAN_SCALAR_COND_EQUAL:
+ update = (pscalar->value == val_compare);
+ break;
+ case MLAN_SCALAR_COND_NOT_EQUAL:
+ update = (pscalar->value != val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_THAN:
+ update = (pscalar->value > val_compare);
+ break;
+ case MLAN_SCALAR_COND_GREATER_OR_EQUAL:
+ update = (pscalar->value >= val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_THAN:
+ update = (pscalar->value < val_compare);
+ break;
+ case MLAN_SCALAR_COND_LESS_OR_EQUAL:
+ update = (pscalar->value <= val_compare);
+ break;
+ default:
+ update = MFALSE;
+ break;
+ }
+ if (update)
+ pscalar->value = val_to_set;
+
+ if (moal_spin_unlock)
+ moal_spin_unlock(pmoal_handle, pscalar->plock);
+ return (update) ? MTRUE : MFALSE;
+}
+
+/**
+ * @brief This function counts the bits of unsigned int number
+ *
+ * @param num number
+ * @return number of bits
+ */
+static INLINE t_u32 bitcount(t_u32 num)
+{
+ t_u32 count = 0;
+ static t_u32 nibblebits[] = {0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4};
+ for (; num != 0; num >>= 4)
+ count += nibblebits[num & 0x0f];
+ return count;
+}
+
+#endif /* !_MLAN_UTIL_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.c
new file mode 100644
index 000000000000..f32a16687090
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.c
@@ -0,0 +1,3282 @@
+/** @file mlan_wmm.c
+ *
+ * @brief This file contains functions for WMM.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/24/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#ifdef STA_SUPPORT
+#include "mlan_join.h"
+#endif
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_wmm.h"
+#include "mlan_11n.h"
+#ifdef SDIO
+#include "mlan_sdio.h"
+#endif /* SDIO */
+#ifdef PCIE
+#include "mlan_pcie.h"
+#endif /* PCIE */
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX 512
+
+/*
+ * Upper and Lower threshold for packet queuing in the driver
+
+ * - When the number of packets queued reaches the upper limit,
+ * the driver will stop the net queue in the app/kernel space.
+
+ * - When the number of packets drops beneath the lower limit after
+ * having reached the upper limit, the driver will restart the net
+ * queue.
+ */
+
+/** Lower threshold for packet queuing in the driver.
+ * When the number of packets drops beneath the lower limit after having
+ * reached the upper limit, the driver will restart the net queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
+
+/** Upper threshold for packet queuing in the driver.
+ * When the number of packets queued reaches the upper limit, the driver
+ * will stop the net queue in the app/kernel space.
+ */
+#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** WMM information IE */
+static const t_u8 wmm_info_ie[] = {WMM_IE, 0x07, 0x00, 0x50, 0xf2,
+ 0x02, 0x00, 0x01, 0x00};
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _wmm_ac_e {
+ AC_BE,
+ AC_BK,
+ AC_VI,
+ AC_VO
+} MLAN_PACK_END wmm_ac_e;
+
+/**
+ * AC Priorities go from AC_BK to AC_VO. The ACI enumeration for AC_BK (1)
+ * is higher than the enumeration for AC_BE (0); hence the needed
+ * mapping conversion for wmm AC to priority Queue Index
+ */
+static const t_u8 wmm_aci_to_qidx_map[] = {WMM_AC_BE, WMM_AC_BK, WMM_AC_VI,
+ WMM_AC_VO};
+/**
+ * This table will be used to store the tid values based on ACs.
+ * It is initialized to default values per TID.
+ */
+t_u8 tos_to_tid[] = {
+ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+ 0x01, /* 0 1 0 AC_BK */
+ 0x02, /* 0 0 0 AC_BK */
+ 0x00, /* 0 0 1 AC_BE */
+ 0x03, /* 0 1 1 AC_BE */
+ 0x04, /* 1 0 0 AC_VI */
+ 0x05, /* 1 0 1 AC_VI */
+ 0x06, /* 1 1 0 AC_VO */
+ 0x07 /* 1 1 1 AC_VO */
+};
+
+/**
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+t_u8 tos_to_tid_inv[] = {0x02, /* from tos_to_tid[2] = 0 */
+ 0x00, /* from tos_to_tid[0] = 1 */
+ 0x01, /* from tos_to_tid[1] = 2 */
+ 0x03, 0x04, 0x05, 0x06, 0x07};
+
+/**
+ * This table will provide the tid value for given ac. This table does not
+ * change and will be used to copy back the default values to tos_to_tid in
+ * case of disconnect.
+ */
+const t_u8 ac_to_tid[4][2] = {{1, 2}, {0, 3}, {4, 5}, {6, 7}};
+
+/* Map of TOS UP values to WMM AC */
+static const mlan_wmm_ac_e tos_to_ac[] = {WMM_AC_BE, WMM_AC_BK, WMM_AC_BK,
+ WMM_AC_BE, WMM_AC_VI, WMM_AC_VI,
+ WMM_AC_VO, WMM_AC_VO};
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 *ra_addr);
+
+/********************************************************
+ Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/**
+ * @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ * @param pac_param Pointer to the AC parameters to display
+ *
+ * @return N/A
+ */
+static void
+wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t *pac_param)
+{
+ const char *ac_str[] = {"BK", "BE", "VI", "VO"};
+
+ ENTER();
+
+ PRINTM(MINFO,
+ "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+ ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
+ pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
+ pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
+ pac_param->ecw.ecw_max,
+ wlan_le16_to_cpu(pac_param->tx_op_limit));
+
+ LEAVE();
+}
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
+#else
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pac_param)
+#endif
+
+/**
+ * @brief Allocate route address
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ * @param ra Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter,
+ t_u8 *ra)
+{
+ raListTbl *ra_list = MNULL;
+
+ ENTER();
+
+ if (pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
+ sizeof(raListTbl), MLAN_MEM_DEF,
+ (t_u8 **)&ra_list)) {
+ PRINTM(MERROR, "Fail to allocate ra_list\n");
+ goto done;
+ }
+ util_init_list((pmlan_linked_list)ra_list);
+ util_init_list_head((t_void *)pmadapter->pmoal_handle,
+ &ra_list->buf_head, MFALSE,
+ pmadapter->callbacks.moal_init_lock);
+
+ memcpy_ext(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+
+ ra_list->del_ba_count = 0;
+ ra_list->total_pkts = 0;
+ ra_list->tx_pause = 0;
+ PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
+done:
+ LEAVE();
+ return ra_list;
+}
+
+/**
+ * @brief Map ACs to TID
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param queue_priority Queue_priority structure
+ *
+ * @return N/A
+ */
+static void wlan_wmm_queue_priorities_tid(pmlan_private priv,
+ t_u8 queue_priority[])
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < 4; ++i) {
+ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8)i;
+
+ /* in case priorities have changed, force highest priority so
+ * next packet will check from top to re-establish the highest
+ */
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
+ priv->adapter->callbacks.moal_spin_lock,
+ priv->adapter->callbacks.moal_spin_unlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Evaluate whether or not an AC is to be downgraded
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param eval_ac AC to evaluate for downgrading
+ *
+ * @return WMM AC The eval_ac traffic is to be sent on.
+ */
+static mlan_wmm_ac_e wlan_wmm_eval_downgrade_ac(pmlan_private priv,
+ mlan_wmm_ac_e eval_ac)
+{
+ int down_ac;
+ mlan_wmm_ac_e ret_ac;
+ WmmAcStatus_t *pac_status;
+
+ ENTER();
+
+ pac_status = &priv->wmm.ac_status[eval_ac];
+
+ if (pac_status->disabled == MFALSE) {
+ LEAVE();
+ /* Okay to use this AC, its enabled */
+ return eval_ac;
+ }
+
+ /* Setup a default return value of the lowest priority */
+ ret_ac = WMM_AC_BK;
+
+ /*
+ * Find the highest AC that is enabled and does not require admission
+ * control. The spec disallows downgrading to an AC, which is enabled
+ * due to a completed admission control. Unadmitted traffic is not
+ * to be sent on an AC with admitted traffic.
+ */
+ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+ pac_status = &priv->wmm.ac_status[down_ac];
+
+ if ((pac_status->disabled == MFALSE) &&
+ (pac_status->flow_required == MFALSE))
+ /* AC is enabled and does not require admission control
+ */
+ ret_ac = (mlan_wmm_ac_e)down_ac;
+ }
+
+ LEAVE();
+ return ret_ac;
+}
+
+/**
+ * @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param tos IP TOS field
+ *
+ * @return WMM AC Queue mapping of the IP TOS field
+ */
+static INLINE mlan_wmm_ac_e wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter,
+ t_u32 tos)
+{
+ ENTER();
+
+ if (tos >= NELEMENTS(tos_to_ac)) {
+ LEAVE();
+ return WMM_AC_BE;
+ }
+
+ LEAVE();
+ return tos_to_ac[tos];
+}
+
+/**
+ * @brief Evaluate a given TID and downgrade it to a lower TID if the
+ * WMM Parameter IE received from the AP indicates that the AP
+ * is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care internally
+ *
+ * @param priv Pointer to the mlan_private data struct
+ * @param tid tid to evaluate for downgrading
+ *
+ * @return Same tid as input if downgrading not required or
+ * the tid the traffic for the given tid should be downgraded to
+ */
+static INLINE t_u8 wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
+{
+ mlan_wmm_ac_e ac_down;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ ac_down = priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(
+ pmadapter, tid)];
+ LEAVE();
+ /*
+ * Send the index to tid array, picking from the array will be
+ * taken care by dequeuing function
+ */
+ if (tid == 1 || tid == 2)
+ return ac_to_tid[ac_down][(tid + 1) % 2];
+ else if (tid >= MAX_NUM_TID)
+ return ac_to_tid[ac_down][0];
+ else
+ return ac_to_tid[ac_down][tid % 2];
+}
+
+/**
+ * @brief Delete packets in RA node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ *
+ * @return N/A
+ */
+static INLINE void wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv,
+ raListTbl *ra_list)
+{
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+ while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
+ &ra_list->buf_head, MNULL,
+ MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list)pmbuf, MNULL, MNULL);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ }
+ util_free_list_head((t_void *)pmadapter->pmoal_handle,
+ &ra_list->buf_head,
+ pmadapter->callbacks.moal_free_lock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ *
+ * @return N/A
+ */
+static INLINE void wlan_wmm_del_pkts_in_ralist(pmlan_private priv,
+ mlan_list_head *ra_list_head)
+{
+ raListTbl *ra_list;
+
+ ENTER();
+
+ ra_list = (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ ra_list_head, MNULL, MNULL);
+
+ while (ra_list && ra_list != (raListTbl *)ra_list_head) {
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Clean up the wmm queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void wlan_wmm_cleanup_queues(pmlan_private priv)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ wlan_wmm_del_pkts_in_ralist(priv,
+ &priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.pkts_queued[i] = 0;
+ priv->wmm.pkts_paused[i] = 0;
+ }
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, 0, MNULL, MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
+ MNULL);
+
+ LEAVE();
+}
+
+/**
+ * @brief Delete all route address from RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+static void wlan_wmm_delete_all_ralist(pmlan_private priv)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
+ while ((ra_list = (raListTbl *)util_peek_list(
+ pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list, MNULL,
+ MNULL))) {
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list)ra_list, MNULL,
+ MNULL);
+
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)ra_list);
+ }
+
+ util_init_list(
+ (pmlan_linked_list)&priv->wmm.tid_tbl_ptr[i].ra_list);
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Get queue RA pointer
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list
+ */
+static raListTbl *wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid,
+ t_u8 *ra_addr)
+{
+ raListTbl *ra_list;
+#ifdef UAP_SUPPORT
+ t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+#endif
+
+ ENTER();
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ if (ra_list) {
+ LEAVE();
+ return ra_list;
+ }
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ (0 !=
+ memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
+ if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
+ PRINTM_NETINTF(MERROR, priv);
+ PRINTM(MERROR,
+ "Drop packets to unknow station " MACSTR "\n",
+ MAC2STR(ra_addr));
+ LEAVE();
+ return MNULL;
+ }
+ }
+#endif
+ wlan_ralist_add(priv, ra_addr);
+
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
+ LEAVE();
+ return ra_list;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Sends wmmac host event
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param type_str Type of host event
+ * @param src_addr Pointer to the source Address
+ * @param tid TID
+ * @param up User priority
+ * @param status Status code or Reason code
+ *
+ * @return N/A
+ */
+static void wlan_send_wmmac_host_event(pmlan_private priv, char *type_str,
+ t_u8 *src_addr, t_u8 tid, t_u8 up,
+ t_u8 status)
+{
+ t_u8 event_buf[100];
+ mlan_event *pevent;
+ t_u8 *pout_buf;
+
+ ENTER();
+
+ /* Format one of the following two output strings:
+ ** - TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y
+ ** - TSPEC:DELTS_RX:[<reason code>]:TID=X:UP=Y
+ */
+ pevent = (mlan_event *)event_buf;
+ pout_buf = pevent->event_buf;
+
+ memcpy_ext(priv->adapter, pout_buf, (t_u8 *)"TSPEC:", 6, 6);
+ pout_buf += 6;
+
+ memcpy_ext(priv->adapter, pout_buf, (t_u8 *)type_str,
+ wlan_strlen(type_str), wlan_strlen(type_str));
+ pout_buf += wlan_strlen(type_str);
+
+ *pout_buf++ = ':';
+ *pout_buf++ = '[';
+
+ if (status >= 100) {
+ *pout_buf++ = (status / 100) + '0';
+ status = (status % 100);
+ }
+
+ if (status >= 10) {
+ *pout_buf++ = (status / 10) + '0';
+ status = (status % 10);
+ }
+
+ *pout_buf++ = status + '0';
+
+ memcpy_ext(priv->adapter, pout_buf, (t_u8 *)"]:TID", 5, 5);
+ pout_buf += 5;
+ *pout_buf++ = tid + '0';
+
+ memcpy_ext(priv->adapter, pout_buf, (t_u8 *)":UP", 3, 3);
+ pout_buf += 3;
+ *pout_buf++ = up + '0';
+
+ *pout_buf = '\0';
+
+ pevent->bss_index = priv->bss_index;
+ pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
+ pevent->event_len = wlan_strlen((const char *)(pevent->event_buf));
+
+ wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function gets the highest priority list pointer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param priv A pointer to mlan_private
+ * @param tid A pointer to return tid
+ *
+ * @return raListTbl
+ */
+static raListTbl *wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
+ pmlan_private *priv,
+ int *tid)
+{
+ pmlan_private priv_tmp;
+ raListTbl *ptr, *head;
+ mlan_bssprio_node *bssprio_node, *bssprio_head;
+ tid_tbl_t *tid_ptr;
+ int i, j;
+ int next_prio = 0;
+ int next_tid = 0;
+ ENTER();
+
+ PRINTM(MDAT_D, "POP\n");
+ for (j = pmadapter->priv_num - 1; j >= 0; --j) {
+ if (!(util_peek_list(pmadapter->pmoal_handle,
+ &pmadapter->bssprio_tbl[j].bssprio_head,
+ MNULL, MNULL)))
+ continue;
+
+ if (pmadapter->bssprio_tbl[j].bssprio_cur ==
+ (mlan_bssprio_node *)&pmadapter->bssprio_tbl[j]
+ .bssprio_head) {
+ pmadapter->bssprio_tbl[j].bssprio_cur =
+ pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
+ }
+
+ bssprio_head = bssprio_node =
+ pmadapter->bssprio_tbl[j].bssprio_cur;
+
+ do {
+ priv_tmp = bssprio_node->priv;
+ if ((priv_tmp->port_ctrl_mode == MTRUE) &&
+ (priv_tmp->port_open == MFALSE)) {
+ PRINTM(MINFO,
+ "get_highest_prio_ptr(): "
+ "PORT_CLOSED Ignore pkts from BSS%d\n",
+ priv_tmp->bss_index);
+ /* Ignore data pkts from a BSS if port is closed
+ */
+ goto next_intf;
+ }
+ if (priv_tmp->tx_pause == MTRUE) {
+ PRINTM(MINFO,
+ "get_highest_prio_ptr(): "
+ "TX PASUE Ignore pkts from BSS%d\n",
+ priv_tmp->bss_index);
+ /* Ignore data pkts from a BSS if tx pause */
+ goto next_intf;
+ }
+
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv_tmp->wmm.ra_list_spinlock);
+
+ for (i = util_scalar_read(
+ pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio, MNULL,
+ MNULL);
+ i >= LOW_PRIO_TID; --i) {
+ tid_ptr = &(priv_tmp)
+ ->wmm
+ .tid_tbl_ptr[tos_to_tid[i]];
+ if (!util_peek_list(pmadapter->pmoal_handle,
+ &tid_ptr->ra_list, MNULL,
+ MNULL))
+ continue;
+
+ /*
+ * Always choose the next ra we transmitted
+ * last time, this way we pick the ra's in
+ * round robin fashion.
+ */
+ head = ptr = tid_ptr->ra_list_curr->pnext;
+ if (ptr == (raListTbl *)&tid_ptr->ra_list)
+ head = ptr = ptr->pnext;
+
+ do {
+ if (!ptr->tx_pause &&
+ util_peek_list(
+ pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL,
+ MNULL)) {
+ /* Because WMM only support
+ * BK/BE/VI/VO, we have 8 tid
+ * We should balance the traffic
+ * of the same AC */
+ if (i % 2)
+ next_prio = i - 1;
+ else
+ next_prio = i + 1;
+ next_tid =
+ tos_to_tid[next_prio];
+ if (priv_tmp->wmm.pkts_queued
+ [next_tid] &&
+ (priv_tmp->wmm.pkts_queued
+ [next_tid] >
+ priv_tmp->wmm.pkts_paused
+ [next_tid]))
+ util_scalar_write(
+ pmadapter->pmoal_handle,
+ &priv_tmp->wmm
+ .highest_queued_prio,
+ next_prio,
+ MNULL, MNULL);
+ else
+ /* if
+ * highest_queued_prio >
+ * i, set it to i */
+ util_scalar_conditional_write(
+ pmadapter->pmoal_handle,
+ &priv_tmp->wmm
+ .highest_queued_prio,
+ MLAN_SCALAR_COND_GREATER_THAN,
+ i, i, MNULL,
+ MNULL);
+ *priv = priv_tmp;
+ *tid = tos_to_tid[i];
+ /* hold priv->ra_list_spinlock
+ * to maintain ptr */
+ PRINTM(MDAT_D,
+ "get highest prio ptr %p, tid %d\n",
+ ptr, *tid);
+ LEAVE();
+ return ptr;
+ }
+
+ ptr = ptr->pnext;
+ if (ptr ==
+ (raListTbl *)&tid_ptr->ra_list)
+ ptr = ptr->pnext;
+ } while (ptr != head);
+ }
+
+ /* If priv still has packets queued, reset to
+ * HIGH_PRIO_TID */
+ if (util_scalar_read(pmadapter->pmoal_handle,
+ &priv_tmp->wmm.tx_pkts_queued,
+ MNULL, MNULL))
+ util_scalar_write(
+ pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ HIGH_PRIO_TID, MNULL, MNULL);
+ else
+ /* No packet at any TID for this priv. Mark as
+ * such to skip checking TIDs for this priv
+ * (until pkt is added). */
+ util_scalar_write(
+ pmadapter->pmoal_handle,
+ &priv_tmp->wmm.highest_queued_prio,
+ NO_PKT_PRIO_TID, MNULL, MNULL);
+
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv_tmp->wmm.ra_list_spinlock);
+
+ next_intf:
+ bssprio_node = bssprio_node->pnext;
+ if (bssprio_node ==
+ (mlan_bssprio_node *)&pmadapter->bssprio_tbl[j]
+ .bssprio_head)
+ bssprio_node = bssprio_node->pnext;
+ pmadapter->bssprio_tbl[j].bssprio_cur = bssprio_node;
+ } while (bssprio_node != bssprio_head);
+ }
+
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief This function gets the number of packets in the Tx queue
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param max_buf_size Maximum buffer size
+ *
+ * @return Packet count
+ */
+static int wlan_num_pkts_in_txq(mlan_private *priv, raListTbl *ptr,
+ int max_buf_size)
+{
+ int count = 0, total_size = 0;
+ pmlan_buffer pmbuf;
+
+ ENTER();
+
+ for (pmbuf = (pmlan_buffer)ptr->buf_head.pnext;
+ pmbuf != (pmlan_buffer)(&ptr->buf_head); pmbuf = pmbuf->pnext) {
+ total_size += pmbuf->data_len;
+ if (total_size < max_buf_size)
+ ++count;
+ else
+ break;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function sends a single packet
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static INLINE void wlan_send_single_packet(pmlan_private priv, raListTbl *ptr,
+ int ptrindex)
+{
+ pmlan_buffer pmbuf;
+ pmlan_buffer pmbuf_next;
+ mlan_tx_param tx_param;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ if (pmbuf) {
+ PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ ptr->total_pkts--;
+ pmbuf_next = (pmlan_buffer)util_peek_list(
+ pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) :
+ 0);
+ status = wlan_process_tx(priv, pmbuf, &tx_param);
+
+ if (status == MLAN_STATUS_RESOURCE) {
+ /** Queue the packet back at the head */
+ PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n",
+ ptr, pmbuf);
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ priv->wmm.pkts_queued[ptrindex]++;
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ (pmlan_linked_list)pmbuf, MNULL,
+ MNULL);
+
+ ptr->total_pkts++;
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ } else {
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr =
+ ptr;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority]
+ .bssprio_cur->pnext;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ PRINTM(MINFO, "Nothing to send\n");
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function checks if this mlan_buffer is already processed.
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ *
+ * @return MTRUE or MFALSE
+ */
+static INLINE int wlan_is_ptr_processed(mlan_private *priv, raListTbl *ptr)
+{
+ pmlan_buffer pmbuf;
+
+ pmbuf = (pmlan_buffer)util_peek_list(priv->adapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ if (pmbuf && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
+ return MTRUE;
+
+ return MFALSE;
+}
+
+/**
+ * @brief This function sends a single packet that has been processed
+ *
+ * @param priv A pointer to mlan_private
+ * @param ptr A pointer to RA list table
+ * @param ptrindex ptr's TID index
+ *
+ * @return N/A
+ */
+static INLINE void wlan_send_processed_packet(pmlan_private priv,
+ raListTbl *ptr, int ptrindex)
+{
+ pmlan_buffer pmbuf_next = MNULL;
+ mlan_tx_param tx_param;
+ pmlan_buffer pmbuf;
+ pmlan_adapter pmadapter = priv->adapter;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ if (pmbuf) {
+ pmbuf_next = (pmlan_buffer)util_peek_list(
+ pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ tx_param.next_pkt_len =
+ ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) :
+ 0);
+
+ ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf,
+ &tx_param);
+ switch (ret) {
+#ifdef USB
+ case MLAN_STATUS_PRESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
+ break;
+#endif
+ case MLAN_STATUS_RESOURCE:
+ PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ util_enqueue_list_head(pmadapter->pmoal_handle,
+ &ptr->buf_head,
+ (pmlan_linked_list)pmbuf, MNULL,
+ MNULL);
+
+ pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ break;
+ case MLAN_STATUS_FAILURE:
+ PRINTM(MERROR, "Error: Failed to write data\n");
+ pmadapter->dbg.num_tx_host_to_card_failure++;
+ pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ case MLAN_STATUS_PENDING:
+ break;
+ case MLAN_STATUS_SUCCESS:
+ DBG_HEXDUMP(MDAT_D, "Tx",
+ pmbuf->pbuf + pmbuf->data_offset,
+ MIN(pmbuf->data_len + sizeof(TxPD),
+ MAX_DATA_DUMP_LEN));
+ wlan_write_data_complete(pmadapter, pmbuf, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != MLAN_STATUS_RESOURCE) {
+ pmadapter->callbacks.moal_spin_lock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr =
+ ptr;
+ ptr->total_pkts--;
+ }
+ pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
+ pmadapter->bssprio_tbl[priv->bss_priority]
+ .bssprio_cur->pnext;
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL,
+ MNULL);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ }
+ } else {
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ }
+}
+
+/**
+ * @brief This function dequeues a packet
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
+{
+ raListTbl *ptr;
+ pmlan_private priv = MNULL;
+ int ptrindex = 0;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ int tid_del = 0;
+ int tid = 0;
+ mlan_buffer *pmbuf = MNULL;
+
+ ENTER();
+
+ ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex);
+ if (!ptr) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr
+ * when it returns a pointer (for the priv it returns),
+ * and is unlocked in wlan_send_processed_packet,
+ * wlan_send_single_packet or wlan_11n_aggregate_pkt.
+ * The spinlock would be required for some parts of both of function.
+ * But, the the bulk of these function will execute w/o spinlock.
+ * Unlocking the spinlock inside these function will help us avoid
+ * taking the spinlock again, check to see if the ptr is still
+ * valid and then proceed. This is done purely to increase
+ * execution time. */
+
+ /* Note:- Also, anybody adding code which does not get into
+ * wlan_send_processed_packet, wlan_send_single_packet, or
+ * wlan_11n_aggregate_pkt should make sure ra_list_spinlock
+ * is freed. Otherwise there would be a lock up. */
+
+ tid = wlan_get_tid(priv->adapter, ptr);
+ if (tid >= MAX_NUM_TID)
+ tid = wlan_wmm_downgrade_tid(priv, tid);
+
+ if (wlan_is_ptr_processed(priv, ptr)) {
+ wlan_send_processed_packet(priv, ptr, ptrindex);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (ptr->del_ba_count >= DEL_BA_THRESHOLD)
+ wlan_update_del_ba_count(priv, ptr);
+ if (pmadapter->tp_state_on) {
+ pmbuf = (pmlan_buffer)util_peek_list(
+ pmadapter->pmoal_handle, &ptr->buf_head, MNULL, MNULL);
+ if (pmbuf) {
+ pmadapter->callbacks.moal_tp_accounting(
+ pmadapter->pmoal_handle, pmbuf->pdesc, 3);
+ if (pmadapter->tp_state_drop_point == 3) {
+ pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle, &ptr->buf_head,
+ MNULL, MNULL);
+ PRINTM(MERROR, "Dequeuing the packet %p %p\n",
+ ptr, pmbuf);
+ priv->wmm.pkts_queued[ptrindex]--;
+ util_scalar_decrement(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ MNULL, MNULL);
+ ptr->total_pkts--;
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_SUCCESS);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ }
+ if (!ptr->is_11n_enabled ||
+ (ptr->ba_status || ptr->del_ba_count >= DEL_BA_THRESHOLD)
+#ifdef STA_SUPPORT
+ || priv->wps.session_enable
+#endif /* STA_SUPPORT */
+ ) {
+ if (ptr->is_11n_enabled && ptr->ba_status &&
+ ptr->amsdu_in_ampdu &&
+ wlan_is_amsdu_allowed(priv, ptr, tid) &&
+ (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
+ MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, priv->intf_hr_len,
+ ptrindex);
+ } else
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ } else {
+ if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
+ (ptr->packet_count > ptr->ba_packet_threshold)) {
+ if (wlan_is_bastream_avail(priv)) {
+ PRINTM(MINFO,
+ "BA setup threshold %d reached. tid=%d\n",
+ ptr->packet_count, tid);
+ if (!wlan_11n_get_txbastream_tbl(
+ priv, tid, ptr->ra, MFALSE)) {
+ wlan_11n_create_txbastream_tbl(
+ priv, ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_addba(priv, tid, ptr->ra);
+ }
+ } else if (wlan_find_stream_to_delete(priv, ptr, tid,
+ &tid_del, ra)) {
+ PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del,
+ tid);
+ if (!wlan_11n_get_txbastream_tbl(
+ priv, tid, ptr->ra, MFALSE)) {
+ wlan_11n_create_txbastream_tbl(
+ priv, ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ wlan_send_delba(priv, MNULL, tid_del,
+ ra, 1);
+ }
+ }
+ }
+ if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
+ (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
+ MIN_NUM_AMSDU)) {
+ wlan_11n_aggregate_pkt(priv, ptr, priv->intf_hr_len,
+ ptrindex);
+ } else {
+ wlan_send_single_packet(priv, ptr, ptrindex);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief update tx_pause flag in ra_list
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ * @param tx_pause tx_pause flag (0/1)
+ *
+ *
+ * @return packets queued for this mac
+ */
+t_u16 wlan_update_ralist_tx_pause(pmlan_private priv, t_u8 *mac, t_u8 tx_pause)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+ ENTER();
+
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list && ra_list->tx_pause != tx_pause) {
+ pkt_cnt += ra_list->total_pkts;
+ ra_list->tx_pause = tx_pause;
+ if (tx_pause)
+ priv->wmm.pkts_paused[i] += ra_list->total_pkts;
+ else
+ priv->wmm.pkts_paused[i] -= ra_list->total_pkts;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ MNULL, MNULL);
+ if (tx_pause)
+ tx_pkts_queued -= pkt_cnt;
+ else
+ tx_pkts_queued += pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued,
+ MNULL, MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
+ MNULL, MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+ return pkt_cnt;
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Get the threshold value for BA setup using system time.
+ *
+ * @param pmadapter Pointer to the mlan_adapter structure
+ *
+ * @return threshold value.
+ */
+t_u8 wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
+{
+ t_u32 sec, usec;
+ t_u8 ba_threshold = 0;
+
+ ENTER();
+
+ /* setup ba_packet_threshold here random number between
+ [BA_SETUP_PACKET_OFFSET,
+ BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
+
+#define BA_SETUP_MAX_PACKET_THRESHOLD 16
+
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
+ &usec);
+ sec = (sec & 0xFFFF) + (sec >> 16);
+ usec = (usec & 0xFFFF) + (usec >> 16);
+
+ ba_threshold = (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
+ pmadapter->min_ba_threshold;
+ PRINTM(MINFO, "pmadapter->min_ba_threshold = %d\n",
+ pmadapter->min_ba_threshold);
+ PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
+
+ LEAVE();
+ return ba_threshold;
+}
+
+/**
+ * @brief This function cleans Tx/Rx queues
+ *
+ * @param priv A pointer to mlan_private
+ *
+ * @return N/A
+ */
+t_void wlan_clean_txrx(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ t_u8 i = 0;
+
+ ENTER();
+ wlan_cleanup_bypass_txq(priv);
+ wlan_11n_cleanup_reorder_tbl(priv);
+ wlan_11n_deleteall_txbastream_tbl(priv);
+#if defined(USB)
+ if (IS_USB(pmadapter->card_type))
+ wlan_reset_usb_tx_aggr(priv->adapter);
+#endif
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type))
+ wlan_clean_pcie_ring_buf(priv->adapter);
+#endif
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ wlan_wmm_cleanup_queues(priv);
+ wlan_wmm_delete_all_ralist(priv);
+ memcpy_ext(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid),
+ sizeof(tos_to_tid));
+ for (i = 0; i < MAX_NUM_TID; i++)
+ tos_to_tid_inv[tos_to_tid[i]] = (t_u8)i;
+#ifdef UAP_SUPPORT
+ priv->num_drop_pkts = 0;
+#endif
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type)) {
+ memset(pmadapter, pmadapter->pcard_sd->mpa_tx_count, 0,
+ sizeof(pmadapter->pcard_sd->mpa_tx_count));
+ pmadapter->pcard_sd->mpa_sent_no_ports = 0;
+ pmadapter->pcard_sd->mpa_sent_last_pkt = 0;
+ memset(pmadapter, pmadapter->pcard_sd->mpa_rx_count, 0,
+ sizeof(pmadapter->pcard_sd->mpa_rx_count));
+ }
+#endif
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+}
+
+/**
+ * @brief Set the WMM queue priorities to their default values
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void wlan_wmm_default_queue_priorities(pmlan_private priv)
+{
+ ENTER();
+
+ /* Default queue priorities: VO->VI->BE->BK */
+ priv->wmm.queue_priority[0] = WMM_AC_VO;
+ priv->wmm.queue_priority[1] = WMM_AC_VI;
+ priv->wmm.queue_priority[2] = WMM_AC_BE;
+ priv->wmm.queue_priority[3] = WMM_AC_BK;
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize WMM priority queues
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param pwmm_ie Pointer to the IEEEtypes_WmmParameter_t data struct
+ *
+ * @return N/A
+ */
+void wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t *pwmm_ie)
+{
+ t_u16 cw_min, avg_back_off, tmp[4];
+ t_u32 i, j, num_ac;
+ t_u8 ac_idx;
+
+ ENTER();
+
+ if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, just set the defaults and return */
+ wlan_wmm_default_queue_priorities(priv);
+ LEAVE();
+ return;
+ }
+ memset(priv->adapter, tmp, 0, sizeof(tmp));
+
+ HEXDUMP("WMM: setup_queue_priorities: param IE", (t_u8 *)pwmm_ie,
+ sizeof(IEEEtypes_WmmParameter_t));
+
+ PRINTM(MINFO,
+ "WMM Parameter IE: version=%d, "
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
+ pwmm_ie->reserved);
+
+ for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
+ cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
+ avg_back_off = (cw_min >> 1) +
+ pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
+
+ ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac]
+ .aci_aifsn.aci];
+ priv->wmm.queue_priority[ac_idx] = ac_idx;
+ tmp[ac_idx] = avg_back_off;
+
+ PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
+ cw_min, avg_back_off);
+ PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
+ }
+
+ HEXDUMP("WMM: avg_back_off", (t_u8 *)tmp, sizeof(tmp));
+ HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
+ sizeof(priv->wmm.queue_priority));
+
+ /* Bubble sort */
+ for (i = 0; i < num_ac; i++) {
+ for (j = 1; j < num_ac - i; j++) {
+ if (tmp[j - 1] > tmp[j]) {
+ SWAP_U16(tmp[j - 1], tmp[j]);
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ } else if (tmp[j - 1] == tmp[j]) {
+ if (priv->wmm.queue_priority[j - 1] <
+ priv->wmm.queue_priority[j]) {
+ SWAP_U8(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ }
+ }
+ }
+ }
+
+ wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
+
+ HEXDUMP("WMM: avg_back_off, sort", (t_u8 *)tmp, sizeof(tmp));
+ DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort",
+ priv->wmm.queue_priority, sizeof(priv->wmm.queue_priority));
+ LEAVE();
+}
+
+/**
+ * @brief Downgrade WMM priority queue
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void wlan_wmm_setup_ac_downgrade(pmlan_private priv)
+{
+ int ac_val;
+
+ ENTER();
+
+ PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+ if (priv->wmm_enabled == MFALSE) {
+ /* WMM is not enabled, default priorities */
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val] =
+ (mlan_wmm_ac_e)ac_val;
+ }
+ } else {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val] =
+ wlan_wmm_eval_downgrade_ac(
+ priv, (mlan_wmm_ac_e)ac_val);
+ PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n", ac_val,
+ priv->wmm.ac_down_graded_vals[ac_val]);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Allocate and add a RA list for all TIDs with the given RA
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra Address of the receiver STA (AP in case of infra)
+ *
+ * @return N/A
+ */
+void wlan_ralist_add(mlan_private *priv, t_u8 *ra)
+{
+ int i;
+ raListTbl *ra_list;
+ pmlan_adapter pmadapter = priv->adapter;
+
+ ENTER();
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
+ PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
+ if (!ra_list)
+ break;
+ ra_list->max_amsdu = 0;
+ ra_list->ba_status = BA_STREAM_NOT_SETUP;
+ ra_list->amsdu_in_ampdu = MFALSE;
+ if (queuing_ra_based(priv)) {
+ ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu =
+ get_station_max_amsdu_size(priv, ra);
+ ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
+ } else {
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = priv->max_amsdu;
+ }
+
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA, "ralist %p: is_11n_enabled=%d max_amsdu=%d\n",
+ ra_list, ra_list->is_11n_enabled, ra_list->max_amsdu);
+
+ if (ra_list->is_11n_enabled) {
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(pmadapter);
+ }
+
+ util_enqueue_list_tail(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list)ra_list, MNULL,
+ MNULL);
+
+ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Initialize the WMM parameter.
+ *
+ * @param pmadapter Pointer to the mlan_adapter data structure
+ *
+ * @return N/A
+ */
+t_void wlan_init_wmm_param(pmlan_adapter pmadapter)
+{
+ /* Reuse the same structure of WmmAcParameters_t for configuration
+ * purpose here. the definition of acm bit is changed to ucm (user
+ * configuration mode) FW will take the setting of
+ * aifsn,ecw_max,ecw_min, tx_op_limit only when ucm is set to 1.
+ * othewise the default setting/behavoir in firmware will be used.
+ */
+ pmadapter->ac_params[AC_BE].aci_aifsn.acm = 0;
+ pmadapter->ac_params[AC_BE].aci_aifsn.aci = AC_BE;
+ pmadapter->ac_params[AC_BE].aci_aifsn.aifsn = 3;
+ pmadapter->ac_params[AC_BE].ecw.ecw_max = 10;
+ pmadapter->ac_params[AC_BE].ecw.ecw_min = 4;
+ pmadapter->ac_params[AC_BE].tx_op_limit = 0;
+
+ pmadapter->ac_params[AC_BK].aci_aifsn.acm = 0;
+ pmadapter->ac_params[AC_BK].aci_aifsn.aci = AC_BK;
+ pmadapter->ac_params[AC_BK].aci_aifsn.aifsn = 7;
+ pmadapter->ac_params[AC_BK].ecw.ecw_max = 10;
+ pmadapter->ac_params[AC_BK].ecw.ecw_min = 4;
+ pmadapter->ac_params[AC_BK].tx_op_limit = 0;
+
+ pmadapter->ac_params[AC_VI].aci_aifsn.acm = 0;
+ pmadapter->ac_params[AC_VI].aci_aifsn.aci = AC_VI;
+ pmadapter->ac_params[AC_VI].aci_aifsn.aifsn = 2;
+ pmadapter->ac_params[AC_VI].ecw.ecw_max = 4;
+ pmadapter->ac_params[AC_VI].ecw.ecw_min = 3;
+ pmadapter->ac_params[AC_VI].tx_op_limit = 188;
+
+ pmadapter->ac_params[AC_VO].aci_aifsn.acm = 0;
+ pmadapter->ac_params[AC_VO].aci_aifsn.aci = AC_VO;
+ pmadapter->ac_params[AC_VO].aci_aifsn.aifsn = 2;
+ pmadapter->ac_params[AC_VO].ecw.ecw_max = 3;
+ pmadapter->ac_params[AC_VO].ecw.ecw_min = 2;
+ pmadapter->ac_params[AC_VO].tx_op_limit = 102;
+}
+
+/**
+ * @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ * @param pmadapter Pointer to the mlan_adapter data structure
+ *
+ * @return N/A
+ */
+t_void wlan_wmm_init(pmlan_adapter pmadapter)
+{
+ int i, j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ priv = pmadapter->priv[j];
+ if (priv) {
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].amsdu =
+ tos_to_tid_inv[i];
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user =
+ tos_to_tid_inv[i];
+ priv->ibss_ampdu[i] =
+ priv->aggr_prio_tbl[i].ampdu_user;
+ priv->wmm.pkts_queued[i] = 0;
+ priv->wmm.pkts_paused[i] = 0;
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
+ }
+ priv->wmm.drv_pkt_delay_max = WMM_DRV_DELAY_MAX;
+
+ priv->aggr_prio_tbl[6].amsdu = BA_STREAM_NOT_ALLOWED;
+ priv->aggr_prio_tbl[7].amsdu = BA_STREAM_NOT_ALLOWED;
+ priv->aggr_prio_tbl[6].ampdu_ap =
+ priv->aggr_prio_tbl[6].ampdu_user =
+ BA_STREAM_NOT_ALLOWED;
+ priv->ibss_ampdu[6] = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].ampdu_ap =
+ priv->aggr_prio_tbl[7].ampdu_user =
+ BA_STREAM_NOT_ALLOWED;
+ priv->ibss_ampdu[7] = BA_STREAM_NOT_ALLOWED;
+
+ priv->add_ba_param.timeout =
+ MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+ priv->add_ba_param.tx_win_size =
+ MLAN_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MLAN_STA_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ priv->add_ba_param.tx_win_size =
+ MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MLAN_WFD_AMPDU_DEF_TXRXWINSIZE;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ MLAN_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MLAN_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+#endif
+ priv->user_rxwinsize = priv->add_ba_param.rx_win_size;
+ priv->add_ba_param.tx_amsdu = MTRUE;
+ priv->add_ba_param.rx_amsdu = MTRUE;
+ memset(priv->adapter, priv->rx_seq, 0xff,
+ sizeof(priv->rx_seq));
+ wlan_wmm_default_queue_priorities(priv);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Setup the queue priorities and downgrade any queues as required
+ * by the WMM info. Setups default values if WMM is not active
+ * for this association.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+void wlan_wmm_setup_queues(pmlan_private priv)
+{
+ ENTER();
+ wlan_wmm_setup_queue_priorities(priv, MNULL);
+ wlan_wmm_setup_ac_downgrade(priv);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Send a command to firmware to retrieve the current WMM status
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
+ */
+mlan_status wlan_cmd_wmm_status_change(pmlan_private priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0,
+ MNULL);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Check if wmm TX queue is empty
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return MFALSE if not empty; MTRUE if empty
+ */
+int wlan_wmm_lists_empty(pmlan_adapter pmadapter)
+{
+ int j;
+ pmlan_private priv;
+
+ ENTER();
+
+ for (j = 0; j < pmadapter->priv_num; ++j) {
+ priv = pmadapter->priv[j];
+ if (priv) {
+ if ((priv->port_ctrl_mode == MTRUE) &&
+ (priv->port_open == MFALSE)) {
+ PRINTM(MINFO,
+ "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
+ j);
+ continue;
+ }
+ if (priv->tx_pause)
+ continue;
+
+ if (util_scalar_read(
+ pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ pmadapter->callbacks.moal_spin_lock,
+ pmadapter->callbacks.moal_spin_unlock)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ }
+
+ LEAVE();
+ return MTRUE;
+}
+
+/**
+ * @brief Get ralist node
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param tid TID
+ * @param ra_addr Pointer to the route address
+ *
+ * @return ra_list or MNULL
+ */
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 *ra_addr)
+{
+ raListTbl *ra_list;
+ ENTER();
+ ra_list =
+ (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid].ra_list,
+ MNULL, MNULL);
+ while (ra_list &&
+ (ra_list != (raListTbl *)&priv->wmm.tid_tbl_ptr[tid].ra_list)) {
+ if (!memcmp(priv->adapter, ra_list->ra, ra_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ LEAVE();
+ return ra_list;
+ }
+ ra_list = ra_list->pnext;
+ }
+ LEAVE();
+ return MNULL;
+}
+
+/**
+ * @brief Check if RA list is valid or not
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list Pointer to raListTbl
+ * @param ptrindex TID pointer index
+ *
+ * @return MTRUE- valid. MFALSE- invalid.
+ */
+int wlan_is_ralist_valid(mlan_private *priv, raListTbl *ra_list, int ptrindex)
+{
+ raListTbl *rlist;
+
+ ENTER();
+
+ rlist = (raListTbl *)util_peek_list(
+ priv->adapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[ptrindex].ra_list, MNULL, MNULL);
+
+ while (rlist &&
+ (rlist !=
+ (raListTbl *)&priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
+ if (rlist == ra_list) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ rlist = rlist->pnext;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief Update an existing raList with a new RA and 11n capability
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param old_ra Old receiver address
+ * @param new_ra New receiver address
+ *
+ * @return integer count of updated nodes
+ */
+int wlan_ralist_update(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra)
+{
+ t_u8 tid;
+ int update_count;
+ raListTbl *ra_list;
+
+ ENTER();
+
+ update_count = 0;
+
+ for (tid = 0; tid < MAX_NUM_TID; ++tid) {
+ ra_list = wlan_wmm_get_ralist_node(priv, tid, old_ra);
+
+ if (ra_list) {
+ update_count++;
+
+ if (queuing_ra_based(priv)) {
+ ra_list->is_11n_enabled =
+ wlan_is_11n_enabled(priv, new_ra);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu =
+ get_station_max_amsdu_size(
+ priv, new_ra);
+ } else {
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = priv->max_amsdu;
+ }
+
+ ra_list->tx_pause = MFALSE;
+ ra_list->packet_count = 0;
+ ra_list->ba_packet_threshold =
+ wlan_get_random_ba_threshold(priv->adapter);
+ ra_list->amsdu_in_ampdu = MFALSE;
+ ra_list->ba_status = BA_STREAM_NOT_SETUP;
+ PRINTM(MINFO,
+ "ralist_update: %p, %d, " MACSTR "-->" MACSTR
+ "\n",
+ ra_list, ra_list->is_11n_enabled,
+ MAC2STR(ra_list->ra), MAC2STR(new_ra));
+
+ memcpy_ext(priv->adapter, ra_list->ra, new_ra,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ }
+ }
+
+ LEAVE();
+ return update_count;
+}
+
+/**
+ * @brief Add packet to WMM queue
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ * @param pmbuf Pointer to the mlan_buffer data struct
+ *
+ * @return N/A
+ */
+t_void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u32 tid;
+ raListTbl *ra_list;
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
+#ifdef UAP_SUPPORT
+ psta_node sta_ptr = MNULL;
+#endif
+
+ ENTER();
+
+ pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
+ if (!priv->media_connected) {
+ PRINTM_NETINTF(MWARN, priv);
+ PRINTM(MWARN, "Drop packet %p in disconnect state\n", pmbuf);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+ tid = pmbuf->priority;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ tid_down = wlan_wmm_downgrade_tid(priv, tid);
+
+ /* In case of infra as we have already created the list during
+ association we just don't have to call get_queue_raptr, we will have
+ only 1 raptr for a tid in case of infra */
+ if (!queuing_ra_based(priv)) {
+ ra_list = (raListTbl *)util_peek_list(
+ pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[tid_down].ra_list, MNULL, MNULL);
+ } else {
+ memcpy_ext(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ /** put multicast/broadcast packet in the same ralist */
+ if (ra[0] & 0x01)
+ memset(pmadapter, ra, 0xff, sizeof(ra));
+#ifdef UAP_SUPPORT
+ else if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ sta_ptr = wlan_get_station_entry(priv, ra);
+ if (sta_ptr) {
+ if (!sta_ptr->is_wmm_enabled &&
+ !priv->is_11ac_enabled) {
+ tid_down = wlan_wmm_downgrade_tid(priv,
+ 0xff);
+ }
+ }
+ }
+#endif
+ ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
+ }
+
+ if (!ra_list) {
+ PRINTM_NETINTF(MWARN, priv);
+ PRINTM(MWARN,
+ "Drop packet %p, ra_list=%p, media_connected=%d\n",
+ pmbuf, ra_list, priv->media_connected);
+ pmadapter->callbacks.moal_spin_unlock(
+ pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock);
+ wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
+ LEAVE();
+ return;
+ }
+
+ PRINTM_NETINTF(MDATA, priv);
+ PRINTM(MDATA,
+ "Adding pkt %p (priority=%d, tid_down=%d) to ra_list %p\n",
+ pmbuf, pmbuf->priority, tid_down, ra_list);
+ util_enqueue_list_tail(pmadapter->pmoal_handle, &ra_list->buf_head,
+ (pmlan_linked_list)pmbuf, MNULL, MNULL);
+
+ ra_list->total_pkts++;
+ ra_list->packet_count++;
+
+ priv->wmm.pkts_queued[tid_down]++;
+ if (ra_list->tx_pause) {
+ priv->wmm.pkts_paused[tid_down]++;
+ } else {
+ util_scalar_increment(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ /* if highest_queued_prio < prio(tid_down), set it to
+ * prio(tid_down) */
+ util_scalar_conditional_write(
+ pmadapter->pmoal_handle, &priv->wmm.highest_queued_prio,
+ MLAN_SCALAR_COND_LESS_THAN, tos_to_tid_inv[tid_down],
+ tos_to_tid_inv[tid_down], MNULL, MNULL);
+ }
+ /* Record the current time the packet was queued; used to determine
+ * the amount of time the packet was queued in the driver before it
+ * was sent to the firmware. The delay is then sent along with the
+ * packet to the firmware for aggregate delay calculation for stats
+ * and MSDU lifetime expiry.
+ */
+ pmadapter->callbacks.moal_get_system_time(
+ pmadapter->pmoal_handle, &pmbuf->in_ts_sec, &pmbuf->in_ts_usec);
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ * The GET_WMM_STATUS response may contain multiple TLVs for:
+ * - AC Queue status TLVs
+ * - Current WMM Parameter IE TLV
+ * - Admission Control action frame TLVs
+ *
+ * This function parses the TLVs and then calls further functions
+ * to process any changes in the queue prioritize or state.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ptlv Pointer to the tlv block returned in the response.
+ * @param resp_len Length of TLV block
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_get_status(pmlan_private priv, t_u8 *ptlv,
+ int resp_len)
+{
+ t_u8 *pcurrent = ptlv;
+ t_u32 tlv_len;
+ t_u8 send_wmm_event;
+ MrvlIEtypes_Data_t *ptlv_hdr;
+ MrvlIEtypes_WmmQueueStatus_t *ptlv_wmm_q_status;
+ IEEEtypes_WmmParameter_t *pwmm_param_ie = MNULL;
+ WmmAcStatus_t *pac_status;
+
+ MrvlIETypes_ActionFrame_t *ptlv_action;
+ IEEEtypes_Action_WMM_AddTsRsp_t *padd_ts_rsp;
+ IEEEtypes_Action_WMM_DelTs_t *pdel_ts;
+
+ ENTER();
+
+ send_wmm_event = MFALSE;
+
+ PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
+ HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
+
+ while (resp_len >= sizeof(ptlv_hdr->header)) {
+ ptlv_hdr = (MrvlIEtypes_Data_t *)pcurrent;
+ tlv_len = wlan_le16_to_cpu(ptlv_hdr->header.len);
+ if ((tlv_len + sizeof(ptlv_hdr->header)) > resp_len) {
+ PRINTM(MERROR,
+ "WMM get status: Error in processing TLV buffer\n");
+ resp_len = 0;
+ continue;
+ }
+
+ switch (wlan_le16_to_cpu(ptlv_hdr->header.type)) {
+ case TLV_TYPE_WMMQSTATUS:
+ ptlv_wmm_q_status =
+ (MrvlIEtypes_WmmQueueStatus_t *)ptlv_hdr;
+ PRINTM(MEVENT, "WMM_STATUS: QSTATUS TLV: %d\n",
+ ptlv_wmm_q_status->queue_index);
+
+ PRINTM(MINFO,
+ "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+ ptlv_wmm_q_status->queue_index,
+ ptlv_wmm_q_status->flow_required,
+ ptlv_wmm_q_status->disabled);
+
+ pac_status =
+ &priv->wmm.ac_status[ptlv_wmm_q_status
+ ->queue_index];
+ pac_status->disabled = ptlv_wmm_q_status->disabled;
+ pac_status->flow_required =
+ ptlv_wmm_q_status->flow_required;
+ pac_status->flow_created =
+ ptlv_wmm_q_status->flow_created;
+ break;
+
+ case TLV_TYPE_VENDOR_SPECIFIC_IE: /* WMM_IE */
+ /*
+ * Point the regular IEEE IE 2 bytes into the NXP IE
+ * and setup the IEEE IE type and length byte fields
+ */
+
+ PRINTM(MEVENT, "WMM STATUS: WMM IE\n");
+
+ HEXDUMP("WMM: WMM TLV:", (t_u8 *)ptlv_hdr, tlv_len + 4);
+
+ pwmm_param_ie =
+ (IEEEtypes_WmmParameter_t *)(pcurrent + 2);
+ pwmm_param_ie->vend_hdr.len = (t_u8)tlv_len;
+ pwmm_param_ie->vend_hdr.element_id = WMM_IE;
+
+ PRINTM(MINFO,
+ "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+ pwmm_param_ie->qos_info.para_set_count);
+
+ memcpy_ext(priv->adapter,
+ (t_u8 *)&priv->curr_bss_params.bss_descriptor
+ .wmm_ie,
+ pwmm_param_ie,
+ (pwmm_param_ie->vend_hdr.len + 2),
+ sizeof(IEEEtypes_WmmParameter_t));
+ send_wmm_event = MTRUE;
+ break;
+
+ case TLV_TYPE_IEEE_ACTION_FRAME:
+ PRINTM(MEVENT, "WMM_STATUS: IEEE Action Frame\n");
+ ptlv_action = (MrvlIETypes_ActionFrame_t *)pcurrent;
+
+ ptlv_action->actionFrame.wmmAc.tspecAct.category =
+ wlan_le32_to_cpu(ptlv_action->actionFrame.wmmAc
+ .tspecAct.category);
+ if (ptlv_action->actionFrame.wmmAc.tspecAct.category ==
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC) {
+ ptlv_action->actionFrame.wmmAc.tspecAct.action =
+ wlan_le32_to_cpu(
+ ptlv_action->actionFrame.wmmAc
+ .tspecAct.action);
+ switch (ptlv_action->actionFrame.wmmAc.tspecAct
+ .action) {
+ case TSPEC_ACTION_CODE_ADDTS_RSP:
+ padd_ts_rsp = &ptlv_action->actionFrame
+ .wmmAc.addTsRsp;
+ wlan_send_wmmac_host_event(
+ priv, "ADDTS_RSP",
+ ptlv_action->srcAddr,
+ padd_ts_rsp->tspecIE.TspecBody
+ .TSInfo.TID,
+ padd_ts_rsp->tspecIE.TspecBody
+ .TSInfo.UserPri,
+ padd_ts_rsp->statusCode);
+ break;
+
+ case TSPEC_ACTION_CODE_DELTS:
+ pdel_ts = &ptlv_action->actionFrame
+ .wmmAc.delTs;
+ wlan_send_wmmac_host_event(
+ priv, "DELTS_RX",
+ ptlv_action->srcAddr,
+ pdel_ts->tspecIE.TspecBody
+ .TSInfo.TID,
+ pdel_ts->tspecIE.TspecBody
+ .TSInfo.UserPri,
+ pdel_ts->reasonCode);
+ break;
+
+ case TSPEC_ACTION_CODE_ADDTS_REQ:
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pcurrent += (tlv_len + sizeof(ptlv_hdr->header));
+ resp_len -= (tlv_len + sizeof(ptlv_hdr->header));
+ }
+
+ wlan_wmm_setup_queue_priorities(priv, pwmm_param_ie);
+ wlan_wmm_setup_ac_downgrade(priv);
+
+ if (send_wmm_event) {
+ wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE,
+ MNULL);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Call back from the command module to allow insertion of a WMM TLV
+ *
+ * If the BSS we are associating to supports WMM, add the required WMM
+ * Information IE to the association request command buffer in the form
+ * of a NXP extended IEEE IE.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ppassoc_buf Output parameter: Pointer to the TLV output buffer,
+ * modified on return to point after the appended WMM TLV
+ * @param pwmm_ie Pointer to the WMM IE for the BSS we are joining
+ * @param pht_cap Pointer to the HT IE for the BSS we are joining
+ *
+ * @return Length of data appended to the association tlv buffer
+ */
+t_u32 wlan_wmm_process_association_req(pmlan_private priv, t_u8 **ppassoc_buf,
+ IEEEtypes_WmmParameter_t *pwmm_ie,
+ IEEEtypes_HTCap_t *pht_cap)
+{
+ MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
+ t_u32 ret_len = 0;
+
+ ENTER();
+
+ /* Null checks */
+ if (!ppassoc_buf) {
+ LEAVE();
+ return 0;
+ }
+ if (!(*ppassoc_buf)) {
+ LEAVE();
+ return 0;
+ }
+
+ if (!pwmm_ie) {
+ LEAVE();
+ return 0;
+ }
+
+ PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
+ pwmm_ie->vend_hdr.element_id);
+
+ if ((priv->wmm_required ||
+ (pht_cap && (pht_cap->ieee_hdr.element_id == HT_CAPABILITY) &&
+ (priv->config_bands & BAND_GN || priv->config_bands & BAND_AN))) &&
+ pwmm_ie->vend_hdr.element_id == WMM_IE) {
+ pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *)*ppassoc_buf;
+ pwmm_tlv->header.type = (t_u16)wmm_info_ie[0];
+ pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
+ pwmm_tlv->header.len = (t_u16)wmm_info_ie[1];
+ memcpy_ext(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2],
+ pwmm_tlv->header.len, pwmm_tlv->header.len);
+ if (pwmm_ie->qos_info.qos_uapsd)
+ memcpy_ext(priv->adapter,
+ (t_u8 *)(pwmm_tlv->wmm_ie +
+ pwmm_tlv->header.len -
+ sizeof(priv->wmm_qosinfo)),
+ &priv->wmm_qosinfo,
+ sizeof(priv->wmm_qosinfo),
+ sizeof(priv->wmm_qosinfo));
+
+ ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
+ pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
+
+ HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *)pwmm_tlv, ret_len);
+ *ppassoc_buf += ret_len;
+ }
+
+ LEAVE();
+ return ret_len;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Compute the time delay in the driver queues for a given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ *
+ * @param priv Ptr to the mlan_private driver data struct
+ * @param pmbuf Ptr to the mlan_buffer which has been previously timestamped
+ *
+ * @return Time delay of the packet in 2ms units after having limit applied
+ */
+t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf)
+{
+ t_u8 ret_val = 0;
+ t_u32 out_ts_sec, out_ts_usec;
+ t_s32 queue_delay;
+
+ ENTER();
+
+ priv->adapter->callbacks.moal_get_system_time(
+ priv->adapter->pmoal_handle, &out_ts_sec, &out_ts_usec);
+
+ queue_delay = (t_s32)(out_ts_sec - pmbuf->in_ts_sec) * 1000;
+ queue_delay += (t_s32)(out_ts_usec - pmbuf->in_ts_usec) / 1000;
+
+ /*
+ * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+ *
+ * Pass max value if queue_delay is beyond the uint8 range
+ */
+ ret_val = (t_u8)(MIN(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+ PRINTM(MINFO, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n", queue_delay,
+ ret_val);
+
+ LEAVE();
+ return ret_val;
+}
+
+/**
+ * @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ * @param pmadapter Pointer to the mlan_adapter driver data struct
+ *
+ * @return N/A
+ */
+void wlan_wmm_process_tx(pmlan_adapter pmadapter)
+{
+ ENTER();
+
+ do {
+ if (wlan_dequeue_tx_packet(pmadapter))
+ break;
+#ifdef SDIO
+ if (IS_SD(pmadapter->card_type) &&
+ (pmadapter->ireg & UP_LD_CMD_PORT_HOST_INT_STATUS)) {
+ wlan_send_mp_aggr_buf(pmadapter);
+ break;
+ }
+#endif
+
+#ifdef PCIE
+ if (IS_PCIE(pmadapter->card_type) &&
+ (pmadapter->ireg &
+ pmadapter->pcard_pcie->reg->host_intr_event_rdy))
+ break;
+#endif
+#ifdef USB
+ if (IS_USB(pmadapter->card_type) && pmadapter->event_received)
+ break;
+#endif
+ /* Check if busy */
+ } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag &&
+ !wlan_wmm_lists_empty(pmadapter));
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief select wmm queue
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param tid TID 0-7
+ *
+ * @return wmm_queue priority (0-3)
+ */
+t_u8 wlan_wmm_select_queue(mlan_private *pmpriv, t_u8 tid)
+{
+ pmlan_adapter pmadapter = pmpriv->adapter;
+ t_u8 i;
+ mlan_wmm_ac_e ac_down =
+ pmpriv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(
+ pmadapter, tid)];
+
+ ENTER();
+
+ for (i = 0; i < 4; i++) {
+ if (pmpriv->wmm.queue_priority[i] == ac_down) {
+ LEAVE();
+ return i;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Delete tx packets in RA list
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param ra_list_head ra list header
+ * @param tid tid
+ *
+ * @return N/A
+ */
+static INLINE t_u8 wlan_del_tx_pkts_in_ralist(pmlan_private priv,
+ mlan_list_head *ra_list_head,
+ int tid)
+{
+ raListTbl *ra_list = MNULL;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmlan_buffer pmbuf = MNULL;
+ t_u8 ret = MFALSE;
+ ENTER();
+ ra_list = (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ ra_list_head, MNULL, MNULL);
+ while (ra_list && ra_list != (raListTbl *)ra_list_head) {
+ if (ra_list->total_pkts &&
+ (ra_list->tx_pause ||
+ (ra_list->total_pkts > RX_LOW_THRESHOLD))) {
+ pmbuf = (pmlan_buffer)util_dequeue_list(
+ pmadapter->pmoal_handle, &ra_list->buf_head,
+ MNULL, MNULL);
+ if (pmbuf) {
+ PRINTM(MDATA,
+ "Drop pkts: tid=%d tx_pause=%d pkts=%d " MACSTR
+ "\n",
+ tid, ra_list->tx_pause,
+ ra_list->total_pkts,
+ MAC2STR(ra_list->ra));
+ wlan_write_data_complete(pmadapter, pmbuf,
+ MLAN_STATUS_FAILURE);
+ priv->wmm.pkts_queued[tid]--;
+ priv->num_drop_pkts++;
+ ra_list->total_pkts--;
+ if (ra_list->tx_pause)
+ priv->wmm.pkts_paused[tid]--;
+ else
+ util_scalar_decrement(
+ pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ MNULL, MNULL);
+ ret = MTRUE;
+ break;
+ }
+ }
+ ra_list = ra_list->pnext;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Drop tx pkts
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ *
+ * @return N/A
+ */
+t_void wlan_drop_tx_pkts(pmlan_private priv)
+{
+ int j;
+ static int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (j = 0; j < MAX_NUM_TID; j++, i++) {
+ if (i == MAX_NUM_TID)
+ i = 0;
+ if (wlan_del_tx_pkts_in_ralist(
+ priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i)) {
+ i++;
+ break;
+ }
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ return;
+}
+
+/**
+ * @brief Remove peer ralist
+ *
+ * @param priv A pointer to mlan_private
+ * @param mac peer mac address
+ *
+ * @return N/A
+ */
+t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac)
+{
+ raListTbl *ra_list;
+ int i;
+ pmlan_adapter pmadapter = priv->adapter;
+ t_u32 pkt_cnt = 0;
+ t_u32 tx_pkts_queued = 0;
+
+ ENTER();
+ pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
+ if (ra_list) {
+ PRINTM(MINFO, "delete sta ralist %p\n", ra_list);
+ priv->wmm.pkts_queued[i] -= ra_list->total_pkts;
+ if (ra_list->tx_pause)
+ priv->wmm.pkts_paused[i] -= ra_list->total_pkts;
+ else
+ pkt_cnt += ra_list->total_pkts;
+ wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
+
+ util_unlink_list(pmadapter->pmoal_handle,
+ &priv->wmm.tid_tbl_ptr[i].ra_list,
+ (pmlan_linked_list)ra_list, MNULL,
+ MNULL);
+ pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
+ (t_u8 *)ra_list);
+ if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr =
+ (raListTbl *)&priv->wmm.tid_tbl_ptr[i]
+ .ra_list;
+ }
+ }
+ if (pkt_cnt) {
+ tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued,
+ MNULL, MNULL);
+ tx_pkts_queued -= pkt_cnt;
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, tx_pkts_queued,
+ MNULL, MNULL);
+ util_scalar_write(priv->adapter->pmoal_handle,
+ &priv->wmm.highest_queued_prio, HIGH_PRIO_TID,
+ MNULL, MNULL);
+ }
+ pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+
+/**
+ * @brief This function prepares the command of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_addts_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
+{
+ mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *)pdata_buf;
+ HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token) +
+ sizeof(pcmd_addts->timeout_ms) +
+ sizeof(pcmd_addts->command_result) +
+ sizeof(pcmd_addts->ieee_status_code) +
+ paddts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
+ pcmd_addts->dialog_token = paddts->dialog_tok;
+ memcpy_ext(pmpriv->adapter, pcmd_addts->tspec_data, paddts->ie_data,
+ paddts->ie_data_len, WMM_TSPEC_SIZE);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of ADDTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_addts_req(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_addts *paddts = MNULL;
+ const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ paddts = (mlan_ds_wmm_addts *)&pwmm->param.addts;
+ paddts->result = wlan_le32_to_cpu(presp_addts->command_result);
+ paddts->dialog_tok = presp_addts->dialog_token;
+ paddts->status_code = (t_u32)presp_addts->ieee_status_code;
+
+ if (paddts->result == MLAN_CMD_RESULT_SUCCESS) {
+ /* The tspecData field is potentially variable in size
+ * due to extra IEs that may have been in the ADDTS
+ * response action frame. Calculate the data length from
+ * the firmware command response.
+ */
+ paddts->ie_data_len =
+ (t_u8)(resp->size -
+ sizeof(presp_addts->command_result) -
+ sizeof(presp_addts->timeout_ms) -
+ sizeof(presp_addts->dialog_token) -
+ sizeof(presp_addts->ieee_status_code) -
+ S_DS_GEN);
+
+ /* Copy the TSPEC data include any extra IEs after the
+ * TSPEC */
+ memcpy_ext(pmpriv->adapter, paddts->ie_data,
+ presp_addts->tspec_data, paddts->ie_data_len,
+ sizeof(paddts->ie_data));
+ } else {
+ paddts->ie_data_len = 0;
+ }
+ PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+ paddts->result, paddts->status_code,
+ paddts->ie_data_len);
+
+ HEXDUMP("TSPEC: ADDTS data", paddts->ie_data,
+ paddts->ie_data_len);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_delts_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
+{
+ mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *)pdata_buf;
+ HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+ cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token) +
+ sizeof(pcmd_delts->command_result) +
+ sizeof(pcmd_delts->ieee_reason_code) +
+ pdelts->ie_data_len + S_DS_GEN);
+ cmd->result = 0;
+ pcmd_delts->ieee_reason_code = (t_u8)pdelts->status_code;
+ memcpy_ext(pmpriv->adapter, pcmd_delts->tspec_data, pdelts->ie_data,
+ pdelts->ie_data_len, WMM_TSPEC_SIZE);
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of DELTS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_delts_req(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm;
+ IEEEtypes_WMM_TSPEC_t *ptspec_ie;
+ const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ pwmm->param.delts.result =
+ wlan_le32_to_cpu(presp_delts->command_result);
+
+ PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
+ presp_delts->command_result);
+
+ if (pwmm->param.delts.result == 0) {
+ ptspec_ie = (IEEEtypes_WMM_TSPEC_t *)
+ presp_delts->tspec_data;
+ wlan_send_wmmac_host_event(
+ pmpriv, "DELTS_TX", MNULL,
+ ptspec_ie->TspecBody.TSInfo.TID,
+ ptspec_ie->TspecBody.TSInfo.UserPri,
+ presp_delts->ieee_reason_code);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_queue_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
+{
+ mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *)pdata_buf;
+ HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS) + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qstats->action = pqstats->action;
+ pcmd_qstats->select_is_userpri = 1;
+ pcmd_qstats->select_bin = pqstats->user_priority;
+ pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
+ pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
+ pcmd_qstats->avg_queue_delay =
+ wlan_cpu_to_le32(pqstats->avg_queue_delay);
+ pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
+ pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
+ pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pcmd_qstats->delay_histogram[id] =
+ wlan_cpu_to_le16(pqstats->delay_histogram[id]);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_STATS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_queue_stats(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ mlan_ds_wmm_queue_stats *pqstats = MNULL;
+ const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats =
+ &resp->params.queue_stats;
+ t_u8 id;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ pqstats = (mlan_ds_wmm_queue_stats *)&pwmm->param.q_stats;
+
+ pqstats->action = presp_qstats->action;
+ pqstats->user_priority = presp_qstats->select_bin;
+ pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
+ pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
+ pqstats->avg_queue_delay =
+ wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
+ pqstats->avg_tx_delay =
+ wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
+ pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
+ pqstats->policed_time =
+ wlan_le16_to_cpu(presp_qstats->policed_time);
+ for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
+ pqstats->delay_histogram[id] = wlan_le16_to_cpu(
+ presp_qstats->delay_histogram[id]);
+ }
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_ts_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
+{
+ mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *)pdata_buf;
+ HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
+ cmd->size =
+ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS) + S_DS_GEN);
+ cmd->result = 0;
+
+ memcpy_ext(pmpriv->adapter, (t_void *)pcmd_ts_status,
+ (t_void *)pts_status, sizeof(HostCmd_DS_WMM_TS_STATUS),
+ sizeof(HostCmd_DS_WMM_TS_STATUS));
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_TS_STATUS
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_ts_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ presp_ts_status->medium_time =
+ wlan_le16_to_cpu(presp_ts_status->medium_time);
+ memcpy_ext(pmpriv->adapter, (t_void *)&pwmm->param.ts_status,
+ (t_void *)presp_ts_status,
+ sizeof(mlan_ds_wmm_ts_status),
+ sizeof(mlan_ds_wmm_ts_status));
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get WMM status
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_wmm_ioctl_enable(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+ ENTER();
+ wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.wmm_enable = (t_u32)pmpriv->wmm_required;
+ else
+ pmpriv->wmm_required = (t_u8)wmm->param.wmm_enable;
+ pioctl_req->data_read_written = sizeof(t_u32) + MLAN_SUB_COMMAND_SIZE;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WMM QoS configuration
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_wmm_ioctl_qos(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ if (pioctl_req->action == MLAN_ACT_GET)
+ wmm->param.qos_cfg = pmpriv->wmm_qosinfo;
+ else {
+ pmpriv->wmm_qosinfo = wmm->param.qos_cfg;
+ }
+
+ pioctl_req->data_read_written = sizeof(t_u8) + MLAN_SUB_COMMAND_SIZE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for add a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_wmm_ioctl_addts_req(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_ADDTS_REQ, 0, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.addts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request for delete a TSPEC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_wmm_ioctl_delts_req(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_DELTS_REQ, 0, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.delts);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief To get and start/stop queue stats on a WMM AC
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_wmm_ioctl_queue_stats(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_STATS, 0, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.q_stats);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM AC queues
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success
+ */
+static mlan_status wlan_wmm_ioctl_queue_status(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+ mlan_ds_wmm_queue_status *pqstatus = MNULL;
+ WmmAcStatus_t *pac_status = MNULL;
+ mlan_wmm_ac_e ac_idx;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+ pqstatus = (mlan_ds_wmm_queue_status *)&cfg->param.q_status;
+
+ for (ac_idx = WMM_AC_BK; ac_idx <= WMM_AC_VO; ac_idx++) {
+ pac_status = &pmpriv->wmm.ac_status[ac_idx];
+
+ /* Firmware status */
+ pqstatus->ac_status[ac_idx].flow_required =
+ pac_status->flow_required;
+ pqstatus->ac_status[ac_idx].flow_created =
+ pac_status->flow_created;
+ pqstatus->ac_status[ac_idx].disabled = pac_status->disabled;
+
+ /* ACM bit reflected in firmware status (redundant) */
+ pqstatus->ac_status[ac_idx].wmm_acm = pac_status->flow_required;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get the status of the WMM Traffic Streams
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_wmm_ioctl_ts_status(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_TS_STATUS, 0, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.ts_status);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function prepares the command of WMM_PARAM_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param cmd_action cmd action.
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_param_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u8 cmd_action,
+ t_void *pdata_buf)
+{
+ wmm_ac_parameters_t *ac_params = (wmm_ac_parameters_t *)pdata_buf;
+ HostCmd_DS_WMM_PARAM_CONFIG *pcmd_cfg = &cmd->params.param_config;
+ t_u8 i = 0;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_PARAM_CONFIG);
+ cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_PARAM_CONFIG) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_cfg->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ memcpy_ext(pmpriv->adapter, pcmd_cfg->ac_params, ac_params,
+ sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES,
+ sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
+ for (i = 0; i < MAX_AC_QUEUES; i++) {
+ pcmd_cfg->ac_params[i].tx_op_limit = wlan_cpu_to_le16(
+ pcmd_cfg->ac_params[i].tx_op_limit);
+ }
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_PARAM_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_param_config(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ HostCmd_DS_WMM_PARAM_CONFIG *pcfg =
+ (HostCmd_DS_WMM_PARAM_CONFIG *)&resp->params.param_config;
+ t_u8 i;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ for (i = 0; i < MAX_AC_QUEUES; i++) {
+ pcfg->ac_params[i].tx_op_limit = wlan_le16_to_cpu(
+ pcfg->ac_params[i].tx_op_limit);
+ }
+ memcpy_ext(pmpriv->adapter, pwmm->param.ac_params,
+ pcfg->ac_params,
+ sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES,
+ sizeof(wmm_ac_parameters_t) * MAX_AC_QUEUES);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prepares the command of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param cmd A pointer to HostCmd_DS_COMMAND structure
+ * @param pdata_buf A pointer to data buffer
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_cmd_wmm_queue_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf)
+{
+ mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *)pdata_buf;
+ HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
+
+ ENTER();
+
+ cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+ cmd->size = wlan_cpu_to_le16(
+ sizeof(pcmd_qcfg->action) + sizeof(pcmd_qcfg->access_category) +
+ sizeof(pcmd_qcfg->msdu_lifetime_expiry) + S_DS_GEN);
+ cmd->result = 0;
+
+ pcmd_qcfg->action = pqcfg->action;
+ pcmd_qcfg->access_category = pqcfg->access_category;
+ pcmd_qcfg->msdu_lifetime_expiry =
+ wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the command response of WMM_QUEUE_CONFIG
+ *
+ * @param pmpriv A pointer to mlan_private structure
+ * @param resp A pointer to HostCmd_DS_COMMAND
+ * @param pioctl_buf A pointer to mlan_ioctl_req structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status wlan_ret_wmm_queue_config(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf)
+{
+ mlan_ds_wmm_cfg *pwmm = MNULL;
+ const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg =
+ &resp->params.queue_config;
+
+ ENTER();
+
+ if (pioctl_buf) {
+ pwmm = (mlan_ds_wmm_cfg *)pioctl_buf->pbuf;
+ pwmm->param.q_cfg.action = wlan_le32_to_cpu(presp_qcfg->action);
+ pwmm->param.q_cfg.access_category =
+ wlan_le32_to_cpu(presp_qcfg->access_category);
+ pwmm->param.q_cfg.msdu_lifetime_expiry =
+ wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
+ }
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Set/Get a specified AC Queue's parameters
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static mlan_status wlan_wmm_ioctl_queue_config(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
+ mlan_ds_wmm_cfg *cfg = MNULL;
+
+ ENTER();
+ cfg = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+
+ /* Send request to firmware */
+ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_WMM_QUEUE_CONFIG, 0, 0,
+ (t_void *)pioctl_req,
+ (t_void *)&cfg->param.q_cfg);
+
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WMM configuration handler
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param pioctl_req A pointer to ioctl request buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+mlan_status wlan_wmm_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *wmm = MNULL;
+
+ ENTER();
+
+ if (pioctl_req->buf_len < sizeof(mlan_ds_wmm_cfg)) {
+ PRINTM(MWARN, "MLAN bss IOCTL length is too short.\n");
+ pioctl_req->data_read_written = 0;
+ pioctl_req->buf_len_needed = sizeof(mlan_ds_wmm_cfg);
+ pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
+ LEAVE();
+ return MLAN_STATUS_RESOURCE;
+ }
+ wmm = (mlan_ds_wmm_cfg *)pioctl_req->pbuf;
+ switch (wmm->sub_command) {
+#ifdef STA_SUPPORT
+ case MLAN_OID_WMM_CFG_ENABLE:
+ status = wlan_wmm_ioctl_enable(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QOS:
+ status = wlan_wmm_ioctl_qos(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_ADDTS:
+ status = wlan_wmm_ioctl_addts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_DELTS:
+ status = wlan_wmm_ioctl_delts_req(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATS:
+ status = wlan_wmm_ioctl_queue_stats(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_QUEUE_STATUS:
+ status = wlan_wmm_ioctl_queue_status(pmadapter, pioctl_req);
+ break;
+ case MLAN_OID_WMM_CFG_TS_STATUS:
+ status = wlan_wmm_ioctl_ts_status(pmadapter, pioctl_req);
+ break;
+#endif
+ case MLAN_OID_WMM_CFG_QUEUE_CONFIG:
+ status = wlan_wmm_ioctl_queue_config(pmadapter, pioctl_req);
+ break;
+ default:
+ pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
+ status = MLAN_STATUS_FAILURE;
+ break;
+ }
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get ralist info
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param buf A pointer to ralist_info structure
+ * @return number of ralist entry
+ *
+ */
+int wlan_get_ralist_info(mlan_private *priv, ralist_info *buf)
+{
+ ralist_info *plist = buf;
+ mlan_list_head *ra_list_head = MNULL;
+ raListTbl *ra_list;
+ int i;
+ int count = 0;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
+ ra_list =
+ (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ ra_list_head, MNULL, MNULL);
+ while (ra_list && ra_list != (raListTbl *)ra_list_head) {
+ if (ra_list->total_pkts) {
+ plist->total_pkts = ra_list->total_pkts;
+ plist->tid = i;
+ plist->tx_pause = ra_list->tx_pause;
+ memcpy_ext(priv->adapter, plist->ra,
+ ra_list->ra, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ plist++;
+ count++;
+ if (count >= MLAN_MAX_RALIST_NUM)
+ break;
+ }
+ ra_list = ra_list->pnext;
+ }
+ }
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief dump ralist info
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ *
+ */
+void wlan_dump_ralist(mlan_private *priv)
+{
+ mlan_list_head *ra_list_head = MNULL;
+ raListTbl *ra_list;
+ mlan_adapter *pmadapter = priv->adapter;
+ int i;
+ t_u32 tx_pkts_queued;
+
+ tx_pkts_queued =
+ util_scalar_read(pmadapter->pmoal_handle,
+ &priv->wmm.tx_pkts_queued, MNULL, MNULL);
+ PRINTM(MERROR, "bss_index = %d, tx_pkts_queued = %d\n", priv->bss_index,
+ tx_pkts_queued);
+ if (!tx_pkts_queued)
+ return;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
+ ra_list =
+ (raListTbl *)util_peek_list(priv->adapter->pmoal_handle,
+ ra_list_head, MNULL, MNULL);
+ while (ra_list && ra_list != (raListTbl *)ra_list_head) {
+ if (ra_list->total_pkts) {
+ PRINTM(MERROR,
+ "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
+ ra_list->ra[0], ra_list->ra[1],
+ ra_list->ra[2], ra_list->ra[3],
+ ra_list->ra[4], ra_list->ra[5], i,
+ ra_list->total_pkts, ra_list->tx_pause);
+ }
+ ra_list = ra_list->pnext;
+ }
+ }
+ return;
+}
+
+/**
+ * @brief get tid down
+ *
+ * @param priv A pointer to mlan_private structure
+ * @param tid tid
+ *
+ * @return tid_down
+ *
+ */
+int wlan_get_wmm_tid_down(mlan_private *priv, int tid)
+{
+ return wlan_wmm_downgrade_tid(priv, tid);
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.h
new file mode 100644
index 000000000000..33856f05935c
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_wmm.h
@@ -0,0 +1,242 @@
+/** @file mlan_wmm.h
+ *
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/****************************************************
+Change log:
+ 10/24/2008: initial version
+****************************************************/
+
+#ifndef _MLAN_WMM_H_
+#define _MLAN_WMM_H_
+
+/**
+ * @brief This function gets the TID
+ *
+ * @param pmadapter A pointer to mlan_adapter structure
+ * @param ptr A pointer to RA list table
+ *
+ * @return TID
+ */
+static INLINE t_u32 wlan_get_tid(pmlan_adapter pmadapter, praListTbl ptr)
+{
+ pmlan_buffer mbuf;
+
+ ENTER();
+ mbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
+ &ptr->buf_head, MNULL, MNULL);
+ LEAVE();
+
+ if (!mbuf) {
+ return 0; // The default TID,BE
+ } else
+ return mbuf->priority;
+}
+
+/**
+ * @brief This function gets the length of a list
+ *
+ * @param head A pointer to mlan_list_head
+ *
+ * @return Length of list
+ */
+static INLINE t_u32 wlan_wmm_list_len(pmlan_list_head head)
+{
+ pmlan_linked_list pos;
+ t_u32 count = 0;
+
+ ENTER();
+
+ pos = head->pnext;
+
+ while (pos != (pmlan_linked_list)head) {
+ ++count;
+ pos = pos->pnext;
+ }
+
+ LEAVE();
+ return count;
+}
+
+/**
+ * @brief This function requests a ralist lock
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static INLINE t_void wlan_request_ralist_lock(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin lock callback function */
+ pcb->moal_spin_lock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function releases a lock on ralist
+ *
+ * @param priv A pointer to mlan_private structure
+ *
+ * @return N/A
+ */
+static INLINE t_void wlan_release_ralist_lock(pmlan_private priv)
+{
+ mlan_adapter *pmadapter = priv->adapter;
+ mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
+
+ ENTER();
+
+ /* Call MOAL spin unlock callback function */
+ pcb->moal_spin_unlock(pmadapter->pmoal_handle,
+ priv->wmm.ra_list_spinlock);
+
+ LEAVE();
+ return;
+}
+
+/** Add buffer to WMM Tx queue */
+void wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf);
+/** Add to RA list */
+void wlan_ralist_add(mlan_private *priv, t_u8 *ra);
+/** Update the RA list */
+int wlan_ralist_update(mlan_private *priv, t_u8 *old_ra, t_u8 *new_ra);
+
+/** WMM status change command handler */
+mlan_status wlan_cmd_wmm_status_change(pmlan_private priv);
+/** Check if WMM lists are empty */
+int wlan_wmm_lists_empty(pmlan_adapter pmadapter);
+/** Process WMM transmission */
+t_void wlan_wmm_process_tx(pmlan_adapter pmadapter);
+/** Test to see if the ralist ptr is valid */
+int wlan_is_ralist_valid(mlan_private *priv, raListTbl *ra_list, int tid);
+
+raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
+ t_u8 *ra_addr);
+t_u8 wlan_get_random_ba_threshold(pmlan_adapter pmadapter);
+
+/** Compute driver packet delay */
+t_u8 wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
+ const pmlan_buffer pmbuf);
+/** Initialize WMM */
+t_void wlan_wmm_init(pmlan_adapter pmadapter);
+/** Initialize WMM paramter */
+t_void wlan_init_wmm_param(pmlan_adapter pmadapter);
+/** Setup WMM queues */
+extern void wlan_wmm_setup_queues(pmlan_private priv);
+/* Setup default queues */
+void wlan_wmm_default_queue_priorities(pmlan_private priv);
+/* process wmm_param_config command */
+mlan_status wlan_cmd_wmm_param_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd, t_u8 cmd_action,
+ t_void *pdata_buf);
+
+/* process wmm_param_config command response */
+mlan_status wlan_ret_wmm_param_config(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+#ifdef STA_SUPPORT
+/** Process WMM association request */
+extern t_u32 wlan_wmm_process_association_req(pmlan_private priv,
+ t_u8 **ppAssocBuf,
+ IEEEtypes_WmmParameter_t *pWmmIE,
+ IEEEtypes_HTCap_t *pHTCap);
+#endif /* STA_SUPPORT */
+
+/** setup wmm queue priorities */
+void wlan_wmm_setup_queue_priorities(pmlan_private priv,
+ IEEEtypes_WmmParameter_t *wmm_ie);
+
+/* Get tid_down from tid */
+int wlan_get_wmm_tid_down(mlan_private *priv, int tid);
+/** Downgrade WMM priority queue */
+void wlan_wmm_setup_ac_downgrade(pmlan_private priv);
+/** select WMM queue */
+t_u8 wlan_wmm_select_queue(mlan_private *pmpriv, t_u8 tid);
+t_void wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 *mac);
+
+#ifdef STA_SUPPORT
+/*
+ * Functions used in the cmd handling routine
+ */
+/** WMM ADDTS request command handler */
+extern mlan_status wlan_cmd_wmm_addts_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+/** WMM DELTS request command handler */
+extern mlan_status wlan_cmd_wmm_delts_req(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+/** WMM QUEUE_STATS command handler */
+extern mlan_status wlan_cmd_wmm_queue_stats(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+/** WMM TS_STATUS command handler */
+extern mlan_status wlan_cmd_wmm_ts_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+/*
+ * Functions used in the cmdresp handling routine
+ */
+/** WMM get status command response handler */
+extern mlan_status wlan_ret_wmm_get_status(pmlan_private priv, t_u8 *ptlv,
+ int resp_len);
+/** WMM ADDTS request command response handler */
+extern mlan_status wlan_ret_wmm_addts_req(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** WMM DELTS request command response handler */
+extern mlan_status wlan_ret_wmm_delts_req(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** WMM QUEUE_STATS command response handler */
+extern mlan_status wlan_ret_wmm_queue_stats(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+/** WMM TS_STATUS command response handler */
+extern mlan_status wlan_ret_wmm_ts_status(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+#endif /* STA_SUPPORT */
+
+/** WMM QUEUE_CONFIG command handler */
+extern mlan_status wlan_cmd_wmm_queue_config(pmlan_private pmpriv,
+ HostCmd_DS_COMMAND *cmd,
+ t_void *pdata_buf);
+
+/** WMM QUEUE_CONFIG command response handler */
+extern mlan_status wlan_ret_wmm_queue_config(pmlan_private pmpriv,
+ const HostCmd_DS_COMMAND *resp,
+ mlan_ioctl_req *pioctl_buf);
+
+mlan_status wlan_wmm_cfg_ioctl(pmlan_adapter pmadapter,
+ pmlan_ioctl_req pioctl_req);
+#endif /* !_MLAN_WMM_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan.h
new file mode 100644
index 000000000000..d2cd022e02d7
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan.h
@@ -0,0 +1,37 @@
+/** @file mlan.h
+ *
+ * @brief This file declares all APIs that will be called from MOAL module.
+ * It also defines the data structures used for APIs between MLAN and MOAL.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 10/13/2008: initial version
+ 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h
+******************************************************/
+
+#ifndef _MLAN_H_
+#define _MLAN_H_
+
+#include "mlan_decl.h"
+#include "mlan_ioctl.h"
+#include "mlan_ieee.h"
+
+#endif /* !_MLAN_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_decl.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_decl.h
new file mode 100644
index 000000000000..7d0b75cc3c54
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_decl.h
@@ -0,0 +1,1988 @@
+/** @file mlan_decl.h
+ *
+ * @brief This file declares the generic data structures and APIs.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MLAN_DECL_H_
+#define _MLAN_DECL_H_
+
+/** MLAN release version */
+#define MLAN_RELEASE_VERSION "215.p2"
+
+/** Re-define generic data types for MLAN/MOAL */
+/** Signed char (1-byte) */
+typedef signed char t_s8, *t_ps8;
+/** Unsigned char (1-byte) */
+typedef unsigned char t_u8, *t_pu8;
+/** Signed short (2-bytes) */
+typedef short t_s16, *t_ps16;
+/** Unsigned short (2-bytes) */
+typedef unsigned short t_u16, *t_pu16;
+/** Signed long (4-bytes) */
+typedef int t_s32, *t_ps32;
+/** Unsigned long (4-bytes) */
+typedef unsigned int t_u32, *t_pu32;
+/** Signed long long 8-bytes) */
+typedef long long t_s64, *t_ps64;
+/** Unsigned long long 8-bytes) */
+typedef unsigned long long t_u64, *t_pu64;
+/** Void pointer (4-bytes) */
+typedef void t_void, *t_pvoid;
+/** Size type */
+typedef t_u32 t_size;
+/** Boolean type */
+typedef t_u8 t_bool;
+
+#ifdef MLAN_64BIT
+/** Pointer type (64-bit) */
+typedef t_u64 t_ptr;
+/** Signed value (64-bit) */
+typedef t_s64 t_sval;
+#else
+/** Pointer type (32-bit) */
+typedef t_u32 t_ptr;
+/** Signed value (32-bit) */
+typedef t_s32 t_sval;
+#endif
+
+/** Constants below */
+
+#ifdef __GNUC__
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END __attribute__((packed))
+#else /* !__GNUC__ */
+#ifdef PRAGMA_PACK
+/** Structure packing begins */
+#define MLAN_PACK_START
+/** Structure packeing end */
+#define MLAN_PACK_END
+#else /* !PRAGMA_PACK */
+/** Structure packing begins */
+#define MLAN_PACK_START __packed
+/** Structure packing end */
+#define MLAN_PACK_END
+#endif /* PRAGMA_PACK */
+#endif /* __GNUC__ */
+
+#ifndef INLINE
+#ifdef __GNUC__
+/** inline directive */
+#define INLINE inline
+#else
+/** inline directive */
+#define INLINE __inline
+#endif
+#endif
+
+/** MLAN TRUE */
+#define MTRUE (1)
+/** MLAN FALSE */
+#define MFALSE (0)
+
+#ifndef MACSTR
+/** MAC address security format */
+#define MACSTR "%02x:XX:XX:XX:%02x:%02x"
+#endif
+
+#ifndef MAC2STR
+/** MAC address security print arguments */
+#define MAC2STR(a) (a)[0], (a)[4], (a)[5]
+#endif
+
+#ifndef FULL_MACSTR
+#define FULL_MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+#ifndef FULL_MAC2STR
+#define FULL_MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#endif
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) (((p) + ((a)-1)) & ~((a)-1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1))
+
+/** Return the byte offset of a field in the given structure */
+#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr) & (((type *)0)->field))
+/** Return aligned offset */
+#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p)
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (16)
+#else
+/** Maximum BSS numbers */
+#define MLAN_MAX_BSS_NUM (2)
+#endif
+
+/** NET IP alignment */
+#define MLAN_NET_IP_ALIGN 2
+
+/** DMA alignment */
+/* SDIO3.0 Inrevium Adapter require 32 bit DMA alignment */
+#define DMA_ALIGNMENT 32
+
+/** max size of TxPD */
+#define MAX_TXPD_SIZE 32
+
+/** Minimum data header length */
+#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT + MAX_TXPD_SIZE)
+
+/** rx data header length */
+#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN
+
+/** This is current limit on Maximum Tx AMPDU allowed */
+#define MLAN_MAX_TX_BASTREAM_SUPPORTED 16
+#define MLAN_MAX_TX_BASTREAM_DEFAULT 2
+/** This is current limit on Maximum Rx AMPDU allowed */
+#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16
+
+#ifdef STA_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_STA_AMPDU_DEF_TXWINSIZE 64
+/** Default Win size attached during ADDBA response */
+#define MLAN_STA_AMPDU_DEF_RXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_STA_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+/** Default Win size attached during ADDBA request */
+#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 64
+/** Default Win size attached during ADDBA response */
+#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_UAP_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif /* UAP_SUPPORT */
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** WFD use the same window size for tx/rx */
+#define MLAN_WFD_AMPDU_DEF_TXRXWINSIZE 64
+/** RX winsize for COEX */
+#define MLAN_WFD_COEX_AMPDU_DEF_RXWINSIZE 16
+#endif
+
+/** Block ack timeout value */
+#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+/** Maximum Tx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff
+/** Maximum Rx Win size configured for ADDBA request [10 bits] */
+#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff
+
+/** Rate index for HR/DSSS 0 */
+#define MLAN_RATE_INDEX_HRDSSS0 0
+/** Rate index for HR/DSSS 3 */
+#define MLAN_RATE_INDEX_HRDSSS3 3
+/** Rate index for OFDM 0 */
+#define MLAN_RATE_INDEX_OFDM0 4
+/** Rate index for OFDM 7 */
+#define MLAN_RATE_INDEX_OFDM7 11
+/** Rate index for MCS 0 */
+#define MLAN_RATE_INDEX_MCS0 0
+/** Rate index for MCS 2 */
+#define MLAN_RATE_INDEX_MCS2 2
+/** Rate index for MCS 4 */
+#define MLAN_RATE_INDEX_MCS4 4
+/** Rate index for MCS 7 */
+#define MLAN_RATE_INDEX_MCS7 7
+/** Rate index for MCS 9 */
+#define MLAN_RATE_INDEX_MCS9 9
+/** Rate index for MCS11 */
+#define MLAN_RATE_INDEX_MCS11 11
+/** Rate index for MCS15 */
+#define MLAN_RATE_INDEX_MCS15 15
+/** Rate index for MCS 32 */
+#define MLAN_RATE_INDEX_MCS32 32
+/** Rate index for MCS 127 */
+#define MLAN_RATE_INDEX_MCS127 127
+#define MLAN_RATE_NSS1 1
+#define MLAN_RATE_NSS2 2
+
+/** Rate bitmap for OFDM 0 */
+#define MLAN_RATE_BITMAP_OFDM0 16
+/** Rate bitmap for OFDM 7 */
+#define MLAN_RATE_BITMAP_OFDM7 23
+/** Rate bitmap for MCS 0 */
+#define MLAN_RATE_BITMAP_MCS0 32
+/** Rate bitmap for MCS 127 */
+#define MLAN_RATE_BITMAP_MCS127 159
+#define MLAN_RATE_BITMAP_NSS1_MCS0 160
+#define MLAN_RATE_BITMAP_NSS1_MCS9 169
+#define MLAN_RATE_BITMAP_NSS2_MCS0 176
+#define MLAN_RATE_BITMAP_NSS2_MCS9 185
+
+/** MU beamformer */
+#define DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK (MBIT(19))
+
+/** Size of rx data buffer 4096+256 */
+#define MLAN_RX_DATA_BUF_SIZE 4352
+
+/** Size of command buffer */
+/** because cal_data_size 2.4 k */
+#define MRVDRV_SIZE_OF_CMD_BUFFER (4 * 1024)
+/** Size of rx command buffer */
+#define MLAN_RX_CMD_BUF_SIZE MRVDRV_SIZE_OF_CMD_BUFFER
+/** Upload size */
+#define WLAN_UPLD_SIZE MRVDRV_SIZE_OF_CMD_BUFFER
+
+#if defined(PCIE)
+#define MLAN_SSU_MAX_PKT_SIZE (283 * 4)
+#define MLAN_SSU_HEADER_SIZE 256
+/**
+ * Size of DMA buffer to collect 10ms SSU data:
+ * 2500 spectral packets, plus header
+ */
+#define MLAN_SSU_BUF_SIZE_1MS (MLAN_SSU_MAX_PKT_SIZE * 250)
+#define MLAN_SSU_BUF_SIZE (MLAN_SSU_HEADER_SIZE + MLAN_SSU_BUF_SIZE_1MS * 10)
+#define MLAN_SSU_BUF_SIZE_HOST (MLAN_SSU_BUF_SIZE)
+#endif
+
+/** driver initial the fw reset */
+#define FW_RELOAD_SDIO_INBAND_RESET 1
+/** out band reset trigger reset, no interface re-emulation */
+#define FW_RELOAD_NO_EMULATION 2
+/** out band reset with interface re-emulation */
+#define FW_RELOAD_WITH_EMULATION 3
+#ifdef PCIE
+/** pcie card reset */
+#define FW_RELOAD_PCIE_RESET 4
+#endif
+
+#ifdef USB
+#define MLAN_USB_BLOCK_SIZE (512)
+#define MLAN_USB_AGGR_MODE_NUM (0)
+#define MLAN_USB_AGGR_MODE_LEN (1)
+#define MLAN_USB_AGGR_MODE_LEN_V2 (2)
+#define MLAN_USB_TX_AGGR_MAX_LEN (16000)
+#define MLAN_USB_TX_AGGR_MAX_NUM 10
+#define MLAN_USB_TX_AGGR_V2_ALIGN 4
+#define MLAN_USB_TX_AGGR_HEADER 4
+#define MLAN_USB_MAX_PKT_SIZE (MLAN_USB_BLOCK_SIZE * 4)
+
+#define MLAN_USB_RX_ALIGN_SIZE MLAN_USB_BLOCK_SIZE
+#define MLAN_USB_RX_MAX_AGGR_NUM (8)
+#define MLAN_USB_RX_DEAGGR_TIMEOUT_USEC (200)
+
+#define MLAN_USB_TX_AGGR_ALIGN (MLAN_USB_BLOCK_SIZE * 4)
+#define MLAN_USB_TX_MAX_AGGR_NUM (8)
+#define MLAN_USB_TX_MAX_AGGR_SIZE \
+ (MLAN_USB_BLOCK_SIZE * 4 * MLAN_USB_TX_MAX_AGGR_NUM)
+#define MLAN_USB_TX_MIN_AGGR_TIMEOUT (1)
+#define MLAN_USB_TX_MAX_AGGR_TIMEOUT (4)
+#define MLAN_USB_TX_AGGR_TIMEOUT_MSEC MLAN_USB_TX_MIN_AGGR_TIMEOUT
+#define MLAN_USB_TX_AGGR_TIMEOUT_DYN (0xFFFF)
+#endif /*USB*/
+
+/** MLAN MAC Address Length */
+#define MLAN_MAC_ADDR_LENGTH (6)
+/** MLAN 802.11 MAC Address */
+typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH];
+
+/** MLAN Maximum SSID Length */
+#define MLAN_MAX_SSID_LENGTH (32)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MLAN_RTS_MIN_VALUE (0)
+/** Maximum RTS value */
+#define MLAN_RTS_MAX_VALUE (2347)
+/** Minimum FRAG value */
+#define MLAN_FRAG_MIN_VALUE (256)
+/** Maximum FRAG value */
+#define MLAN_FRAG_MAX_VALUE (2346)
+
+/** Minimum tx retry count */
+#define MLAN_TX_RETRY_MIN (0)
+/** Maximum tx retry count */
+#define MLAN_TX_RETRY_MAX (14)
+
+/** max Wmm AC queues */
+#define MAX_AC_QUEUES 4
+
+#ifdef SDIO
+/** define SDIO block size for data Tx/Rx */
+/* We support up to 480-byte block size due to FW buffer limitation. */
+#define MLAN_SDIO_BLOCK_SIZE 256
+
+/** define SDIO block size for firmware download */
+#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE MLAN_RX_DATA_BUF_SIZE
+/** SDIO MP aggr pkt limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT (16)
+/** max SDIO MP aggr pkt limit */
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX (16)
+
+/** SDIO IO Port mask */
+#define MLAN_SDIO_IO_PORT_MASK 0xfffff
+/** SDIO Block/Byte mode mask */
+#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000
+#endif /* SDIO */
+
+/** SD Interface */
+#define INTF_SD MBIT(0)
+#define IS_SD(ct) (ct & (INTF_SD << 8))
+/** PCIE Interface */
+#define INTF_PCIE MBIT(1)
+#define IS_PCIE(ct) (ct & (INTF_PCIE << 8))
+/** USB Interface */
+#define INTF_USB MBIT(2)
+#define IS_USB(ct) (ct & (INTF_USB << 8))
+
+/** 8887 card type */
+#define CARD_TYPE_8887 0x01
+/** 8897 card type */
+#define CARD_TYPE_8897 0x02
+/** 8977 card type */
+#define CARD_TYPE_8977 0x03
+/** 8997 card type */
+#define CARD_TYPE_8997 0x04
+/** 8987 card type */
+#define CARD_TYPE_8987 0x05
+/** 9098 card type */
+#define CARD_TYPE_9098 0x06
+/** 9097 card type */
+#define CARD_TYPE_9097 0x07
+/** 8978 card type */
+#define CARD_TYPE_8978 0x08
+
+/** 9098 A0 reverion num */
+#define CHIP_9098_REV_A0 1
+#define CHIP_9098_REV_A1 2
+/** 9097 CHIP REV */
+#define CHIP_9097_REV_B0 1
+
+#define INTF_MASK 0xff
+#define CARD_TYPE_MASK 0xff
+
+#ifdef SDIO
+/** SD8887 card type */
+#define CARD_TYPE_SD8887 (CARD_TYPE_8887 | (INTF_SD << 8))
+/** SD8897 card type */
+#define CARD_TYPE_SD8897 (CARD_TYPE_8897 | (INTF_SD << 8))
+/** SD8977 card type */
+#define CARD_TYPE_SD8977 (CARD_TYPE_8977 | (INTF_SD << 8))
+/** SD8978 card type */
+#define CARD_TYPE_SD8978 (CARD_TYPE_8978 | (INTF_SD << 8))
+/** SD8997 card type */
+#define CARD_TYPE_SD8997 (CARD_TYPE_8997 | (INTF_SD << 8))
+/** SD8987 card type */
+#define CARD_TYPE_SD8987 (CARD_TYPE_8987 | (INTF_SD << 8))
+/** SD9097 card type */
+#define CARD_TYPE_SD9097 (CARD_TYPE_9097 | (INTF_SD << 8))
+/** SD9098 card type */
+#define CARD_TYPE_SD9098 (CARD_TYPE_9098 | (INTF_SD << 8))
+
+#define IS_SD8887(ct) (CARD_TYPE_SD8887 == (ct))
+#define IS_SD8897(ct) (CARD_TYPE_SD8897 == (ct))
+#define IS_SD8977(ct) (CARD_TYPE_SD8977 == (ct))
+#define IS_SD8978(ct) (CARD_TYPE_SD8978 == (ct))
+#define IS_SD8997(ct) (CARD_TYPE_SD8997 == (ct))
+#define IS_SD8987(ct) (CARD_TYPE_SD8987 == (ct))
+#define IS_SD9097(ct) (CARD_TYPE_SD9097 == (ct))
+#define IS_SD9098(ct) (CARD_TYPE_SD9098 == (ct))
+
+/** SD8887 Card */
+#define CARD_SD8887 "SD8887"
+/** SD8897 Card */
+#define CARD_SD8897 "SD8897"
+/** SD8977 Card */
+#define CARD_SD8977 "SD8977"
+/** SD8978 Card */
+#define CARD_SD8978 "SD8978"
+/** SD8997 Card */
+#define CARD_SD8997 "SD8997"
+/** SD8987 Card */
+#define CARD_SD8987 "SD8987"
+/** SD9097 Card */
+#define CARD_SD9097 "SD9097"
+/** SD9098 Card */
+#define CARD_SD9098 "SD9098"
+#endif
+
+#ifdef PCIE
+/** PCIE8897 card type */
+#define CARD_TYPE_PCIE8897 (CARD_TYPE_8897 | (INTF_PCIE << 8))
+/** PCIE8997 card type */
+#define CARD_TYPE_PCIE8997 (CARD_TYPE_8997 | (INTF_PCIE << 8))
+/** PCIE9097 card type */
+#define CARD_TYPE_PCIE9097 (CARD_TYPE_9097 | (INTF_PCIE << 8))
+/** PCIE9098 card type */
+#define CARD_TYPE_PCIE9098 (CARD_TYPE_9098 | (INTF_PCIE << 8))
+
+#define IS_PCIE8897(ct) (CARD_TYPE_PCIE8897 == (ct))
+#define IS_PCIE8997(ct) (CARD_TYPE_PCIE8997 == (ct))
+#define IS_PCIE9097(ct) (CARD_TYPE_PCIE9097 == (ct))
+#define IS_PCIE9098(ct) (CARD_TYPE_PCIE9098 == (ct))
+
+/** PCIE8897 Card */
+#define CARD_PCIE8897 "PCIE8897"
+/** PCIE8997 Card */
+#define CARD_PCIE8997 "PCIE8997"
+/** PCIE9097 Card */
+#define CARD_PCIE9097 "PCIE9097"
+/** PCIE9000S Card */
+#define CARD_PCIE9000S "PCIE9000S"
+/** PCIE9098 Card */
+#define CARD_PCIE9098 "PCIE9098"
+#endif
+
+#ifdef USB
+/** USB8897 card type */
+#define CARD_TYPE_USB8897 (CARD_TYPE_8897 | (INTF_USB << 8))
+/** USB8997 card type */
+#define CARD_TYPE_USB8997 (CARD_TYPE_8997 | (INTF_USB << 8))
+/** USB8978 card type */
+#define CARD_TYPE_USB8978 (CARD_TYPE_8978 | (INTF_USB << 8))
+/** USB9098 card type */
+#define CARD_TYPE_USB9098 (CARD_TYPE_9098 | (INTF_USB << 8))
+/** USB9097 card type */
+#define CARD_TYPE_USB9097 (CARD_TYPE_9097 | (INTF_USB << 8))
+
+#define IS_USB8897(ct) (CARD_TYPE_USB8897 == (ct))
+#define IS_USB8997(ct) (CARD_TYPE_USB8997 == (ct))
+#define IS_USB8978(ct) (CARD_TYPE_USB8978 == (ct))
+#define IS_USB9098(ct) (CARD_TYPE_USB9098 == (ct))
+#define IS_USB9097(ct) (CARD_TYPE_USB9097 == (ct))
+
+/** USB8897 Card */
+#define CARD_USB8897 "USB8897"
+/** USB8997 Card */
+#define CARD_USB8997 "USB8997"
+/** USB8978 Card */
+#define CARD_USB8978 "USB8978"
+/** USB9098 Card */
+#define CARD_USB9098 "USB9098"
+/** USB9097 Card */
+#define CARD_USB9097 "USB9097"
+#endif
+
+#define IS_CARD8887(ct) (CARD_TYPE_8887 == ((ct)&0xf))
+#define IS_CARD8897(ct) (CARD_TYPE_8897 == ((ct)&0xf))
+#define IS_CARD8977(ct) (CARD_TYPE_8977 == ((ct)&0xf))
+#define IS_CARD8997(ct) (CARD_TYPE_8997 == ((ct)&0xf))
+#define IS_CARD8987(ct) (CARD_TYPE_8987 == ((ct)&0xf))
+#define IS_CARD9098(ct) (CARD_TYPE_9098 == ((ct)&0xf))
+#define IS_CARD9097(ct) (CARD_TYPE_9097 == ((ct)&0xf))
+
+typedef struct _card_type_entry {
+ t_u16 card_type;
+ t_u16 func_id;
+ char *name;
+} card_type_entry;
+
+#if defined(SDIO) || defined(PCIE)
+/** Max retry number of IO write */
+#define MAX_WRITE_IOMEM_RETRY 2
+#endif /* SDIO || PCIE */
+
+#ifdef PCIE
+typedef enum {
+ PCIE_INT_MODE_LEGACY = 0,
+ PCIE_INT_MODE_MSI,
+ PCIE_INT_MODE_MSIX,
+ PCIE_INT_MODE_MAX,
+} PCIE_INT_MODE;
+#endif /* PCIE */
+
+/** IN parameter */
+#define IN
+/** OUT parameter */
+#define OUT
+
+/** BIT value */
+#define MBIT(x) (((t_u32)1) << (x))
+
+/** Buffer flag for requeued packet */
+#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0)
+/** Buffer flag for transmit buf from moal */
+#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1)
+/** Buffer flag for malloc mlan_buffer */
+#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2)
+
+/** Buffer flag for bridge packet */
+#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3)
+
+#ifdef USB
+/** Buffer flag for deaggregated rx packet */
+#define MLAN_BUF_FLAG_RX_DEAGGR MBIT(5)
+
+/** Buffer flag for sleep confirm resp packet */
+#define MLAN_BUF_FLAG_SLEEPCFM_RESP MBIT(6)
+
+/** Buffer flag for USB TX AGGR */
+#define MLAN_BUF_FLAG_USB_TX_AGGR MBIT(7)
+#endif
+
+/** Buffer flag for TCP_ACK */
+#define MLAN_BUF_FLAG_TCP_ACK MBIT(9)
+
+/** Buffer flag for TX_STATUS */
+#define MLAN_BUF_FLAG_TX_STATUS MBIT(10)
+
+/** Buffer flag for NULL data packet */
+#define MLAN_BUF_FLAG_NULL_PKT MBIT(12)
+/** Buffer flag for Diag pkt */
+#define MLAN_BUF_FLAG_DIAG_BUF MBIT(13)
+
+#define MLAN_BUF_FLAG_TX_CTRL MBIT(14)
+
+#ifdef DEBUG_LEVEL1
+/** Debug level bit definition */
+#define MMSG MBIT(0)
+#define MFATAL MBIT(1)
+#define MERROR MBIT(2)
+#define MDATA MBIT(3)
+#define MCMND MBIT(4)
+#define MEVENT MBIT(5)
+#define MINTR MBIT(6)
+#define MIOCTL MBIT(7)
+
+#define MREG_D MBIT(9)
+
+#define MMPA_D MBIT(15)
+#define MDAT_D MBIT(16)
+#define MCMD_D MBIT(17)
+#define MEVT_D MBIT(18)
+#define MFW_D MBIT(19)
+#define MIF_D MBIT(20)
+
+#define MENTRY MBIT(28)
+#define MWARN MBIT(29)
+#define MINFO MBIT(30)
+#define MHEX_DUMP MBIT(31)
+#endif /* DEBUG_LEVEL1 */
+
+/** Memory allocation type: DMA */
+#define MLAN_MEM_DMA MBIT(0)
+
+/** Default memory allocation flag */
+#define MLAN_MEM_DEF 0
+
+/** mlan_status */
+typedef enum _mlan_status {
+ MLAN_STATUS_FAILURE = 0xffffffff,
+ MLAN_STATUS_SUCCESS = 0,
+ MLAN_STATUS_PENDING,
+ MLAN_STATUS_RESOURCE,
+#ifdef USB
+ /* Status pending and no resource */
+ MLAN_STATUS_PRESOURCE,
+#endif
+ MLAN_STATUS_COMPLETE,
+ MLAN_STATUS_FILE_ERR,
+} mlan_status;
+
+/** mlan_error_code */
+typedef enum _mlan_error_code {
+ /** No error */
+ MLAN_ERROR_NO_ERROR = 0,
+ /** Firmware/device errors below (MSB=0) */
+ MLAN_ERROR_FW_NOT_READY = 0x00000001,
+ MLAN_ERROR_FW_BUSY = 0x00000002,
+ MLAN_ERROR_FW_CMDRESP = 0x00000003,
+ MLAN_ERROR_DATA_TX_FAIL = 0x00000004,
+ MLAN_ERROR_DATA_RX_FAIL = 0x00000005,
+ /** Driver errors below (MSB=1) */
+ MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001,
+ MLAN_ERROR_PKT_TIMEOUT = 0x80000002,
+ MLAN_ERROR_PKT_INVALID = 0x80000003,
+ MLAN_ERROR_CMD_INVALID = 0x80000004,
+ MLAN_ERROR_CMD_TIMEOUT = 0x80000005,
+ MLAN_ERROR_CMD_DNLD_FAIL = 0x80000006,
+ MLAN_ERROR_CMD_CANCEL = 0x80000007,
+ MLAN_ERROR_CMD_RESP_FAIL = 0x80000008,
+ MLAN_ERROR_CMD_ASSOC_FAIL = 0x80000009,
+ MLAN_ERROR_CMD_SCAN_FAIL = 0x8000000A,
+ MLAN_ERROR_IOCTL_INVALID = 0x8000000B,
+ MLAN_ERROR_IOCTL_FAIL = 0x8000000C,
+ MLAN_ERROR_EVENT_UNKNOWN = 0x8000000D,
+ MLAN_ERROR_INVALID_PARAMETER = 0x8000000E,
+ MLAN_ERROR_NO_MEM = 0x8000000F,
+ /** More to add */
+} mlan_error_code;
+
+/** mlan_buf_type */
+typedef enum _mlan_buf_type {
+ MLAN_BUF_TYPE_CMD = 1,
+ MLAN_BUF_TYPE_DATA,
+ MLAN_BUF_TYPE_EVENT,
+ MLAN_BUF_TYPE_RAW_DATA,
+#ifdef SDIO
+ MLAN_BUF_TYPE_SPA_DATA,
+#endif
+} mlan_buf_type;
+
+#ifdef USB
+/** mlan_usb_ep */
+typedef enum _mlan_usb_ep {
+ MLAN_USB_EP_CTRL = 0,
+ MLAN_USB_EP_CMD_EVENT = 1,
+ MLAN_USB_EP_DATA = 2,
+ MLAN_USB_EP_DATA_CH2 = 3,
+ MLAN_USB_EP_CMD_EVENT_IF2 = 4,
+ MLAN_USB_EP_DATA_IF2 = 5,
+ MLAN_USB_EP_DATA_CH2_IF2 = 6,
+} mlan_usb_ep;
+
+/** Timeout in milliseconds for usb_bulk_msg function */
+#define MLAN_USB_BULK_MSG_TIMEOUT 100
+#endif /* USB */
+
+/** MLAN BSS type */
+typedef enum _mlan_bss_type {
+ MLAN_BSS_TYPE_STA = 0,
+ MLAN_BSS_TYPE_UAP = 1,
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_BSS_TYPE_WIFIDIRECT = 2,
+#endif
+ MLAN_BSS_TYPE_ANY = 0xff,
+} mlan_bss_type;
+
+/** MLAN BSS role */
+typedef enum _mlan_bss_role {
+ MLAN_BSS_ROLE_STA = 0,
+ MLAN_BSS_ROLE_UAP = 1,
+ MLAN_BSS_ROLE_ANY = 0xff,
+} mlan_bss_role;
+
+/** BSS role mask */
+#define BSS_ROLE_MASK (MBIT(0) | MBIT(1))
+
+/** Get BSS role */
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_MASK)
+
+/** mlan_data_frame_type */
+typedef enum _mlan_data_frame_type {
+ MLAN_DATA_FRAME_TYPE_ETH_II = 0,
+ MLAN_DATA_FRAME_TYPE_802_11,
+} mlan_data_frame_type;
+
+/** mlan_event_id */
+typedef enum _mlan_event_id {
+ /* Event generated by firmware (MSB=0) */
+ MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED = 0x00000002,
+ MLAN_EVENT_ID_FW_ADHOC_LINK_LOST = 0x00000003,
+ MLAN_EVENT_ID_FW_DISCONNECTED = 0x00000004,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI = 0x00000005,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL = 0x00000006,
+ MLAN_EVENT_ID_FW_BCN_RSSI_LOW = 0x00000007,
+ MLAN_EVENT_ID_FW_BCN_RSSI_HIGH = 0x00000008,
+ MLAN_EVENT_ID_FW_BCN_SNR_LOW = 0x00000009,
+ MLAN_EVENT_ID_FW_BCN_SNR_HIGH = 0x0000000A,
+ MLAN_EVENT_ID_FW_MAX_FAIL = 0x0000000B,
+ MLAN_EVENT_ID_FW_DATA_RSSI_LOW = 0x0000000C,
+ MLAN_EVENT_ID_FW_DATA_RSSI_HIGH = 0x0000000D,
+ MLAN_EVENT_ID_FW_DATA_SNR_LOW = 0x0000000E,
+ MLAN_EVENT_ID_FW_DATA_SNR_HIGH = 0x0000000F,
+ MLAN_EVENT_ID_FW_LINK_QUALITY = 0x00000010,
+ MLAN_EVENT_ID_FW_PORT_RELEASE = 0x00000011,
+ MLAN_EVENT_ID_FW_PRE_BCN_LOST = 0x00000012,
+ MLAN_EVENT_ID_FW_DEBUG_INFO = 0x00000013,
+ MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE = 0x0000001A,
+ MLAN_EVENT_ID_FW_HS_WAKEUP = 0x0000001B,
+ MLAN_EVENT_ID_FW_BG_SCAN = 0x0000001D,
+ MLAN_EVENT_ID_FW_BG_SCAN_STOPPED = 0x0000001E,
+ MLAN_EVENT_ID_FW_WEP_ICV_ERR = 0x00000020,
+ MLAN_EVENT_ID_FW_STOP_TX = 0x00000021,
+ MLAN_EVENT_ID_FW_START_TX = 0x00000022,
+ MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN = 0x00000023,
+ MLAN_EVENT_ID_FW_RADAR_DETECTED = 0x00000024,
+ MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY = 0x00000025,
+ MLAN_EVENT_ID_FW_BW_CHANGED = 0x00000026,
+ MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED = 0x0000002B,
+
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_UAP_FW_BSS_START = 0x0000002C,
+ MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE = 0x0000002D,
+ MLAN_EVENT_ID_UAP_FW_BSS_IDLE = 0x0000002E,
+ MLAN_EVENT_ID_UAP_FW_MIC_COUNTERMEASURES = 0x0000002F,
+ MLAN_EVENT_ID_UAP_FW_STA_CONNECT = 0x00000030,
+ MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT = 0x00000031,
+#endif
+
+ MLAN_EVENT_ID_FW_DUMP_INFO = 0x00000033,
+
+ MLAN_EVENT_ID_FW_TX_STATUS = 0x00000034,
+ MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE = 0x00000036,
+#if defined(PCIE)
+ MLAN_EVENT_ID_SSU_DUMP_FILE = 0x00000039,
+#endif /* SSU_SUPPORT */
+ /* Event generated by MLAN driver (MSB=1) */
+ MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001,
+ MLAN_EVENT_ID_DRV_DEFER_HANDLING = 0x80000002,
+ MLAN_EVENT_ID_DRV_HS_ACTIVATED = 0x80000003,
+ MLAN_EVENT_ID_DRV_HS_DEACTIVATED = 0x80000004,
+ MLAN_EVENT_ID_DRV_MGMT_FRAME = 0x80000005,
+ MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM = 0x80000006,
+ MLAN_EVENT_ID_DRV_PASSTHRU = 0x80000007,
+ MLAN_EVENT_ID_DRV_SCAN_REPORT = 0x80000009,
+ MLAN_EVENT_ID_DRV_MEAS_REPORT = 0x8000000A,
+ MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT = 0x8000000B,
+ MLAN_EVENT_ID_DRV_REPORT_STRING = 0x8000000F,
+ MLAN_EVENT_ID_DRV_DBG_DUMP = 0x80000012,
+ MLAN_EVENT_ID_DRV_BGSCAN_RESULT = 0x80000013,
+ MLAN_EVENT_ID_DRV_FLUSH_RX_WORK = 0x80000015,
+ MLAN_EVENT_ID_DRV_DEFER_RX_WORK = 0x80000016,
+ MLAN_EVENT_ID_DRV_FT_RESPONSE = 0x80000018,
+ MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK = 0x80000019,
+#ifdef UAP_SUPPORT
+ MLAN_EVENT_ID_DRV_UAP_CHAN_INFO = 0x80000020,
+#endif
+ MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER = 0x80000026,
+ MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER = 0x80000027,
+ MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER = 0x80000028,
+ MLAN_EVENT_ID_DRV_WIFI_STATUS = 0x80000029,
+ MLAN_EVENT_ID_STORE_HOST_CMD_RESP = 0x80000030,
+} mlan_event_id;
+
+/** Data Structures */
+/** mlan_image data structure */
+typedef struct _mlan_fw_image {
+ /** Firmware image buffer pointer */
+ t_u8 *pfw_buf;
+ /** Firmware image length */
+ t_u32 fw_len;
+ /** Firmware reload flag */
+ t_u8 fw_reload;
+} mlan_fw_image, *pmlan_fw_image;
+
+/** MrvlIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlIEtypesHeader {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+} MLAN_PACK_END MrvlIEtypesHeader_t;
+
+/** MrvlExtIEtypesHeader_t */
+typedef MLAN_PACK_START struct _MrvlExtIEtypesHeader {
+ /** Header type */
+ t_u16 type;
+ /** Header length */
+ t_u16 len;
+ /** ext id */
+ t_u8 ext_id;
+} MLAN_PACK_END MrvlExtIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlExtIEtypes_Data_t {
+ /** Header */
+ MrvlExtIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[];
+} MLAN_PACK_END MrvlExtIEtypes_Data_t;
+
+/** MrvlIEtypes_Data_t */
+typedef MLAN_PACK_START struct _MrvlIEtypes_Data_t {
+ /** Header */
+ MrvlIEtypesHeader_t header;
+ /** Data */
+ t_u8 data[];
+} MLAN_PACK_END MrvlIEtypes_Data_t;
+
+#define OID_TYPE_CAL 0x2
+#define OID_TYPE_DPD 0xa
+#define UNKNOW_DPD_LENGTH 0xffffffff
+
+/** Custom data structure */
+typedef struct _mlan_init_param {
+ /** DPD data buffer pointer */
+ t_u8 *pdpd_data_buf;
+ /** DPD data length */
+ t_u32 dpd_data_len;
+ /** region txpowerlimit cfg data buffer pointer */
+ t_u8 *ptxpwr_data_buf;
+ /** region txpowerlimit cfg data length */
+ t_u32 txpwr_data_len;
+ /** Cal data buffer pointer */
+ t_u8 *pcal_data_buf;
+ /** Cal data length */
+ t_u32 cal_data_len;
+ /** Other custom data */
+} mlan_init_param, *pmlan_init_param;
+
+/** channel type */
+enum mlan_channel_type {
+ CHAN_NO_HT,
+ CHAN_HT20,
+ CHAN_HT40MINUS,
+ CHAN_HT40PLUS,
+ CHAN_VHT80
+};
+
+/** channel band */
+enum { BAND_2GHZ = 0,
+ BAND_5GHZ = 1,
+ BAND_4GHZ = 2,
+};
+
+/** channel offset */
+enum { SEC_CHAN_NONE = 0,
+ SEC_CHAN_ABOVE = 1,
+ SEC_CHAN_5MHZ = 2,
+ SEC_CHAN_BELOW = 3 };
+
+/** channel bandwidth */
+enum { CHAN_BW_20MHZ = 0,
+ CHAN_BW_10MHZ,
+ CHAN_BW_40MHZ,
+ CHAN_BW_80MHZ,
+};
+
+/** scan mode */
+enum { SCAN_MODE_MANUAL = 0,
+ SCAN_MODE_ACS,
+ SCAN_MODE_USER,
+};
+
+/** max cac time 10 minutes */
+#define MAX_CAC_DWELL_TIME 600000
+/** default cac time 60 seconds */
+#define DEF_CAC_DWELL_TIME 60000
+/** start freq for 5G */
+#define START_FREQ_11A_BAND 5000
+/** DFS state */
+typedef enum _dfs_state_t {
+ /** Channel can be used, CAC (Channel Availability Check) must be done
+ before using it */
+ DFS_USABLE = 0,
+ /** Channel is not available, radar was detected */
+ DFS_UNAVAILABLE = 1,
+ /** Channel is Available, CAC is done and is free of radar */
+ DFS_AVAILABLE = 2,
+} dfs_state_t;
+
+typedef enum _dfs_w53_cfg_t {
+ /** DFS W53 Default Fw Value */
+ DFS_W53_DEFAULT_FW = 0,
+ /** DFS W53 New W53 Rules/Standard */
+ DFS_W53_NEW = 1,
+ /** DFS W53 Old W53 Rules/Standard */
+ DFS_W53_OLD = 2
+} dfs_w53_cfg_t;
+
+/** Band_Config_t */
+typedef MLAN_PACK_START struct _Band_Config_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=user*/
+ t_u8 scanMode : 2;
+ /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */
+ t_u8 chan2Offset : 2;
+ /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */
+ t_u8 chanWidth : 2;
+ /** Band Info - (00)=2.4GHz, (01)=5GHz */
+ t_u8 chanBand : 2;
+#else
+ /** Band Info - (00)=2.4GHz, (01)=5GHz */
+ t_u8 chanBand : 2;
+ /** Channel Width - (00)=20MHz, (10)=40MHz, (11)=80MHz */
+ t_u8 chanWidth : 2;
+ /** Secondary Channel Offset - (00)=None, (01)=Above, (11)=Below */
+ t_u8 chan2Offset : 2;
+ /** Channel Selection Mode - (00)=manual, (01)=ACS, (02)=Adoption mode*/
+ t_u8 scanMode : 2;
+#endif
+} MLAN_PACK_END Band_Config_t;
+
+/** channel_band_t */
+typedef MLAN_PACK_START struct _chan_band_info {
+ /** Band Configuration */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** 11n flag */
+ t_u8 is_11n_enabled;
+ /** center channel */
+ t_u8 center_chan;
+ /** dfs channel flag */
+ t_u8 is_dfs_chan;
+} MLAN_PACK_END chan_band_info, *pchan_band_info;
+
+/** Channel usability flags */
+#define NXP_CHANNEL_NO_OFDM MBIT(9)
+#define NXP_CHANNEL_NO_CCK MBIT(8)
+#define NXP_CHANNEL_DISABLED MBIT(7)
+/* BIT 5/6 resevered for FW */
+#define NXP_CHANNEL_NOHT160 MBIT(4)
+#define NXP_CHANNEL_NOHT80 MBIT(3)
+#define NXP_CHANNEL_NOHT40 MBIT(2)
+#define NXP_CHANNEL_DFS MBIT(1)
+#define NXP_CHANNEL_PASSIVE MBIT(0)
+
+/** CFP dynamic (non-const) elements */
+typedef struct _cfp_dyn_t {
+ /** extra flags to specify channel usability
+ * bit 9 : if set, channel is non-OFDM
+ * bit 8 : if set, channel is non-CCK
+ * bit 7 : if set, channel is disabled
+ * bit 5/6 resevered for FW
+ * bit 4 : if set, 160MHz on channel is disabled
+ * bit 3 : if set, 80MHz on channel is disabled
+ * bit 2 : if set, 40MHz on channel is disabled
+ * bit 1 : if set, channel is DFS channel
+ * bit 0 : if set, channel is passive
+ */
+ t_u16 flags;
+ /** TRUE: Channel is blacklisted (do not use) */
+ t_bool blacklist;
+} cfp_dyn_t;
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _chan_freq_power_t {
+ /** Channel Number */
+ t_u16 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+ /** Max allowed Tx power level */
+ t_u16 max_tx_power;
+ /** TRUE:radar detect required for BAND A or passive scan for BAND B/G;
+ * FALSE:radar detect not required for BAND A or active scan for BAND
+ * B/G*/
+ t_bool passive_scan_or_radar_detect;
+ /** Elements associated to cfp that change at run-time */
+ cfp_dyn_t dynamic;
+} chan_freq_power_t;
+
+/** mlan_event data structure */
+typedef struct _mlan_event {
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** Event buffer */
+ t_u8 event_buf[];
+} mlan_event, *pmlan_event;
+
+/** mlan_cmdresp_event data structure */
+typedef struct _mlan_cmdresp_event {
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Event ID */
+ mlan_event_id event_id;
+ /** Event length */
+ t_u32 event_len;
+ /** resp buffer pointer */
+ t_u8 *resp;
+} mlan_cmdresp_event, *pmlan_cmdresp_event;
+
+/** csi event data structure */
+
+/** mlan_ioctl_req data structure */
+typedef struct _mlan_ioctl_req {
+ /** Pointer to previous mlan_ioctl_req */
+ struct _mlan_ioctl_req *pprev;
+ /** Pointer to next mlan_ioctl_req */
+ struct _mlan_ioctl_req *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Request id */
+ t_u32 req_id;
+ /** Action: set or get */
+ t_u32 action;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+ /** Length of buffer */
+ t_u32 buf_len;
+ /** Length of the data read/written in buffer */
+ t_u32 data_read_written;
+ /** Length of buffer needed */
+ t_u32 buf_len_needed;
+ /** Reserved for MOAL module */
+ t_ptr reserved_1;
+} mlan_ioctl_req, *pmlan_ioctl_req;
+
+/** txpower structure */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Host tx power ctrl:
+ 0x0: use fw setting for TX power
+ 0x1: value specified in bit[6] and bit[5:0] are valid */
+ t_u8 hostctl : 1;
+ /** Sign of the power specified in bit[5:0] */
+ t_u8 sign : 1;
+ /** Power to be used for transmission(in dBm) */
+ t_u8 abs_val : 6;
+#else
+ /** Power to be used for transmission(in dBm) */
+ t_u8 abs_val : 6;
+ /** Sign of the power specified in bit[5:0] */
+ t_u8 sign : 1;
+ /** Host tx power ctrl:
+ 0x0: use fw setting for TX power
+ 0x1: value specified in bit[6] and bit[5:0] are valid */
+ t_u8 hostctl : 1;
+#endif
+} MLAN_PACK_END tx_power_t;
+/* pkt_txctrl */
+typedef MLAN_PACK_START struct _pkt_txctrl {
+ /**Data rate in unit of 0.5Mbps */
+ t_u16 data_rate;
+ /*Channel number to transmit the frame */
+ t_u8 channel;
+ /** Bandwidth to transmit the frame*/
+ t_u8 bw;
+ /** Power to be used for transmission*/
+ union {
+ tx_power_t tp;
+ t_u8 val;
+ } tx_power;
+ /** Retry time of tx transmission*/
+ t_u8 retry_limit;
+} MLAN_PACK_END pkt_txctrl, *ppkt_txctrl;
+
+/** pkt_rxinfo */
+typedef MLAN_PACK_START struct _pkt_rxinfo {
+ /** Data rate of received paccket*/
+ t_u16 data_rate;
+ /** Channel on which packet was received*/
+ t_u8 channel;
+ /** Rx antenna*/
+ t_u8 antenna;
+ /** Rx Rssi*/
+ t_u8 rssi;
+} MLAN_PACK_END pkt_rxinfo, *ppkt_rxinfo;
+
+/** mlan_buffer data structure */
+typedef struct _mlan_buffer {
+ /** Pointer to previous mlan_buffer */
+ struct _mlan_buffer *pprev;
+ /** Pointer to next mlan_buffer */
+ struct _mlan_buffer *pnext;
+ /** Status code from firmware/driver */
+ t_u32 status_code;
+ /** Flags for this buffer */
+ t_u32 flags;
+ /** BSS index number for multiple BSS support */
+ t_u32 bss_index;
+ /** Buffer descriptor, e.g. skb in Linux */
+ t_void *pdesc;
+ /** Pointer to buffer */
+ t_u8 *pbuf;
+#ifdef PCIE
+ /** Physical address of the pbuf pointer */
+ t_u64 buf_pa;
+ t_u32 total_pcie_buf_len;
+#endif
+ /** Offset to data */
+ t_u32 data_offset;
+ /** Data length */
+ t_u32 data_len;
+ /** Buffer type: data, cmd, event etc. */
+ mlan_buf_type buf_type;
+
+ /** Fields below are valid for data packet only */
+ /** QoS priority */
+ t_u32 priority;
+ /** Time stamp when packet is received (seconds) */
+ t_u32 in_ts_sec;
+ /** Time stamp when packet is received (micro seconds) */
+ t_u32 in_ts_usec;
+ /** Time stamp when packet is processed (seconds) */
+ t_u32 out_ts_sec;
+ /** Time stamp when packet is processed (micro seconds) */
+ t_u32 out_ts_usec;
+ /** tx_seq_num */
+ t_u32 tx_seq_num;
+
+ /** Fields below are valid for MLAN module only */
+ /** Pointer to parent mlan_buffer */
+ struct _mlan_buffer *pparent;
+ /** Use count for this buffer */
+ t_u32 use_count;
+ union {
+ pkt_txctrl tx_info;
+ pkt_rxinfo rx_info;
+ } u;
+} mlan_buffer, *pmlan_buffer, **ppmlan_buffer;
+
+/** mlan_fw_info data structure */
+typedef struct _mlan_hw_info {
+ t_u32 fw_cap;
+} mlan_hw_info, *pmlan_hw_info;
+
+/** mlan_bss_attr data structure */
+typedef struct _mlan_bss_attr {
+ /** BSS type */
+ t_u32 bss_type;
+ /** Data frame type: Ethernet II, 802.11, etc. */
+ t_u32 frame_type;
+ /** The BSS is active (non-0) or not (0). */
+ t_u32 active;
+ /** BSS Priority */
+ t_u32 bss_priority;
+ /** BSS number */
+ t_u32 bss_num;
+ /** The BSS is virtual */
+ t_u32 bss_virtual;
+} mlan_bss_attr, *pmlan_bss_attr;
+
+/** bss tbl data structure */
+typedef struct _mlan_bss_tbl {
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+} mlan_bss_tbl, *pmlan_bss_tbl;
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/** Type enumeration for the command result */
+typedef MLAN_PACK_START enum _mlan_cmd_result_e {
+ MLAN_CMD_RESULT_SUCCESS = 0,
+ MLAN_CMD_RESULT_FAILURE = 1,
+ MLAN_CMD_RESULT_TIMEOUT = 2,
+ MLAN_CMD_RESULT_INVALID_DATA = 3
+} MLAN_PACK_END mlan_cmd_result_e;
+
+/** Type enumeration of WMM AC_QUEUES */
+typedef MLAN_PACK_START enum _mlan_wmm_ac_e {
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} MLAN_PACK_END mlan_wmm_ac_e;
+
+/** Type enumeration for the action field in the Queue Config command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e {
+ MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+ MLAN_WMM_QUEUE_CONFIG_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_config_action_e;
+
+/** Type enumeration for the action field in the queue stats command */
+typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e {
+ MLAN_WMM_STATS_ACTION_START = 0,
+ MLAN_WMM_STATS_ACTION_STOP = 1,
+ MLAN_WMM_STATS_ACTION_GET_CLR = 2,
+ MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
+ MLAN_WMM_STATS_ACTION_MAX
+} MLAN_PACK_END mlan_wmm_queue_stats_action_e;
+
+/**
+ * @brief IOCTL structure for a Traffic stream status.
+ *
+ */
+typedef MLAN_PACK_START struct {
+ /** TSID: Range: 0->7 */
+ t_u8 tid;
+ /** TSID specified is valid */
+ t_u8 valid;
+ /** AC TSID is active on */
+ t_u8 access_category;
+ /** UP specified for the TSID */
+ t_u8 user_priority;
+ /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */
+ t_u8 psb;
+ /** Upstream(0), Downlink(1), Bidirectional(3) */
+ t_u8 flow_dir;
+ /** Medium time granted for the TSID */
+ t_u16 medium_time;
+} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t,
+ /** Type definition of mlan_ds_wmm_ts_status for
+ MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status;
+
+/** Max Ie length */
+#define MAX_IE_SIZE 256
+
+/** custom IE */
+typedef MLAN_PACK_START struct _custom_ie {
+ /** IE Index */
+ t_u16 ie_index;
+ /** Mgmt Subtype Mask */
+ t_u16 mgmt_subtype_mask;
+ /** IE Length */
+ t_u16 ie_length;
+ /** IE buffer */
+ t_u8 ie_buffer[MAX_IE_SIZE];
+} MLAN_PACK_END custom_ie;
+
+/** Max IE index to FW */
+#define MAX_MGMT_IE_INDEX_TO_FW 4
+/** Max IE index per BSS */
+#define MAX_MGMT_IE_INDEX 26
+
+/** custom IE info */
+typedef MLAN_PACK_START struct _custom_ie_info {
+ /** size of buffer */
+ t_u16 buf_size;
+ /** no of buffers of buf_size */
+ t_u16 buf_count;
+} MLAN_PACK_END custom_ie_info;
+
+/** TLV buffer : Max Mgmt IE */
+typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** No of tuples */
+ t_u16 count;
+ /** custom IE info tuples */
+ custom_ie_info info[MAX_MGMT_IE_INDEX];
+} MLAN_PACK_END tlvbuf_max_mgmt_ie;
+
+/** TLV buffer : custom IE */
+typedef MLAN_PACK_START struct _tlvbuf_custom_ie {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+ /** IE data */
+ custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW];
+ /** Max mgmt IE TLV */
+ tlvbuf_max_mgmt_ie max_mgmt_ie;
+} MLAN_PACK_END mlan_ds_misc_custom_ie;
+
+/** channel width */
+typedef enum wifi_channel_width {
+ WIFI_CHAN_WIDTH_20 = 0,
+ WIFI_CHAN_WIDTH_40 = 1,
+ WIFI_CHAN_WIDTH_80 = 2,
+ WIFI_CHAN_WIDTH_160 = 3,
+ WIFI_CHAN_WIDTH_80P80 = 4,
+ WIFI_CHAN_WIDTH_5 = 5,
+ WIFI_CHAN_WIDTH_10 = 6,
+ WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width_t;
+
+/** channel information */
+typedef struct {
+ /** channel width (20, 40, 80, 80+80, 160) */
+ wifi_channel_width_t width;
+ /** primary 20 MHz channel */
+ int center_freq;
+ /** center frequency (MHz) first segment */
+ int center_freq0;
+ /** center frequency (MHz) second segment */
+ int center_freq1;
+} wifi_channel_info;
+
+/** wifi rate */
+typedef struct {
+ /** 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ t_u32 preamble : 3;
+ /** 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ t_u32 nss : 2;
+ /** 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
+ t_u32 bw : 3;
+ /** OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps
+ */
+ /** HT/VHT it would be mcs index */
+ t_u32 rateMcsIdx : 8;
+ /** reserved */
+ t_u32 reserved : 16;
+ /** units of 100 Kbps */
+ t_u32 bitrate;
+} wifi_rate;
+
+/** wifi Preamble type */
+typedef enum {
+ WIFI_PREAMBLE_LEGACY = 0x1,
+ WIFI_PREAMBLE_HT = 0x2,
+ WIFI_PREAMBLE_VHT = 0x4
+} wifi_preamble;
+
+/** timeval */
+typedef struct {
+ /** Time (seconds) */
+ t_u32 time_sec;
+ /** Time (micro seconds) */
+ t_u32 time_usec;
+} wifi_timeval;
+
+#define MAX_NUM_RATE 32
+#define MAX_RADIO 2
+#define MAX_NUM_CHAN 1
+#define VHT_NUM_SUPPORT_MCS 10
+#define MCS_NUM_SUPP 16
+
+#define BUF_MAXLEN 4096
+/** connection state */
+typedef enum {
+ MLAN_DISCONNECTED = 0,
+ MLAN_AUTHENTICATING = 1,
+ MLAN_ASSOCIATING = 2,
+ MLAN_ASSOCIATED = 3,
+ /** if done by firmware/driver */
+ MLAN_EAPOL_STARTED = 4,
+ /** if done by firmware/driver */
+ MLAN_EAPOL_COMPLETED = 5,
+} mlan_connection_state;
+/** roam state */
+typedef enum {
+ MLAN_ROAMING_IDLE = 0,
+ MLAN_ROAMING_ACTIVE = 1,
+} mlan_roam_state;
+/** interface mode */
+typedef enum {
+ MLAN_INTERFACE_STA = 0,
+ MLAN_INTERFACE_SOFTAP = 1,
+ MLAN_INTERFACE_IBSS = 2,
+ MLAN_INTERFACE_P2P_CLIENT = 3,
+ MLAN_INTERFACE_P2P_GO = 4,
+ MLAN_INTERFACE_NAN = 5,
+ MLAN_INTERFACE_MESH = 6,
+} mlan_interface_mode;
+
+/** set for QOS association */
+#define MLAN_CAPABILITY_QOS 0x00000001
+/** set for protected association (802.11 beacon frame control protected bit
+ * set) */
+#define MLAN_CAPABILITY_PROTECTED 0x00000002
+/** set if 802.11 Extended Capabilities element interworking bit is set */
+#define MLAN_CAPABILITY_INTERWORKING 0x00000004
+/** set for HS20 association */
+#define MLAN_CAPABILITY_HS20 0x00000008
+/** set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */
+#define MLAN_CAPABILITY_SSID_UTF8 0x00000010
+/** set is 802.11 Country Element is present */
+#define MLAN_CAPABILITY_COUNTRY 0x00000020
+
+/** link layer status */
+typedef struct {
+ /** interface mode */
+ mlan_interface_mode mode;
+ /** interface mac address (self) */
+ t_u8 mac_addr[6];
+ /** connection state (valid for STA, CLI only) */
+ mlan_connection_state state;
+ /** roaming state */
+ mlan_roam_state roaming;
+ /** WIFI_CAPABILITY_XXX (self) */
+ t_u32 capabilities;
+ /** null terminated SSID */
+ t_u8 ssid[33];
+ /** bssid */
+ t_u8 bssid[6];
+ /** country string advertised by AP */
+ t_u8 ap_country_str[3];
+ /** country string for this association */
+ t_u8 country_str[3];
+} mlan_interface_link_layer_info, *mlan_interface_handle;
+
+/** channel statistics */
+typedef struct {
+ /** channel */
+ wifi_channel_info channel;
+ /** msecs the radio is awake (32 bits number accruing over time) */
+ t_u32 on_time;
+ /** msecs the CCA register is busy (32 bits number accruing over time)
+ */
+ t_u32 cca_busy_time;
+} wifi_channel_stat;
+
+#define timeval_to_msec(timeval) \
+ (t_u64)((t_u64)(timeval.time_sec) * 1000 + \
+ (t_u64)(timeval.time_usec) / 1000)
+#define timeval_to_usec(timeval) \
+ (t_u64)((t_u64)(timeval.time_sec) * 1000 * 1000 + \
+ (t_u64)(timeval.time_usec))
+#define is_zero_timeval(timeval) \
+ ((timeval.time_sec == 0) && (timeval.time_usec == 0))
+
+/** radio statistics */
+typedef struct {
+ /** wifi radio (if multiple radio supported) */
+ int radio;
+ /** msecs the radio is awake (32 bits number accruing over time) */
+ t_u32 on_time;
+ /** msecs the radio is transmitting (32 bits number accruing over time)
+ */
+ t_u32 tx_time;
+ /** TBD: num_tx_levels: number of radio transmit power levels */
+ t_u32 reserved0;
+ /** TBD: tx_time_per_levels: pointer to an array of radio transmit per
+ * power levels in msecs accured over time */
+ /* t_u32 *reserved1;*/
+ /** msecs the radio is in active receive (32 bits number accruing over
+ * time) */
+ t_u32 rx_time;
+ /** msecs the radio is awake due to all scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_scan;
+ /** msecs the radio is awake due to NAN (32 bits number accruing over
+ * time) */
+ t_u32 on_time_nbd;
+ /** msecs the radio is awake due to G?scan (32 bits number accruing over
+ * time) */
+ t_u32 on_time_gscan;
+ /** msecs the radio is awake due to roam?scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_roam_scan;
+ /** msecs the radio is awake due to PNO scan (32 bits number accruing
+ * over time) */
+ t_u32 on_time_pno_scan;
+ /** msecs the radio is awake due to HS2.0 scans and GAS exchange (32
+ * bits number accruing over time) */
+ t_u32 on_time_hs20;
+ /** number of channels */
+ t_u32 num_channels;
+ /** channel statistics */
+ wifi_channel_stat channels[MAX_NUM_CHAN];
+} wifi_radio_stat;
+
+/** per rate statistics */
+typedef struct {
+ /** rate information */
+ wifi_rate rate;
+ /** number of successfully transmitted data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received data pkts */
+ t_u32 rx_mpdu;
+ /** number of data packet losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+} wifi_rate_stat;
+
+/** wifi peer type */
+typedef enum {
+ WIFI_PEER_STA,
+ WIFI_PEER_AP,
+ WIFI_PEER_P2P_GO,
+ WIFI_PEER_P2P_CLIENT,
+ WIFI_PEER_NAN,
+ WIFI_PEER_TDLS,
+ WIFI_PEER_INVALID,
+} wifi_peer_type;
+
+/** per peer statistics */
+typedef struct {
+ /** peer type (AP, TDLS, GO etc.) */
+ wifi_peer_type type;
+ /** mac address */
+ t_u8 peer_mac_address[6];
+ /** peer WIFI_CAPABILITY_XXX */
+ t_u32 capabilities;
+ /** number of rates */
+ t_u32 num_rate;
+ /** per rate statistics, number of entries = num_rate */
+ wifi_rate_stat rate_stats[];
+} wifi_peer_info;
+
+/** per access category statistics */
+typedef struct {
+ /** access category (VI, VO, BE, BK) */
+ mlan_wmm_ac_e ac;
+ /** number of successfully transmitted unicast data pkts (ACK rcvd) */
+ t_u32 tx_mpdu;
+ /** number of received unicast mpdus */
+ t_u32 rx_mpdu;
+ /** number of succesfully transmitted multicast data packets */
+ /** STA case: implies ACK received from AP for the unicast packet in
+ * which mcast pkt was sent */
+ t_u32 tx_mcast;
+ /** number of received multicast data packets */
+ t_u32 rx_mcast;
+ /** number of received unicast a-mpdus */
+ t_u32 rx_ampdu;
+ /** number of transmitted unicast a-mpdus */
+ t_u32 tx_ampdu;
+ /** number of data pkt losses (no ACK) */
+ t_u32 mpdu_lost;
+ /** total number of data pkt retries */
+ t_u32 retries;
+ /** number of short data pkt retries */
+ t_u32 retries_short;
+ /** number of long data pkt retries */
+ t_u32 retries_long;
+ /** data pkt min contention time (usecs) */
+ t_u32 contention_time_min;
+ /** data pkt max contention time (usecs) */
+ t_u32 contention_time_max;
+ /** data pkt avg contention time (usecs) */
+ t_u32 contention_time_avg;
+ /** num of data pkts used for contention statistics */
+ t_u32 contention_num_samples;
+} wifi_wmm_ac_stat;
+
+/** interface statistics */
+typedef struct {
+ /** wifi interface */
+ /* wifi_interface_handle iface;*/
+ /** current state of the interface */
+ mlan_interface_link_layer_info info;
+ /** access point beacon received count from connected AP */
+ t_u32 beacon_rx;
+ /** Average beacon offset encountered (beacon_TSF - TBTT)
+ * the average_tsf_offset field is used so as to calculate the
+ * typical beacon contention time on the channel as well may be
+ * used to debug beacon synchronization and related power consumption
+ * issue
+ */
+ t_u64 average_tsf_offset;
+ /** indicate that this AP typically leaks packets beyond the driver
+ * guard time */
+ t_u32 leaky_ap_detected;
+ /** average number of frame leaked by AP after frame with PM bit set was
+ * ACK'ed by AP */
+ t_u32 leaky_ap_avg_num_frames_leaked;
+ /** Guard time currently in force (when implementing IEEE power
+ * management based on frame control PM bit), How long driver waits
+ * before shutting down the radio and after receiving an ACK for a data
+ * frame with PM bit set)
+ */
+ t_u32 leaky_ap_guard_time;
+ /** access point mgmt frames received count from connected AP (including
+ * Beacon) */
+ t_u32 mgmt_rx;
+ /** action frames received count */
+ t_u32 mgmt_action_rx;
+ /** action frames transmit count */
+ t_u32 mgmt_action_tx;
+ /** access Point Beacon and Management frames RSSI (averaged) */
+ t_s32 rssi_mgmt;
+ /** access Point Data Frames RSSI (averaged) from connected AP */
+ t_s32 rssi_data;
+ /** access Point ACK RSSI (averaged) from connected AP */
+ t_s32 rssi_ack;
+ /** per ac data packet statistics */
+ wifi_wmm_ac_stat ac[MAX_AC_QUEUES];
+ /** number of peers */
+ t_u32 num_peers;
+ /** per peer statistics */
+ wifi_peer_info peer_info[];
+} wifi_iface_stat;
+
+/** link layer stat configuration params */
+typedef struct {
+ /** threshold to classify the pkts as short or long */
+ t_u32 mpdu_size_threshold;
+ /** wifi statistics bitmap */
+ t_u32 aggressive_statistics_gathering;
+} wifi_link_layer_params;
+
+/** wifi statistics bitmap */
+#define WIFI_STATS_RADIO 0x00000001 /** all radio statistics */
+#define WIFI_STATS_RADIO_CCA \
+ 0x00000002 /** cca_busy_time (within radio statistics) */
+#define WIFI_STATS_RADIO_CHANNELS \
+ 0x00000004 /** all channel statistics (within radio statistics) */
+#define WIFI_STATS_RADIO_SCAN \
+ 0x00000008 /** all scan statistics (within radio statistics) */
+#define WIFI_STATS_IFACE 0x00000010 /** all interface statistics */
+#define WIFI_STATS_IFACE_TXRATE \
+ 0x00000020 /** all tx rate statistics (within interface statistics) */
+#define WIFI_STATS_IFACE_AC \
+ 0x00000040 /** all ac statistics (within interface statistics) */
+#define WIFI_STATS_IFACE_CONTENTION \
+ 0x00000080 /** all contention (min, max, avg) statistics (within ac \
+ statisctics) */
+
+/** station stats */
+typedef struct _sta_stats {
+ t_u64 last_rx_in_msec;
+} sta_stats;
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** mlan_callbacks data structure */
+typedef struct _mlan_callbacks {
+ /** moal_get_fw_data */
+ mlan_status (*moal_get_fw_data)(t_void *pmoal_handle, t_u32 offset,
+ t_u32 len, t_u8 *pbuf);
+ mlan_status (*moal_get_vdll_data)(t_void *pmoal_handle, t_u32 len,
+ t_u8 *pbuf);
+ /** moal_get_hw_spec_complete */
+ mlan_status (*moal_get_hw_spec_complete)(t_void *pmoal_handle,
+ mlan_status status,
+ pmlan_hw_info phw,
+ pmlan_bss_tbl ptbl);
+ /** moal_init_fw_complete */
+ mlan_status (*moal_init_fw_complete)(t_void *pmoal_handle,
+ mlan_status status);
+ /** moal_shutdown_fw_complete */
+ mlan_status (*moal_shutdown_fw_complete)(t_void *pmoal_handle,
+ mlan_status status);
+ /** moal_send_packet_complete */
+ mlan_status (*moal_send_packet_complete)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf,
+ mlan_status status);
+ /** moal_recv_complete */
+ mlan_status (*moal_recv_complete)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ mlan_status status);
+ /** moal_recv_packet */
+ mlan_status (*moal_recv_packet)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf);
+ /** moal_recv_event */
+ mlan_status (*moal_recv_event)(t_void *pmoal_handle,
+ pmlan_event pmevent);
+ /** moal_ioctl_complete */
+ mlan_status (*moal_ioctl_complete)(t_void *pmoal_handle,
+ pmlan_ioctl_req pioctl_req,
+ mlan_status status);
+
+ /** moal_alloc_mlan_buffer */
+ mlan_status (*moal_alloc_mlan_buffer)(t_void *pmoal_handle, t_u32 size,
+ ppmlan_buffer pmbuf);
+ /** moal_free_mlan_buffer */
+ mlan_status (*moal_free_mlan_buffer)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf);
+
+#ifdef USB
+ /** moal_write_data_async */
+ mlan_status (*moal_write_data_async)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port);
+#endif /* USB */
+#if defined(SDIO) || defined(PCIE)
+ /** moal_write_reg */
+ mlan_status (*moal_write_reg)(t_void *pmoal_handle, t_u32 reg,
+ t_u32 data);
+ /** moal_read_reg */
+ mlan_status (*moal_read_reg)(t_void *pmoal_handle, t_u32 reg,
+ t_u32 *data);
+#endif /* SDIO || PCIE */
+ /** moal_write_data_sync */
+ mlan_status (*moal_write_data_sync)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ t_u32 timeout);
+ /** moal_read_data_sync */
+ mlan_status (*moal_read_data_sync)(t_void *pmoal_handle,
+ pmlan_buffer pmbuf, t_u32 port,
+ t_u32 timeout);
+ /** moal_malloc */
+ mlan_status (*moal_malloc)(t_void *pmoal_handle, t_u32 size, t_u32 flag,
+ t_u8 **ppbuf);
+ /** moal_mfree */
+ mlan_status (*moal_mfree)(t_void *pmoal_handle, t_u8 *pbuf);
+ /** moal_vmalloc */
+ mlan_status (*moal_vmalloc)(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf);
+ /** moal_vfree */
+ mlan_status (*moal_vfree)(t_void *pmoal_handle, t_u8 *pbuf);
+#ifdef PCIE
+ /** moal_malloc_consistent */
+ mlan_status (*moal_malloc_consistent)(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf, t_u64 *pbuf_pa);
+ /** moal_mfree_consistent */
+ mlan_status (*moal_mfree_consistent)(t_void *pmoal_handle, t_u32 size,
+ t_u8 *pbuf, t_u64 buf_pa);
+ /** moal_map_memory */
+ mlan_status (*moal_map_memory)(t_void *pmoal_handle, t_u8 *pbuf,
+ t_u64 *pbuf_pa, t_u32 size, t_u32 flag);
+ /** moal_unmap_memory */
+ mlan_status (*moal_unmap_memory)(t_void *pmoal_handle, t_u8 *pbuf,
+ t_u64 buf_pa, t_u32 size, t_u32 flag);
+#endif /* PCIE */
+ /** moal_memset */
+ t_void *(*moal_memset)(t_void *pmoal_handle, t_void *pmem, t_u8 byte,
+ t_u32 num);
+ /** moal_memcpy */
+ t_void *(*moal_memcpy)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num);
+ /** moal_memcpy_ext */
+ t_void *(*moal_memcpy_ext)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num,
+ t_u32 dest_size);
+ /** moal_memmove */
+ t_void *(*moal_memmove)(t_void *pmoal_handle, t_void *pdest,
+ const t_void *psrc, t_u32 num);
+ /** moal_memcmp */
+ t_s32 (*moal_memcmp)(t_void *pmoal_handle, const t_void *pmem1,
+ const t_void *pmem2, t_u32 num);
+ /** moal_udelay */
+ t_void (*moal_udelay)(t_void *pmoal_handle, t_u32 udelay);
+ /** moal_usleep_range */
+ t_void (*moal_usleep_range)(t_void *pmoal_handle, t_u32 min_delay,
+ t_u32 max_delay);
+ /** moal_get_boot_ktime */
+ mlan_status (*moal_get_boot_ktime)(t_void *pmoal_handle, t_u64 *pnsec);
+ /** moal_get_system_time */
+ mlan_status (*moal_get_system_time)(t_void *pmoal_handle, t_u32 *psec,
+ t_u32 *pusec);
+ /** moal_init_timer*/
+ mlan_status (*moal_init_timer)(t_void *pmoal_handle, t_void **pptimer,
+ IN t_void (*callback)(t_void *pcontext),
+ t_void *pcontext);
+ /** moal_free_timer */
+ mlan_status (*moal_free_timer)(t_void *pmoal_handle, t_void *ptimer);
+ /** moal_start_timer*/
+ mlan_status (*moal_start_timer)(t_void *pmoal_handle, t_void *ptimer,
+ t_u8 periodic, t_u32 msec);
+ /** moal_stop_timer*/
+ mlan_status (*moal_stop_timer)(t_void *pmoal_handle, t_void *ptimer);
+ /** moal_init_lock */
+ mlan_status (*moal_init_lock)(t_void *pmoal_handle, t_void **pplock);
+ /** moal_free_lock */
+ mlan_status (*moal_free_lock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_spin_lock */
+ mlan_status (*moal_spin_lock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_spin_unlock */
+ mlan_status (*moal_spin_unlock)(t_void *pmoal_handle, t_void *plock);
+ /** moal_print */
+ t_void (*moal_print)(t_void *pmoal_handle, t_u32 level, char *pformat,
+ IN...);
+ /** moal_print_netintf */
+ t_void (*moal_print_netintf)(t_void *pmoal_handle, t_u32 bss_index,
+ t_u32 level);
+ /** moal_assert */
+ t_void (*moal_assert)(t_void *pmoal_handle, t_u32 cond);
+
+ /** moal_hist_data_add */
+ t_void (*moal_hist_data_add)(t_void *pmoal_handle, t_u32 bss_index,
+ t_u16 rx_rate, t_s8 snr, t_s8 nflr,
+ t_u8 antenna);
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ mlan_status (*moal_wait_hostcmd_complete)(t_void *pmoal_handle,
+ t_u32 bss_index);
+ mlan_status (*moal_notify_hostcmd_complete)(t_void *pmoal_handle,
+ t_u32 bss_index);
+#endif
+ void (*moal_tp_accounting)(t_void *pmoal_handle, t_void *buf,
+ t_u32 drop_point);
+ void (*moal_tp_accounting_rx_param)(t_void *pmoal_handle,
+ unsigned int type,
+ unsigned int rsvd1);
+
+} mlan_callbacks, *pmlan_callbacks;
+
+/** Parameter unchanged, use MLAN default setting */
+#define ROBUSTCOEX_GPIO_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define ROBUSTCOEX_GPIO_CFG 1
+
+#if defined(SDIO)
+/** Interrupt Mode SDIO */
+#define INT_MODE_SDIO 0
+/** Interrupt Mode GPIO */
+#define INT_MODE_GPIO 1
+/** New mode: GPIO-1 as a duplicated signal of interrupt as appear of SDIO_DAT1
+ */
+#define GPIO_INT_NEW_MODE 255
+#endif
+
+/** Parameter unchanged, use MLAN default setting */
+#define MLAN_INIT_PARA_UNCHANGED 0
+/** Parameter enabled, override MLAN default setting */
+#define MLAN_INIT_PARA_ENABLED 1
+/** Parameter disabled, override MLAN default setting */
+#define MLAN_INIT_PARA_DISABLED 2
+
+/** Control bit for stream 2X2 */
+#define FEATURE_CTRL_STREAM_2X2 MBIT(0)
+/** Control bit for DFS support */
+#define FEATURE_CTRL_DFS_SUPPORT MBIT(1)
+#ifdef USB
+/** Control bit for winner check & not wait for FW ready event */
+#define FEATURE_CTRL_USB_NEW_INIT MBIT(2)
+#endif
+/** Default feature control */
+#define FEATURE_CTRL_DEFAULT 0xffffffff
+/** Check if stream 2X2 enabled */
+#define IS_STREAM_2X2(x) ((x)&FEATURE_CTRL_STREAM_2X2)
+/** Check if DFS support enabled */
+#define IS_DFS_SUPPORT(x) ((x)&FEATURE_CTRL_DFS_SUPPORT)
+#ifdef USB
+/** Check if winner check & not wait for FW ready event */
+#define IS_USB_NEW_INIT(x) ((x)&FEATURE_CTRL_USB_NEW_INIT)
+#endif
+
+/*
+#define DRV_MODE_NAN MBIT(4)
+#define DRV_MODE_11P MBIT(5)
+#define DRV_MODE_MAC80211 MBIT(6)
+#define DRV_MODE_DFS MBIT(7)*/
+#define DRV_MODE_MASK (MBIT(4) | MBIT(5) | MBIT(6) | MBIT(7))
+
+/** mlan_device data structure */
+typedef struct _mlan_device {
+ /** MOAL Handle */
+ t_void *pmoal_handle;
+ /** BSS Attributes */
+ mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM];
+ /** Callbacks */
+ mlan_callbacks callbacks;
+#ifdef MFG_CMD_SUPPORT
+ /** MFG mode */
+ t_u32 mfg_mode;
+#endif
+#if defined(SDIO)
+ /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+ t_u32 int_mode;
+ /** GPIO interrupt pin number */
+ t_u32 gpio_pin;
+#endif
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ /** allocate fixed buffer size for scan beacon buffer*/
+ t_u32 fixed_beacon_buffer;
+ /** SDIO MPA Tx */
+ t_u32 mpa_tx_cfg;
+ /** SDIO MPA Rx */
+ t_u32 mpa_rx_cfg;
+#ifdef SDIO
+ /** SDIO Single port rx aggr */
+ t_u8 sdio_rx_aggr_enable;
+ /* see blk_queue_max_segment_size */
+ t_u32 max_seg_size;
+ /* see blk_queue_max_segments */
+ t_u16 max_segs;
+#endif
+ /** Auto deep sleep */
+ t_u32 auto_ds;
+ /** IEEE PS mode */
+ t_u32 ps_mode;
+ /** Max Tx buffer size */
+ t_u32 max_tx_buf;
+#if defined(STA_SUPPORT)
+ /** 802.11d configuration */
+ t_u32 cfg_11d;
+#endif
+ /** Feature control bitmask */
+ t_u32 feature_control;
+ /** enable/disable rx work */
+ t_u8 rx_work;
+ /** dev cap mask */
+ t_u32 dev_cap_mask;
+ /** oob independent reset */
+ t_u32 indrstcfg;
+ /** dtim interval */
+ t_u16 multi_dtim;
+ /** IEEE ps inactivity timeout value */
+ t_u16 inact_tmo;
+ /** card type */
+ t_u16 card_type;
+ /** card rev */
+ t_u8 card_rev;
+ /** Host sleep wakeup interval */
+ t_u32 hs_wake_interval;
+ /** GPIO to indicate wakeup source */
+ t_u8 indication_gpio;
+ /** Dynamic MIMO-SISO switch for hscfg*/
+ t_u8 hs_mimo_switch;
+#ifdef USB
+ /** Tx CMD endpoint address */
+ t_u8 tx_cmd_ep;
+ /** Rx CMD/EVT endpoint address */
+ t_u8 rx_cmd_ep;
+
+ /** Rx data endpoint address */
+ t_u8 rx_data_ep;
+ /** Tx data endpoint address */
+ t_u8 tx_data_ep;
+#endif
+ /** fw region */
+ t_bool fw_region;
+ /** passive to active scan */
+ t_u8 passive_to_active_scan;
+ /** uap max supported station per chip */
+ t_u8 uap_max_sta;
+ /** drv mode */
+ t_u32 drv_mode;
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+} mlan_device, *pmlan_device;
+
+/** MLAN API function prototype */
+#define MLAN_API
+
+/** Registration */
+MLAN_API mlan_status mlan_register(pmlan_device pmdevice,
+ t_void **ppmlan_adapter);
+
+/** Un-registration */
+MLAN_API mlan_status mlan_unregister(t_void *pmlan_adapter);
+
+/** Firmware Downloading */
+MLAN_API mlan_status mlan_dnld_fw(t_void *pmlan_adapter, pmlan_fw_image pmfw);
+
+/** Custom data pass API */
+MLAN_API mlan_status mlan_set_init_param(t_void *pmlan_adapter,
+ pmlan_init_param pparam);
+
+/** Firmware Initialization */
+MLAN_API mlan_status mlan_init_fw(t_void *pmlan_adapter);
+
+/** Firmware Shutdown */
+MLAN_API mlan_status mlan_shutdown_fw(t_void *pmlan_adapter);
+
+/** Main Process */
+MLAN_API mlan_status mlan_main_process(t_void *pmlan_adapter);
+
+/** Rx process */
+mlan_status mlan_rx_process(t_void *pmlan_adapter, t_u8 *rx_pkts);
+
+/** Packet Transmission */
+MLAN_API mlan_status mlan_send_packet(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf);
+
+#ifdef USB
+/** mlan_write_data_async_complete */
+MLAN_API mlan_status mlan_write_data_async_complete(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf,
+ t_u32 port,
+ mlan_status status);
+
+/** Packet Reception */
+MLAN_API mlan_status mlan_recv(t_void *pmlan_adapter, pmlan_buffer pmbuf,
+ t_u32 port);
+#endif /* USB */
+
+/** Packet Reception complete callback */
+MLAN_API mlan_status mlan_recv_packet_complete(t_void *pmlan_adapter,
+ pmlan_buffer pmbuf,
+ mlan_status status);
+
+#if defined(SDIO) || defined(PCIE)
+/** interrupt handler */
+MLAN_API mlan_status mlan_interrupt(t_u16 msg_id, t_void *pmlan_adapter);
+
+#if defined(SYSKT)
+/** GPIO IRQ callback function */
+MLAN_API t_void mlan_hs_callback(t_void *pctx);
+#endif /* SYSKT_MULTI || SYSKT */
+#endif /* SDIO || PCIE */
+
+MLAN_API t_void mlan_pm_wakeup_card(t_void *pmlan_adapter, t_u8 keep_wakeup);
+
+MLAN_API t_u8 mlan_is_main_process_running(t_void *adapter);
+#ifdef PCIE
+MLAN_API t_void mlan_set_int_mode(t_void *adapter, t_u32 int_mode,
+ t_u8 func_num);
+#endif
+/** mlan ioctl */
+MLAN_API mlan_status mlan_ioctl(t_void *pmlan_adapter,
+ pmlan_ioctl_req pioctl_req);
+/** mlan select wmm queue */
+MLAN_API t_u8 mlan_select_wmm_queue(t_void *pmlan_adapter, t_u8 bss_num,
+ t_u8 tid);
+
+#endif /* !_MLAN_DECL_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ieee.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ieee.h
new file mode 100644
index 000000000000..03b5fd4ffc92
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ieee.h
@@ -0,0 +1,1888 @@
+/** @file mlan_ieee.h
+ *
+ * @brief This file contains IEEE information element related
+ * definitions used in MLAN and MOAL module.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 11/03/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IEEE_H_
+#define _MLAN_IEEE_H_
+
+/** FIX IES size in beacon buffer */
+#define WLAN_802_11_FIXED_IE_SIZE 12
+/** WLAN supported rates */
+#define WLAN_SUPPORTED_RATES 14
+
+/** WLAN supported rates extension */
+#define WLAN_SUPPORTED_RATES_EXT 60
+
+/** Enumeration definition*/
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE {
+ Wlan802_11FH,
+ Wlan802_11DS,
+ /* Defined as upper bound*/
+ Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc)&0xF000) >> 12)
+#else
+/** Frame control: Type Mgmt frame */
+#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C
+/** Frame control: SubType Mgmt frame */
+#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc)&0x00F0) >> 4)
+#endif
+
+#ifdef PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+
+/* Reason codes */
+#define IEEE_80211_REASONCODE_UNSPECIFIED 1
+
+typedef enum _IEEEtypes_Ext_ElementId_e {
+ HE_CAPABILITY = 35,
+ HE_OPERATION = 36
+} IEEEtypes_Ext_ElementId_e;
+
+/** IEEE Type definitions */
+typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e {
+ SSID = 0,
+ SUPPORTED_RATES = 1,
+
+ FH_PARAM_SET = 2,
+ DS_PARAM_SET = 3,
+ CF_PARAM_SET = 4,
+
+ IBSS_PARAM_SET = 6,
+ COUNTRY_INFO = 7,
+ POWER_CONSTRAINT = 32,
+ POWER_CAPABILITY = 33,
+ TPC_REQUEST = 34,
+ TPC_REPORT = 35,
+ CHANNEL_SWITCH_ANN = 37,
+ EXTEND_CHANNEL_SWITCH_ANN = 60,
+ QUIET = 40,
+ IBSS_DFS = 41,
+ SUPPORTED_CHANNELS = 36,
+ REGULATORY_CLASS = 59,
+ HT_CAPABILITY = 45,
+ QOS_INFO = 46,
+ HT_OPERATION = 61,
+ MULTI_BSSID = 71,
+ BSSCO_2040 = 72,
+ OVERLAPBSSSCANPARAM = 74,
+ NONTX_BSSID_CAP = 83,
+ MBSSID_INDEX = 85,
+ EXT_CAPABILITY = 127,
+ /*IEEE802.11r*/
+ MOBILITY_DOMAIN = 54,
+ FAST_BSS_TRANSITION = 55,
+ TIMEOUT_INTERVAL = 56,
+ RIC = 57,
+ QOS_MAPPING = 110,
+ VHT_CAPABILITY = 191,
+ VHT_OPERATION = 192,
+ EXT_BSS_LOAD = 193,
+ BW_CHANNEL_SWITCH = 194,
+ VHT_TX_POWER_ENV = 195,
+ EXT_POWER_CONSTR = 196,
+ AID_INFO = 197,
+ QUIET_CHAN = 198,
+ OPER_MODE_NTF = 199,
+
+ ERP_INFO = 42,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+ WMM_IE = VENDOR_SPECIFIC_221,
+
+ WPS_IE = VENDOR_SPECIFIC_221,
+ /* WPA */
+ WPA_IE = VENDOR_SPECIFIC_221,
+ /* WPA2 */
+ RSN_IE = 48,
+ VS_IE = VENDOR_SPECIFIC_221,
+ WAPI_IE = 68,
+ FRAGMENT = 242,
+ EXTENSION = 255
+} MLAN_PACK_END IEEEtypes_ElementId_e;
+
+/** IEEE IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_Header_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t;
+
+/** Vendor specific IE header */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** OUI */
+ t_u8 oui[3];
+ /** OUI type */
+ t_u8 oui_type;
+ /** OUI subtype */
+ t_u8 oui_subtype;
+ /** Version */
+ t_u8 version;
+} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t;
+
+/** Vendor specific IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t {
+ /** Vendor specific IE header */
+ IEEEtypes_VendorHeader_t vend_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+} MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t;
+
+/** IEEE IE */
+typedef MLAN_PACK_START struct _IEEEtypes_Generic_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** IE Max - size of previous fields */
+ t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+} MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t;
+
+/**ft capability policy*/
+typedef MLAN_PACK_START struct _IEEEtypes_FtCapPolicy_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 6;
+ /** RIC support */
+ t_u8 ric : 1;
+ /** FT over the DS capable */
+ t_u8 ft_over_ds : 1;
+#else
+ /** FT over the DS capable */
+ t_u8 ft_over_ds : 1;
+ /** RIC support */
+ t_u8 ric : 1;
+ /** Reserved */
+ t_u8 reserved : 6;
+#endif
+} MLAN_PACK_END IEEEtypes_FtCapPolicy_t;
+
+/** Mobility domain IE */
+typedef MLAN_PACK_START struct _IEEEtypes_MobilityDomain_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Mobility Domain ID */
+ t_u16 mdid;
+ /** FT Capability policy */
+ t_u8 ft_cap;
+} MLAN_PACK_END IEEEtypes_MobilityDomain_t;
+
+/**FT MIC Control*/
+typedef MLAN_PACK_START struct _IEEEtypes_FT_MICControl_t {
+ /** reserved */
+ t_u8 reserved;
+ /** element count */
+ t_u8 element_count;
+} MLAN_PACK_END IEEEtypes_FT_MICControl_t;
+
+/** FTIE MIC LEN */
+#define FTIE_MIC_LEN 16
+
+/**FT IE*/
+typedef MLAN_PACK_START struct _IEEEtypes_FastBssTransElement_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** mic control */
+ IEEEtypes_FT_MICControl_t mic_control;
+ /** mic */
+ t_u8 mic[FTIE_MIC_LEN];
+ /** ANonce */
+ t_u8 a_nonce[32];
+ /** SNonce */
+ t_u8 s_nonce[32];
+ /** sub element */
+ t_u8 sub_element[1];
+} MLAN_PACK_END IEEEtypes_FastBssTransElement_t;
+
+/*Category for FT*/
+#define FT_CATEGORY 6
+/** FT ACTION request */
+#define FT_ACTION_REQUEST 1
+/** FT ACTION response */
+#define FT_ACTION_RESPONSE 2
+
+/*FT response and FT ack*/
+typedef MLAN_PACK_START struct {
+ /** category */
+ t_u8 category;
+ /** action */
+ t_u8 action;
+ /** sta address */
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** target ap address */
+ t_u8 target_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /** status code */
+ t_u16 status_code;
+ /** varible */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Ft_action_response;
+
+/**FT request */
+typedef MLAN_PACK_START struct {
+ /** category */
+ t_u8 category;
+ /** action */
+ t_u8 action;
+ /** sta address */
+ t_u8 sta_addr[MLAN_MAC_ADDR_LENGTH];
+ /** target ap address */
+ t_u8 target_ap_addr[MLAN_MAC_ADDR_LENGTH];
+ /** varible */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Ft_action_request;
+
+/** auth frame body*/
+typedef MLAN_PACK_START struct {
+ /** auth alg */
+ t_u16 auth_alg;
+ /** auth transaction */
+ t_u16 auth_transaction;
+ /** status code */
+ t_u16 status_code;
+ /** variable */
+ t_u8 variable[];
+} MLAN_PACK_END IEEEtypes_Auth_framebody;
+
+/** associate request frame */
+typedef MLAN_PACK_START struct {
+ t_u16 capab_info;
+ t_u16 listen_interval;
+ /** followed by SSID and Supported rates */
+ t_u8 variablep[];
+} MLAN_PACK_END IEEEtypes_assoc_req;
+
+/*Mgmt frame*/
+typedef MLAN_PACK_START struct {
+ /** frame control */
+ t_u16 frame_control;
+ /** duration */
+ t_u16 duration;
+ /** dest address */
+ t_u8 da[MLAN_MAC_ADDR_LENGTH];
+ /** source address */
+ t_u8 sa[MLAN_MAC_ADDR_LENGTH];
+ /** bssid */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** seq control */
+ t_u16 seq_ctrl;
+ /** address 4 */
+ t_u8 addr4[MLAN_MAC_ADDR_LENGTH];
+ union {
+ IEEEtypes_Auth_framebody auth;
+ IEEEtypes_assoc_req assoc_req;
+ IEEEtypes_Ft_action_response ft_resp;
+ IEEEtypes_Ft_action_request ft_req;
+ } u;
+} MLAN_PACK_END IEEE80211_MGMT;
+
+/** TLV header */
+typedef MLAN_PACK_START struct _TLV_Generic_t {
+ /** Type */
+ t_u16 type;
+ /** Length */
+ t_u16 len;
+} MLAN_PACK_END TLV_Generic_t, *pTLV_Generic_t;
+
+/** Capability information mask */
+#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | MBIT(11) | MBIT(9)))
+
+/** Capability Bit Map*/
+#ifdef BIG_ENDIAN_SUPPORT
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t {
+ t_u8 rsrvd1 : 2;
+ t_u8 dsss_ofdm : 1;
+ t_u8 radio_measurement : 1;
+ t_u8 rsvrd2 : 1;
+ t_u8 short_slot_time : 1;
+ t_u8 rsrvd3 : 1;
+ t_u8 spectrum_mgmt : 1;
+ t_u8 chan_agility : 1;
+ t_u8 pbcc : 1;
+ t_u8 short_preamble : 1;
+ t_u8 privacy : 1;
+ t_u8 cf_poll_rqst : 1;
+ t_u8 cf_pollable : 1;
+ t_u8 ibss : 1;
+ t_u8 ess : 1;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#else
+typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t {
+ /** Capability Bit Map : ESS */
+ t_u8 ess : 1;
+ /** Capability Bit Map : IBSS */
+ t_u8 ibss : 1;
+ /** Capability Bit Map : CF pollable */
+ t_u8 cf_pollable : 1;
+ /** Capability Bit Map : CF poll request */
+ t_u8 cf_poll_rqst : 1;
+ /** Capability Bit Map : privacy */
+ t_u8 privacy : 1;
+ /** Capability Bit Map : Short preamble */
+ t_u8 short_preamble : 1;
+ /** Capability Bit Map : PBCC */
+ t_u8 pbcc : 1;
+ /** Capability Bit Map : Channel agility */
+ t_u8 chan_agility : 1;
+ /** Capability Bit Map : Spectrum management */
+ t_u8 spectrum_mgmt : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd3 : 1;
+ /** Capability Bit Map : Short slot time */
+ t_u8 short_slot_time : 1;
+ /** Capability Bit Map : APSD */
+ t_u8 Apsd : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsvrd2 : 1;
+ /** Capability Bit Map : DSS OFDM */
+ t_u8 dsss_ofdm : 1;
+ /** Capability Bit Map : Reserved */
+ t_u8 rsrvd1 : 2;
+} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+/** IEEEtypes_Ssid_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Ssid_t {
+ /** SSID: Element ID */
+ t_u8 element_id;
+ /** SSID : Length */
+ t_u8 len;
+ /** ssid */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} MLAN_PACK_END IEEEtypes_Ssid_t, *pIEEEtypes_Ssid_t;
+
+/** IEEEtypes_CfParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t {
+ /** CF peremeter : Element ID */
+ t_u8 element_id;
+ /** CF peremeter : Length */
+ t_u8 len;
+ /** CF peremeter : Count */
+ t_u8 cfp_cnt;
+ /** CF peremeter : Period */
+ t_u8 cfp_period;
+ /** CF peremeter : Maximum duration */
+ t_u16 cfp_max_duration;
+ /** CF peremeter : Remaining duration */
+ t_u16 cfp_duration_remaining;
+} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t;
+
+/** IEEEtypes_IbssParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ATIM window value in milliseconds */
+ t_u16 atim_window;
+} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t {
+ /** SS parameter : CF parameter set */
+ IEEEtypes_CfParamSet_t cf_param_set;
+ /** SS parameter : IBSS parameter set */
+ IEEEtypes_IbssParamSet_t ibss_param_set;
+} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t {
+ /** FH parameter : Element ID */
+ t_u8 element_id;
+ /** FH parameter : Length */
+ t_u8 len;
+ /** FH parameter : Dwell time in milliseconds */
+ t_u16 dwell_time;
+ /** FH parameter : Hop set */
+ t_u8 hop_set;
+ /** FH parameter : Hop pattern */
+ t_u8 hop_pattern;
+ /** FH parameter : Hop index */
+ t_u8 hop_index;
+} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t {
+ /** DS parameter : Element ID */
+ t_u8 element_id;
+ /** DS parameter : Length */
+ t_u8 len;
+ /** DS parameter : Current channel */
+ t_u8 current_chan;
+} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t {
+ /** FH parameter set */
+ IEEEtypes_FhParamSet_t fh_param_set;
+ /** DS parameter set */
+ IEEEtypes_DsParamSet_t ds_param_set;
+} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t;
+
+/** IEEEtypes_ERPInfo_t */
+typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** ERP flags */
+ t_u8 erp_flags;
+} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t;
+
+/** IEEEtypes_AId_t */
+typedef t_u16 IEEEtypes_AId_t;
+
+/** IEEEtypes_StatusCode_t */
+typedef t_u16 IEEEtypes_StatusCode_t;
+
+/** Fixed size in assoc_resp */
+#define ASSOC_RESP_FIXED_SIZE 6
+
+/** IEEEtypes_SeqCtl_t */
+typedef MLAN_PACK_START struct _IEEEtypes_SeqCtl_t {
+ /** Fragment Number */
+ t_u16 FragNum : 4;
+ /** Sequence Number */
+ t_u16 SeqNum : 12;
+} MLAN_PACK_END IEEEtypes_SeqCtl_t;
+
+/** IEEEtypes_MgmtHdr_t */
+typedef MLAN_PACK_START struct _IEEEtypes_MgmtHdr_t {
+ /** FrmCtl*/
+ t_u16 FrmCtl;
+ /** Duration*/
+ t_u16 Duration;
+ /** Destination Addr*/
+ t_u8 DestAddr[6];
+ /** Source Addr*/
+ t_u8 SrcAddr[6];
+ /** BSSID */
+ t_u8 BssId[6];
+ /** IEEEtypes_SeqCtl_t */
+ IEEEtypes_SeqCtl_t SeqCtl;
+} MLAN_PACK_END IEEEtypes_MgmtHdr_t;
+
+/** IEEEtypes_AssocRsp_t */
+typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t {
+ /** Capability information */
+ IEEEtypes_CapInfo_t capability;
+ /** Association response status code */
+ IEEEtypes_StatusCode_t status_code;
+ /** Association ID */
+ IEEEtypes_AId_t a_id;
+ /** IE data buffer */
+ t_u8 ie_buffer[1];
+} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t;
+
+/** 802.11 supported rates */
+typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+
+/** cipher TKIP */
+#define WPA_CIPHER_TKIP 2
+/** cipher AES */
+#define WPA_CIPHER_AES_CCM 4
+/** AKM: 8021x */
+#define RSN_AKM_8021X 1
+/** AKM: PSK */
+#define RSN_AKM_PSK 2
+/** AKM: PSK SHA256 */
+#define RSN_AKM_PSK_SHA256 6
+
+/** AKM: PSK SHA256 */
+#define RSN_AKM_SAE 8
+/** AKM: PSK SHA256 */
+#define RSN_AKM_OWE 18
+
+#if defined(STA_SUPPORT)
+/** Pairwise Cipher Suite length */
+#define PAIRWISE_CIPHER_SUITE_LEN 4
+/** AKM Suite length */
+#define AKM_SUITE_LEN 4
+/** MFPC bit in RSN capability */
+#define MFPC_BIT 7
+/** MFPR bit in RSN capability */
+#define MFPR_BIT 6
+/** PMF ORing mask */
+#define PMF_MASK 0x00c0
+#endif
+
+/** wpa_suite_t */
+typedef MLAN_PACK_START struct _wpa_suite_t {
+ /** OUI */
+ t_u8 oui[3];
+ /** tyep */
+ t_u8 type;
+} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t;
+
+/** wpa_suite_ucast_t */
+typedef MLAN_PACK_START struct {
+ /* count */
+ t_u16 count;
+ /** wpa_suite list */
+ wpa_suite list[1];
+} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
+
+/** IEEEtypes_Rsn_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t {
+ /** Rsn : Element ID */
+ t_u8 element_id;
+ /** Rsn : Length */
+ t_u8 len;
+ /** Rsn : version */
+ t_u16 version;
+ /** Rsn : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Rsn : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t;
+
+/** IEEEtypes_Wpa_t */
+typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t {
+ /** Wpa : Element ID */
+ t_u8 element_id;
+ /** Wpa : Length */
+ t_u8 len;
+ /** Wpa : oui */
+ t_u8 oui[4];
+ /** version */
+ t_u16 version;
+ /** Wpa : group cipher */
+ wpa_suite_mcast_t group_cipher;
+ /** Wpa : pairwise cipher */
+ wpa_suite_ucast_t pairwise_cipher;
+} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t;
+
+/** Data structure of WMM QoS information */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aifsn */
+ t_u8 aifsn : 4;
+#else
+ /** Aifsn */
+ t_u8 aifsn : 4;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Reserved */
+ t_u8 reserved : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t;
+
+/** Data structure of WMM ECW */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t;
+
+/** Data structure of WMM AC parameters */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t {
+ IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */
+ IEEEtypes_WmmEcw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t;
+
+/** Data structure of WMM Info IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t {
+ /**
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+
+} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t;
+
+/** Data structure of WMM parameter IE */
+typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t {
+ /**
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ IEEEtypes_VendorHeader_t vend_hdr;
+
+ /** QoS information */
+ IEEEtypes_WmmQosInfo_t qos_info;
+ /** Reserved */
+ t_u8 reserved;
+
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES];
+} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t;
+
+/** Enumerator for TSPEC direction */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e {
+
+ TSPEC_DIR_UPLINK = 0,
+ TSPEC_DIR_DOWNLINK = 1,
+ /* 2 is a reserved value */
+ TSPEC_DIR_BIDIRECT = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e;
+
+/** Enumerator for TSPEC PSB */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e {
+
+ TSPEC_PSB_LEGACY = 0,
+ TSPEC_PSB_TRIG = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e;
+
+/** Enumerator for TSPEC Ack Policy */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e {
+
+ TSPEC_ACKPOLICY_NORMAL = 0,
+ TSPEC_ACKPOLICY_NOACK = 1,
+ /* 2 is reserved */
+ TSPEC_ACKPOLICY_BLOCKACK = 3,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e;
+
+/** Enumerator for TSPEC Trafffice type */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e {
+
+ TSPEC_TRAFFIC_APERIODIC = 0,
+ TSPEC_TRAFFIC_PERIODIC = 1,
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e;
+
+/** Data structure of WMM TSPEC information */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 Reserved17_23 : 7; /* ! Reserved */
+ t_u8 Schedule : 1;
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy : 2;
+ t_u8 UserPri : 3; /* ! 802.1d User Priority */
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior : 1; /* !
+ Legacy/Trigg
+ */
+ t_u8 Aggregation : 1; /* ! Reserved */
+ t_u8 AccessPolicy2 : 1; /* ! */
+ t_u8 AccessPolicy1 : 1; /* ! */
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction : 2;
+ t_u8 TID : 4; /* ! Unique identifier */
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType : 1;
+#else
+ IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType : 1;
+ t_u8 TID : 4; /* ! Unique identifier */
+ IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction : 2;
+ t_u8 AccessPolicy1 : 1; /* ! */
+ t_u8 AccessPolicy2 : 1; /* ! */
+ t_u8 Aggregation : 1; /* ! Reserved */
+ IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior : 1; /* !
+ Legacy/Trigg
+ */
+ t_u8 UserPri : 3; /* ! 802.1d User Priority */
+ IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy : 2;
+ t_u8 Schedule : 1;
+ t_u8 Reserved17_23 : 7; /* ! Reserved */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t;
+
+/** Data structure of WMM TSPEC Nominal Size */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Fixed : 1; /* ! 1: Fixed size given in Size, 0: Var, size is
+ nominal */
+ t_u16 Size : 15; /* ! Nominal size in octets */
+#else
+ t_u16 Size : 15; /* ! Nominal size in octets */
+ t_u16 Fixed : 1; /* ! 1: Fixed size given in Size, 0: Var, size is
+ nominal */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t;
+
+/** Data structure of WMM TSPEC SBWA */
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u16 Whole : 3; /* ! Whole portion */
+ t_u16 Fractional : 13; /* ! Fractional portion */
+#else
+ t_u16 Fractional : 13; /* ! Fractional portion */
+ t_u16 Whole : 3; /* ! Whole portion */
+#endif
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA;
+
+/** Data structure of WMM TSPEC Body */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo;
+ IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize;
+ t_u16 MaximumMSDUSize;
+ t_u32 MinServiceInterval;
+ t_u32 MaxServiceInterval;
+ t_u32 InactivityInterval;
+ t_u32 SuspensionInterval;
+ t_u32 ServiceStartTime;
+ t_u32 MinimumDataRate;
+ t_u32 MeanDataRate;
+ t_u32 PeakDataRate;
+ t_u32 MaxBurstSize;
+ t_u32 DelayBound;
+ t_u32 MinPHYRate;
+ IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance;
+ t_u16 MediumTime;
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t;
+
+/** Data structure of WMM TSPEC all elements */
+typedef MLAN_PACK_START struct {
+ t_u8 ElementId;
+ t_u8 Len;
+ t_u8 OuiType[4]; /* 00:50:f2:02 */
+ t_u8 OuiSubType; /* 01 */
+ t_u8 Version;
+
+ IEEEtypes_WMM_TSPEC_Body_t TspecBody;
+
+} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t;
+
+/** WMM Action Category values */
+typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e {
+
+ IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0,
+ IEEE_MGMT_ACTION_CATEGORY_QOS = 1,
+ IEEE_MGMT_ACTION_CATEGORY_DLS = 2,
+ IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3,
+ IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4,
+ IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5,
+ IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6,
+ IEEE_MGMT_ACTION_CATEGORY_HT = 7,
+
+ IEEE_MGMT_ACTION_CATEGORY_WNM = 10,
+ IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11,
+
+ IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17
+
+} MLAN_PACK_END IEEEtypes_ActionCategory_e;
+
+/** WMM TSPEC operations */
+typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e {
+
+ TSPEC_ACTION_CODE_ADDTS_REQ = 0,
+ TSPEC_ACTION_CODE_ADDTS_RSP = 1,
+ TSPEC_ACTION_CODE_DELTS = 2,
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e;
+
+/** WMM TSPEC Category Action Base */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_ActionCategory_e category;
+ IEEEtypes_WMM_Tspec_Action_e action;
+ t_u8 dialogToken;
+
+} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t;
+
+/** WMM TSPEC AddTS request structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t;
+
+/** WMM TSPEC AddTS response structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 statusCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+ /* Place holder for additional elements after the TSPEC */
+ t_u8 subElem[256];
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t;
+
+/** WMM TSPEC DelTS structure */
+typedef MLAN_PACK_START struct {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+ t_u8 reasonCode;
+ IEEEtypes_WMM_TSPEC_t tspecIE;
+
+} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t;
+
+/** union of WMM TSPEC structures */
+typedef MLAN_PACK_START union {
+ IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct;
+
+ IEEEtypes_Action_WMM_AddTsReq_t addTsReq;
+ IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp;
+ IEEEtypes_Action_WMM_DelTs_t delTs;
+
+} MLAN_PACK_END IEEEtypes_Action_WMMAC_t;
+
+/** union of WMM TSPEC & Action category */
+typedef MLAN_PACK_START union {
+ IEEEtypes_ActionCategory_e category;
+
+ IEEEtypes_Action_WMMAC_t wmmAc;
+
+} MLAN_PACK_END IEEEtypes_ActionFrame_t;
+
+/** Data structure for subband set */
+typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t {
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t;
+
+#ifdef STA_SUPPORT
+/** Data structure for Country IE */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[1];
+} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t;
+
+/** Data structure for Country IE full set */
+typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t {
+ /** Element ID */
+ t_u8 element_id;
+ /** Length */
+ t_u8 len;
+ /** Country code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Set of subbands */
+ IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t,
+ *pIEEEtypes_CountryInfoFullSet_t;
+
+#endif /* STA_SUPPORT */
+
+/** HT Capabilities Data */
+typedef struct MLAN_PACK_START _HTCap_t {
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+} MLAN_PACK_END HTCap_t, *pHTCap_t;
+
+/** HT Information Data */
+typedef struct MLAN_PACK_START _HTInfo_t {
+ /** Primary channel */
+ t_u8 pri_chan;
+ /** Field 2 */
+ t_u8 field2;
+ /** Field 3 */
+ t_u16 field3;
+ /** Field 4 */
+ t_u16 field4;
+ /** Bitmap indicating MCSs supported by all HT STAs in the BSS */
+ t_u8 basic_mcs_set[16];
+} MLAN_PACK_END HTInfo_t, *pHTInfo_t;
+
+/** 20/40 BSS Coexistence Data */
+typedef struct MLAN_PACK_START _BSSCo2040_t {
+ /** 20/40 BSS Coexistence value */
+ t_u8 bss_co_2040_value;
+} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t;
+
+#define MAX_DSCP_EXCEPTION_NUM 21
+/** DSCP Range */
+typedef struct MLAN_PACK_START _DSCP_Exception_t {
+ /* DSCP value 0 to 63 or ff */
+ t_u8 dscp_value;
+ /* user priority 0-7*/
+ t_u8 user_priority;
+} MLAN_PACK_END DSCP_Exception_t, *pDSCP_Exception_t;
+
+/** DSCP Range */
+typedef struct MLAN_PACK_START _DSCP_Range_t {
+ /* DSCP low value */
+ t_u8 dscp_low_value;
+ /* DSCP high value */
+ t_u8 dscp_high_value;
+} MLAN_PACK_END DSCP_Range_t, *pDSCP_Range_t;
+
+/** Overlapping BSS Scan Parameters Data */
+typedef struct MLAN_PACK_START _OverlapBSSScanParam_t {
+ /** OBSS Scan Passive Dwell in milliseconds */
+ t_u16 obss_scan_passive_dwell;
+ /** OBSS Scan Active Dwell in milliseconds */
+ t_u16 obss_scan_active_dwell;
+ /** BSS Channel Width Trigger Scan Interval in seconds */
+ t_u16 bss_chan_width_trigger_scan_int;
+ /** OBSS Scan Passive Total Per Channel */
+ t_u16 obss_scan_passive_total;
+ /** OBSS Scan Active Total Per Channel */
+ t_u16 obss_scan_active_total;
+ /** BSS Width Channel Transition Delay Factor */
+ t_u16 bss_width_chan_trans_delay;
+ /** OBSS Scan Activity Threshold */
+ t_u16 obss_scan_active_threshold;
+} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t;
+
+/** HT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTCap struct */
+ HTCap_t ht_cap;
+} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t;
+
+/** HT Information IE */
+typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** HTInfo struct */
+ HTInfo_t ht_info;
+} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t;
+
+/** 20/40 BSS Coexistence IE */
+typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** BSSCo2040_t struct */
+ BSSCo2040_t bss_co_2040;
+} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t;
+
+/** Extended Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** ExtCap_t struct */
+ ExtCap_t ext_cap;
+} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t;
+
+/** Overlapping BSS Scan Parameters IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** OBSSScanParam_t struct */
+ OBSSScanParam_t obss_scan_param;
+} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t,
+ *pIEEEtypes_OverlapBSSScanParam_t;
+
+/** VHT MCS rate set field, refer to 802.11ac */
+typedef MLAN_PACK_START struct _VHT_MCS_set {
+ t_u16 rx_mcs_map;
+ t_u16 rx_max_rate; /* bit 29-31 reserved */
+ t_u16 tx_mcs_map;
+ t_u16 tx_max_rate; /* bit 61-63 reserved */
+} MLAN_PACK_END VHT_MCS_set_t, *pVHT_MCS_set_t;
+
+/** VHT Capabilities info field, reference 802.11ac D1.4 p89 */
+typedef MLAN_PACK_START struct _VHT_capa {
+#if 0
+#ifdef BIG_ENDIAN_SUPPORT
+ t_u8 mpdu_max_len:2;
+ t_u8 chan_width:2;
+ t_u8 rx_LDPC:1;
+ t_u8 sgi_80:1;
+ t_u8 sgi_160:1;
+ t_u8 tx_STBC:1;
+ t_u8 rx_STBC:3;
+ t_u8 SU_beamformer_capa:1;
+ t_u8 SU_beamformee_capa:1;
+ t_u8 beamformer_ante_num:3;
+ t_u8 sounding_dim_num:3;
+ t_u8 MU_beamformer_capa:1;
+ t_u8 MU_beamformee_capa:1;
+ t_u8 VHT_TXOP_ps:1;
+ t_u8 HTC_VHT_capa:1;
+ t_u8 max_ampdu_len:3;
+ t_u8 link_apapt_capa:2;
+ t_u8 reserved_1:4;
+#else
+ t_u8 reserved_1:4;
+ t_u8 link_apapt_capa:2;
+ t_u8 max_ampdu_len:3;
+ t_u8 HTC_VHT_capa:1;
+ t_u8 VHT_TXOP_ps:1;
+ t_u8 MU_beamformee_capa:1;
+ t_u8 MU_beamformer_capa:1;
+ t_u8 sounding_dim_num:3;
+ t_u8 beamformer_ante_num:3;
+ t_u8 SU_beamformee_capa:1;
+ t_u8 SU_beamformer_capa:1;
+ t_u8 rx_STBC:3;
+ t_u8 tx_STBC:1;
+ t_u8 sgi_160:1;
+ t_u8 sgi_80:1;
+ t_u8 rx_LDPC:1;
+ t_u8 chan_width:2;
+ t_u8 mpdu_max_len:2;
+#endif /* BIG_ENDIAN_SUPPORT */
+#endif
+ t_u32 vht_cap_info;
+ VHT_MCS_set_t mcs_sets;
+} MLAN_PACK_END VHT_capa_t, *pVHT_capa_t;
+
+/** VHT Capabilities IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTCap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ VHT_capa_t vht_cap;
+} MLAN_PACK_END IEEEtypes_VHTCap_t, *pIEEEtypes_VHTCap_t;
+
+#define VHT_CAP_CHWD_80MHZ 0
+#define VHT_CAP_CHWD_160MHZ 1
+#define VHT_CAP_CHWD_80_80MHZ 2
+
+/** VHT Operations IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTOprat_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 chan_width;
+ t_u8 chan_center_freq_1;
+ t_u8 chan_center_freq_2;
+ /** Basic MCS set map, each 2 bits stands for a Nss */
+ t_u16 basic_MCS_map;
+} MLAN_PACK_END IEEEtypes_VHTOprat_t, *pIEEEtypes_VHTOprat_t;
+
+#define VHT_OPER_CHWD_20_40MHZ 0
+#define VHT_OPER_CHWD_80MHZ 1
+#define VHT_OPER_CHWD_160MHZ 2
+#define VHT_OPER_CHWD_80_80MHZ 3
+
+/** VHT Transmit Power Envelope IE */
+typedef MLAN_PACK_START struct _IEEEtypes_VHTtxpower_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 max_tx_power;
+ t_u8 chan_center_freq;
+ t_u8 chan_width;
+} MLAN_PACK_END IEEEtypes_VHTtxpower_t, *pIEEEtypes_VHTtxpower_t;
+
+/** Extended Power Constraint IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtPwerCons_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** channel width */
+ t_u8 chan_width;
+ /** local power constraint */
+ t_u8 local_power_cons;
+} MLAN_PACK_END IEEEtypes_ExtPwerCons_t, *pIEEEtypes_ExtPwerCons_t;
+
+/** Extended BSS Load IE */
+typedef MLAN_PACK_START struct _IEEEtypes_ExtBSSload_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 MU_MIMO_capa_count;
+ t_u8 stream_underutilization;
+ t_u8 VHT40_util;
+ t_u8 VHT80_util;
+ t_u8 VHT160_util;
+} MLAN_PACK_END IEEEtypes_ExtBSSload_t, *pIEEEtypes_ExtBSSload_t;
+
+/** Quiet Channel IE */
+typedef MLAN_PACK_START struct _IEEEtypes_QuietChan_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 AP_quiet_mode;
+ t_u8 quiet_count;
+ t_u8 quiet_period;
+ t_u16 quiet_dur;
+ t_u16 quiet_offset;
+} MLAN_PACK_END IEEEtypes_QuietChan_t, *pIEEEtypes_QuietChan_t;
+
+/** Wide Bandwidth Channel Switch IE */
+typedef MLAN_PACK_START struct _IEEEtypes_BWSwitch_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 new_chan_width;
+ t_u8 new_chan_center_freq_1;
+ t_u8 new_chan_center_freq_2;
+} MLAN_PACK_END IEEEtypes_BWSwitch_t, *pIEEEtypes_BWSwitch_t;
+
+/** AID IE */
+typedef MLAN_PACK_START struct _IEEEtypes_AID_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** AID number */
+ t_u16 AID;
+} MLAN_PACK_END IEEEtypes_AID_t, *pIEEEtypes_AID_t;
+
+/** Operating Mode Notificaton IE */
+typedef MLAN_PACK_START struct _IEEEtypes_OperModeNtf_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Operating Mode */
+ t_u8 oper_mode;
+} MLAN_PACK_END IEEEtypes_OperModeNtf_t, *pIEEEtypes_OperModeNtf_t;
+
+typedef MLAN_PACK_START struct _IEEEtypes_Extension_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** payload */
+ t_u8 data[];
+} MLAN_PACK_END IEEEtypes_Extension_t, *pIEEEtypes_Extension_t;
+
+typedef MLAN_PACK_START struct _IEEEtypes_HECap_t {
+ /** Generic IE header */
+ IEEEtypes_Header_t ieee_hdr;
+ /** Element id extension */
+ t_u8 ext_id;
+ /** he mac capability info */
+ t_u8 he_mac_cap[6];
+ /** he phy capability info */
+ t_u8 he_phy_cap[11];
+ /** he txrx mcs support , size would be 4 or 8 or 12 */
+ t_u8 he_txrx_mcs_support[4];
+ /** PPE Thresholds (optional) */
+} MLAN_PACK_END IEEEtypes_HECap_t, *pIEEEtypes_HECap_t;
+
+/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */
+#define WLAN_11H_MAX_SUBBANDS 5
+
+/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/** IEEE Power Constraint element (7.3.2.15) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 32 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 local_constraint; /**< Local power constraint applied to 11d
+ chan info */
+} MLAN_PACK_END IEEEtypes_PowerConstraint_t;
+
+/** IEEE Power Capability element (7.3.2.16) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 33 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */
+ t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */
+} MLAN_PACK_END IEEEtypes_PowerCapability_t;
+
+/** IEEE TPC Report element (7.3.2.18) */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 35 */
+ t_u8 len; /**< Element length after id and len */
+ t_s8 tx_power; /**< Max power used to transmit the TPC Report frame
+ (dBm) */
+ t_s8 link_margin; /**< Link margin when TPC Request received (dB) */
+} MLAN_PACK_END IEEEtypes_TPCReport_t;
+
+/* IEEE Supported Channel sub-band description (7.3.2.19) */
+/**
+ * Sub-band description used in the supported channels element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 start_chan; /**< Starting channel in the subband */
+ t_u8 num_chans; /**< Number of channels in the subband */
+
+} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t;
+
+/* IEEE Supported Channel element (7.3.2.19) */
+/**
+ * Sent in association requests. Details the sub-bands and number
+ * of channels supported in each subband
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 36 */
+ t_u8 len; /**< Element length after id and len */
+
+ /** Configured sub-bands information in the element */
+ IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} MLAN_PACK_END IEEEtypes_SupportedChannels_t;
+
+/** default channel switch count */
+#define DEF_CHAN_SWITCH_COUNT 5
+
+/* IEEE Channel Switch Announcement Element (7.3.2.20) */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a chan switch element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 37 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */
+ t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */
+ t_u8 chan_switch_count; /**< # of TBTTs before channel switch */
+
+} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t;
+
+/** data structure for extended channel switch */
+typedef MLAN_PACK_START struct {
+ /** IEEE element ID = 60 */
+ t_u8 element_id;
+ /** Element length after id and len, set to 4 */
+ t_u8 len;
+ /** STA should not transmit any frames if 1 */
+ t_u8 chan_switch_mode;
+ /** Operate class # that AP/IBSS is moving to */
+ t_u8 new_oper_class;
+ /** Channel # that AP/IBSS is moving to */
+ t_u8 new_channel_num;
+ /** of TBTTs before channel switch */
+ t_u8 chan_switch_count;
+} MLAN_PACK_END IEEEtypes_ExtChanSwitchAnn_t;
+
+/* IEEE Wide Bandwidth Channel Switch Element */
+/**
+ * Provided in beacons and probe responses. Used to advertise when
+ * and to which channel it is changing to. Only starting STAs in
+ * an IBSS and APs are allowed to originate a wide bandwidth chan
+ * switch element.
+ */
+typedef MLAN_PACK_START struct {
+ /** Generic IE header IEEE Element ID = 194*/
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 new_channel_width;
+ t_u8 new_channel_center_freq0;
+ t_u8 new_channel_center_freq1;
+} MLAN_PACK_END IEEEtypes_WideBWChanSwitch_t;
+
+/* IEEE VHT Transmit Power Envelope Element */
+/**
+ * Provided in beacons and probe responses. Used to advertise the max
+ * TX power in sepeate bandwidth and as a sub element of Channel Switch
+ * Wrapper IE.
+ */
+typedef MLAN_PACK_START struct {
+ /** Generic IE header IEEE Element ID = 195*/
+ IEEEtypes_Header_t ieee_hdr;
+ t_u8 tpc_info; /**< Transmit Power Information>*/
+ t_u8 local_max_tp_20mhz; /**< Local Maximum Transmit Power for 20 MHZ>*/
+ t_u8 local_max_tp_40mhz; /**< Local Maximum Transmit Power for 40 MHZ>*/
+ t_u8 local_max_tp_80mhz; /**< Local Maximum Transmit Power for 80 MHZ>*/
+} MLAN_PACK_END IEEEtypes_VhtTpcEnvelope_t;
+
+/* IEEE Quiet Period Element (7.3.2.23) */
+/**
+ * Provided in beacons and probe responses. Indicates times during
+ * which the STA should not be transmitting data. Only starting STAs in
+ * an IBSS and APs are allowed to originate a quiet element.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 40 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet
+ period */
+ t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods
+ */
+ t_u16 quiet_duration; /**< Duration of the quiet period in TUs */
+ t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet
+ period */
+
+} MLAN_PACK_END IEEEtypes_Quiet_t;
+
+/**
+*** @brief Map octet of the basic measurement report (7.3.2.22.1)
+**/
+typedef MLAN_PACK_START struct {
+#ifdef BIG_ENDIAN_SUPPORT
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+ /**< Channel is unmeasured */
+ t_u8 unmeasured : 1;
+ /**< Radar detected on channel */
+ t_u8 radar : 1;
+ /**< Unidentified signal found on channel */
+ t_u8 unidentified_sig : 1;
+ /**< OFDM preamble detected on channel */
+ t_u8 ofdm_preamble : 1;
+ /**< At least one valid MPDU received on channel */
+ t_u8 bss : 1;
+#else
+ /**< At least one valid MPDU received on channel */
+ t_u8 bss : 1;
+ /**< OFDM preamble detected on channel */
+ t_u8 ofdm_preamble : 1;
+ /**< Unidentified signal found on channel */
+ t_u8 unidentified_sig : 1;
+ /**< Radar detected on channel */
+ t_u8 radar : 1;
+ /**< Channel is unmeasured */
+ t_u8 unmeasured : 1;
+ /**< Reserved */
+ t_u8 rsvd5_7 : 3;
+#endif /* BIG_ENDIAN_SUPPORT */
+
+} MLAN_PACK_END MeasRptBasicMap_t;
+
+/* IEEE DFS Channel Map field (7.3.2.24) */
+/**
+ * Used to list supported channels and provide a octet "map" field which
+ * contains a basic measurement report for that channel in the
+ * IEEEtypes_IBSS_DFS_t element
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 channel_number; /**< Channel number */
+ MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel
+ */
+
+} MLAN_PACK_END IEEEtypes_ChannelMap_t;
+
+/* IEEE IBSS DFS Element (7.3.2.24) */
+/**
+ * IBSS DFS element included in ad hoc beacons and probe responses.
+ * Provides information regarding the IBSS DFS Owner as well as the
+ * originating STAs supported channels and basic measurement results.
+ */
+typedef MLAN_PACK_START struct {
+ t_u8 element_id; /**< IEEE Element ID = 41 */
+ t_u8 len; /**< Element length after id and len */
+ t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */
+ t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */
+
+ /** Variable length map field, one Map entry for each supported channel
+ */
+ IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} MLAN_PACK_END IEEEtypes_IBSS_DFS_t;
+
+/* 802.11h BSS information kept for each BSSID received in scan results */
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ * join commands
+ */
+typedef struct {
+ t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */
+
+ IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE
+ */
+ IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE
+ */
+ IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */
+ IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch
+ Announcement IE */
+ IEEEtypes_Quiet_t quiet; /**< Quiet IE */
+ IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */
+
+} wlan_11h_bss_info_t;
+
+/** action code for 20/40 BSS Coexsitence Management frame */
+#define BSS_20_40_COEX 0
+
+#ifdef STA_SUPPORT
+/** Macro for maximum size of scan response buffer */
+#define MAX_SCAN_RSP_BUF (16 * 1024)
+
+/** Maximum number of channels that can be sent in user scan config */
+#define WLAN_USER_SCAN_CHAN_MAX 50
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH 10
+
+/** Maximum length of BSSID list */
+#define MAX_BSSID_FILTER_LIST 5
+
+/** Scan all the channels in specified band */
+#define BAND_SPECIFIED 0x80
+
+/**
+ * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Used to specify SSID specific filters as well as SSID pattern matching
+ * filters for scan result processing in firmware.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_ssid {
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+} MLAN_PACK_END wlan_user_scan_ssid;
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+typedef MLAN_PACK_START struct _wlan_user_scan_chan {
+ /** Channel Number to scan */
+ t_u8 chan_number;
+ /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */
+ t_u8 radio_type;
+ /** Scan type: Active = 1, Passive = 2 */
+ t_u8 scan_type;
+ /** Reserved */
+ t_u8 reserved;
+ /** Scan duration in milliseconds; if 0 default used */
+ t_u32 scan_time;
+} MLAN_PACK_END wlan_user_scan_chan;
+
+/** channel statictics */
+typedef MLAN_PACK_START struct _ChanStatistics_t {
+ /** channle number */
+ t_u8 chan_num;
+ /** band info */
+ Band_Config_t bandcfg;
+ /** flags */
+ t_u8 flags;
+ /** noise */
+ t_s8 noise;
+ /** total network */
+ t_u16 total_networks;
+ /** scan duration */
+ t_u16 cca_scan_duration;
+ /** busy duration */
+ t_u16 cca_busy_duration;
+ /** min rss */
+ t_u8 min_rss;
+ /** max rssi */
+ t_u8 max_rss;
+} MLAN_PACK_END ChanStatistics_t;
+
+/** Enhance ext scan type defination */
+typedef enum _MLAN_EXT_SCAN_TYPE {
+ EXT_SCAN_DEFAULT,
+ EXT_SCAN_ENHANCE,
+ EXT_SCAN_CANCEL,
+} MLAN_EXT_SCAN_TYPE;
+
+/**
+ * Input structure to configure an immediate scan cmd to firmware
+ *
+ * Specifies a number of parameters to be used in general for the scan
+ * as well as a channel list (wlan_user_scan_chan) for each scan period
+ * desired.
+ */
+typedef MLAN_PACK_START struct {
+ /**
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ t_u8 keep_previous_scan;
+ /**
+ * BSS mode to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. Valid settings are:
+ *
+ * - MLAN_SCAN_MODE_BSS (infrastructure)
+ * - MLAN_SCAN_MODE_IBSS (adhoc)
+ * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_mode;
+ /**
+ * Configure the number of probe requests for active chan scans
+ */
+ t_u8 num_probes;
+ /**
+ * @brief ssid filter flag
+ */
+ t_u8 ssid_filter;
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the
+ * results
+ */
+ t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH];
+ /**
+ * SSID filter list used in the to limit the scan results
+ */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /**
+ * Variable number (fixed maximum) of channels to scan up
+ */
+ wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX];
+ /** scan channel gap */
+ t_u16 scan_chan_gap;
+ /** scan type: 0 legacy, 1: enhance scan*/
+ t_u8 ext_scan_type;
+ /** flag to filer only probe response */
+ t_u8 proberesp_only;
+ t_u8 random_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Number of BSSIDs to be filtered */
+ t_u8 bssid_num;
+ /** BSSID filter list used in the to limit the scan results */
+ mlan_802_11_mac_addr bssid_list[MAX_BSSID_FILTER_LIST];
+} MLAN_PACK_END wlan_user_scan_cfg;
+
+/** Default scan interval in millisecond*/
+#define DEFAULT_BGSCAN_INTERVAL 30000
+
+/** action get all, except pps/uapsd config */
+#define BG_SCAN_ACT_GET 0x0000
+/** action set all, except pps/uapsd config */
+#define BG_SCAN_ACT_SET 0x0001
+/** action get pps/uapsd config */
+#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100
+/** action set pps/uapsd config */
+#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101
+/** action set all */
+#define BG_SCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define BG_SCAN_SSID_MATCH 0x0001
+/** ssid match and RSSI exceeded */
+#define BG_SCAN_SSID_RSSI_MATCH 0x0004
+/**wait for all channel scan to complete to report scan result*/
+#define BG_SCAN_WAIT_ALL_CHAN_DONE 0x80000000
+/** Maximum number of channels that can be sent in bg scan config */
+#define WLAN_BG_SCAN_CHAN_MAX 38
+
+/** Enumeration definition */
+/** EES MODE */
+typedef enum {
+ /** EES MODE: LOW */
+ EES_MODE_LOW = 0,
+ /** EES MODE: MID */
+ EES_MODE_MID,
+ /** EES MODE: HIGH */
+ EES_MODE_HIGH,
+ /** EES MODE: OFF */
+ EES_MODE_OFF,
+ /** EES MODE: LOOP */
+ EES_MODE_LOOP = 15,
+} ees_modes;
+
+/** EES Maximum SSID */
+#define EES_MAX_SSIDS 2
+
+/** ees_ssid_config */
+typedef MLAN_PACK_START struct {
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1];
+ /** Maximum length of SSID */
+ t_u8 max_len;
+ /** PairCipher */
+ t_u8 pair_cipher;
+ /** GroupCipher */
+ t_u8 group_cipher;
+} MLAN_PACK_END ees_ssid_config;
+
+/**
+ * Input structure to configure bs scan cmd to firmware
+ */
+typedef MLAN_PACK_START struct {
+ /** action */
+ t_u16 action;
+ /** enable/disable */
+ t_u8 enable;
+ /** BSS type:
+ * MLAN_SCAN_MODE_BSS (infrastructure)
+ * MLAN_SCAN_MODE_IBSS (adhoc)
+ * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ t_u8 bss_type;
+ /** number of channel scanned during each scan */
+ t_u8 chan_per_scan;
+ /** interval between consecutive scan */
+ t_u32 scan_interval;
+ /** bit 0: ssid match bit 1: ssid match and SNR exceeded
+ * bit 2: ssid match and RSSI exceeded
+ * bit 31: wait for all channel scan to complete to report scan result
+ */
+ t_u32 report_condition;
+ /* Configure the number of probe requests for active chan scans */
+ t_u8 num_probes;
+ /** RSSI threshold */
+ t_u8 rssi_threshold;
+ /** SNR threshold */
+ t_u8 snr_threshold;
+ /** repeat count */
+ t_u16 repeat_count;
+ /** start later flag */
+ t_u16 start_later;
+ /** SSID filter list used in the to limit the scan results */
+ wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH];
+ /** Variable number (fixed maximum) of channels to scan up */
+ wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX];
+ /** scan channel gap */
+ t_u16 scan_chan_gap;
+ /** Enable EES configuration */
+ t_u8 config_ees;
+ /** EES scan mode */
+ t_u16 ees_mode;
+ /** EES report condition */
+ t_u16 report_cond;
+ /** EES High Period scan interval */
+ t_u16 high_period;
+ /** EES High Period scan count */
+ t_u16 high_period_count;
+ /** EES Medium Period scan interval */
+ t_u16 mid_period;
+ /** EES Medium Period scan count */
+ t_u16 mid_period_count;
+ /** EES Low Period scan interval */
+ t_u16 low_period;
+ /** EES Low Period scan count */
+ t_u16 low_period_count;
+ /** Number of networks in the list */
+ t_u8 network_count;
+ /** Maximum number of connection count */
+ t_u8 max_conn_count;
+ /** Black List Exp */
+ t_u8 black_list_exp;
+ /** Array of ees config struct */
+ ees_ssid_config ees_ssid_cfg[EES_MAX_SSIDS];
+ t_u8 random_mac[MLAN_MAC_ADDR_LENGTH];
+} MLAN_PACK_END wlan_bgscan_cfg;
+#endif /* STA_SUPPORT */
+
+#ifdef PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/** BSSDescriptor_t
+ * Structure used to store information for beacon/probe response
+ */
+typedef struct _BSSDescriptor_t {
+ /** MAC address */
+ mlan_802_11_mac_addr mac_address;
+
+ /** SSID */
+ mlan_802_11_ssid ssid;
+
+ /** WEP encryption requirement */
+ t_u32 privacy;
+
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+ /** channel load */
+ t_u8 chan_load;
+ /** Channel */
+ t_u32 channel;
+
+ /** Freq */
+ t_u32 freq;
+
+ /** Beacon period */
+ t_u16 beacon_period;
+
+ /** ATIM window */
+ t_u32 atim_window;
+
+ /** ERP flags */
+ t_u8 erp_flags;
+
+ /** Type of network in use */
+ WLAN_802_11_NETWORK_TYPE network_type_use;
+
+ /** Network infrastructure mode */
+ t_u32 bss_mode;
+
+ /** Network supported rates */
+ WLAN_802_11_RATES supported_rates;
+
+ /** Supported data rates */
+ t_u8 data_rates[WLAN_SUPPORTED_RATES];
+
+ /** Current channel bandwidth
+ * 0 : 20MHZ
+ * 1 : 40MHZ
+ * 2 : 80MHZ
+ * 3 : 160MHZ
+ */
+ t_u8 curr_bandwidth;
+
+ /** Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ t_u16 bss_band;
+
+ /** TSF timestamp from the current firmware TSF */
+ t_u64 network_tsf;
+
+ /** TSF value included in the beacon/probe response */
+ t_u8 time_stamp[8];
+
+ /** PHY parameter set */
+ IEEEtypes_PhyParamSet_t phy_param_set;
+
+ /** SS parameter set */
+ IEEEtypes_SsParamSet_t ss_param_set;
+
+ /** Capability information */
+ IEEEtypes_CapInfo_t cap_info;
+
+ /** WMM IE */
+ IEEEtypes_WmmParameter_t wmm_ie;
+
+ /** 802.11h BSS information */
+ wlan_11h_bss_info_t wlan_11h_bss_info;
+
+ /** Indicate disabling 11n when associate with AP */
+ t_u8 disable_11n;
+ /** 802.11n BSS information */
+ /** HT Capabilities IE */
+ IEEEtypes_HTCap_t *pht_cap;
+ /** HT Capabilities Offset */
+ t_u16 ht_cap_offset;
+ /** HT Information IE */
+ IEEEtypes_HTInfo_t *pht_info;
+ /** HT Information Offset */
+ t_u16 ht_info_offset;
+ /** 20/40 BSS Coexistence IE */
+ IEEEtypes_2040BSSCo_t *pbss_co_2040;
+ /** 20/40 BSS Coexistence Offset */
+ t_u16 bss_co_2040_offset;
+ /** Extended Capabilities IE */
+ IEEEtypes_ExtCap_t *pext_cap;
+ /** Extended Capabilities Offset */
+ t_u16 ext_cap_offset;
+ /** Overlapping BSS Scan Parameters IE */
+ IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param;
+ /** Overlapping BSS Scan Parameters Offset */
+ t_u16 overlap_bss_offset;
+
+ /** VHT Capabilities IE */
+ IEEEtypes_VHTCap_t *pvht_cap;
+ /** VHT Capabilities IE offset */
+ t_u16 vht_cap_offset;
+ /** VHT Operations IE */
+ IEEEtypes_VHTOprat_t *pvht_oprat;
+ /** VHT Operations IE offset */
+ t_u16 vht_oprat_offset;
+ /** VHT Transmit Power Envelope IE */
+ IEEEtypes_VHTtxpower_t *pvht_txpower;
+ /** VHT Transmit Power Envelope IE offset */
+ t_u16 vht_txpower_offset;
+ /** Extended Power Constraint IE */
+ IEEEtypes_ExtPwerCons_t *pext_pwer;
+ /** Extended Power Constraint IE offset */
+ t_u16 ext_pwer_offset;
+ /** Extended BSS Load IE */
+ IEEEtypes_ExtBSSload_t *pext_bssload;
+ /** Extended BSS Load IE offset */
+ t_u16 ext_bssload_offset;
+ /** Quiet Channel IE */
+ IEEEtypes_QuietChan_t *pquiet_chan;
+ /** Quiet Channel IE offset */
+ t_u16 quiet_chan_offset;
+ /** Operating Mode Notification IE */
+ IEEEtypes_OperModeNtf_t *poper_mode;
+ /** Operating Mode Notification IE offset */
+ t_u16 oper_mode_offset;
+ /** HE Capability IE */
+ IEEEtypes_HECap_t *phe_cap;
+ /** HE Capability IE offset */
+ t_u16 he_cap_offset;
+ /** HE operation IE */
+ IEEEtypes_Extension_t *phe_oprat;
+ /** HE operation IE offset */
+ t_u16 he_oprat_offset;
+#ifdef STA_SUPPORT
+ /** Country information set */
+ IEEEtypes_CountryInfoFullSet_t country_info;
+#endif /* STA_SUPPORT */
+
+ /** WPA IE */
+ IEEEtypes_VendorSpecific_t *pwpa_ie;
+ /** WPA IE offset in the beacon buffer */
+ t_u16 wpa_offset;
+ /** RSN IE */
+ IEEEtypes_Generic_t *prsn_ie;
+ /** RSN IE offset in the beacon buffer */
+ t_u16 rsn_offset;
+#ifdef STA_SUPPORT
+ /** WAPI IE */
+ IEEEtypes_Generic_t *pwapi_ie;
+ /** WAPI IE offset in the beacon buffer */
+ t_u16 wapi_offset;
+#endif
+ /* Hotspot 2.0 OSEN AKM IE*/
+ IEEEtypes_Generic_t *posen_ie;
+ /** osen IE offset in the beacon buffer */
+ t_u16 osen_offset;
+ /* Mobility domain IE */
+ IEEEtypes_MobilityDomain_t *pmd_ie;
+ /** Mobility domain IE offset in the beacon buffer */
+ t_u16 md_offset;
+
+ /** Pointer to the returned scan response */
+ t_u8 *pbeacon_buf;
+ /** Length of the stored scan response */
+ t_u32 beacon_buf_size;
+ /** Max allocated size for updated scan response */
+ t_u32 beacon_buf_size_max;
+
+} BSSDescriptor_t, *pBSSDescriptor_t;
+
+#endif /* !_MLAN_IEEE_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ioctl.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ioctl.h
new file mode 100644
index 000000000000..2315b2a2b79e
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/mlan_ioctl.h
@@ -0,0 +1,5159 @@
+/** @file mlan_ioctl.h
+ *
+ * @brief This file declares the IOCTL data structures and APIs.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/******************************************************
+Change log:
+ 11/07/2008: initial version
+******************************************************/
+
+#ifndef _MLAN_IOCTL_H_
+#define _MLAN_IOCTL_H_
+
+/** Enumeration for IOCTL request ID */
+enum _mlan_ioctl_req_id {
+ /* Scan Group */
+ MLAN_IOCTL_SCAN = 0x00010000,
+ MLAN_OID_SCAN_NORMAL = 0x00010001,
+ MLAN_OID_SCAN_SPECIFIC_SSID = 0x00010002,
+ MLAN_OID_SCAN_USER_CONFIG = 0x00010003,
+ MLAN_OID_SCAN_CONFIG = 0x00010004,
+ MLAN_OID_SCAN_GET_CURRENT_BSS = 0x00010005,
+ MLAN_OID_SCAN_CANCEL = 0x00010006,
+ MLAN_OID_SCAN_TABLE_FLUSH = 0x0001000A,
+ MLAN_OID_SCAN_BGSCAN_CONFIG = 0x0001000B,
+ /* BSS Configuration Group */
+ MLAN_IOCTL_BSS = 0x00020000,
+ MLAN_OID_BSS_START = 0x00020001,
+ MLAN_OID_BSS_STOP = 0x00020002,
+ MLAN_OID_BSS_MODE = 0x00020003,
+ MLAN_OID_BSS_CHANNEL = 0x00020004,
+ MLAN_OID_BSS_CHANNEL_LIST = 0x00020005,
+ MLAN_OID_BSS_MAC_ADDR = 0x00020006,
+ MLAN_OID_BSS_MULTICAST_LIST = 0x00020007,
+ MLAN_OID_BSS_FIND_BSS = 0x00020008,
+ MLAN_OID_IBSS_BCN_INTERVAL = 0x00020009,
+ MLAN_OID_IBSS_ATIM_WINDOW = 0x0002000A,
+ MLAN_OID_IBSS_CHANNEL = 0x0002000B,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_BSS_CONFIG = 0x0002000C,
+ MLAN_OID_UAP_DEAUTH_STA = 0x0002000D,
+ MLAN_OID_UAP_BSS_RESET = 0x0002000E,
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ MLAN_OID_BSS_ROLE = 0x0002000F,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_WIFI_DIRECT_MODE = 0x00020010,
+#endif
+#ifdef STA_SUPPORT
+ MLAN_OID_BSS_LISTEN_INTERVAL = 0x00020011,
+#endif
+ MLAN_OID_BSS_REMOVE = 0x00020014,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_CFG_WMM_PARAM = 0x00020015,
+#endif
+ MLAN_OID_BSS_11D_CHECK_CHANNEL = 0x00020016,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_ACS_SCAN = 0x00020017,
+ MLAN_OID_UAP_SCAN_CHANNELS = 0x00020018,
+ MLAN_OID_UAP_CHANNEL = 0x00020019,
+ MLAN_OID_UAP_OPER_CTRL = 0x0002001A,
+#endif
+#ifdef STA_SUPPORT
+ MLAN_OID_BSS_CHAN_INFO = 0x0002001B,
+#endif
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_ADD_STATION = 0x0002001C,
+#endif
+
+ MLAN_OID_BSS_FIND_BSSID = 0x0002001D,
+
+ /* Radio Configuration Group */
+ MLAN_IOCTL_RADIO_CFG = 0x00030000,
+ MLAN_OID_RADIO_CTRL = 0x00030001,
+ MLAN_OID_BAND_CFG = 0x00030002,
+ MLAN_OID_ANT_CFG = 0x00030003,
+ MLAN_OID_REMAIN_CHAN_CFG = 0x00030004,
+ MLAN_OID_MIMO_SWITCH = 0x00030005,
+
+ /* SNMP MIB Group */
+ MLAN_IOCTL_SNMP_MIB = 0x00040000,
+ MLAN_OID_SNMP_MIB_RTS_THRESHOLD = 0x00040001,
+ MLAN_OID_SNMP_MIB_FRAG_THRESHOLD = 0x00040002,
+ MLAN_OID_SNMP_MIB_RETRY_COUNT = 0x00040003,
+ MLAN_OID_SNMP_MIB_DOT11D = 0x00040004,
+#if defined(UAP_SUPPORT)
+ MLAN_OID_SNMP_MIB_DOT11H = 0x00040005,
+#endif
+ MLAN_OID_SNMP_MIB_DTIM_PERIOD = 0x00040006,
+ MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE = 0x00040007,
+ MLAN_OID_SNMP_MIB_CTRL_DEAUTH = 0x00040008,
+
+ /* Status Information Group */
+ MLAN_IOCTL_GET_INFO = 0x00050000,
+ MLAN_OID_GET_STATS = 0x00050001,
+ MLAN_OID_GET_SIGNAL = 0x00050002,
+ MLAN_OID_GET_FW_INFO = 0x00050003,
+ MLAN_OID_GET_VER_EXT = 0x00050004,
+ MLAN_OID_GET_BSS_INFO = 0x00050005,
+ MLAN_OID_GET_DEBUG_INFO = 0x00050006,
+#ifdef UAP_SUPPORT
+ MLAN_OID_UAP_STA_LIST = 0x00050007,
+#endif
+ MLAN_OID_GET_SIGNAL_EXT = 0x00050008,
+ MLAN_OID_LINK_STATS = 0x00050009,
+ MLAN_OID_GET_UAP_STATS_LOG = 0x0005000A,
+ /* Security Configuration Group */
+ MLAN_IOCTL_SEC_CFG = 0x00060000,
+ MLAN_OID_SEC_CFG_AUTH_MODE = 0x00060001,
+ MLAN_OID_SEC_CFG_ENCRYPT_MODE = 0x00060002,
+ MLAN_OID_SEC_CFG_WPA_ENABLED = 0x00060003,
+ MLAN_OID_SEC_CFG_ENCRYPT_KEY = 0x00060004,
+ MLAN_OID_SEC_CFG_PASSPHRASE = 0x00060005,
+ MLAN_OID_SEC_CFG_EWPA_ENABLED = 0x00060006,
+ MLAN_OID_SEC_CFG_ESUPP_MODE = 0x00060007,
+ MLAN_OID_SEC_CFG_WAPI_ENABLED = 0x00060009,
+ MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED = 0x0006000A,
+#ifdef UAP_SUPPORT
+ MLAN_OID_SEC_CFG_REPORT_MIC_ERR = 0x0006000B,
+#endif
+ MLAN_OID_SEC_QUERY_KEY = 0x0006000C,
+
+ /* Rate Group */
+ MLAN_IOCTL_RATE = 0x00070000,
+ MLAN_OID_RATE_CFG = 0x00070001,
+ MLAN_OID_GET_DATA_RATE = 0x00070002,
+ MLAN_OID_SUPPORTED_RATES = 0x00070003,
+
+ /* Power Configuration Group */
+ MLAN_IOCTL_POWER_CFG = 0x00080000,
+ MLAN_OID_POWER_CFG = 0x00080001,
+ MLAN_OID_POWER_CFG_EXT = 0x00080002,
+ MLAN_OID_POWER_LOW_POWER_MODE = 0x00080003,
+
+ /* Power Management Configuration Group */
+ MLAN_IOCTL_PM_CFG = 0x00090000,
+ MLAN_OID_PM_CFG_IEEE_PS = 0x00090001,
+ MLAN_OID_PM_CFG_HS_CFG = 0x00090002,
+ MLAN_OID_PM_CFG_INACTIVITY_TO = 0x00090003,
+ MLAN_OID_PM_CFG_DEEP_SLEEP = 0x00090004,
+ MLAN_OID_PM_CFG_SLEEP_PD = 0x00090005,
+ MLAN_OID_PM_CFG_PS_CFG = 0x00090006,
+ MLAN_OID_PM_CFG_SLEEP_PARAMS = 0x00090008,
+#ifdef UAP_SUPPORT
+ MLAN_OID_PM_CFG_PS_MODE = 0x00090009,
+#endif /* UAP_SUPPORT */
+ MLAN_OID_PM_INFO = 0x0009000A,
+ MLAN_OID_PM_HS_WAKEUP_REASON = 0x0009000B,
+ MLAN_OID_PM_MGMT_FILTER = 0x0009000C,
+ MLAN_OID_PM_CFG_BCN_TIMEOUT = 0x0009000D,
+
+ /* WMM Configuration Group */
+ MLAN_IOCTL_WMM_CFG = 0x000A0000,
+ MLAN_OID_WMM_CFG_ENABLE = 0x000A0001,
+ MLAN_OID_WMM_CFG_QOS = 0x000A0002,
+ MLAN_OID_WMM_CFG_ADDTS = 0x000A0003,
+ MLAN_OID_WMM_CFG_DELTS = 0x000A0004,
+ MLAN_OID_WMM_CFG_QUEUE_CONFIG = 0x000A0005,
+ MLAN_OID_WMM_CFG_QUEUE_STATS = 0x000A0006,
+ MLAN_OID_WMM_CFG_QUEUE_STATUS = 0x000A0007,
+ MLAN_OID_WMM_CFG_TS_STATUS = 0x000A0008,
+
+ /* WPS Configuration Group */
+ MLAN_IOCTL_WPS_CFG = 0x000B0000,
+ MLAN_OID_WPS_CFG_SESSION = 0x000B0001,
+
+ /* 802.11n Configuration Group */
+ MLAN_IOCTL_11N_CFG = 0x000C0000,
+ MLAN_OID_11N_CFG_TX = 0x000C0001,
+ MLAN_OID_11N_HTCAP_CFG = 0x000C0002,
+ MLAN_OID_11N_CFG_ADDBA_REJECT = 0x000C0003,
+ MLAN_OID_11N_CFG_AGGR_PRIO_TBL = 0x000C0004,
+ MLAN_OID_11N_CFG_ADDBA_PARAM = 0x000C0005,
+ MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE = 0x000C0006,
+ MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL = 0x000C0007,
+ MLAN_OID_11N_CFG_SUPPORTED_MCS_SET = 0x000C0008,
+ MLAN_OID_11N_CFG_TX_BF_CAP = 0x000C0009,
+ MLAN_OID_11N_CFG_TX_BF_CFG = 0x000C000A,
+ MLAN_OID_11N_CFG_STREAM_CFG = 0x000C000B,
+ MLAN_OID_11N_CFG_DELBA = 0x000C000C,
+ MLAN_OID_11N_CFG_REJECT_ADDBA_REQ = 0x000C000D,
+ MLAN_OID_11N_CFG_COEX_RX_WINSIZE = 0x000C000E,
+ MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM = 0x000C0010,
+ MLAN_OID_11N_CFG_MIN_BA_THRESHOLD = 0x000C0011,
+
+ /* 802.11d Configuration Group */
+ MLAN_IOCTL_11D_CFG = 0x000D0000,
+#ifdef STA_SUPPORT
+ MLAN_OID_11D_CFG_ENABLE = 0x000D0001,
+ MLAN_OID_11D_CLR_CHAN_TABLE = 0x000D0002,
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ MLAN_OID_11D_DOMAIN_INFO = 0x000D0003,
+#endif
+ MLAN_OID_11D_DOMAIN_INFO_EXT = 0x000D0004,
+
+ /* Register Memory Access Group */
+ MLAN_IOCTL_REG_MEM = 0x000E0000,
+ MLAN_OID_REG_RW = 0x000E0001,
+ MLAN_OID_EEPROM_RD = 0x000E0002,
+ MLAN_OID_MEM_RW = 0x000E0003,
+
+ /* Multi-Radio Configuration Group */
+ MLAN_IOCTL_MFR_CFG = 0x00100000,
+ /* 802.11h Configuration Group */
+ MLAN_IOCTL_11H_CFG = 0x00110000,
+ MLAN_OID_11H_CHANNEL_CHECK = 0x00110001,
+ MLAN_OID_11H_LOCAL_POWER_CONSTRAINT = 0x00110002,
+ MLAN_OID_11H_DFS_TESTING = 0x00110003,
+ MLAN_OID_11H_CHAN_REPORT_REQUEST = 0x00110004,
+ MLAN_OID_11H_CHAN_SWITCH_COUNT = 0x00110005,
+ MLAN_OID_11H_CHAN_NOP_INFO = 0x00110006,
+ MLAN_OID_11H_DFS_W53_CFG = 0x00110008,
+
+ /* 802.11n Configuration Group RANDYTODO for value assign */
+ MLAN_IOCTL_11AC_CFG = 0x00120000,
+ MLAN_OID_11AC_VHT_CFG = 0x00120001,
+ MLAN_OID_11AC_CFG_SUPPORTED_MCS_SET = 0x00120002,
+ MLAN_OID_11AC_OPERMODE_CFG = 0x00120003,
+
+ /* 802.11ax Configuration Group */
+ MLAN_IOCTL_11AX_CFG = 0x00170000,
+ MLAN_OID_11AX_HE_CFG = 0x00170001,
+ MLAN_OID_11AX_CMD_CFG = 0x00170002,
+ MLAN_OID_11AX_TWT_CFG = 0x00170003,
+
+ /* Miscellaneous Configuration Group */
+ MLAN_IOCTL_MISC_CFG = 0x00200000,
+ MLAN_OID_MISC_GEN_IE = 0x00200001,
+ MLAN_OID_MISC_REGION = 0x00200002,
+ MLAN_OID_MISC_WARM_RESET = 0x00200003,
+#ifdef SDIO
+ MLAN_OID_MISC_SDIO_MPA_CTRL = 0x00200006,
+#endif
+ MLAN_OID_MISC_HOST_CMD = 0x00200007,
+ MLAN_OID_MISC_SYS_CLOCK = 0x00200009,
+ MLAN_OID_MISC_SOFT_RESET = 0x0020000A,
+ MLAN_OID_MISC_WWS = 0x0020000B,
+ MLAN_OID_MISC_ASSOC_RSP = 0x0020000C,
+ MLAN_OID_MISC_INIT_SHUTDOWN = 0x0020000D,
+ MLAN_OID_MISC_CUSTOM_IE = 0x0020000F,
+ MLAN_OID_MISC_TX_DATAPAUSE = 0x00200012,
+ MLAN_OID_MISC_IP_ADDR = 0x00200013,
+ MLAN_OID_MISC_MAC_CONTROL = 0x00200014,
+ MLAN_OID_MISC_MEF_CFG = 0x00200015,
+ MLAN_OID_MISC_CFP_CODE = 0x00200016,
+ MLAN_OID_MISC_COUNTRY_CODE = 0x00200017,
+ MLAN_OID_MISC_THERMAL = 0x00200018,
+ MLAN_OID_MISC_RX_MGMT_IND = 0x00200019,
+ MLAN_OID_MISC_SUBSCRIBE_EVENT = 0x0020001A,
+#ifdef DEBUG_LEVEL1
+ MLAN_OID_MISC_DRVDBG = 0x0020001B,
+#endif
+ MLAN_OID_MISC_HOTSPOT_CFG = 0x0020001C,
+ MLAN_OID_MISC_OTP_USER_DATA = 0x0020001D,
+#ifdef USB
+ MLAN_OID_MISC_USB_AGGR_CTRL = 0x0020001F,
+#endif
+ MLAN_OID_MISC_TXCONTROL = 0x00200020,
+#ifdef STA_SUPPORT
+ MLAN_OID_MISC_EXT_CAP_CFG = 0x00200021,
+#endif
+#if defined(STA_SUPPORT)
+ MLAN_OID_MISC_PMFCFG = 0x00200022,
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ MLAN_OID_MISC_WIFI_DIRECT_CONFIG = 0x00200025,
+#endif
+ MLAN_OID_MISC_LOW_PWR_MODE = 0x00200029,
+ MLAN_OID_MISC_MEF_FLT_CFG = 0x0020002A,
+ MLAN_OID_MISC_DFS_REAPTER_MODE = 0x0020002B,
+#ifdef RX_PACKET_COALESCE
+ MLAN_OID_MISC_RX_PACKET_COALESCE = 0x0020002C,
+#endif
+ MLAN_OID_MISC_COALESCE_CFG = 0x0020002E,
+ MLAN_OID_MISC_GET_SENSOR_TEMP = 0x00200030,
+ MLAN_OID_MISC_GTK_REKEY_OFFLOAD = 0x00200037,
+ MLAN_OID_MISC_OPER_CLASS = 0x00200038,
+ MLAN_OID_MISC_PMIC_CFG = 0x00200039,
+ MLAN_OID_MISC_IND_RST_CFG = 0x00200040,
+ MLAN_OID_MISC_GET_TSF = 0x00200045,
+ MLAN_OID_MISC_GET_CHAN_REGION_CFG = 0x00200046,
+ MLAN_OID_MISC_CLOUD_KEEP_ALIVE = 0x00200048,
+ MLAN_OID_MISC_OPER_CLASS_CHECK = 0x00200049,
+
+ MLAN_OID_MISC_CWMODE_CTRL = 0x00200051,
+ MLAN_OID_MISC_AGGR_CTRL = 0x00200052,
+ MLAN_OID_MISC_DYN_BW = 0x00200053,
+ MLAN_OID_MISC_FW_DUMP_EVENT = 0x00200054,
+ MLAN_OID_MISC_PER_PKT_CFG = 0x00200055,
+
+ MLAN_OID_MISC_ROBUSTCOEX = 0x00200056,
+ MLAN_OID_MISC_GET_TX_RX_HISTOGRAM = 0x00200057,
+ MLAN_OID_MISC_CFP_INFO = 0x00200060,
+ MLAN_OID_MISC_BOOT_SLEEP = 0x00200061,
+#if defined(PCIE)
+ MLAN_OID_MISC_SSU = 0x00200062,
+#endif
+ MLAN_OID_MISC_DMCS_CONFIG = 0x00200065,
+ MLAN_OID_MISC_RX_ABORT_CFG = 0x00200066,
+ MLAN_OID_MISC_RX_ABORT_CFG_EXT = 0x00200067,
+ MLAN_OID_MISC_TX_AMPDU_PROT_MODE = 0x00200068,
+ MLAN_OID_MISC_RATE_ADAPT_CFG = 0x00200069,
+ MLAN_OID_MISC_CCK_DESENSE_CFG = 0x00200070,
+ MLAN_OID_MISC_GET_CHAN_TRPC_CFG = 0x00200072,
+ MLAN_OID_MISC_BAND_STEERING = 0x00200073,
+ MLAN_OID_MISC_GET_REGIONPWR_CFG = 0x00200074,
+ MLAN_OID_MISC_RF_TEST_GENERIC = 0x00200075,
+ MLAN_OID_MISC_RF_TEST_TX_CONT = 0x00200076,
+ MLAN_OID_MISC_RF_TEST_TX_FRAME = 0x00200077,
+ MLAN_OID_MISC_ARB_CONFIG = 0x00200078,
+ MLAN_OID_MISC_BEACON_STUCK = 0x00200079,
+ MLAN_OID_MISC_CFP_TABLE = 0x0020007A,
+ MLAN_OID_MISC_RANGE_EXT = 0x0020007B,
+ MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG = 0x0020007C,
+ MLAN_OID_MISC_TP_STATE = 0x0020007D,
+};
+
+/** Sub command size */
+#define MLAN_SUB_COMMAND_SIZE 4
+
+/** Enumeration for the action of IOCTL request */
+enum _mlan_act_ioctl {
+ MLAN_ACT_SET = 1,
+ MLAN_ACT_GET,
+ MLAN_ACT_CANCEL,
+ MLAN_ACT_CLEAR,
+ MLAN_ACT_RESET,
+ MLAN_ACT_DEFAULT
+};
+
+/** Enumeration for generic enable/disable */
+enum _mlan_act_generic { MLAN_ACT_DISABLE = 0, MLAN_ACT_ENABLE = 1 };
+
+/** Enumeration for scan mode */
+enum _mlan_scan_mode {
+ MLAN_SCAN_MODE_UNCHANGED = 0,
+ MLAN_SCAN_MODE_BSS,
+ MLAN_SCAN_MODE_IBSS,
+ MLAN_SCAN_MODE_ANY
+};
+
+/** Enumeration for scan type */
+enum _mlan_scan_type {
+ MLAN_SCAN_TYPE_UNCHANGED = 0,
+ MLAN_SCAN_TYPE_ACTIVE,
+ MLAN_SCAN_TYPE_PASSIVE,
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE
+};
+
+/** Enumeration for passive to active scan */
+enum _mlan_pass_to_act_scan {
+ MLAN_PASS_TO_ACT_SCAN_UNCHANGED = 0,
+ MLAN_PASS_TO_ACT_SCAN_EN,
+ MLAN_PASS_TO_ACT_SCAN_DIS
+};
+
+/** Max number of supported rates */
+#define MLAN_SUPPORTED_RATES 32
+
+/** Mrvl Proprietary Tlv base */
+#define PROPRIETARY_TLV_BASE_ID 0x100
+
+/** RSSI scan */
+#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI)))
+
+/** Max passive scan time for each channel in milliseconds */
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
+
+/** Max active scan time for each channel in milliseconds */
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
+/** Max gap time between 2 scan in milliseconds */
+#define MRVDRV_MAX_SCAN_CHAN_GAP_TIME 500
+
+/** Maximum number of probes to send on each channel */
+#define MAX_PROBES 5
+
+/** Default number of probes to send on each channel */
+#define DEFAULT_PROBES 4
+
+/**
+ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ * Fixed field information returned for the scan response in the IOCTL
+ * response.
+ */
+typedef struct _wlan_get_scan_table_fixed {
+ /** BSSID of this network */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Channel this beacon/probe response was detected */
+ t_u8 channel;
+ /** RSSI for the received packet */
+ t_u8 rssi;
+ /** channel load */
+ t_u8 chan_load;
+ /** TSF value in microseconds from the firmware at packet reception */
+ t_u64 network_tsf;
+} wlan_get_scan_table_fixed;
+
+/** mlan_802_11_ssid data structure */
+typedef struct _mlan_802_11_ssid {
+ /** SSID Length */
+ t_u32 ssid_len;
+ /** SSID information field */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+} mlan_802_11_ssid, *pmlan_802_11_ssid;
+
+typedef MLAN_PACK_START struct _tx_status_event {
+ /** packet type */
+ t_u8 packet_type;
+ /** tx_token_id */
+ t_u8 tx_token_id;
+ /** 0--success, 1--fail, 2--watchdogtimeout */
+ t_u8 status;
+} MLAN_PACK_END tx_status_event;
+
+/**
+ * Sructure to retrieve the scan table
+ */
+typedef struct {
+ /**
+ * - Zero based scan entry to start retrieval in command request
+ * - Number of scans entries returned in command response
+ */
+ t_u32 scan_number;
+ /**
+ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry
+ * structures. Each struct is padded to the nearest 32 bit boundary.
+ */
+ t_u8 scan_table_entry_buf[1];
+} wlan_ioctl_get_scan_table_info;
+
+/**
+ * Structure passed in the wlan_ioctl_get_scan_table_info for each
+ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ */
+typedef struct _wlan_ioctl_get_scan_table_entry {
+ /**
+ * Fixed field length included in the response.
+ *
+ * Length value is included so future fixed fields can be added to the
+ * response without breaking backwards compatibility. Use the length
+ * to find the offset for the bssInfoLength field, not a sizeof()
+ * calc.
+ */
+ t_u32 fixed_field_length;
+
+ /**
+ * Length of the BSS Information (probe resp or beacon) that
+ * follows after the fixed_field_length
+ */
+ t_u32 bss_info_length;
+
+ /**
+ * Always present, fixed length data fields for the BSS
+ */
+ wlan_get_scan_table_fixed fixed_fields;
+
+ /*
+ * Probe response or beacon scanned for the BSS.
+ *
+ * Field layout:
+ * - TSF 8 octets
+ * - Beacon Interval 2 octets
+ * - Capability Info 2 octets
+ *
+ * - IEEE Infomation Elements; variable number & length per 802.11 spec
+ */
+ /* t_u8 bss_info_buffer[]; */
+} wlan_ioctl_get_scan_table_entry;
+
+/** Type definition of mlan_scan_time_params */
+typedef struct _mlan_scan_time_params {
+ /** Scan channel time for specific scan in milliseconds */
+ t_u32 specific_scan_time;
+ /** Scan channel time for active scan in milliseconds */
+ t_u32 active_scan_time;
+ /** Scan channel time for passive scan in milliseconds */
+ t_u32 passive_scan_time;
+} mlan_scan_time_params, *pmlan_scan_time_params;
+
+/** Type definition of mlan_user_scan */
+typedef struct _mlan_user_scan {
+ /** Length of scan_cfg_buf */
+ t_u32 scan_cfg_len;
+ /** Buffer of scan config */
+ t_u8 scan_cfg_buf[1];
+} mlan_user_scan, *pmlan_user_scan;
+
+/** Type definition of mlan_scan_req */
+typedef struct _mlan_scan_req {
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan type */
+ t_u32 scan_type;
+ /** SSID */
+ mlan_802_11_ssid scan_ssid;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+} mlan_scan_req, *pmlan_scan_req;
+
+/** Type defnition of mlan_scan_resp */
+typedef struct _mlan_scan_resp {
+ /** Number of scan result */
+ t_u32 num_in_scan_table;
+ /** Scan table */
+ t_u8 *pscan_table;
+ /* Age in seconds */
+ t_u32 age_in_secs;
+ /** channel statstics */
+ t_u8 *pchan_stats;
+ /** Number of records in the chan_stats */
+ t_u32 num_in_chan_stats;
+} mlan_scan_resp, *pmlan_scan_resp;
+
+#define EXT_SCAN_TYPE_ENH 2
+/** Type definition of mlan_scan_cfg */
+typedef struct _mlan_scan_cfg {
+ /** Scan type */
+ t_u32 scan_type;
+ /** BSS mode for scanning */
+ t_u32 scan_mode;
+ /** Scan probe */
+ t_u32 scan_probe;
+ /** Scan time parameters */
+ mlan_scan_time_params scan_time;
+ /** First passive scan then active scan */
+ t_u8 passive_to_active_scan;
+ /** Ext_scan: 0 disable, 1: enable, 2: enhance scan*/
+ t_u32 ext_scan;
+ /** scan channel gap */
+ t_u32 scan_chan_gap;
+} mlan_scan_cfg, *pmlan_scan_cfg;
+
+/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */
+typedef struct _mlan_ds_scan {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Scan request/response */
+ union {
+ /** Scan request */
+ mlan_scan_req scan_req;
+ /** Scan response */
+ mlan_scan_resp scan_resp;
+ /** Scan config parameters in user scan */
+ mlan_user_scan user_scan;
+ /** Scan config parameters */
+ mlan_scan_cfg scan_cfg;
+ } param;
+} mlan_ds_scan, *pmlan_ds_scan;
+
+/*-----------------------------------------------------------------*/
+/** BSS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for BSS mode */
+enum _mlan_bss_mode {
+ MLAN_BSS_MODE_INFRA = 1,
+ MLAN_BSS_MODE_IBSS,
+ MLAN_BSS_MODE_AUTO
+};
+
+/** Maximum key length */
+#define MLAN_MAX_KEY_LENGTH 32
+
+/** Maximum atim window in milliseconds */
+#define MLAN_MAX_ATIM_WINDOW 50
+
+/** Minimum beacon interval */
+#define MLAN_MIN_BEACON_INTERVAL 20
+/** Maximum beacon interval */
+#define MLAN_MAX_BEACON_INTERVAL 1000
+/** Default beacon interval */
+#define MLAN_BEACON_INTERVAL 100
+
+/** Receive all packets */
+#define MLAN_PROMISC_MODE 1
+/** Receive multicast packets in multicast list */
+#define MLAN_MULTICAST_MODE 2
+/** Receive all multicast packets */
+#define MLAN_ALL_MULTI_MODE 4
+
+/** Maximum size of multicast list */
+#define MLAN_MAX_MULTICAST_LIST_SIZE 32
+
+/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */
+typedef struct _mlan_multicast_list {
+ /** Multicast mode */
+ t_u32 mode;
+ /** Number of multicast addresses in the list */
+ t_u32 num_multicast_addr;
+ /** Multicast address list */
+ mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE];
+} mlan_multicast_list, *pmlan_multicast_list;
+
+/** Max channel */
+#define MLAN_MAX_CHANNEL 165
+/** Maximum number of channels in table */
+#define MLAN_MAX_CHANNEL_NUM 128
+
+/** Channel/frequence for MLAN_OID_BSS_CHANNEL */
+typedef struct _chan_freq {
+ /** Channel Number */
+ t_u32 channel;
+ /** Frequency of this Channel */
+ t_u32 freq;
+} chan_freq;
+
+/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */
+typedef struct _mlan_chan_list {
+ /** Number of channel */
+ t_u32 num_of_chan;
+ /** Channel-Frequency table */
+ chan_freq cf[MLAN_MAX_CHANNEL_NUM];
+} mlan_chan_list;
+
+/* This channel is disabled.*/
+#define CHAN_FLAGS_DISABLED MBIT(0)
+/* do not initiate radiation, this includes sending probe requests or beaconing
+ */
+#define CHAN_FLAGS_NO_IR MBIT(1)
+/* Radar detection is required on this channel */
+#define CHAN_FLAGS_RADAR MBIT(3)
+/* extension channel above this channel is not permitted */
+#define CHAN_FLAGS_NO_HT40PLUS MBIT(4)
+/* extension channel below this channel is not permitted */
+#define CHAN_FLAGS_NO_HT40MINUS MBIT(5)
+/* OFDM is not allowed on this channel */
+#define CHAN_FLAGS_NO_OFDM MBIT(6)
+/** 80Mhz can not used on this channel */
+#define CHAN_FLAGS_NO_80MHZ MBIT(7)
+/** 180Mhz can not used on this channel */
+#define CHAN_FLAGS_NO_160MHZ MBIT(8)
+/* Only indoor use is permitted on this channel */
+#define CHAN_FLAGS_INDOOR_ONLY MBIT(9)
+/* IR operation is allowed on this channel if it's
+ * connected concurrently to a BSS on the same channel on
+ * the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
+ * band), and IEEE80211_CHAN_RADAR is not set */
+#define CHAN_FLAGS_IR_CONCURRENT MBIT(10)
+/* 20 MHz operation is not allowed on this channel */
+#define CHAN_FLAGS_20MHZ MBIT(11)
+/* 10 MHz operation is not allowed on this channel */
+#define CHAN_FLAGS_NO_10MHZ MBIT(12)
+/** This channel's flag is valid */
+#define CHAN_FLAGS_MAX MBIT(31)
+
+/** Maximum response buffer length */
+#define ASSOC_RSP_BUF_SIZE 500
+
+/** Type definition of mlan_ds_misc_assoc_rsp for MLAN_OID_MISC_ASSOC_RSP */
+typedef struct _mlan_ds_misc_assoc_rsp {
+ /** Associate response buffer */
+ t_u8 assoc_resp_buf[ASSOC_RSP_BUF_SIZE];
+ /** Response buffer length */
+ t_u32 assoc_resp_len;
+} mlan_ds_misc_assoc_rsp, *pmlan_ds_misc_assoc_rsp;
+
+/** mlan_ssid_bssid data structure for
+ * MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS
+ */
+typedef struct _mlan_ssid_bssid {
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+ /** index in BSSID list, start from 1 */
+ t_u32 idx;
+ /** Receive signal strength in dBm */
+ t_s32 rssi;
+ /**channel*/
+ t_u16 channel;
+ /**mobility domain value*/
+ t_u16 ft_md;
+ /**ft capability*/
+ t_u8 ft_cap;
+ /**band*/
+ t_u16 bss_band;
+ /** channel flag */
+ t_u32 channel_flags;
+ /** host mlme flag*/
+ t_u8 host_mlme;
+ /** assoicate resp frame/ie from firmware */
+ mlan_ds_misc_assoc_rsp assoc_rsp;
+} mlan_ssid_bssid, *pmlan_ssid_bssid;
+
+/** Data structure of WMM ECW */
+typedef struct _wmm_ecw_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+#else
+ /** Minimum Ecw */
+ t_u8 ecw_min : 4;
+ /** Maximum Ecw */
+ t_u8 ecw_max : 4;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_ecw_t, *pwmm_ecw_t;
+
+/** Data structure of WMM Aci/Aifsn */
+typedef struct _wmm_aci_aifsn_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** Reserved */
+ t_u8 reserved : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aifsn */
+ t_u8 aifsn : 4;
+#else
+ /** Aifsn */
+ t_u8 aifsn : 4;
+ /** Acm */
+ t_u8 acm : 1;
+ /** Aci */
+ t_u8 aci : 2;
+ /** Reserved */
+ t_u8 reserved : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t;
+
+/** Data structure of WMM AC parameters */
+typedef struct _wmm_ac_parameters_t {
+ wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */
+ wmm_ecw_t ecw; /**< Ecw */
+ t_u16 tx_op_limit; /**< Tx op limit */
+} wmm_ac_parameters_t, *pwmm_ac_parameters_t;
+
+/** mlan_deauth_param */
+typedef struct _mlan_deauth_param {
+ /** STA mac addr */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** deauth reason */
+ t_u16 reason_code;
+} mlan_deauth_param;
+
+#ifdef UAP_SUPPORT
+/** UAP FLAG: Host based */
+#define UAP_FLAG_HOST_BASED MBIT(0)
+/** UAP FLAG: Host mlme */
+#define UAP_FLAG_HOST_MLME MBIT(1)
+
+/** Maximum packet forward control value */
+#define MAX_PKT_FWD_CTRL 15
+/** Maximum BEACON period */
+#define MAX_BEACON_PERIOD 4000
+/** Minimum BEACON period */
+#define MIN_BEACON_PERIOD 50
+/** Maximum DTIM period */
+#define MAX_DTIM_PERIOD 100
+/** Minimum DTIM period */
+#define MIN_DTIM_PERIOD 1
+/** Maximum TX Power Limit */
+#define MAX_TX_POWER 20
+/** Minimum TX Power Limit */
+#define MIN_TX_POWER 0
+/** MAX station count */
+#define MAX_STA_COUNT 64
+/** Maximum RTS threshold */
+#define MAX_RTS_THRESHOLD 2347
+/** Maximum fragmentation threshold */
+#define MAX_FRAG_THRESHOLD 2346
+/** Minimum fragmentation threshold */
+#define MIN_FRAG_THRESHOLD 256
+/** data rate 54 M */
+#define DATA_RATE_54M 108
+/** Maximum value of bcast_ssid_ctl */
+#define MAX_BCAST_SSID_CTL 2
+/** antenna A */
+#define ANTENNA_MODE_A 0
+/** antenna B */
+#define ANTENNA_MODE_B 1
+/** transmit antenna */
+#define TX_ANTENNA 1
+/** receive antenna */
+#define RX_ANTENNA 0
+/** Maximum stage out time */
+#define MAX_STAGE_OUT_TIME 864000
+/** Minimum stage out time */
+#define MIN_STAGE_OUT_TIME 50
+/** Maximum Retry Limit */
+#define MAX_RETRY_LIMIT 14
+
+/** Maximum group key timer in seconds */
+#define MAX_GRP_TIMER 86400
+
+/** Maximum value of 4 byte configuration */
+#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */
+
+/** default UAP BAND 2.4G */
+#define DEFAULT_UAP_BAND 0
+/** default UAP channel 6 */
+#define DEFAULT_UAP_CHANNEL 6
+
+/** Maximum data rates */
+#define MAX_DATA_RATES 14
+
+/** auto data rate */
+#define DATA_RATE_AUTO 0
+
+/**filter mode: disable */
+#define MAC_FILTER_MODE_DISABLE 0
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_ALLOW_MAC 1
+/**filter mode: block mac address */
+#define MAC_FILTER_MODE_BLOCK_MAC 2
+/** Maximum mac filter num */
+#define MAX_MAC_FILTER_NUM 64
+
+/* Bitmap for protocol to use */
+/** No security */
+#define PROTOCOL_NO_SECURITY 0x01
+/** Static WEP */
+#define PROTOCOL_STATIC_WEP 0x02
+/** WPA */
+#define PROTOCOL_WPA 0x08
+/** WPA2 */
+#define PROTOCOL_WPA2 0x20
+/** WP2 Mixed */
+#define PROTOCOL_WPA2_MIXED 0x28
+/** EAP */
+#define PROTOCOL_EAP 0x40
+/** WAPI */
+#define PROTOCOL_WAPI 0x80
+/** WPA3 SAE */
+#define PROTOCOL_WPA3_SAE 0x100
+
+/** Key_mgmt_psk */
+#define KEY_MGMT_NONE 0x04
+/** Key_mgmt_none */
+#define KEY_MGMT_PSK 0x02
+/** Key_mgmt_eap */
+#define KEY_MGMT_EAP 0x01
+/** Key_mgmt_psk_sha256 */
+#define KEY_MGMT_PSK_SHA256 0x100
+/** Key_mgmt_sae */
+#define KEY_MGMT_SAE 0x400
+/** Key_mgmt_owe */
+#define KEY_MGMT_OWE 0x200
+
+/** TKIP */
+#define CIPHER_TKIP 0x04
+/** AES CCMP */
+#define CIPHER_AES_CCMP 0x08
+
+/** Valid cipher bitmap */
+#define VALID_CIPHER_BITMAP 0x0c
+
+/** Packet forwarding to be done by FW or host */
+#define PKT_FWD_FW_BIT 0x01
+/** Intra-BSS broadcast packet forwarding allow bit */
+#define PKT_FWD_INTRA_BCAST 0x02
+/** Intra-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTRA_UCAST 0x04
+/** Inter-BSS unicast packet forwarding allow bit */
+#define PKT_FWD_INTER_UCAST 0x08
+/** Intra-BSS unicast packet */
+#define PKT_INTRA_UCAST 0x01
+/** Inter-BSS unicast packet */
+#define PKT_INTER_UCAST 0x02
+/** Enable Host PKT forwarding */
+#define PKT_FWD_ENABLE_BIT 0x01
+
+/** Channel List Entry */
+typedef struct _channel_list {
+ /** Channel Number */
+ t_u8 chan_number;
+ /** Band Config */
+ Band_Config_t bandcfg;
+} scan_chan_list;
+
+/** mac_filter data structure */
+typedef struct _mac_filter {
+ /** mac filter mode */
+ t_u16 filter_mode;
+ /** mac adress count */
+ t_u16 mac_count;
+ /** mac address list */
+ mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM];
+} mac_filter;
+
+/** wpa parameter */
+typedef struct _wpa_param {
+ /** Pairwise cipher WPA */
+ t_u8 pairwise_cipher_wpa;
+ /** Pairwise cipher WPA2 */
+ t_u8 pairwise_cipher_wpa2;
+ /** group cipher */
+ t_u8 group_cipher;
+ /** RSN replay protection */
+ t_u8 rsn_protection;
+ /** passphrase length */
+ t_u32 length;
+ /** passphrase */
+ t_u8 passphrase[64];
+ /**group key rekey time in seconds */
+ t_u32 gk_rekey_time;
+} wpa_param;
+
+/** wep key */
+typedef struct _wep_key {
+ /** key index 0-3 */
+ t_u8 key_index;
+ /** is default */
+ t_u8 is_default;
+ /** length */
+ t_u16 length;
+ /** key data */
+ t_u8 key[26];
+} wep_key;
+
+/** wep param */
+typedef struct _wep_param {
+ /** key 0 */
+ wep_key key0;
+ /** key 1 */
+ wep_key key1;
+ /** key 2 */
+ wep_key key2;
+ /** key 3 */
+ wep_key key3;
+} wep_param;
+
+/** Data structure of WMM QoS information */
+typedef struct _wmm_qos_info_t {
+#ifdef BIG_ENDIAN_SUPPORT
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+#else
+ /** Parameter set count */
+ t_u8 para_set_count : 4;
+ /** Reserved */
+ t_u8 reserved : 3;
+ /** QoS UAPSD */
+ t_u8 qos_uapsd : 1;
+#endif /* BIG_ENDIAN_SUPPORT */
+} wmm_qos_info_t, *pwmm_qos_info_t;
+
+/** Data structure of WMM parameter IE */
+typedef struct _wmm_parameter_t {
+ /** OuiType: 00:50:f2:02 */
+ t_u8 ouitype[4];
+ /** Oui subtype: 01 */
+ t_u8 ouisubtype;
+ /** version: 01 */
+ t_u8 version;
+ /** QoS information */
+ t_u8 qos_info;
+ /** Reserved */
+ t_u8 reserved;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+} wmm_parameter_t, *pwmm_parameter_t;
+
+/** MAX BG channel */
+#define MAX_BG_CHANNEL 14
+/** mlan_bss_param
+ * Note: For each entry you must enter an invalid value
+ * in the MOAL function woal_set_sys_config_invalid_data().
+ * Otherwise for a valid data an unwanted TLV will be
+ * added to that command.
+ */
+typedef struct _mlan_uap_bss_param {
+ /** AP mac addr */
+ mlan_802_11_mac_addr mac_addr;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Broadcast ssid control */
+ t_u8 bcast_ssid_ctl;
+ /** Radio control: on/off */
+ t_u8 radio_ctl;
+ /** dtim period */
+ t_u8 dtim_period;
+ /** beacon period */
+ t_u16 beacon_period;
+ /** rates */
+ t_u8 rates[MAX_DATA_RATES];
+ /** Tx data rate */
+ t_u16 tx_data_rate;
+ /** Tx beacon rate */
+ t_u16 tx_beacon_rate;
+ /** multicast/broadcast data rate */
+ t_u16 mcbc_data_rate;
+ /** Tx power level in dBm */
+ t_u8 tx_power_level;
+ /** Tx antenna */
+ t_u8 tx_antenna;
+ /** Rx antenna */
+ t_u8 rx_antenna;
+ /** packet forward control */
+ t_u8 pkt_forward_ctl;
+ /** max station count */
+ t_u16 max_sta_count;
+ /** mac filter */
+ mac_filter filter;
+ /** station ageout timer in unit of 100ms */
+ t_u32 sta_ageout_timer;
+ /** PS station ageout timer in unit of 100ms */
+ t_u32 ps_sta_ageout_timer;
+ /** RTS threshold */
+ t_u16 rts_threshold;
+ /** fragmentation threshold */
+ t_u16 frag_threshold;
+ /** retry_limit */
+ t_u16 retry_limit;
+ /** pairwise update timeout in milliseconds */
+ t_u32 pairwise_update_timeout;
+ /** pairwise handshake retries */
+ t_u32 pwk_retries;
+ /** groupwise update timeout in milliseconds */
+ t_u32 groupwise_update_timeout;
+ /** groupwise handshake retries */
+ t_u32 gwk_retries;
+ /** preamble type */
+ t_u8 preamble_type;
+ /** band cfg */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** auth mode */
+ t_u16 auth_mode;
+ /** encryption protocol */
+ t_u16 protocol;
+ /** key managment type */
+ t_u16 key_mgmt;
+ /** wep param */
+ wep_param wep_cfg;
+ /** wpa param */
+ wpa_param wpa_cfg;
+ /** Mgmt IE passthru mask */
+ t_u32 mgmt_ie_passthru_mask;
+ /*
+ * 11n HT Cap HTCap_t ht_cap
+ */
+ /** HT Capabilities Info field */
+ t_u16 ht_cap_info;
+ /** A-MPDU Parameters field */
+ t_u8 ampdu_param;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[16];
+ /** HT Extended Capabilities field */
+ t_u16 ht_ext_cap;
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Antenna Selection Capability field */
+ t_u8 asel;
+ /** Enable 2040 Coex */
+ t_u8 enable_2040coex;
+ /** key management operation */
+ t_u16 key_mgmt_operation;
+ /** BSS status */
+ t_u16 bss_status;
+#ifdef WIFI_DIRECT_SUPPORT
+ /* pre shared key */
+ t_u8 psk[MLAN_MAX_KEY_LENGTH];
+#endif /* WIFI_DIRECT_SUPPORT */
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+ /** Wmm parameters */
+ wmm_parameter_t wmm_para;
+
+ /** uap host based config */
+ t_u32 uap_host_based_config;
+} mlan_uap_bss_param, *pmlan_uap_bss_param;
+
+/** mlan_uap_scan_channels */
+typedef struct _mlan_uap_scan_channels {
+ /** flag for remove nop channel*/
+ t_u8 remove_nop_channel;
+ /** num of removed channel */
+ t_u8 num_remvoed_channel;
+ /** Number of channels in scan_channel_list */
+ t_u32 num_of_chan;
+ /** scan channel list in ACS mode */
+ scan_chan_list chan_list[MLAN_MAX_CHANNEL];
+} mlan_uap_scan_channels;
+
+/** mlan_uap_oper_ctrl */
+typedef struct _mlan_uap_oper_ctrl {
+ /** control value
+ * 0: do nothing,
+ * 2: uap stops and restarts automaticaly
+ */
+ t_u16 ctrl_value;
+ /** channel opt
+ * 1: uap restart on default 2.4G/channel 6
+ * 2: uap restart on the band/channel configured by driver previously
+ * 3: uap restart on the band/channel specified by band_cfg and channel
+ */
+ t_u16 chan_opt;
+ /** band cfg 0
+ * 0: 20Mhz 2: 40 Mhz 3: 80Mhz
+ */
+ t_u8 band_cfg;
+ /** channel */
+ t_u8 channel;
+} mlan_uap_oper_ctrl;
+
+/** mlan_uap_acs_scan */
+typedef struct _mlan_uap_acs_scan {
+ /** band */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 chan;
+} mlan_uap_acs_scan;
+
+/** station is authorized (802.1X) */
+#define STA_FLAG_AUTHORIZED MBIT(1)
+/** Station is capable of receiving frames with short barker preamble */
+#define STA_FLAG_SHORT_PREAMBLE MBIT(2)
+/** station is WME/QoS capable */
+#define STA_FLAG_WME MBIT(3)
+/** station uses management frame protection */
+#define STA_FLAG_MFP MBIT(4)
+/** station is authenticated */
+#define STA_FLAG_AUTHENTICATED MBIT(5)
+/** station is a TDLS peer */
+#define STA_FLAG_TDLS_PEER MBIT(6)
+/** station is associated */
+#define STA_FLAG_ASSOCIATED MBIT(7)
+/** mlan_ds_sta_info */
+typedef struct _mlan_ds_sta_info {
+ /** aid */
+ t_u16 aid;
+ /** peer_mac */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Listen Interval */
+ int listen_interval;
+ /** Capability Info */
+ t_u16 cap_info;
+ /** station flag */
+ t_u32 sta_flags;
+ /** tlv len */
+ t_u16 tlv_len;
+ /** tlv start */
+ t_u8 tlv[];
+} mlan_ds_sta_info;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** mode: disable wifi direct */
+#define WIFI_DIRECT_MODE_DISABLE 0
+/** mode: listen */
+#define WIFI_DIRECT_MODE_LISTEN 1
+/** mode: GO */
+#define WIFI_DIRECT_MODE_GO 2
+/** mode: client */
+#define WIFI_DIRECT_MODE_CLIENT 3
+/** mode: find */
+#define WIFI_DIRECT_MODE_FIND 4
+/** mode: stop find */
+#define WIFI_DIRECT_MODE_STOP_FIND 5
+#endif
+
+/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */
+typedef struct _mlan_ds_bss {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** BSS parameter */
+ union {
+ /** SSID-BSSID for MLAN_OID_BSS_START */
+ mlan_ssid_bssid ssid_bssid;
+ /** BSSID for MLAN_OID_BSS_STOP */
+ mlan_802_11_mac_addr bssid;
+ /** BSS mode for MLAN_OID_BSS_MODE */
+ t_u32 bss_mode;
+ /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */
+ chan_freq bss_chan;
+ /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */
+ mlan_chan_list chanlist;
+ /** MAC address for MLAN_OID_BSS_MAC_ADDR */
+ mlan_802_11_mac_addr mac_addr;
+ /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */
+ mlan_multicast_list multicast_list;
+ /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */
+ t_u32 bcn_interval;
+ /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */
+ t_u32 atim_window;
+ /** deauth param for MLAN_OID_BSS_STOP & MLAN_OID_UAP_DEAUTH_STA
+ */
+ mlan_deauth_param deauth_param;
+#ifdef UAP_SUPPORT
+ /** host based flag for MLAN_OID_BSS_START */
+ t_u8 host_based;
+ /** BSS param for AP mode for MLAN_OID_UAP_BSS_CONFIG */
+ mlan_uap_bss_param bss_config;
+ /** AP Wmm parameters for MLAN_OID_UAP_CFG_WMM_PARAM */
+ wmm_parameter_t ap_wmm_para;
+ /** ap scan channels for MLAN_OID_UAP_SCAN_CHANNELS*/
+ mlan_uap_scan_channels ap_scan_channels;
+ /** ap channel for MLAN_OID_UAP_CHANNEL*/
+ chan_band_info ap_channel;
+ /** ap operation control for MLAN_OID_UAP_OPER_CTRL*/
+ mlan_uap_oper_ctrl ap_oper_ctrl;
+ /** AP acs scan MLAN_OID_UAP_ACS_SCAN */
+ mlan_uap_acs_scan ap_acs_scan;
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ /** BSS role for MLAN_OID_BSS_ROLE */
+ t_u8 bss_role;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ /** wifi direct mode for MLAN_OID_WIFI_DIRECT_MODE */
+ t_u16 wfd_mode;
+#endif
+#ifdef STA_SUPPORT
+ /** Listen interval for MLAN_OID_BSS_LISTEN_INTERVAL */
+ t_u16 listen_interval;
+ /** STA channel info for MLAN_OID_BSS_CHAN_INFO */
+ chan_band_info sta_channel;
+#endif
+#ifdef UAP_SUPPORT
+ /** STA info for MLAN_OID_UAP_ADD_STATION */
+ mlan_ds_sta_info sta_info;
+#endif
+ } param;
+} mlan_ds_bss, *pmlan_ds_bss;
+
+/* OTP Region info */
+typedef MLAN_PACK_START struct _otp_region_info {
+ t_u8 country_code[2];
+ t_u8 region_code;
+ t_u8 environment;
+ t_u16 force_reg : 1;
+ t_u16 reserved : 15;
+} MLAN_PACK_END otp_region_info_t;
+
+/** Type definition of mlan_ds_custom_reg_domain */
+typedef struct _mlan_ds_custom_reg_domain {
+ otp_region_info_t region;
+ /** num of 2g channels in custom_reg_domain */
+ t_u8 num_bg_chan;
+ /** num of 5g channels in custom_reg_domain */
+ t_u8 num_a_chan;
+ /** cfp table */
+ chan_freq_power_t cfp_tbl[];
+} mlan_ds_custom_reg_domain;
+/*-----------------------------------------------------------------*/
+/** Radio Control Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for band */
+enum _mlan_band_def {
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+ BAND_GAC = 32,
+ BAND_AAC = 64,
+ BAND_GAX = 256,
+ BAND_AAX = 512,
+
+};
+
+/** Channel bandwidth */
+#define CHANNEL_BW_20MHZ 0
+#define CHANNEL_BW_40MHZ_ABOVE 1
+#define CHANNEL_BW_40MHZ_BELOW 3
+/** secondary channel is 80Mhz bandwidth for 11ac */
+#define CHANNEL_BW_80MHZ 4
+#define CHANNEL_BW_160MHZ 5
+
+/** RF antenna selection */
+#define RF_ANTENNA_MASK(n) ((1 << (n)) - 1)
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO 0xFFFF
+
+/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */
+typedef struct _mlan_ds_band_cfg {
+ /** Infra band */
+ t_u32 config_bands;
+ /** Ad-hoc start band */
+ t_u32 adhoc_start_band;
+ /** Ad-hoc start channel */
+ t_u32 adhoc_channel;
+ /** fw supported band */
+ t_u32 fw_bands;
+} mlan_ds_band_cfg;
+
+/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg {
+ /** Tx antenna mode */
+ t_u32 tx_antenna;
+ /** Rx antenna mode */
+ t_u32 rx_antenna;
+} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg;
+/** Type definition of mlan_ds_mimo_switch for MLAN_OID_MIMO_SWITCH */
+typedef struct _mlan_ds_mimo_switch {
+ /** Tx antenna mode */
+ t_u8 txpath_antmode;
+ /** Rx antenna mode */
+ t_u8 rxpath_antmode;
+} mlan_ds_mimo_switch, *pmlan_ds_mimo_switch;
+/** Type definition of mlan_ds_ant_cfg_1x1 for MLAN_OID_ANT_CFG */
+typedef struct _mlan_ds_ant_cfg_1x1 {
+ /** Antenna mode */
+ t_u32 antenna;
+ /** Evaluate time */
+ t_u16 evaluate_time;
+ /** Current antenna */
+ t_u16 current_antenna;
+} mlan_ds_ant_cfg_1x1, *pmlan_ds_ant_cfg_1x1;
+
+/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */
+typedef struct _mlan_ds_remain_chan {
+ /** remove flag */
+ t_u16 remove;
+ /** status */
+ t_u8 status;
+ /** Band cfg */
+ Band_Config_t bandcfg;
+ /** channel */
+ t_u8 channel;
+ /** remain time: Unit ms*/
+ t_u32 remain_period;
+} mlan_ds_remain_chan, *pmlan_ds_remain_chan;
+
+/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */
+typedef struct _mlan_ds_radio_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Radio control parameter */
+ union {
+ /** Radio on/off for MLAN_OID_RADIO_CTRL */
+ t_u32 radio_on_off;
+ /** Band info for MLAN_OID_BAND_CFG */
+ mlan_ds_band_cfg band_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg ant_cfg;
+ /** Antenna mode for MLAN_OID_MIMO_SWITCH */
+ mlan_ds_mimo_switch mimo_switch_cfg;
+ /** Antenna info for MLAN_OID_ANT_CFG */
+ mlan_ds_ant_cfg_1x1 ant_cfg_1x1;
+ /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */
+ mlan_ds_remain_chan remain_chan;
+ } param;
+} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg;
+
+enum COALESCE_OPERATION {
+ RECV_FILTER_MATCH_TYPE_EQ = 0x80,
+ RECV_FILTER_MATCH_TYPE_NE,
+};
+
+enum COALESCE_PACKET_TYPE {
+ PACKET_TYPE_UNICAST = 1,
+ PACKET_TYPE_MULTICAST = 2,
+ PACKET_TYPE_BROADCAST = 3
+};
+
+#define COALESCE_MAX_RULES 8
+#define COALESCE_MAX_BYTESEQ 4 /* non-adjustable */
+#define COALESCE_MAX_FILTERS 4
+#define MAX_COALESCING_DELAY 100 /* in msecs */
+#define MAX_PATTERN_LEN 20
+#define MAX_OFFSET_LEN 100
+
+struct filt_field_param {
+ t_u8 operation;
+ t_u8 operand_len;
+ t_u16 offset;
+ t_u8 operand_byte_stream[COALESCE_MAX_BYTESEQ];
+};
+
+struct coalesce_rule {
+ t_u16 max_coalescing_delay;
+ t_u8 num_of_fields;
+ t_u8 pkt_type;
+ struct filt_field_param params[COALESCE_MAX_FILTERS];
+};
+
+typedef struct _mlan_ds_coalesce_cfg {
+ t_u16 num_of_rules;
+ struct coalesce_rule rule[COALESCE_MAX_RULES];
+} mlan_ds_coalesce_cfg;
+
+/*-----------------------------------------------------------------*/
+/** SNMP MIB Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */
+typedef struct _mlan_ds_snmp_mib {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** SNMP MIB parameter */
+ union {
+ /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */
+ t_u32 rts_threshold;
+ /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */
+ t_u32 frag_threshold;
+ /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */
+ t_u32 retry_count;
+ /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */
+ t_u32 oid_value;
+ /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */
+ t_u32 dtim_period;
+ /** Singal_ext Enable for MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE */
+ t_u8 signalext_enable;
+ /** Control deauth when uap switch channel */
+ t_u8 deauthctrl;
+ } param;
+} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib;
+
+/*-----------------------------------------------------------------*/
+/** Status Information Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for ad-hoc status */
+enum _mlan_adhoc_status {
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED,
+ ADHOC_STARTING
+};
+
+typedef struct _mlan_ds_get_stats_org {
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+ /** beacon recv count */
+ t_u32 bcn_rcv_cnt;
+ /** beacon miss count */
+ t_u32 bcn_miss_cnt;
+ /** received amsdu count*/
+ t_u32 amsdu_rx_cnt;
+ /** received msdu count in amsdu*/
+ t_u32 msdu_in_rx_amsdu_cnt;
+ /** tx amsdu count*/
+ t_u32 amsdu_tx_cnt;
+ /** tx msdu count in amsdu*/
+ t_u32 msdu_in_tx_amsdu_cnt;
+} mlan_ds_get_stats_org;
+
+/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_get_stats {
+ /** Statistics counter */
+ /** Multicast transmitted frame count */
+ t_u32 mcast_tx_frame;
+ /** Failure count */
+ t_u32 failed;
+ /** Retry count */
+ t_u32 retry;
+ /** Multi entry count */
+ t_u32 multi_retry;
+ /** Duplicate frame count */
+ t_u32 frame_dup;
+ /** RTS success count */
+ t_u32 rts_success;
+ /** RTS failure count */
+ t_u32 rts_failure;
+ /** Ack failure count */
+ t_u32 ack_failure;
+ /** Rx fragmentation count */
+ t_u32 rx_frag;
+ /** Multicast Tx frame count */
+ t_u32 mcast_rx_frame;
+ /** FCS error count */
+ t_u32 fcs_error;
+ /** Tx frame count */
+ t_u32 tx_frame;
+ /** WEP ICV error count */
+ t_u32 wep_icv_error[4];
+ /** beacon recv count */
+ t_u32 bcn_rcv_cnt;
+ /** beacon miss count */
+ t_u32 bcn_miss_cnt;
+ /** received amsdu count*/
+ t_u32 amsdu_rx_cnt;
+ /** received msdu count in amsdu*/
+ t_u32 msdu_in_rx_amsdu_cnt;
+ /** tx amsdu count*/
+ t_u32 amsdu_tx_cnt;
+ /** tx msdu count in amsdu*/
+ t_u32 msdu_in_tx_amsdu_cnt;
+
+ /** Tx frag count */
+ t_u32 tx_frag_cnt;
+ /** Qos Tx frag count */
+ t_u32 qos_tx_frag_cnt[8];
+ /** Qos failed count */
+ t_u32 qos_failed_cnt[8];
+ /** Qos retry count */
+ t_u32 qos_retry_cnt[8];
+ /** Qos multi retry count */
+ t_u32 qos_multi_retry_cnt[8];
+ /** Qos frame dup count */
+ t_u32 qos_frm_dup_cnt[8];
+ /** Qos rts success count */
+ t_u32 qos_rts_suc_cnt[8];
+ /** Qos rts failure count */
+ t_u32 qos_rts_failure_cnt[8];
+ /** Qos ack failure count */
+ t_u32 qos_ack_failure_cnt[8];
+ /** Qos Rx frag count */
+ t_u32 qos_rx_frag_cnt[8];
+ /** Qos Tx frame count */
+ t_u32 qos_tx_frm_cnt[8];
+ /** Qos discarded frame count */
+ t_u32 qos_discarded_frm_cnt[8];
+ /** Qos mpdus Rx count */
+ t_u32 qos_mpdus_rx_cnt[8];
+ /** Qos retry rx count */
+ t_u32 qos_retries_rx_cnt[8];
+ /** CMAC ICV errors count */
+ t_u32 cmacicv_errors;
+ /** CMAC replays count */
+ t_u32 cmac_replays;
+ /** mgmt CCMP replays count */
+ t_u32 mgmt_ccmp_replays;
+ /** TKIP ICV errors count */
+ t_u32 tkipicv_errors;
+ /** TKIP replays count */
+ t_u32 tkip_replays;
+ /** CCMP decrypt errors count */
+ t_u32 ccmp_decrypt_errors;
+ /** CCMP replays count */
+ t_u32 ccmp_replays;
+ /** Tx amsdu count */
+ t_u32 tx_amsdu_cnt;
+ /** failed amsdu count */
+ t_u32 failed_amsdu_cnt;
+ /** retry amsdu count */
+ t_u32 retry_amsdu_cnt;
+ /** multi-retry amsdu count */
+ t_u32 multi_retry_amsdu_cnt;
+ /** Tx octets in amsdu count */
+ t_u64 tx_octets_in_amsdu_cnt;
+ /** amsdu ack failure count */
+ t_u32 amsdu_ack_failure_cnt;
+ /** Rx amsdu count */
+ t_u32 rx_amsdu_cnt;
+ /** Rx octets in amsdu count */
+ t_u64 rx_octets_in_amsdu_cnt;
+ /** Tx ampdu count */
+ t_u32 tx_ampdu_cnt;
+ /** tx mpdus in ampdu count */
+ t_u32 tx_mpdus_in_ampdu_cnt;
+ /** tx octets in ampdu count */
+ t_u64 tx_octets_in_ampdu_cnt;
+ /** ampdu Rx count */
+ t_u32 ampdu_rx_cnt;
+ /** mpdu in Rx ampdu count */
+ t_u32 mpdu_in_rx_ampdu_cnt;
+ /** Rx octets ampdu count */
+ t_u64 rx_octets_in_ampdu_cnt;
+ /** ampdu delimiter CRC error count */
+ t_u32 ampdu_delimiter_crc_error_cnt;
+ /** Rx Stuck Related Info*/
+ /** Rx Stuck Issue count */
+ t_u32 rx_stuck_issue_cnt[2];
+ /** Rx Stuck Recovery count */
+ t_u32 rx_stuck_recovery_cnt;
+ /** Rx Stuck TSF */
+ t_u64 rx_stuck_tsf[2];
+ /** Tx Watchdog Recovery Related Info */
+ /** Tx Watchdog Recovery count */
+ t_u32 tx_watchdog_recovery_cnt;
+ /** Tx Watchdog TSF */
+ t_u64 tx_watchdog_tsf[2];
+ /** Channel Switch Related Info */
+ /** Channel Switch Announcement Sent */
+ t_u32 channel_switch_ann_sent;
+ /** Channel Switch State */
+ t_u32 channel_switch_state;
+ /** Register Class */
+ t_u32 reg_class;
+ /** Channel Number */
+ t_u32 channel_number;
+ /** Channel Switch Mode */
+ t_u32 channel_switch_mode;
+} mlan_ds_get_stats, *pmlan_ds_get_stats;
+
+/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */
+typedef struct _mlan_ds_uap_stats {
+ /** tkip mic failures */
+ t_u32 tkip_mic_failures;
+ /** ccmp decrypt errors */
+ t_u32 ccmp_decrypt_errors;
+ /** wep undecryptable count */
+ t_u32 wep_undecryptable_count;
+ /** wep icv error count */
+ t_u32 wep_icv_error_count;
+ /** decrypt failure count */
+ t_u32 decrypt_failure_count;
+ /** dot11 multicast tx count */
+ t_u32 mcast_tx_count;
+ /** dot11 failed count */
+ t_u32 failed_count;
+ /** dot11 retry count */
+ t_u32 retry_count;
+ /** dot11 multi retry count */
+ t_u32 multi_retry_count;
+ /** dot11 frame duplicate count */
+ t_u32 frame_dup_count;
+ /** dot11 rts success count */
+ t_u32 rts_success_count;
+ /** dot11 rts failure count */
+ t_u32 rts_failure_count;
+ /** dot11 ack failure count */
+ t_u32 ack_failure_count;
+ /** dot11 rx ragment count */
+ t_u32 rx_fragment_count;
+ /** dot11 mcast rx frame count */
+ t_u32 mcast_rx_frame_count;
+ /** dot11 fcs error count */
+ t_u32 fcs_error_count;
+ /** dot11 tx frame count */
+ t_u32 tx_frame_count;
+ /** dot11 rsna tkip cm invoked */
+ t_u32 rsna_tkip_cm_invoked;
+ /** dot11 rsna 4way handshake failures */
+ t_u32 rsna_4way_hshk_failures;
+} mlan_ds_uap_stats, *pmlan_ds_uap_stats;
+
+/** Mask of last beacon RSSI */
+#define BCN_RSSI_LAST_MASK 0x00000001
+/** Mask of average beacon RSSI */
+#define BCN_RSSI_AVG_MASK 0x00000002
+/** Mask of last data RSSI */
+#define DATA_RSSI_LAST_MASK 0x00000004
+/** Mask of average data RSSI */
+#define DATA_RSSI_AVG_MASK 0x00000008
+/** Mask of last beacon SNR */
+#define BCN_SNR_LAST_MASK 0x00000010
+/** Mask of average beacon SNR */
+#define BCN_SNR_AVG_MASK 0x00000020
+/** Mask of last data SNR */
+#define DATA_SNR_LAST_MASK 0x00000040
+/** Mask of average data SNR */
+#define DATA_SNR_AVG_MASK 0x00000080
+/** Mask of last beacon NF */
+#define BCN_NF_LAST_MASK 0x00000100
+/** Mask of average beacon NF */
+#define BCN_NF_AVG_MASK 0x00000200
+/** Mask of last data NF */
+#define DATA_NF_LAST_MASK 0x00000400
+/** Mask of average data NF */
+#define DATA_NF_AVG_MASK 0x00000800
+/** Mask of all RSSI_INFO */
+#define ALL_RSSI_INFO_MASK 0x00000fff
+#define MAX_PATH_NUM 3
+/** path A */
+#define PATH_A 0x01
+/** path B */
+#define PATH_B 0x02
+/** path AB */
+#define PATH_AB 0x03
+/** ALL the path */
+#define PATH_ALL 0
+/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */
+typedef struct _mlan_ds_get_signal {
+ /** Selector of get operation */
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ *
+ * Bit0: PATH A
+ * Bit1: PATH B
+ */
+ t_u16 selector;
+
+ /** RSSI */
+ /** RSSI of last beacon */
+ t_s16 bcn_rssi_last;
+ /** RSSI of beacon average */
+ t_s16 bcn_rssi_avg;
+ /** RSSI of last data packet */
+ t_s16 data_rssi_last;
+ /** RSSI of data packet average */
+ t_s16 data_rssi_avg;
+
+ /** SNR */
+ /** SNR of last beacon */
+ t_s16 bcn_snr_last;
+ /** SNR of beacon average */
+ t_s16 bcn_snr_avg;
+ /** SNR of last data packet */
+ t_s16 data_snr_last;
+ /** SNR of data packet average */
+ t_s16 data_snr_avg;
+
+ /** NF */
+ /** NF of last beacon */
+ t_s16 bcn_nf_last;
+ /** NF of beacon average */
+ t_s16 bcn_nf_avg;
+ /** NF of last data packet */
+ t_s16 data_nf_last;
+ /** NF of data packet average */
+ t_s16 data_nf_avg;
+} mlan_ds_get_signal, *pmlan_ds_get_signal;
+
+/** bit for 2.4 G antenna diversity */
+#define ANT_DIVERSITY_2G MBIT(3)
+/** bit for 5 G antenna diversity */
+#define ANT_DIVERSITY_5G MBIT(7)
+
+/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */
+typedef struct _mlan_fw_info {
+ /** Firmware version */
+ t_u32 fw_ver;
+ /** MAC address */
+ mlan_802_11_mac_addr mac_addr;
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** user's MCS setting */
+ t_u8 usr_dev_mcs_support;
+ /** 802.11ac device capabilities */
+ t_u32 hw_dot_11ac_dev_cap;
+ /** 802.11ac device Capabilities for 2.4GHz */
+ t_u32 usr_dot_11ac_dev_cap_bg;
+ /** 802.11ac device Capabilities for 5GHz */
+ t_u32 usr_dot_11ac_dev_cap_a;
+ /** length of hw he capability */
+ t_u8 hw_hecap_len;
+ /** 802.11ax HE capability */
+ t_u8 hw_he_cap[54];
+ /** length of hw 2.4G he capability */
+ t_u8 hw_2g_hecap_len;
+ /** 802.11ax 2.4G HE capability */
+ t_u8 hw_2g_he_cap[54];
+ /** 802.11ac device support for MIMO abstraction of MCSs */
+ t_u32 hw_dot_11ac_mcs_support;
+ /** User conf 802.11ac device support for MIMO abstraction of MCSs */
+ t_u32 usr_dot_11ac_mcs_support;
+ /** fw supported band */
+ t_u16 fw_bands;
+ /** region code */
+ t_u16 region_code;
+ /** force_reg */
+ t_u8 force_reg;
+ /** ECSA support */
+ t_u8 ecsa_enable;
+ /** Get log support */
+ t_u8 getlog_enable;
+ /** FW support for embedded supplicant */
+ t_u8 fw_supplicant_support;
+ /** ant info */
+ t_u8 antinfo;
+ /** max AP associated sta count supported by fw */
+ t_u8 max_ap_assoc_sta;
+ /** Bandwidth not support 80Mhz */
+ t_u8 prohibit_80mhz;
+} mlan_fw_info, *pmlan_fw_info;
+
+/** Version string buffer length */
+#define MLAN_MAX_VER_STR_LEN 128
+
+/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */
+typedef struct _mlan_ver_ext {
+ /** Selected version string */
+ t_u32 version_str_sel;
+ /** Version string */
+ char version_str[MLAN_MAX_VER_STR_LEN];
+} mlan_ver_ext, *pmlan_ver_ext;
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t {
+ /** Extended Capabilities value */
+ t_u8 rsvdBit79 : 1; /* bit 79 */
+ t_u8 TWTResp : 1; /* bit 78 */
+ t_u8 TWTReq : 1; /* bit 77 */
+ t_u8 rsvdBit76 : 1; /* bit 76 */
+ t_u8 rsvdBit75 : 1; /* bit 75 */
+ t_u8 rsvdBit74 : 1; /* bit 74 */
+ t_u8 rsvdBit73 : 1; /* bit 73 */
+ t_u8 FILS : 1; /* bit 72 */
+ t_u8 FTMI : 1; /* bit 71 */
+ t_u8 FTMR : 1; /* bit 70 */
+ t_u8 CAQ : 1; /* bit 69 */
+ t_u8 rsvdBit68 : 1; /* bit 68 */
+ t_u8 NCC : 1; /* bit 67 */
+ t_u8 rsvdBit66 : 1; /* bit 66 */
+ t_u8 chanSchedMgnt : 1; /* bit 65 */
+ t_u8 MaxAMSDU1 : 1; /* bit 64 */
+ t_u8 MaxAMSDU0 : 1; /* bit 63 */
+ t_u8 OperModeNtf : 1; /* bit 62 */
+ t_u8 TDLSWildBandwidth : 1; /* bit 61 */
+ t_u8 rsvdBit60 : 1; /* bit 60 */
+ t_u8 rsvdBit59 : 1; /* bit 59 */
+ t_u8 rsvdBit58 : 1; /* bit 58 */
+ t_u8 rsvdBit57 : 1; /* bit 57 */
+ t_u8 rsvdBit56 : 1; /* bit 56 */
+ t_u8 rsvdBit55 : 1; /* bit 55 */
+ t_u8 rsvdBit54 : 1; /* bit 54 */
+ t_u8 rsvdBit53 : 1; /* bit 53 */
+ t_u8 rsvdBit52 : 1; /* bit 52 */
+ t_u8 rsvdBit51 : 1; /* bit 51 */
+ t_u8 rsvdBit50 : 1; /* bit 50 */
+ t_u8 rsvdBit49 : 1; /* bit 49 */
+ t_u8 rsvdBit48 : 1; /* bit 48 */
+ t_u8 rsvdBit47 : 1; /* bit 47 */
+ t_u8 rsvdBit46 : 1; /* bit 46 */
+ t_u8 rsvdBit45 : 1; /* bit 45 */
+ t_u8 rsvdBit44 : 1; /* bit 44 */
+ t_u8 rsvdBit43 : 1; /* bit 43 */
+ t_u8 rsvdBit42 : 1; /* bit 42 */
+ t_u8 rsvdBit41 : 1; /* bit 41 */
+ t_u8 rsvdBit40 : 1; /* bit 40 */
+ t_u8 TDLSChlSwitchProhib : 1; /* bit 39 */
+ t_u8 TDLSProhibited : 1; /* bit 38 */
+ t_u8 TDLSSupport : 1; /* bit 37 */
+ t_u8 MSGCF_Capa : 1; /* bit 36 */
+ t_u8 Reserved35 : 1; /* bit 35 */
+ t_u8 SSPN_Interface : 1; /* bit 34 */
+ t_u8 EBR : 1; /* bit 33 */
+ t_u8 Qos_Map : 1; /* bit 32 */
+ t_u8 Interworking : 1; /* bit 31 */
+ t_u8 TDLSChannelSwitching : 1; /* bit 30 */
+ t_u8 TDLSPeerPSMSupport : 1; /* bit 29 */
+ t_u8 TDLSPeerUAPSDSupport : 1; /* bit 28 */
+ t_u8 UTC : 1; /* bit 27 */
+ t_u8 DMS : 1; /* bit 26 */
+ t_u8 SSID_List : 1; /* bit 25 */
+ t_u8 ChannelUsage : 1; /* bit 24 */
+ t_u8 TimingMeasurement : 1; /* bit 23 */
+ t_u8 MultipleBSSID : 1; /* bit 22 */
+ t_u8 AC_StationCount : 1; /* bit 21 */
+ t_u8 QoSTrafficCap : 1; /* bit 20 */
+ t_u8 BSS_Transition : 1; /* bit 19 */
+ t_u8 TIM_Broadcast : 1; /* bit 18 */
+ t_u8 WNM_Sleep : 1; /* bit 17 */
+ t_u8 TFS : 1; /* bit 16 */
+ t_u8 GeospatialLocation : 1; /* bit 15 */
+ t_u8 CivicLocation : 1; /* bit 14 */
+ t_u8 CollocatedIntf : 1; /* bit 13 */
+ t_u8 ProxyARPService : 1; /* bit 12 */
+ t_u8 FMS : 1; /* bit 11 */
+ t_u8 LocationTracking : 1; /* bit 10 */
+ t_u8 MulticastDiagnostics : 1; /* bit 9 */
+ t_u8 Diagnostics : 1; /* bit 8 */
+ t_u8 Event : 1; /* bit 7 */
+ t_u8 SPSMP_Support : 1; /* bit 6 */
+ t_u8 Reserved5 : 1; /* bit 5 */
+ t_u8 PSMP_Capable : 1; /* bit 4 */
+ t_u8 RejectUnadmFrame : 1; /* bit 3 */
+ t_u8 ExtChanSwitching : 1; /* bit 2 */
+ t_u8 Reserved1 : 1; /* bit 1 */
+ t_u8 BSS_CoexistSupport : 1; /* bit 0 */
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+#else
+/** Extended Capabilities Data */
+typedef struct MLAN_PACK_START _ExtCap_t {
+ /** Extended Capabilities value */
+ t_u8 BSS_CoexistSupport : 1; /* bit 0 */
+ t_u8 Reserved1 : 1; /* bit 1 */
+ t_u8 ExtChanSwitching : 1; /* bit 2 */
+ t_u8 RejectUnadmFrame : 1; /* bit 3 */
+ t_u8 PSMP_Capable : 1; /* bit 4 */
+ t_u8 Reserved5 : 1; /* bit 5 */
+ t_u8 SPSMP_Support : 1; /* bit 6 */
+ t_u8 Event : 1; /* bit 7 */
+ t_u8 Diagnostics : 1; /* bit 8 */
+ t_u8 MulticastDiagnostics : 1; /* bit 9 */
+ t_u8 LocationTracking : 1; /* bit 10 */
+ t_u8 FMS : 1; /* bit 11 */
+ t_u8 ProxyARPService : 1; /* bit 12 */
+ t_u8 CollocatedIntf : 1; /* bit 13 */
+ t_u8 CivicLocation : 1; /* bit 14 */
+ t_u8 GeospatialLocation : 1; /* bit 15 */
+ t_u8 TFS : 1; /* bit 16 */
+ t_u8 WNM_Sleep : 1; /* bit 17 */
+ t_u8 TIM_Broadcast : 1; /* bit 18 */
+ t_u8 BSS_Transition : 1; /* bit 19 */
+ t_u8 QoSTrafficCap : 1; /* bit 20 */
+ t_u8 AC_StationCount : 1; /* bit 21 */
+ t_u8 MultipleBSSID : 1; /* bit 22 */
+ t_u8 TimingMeasurement : 1; /* bit 23 */
+ t_u8 ChannelUsage : 1; /* bit 24 */
+ t_u8 SSID_List : 1; /* bit 25 */
+ t_u8 DMS : 1; /* bit 26 */
+ t_u8 UTC : 1; /* bit 27 */
+ t_u8 TDLSPeerUAPSDSupport : 1; /* bit 28 */
+ t_u8 TDLSPeerPSMSupport : 1; /* bit 29 */
+ t_u8 TDLSChannelSwitching : 1; /* bit 30 */
+ t_u8 Interworking : 1; /* bit 31 */
+ t_u8 Qos_Map : 1; /* bit 32 */
+ t_u8 EBR : 1; /* bit 33 */
+ t_u8 SSPN_Interface : 1; /* bit 34 */
+ t_u8 Reserved35 : 1; /* bit 35 */
+ t_u8 MSGCF_Capa : 1; /* bit 36 */
+ t_u8 TDLSSupport : 1; /* bit 37 */
+ t_u8 TDLSProhibited : 1; /* bit 38 */
+ t_u8 TDLSChlSwitchProhib : 1; /* bit 39 */
+ t_u8 rsvdBit40 : 1; /* bit 40 */
+ t_u8 rsvdBit41 : 1; /* bit 41 */
+ t_u8 rsvdBit42 : 1; /* bit 42 */
+ t_u8 rsvdBit43 : 1; /* bit 43 */
+ t_u8 rsvdBit44 : 1; /* bit 44 */
+ t_u8 rsvdBit45 : 1; /* bit 45 */
+ t_u8 rsvdBit46 : 1; /* bit 46 */
+ t_u8 rsvdBit47 : 1; /* bit 47 */
+ t_u8 rsvdBit48 : 1; /* bit 48 */
+ t_u8 rsvdBit49 : 1; /* bit 49 */
+ t_u8 rsvdBit50 : 1; /* bit 50 */
+ t_u8 rsvdBit51 : 1; /* bit 51 */
+ t_u8 rsvdBit52 : 1; /* bit 52 */
+ t_u8 rsvdBit53 : 1; /* bit 53 */
+ t_u8 rsvdBit54 : 1; /* bit 54 */
+ t_u8 rsvdBit55 : 1; /* bit 55 */
+ t_u8 rsvdBit56 : 1; /* bit 56 */
+ t_u8 rsvdBit57 : 1; /* bit 57 */
+ t_u8 rsvdBit58 : 1; /* bit 58 */
+ t_u8 rsvdBit59 : 1; /* bit 59 */
+ t_u8 rsvdBit60 : 1; /* bit 60 */
+ t_u8 TDLSWildBandwidth : 1; /* bit 61 */
+ t_u8 OperModeNtf : 1; /* bit 62 */
+ t_u8 MaxAMSDU0 : 1; /* bit 63 */
+ t_u8 MaxAMSDU1 : 1; /* bit 64 */
+ t_u8 chanSchedMgnt : 1; /* bit 65 */
+ t_u8 rsvdBit66 : 1; /* bit 66 */
+ t_u8 NCC : 1; /* bit 67 */
+ t_u8 rsvdBit68 : 1; /* bit 68 */
+ t_u8 CAQ : 1; /* bit 69 */
+ t_u8 FTMR : 1; /* bit 70 */
+ t_u8 FTMI : 1; /* bit 71 */
+ t_u8 FILS : 1; /* bit 72 */
+ t_u8 rsvdBit73 : 1; /* bit 73 */
+ t_u8 rsvdBit74 : 1; /* bit 74 */
+ t_u8 rsvdBit75 : 1; /* bit 75 */
+ t_u8 rsvdBit76 : 1; /* bit 76 */
+ t_u8 TWTReq : 1; /* bit 77 */
+ t_u8 TWTResp : 1; /* bit 78 */
+ t_u8 rsvdBit79 : 1; /* bit 79 */
+} MLAN_PACK_END ExtCap_t, *pExtCap_t;
+#endif
+
+/** ExtCap : TDLS prohibited */
+#define IS_EXTCAP_TDLS_PROHIBITED(ext_cap) (ext_cap.TDLSProhibited)
+/** ExtCap : TDLS channel switch prohibited */
+#define IS_EXTCAP_TDLS_CHLSWITCHPROHIB(ext_cap) (ext_cap.TDLSChlSwitchProhib)
+
+/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */
+typedef struct _mlan_bss_info {
+ /** BSS mode */
+ t_u32 bss_mode;
+ /** SSID */
+ mlan_802_11_ssid ssid;
+ /** Table index */
+ t_u32 scan_table_idx;
+ /** Channel */
+ t_u32 bss_chan;
+ /** Band */
+ t_u8 bss_band;
+ /** Region code */
+ t_u32 region_code;
+ /** Connection status */
+ t_u32 media_connected;
+ /** Radio on */
+ t_u32 radio_on;
+ /** Max power level in dBm */
+ t_s32 max_power_level;
+ /** Min power level in dBm */
+ t_s32 min_power_level;
+ /** Adhoc state */
+ t_u32 adhoc_state;
+ /** NF of last beacon */
+ t_s32 bcn_nf_last;
+ /** wep status */
+ t_u32 wep_status;
+ /** scan block status */
+ t_u8 scan_block;
+ /** Host Sleep configured flag */
+ t_u32 is_hs_configured;
+ /** Deep Sleep flag */
+ t_u32 is_deep_sleep;
+ /** BSSID */
+ mlan_802_11_mac_addr bssid;
+#ifdef STA_SUPPORT
+ /** Capability Info */
+ t_u16 capability_info;
+ /** Beacon Interval */
+ t_u16 beacon_interval;
+ /** Listen Interval */
+ t_u16 listen_interval;
+ /** Association Id */
+ t_u16 assoc_id;
+ /** AP/Peer supported rates */
+ t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES];
+ /** extend capability for AP */
+ ExtCap_t ext_cap;
+#endif /* STA_SUPPORT */
+ /** Mobility Domain ID */
+ t_u16 mdid;
+ /** FT Capability policy */
+ t_u8 ft_cap;
+ /** 11h active */
+ t_bool is_11h_active;
+ /** dfs check channel */
+ t_u8 dfs_check_channel;
+} mlan_bss_info, *pmlan_bss_info;
+
+/** MAXIMUM number of TID */
+#define MAX_NUM_TID 8
+
+/** Max RX Win size */
+#define MAX_RX_WINSIZE 64
+
+/** rx_reorder_tbl */
+typedef struct {
+ /** TID */
+ t_u16 tid;
+ /** TA */
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ /** Start window */
+ t_u32 start_win;
+ /** Window size */
+ t_u32 win_size;
+ /** amsdu flag */
+ t_u8 amsdu;
+ /** buffer status */
+ t_u32 buffer[MAX_RX_WINSIZE];
+} rx_reorder_tbl;
+
+/** tx_ba_stream_tbl */
+typedef struct {
+ /** TID */
+ t_u16 tid;
+ /** RA */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** amsdu flag */
+ t_u8 amsdu;
+} tx_ba_stream_tbl;
+
+/** Debug command number */
+#define DBG_CMD_NUM 10
+
+#ifdef SDIO
+/** sdio mp debug number */
+#define SDIO_MP_DBG_NUM 10
+#endif
+
+#ifdef PCIE
+#define MLAN_MAX_TXRX_BD 0x20
+#endif
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE 256
+
+/** max ralist num */
+#define MLAN_MAX_RALIST_NUM 8
+/** ralist info */
+typedef struct _ralist_info {
+ /** RA list buffer */
+ t_u8 ra[MLAN_MAC_ADDR_LENGTH];
+ /** total packets in RA list */
+ t_u16 total_pkts;
+ /** tid num */
+ t_u8 tid;
+ /** tx_pause flag */
+ t_u8 tx_pause;
+} ralist_info, *pralist_info;
+
+/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */
+typedef struct _mlan_debug_info {
+ /* WMM AC_BK count */
+ t_u32 wmm_ac_bk;
+ /* WMM AC_BE count */
+ t_u32 wmm_ac_be;
+ /* WMM AC_VI count */
+ t_u32 wmm_ac_vi;
+ /* WMM AC_VO count */
+ t_u32 wmm_ac_vo;
+ /** Corresponds to max_tx_buf_size member of mlan_adapter*/
+ t_u32 max_tx_buf_size;
+ /** Corresponds to tx_buf_size member of mlan_adapter*/
+ t_u32 tx_buf_size;
+ /** Corresponds to curr_tx_buf_size member of mlan_adapter*/
+ t_u32 curr_tx_buf_size;
+ /** Tx table num */
+ t_u32 tx_tbl_num;
+ /** Tx ba stream table */
+ tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED];
+ /** Rx table num */
+ t_u32 rx_tbl_num;
+ /** Rx reorder table*/
+ rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED];
+ /** ralist num */
+ t_u32 ralist_num;
+ /** ralist info */
+ ralist_info ralist[MLAN_MAX_RALIST_NUM];
+ /** Corresponds to ps_mode member of mlan_adapter */
+ t_u16 ps_mode;
+ /** Corresponds to ps_state member of mlan_adapter */
+ t_u32 ps_state;
+#ifdef STA_SUPPORT
+ /** Corresponds to is_deep_sleep member of mlan_adapter */
+ t_u8 is_deep_sleep;
+#endif /** STA_SUPPORT */
+ /** Corresponds to pm_wakeup_card_req member of mlan_adapter */
+ t_u8 pm_wakeup_card_req;
+ /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */
+ t_u32 pm_wakeup_fw_try;
+ /** time stamp when host try to wake up firmware */
+ t_u32 pm_wakeup_in_secs;
+ /** wake up timeout happened */
+ t_u32 pm_wakeup_timeout;
+ /** Corresponds to is_hs_configured member of mlan_adapter */
+ t_u8 is_hs_configured;
+ /** Corresponds to hs_activated member of mlan_adapter */
+ t_u8 hs_activated;
+ /** Corresponds to pps_uapsd_mode member of mlan_adapter */
+ t_u16 pps_uapsd_mode;
+ /** Corresponds to sleep_period.period member of mlan_adapter */
+ t_u16 sleep_pd;
+ /** Corresponds to wmm_qosinfo member of mlan_private */
+ t_u8 qos_cfg;
+ /** Corresponds to tx_lock_flag member of mlan_adapter */
+ t_u8 tx_lock_flag;
+ /** Corresponds to port_open member of mlan_private */
+ t_u8 port_open;
+ /** bypass pkt count */
+ t_u16 bypass_pkt_count;
+ /** Corresponds to scan_processing member of mlan_adapter */
+ t_u32 scan_processing;
+ /** Corresponds to mlan_processing member of mlan_adapter */
+ t_u32 mlan_processing;
+ /** Corresponds to main_lock_flag member of mlan_adapter */
+ t_u32 main_lock_flag;
+ /** Corresponds to main_process_cnt member of mlan_adapter */
+ t_u32 main_process_cnt;
+ /** Corresponds to delay_task_flag member of mlan_adapter */
+ t_u32 delay_task_flag;
+ /** mlan_rx_processing */
+ t_u32 mlan_rx_processing;
+ /** rx pkts queued */
+ t_u32 rx_pkts_queued;
+ /** Number of host to card command failures */
+ t_u32 num_cmd_host_to_card_failure;
+ /** Number of host to card sleep confirm failures */
+ t_u32 num_cmd_sleep_cfm_host_to_card_failure;
+ /** Number of host to card Tx failures */
+ t_u32 num_tx_host_to_card_failure;
+ /** Number of allocate buffer failure */
+ t_u32 num_alloc_buffer_failure;
+ /** Number of pkt dropped */
+ t_u32 num_pkt_dropped;
+#ifdef SDIO
+ /** Number of card to host command/event failures */
+ t_u32 num_cmdevt_card_to_host_failure;
+ /** Number of card to host Rx failures */
+ t_u32 num_rx_card_to_host_failure;
+ /** Number of interrupt read failures */
+ t_u32 num_int_read_failure;
+ /** Last interrupt status */
+ t_u32 last_int_status;
+ /** number of interrupt receive */
+ t_u32 num_of_irq;
+ /** flag for sdio rx aggr */
+ t_u8 sdio_rx_aggr;
+ /** FW update port number */
+ t_u32 mp_update[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX * 2];
+ /** Invalid port update count */
+ t_u32 mp_invalid_update;
+ /** Number of packets tx aggr */
+ t_u32 mpa_tx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** no more packets count*/
+ t_u32 mpa_sent_last_pkt;
+ /** no write_ports count */
+ t_u32 mpa_sent_no_ports;
+ /** last recv wr_bitmap */
+ t_u32 last_recv_wr_bitmap;
+ /** last mp_wr_bitmap */
+ t_u32 last_mp_wr_bitmap[SDIO_MP_DBG_NUM];
+ /** last ports for cmd53 write data */
+ t_u32 last_mp_wr_ports[SDIO_MP_DBG_NUM];
+ /** last len for cmd53 write data */
+ t_u32 last_mp_wr_len[SDIO_MP_DBG_NUM];
+ /** last curr_wr_port */
+ t_u8 last_curr_wr_port[SDIO_MP_DBG_NUM];
+ /** length info for cmd53 write data */
+ t_u16 last_mp_wr_info[SDIO_MP_DBG_NUM * SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** last mp_index */
+ t_u8 last_mp_index;
+ /** buffer for mp debug */
+ t_u8 *mpa_buf;
+ /** length info for mp buf size */
+ t_u32 mpa_buf_size;
+ /** Number of packets rx aggr */
+ t_u32 mpa_rx_count[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ /** mp aggr_pkt limit */
+ t_u8 mp_aggr_pkt_limit;
+#endif
+ /** Number of deauthentication events */
+ t_u32 num_event_deauth;
+ /** Number of disassosiation events */
+ t_u32 num_event_disassoc;
+ /** Number of link lost events */
+ t_u32 num_event_link_lost;
+ /** Number of deauthentication commands */
+ t_u32 num_cmd_deauth;
+ /** Number of association comamnd successes */
+ t_u32 num_cmd_assoc_success;
+ /** Number of association command failures */
+ t_u32 num_cmd_assoc_failure;
+ /** Number of consecutive association failures */
+ t_u32 num_cons_assoc_failure;
+
+ /** Number of command timeouts */
+ t_u32 num_cmd_timeout;
+ /** Timeout command ID */
+ t_u16 timeout_cmd_id;
+ /** Timeout command action */
+ t_u16 timeout_cmd_act;
+ /** List of last command IDs */
+ t_u16 last_cmd_id[DBG_CMD_NUM];
+ /** List of last command actions */
+ t_u16 last_cmd_act[DBG_CMD_NUM];
+ /** Last command index */
+ t_u16 last_cmd_index;
+ /** List of last command response IDs */
+ t_u16 last_cmd_resp_id[DBG_CMD_NUM];
+ /** Last command response index */
+ t_u16 last_cmd_resp_index;
+ /** List of last events */
+ t_u16 last_event[DBG_CMD_NUM];
+ /** Last event index */
+ t_u16 last_event_index;
+ /** Number of no free command node */
+ t_u16 num_no_cmd_node;
+ /** pending command id */
+ t_u16 pending_cmd;
+ /** time stamp for dnld last cmd */
+ t_u32 dnld_cmd_in_secs;
+ /** Corresponds to data_sent member of mlan_adapter */
+ t_u8 data_sent;
+ /** Corresponds to cmd_sent member of mlan_adapter */
+ t_u8 cmd_sent;
+ /** SDIO multiple port read bitmap */
+ t_u32 mp_rd_bitmap;
+ /** SDIO multiple port write bitmap */
+ t_u32 mp_wr_bitmap;
+ /** Current available port for read */
+ t_u8 curr_rd_port;
+ /** Current available port for write */
+ t_u8 curr_wr_port;
+#ifdef PCIE
+ /** PCIE txbd read pointer */
+ t_u32 txbd_rdptr;
+ /** PCIE txbd write pointer */
+ t_u32 txbd_wrptr;
+ /** PCIE rxbd read pointer */
+ t_u32 rxbd_rdptr;
+ /** PCIE rxbd write pointer */
+ t_u32 rxbd_wrptr;
+ /** PCIE eventbd read pointer */
+ t_u32 eventbd_rdptr;
+ /** PCIE eventbd write pointer */
+ t_u32 eventbd_wrptr;
+ /** Last pkt size in transmit */
+ t_u32 last_tx_pkt_size[MLAN_MAX_TXRX_BD];
+ /** txbd ring vbase */
+ t_u8 *txbd_ring_vbase;
+ /** txbd ring size */
+ t_u32 txbd_ring_size;
+ /** rxbd ring vbase */
+ t_u8 *rxbd_ring_vbase;
+ /** rxbd ring size */
+ t_u32 rxbd_ring_size;
+ /** evtbd ring vbase */
+ t_u8 *evtbd_ring_vbase;
+ /** evtbd ring size */
+ t_u32 evtbd_ring_size;
+#endif
+ /** Corresponds to cmdresp_received member of mlan_adapter */
+ t_u8 cmd_resp_received;
+ /** Corresponds to event_received member of mlan_adapter */
+ t_u8 event_received;
+ /** pendig tx pkts */
+ t_u32 tx_pkts_queued;
+#ifdef UAP_SUPPORT
+ /** pending bridge pkts */
+ t_u16 num_bridge_pkts;
+ /** dropped pkts */
+ t_u32 num_drop_pkts;
+#endif
+ /** FW hang report */
+ t_u8 fw_hang_report;
+ /** mlan_adapter pointer */
+ t_void *mlan_adapter;
+ /** mlan_adapter_size */
+ t_u32 mlan_adapter_size;
+ /** mlan_priv vector */
+ t_void *mlan_priv[MLAN_MAX_BSS_NUM];
+ /** mlan_priv_size */
+ t_u32 mlan_priv_size[MLAN_MAX_BSS_NUM];
+ /** mlan_priv_num */
+ t_u8 mlan_priv_num;
+} mlan_debug_info, *pmlan_debug_info;
+
+#ifdef UAP_SUPPORT
+/** Maximum number of clients supported by AP */
+#define MAX_NUM_CLIENTS MAX_STA_COUNT
+
+/** station info */
+typedef struct _sta_info {
+ /** STA MAC address */
+ t_u8 mac_address[MLAN_MAC_ADDR_LENGTH];
+ /** Power mgmt status */
+ t_u8 power_mgmt_status;
+ /** RSSI */
+ t_s8 rssi;
+ /** station bandmode */
+ t_u16 bandmode;
+ /** station stats */
+ sta_stats stats;
+ /** ie length */
+ t_u16 ie_len;
+ /** ie buffer */
+ t_u8 ie_buf[];
+} sta_info;
+
+/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */
+typedef struct _mlan_ds_sta_list {
+ /** station count */
+ t_u16 sta_count;
+ /** station list */
+ sta_info info[MAX_NUM_CLIENTS];
+} mlan_ds_sta_list, *pmlan_ds_sta_list;
+#endif
+
+/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */
+typedef struct _mlan_ds_get_info {
+ /** Sub-command */
+ t_u32 sub_command;
+
+ /** Status information parameter */
+ union {
+ /** Signal information for MLAN_OID_GET_SIGNAL */
+ mlan_ds_get_signal signal;
+ /** Signal path id for MLAN_OID_GET_SIGNAL_EXT */
+ t_u16 path_id;
+ /** Signal information for MLAN_OID_GET_SIGNAL_EXT */
+ mlan_ds_get_signal signal_ext[MAX_PATH_NUM];
+ /** Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_get_stats stats;
+ /** Statistics information for MLAN_OID_LINK_STATS*/
+ t_u8 link_statistic[1];
+ /** Firmware information for MLAN_OID_GET_FW_INFO */
+ mlan_fw_info fw_info;
+ /** Extended version information for MLAN_OID_GET_VER_EXT */
+ mlan_ver_ext ver_ext;
+ /** BSS information for MLAN_OID_GET_BSS_INFO */
+ mlan_bss_info bss_info;
+ /** Debug information for MLAN_OID_GET_DEBUG_INFO */
+ t_u8 debug_info[1];
+#ifdef UAP_SUPPORT
+ /** UAP Statistics information for MLAN_OID_GET_STATS */
+ mlan_ds_uap_stats ustats;
+ /** UAP station list for MLAN_OID_UAP_STA_LIST */
+ mlan_ds_sta_list sta_list;
+#endif
+ } param;
+} mlan_ds_get_info, *pmlan_ds_get_info;
+
+/*-----------------------------------------------------------------*/
+/** Security Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for authentication mode */
+enum _mlan_auth_mode {
+ MLAN_AUTH_MODE_OPEN = 0x00,
+ MLAN_AUTH_MODE_SHARED = 0x01,
+ MLAN_AUTH_MODE_FT = 0x02,
+ MLAN_AUTH_MODE_SAE = 0x03,
+ MLAN_AUTH_MODE_NETWORKEAP = 0x80,
+ MLAN_AUTH_MODE_AUTO = 0xFF,
+};
+
+/**Enumeration for AssocAgent authentication mode, sync from FW.*/
+typedef enum {
+ AssocAgentAuth_Open,
+ AssocAgentAuth_Shared,
+ AssocAgentAuth_FastBss,
+ AssocAgentAuth_FastBss_Skip,
+ AssocAgentAuth_Network_EAP,
+ AssocAgentAuth_Wpa3Sae,
+ AssocAgentAuth_Auto,
+} AssocAgentAuthType_e;
+
+/** Enumeration for encryption mode */
+enum _mlan_encryption_mode {
+ MLAN_ENCRYPTION_MODE_NONE = 0,
+ MLAN_ENCRYPTION_MODE_WEP40 = 1,
+ MLAN_ENCRYPTION_MODE_TKIP = 2,
+ MLAN_ENCRYPTION_MODE_CCMP = 3,
+ MLAN_ENCRYPTION_MODE_WEP104 = 4,
+ MLAN_ENCRYPTION_MODE_GCMP = 5,
+ MLAN_ENCRYPTION_MODE_GCMP_256 = 6,
+ MLAN_ENCRYPTION_MODE_CCMP_256 = 7,
+};
+
+/** Enumeration for PSK */
+enum _mlan_psk_type {
+ MLAN_PSK_PASSPHRASE = 1,
+ MLAN_PSK_PMK,
+ MLAN_PSK_CLEAR,
+ MLAN_PSK_QUERY,
+ MLAN_PSK_SAE_PASSWORD,
+};
+
+/** The bit to indicate the key is for unicast */
+#define MLAN_KEY_INDEX_UNICAST 0x40000000
+/** The key index to indicate default key */
+#define MLAN_KEY_INDEX_DEFAULT 0x000000ff
+/** Maximum key length */
+/* #define MLAN_MAX_KEY_LENGTH 32 */
+/** Minimum passphrase length */
+#define MLAN_MIN_PASSPHRASE_LENGTH 8
+/** Maximum passphrase length */
+#define MLAN_MAX_PASSPHRASE_LENGTH 63
+/** Minimum sae_password length */
+#define MLAN_MIN_SAE_PASSWORD_LENGTH 8
+/** Maximum sae_password length */
+#define MLAN_MAX_SAE_PASSWORD_LENGTH 255
+/** PMK length */
+#define MLAN_PMK_HEXSTR_LENGTH 64
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE 13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE 5
+/** packet number size */
+#define PN_SIZE 16
+/** max seq size of wpa/wpa2 key */
+#define SEQ_MAX_SIZE 8
+
+/** key flag for tx_seq */
+#define KEY_FLAG_TX_SEQ_VALID 0x00000001
+/** key flag for rx_seq */
+#define KEY_FLAG_RX_SEQ_VALID 0x00000002
+/** key flag for group key */
+#define KEY_FLAG_GROUP_KEY 0x00000004
+/** key flag for tx */
+#define KEY_FLAG_SET_TX_KEY 0x00000008
+/** key flag for mcast IGTK */
+#define KEY_FLAG_AES_MCAST_IGTK 0x00000010
+/** key flag for remove key */
+#define KEY_FLAG_REMOVE_KEY 0x80000000
+/** key flag for GCMP */
+#define KEY_FLAG_GCMP 0x00000020
+/** key flag for GCMP_256 */
+#define KEY_FLAG_GCMP_256 0x00000040
+/** key flag for ccmp 256 */
+#define KEY_FLAG_CCMP_256 0x00000080
+
+/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+typedef struct _mlan_ds_encrypt_key {
+ /** Key disabled, all other fields will be
+ * ignore when this flag set to MTRUE
+ */
+ t_u32 key_disable;
+ /** key removed flag, when this flag is set
+ * to MTRUE, only key_index will be check
+ */
+ t_u32 key_remove;
+ /** Key index, used as current tx key index
+ * when is_current_wep_key is set to MTRUE
+ */
+ t_u32 key_index;
+ /** Current Tx key flag */
+ t_u32 is_current_wep_key;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** wapi key flag */
+ t_u32 is_wapi_key;
+ /** Initial packet number */
+ t_u8 pn[PN_SIZE];
+ /** key flags */
+ t_u32 key_flags;
+} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key;
+
+/** Type definition of mlan_passphrase_t */
+typedef struct _mlan_passphrase_t {
+ /** Length of passphrase */
+ t_u32 passphrase_len;
+ /** Passphrase */
+ t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH];
+} mlan_passphrase_t;
+
+/** Type definition of mlan_sae_password_t */
+typedef struct _mlan_sae_password_t {
+ /** Length of SAE Password */
+ t_u32 sae_password_len;
+ /** SAE Password */
+ t_u8 sae_password[MLAN_MAX_SAE_PASSWORD_LENGTH];
+} mlan_sae_password_t;
+
+/** Type defnition of mlan_pmk_t */
+typedef struct _mlan_pmk_t {
+ /** PMK */
+ t_u8 pmk[MLAN_MAX_KEY_LENGTH];
+} mlan_pmk_t;
+
+/** Embedded supplicant RSN type: No RSN */
+#define RSN_TYPE_NO_RSN MBIT(0)
+/** Embedded supplicant RSN type: WPA */
+#define RSN_TYPE_WPA MBIT(3)
+/** Embedded supplicant RSN type: WPA-NONE */
+#define RSN_TYPE_WPANONE MBIT(4)
+/** Embedded supplicant RSN type: WPA2 */
+#define RSN_TYPE_WPA2 MBIT(5)
+/** Embedded supplicant RSN type: RFU */
+#define RSN_TYPE_VALID_BITS \
+ (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2)
+
+/** Embedded supplicant cipher type: TKIP */
+#define EMBED_CIPHER_TKIP MBIT(2)
+/** Embedded supplicant cipher type: AES */
+#define EMBED_CIPHER_AES MBIT(3)
+/** Embedded supplicant cipher type: RFU */
+#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES)
+
+/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+typedef struct _mlan_ds_passphrase {
+ /** SSID may be used */
+ mlan_802_11_ssid ssid;
+ /** BSSID may be used */
+ mlan_802_11_mac_addr bssid;
+ /** Flag for passphrase or pmk used */
+ t_u16 psk_type;
+ /** Passphrase or PMK */
+ union {
+ /** Passphrase */
+ mlan_passphrase_t passphrase;
+ /** SAE Password */
+ mlan_sae_password_t sae_password;
+ /** PMK */
+ mlan_pmk_t pmk;
+ } psk;
+} mlan_ds_passphrase, *pmlan_ds_passphrase;
+
+/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+typedef struct _mlan_ds_ewpa_mode {
+ /** RSN mode */
+ t_u32 rsn_mode;
+ /** Active pairwise cipher */
+ t_u32 act_paircipher;
+ /** Active pairwise cipher */
+ t_u32 act_groupcipher;
+} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode;
+
+/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */
+typedef struct _mlan_ds_sec_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Security configuration parameter */
+ union {
+ /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */
+ t_u32 auth_mode;
+ /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */
+ t_u32 encrypt_mode;
+ /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */
+ t_u32 wpa_enabled;
+ /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */
+ t_u32 wapi_enabled;
+ /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */
+ t_u32 port_ctrl_enabled;
+ /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */
+ mlan_ds_encrypt_key encrypt_key;
+ /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */
+ mlan_ds_passphrase passphrase;
+ /** Embedded supplicant WPA enabled flag for
+ * MLAN_OID_SEC_CFG_EWPA_ENABLED
+ */
+ t_u32 ewpa_enabled;
+ /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */
+ mlan_ds_esupp_mode esupp_mode;
+#ifdef UAP_SUPPORT
+ t_u8 sta_mac[MLAN_MAC_ADDR_LENGTH];
+#endif
+ } param;
+} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg;
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+#define BIT_TLV_TYPE_CRYPTO_KEY (1 << 0)
+#define BIT_TLV_TYPE_CRYPTO_KEY_IV (1 << 1)
+#define BIT_TLV_TYPE_CRYPTO_KEY_PREFIX (1 << 2)
+#define BIT_TLV_TYPE_CRYPTO_KEY_DATA_BLK (1 << 3)
+
+/** Type definition of mlan_ds_sup_cfg */
+typedef struct _mlan_ds_sup_cfg {
+ /** Sub-command */
+ t_u8 sub_command;
+ /** output length */
+ t_u16 output_len;
+ /** number of data blks */
+ t_u16 data_blks_nr;
+ /** sub action code */
+ t_u8 sub_action_code;
+ /** skip bytes */
+ t_u16 skip_bytes;
+ /** iteration */
+ t_u32 iteration;
+ /** count */
+ t_u32 count;
+ /** pointer to output */
+ t_u8 *output;
+ /** key length */
+ t_u16 key_len;
+ /** pointer to key */
+ t_u8 *key;
+ /** key iv length */
+ t_u16 key_iv_len;
+ /** pointer to key iv */
+ t_u8 *key_iv;
+ /** key prefix length */
+ t_u16 key_prefix_len;
+ /** pointer to key prefix */
+ t_u8 *key_prefix;
+ /** pointer to data blk length array */
+ t_u32 *key_data_blk_len;
+ /** pointer to key data blk pointer array */
+ t_u8 **key_data_blk;
+ /** callback */
+ t_u8 call_back;
+} mlan_ds_sup_cfg, *pmlan_ds_sup_cfg;
+#endif
+
+/*-----------------------------------------------------------------*/
+/** Rate Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for rate type */
+enum _mlan_rate_type { MLAN_RATE_INDEX, MLAN_RATE_VALUE, MLAN_RATE_BITMAP };
+
+/** Enumeration for rate format */
+enum _mlan_rate_format {
+ MLAN_RATE_FORMAT_LG = 0,
+ MLAN_RATE_FORMAT_HT,
+ MLAN_RATE_FORMAT_VHT,
+ MLAN_RATE_FORMAT_HE,
+ MLAN_RATE_FORMAT_AUTO = 0xFF,
+};
+
+/** Max bitmap rates size */
+#define MAX_BITMAP_RATES_SIZE 26
+
+/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */
+typedef struct _mlan_rate_cfg_t {
+ /** Fixed rate: 0, auto rate: 1 */
+ t_u32 is_rate_auto;
+ /** Rate type. 0: index; 1: value; 2: bitmap */
+ t_u32 rate_type;
+ /** Rate/MCS index or rate value if fixed rate */
+ t_u32 rate;
+ /** Rate Bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** NSS */
+ t_u32 nss;
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 rate_format;
+ /** Rate Setting */
+ t_u16 rate_setting;
+} mlan_rate_cfg_t;
+
+/** HT channel bandwidth */
+typedef enum _mlan_ht_bw {
+ MLAN_HT_BW20,
+ MLAN_HT_BW40,
+ /** VHT channel bandwidth */
+ MLAN_VHT_BW80,
+ MLAN_VHT_BW160,
+} mlan_ht_bw;
+
+/** HT guard interval */
+typedef enum _mlan_ht_gi {
+ MLAN_HT_LGI,
+ MLAN_HT_SGI,
+} mlan_ht_gi;
+
+typedef enum _mlan_vht_stbc {
+ MLAN_VHT_STBC,
+ MLAN_VHT_NO_STBC,
+} mlan_vht_stbc;
+
+typedef enum _mlan_vht_ldpc {
+ MLAN_VHT_LDPC,
+ MLAN_VHT_NO_LDPC,
+} mlan_vht_ldpc;
+
+/** Band and BSS mode */
+typedef struct _mlan_band_data_rate {
+ /** Band configuration */
+ t_u8 config_bands;
+ /** BSS mode (Infra or IBSS) */
+ t_u8 bss_mode;
+} mlan_band_data_rate;
+
+/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */
+typedef struct _mlan_data_rate {
+ /** Tx data rate */
+ t_u32 tx_data_rate;
+ /** Rx data rate */
+ t_u32 rx_data_rate;
+
+ /** Tx channel bandwidth */
+ t_u32 tx_ht_bw;
+ /** Tx guard interval */
+ t_u32 tx_ht_gi;
+ /** Rx channel bandwidth */
+ t_u32 rx_ht_bw;
+ /** Rx guard interval */
+ t_u32 rx_ht_gi;
+ /** MCS index */
+ t_u32 tx_mcs_index;
+ t_u32 rx_mcs_index;
+ /** NSS */
+ t_u32 tx_nss;
+ t_u32 rx_nss;
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 tx_rate_format;
+ t_u32 rx_rate_format;
+} mlan_data_rate;
+
+/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */
+typedef struct _mlan_ds_rate {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Rate configuration parameter */
+ union {
+ /** Rate configuration for MLAN_OID_RATE_CFG */
+ mlan_rate_cfg_t rate_cfg;
+ /** Data rate for MLAN_OID_GET_DATA_RATE */
+ mlan_data_rate data_rate;
+ /** Supported rates for MLAN_OID_SUPPORTED_RATES */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+ /** Band/BSS mode for getting supported rates */
+ mlan_band_data_rate rate_band_cfg;
+ } param;
+} mlan_ds_rate, *pmlan_ds_rate;
+
+/*-----------------------------------------------------------------*/
+/** Power Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */
+typedef struct _mlan_power_cfg_t {
+ /** Is power auto */
+ t_u32 is_power_auto;
+ /** Power level in dBm */
+ t_s32 power_level;
+} mlan_power_cfg_t;
+
+/** max power table size */
+#define MAX_POWER_TABLE_SIZE 128
+#define TX_PWR_CFG_AUTO_CTRL_OFF 0xFF
+#define MAX_POWER_GROUP 64
+/** Type definition of mlan_power group info */
+typedef struct mlan_power_group {
+ /** rate format (LG: 0, HT: 1, VHT: 2, no auto ctrl: 0xFF) */
+ t_u32 rate_format;
+ /** bandwidth (LG: 20 MHz, HT: 20/40 MHz, VHT: 80/160/80+80 MHz) */
+ t_u8 bandwidth;
+ /** NSS */
+ t_u32 nss;
+ /** LG: first rate index, HT/VHT: first MCS */
+ t_u8 first_rate_ind;
+ /** LG: last rate index, HT/VHT: last MCS */
+ t_u8 last_rate_ind;
+ /** minmum tx power (dBm) */
+ t_s8 power_min;
+ /** maximum tx power (dBm) */
+ t_s8 power_max;
+ /** tx power step (dB) */
+ t_s8 power_step;
+} mlan_power_group;
+
+/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */
+typedef struct _mlan_power_cfg_ext {
+ /** number of power_groups */
+ t_u32 num_pwr_grp;
+ /** array of power groups */
+ mlan_power_group power_group[MAX_POWER_GROUP];
+} mlan_power_cfg_ext;
+
+/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_power_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power configuration parameter */
+ union {
+ /** Power configuration for MLAN_OID_POWER_CFG */
+ mlan_power_cfg_t power_cfg;
+ /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */
+ mlan_power_cfg_ext power_ext;
+ /** Low power mode for MLAN_OID_POWER_LOW_POWER_MODE */
+ t_u16 lpm;
+ } param;
+} mlan_ds_power_cfg, *pmlan_ds_power_cfg;
+
+/** Type definition of mlan_ds_band_steer_cfg for MLAN_IOCTL_POWER_CFG */
+typedef struct _mlan_ds_band_steer_cfg {
+ /** Set/Get */
+ t_u8 action;
+ /** enable/disable band steering*/
+ t_u8 state;
+ /** Probe Response will be blocked to 2G channel for first
+ * block_2g_prb_req probe requests*/
+ t_u8 block_2g_prb_req;
+ /** When band steering is enabled, limit the btm request sent to STA at
+ * <max_btm_req_allowed>*/
+ t_u8 max_btm_req_allowed;
+} mlan_ds_band_steer_cfg, *pmlan_ds_band_steer_cfg;
+
+/** Type definition of mlan_ds_beacon_stuck_param_cfg for MLAN_IOCTL_POWER_CFG
+ */
+typedef struct _mlan_ds_beacon_stuck_param_cfg {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u8 action;
+ /** No of beacon interval after which firmware will check if beacon Tx
+ * is going fine */
+ t_u8 beacon_stuck_detect_count;
+ /** Upon performing MAC reset, no of beacon interval after which
+ * firmware will check if recovery was successful */
+ t_u8 recovery_confirm_count;
+} mlan_ds_beacon_stuck_param_cfg, *pmlan_ds_beacon_stuck_param_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Power Management Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Host sleep config conditions : Cancel */
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+
+/** Host sleep config condition: broadcast data */
+#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0)
+/** Host sleep config condition: unicast data */
+#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1)
+/** Host sleep config condition: mac event */
+#define HOST_SLEEP_COND_MAC_EVENT MBIT(2)
+/** Host sleep config condition: multicast data */
+#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3)
+/** Host sleep config condition: IPV6 packet */
+#define HOST_SLEEP_COND_IPV6_PACKET MBIT(31)
+
+/** Host sleep config conditions: Default */
+#define HOST_SLEEP_DEF_COND 0
+
+/** Host sleep config GPIO : Default */
+#define HOST_SLEEP_DEF_GPIO 0xff
+/** Host sleep config gap : Default */
+#define HOST_SLEEP_DEF_GAP 200
+/** Host sleep config min wake holdoff */
+#define HOST_SLEEP_DEF_WAKE_HOLDOFF 0;
+/** Host sleep config inactivity timeout */
+#define HOST_SLEEP_DEF_INACTIVITY_TIMEOUT 10;
+
+/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */
+typedef struct _mlan_ds_hs_cfg {
+ /** MTRUE to invoke the HostCmd, MFALSE otherwise */
+ t_u32 is_invoke_hostcmd;
+ /** Host sleep config condition */
+ /** Bit0: broadcast data
+ * Bit1: unicast data
+ * Bit2: mac event
+ * Bit3: multicast data
+ */
+ t_u32 conditions;
+ /** GPIO pin or 0xff for interface */
+ t_u32 gpio;
+ /** Gap in milliseconds or or 0xff for special
+ * setting when GPIO is used to wakeup host
+ */
+ t_u32 gap;
+ /** Host sleep wake interval */
+ t_u32 hs_wake_interval;
+ /** Parameter type for indication gpio*/
+ t_u8 param_type_ind;
+ /** GPIO pin for indication wakeup source */
+ t_u32 ind_gpio;
+ /** Level on ind_gpio pin for indication normal wakeup source */
+ t_u32 level;
+ /** Parameter type for extend hscfg*/
+ t_u8 param_type_ext;
+ /** Events that will be forced ignore*/
+ t_u32 event_force_ignore;
+ /** Events that will use extend gap to inform host*/
+ t_u32 event_use_ext_gap;
+ /** Ext gap*/
+ t_u8 ext_gap;
+ /** GPIO wave level for extend hscfg*/
+ t_u8 gpio_wave;
+} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg;
+
+#define MAX_MGMT_FRAME_FILTER 2
+typedef struct _mlan_mgmt_frame_wakeup {
+ /** action - bitmap
+ ** On matching rx'd pkt and filter during NON_HOSTSLEEP mode:
+ ** Action[1]=0 Discard
+ ** Action[1]=1 Allow
+ ** Note that default action on non-match is "Allow".
+ **
+ ** On matching rx'd pkt and filter during HOSTSLEEP mode:
+ ** Action[1:0]=00 Discard and Not Wake host
+ ** Action[1:0]=01 Discard and Wake host
+ ** Action[1:0]=10 Invalid
+ ** Note that default action on non-match is "Discard and Not Wake
+ *host".
+ **/
+ t_u32 action;
+ /** Frame type(p2p, tdls...)
+ ** type=0: invalid
+ ** type=1: p2p
+ ** type=others: reserved
+ **/
+ t_u32 type;
+ /** Frame mask according to each type
+ ** When type=1 for p2p, frame-mask have following define:
+ ** Bit Frame
+ ** 0 GO Negotiation Request
+ ** 1 GO Negotiation Response
+ ** 2 GO Negotiation Confirmation
+ ** 3 P2P Invitation Request
+ ** 4 P2P Invitation Response
+ ** 5 Device Discoverability Request
+ ** 6 Device Discoverability Response
+ ** 7 Provision Discovery Request
+ ** 8 Provision Discovery Response
+ ** 9 Notice of Absence
+ ** 10 P2P Presence Request
+ ** 11 P2P Presence Response
+ ** 12 GO Discoverability Request
+ ** 13-31 Reserved
+ **
+ ** When type=others, frame-mask is reserved.
+ **/
+ t_u32 frame_mask;
+} mlan_mgmt_frame_wakeup, *pmlan_mgmt_frame_wakeup;
+
+/** Enable deep sleep mode */
+#define DEEP_SLEEP_ON 1
+/** Disable deep sleep mode */
+#define DEEP_SLEEP_OFF 0
+
+/** Default idle time in milliseconds for auto deep sleep */
+#define DEEP_SLEEP_IDLE_TIME 100
+
+typedef struct _mlan_ds_auto_ds {
+ /** auto ds mode, 0 - disable, 1 - enable */
+ t_u16 auto_ds;
+ /** auto ds idle time in milliseconds */
+ t_u16 idletime;
+} mlan_ds_auto_ds;
+
+/** Type definition of mlan_ds_inactivity_to
+ * for MLAN_OID_PM_CFG_INACTIVITY_TO
+ */
+typedef struct _mlan_ds_inactivity_to {
+ /** Timeout unit in microsecond, 0 means 1000us (1ms) */
+ t_u32 timeout_unit;
+ /** Inactivity timeout for unicast data */
+ t_u32 unicast_timeout;
+ /** Inactivity timeout for multicast data */
+ t_u32 mcast_timeout;
+ /** Timeout for additional Rx traffic after Null PM1 packet exchange */
+ t_u32 ps_entry_timeout;
+} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to;
+
+/** Minimum sleep period in milliseconds */
+#define MIN_SLEEP_PERIOD 10
+/** Maximum sleep period in milliseconds */
+#define MAX_SLEEP_PERIOD 60
+/** Special setting for UPSD certification tests */
+#define SLEEP_PERIOD_RESERVED_FF 0xFF
+
+/** PS null interval disable */
+#define PS_NULL_DISABLE (-1)
+
+/** Local listen interval disable */
+#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1)
+/** Minimum listen interval */
+#define MRVDRV_MIN_LISTEN_INTERVAL 0
+
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM 0
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+/** Match listen interval to closest DTIM */
+#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd
+
+/** Minimum beacon miss timeout in milliseconds */
+#define MIN_BCN_MISS_TO 0
+/** Maximum beacon miss timeout in milliseconds */
+#define MAX_BCN_MISS_TO 50
+/** Disable beacon miss timeout */
+#define DISABLE_BCN_MISS_TO 65535
+
+/** Minimum delay to PS in milliseconds */
+#define MIN_DELAY_TO_PS 0
+/** Maximum delay to PS in milliseconds */
+#define MAX_DELAY_TO_PS 65535
+/** Delay to PS unchanged */
+#define DELAY_TO_PS_UNCHANGED (-1)
+/** Default delay to PS in milliseconds */
+#define DELAY_TO_PS_DEFAULT 1000
+
+/** PS mode: Unchanged */
+#define PS_MODE_UNCHANGED 0
+/** PS mode: Auto */
+#define PS_MODE_AUTO 1
+/** PS mode: Poll */
+#define PS_MODE_POLL 2
+/** PS mode: Null */
+#define PS_MODE_NULL 3
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_ps_cfg {
+ /** PS null interval in seconds */
+ t_u32 ps_null_interval;
+ /** Multiple DTIM interval */
+ t_u32 multiple_dtim_interval;
+ /** Listen interval */
+ t_u32 listen_interval;
+ /** Beacon miss timeout in milliseconds */
+ t_u32 bcn_miss_timeout;
+ /** Delay to PS in milliseconds */
+ t_s32 delay_to_ps;
+ /** PS mode */
+ t_u32 ps_mode;
+} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg;
+
+/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */
+typedef struct _mlan_ds_sleep_params {
+ /** Error */
+ t_u32 error;
+ /** Offset in microseconds */
+ t_u32 offset;
+ /** Stable time in microseconds */
+ t_u32 stable_time;
+ /** Calibration control */
+ t_u32 cal_control;
+ /** External sleep clock */
+ t_u32 ext_sleep_clk;
+ /** Reserved */
+ t_u32 reserved;
+} mlan_ds_sleep_params, *pmlan_ds_sleep_params;
+
+/** sleep_param */
+typedef struct _ps_sleep_param {
+ /** control bitmap */
+ t_u32 ctrl_bitmap;
+ /** minimum sleep period (micro second) */
+ t_u32 min_sleep;
+ /** maximum sleep period (micro second) */
+ t_u32 max_sleep;
+} ps_sleep_param;
+
+/** inactivity sleep_param */
+typedef struct _inact_sleep_param {
+ /** inactivity timeout (micro second) */
+ t_u32 inactivity_to;
+ /** miniumu awake period (micro second) */
+ t_u32 min_awake;
+ /** maximum awake period (micro second) */
+ t_u32 max_awake;
+} inact_sleep_param;
+
+/** flag for ps mode */
+#define PS_FLAG_PS_MODE 1
+/** flag for sleep param */
+#define PS_FLAG_SLEEP_PARAM 2
+/** flag for inactivity sleep param */
+#define PS_FLAG_INACT_SLEEP_PARAM 4
+
+/** Enable Robust Coex mode */
+#define ROBUSTCOEX_GPIOCFG_ENABLE 1
+/** Disable Robust Coex mode */
+#define ROBUSTCOEX_GPIOCFG_DISABLE 0
+
+/** Disable power mode */
+#define PS_MODE_DISABLE 0
+/** Enable periodic dtim ps */
+#define PS_MODE_PERIODIC_DTIM 1
+/** Enable inactivity ps */
+#define PS_MODE_INACTIVITY 2
+/** FW wake up method interface */
+#define FW_WAKEUP_METHOD_INTERFACE 1
+/** FW wake up method gpio */
+#define FW_WAKEUP_METHOD_GPIO 2
+/** mlan_ds_ps_mgmt */
+typedef struct _mlan_ds_ps_mgmt {
+ /** flags for valid field */
+ t_u16 flags;
+ /** power mode */
+ t_u16 ps_mode;
+ /** sleep param */
+ ps_sleep_param sleep_param;
+ /** inactivity sleep param */
+ inact_sleep_param inact_param;
+} mlan_ds_ps_mgmt;
+
+/** mlan_ds_ps_info */
+typedef struct _mlan_ds_ps_info {
+ /** suspend allowed flag */
+ t_u32 is_suspend_allowed;
+} mlan_ds_ps_info;
+
+/** Type definition of mlan_ds_wakeup_reason for MLAN_OID_PM_HS_WAKEUP_REASON */
+typedef struct _mlan_ds_hs_wakeup_reason {
+ t_u16 hs_wakeup_reason;
+} mlan_ds_hs_wakeup_reason;
+
+/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */
+typedef struct _mlan_ds_bcn_timeout {
+ /** Beacon miss timeout period window */
+ t_u16 bcn_miss_tmo_window;
+ /** Beacon miss timeout period */
+ t_u16 bcn_miss_tmo_period;
+ /** Beacon reacquire timeout period window */
+ t_u16 bcn_rq_tmo_window;
+ /** Beacon reacquire timeout period */
+ t_u16 bcn_rq_tmo_period;
+} mlan_ds_bcn_timeout, *pmlan_ds_bcn_timeout;
+
+/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */
+typedef struct _mlan_ds_pm_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Power management parameter */
+ union {
+ /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */
+ t_u32 ps_mode;
+ /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */
+ mlan_ds_hs_cfg hs_cfg;
+ /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */
+ mlan_ds_auto_ds auto_deep_sleep;
+ /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */
+ mlan_ds_inactivity_to inactivity_to;
+ /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */
+ t_u32 sleep_period;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */
+ mlan_ds_ps_cfg ps_cfg;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS
+ */
+ mlan_ds_sleep_params sleep_params;
+ /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */
+ mlan_ds_ps_mgmt ps_mgmt;
+ /** power info for MLAN_OID_PM_INFO */
+ mlan_ds_ps_info ps_info;
+ /** hs wakeup reason for MLAN_OID_PM_HS_WAKEUP_REASON */
+ mlan_ds_hs_wakeup_reason wakeup_reason;
+ /** config manamgement frame for hs wakeup */
+ mlan_mgmt_frame_wakeup mgmt_filter[MAX_MGMT_FRAME_FILTER];
+ /** Beacon timout parameters for MLAN_OID_PM_CFG_BCN_TIMEOUT */
+ mlan_ds_bcn_timeout bcn_timeout;
+ } param;
+} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg;
+
+#ifdef RX_PACKET_COALESCE
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 pkt_threshold; /** Packet threshold */
+ t_u16 delay; /** Timeout value in milliseconds */
+} wlan_ioctl_rx_pkt_coalesce_config_t;
+#endif
+
+/*-----------------------------------------------------------------*/
+/** WMM Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** WMM TSpec size */
+#define MLAN_WMM_TSPEC_SIZE 63
+/** WMM Add TS extra IE bytes */
+#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256
+/** WMM statistics for packets hist bins */
+#define MLAN_WMM_STATS_PKTS_HIST_BINS 7
+/** Maximum number of AC QOS queues available */
+#define MLAN_WMM_MAX_AC_QUEUES 4
+
+/**
+ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ * as any additional IEs appended in the ADDTS Action frame.
+ *
+ * @sa woal_wmm_addts_req_ioctl
+ */
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+
+ t_u32 timeout_ms; /**< Timeout value in milliseconds */
+ t_u8 ieee_status_code; /**< IEEE status code */
+
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */
+ + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/
+} wlan_ioctl_wmm_addts_req_t;
+
+/**
+ * @brief IOCTL structure to send a DELTS request.
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ * @sa woal_wmm_delts_req_ioctl
+ */
+typedef struct {
+ mlan_cmd_result_e cmd_result; /**< Firmware execution result */
+ t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */
+ t_u32 ie_data_len; /**< Length of ie block in ie_data */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */
+} wlan_ioctl_wmm_delts_req_t;
+
+/**
+ * @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * get, set, or default the WMM AC queue parameters.
+ *
+ * - msdu_lifetime_expiry is ignored if set to 0 on a set command
+ *
+ * @sa woal_wmm_queue_config_ioctl
+ */
+typedef struct {
+ mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */
+ mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */
+ t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */
+ t_u8 supported_rates[10]; /**< Not supported yet */
+} wlan_ioctl_wmm_queue_config_t;
+
+/**
+ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ * IOCTL structure from the application layer relayed to firmware to
+ * start or stop statistical collection for a given AC. Also used to
+ * retrieve and clear the collected stats on a given AC.
+ *
+ * @sa woal_wmm_queue_stats_ioctl
+ */
+typedef struct {
+ /** Action of Queue Config : Start, Stop, or Get */
+ mlan_wmm_queue_stats_action_e action;
+ /** User Priority */
+ t_u8 user_priority;
+ /** Number of successful packets transmitted */
+ t_u16 pkt_count;
+ /** Packets lost; not included in pkt_count */
+ t_u16 pkt_loss;
+ /** Average Queue delay in microseconds */
+ t_u32 avg_queue_delay;
+ /** Average Transmission delay in microseconds */
+ t_u32 avg_tx_delay;
+ /** Calculated used time in units of 32 microseconds */
+ t_u16 used_time;
+ /** Calculated policed time in units of 32 microseconds */
+ t_u16 policed_time;
+ /** Queue Delay Histogram; number of packets per queue delay range
+ *
+ * [0] - 0ms <= delay < 5ms
+ * [1] - 5ms <= delay < 10ms
+ * [2] - 10ms <= delay < 20ms
+ * [3] - 20ms <= delay < 30ms
+ * [4] - 30ms <= delay < 40ms
+ * [5] - 40ms <= delay < 50ms
+ * [6] - 50ms <= delay < msduLifetime (TUs)
+ */
+ t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS];
+} wlan_ioctl_wmm_queue_stats_t,
+ /** Type definition of mlan_ds_wmm_queue_stats
+ * for MLAN_OID_WMM_CFG_QUEUE_STATS
+ */
+ mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats;
+
+/**
+ * @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct {
+ /** WMM Acm */
+ t_u8 wmm_acm;
+ /** Flow required flag */
+ t_u8 flow_required;
+ /** Flow created flag */
+ t_u8 flow_created;
+ /** Disabled flag */
+ t_u8 disabled;
+} wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ * @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ * IOCTL structure from the application layer to retrieve:
+ * - ACM bit setting for the AC
+ * - Firmware status (flow required, flow created, flow disabled)
+ *
+ * @sa woal_wmm_queue_status_ioctl
+ */
+typedef struct {
+ /** WMM AC queue status */
+ wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES];
+} wlan_ioctl_wmm_queue_status_t,
+ /** Type definition of mlan_ds_wmm_queue_status
+ * for MLAN_OID_WMM_CFG_QUEUE_STATUS
+ */
+ mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status;
+
+/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */
+typedef struct _mlan_ds_wmm_addts {
+ /** Result of ADDTS request */
+ mlan_cmd_result_e result;
+ /** Timeout value in milliseconds */
+ t_u32 timeout;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** Dialog token */
+ t_u8 dialog_tok;
+ /** TSPEC data length */
+ t_u32 ie_data_len;
+ /** TSPEC to send in the ADDTS + buffering for any extra IEs */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES];
+} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts;
+
+/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */
+typedef struct _mlan_ds_wmm_delts {
+ /** Result of DELTS request */
+ mlan_cmd_result_e result;
+ /** IEEE status code */
+ t_u32 status_code;
+ /** TSPEC data length */
+ t_u8 ie_data_len;
+ /** TSPEC to send in the DELTS */
+ t_u8 ie_data[MLAN_WMM_TSPEC_SIZE];
+} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts;
+
+/** Type definition of mlan_ds_wmm_queue_config
+ * for MLAN_OID_WMM_CFG_QUEUE_CONFIG
+ */
+typedef struct _mlan_ds_wmm_queue_config {
+ /** Action of Queue Config : Set, Get, or Default */
+ mlan_wmm_queue_config_action_e action;
+ /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */
+ mlan_wmm_ac_e access_category;
+ /** Lifetime expiry in TUs */
+ t_u16 msdu_lifetime_expiry;
+ /** Reserve for future use */
+ t_u8 reserved[10];
+} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config;
+
+/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */
+typedef struct _mlan_ds_wmm_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WMM configuration parameter */
+ union {
+ /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */
+ t_u32 wmm_enable;
+ /** QoS configuration for MLAN_OID_WMM_CFG_QOS */
+ t_u8 qos_cfg;
+ /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */
+ mlan_ds_wmm_addts addts;
+ /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */
+ mlan_ds_wmm_delts delts;
+ /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */
+ mlan_ds_wmm_queue_config q_cfg;
+ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI,
+ * WMM_AC_VO */
+ wmm_ac_parameters_t ac_params[MAX_AC_QUEUES];
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */
+ mlan_ds_wmm_queue_stats q_stats;
+ /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */
+ mlan_ds_wmm_queue_status q_status;
+ /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */
+ mlan_ds_wmm_ts_status ts_status;
+ } param;
+} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg;
+
+/*-----------------------------------------------------------------*/
+/** WPS Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for WPS session */
+enum _mlan_wps_status {
+ MLAN_WPS_CFG_SESSION_START = 1,
+ MLAN_WPS_CFG_SESSION_END = 0
+};
+
+/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */
+typedef struct _mlan_ds_wps_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** WPS configuration parameter */
+ union {
+ /** WPS session for MLAN_OID_WPS_CFG_SESSION */
+ t_u32 wps_session;
+ } param;
+} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg;
+
+/*-----------------------------------------------------------------*/
+/** 802.11n Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum MCS */
+#define NUM_MCS_FIELD 16
+
+/** Supported stream modes */
+#define HT_STREAM_MODE_1X1 0x11
+#define HT_STREAM_MODE_2X2 0x22
+
+/* Both 2.4G and 5G band selected */
+#define BAND_SELECT_BOTH 0
+/* Band 2.4G selected */
+#define BAND_SELECT_BG 1
+/* Band 5G selected */
+#define BAND_SELECT_A 2
+
+/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */
+typedef struct _mlan_ds_11n_htcap_cfg {
+ /** HT Capability information */
+ t_u32 htcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg;
+
+/** Type definition of mlan_ds_11n_addba_param
+ * for MLAN_OID_11N_CFG_ADDBA_PARAM
+ */
+typedef struct _mlan_ds_11n_addba_param {
+ /** Timeout */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param;
+
+/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */
+typedef struct _mlan_ds_11n_tx_cfg {
+ /** HTTxCap */
+ t_u16 httxcap;
+ /** HTTxInfo */
+ t_u16 httxinfo;
+ /** Band selection */
+ t_u32 misc_cfg;
+} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg;
+
+/** BF Global Configuration */
+#define BF_GLOBAL_CONFIGURATION 0x00
+/** Performs NDP sounding for PEER specified */
+#define TRIGGER_SOUNDING_FOR_PEER 0x01
+/** TX BF interval for channel sounding */
+#define SET_GET_BF_PERIODICITY 0x02
+/** Tell FW not to perform any sounding for peer */
+#define TX_BF_FOR_PEER_ENBL 0x03
+/** TX BF SNR threshold for peer */
+#define SET_SNR_THR_PEER 0x04
+/** TX Sounding*/
+#define TX_SOUNDING_CFG 0x05
+
+/* Maximum number of peer MAC and status/SNR tuples */
+#define MAX_PEER_MAC_TUPLES 10
+
+/** Any new subcommand structure should be declare here */
+
+/** bf global cfg args */
+typedef struct _mlan_bf_global_cfg_args {
+ /** Global enable/disable bf */
+ t_u8 bf_enbl;
+ /** Global enable/disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+ /** SNR Threshold */
+ t_u8 snr_threshold;
+ /** Sounding interval in milliseconds */
+ t_u16 sounding_interval;
+ /** BF mode */
+ t_u8 bf_mode;
+ /** Reserved */
+ t_u8 reserved;
+} mlan_bf_global_cfg_args;
+
+/** trigger sounding args */
+typedef struct _mlan_trigger_sound_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Status */
+ t_u8 status;
+} mlan_trigger_sound_args;
+
+/** bf periodicity args */
+typedef struct _mlan_bf_periodicity_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Current Tx BF Interval in milliseconds */
+ t_u16 interval;
+ /** Status */
+ t_u8 status;
+} mlan_bf_periodicity_args;
+
+/** tx bf peer args */
+typedef struct _mlan_tx_bf_peer_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** Reserved */
+ t_u16 reserved;
+ /** Enable/Disable Beamforming */
+ t_u8 bf_enbl;
+ /** Enable/Disable sounding */
+ t_u8 sounding_enbl;
+ /** FB Type */
+ t_u8 fb_type;
+} mlan_tx_bf_peer_args;
+
+/** SNR threshold args */
+typedef struct _mlan_snr_thr_args {
+ /** Peer MAC address */
+ t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH];
+ /** SNR for peer */
+ t_u8 snr;
+} mlan_snr_thr_args;
+
+/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */
+typedef struct _mlan_ds_11n_tx_bf_cfg {
+ /** BF Action */
+ t_u16 bf_action;
+ /** Action */
+ t_u16 action;
+ /** Number of peers */
+ t_u32 no_of_peers;
+ union {
+ mlan_bf_global_cfg_args bf_global_cfg;
+ mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES];
+ mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES];
+ mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES];
+ mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES];
+ } body;
+} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg;
+
+/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for
+ * MLAN_OID_11N_AMSDU_AGGR_CTRL*/
+typedef struct _mlan_ds_11n_amsdu_aggr_ctrl {
+ /** Enable/Disable */
+ t_u16 enable;
+ /** Current AMSDU size valid */
+ t_u16 curr_buf_size;
+} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl;
+
+/** Type definition of mlan_ds_11n_aggr_prio_tbl
+ * for MLAN_OID_11N_CFG_AGGR_PRIO_TBL
+ */
+typedef struct _mlan_ds_11n_aggr_prio_tbl {
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl;
+
+/** DelBA All TIDs */
+#define DELBA_ALL_TIDS 0xff
+/** DelBA Tx */
+#define DELBA_TX MBIT(0)
+/** DelBA Rx */
+#define DELBA_RX MBIT(1)
+
+/** Type definition of mlan_ds_11n_delba for MLAN_OID_11N_CFG_DELBA */
+typedef struct _mlan_ds_11n_delba {
+ /** TID */
+ t_u8 tid;
+ /** Peer MAC address */
+ t_u8 peer_mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Direction (Tx: bit 0, Rx: bit 1) */
+ t_u8 direction;
+} mlan_ds_11n_delba, *pmlan_ds_11n_delba;
+
+/** Type definition of mlan_ds_delba for MLAN_OID_11N_CFG_REJECT_ADDBA_REQ */
+typedef struct _mlan_ds_reject_addba_req {
+ /** Bit0 : host sleep activated
+ * Bit1 : auto reconnect enabled
+ * Others : reserved
+ */
+ t_u32 conditions;
+} mlan_ds_reject_addba_req, *pmlan_ds_reject_addba_req;
+
+/** Type definition of mlan_ds_ibss_ampdu_param */
+typedef struct _mlan_ds_ibss_ampdu_param {
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** rx amdpdu setting */
+ t_u8 addba_reject[MAX_NUM_TID];
+} mlan_ds_ibss_ampdu_param, *pmlan_ds_ibss_ampdu_param;
+
+/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */
+typedef struct _mlan_ds_11n_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** Tx param for 11n for MLAN_OID_11N_CFG_TX */
+ mlan_ds_11n_tx_cfg tx_cfg;
+ /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */
+ mlan_ds_11n_addba_param addba_param;
+ /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */
+ t_u8 addba_reject[MAX_NUM_TID];
+ /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */
+ t_u32 tx_buf_size;
+ /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */
+ mlan_ds_11n_htcap_cfg htcap_cfg;
+ /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */
+ mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_FIELD];
+ /** Transmit Beamforming Capabilities field */
+ t_u32 tx_bf_cap;
+ /** Transmit Beamforming configuration */
+ mlan_ds_11n_tx_bf_cfg tx_bf;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+ /** DelBA for MLAN_OID_11N_CFG_DELBA */
+ mlan_ds_11n_delba del_ba;
+ /** Reject Addba Req for MLAN_OID_11N_CFG_REJECT_ADDBA_REQ */
+ mlan_ds_reject_addba_req reject_addba_req;
+ /** Control coex RX window size configuration */
+ t_u32 coex_rx_winsize;
+ /** aggrprirotity table for MLAN_OID_11N_CFG_IBSS_AMPDU_PARAM */
+ mlan_ds_ibss_ampdu_param ibss_ampdu;
+ /** Minimum BA Threshold for MLAN_OID_11N_CFG_MIN_BA_THRESHOLD
+ */
+ t_u8 min_ba_threshold;
+ } param;
+} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg;
+
+#define NUM_MCS_SUPP 20
+#define VHT_MCS_SET_LEN 8
+
+/** Type definition of mlan_ds_11ac_vhtcap_cfg for MLAN_OID_11AC_VHTCAP_CFG */
+typedef struct _mlan_ds_11ac_vhtcap_cfg {
+ /** HT Capability information */
+ t_u32 vhtcap;
+ /** Band selection */
+ t_u32 misc_cfg;
+ /** Hardware HT cap information required */
+ t_u32 hw_cap_req;
+} mlan_ds_11ac_vhtcap_cfg, *pmlan_ds_11ac_vhtcap_cfg;
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG_TX */
+typedef struct _mlan_ds_11ac_tx_cfg {
+ /** Band selection */
+ t_u8 band_cfg;
+ /** misc configuration */
+ t_u8 misc_cfg;
+ /** HTTxCap */
+ t_u16 vhttxcap;
+ /** HTTxInfo */
+ t_u16 vhttxinfo;
+} mlan_ds_11ac_tx_cfg, *pmlan_ds_11ac_tx_cfg;
+
+/** Tx */
+#define MLAN_RADIO_TX MBIT(0)
+/** Rx */
+#define MLAN_RADIO_RX MBIT(1)
+/** Tx & Rx */
+#define MLAN_RADIO_TXRX (MLAN_RADIO_TX | MLAN_RADIO_RX)
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG */
+typedef struct _mlan_ds_11ac_vht_cfg {
+ /** Band selection (1: 2.4G, 2: 5 G, 3: both 2.4G and 5G) */
+ t_u32 band;
+ /** TxRx (1: Tx, 2: Rx, 3: both Tx and Rx) */
+ t_u32 txrx;
+ /** BW CFG (0: 11N CFG, 1: vhtcap) */
+ t_u32 bwcfg;
+ /** VHT capabilities. */
+ t_u32 vht_cap_info;
+ /** VHT Tx mcs */
+ t_u32 vht_tx_mcs;
+ /** VHT Rx mcs */
+ t_u32 vht_rx_mcs;
+ /** VHT rx max rate */
+ t_u16 vht_rx_max_rate;
+ /** VHT max tx rate */
+ t_u16 vht_tx_max_rate;
+ /** Skip usr 11ac mcs cfg */
+ t_bool skip_usr_11ac_mcs_cfg;
+} mlan_ds_11ac_vht_cfg, *pmlan_ds_11ac_vht_cfg;
+
+/** Type definition of mlan_ds_11ac_tx_cfg for MLAN_OID_11AC_CFG */
+typedef struct _mlan_ds_11ac_opermode_cfg {
+ /** channel width: 1-20MHz, 2-40MHz, 3-80MHz, 4-160MHz or 80+80MHz */
+ t_u8 bw;
+ /** Rx NSS */
+ t_u8 nss;
+} mlan_ds_11ac_opermode_cfg, *pmlan_ds_11ac_opermode_cfg;
+
+/** Type definition of mlan_ds_11ac_cfg for MLAN_IOCTL_11AC_CFG */
+typedef struct _mlan_ds_11ac_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** VHT configuration for MLAN_OID_11AC_VHT_CFG */
+ mlan_ds_11ac_vht_cfg vht_cfg;
+ /** Supported MCS Set field */
+ t_u8 supported_mcs_set[NUM_MCS_SUPP];
+ /** Oper mode configuration for MLAN_OID_11AC_OPERMODE_CFG */
+ mlan_ds_11ac_opermode_cfg opermode_cfg;
+ } param;
+} mlan_ds_11ac_cfg, *pmlan_ds_11ac_cfg;
+
+/** Type definition of mlan_ds_11ax_he_capa for MLAN_OID_11AX_HE_CFG */
+typedef MLAN_PACK_START struct _mlan_ds_11ax_he_capa {
+ /** tlv id of he capability */
+ t_u16 id;
+ /** length of the payload */
+ t_u16 len;
+ /** extension id */
+ t_u8 ext_id;
+ /** he mac capability info */
+ t_u8 he_mac_cap[6];
+ /** he phy capability info */
+ t_u8 he_phy_cap[11];
+ /** he txrx mcs support for 80MHz */
+ t_u8 he_txrx_mcs_support[4];
+ /** val for txrx mcs 160Mhz or 80+80, and PPE thresholds */
+ t_u8 val[28];
+} MLAN_PACK_END mlan_ds_11ax_he_capa, *pmlan_ds_11ax_he_capa;
+
+/** Type definition of mlan_ds_11ax_he_cfg for MLAN_OID_11AX_HE_CFG */
+typedef struct _mlan_ds_11ax_he_cfg {
+ /** band, BIT0:2.4G, BIT1:5G*/
+ t_u8 band;
+ /** mlan_ds_11ax_he_capa */
+ mlan_ds_11ax_he_capa he_cap;
+} mlan_ds_11ax_he_cfg, *pmlan_ds_11ax_he_cfg;
+/** Type definition of mlan_ds_11as_cfg for MLAN_IOCTL_11AX_CFG */
+typedef struct _mlan_ds_11ax_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11n configuration parameter */
+ union {
+ /** HE configuration for MLAN_OID_11AX_HE_CFG */
+ mlan_ds_11ax_he_cfg he_cfg;
+ } param;
+} mlan_ds_11ax_cfg, *pmlan_ds_11ax_cfg;
+
+#define MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET 1
+#define MLAN_11AXCMD_CFG_ID_SR_ENABLE 2
+#define MLAN_11AXCMD_CFG_ID_BEAM_CHANGE 3
+#define MLAN_11AXCMD_CFG_ID_HTC_ENABLE 4
+#define MLAN_11AXCMD_CFG_ID_TXOP_RTS 5
+#define MLAN_11AXCMD_CFG_ID_TX_OMI 6
+#define MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME 7
+
+#define MLAN_11AXCMD_SR_SUBID 0x102
+#define MLAN_11AXCMD_BEAM_SUBID 0x103
+#define MLAN_11AXCMD_HTC_SUBID 0x104
+#define MLAN_11AXCMD_TXOMI_SUBID 0x105
+#define MLAN_11AXCMD_OBSS_TOLTIME_SUBID 0x106
+#define MLAN_11AXCMD_TXOPRTS_SUBID 0x108
+
+#define MLAN_11AX_TWT_SETUP_SUBID 0x114
+#define MLAN_11AX_TWT_TEARDOWN_SUBID 0x115
+
+#define MRVL_DOT11AX_ENABLE_SR_TLV_ID (PROPRIETARY_TLV_BASE_ID + 322)
+#define MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID (PROPRIETARY_TLV_BASE_ID + 323)
+
+/** Type definition of mlan_11axcmdcfg_obss_pd_offset for MLAN_OID_11AX_CMD_CFG
+ */
+typedef struct MLAN_PACK_START _mlan_11axcmdcfg_obss_pd_offset {
+ /** <NON_SRG_OffSET, SRG_OFFSET> */
+ t_u8 offset[2];
+} MLAN_PACK_END mlan_11axcmdcfg_obss_pd_offset;
+
+/** Type definition of mlan_11axcmdcfg_sr_control for MLAN_OID_11AX_CMD_CFG */
+typedef struct MLAN_PACK_START _mlan_11axcmdcfg_sr_control {
+ /** 1 enable, 0 disable */
+ t_u8 control;
+} MLAN_PACK_END mlan_11axcmdcfg_sr_control;
+
+/** Type definition of mlan_ds_11ax_sr_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_11ax_sr_cmd {
+ /** type*/
+ t_u16 type;
+ /** length of TLV */
+ t_u16 len;
+ /** value */
+ union {
+ mlan_11axcmdcfg_obss_pd_offset obss_pd_offset;
+ mlan_11axcmdcfg_sr_control sr_control;
+ } param;
+} MLAN_PACK_END mlan_ds_11ax_sr_cmd, *pmlan_ds_11ax_sr_cmd;
+
+/** Type definition of mlan_ds_11ax_beam_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_beam_cmd {
+ /** command value: 1 is disable, 0 is enable*/
+ t_u8 value;
+} mlan_ds_11ax_beam_cmd, *pmlan_ds_11ax_beam_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_htc_cmd {
+ /** command value: 1 is enable, 0 is disable*/
+ t_u8 value;
+} mlan_ds_11ax_htc_cmd, *pmlan_ds_11ax_htc_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_txop_cmd {
+ /** Two byte rts threshold value of which only 10 bits, bit 0 to bit 9
+ * are valid */
+ t_u16 rts_thres;
+} mlan_ds_11ax_txop_cmd, *pmlan_ds_11ax_txop_cmd;
+
+/** Type definition of mlan_ds_11ax_htc_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_txomi_cmd {
+ /* 11ax spec 9.2.4.6a.2 OM Control 12 bits. Bit 0 to bit 11 */
+ t_u16 omi;
+} mlan_ds_11ax_txomi_cmd, *pmlan_ds_11ax_txomi_cmd;
+
+/** Type definition of mlan_ds_11ax_toltime_cmd for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_toltime_cmd {
+ /* OBSS Narrow Bandwidth RU Tolerance Time */
+ t_u32 tol_time;
+} mlan_ds_11ax_toltime_cmd, *pmlan_ds_11ax_toltime_cmd;
+
+/** Type definition of mlan_ds_11ax_cmd_cfg for MLAN_OID_11AX_CMD_CFG */
+typedef struct _mlan_ds_11ax_cmd_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Sub-id */
+ t_u32 sub_id;
+ /** 802.11n configuration parameter */
+ union {
+ /** SR configuration for MLAN_11AXCMD_SR_SUBID */
+ mlan_ds_11ax_sr_cmd sr_cfg;
+ /** Beam configuration for MLAN_11AXCMD_BEAM_SUBID */
+ mlan_ds_11ax_beam_cmd beam_cfg;
+ /** HTC configuration for MLAN_11AXCMD_HTC_SUBID */
+ mlan_ds_11ax_htc_cmd htc_cfg;
+ /** txop RTS configuration for MLAN_11AXCMD_TXOPRTS_SUBID */
+ mlan_ds_11ax_txop_cmd txop_cfg;
+ /** tx omi configuration for MLAN_11AXCMD_TXOMI_SUBID */
+ mlan_ds_11ax_txomi_cmd txomi_cfg;
+ /** OBSS tolerance time configuration for
+ * MLAN_11AXCMD_TOLTIME_SUBID */
+ mlan_ds_11ax_toltime_cmd toltime_cfg;
+ } param;
+} mlan_ds_11ax_cmd_cfg, *pmlan_ds_11ax_cmd_cfg;
+
+/** Type definition of mlan_ds_twt_setup for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twt_setup {
+ /** Implicit, 0: TWT session is explicit, 1: Session is implicit */
+ t_u8 implicit;
+ /** Announced, 0: Unannounced, 1: Announced TWT */
+ t_u8 announced;
+ /** Trigger Enabled, 0: Non-Trigger enabled, 1: Trigger enabled TWT */
+ t_u8 trigger_enabled;
+ /** TWT Information Disabled, 0: TWT info enabled, 1: TWT info disabled
+ */
+ t_u8 twt_info_disabled;
+ /** Negotiation Type, 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** TWT Wakeup Duration, time after which the TWT requesting STA can
+ * transition to doze state */
+ t_u8 twt_wakeup_duration;
+ /** Flow Identifier. Range: [0-7]*/
+ t_u8 flow_identifier;
+ /** Hard Constraint, 0: FW can tweak the TWT setup parameters if it is
+ *rejected by AP.
+ ** 1: Firmware should not tweak any parameters. */
+ t_u8 hard_constraint;
+ /** TWT Exponent, Range: [0-63] */
+ t_u8 twt_exponent;
+ /** TWT Mantissa Range: [0-sizeof(UINT16)] */
+ t_u16 twt_mantissa;
+ /** TWT Request Type, 0: REQUEST_TWT, 1: SUGGEST_TWT*/
+ t_u8 twt_request;
+} MLAN_PACK_END mlan_ds_twt_setup, *pmlan_ds_twt_setup;
+
+/** Type definition of mlan_ds_twt_teardown for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twt_teardown {
+ /** TWT Flow Identifier. Range: [0-7] */
+ t_u8 flow_identifier;
+ /** Negotiation Type. 0: Future Individual TWT SP start time, 1: Next
+ * Wake TBTT time */
+ t_u8 negotiation_type;
+ /** Tear down all TWT. 1: To teardown all TWT, 0 otherwise */
+ t_u8 teardown_all_twt;
+} MLAN_PACK_END mlan_ds_twt_teardown, *pmlan_ds_twt_teardown;
+
+/** Type definition of mlan_ds_twtcfg for MLAN_OID_11AX_TWT_CFG */
+typedef struct MLAN_PACK_START _mlan_ds_twtcfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Sub-id */
+ t_u32 sub_id;
+ /** TWT Setup/Teardown configuration parameter */
+ union {
+ /** TWT Setup config for Sub ID: MLAN_11AX_TWT_SETUP_SUBID */
+ mlan_ds_twt_setup twt_setup;
+ /** TWT Teardown config for Sub ID: MLAN_11AX_TWT_TEARDOWN_SUBID
+ */
+ mlan_ds_twt_teardown twt_teardown;
+ } param;
+} MLAN_PACK_END mlan_ds_twtcfg, *pmlan_ds_twtcfg;
+
+/** Country code length */
+#define COUNTRY_CODE_LEN 3
+
+/*-----------------------------------------------------------------*/
+/** 802.11d Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+/** Data structure for subband set */
+typedef struct _mlan_ds_subband_set_t {
+ /** First channel */
+ t_u8 first_chan;
+ /** Number of channels */
+ t_u8 no_of_chan;
+ /** Maximum Tx power in dBm */
+ t_u8 max_tx_pwr;
+} mlan_ds_subband_set_t;
+
+/** Domain regulatory information */
+typedef struct _mlan_ds_11d_domain_info {
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** Band that channels in sub_band belong to */
+ t_u8 band;
+ /** No. of subband in below */
+ t_u8 no_of_sub_band;
+ /** Subband data to send/last sent */
+ mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D];
+} mlan_ds_11d_domain_info;
+
+/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */
+typedef struct _mlan_ds_11d_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** 802.11d configuration parameter */
+ union {
+#ifdef STA_SUPPORT
+ /** Enable for MLAN_OID_11D_CFG_ENABLE */
+ t_u32 enable_11d;
+#endif /* STA_SUPPORT */
+ /** Domain info for MLAN_OID_11D_DOMAIN_INFO_EXT */
+ mlan_ds_11d_domain_info domain_info;
+#ifdef UAP_SUPPORT
+ /** tlv data for MLAN_OID_11D_DOMAIN_INFO */
+ t_u8 domain_tlv[MAX_IE_SIZE];
+#endif /* UAP_SUPPORT */
+ } param;
+} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Register Memory Access Group */
+/*-----------------------------------------------------------------*/
+/** Enumeration for CSU target device type */
+enum _mlan_csu_target_type {
+ MLAN_CSU_TARGET_CAU = 1,
+ MLAN_CSU_TARGET_PSU,
+};
+
+/** Enumeration for register type */
+enum _mlan_reg_type {
+ MLAN_REG_MAC = 1,
+ MLAN_REG_BBP,
+ MLAN_REG_RF,
+ MLAN_REG_CAU = 5,
+ MLAN_REG_PSU = 6,
+ MLAN_REG_BCA = 7,
+#if defined(PCIE9098) || defined(SD9098) || defined(USB9098) || \
+ defined(PCIE9097) || defined(USB9097) || defined(SD9097)
+ MLAN_REG_MAC2 = 0x81,
+ MLAN_REG_BBP2 = 0x82,
+ MLAN_REG_RF2 = 0x83,
+ MLAN_REG_BCA2 = 0x87
+#endif
+};
+
+/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */
+typedef struct _mlan_ds_reg_rw {
+ /** Register type */
+ t_u32 type;
+ /** Offset */
+ t_u32 offset;
+ /** Value */
+ t_u32 value;
+} mlan_ds_reg_rw;
+
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA 256
+
+/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */
+typedef struct _mlan_ds_read_eeprom {
+ /** Multiples of 4 */
+ t_u16 offset;
+ /** Number of bytes */
+ t_u16 byte_count;
+ /** Value */
+ t_u8 value[MAX_EEPROM_DATA];
+} mlan_ds_read_eeprom;
+
+/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */
+typedef struct _mlan_ds_mem_rw {
+ /** Address */
+ t_u32 addr;
+ /** Value */
+ t_u32 value;
+} mlan_ds_mem_rw;
+
+/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */
+typedef struct _mlan_ds_reg_mem {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Register memory access parameter */
+ union {
+ /** Register access for MLAN_OID_REG_RW */
+ mlan_ds_reg_rw reg_rw;
+ /** EEPROM access for MLAN_OID_EEPROM_RD */
+ mlan_ds_read_eeprom rd_eeprom;
+ /** Memory access for MLAN_OID_MEM_RW */
+ mlan_ds_mem_rw mem_rw;
+ } param;
+} mlan_ds_reg_mem, *pmlan_ds_reg_mem;
+
+/*-----------------------------------------------------------------*/
+/** Multi-Radio Configuration Group */
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/** 802.11h Configuration Group */
+/*-----------------------------------------------------------------*/
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */
+typedef struct _mlan_ds_11h_dfs_testing {
+ /** User-configured CAC period in milliseconds, 0 to use default */
+ t_u32 usr_cac_period_msec;
+ /** User-configured NOP period in seconds, 0 to use default */
+ t_u16 usr_nop_period_sec;
+ /** User-configured skip channel change, 0 to disable */
+ t_u8 usr_no_chan_change;
+ /** User-configured fixed channel to change to, 0 to use random channel
+ */
+ t_u8 usr_fixed_new_chan;
+ /** User-configured cac restart */
+ t_u8 usr_cac_restart;
+} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing;
+
+/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_CHAN_NOP_INFO */
+typedef struct _mlan_ds_11h_chan_nop_info {
+ /** current channel */
+ t_u8 curr_chan;
+ /** channel_width */
+ t_u8 chan_width;
+ /** flag for chan under nop */
+ t_bool chan_under_nop;
+ /** chan_ban_info for new channel */
+ chan_band_info new_chan;
+} mlan_ds_11h_chan_nop_info, *pmlan_ds_11h_chan_nop_info;
+
+typedef struct _mlan_ds_11h_chan_rep_req {
+ t_u16 startFreq;
+ Band_Config_t bandcfg;
+ t_u8 chanNum;
+ t_u32 millisec_dwell_time; /**< Channel dwell time in milliseconds */
+ t_u8 host_based;
+} mlan_ds_11h_chan_rep_req;
+
+typedef struct _mlan_ds_11h_dfs_w53_cfg {
+ /** dfs w53 cfg */
+ t_u8 dfs53cfg;
+} mlan_ds_11h_dfs_w53_cfg;
+
+/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */
+typedef struct _mlan_ds_11h_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ union {
+ /** Local power constraint for
+ * MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */
+ t_s8 usr_local_power_constraint;
+ /** User-configuation for MLAN_OID_11H_DFS_TESTING */
+ mlan_ds_11h_dfs_testing dfs_testing;
+ /** channel NOP information for MLAN_OID_11H_CHAN_NOP_INFO */
+ mlan_ds_11h_chan_nop_info ch_nop_info;
+ /** channel report req for MLAN_OID_11H_CHAN_REPORT_REQUEST */
+ mlan_ds_11h_chan_rep_req chan_rpt_req;
+ /** channel switch count for MLAN_OID_11H_CHAN_SWITCH_COUNT*/
+ t_s8 cs_count;
+ mlan_ds_11h_dfs_w53_cfg dfs_w53_cfg;
+ } param;
+} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg;
+
+/*-----------------------------------------------------------------*/
+/** Miscellaneous Configuration Group */
+/*-----------------------------------------------------------------*/
+
+/** CMD buffer size */
+#define MLAN_SIZE_OF_CMD_BUFFER (3 * 1024)
+
+/** LDO Internal */
+#define LDO_INTERNAL 0
+/** LDO External */
+#define LDO_EXTERNAL 1
+
+/** Enumeration for IE type */
+enum _mlan_ie_type {
+ MLAN_IE_TYPE_GEN_IE = 0,
+};
+
+/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */
+typedef struct _mlan_ds_misc_gen_ie {
+ /** IE type */
+ t_u32 type;
+ /** IE length */
+ t_u32 len;
+ /** IE buffer */
+ t_u8 ie_data[MAX_IE_SIZE];
+} mlan_ds_misc_gen_ie;
+
+#ifdef SDIO
+/** Type definition of mlan_ds_misc_sdio_mpa_ctrl
+ * for MLAN_OID_MISC_SDIO_MPA_CTRL
+ */
+typedef struct _mlan_ds_misc_sdio_mpa_ctrl {
+ /** SDIO MP-A TX enable/disable */
+ t_u16 tx_enable;
+ /** SDIO MP-A RX enable/disable */
+ t_u16 rx_enable;
+ /** SDIO MP-A TX buf size */
+ t_u16 tx_buf_size;
+ /** SDIO MP-A RX buf size */
+ t_u16 rx_buf_size;
+ /** SDIO MP-A TX Max Ports */
+ t_u16 tx_max_ports;
+ /** SDIO MP-A RX Max Ports */
+ t_u16 rx_max_ports;
+} mlan_ds_misc_sdio_mpa_ctrl;
+#endif
+
+/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */
+typedef struct _mlan_ds_misc_cmd {
+ /** Command length */
+ t_u32 len;
+ /** Command buffer */
+ t_u8 cmd[MRVDRV_SIZE_OF_CMD_BUFFER];
+} mlan_ds_misc_cmd;
+
+/** Maximum number of system clocks */
+#define MLAN_MAX_CLK_NUM 16
+
+/** Clock type : Configurable */
+#define MLAN_CLK_CONFIGURABLE 0
+/** Clock type : Supported */
+#define MLAN_CLK_SUPPORTED 1
+
+/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */
+typedef struct _mlan_ds_misc_sys_clock {
+ /** Current system clock */
+ t_u16 cur_sys_clk;
+ /** Clock type */
+ t_u16 sys_clk_type;
+ /** Number of clocks */
+ t_u16 sys_clk_num;
+ /** System clocks */
+ t_u16 sys_clk[MLAN_MAX_CLK_NUM];
+} mlan_ds_misc_sys_clock;
+
+/** Enumeration for function init/shutdown */
+enum _mlan_func_cmd {
+ MLAN_FUNC_INIT = 1,
+ MLAN_FUNC_SHUTDOWN,
+};
+
+/** Type definition of mlan_ds_misc_tx_datapause
+ * for MLAN_OID_MISC_TX_DATAPAUSE
+ */
+typedef struct _mlan_ds_misc_tx_datapause {
+ /** Tx data pause flag */
+ t_u16 tx_pause;
+ /** Max number of Tx buffers for all PS clients */
+ t_u16 tx_buf_cnt;
+} mlan_ds_misc_tx_datapause;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg
+ * for MLAN_OID_MISC_RX_ABORT_CFG
+ */
+typedef struct _mlan_ds_misc_rx_abort_cfg {
+ /** enable/disable rx abort */
+ t_u8 enable;
+ /** Rx weak RSSI pkt threshold */
+ t_s8 rssi_threshold;
+} mlan_ds_misc_rx_abort_cfg;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg_ext
+ * for MLAN_OID_MISC_RX_ABORT_CFG_EXT
+ */
+typedef struct _mlan_ds_misc_rx_abort_cfg_ext {
+ /** enable/disable dynamic rx abort */
+ t_u8 enable;
+ /** rssi margin */
+ t_s8 rssi_margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_rssi_threshold;
+} mlan_ds_misc_rx_abort_cfg_ext;
+
+/** Type definition of mlan_ds_misc_rx_abort_cfg_ext
+ * for MLAN_OID_MISC_TX_AMDPU_PROT_MODE
+ */
+typedef struct _mlan_ds_misc_tx_ampdu_prot_mode {
+ /** set prot mode */
+ t_u16 mode;
+} mlan_ds_misc_tx_ampdu_prot_mode;
+
+/** Type definition of mlan_ds_misc_dot11mc_unassoc_ftm_cfg
+ * for MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG
+ */
+typedef struct _mlan_ds_misc_dot11mc_unassoc_ftm_cfg {
+ /** set the state */
+ t_u16 state;
+} mlan_ds_misc_dot11mc_unassoc_ftm_cfg;
+
+#define RATEADAPT_ALGO_LEGACY 0
+#define RATEADAPT_ALGO_SR 1
+
+/** Type definition of mlan_ds_misc_rate_adapt_cfg
+ * for MLAN_OID_MISC_RATE_ADAPT_CFG
+ */
+typedef struct _mlan_ds_misc_rate_adapt_cfg {
+ /** SR Rateadapt */
+ t_u8 sr_rateadapt;
+ /** set low threshold */
+ t_u8 ra_low_thresh;
+ /** set high threshold */
+ t_u8 ra_high_thresh;
+ /** set interval */
+ t_u16 ra_interval;
+} mlan_ds_misc_rate_adapt_cfg;
+
+/** Type definition of mlan_ds_misc_cck_desense_cfg
+ * for MLAN_OID_MISC_CCK_DESENSE_CFG
+ */
+typedef struct _mlan_ds_misc_cck_desense_cfg {
+ /** cck desense mode: 0:disable 1:normal 2:dynamic */
+ t_u16 mode;
+ /** specify rssi margin */
+ t_s8 margin;
+ /** specify ceil rssi threshold */
+ t_s8 ceil_thresh;
+ /** cck desense "on" interval count */
+ t_u8 num_on_intervals;
+ /** cck desense "off" interval count */
+ t_u8 num_off_intervals;
+} mlan_ds_misc_cck_desense_cfg;
+
+/** IP address length */
+#define IPADDR_LEN (16)
+/** Max number of ip */
+#define MAX_IPADDR (4)
+/** IP address type - NONE*/
+#define IPADDR_TYPE_NONE (0)
+/** IP address type - IPv4*/
+#define IPADDR_TYPE_IPV4 (1)
+/** IP operation remove */
+#define MLAN_IPADDR_OP_IP_REMOVE (0)
+/** IP operation ARP response */
+#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1)
+
+/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */
+typedef struct _mlan_ds_misc_ipaddr_cfg {
+ /** Operation code */
+ t_u32 op_code;
+ /** IP address type */
+ t_u32 ip_addr_type;
+ /** Number of IP */
+ t_u32 ip_addr_num;
+ /** IP address */
+ t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN];
+} mlan_ds_misc_ipaddr_cfg;
+
+/* MEF configuration disable */
+#define MEF_CFG_DISABLE 0
+/* MEF configuration Rx filter enable */
+#define MEF_CFG_RX_FILTER_ENABLE 1
+/* MEF configuration auto ARP response */
+#define MEF_CFG_AUTO_ARP_RESP 2
+/* MEF configuration host command */
+#define MEF_CFG_HOSTCMD 0xFFFF
+
+/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */
+typedef struct _mlan_ds_misc_mef_cfg {
+ /** Sub-ID for operation */
+ t_u32 sub_id;
+ /** Parameter according to sub-ID */
+ union {
+ /** MEF command buffer for MEF_CFG_HOSTCMD */
+ mlan_ds_misc_cmd cmd_buf;
+ } param;
+} mlan_ds_misc_mef_cfg;
+
+/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_misc_cfp_code {
+ /** CFP table code for 2.4GHz */
+ t_u32 cfp_code_bg;
+ /** CFP table code for 5GHz */
+ t_u32 cfp_code_a;
+} mlan_ds_misc_cfp_code;
+
+/** Type definition of mlan_ds_misc_arb_cfg
+ * for MLAN_OID_MISC_ARB_CFG
+ */
+typedef struct _mlan_ds_misc_arb_cfg {
+ /** arb mode 0-4 */
+ t_u32 arb_mode;
+} mlan_ds_misc_arb_cfg;
+
+/** Type definition of mlan_ds_misc_tp_state
+ * for MLAN_OID_MISC_TP_STATE
+ */
+typedef struct _mlan_ds_misc_tp_state {
+ /** TP account mode 0-disable 1-enable */
+ t_u32 on;
+ /** Packet drop point */
+ t_u32 drop_point;
+} mlan_ds_misc_tp_state;
+
+/** Type definition of mlan_ds_misc_country_code
+ * for MLAN_OID_MISC_COUNTRY_CODE
+ */
+typedef struct _mlan_ds_misc_country_code {
+ /** Country Code */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+} mlan_ds_misc_country_code;
+
+/** action for set */
+#define SUBSCRIBE_EVT_ACT_BITWISE_SET 0x0002
+/** action for clear */
+#define SUBSCRIBE_EVT_ACT_BITWISE_CLR 0x0003
+/** BITMAP for subscribe event rssi low */
+#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0)
+/** BITMAP for subscribe event snr low */
+#define SUBSCRIBE_EVT_SNR_LOW MBIT(1)
+/** BITMAP for subscribe event max fail */
+#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2)
+/** BITMAP for subscribe event beacon missed */
+#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3)
+/** BITMAP for subscribe event rssi high */
+#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4)
+/** BITMAP for subscribe event snr high */
+#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5)
+/** BITMAP for subscribe event data rssi low */
+#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6)
+/** BITMAP for subscribe event data snr low */
+#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7)
+/** BITMAP for subscribe event data rssi high */
+#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8)
+/** BITMAP for subscribe event data snr high */
+#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9)
+/** BITMAP for subscribe event link quality */
+#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10)
+/** BITMAP for subscribe event pre_beacon_lost */
+#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11)
+/** default PRE_BEACON_MISS_COUNT */
+#define DEFAULT_PRE_BEACON_MISS 30
+
+/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */
+typedef struct _mlan_ds_subscribe_evt {
+ /** evt action */
+ t_u16 evt_action;
+ /** bitmap for subscribe event */
+ t_u16 evt_bitmap;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 low_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 low_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 low_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 low_snr_freq;
+ /** Failure count threshold */
+ t_u8 failure_count;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 failure_count_freq;
+ /** num of missed beacons */
+ t_u8 beacon_miss;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 beacon_miss_freq;
+ /** Absolute value of RSSI threshold value (dBm) */
+ t_u8 high_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 high_rssi_freq;
+ /** SNR threshold value (dB) */
+ t_u8 high_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 high_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_low_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_low_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_low_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_low_snr_freq;
+ /** Absolute value of data RSSI threshold value (dBm) */
+ t_u8 data_high_rssi;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_high_rssi_freq;
+ /** Absolute value of data SNR threshold value (dBm) */
+ t_u8 data_high_snr;
+ /** 0--report once, 1--report everytime happen,
+ * N -- report only happend > N consecutive times
+ */
+ t_u8 data_high_snr_freq;
+ /* Link SNR threshold (dB)*/
+ t_u16 link_snr;
+ /* Link SNR frequency */
+ t_u16 link_snr_freq;
+ /* Second minimum rate value as per the rate table below */
+ t_u16 link_rate;
+ /* Second minimum rate frequency */
+ t_u16 link_rate_freq;
+ /* Tx latency value (us) */
+ t_u16 link_tx_latency;
+ /* Tx latency frequency */
+ t_u16 link_tx_lantency_freq;
+ /* Number of pre missed beacons */
+ t_u8 pre_beacon_miss;
+} mlan_ds_subscribe_evt;
+
+/** Max OTP user data length */
+#define MAX_OTP_USER_DATA_LEN 252
+
+/** Type definition of mlan_ds_misc_otp_user_data
+ * for MLAN_OID_MISC_OTP_USER_DATA
+ */
+typedef struct _mlan_ds_misc_otp_user_data {
+ /** Reserved */
+ t_u16 reserved;
+ /** OTP user data length */
+ t_u16 user_data_length;
+ /** User data buffer */
+ t_u8 user_data[MAX_OTP_USER_DATA_LEN];
+} mlan_ds_misc_otp_user_data;
+
+typedef struct _aggr_ctrl {
+ /** Enable */
+ t_u16 enable;
+ /** Aggregation alignment */
+ t_u16 aggr_align;
+ /** Aggregation max size */
+ t_u16 aggr_max_size;
+ /** Aggregation max packet number */
+ t_u16 aggr_max_num;
+ /** Aggrgation timeout, in microseconds */
+ t_u16 aggr_tmo;
+} aggr_ctrl;
+
+/** Type definition of mlan_ds_misc_aggr_ctrl
+ * for MLAN_OID_MISC_AGGR_CTRL
+ */
+typedef struct _mlan_ds_misc_aggr_ctrl {
+ /** Tx aggregation control */
+ aggr_ctrl tx;
+} mlan_ds_misc_aggr_ctrl;
+
+#ifdef USB
+typedef struct _usb_aggr_ctrl {
+ /** Enable */
+ t_u16 enable;
+ /** Aggregation mode */
+ t_u16 aggr_mode;
+ /** Aggregation alignment */
+ t_u16 aggr_align;
+ /** Aggregation max packet/size */
+ t_u16 aggr_max;
+ /** Aggrgation timeout, in microseconds */
+ t_u16 aggr_tmo;
+} usb_aggr_ctrl;
+
+/** Type definition of mlan_ds_misc_usb_aggr_ctrl
+ * for MLAN_OID_MISC_USB_AGGR_CTRL
+ */
+typedef struct _mlan_ds_misc_usb_aggr_ctrl {
+ /** Tx aggregation control */
+ usb_aggr_ctrl tx_aggr_ctrl;
+ /** Rx deaggregation control */
+ usb_aggr_ctrl rx_deaggr_ctrl;
+} mlan_ds_misc_usb_aggr_ctrl;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** flag for NOA */
+#define WIFI_DIRECT_NOA 1
+/** flag for OPP_PS */
+#define WIFI_DIRECT_OPP_PS 2
+/** Type definition of mlan_ds_wifi_direct_config
+ * for MLAN_OID_MISC_WIFI_DIRECT_CONFIG
+ */
+typedef struct _mlan_ds_wifi_direct_config {
+ /** flags for NOA/OPP_PS */
+ t_u8 flags;
+ /** NoA enable/disable */
+ t_u8 noa_enable;
+ /** index */
+ t_u16 index;
+ /** NoA count */
+ t_u8 noa_count;
+ /** NoA duration */
+ t_u32 noa_duration;
+ /** NoA interval */
+ t_u32 noa_interval;
+ /** opp ps enable/disable */
+ t_u8 opp_ps_enable;
+ /** CT window value */
+ t_u8 ct_window;
+} mlan_ds_wifi_direct_config;
+#endif
+
+#if defined(STA_SUPPORT)
+typedef struct _mlan_ds_misc_pmfcfg {
+ /** Management Frame Protection Capable */
+ t_u8 mfpc;
+ /** Management Frame Protection Required */
+ t_u8 mfpr;
+} mlan_ds_misc_pmfcfg;
+#endif
+
+#define MAX_SSID_NUM 16
+#define MAX_AP_LIST 8
+
+#ifdef RX_PACKET_COALESCE
+typedef struct _mlan_ds_misc_rx_packet_coalesce {
+ /** packet threshold */
+ t_u32 packet_threshold;
+ /** timeout value */
+ t_u16 delay;
+} mlan_ds_misc_rx_packet_coalesce;
+#endif
+
+typedef struct _mlan_ds_misc_dfs_repeater {
+ /** Set or Get */
+ t_u16 action;
+ /** 1 on or 0 off */
+ t_u16 mode;
+} mlan_ds_misc_dfs_repeater;
+
+#define WOWLAN_MAX_PATTERN_LEN 20
+#define WOWLAN_MAX_OFFSET_LEN 50
+#define MAX_NUM_FILTERS 10
+#define MEF_MODE_HOST_SLEEP (1 << 0)
+#define MEF_MODE_NON_HOST_SLEEP (1 << 1)
+#define MEF_ACTION_WAKE (1 << 0)
+#define MEF_ACTION_ALLOW (1 << 1)
+#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
+#define MEF_AUTO_ARP 0x10
+#define MEF_AUTO_PING 0x20
+#define MEF_NS_RESP 0x40
+#define MEF_MAGIC_PKT 0x80
+#define CRITERIA_BROADCAST BIT(0)
+#define CRITERIA_UNICAST BIT(1)
+#define CRITERIA_MULTICAST BIT(3)
+
+#define MAX_NUM_ENTRIES 8
+#define MAX_NUM_BYTE_SEQ 6
+#define MAX_NUM_MASK_SEQ 6
+
+#define OPERAND_DNUM 1
+#define OPERAND_BYTE_SEQ 2
+
+#define MAX_OPERAND 0x40
+#define TYPE_BYTE_EQ (MAX_OPERAND + 1)
+#define TYPE_DNUM_EQ (MAX_OPERAND + 2)
+#define TYPE_BIT_EQ (MAX_OPERAND + 3)
+
+#define RPN_TYPE_AND (MAX_OPERAND + 4)
+#define RPN_TYPE_OR (MAX_OPERAND + 5)
+
+#define ICMP_OF_IP_PROTOCOL 0x01
+#define TCP_OF_IP_PROTOCOL 0x06
+#define UDP_OF_IP_PROTOCOL 0x11
+
+#define IPV4_PKT_OFFSET 20
+#define IP_PROTOCOL_OFFSET 31
+#define PORT_PROTOCOL_OFFSET 44
+
+#define FILLING_TYPE MBIT(0)
+#define FILLING_PATTERN MBIT(1)
+#define FILLING_OFFSET MBIT(2)
+#define FILLING_NUM_BYTES MBIT(3)
+#define FILLING_REPEAT MBIT(4)
+#define FILLING_BYTE_SEQ MBIT(5)
+#define FILLING_MASK_SEQ MBIT(6)
+
+/** Type definition of filter_item
+ * Support three match methods:
+ * <1>Byte comparison type=0x41
+ * <2>Decimal comparison type=0x42
+ * <3>Bit comparison type=0x43
+ */
+typedef struct _mef_filter_t {
+ /** flag*/
+ t_u32 fill_flag;
+ /** BYTE 0X41; Decimal 0X42; Bit 0x43*/
+ t_u16 type;
+ /** value*/
+ t_u32 pattern;
+ /** offset*/
+ t_u16 offset;
+ /** number of bytes*/
+ t_u16 num_bytes;
+ /** repeat*/
+ t_u16 repeat;
+ /** byte number*/
+ t_u8 num_byte_seq;
+ /** array*/
+ t_u8 byte_seq[MAX_NUM_BYTE_SEQ];
+ /** mask numbers*/
+ t_u8 num_mask_seq;
+ /** array*/
+ t_u8 mask_seq[MAX_NUM_MASK_SEQ];
+} mef_filter_t;
+
+typedef struct _mef_entry_t {
+ /** mode: bit0--hostsleep mode; bit1--non hostsleep mode */
+ t_u8 mode;
+ /** action: 0--discard and not wake host;
+ 1--discard and wake host;
+ 3--allow and wake host;*/
+ t_u8 action;
+ /** filter number */
+ t_u8 filter_num;
+ /** filter array*/
+ mef_filter_t filter_item[MAX_NUM_FILTERS];
+ /** rpn array*/
+ t_u8 rpn[MAX_NUM_FILTERS];
+} mef_entry_t;
+
+/** Type definition of mlan_ds_nvflt_mef_entry
+ *for MLAN_OID_MISC_MEF_FLT_CFG
+ */
+typedef struct _mlan_ds_misc_mef_flt_cfg {
+ /** Type of action*/
+ int mef_act_type;
+ /** NV Filter Criteria*/
+ t_u32 criteria;
+ /** NV MEF entry*/
+ mef_entry_t mef_entry;
+} mlan_ds_misc_mef_flt_cfg;
+
+/** Enumeration for action type*/
+enum _mlan_act_mef_act_type {
+ MEF_ACT_ADD = 1,
+ MEF_ACT_ENABLE,
+ MEF_ACT_DISABLE,
+ MEF_ACT_CANCEL,
+ MEF_ACT_AUTOARP,
+ MEF_ACT_WOWLAN,
+ MEF_ACT_IPV6_NS,
+};
+
+typedef struct _mlan_ds_sensor_temp {
+ t_u32 temperature;
+} mlan_ds_sensor_temp;
+
+#define MLAN_KCK_LEN 16
+#define MLAN_KEK_LEN 16
+#define MLAN_REPLAY_CTR_LEN 8
+/** mlan_ds_misc_gtk_rekey_data */
+typedef struct _mlan_ds_misc_gtk_rekey_data {
+ /** key encryption key */
+ t_u8 kek[MLAN_KEK_LEN];
+ /** key confirmation key */
+ t_u8 kck[MLAN_KCK_LEN];
+ /** replay counter */
+ t_u8 replay_ctr[MLAN_REPLAY_CTR_LEN];
+} mlan_ds_misc_gtk_rekey_data;
+typedef struct _mlan_ds_bw_chan_oper {
+ /* bandwidth 20:20M 40:40M 80:80M*/
+ t_u8 bandwidth;
+ /* channel number */
+ t_u8 channel;
+ /* Non-global operating class */
+ t_u8 oper_class;
+} mlan_ds_bw_chan_oper;
+
+typedef struct _mlan_ds_ind_rst_cfg {
+ /** Set or Get */
+ t_u16 action;
+ /** oob mode enable/ disable */
+ t_u8 ir_mode;
+ /** gpio pin */
+ t_u8 gpio_pin;
+} mlan_ds_ind_rst_cfg;
+
+#define MKEEP_ALIVE_IP_PKT_MAX 256
+typedef struct _mlan_ds_misc_keep_alive {
+ t_u8 mkeep_alive_id;
+ t_u8 enable;
+ /** enable/disable tcp reset*/
+ t_u8 reset;
+ /**True means saved in driver, false means not saved or download*/
+ t_u8 cached;
+ t_u32 send_interval;
+ t_u16 retry_interval;
+ t_u16 retry_count;
+ t_u8 dst_mac[MLAN_MAC_ADDR_LENGTH];
+ t_u8 src_mac[MLAN_MAC_ADDR_LENGTH];
+ t_u16 pkt_len;
+ t_u8 packet[MKEEP_ALIVE_IP_PKT_MAX];
+ /** Ethernet type */
+ t_u16 ether_type;
+} mlan_ds_misc_keep_alive, *pmlan_ds_misc_keep_alive;
+
+/** TX and RX histogram statistic parameters*/
+typedef MLAN_PACK_START struct _mlan_ds_misc_tx_rx_histogram {
+ /** Enable or disable get tx/rx histogram statistic */
+ t_u8 enable;
+ /** Choose to get TX, RX or both histogram statistic */
+ t_u16 action;
+ /** Size of Tx/Rx info */
+ t_u16 size;
+ /** Store Tx/Rx info */
+ t_u8 value[1];
+} MLAN_PACK_END mlan_ds_misc_tx_rx_histogram;
+
+typedef MLAN_PACK_START struct _mlan_ds_cw_mode_ctrl {
+ /** Mode of Operation 0: Disable 1: Tx Continuous Packet 2: Tx
+ * Continuous Wave */
+ t_u8 mode;
+ /*channel*/
+ t_u8 channel;
+ /* channel info*/
+ t_u8 chanInfo;
+ /** Tx Power level in dBm */
+ t_u16 txPower;
+ /** Packet Length */
+ t_u16 pktLength;
+ /** bit rate Info */
+ t_u32 rateInfo;
+} MLAN_PACK_END mlan_ds_cw_mode_ctrl;
+
+#define RX_PKT_INFO MBIT(1)
+/** Struct for per-packet configuration */
+typedef struct _mlan_per_pkt_cfg {
+ /** Type ID*/
+ t_u16 type;
+ /** Length of payload*/
+ t_u16 len;
+ /** Tx/Rx per-packet control */
+ t_u8 tx_rx_control;
+ /** Number of ethernet types in ether_type array */
+ t_u8 proto_type_num;
+ /** Array of ether_type for per-packet control */
+ t_u16 ether_type[];
+} mlan_per_pkt_cfg;
+
+/** Type definition of mlan_ds_misc_robustcoex_params for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_robustcoex_params {
+ t_u16 method;
+ /** enable/disable robustcoex gpio cfg */
+ t_u8 enable;
+ /** Number of GPIO */
+ t_u8 gpio_num;
+ /** Polarity of GPIO */
+ t_u8 gpio_polarity;
+} mlan_ds_misc_robustcoex_params;
+
+#if defined(PCIE)
+typedef struct _mlan_ds_ssu_params {
+ t_u32 nskip;
+ t_u32 nsel;
+ t_u32 adcdownsample;
+ t_u32 mask_adc_pkt;
+ t_u32 out_16bits;
+ t_u32 spec_pwr_enable;
+ t_u32 rate_deduction;
+ t_u32 n_pkt_avg;
+} mlan_ds_ssu_params;
+#endif
+
+#define MAX_NUM_MAC 2
+/** Type definition of mlan_ds_misc_mapping_policy */
+typedef struct _mlan_ds_misc_mapping_policy {
+ /** Enable/disable dynamic mapping */
+ t_u16 subcmd;
+ /** Mapping policy */
+ t_u8 mapping_policy;
+} mlan_ds_misc_mapping_policy, *pmlan_ds_misc_mapping_policy;
+
+typedef struct _dmcsChanStatus_t {
+ /** Channel number */
+ t_u8 channel;
+ /** Number of ap on this channel */
+ t_u8 ap_count;
+ /** Number of sta on this channel */
+ t_u8 sta_count;
+} dmcsChanStatus_t, *pdmcsChanStatus_t;
+
+typedef struct _dmcsStatus_t {
+ /** Radio ID */
+ t_u8 radio_id;
+ /** Running mode
+ ** 0 - Idle
+ ** 1 - DBC
+ ** 2 - DRCS
+ */
+ t_u8 running_mode;
+ /** Current channel status */
+ dmcsChanStatus_t chan_status[2];
+} dmcsStatus_t, *pdmcsStatus_t;
+
+/** Type definition of mlan_ds_misc_dmcs_status */
+typedef struct _mlan_ds_misc_dmcs_status {
+ t_u8 mapping_policy;
+ dmcsStatus_t radio_status[MAX_NUM_MAC];
+} mlan_ds_misc_dmcs_status, *pmlan_ds_misc_dmcs_status;
+
+/** Type definition of mlan_ds_misc_chan_trpc_cfg for
+ * MLAN_OID_MISC_GET_CHAN_TRPC_CFG */
+typedef struct _mlan_ds_misc_chan_trpc_cfg {
+ /** sub_band */
+ t_u16 sub_band;
+ /** length */
+ t_u16 length;
+ /** buf */
+ t_u8 trpc_buf[2048];
+} mlan_ds_misc_chan_trpc_cfg;
+
+#define MFG_CMD_SET_TEST_MODE 1
+#define MFG_CMD_UNSET_TEST_MODE 0
+#define MFG_CMD_TX_ANT 0x1004
+#define MFG_CMD_RX_ANT 0x1005
+#define MFG_CMD_TX_CONT 0x1009
+#define MFG_CMD_RF_CHAN 0x100A
+#define MFG_CMD_CLR_RX_ERR 0x1010
+#define MFG_CMD_TX_FRAME 0x1021
+#define MFG_CMD_RFPWR 0x1033
+#define MFG_CMD_RF_BAND_AG 0x1034
+#define MFG_CMD_RF_CHANNELBW 0x1044
+/** MFG CMD generic cfg */
+struct MLAN_PACK_START mfg_cmd_generic_cfg {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** value 1 */
+ t_u32 data1;
+ /** value 2 */
+ t_u32 data2;
+ /** value 3 */
+ t_u32 data3;
+} MLAN_PACK_END;
+
+/** MFG CMD Tx Frame 2 */
+struct MLAN_PACK_START mfg_cmd_tx_frame2 {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** enable */
+ t_u32 enable;
+ /** data_rate */
+ t_u32 data_rate;
+ /** frame pattern */
+ t_u32 frame_pattern;
+ /** frame length */
+ t_u32 frame_length;
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** Adjust burst sifs */
+ t_u16 adjust_burst_sifs;
+ /** Burst sifs in us*/
+ t_u32 burst_sifs_in_us;
+ /** short preamble */
+ t_u32 short_preamble;
+ /** active sub channel */
+ t_u32 act_sub_ch;
+ /** short GI */
+ t_u32 short_gi;
+ /** Adv coding */
+ t_u32 adv_coding;
+ /** Tx beamforming */
+ t_u32 tx_bf;
+ /** HT Greenfield Mode*/
+ t_u32 gf_mode;
+ /** STBC */
+ t_u32 stbc;
+ /** power id */
+ t_u32 rsvd[2];
+} MLAN_PACK_END;
+
+/* MFG CMD Tx Continuous */
+struct MLAN_PACK_START mfg_cmd_tx_cont {
+ /** MFG command code */
+ t_u32 mfg_cmd;
+ /** Action */
+ t_u16 action;
+ /** Device ID */
+ t_u16 device_id;
+ /** MFG Error code */
+ t_u32 error;
+ /** enable Tx*/
+ t_u32 enable_tx;
+ /** Continuous Wave mode */
+ t_u32 cw_mode;
+ /** payload pattern */
+ t_u32 payload_pattern;
+ /** CS Mode */
+ t_u32 cs_mode;
+ /** active sub channel */
+ t_u32 act_sub_ch;
+ /** Tx rate */
+ t_u32 tx_rate;
+ /** power id */
+ t_u32 rsvd;
+} MLAN_PACK_END;
+
+typedef struct _mlan_ds_misc_chnrgpwr_cfg {
+ /** length */
+ t_u16 length;
+ /** chnrgpwr buf */
+ t_u8 chnrgpwr_buf[2048];
+} mlan_ds_misc_chnrgpwr_cfg;
+
+/** dfs chan list for MLAN_OID_MISC_CFP_TABLE */
+typedef struct _mlan_ds_misc_cfp_tbl {
+ /** band */
+ t_u8 band;
+ /** num chan */
+ t_u8 num_chan;
+ /** cfp table */
+ chan_freq_power_t cfp_tbl[];
+} mlan_ds_misc_cfp_tbl;
+
+/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */
+typedef struct _mlan_ds_misc_cfg {
+ /** Sub-command */
+ t_u32 sub_command;
+ /** Miscellaneous configuration parameter */
+ union {
+ /** Generic IE for MLAN_OID_MISC_GEN_IE */
+ mlan_ds_misc_gen_ie gen_ie;
+ /** Region code for MLAN_OID_MISC_REGION */
+ t_u32 region_code;
+#ifdef SDIO
+ /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */
+ mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl;
+#endif
+ /** Hostcmd for MLAN_OID_MISC_HOST_CMD */
+ mlan_ds_misc_cmd hostcmd;
+ /** System clock for MLAN_OID_MISC_SYS_CLOCK */
+ mlan_ds_misc_sys_clock sys_clock;
+ /** WWS set/get for MLAN_OID_MISC_WWS */
+ t_u32 wws_cfg;
+ /** Get associate response for MLAN_OID_MISC_ASSOC_RSP */
+ mlan_ds_misc_assoc_rsp assoc_resp;
+ /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */
+ t_u32 func_init_shutdown;
+ /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */
+ mlan_ds_misc_custom_ie cust_ie;
+ /** Config dynamic bandwidth*/
+ t_u16 dyn_bw;
+ /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */
+ mlan_ds_misc_tx_datapause tx_datapause;
+ /** IP address configuration */
+ mlan_ds_misc_ipaddr_cfg ipaddr_cfg;
+ /** MAC control for MLAN_OID_MISC_MAC_CONTROL */
+ t_u32 mac_ctrl;
+ /** MEF configuration for MLAN_OID_MISC_MEF_CFG */
+ mlan_ds_misc_mef_cfg mef_cfg;
+ /** CFP code for MLAN_OID_MISC_CFP_CODE */
+ mlan_ds_misc_cfp_code cfp_code;
+ /** Country code for MLAN_OID_MISC_COUNTRY_CODE */
+ mlan_ds_misc_country_code country_code;
+ /** Thermal reading for MLAN_OID_MISC_THERMAL */
+ t_u32 thermal;
+ /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */
+ t_u32 mgmt_subtype_mask;
+ /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */
+ mlan_ds_subscribe_evt subscribe_event;
+#ifdef DEBUG_LEVEL1
+ /** Driver debug bit masks */
+ t_u32 drvdbg;
+#endif
+ /** Hotspot config param set */
+ t_u32 hotspot_cfg;
+#ifdef STA_SUPPORT
+ ExtCap_t ext_cap;
+#endif
+ mlan_ds_misc_otp_user_data otp_user_data;
+#ifdef USB
+ /** USB aggregation parameters for MLAN_OID_MISC_USB_AGGR_CTRL
+ */
+ mlan_ds_misc_usb_aggr_ctrl usb_aggr_params;
+#endif
+ mlan_ds_misc_aggr_ctrl aggr_params;
+ /** Tx control */
+ t_u32 tx_control;
+#if defined(STA_SUPPORT)
+ mlan_ds_misc_pmfcfg pmfcfg;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ mlan_ds_wifi_direct_config p2p_config;
+#endif
+ mlan_ds_coalesce_cfg coalesce_cfg;
+ t_u8 low_pwr_mode;
+ /** MEF-FLT-CONFIG for MLAN_OID_MISC_NV_FLT_CFG */
+ mlan_ds_misc_mef_flt_cfg mef_flt_cfg;
+ mlan_ds_misc_dfs_repeater dfs_repeater;
+#ifdef RX_PACKET_COALESCE
+ mlan_ds_misc_rx_packet_coalesce rx_coalesce;
+#endif
+ /** FW reload flag */
+ t_u8 fw_reload;
+ mlan_ds_sensor_temp sensor_temp;
+ /** GTK rekey data */
+ mlan_ds_misc_gtk_rekey_data gtk_rekey;
+ mlan_ds_bw_chan_oper bw_chan_oper;
+ mlan_ds_ind_rst_cfg ind_rst_cfg;
+ t_u64 misc_tsf;
+ mlan_ds_custom_reg_domain custom_reg_domain;
+ mlan_ds_misc_keep_alive keep_alive;
+ mlan_ds_misc_tx_rx_histogram tx_rx_histogram;
+ mlan_ds_cw_mode_ctrl cwmode;
+ /** Tx/Rx per-packet control */
+ t_u8 txrx_pkt_ctrl;
+ mlan_ds_misc_robustcoex_params robustcoexparams;
+#if defined(PCIE)
+ mlan_ds_ssu_params ssu_params;
+#endif
+ /** boot sleep enable or disable */
+ t_u16 boot_sleep;
+ /** Mapping Policy */
+ mlan_ds_misc_mapping_policy dmcs_policy;
+ mlan_ds_misc_dmcs_status dmcs_status;
+ mlan_ds_misc_rx_abort_cfg rx_abort_cfg;
+ mlan_ds_misc_rx_abort_cfg_ext rx_abort_cfg_ext;
+ mlan_ds_misc_tx_ampdu_prot_mode tx_ampdu_prot_mode;
+ mlan_ds_misc_rate_adapt_cfg rate_adapt_cfg;
+ mlan_ds_misc_cck_desense_cfg cck_desense_cfg;
+ mlan_ds_misc_chan_trpc_cfg trpc_cfg;
+ mlan_ds_misc_chnrgpwr_cfg rgchnpwr_cfg;
+
+ mlan_ds_band_steer_cfg band_steer_cfg;
+ mlan_ds_beacon_stuck_param_cfg beacon_stuck_cfg;
+ struct mfg_cmd_generic_cfg mfg_generic_cfg;
+ struct mfg_cmd_tx_cont mfg_tx_cont;
+ struct mfg_cmd_tx_frame2 mfg_tx_frame2;
+ mlan_ds_misc_arb_cfg arb_cfg;
+ mlan_ds_misc_cfp_tbl cfp;
+ t_u8 range_ext_mode;
+ mlan_ds_misc_dot11mc_unassoc_ftm_cfg dot11mc_unassoc_ftm_cfg;
+ mlan_ds_misc_tp_state tp_state;
+ } param;
+} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg;
+
+/** Hotspot status enable */
+#define HOTSPOT_ENABLED MBIT(0)
+/** Hotspot status disable */
+#define HOTSPOT_DISABLED MFALSE
+/** Keep Hotspot2.0 compatible in mwu and wpa_supplicant */
+#define HOTSPOT_BY_SUPPLICANT MBIT(1)
+
+/** Reason codes */
+#define MLAN_REASON_UNSPECIFIED 1
+#define MLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define MLAN_REASON_DEAUTH_LEAVING 3
+#define MLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define MLAN_REASON_DISASSOC_AP_BUSY 5
+#define MLAN_REASON_CLASS2_FRAME_FROM_NOAUTH_STA 6
+#define MLAN_REASON_CLASS3_FRAME_FROM_NOASSOC_STA 7
+#define MLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define MLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+#endif /* !_MLAN_IOCTL_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.c
new file mode 100644
index 000000000000..abcf6149bd34
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.c
@@ -0,0 +1,4679 @@
+/** @file moal_cfg80211.c
+ *
+ * @brief This file contains the functions for CFG80211.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "moal_cfg80211.h"
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#endif
+
+/********************************************************
+ * Local Variables
+ ********************************************************/
+/** Supported rates to be advertised to the cfg80211 */
+static struct ieee80211_rate cfg80211_rates[] = {
+ {
+ .bitrate = 10,
+ .hw_value = 2,
+ },
+ {
+ .bitrate = 20,
+ .hw_value = 4,
+ },
+ {
+ .bitrate = 55,
+ .hw_value = 11,
+ },
+ {
+ .bitrate = 110,
+ .hw_value = 22,
+ },
+ {
+ .bitrate = 60,
+ .hw_value = 12,
+ },
+ {
+ .bitrate = 90,
+ .hw_value = 18,
+ },
+ {
+ .bitrate = 120,
+ .hw_value = 24,
+ },
+ {
+ .bitrate = 180,
+ .hw_value = 36,
+ },
+ {
+ .bitrate = 240,
+ .hw_value = 48,
+ },
+ {
+ .bitrate = 360,
+ .hw_value = 72,
+ },
+ {
+ .bitrate = 480,
+ .hw_value = 96,
+ },
+ {
+ .bitrate = 540,
+ .hw_value = 108,
+ },
+};
+
+/** Channel definitions for 2 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_2ghz[] = {
+ {.center_freq = 2412, .hw_value = 1, .max_power = 20},
+ {.center_freq = 2417, .hw_value = 2, .max_power = 20},
+ {.center_freq = 2422, .hw_value = 3, .max_power = 20},
+ {.center_freq = 2427, .hw_value = 4, .max_power = 20},
+ {.center_freq = 2432, .hw_value = 5, .max_power = 20},
+ {.center_freq = 2437, .hw_value = 6, .max_power = 20},
+ {.center_freq = 2442, .hw_value = 7, .max_power = 20},
+ {.center_freq = 2447, .hw_value = 8, .max_power = 20},
+ {.center_freq = 2452, .hw_value = 9, .max_power = 20},
+ {.center_freq = 2457, .hw_value = 10, .max_power = 20},
+ {.center_freq = 2462, .hw_value = 11, .max_power = 20},
+ {.center_freq = 2467, .hw_value = 12, .max_power = 20},
+ {.center_freq = 2472, .hw_value = 13, .max_power = 20},
+ {.center_freq = 2484, .hw_value = 14, .max_power = 20},
+};
+
+/** Channel definitions for 5 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel cfg80211_channels_5ghz[] = {
+ {.center_freq = 5180, .hw_value = 36, .max_power = 20},
+ {.center_freq = 5200, .hw_value = 40, .max_power = 20},
+ {.center_freq = 5220, .hw_value = 44, .max_power = 20},
+ {.center_freq = 5240, .hw_value = 48, .max_power = 20},
+ {.center_freq = 5260, .hw_value = 52, .max_power = 20},
+ {.center_freq = 5280, .hw_value = 56, .max_power = 20},
+ {.center_freq = 5300, .hw_value = 60, .max_power = 20},
+ {.center_freq = 5320, .hw_value = 64, .max_power = 20},
+ {.center_freq = 5500, .hw_value = 100, .max_power = 20},
+ {.center_freq = 5520, .hw_value = 104, .max_power = 20},
+ {.center_freq = 5540, .hw_value = 108, .max_power = 20},
+ {.center_freq = 5560, .hw_value = 112, .max_power = 20},
+ {.center_freq = 5580, .hw_value = 116, .max_power = 20},
+ {.center_freq = 5600, .hw_value = 120, .max_power = 20},
+ {.center_freq = 5620, .hw_value = 124, .max_power = 20},
+ {.center_freq = 5640, .hw_value = 128, .max_power = 20},
+ {.center_freq = 5660, .hw_value = 132, .max_power = 20},
+ {.center_freq = 5680, .hw_value = 136, .max_power = 20},
+ {.center_freq = 5700, .hw_value = 140, .max_power = 20},
+ {.center_freq = 5720, .hw_value = 144, .max_power = 20},
+ {.center_freq = 5745, .hw_value = 149, .max_power = 20},
+ {.center_freq = 5765, .hw_value = 153, .max_power = 20},
+ {.center_freq = 5785, .hw_value = 157, .max_power = 20},
+ {.center_freq = 5805, .hw_value = 161, .max_power = 20},
+ {.center_freq = 5825, .hw_value = 165, .max_power = 20},
+};
+
+struct ieee80211_supported_band cfg80211_band_2ghz = {
+ .channels = cfg80211_channels_2ghz,
+ .band = IEEE80211_BAND_2GHZ,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
+ .bitrates = cfg80211_rates,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates),
+};
+
+struct ieee80211_supported_band cfg80211_band_5ghz = {
+ .channels = cfg80211_channels_5ghz,
+ .band = IEEE80211_BAND_5GHZ,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_5ghz),
+ .bitrates = cfg80211_rates + 4,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates) - 4,
+};
+
+/** Channel definitions for 5 GHz to be advertised to cfg80211 */
+static struct ieee80211_channel mac1_cfg80211_channels_5ghz[] = {
+ {.center_freq = 5180, .hw_value = 36, .max_power = 20},
+ {.center_freq = 5200, .hw_value = 40, .max_power = 20},
+ {.center_freq = 5220, .hw_value = 44, .max_power = 20},
+ {.center_freq = 5240, .hw_value = 48, .max_power = 20},
+ {.center_freq = 5260, .hw_value = 52, .max_power = 20},
+ {.center_freq = 5280, .hw_value = 56, .max_power = 20},
+ {.center_freq = 5300, .hw_value = 60, .max_power = 20},
+ {.center_freq = 5320, .hw_value = 64, .max_power = 20},
+ {.center_freq = 5500, .hw_value = 100, .max_power = 20},
+ {.center_freq = 5520, .hw_value = 104, .max_power = 20},
+ {.center_freq = 5540, .hw_value = 108, .max_power = 20},
+ {.center_freq = 5560, .hw_value = 112, .max_power = 20},
+ {.center_freq = 5580, .hw_value = 116, .max_power = 20},
+ {.center_freq = 5600, .hw_value = 120, .max_power = 20},
+ {.center_freq = 5620, .hw_value = 124, .max_power = 20},
+ {.center_freq = 5640, .hw_value = 128, .max_power = 20},
+ {.center_freq = 5660, .hw_value = 132, .max_power = 20},
+ {.center_freq = 5680, .hw_value = 136, .max_power = 20},
+ {.center_freq = 5700, .hw_value = 140, .max_power = 20},
+ {.center_freq = 5720, .hw_value = 144, .max_power = 20},
+ {.center_freq = 5745, .hw_value = 149, .max_power = 20},
+ {.center_freq = 5765, .hw_value = 153, .max_power = 20},
+ {.center_freq = 5785, .hw_value = 157, .max_power = 20},
+ {.center_freq = 5805, .hw_value = 161, .max_power = 20},
+ {.center_freq = 5825, .hw_value = 165, .max_power = 20},
+};
+
+struct ieee80211_supported_band mac1_cfg80211_band_2ghz = {
+ .channels = cfg80211_channels_2ghz,
+ .band = IEEE80211_BAND_2GHZ,
+ .n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
+ .bitrates = cfg80211_rates,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates),
+};
+
+struct ieee80211_supported_band mac1_cfg80211_band_5ghz = {
+ .channels = mac1_cfg80211_channels_5ghz,
+ .band = IEEE80211_BAND_5GHZ,
+ .n_channels = ARRAY_SIZE(mac1_cfg80211_channels_5ghz),
+ .bitrates = cfg80211_rates + 4,
+ .n_bitrates = ARRAY_SIZE(cfg80211_rates) - 4,
+};
+
+#if KERNEL_VERSION(2, 6, 29) < LINUX_VERSION_CODE
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+/********************************************************
+ * Local Functions
+ ********************************************************/
+
+/********************************************************
+ * Global Functions
+ ********************************************************/
+
+/**
+ * @brief Get the private structure from wiphy
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return Pointer to moal_private
+ */
+void *woal_get_wiphy_priv(struct wiphy *wiphy)
+{
+ return (void *)(*(unsigned long *)wiphy_priv(wiphy));
+}
+
+/**
+ * @brief Get the private structure from net device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return Pointer to moal_private
+ */
+void *woal_get_netdev_priv(struct net_device *dev)
+{
+ return (void *)netdev_priv(dev);
+}
+
+/**
+ * @brief Get current frequency of active interface
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return channel frequency
+ */
+int woal_get_active_intf_freq(moal_private *priv)
+{
+ moal_handle *handle = priv->phandle;
+ int i;
+
+ if (priv->media_connected == MTRUE
+#ifdef UAP_SUPPORT
+ || priv->bss_started == MTRUE
+#endif
+ )
+ return ieee80211_channel_to_frequency(
+ priv->channel
+#if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
+ ,
+ (priv->channel <= 14 ? IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ)
+#endif
+ );
+
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE)
+ return ieee80211_channel_to_frequency(
+ handle->priv[i]->channel
+#if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
+ ,
+ (handle->priv[i]->channel <= 14 ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ)
+#endif
+ );
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
+ if (handle->priv[i]->bss_started == MTRUE)
+ return ieee80211_channel_to_frequency(
+ handle->priv[i]->channel
+#if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
+ ,
+ (handle->priv[i]->channel <= 14 ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ)
+#endif
+ );
+ }
+#endif
+ }
+ return 0;
+}
+
+/**
+ * @brief Convert driver band configuration to IEEE band type
+ *
+ * @param band Driver band configuration
+ *
+ * @return IEEE band type
+ */
+t_u8 woal_band_cfg_to_ieee_band(t_u32 band)
+{
+ t_u8 ret_radio_type;
+
+ ENTER();
+
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ ret_radio_type = IEEE80211_BAND_5GHZ;
+ break;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ case BAND_GN:
+ case BAND_B | BAND_GN:
+ /* Fall Through */
+ default:
+ ret_radio_type = IEEE80211_BAND_2GHZ;
+ break;
+ }
+
+ LEAVE();
+ return ret_radio_type;
+}
+
+/**
+ * @brief Set/Enable encryption key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param is_enable_wep Enable WEP default key
+ * @param cipher Cipher suite selector
+ * @param key A pointer to key
+ * @param key_len Key length
+ * @param seq A pointer to sequence
+ * @param seq_len Sequence length
+ * @param key_index Key index
+ * @param addr Mac for which key is to be set
+ * @param disable Key disabled or not
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_cfg80211_set_key(moal_private *priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 *key, int key_len,
+ const t_u8 *seq, int seq_len, t_u8 key_index,
+ const t_u8 *addr, int disable,
+ t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ ENTER();
+
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (is_enable_wep) {
+ PRINTM(MIOCTL, "Enable UAP default key=%d\n",
+ key_index);
+ priv->uap_wep_key[key_index].is_default = MTRUE;
+ goto done;
+ }
+ if (key && key_len &&
+ ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (cipher == WLAN_CIPHER_SUITE_WEP104))) {
+ priv->uap_wep_key[key_index].length = key_len;
+ moal_memcpy_ext(
+ priv->phandle, priv->uap_wep_key[key_index].key,
+ key, key_len,
+ sizeof(priv->uap_wep_key[key_index].key));
+ priv->cipher = cipher;
+ priv->uap_wep_key[key_index].key_index = key_index;
+ priv->uap_wep_key[key_index].is_default = MFALSE;
+ PRINTM(MIOCTL, "Set UAP WEP key: key_index=%d len=%d\n",
+ key_index, key_len);
+ goto done;
+ }
+ }
+#endif
+#endif
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (is_enable_wep) {
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else if (!disable) {
+ if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ cipher != WLAN_CIPHER_SUITE_WEP104 &&
+ cipher != WLAN_CIPHER_SUITE_TKIP &&
+ cipher != WLAN_CIPHER_SUITE_SMS4 &&
+ cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+ cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
+#endif
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ cipher != WLAN_CIPHER_SUITE_GCMP &&
+#endif
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+ cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256 &&
+ cipher != WLAN_CIPHER_SUITE_GCMP_256 &&
+#endif
+ cipher != WLAN_CIPHER_SUITE_CCMP) {
+ PRINTM(MERROR, "Invalid cipher suite specified\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ sec->param.encrypt_key.key_index = key_index;
+ if (key && key_len) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.key_material,
+ key, key_len, MLAN_MAX_KEY_LENGTH);
+ sec->param.encrypt_key.key_len = key_len;
+ }
+ /* Set WAPI key */
+ if (cipher == WLAN_CIPHER_SUITE_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ if (seq_len) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn, seq,
+ PN_SIZE, PN_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN",
+ sec->param.encrypt_key.pn, seq_len);
+ }
+ }
+ if (addr) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.mac_addr, addr,
+ ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
+ if (memcmp(sec->param.encrypt_key.mac_addr, bcast_addr,
+ ETH_ALEN) == 0)
+ sec->param.encrypt_key.key_flags =
+ KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags =
+ KEY_FLAG_SET_TX_KEY;
+ } else {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.mac_addr,
+ bcast_addr, ETH_ALEN,
+ MLAN_MAC_ADDR_LENGTH);
+ sec->param.encrypt_key.key_flags =
+ KEY_FLAG_GROUP_KEY | KEY_FLAG_SET_TX_KEY;
+ }
+ if (seq && seq_len) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn, seq, seq_len,
+ PN_SIZE);
+ sec->param.encrypt_key.key_flags |=
+ KEY_FLAG_RX_SEQ_VALID;
+ }
+
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ if (cipher == WLAN_CIPHER_SUITE_GCMP)
+ sec->param.encrypt_key.key_flags |= KEY_FLAG_GCMP;
+#endif
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+ else if (cipher == WLAN_CIPHER_SUITE_GCMP_256)
+ sec->param.encrypt_key.key_flags |= KEY_FLAG_GCMP_256;
+#endif
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+ if (cipher == WLAN_CIPHER_SUITE_CCMP_256)
+ sec->param.encrypt_key.key_flags |= KEY_FLAG_CCMP_256;
+#endif
+
+ if (cipher == WLAN_CIPHER_SUITE_AES_CMAC
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+ || cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256
+#endif
+ ) {
+ sec->param.encrypt_key.key_flags |=
+ KEY_FLAG_AES_MCAST_IGTK;
+ }
+ } else {
+ if (key_index == KEY_INDEX_CLEAR_ALL)
+ sec->param.encrypt_key.key_disable = MTRUE;
+ else {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ }
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ if (addr)
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.mac_addr, addr,
+ ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Enable the WEP key to driver
+ *
+ * @param priv A pointer to moal_private structure
+ * @param key A pointer to key data
+ * @param key_len Length of the key data
+ * @param index Key index
+ * @param wait_option wait_option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_cfg80211_set_wep_keys(moal_private *priv, const t_u8 *key,
+ int key_len, t_u8 index,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 cipher = 0;
+
+ ENTER();
+
+ if (key_len) {
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ ret = woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL,
+ 0, index, NULL, 0, wait_option);
+ } else {
+ /* No key provided so it is enable key. We
+ * want to just set the transmit key index
+ */
+ woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL, 0,
+ index, NULL, 0, wait_option);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief clear all mgmt ies
+ *
+ * @param priv A pointer to moal private structure
+ * @param wait_option wait_option
+ * @return N/A
+ */
+void woal_clear_all_mgmt_ies(moal_private *priv, t_u8 wait_option)
+{
+ t_u16 mask = 0;
+ /* clear BEACON WPS/P2P IE */
+ if (priv->beacon_wps_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ PRINTM(MCMND, "Clear BEACON WPS ie\n");
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
+ NULL, 0, MGMT_MASK_BEACON_WPS_P2P,
+ wait_option);
+ priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ if (priv->assocresp_qos_map_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ PRINTM(MCMND, "Clear associate response QOS map ie\n");
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
+ NULL, 0,
+ MGMT_MASK_ASSOC_RESP_QOS_MAP,
+ wait_option);
+ priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ /* clear mgmt frame ies */
+ if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_PROBE_REQ;
+ if (priv->beacon_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_BEACON;
+ if (priv->proberesp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_PROBE_RESP;
+ if (priv->assocresp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_ASSOC_RESP;
+ if (priv->proberesp_p2p_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_PROBE_RESP;
+ if (priv->beacon_vendor_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ mask |= MGMT_MASK_BEACON;
+ if (mask) {
+ PRINTM(MCMND, "Clear IES: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ priv->beacon_index, priv->probereq_index,
+ priv->proberesp_index, priv->assocresp_index,
+ priv->proberesp_p2p_index, priv->beacon_vendor_index);
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
+ NULL, 0, mask, wait_option);
+ }
+ priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+}
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief set bss role
+ *
+ * @param priv A pointer to moal private structure
+ * @param action Action: set or get
+ * @param role A pointer to bss role
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_bss_role_cfg(moal_private *priv, t_u16 action, t_u8 *bss_role)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (action == MLAN_ACT_SET) {
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET) {
+ /* set back the mac address */
+ woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT);
+ /* clear the mgmt ies */
+ woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief This function display P2P public action frame type
+ *
+ * @param buf A buffer to a management frame
+ * @param len buffer len
+ * @param chan the channel
+ * @param flag Tx/Rx flag. Tx:flag = 1;Rx:flag = 0;
+ *
+ * @return N/A
+ */
+void woal_cfg80211_display_p2p_actframe(const t_u8 *buf, int len,
+ struct ieee80211_channel *chan,
+ const t_u8 flag)
+{
+ const t_u8 p2p_oui[] = {0x50, 0x6f, 0x9a, 0x09};
+ t_u8 subtype;
+
+ ENTER();
+
+ if (!buf || len < (P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET + 1)) {
+ LEAVE();
+ return;
+ }
+
+ if (((struct ieee80211_mgmt *)buf)->u.action.category ==
+ P2P_ACT_FRAME_CATEGORY &&
+ !memcmp(buf + P2P_ACT_FRAME_OUI_OFFSET, p2p_oui, sizeof(p2p_oui))) {
+ subtype = *(buf + P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET);
+ switch (subtype) {
+ case P2P_GO_NEG_REQ:
+ PRINTM(MMSG,
+ "wlan: %s P2P Group Owner Negotiation Req Frame, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_GO_NEG_RSP:
+ PRINTM(MMSG,
+ "wlan: %s P2P Group Owner Negotiation Rsp Frame, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_GO_NEG_CONF:
+ PRINTM(MMSG,
+ "wlan: %s P2P Group Owner Negotiation Confirm Frame, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_INVITE_REQ:
+ PRINTM(MMSG,
+ "wlan: %s P2P Invitation Request, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_INVITE_RSP:
+ PRINTM(MMSG,
+ "wlan: %s P2P Invitation Response, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_DEVDIS_REQ:
+ PRINTM(MMSG,
+ "wlan: %s P2P Device Discoverability Request, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_DEVDIS_RSP:
+ PRINTM(MIOCTL,
+ "wlan: %s P2P Device Discoverability Response, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_PROVDIS_REQ:
+ PRINTM(MMSG,
+ "wlan: %s P2P Provision Discovery Request, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ case P2P_PROVDIS_RSP:
+ PRINTM(MMSG,
+ "wlan: %s P2P Provision Discovery Response, channel=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0);
+ break;
+ default:
+ PRINTM(MMSG,
+ "wlan: %s Unknown P2P Action Frame, channel=%d, subtype=%d\n",
+ (flag) ? "TX" : "RX",
+ (chan) ? chan->hw_value : 0, subtype);
+ break;
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief initialize p2p client for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_init_p2p_client(moal_private *priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ t_u8 bss_role;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p client\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct client */
+ wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief initialize p2p GO for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_init_p2p_go(moal_private *priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+ mlan_ds_wifi_direct_config p2p_config;
+ mlan_ds_ps_mgmt ps_mgmt;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when init p2p GO\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* first, init wifi direct to listen mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* second, init wifi direct to GO mode */
+ wifi_direct_mode = WIFI_DIRECT_MODE_GO;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* get the bss role, and set it to uAP */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_role != MLAN_BSS_ROLE_UAP) {
+ bss_role = MLAN_BSS_ROLE_UAP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+/* NoA:-- Interval = 100TUs and Duration= 50TUs, count=255*/
+#define DEF_NOA_COUNT 255
+ if (priv->phandle->noa_duration && priv->phandle->card_info->go_noa) {
+ memset(&p2p_config, 0, sizeof(p2p_config));
+ p2p_config.noa_enable = MTRUE;
+ p2p_config.index = 0;
+ p2p_config.noa_count = DEF_NOA_COUNT;
+ p2p_config.noa_duration = priv->phandle->noa_duration;
+ p2p_config.noa_interval = priv->phandle->noa_interval;
+ p2p_config.flags = WIFI_DIRECT_NOA;
+ woal_p2p_config(priv, MLAN_ACT_SET, &p2p_config);
+ memset(&ps_mgmt, 0, sizeof(ps_mgmt));
+ ps_mgmt.flags = PS_FLAG_PS_MODE;
+ ps_mgmt.ps_mode = PS_MODE_INACTIVITY;
+ woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt);
+ PRINTM(MMSG, "Enable NOA: duration=%d, interval=%d\n",
+ priv->phandle->noa_duration,
+ priv->phandle->noa_interval);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset bss role and wifi direct mode for wpa_supplicant
+ *
+ * @param priv A pointer to moal private structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_deinit_p2p(moal_private *priv)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u16 wifi_direct_mode;
+ t_u8 bss_role;
+ t_u8 channel_status;
+ moal_private *remain_priv = NULL;
+ mlan_ds_ps_mgmt ps_mgmt;
+
+ ENTER();
+
+ /* bss type check */
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MERROR, "Unexpected bss type when deinit p2p\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* unregister mgmt frame from FW */
+ if (priv->mgmt_subtype_mask) {
+ priv->mgmt_subtype_mask = 0;
+ if (woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
+ &priv->mgmt_subtype_mask,
+ MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR,
+ "deinit_p2p: fail to unregister mgmt frame\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (!remain_priv) {
+ PRINTM(MERROR,
+ "deinit_p2p: wrong remain_bss_index=%d\n",
+ priv->phandle->remain_bss_index);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_IOCTL_WAIT, MTRUE,
+ &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "deinit_p2p: Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie, &priv->phandle->chan,
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+ /* get the bss role */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* reset bss role */
+ if (bss_role != MLAN_BSS_ROLE_STA) {
+ memset(&ps_mgmt, 0, sizeof(ps_mgmt));
+ ps_mgmt.flags = PS_FLAG_PS_MODE;
+ ps_mgmt.ps_mode = PS_MODE_DISABLE;
+ woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt);
+ bss_role = MLAN_BSS_ROLE_STA;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/**
+ * @brief Request the driver to change the interface type
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param type Virtual interface types
+ * @param flags Flags
+ * @param params A pointer to vif_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type,
+#if KERNEL_VERSION(4, 12, 0) > CFG80211_VERSION_CODE
+ u32 *flags,
+#endif
+ struct vif_params *params)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ t_u8 bss_role;
+#endif
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (priv->wdev->iftype == type) {
+ PRINTM(MINFO, "Already set to required type\n");
+ goto done;
+ }
+#ifdef UAP_SUPPORT
+ if ((priv->bss_type == MLAN_BSS_TYPE_UAP) && (priv->bss_index > 0)) {
+ priv->wdev->iftype = type;
+ PRINTM(MMSG, "%s: Skip change virtual intf on uap: type=%d\n",
+ dev->name, type);
+ goto done;
+ }
+#endif
+
+ PRINTM(MIOCTL, "%s: change virturl intf=%d\n", dev->name, type);
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /** cancel previous remain on channel to avoid firmware hang */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ moal_private *remain_priv = NULL;
+
+ remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (!remain_priv) {
+ PRINTM(MERROR,
+ "change_virtual_intf:wrong remain_bss_index=%d\n",
+ priv->phandle->remain_bss_index);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_IOCTL_WAIT, MTRUE,
+ &channel_status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "change_virtual_intf: Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie, &priv->phandle->chan,
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+#endif
+#endif
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ (priv->wdev->iftype == NL80211_IFTYPE_AP ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_GO ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ if (priv->phandle->is_go_timer_set) {
+ woal_cancel_timer(&priv->phandle->go_timer);
+ priv->phandle->is_go_timer_set = MFALSE;
+ }
+ /* if we support wifi direct && priv->bss_type ==
+ * wifi_direct, and currently the interface type is AP
+ * or GO or client, that means wpa_supplicant deinit()
+ * wifi direct interface, so we should deinit bss_role
+ * and wifi direct mode, for other bss_type, we should
+ * not update bss_role and wifi direct mode
+ */
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_deinit_p2p(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ woal_cfg80211_del_beacon(wiphy, dev);
+ bss_role = MLAN_BSS_ROLE_STA;
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
+ &bss_role);
+ PRINTM(MIOCTL, "set bss role for STA\n");
+ }
+#endif
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to managed\n");
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (priv->phandle->is_go_timer_set) {
+ woal_cancel_timer(&priv->phandle->go_timer);
+ priv->phandle->is_go_timer_set = MFALSE;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_init_p2p_client(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ PRINTM(MINFO, "Setting interface type to P2P client\n");
+
+ break;
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+ case NL80211_IFTYPE_AP:
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /* Fall Through */
+ case NL80211_IFTYPE_P2P_GO:
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_init_p2p_go(priv)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->is_go_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->go_timer,
+ MOAL_TIMER_10S);
+ }
+ if (type == NL80211_IFTYPE_P2P_GO)
+ priv->wdev->iftype = NL80211_IFTYPE_P2P_GO;
+#endif
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ if (priv->bss_type == MLAN_BSS_TYPE_STA) {
+#ifdef STA_CFG80211
+ /** cancel pending scan */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+#endif
+ if (priv->probereq_index !=
+ MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL,
+ 0, NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ,
+ MOAL_IOCTL_WAIT);
+ bss_role = MLAN_BSS_ROLE_UAP;
+ woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
+ &bss_role);
+ PRINTM(MIOCTL, "set bss role for AP\n");
+ }
+#endif
+ if (type == NL80211_IFTYPE_AP)
+ priv->wdev->iftype = NL80211_IFTYPE_AP;
+ PRINTM(MINFO, "Setting interface type to P2P GO\n");
+
+ /* there is no need for P2P GO to set bss_mode */
+ goto done;
+
+ break;
+
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ priv->wdev->iftype = NL80211_IFTYPE_STATION;
+ PRINTM(MINFO, "Setting interface type to auto\n");
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the value of fragment
+ * threshold or rts threshold or retry limit
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param changed Change flags
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ pmlan_uap_bss_param sys_cfg = NULL;
+#endif
+#endif
+ int frag_thr = wiphy->frag_threshold;
+ int rts_thr = wiphy->rts_threshold;
+ int retry = wiphy->retry_long;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if (rts_thr == MLAN_FRAG_RTS_DISABLED)
+ rts_thr = MLAN_RTS_MAX_VALUE;
+ if (frag_thr == MLAN_FRAG_RTS_DISABLED)
+ frag_thr = MLAN_FRAG_MAX_VALUE;
+
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR,
+ "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ /* Initialize the invalid values so that the correct
+ * values below are downloaded to firmware
+ */
+ woal_set_sys_config_invalid_data(sys_cfg);
+ sys_cfg->frag_threshold = frag_thr;
+ sys_cfg->rts_threshold = rts_thr;
+ sys_cfg->retry_limit = retry;
+
+ if ((changed & WIPHY_PARAM_RTS_THRESHOLD) ||
+ (changed & WIPHY_PARAM_FRAG_THRESHOLD) ||
+ (changed &
+ (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) {
+ if (woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, sys_cfg)) {
+ kfree(sys_cfg);
+ goto fail;
+ }
+ }
+ kfree(sys_cfg);
+ }
+#endif
+#endif
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (woal_set_get_rts(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &rts_thr))
+ goto fail;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (woal_set_get_frag(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &frag_thr))
+ goto fail;
+ }
+ if (changed &
+ (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))
+ if (woal_set_get_retry(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &retry))
+ goto fail;
+ }
+#endif
+#endif
+ LEAVE();
+ return 0;
+
+fail:
+ PRINTM(MERROR, "Failed to change wiphy params %x\n", changed);
+ LEAVE();
+ return -EFAULT;
+}
+
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+/**
+ * @brief Request the driver to add a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ * @param params A pointer to key_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief Request the driver to add a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param mac_addr MAC address (NULL for group key)
+ * @param params A pointer to key_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+ bool pairwise,
+#endif
+ const t_u8 *mac_addr, struct key_params *params)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
+
+ ENTER();
+ if (priv->ft_pre_connect) {
+ PRINTM(MINFO, "Skip set keys during ft connecting\n");
+ return -EFAULT;
+ }
+ if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key,
+ params->key_len, params->seq, params->seq_len,
+ key_index, mac_addr, 0, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Error adding the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys added\n");
+
+ LEAVE();
+ return 0;
+}
+
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+/**
+ * @brief Request the driver to delete a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36)
+ * @param mac_addr MAC address (NULL for group key)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief Request the driver to delete a key
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param mac_addr MAC address (NULL for group key)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ t_u8 key_index,
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+ bool pairwise,
+#endif
+ const t_u8 *mac_addr)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
+
+ ENTER();
+ if (priv->phandle->driver_status) {
+ PRINTM(MERROR, "Block %s in abnormal driver state\n", __func__);
+ LEAVE();
+ return -EFAULT;
+ }
+ /* del_key will be trigger from cfg80211_rx_mlme_mgmt funtion
+ * where we receive deauth/disassoicate packet in rx_work
+ * use MOAL_NO_WAIT to avoid dead lock
+ */
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index,
+ mac_addr, 1, MOAL_NO_WAIT)) {
+ PRINTM(MERROR, "Error deleting the crypto keys\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ PRINTM(MINFO, "Crypto keys deleted\n");
+ LEAVE();
+ return 0;
+}
+
+#if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
+/**
+ * @brief Request to enable WEP key to driver
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ * @param ucast Unicast flag (for kernel > 2.6.37)
+ * @param mcast Multicast flag (for kernel > 2.6.37)
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief Request to enable WEP key to driver
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param netdev A pointer to net_device structure
+ * @param key_index Key index
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *netdev, t_u8 key_index
+#if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
+ ,
+ bool ucast, bool mcast
+#endif
+)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
+ mlan_bss_info bss_info;
+
+ ENTER();
+ memset(&bss_info, 0, sizeof(mlan_bss_info));
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (!bss_info.wep_status) {
+ LEAVE();
+ return ret;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+#if KERNEL_VERSION(2, 6, 30) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *netdev,
+ t_u8 key_index)
+{
+ PRINTM(MINFO, "set default mgmt key, key index=%d\n", key_index);
+
+ return 0;
+}
+#endif
+
+#if KERNEL_VERSION(3, 1, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief Set GTK rekey data to driver
+ *
+ * @param priv A pointer to moal_private structure
+ * @param gtk_rekey A pointer to mlan_ds_misc_gtk_rekey_data structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ *
+ * @return 0 --success, otherwise fail
+ */
+mlan_status woal_set_rekey_data(moal_private *priv,
+ mlan_ds_misc_gtk_rekey_data *gtk_rekey,
+ t_u8 action, t_u8 wait_option)
+{
+ mlan_ioctl_req *req;
+ mlan_ds_misc_cfg *misc_cfg;
+ int ret = 0;
+ mlan_status status;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+
+ if (req == NULL) {
+ ret = -ENOMEM;
+ } else {
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_GTK_REKEY_OFFLOAD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle,
+ &misc_cfg->param.gtk_rekey, gtk_rekey,
+ sizeof(mlan_ds_misc_gtk_rekey_data),
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Give the data necessary for GTK rekeying to the driver
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param data A pointer to cfg80211_gtk_rekey_data structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_gtk_rekey_data *data)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ mlan_ds_misc_gtk_rekey_data rekey;
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ if (priv->phandle->params.gtk_rekey_offload ==
+ GTK_REKEY_OFFLOAD_DISABLE) {
+ PRINTM(MMSG, "%s return: gtk_rekey_offload is DISABLE\n",
+ __func__);
+ LEAVE();
+ return ret;
+ }
+
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if (!fw_info.fw_supplicant_support) {
+ LEAVE();
+ return -1;
+ }
+
+ moal_memcpy_ext(priv->phandle, rekey.kek, data->kek, MLAN_KEK_LEN,
+ MLAN_KEK_LEN);
+ moal_memcpy_ext(priv->phandle, rekey.kck, data->kck, MLAN_KCK_LEN,
+ MLAN_KCK_LEN);
+ moal_memcpy_ext(priv->phandle, rekey.replay_ctr, data->replay_ctr,
+ MLAN_REPLAY_CTR_LEN, MLAN_REPLAY_CTR_LEN);
+
+ moal_memcpy_ext(priv->phandle, &priv->gtk_rekey_data, &rekey,
+ sizeof(mlan_ds_misc_gtk_rekey_data),
+ sizeof(mlan_ds_misc_gtk_rekey_data));
+ if (priv->phandle->params.gtk_rekey_offload ==
+ GTK_REKEY_OFFLOAD_SUSPEND) {
+ priv->gtk_data_ready = MTRUE;
+ LEAVE();
+ return ret;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_rekey_data(priv, &rekey, MLAN_ACT_SET, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef STA_SUPPORT
+/* Opportunistic Key Caching APIs functions support
+ *
+ * this function get pmksa entry list in private structure
+ * @param priv A pointer to moal_private structure
+ * @param bssid A pointer to bssid
+ * @return pointer to target entry or NULL
+ */
+struct pmksa_entry *woal_get_pmksa_entry(moal_private *priv, const u8 *bssid)
+{
+ struct pmksa_entry *entry = NULL;
+ unsigned long flags;
+
+ if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
+ PRINTM(MERROR, "Invalid interface structure\n");
+ return NULL;
+ }
+
+ spin_lock_irqsave(&priv->pmksa_list_lock, flags);
+ list_for_each_entry (entry, &priv->pmksa_cache_list, link) {
+ if (!memcmp(entry->bssid, bssid, ETH_ALEN)) {
+ spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
+
+ return NULL;
+}
+
+/**
+ * This function flush pmksa entry list in private structure
+ * @param priv A pointer to moal_private structure
+ * @return success of failure
+ */
+int woal_flush_pmksa_list(moal_private *priv)
+{
+ struct pmksa_entry *entry, *tmp;
+ unsigned long flags;
+
+ if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
+ PRINTM(MERROR, "Invalid interface structure\n");
+ return -1;
+ }
+
+ spin_lock_irqsave(&priv->pmksa_list_lock, flags);
+ list_for_each_entry_safe (entry, tmp, &priv->pmksa_cache_list, link) {
+ list_del(&entry->link);
+ kfree(entry);
+ }
+ INIT_LIST_HEAD(&priv->pmksa_cache_list);
+ spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
+
+ return 0;
+}
+
+/**
+ * This function add new pmksa entry to list
+ * @param wiphy A pointer to struct wiphy
+ * @param dev A pointer to net_device structure
+ * @param pmksa A pointer to cfg80211_pmksa structure
+ * @return success of failure
+ */
+int woal_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct pmksa_entry *entry = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
+ PRINTM(MERROR, "Invalid interface structure\n");
+ ret = -1;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "Set pmksa entry: bssid=" MACSTR "\n",
+ MAC2STR(pmksa->bssid));
+ entry = woal_get_pmksa_entry(priv, pmksa->bssid);
+ if (!entry) {
+ entry = kzalloc(sizeof(struct pmksa_entry), GFP_ATOMIC);
+ if (!entry) {
+ PRINTM(MERROR, "Fail to allocate pmksa entry\n");
+ goto done;
+ }
+ INIT_LIST_HEAD(&entry->link);
+ moal_memcpy_ext(priv->phandle, entry->bssid, pmksa->bssid,
+ ETH_ALEN, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, entry->pmkid, pmksa->pmkid,
+ PMKID_LEN, PMKID_LEN);
+ spin_lock_irqsave(&priv->pmksa_list_lock, flags);
+ list_add_tail(&entry->link, &priv->pmksa_cache_list);
+ spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
+ } else {
+ /** pmkid is differnt from previous value? */
+ memset(entry->pmkid, 0, PMKID_LEN);
+ moal_memcpy_ext(priv->phandle, entry->pmkid, pmksa->pmkid,
+ PMKID_LEN, PMKID_LEN);
+ }
+
+ /** Check if current roaming is going and received target pmkid */
+ if (priv->wait_target_ap_pmkid) {
+ struct cfg80211_connect_params *param = &priv->sme_current;
+
+ if (param && !memcmp(pmksa->bssid, param->bssid, ETH_ALEN)) {
+ PRINTM(MIOCTL,
+ "Current roaming target bssid=" MACSTR "\n",
+ MAC2STR(param->bssid));
+ priv->target_ap_pmksa = entry;
+ priv->wait_target_ap_pmkid = MFALSE;
+ wake_up_interruptible(&priv->okc_wait_q);
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * This function delete pmksa entry
+ * @param wiphy A pointer to struct wiphy
+ * @param dev A pointer to net_device structure
+ * @param pmksa A pointer to cfg80211_pmksa structure
+ * @return success of failure
+ */
+int woal_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct pmksa_entry *entry, *tmp;
+ unsigned long flags;
+
+ ENTER();
+
+ if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
+ PRINTM(MERROR, "Invalid interface structure\n");
+ LEAVE();
+ return -1;
+ }
+
+ PRINTM(MIOCTL, "Delete pmksa: bssid=" MACSTR "\n",
+ MAC2STR(pmksa->bssid));
+ spin_lock_irqsave(&priv->pmksa_list_lock, flags);
+ list_for_each_entry_safe (entry, tmp, &priv->pmksa_cache_list, link) {
+ if (!memcmp(entry->bssid, pmksa->bssid, ETH_ALEN)) {
+ list_del(&entry->link);
+ kfree(entry);
+ }
+ }
+ spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * This function flush pmksa entry list
+ * @param wiphy A pointer to struct wiphy
+ * @param dev A pointer to net_device structure
+ * @return success of failure
+ */
+int woal_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA)
+ return -1;
+
+ PRINTM(MIOCTL, "Flush pmksa list.\n");
+ return woal_flush_pmksa_list(priv);
+}
+#endif
+
+#if KERNEL_VERSION(3, 5, 0) > CFG80211_VERSION_CODE
+#if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
+/**
+ * @brief Request the driver to change the channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief Request the driver to change the channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ int ret = 0;
+ moal_private *priv = NULL;
+
+ ENTER();
+
+#if KERNEL_VERSION(3, 5, 0) > CFG80211_VERSION_CODE
+#if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
+ if (dev)
+ priv = woal_get_netdev_priv(dev);
+#endif
+#endif
+ if (!priv) {
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+
+ if (handle)
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ }
+ if (priv) {
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MERROR,
+ "This configuration is valid only when station is not connected\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ ret = woal_set_rf_channel(priv, chan, channel_type,
+ MOAL_IOCTL_WAIT);
+ }
+#endif
+#endif
+ priv->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+ }
+ /* set monitor channel support */
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
+static bool woal_is_pattern_supported(struct cfg80211_pkt_pattern *pat,
+ t_u8 *byte_seq, t_u8 max_byte_seq)
+{
+ int j, k, valid_byte_cnt = 0;
+ bool dont_care_byte = false;
+
+ for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
+ for (k = 0; k < 8; k++) {
+ if (pat->mask[j] & 1 << k) {
+ moal_memcpy_ext(NULL, byte_seq + valid_byte_cnt,
+ &pat->pattern[j * 8 + k], 1,
+ (t_u32)max_byte_seq -
+ (t_u32)valid_byte_cnt);
+ valid_byte_cnt++;
+ if (dont_care_byte)
+ return false;
+ } else {
+ if (valid_byte_cnt)
+ dont_care_byte = true;
+ }
+
+ if (valid_byte_cnt > max_byte_seq)
+ return false;
+ }
+ }
+
+ byte_seq[max_byte_seq] = valid_byte_cnt;
+
+ return true;
+}
+
+static int woal_get_coalesce_pkt_type(t_u8 *byte_seq)
+{
+ const t_u8 ipv4_mc_mac[] = {0x33, 0x33};
+ const t_u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
+ const t_u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff};
+
+ if ((byte_seq[0] & 0x01) && (byte_seq[COALESCE_MAX_BYTESEQ] == 1))
+ return PACKET_TYPE_UNICAST;
+ else if (!memcmp(byte_seq, bc_mac, 4))
+ return PACKET_TYPE_BROADCAST;
+ else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
+ byte_seq[COALESCE_MAX_BYTESEQ] == 2) ||
+ (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
+ byte_seq[COALESCE_MAX_BYTESEQ] == 3))
+ return PACKET_TYPE_MULTICAST;
+
+ return 0;
+}
+
+static int woal_fill_coalesce_rule_info(struct cfg80211_coalesce_rules *crule,
+ struct coalesce_rule *mrule)
+{
+ t_u8 byte_seq[COALESCE_MAX_BYTESEQ + 1];
+ struct filt_field_param *param;
+ int i;
+
+ mrule->max_coalescing_delay = crule->delay;
+
+ param = mrule->params;
+
+ for (i = 0; i < crule->n_patterns; i++) {
+ memset(byte_seq, 0, sizeof(byte_seq));
+ if (!woal_is_pattern_supported(&crule->patterns[i], byte_seq,
+ COALESCE_MAX_BYTESEQ)) {
+ PRINTM(MERROR, "Pattern not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!crule->patterns[i].pkt_offset) {
+ u8 pkt_type;
+
+ pkt_type = woal_get_coalesce_pkt_type(byte_seq);
+ if (pkt_type && mrule->pkt_type) {
+ PRINTM(MERROR,
+ "Multiple packet types not allowed\n");
+ return -EOPNOTSUPP;
+ } else if (pkt_type) {
+ mrule->pkt_type = pkt_type;
+ continue;
+ }
+ }
+
+ if (crule->condition == NL80211_COALESCE_CONDITION_MATCH)
+ param->operation = RECV_FILTER_MATCH_TYPE_EQ;
+ else
+ param->operation = RECV_FILTER_MATCH_TYPE_NE;
+
+ param->operand_len = byte_seq[COALESCE_MAX_BYTESEQ];
+ moal_memcpy_ext(NULL, param->operand_byte_stream, byte_seq,
+ param->operand_len, COALESCE_MAX_BYTESEQ);
+ param->offset = crule->patterns[i].pkt_offset;
+ param++;
+
+ mrule->num_of_fields++;
+ }
+
+ if (!mrule->pkt_type) {
+ PRINTM(MERROR, "Packet type can not be determined\n");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Set coalesce parameter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param coalesce_cfg A pointer to coalesce structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_coalesce(moal_private *priv, t_u16 action,
+ mlan_ds_coalesce_cfg *coalesce_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_COALESCE_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+
+ moal_memcpy_ext(priv->phandle, &misc_cfg->param.coalesce_cfg,
+ coalesce_cfg, sizeof(mlan_ds_coalesce_cfg),
+ sizeof(mlan_ds_coalesce_cfg));
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to set the coalesce
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param coalesce A pointer to cfg80211_coalesce structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_coalesce(struct wiphy *wiphy,
+ struct cfg80211_coalesce *coalesce)
+{
+ int ret = 0;
+ int i;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv = NULL;
+ mlan_ds_coalesce_cfg coalesce_cfg;
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MFATAL, "Unable to get handle\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
+ if (!coalesce) {
+ PRINTM(MMSG, "Disable coalesce and reset all previous rules\n");
+ } else {
+ coalesce_cfg.num_of_rules = coalesce->n_rules;
+ for (i = 0; i < coalesce->n_rules; i++) {
+ ret = woal_fill_coalesce_rule_info(
+ &coalesce->rules[i], &coalesce_cfg.rule[i]);
+ if (ret) {
+ PRINTM(MERROR,
+ "Recheck the patterns provided for rule %d\n",
+ i + 1);
+ return ret;
+ }
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_coalesce(priv, MLAN_ACT_SET, &coalesce_cfg)) {
+ PRINTM(MERROR, "wlan: Fail to set coalesce\n");
+ ret = -EFAULT;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Request the driver to set the bitrate
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param peer A pointer to peer address
+ * @param mask A pointer to cfg80211_bitrate_mask structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ mlan_bss_info bss_info;
+ enum ieee80211_band band;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ mlan_rate_cfg_t *rate_cfg = NULL;
+
+ ENTER();
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not set data rate in disconnected state\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (status)
+ goto done;
+ band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate_cfg = &rate->param.rate_cfg;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_SET;
+ rate_cfg->rate_type = MLAN_RATE_BITMAP;
+
+ /* Fill HR/DSSS rates. */
+ if (band == IEEE80211_BAND_2GHZ)
+ rate_cfg->bitmap_rates[0] = mask->control[band].legacy & 0x000f;
+
+ /* Fill OFDM rates */
+ if (band == IEEE80211_BAND_2GHZ)
+ rate_cfg->bitmap_rates[1] =
+ (mask->control[band].legacy & 0x0ff0) >> 4;
+ else
+ rate_cfg->bitmap_rates[1] = mask->control[band].legacy;
+
+#if KERNEL_VERSION(3, 4, 0) <= CFG80211_VERSION_CODE
+ /* Fill MCS rates */
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+ rate_cfg->bitmap_rates[2] = mask->control[band].ht_mcs[0];
+#else
+ rate_cfg->bitmap_rates[2] = mask->control[band].mcs[0];
+#endif
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+ rate_cfg->bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
+#else
+ rate_cfg->bitmap_rates[2] |= mask->control[band].mcs[1] << 8;
+#endif
+#endif
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if KERNEL_VERSION(2, 6, 38) <= CFG80211_VERSION_CODE
+/**
+ * @brief Request the driver to get antenna configuration
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param tx_ant Bitmaps of allowed antennas to use for TX
+ * @param rx_ant Bitmaps of allowed antennas to use for RX
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv = NULL;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MFATAL, "Unable to get handle\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ *tx_ant = radio->param.ant_cfg.tx_antenna;
+ *rx_ant = radio->param.ant_cfg.rx_antenna;
+ } else {
+ *tx_ant = radio->param.ant_cfg_1x1.antenna;
+ *rx_ant = radio->param.ant_cfg_1x1.antenna;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ /* Driver must return -EINVAL to cfg80211 */
+ if (ret)
+ ret = -EINVAL;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to set antenna configuration
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param tx_ant Bitmaps of allowed antennas to use for TX
+ * @param rx_ant Bitmaps of allowed antennas to use for RX
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv = NULL;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MFATAL, "Unable to get handle\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+ if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ radio->param.ant_cfg.tx_antenna = tx_ant;
+ radio->param.ant_cfg.rx_antenna = rx_ant;
+ } else {
+ radio->param.ant_cfg_1x1.antenna = tx_ant;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ /* Driver must return -EINVAL to cfg80211 */
+ if (ret)
+ ret = -EINVAL;
+ LEAVE();
+ return ret;
+}
+#endif
+/**
+ * @brief register/unregister mgmt frame forwarding
+ *
+ * @param priv A pointer to moal_private structure
+ * @param frame_type Bit mask for mgmt frame type
+ * @param reg Register or unregister
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void woal_mgmt_frame_register(moal_private *priv, u16 frame_type, bool reg)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mgmt_subtype_mask = 0x0;
+ t_u32 last_mgmt_subtype_mask = priv->mgmt_subtype_mask;
+
+ ENTER();
+
+#ifdef SDIO_SUSPEND_RESUME
+ if (priv->phandle->shutdown_hs_in_process) {
+ LEAVE();
+ return;
+ }
+#endif
+
+ if (reg == MTRUE) {
+ /* set mgmt_subtype_mask based on origin value */
+ mgmt_subtype_mask =
+ last_mgmt_subtype_mask | BIT(frame_type >> 4);
+ } else {
+ /* clear mgmt_subtype_mask */
+ mgmt_subtype_mask =
+ last_mgmt_subtype_mask & ~BIT(frame_type >> 4);
+ }
+ PRINTM(MIOCTL,
+ "%s: frame_type=0x%x mgmt_subtype_mask=0x%x last_mgmt_subtype_mask=0x%x\n",
+ priv->netdev->name, frame_type, mgmt_subtype_mask,
+ last_mgmt_subtype_mask);
+ if (mgmt_subtype_mask != last_mgmt_subtype_mask) {
+ last_mgmt_subtype_mask = mgmt_subtype_mask;
+ /* Notify driver that a mgmt frame type was registered.
+ * Note that this callback may not sleep, and cannot run
+ * concurrently with itself.
+ */
+ status = woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
+ &mgmt_subtype_mask, MOAL_NO_WAIT);
+ priv->mgmt_subtype_mask = last_mgmt_subtype_mask;
+ }
+
+ LEAVE();
+}
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+/**
+ * @brief register/unregister mgmt frame forwarding
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param frame_type Bit mask for mgmt frame type
+ * @param reg Register or unregister
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev, u16 frame_type,
+ bool reg)
+#else
+#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct mgmt_frame_regs *upd)
+#else
+/**
+ * @brief register/unregister mgmt frame forwarding
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param frame_type Bit mask for mgmt frame type
+ * @param reg Register or unregister
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u16 frame_type, bool reg)
+#endif
+#endif
+{
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ struct net_device *dev = wdev->netdev;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
+ if ((upd->interface_stypes & BIT(IEEE80211_STYPE_AUTH >> 4))
+ /** Supplicant 2.8 always register auth, FW will handle auth when
+ * host_mlme=0
+ */
+ && !moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ upd->interface_stypes &= ~BIT(IEEE80211_STYPE_AUTH >> 4);
+ woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET, &upd->interface_stypes,
+ MOAL_NO_WAIT);
+#else
+ if (frame_type == IEEE80211_STYPE_AUTH
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ /** Supplicant 2.8 always register auth, FW will handle auth when
+ * host_mlme=0
+ */
+ && !moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
+#endif
+ ) {
+ LEAVE();
+ return;
+ }
+ woal_mgmt_frame_register(priv, frame_type, reg);
+#endif
+ LEAVE();
+}
+
+#if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 3, 0) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param params A pointer to cfg80211_mgmt_tx_params structure
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param wait Duration to wait
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param no_cck No CCK check
+ * @param dont_wait_for_ack Do not wait for ACK
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param wait Duration to wait
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param no_cck No CCK check
+ * @param dont_wait_for_ack Do not wait for ACK
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param wait Duration to wait
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param no_cck No CCK check
+ * @param dont_wait_for_ack Do not wait for ACK
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param wait Duration to wait
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param no_cck No CCK check
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param offchan Off channel or not
+ * @param channel_type Channel type
+ * @param channel_type_valid Is channel type valid or not
+ * @param wait Duration to wait
+ * @param buf Frame buffer
+ * @param len Frame length
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+ struct net_device *dev,
+#else
+ struct wireless_dev *wdev,
+#endif
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+ struct cfg80211_mgmt_tx_params *params,
+#else
+ struct ieee80211_channel *chan, bool offchan,
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+#endif
+ unsigned int wait, const u8 *buf, size_t len,
+#if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
+ bool no_cck,
+#endif
+#if KERNEL_VERSION(3, 3, 0) <= CFG80211_VERSION_CODE
+ bool dont_wait_for_ack,
+#endif
+#endif
+ u64 *cookie)
+{
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ struct net_device *dev = wdev->netdev;
+#endif
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+ struct ieee80211_channel *chan = params->chan;
+ unsigned int wait = params->wait;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u16 packet_len = 0;
+ t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ t_u32 pkt_type;
+ t_u32 tx_control;
+#if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
+ t_u8 channel_status;
+ t_u32 duration;
+ moal_private *remain_priv = NULL;
+#endif
+
+ unsigned long flags;
+ struct sk_buff *skb = NULL;
+ struct tx_status_info *tx_info = NULL;
+ t_u32 remain_len = 0;
+ t_u16 fc, type, stype;
+
+ ENTER();
+
+ if (buf == NULL || len == 0) {
+ PRINTM(MERROR, "%s: corrupt data\n", __func__);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* If the packet is probe response, that means we are in listen phase,
+ * so we should not call remain_on_channel_cfg because
+ * remain_on_channl already handled it. If the packet if action, that
+ * means we are in PD/GO negotiation, so we should call
+ * remain_on_channel_cfg in order to receive action frame from peer
+ * device
+ */
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (ieee80211_is_probe_resp(
+ ((struct ieee80211_mgmt *)buf)->frame_control)) {
+ PRINTM(MIOCTL, "Skip send probe_resp in GO/UAP mode\n");
+ goto done;
+ }
+ fc = le16_to_cpu(((struct ieee80211_mgmt *)buf)->frame_control);
+ type = fc & IEEE80211_FCTL_FTYPE;
+ stype = fc & IEEE80211_FCTL_STYPE;
+ if (type == IEEE80211_FTYPE_MGMT) {
+ switch (stype) {
+ case IEEE80211_STYPE_AUTH:
+ PRINTM(MMSG, "wlan: HostMlme %s send Auth\n",
+ priv->netdev->name);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_DISASSOC:
+ PRINTM(MMSG,
+ "wlan: HostMlme %s send deauth/disassoc\n",
+ priv->netdev->name);
+ break;
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+ PRINTM(MMSG,
+ "wlan: HostMlme %s send assoc/reassoc resp\n",
+ priv->netdev->name);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+#if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
+ if ((ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control))
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
+#endif
+ ) {
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ woal_cfg80211_display_p2p_actframe(buf, len, chan,
+ MTRUE);
+ if (priv->phandle->is_go_timer_set) {
+ woal_cancel_timer(&priv->phandle->go_timer);
+ priv->phandle->is_go_timer_set = MFALSE;
+ }
+#endif
+ if (priv->phandle->is_remain_timer_set) {
+ woal_cancel_timer(&priv->phandle->remain_timer);
+ woal_remain_timer_func(priv->phandle);
+ }
+ /* With sd8777 We have difficulty to receive response packet in
+ * 500ms
+ */
+#define MGMT_TX_DEFAULT_WAIT_TIME 1500
+ if (priv->phandle->remain_on_channel)
+ remain_priv =
+ priv->phandle
+ ->priv[priv->phandle->remain_bss_index];
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel && remain_priv) {
+ if (woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_IOCTL_WAIT, MTRUE,
+ &channel_status, NULL, 0, 0))
+ PRINTM(MERROR,
+ "mgmt_tx:Fail to cancel remain on channel\n");
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+#ifdef STA_CFG80211
+ /** cancel pending scan */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+#endif
+
+ if (chan) {
+ duration = (wait > MGMT_TX_DEFAULT_WAIT_TIME) ?
+ wait :
+ MGMT_TX_DEFAULT_WAIT_TIME;
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ if (channel_type_valid)
+ ret = woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE,
+ &channel_status, chan, channel_type,
+ duration);
+ else
+#endif
+ ret = woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE,
+ &channel_status, chan, 0, duration);
+ if (ret) {
+ /* Return fail will cause p2p connection fail
+ */
+ woal_sched_timeout(2);
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ if (channel_type_valid)
+ ret = woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE,
+ &channel_status, chan,
+ channel_type, duration);
+ else
+#endif
+ ret = woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE,
+ &channel_status, chan, 0,
+ duration);
+ PRINTM(MERROR,
+ "Try configure remain on channel again, ret=%d\n",
+ ret);
+ ret = 0;
+ } else {
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->remain_bss_index =
+ priv->bss_index;
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ priv->phandle->channel_type = channel_type;
+#endif
+ moal_memcpy_ext(
+ priv->phandle, &priv->phandle->chan,
+ chan, sizeof(struct ieee80211_channel),
+ sizeof(struct ieee80211_channel));
+ PRINTM(MIOCTL,
+ "%s: Mgmt Tx: Set remain channel=%d duration=%d\n",
+ dev->name,
+ ieee80211_frequency_to_channel(
+ chan->center_freq),
+ duration);
+ }
+ }
+ }
+#endif
+
+ /* pkt_type + tx_control */
+#define HEADER_SIZE 8
+ packet_len = (t_u16)len + MLAN_MAC_ADDR_LENGTH;
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+#if KERNEL_VERSION(3, 8, 0) > LINUX_VERSION_CODE
+ *cookie = random32() | 1;
+#else
+ *cookie = prandom_u32() | 1;
+#endif
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ remain_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ /* Add pkt_type and tx_control */
+ moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
+ &pkt_type, sizeof(pkt_type), remain_len);
+ remain_len -= sizeof(pkt_type);
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ &tx_control, sizeof(tx_control), remain_len);
+ remain_len -= sizeof(tx_control);
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
+ &packet_len, sizeof(packet_len), remain_len);
+ remain_len -= sizeof(packet_len);
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
+ sizeof(packet_len),
+ buf, PACKET_ADDR4_POS, remain_len);
+ remain_len -= PACKET_ADDR4_POS;
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
+ sizeof(packet_len) + PACKET_ADDR4_POS,
+ addr, MLAN_MAC_ADDR_LENGTH, remain_len);
+ remain_len -= MLAN_MAC_ADDR_LENGTH;
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
+ sizeof(packet_len) + PACKET_ADDR4_POS +
+ MLAN_MAC_ADDR_LENGTH,
+ buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS,
+ remain_len);
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ if ((ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control))
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
+#endif
+ ) {
+ pmbuf->flags = MLAN_BUF_FLAG_TX_STATUS;
+ if (!priv->tx_seq_num)
+ priv->tx_seq_num++;
+ pmbuf->tx_seq_num = priv->tx_seq_num++;
+ tx_info = kzalloc(sizeof(struct tx_status_info), GFP_ATOMIC);
+ if (tx_info) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb) {
+ moal_memcpy_ext(priv->phandle, skb->data, buf,
+ len, len);
+ skb_put(skb, len);
+ spin_lock_irqsave(&priv->tx_stat_lock, flags);
+ tx_info->tx_cookie = *cookie;
+ tx_info->tx_skb = skb;
+ tx_info->tx_seq_num = pmbuf->tx_seq_num;
+ if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
+ (priv->phandle->remain_on_channel && !wait))
+ tx_info->cancel_remain_on_channel =
+ MTRUE;
+ INIT_LIST_HEAD(&tx_info->link);
+ list_add_tail(&tx_info->link,
+ &priv->tx_stat_queue);
+ spin_unlock_irqrestore(&priv->tx_stat_lock,
+ flags);
+ } else {
+ kfree(tx_info);
+ tx_info = NULL;
+ }
+ }
+ }
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* Delay 30ms to guarantee the packet has been already tx'ed,
+ * because if we call cfg80211_mgmt_tx_status() immediately,
+ * then wpa_supplicant will call cancel_remain_on_channel(),
+ * which may affect the mgmt frame tx. Meanwhile it is only
+ * necessary for P2P action handshake to wait 30ms.
+ */
+ if ((ieee80211_is_action(
+ ((struct ieee80211_mgmt *)buf)->frame_control))
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
+#endif
+ ) {
+ if (tx_info)
+ break;
+ else
+ woal_sched_timeout(30);
+ }
+ /* Notify the mgmt tx status */
+#if KERNEL_VERSION(2, 6, 37) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
+ cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true,
+ GFP_ATOMIC);
+#else
+ cfg80211_mgmt_tx_status(priv->wdev, *cookie, buf, len, true,
+ GFP_ATOMIC);
+#endif
+#endif
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+
+done:
+
+ if (status != MLAN_STATUS_PENDING) {
+ if (tx_info)
+ woal_remove_tx_info(priv, tx_info->tx_seq_num);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add custom ie to mgmt frames.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies_data Beacon ie
+ * @param beacon_index The index for beacon when auto index
+ * @param proberesp_ies_data Probe resp ie
+ * @param proberesp_index The index for probe resp when auto index
+ * @param assocresp_ies_data Assoc resp ie
+ * @param assocresp_index The index for assoc resp when auto index
+ * @param probereq_ies_data Probe req ie
+ * @param probereq_index The index for probe req when auto index
+ * @param wait_option wait option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static mlan_status
+woal_cfg80211_custom_ie(moal_private *priv, custom_ie *beacon_ies_data,
+ t_u16 *beacon_index, custom_ie *proberesp_ies_data,
+ t_u16 *proberesp_index, custom_ie *assocresp_ies_data,
+ t_u16 *assocresp_index, custom_ie *probereq_ies_data,
+ t_u16 *probereq_index, t_u8 wait_option)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ t_u8 *pos = NULL;
+ t_u16 len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 remain_len = 0;
+
+ ENTER();
+
+ custom_ie = kzalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL);
+ if (!custom_ie) {
+ PRINTM(MERROR, "Fail to allocate custome_ie\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ custom_ie->type = TLV_TYPE_MGMT_IE;
+
+ pos = (t_u8 *)custom_ie->ie_data_list;
+ remain_len = sizeof(custom_ie->ie_data_list);
+ if (beacon_ies_data) {
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE +
+ beacon_ies_data->ie_length;
+ moal_memcpy_ext(priv->phandle, pos, beacon_ies_data, len,
+ remain_len);
+ pos += len;
+ remain_len -= len;
+ custom_ie->len += len;
+ }
+
+ if (proberesp_ies_data) {
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE +
+ proberesp_ies_data->ie_length;
+ moal_memcpy_ext(priv->phandle, pos, proberesp_ies_data, len,
+ remain_len);
+ pos += len;
+ remain_len -= len;
+ custom_ie->len += len;
+ }
+
+ if (assocresp_ies_data) {
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE +
+ assocresp_ies_data->ie_length;
+ moal_memcpy_ext(priv->phandle, pos, assocresp_ies_data, len,
+ remain_len);
+ pos += len;
+ remain_len -= len;
+ custom_ie->len += len;
+ }
+
+ if (probereq_ies_data) {
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE +
+ probereq_ies_data->ie_length;
+ moal_memcpy_ext(priv->phandle, pos, probereq_ies_data, len,
+ remain_len);
+ pos += len;
+ remain_len -= len;
+ custom_ie->len += len;
+ }
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ PRINTM(MERROR, "Fail to allocate ioctl_req\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, custom_ie,
+ sizeof(mlan_ds_misc_custom_ie),
+ sizeof(mlan_ds_misc_custom_ie));
+
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* get the assigned index */
+ pos = (t_u8 *)(&misc->param.cust_ie.ie_data_list[0].ie_index);
+ if (beacon_ies_data && beacon_ies_data->ie_length &&
+ beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save beacon ie index after auto-indexing */
+ *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
+ len = sizeof(*beacon_ies_data) - MAX_IE_SIZE +
+ beacon_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (proberesp_ies_data && proberesp_ies_data->ie_length &&
+ proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *proberesp_index = *((t_u16 *)pos);
+ len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE +
+ proberesp_ies_data->ie_length;
+ pos += len;
+ }
+
+ if (assocresp_ies_data && assocresp_ies_data->ie_length &&
+ assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save assoc resp ie index after auto-indexing */
+ *assocresp_index = *((t_u16 *)pos);
+ len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE +
+ assocresp_ies_data->ie_length;
+ pos += len;
+ }
+ if (probereq_ies_data && probereq_ies_data->ie_length &&
+ probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *probereq_index = *((t_u16 *)pos);
+ len = sizeof(*probereq_ies_data) - MAX_IE_SIZE +
+ probereq_ies_data->ie_length;
+ pos += len;
+ }
+ // TODO why we check status_code at end
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
+ status = MLAN_STATUS_FAILURE;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ kfree(custom_ie);
+ LEAVE();
+ return status;
+}
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief set Qos map
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param qos_map A pointer to cfg80211_qos_map structure
+ *
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_qos_map(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_qos_map *qos_map)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int i, j, ret = 0;
+
+ ENTER();
+ /**clear dscp map*/
+ if (!qos_map) {
+ memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
+ goto done;
+ }
+
+ /**update dscp map*/
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ PRINTM(MINFO, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
+ qos_map->up[i].low, qos_map->up[i].high);
+ if (qos_map->up[i].low != 0xff && qos_map->up[i].high != 0xff &&
+ qos_map->up[i].high <= 63) {
+ for (j = qos_map->up[i].low; j <= qos_map->up[i].high;
+ j++)
+ priv->dscp_map[j] = i;
+ }
+ }
+
+ for (i = 0; i < qos_map->num_des; i++) {
+ if ((qos_map->dscp_exception[i].dscp <= 63) &&
+ (qos_map->dscp_exception[i].up <= 7)) {
+ PRINTM(MINFO, "dscp excpt: value=%d priority=%d\n",
+ qos_map->dscp_exception[i].dscp,
+ qos_map->dscp_exception[i].up);
+ priv->dscp_map[qos_map->dscp_exception[i].dscp] =
+ qos_map->dscp_exception[i].up;
+ }
+ }
+
+ /**UAP update (re)associate response*/
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ IEEEtypes_Generic_t qos_map_ie;
+ t_u16 qos_map_ies_len;
+
+ qos_map_ie.ieee_hdr.element_id = QOS_MAPPING;
+ qos_map_ie.ieee_hdr.len =
+ 2 * qos_map->num_des + sizeof(qos_map->up);
+ qos_map_ies_len =
+ qos_map_ie.ieee_hdr.len + sizeof(qos_map_ie.ieee_hdr);
+
+ if (qos_map_ies_len > sizeof(qos_map_ie.data)) {
+ PRINTM(MERROR,
+ "QoS MAP IE size exceeds the buffer len\n");
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, qos_map_ie.data,
+ (t_u8 *)qos_map->dscp_exception,
+ 2 * qos_map->num_des, sizeof(qos_map_ie.data));
+ moal_memcpy_ext(priv->phandle,
+ &qos_map_ie.data[2 * qos_map->num_des],
+ (t_u8 *)qos_map->up, sizeof(qos_map->up),
+ sizeof(qos_map_ie.data) - 2 * qos_map->num_des);
+
+ /* set the assoc response ies */
+ ret = woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
+ (t_u8 *)&qos_map_ie,
+ qos_map_ies_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP_QOS_MAP,
+ MOAL_IOCTL_WAIT);
+ if (ret) {
+ PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
+ goto done;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief get specific ie
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ie_out Pointer to out IE buf
+ * @param ie_out_len Total length of ie_out
+ * @param mask IE mask
+ *
+ * @return out IE length
+ */
+static t_u16 woal_get_specific_ie(const t_u8 *ie, int len, t_u8 *ie_out,
+ t_u32 ie_out_len, t_u16 mask)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ t_u16 out_len = 0;
+ IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
+ const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
+ const u8 p2p_oui[4] = {0x50, 0x6f, 0x9a, 0x09};
+ const u8 wfd_oui[4] = {0x50, 0x6f, 0x9a, 0x0a};
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+
+ ENTER();
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ if (id == VENDOR_SPECIFIC_221) {
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
+ PRINTM(MIOCTL, "find WMM IE\n");
+ } else if (!memcmp(pvendor_ie->vend_hdr.oui, p2p_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type ==
+ p2p_oui[3]) {
+ if (mask & IE_MASK_P2P) {
+ /** only get first p2p ie here */
+ moal_memcpy_ext(NULL, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ break;
+ }
+ } else if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type ==
+ wps_oui[3]) {
+ if (mask & IE_MASK_WPS) {
+ if ((out_len + length + 2) <
+ ie_out_len) {
+ moal_memcpy_ext(
+ NULL, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "get_specific_ie: IE too big, fail copy WPS IE\n");
+ break;
+ }
+ }
+ } else if (!memcmp(pvendor_ie->vend_hdr.oui, wfd_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type ==
+ wfd_oui[3]) {
+ if (mask & IE_MASK_WFD) {
+ if ((out_len + length + 2) <
+ ie_out_len) {
+ moal_memcpy_ext(
+ NULL, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "get_specific_ie: IE too big, fail copy WFD IE\n");
+ break;
+ }
+ }
+ } else if (mask & IE_MASK_VENDOR) {
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(NULL, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "get_specific_ie:IE too big, fail copy VENDOR IE\n");
+ break;
+ }
+ }
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ LEAVE();
+ return out_len;
+}
+
+/**
+ * @brief Find specific IE from IE buffer
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param spec_ie Pointer to specific IE buffer
+ * @param spec_len Total length of specific IE
+ *
+ * @return out IE length
+ */
+static t_u8 woal_find_ie(const t_u8 *ie, int len, const t_u8 *spec_ie,
+ int spec_len)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ if ((length + 2) == spec_len) {
+ if (!memcmp(pos, spec_ie, spec_len))
+ return MTRUE;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief Filter specific IE in ie buf
+ *
+ * @param priv pointer to moal private structure
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ie_out Pointer to out IE buf
+ * @param ie_out_len Total length of ie_out
+ * @param wps_flag flag for wps/p2p
+ * @param dup_ie Pointer to duplicate ie
+ * @param dup_ie_len duplicate IE len
+ *
+ * @return out IE length
+ */
+static t_u16 woal_filter_beacon_ies(moal_private *priv, const t_u8 *ie, int len,
+ t_u8 *ie_out, t_u32 ie_out_len,
+ t_u16 wps_flag, const t_u8 *dup_ie,
+ int dup_ie_len)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ t_u16 out_len = 0;
+ IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
+ const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
+ const u8 p2p_oui[4] = {0x50, 0x6f, 0x9a, 0x09};
+ const u8 wfd_oui[4] = {0x50, 0x6f, 0x9a, 0x0a};
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+ t_u8 find_p2p_ie = MFALSE;
+ t_u8 enable_11d = MFALSE;
+ t_u8 ext_id = 0;
+ int ie_len;
+
+ /* ERP_INFO/EXTENDED_SUPPORT_RATES/HT_CAPABILITY/HT_OPERATION/WMM
+ * and WPS/P2P/WFD IE will be fileter out
+ */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ if (dup_ie && dup_ie_len &&
+ woal_find_ie(dup_ie, dup_ie_len, pos, length + 2)) {
+ PRINTM(MIOCTL, "skip duplicate IE\n");
+ pos += (length + 2);
+ left_len -= (length + 2);
+ continue;
+ }
+ switch (id) {
+ case COUNTRY_INFO:
+ enable_11d = MTRUE;
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "IE too big, fail copy COUNTRY INFO IE\n");
+ }
+ break;
+ case HT_CAPABILITY:
+ case HT_OPERATION:
+ case VHT_CAPABILITY:
+ case VHT_OPERATION:
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle,
+ ie_out + out_len, pos,
+ length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "IE too big, fail copy COUNTRY INFO IE\n");
+ }
+ }
+ break;
+ case EXTENDED_SUPPORTED_RATES:
+ case WLAN_EID_ERP_INFO:
+ /* Fall Through */
+ case REGULATORY_CLASS:
+ /* Fall Through */
+ case OVERLAPBSSSCANPARAM:
+ /* Fall Through */
+ case WAPI_IE:
+ break;
+ case EXTENSION:
+ ext_id = *(pos + 2);
+ if ((ext_id == HE_CAPABILITY ||
+ ext_id == HE_OPERATION) &&
+ !moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ break;
+ else {
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle,
+ ie_out + out_len, pos,
+ length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "IE too big, fail copy EXTENSION IE\n");
+ }
+ break;
+ }
+ case EXT_CAPABILITY:
+ /* filter out EXTCAP */
+ if (wps_flag & IE_MASK_EXTCAP) {
+ ie_len = length + 2;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ (t_u8 *)pos, &ie_len,
+ MOAL_IOCTL_WAIT))
+ PRINTM(MERROR,
+ "Fail to set EXTCAP IE\n");
+ break;
+ }
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "IE too big, fail copy EXTCAP IE\n");
+ }
+ break;
+ case VENDOR_SPECIFIC_221:
+ /* filter out wmm ie */
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
+ break;
+ }
+ /* filter out wps ie */
+ else if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
+ if (wps_flag & IE_MASK_WPS)
+ break;
+ }
+ /* filter out first p2p ie */
+ else if (!memcmp(pvendor_ie->vend_hdr.oui, p2p_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == p2p_oui[3]) {
+ if (!find_p2p_ie && (wps_flag & IE_MASK_P2P)) {
+ find_p2p_ie = MTRUE;
+ break;
+ }
+ }
+ /* filter out wfd ie */
+ else if (!memcmp(pvendor_ie->vend_hdr.oui, wfd_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wfd_oui[3]) {
+ if (wps_flag & IE_MASK_WFD)
+ break;
+ } else if (wps_flag & IE_MASK_VENDOR) {
+ // filter out vendor IE
+ break;
+ }
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR,
+ "IE too big, fail copy VENDOR_SPECIFIC_221 IE\n");
+ }
+ break;
+ default:
+ if ((out_len + length + 2) < ie_out_len) {
+ moal_memcpy_ext(priv->phandle, ie_out + out_len,
+ pos, length + 2,
+ ie_out_len - out_len);
+ out_len += length + 2;
+ } else {
+ PRINTM(MERROR, "IE too big, fail copy %d IE\n",
+ id);
+ }
+ break;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+
+ if (enable_11d)
+ woal_set_11d(priv, MOAL_IOCTL_WAIT, MTRUE);
+ return out_len;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief Check if selected_registrar_on in wps_ie
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 is_selected_registrar_on(const t_u8 *ie, int len)
+{
+#define WPS_IE_FIX_LEN 6
+#define TLV_ID_SELECTED_REGISTRAR 0x1041
+ int left_len = len - WPS_IE_FIX_LEN;
+
+ TLV_Generic_t *tlv = (TLV_Generic_t *)(ie + WPS_IE_FIX_LEN);
+ u16 tlv_type, tlv_len;
+ u8 *pos = NULL;
+
+ while (left_len > sizeof(TLV_Generic_t)) {
+ tlv_type = ntohs(tlv->type);
+ tlv_len = ntohs(tlv->len);
+ if (tlv_type == TLV_ID_SELECTED_REGISTRAR) {
+ PRINTM(MIOCTL, "Selected Registrar found !");
+ pos = (u8 *)tlv + sizeof(TLV_Generic_t);
+ if (*pos == 1)
+ return MTRUE;
+ else
+ return MFALSE;
+ }
+ tlv = (TLV_Generic_t *)((u8 *)tlv + tlv_len +
+ sizeof(TLV_Generic_t));
+ left_len -= tlv_len + sizeof(TLV_Generic_t);
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief Check if selected_registrar_on in ies
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ *
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u16 woal_is_selected_registrar_on(const t_u8 *ie, int len)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+ t_u8 id = 0;
+ IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
+ const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
+
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ id = *pos;
+ if ((length + 2) > left_len)
+ break;
+ switch (id) {
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
+ PRINTM(MIOCTL, "Find WPS ie\n");
+ return is_selected_registrar_on(pos,
+ length + 2);
+ }
+ break;
+ default:
+ break;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return MFALSE;
+}
+#endif
+
+/**
+ * @brief config AP or GO for mgmt frame ies.
+ *
+ * @param priv A pointer to moal private structure
+ * @param beacon_ies A pointer to beacon ies
+ * @param beacon_ies_len Beacon ies length
+ * @param proberesp_ies A pointer to probe resp ies
+ * @param proberesp_ies_len Probe resp ies length
+ * @param assocresp_ies A pointer to probe resp ies
+ * @param assocresp_ies_len Assoc resp ies length
+ * @param probereq_ies A pointer to probe req ies
+ * @param probereq_ies_len Probe req ies length *
+ * @param mask Mgmt frame mask
+ * @param wait_option wait_option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_mgmt_frame_ie(
+ moal_private *priv, const t_u8 *beacon_ies, size_t beacon_ies_len,
+ const t_u8 *proberesp_ies, size_t proberesp_ies_len,
+ const t_u8 *assocresp_ies, size_t assocresp_ies_len,
+ const t_u8 *probereq_ies, size_t probereq_ies_len, t_u16 mask,
+ t_u8 wait_option)
+{
+ int ret = 0;
+ t_u8 *pos = NULL;
+ custom_ie *beacon_ies_data = NULL;
+ custom_ie *proberesp_ies_data = NULL;
+ custom_ie *assocresp_ies_data = NULL;
+ custom_ie *probereq_ies_data = NULL;
+
+ /* static variables for mgmt frame ie auto-indexing */
+ t_u16 beacon_index = priv->beacon_index;
+ t_u16 proberesp_index = priv->proberesp_index;
+ t_u16 assocresp_index = priv->assocresp_index;
+ t_u16 probereq_index = priv->probereq_index;
+ t_u16 beacon_wps_index = priv->beacon_wps_index;
+ t_u16 proberesp_p2p_index = priv->proberesp_p2p_index;
+ t_u16 assocrep_qos_map_index = priv->assocresp_qos_map_index;
+ t_u16 beacon_vendor_index = priv->beacon_vendor_index;
+
+ ENTER();
+
+ /* we need remove vendor IE from beacon extra IE, vendor IE will be
+ * configure through proberesp_vendor_index
+ */
+ if (mask & MGMT_MASK_BEACON_WPS_P2P) {
+ beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!beacon_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (beacon_ies && beacon_ies_len) {
+#ifdef WIFI_DIRECT_SUPPORT
+ if (woal_is_selected_registrar_on(beacon_ies,
+ beacon_ies_len)) {
+ PRINTM(MIOCTL, "selected_registrar is on\n");
+ priv->phandle->is_go_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->go_timer,
+ MOAL_TIMER_10S);
+ } else
+ PRINTM(MIOCTL, "selected_registrar is off\n");
+#endif
+ beacon_ies_data->ie_index = beacon_wps_index;
+ beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
+ beacon_ies_data->ie_length = woal_filter_beacon_ies(
+ priv, beacon_ies, beacon_ies_len,
+ beacon_ies_data->ie_buffer, MAX_IE_SIZE,
+ IE_MASK_VENDOR, NULL, 0);
+ DBG_HEXDUMP(MCMD_D, "beacon extra ie",
+ beacon_ies_data->ie_buffer,
+ beacon_ies_data->ie_length);
+ } else {
+ /* clear the beacon wps ies */
+ if (beacon_wps_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid beacon wps index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ beacon_ies_data->ie_index = beacon_wps_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ if ((beacon_ies && beacon_ies_len &&
+ beacon_ies_data->ie_length) ||
+ (beacon_ies_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)) {
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_custom_ie(
+ priv, beacon_ies_data, &beacon_wps_index,
+ proberesp_ies_data, &proberesp_index,
+ assocresp_ies_data, &assocresp_index,
+ probereq_ies_data, &probereq_index,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set beacon wps IE\n");
+ ret = -EFAULT;
+ }
+ priv->beacon_wps_index = beacon_wps_index;
+ PRINTM(MCMND, "beacon_wps_index=0x%x len=%d\n",
+ beacon_wps_index, beacon_ies_data->ie_length);
+ goto done;
+ }
+ kfree(beacon_ies_data); // Further allocation of beacon_ies_data
+ // is happening, so need to free here.
+ beacon_ies_data = NULL;
+ }
+
+ if (mask & MGMT_MASK_ASSOC_RESP_QOS_MAP) {
+ assocresp_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!assocresp_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (assocresp_ies && assocresp_ies_len) {
+ /* set the assoc response qos map ies */
+ assocresp_ies_data->ie_index = assocrep_qos_map_index;
+ assocresp_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_ASSOC_RESP;
+ if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
+ assocrep_qos_map_index)
+ assocresp_ies_data->mgmt_subtype_mask |=
+ MLAN_CUSTOM_IE_NEW_MASK;
+ if (assocresp_ies_len > MAX_IE_SIZE) {
+ PRINTM(MERROR,
+ "IE too big: assocresp_ies_len=%d\n",
+ (int)assocresp_ies_len);
+ goto done;
+ }
+ assocresp_ies_data->ie_length = assocresp_ies_len;
+ pos = assocresp_ies_data->ie_buffer;
+ moal_memcpy_ext(priv->phandle, pos, assocresp_ies,
+ assocresp_ies_len, MAX_IE_SIZE);
+ DBG_HEXDUMP(MCMD_D, "Qos Map",
+ assocresp_ies_data->ie_buffer,
+ assocresp_ies_data->ie_length);
+ } else {
+ /* clear the assoc response qos map ie */
+ if (assocrep_qos_map_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid Qos map index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ assocresp_ies_data->ie_index = assocrep_qos_map_index;
+ assocresp_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ assocresp_ies_data->ie_length = 0;
+ assocrep_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_custom_ie(priv, NULL, &beacon_wps_index, NULL,
+ &proberesp_index,
+ assocresp_ies_data,
+ &assocrep_qos_map_index, NULL,
+ &probereq_index, wait_option)) {
+ PRINTM(MERROR, "Fail to set Qos map IE\n");
+ ret = -EFAULT;
+ }
+ priv->assocresp_qos_map_index = assocrep_qos_map_index;
+ PRINTM(MCMND, "qos map ie index=0x%x len=%d\n",
+ assocrep_qos_map_index, assocresp_ies_data->ie_length);
+ goto done;
+ }
+
+ if (mask & MGMT_MASK_BEACON) {
+ beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!beacon_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (mask & MGMT_MASK_PROBE_RESP) {
+ /** set or clear proberesp ie */
+ if (proberesp_ies_len ||
+ (!proberesp_ies_len && !beacon_ies_len)) {
+ proberesp_ies_data =
+ kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!proberesp_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ if (mask & MGMT_MASK_ASSOC_RESP) {
+ /** set or clear assocresp ie */
+ if (assocresp_ies_len ||
+ (!assocresp_ies_len && !beacon_ies_len)) {
+ assocresp_ies_data =
+ kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!assocresp_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ }
+ if (mask & MGMT_MASK_PROBE_REQ) {
+ probereq_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
+ if (!probereq_ies_data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (beacon_ies_data) {
+ if (beacon_ies && beacon_ies_len) {
+ /* set the probe response/beacon vendor ies which
+ * includes wpa IE
+ */
+ beacon_ies_data->ie_index = beacon_vendor_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_PROBE_RESP | MGMT_MASK_BEACON;
+ if (beacon_vendor_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ beacon_ies_data->mgmt_subtype_mask |=
+ MLAN_CUSTOM_IE_NEW_MASK;
+ beacon_ies_data->ie_length =
+ woal_get_specific_ie(beacon_ies, beacon_ies_len,
+ beacon_ies_data->ie_buffer,
+ MAX_IE_SIZE,
+ IE_MASK_VENDOR);
+ DBG_HEXDUMP(MCMD_D, "beacon vendor IE",
+ beacon_ies_data->ie_buffer,
+ beacon_ies_data->ie_length);
+ }
+ if (beacon_vendor_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK &&
+ !beacon_ies_data->ie_length) {
+ /* clear the beacon vendor ies */
+ if (beacon_vendor_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid beacon_vendor_index for mgmt frame ie.\n");
+ goto done;
+ }
+ beacon_ies_data->ie_index = beacon_vendor_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ if ((beacon_ies && beacon_ies_len &&
+ beacon_ies_data->ie_length) ||
+ (beacon_ies_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)) {
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_custom_ie(
+ priv, beacon_ies_data, &beacon_vendor_index,
+ NULL, &proberesp_index, NULL,
+ &assocresp_index, NULL, &probereq_index,
+ wait_option)) {
+ PRINTM(MERROR,
+ "Fail to set beacon vendor IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->beacon_vendor_index = beacon_vendor_index;
+ PRINTM(MCMND, "beacon_vendor=0x%x len=%d\n",
+ beacon_vendor_index, beacon_ies_data->ie_length);
+ }
+ memset(beacon_ies_data, 0x00, sizeof(custom_ie));
+ if (beacon_ies && beacon_ies_len) {
+ /* set the beacon ies */
+ /* we need remove vendor IE from beacon tail, vendor/wpa
+ * IE will be configure through beacon_vendor_index
+ */
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_ASSOC_RESP |
+ MGMT_MASK_PROBE_RESP;
+ beacon_ies_data->ie_length = woal_filter_beacon_ies(
+ priv, beacon_ies, beacon_ies_len,
+ beacon_ies_data->ie_buffer, MAX_IE_SIZE,
+ IE_MASK_WPS | IE_MASK_WFD | IE_MASK_P2P |
+ IE_MASK_VENDOR,
+ proberesp_ies, proberesp_ies_len);
+ if (beacon_ies_data->ie_length)
+ DBG_HEXDUMP(MCMD_D, "beacon ie",
+ beacon_ies_data->ie_buffer,
+ beacon_ies_data->ie_length);
+ else {
+ kfree(beacon_ies_data);
+ beacon_ies_data = NULL;
+ }
+ } else {
+ /* clear the beacon ies */
+ if (beacon_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MINFO,
+ "Invalid beacon index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ beacon_ies_data->ie_index = beacon_index;
+ beacon_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ beacon_ies_data->ie_length = 0;
+ beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (proberesp_ies_data) {
+ if (proberesp_ies && proberesp_ies_len) {
+ /* set the probe response p2p ies */
+ proberesp_ies_data->ie_index = proberesp_p2p_index;
+ proberesp_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_PROBE_RESP;
+ proberesp_ies_data->ie_length = woal_get_specific_ie(
+ proberesp_ies, proberesp_ies_len,
+ proberesp_ies_data->ie_buffer, MAX_IE_SIZE,
+ IE_MASK_P2P);
+ DBG_HEXDUMP(MCMD_D, "proberesp p2p ie",
+ proberesp_ies_data->ie_buffer,
+ proberesp_ies_data->ie_length);
+ } else if (proberesp_p2p_index !=
+ MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
+ /* clear the probe response p2p ies */
+ if (proberesp_p2p_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid proberesp_p2p_index for mgmt frame ie.\n");
+ goto done;
+ }
+ proberesp_ies_data->ie_index = proberesp_p2p_index;
+ proberesp_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ proberesp_ies_data->ie_length = 0;
+ proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ if ((proberesp_ies && proberesp_ies_len &&
+ proberesp_ies_data->ie_length) ||
+ (proberesp_ies_data->mgmt_subtype_mask ==
+ MLAN_CUSTOM_IE_DELETE_MASK)) {
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_custom_ie(
+ priv, NULL, &beacon_index,
+ proberesp_ies_data, &proberesp_p2p_index,
+ NULL, &assocresp_index, NULL,
+ &probereq_index, wait_option)) {
+ PRINTM(MERROR,
+ "Fail to set proberesp p2p IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->proberesp_p2p_index = proberesp_p2p_index;
+ PRINTM(MCMND, "proberesp_p2p=0x%x len=%d\n",
+ proberesp_p2p_index,
+ proberesp_ies_data->ie_length);
+ }
+ memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
+ if (proberesp_ies && proberesp_ies_len) {
+ /* set the probe response ies */
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_PROBE_RESP;
+ if (proberesp_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ proberesp_ies_data->mgmt_subtype_mask |=
+ MLAN_CUSTOM_IE_NEW_MASK;
+ proberesp_ies_data->ie_length = woal_filter_beacon_ies(
+ priv, proberesp_ies, proberesp_ies_len,
+ proberesp_ies_data->ie_buffer, MAX_IE_SIZE,
+ IE_MASK_P2P | IE_MASK_VENDOR, NULL, 0);
+ if (proberesp_ies_data->ie_length) {
+ DBG_HEXDUMP(MCMD_D, "proberesp ie",
+ proberesp_ies_data->ie_buffer,
+ proberesp_ies_data->ie_length);
+ } else {
+ kfree(proberesp_ies_data);
+ proberesp_ies_data = NULL;
+ }
+ } else {
+ /* clear the probe response ies */
+ if (proberesp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid probe resp index for mgmt frame ie.\n");
+ goto done;
+ }
+ proberesp_ies_data->ie_index = proberesp_index;
+ proberesp_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ proberesp_ies_data->ie_length = 0;
+ proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+ if (assocresp_ies_data) {
+ if (assocresp_ies && assocresp_ies_len) {
+ /* set the assoc response ies */
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_ASSOC_RESP;
+ if (assocresp_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ assocresp_ies_data->mgmt_subtype_mask |=
+ MLAN_CUSTOM_IE_NEW_MASK;
+ if (assocresp_ies_len > MAX_IE_SIZE) {
+ PRINTM(MERROR,
+ "IE too big, assocresp_ies_len=%d\n",
+ (int)assocresp_ies_len);
+ goto done;
+ }
+ assocresp_ies_data->ie_length = assocresp_ies_len;
+ pos = assocresp_ies_data->ie_buffer;
+ moal_memcpy_ext(priv->phandle, pos, assocresp_ies,
+ assocresp_ies_len, MAX_IE_SIZE);
+ DBG_HEXDUMP(MCMD_D, "assocresp ie",
+ assocresp_ies_data->ie_buffer,
+ assocresp_ies_data->ie_length);
+ } else {
+ /* clear the assoc response ies */
+ if (assocresp_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid assoc resp index for mgmt frame ie.\n");
+ goto done;
+ }
+
+ assocresp_ies_data->ie_index = assocresp_index;
+ assocresp_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ assocresp_ies_data->ie_length = 0;
+ assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (probereq_ies_data) {
+ if (probereq_ies && probereq_ies_len) {
+ /* set the probe req ies */
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask =
+ MGMT_MASK_PROBE_REQ;
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ /* filter out P2P/WFD ie/EXT_CAP ie */
+ probereq_ies_data->ie_length =
+ woal_filter_beacon_ies(
+ priv, probereq_ies,
+ probereq_ies_len,
+ probereq_ies_data->ie_buffer,
+ MAX_IE_SIZE,
+ IE_MASK_P2P | IE_MASK_WFD |
+ IE_MASK_EXTCAP,
+ NULL, 0);
+ } else {
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+ if (probereq_ies_len > MAX_IE_SIZE) {
+ PRINTM(MERROR,
+ "IE too big, probereq_ies_len=%d\n",
+ (int)probereq_ies_len);
+ goto done;
+ }
+ probereq_ies_data->ie_length = probereq_ies_len;
+ pos = probereq_ies_data->ie_buffer;
+ moal_memcpy_ext(priv->phandle, pos,
+ probereq_ies, probereq_ies_len,
+ MAX_IE_SIZE);
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ }
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+ if (probereq_ies_data->ie_length)
+ DBG_HEXDUMP(MCMD_D, "probereq ie",
+ probereq_ies_data->ie_buffer,
+ probereq_ies_data->ie_length);
+ else {
+ kfree(probereq_ies_data);
+ probereq_ies_data = NULL;
+ }
+ } else {
+ /* clear the probe req ies */
+ if (probereq_index > MAX_MGMT_IE_INDEX) {
+ PRINTM(MERROR,
+ "Invalid probe req index for mgmt frame ie.\n");
+ goto done;
+ }
+ probereq_ies_data->ie_index = probereq_index;
+ probereq_ies_data->mgmt_subtype_mask =
+ MLAN_CUSTOM_IE_DELETE_MASK;
+ probereq_ies_data->ie_length = 0;
+ probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ }
+ }
+
+ if (beacon_ies_data || proberesp_ies_data || assocresp_ies_data ||
+ probereq_ies_data) {
+ if (MLAN_STATUS_FAILURE ==
+ woal_cfg80211_custom_ie(
+ priv, beacon_ies_data, &beacon_index,
+ proberesp_ies_data, &proberesp_index,
+ assocresp_ies_data, &assocresp_index,
+ probereq_ies_data, &probereq_index, wait_option)) {
+ PRINTM(MERROR,
+ "Fail to set beacon proberesp assoc probereq IES\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (beacon_ies_data) {
+ priv->beacon_index = beacon_index;
+ PRINTM(MCMND, "beacon ie length = %d\n",
+ beacon_ies_data->ie_length);
+ }
+ if (assocresp_ies_data) {
+ priv->assocresp_index = assocresp_index;
+ PRINTM(MCMND, "assocresp ie length = %d\n",
+ assocresp_ies_data->ie_length);
+ }
+ if (proberesp_ies_data) {
+ priv->proberesp_index = proberesp_index;
+ PRINTM(MCMND, "proberesp ie length = %d\n",
+ proberesp_ies_data->ie_length);
+ }
+ if (probereq_ies_data) {
+ priv->probereq_index = probereq_index;
+ PRINTM(MCMND, "probereq ie length = %d\n",
+ probereq_ies_data->ie_length);
+ }
+ PRINTM(MCMND, "beacon=%x assocresp=%x proberesp=%x probereq=%x\n",
+ beacon_index, assocresp_index, proberesp_index, probereq_index);
+done:
+ kfree(beacon_ies_data);
+ kfree(proberesp_ies_data);
+ kfree(assocresp_ies_data);
+ kfree(probereq_ies_data);
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief Sets up the CFG802.11 specific HT capability fields
+ * with default values
+ *
+ * @param ht_info A pointer to ieee80211_sta_ht_cap structure
+ * @param dev_cap Device capability information
+ * @param mcs_set Device MCS sets
+ *
+ * @return N/A
+ */
+void woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ t_u32 dev_cap, t_u8 *mcs_set)
+{
+ ENTER();
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = 0x3;
+ ht_info->ampdu_density = 0;
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ ht_info->cap = 0;
+ if (mcs_set)
+ moal_memcpy_ext(NULL, ht_info->mcs.rx_mask, mcs_set,
+ sizeof(ht_info->mcs.rx_mask),
+ sizeof(ht_info->mcs.rx_mask));
+ if (dev_cap & MBIT(8)) /* 40Mhz intolarance enabled */
+ ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
+ if (dev_cap & MBIT(17)) /* Channel width 20/40Mhz support */
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ if ((dev_cap >> 20) & 0x03) /* Delayed ACK supported */
+ ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA;
+ if (dev_cap & MBIT(22)) /* Rx LDPC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+ if (dev_cap & MBIT(23)) /* Short GI @ 20Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ if (dev_cap & MBIT(24)) /* Short GI @ 40Mhz supported */
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ if (dev_cap & MBIT(25)) /* Tx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ if (dev_cap & MBIT(26)) /* Rx STBC supported */
+ ht_info->cap |= IEEE80211_HT_CAP_RX_STBC;
+ if (dev_cap & MBIT(27)) /* MIMO PS supported */
+ ht_info->cap |= 0; /* WLAN_HT_CAP_SM_PS_STATIC */
+ else /* Disable HT SM PS */
+ ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
+ if (dev_cap & MBIT(29)) /* Green field supported */
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ if (dev_cap & MBIT(31)) /* MAX AMSDU supported */
+ ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+ /* DSSS/CCK in 40Mhz supported*/
+ ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ LEAVE();
+}
+
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief Sets up the CFG802.11 specific VHT capability fields
+ * with default values
+ *
+ * @param priv A pointer to moal private structure
+ * @param vht_cap A pointer to ieee80211_sta_vht_cap structure
+ *
+ * @return N/A
+ */
+void woal_cfg80211_setup_vht_cap(moal_private *priv,
+ struct ieee80211_sta_vht_cap *vht_cap)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ac_cfg *cfg_11ac = NULL;
+ mlan_status status;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "Fail to allocate buf for setup vht_cap\n");
+ goto done;
+ }
+ cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
+ cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
+ req->req_id = MLAN_IOCTL_11AC_CFG;
+ req->action = MLAN_ACT_GET;
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
+ cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Fail to get vht_cfg\n");
+ goto done;
+ }
+ vht_cap->vht_supported = true;
+ vht_cap->cap = cfg_11ac->param.vht_cfg.vht_cap_info;
+ vht_cap->vht_mcs.rx_mcs_map = (t_u16)cfg_11ac->param.vht_cfg.vht_rx_mcs;
+ vht_cap->vht_mcs.rx_highest =
+ (t_u16)cfg_11ac->param.vht_cfg.vht_rx_max_rate;
+ vht_cap->vht_mcs.tx_mcs_map = (t_u16)cfg_11ac->param.vht_cfg.vht_tx_mcs;
+ vht_cap->vht_mcs.tx_highest =
+ (t_u16)cfg_11ac->param.vht_cfg.vht_tx_max_rate;
+ PRINTM(MCMND,
+ "vht_cap=0x%x rx_mcs_map=0x%x rx_max=0x%x tx_mcs_map=0x%x tx_max=0x%x\n",
+ vht_cap->cap, vht_cap->vht_mcs.rx_mcs_map,
+ vht_cap->vht_mcs.rx_highest, vht_cap->vht_mcs.tx_mcs_map,
+ vht_cap->vht_mcs.tx_highest);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+}
+#endif
+
+#if KERNEL_VERSION(4, 20, 0) <= CFG80211_VERSION_CODE
+/*
+===============
+11AX CAP for uAP
+===============
+Note: bits not mentioned below are set to 0.
+
+5G
+===
+HE MAC Cap:
+Bit0: 1 (+HTC HE Support)
+Bit25: 1 (OM Control Support. But uAP does not support
+ Tx OM received from the STA, as it does not support UL OFDMA)
+
+HE PHY Cap:
+Bit1-7: 0x2 (Supported Channel Width Set.
+ Note it would be changed after 80+80 MHz is supported)
+Bit8-11: 0x3 (Punctured Preamble Rx.
+ Note: it would be changed after 80+80 MHz is supported)
+Bit12: 0x0 (Device Class)
+Bit13: 0x1 (LDPC coding in Payload)
+Bit17: 0x1 (NDP with 4xHE-LTF+3.2usGI)
+Bit18: 0x1 (STBC Tx <= 80 MHz)
+Bit19: 0x1 (STBC Rx <= 80 MHz)
+Bit20: 0x1 (Doppler Tx)
+Bit21: 0x1 (Doppler Rx)
+Bit27-28: 0x1 (DCM Max Constellation Rx)
+Bit31: 0x1 (SU Beamformer)
+Bit32: 0x1 (SU BeamFormee)
+Bit34-36: 0x7 (Beamformee STS <= 80 MHz)
+Bit40-42: 0x1 (Number of Sounding Dimentions <= 80 MHz)
+Bit53: 0x1 (Partial Bandwidth Extended Range)
+Bit55: 0x1 (PPE Threshold Present.
+ Note: PPE threshold may have some changes later)
+Bit58: 0x1 (HE SU PPDU and HE MU PPDU with 4xHE-LTF+0.8usGI)
+Bit59-61: 0x1 (Max Nc)
+Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU)
+*/
+
+#define UAP_HE_MAC_CAP0_MASK 0x00
+#define UAP_HE_MAC_CAP1_MASK 0x00
+#define UAP_HE_MAC_CAP2_MASK 0x00
+#define UAP_HE_MAC_CAP3_MASK 0x00
+#define UAP_HE_MAC_CAP4_MASK 0x02
+#define UAP_HE_MAC_CAP5_MASK 0x00
+#define UAP_HE_PHY_CAP0_MASK 0x04
+#define UAP_HE_PHY_CAP1_MASK 0x23
+#define UAP_HE_PHY_CAP2_MASK 0x3E
+#define UAP_HE_PHY_CAP3_MASK 0x88
+#define UAP_HE_PHY_CAP4_MASK 0x1D
+#define UAP_HE_PHY_CAP5_MASK 0x01
+#define UAP_HE_PHY_CAP6_MASK 0xA0
+#define UAP_HE_PHY_CAP7_MASK 0x0C
+#define UAP_HE_PHY_CAP8_MASK 0x00
+#define UAP_HE_PHY_CAP9_MASK 0x08
+#define UAP_HE_PHY_CAP10_MASK 0x00
+
+/*
+2G
+===
+HE MAC Cap:
+Bit0: 1 (+HTC HE Support)
+Bit25: 1 (OM Control Support. Note: uAP does not support
+ Tx OM received from the STA, as it does not support UL OFDMA)
+
+HE PHY Cap:
+Bit1-7: 0x1 (Supported Channel Width Set)
+Bit8-11: 0x0 (Punctured Preamble Rx)
+Bit12: 0x0 (Device Class)
+Bit13: 0x1 (LDPC coding in Payload)
+Bit17: 0x1 (NDP with 4xLTF+3.2usGI)
+Bit18: 0x1 (STBC Tx <= 80 MHz)
+Bit19: 0x1 (STBC Rx <= 80 MHz)
+Bit20: 0x1 (Doppler Tx)
+Bit21: 0x1 (Doppler Rx)
+Bit27-28: 0x1 (DCM Max Constellation Rx)
+Bit31: 0x1 (SU Beamformer)
+Bit32: 0x1 (SU BeamFormee)
+Bit34-36: 0x7 (Beamformee STS <= 80 MHz)
+Bit40-42: 0x1 (Number of Sounding Dimentions <= 80 MHz)
+Bit53: 0x1 (Partial Bandwidth Extended Range)
+Bit55: 0x1 (PPE Threshold Present.
+ Note: PPE threshold may have some changes later)
+Bit58: 0x1 (HE SU PPDU and HE MU PPDU with 4xHE-LTF+0.8usGI)
+Bit59-61: 0x1 (Max Nc)
+Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU)
+*/
+#define UAP_HE_2G_MAC_CAP0_MASK 0x00
+#define UAP_HE_2G_MAC_CAP1_MASK 0x00
+#define UAP_HE_2G_MAC_CAP2_MASK 0x00
+#define UAP_HE_2G_MAC_CAP3_MASK 0x00
+#define UAP_HE_2G_MAC_CAP4_MASK 0x02
+#define UAP_HE_2G_MAC_CAP5_MASK 0x00
+#define UAP_HE_2G_PHY_CAP0_MASK 0x04
+#define UAP_HE_2G_PHY_CAP1_MASK 0x20
+#define UAP_HE_2G_PHY_CAP2_MASK 0x3E
+#define UAP_HE_2G_PHY_CAP3_MASK 0x88
+#define UAP_HE_2G_PHY_CAP4_MASK 0x1D
+#define UAP_HE_2G_PHY_CAP5_MASK 0x01
+#define UAP_HE_2G_PHY_CAP6_MASK 0xA0
+#define UAP_HE_2G_PHY_CAP7_MASK 0x0C
+#define UAP_HE_2G_PHY_CAP8_MASK 0x00
+#define UAP_HE_2G_PHY_CAP9_MASK 0x08
+#define UAP_HE_2G_PHY_CAP10_MASK 0x00
+
+/**
+ * @brief update 11ax ie for AP mode *
+ * @param band band config
+ * @hecap_ie a pointer to mlan_ds_11ax_he_capa
+ *
+ * @return 0--success, otherwise failure
+ */
+void woal_uap_update_11ax_ie(t_u8 band, mlan_ds_11ax_he_capa *hecap_ie)
+{
+ if (band == BAND_5GHZ) {
+ hecap_ie->he_mac_cap[0] &= UAP_HE_MAC_CAP0_MASK;
+ hecap_ie->he_mac_cap[1] &= UAP_HE_MAC_CAP1_MASK;
+ hecap_ie->he_mac_cap[2] &= UAP_HE_MAC_CAP2_MASK;
+ hecap_ie->he_mac_cap[3] &= UAP_HE_MAC_CAP3_MASK;
+ hecap_ie->he_mac_cap[4] &= UAP_HE_MAC_CAP4_MASK;
+ hecap_ie->he_mac_cap[5] &= UAP_HE_MAC_CAP5_MASK;
+ hecap_ie->he_phy_cap[0] &= UAP_HE_PHY_CAP0_MASK;
+ hecap_ie->he_phy_cap[1] &= UAP_HE_PHY_CAP1_MASK;
+ hecap_ie->he_phy_cap[2] &= UAP_HE_PHY_CAP2_MASK;
+ hecap_ie->he_phy_cap[3] &= UAP_HE_PHY_CAP3_MASK;
+ hecap_ie->he_phy_cap[4] &= UAP_HE_PHY_CAP4_MASK;
+ hecap_ie->he_phy_cap[5] &= UAP_HE_PHY_CAP5_MASK;
+ hecap_ie->he_phy_cap[6] &= UAP_HE_PHY_CAP6_MASK;
+ hecap_ie->he_phy_cap[7] &= UAP_HE_PHY_CAP7_MASK;
+ hecap_ie->he_phy_cap[8] &= UAP_HE_PHY_CAP8_MASK;
+ hecap_ie->he_phy_cap[9] &= UAP_HE_PHY_CAP9_MASK;
+ hecap_ie->he_phy_cap[10] &= UAP_HE_PHY_CAP10_MASK;
+ } else {
+ hecap_ie->he_mac_cap[0] &= UAP_HE_2G_MAC_CAP0_MASK;
+ hecap_ie->he_mac_cap[1] &= UAP_HE_2G_MAC_CAP1_MASK;
+ hecap_ie->he_mac_cap[2] &= UAP_HE_2G_MAC_CAP2_MASK;
+ hecap_ie->he_mac_cap[3] &= UAP_HE_2G_MAC_CAP3_MASK;
+ hecap_ie->he_mac_cap[4] &= UAP_HE_2G_MAC_CAP4_MASK;
+ hecap_ie->he_mac_cap[5] &= UAP_HE_2G_MAC_CAP5_MASK;
+ hecap_ie->he_phy_cap[0] &= UAP_HE_2G_PHY_CAP0_MASK;
+ hecap_ie->he_phy_cap[1] &= UAP_HE_2G_PHY_CAP1_MASK;
+ hecap_ie->he_phy_cap[2] &= UAP_HE_2G_PHY_CAP2_MASK;
+ hecap_ie->he_phy_cap[3] &= UAP_HE_2G_PHY_CAP3_MASK;
+ hecap_ie->he_phy_cap[4] &= UAP_HE_2G_PHY_CAP4_MASK;
+ hecap_ie->he_phy_cap[5] &= UAP_HE_2G_PHY_CAP5_MASK;
+ hecap_ie->he_phy_cap[6] &= UAP_HE_2G_PHY_CAP6_MASK;
+ hecap_ie->he_phy_cap[7] &= UAP_HE_2G_PHY_CAP7_MASK;
+ hecap_ie->he_phy_cap[8] &= UAP_HE_2G_PHY_CAP8_MASK;
+ hecap_ie->he_phy_cap[9] &= UAP_HE_2G_PHY_CAP9_MASK;
+ hecap_ie->he_phy_cap[10] &= UAP_HE_2G_PHY_CAP10_MASK;
+ }
+ return;
+}
+
+/**
+ * @brief Sets up the CFG802.11 specific HE capability fields * with default
+ * values
+ *
+ * @param priv A pointer to moal private structure
+ * @param iftype_data A pointer to ieee80211_sband_iftype_data structure
+ *
+ * @return N/A
+ */
+void woal_cfg80211_setup_he_cap(moal_private *priv,
+ struct ieee80211_supported_band *band)
+{
+ mlan_fw_info fw_info;
+ struct ieee80211_sband_iftype_data *iftype_data = NULL;
+ t_u8 extra_mcs_size = 0;
+ int ppe_threshold_len = 0;
+ mlan_ds_11ax_he_capa *phe_cap = NULL;
+ t_u8 hw_hecap_len;
+
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if (band->band == NL80211_BAND_5GHZ) {
+ phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_he_cap;
+ hw_hecap_len = fw_info.hw_hecap_len;
+ woal_uap_update_11ax_ie(BAND_5GHZ, phe_cap);
+ } else {
+ phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_2g_he_cap;
+ hw_hecap_len = fw_info.hw_2g_hecap_len;
+ woal_uap_update_11ax_ie(BAND_2GHZ, phe_cap);
+ }
+
+ if (!hw_hecap_len)
+ return;
+ DBG_HEXDUMP(MCMD_D, "Setup HECAP", (u8 *)phe_cap, hw_hecap_len);
+ iftype_data =
+ kmalloc(sizeof(struct ieee80211_sband_iftype_data), GFP_KERNEL);
+ if (!iftype_data) {
+ PRINTM(MERROR, "Fail to allocate iftype data\n");
+ goto done;
+ }
+ iftype_data->types_mask =
+ MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_AP) |
+ MBIT(NL80211_IFTYPE_P2P_CLIENT) | MBIT(NL80211_IFTYPE_P2P_GO);
+ iftype_data->he_cap.has_he = true;
+ moal_memcpy_ext(priv->phandle,
+ iftype_data->he_cap.he_cap_elem.mac_cap_info,
+ phe_cap->he_mac_cap, sizeof(phe_cap->he_mac_cap),
+ sizeof(iftype_data->he_cap.he_cap_elem.mac_cap_info));
+ moal_memcpy_ext(priv->phandle,
+ iftype_data->he_cap.he_cap_elem.phy_cap_info,
+ phe_cap->he_phy_cap, sizeof(phe_cap->he_phy_cap),
+ sizeof(iftype_data->he_cap.he_cap_elem.phy_cap_info));
+ memset(&iftype_data->he_cap.he_mcs_nss_supp, 0xff,
+ sizeof(struct ieee80211_he_mcs_nss_supp));
+ moal_memcpy_ext(priv->phandle, &iftype_data->he_cap.he_mcs_nss_supp,
+ phe_cap->he_txrx_mcs_support,
+ sizeof(phe_cap->he_txrx_mcs_support),
+ sizeof(struct ieee80211_he_mcs_nss_supp));
+ // Support 160Mhz
+ if (phe_cap->he_phy_cap[0] & MBIT(3))
+ extra_mcs_size += 4;
+
+ // Support 80+80
+ if (phe_cap->he_phy_cap[0] & MBIT(4))
+ extra_mcs_size += 4;
+ if (extra_mcs_size)
+ moal_memcpy_ext(
+ priv->phandle,
+ (t_u8 *)&iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160,
+ phe_cap->val, extra_mcs_size,
+ sizeof(struct ieee80211_he_mcs_nss_supp) - 4);
+
+#define HE_CAP_FIX_SIZE 22
+ // Support PPE threshold
+ ppe_threshold_len = phe_cap->len - HE_CAP_FIX_SIZE - extra_mcs_size;
+ if (phe_cap->he_phy_cap[6] & MBIT(7) && ppe_threshold_len) {
+ moal_memcpy_ext(priv->phandle, iftype_data->he_cap.ppe_thres,
+ &phe_cap->val[extra_mcs_size],
+ ppe_threshold_len,
+ sizeof(iftype_data->he_cap.ppe_thres));
+ } else {
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[6] &= ~MBIT(7);
+ PRINTM(MCMND, "Clear PPE threshold 0x%x\n",
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[7]);
+ }
+ band->n_iftype_data = 1;
+ band->iftype_data = iftype_data;
+done:
+ LEAVE();
+}
+
+/**
+ * @brief free iftype_data
+ *
+ * @param wiphy A pointer to struct wiphy
+ *
+ *
+ * @return N/A
+ */
+void woal_cfg80211_free_iftype_data(struct wiphy *wiphy)
+{
+ enum nl80211_band band;
+
+ for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; ++band) {
+ if (!wiphy->bands[band])
+ continue;
+ if (!wiphy->bands[band]->iftype_data)
+ continue;
+ kfree(wiphy->bands[band]->iftype_data);
+ wiphy->bands[band]->n_iftype_data = 0;
+ }
+}
+#endif
+
+/*
+ * @brief prepare and send fake deauth packet to cfg80211 to
+ * notify wpa_supplicant about disconnection
+ * <host_mlme, wiphy suspend case>
+ *
+ * @param priv A pointer moal_private structure
+ * @param reason_code disconnect reason code
+ *
+ * @return N/A
+ */
+void woal_deauth_event(moal_private *priv, int reason_code)
+{
+ struct woal_event *evt;
+ unsigned long flags;
+ moal_handle *handle = priv->phandle;
+
+ evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
+ if (!evt) {
+ PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
+ LEAVE();
+ return;
+ }
+ evt->priv = priv;
+ evt->type = WOAL_EVENT_DEAUTH;
+ evt->reason_code = reason_code;
+ INIT_LIST_HEAD(&evt->link);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ list_add_tail(&evt->link, &handle->evt_queue);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ queue_work(handle->evt_workqueue, &handle->evt_work);
+}
+
+#ifdef STA_CFG80211
+#if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief prepare woal_bgscan_stop event
+ *
+ * @param priv A pointer moal_private structure
+ * @param pchan_info A pointer to chan_band structure
+ *
+ * @return N/A
+ */
+void woal_bgscan_stop_event(moal_private *priv)
+{
+ struct woal_event *evt;
+ unsigned long flags;
+ moal_handle *handle = priv->phandle;
+
+ evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
+ if (evt) {
+ evt->priv = priv;
+ evt->type = WOAL_EVENT_BGSCAN_STOP;
+ INIT_LIST_HEAD(&evt->link);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ list_add_tail(&evt->link, &handle->evt_queue);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ queue_work(handle->evt_workqueue, &handle->evt_work);
+ }
+}
+
+/**
+ * @brief Notify cfg80211 schedule scan stopped
+ *
+ * @param priv A pointer moal_private structure
+ *
+ * @return N/A
+ */
+void woal_cfg80211_notify_sched_scan_stop(moal_private *priv)
+{
+ cfg80211_sched_scan_stopped(priv->wdev->wiphy
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ 0
+#endif
+ );
+ priv->sched_scanning = MFALSE;
+ PRINTM(MEVENT, "Sched_Scan stopped\n");
+}
+#endif
+#endif
+
+#if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief Handle woal_channel_switch event
+ *
+ * @param priv A pointer moal_private structure
+ * @param pchan_info A pointer to chan_band structure
+ *
+ * @return N/A
+ */
+void woal_channel_switch_event(moal_private *priv, chan_band_info *pchan_info)
+{
+ struct woal_event *evt;
+ unsigned long flags;
+ moal_handle *handle = priv->phandle;
+
+ evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
+ if (evt) {
+ evt->priv = priv;
+ evt->type = WOAL_EVENT_CHAN_SWITCH;
+ moal_memcpy_ext(priv->phandle, &evt->chan_info, pchan_info,
+ sizeof(chan_band_info), sizeof(chan_band_info));
+ INIT_LIST_HEAD(&evt->link);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ list_add_tail(&evt->link, &handle->evt_queue);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ queue_work(handle->evt_workqueue, &handle->evt_work);
+ }
+}
+
+/**
+ * @brief Notify cfg80211 supplicant channel changed
+ *
+ * @param priv A pointer moal_private structure
+ * @param pchan_info A pointer to chan_band structure
+ *
+ * @return N/A
+ */
+void woal_cfg80211_notify_channel(moal_private *priv,
+ chan_band_info *pchan_info)
+{
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ struct cfg80211_chan_def chandef;
+#else
+#if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
+ enum nl80211_channel_type type;
+ enum ieee80211_band band;
+ int freq = 0;
+#endif
+#endif
+ ENTER();
+
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+ if (MLAN_STATUS_SUCCESS ==
+ woal_chandef_create(priv, &chandef, pchan_info)) {
+ cfg80211_ch_switch_notify(priv->netdev, &chandef);
+ priv->channel = pchan_info->channel;
+#ifdef UAP_CFG80211
+ moal_memcpy_ext(priv->phandle, &priv->chan, &chandef,
+ sizeof(struct cfg80211_chan_def),
+ sizeof(struct cfg80211_chan_def));
+#endif
+ }
+#else
+#if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
+ if (pchan_info->bandcfg.chanBand == BAND_2GHZ)
+ band = IEEE80211_BAND_2GHZ;
+ else if (pchan_info->bandcfg.chanBand == BAND_5GHZ)
+ band = IEEE80211_BAND_5GHZ;
+ else {
+ LEAVE();
+ return;
+ }
+ priv->channel = pchan_info->channel;
+ freq = ieee80211_channel_to_frequency(pchan_info->channel, band);
+ switch (pchan_info->bandcfg.chanWidth) {
+ case CHAN_BW_20MHZ:
+ if (pchan_info->is_11n_enabled)
+ type = NL80211_CHAN_HT20;
+ else
+ type = NL80211_CHAN_NO_HT;
+ break;
+ default:
+ if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_ABOVE)
+ type = NL80211_CHAN_HT40PLUS;
+ else if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_BELOW)
+ type = NL80211_CHAN_HT40MINUS;
+ else
+ type = NL80211_CHAN_HT20;
+ break;
+ }
+ cfg80211_ch_switch_notify(priv->netdev, freq, type);
+#endif
+#endif
+ LEAVE();
+}
+#endif
+
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+/**
+ * @brief create cfg80211_chan_def structure based on chan_band info
+ *
+ * @param priv A pointer moal_private structure
+ * @param chandef A pointer to cfg80211_chan_def structure
+ * @param pchan_info A pointer to chan_band_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+mlan_status woal_chandef_create(moal_private *priv,
+ struct cfg80211_chan_def *chandef,
+ chan_band_info *pchan_info)
+{
+ enum ieee80211_band band = IEEE80211_BAND_2GHZ;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(chandef, 0, sizeof(struct cfg80211_chan_def));
+ chandef->center_freq2 = 0;
+ if (pchan_info->bandcfg.chanBand == BAND_2GHZ)
+ band = IEEE80211_BAND_2GHZ;
+ else if (pchan_info->bandcfg.chanBand == BAND_5GHZ)
+ band = IEEE80211_BAND_5GHZ;
+ chandef->chan = ieee80211_get_channel(
+ priv->wdev->wiphy,
+ ieee80211_channel_to_frequency(pchan_info->channel, band));
+ if (chandef->chan == NULL) {
+ PRINTM(MERROR,
+ "Fail on ieee80211_get_channel, channel=%d, band=%d\n",
+ pchan_info->channel, band);
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ switch (pchan_info->bandcfg.chanWidth) {
+ case CHAN_BW_20MHZ:
+ if (pchan_info->is_11n_enabled)
+ chandef->width = NL80211_CHAN_WIDTH_20;
+ else
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = chandef->chan->center_freq;
+ break;
+ case CHAN_BW_40MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_ABOVE)
+ chandef->center_freq1 = chandef->chan->center_freq + 10;
+ else if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_BELOW)
+ chandef->center_freq1 = chandef->chan->center_freq - 10;
+ break;
+ case CHAN_BW_80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ chandef->center_freq1 = ieee80211_channel_to_frequency(
+ pchan_info->center_chan, band);
+ break;
+ default:
+ break;
+ }
+done:
+ LEAVE();
+ return status;
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.h
new file mode 100644
index 000000000000..f68e50c95c7f
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211.h
@@ -0,0 +1,478 @@
+/** @file moal_cfg80211.h
+ *
+ * @brief This file contains the CFG80211 specific defines.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MOAL_CFG80211_H_
+#define _MOAL_CFG80211_H_
+
+#include "moal_main.h"
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
+#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
+#endif
+
+#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
+#define MAX_CSA_COUNTERS_NUM 2
+#endif
+
+/* Clear all key indexes */
+#define KEY_INDEX_CLEAR_ALL (0x0000000F)
+
+/** RTS/FRAG disabled value */
+#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF)
+
+#ifndef WLAN_CIPHER_SUITE_SMS4
+#define WLAN_CIPHER_SUITE_SMS4 0x00000020
+#endif
+
+#ifndef WLAN_CIPHER_SUITE_AES_CMAC
+#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+#endif
+#if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
+#ifndef WLAN_CIPHER_SUITE_BIP_GMAC_256
+#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
+#endif
+#endif
+
+/* define for custom ie operation */
+#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff
+#define MLAN_CUSTOM_IE_NEW_MASK 0x8000
+#define IE_MASK_WPS 0x0001
+#define IE_MASK_P2P 0x0002
+#define IE_MASK_WFD 0x0004
+#define IE_MASK_VENDOR 0x0008
+#define IE_MASK_EXTCAP 0x0010
+
+#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5
+
+/**
+ * If multiple wiphys are registered e.g. a regular netdev with
+ * assigned ieee80211_ptr and you won't know whether it points
+ * to a wiphy your driver has registered or not. Assign this to
+ * something global to your driver to help determine whether
+ * you own this wiphy or not.
+ */
+static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid;
+
+/* Get the private structure from wiphy */
+void *woal_get_wiphy_priv(struct wiphy *wiphy);
+
+/* Get the private structure from net device */
+void *woal_get_netdev_priv(struct net_device *dev);
+#ifdef STA_SUPPORT
+/** get scan interface */
+pmoal_private woal_get_scan_interface(pmoal_handle handle);
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+/** AUTH pending flag */
+#define HOST_MLME_AUTH_PENDING MBIT(0)
+/** AUTH complete flag */
+#define HOST_MLME_AUTH_DONE MBIT(1)
+#define HOST_MLME_ASSOC_PENDING MBIT(2)
+#define HOST_MLME_ASSOC_DONE MBIT(3)
+void woal_host_mlme_disconnect(pmoal_private priv, u16 reason_code, u8 *sa);
+void woal_host_mlme_work_queue(struct work_struct *work);
+void woal_host_mlme_process_assoc_resp(moal_private *priv,
+ mlan_ds_misc_assoc_rsp *assoc_rsp);
+#endif
+#endif
+
+t_u8 woal_band_cfg_to_ieee_band(t_u32 band);
+
+int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type,
+#if KERNEL_VERSION(4, 12, 0) > CFG80211_VERSION_CODE
+ u32 *flags,
+#endif
+ struct vif_params *params);
+
+int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+int woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ t_u8 key_index,
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+ bool pairwise,
+#endif
+ const t_u8 *mac_addr, struct key_params *params);
+
+int woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ t_u8 key_index,
+#if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
+ bool pairwise,
+#endif
+ const t_u8 *mac_addr);
+#ifdef STA_SUPPORT
+/** Opportunistic Key Caching APIs support */
+struct pmksa_entry *woal_get_pmksa_entry(pmoal_private priv, const u8 *bssid);
+
+int woal_flush_pmksa_list(moal_private *priv);
+
+int woal_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+
+int woal_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+
+int woal_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev);
+#endif
+
+int woal_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer,
+ const struct cfg80211_bitrate_mask *mask);
+#if KERNEL_VERSION(2, 6, 38) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
+int woal_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
+#endif
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_qos_map(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_qos_map *qos_map);
+#endif
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+int woal_set_rf_channel(moal_private *priv, struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u8 wait_option);
+
+static inline int woal_cfg80211_scan_done(struct cfg80211_scan_request *request,
+ bool aborted)
+{
+#if KERNEL_VERSION(4, 8, 0) <= CFG80211_VERSION_CODE
+ struct cfg80211_scan_info info;
+
+ info.aborted = aborted;
+ cfg80211_scan_done(request, &info);
+#else
+ cfg80211_scan_done(request, aborted);
+#endif
+ return 0;
+}
+mlan_status woal_inform_bss_from_scan_result(moal_private *priv,
+ pmlan_ssid_bssid ssid_bssid,
+ t_u8 wait_option);
+#endif
+#endif
+
+#if KERNEL_VERSION(3, 5, 0) > CFG80211_VERSION_CODE
+int woal_cfg80211_set_channel(struct wiphy *wiphy,
+#if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
+#endif
+
+#if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
+int woal_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *dev,
+ t_u8 key_index, bool ucast, bool mcast);
+#else
+int woal_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *dev,
+ t_u8 key_index);
+#endif
+
+#if KERNEL_VERSION(2, 6, 30) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *netdev,
+ t_u8 key_index);
+#endif
+
+#if KERNEL_VERSION(3, 1, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_gtk_rekey_data *data);
+#endif
+void woal_mgmt_frame_register(moal_private *priv, u16 frame_type, bool reg);
+void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ struct wireless_dev *wdev,
+#else
+ struct net_device *dev,
+#endif
+#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
+ struct mgmt_frame_regs *upd
+#else
+ t_u16 frame_type, bool reg
+#endif
+);
+
+int woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+ struct wireless_dev *wdev,
+#else
+ struct net_device *dev,
+#endif
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+ struct cfg80211_mgmt_tx_params *params,
+#else
+ struct ieee80211_channel *chan, bool offchan,
+#if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+#endif
+ unsigned int wait, const u8 *buf, size_t len,
+#if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
+ bool no_cck,
+#endif
+#if KERNEL_VERSION(3, 3, 0) <= CFG80211_VERSION_CODE
+ bool dont_wait_for_ack,
+#endif
+#endif
+ u64 *cookie);
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+void woal_update_radar_chans_dfs_state(struct wiphy *wiphy);
+#endif
+
+mlan_status woal_register_cfg80211(moal_private *priv);
+
+extern struct ieee80211_supported_band cfg80211_band_2ghz;
+extern struct ieee80211_supported_band cfg80211_band_5ghz;
+extern struct ieee80211_supported_band mac1_cfg80211_band_2ghz;
+extern struct ieee80211_supported_band mac1_cfg80211_band_5ghz;
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+int woal_cfg80211_bss_role_cfg(moal_private *priv, t_u16 action,
+ t_u8 *bss_role);
+#endif
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+struct wireless_dev *
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
+ enum nl80211_iftype type,
+#if KERNEL_VERSION(4, 12, 0) > CFG80211_VERSION_CODE
+ u32 *flags,
+#endif
+ struct vif_params *params);
+#else
+#if KERNEL_VERSION(3, 7, 0) <= CFG80211_VERSION_CODE
+struct wireless_dev *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ const char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params);
+#else
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+struct wireless_dev *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params);
+#else
+#if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
+struct net_device *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params);
+#else
+int woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, char *name,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
+#endif
+#endif
+#endif
+#endif
+int woal_cfg80211_del_virt_if(struct wiphy *wiphy, struct net_device *dev);
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
+#else
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/* Group Owner Negotiation Req */
+#define P2P_GO_NEG_REQ 0
+/* Group Owner Negotiation Rsp */
+#define P2P_GO_NEG_RSP 1
+/* Group Owner Negotiation Confirm */
+#define P2P_GO_NEG_CONF 2
+/* P2P Invitation Request */
+#define P2P_INVITE_REQ 3
+/* P2P Invitation Response */
+#define P2P_INVITE_RSP 4
+/* Device Discoverability Request */
+#define P2P_DEVDIS_REQ 5
+/* Device Discoverability Response */
+#define P2P_DEVDIS_RSP 6
+/* Provision Discovery Request */
+#define P2P_PROVDIS_REQ 7
+/* Provision Discovery Response */
+#define P2P_PROVDIS_RSP 8
+/** P2P category */
+#define P2P_ACT_FRAME_CATEGORY 0x04
+/** P2P oui offset */
+#define P2P_ACT_FRAME_OUI_OFFSET 26
+/** P2P subtype offset */
+#define P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET 30
+void woal_cfg80211_display_p2p_actframe(const t_u8 *buf, int len,
+ struct ieee80211_channel *chan,
+ const t_u8 flag);
+
+/** Define kernel version for wifi direct */
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2, 6, 39)
+
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+
+int woal_cfg80211_init_p2p_client(moal_private *priv);
+
+int woal_cfg80211_init_p2p_go(moal_private *priv);
+
+int woal_cfg80211_deinit_p2p(moal_private *priv);
+
+void woal_remove_virtual_interface(moal_handle *handle);
+
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+
+/** Define for remain on channel duration timer */
+#define MAX_REMAIN_ON_CHANNEL_DURATION (1000)
+
+int woal_cfg80211_remain_on_channel_cfg(moal_private *priv, t_u8 wait_option,
+ t_u8 remove, t_u8 *status,
+ struct ieee80211_channel *chan,
+ enum mlan_channel_type channel_type,
+ t_u32 duration);
+
+#ifdef UAP_CFG80211
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_info *stainfo);
+
+int woal_uap_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, t_u8 *mac,
+ struct station_info *sinfo);
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
+ struct bss_parameters *params);
+#endif
+#if KERNEL_VERSION(3, 9, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_acl_data *params);
+#endif
+#if KERNEL_VERSION(3, 1, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_txq_params(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_txq_params *params);
+#endif
+
+#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_set_coalesce(struct wiphy *wiphy,
+ struct cfg80211_coalesce *coalesce);
+#endif
+
+#if KERNEL_VERSION(3, 4, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *params);
+#else
+int woal_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params);
+
+int woal_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params);
+#endif
+
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev);
+int woal_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+#if KERNEL_VERSION(3, 19, 0) <= CFG80211_VERSION_CODE
+ struct station_del_parameters *param);
+#else
+#if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
+ const u8 *mac_addr);
+#else
+ u8 *mac_addr);
+#endif
+#endif
+#if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
+#if KERNEL_VERSION(3, 15, 0) <= CFG80211_VERSION_CODE
+int woal_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef,
+ u32 cac_time_ms);
+#else
+int woal_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef);
+#endif
+
+int woal_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_csa_settings *params);
+
+void woal_cac_timer_func(void *context);
+void woal_csa_work_queue(struct work_struct *work);
+#endif
+#endif /* UAP_CFG80211 */
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+#if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
+void woal_cfg80211_notify_channel(moal_private *priv,
+ pchan_band_info pchan_info);
+void woal_channel_switch_event(moal_private *priv, chan_band_info *pchan_info);
+#endif
+#endif
+
+#ifdef STA_CFG80211
+#if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
+void woal_bgscan_stop_event(moal_private *priv);
+void woal_cfg80211_notify_sched_scan_stop(moal_private *priv);
+#endif
+#endif
+
+void woal_deauth_event(moal_private *priv, int reason_code);
+
+#if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
+mlan_status woal_chandef_create(moal_private *priv,
+ struct cfg80211_chan_def *chandef,
+ chan_band_info *pchan_info);
+#endif
+
+#if KERNEL_VERSION(4, 20, 0) <= CFG80211_VERSION_CODE
+void woal_cfg80211_setup_he_cap(moal_private *priv,
+ struct ieee80211_supported_band *band);
+void woal_cfg80211_free_iftype_data(struct wiphy *wiphy);
+#endif
+
+void woal_clear_all_mgmt_ies(moal_private *priv, t_u8 wait_option);
+int woal_cfg80211_mgmt_frame_ie(
+ moal_private *priv, const t_u8 *beacon_ies, size_t beacon_ies_len,
+ const t_u8 *proberesp_ies, size_t proberesp_ies_len,
+ const t_u8 *assocresp_ies, size_t assocresp_ies_len,
+ const t_u8 *probereq_ies, size_t probereq_ies_len, t_u16 mask,
+ t_u8 wait_option);
+
+int woal_get_active_intf_freq(moal_private *priv);
+
+void woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
+ t_u32 dev_cap, t_u8 *mcs_set);
+#if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
+void woal_cfg80211_setup_vht_cap(moal_private *priv,
+ struct ieee80211_sta_vht_cap *vht_cap);
+#endif
+int woal_cfg80211_assoc(moal_private *priv, void *sme, t_u8 wait_option,
+ pmlan_ds_misc_assoc_rsp assoc_rsp);
+
+#endif /* _MOAL_CFG80211_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.c
new file mode 100644
index 000000000000..464999f9bda2
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.c
@@ -0,0 +1,4207 @@
+/** @file moal_cfg80211_util.c
+ *
+ * @brief This file contains the functions for CFG80211 vendor.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "moal_cfg80211_util.h"
+#include "moal_cfg80211.h"
+
+/********************************************************
+ * Local Variables
+ ********************************************************/
+
+/********************************************************
+ * Global Variables
+ ********************************************************/
+
+/********************************************************
+ * Local Functions
+ ********************************************************/
+
+/********************************************************
+ * Global Functions
+ ********************************************************/
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+/**nxp vendor command and event*/
+#define MRVL_VENDOR_ID 0x005043
+/** vendor events */
+const struct nl80211_vendor_cmd_info vendor_events[] = {
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_hang,
+ }, /*event_id 0*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_rssi_monitor,
+ }, /*event_id 0x1501*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_cloud_keep_alive,
+ }, /*event_id 0x10003*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_dfs_radar_detected,
+ }, /*event_id 0x10004*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_dfs_cac_started,
+ }, /*event_id 0x10005*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_dfs_cac_finished,
+ }, /*event_id 0x10006*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_dfs_cac_aborted,
+ }, /*event_id 0x10007*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_dfs_nop_finished,
+ }, /*event_id 0x10008*/
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_wifi_logger_ring_buffer_data,
+ },
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_wifi_logger_alert,
+ },
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_packet_fate_monitor,
+ },
+ {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = event_wake_reason_report,
+ },
+ /**add vendor event here*/
+};
+
+/**nxp vendor policies*/
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+
+static const struct nla_policy woal_ll_stat_policy[ATTR_LL_STATS_MAX + 1] = {
+ [ATTR_LL_STATS_MPDU_SIZE_THRESHOLD] = {.type = NLA_U32},
+ [ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING] = {.type = NLA_U32},
+ [ATTR_LL_STATS_CLEAR_REQ_MASK] = {.type = NLA_U32},
+ [ATTR_LL_STATS_STOP_REQ] = {.type = NLA_U8}};
+
+static const struct nla_policy woal_logger_policy[ATTR_WIFI_LOGGER_MAX + 1] = {
+ [ATTR_WIFI_LOGGER_RING_ID] = {.type = NLA_STRING},
+ [ATTR_WIFI_LOGGER_VERBOSE_LEVEL] = {.type = NLA_U32},
+ [ATTR_WIFI_LOGGER_FLAGS] = {.type = NLA_U32},
+ [ATTR_WIFI_LOGGER_MIN_DATA_SIZE] = {.type = NLA_U32},
+ [ATTR_WIFI_LOGGER_MAX_INTERVAL_SEC] = {.type = NLA_U32}};
+
+static const struct nla_policy woal_attr_policy[ATTR_WIFI_MAX + 1] = {
+ [ATTR_CHANNELS_BAND] = {.type = NLA_U32},
+ [ATTR_SCAN_MAC_OUI_SET] = {.type = NLA_STRING, .len = 3},
+ [ATTR_NODFS_VALUE] = {.type = NLA_U32},
+ [ATTR_GET_CONCURRENCY_MATRIX_SET_SIZE_MAX] = {.type = NLA_U32},
+};
+
+// clang-format off
+static const struct nla_policy
+ woal_nd_offload_policy[ATTR_ND_OFFLOAD_MAX + 1] = {
+ [ATTR_ND_OFFLOAD_CONTROL] = {.type = NLA_U8},
+};
+// clang-format on
+
+static const struct nla_policy
+ woal_rssi_monitor_policy[ATTR_RSSI_MONITOR_MAX + 1] = {
+ [ATTR_RSSI_MONITOR_CONTROL] = {.type = NLA_U32},
+ [ATTR_RSSI_MONITOR_MIN_RSSI] = {.type = NLA_S8},
+ [ATTR_RSSI_MONITOR_MAX_RSSI] = {.type = NLA_S8},
+};
+
+static const struct nla_policy
+ woal_packet_filter_policy[ATTR_PACKET_FILTER_MAX + 1] = {
+ [ATTR_PACKET_FILTER_TOTAL_LENGTH] = {.type = NLA_U32},
+ [ATTR_PACKET_FILTER_PROGRAM] = {.type = NLA_STRING},
+};
+
+// clang-format off
+static const struct nla_policy
+ woal_fw_roaming_policy[MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX + 1] = {
+ [MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL] = {.type = NLA_U32},
+ [MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_BSSID] = {
+ .type = NLA_BINARY},
+ [MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_SSID] = {
+ .type = NLA_BINARY},
+};
+// clang-format on
+
+static const struct nla_policy
+ woal_keep_alive_policy[MKEEP_ALIVE_ATTRIBUTE_MAX + 1] = {
+ [MKEEP_ALIVE_ATTRIBUTE_ID] = {.type = NLA_U8},
+ [MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = {.type = NLA_U16},
+ [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = {.type = NLA_BINARY},
+ [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = {.type = NLA_U16},
+ [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = {.type = NLA_STRING,
+ .len = ETH_ALEN},
+ [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = {.type = NLA_STRING,
+ .len = ETH_ALEN},
+ [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = {.type = NLA_U32},
+ [MKEEP_ALIVE_ATTRIBUTE_RETRY_INTERVAL] = {.type = NLA_U32},
+ [MKEEP_ALIVE_ATTRIBUTE_RETRY_CNT] = {.type = NLA_U8},
+};
+#endif
+
+/**
+ * @brief get the event id of the events array
+ *
+ * @param event vendor event
+ *
+ * @return index of events array
+ */
+int woal_get_event_id(int event)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vendor_events); i++) {
+ if (vendor_events[i].subcmd == event)
+ return i;
+ }
+
+ return event_max;
+}
+
+/**
+ * @brief send vendor event to kernel
+ *
+ * @param priv A pointer to moal_private
+ * @param event vendor event
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+int woal_cfg80211_vendor_event(moal_private *priv, int event, t_u8 *data,
+ int len)
+{
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *skb = NULL;
+ int event_id = 0;
+ t_u8 *pos = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || !priv->wdev || !priv->wdev->wiphy) {
+ LEAVE();
+ return ret;
+ }
+ wiphy = priv->wdev->wiphy;
+ PRINTM(MEVENT, "vendor event :0x%x\n", event);
+ event_id = woal_get_event_id(event);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ ret = 1;
+ LEAVE();
+ return ret;
+ }
+
+ /**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len, event_id,
+ GFP_ATOMIC);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, GFP_ATOMIC);
+#endif
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ ret = 1;
+ LEAVE();
+ return ret;
+ }
+ pos = skb_put(skb, len);
+ moal_memcpy_ext(priv->phandle, pos, data, len, len);
+ /**send event*/
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send vendor event to kernel
+ *
+ * @param priv A pointer to moal_private
+ * @param event vendor event
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+struct sk_buff *woal_cfg80211_alloc_vendor_event(moal_private *priv, int event,
+ int len)
+{
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *skb = NULL;
+ int event_id = 0;
+
+ ENTER();
+
+ if (!priv || !priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ goto done;
+ }
+ wiphy = priv->wdev->wiphy;
+ PRINTM(MEVENT, "vendor event :0x%x\n", event);
+ event_id = woal_get_event_id(event);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ goto done;
+ }
+
+ /**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len, event_id,
+ GFP_ATOMIC);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, GFP_ATOMIC);
+#endif
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return skb;
+}
+
+/**
+ * @brief send dfs vendor event to kernel
+ *
+ * @param priv A pointer to moal_private
+ * @param event dfs vendor event
+ * @param chandef a pointer to struct cfg80211_chan_def
+ *
+ * @return N/A
+ */
+void woal_cfg80211_dfs_vendor_event(moal_private *priv, int event,
+ struct cfg80211_chan_def *chandef)
+{
+ dfs_event evt;
+
+ ENTER();
+ if (!chandef) {
+ LEAVE();
+ return;
+ }
+ memset(&evt, 0, sizeof(dfs_event));
+ evt.freq = chandef->chan->center_freq;
+ evt.chan_width = chandef->width;
+ evt.cf1 = chandef->center_freq1;
+ evt.cf2 = chandef->center_freq2;
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ evt.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ evt.ht_enabled = 1;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ evt.ht_enabled = 1;
+ if (chandef->center_freq1 < chandef->chan->center_freq)
+ evt.chan_offset = -1;
+ else
+ evt.chan_offset = 1;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ evt.ht_enabled = 1;
+ break;
+ default:
+ break;
+ }
+ woal_cfg80211_vendor_event(priv, event, (t_u8 *)&evt,
+ sizeof(dfs_event));
+ LEAVE();
+}
+
+/**
+ * @brief vendor command to set drvdbg
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_set_drvdbg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+#ifdef DEBUG_LEVEL1
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ t_u8 *pos = NULL;
+#endif
+ int ret = 1;
+
+ ENTER();
+#ifdef DEBUG_LEVEL1
+ /**handle this sub command*/
+ DBG_HEXDUMP(MCMD_D, "Vendor drvdbg", (t_u8 *)data, data_len);
+
+ if (data_len) {
+ /* Get the driver debug bit masks from user */
+ drvdbg = *((t_u32 *)data);
+ PRINTM(MIOCTL, "new drvdbg %x\n", drvdbg);
+ /* Set the driver debug bit masks into mlan */
+ if (woal_set_drvdbg(priv, drvdbg)) {
+ PRINTM(MERROR, "Set drvdbg failed!\n");
+ ret = 1;
+ }
+ }
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(drvdbg));
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = 1;
+ LEAVE();
+ return ret;
+ }
+ pos = skb_put(skb, sizeof(drvdbg));
+ moal_memcpy_ext(priv->phandle, pos, &drvdbg, sizeof(drvdbg),
+ sizeof(drvdbg));
+ ret = cfg80211_vendor_cmd_reply(skb);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief process one channel in bucket
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @param channel a pointer to channel
+ *
+ * @return 0: success other: fail
+ */
+static mlan_status woal_band_to_valid_channels(moal_private *priv,
+ wifi_band w_band, int channel[],
+ t_u32 *nchannel)
+{
+ int band = 0;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ int i = 0;
+ t_u8 cnt = 0;
+ int *ch_ptr = channel;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!priv->wdev->wiphy->bands[band])
+ continue;
+ if ((band == IEEE80211_BAND_2GHZ) && !(w_band & WIFI_BAND_BG))
+ continue;
+ if ((band == IEEE80211_BAND_5GHZ) &&
+ !((w_band & WIFI_BAND_A) || (w_band & WIFI_BAND_A_DFS)))
+ continue;
+ sband = priv->wdev->wiphy->bands[band];
+ for (i = 0; (i < sband->n_channels); i++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED) {
+ PRINTM(MERROR, "Skip DISABLED channel %d\n",
+ ch->center_freq);
+ continue;
+ }
+ if (band == IEEE80211_BAND_5GHZ) {
+ if (((ch->flags & IEEE80211_CHAN_RADAR) &&
+ !(w_band & WIFI_BAND_A_DFS)) ||
+ (!(ch->flags & IEEE80211_CHAN_RADAR) &&
+ !(w_band & WIFI_BAND_A)))
+ continue;
+ }
+ if (cnt >= *nchannel) {
+ PRINTM(MERROR,
+ "cnt=%d is exceed %d, cur ch=%d %dMHz\n",
+ cnt, *nchannel, ch->hw_value,
+ ch->center_freq);
+ break;
+ }
+ *ch_ptr = ch->center_freq;
+ ch_ptr++;
+ cnt++;
+ }
+ }
+
+ PRINTM(MCMND, "w_band=%d cnt=%d\n", w_band, cnt);
+ *nchannel = cnt;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief GSCAN subcmd - enable full scan results
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ *
+ * @param data a pointer to data
+ * @param data_len data length
+ *
+ * @return 0: success other: fail
+ */
+static int woal_cfg80211_subcmd_get_valid_channels(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct nlattr *tb[ATTR_WIFI_MAX + 1];
+ t_u32 band = 0;
+ int ch_out[MAX_CHANNEL_NUM];
+ t_u32 nchannel = 0;
+ t_u32 mem_needed = 0;
+ struct sk_buff *skb = NULL;
+ int err = 0;
+
+ ENTER();
+ PRINTM(MCMND, "Enter %s()\n", __func__);
+
+ err = nla_parse(tb, ATTR_WIFI_MAX, data, len, NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (err) {
+ PRINTM(MERROR, "%s: nla_parse fail\n", __func__);
+ err = -EFAULT;
+ goto done;
+ }
+
+ if (!tb[ATTR_CHANNELS_BAND]) {
+ PRINTM(MERROR, "%s: null attr: tb[ATTR_GET_CH]=%p\n", __func__,
+ tb[ATTR_CHANNELS_BAND]);
+ err = -EINVAL;
+ goto done;
+ }
+ band = nla_get_u32(tb[ATTR_CHANNELS_BAND]);
+ if (band > WIFI_BAND_MAX) {
+ PRINTM(MERROR, "%s: invalid band=%d\n", __func__, band);
+ err = -EINVAL;
+ goto done;
+ }
+
+ memset(ch_out, 0x00, sizeof(ch_out));
+ nchannel = MAX_CHANNEL_NUM;
+ if (woal_band_to_valid_channels(priv, band, ch_out, &nchannel) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "get_channel_list: woal_band_to_valid_channels fail\n");
+ return -EFAULT;
+ }
+
+ mem_needed = nla_total_size(nchannel * sizeof(ch_out[0])) +
+ nla_total_size(sizeof(nchannel)) + VENDOR_REPLY_OVERHEAD;
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed");
+ err = -ENOMEM;
+ goto done;
+ }
+
+ if (nla_put_u32(skb, ATTR_NUM_CHANNELS, nchannel) ||
+ nla_put(skb, ATTR_CHANNEL_LIST, nchannel * sizeof(ch_out[0]),
+ ch_out)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ err = -ENOMEM;
+ goto done;
+ }
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (err) {
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return err;
+}
+
+/**
+ * @brief vendor command to get driver version
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_drv_version(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ int ret = 0;
+ t_u32 drv_len = 0;
+ char drv_version[MLAN_MAX_VER_STR_LEN] = {0};
+ char *pos;
+
+ ENTER();
+ moal_memcpy_ext(priv->phandle, drv_version,
+ &priv->phandle->driver_version, MLAN_MAX_VER_STR_LEN,
+ MLAN_MAX_VER_STR_LEN);
+ drv_len = strlen(drv_version);
+ pos = strstr(drv_version, "%s");
+ /* remove 3 char "-%s" in driver_version string */
+ if (pos != NULL)
+ moal_memcpy_ext(priv->phandle, pos, pos + 3, strlen(pos) - 3,
+ strlen(pos));
+
+ reply_len = strlen(drv_version) + 1;
+ drv_len -= 3;
+ drv_version[drv_len] = '\0';
+
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ nla_put(skb, MRVL_WLAN_VENDOR_ATTR_NAME, reply_len,
+ (t_u8 *)drv_version);
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get firmware version
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_fw_version(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ char end_c = '\0';
+ int ret = 0;
+ char fw_ver[32] = {0};
+ union {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+
+ ENTER();
+
+ ver.l = priv->phandle->fw_release_number;
+ snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u%c", ver.c[2], ver.c[1],
+ ver.c[0], ver.c[3], end_c);
+ reply_len = strlen(fw_ver) + 1;
+
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ nla_put(skb, MRVL_WLAN_VENDOR_ATTR_NAME, reply_len, (t_u8 *)fw_ver);
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get firmware memory dump
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_fw_dump(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ moal_handle *handle = NULL;
+ int ret = MLAN_STATUS_SUCCESS;
+ int length = 0;
+ struct sk_buff *skb = NULL;
+
+ ENTER();
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ handle = priv->phandle;
+ if (handle) {
+ memset(handle->firmware_dump_file, 0,
+ sizeof(handle->firmware_dump_file));
+ }
+ length = sizeof(handle->firmware_dump_file);
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
+ if (!skb) {
+ PRINTM(MERROR, "Failed to allocate memory for skb\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ nla_put(skb, ATTR_FW_DUMP_PATH, sizeof(handle->firmware_dump_file),
+ handle->firmware_dump_file);
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get driver memory dump
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_drv_dump(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ moal_handle *handle = NULL;
+ int ret = MLAN_STATUS_SUCCESS;
+ int length = 0;
+ char driver_dump_file[128];
+ char path_name[64];
+ struct sk_buff *skb = NULL;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ handle = priv->phandle;
+ memset(path_name, 0, sizeof(path_name));
+ woal_create_dump_dir(handle, path_name, sizeof(path_name));
+ PRINTM(MMSG, "driver dump path name is %s\n", path_name);
+ woal_dump_drv_info(handle, path_name);
+ memset(driver_dump_file, 0, sizeof(driver_dump_file));
+ sprintf(driver_dump_file, "%s/%s", path_name, "file_drv_info");
+ PRINTM(MMSG, "driver dump file is %s\n", driver_dump_file);
+ length = sizeof(driver_dump_file);
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
+ if (!skb) {
+ PRINTM(MERROR, "Failed to allocate memory for skb\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (nla_put_string(skb, ATTR_DRV_DUMP_PATH, driver_dump_file)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get supported feature set
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_supp_feature_set(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ struct sk_buff *skb = NULL;
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ mlan_fw_info fw_info;
+ t_u32 reply_len = 0;
+ int ret = 0;
+ t_u32 supp_feature_set = 0;
+
+ ENTER();
+
+ supp_feature_set = WLAN_FEATURE_INFRA
+#if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
+ | WLAN_FEATURE_AP_STA
+#endif
+ | WLAN_FEATURE_LINK_LAYER_STATS |
+ WLAN_FEATURE_LOGGER | WLAN_FEATURE_RSSI_MONITOR |
+ WLAN_FEATURE_CONFIG_NDO |
+ WLAN_FEATURE_CONTROL_ROAMING |
+ WLAN_FEATURE_SCAN_RAND | WLAN_FEATURE_MKEEP_ALIVE;
+
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if (fw_info.fw_bands & BAND_A)
+ supp_feature_set |= WLAN_FEATURE_INFRA_5G;
+
+ reply_len = sizeof(supp_feature_set);
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (nla_put_u32(skb, ATTR_FEATURE_SET, supp_feature_set)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to set country code
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_set_country_code(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ int ret = 0, rem, type;
+ const struct nlattr *iter;
+ char country[COUNTRY_CODE_LEN] = {0};
+
+ ENTER();
+
+ nla_for_each_attr (iter, data, data_len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case ATTR_COUNTRY_CODE:
+ strncpy(country, nla_data(iter),
+ MIN(sizeof(country) - 1, nla_len(iter)));
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ return ret;
+ }
+ }
+
+ if (!moal_extflg_isset((moal_handle *)woal_get_wiphy_priv(wiphy),
+ EXT_DISABLE_REGD_BY_DRIVER))
+ regulatory_hint(wiphy, country);
+
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get supported feature set
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_wifi_logger_supp_feature_set(
+ struct wiphy *wiphy, struct wireless_dev *wdev, const void *data,
+ int data_len)
+{
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ int ret = 0;
+ t_u32 supp_feature_set = 0;
+
+ ENTER();
+
+ supp_feature_set = WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
+ reply_len = sizeof(supp_feature_set);
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (nla_put_u32(skb, ATTR_WIFI_LOGGER_FEATURE_SET, supp_feature_set)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+ ret = cfg80211_vendor_cmd_reply(skb);
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief get ring status
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_id ring buffer id
+ * @param status a pointer to wifi_ring_buffer_status
+ *
+ * @return void
+ */
+static void woal_get_ring_status(moal_private *priv, int ring_id,
+ wifi_ring_buffer_status *status)
+{
+ int id = 0;
+ wifi_ring_buffer *ring;
+
+ ENTER();
+ for (id = 0; id < RING_ID_MAX; id++) {
+ ring = (wifi_ring_buffer *)priv->rings[id];
+ if (ring && VALID_RING(ring->ring_id) &&
+ ring_id == ring->ring_id) {
+ strncpy(status->name, ring->name,
+ sizeof(status->name) - 1);
+ status->ring_id = ring->ring_id;
+ status->ring_buffer_byte_size = ring->ring_size;
+ status->written_bytes = ring->ctrl.written_bytes;
+ status->written_records = ring->ctrl.written_records;
+ status->read_bytes = ring->ctrl.read_bytes;
+ status->verbose_level = ring->log_level;
+ PRINTM(MINFO,
+ "%s, name: %s, ring_id: %d, ring_size : %d, written_bytes: %d, written_records: %d, read_bytes: %d\n",
+ __func__, status->name, status->ring_id,
+ status->ring_buffer_byte_size,
+ status->written_bytes, status->written_records,
+ status->read_bytes);
+ break;
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief vendor command to get ring buffer status
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_ring_buff_status(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ t_u8 ringIdx, ring_cnt = 0;
+ int ret = 0;
+ wifi_ring_buffer_status status[RING_ID_MAX];
+ wifi_ring_buffer_status ring_status;
+
+ ENTER();
+ reply_len =
+ RING_ID_MAX * sizeof(wifi_ring_buffer_status) + sizeof(t_u32);
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* should sync with HAL side to decide payload layout.
+ * just ring buffer status or ring buffer num + ring buffer status
+ * currently only have ring buffer status
+ */
+ for (ringIdx = 0; ringIdx < RING_ID_MAX; ringIdx++) {
+ memset(&ring_status, 0, sizeof(wifi_ring_buffer_status));
+ woal_get_ring_status(priv, ringIdx, &ring_status);
+ moal_memcpy_ext(priv->phandle, &status[ring_cnt++],
+ &ring_status, sizeof(wifi_ring_buffer_status),
+ sizeof(wifi_ring_buffer_status));
+ }
+
+ if (nla_put_u32(skb, ATTR_NUM_RINGS, ring_cnt) ||
+ nla_put(skb, ATTR_RING_BUFFER_STATUS,
+ sizeof(wifi_ring_buffer_status) * ring_cnt, status)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(skb);
+
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief return ring_id based on ring_name
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_name A pointer to ring_name
+ *
+ * @return An invalid ring id for failure or valid ring id on success.
+ */
+int woal_get_ring_id_by_name(moal_private *priv, char *ring_name)
+{
+ int id;
+ wifi_ring_buffer *ring;
+
+ ENTER();
+
+ for (id = 0; id < RING_ID_MAX; id++) {
+ ring = (wifi_ring_buffer *)priv->rings[id];
+ if (ring &&
+ !strncmp(ring->name, ring_name, sizeof(ring->name) - 1))
+ break;
+ }
+
+ LEAVE();
+ return id;
+}
+
+/**
+ * @brief start logger
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_name string ring_name
+ * @param log_level log level to record
+ * @param flags reserved
+ * @param time_intval interval to report log to HAL
+ * @param threshold buffer threshold to report log to HAL
+ *
+ * @return 0: success 1: fail
+ */
+int woal_start_logging(moal_private *priv, char *ring_name, int log_level,
+ int flags, int time_intval, int threshold)
+{
+ int ret = 0;
+ int ring_id;
+ wifi_ring_buffer *ring_buffer;
+ unsigned long lock_flags;
+
+ ENTER();
+
+ ring_id = woal_get_ring_id_by_name(priv, ring_name);
+ if (!VALID_RING(ring_id)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MCMND,
+ "%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
+ __func__, log_level, time_intval, threshold);
+
+ ring_buffer = (wifi_ring_buffer *)priv->rings[ring_id];
+ if (!ring_buffer || ring_buffer->state == RING_STOP) {
+ PRINTM(MERROR, "Ring is stopped!\n");
+ ret = -EAGAIN;
+ goto done;
+ }
+
+ spin_lock_irqsave(&ring_buffer->lock, lock_flags);
+ ring_buffer->log_level = log_level;
+ ring_buffer->threshold = threshold;
+ if (log_level == 0)
+ ring_buffer->state = RING_SUSPEND;
+ else
+ ring_buffer->state = RING_ACTIVE;
+ ring_buffer->interval = msecs_to_jiffies(time_intval * MSEC_PER_SEC);
+ spin_unlock_irqrestore(&ring_buffer->lock, lock_flags);
+
+ if (log_level == 0) {
+ cancel_delayed_work_sync(&ring_buffer->work);
+ } else {
+ if (ring_buffer->interval)
+ schedule_delayed_work(&ring_buffer->work,
+ ring_buffer->interval);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to start logging
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_start_logging(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int ret = 0, rem, type;
+ char ring_name[RING_NAME_MAX] = {0};
+ int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
+ const struct nlattr *iter;
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case ATTR_WIFI_LOGGER_RING_ID:
+ strncpy(ring_name, nla_data(iter),
+ MIN(sizeof(ring_name) - 1, nla_len(iter)));
+ break;
+ case ATTR_WIFI_LOGGER_VERBOSE_LEVEL:
+ log_level = nla_get_u32(iter);
+ break;
+ case ATTR_WIFI_LOGGER_FLAGS:
+ flags = nla_get_u32(iter);
+ break;
+ case ATTR_WIFI_LOGGER_MAX_INTERVAL_SEC:
+ time_intval = nla_get_u32(iter);
+ break;
+ case ATTR_WIFI_LOGGER_MIN_DATA_SIZE:
+ threshold = nla_get_u32(iter);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ ret = woal_start_logging(priv, ring_name, log_level, flags, time_intval,
+ threshold);
+ if (ret < 0)
+ PRINTM(MERROR, "Start_logging is failed ret: %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief get log data in ring buffer
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_name ring name string
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_trigger_get_ring_data(moal_private *priv, char *ring_name)
+{
+ int ret = 0;
+ int ring_id;
+ wifi_ring_buffer *ring_buffer;
+
+ ENTER();
+
+ ring_id = woal_get_ring_id_by_name(priv, ring_name);
+ if (!VALID_RING(ring_id)) {
+ PRINTM(MERROR, "invalid ring_id\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ring_buffer = (wifi_ring_buffer *)priv->rings[ring_id];
+ if (!ring_buffer) {
+ PRINTM(MERROR, "invalid ring_buffer\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ring_buffer->interval)
+ cancel_delayed_work_sync(&ring_buffer->work);
+ schedule_delayed_work(&ring_buffer->work, 0);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get ring buffer data
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_ring_data(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int ret = 0, rem, type;
+ char ring_name[RING_NAME_MAX] = {0};
+ const struct nlattr *iter;
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case ATTR_WIFI_LOGGER_RING_ID:
+ strncpy(ring_name, nla_data(iter),
+ MIN(sizeof(ring_name) - 1, nla_len(iter)));
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ ret = woal_trigger_get_ring_data(priv, ring_name);
+ if (ret < 0)
+ PRINTM(MERROR, "trigger_get_data failed ret:%d\n", ret);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ring reset
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring A pointer to wifi_ring_buffer
+ *
+ * @return void
+ */
+static void woal_ring_reset(wifi_ring_buffer *ring)
+{
+ ENTER();
+ ring->wp = 0;
+ ring->rp = 0;
+ memset(&(ring->ctrl), 0x00, sizeof(ring->ctrl));
+ memset(ring->ring_buf, 0, ring->ring_size);
+
+ LEAVE();
+}
+
+/**
+ * @brief get ring buffer entry
+ *
+ * @param ring A pointer to wifi_ring_buffer struct
+ * @param offset entry offset
+ *
+ * @return A pointer to wifi_ring_buffer_entry struct
+ */
+static wifi_ring_buffer_entry *woal_get_ring_entry(wifi_ring_buffer *ring,
+ t_u32 offset)
+{
+ wifi_ring_buffer_entry *entry =
+ (wifi_ring_buffer_entry *)(ring->ring_buf + offset);
+
+ ENTER();
+
+ if (!entry->entry_size)
+ return (wifi_ring_buffer_entry *)ring->ring_buf;
+
+ LEAVE();
+ return entry;
+}
+
+/**
+ * @brief get next ring buffer entry
+ *
+ * @param ring A pointer to wifi_ring_buffer struct
+ * @param offset next entry offset
+ *
+ * @return offset of next entry
+ */
+static t_u32 woal_get_ring_next_entry(wifi_ring_buffer *ring, t_u32 offset)
+{
+ wifi_ring_buffer_entry *entry =
+ (wifi_ring_buffer_entry *)(ring->ring_buf + offset);
+ wifi_ring_buffer_entry *next_entry = NULL;
+
+ ENTER();
+
+ if (!entry->entry_size) {
+ entry = (wifi_ring_buffer_entry *)ring->ring_buf;
+ LEAVE();
+ return ENTRY_LENGTH(entry);
+ }
+ if ((offset + ENTRY_LENGTH(entry)) >= ring->ring_size) {
+ /* move to head */
+ LEAVE();
+ return 0;
+ }
+ next_entry = (wifi_ring_buffer_entry *)(ring->ring_buf + offset +
+ ENTRY_LENGTH(entry));
+ if (!next_entry->entry_size) {
+ /* move to head */
+ LEAVE();
+ return 0;
+ }
+ LEAVE();
+ return offset + ENTRY_LENGTH(entry);
+}
+
+/**
+ * @brief prepare log data to send to HAL
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_id ring ID
+ * @param data A pointer to data buffer
+ * @param buf_len log data length
+ *
+ * @return data length
+ */
+int woal_ring_pull_data(moal_private *priv, int ring_id, void *data,
+ t_s32 buf_len)
+{
+ t_s32 r_len = 0;
+ wifi_ring_buffer *ring;
+ wifi_ring_buffer_entry *hdr;
+ t_s32 buf_left = buf_len;
+
+ ENTER();
+
+ ring = (wifi_ring_buffer *)priv->rings[ring_id];
+
+ /* get a fresh pending length */
+ while (buf_left > 0) {
+ hdr = woal_get_ring_entry(ring, ring->rp);
+ if (buf_left < ENTRY_LENGTH(hdr))
+ break;
+ moal_memcpy_ext(priv->phandle, data, hdr, ENTRY_LENGTH(hdr),
+ buf_left);
+ r_len += ENTRY_LENGTH(hdr);
+ data += ENTRY_LENGTH(hdr);
+ buf_left -= ENTRY_LENGTH(hdr);
+ ring->ctrl.read_bytes += ENTRY_LENGTH(hdr);
+ if (!buf_left) {
+ ring->rp += ENTRY_LENGTH(hdr);
+ break;
+ }
+ ring->rp = woal_get_ring_next_entry(ring, ring->rp);
+ }
+ PRINTM(MDATA, "Ring pull data: [wp=%d rp=%d] r_len=%d buf_len=%d\n",
+ ring->wp, ring->rp, r_len, buf_len);
+
+ LEAVE();
+ return r_len;
+}
+
+/**
+ * @brief send vendor event to kernel
+ *
+ * @param priv A pointer to moal_private
+ * @param event vendor event
+ * @param data a pointer to data
+ * @param len data length
+ * @param ring_status A pointer to wifi_ring_buffer status struct
+ *
+ * @return 0: success 1: fail
+ */
+int woal_ring_buffer_data_vendor_event(moal_private *priv, int ring_id,
+ t_u8 *data, int len,
+ wifi_ring_buffer_status *ring_status)
+{
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *skb = NULL;
+ int event_id = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || !priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "priv is null\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ wiphy = priv->wdev->wiphy;
+ PRINTM(MEVENT, "%s ring_id:%d\n", __func__, ring_id);
+ event_id = woal_get_event_id(event_wifi_logger_ring_buffer_data);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+/**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
+ len + sizeof(wifi_ring_buffer_status),
+ event_id, GFP_ATOMIC);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy,
+ len + sizeof(wifi_ring_buffer_status),
+ event_id, GFP_ATOMIC);
+#endif
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ nla_put(skb, ATTR_RING_BUFFER_STATUS, sizeof(wifi_ring_buffer_status),
+ ring_status);
+ DBG_HEXDUMP(MEVT_D, "ring_buffer_data", data, len);
+ nla_put(skb, ATTR_RING_BUFFER, len, data);
+
+ /**send event*/
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send log data to HAL
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_id ring ID
+ * @param data A pointer to data buffer
+ * @param len log data length
+ * @param ring_status A pointer to wifi_ring_buffer status struct
+ *
+ * @return void
+ */
+static void woal_ring_data_send(moal_private *priv, int ring_id,
+ const void *data, const t_u32 len,
+ wifi_ring_buffer_status *ring_status)
+{
+ struct net_device *ndev = priv->netdev;
+
+ ENTER();
+
+ if (!ndev)
+ goto done;
+ woal_ring_buffer_data_vendor_event(priv, ring_id, (t_u8 *)data, len,
+ ring_status);
+
+done:
+ LEAVE();
+}
+
+/**
+ * @brief main thread to send log data
+ *
+ * @param work A pointer to work_struct struct
+ *
+ * @return void
+ */
+void woal_ring_poll_worker(struct work_struct *work)
+{
+ struct delayed_work *d_work = to_delayed_work(work);
+ wifi_ring_buffer *ring_info =
+ container_of(d_work, wifi_ring_buffer, work);
+ moal_private *priv = ring_info->priv;
+ int ringid = ring_info->ring_id;
+ wifi_ring_buffer_status ring_status;
+ void *buf = NULL;
+ wifi_ring_buffer_entry *hdr;
+ t_s32 buflen, rlen;
+ unsigned long flags;
+
+ ENTER();
+ if (ring_info->state != RING_ACTIVE) {
+ PRINTM(MERROR, "Ring is not active!\n");
+ goto exit;
+ }
+ buf = kmalloc(ring_info->ring_size, GFP_KERNEL);
+ if (!buf) {
+ PRINTM(MERROR, "Fail to allocate buffer for poll work\n");
+ goto exit;
+ }
+ spin_lock_irqsave(&ring_info->lock, flags);
+ memset(&ring_status, 0, sizeof(ring_status));
+ woal_get_ring_status(priv, ringid, &ring_status);
+ PRINTM(MDATA, "Ring work: ringid %d write %d, read %d, size %d\n",
+ ringid, ring_status.written_bytes, ring_status.read_bytes,
+ ring_status.ring_buffer_byte_size);
+ if (ring_status.written_bytes > ring_status.read_bytes) {
+ buflen = ring_status.written_bytes - ring_status.read_bytes;
+ if (buflen > ring_info->ring_size) {
+ PRINTM(MERROR, "Pending data bigger than ring size\n");
+ spin_unlock_irqrestore(&ring_info->lock, flags);
+ goto exit;
+ }
+ } else {
+ spin_unlock_irqrestore(&ring_info->lock, flags);
+ PRINTM(MINFO, "No new records\n");
+ goto exit;
+ }
+
+ rlen = woal_ring_pull_data(priv, ringid, buf, buflen);
+ spin_unlock_irqrestore(&ring_info->lock, flags);
+ hdr = (wifi_ring_buffer_entry *)buf;
+ while (rlen > 0) {
+ ring_status.read_bytes += ENTRY_LENGTH(hdr);
+ woal_ring_data_send(priv, ringid, hdr, ENTRY_LENGTH(hdr),
+ &ring_status);
+ rlen -= ENTRY_LENGTH(hdr);
+ hdr = (wifi_ring_buffer_entry *)((void *)hdr +
+ ENTRY_LENGTH(hdr));
+ }
+exit:
+ kfree(buf);
+ if (ring_info->interval)
+ schedule_delayed_work(&ring_info->work, ring_info->interval);
+
+ LEAVE();
+}
+
+/**
+ * @brief add log data to ring buffer
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_id ring ID
+ * @param hdr A pointer to wifi_ring_buffer_entry struct
+ * @param data A pointer to data buffer
+ *
+ * @return 0: success -1: fail
+ */
+int woal_ring_push_data(moal_private *priv, int ring_id,
+ wifi_ring_buffer_entry *hdr, void *data)
+{
+ unsigned long flags;
+ t_u32 w_len;
+ wifi_ring_buffer *ring;
+ wifi_ring_buffer_entry *w_entry;
+ int ret = 0;
+
+ ENTER();
+
+ ring = (wifi_ring_buffer *)priv->rings[ring_id];
+
+ if (!ring || ring->state != RING_ACTIVE) {
+ PRINTM(MERROR, "Ring is not active\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ w_len = ENTRY_LENGTH(hdr);
+ if (w_len > ring->ring_size) {
+ PRINTM(MERROR, "event size too big =%d\n", w_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ spin_lock_irqsave(&ring->lock, flags);
+ PRINTM(MDATA, "Ring push data: rp=%d wp=%d, w_len=%d\n", ring->rp,
+ ring->wp, w_len);
+ /* prep the space */
+ do {
+ if (ring->rp == ring->wp) {
+ if (ring->ctrl.read_bytes == ring->ctrl.written_bytes) {
+ if (ring->wp)
+ woal_ring_reset(ring);
+ break;
+ } else {
+ /* full, we should drop one entry */
+ w_entry =
+ (wifi_ring_buffer_entry
+ *)(ring->ring_buf + ring->rp);
+ ring->rp = woal_get_ring_next_entry(ring,
+ ring->rp);
+ ring->ctrl.written_bytes -=
+ ENTRY_LENGTH(w_entry);
+ memset((u8 *)w_entry, 0, ENTRY_LENGTH(w_entry));
+ ring->ctrl.written_records--;
+ continue;
+ }
+ }
+ if (ring->rp < ring->wp) {
+ if (ring->ring_size - ring->wp >= w_len) {
+ break;
+ } else if (ring->ring_size - ring->wp < w_len) {
+ if (ring->rp == 0) {
+ /** drop one entry */
+ w_entry = (wifi_ring_buffer_entry
+ *)(ring->ring_buf +
+ ring->rp);
+ ring->rp = woal_get_ring_next_entry(
+ ring, ring->rp);
+ ring->ctrl.written_bytes -=
+ ENTRY_LENGTH(w_entry);
+ memset((u8 *)w_entry, 0,
+ ENTRY_LENGTH(w_entry));
+ ring->ctrl.written_records--;
+ }
+ ring->wp = 0;
+ continue;
+ }
+ }
+ if (ring->rp > ring->wp) {
+ if (ring->rp - ring->wp < w_len) {
+ /** drop one entry */
+ w_entry =
+ (wifi_ring_buffer_entry
+ *)(ring->ring_buf + ring->rp);
+ ring->rp = woal_get_ring_next_entry(ring,
+ ring->rp);
+ ring->ctrl.written_bytes -=
+ ENTRY_LENGTH(w_entry);
+ memset((u8 *)w_entry, 0, ENTRY_LENGTH(w_entry));
+ ring->ctrl.written_records--;
+ continue;
+ } else {
+ break;
+ }
+ }
+ } while (1);
+
+ if ((ring->wp + w_len) > ring->ring_size ||
+ (ring->ctrl.written_bytes + w_len) > ring->ring_size) {
+ PRINTM(MERROR,
+ "Ring push buffer overflow: rp=%d wp=%d, write_bytes=%d\n",
+ ring->rp, ring->wp, ring->ctrl.written_bytes);
+ goto done;
+ }
+
+ w_entry = (wifi_ring_buffer_entry *)(ring->ring_buf + ring->wp);
+ /* header */
+ moal_memcpy_ext(priv->phandle, w_entry, hdr, RING_ENTRY_SIZE,
+ ENTRY_LENGTH(w_entry));
+ /* payload */
+ moal_memcpy_ext(priv->phandle, (char *)w_entry + RING_ENTRY_SIZE, data,
+ w_entry->entry_size, w_entry->entry_size);
+ /* update write pointer */
+ ring->wp += w_len;
+ /* update statistics */
+ ring->ctrl.written_records++;
+ ring->ctrl.written_bytes += w_len;
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ PRINTM(MDATA,
+ "Ring push data: wp=%d rp=%d write_bytes=%d, read_bytes=%d\n",
+ ring->wp, ring->rp, ring->ctrl.written_bytes,
+ ring->ctrl.read_bytes);
+
+ /* if the current pending size is bigger than threshold */
+ if (ring->threshold && (READ_AVAIL_SPACE(ring) >= ring->threshold)) {
+ PRINTM(MDATA, "Ring threshold reached\n");
+ if (ring->interval)
+ cancel_delayed_work_sync(&ring->work);
+ schedule_delayed_work(&ring->work, 0);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will init wifi logger ring buffer
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ring_buff A pointer to wifi_ring_buffer structure
+ * @param ringIdx Ring buffer ID
+ * @param name Ring buffer name
+ * @param ring_sz Ring buffer size
+ *
+ * @return 0 - success
+ */
+static int woal_init_ring_buffer_internal(moal_private *priv, void **ring,
+ t_u16 ringIdx, t_u8 *name,
+ t_u32 ring_sz)
+{
+ unsigned long flags;
+ wifi_ring_buffer *ring_buff;
+
+ ENTER();
+
+ *ring = vmalloc(sizeof(wifi_ring_buffer));
+ if (!unlikely(*ring)) {
+ PRINTM(MERROR, "WiFi Logger: ring alloc failed\n");
+ goto done;
+ }
+ memset(*ring, 0, sizeof(wifi_ring_buffer));
+ ring_buff = (wifi_ring_buffer *)*ring;
+
+ ring_buff->ring_buf = vmalloc(ring_sz);
+ if (!unlikely(ring_buff->ring_buf)) {
+ PRINTM(MERROR, "WiFi Logger: ring buffer data alloc failed\n");
+ vfree(ring_buff);
+ *ring = NULL;
+ goto done;
+ }
+ memset(ring_buff->ring_buf, 0, ring_sz);
+ spin_lock_init(&ring_buff->lock);
+ spin_lock_irqsave(&ring_buff->lock, flags);
+ ring_buff->rp = ring_buff->wp = 0;
+ INIT_DELAYED_WORK(&ring_buff->work, woal_ring_poll_worker);
+ moal_memcpy_ext(priv->phandle, ring_buff->name, name, strlen(name),
+ RING_NAME_MAX - 1);
+ ring_buff->name[RING_NAME_MAX - 1] = 0;
+ ring_buff->ring_id = ringIdx;
+ ring_buff->ring_size = ring_sz;
+ ring_buff->state = RING_SUSPEND;
+ ring_buff->threshold = ring_buff->ring_size / 2;
+ ring_buff->priv = priv;
+ spin_unlock_irqrestore(&ring_buff->lock, flags);
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief init each ring in moal_private
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return data length
+ */
+static int woal_init_ring_buffer(moal_private *priv)
+{
+ ENTER();
+ woal_init_ring_buffer_internal(priv, &priv->rings[VERBOSE_RING_ID],
+ VERBOSE_RING_ID, VERBOSE_RING_NAME,
+ DEFAULT_RING_BUFFER_SIZE);
+ woal_init_ring_buffer_internal(priv, &priv->rings[EVENT_RING_ID],
+ EVENT_RING_ID, EVENT_RING_NAME,
+ DEFAULT_RING_BUFFER_SIZE);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief deinit each ring in moal_private
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return data length
+ */
+static int woal_deinit_ring_buffer(moal_private *priv)
+{
+ int i;
+ enum ring_state ring_state = RING_STOP;
+ unsigned long lock_flags = 0;
+ wifi_ring_buffer *ring_buff;
+
+ ENTER();
+
+ for (i = 0; i < RING_ID_MAX - 1; i++) {
+ ring_buff = (wifi_ring_buffer *)priv->rings[i];
+ if (!ring_buff)
+ continue;
+ spin_lock_irqsave(&ring_buff->lock, lock_flags);
+ ring_state = ring_buff->state;
+ if (ring_state == RING_ACTIVE)
+ ring_buff->state = RING_STOP;
+ spin_unlock_irqrestore(&ring_buff->lock, lock_flags);
+ if (ring_state == RING_ACTIVE)
+ cancel_delayed_work_sync(&ring_buff->work);
+ vfree(ring_buff->ring_buf);
+ ring_buff->ring_buf = NULL;
+ vfree(ring_buff);
+ priv->rings[i] = NULL;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief add log data to ring buffer
+ *
+ * @param priv A pointer to moal_private struct
+ * @param ring_id ring ID
+ * @param hdr A pointer to wifi_ring_buffer_entry struct
+ * @param data A pointer to data buffer
+ *
+ * @return 0: success -1: fail
+ */
+int woal_ring_event_logger(moal_private *priv, int ring_id, pmlan_event pmevent)
+{
+ t_u8 event_buf[100] = {0};
+ wifi_ring_buffer_driver_connectivity_event *connectivity_event;
+ tlv_log *tlv;
+ t_u8 *pos;
+ wifi_ring_buffer_entry msg_hdr;
+ wifi_ring_buffer *ring;
+
+ ENTER();
+ ring = (wifi_ring_buffer *)priv->rings[ring_id];
+
+ if (!ring || ring->state != RING_ACTIVE) {
+ PRINTM(MINFO, "Ring is not active\n");
+ goto done;
+ }
+
+ switch (pmevent->event_id) {
+ case MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER:
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ assoc_logger_data *pbss_desc =
+ (assoc_logger_data *)pmevent->event_buf;
+ memset(&msg_hdr, 0, sizeof(msg_hdr));
+ msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
+ msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
+ connectivity_event =
+ (wifi_ring_buffer_driver_connectivity_event *)
+ event_buf;
+ connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
+ pos = (t_u8 *)connectivity_event->tlvs;
+
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_VENDOR_SPECIFIC;
+ tlv->length = MLAN_MAC_ADDR_LENGTH / 2;
+ moal_memcpy_ext(priv->phandle, tlv->value,
+ pbss_desc->oui, tlv->length,
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
+ pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
+
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_BSSID;
+ tlv->length = sizeof(pbss_desc->bssid);
+ moal_memcpy_ext(
+ priv->phandle, tlv->value, pbss_desc->bssid,
+ sizeof(pbss_desc->bssid),
+ sizeof(event_buf) - (tlv->value - event_buf));
+ msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
+ pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
+
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_SSID;
+ tlv->length = strlen(pbss_desc->ssid);
+ moal_memcpy_ext(priv->phandle, tlv->value,
+ pbss_desc->ssid, tlv->length,
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
+ pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
+
+ if (pbss_desc->rssi) {
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_RSSI;
+ tlv->length = sizeof(pbss_desc->rssi);
+ moal_memcpy_ext(
+ priv->phandle, tlv->value,
+ &pbss_desc->rssi, tlv->length,
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size +=
+ tlv->length + TLV_LOG_HEADER_LEN;
+ pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
+ }
+ if (pbss_desc->channel) {
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_CHANNEL;
+ tlv->length = sizeof(pbss_desc->channel);
+ moal_memcpy_ext(
+ priv->phandle, tlv->value,
+ &pbss_desc->channel,
+ sizeof(pbss_desc->channel),
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size +=
+ tlv->length + TLV_LOG_HEADER_LEN;
+ }
+ msg_hdr.entry_size += sizeof(connectivity_event->event);
+ DBG_HEXDUMP(MCMD_D, "connectivity_event",
+ (t_u8 *)connectivity_event,
+ msg_hdr.entry_size);
+ woal_ring_push_data(priv, ring_id, &msg_hdr,
+ connectivity_event);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER:
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ int status_code = *(int *)pmevent->event_buf;
+
+ memset(&msg_hdr, 0, sizeof(msg_hdr));
+ msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
+ msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
+ connectivity_event =
+ (wifi_ring_buffer_driver_connectivity_event *)
+ event_buf;
+ connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
+ pos = (t_u8 *)connectivity_event->tlvs;
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_STATUS;
+ tlv->length = sizeof(status_code);
+ moal_memcpy_ext(priv->phandle, tlv->value, &status_code,
+ sizeof(status_code),
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size += tlv->length + 4;
+ msg_hdr.entry_size += sizeof(connectivity_event->event);
+ woal_ring_push_data(priv, ring_id, &msg_hdr,
+ connectivity_event);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER:
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ t_u16 reason_code = *(t_u16 *)pmevent->event_buf;
+
+ memset(&msg_hdr, 0, sizeof(msg_hdr));
+ msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
+ msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
+ connectivity_event =
+ (wifi_ring_buffer_driver_connectivity_event *)
+ event_buf;
+ connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
+ pos = (t_u8 *)connectivity_event->tlvs;
+ tlv = (tlv_log *)pos;
+ tlv->tag = WIFI_TAG_REASON_CODE;
+ tlv->length = sizeof(reason_code);
+ moal_memcpy_ext(priv->phandle, tlv->value, &reason_code,
+ sizeof(reason_code),
+ sizeof(event_buf) -
+ (tlv->value - event_buf));
+ msg_hdr.entry_size += tlv->length + 4;
+ msg_hdr.entry_size += sizeof(connectivity_event->event);
+ woal_ring_push_data(priv, ring_id, &msg_hdr,
+ connectivity_event);
+ }
+ break;
+ default:
+ break;
+ }
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief send vendor event to kernel
+ *
+ * @param priv A pointer to moal_private struct
+ * @param wake_reason wake_reason
+ *
+ * @return 0: success 1: fail
+ */
+int woal_wake_reason_vendor_event(moal_private *priv,
+ mlan_ds_hs_wakeup_reason wake_reason)
+{
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *skb = NULL;
+ int event_id = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || !priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "priv is null\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ wiphy = priv->wdev->wiphy;
+
+ event_id = woal_get_event_id(event_wake_reason_report);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+/**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
+ sizeof(wake_reason.hs_wakeup_reason),
+ event_id, GFP_ATOMIC);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy,
+ sizeof(wake_reason.hs_wakeup_reason),
+ event_id, GFP_ATOMIC);
+#endif
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ PRINTM(MINFO, "wake_reason.hs_wakeup_reason = %d\n",
+ wake_reason.hs_wakeup_reason);
+ nla_put_u16(skb, ATTR_WAKE_REASON_STAT, wake_reason.hs_wakeup_reason);
+ /**send event*/
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+done:
+ PRINTM(MINFO, "wake reason vendor event ret %d\n", ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief log wake reason
+ *
+ * @param priv A pointer to moal_private struct
+ * @param wake_reason wake_reason
+ *
+ * @return 0: success -1: fail
+ */
+int woal_wake_reason_logger(moal_private *priv,
+ mlan_ds_hs_wakeup_reason wake_reason)
+{
+ int ret = 0;
+
+ ENTER();
+
+ ret = woal_wake_reason_vendor_event(priv, wake_reason);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to start packet fate monitor
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int
+woal_cfg80211_subcmd_start_packet_fate_monitor(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ int ret = 0;
+
+ /* TODO: Tune pkt fate monitor for TP, Disabling it for now */
+ // struct net_device *dev = wdev->netdev;
+ // moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* TODO: Tune pkt fate monitor for TP, Disabling it for now */
+ // priv->pkt_fate_monitor_enable = MTRUE;
+
+ ret = cfg80211_vendor_cmd_reply(skb);
+
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send vendor event to kernel
+ *
+ * @param priv A pointer to moal_private struct
+ * @param pkt_type tx or rx
+ * @param fate packet fate
+ * @param payload_type type of payload
+ * @param drv_ts_usec driver time in usec
+ * @param fw_ts_usec firmware time in usec
+ * @param data frame data
+ * @param len frame data len
+ *
+ * @return 0: success 1: fail
+ */
+int woal_packet_fate_vendor_event(moal_private *priv,
+ packet_fate_packet_type pkt_type, t_u8 fate,
+ frame_type payload_type, t_u32 drv_ts_usec,
+ t_u32 fw_ts_usec, t_u8 *data, t_u32 len)
+{
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *skb = NULL;
+ int event_id = 0;
+ int ret = 0;
+ PACKET_FATE_REPORT fate_report;
+
+ ENTER();
+
+ if (!priv || !priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "priv is null\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ wiphy = priv->wdev->wiphy;
+
+ event_id = woal_get_event_id(event_packet_fate_monitor);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+/**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
+ len + sizeof(PACKET_FATE_REPORT),
+ event_id, GFP_ATOMIC);
+#else
+ skb = cfg80211_vendor_event_alloc(
+ wiphy, len + sizeof(PACKET_FATE_REPORT), event_id, GFP_ATOMIC);
+#endif
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(&fate_report, 0, sizeof(PACKET_FATE_REPORT));
+ if (pkt_type == PACKET_TYPE_TX) {
+ fate_report.u.tx_report_i.fate = fate;
+ fate_report.u.tx_report_i.frame_inf.payload_type = payload_type;
+ fate_report.u.tx_report_i.frame_inf.driver_timestamp_usec =
+ drv_ts_usec;
+ fate_report.u.tx_report_i.frame_inf.firmware_timestamp_usec =
+ fw_ts_usec;
+ fate_report.u.tx_report_i.frame_inf.frame_len = len;
+ nla_put(skb, ATTR_PACKET_FATE_TX, sizeof(PACKET_FATE_REPORT),
+ &fate_report);
+ } else {
+ fate_report.u.rx_report_i.fate = fate;
+ fate_report.u.rx_report_i.frame_inf.payload_type = payload_type;
+ fate_report.u.rx_report_i.frame_inf.driver_timestamp_usec =
+ drv_ts_usec;
+ fate_report.u.rx_report_i.frame_inf.firmware_timestamp_usec =
+ fw_ts_usec;
+ fate_report.u.rx_report_i.frame_inf.frame_len = len;
+ nla_put(skb, ATTR_PACKET_FATE_RX, sizeof(PACKET_FATE_REPORT),
+ &fate_report);
+ }
+ DBG_HEXDUMP(MCMD_D, "fate_report", (t_u8 *)&fate_report,
+ sizeof(PACKET_FATE_REPORT));
+
+ nla_put(skb, ATTR_PACKET_FATE_DATA, len, data);
+ DBG_HEXDUMP(MCMD_D, "packet_fate_data", data, len);
+
+ /**send event*/
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+done:
+ PRINTM(MINFO, "packet fate vendor event ret %d\n", ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief log packet fate
+ *
+ * @param priv A pointer to moal_private struct
+ * @param pkt_type tx or rx
+ * @param fate packet fate
+ * @param payload_type type of payload
+ * @param drv_ts_usec driver time in usec
+ * @param fw_ts_usec firmware time in usec
+ * @param data frame data
+ * @param len frame data len
+ *
+ * @return 0: success -1: fail
+ */
+int woal_packet_fate_monitor(moal_private *priv,
+ packet_fate_packet_type pkt_type, t_u8 fate,
+ frame_type payload_type, t_u32 drv_ts_usec,
+ t_u32 fw_ts_usec, t_u8 *data, t_u32 len)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->pkt_fate_monitor_enable)
+ ret = woal_packet_fate_vendor_event(priv, pkt_type, fate,
+ payload_type, drv_ts_usec,
+ fw_ts_usec, data, len);
+
+ PRINTM(MINFO, "packet fate monitor ret %d\n", ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief init packet_filter in moal_private
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_init_packet_filter(moal_private *priv)
+{
+ int ret = 0;
+ packet_filter *pkt_filter = NULL;
+
+ ENTER();
+
+ pkt_filter = vmalloc(sizeof(packet_filter));
+ if (!unlikely(pkt_filter)) {
+ PRINTM(MERROR, "WiFi Logger: packet_filter alloc failed\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(pkt_filter, 0, sizeof(packet_filter));
+
+ spin_lock_init(&pkt_filter->lock);
+ pkt_filter->packet_filter_max_len = PACKET_FILTER_MAX_LEN;
+ pkt_filter->packet_filter_len = 0;
+ pkt_filter->packet_filter_version = APF_VERSION;
+ pkt_filter->state = PACKET_FILTER_STATE_STOP;
+
+ priv->packet_filter = pkt_filter;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief deinit packet_filter in moal_private
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_deinit_packet_filter(moal_private *priv)
+{
+ int ret = 0;
+ packet_filter *pkt_filter = NULL;
+ unsigned long flags;
+
+ ENTER();
+
+ pkt_filter = priv->packet_filter;
+
+ if (!unlikely(pkt_filter))
+ goto done;
+
+ spin_lock_irqsave(&pkt_filter->lock, flags);
+ pkt_filter->state = PACKET_FILTER_STATE_INIT;
+ spin_unlock_irqrestore(&pkt_filter->lock, flags);
+
+ vfree(pkt_filter);
+ priv->packet_filter = NULL;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to set packet filter
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_set_packet_filter(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0, rem, type;
+ const struct nlattr *iter;
+ packet_filter *pkt_filter = NULL;
+ t_u32 packet_filter_len = 0;
+ unsigned long flags;
+
+ ENTER();
+ pkt_filter = priv->packet_filter;
+ if (!unlikely(pkt_filter) ||
+ pkt_filter->state == PACKET_FILTER_STATE_INIT) {
+ PRINTM(MERROR, "packet_filter not init\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case ATTR_PACKET_FILTER_TOTAL_LENGTH:
+ packet_filter_len = nla_get_u32(iter);
+ if (packet_filter_len >
+ pkt_filter->packet_filter_max_len) {
+ PRINTM(MERROR,
+ "packet_filter_len exceed max\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ case ATTR_PACKET_FILTER_PROGRAM:
+ spin_lock_irqsave(&pkt_filter->lock, flags);
+ strncpy(pkt_filter->packet_filter_program,
+ nla_data(iter),
+ MIN(packet_filter_len, nla_len(iter)));
+ pkt_filter->packet_filter_len =
+ MIN(packet_filter_len, nla_len(iter));
+ pkt_filter->state = PACKET_FILTER_STATE_START;
+ spin_unlock_irqrestore(&pkt_filter->lock, flags);
+ DBG_HEXDUMP(MCMD_D, "packet_filter_program",
+ pkt_filter->packet_filter_program,
+ pkt_filter->packet_filter_len);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to get packet filter capability
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_get_packet_filter_capability(
+ struct wiphy *wiphy, struct wireless_dev *wdev, const void *data,
+ int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ t_u32 reply_len = 0;
+ int ret = 0;
+ packet_filter *pkt_filter;
+
+ ENTER();
+ pkt_filter = priv->packet_filter;
+ if (!unlikely(pkt_filter)) {
+ PRINTM(MERROR, "packet_filter not init\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reply_len = sizeof(pkt_filter->packet_filter_version) +
+ sizeof(pkt_filter->packet_filter_max_len);
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (nla_put_u32(skb, ATTR_PACKET_FILTER_VERSION,
+ pkt_filter->packet_filter_version) ||
+ nla_put_u32(skb, ATTR_PACKET_FILTER_MAX_LEN,
+ pkt_filter->packet_filter_max_len)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(skb);
+
+ if (ret)
+ PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * Runs a packet filtering program over a packet.
+ *
+ * @param program the program bytecode.
+ * @param program_len the length of {@code apf_program} in bytes.
+ * @param packet the packet bytes, starting from the 802.3 header and not
+ * including any CRC bytes at the end.
+ * @param packet_len the length of {@code packet} in bytes.
+ * @param filter_age the number of seconds since the filter was programmed.
+ *
+ * @return non-zero if packet should be passed to AP, zero if
+ * packet should be dropped.
+ */
+int process_packet(const t_u8 *program, t_u32 program_len, const t_u8 *packet,
+ t_u32 packet_len, t_u32 filter_age)
+{
+ /* Program counter */
+ t_u32 pc = 0;
+ /* Memory slot values. */
+ t_u32 mem[MEM_ITEMS] = {};
+ /* Register values. */
+ t_u32 reg[2] = {};
+ /* Number of instructions remaining to execute. This is done to make
+ * sure there is upper bound on execution time. It should never be hit
+ * and is only for safety. Initialize to the number of bytes in the
+ * program which is an
+ * upper bound on the number of instructions in the program.
+ */
+ t_u32 instructions_left = program_len;
+
+ t_u8 bytecode;
+ t_u32 opcode;
+ t_u32 reg_num;
+ t_u32 len_field;
+ t_u32 imm_len;
+ t_u32 end_offs;
+ t_u32 val = 0;
+ t_u32 last_pkt_offs;
+ t_u32 imm = 0;
+ int32_t sign_imm = 0;
+ t_u32 offs = 0;
+ t_u32 i;
+ t_u32 load_size;
+
+/* Is offset within program bounds? */
+#define WITHIN_PROGRAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < program_len)
+/* Is offset within packet bounds? */
+#define WITHIN_PACKET_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < packet_len)
+/* Verify an internal condition and accept packet if it fails. */
+#define ASSERT_RETURN(c) \
+ do { \
+ if (!(c)) \
+ return PASS_PKT; \
+ } while (0)
+/* If not within program bounds, Accept the packet */
+#define ASSERT_WITHIN_PROGRAM_BOUNDS(p) ASSERT_RETURN(WITHIN_PROGRAM_BOUNDS(p))
+/* If not within packet bounds, Accept the packet */
+#define ASSERT_WITHIN_PKT_BOUNDS(p) ASSERT_RETURN(WITHIN_PACKET_BOUNDS(p))
+/* If not within program or not ahead of program counter, Accept the packet */
+#define ASSERT_FORWARD_WITHIN_PROGRAM(p) \
+ ASSERT_RETURN(WITHIN_PROGRAM_BOUNDS(p) && (p) >= pc)
+
+ /* Fill in pre-filled memory slot values. */
+ mem[MEM_OFFSET_PKT_SIZE] = packet_len;
+ mem[MEM_OFFSET_FILTER_AGE] = filter_age;
+ ASSERT_WITHIN_PKT_BOUNDS(APF_FRAME_HEADER_SIZE);
+
+ /* Only populate if IP version is IPv4. */
+ if ((packet[APF_FRAME_HEADER_SIZE] & 0xf0) == 0x40) {
+ mem[MEM_OFFSET_IPV4_HEADER_SIZE] =
+ (packet[APF_FRAME_HEADER_SIZE] & 15) * 4;
+ }
+
+ do {
+ if (pc == program_len)
+ return PASS_PKT;
+ else if (pc == (program_len + 1))
+ return DROP_PKT;
+ ASSERT_WITHIN_PROGRAM_BOUNDS(pc);
+ bytecode = program[pc++];
+ opcode = GET_OPCODE(bytecode);
+ reg_num = GET_REGISTER(bytecode);
+
+ /* All instructions have immediate fields, so load them now. */
+ len_field = GET_IMM_LENGTH(bytecode);
+ imm = 0;
+ sign_imm = 0;
+
+#define REG (reg[reg_num])
+#define OTHER_REG (reg[reg_num ^ 1])
+
+ if (len_field) {
+ imm_len = 1 << (len_field - 1);
+ ASSERT_FORWARD_WITHIN_PROGRAM(pc + imm_len - 1);
+ for (i = 0; i < imm_len; i++)
+ imm = (imm << 8) | program[pc++];
+ /* Sign extend imm into signed_imm. */
+ sign_imm = imm << ((4 - imm_len) * 8);
+ sign_imm >>= (4 - imm_len) * 8;
+ }
+ switch (opcode) {
+ case NXP_LDB_OPCODE:
+ case NXP_LDH_OPCODE:
+ case NXP_LDW_OPCODE:
+ case NXP_LDBX_OPCODE:
+ case NXP_LDHX_OPCODE:
+ case NXP_LDWX_OPCODE: {
+ offs = imm;
+ if (opcode >= NXP_LDBX_OPCODE) {
+ /* Note: this can overflow and actually decrease
+ * offs.
+ */
+ offs += reg[1];
+ }
+ ASSERT_WITHIN_PKT_BOUNDS(offs);
+ switch (opcode) {
+ case NXP_LDB_OPCODE:
+ case NXP_LDBX_OPCODE:
+ load_size = 1;
+ break;
+ case NXP_LDH_OPCODE:
+ case NXP_LDHX_OPCODE:
+ load_size = 2;
+ break;
+ case NXP_LDW_OPCODE:
+ case NXP_LDWX_OPCODE:
+ load_size = 4;
+ break;
+ /* Immediately enclosing switch statement
+ * guarantees
+ * opcode cannot be any other value.
+ */
+ }
+ end_offs = offs + (load_size - 1);
+ /* Catch overflow/wrap-around. */
+ ASSERT_RETURN(end_offs >= offs);
+ ASSERT_WITHIN_PKT_BOUNDS(end_offs);
+ val = 0;
+ while (load_size--)
+ val = (val << 8) | packet[offs++];
+ REG = val;
+ break;
+ }
+ case NXP_JMP_OPCODE:
+ /* This can jump backwards. Infinite looping prevented
+ * by instructions_remaining.
+ */
+ pc += imm;
+ break;
+ case NXP_JEQ_OPCODE:
+ case NXP_JNE_OPCODE:
+ case NXP_JGT_OPCODE:
+ case NXP_JLT_OPCODE:
+ case NXP_JSET_OPCODE:
+ case NXP_JNEBS_OPCODE: {
+ /* Load second immediate field. */
+ t_u32 cmp_imm = 0;
+
+ if (reg_num == 1) {
+ cmp_imm = reg[1];
+ } else if (len_field != 0) {
+ t_u32 cmp_imm_len = 1 << (len_field - 1);
+
+ ASSERT_FORWARD_WITHIN_PROGRAM(pc + cmp_imm_len -
+ 1);
+ for (i = 0; i < cmp_imm_len; i++)
+ cmp_imm =
+ (cmp_imm << 8) | program[pc++];
+ }
+ switch (opcode) {
+ case NXP_JEQ_OPCODE:
+ if (reg[0] == cmp_imm)
+ pc += imm;
+ break;
+ case NXP_JNE_OPCODE:
+ if (reg[0] != cmp_imm)
+ pc += imm;
+ break;
+ case NXP_JGT_OPCODE:
+ if (reg[0] > cmp_imm)
+ pc += imm;
+ break;
+ case NXP_JLT_OPCODE:
+ if (reg[0] < cmp_imm)
+ pc += imm;
+ break;
+ case NXP_JSET_OPCODE:
+ if (reg[0] & cmp_imm)
+ pc += imm;
+ break;
+ case NXP_JNEBS_OPCODE: {
+ /* cmp_imm is size in bytes of data to compare.
+ * pc is offset of program bytes to compare.
+ * imm is jump target offset.
+ * REG is offset of packet bytes to compare.
+ */
+ ASSERT_FORWARD_WITHIN_PROGRAM(pc + cmp_imm - 1);
+ ASSERT_WITHIN_PKT_BOUNDS(REG);
+ last_pkt_offs = REG + cmp_imm - 1;
+ ASSERT_RETURN(last_pkt_offs >= REG);
+ ASSERT_WITHIN_PKT_BOUNDS(last_pkt_offs);
+ if (memcmp(program + pc, packet + REG, cmp_imm))
+ pc += imm;
+ /* skip past comparison bytes */
+ pc += cmp_imm;
+ break;
+ }
+ }
+ break;
+ }
+ case NXP_ADD_OPCODE:
+ reg[0] += reg_num ? reg[1] : imm;
+ break;
+ case NXP_MUL_OPCODE:
+ reg[0] *= reg_num ? reg[1] : imm;
+ break;
+ case NXP_DIV_OPCODE: {
+ const t_u32 div_operand = reg_num ? reg[1] : imm;
+
+ ASSERT_RETURN(div_operand);
+ reg[0] /= div_operand;
+ break;
+ }
+ case NXP_AND_OPCODE:
+ reg[0] &= reg_num ? reg[1] : imm;
+ break;
+ case NXP_OR_OPCODE:
+ reg[0] |= reg_num ? reg[1] : imm;
+ break;
+ case NXP_SH_OPCODE: {
+ const int32_t shift_val =
+ reg_num ? (int32_t)reg[1] : sign_imm;
+ if (shift_val > 0)
+ reg[0] <<= shift_val;
+ else
+ reg[0] >>= -shift_val;
+ break;
+ }
+ case NXP_LI_OPCODE:
+ REG = sign_imm;
+ break;
+ case NXP_EXT_OPCODE:
+ if (
+/* If LDM_EXT_OPCODE is 0 and imm is compared with it, a compiler error will
+ * result,
+ * instead just enforce that imm is unsigned (so it's always greater or equal to
+ * 0).
+ */
+#if NXP_LDM_EXT_OPCODE == 0
+ ENFORCE_UNSIGNED(imm) &&
+#else
+ imm >= NXP_LDM_EXT_OPCODE &&
+#endif
+ imm < (NXP_LDM_EXT_OPCODE + MEM_ITEMS)) {
+ REG = mem[imm - NXP_LDM_EXT_OPCODE];
+ } else if (imm >= NXP_STM_EXT_OPCODE &&
+ imm < (NXP_STM_EXT_OPCODE + MEM_ITEMS)) {
+ mem[imm - NXP_STM_EXT_OPCODE] = REG;
+ } else
+ switch (imm) {
+ case NXP_NOT_EXT_OPCODE:
+ REG = ~REG;
+ break;
+ case NXP_NEG_EXT_OPCODE:
+ REG = -REG;
+ break;
+ case NXP_SWAP_EXT_OPCODE: {
+ t_u32 tmp = REG;
+
+ REG = OTHER_REG;
+ OTHER_REG = tmp;
+ break;
+ }
+ case NXP_MOV_EXT_OPCODE:
+ REG = OTHER_REG;
+ break;
+ /* Unknown extended opcode */
+ default:
+ /* Bail out */
+ return PASS_PKT;
+ }
+ break;
+ /* Unknown opcode */
+ default:
+ /* Bail out */
+ return PASS_PKT;
+ }
+ } while (instructions_left--);
+ return PASS_PKT;
+}
+
+/**
+ * @brief filter packet
+ *
+ * @param priv A pointer to moal_private struct
+ * @param data packet data
+ * @param len packet len
+ * @param filter_age filter age
+ * @return non-zero if packet should be passed to AP, zero if
+ * packet should be dropped.
+ */
+int woal_filter_packet(moal_private *priv, t_u8 *data, t_u32 len,
+ t_u32 filter_age)
+{
+ packet_filter *pkt_filter = NULL;
+ int ret = PASS_PKT;
+ unsigned long flags;
+
+ ENTER();
+ pkt_filter = priv->packet_filter;
+ if (!unlikely(pkt_filter)) {
+ PRINTM(MINFO, "packet_filter not init\n");
+ goto done;
+ }
+
+ if (pkt_filter->state != PACKET_FILTER_STATE_START)
+ goto done;
+
+ DBG_HEXDUMP(MCMD_D, "packet_filter_program",
+ pkt_filter->packet_filter_program,
+ pkt_filter->packet_filter_len);
+ DBG_HEXDUMP(MCMD_D, "packet_filter_data", data, len);
+ spin_lock_irqsave(&pkt_filter->lock, flags);
+ ret = process_packet(pkt_filter->packet_filter_program,
+ pkt_filter->packet_filter_len, data, len,
+ filter_age);
+ spin_unlock_irqrestore(&pkt_filter->lock, flags);
+
+done:
+ PRINTM(MINFO, "packet filter ret %d\n", ret);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief init wifi hal
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return 0: success 1: fail
+ */
+int woal_init_wifi_hal(moal_private *priv)
+{
+ ENTER();
+ woal_init_ring_buffer(priv);
+ priv->pkt_fate_monitor_enable = MFALSE;
+ woal_init_packet_filter(priv);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief deinit wifi hal
+ *
+ * @param priv A pointer to moal_private struct
+ *
+ * @return 0: success 1: fail
+ */
+int woal_deinit_wifi_hal(moal_private *priv)
+{
+ ENTER();
+ woal_deinit_ring_buffer(priv);
+ priv->pkt_fate_monitor_enable = MFALSE;
+ woal_deinit_packet_filter(priv);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief vendor command to get link layer statistic
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_cfg80211_subcmd_link_statistic_get(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ struct net_device *dev = wdev->netdev;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ wifi_radio_stat *radio_stat = NULL;
+ wifi_radio_stat *radio_stat_tmp = NULL;
+ wifi_iface_stat *iface_stat = NULL;
+ t_u32 num_radio = 0, iface_stat_len = 0, radio_stat_len = 0;
+ int err = -1, length = 0, i;
+ char *ioctl_link_stats_buf = NULL;
+ mlan_ds_get_stats stats;
+ t_u64 cur_time = 0;
+ t_u64 inter_msec = 0;
+ t_u64 max_msec = (t_u64)24 * (t_u64)24 * (t_u64)3600 * (t_u64)1000;
+ moal_handle *handle = priv->phandle;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) + BUF_MAXLEN);
+ if (req == NULL) {
+ PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
+ return -ENOMEM;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_LINK_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "get link layer statistic fail\n");
+ goto done;
+ }
+
+ /* Get Log from the firmware */
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ PRINTM(MERROR, "Error getting stats information\n");
+ goto done;
+ }
+
+ ioctl_link_stats_buf = info->param.link_statistic;
+ num_radio = *((t_u32 *)info->param.link_statistic);
+
+ radio_stat = (wifi_radio_stat *)(info->param.link_statistic +
+ sizeof(num_radio));
+ radio_stat_len = num_radio * sizeof(wifi_radio_stat);
+
+ /* Re-write on_time/tx_time/rx_time/on_time_scan from moal handle */
+ PRINTM(MINFO, "handle->on_time=%llu\n", handle->on_time);
+ if (handle->on_time) {
+ moal_get_boot_ktime(handle, &cur_time);
+ inter_msec = moal_do_div(cur_time - handle->on_time, 1000000);
+ PRINTM(MINFO, "cur_time=%llu inter_msec=%llu max_msec=%llu\n",
+ cur_time, inter_msec, max_msec);
+ /* When we report the time up, u32 is not big enough(represent
+ * max 49days) and might out of range, make the max value to
+ * 24days.
+ */
+ if (inter_msec > max_msec) {
+ PRINTM(MMSG,
+ "Out of range, set inter_msec=%llu to max_msec=%llu\n",
+ inter_msec, max_msec);
+ inter_msec = max_msec;
+ }
+ }
+ PRINTM(MINFO, "handle->tx_time=%llu\n", handle->tx_time);
+ PRINTM(MINFO, "handle->rx_time=%llu\n", handle->rx_time);
+ PRINTM(MINFO, "handle->scan_time=%llu\n", handle->scan_time);
+ radio_stat_tmp = radio_stat;
+ for (i = 0; i < num_radio; i++) {
+ radio_stat_tmp->on_time = (t_u32)inter_msec;
+ radio_stat_tmp->tx_time =
+ (t_u32)moal_do_div(handle->tx_time, 1000);
+ radio_stat_tmp->rx_time =
+ (t_u32)moal_do_div(handle->rx_time, 1000);
+ radio_stat_tmp->on_time_scan =
+ (t_u32)moal_do_div(handle->scan_time, 1000);
+ radio_stat_tmp++;
+ }
+
+ iface_stat = (wifi_iface_stat *)(info->param.link_statistic +
+ sizeof(num_radio) + radio_stat_len);
+ iface_stat_len = sizeof(wifi_iface_stat);
+ /* Fill some fileds */
+ iface_stat->beacon_rx = stats.bcn_rcv_cnt;
+
+ /* could get peer info with separate cmd */
+ for (i = 0; i < iface_stat->num_peers; i++) {
+ /* no need copy, just increase iface_stat length*/
+ iface_stat_len += sizeof(wifi_peer_info) +
+ sizeof(wifi_rate_stat) *
+ iface_stat->peer_info[i].num_rate;
+ }
+
+ /* Here the length doesn't contain addition 2 attribute header length */
+ length = NLA_HDRLEN * 2 + sizeof(num_radio) + radio_stat_len +
+ iface_stat_len;
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed\n");
+ goto done;
+ }
+
+ if (nla_put_u32(skb, ATTR_LL_STATS_NUM_RADIO, num_radio) ||
+ nla_put(skb, ATTR_LL_STATS_RADIO, radio_stat_len, radio_stat) ||
+ nla_put(skb, ATTR_LL_STATS_IFACE, iface_stat_len, iface_stat)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ goto done;
+ }
+
+ PRINTM(MCMD_D, "%s: <<< Start DUMP\n", __func__);
+ PRINTM(MCMD_D, "sizeof(wifi_radio_stat)=%zu\n",
+ sizeof(wifi_radio_stat));
+ DBG_HEXDUMP(MCMD_D, "radio_stat", (t_u8 *)radio_stat, radio_stat_len);
+ PRINTM(MCMD_D, "sizeof(wifi_channel_stat)=%zu\n",
+ sizeof(wifi_channel_stat));
+ DBG_HEXDUMP(MCMD_D, "iface_stat", (t_u8 *)iface_stat, iface_stat_len);
+ PRINTM(MCMD_D, "num_radio=%d\n", num_radio);
+ radio_stat_tmp = radio_stat;
+ for (i = 0; i < num_radio; i++) {
+ PRINTM(MCMD_D, "--radio_stat[%d]--\n", i);
+ PRINTM(MCMD_D, "radio=%d\n", radio_stat_tmp->radio);
+ PRINTM(MCMD_D, "on_time=%d\n", radio_stat_tmp->on_time);
+ PRINTM(MCMD_D, "tx_time=%d\n", radio_stat_tmp->tx_time);
+ PRINTM(MCMD_D, "reserved0=%d\n", radio_stat_tmp->reserved0);
+ PRINTM(MCMD_D, "rx_time=%d\n", radio_stat_tmp->rx_time);
+ PRINTM(MCMD_D, "on_time_scan=%d\n",
+ radio_stat_tmp->on_time_scan);
+ PRINTM(MCMD_D, "on_time_nbd=%d\n", radio_stat_tmp->on_time_nbd);
+ PRINTM(MCMD_D, "on_time_gscan=%d\n",
+ radio_stat_tmp->on_time_gscan);
+ PRINTM(MCMD_D, "on_time_roam_scan=%d\n",
+ radio_stat_tmp->on_time_roam_scan);
+ PRINTM(MCMD_D, "on_time_pno_scan=%d\n",
+ radio_stat_tmp->on_time_pno_scan);
+ PRINTM(MCMD_D, "on_time_hs20=%d\n",
+ radio_stat_tmp->on_time_hs20);
+ PRINTM(MCMD_D, "num_channels=%d\n",
+ radio_stat_tmp->num_channels);
+ radio_stat_tmp++;
+ }
+ PRINTM(MCMD_D, "%s: >>> End DUMP\n", __func__);
+
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (unlikely(err))
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ return err;
+}
+
+/**
+ * @brief API to trigger the link layer statistics collection.
+ * Unless his API is invoked - link layer statistics will not be collected.
+ * Radio statistics (once started) do not stop or get reset unless
+ * wifi_clear_link_stats is invoked, Interface statistics (once started)
+ * reset and start afresh after each connection.
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_cfg80211_subcmd_link_statistic_set(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
+ struct nlattr *tb[ATTR_LL_STATS_MAX + 1];
+ wifi_link_layer_params ll_params;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int err = 0;
+
+ err = nla_parse(tb, ATTR_LL_STATS_MAX, data, len, NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (err)
+ return err;
+
+ if (!tb[ATTR_LL_STATS_MPDU_SIZE_THRESHOLD] ||
+ !tb[ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING])
+ return -EINVAL;
+
+ ll_params.mpdu_size_threshold =
+ nla_get_u32(tb[ATTR_LL_STATS_MPDU_SIZE_THRESHOLD]);
+ ll_params.aggressive_statistics_gathering =
+ nla_get_u32(tb[ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING]);
+
+ PRINTM(MEVENT,
+ "link layer params mpdu_size_threshold = 0x%x, aggressive_statistics_gathering = 0x%x\n",
+ ll_params.mpdu_size_threshold,
+ ll_params.aggressive_statistics_gathering);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) +
+ sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
+ return -ENOMEM;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_LINK_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_SET;
+
+ /* Configure parameter to firmware */
+ moal_memcpy_ext(priv->phandle, info->param.link_statistic, &ll_params,
+ sizeof(ll_params),
+ sizeof(mlan_ds_get_info) - sizeof(t_u32));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS)
+ PRINTM(MMSG, "enable link layer statistic successfully\n");
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ return 0;
+}
+
+/**
+ * @brief clear function should download command to fimrware,
+ * so that firmware could cleanup per peer statistic number
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_cfg80211_subcmd_link_statistic_clr(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
+ struct nlattr *tb[ATTR_LL_STATS_MAX + 1];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ u32 stats_clear_req_mask = 0x0, stats_clear_rsp_mask = 0x0;
+ u8 stop_req = 0x0, stop_rsp = 0x0;
+ struct sk_buff *skb = NULL;
+ int err = 0, length = 0;
+
+ err = nla_parse(tb, ATTR_LL_STATS_MAX, data, len, NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (err)
+ return err;
+
+ if (!tb[ATTR_LL_STATS_CLEAR_REQ_MASK])
+ return -EINVAL;
+ else
+ stats_clear_req_mask =
+ nla_get_u32(tb[ATTR_LL_STATS_CLEAR_REQ_MASK]);
+
+ if (!tb[ATTR_LL_STATS_STOP_REQ])
+ return -EINVAL;
+ else
+ stop_req = nla_get_u8(tb[ATTR_LL_STATS_STOP_REQ]);
+
+ PRINTM(MEVENT,
+ "link layer clear stats_clear_req_mask = 0x%x, stop_req = 0x%x\n",
+ stats_clear_req_mask, stop_req);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) +
+ sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
+ return -ENOMEM;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_LINK_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_CLEAR;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS)
+ PRINTM(MMSG, "enable link layer statistic successfully\n");
+
+ length = NLA_HDRLEN + sizeof(stats_clear_rsp_mask) + sizeof(stop_rsp);
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed\n");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* clear api to reset statistics, stats_clear_rsp_mask identifies what
+ * stats have been cleared stop_req = 1 will imply whether to stop the
+ * statistics collection. stop_rsp = 1 will imply that stop_req was
+ * honored and statistics collection was stopped.
+ */
+ stats_clear_rsp_mask = WIFI_STATS_RADIO | WIFI_STATS_IFACE;
+ stop_rsp = 1;
+ if (nla_put_u32(skb, ATTR_LL_STATS_CLEAR_RSP_MASK,
+ stats_clear_rsp_mask) ||
+ nla_put_u8(skb, ATTR_LL_STATS_STOP_RSP, stop_rsp)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree_skb(skb);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (unlikely(err)) {
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+ goto exit;
+ ;
+ }
+
+exit:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ return err;
+}
+
+#ifdef STA_CFG80211
+#define RSSI_MONOTOR_START 1
+#define RSSI_MONOTOR_STOP 0
+
+/**
+ * @brief vendor command to control rssi monitor
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success -1: fail
+ */
+static int woal_cfg80211_subcmd_rssi_monitor(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ struct nlattr *tb[ATTR_RSSI_MONITOR_MAX + 1];
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
+ u32 rssi_monitor_control = 0x0;
+ s8 rssi_min = 0, rssi_max = 0;
+ int err = 0;
+ t_u8 *pos = NULL;
+ struct sk_buff *skb = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv->media_connected) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = nla_parse(tb, ATTR_RSSI_MONITOR_MAX, data, len, NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (ret)
+ goto done;
+
+ if (!tb[ATTR_RSSI_MONITOR_CONTROL]) {
+ ret = -EINVAL;
+ goto done;
+ }
+ rssi_monitor_control = nla_get_u32(tb[ATTR_RSSI_MONITOR_CONTROL]);
+
+ if (rssi_monitor_control == RSSI_MONOTOR_START) {
+ if ((!tb[ATTR_RSSI_MONITOR_MIN_RSSI]) ||
+ (!tb[ATTR_RSSI_MONITOR_MAX_RSSI])) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ rssi_min = nla_get_s8(tb[ATTR_RSSI_MONITOR_MIN_RSSI]);
+ rssi_max = nla_get_s8(tb[ATTR_RSSI_MONITOR_MAX_RSSI]);
+
+ PRINTM(MEVENT,
+ "start rssi monitor rssi_min = %d, rssi_max= %d\n",
+ rssi_min, rssi_max);
+
+ /* set rssi low/high threshold */
+ priv->cqm_rssi_high_thold = rssi_max;
+ priv->cqm_rssi_thold = rssi_min;
+ priv->cqm_rssi_hyst = 4;
+ woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT);
+ } else if (rssi_monitor_control == RSSI_MONOTOR_STOP) {
+ /* stop rssi monitor */
+ PRINTM(MEVENT, "stop rssi monitor\n");
+ /* set both rssi_thold/hyst to 0, will trigger subscribe event
+ * clear
+ */
+ priv->cqm_rssi_high_thold = 0;
+ priv->cqm_rssi_thold = 0;
+ priv->cqm_rssi_hyst = 0;
+ woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT);
+ } else {
+ PRINTM(MERROR, "invalid rssi_monitor control request\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Alloc the SKB for cmd reply */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ pos = skb_put(skb, len);
+ moal_memcpy_ext(priv->phandle, pos, data, len, len);
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (unlikely(err)) {
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+ ret = err;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send rssi event to kernel
+ *
+ * @param priv A pointer to moal_private
+ * @param rssi current rssi value
+ *
+ * @return N/A
+ */
+void woal_cfg80211_rssi_monitor_event(moal_private *priv, t_s16 rssi)
+{
+ struct sk_buff *skb = NULL;
+ t_s8 rssi_value = 0;
+
+ ENTER();
+
+ skb = dev_alloc_skb(NLA_HDRLEN * 2 + ETH_ALEN + sizeof(t_s8));
+ if (!skb)
+ goto done;
+ /* convert t_s16 to t_s8*/
+ rssi_value = -abs(rssi);
+ if (nla_put(skb, ATTR_RSSI_MONITOR_CUR_BSSID, ETH_ALEN,
+ priv->conn_bssid) ||
+ nla_put_s8(skb, ATTR_RSSI_MONITOR_CUR_RSSI, rssi_value)) {
+ PRINTM(MERROR, "nla_put failed!\n");
+ kfree(skb);
+ goto done;
+ }
+ woal_cfg80211_vendor_event(priv, event_rssi_monitor, (t_u8 *)skb->data,
+ skb->len);
+ kfree(skb);
+done:
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief vendor command to get fw roaming capability
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success fail otherwise
+ */
+static int
+woal_cfg80211_subcmd_get_roaming_capability(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ wifi_roaming_capabilities capa;
+ struct sk_buff *skb = NULL;
+ int err = 0;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ capa.max_blacklist_size = MAX_AP_LIST;
+ capa.max_whitelist_size = MAX_SSID_NUM;
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(
+ wiphy, sizeof(wifi_roaming_capabilities) + 50);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed\n");
+ goto done;
+ }
+
+ /* Push the data to the skb */
+ nla_put(skb, MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CAPA,
+ sizeof(wifi_roaming_capabilities), (t_u8 *)&capa);
+
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (unlikely(err))
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to enable/disable fw roaming
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success fail otherwise
+ */
+static int woal_cfg80211_subcmd_fw_roaming_enable(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv;
+ struct net_device *dev;
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sk_buff *skb = NULL;
+ const struct nlattr *iter;
+ int type, rem, err;
+ t_u32 fw_roaming_enable = 0;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (!priv || !priv->phandle) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL:
+ fw_roaming_enable = nla_get_u32(iter);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ PRINTM(MMSG, "FW roaming set enable=%d from wifi hal.\n",
+ fw_roaming_enable);
+#if defined(STA_CFG80211)
+ if (fw_roaming_enable)
+ priv->roaming_enabled = MTRUE;
+ else
+ priv->roaming_enabled = MFALSE;
+#endif
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(t_u32) + 50);
+ if (unlikely(!skb)) {
+ PRINTM(MERROR, "skb alloc failed\n");
+ goto done;
+ }
+
+ nla_put(skb, MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL, sizeof(t_u32),
+ &fw_roaming_enable);
+ err = cfg80211_vendor_cmd_reply(skb);
+ if (unlikely(err))
+ PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to config blacklist and whitelist for fw roaming
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success fail otherwise
+ */
+static int woal_cfg80211_subcmd_fw_roaming_config(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv;
+ struct net_device *dev;
+ int ret = MLAN_STATUS_SUCCESS;
+ const struct nlattr *iter;
+ int type, rem;
+ wifi_bssid_params blacklist;
+ wifi_ssid_params whitelist;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (!priv || !priv->phandle) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ memset((char *)&blacklist, 0, sizeof(wifi_bssid_params));
+ memset((char *)&whitelist, 0, sizeof(wifi_ssid_params));
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_BSSID:
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&blacklist,
+ nla_data(iter), nla_len(iter),
+ sizeof(wifi_bssid_params));
+ break;
+ case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_SSID:
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&whitelist,
+ nla_data(iter), nla_len(iter),
+ sizeof(wifi_ssid_params));
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to enable/disable 11k
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param data_len data length
+ *
+ * @return 0: success <0: fail
+ */
+static int woal_cfg80211_subcmd_11k_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ struct nlattr *tb_vendor[ATTR_ND_OFFLOAD_MAX + 1];
+ int ret = 0;
+ int status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ nla_parse(tb_vendor, ATTR_ND_OFFLOAD_MAX, (struct nlattr *)data,
+ data_len, NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (!tb_vendor[ATTR_ND_OFFLOAD_CONTROL]) {
+ PRINTM(MINFO, "%s: ATTR_ND_OFFLOAD not found\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to set scan mac oui
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param data_len data length
+ *
+ * @return 0: success <0: fail
+ */
+static int woal_cfg80211_subcmd_set_scan_mac_oui(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ struct nlattr *tb_vendor[ATTR_WIFI_MAX + 1];
+ t_u8 mac_oui[3];
+ int ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ nla_parse(tb_vendor, ATTR_WIFI_MAX, (struct nlattr *)data, data_len,
+ NULL
+#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
+ ,
+ NULL
+#endif
+ );
+ if (!tb_vendor[ATTR_SCAN_MAC_OUI_SET]) {
+ PRINTM(MINFO, "%s: ATTR_SCAN_MAC_OUI_SET not found\n",
+ __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, mac_oui,
+ nla_data(tb_vendor[ATTR_SCAN_MAC_OUI_SET]), 3, 3);
+ moal_memcpy_ext(priv->phandle, priv->random_mac, priv->current_addr,
+ ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
+ moal_memcpy_ext(priv->phandle, priv->random_mac, mac_oui, 3,
+ MLAN_MAC_ADDR_LENGTH);
+ PRINTM(MCMND, "random_mac is " FULL_MACSTR "\n",
+ FULL_MAC2STR(priv->random_mac));
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to start keep alive
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success fail otherwise
+ */
+static int woal_cfg80211_subcmd_start_keep_alive(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv;
+ struct net_device *dev;
+ int ret = MLAN_STATUS_SUCCESS;
+ int type, rem;
+ t_u8 mkeep_alive_id = 0;
+ t_u16 ether_type = 0;
+ t_u8 *ip_pkt = NULL;
+ t_u16 ip_pkt_len = 0;
+ t_u8 src_mac[ETH_ALEN];
+ t_u8 dst_mac[ETH_ALEN];
+ t_u32 period_msec = 0;
+ t_u32 retry_interval = 0;
+ t_u8 retry_cnt = 0;
+ const struct nlattr *iter;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (!priv) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MKEEP_ALIVE_ATTRIBUTE_ID:
+ mkeep_alive_id = nla_get_u8(iter);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE:
+ ether_type = nla_get_u16(iter);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
+ ip_pkt_len = nla_get_u16(iter);
+ if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
+ if (ip_pkt_len) {
+ ip_pkt = (u8 *)kzalloc(ip_pkt_len, GFP_ATOMIC);
+ if (ip_pkt == NULL) {
+ ret = -ENOMEM;
+ PRINTM(MERROR,
+ "Failed to allocate mem for ip packet\n");
+ goto exit;
+ }
+ moal_memcpy_ext(priv->phandle, ip_pkt,
+ (u8 *)nla_data(iter),
+ nla_len(iter), ip_pkt_len);
+ }
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
+ moal_memcpy_ext(priv->phandle, src_mac, nla_data(iter),
+ nla_len(iter), ETH_ALEN);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
+ moal_memcpy_ext(priv->phandle, dst_mac, nla_data(iter),
+ nla_len(iter), ETH_ALEN);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
+ period_msec = nla_get_u32(iter);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_RETRY_INTERVAL:
+ retry_interval = nla_get_u32(iter);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_RETRY_CNT:
+ retry_cnt = nla_get_u8(iter);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ ret = woal_priv_save_cloud_keep_alive_params(
+ priv, mkeep_alive_id, true, ether_type, ip_pkt, ip_pkt_len,
+ src_mac, dst_mac, period_msec, retry_interval, retry_cnt);
+ if (ret < 0)
+ PRINTM(MERROR, "start_mkeep_alive is failed ret: %d\n", ret);
+
+exit:
+ if (ip_pkt)
+ kfree(ip_pkt);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to stop keep alive
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success fail otherwise
+ */
+static int woal_cfg80211_subcmd_stop_keep_alive(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ moal_private *priv;
+ struct net_device *dev;
+ int ret = MLAN_STATUS_SUCCESS;
+ int type, rem;
+ t_u8 mkeep_alive_id = 0;
+ const struct nlattr *iter;
+
+ ENTER();
+
+ if (!wdev || !wdev->netdev) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ dev = wdev->netdev;
+ priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (!priv) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ nla_for_each_attr (iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MKEEP_ALIVE_ATTRIBUTE_ID:
+ mkeep_alive_id = nla_get_u8(iter);
+ break;
+ default:
+ PRINTM(MERROR, "Unknown type: %d\n", type);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ ret = woal_stop_mkeep_alive(priv, mkeep_alive_id, 0, NULL, NULL);
+ if (ret < 0)
+ PRINTM(MERROR, "stop_mkeep_alive is failed ret: %d\n", ret);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Upload last keep alive packet to Host through vendor
+ event
+ *
+ * @param priv Pointer to moal_private structure
+ * @param mkeep_alive Pointer to mlan_ds_misc_keep_alive structure
+
+ * @return 0: success fail otherwise
+ */
+int woal_mkeep_alive_vendor_event(moal_private *priv,
+ mlan_ds_misc_keep_alive *mkeep_alive)
+{
+ struct wiphy *wiphy = priv->wdev->wiphy;
+ struct sk_buff *skb = NULL;
+ int ret = MLAN_STATUS_SUCCESS;
+ int event_id = 0;
+ t_u16 len = 0;
+
+ ENTER();
+
+ event_id = woal_get_event_id(event_cloud_keep_alive);
+ if (event_max == event_id) {
+ PRINTM(MERROR, "Not find this event %d\n", event_id);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (!mkeep_alive) {
+ PRINTM(MERROR, "Parameter is NULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ len = mkeep_alive->pkt_len;
+
+ /**allocate skb*/
+#if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
+ skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len + 50,
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, len + 50,
+#endif
+ event_id, GFP_ATOMIC);
+
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor event\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ nla_put(skb, MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, sizeof(t_u16), &len);
+ nla_put(skb, MKEEP_ALIVE_ATTRIBUTE_IP_PKT, len, mkeep_alive->packet);
+
+ /**send event*/
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief vendor command to set enable/disable dfs offload
+ *
+ * @param wiphy A pointer to wiphy struct
+ * @param wdev A pointer to wireless_dev struct
+ * @param data a pointer to data
+ * @param len data length
+ *
+ * @return 0: success 1: fail
+ */
+static int woal_cfg80211_subcmd_set_dfs_offload(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct sk_buff *skb = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ int dfs_offload;
+ int ret = 1;
+
+ ENTER();
+ dfs_offload = moal_extflg_isset(handle, EXT_DFS_OFFLOAD);
+
+ /** Allocate skb for cmd reply*/
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(dfs_offload));
+ if (!skb) {
+ PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
+ ret = 1;
+ LEAVE();
+ return ret;
+ }
+ nla_put(skb, MRVL_WLAN_VENDOR_ATTR_DFS, sizeof(t_u32), &dfs_offload);
+ ret = cfg80211_vendor_cmd_reply(skb);
+
+ LEAVE();
+ return ret;
+}
+
+// clang-format off
+const struct wiphy_vendor_command vendor_commands[] = {
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_set_drvdbg,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_set_drvdbg,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_valid_channels,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_valid_channels,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_attr_policy,
+ .maxattr = ATTR_WIFI_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_set_scan_mac_oui,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_set_scan_mac_oui,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_attr_policy,
+ .maxattr = ATTR_WIFI_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_link_statistic_set,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_link_statistic_set,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_ll_stat_policy,
+ .maxattr = ATTR_LL_STATS_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_link_statistic_get,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_link_statistic_get,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_link_statistic_clr,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_link_statistic_clr,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_ll_stat_policy,
+ .maxattr = ATTR_LL_STATS_MAX,
+#endif
+ },
+#ifdef STA_CFG80211
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_rssi_monitor,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_rssi_monitor,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_rssi_monitor_policy,
+ .maxattr = ATTR_RSSI_MONITOR_MAX,
+#endif
+ },
+#endif
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_roaming_capability,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_roaming_capability,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_fw_roaming_enable,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_fw_roaming_enable,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_fw_roaming_policy,
+ .maxattr = MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_fw_roaming_config,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_fw_roaming_config,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_fw_roaming_policy,
+ .maxattr = MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_start_keep_alive,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_start_keep_alive,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_keep_alive_policy,
+ .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_stop_keep_alive,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_stop_keep_alive,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_dfs_capability,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_set_dfs_offload,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+
+
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_nd_offload
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_11k_cfg,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_nd_offload_policy,
+ .maxattr = ATTR_ND_OFFLOAD_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_drv_version,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_drv_version,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_fw_version,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_fw_version,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_wifi_supp_feature_set,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_supp_feature_set,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_set_country_code,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_set_country_code,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd =
+ sub_cmd_get_wifi_logger_supp_feature_set,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = woal_cfg80211_subcmd_get_wifi_logger_supp_feature_set,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_logger_policy,
+ .maxattr = ATTR_WIFI_LOGGER_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_ring_buff_status,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_get_ring_buff_status,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_logger_policy,
+ .maxattr = ATTR_WIFI_LOGGER_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_start_logging,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_start_logging,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_logger_policy,
+ .maxattr = ATTR_WIFI_LOGGER_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_ring_buff_data,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_get_ring_data,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_logger_policy,
+ .maxattr = ATTR_WIFI_LOGGER_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_start_packet_fate_monitor,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_start_packet_fate_monitor,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_fw_mem_dump,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_get_fw_dump,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_drv_mem_dump,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_get_drv_dump,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_set_packet_filter,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_set_packet_filter,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = woal_packet_filter_policy,
+ .maxattr = ATTR_PACKET_FILTER_MAX,
+#endif
+ },
+ {
+ .info = {
+ .vendor_id = MRVL_VENDOR_ID,
+ .subcmd = sub_cmd_get_packet_filter_capability,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = woal_cfg80211_subcmd_get_packet_filter_capability,
+#if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ },
+};
+// clang-format on
+
+/**
+ * @brief register vendor commands and events
+ *
+ * @param wiphy A pointer to wiphy struct
+ *
+ * @return
+ */
+void woal_register_cfg80211_vendor_command(struct wiphy *wiphy)
+{
+ ENTER();
+ wiphy->vendor_commands = vendor_commands;
+ wiphy->n_vendor_commands = ARRAY_SIZE(vendor_commands);
+ wiphy->vendor_events = vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(vendor_events);
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.h
new file mode 100644
index 000000000000..d98eca3923fe
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_cfg80211_util.h
@@ -0,0 +1,781 @@
+/** @file moal_cfg80211_util.h
+ *
+ * @brief This file contains the CFG80211 vendor specific defines.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MOAL_CFGVENDOR_H_
+#define _MOAL_CFGVENDOR_H_
+
+#include "moal_main.h"
+
+#if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
+#define RING_NAME_MAX 32
+typedef int wifi_ring_buffer_id;
+
+#define VALID_RING(id) (id >= 0 && id < RING_ID_MAX)
+
+/** WiFi ring control structure */
+typedef struct _wifi_ring_ctrl {
+ /** Written bytes */
+ t_u32 written_bytes;
+ /** Read Bytes */
+ t_u32 read_bytes;
+ /** Written records */
+ t_u32 written_records;
+} ring_buffer_ctrl;
+
+enum ring_state {
+ /** ring is not initialized*/
+ RING_STOP = 0,
+ /** ring is live and logging*/
+ RING_ACTIVE,
+ /** ring is initialized but not logging*/
+ RING_SUSPEND,
+};
+
+/** WiFi ring buffer sttructure */
+typedef struct _wifi_ring_buffer {
+ /** Ring ID */
+ wifi_ring_buffer_id ring_id;
+ /** Ring name */
+ t_u8 name[RING_NAME_MAX];
+ /** Ring size */
+ t_u32 ring_size;
+ /** Write pointer */
+ t_u32 wp;
+ /** Read pointer */
+ t_u32 rp;
+ /** Log level */
+ t_u32 log_level;
+ /** Threshold */
+ t_u32 threshold;
+ /** Ring buffer */
+ void *ring_buf;
+ /** Lock */
+ spinlock_t lock;
+ /** Buffer control */
+ ring_buffer_ctrl ctrl;
+ /** Ring state */
+ enum ring_state state;
+ /** Delayed work */
+ struct delayed_work work;
+ /** Interval */
+ unsigned long interval;
+ /** Moal priv */
+ moal_private *priv;
+} wifi_ring_buffer;
+
+#define VERBOSE_RING_NAME "verbose"
+#define EVENT_RING_NAME "event"
+
+#define DEFAULT_RING_BUFFER_SIZE 1024
+
+#define TLV_LOG_HEADER_LEN 4
+
+#define WIFI_LOGGER_MEMORY_DUMP_SUPPORTED MBIT(0) /* Memory dump of Fw*/
+#define WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORT MBIT(1) /*PKT status*/
+#define WIFI_LOGGER_CONNECT_EVENT_SUPPORTED MBIT(2) /* connectivity event*/
+#define WIFI_LOGGER_POWER_EVENT_SUPPORTED MBIT(3) /* Power of driver*/
+#define WIFI_LOGGER_WAKE_LOCK_SUPPORTED MBIT(4) /* Wake lock of driver*/
+#define WIFI_LOGGER_VERBOSE_SUPPORTED MBIT(5) /*verbose log of Fw*/
+#define WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED \
+ MBIT(6) /*monitor the health of Fw*/
+
+/**
+ * Parameters of wifi logger events are TLVs
+ * Event parameters tags are defined as:
+ */
+#define WIFI_TAG_VENDOR_SPECIFIC 0 // take a byte stream as parameter
+#define WIFI_TAG_BSSID 1 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR 2 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_SSID 3 // takes a 32 bytes SSID address as parameter
+#define WIFI_TAG_STATUS 4 // takes an integer as parameter
+#define WIFI_TAG_REASON_CODE 14 // take a reason code as per 802.11 as parameter
+#define WIFI_TAG_RSSI 21 // take an integer as parameter
+#define WIFI_TAG_CHANNEL 22 // take an integer as parameter
+
+#define RING_ENTRY_SIZE (sizeof(wifi_ring_buffer_entry))
+#define ENTRY_LENGTH(hdr) (hdr->entry_size + RING_ENTRY_SIZE)
+#define READ_AVAIL_SPACE(ring) \
+ (ring->ctrl.written_bytes - ring->ctrl.read_bytes)
+
+enum logger_attributes {
+ ATTR_WIFI_LOGGER_INVALID = 0,
+ ATTR_WIFI_LOGGER_RING_ID,
+ ATTR_WIFI_LOGGER_FLAGS,
+ ATTR_WIFI_LOGGER_VERBOSE_LEVEL,
+ ATTR_WIFI_LOGGER_MIN_DATA_SIZE,
+ ATTR_RING_BUFFER_STATUS,
+ ATTR_NUM_RINGS,
+ ATTR_WIFI_LOGGER_FEATURE_SET,
+ ATTR_WIFI_LOGGER_MAX_INTERVAL_SEC,
+ ATTR_RING_BUFFER,
+ ATTR_NAME,
+ ATTR_MEM_DUMP,
+ ATTR_ERR_CODE,
+ ATTR_RING_DATA,
+ ATTR_WAKE_REASON_STAT,
+ ATTR_PACKET_FATE_TX,
+ ATTR_PACKET_FATE_RX,
+ ATTR_PACKET_FATE_DATA,
+ ATTR_FW_DUMP_PATH = 20,
+ ATTR_DRV_DUMP_PATH = 21,
+ ATTR_WIFI_LOGGER_AFTER_LAST,
+ ATTR_WIFI_LOGGER_MAX = ATTR_WIFI_LOGGER_AFTER_LAST - 1
+};
+
+/* Below events refer to the wifi_connectivity_event ring and shall be supported
+ */
+enum { WIFI_EVENT_ASSOCIATION_REQUESTED = 0,
+ WIFI_EVENT_AUTH_COMPLETE,
+ WIFI_EVENT_ASSOC_COMPLETE,
+};
+
+enum {
+ /* set for binary entries */
+ RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)),
+ /* set if 64 bits timestamp is present */
+ RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))
+};
+
+enum { ENTRY_TYPE_CONNECT_EVENT = 1,
+ ENTRY_TYPE_PKT,
+ ENTRY_TYPE_WAKE_LOCK,
+ ENTRY_TYPE_POWER_EVENT,
+ ENTRY_TYPE_DATA };
+
+/** WiFi ring buffer entry structure */
+typedef struct {
+ /** size of payload excluding the header */
+ t_u16 entry_size;
+ /** Flags */
+ t_u8 flags;
+ /** entry type */
+ t_u8 type;
+ /** present if has_timestamp bit is set. */
+ t_u64 timestamp;
+} __attribute__((packed)) wifi_ring_buffer_entry;
+
+/** WiFi ring buffer status structure*/
+typedef struct _wifi_ring_buffer_status {
+ /** Ring name */
+ t_u8 name[RING_NAME_MAX];
+ /** Flag */
+ t_u32 flag;
+ /** Ring ID */
+ wifi_ring_buffer_id ring_id;
+ /** Buffer size */
+ t_u32 ring_buffer_byte_size;
+ /** Verbose Level */
+ t_u32 verbose_level;
+ /** Written bytes */
+ t_u32 written_bytes;
+ /** Read bytes */
+ t_u32 read_bytes;
+ /** Written records */
+ t_u32 written_records;
+} wifi_ring_buffer_status;
+
+/** TLV log structure */
+typedef struct {
+ /** Tag */
+ u16 tag;
+ /** Length of value*/
+ u16 length;
+ /** Value */
+ u8 value[];
+} __attribute__((packed)) tlv_log;
+
+/** WiFi ring buffer driver structure */
+typedef struct {
+ /** event */
+ u16 event;
+ /** TLV log structure array */
+ tlv_log tlvs[];
+ /** separate parameter structure per event to be provided and optional
+ * data the event_data is expected to include an official android part,
+ * with some parameter as transmit rate, num retries, num scan result
+ * found etc... as well, event_data can include a vendor proprietary
+ * part which is understood by the developer only
+ */
+} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;
+
+/** Assoc logger data structure */
+typedef struct _assoc_logger {
+ /** vendor specific */
+ t_u8 oui[3];
+ /** BSSID */
+ t_u8 bssid[MLAN_MAC_ADDR_LENGTH];
+ /** SSID */
+ t_u8 ssid[MLAN_MAX_SSID_LENGTH];
+ /** RSSI */
+ t_s32 rssi;
+ /** Channel */
+ t_u32 channel;
+} assoc_logger_data;
+
+int woal_ring_event_logger(moal_private *priv, int ring_id,
+ pmlan_event pmevent);
+
+int woal_wake_reason_logger(moal_private *priv,
+ mlan_ds_hs_wakeup_reason wake_reason);
+
+#define MD5_PREFIX_LEN 4
+#define MAX_FATE_LOG_LEN 32
+#define MAX_FRAME_LEN_ETHERNET 1518
+#define MAX_FRAME_LEN_80211_MGMT 2352
+
+/** packet_fate_packet_type */
+typedef enum {
+ PACKET_TYPE_TX,
+ PACKET_TYPE_RX,
+} packet_fate_packet_type;
+
+/** packet fate frame_type */
+typedef enum {
+ FRAME_TYPE_UNKNOWN,
+ FRAME_TYPE_ETHERNET_II,
+ FRAME_TYPE_80211_MGMT,
+} frame_type;
+
+/** wifi_tx_packet_fate */
+typedef enum {
+ /** Sent over air and ACKed. */
+ TX_PKT_FATE_ACKED,
+
+ /** Sent over air but not ACKed. (Normal for broadcast/multicast.) */
+ TX_PKT_FATE_SENT,
+
+ /** Queued within firmware, but not yet sent over air. */
+ TX_PKT_FATE_FW_QUEUED,
+
+ /** Dropped by firmware as invalid. E.g. bad source address, bad
+ * checksum, or invalid for current state.
+ */
+ TX_PKT_FATE_FW_DROP_INVALID,
+
+ /** Dropped by firmware due to lack of buffer space. */
+ TX_PKT_FATE_FW_DROP_NOBUFS,
+
+ /** Dropped by firmware for any other reason. Includes frames that were
+ * sent by driver to firmware, but unaccounted for by firmware.
+ */
+ TX_PKT_FATE_FW_DROP_OTHER,
+
+ /** Queued within driver, not yet sent to firmware. */
+ TX_PKT_FATE_DRV_QUEUED,
+
+ /** Dropped by driver as invalid. E.g. bad source address, or invalid
+ * for current state.
+ */
+ TX_PKT_FATE_DRV_DROP_INVALID,
+
+ /** Dropped by driver due to lack of buffer space. */
+ TX_PKT_FATE_DRV_DROP_NOBUFS,
+
+ /** Dropped by driver for any other reason. */
+ TX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_tx_packet_fate;
+
+/** wifi_rx_packet_fate */
+typedef enum {
+ /** Valid and delivered to network stack (e.g., netif_rx()). */
+ RX_PKT_FATE_SUCCESS,
+
+ /** Queued within firmware, but not yet sent to driver. */
+ RX_PKT_FATE_FW_QUEUED,
+
+ /** Dropped by firmware due to host-programmable filters. */
+ RX_PKT_FATE_FW_DROP_FILTER,
+
+ /** Dropped by firmware as invalid. E.g. bad checksum, decrypt failed,
+ * or invalid for current state.
+ */
+ RX_PKT_FATE_FW_DROP_INVALID,
+
+ /** Dropped by firmware due to lack of buffer space. */
+ RX_PKT_FATE_FW_DROP_NOBUFS,
+
+ /** Dropped by firmware for any other reason. */
+ RX_PKT_FATE_FW_DROP_OTHER,
+
+ /** Queued within driver, not yet delivered to network stack. */
+ RX_PKT_FATE_DRV_QUEUED,
+
+ /** Dropped by driver due to filter rules. */
+ RX_PKT_FATE_DRV_DROP_FILTER,
+
+ /** Dropped by driver as invalid. E.g. not permitted in current state.
+ */
+ RX_PKT_FATE_DRV_DROP_INVALID,
+
+ /** Dropped by driver due to lack of buffer space. */
+ RX_PKT_FATE_DRV_DROP_NOBUFS,
+
+ /** Dropped by driver for any other reason. */
+ RX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_rx_packet_fate;
+
+/** frame_info_i */
+typedef struct {
+ /** Payload Type */
+ frame_type payload_type;
+ /** Driver timestamp in uS */
+ u32 driver_timestamp_usec;
+ /** FW timestamp in uS */
+ u32 firmware_timestamp_usec;
+ /** Frame Length */
+ u32 frame_len;
+} frame_info_i;
+
+/** wifi_tx_report_i */
+typedef struct {
+ /** MD5 prefix */
+ char md5_prefix[MD5_PREFIX_LEN];
+ /** TX packet fate */
+ wifi_tx_packet_fate fate;
+ /** frame information */
+ frame_info_i frame_inf;
+} wifi_tx_report_i;
+
+/** wifi_rx_report_i */
+typedef struct {
+ /** MD5 prefix */
+ char md5_prefix[MD5_PREFIX_LEN];
+ /** TX packet fate */
+ wifi_rx_packet_fate fate;
+ /** frame information */
+ frame_info_i frame_inf;
+} wifi_rx_report_i;
+
+/** packet_fate_report_t */
+typedef struct packet_fate_report_t {
+ union {
+ wifi_tx_report_i tx_report_i;
+ wifi_rx_report_i rx_report_i;
+ } u;
+} PACKET_FATE_REPORT;
+
+int woal_packet_fate_monitor(moal_private *priv,
+ packet_fate_packet_type pkt_type, t_u8 fate,
+ frame_type payload_type,
+ t_u32 driver_timestamp_usec,
+ t_u32 firmware_timestamp_usec, t_u8 *data,
+ t_u32 len);
+
+/** =========== Define Copied from apf.h START =========== */
+/* Number of memory slots, see ldm/stm instructions. */
+#define MEM_ITEMS 16
+/* Upon program execution starting some memory slots are prefilled: */
+/* 4*([APF_FRAME_HEADER_SIZE]&15) */
+#define MEM_OFFSET_IPV4_HEADER_SIZE 13
+/* Size of packet in bytes. */
+#define MEM_OFFSET_PKT_SIZE 14
+/* Age since filter installed in seconds. */
+#define MEM_OFFSET_FILTER_AGE 15
+
+/* Leave 0 opcode unused as it's a good indicator of accidental incorrect
+ * execution (e.g. data).
+ */
+/* Load 1 byte from immediate offset, e.g. "ldb R0, [5]" */
+#define NXP_LDB_OPCODE 1
+/* Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" */
+#define NXP_LDH_OPCODE 2
+/* Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" */
+#define NXP_LDW_OPCODE 3
+/* Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0" */
+#define NXP_LDBX_OPCODE 4
+/* Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0" */
+#define NXP_LDHX_OPCODE 5
+/* Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0" */
+#define NXP_LDWX_OPCODE 6
+/* Add, e.g. "add R0,5" */
+#define NXP_ADD_OPCODE 7
+/* Multiply, e.g. "mul R0,5" */
+#define NXP_MUL_OPCODE 8
+/* Divide, e.g. "div R0,5" */
+#define NXP_DIV_OPCODE 9
+/* And, e.g. "and R0,5" */
+#define NXP_AND_OPCODE 10
+/* Or, e.g. "or R0,5" */
+#define NXP_OR_OPCODE 11
+/* Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right) */
+#define NXP_SH_OPCODE 12
+/* Load immediate, e.g. "li R0,5" (immediate encoded as signed value) */
+#define NXP_LI_OPCODE 13
+/* Unconditional jump, e.g. "jmp label" */
+#define NXP_JMP_OPCODE 14
+/* Compare equal and branch, e.g. "jeq R0,5,label" */
+#define NXP_JEQ_OPCODE 15
+/* Compare not equal and branch, e.g. "jne R0,5,label" */
+#define NXP_JNE_OPCODE 16
+/* Compare greater than and branch, e.g. "jgt R0,5,label" */
+#define NXP_JGT_OPCODE 17
+/* Compare less than and branch, e.g. "jlt R0,5,label" */
+#define NXP_JLT_OPCODE 18
+/* Compare any bits set and branch, e.g. "jset R0,5,label" */
+#define NXP_JSET_OPCODE 19
+/* Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455" */
+#define NXP_JNEBS_OPCODE 20
+/* Immediate value is one of *_EXT_OPCODE
+ * Extended opcodes. These all have an opcode of EXT_OPCODE
+ * and specify the actual opcode in the immediate field.
+ */
+#define NXP_EXT_OPCODE 21
+/* Load from memory, e.g. "ldm R0,5"
+ * Values 0-15 represent loading the different memory slots.
+ */
+#define NXP_LDM_EXT_OPCODE 0
+/* Store to memory, e.g. "stm R0,5" *
+ * Values 16-31 represent storing to the different memory slots.
+ */
+#define NXP_STM_EXT_OPCODE 16
+/* Not, e.g. "not R0" */
+#define NXP_NOT_EXT_OPCODE 32
+/* Negate, e.g. "neg R0" */
+#define NXP_NEG_EXT_OPCODE 33
+/* Swap, e.g. "swap R0,R1" */
+#define NXP_SWAP_EXT_OPCODE 34
+/* Move, e.g. "move R0,R1" */
+#define NXP_MOV_EXT_OPCODE 35
+
+#define GET_OPCODE(i) (((i) >> 3) & 31)
+#define GET_REGISTER(i) ((i)&1)
+#define GET_IMM_LENGTH(i) (((i) >> 1) & 3)
+/** =========== Define Copied from apf.h END =========== */
+
+/** =========== Define Copied from apf_interpreter.h START =========== */
+/**
+ * Version of APF instruction set processed by accept_packet().
+ * Should be returned by wifi_get_packet_filter_info.
+ */
+#define APF_VERSION 2
+/** =========== Define Copied from apf_interpreter.h END =========== */
+
+/** =========== Define Copied from apf_interpreter.c START =========== */
+/* Return code indicating "packet" should accepted. */
+#define PASS_PKT 1
+/* Return code indicating "packet" should be dropped. */
+#define DROP_PKT 0
+/* If "c" is of an unsigned type, generate a compile warning that gets promoted
+ * to an error. This makes bounds checking simpler because ">= 0" can be
+ * avoided. Otherwise adding superfluous ">= 0" with unsigned expressions
+ * generates compile warnings.
+ */
+#define ENFORCE_UNSIGNED(c) ((c) == (uint32_t)(c))
+/** =========== Define Copied from apf_interpreter.c END =========== */
+
+/** depend on the format of skb->data */
+#define APF_FRAME_HEADER_SIZE 14
+#define PACKET_FILTER_MAX_LEN 1024
+
+enum { PACKET_FILTER_STATE_INIT = 0,
+ PACKET_FILTER_STATE_STOP,
+ PACKET_FILTER_STATE_START,
+};
+
+enum wifi_attr_packet_filter {
+ ATTR_PACKET_FILTER_INVALID = 0,
+ ATTR_PACKET_FILTER_TOTAL_LENGTH,
+ ATTR_PACKET_FILTER_PROGRAM,
+ ATTR_PACKET_FILTER_VERSION,
+ ATTR_PACKET_FILTER_MAX_LEN,
+ ATTR_PACKET_FILTER_AFTER_LAST,
+ ATTR_PACKET_FILTER_MAX = ATTR_PACKET_FILTER_AFTER_LAST - 1
+};
+
+/** Packet filter structure */
+typedef struct _packet_filter {
+ spinlock_t lock;
+ t_u8 state;
+ t_u8 packet_filter_program[PACKET_FILTER_MAX_LEN];
+ t_u8 packet_filter_len;
+ t_u32 packet_filter_version;
+ t_u32 packet_filter_max_len;
+} packet_filter;
+
+int woal_filter_packet(moal_private *priv, t_u8 *data, t_u32 len,
+ t_u32 filter_age);
+
+int woal_init_wifi_hal(moal_private *priv);
+int woal_deinit_wifi_hal(moal_private *priv);
+
+#define ATTRIBUTE_U32_LEN (nla_total_size(NLA_HDRLEN + 4))
+#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_DATA_OVERHEAD (nla_total_size(NLA_HDRLEN))
+
+#define VENDOR_REPLY_OVERHEAD \
+ (VENDOR_ID_OVERHEAD + VENDOR_SUBCMD_OVERHEAD + VENDOR_DATA_OVERHEAD)
+
+/* Features Enums*/
+#define WLAN_FEATURE_INFRA 0x0001 // Basic infrastructure mode support
+#define WLAN_FEATURE_INFRA_5G 0x0002 // 5 GHz Band support
+#define WLAN_FEATURE_HOTSPOT 0x0004 // GAS/ANQP support
+#define WLAN_FEATURE_P2P 0x0008 // Wifi-Direct/P2P
+#define WLAN_FEATURE_SOFT_AP 0x0010 // Soft AP support
+#define WLAN_FEATURE_GSCAN 0x0020 // Google-Scan APIsi support
+#define WLAN_FEATURE_NAN 0x0040 // Neighbor Awareness Networking (NAN)
+#define WLAN_FEATURE_D2D_RTT 0x0080 // Device-to-device RTT support
+#define WLAN_FEATURE_D2AP_RTT 0x0100 // Device-to-AP RTT support
+#define WLAN_FEATURE_BATCH_SCAN 0x0200 // Batched Scan (legacy) support
+#define WLAN_FEATURE_PNO 0x0400 // Preferred network offload support
+#define WLAN_FEATURE_ADDITIONAL_STA 0x0800 // Two STAs support
+#define WLAN_FEATURE_TDLS 0x1000 // Tunnel directed link setup (TDLS)
+#define WLAN_FEATURE_TDLS_OFFCHANNEL 0x2000 // TDLS off channel support
+#define WLAN_FEATURE_EPR 0x4000 // Enhanced power reporting support
+#define WLAN_FEATURE_AP_STA 0x8000 // AP STA Concurrency support
+#define WLAN_FEATURE_LINK_LAYER_STATS \
+ 0x10000 // Link layer stats collection support
+#define WLAN_FEATURE_LOGGER 0x20000 // WiFi Logger support
+#define WLAN_FEATURE_HAL_EPNO 0x40000 // WiFi enhanced PNO support
+#define WLAN_FEATURE_RSSI_MONITOR 0x80000 // RSSI Monitor support
+#define WLAN_FEATURE_MKEEP_ALIVE 0x100000 // WiFi mkeep_alive support
+#define WLAN_FEATURE_CONFIG_NDO 0x200000 // ND offload configure support
+#define WLAN_FEATURE_TX_TRANSMIT_POWER \
+ 0x400000 // Capture Tx transmit power levels
+#define WLAN_FEATURE_CONTROL_ROAMING 0x800000 // Enable/Disable firmware roaming
+#define WLAN_FEATURE_IE_WHITELIST 0x1000000 // Probe IE white listing support
+#define WLAN_FEATURE_SCAN_RAND \
+ 0x2000000 // MAC & Probe Sequence Number randomization Support
+// Add more features here
+
+#define MAX_CHANNEL_NUM 200
+
+/** Wifi Band */
+typedef enum {
+ WIFI_BAND_UNSPECIFIED,
+ /** 2.4 GHz */
+ WIFI_BAND_BG = 1,
+ /** 5 GHz without DFS */
+ WIFI_BAND_A = 2,
+ /** 5 GHz DFS only */
+ WIFI_BAND_A_DFS = 4,
+ /** 5 GHz with DFS */
+ WIFI_BAND_A_WITH_DFS = 6,
+ /** 2.4 GHz + 5 GHz; no DFS */
+ WIFI_BAND_ABG = 3,
+ /** 2.4 GHz + 5 GHz with DFS */
+ WIFI_BAND_ABG_WITH_DFS = 7,
+
+ /** Keep it last */
+ WIFI_BAND_LAST,
+ WIFI_BAND_MAX = WIFI_BAND_LAST - 1,
+} wifi_band;
+
+typedef enum wifi_attr {
+ ATTR_FEATURE_SET_INVALID = 0,
+ ATTR_SCAN_MAC_OUI_SET = 1,
+ ATTR_FEATURE_SET = 2,
+ ATTR_NODFS_VALUE = 3,
+ ATTR_COUNTRY_CODE = 4,
+ ATTR_CHANNELS_BAND = 5,
+ ATTR_NUM_CHANNELS = 6,
+ ATTR_CHANNEL_LIST = 7,
+ ATTR_GET_CONCURRENCY_MATRIX_SET_SIZE_MAX = 8,
+ ATTR_GET_CONCURRENCY_MATRIX_SET_SIZE = 9,
+ ATTR_GET_CONCURRENCY_MATRIX_SET = 10,
+ ATTR_WIFI_AFTER_LAST,
+ ATTR_WIFI_MAX = ATTR_WIFI_AFTER_LAST - 1
+} wifi_attr_t;
+
+enum mrvl_wlan_vendor_attr_wifi_logger {
+ MRVL_WLAN_VENDOR_ATTR_NAME = 10,
+};
+
+/**vendor event*/
+enum vendor_event {
+ event_hang = 0,
+ event_rssi_monitor = 0x1501,
+ event_cloud_keep_alive = 0x10003,
+ event_dfs_radar_detected = 0x10004,
+ event_dfs_cac_started = 0x10005,
+ event_dfs_cac_finished = 0x10006,
+ event_dfs_cac_aborted = 0x10007,
+ event_dfs_nop_finished = 0x10008,
+ event_wifi_logger_ring_buffer_data = 0x1000b,
+ event_wifi_logger_alert,
+ event_packet_fate_monitor,
+ event_wake_reason_report,
+ event_max,
+};
+
+/** struct dfs_event */
+typedef struct _dfs_event {
+ /** Frequency */
+ int freq;
+ /** HT enable */
+ int ht_enabled;
+ /** Channel Offset */
+ int chan_offset;
+ /** Channel width */
+ enum nl80211_chan_width chan_width;
+ /** Center Frequency 1 */
+ int cf1;
+ /** Center Frequency 2 */
+ int cf2;
+} dfs_event;
+
+void woal_cfg80211_dfs_vendor_event(moal_private *priv, int event,
+ struct cfg80211_chan_def *chandef);
+
+enum ATTR_LINK_LAYER_STAT {
+ ATTR_LL_STATS_INVALID,
+ ATTR_LL_STATS_MPDU_SIZE_THRESHOLD,
+ ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING,
+ ATTR_LL_STATS_IFACE,
+ ATTR_LL_STATS_NUM_RADIO,
+ ATTR_LL_STATS_RADIO,
+ ATTR_LL_STATS_CLEAR_REQ_MASK,
+ ATTR_LL_STATS_STOP_REQ,
+ ATTR_LL_STATS_CLEAR_RSP_MASK,
+ ATTR_LL_STATS_STOP_RSP,
+ ATTR_LL_STATS_AFTER_LAST,
+ ATTR_LL_STATS_MAX = ATTR_LL_STATS_AFTER_LAST - 1,
+};
+
+enum ATTR_RSSI_MONITOR {
+ ATTR_RSSI_MONITOR_INVALID,
+ ATTR_RSSI_MONITOR_CONTROL,
+ ATTR_RSSI_MONITOR_MIN_RSSI,
+ ATTR_RSSI_MONITOR_MAX_RSSI,
+ ATTR_RSSI_MONITOR_CUR_BSSID,
+ ATTR_RSSI_MONITOR_CUR_RSSI,
+ ATTR_RSSI_MONITOR_AFTER_LAST,
+ ATTR_RSSI_MONITOR_MAX = ATTR_RSSI_MONITOR_AFTER_LAST - 1,
+};
+void woal_cfg80211_rssi_monitor_event(moal_private *priv, t_s16 rssi);
+
+/**vendor sub command*/
+enum vendor_sub_command {
+ sub_cmd_set_drvdbg = 0,
+ sub_cmd_start_keep_alive = 0x0003,
+ sub_cmd_stop_keep_alive = 0x0004,
+ sub_cmd_dfs_capability = 0x0005,
+ sub_cmd_set_scan_mac_oui = 0x0007,
+ sub_cmd_set_packet_filter = 0x0011,
+ sub_cmd_get_packet_filter_capability,
+ sub_cmd_nd_offload = 0x0100,
+ sub_cmd_link_statistic_set = 0x1200,
+ sub_cmd_link_statistic_get = 0x1201,
+ sub_cmd_link_statistic_clr = 0x1202,
+ sub_cmd_get_valid_channels = 0x1009,
+ sub_cmd_get_wifi_supp_feature_set = 0x100a,
+ sub_cmd_set_country_code = 0x100d,
+ sub_cmd_get_fw_version = 0x1404,
+ sub_cmd_get_drv_version = 0x1406,
+ sub_cmd_start_logging = 0x1400,
+ sub_cmd_get_wifi_logger_supp_feature_set,
+ sub_cmd_get_ring_buff_data,
+ sub_cmd_get_ring_buff_status,
+ sub_cmd_get_fw_mem_dump = 0x1405,
+ sub_cmd_get_drv_mem_dump = 0x1407,
+ sub_cmd_start_packet_fate_monitor = 0x1408,
+ sub_cmd_rssi_monitor = 0x1500,
+ /*Sub-command for wifi hal*/
+ sub_cmd_get_roaming_capability = 0x1700,
+ sub_cmd_fw_roaming_enable = 0x1701,
+ sub_cmd_fw_roaming_config = 0x1702,
+ sub_cmd_max,
+};
+
+void woal_register_cfg80211_vendor_command(struct wiphy *wiphy);
+int woal_cfg80211_vendor_event(moal_private *priv, int event, t_u8 *data,
+ int len);
+
+enum mrvl_wlan_vendor_attr {
+ MRVL_WLAN_VENDOR_ATTR_INVALID = 0,
+ /* Used by MRVL_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
+ MRVL_WLAN_VENDOR_ATTR_DFS = 1,
+ MRVL_WLAN_VENDOR_ATTR_AFTER_LAST,
+
+ MRVL_WLAN_VENDOR_ATTR_MAX = MRVL_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
+};
+
+typedef enum {
+ ATTR_ND_OFFLOAD_INVALID = 0,
+ ATTR_ND_OFFLOAD_CONTROL,
+ ATTR_ND_OFFLOAD_AFTER_LAST,
+ ATTR_ND_OFFLOAD_MAX = ATTR_ND_OFFLOAD_AFTER_LAST - 1,
+} ND_OFFLOAD_ATTR;
+
+#define MKEEP_ALIVE_IP_PKT_MAX 256
+enum mkeep_alive_attributes {
+ MKEEP_ALIVE_ATTRIBUTE_INVALID = 0,
+ MKEEP_ALIVE_ATTRIBUTE_ID,
+ MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
+ MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC,
+ MKEEP_ALIVE_ATTRIBUTE_RETRY_INTERVAL,
+ MKEEP_ALIVE_ATTRIBUTE_RETRY_CNT,
+ MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST,
+ MKEEP_ALIVE_ATTRIBUTE_MAX = MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST - 1
+};
+
+/** WiFi roaming capabilities structure */
+typedef struct {
+ /** max blacklist size */
+ u32 max_blacklist_size;
+ /** max whitelist size */
+ u32 max_whitelist_size;
+} wifi_roaming_capabilities;
+
+/** WiFi BSSID params structure */
+typedef struct {
+ /** Num of BSSID */
+ u32 num_bssid;
+ /** List of AP mac address */
+ t_u8 mac_addr[MAX_AP_LIST][MLAN_MAC_ADDR_LENGTH];
+} wifi_bssid_params;
+
+/** SSID structure */
+typedef struct {
+ /** Length */
+ u32 length;
+ /** SSID */
+ char ssid[MLAN_MAX_SSID_LENGTH];
+} ssid_t;
+
+/** WiFi SSID params structure */
+typedef struct {
+ /** No of SSID */
+ u32 num_ssid;
+ /** Whitelist SSID */
+ ssid_t whitelist_ssid[MAX_SSID_NUM];
+} wifi_ssid_params;
+
+/*Attribute for wifi hal*/
+enum mrvl_wlan_vendor_attr_fw_roaming {
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_INVALID = 0,
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CAPA,
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL,
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_BSSID,
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_SSID,
+ /* keep last */
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_AFTER_LAST,
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX =
+ MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_AFTER_LAST - 1
+};
+
+#endif
+#endif /* _MOAL_CFGVENDOR_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_debug.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_debug.c
new file mode 100644
index 000000000000..10da4dc270b4
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_debug.c
@@ -0,0 +1,1468 @@
+/** @file moal_debug.c
+ *
+ * @brief This file contains functions for debug proc file.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 11/03/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#ifdef USB
+#include "moal_usb.h"
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+
+/** Get info item size */
+#define item_size(n) (sizeof(((mlan_debug_info *)0)->n))
+/** Get info item address */
+#define item_addr(n) ((t_ptr) & (((mlan_debug_info *)0)->n))
+
+/** Get moal_private member size */
+#define item_priv_size(n) (sizeof(((moal_private *)0)->n))
+/** Get moal_private member address */
+#define item_priv_addr(n) ((t_ptr) & (((moal_private *)0)->n))
+
+/** Get moal_handle member size */
+#define item_handle_size(n) (sizeof(((moal_handle *)0)->n))
+/** Get moal_handle member address */
+#define item_handle_addr(n) ((t_ptr) & (((moal_handle *)0)->n))
+
+#ifdef USB
+/** Get moal card member size */
+#define item_card_size(n) (sizeof(((struct usb_card_rec *)0)->n))
+/** Get moal card member address */
+#define item_card_addr(n) ((t_ptr) & (((struct usb_card_rec *)0)->n))
+#endif
+
+#ifdef STA_SUPPORT
+static struct debug_data items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr)&drvdbg, 0},
+#endif
+ {"mlan_processing", item_size(mlan_processing),
+ item_addr(mlan_processing), INFO_ADDR},
+ {"main_process_cnt", item_size(main_process_cnt),
+ item_addr(main_process_cnt), INFO_ADDR},
+ {"main_lock_flag", item_size(main_lock_flag), item_addr(main_lock_flag),
+ INFO_ADDR},
+ {"delay_task_flag", item_size(delay_task_flag),
+ item_addr(delay_task_flag), INFO_ADDR},
+ {"mlan_rx_processing", item_size(mlan_rx_processing),
+ item_addr(mlan_rx_processing), INFO_ADDR},
+ {"rx_pkts_queued", item_size(rx_pkts_queued), item_addr(rx_pkts_queued),
+ INFO_ADDR},
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo), INFO_ADDR},
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi), INFO_ADDR},
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be), INFO_ADDR},
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk), INFO_ADDR},
+ {"max_tx_buf_size", item_size(max_tx_buf_size),
+ item_addr(max_tx_buf_size), INFO_ADDR},
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size),
+ INFO_ADDR},
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size), INFO_ADDR},
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode), INFO_ADDR},
+ {"ps_state", item_size(ps_state), item_addr(ps_state), INFO_ADDR},
+ {"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep),
+ INFO_ADDR},
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req), INFO_ADDR},
+ {"wakeup_tries", item_size(pm_wakeup_fw_try),
+ item_addr(pm_wakeup_fw_try), INFO_ADDR},
+ {"wakeup_timeout", item_size(pm_wakeup_timeout),
+ item_addr(pm_wakeup_timeout), INFO_ADDR},
+ {"hs_configured", item_size(is_hs_configured),
+ item_addr(is_hs_configured), INFO_ADDR},
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated),
+ INFO_ADDR},
+ {"rx_pkts_queued", item_size(rx_pkts_queued), item_addr(rx_pkts_queued),
+ INFO_ADDR},
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued),
+ INFO_ADDR},
+ {"pps_uapsd_mode", item_size(pps_uapsd_mode), item_addr(pps_uapsd_mode),
+ INFO_ADDR},
+ {"sleep_pd", item_size(sleep_pd), item_addr(sleep_pd), INFO_ADDR},
+ {"qos_cfg", item_size(qos_cfg), item_addr(qos_cfg), INFO_ADDR},
+ {"tx_lock_flag", item_size(tx_lock_flag), item_addr(tx_lock_flag),
+ INFO_ADDR},
+ {"port_open", item_size(port_open), item_addr(port_open), INFO_ADDR},
+ {"bypass_pkt_count", item_size(bypass_pkt_count),
+ item_addr(bypass_pkt_count), INFO_ADDR},
+ {"scan_processing", item_size(scan_processing),
+ item_addr(scan_processing), INFO_ADDR},
+ {"num_cmd_timeout", item_size(num_cmd_timeout),
+ item_addr(num_cmd_timeout), INFO_ADDR},
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id),
+ INFO_ADDR},
+ {"timeout_cmd_act", item_size(timeout_cmd_act),
+ item_addr(timeout_cmd_act), INFO_ADDR},
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id),
+ INFO_ADDR},
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act),
+ INFO_ADDR},
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index),
+ INFO_ADDR},
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id), INFO_ADDR},
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index), INFO_ADDR},
+ {"last_event", item_size(last_event), item_addr(last_event), INFO_ADDR},
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index), INFO_ADDR},
+ {"num_no_cmd_node", item_size(num_no_cmd_node),
+ item_addr(num_no_cmd_node), INFO_ADDR},
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure), INFO_ADDR},
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure), INFO_ADDR},
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure), INFO_ADDR},
+ {"num_alloc_buffer_failure", item_size(num_alloc_buffer_failure),
+ item_addr(num_alloc_buffer_failure), INFO_ADDR},
+#ifdef SDIO
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure), INFO_ADDR | (INTF_SD << 8)},
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure), INFO_ADDR | (INTF_SD << 8)},
+ {"last_int_status", item_size(last_int_status),
+ item_addr(last_int_status), INFO_ADDR | (INTF_SD << 8)},
+ {"num_of_irq", item_size(num_of_irq), item_addr(num_of_irq),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"mp_invalid_update", item_size(mp_invalid_update),
+ item_addr(mp_invalid_update), INFO_ADDR | (INTF_SD << 8)},
+ {"sdio_rx_aggr", item_size(sdio_rx_aggr), item_addr(sdio_rx_aggr),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"mpa_sent_last_pkt", item_size(mpa_sent_last_pkt),
+ item_addr(mpa_sent_last_pkt), INFO_ADDR | (INTF_SD << 8)},
+ {"mpa_sent_no_ports", item_size(mpa_sent_no_ports),
+ item_addr(mpa_sent_no_ports), INFO_ADDR | (INTF_SD << 8)},
+#endif
+ {"num_evt_deauth", item_size(num_event_deauth),
+ item_addr(num_event_deauth), INFO_ADDR},
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc), INFO_ADDR},
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost), INFO_ADDR},
+ {"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth),
+ INFO_ADDR},
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success), INFO_ADDR},
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure), INFO_ADDR},
+ {"num_cons_assoc_failure", item_size(num_cons_assoc_failure),
+ item_addr(num_cons_assoc_failure), INFO_ADDR},
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent), INFO_ADDR},
+ {"data_sent", item_size(data_sent), item_addr(data_sent), INFO_ADDR},
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap),
+ INFO_ADDR},
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port),
+ INFO_ADDR},
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap),
+ INFO_ADDR},
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port),
+ INFO_ADDR},
+#ifdef PCIE
+ {"txbd_rdptr", item_size(txbd_rdptr), item_addr(txbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"txbd_wrptr", item_size(txbd_wrptr), item_addr(txbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"rxbd_rdptr", item_size(rxbd_rdptr), item_addr(rxbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"rxbd_wrptr", item_size(rxbd_wrptr), item_addr(rxbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"eventbd_rdptr", item_size(eventbd_rdptr), item_addr(eventbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"eventbd_wrptr", item_size(eventbd_wrptr), item_addr(eventbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+#endif
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received), INFO_ADDR},
+ {"event_received", item_size(event_received), item_addr(event_received),
+ INFO_ADDR},
+
+#ifdef USB
+ {"tx_cmd_urb_pending", item_card_size(tx_cmd_urb_pending),
+ item_card_addr(tx_cmd_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+ {"tx_data_urb_pending", item_card_size(tx_data_urb_pending),
+ item_card_addr(tx_data_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#ifdef USB_CMD_DATA_EP
+ {"rx_cmd_urb_pending", item_card_size(rx_cmd_urb_pending),
+ item_card_addr(rx_cmd_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#endif
+ {"rx_data_urb_pending", item_card_size(rx_data_urb_pending),
+ item_card_addr(rx_data_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#endif /* USB */
+ {"num_tx_timeout", item_priv_size(num_tx_timeout),
+ item_priv_addr(num_tx_timeout), PRIV_ADDR},
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending), HANDLE_ADDR},
+ {"tx_pending", item_handle_size(tx_pending),
+ item_handle_addr(tx_pending), HANDLE_ADDR},
+ {"rx_pending", item_handle_size(rx_pending),
+ item_handle_addr(rx_pending), HANDLE_ADDR},
+ {"lock_count", item_handle_size(lock_count),
+ item_handle_addr(lock_count), HANDLE_ADDR},
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count), HANDLE_ADDR},
+ {"vmalloc_count", item_handle_size(vmalloc_count),
+ item_handle_addr(vmalloc_count), HANDLE_ADDR},
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count), HANDLE_ADDR},
+#ifdef PCIE
+ {"malloc_cons_count", item_handle_size(malloc_cons_count),
+ item_handle_addr(malloc_cons_count), HANDLE_ADDR},
+#endif
+ {"main_state", item_handle_size(main_state),
+ item_handle_addr(main_state), HANDLE_ADDR},
+ {"driver_state", item_handle_size(driver_state),
+ item_handle_addr(driver_state), HANDLE_ADDR},
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w),
+ HANDLE_ADDR},
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r),
+ HANDLE_ADDR},
+#endif
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count), HANDLE_ADDR},
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count), HANDLE_ADDR},
+};
+
+#endif
+
+#ifdef UAP_SUPPORT
+static struct debug_data uap_items[] = {
+#ifdef DEBUG_LEVEL1
+ {"drvdbg", sizeof(drvdbg), (t_ptr)&drvdbg, 0},
+#endif
+ {"mlan_processing", item_size(mlan_processing),
+ item_addr(mlan_processing), INFO_ADDR},
+ {"main_process_cnt", item_size(main_process_cnt),
+ item_addr(main_process_cnt), INFO_ADDR},
+ {"main_lock_flag", item_size(main_lock_flag), item_addr(main_lock_flag),
+ INFO_ADDR},
+ {"delay_task_flag", item_size(delay_task_flag),
+ item_addr(delay_task_flag), INFO_ADDR},
+ {"mlan_rx_processing", item_size(mlan_rx_processing),
+ item_addr(mlan_rx_processing), INFO_ADDR},
+ {"rx_pkts_queued", item_size(rx_pkts_queued), item_addr(rx_pkts_queued),
+ INFO_ADDR},
+ {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo), INFO_ADDR},
+ {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi), INFO_ADDR},
+ {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be), INFO_ADDR},
+ {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk), INFO_ADDR},
+ {"max_tx_buf_size", item_size(max_tx_buf_size),
+ item_addr(max_tx_buf_size), INFO_ADDR},
+ {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size),
+ INFO_ADDR},
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size), INFO_ADDR},
+ {"ps_mode", item_size(ps_mode), item_addr(ps_mode), INFO_ADDR},
+ {"ps_state", item_size(ps_state), item_addr(ps_state), INFO_ADDR},
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req), INFO_ADDR},
+ {"wakeup_tries", item_size(pm_wakeup_fw_try),
+ item_addr(pm_wakeup_fw_try), INFO_ADDR},
+ {"wakeup_timeout", item_size(pm_wakeup_timeout),
+ item_addr(pm_wakeup_timeout), INFO_ADDR},
+ {"hs_configured", item_size(is_hs_configured),
+ item_addr(is_hs_configured), INFO_ADDR},
+ {"hs_activated", item_size(hs_activated), item_addr(hs_activated),
+ INFO_ADDR},
+ {"rx_pkts_queued", item_size(rx_pkts_queued), item_addr(rx_pkts_queued),
+ INFO_ADDR},
+ {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued),
+ INFO_ADDR},
+ {"bypass_pkt_count", item_size(bypass_pkt_count),
+ item_addr(bypass_pkt_count), INFO_ADDR},
+ {"num_bridge_pkts", item_size(num_bridge_pkts),
+ item_addr(num_bridge_pkts), INFO_ADDR},
+ {"num_drop_pkts", item_size(num_drop_pkts), item_addr(num_drop_pkts),
+ INFO_ADDR},
+ {"num_cmd_timeout", item_size(num_cmd_timeout),
+ item_addr(num_cmd_timeout), INFO_ADDR},
+ {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id),
+ INFO_ADDR},
+ {"timeout_cmd_act", item_size(timeout_cmd_act),
+ item_addr(timeout_cmd_act), INFO_ADDR},
+ {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id),
+ INFO_ADDR},
+ {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act),
+ INFO_ADDR},
+ {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index),
+ INFO_ADDR},
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id), INFO_ADDR},
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index), INFO_ADDR},
+ {"last_event", item_size(last_event), item_addr(last_event), INFO_ADDR},
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index), INFO_ADDR},
+ {"num_no_cmd_node", item_size(num_no_cmd_node),
+ item_addr(num_no_cmd_node), INFO_ADDR},
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure), INFO_ADDR},
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure), INFO_ADDR},
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure), INFO_ADDR},
+ {"num_alloc_buffer_failure", item_size(num_alloc_buffer_failure),
+ item_addr(num_alloc_buffer_failure), INFO_ADDR},
+#ifdef SDIO
+ {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure),
+ item_addr(num_cmdevt_card_to_host_failure),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure),
+ item_addr(num_rx_card_to_host_failure), INFO_ADDR | (INTF_SD << 8)},
+ {"num_int_read_fail", item_size(num_int_read_failure),
+ item_addr(num_int_read_failure), INFO_ADDR | (INTF_SD << 8)},
+ {"last_int_status", item_size(last_int_status),
+ item_addr(last_int_status), INFO_ADDR | (INTF_SD << 8)},
+ {"num_of_irq", item_size(num_of_irq), item_addr(num_of_irq),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"mp_invalid_update", item_size(mp_invalid_update),
+ item_addr(mp_invalid_update), INFO_ADDR | (INTF_SD << 8)},
+ {"sdio_rx_aggr", item_size(sdio_rx_aggr), item_addr(sdio_rx_aggr),
+ INFO_ADDR | (INTF_SD << 8)},
+ {"mpa_sent_last_pkt", item_size(mpa_sent_last_pkt),
+ item_addr(mpa_sent_last_pkt), INFO_ADDR | (INTF_SD << 8)},
+ {"mpa_sent_no_ports", item_size(mpa_sent_no_ports),
+ item_addr(mpa_sent_no_ports), INFO_ADDR | (INTF_SD << 8)},
+#endif
+ {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent), INFO_ADDR},
+ {"data_sent", item_size(data_sent), item_addr(data_sent), INFO_ADDR},
+ {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap),
+ INFO_ADDR},
+ {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port),
+ INFO_ADDR},
+ {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap),
+ INFO_ADDR},
+ {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port),
+ INFO_ADDR},
+#ifdef PCIE
+ {"txbd_rdptr", item_size(txbd_rdptr), item_addr(txbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"txbd_wrptr", item_size(txbd_wrptr), item_addr(txbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"rxbd_rdptr", item_size(rxbd_rdptr), item_addr(rxbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"rxbd_wrptr", item_size(rxbd_wrptr), item_addr(rxbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"eventbd_rdptr", item_size(eventbd_rdptr), item_addr(eventbd_rdptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+ {"eventbd_wrptr", item_size(eventbd_wrptr), item_addr(eventbd_wrptr),
+ INFO_ADDR | (INTF_PCIE << 8)},
+#endif
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received), INFO_ADDR},
+ {"event_received", item_size(event_received), item_addr(event_received),
+ INFO_ADDR},
+
+#ifdef USB
+ {"tx_cmd_urb_pending", item_card_size(tx_cmd_urb_pending),
+ item_card_addr(tx_cmd_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+ {"tx_data_urb_pending", item_card_size(tx_data_urb_pending),
+ item_card_addr(tx_data_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#ifdef USB_CMD_DATA_EP
+ {"rx_cmd_urb_pending", item_card_size(rx_cmd_urb_pending),
+ item_card_addr(rx_cmd_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#endif
+ {"rx_data_urb_pending", item_card_size(rx_data_urb_pending),
+ item_card_addr(rx_data_urb_pending), CARD_ADDR | (INTF_USB << 8)},
+#endif /* USB */
+ {"num_tx_timeout", item_priv_size(num_tx_timeout),
+ item_priv_addr(num_tx_timeout), PRIV_ADDR},
+ {"ioctl_pending", item_handle_size(ioctl_pending),
+ item_handle_addr(ioctl_pending), HANDLE_ADDR},
+ {"tx_pending", item_handle_size(tx_pending),
+ item_handle_addr(tx_pending), HANDLE_ADDR},
+ {"rx_pending", item_handle_size(rx_pending),
+ item_handle_addr(rx_pending), HANDLE_ADDR},
+ {"lock_count", item_handle_size(lock_count),
+ item_handle_addr(lock_count), HANDLE_ADDR},
+ {"malloc_count", item_handle_size(malloc_count),
+ item_handle_addr(malloc_count), HANDLE_ADDR},
+ {"vmalloc_count", item_handle_size(vmalloc_count),
+ item_handle_addr(vmalloc_count), HANDLE_ADDR},
+ {"mbufalloc_count", item_handle_size(mbufalloc_count),
+ item_handle_addr(mbufalloc_count), HANDLE_ADDR},
+#ifdef PCIE
+ {"malloc_cons_count", item_handle_size(malloc_cons_count),
+ item_handle_addr(malloc_cons_count), HANDLE_ADDR | (INTF_PCIE << 8)},
+#endif
+ {"main_state", item_handle_size(main_state),
+ item_handle_addr(main_state), HANDLE_ADDR},
+ {"driver_state", item_handle_size(driver_state),
+ item_handle_addr(driver_state), HANDLE_ADDR},
+#ifdef SDIO_MMC_DEBUG
+ {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w),
+ HANDLE_ADDR | (INTF_SD << 8)},
+ {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r),
+ HANDLE_ADDR | (INTF_SD << 8)},
+#endif
+ {"hs_skip_count", item_handle_size(hs_skip_count),
+ item_handle_addr(hs_skip_count), HANDLE_ADDR},
+ {"hs_force_count", item_handle_size(hs_force_count),
+ item_handle_addr(hs_force_count), HANDLE_ADDR},
+};
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief This function reset histogram data
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void woal_hist_do_reset(moal_private *priv, void *data)
+{
+ hgm_data *phist_data = (hgm_data *)data;
+ int ix;
+ t_u16 rx_rate_max_size = priv->phandle->card_info->rx_rate_max;
+
+ if (!phist_data)
+ return;
+ atomic_set(&(phist_data->num_samples), 0);
+ for (ix = 0; ix < rx_rate_max_size; ix++)
+ atomic_set(&(phist_data->rx_rate[ix]), 0);
+ for (ix = 0; ix < SNR_MAX; ix++)
+ atomic_set(&(phist_data->snr[ix]), 0);
+ for (ix = 0; ix < NOISE_FLR_MAX; ix++)
+ atomic_set(&(phist_data->noise_flr[ix]), 0);
+ for (ix = 0; ix < SIG_STRENGTH_MAX; ix++)
+ atomic_set(&(phist_data->sig_str[ix]), 0);
+}
+
+/**
+ * @brief This function reset all histogram data
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void woal_hist_data_reset(moal_private *priv)
+{
+ int i = 0;
+ for (i = 0; i < priv->phandle->card_info->histogram_table_num; i++)
+ woal_hist_do_reset(priv, priv->hist_data[i]);
+}
+/**
+ * @brief This function reset histogram data according to antenna
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void woal_hist_reset_table(moal_private *priv, t_u8 antenna)
+{
+ hgm_data *phist_data = priv->hist_data[antenna];
+
+ woal_hist_do_reset(priv, phist_data);
+}
+
+/** NF calculation */
+#define CAL_NF(NF) ((t_s8)(-(t_s8)(NF)))
+/** RSSI calculation */
+#define CAL_RSSI(SNR, NF) ((t_s8)((t_s8)(SNR) + CAL_NF(NF)))
+
+/**
+ * @brief This function set histogram data
+ *
+ * @param priv A pointer to moal_private
+ * @param rx_rate rx rate
+ * @param snr snr
+ * @param nflr NF
+ *
+ * @return N/A
+ */
+static void woal_hist_data_set(moal_private *priv, t_u16 rx_rate, t_s8 snr,
+ t_s8 nflr, t_u8 antenna)
+{
+ hgm_data *phist_data = priv->hist_data[antenna];
+ t_s8 nf = CAL_NF(nflr);
+ t_s8 rssi = CAL_RSSI(snr, nflr);
+
+ atomic_inc(&(phist_data->num_samples));
+ if (rx_rate < priv->phandle->card_info->rx_rate_max)
+ atomic_inc(&(phist_data->rx_rate[rx_rate]));
+ atomic_inc(&(phist_data->snr[snr + 128]));
+ atomic_inc(&(phist_data->noise_flr[nf + 128]));
+ atomic_inc(&(phist_data->sig_str[rssi + 128]));
+}
+
+/**
+ * @brief This function add histogram data
+ *
+ * @param priv A pointer to moal_private
+ * @param rx_rate rx rate
+ * @param snr snr
+ * @param nflr NF
+ *
+ * @return N/A
+ */
+void woal_hist_data_add(moal_private *priv, t_u16 rx_rate, t_s8 snr, t_s8 nflr,
+ t_u8 antenna)
+{
+ hgm_data *phist_data = NULL;
+ unsigned long curr_size;
+
+ if ((antenna + 1) > priv->phandle->card_info->histogram_table_num)
+ antenna = 0;
+ phist_data = priv->hist_data[antenna];
+ curr_size = atomic_read(&(phist_data->num_samples));
+ if (curr_size > HIST_MAX_SAMPLES)
+ woal_hist_reset_table(priv, antenna);
+ woal_hist_data_set(priv, rx_rate, snr, nflr, antenna);
+}
+#define MAX_MCS_NUM_SUPP 16
+#define MAX_MCS_NUM_AC 10
+#define MAX_MCS_NUM_AX 12
+#define RATE_INDEX_MCS0 12
+/**
+ * @brief histogram info in proc
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int woal_histogram_info(struct seq_file *sfp, void *data)
+{
+ hgm_data *phist_data = (hgm_data *)data;
+ int i = 0;
+ int value = 0;
+ t_bool sgi_enable = 0;
+ t_u8 bw = 0;
+ t_u8 mcs_index = 0;
+ t_u8 nss = 0;
+ t_u8 gi = 0;
+ wlan_hist_proc_data *hist_data = (wlan_hist_proc_data *)sfp->private;
+ moal_private *priv = (moal_private *)hist_data->priv;
+ t_u16 rx_rate_max_size = priv->phandle->card_info->rx_rate_max;
+
+ ENTER();
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ seq_printf(sfp, "total samples = %d \n",
+ atomic_read(&(phist_data->num_samples)));
+ seq_printf(sfp, "rx rates (in Mbps):\n");
+ seq_printf(sfp, "\t0-3: B-MCS 0-3\n");
+ seq_printf(sfp, "\t4-11: G-MCS 0-7\n");
+ seq_printf(
+ sfp,
+ "\t12-27: N-MCS 0-15(BW20) 28-43: N-MCS 0-15(BW40)\n");
+ seq_printf(
+ sfp,
+ "\t44-59: N-MCS 0-15(BW20:SGI) 60-75: N-MCS 0-15(BW40:SGI)\n");
+ seq_printf(
+ sfp,
+ "\t76-85: AC-MCS 0-9(VHT:BW20:NSS1) 86-95: AC-MCS 0-9(VHT:BW20:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t96-105: AC-MCS 0-9(VHT:BW40:NSS1) 106-115: AC-MCS 0-9(VHT:BW40:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t116-125: AC-MCS 0-9(VHT:BW80:NSS1) 126-135: AC-MCS 0-9(VHT:BW80:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t136-145: AC-MCS 0-9(VHT:BW20:NSS1:SGI) 146-155: AC-MCS 0-9(VHT:BW20:NSS2:SGI)\n");
+ seq_printf(
+ sfp,
+ "\t156-165: AC-MCS 0-9(VHT:BW40:NSS1:SGI) 166-175: AC-MCS 0-9(VHT:BW40:NSS2:SGI)\n");
+ seq_printf(
+ sfp,
+ "\t176-185: AC-MCS 0-9(VHT:BW80:NSS1:SGI) 186-195: AC-MCS 0-9(VHT:BW80:NSS2:SGI)\n\n");
+ seq_printf(
+ sfp,
+ "\t196-207: AX-MCS 0-11(BW20:NSS1) 208-219: AX-MCS 0-11(BW20:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t220-231: AX-MCS 0-11(BW40:NSS1) 232-243: AX-MCS 0-11(BW40:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t244-255: AX-MCS 0-11(BW80:NSS1) 256-267: AX-MCS 0-11(BW80:NSS2)\n");
+ seq_printf(
+ sfp,
+ "\t268-279: AX-MCS 0-11(BW20:NSS1:GI1) 280-291: AX-MCS 0-11(BW20:NSS2:GI1)\n");
+ seq_printf(
+ sfp,
+ "\t292-303: AX-MCS 0-11(BW40:NSS1:GI1) 304-315: AX-MCS 0-11(BW40:NSS2:GI1)\n");
+ seq_printf(
+ sfp,
+ "\t316-327: AX-MCS 0-11(BW80:NSS1:GI1) 328-339: AX-MCS 0-11(BW80:NSS2:GI1)\n");
+ seq_printf(
+ sfp,
+ "\t340-351: AX-MCS 0-11(BW20:NSS1:GI2) 352-363: AX-MCS 0-11(BW20:NSS2:GI2)\n");
+ seq_printf(
+ sfp,
+ "\t364-375: AX-MCS 0-11(BW40:NSS1:GI2) 376-387: AX-MCS 0-11(BW40:NSS2:GI2)\n");
+ seq_printf(
+ sfp,
+ "\t388-399: AX-MCS 0-11(BW80:NSS1:GI2) 400-411: AX-MCS 0-11(BW80:NSS2:GI2)\n");
+
+ for (i = 0; i < rx_rate_max_size; i++) {
+ value = atomic_read(&(phist_data->rx_rate[i]));
+ if (value) {
+ if (i <= 11)
+ seq_printf(sfp, "rx_rate[%03d] = %d\n", i,
+ value);
+ else if (i <= 75) {
+ sgi_enable = (i - 12) /
+ (MAX_MCS_NUM_SUPP * 2); // 0:LGI,
+ // 1:SGI
+ bw = ((i - 12) % (MAX_MCS_NUM_SUPP * 2)) /
+ MAX_MCS_NUM_SUPP; // 0:20MHz, 1:40MHz
+ mcs_index = (i - 12) % MAX_MCS_NUM_SUPP;
+ seq_printf(
+ sfp,
+ "rx_rate[%03d] = %d (MCS:%d HT BW:%dMHz%s)\n",
+ i, value, mcs_index, (1 << bw) * 20,
+ sgi_enable ? " SGI" : "");
+ } else if (i <= 195) {
+ sgi_enable = (i - 76) /
+ (MAX_MCS_NUM_AC * 6); // 0:LGI,
+ // 1:SGI
+ bw = ((i - 76) % (MAX_MCS_NUM_AC * 6)) /
+ (MAX_MCS_NUM_AC * 2); // 0:20MHz, 1:40MHz,
+ // 2:80MHz
+ nss = (((i - 76) % (MAX_MCS_NUM_AC * 6)) %
+ (MAX_MCS_NUM_AC * 2)) /
+ MAX_MCS_NUM_AC; // 0:NSS1, 1:NSS2
+ mcs_index = (i - 76) % MAX_MCS_NUM_AC;
+
+ seq_printf(
+ sfp,
+ "rx_rate[%03d] = %d (MCS:%d VHT BW:%dMHz NSS:%d%s)\n",
+ i, value, mcs_index, (1 << bw) * 20,
+ nss + 1, sgi_enable ? " SGI" : "");
+ } else if (i <= 411) {
+ gi = (i - 196) / (MAX_MCS_NUM_AX * 6); // 0,1,2
+ bw = ((i - 196) % (MAX_MCS_NUM_AX * 6)) /
+ (MAX_MCS_NUM_AX * 2); // 0:20MHz, 1:40MHz,
+ // 2:80MHz
+ nss = (((i - 196) % (MAX_MCS_NUM_AX * 6)) %
+ (MAX_MCS_NUM_AX * 2)) /
+ MAX_MCS_NUM_AX; // 0:NSS1, 1:NSS2
+ mcs_index = (i - 196) % MAX_MCS_NUM_AX;
+
+ seq_printf(
+ sfp,
+ "rx_rate[%03d] = %d (MCS:%d AX BW:%dMHz NSS:%d GI:%d)\n",
+ i, value, mcs_index, (1 << bw) * 20,
+ nss + 1, gi);
+ }
+ }
+ }
+ for (i = 0; i < SNR_MAX; i++) {
+ value = atomic_read(&(phist_data->snr[i]));
+ if (value)
+ seq_printf(sfp, "snr[%02ddB] = %d\n", (int)(i - 128),
+ value);
+ }
+ for (i = 0; i < NOISE_FLR_MAX; i++) {
+ value = atomic_read(&(phist_data->noise_flr[i]));
+ if (value)
+ seq_printf(sfp, "noise_flr[%02ddBm] = %d\n",
+ (int)(i - 128), value);
+ }
+ for (i = 0; i < SIG_STRENGTH_MAX; i++) {
+ value = atomic_read(&(phist_data->sig_str[i]));
+ if (value)
+ seq_printf(sfp, "sig_strength[%02ddBm] = %d\n",
+ (int)(i - 128), value);
+ }
+
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Proc read function for histogram
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int woal_histogram_read(struct seq_file *sfp, void *data)
+{
+ wlan_hist_proc_data *hist_data = (wlan_hist_proc_data *)sfp->private;
+ moal_private *priv = (moal_private *)hist_data->priv;
+
+ ENTER();
+ if (!priv) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (hist_data->ant_idx < priv->phandle->card_info->histogram_table_num)
+ woal_histogram_info(sfp, priv->hist_data[hist_data->ant_idx]);
+
+ LEAVE();
+ return 0;
+}
+
+static int woal_histogram_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_histogram_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_histogram_read, PDE(inode)->data);
+#endif
+}
+
+/**
+ * @brief Proc write function for histogram
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param count data number to write
+ * @param off Offset
+ *
+ * @return number of data
+ */
+static ssize_t woal_histogram_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ struct seq_file *sfp = f->private_data;
+ wlan_hist_proc_data *hist_data = (wlan_hist_proc_data *)sfp->private;
+ moal_private *priv = (moal_private *)hist_data->priv;
+ woal_hist_reset_table(priv, hist_data->ant_idx);
+ return count;
+}
+
+/**
+ * @brief Proc read function for log
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int woal_log_read(struct seq_file *sfp, void *data)
+{
+ moal_private *priv = (moal_private *)sfp->private;
+ mlan_ds_get_stats stats;
+ int i = 0;
+ ENTER();
+ if (!priv) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ memset(&stats, 0x00, sizeof(stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ PRINTM(MERROR,
+ "woal_log_read: Get log: Failed to get stats info!");
+ MODULE_PUT;
+ LEAVE();
+ return -EFAULT;
+ }
+
+ seq_printf(sfp, "dot11GroupTransmittedFrameCount = %d\n",
+ stats.mcast_tx_frame);
+ seq_printf(sfp, "dot11FailedCount = %d\n", stats.failed);
+ seq_printf(sfp, "dot11RetryCount = %d\n", stats.retry);
+ seq_printf(sfp, "dot11MultipleRetryCount = %d\n", stats.multi_retry);
+ seq_printf(sfp, "dot11FrameDuplicateCount = %d\n", stats.frame_dup);
+ seq_printf(sfp, "dot11RTSSuccessCount = %d\n", stats.rts_success);
+ seq_printf(sfp, "dot11RTSFailureCount = %d\n", stats.rts_failure);
+ seq_printf(sfp, "dot11ACKFailureCount = %d\n", stats.ack_failure);
+ seq_printf(sfp, "dot11ReceivedFragmentCount = %d\n", stats.rx_frag);
+ seq_printf(sfp, "dot11GroupReceivedFrameCount = %d\n",
+ stats.mcast_rx_frame);
+ seq_printf(sfp, "dot11FCSErrorCount = %d\n", stats.fcs_error);
+ seq_printf(sfp, "dot11TransmittedFrameCount = %d\n", stats.tx_frame);
+ seq_printf(sfp, "wepicverrcnt-1 = %d\n", stats.wep_icv_error[0]);
+ seq_printf(sfp, "wepicverrcnt-2 = %d\n", stats.wep_icv_error[1]);
+ seq_printf(sfp, "wepicverrcnt-3 = %d\n", stats.wep_icv_error[2]);
+ seq_printf(sfp, "wepicverrcnt-4 = %d\n", stats.wep_icv_error[3]);
+ seq_printf(sfp, "beaconReceivedCount = %d\n", stats.bcn_rcv_cnt);
+ seq_printf(sfp, "beaconMissedCount = %d\n", stats.bcn_miss_cnt);
+ if (stats.amsdu_rx_cnt)
+ seq_printf(sfp, "ReceivedMSDUinPerAMSDU = %d\n",
+ stats.msdu_in_rx_amsdu_cnt / stats.amsdu_rx_cnt);
+ seq_printf(sfp, "ReceivedMSDUinAMSDUCount = %d\n",
+ stats.msdu_in_rx_amsdu_cnt);
+ if (stats.amsdu_tx_cnt)
+ seq_printf(sfp, "TransmitMSDUinPerAMSDU = %d\n",
+ stats.msdu_in_tx_amsdu_cnt / stats.amsdu_tx_cnt);
+ seq_printf(sfp, "TransmitMSDUinAMSDUCount = %d\n",
+ stats.msdu_in_tx_amsdu_cnt);
+ if (priv->phandle->fw_getlog_enable) {
+ seq_printf(sfp, "dot11TransmittedFragmentCount = %u\n",
+ stats.tx_frag_cnt);
+ seq_printf(sfp, "dot11QosTransmittedFragmentCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_tx_frag_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosFailedCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_failed_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosRetryCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_retry_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosMultipleRetryCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_multi_retry_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosFrameDuplicateCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_frm_dup_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosRTSSuccessCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_rts_suc_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosRTSFailureCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_rts_failure_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosACKFailureCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_ack_failure_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosReceivedFragmentCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_rx_frag_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosTransmittedFrameCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_tx_frm_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosDiscardedFrameCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_discarded_frm_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosMPDUsReceivedCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_mpdus_rx_cnt[i]);
+ }
+ seq_printf(sfp, "\ndot11QosRetriesReceivedCount = ");
+ for (i = 0; i < 8; i++) {
+ seq_printf(sfp, "%u ", stats.qos_retries_rx_cnt[i]);
+ }
+ seq_printf(sfp,
+ "\ndot11RSNAStatsCMACICVErrors = %u\n"
+ "dot11RSNAStatsCMACReplays = %u\n"
+ "dot11RSNAStatsRobustMgmtCCMPReplays = %u\n"
+ "dot11RSNAStatsTKIPICVErrors = %u\n"
+ "dot11RSNAStatsTKIPReplays = %u\n"
+ "dot11RSNAStatsCCMPDecryptErrors = %u\n"
+ "dot11RSNAstatsCCMPReplays = %u\n"
+ "dot11TransmittedAMSDUCount = %u\n"
+ "dot11FailedAMSDUCount = %u\n"
+ "dot11RetryAMSDUCount = %u\n"
+ "dot11MultipleRetryAMSDUCount = %u\n"
+ "dot11TransmittedOctetsInAMSDUCount = %llu\n"
+ "dot11AMSDUAckFailureCount = %u\n"
+ "dot11ReceivedAMSDUCount = %u\n"
+ "dot11ReceivedOctetsInAMSDUCount = %llu\n"
+ "dot11TransmittedAMPDUCount = %u\n"
+ "dot11TransmittedMPDUsInAMPDUCount = %u\n"
+ "dot11TransmittedOctetsInAMPDUCount = %llu\n"
+ "dot11AMPDUReceivedCount = %u\n"
+ "dot11MPDUInReceivedAMPDUCount = %u\n"
+ "dot11ReceivedOctetsInAMPDUCount = %llu\n"
+ "dot11AMPDUDelimiterCRCErrorCount = %u\n",
+ stats.cmacicv_errors, stats.cmac_replays,
+ stats.mgmt_ccmp_replays, stats.tkipicv_errors,
+ stats.tkip_replays, stats.ccmp_decrypt_errors,
+ stats.ccmp_replays, stats.tx_amsdu_cnt,
+ stats.failed_amsdu_cnt, stats.retry_amsdu_cnt,
+ stats.multi_retry_amsdu_cnt,
+ stats.tx_octets_in_amsdu_cnt,
+ stats.amsdu_ack_failure_cnt, stats.rx_amsdu_cnt,
+ stats.rx_octets_in_amsdu_cnt, stats.tx_ampdu_cnt,
+ stats.tx_mpdus_in_ampdu_cnt,
+ stats.tx_octets_in_ampdu_cnt, stats.ampdu_rx_cnt,
+ stats.mpdu_in_rx_ampdu_cnt,
+ stats.rx_octets_in_ampdu_cnt,
+ stats.ampdu_delimiter_crc_error_cnt);
+ }
+
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Proc read function for log
+ *
+ * @param inode pointer to inode
+ * @param file file pointer
+ *
+ * @return number of data
+ */
+static int woal_log_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_log_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_log_read, PDE(inode)->data);
+#endif
+}
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return Number of output data or MLAN_STATUS_FAILURE
+ */
+static int woal_debug_read(struct seq_file *sfp, void *data)
+{
+ int val = 0;
+ unsigned int i;
+
+ struct debug_data_priv *items_priv =
+ (struct debug_data_priv *)sfp->private;
+ struct debug_data *d = items_priv->items;
+ moal_private *priv = items_priv->priv;
+ mlan_debug_info *info = NULL;
+ t_u32 intf_mask = INTF_MASK << 8;
+#ifdef SDIO
+ unsigned int j;
+ t_u8 mp_aggr_pkt_limit = 0;
+#endif
+
+ ENTER();
+
+ if (priv == NULL) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ info = &(priv->phandle->debug_info);
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ priv->phandle->driver_state = woal_check_driver_status(priv->phandle);
+ /* Get debug information */
+ if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info))
+ goto exit;
+
+ for (i = 0; i < (unsigned int)items_priv->num_of_items; i++) {
+ /* If this item is interface specific but card interface is NOT
+ * correspond type, we will not count it. */
+ if ((d[i].attr & intf_mask) &&
+ !((d[i].attr & intf_mask) &
+ (priv->phandle->card_type & intf_mask)))
+ continue;
+
+ if (d[i].size == 1)
+ val = *((t_u8 *)d[i].addr);
+ else if (d[i].size == 2)
+ val = *((t_u16 *)d[i].addr);
+ else if (d[i].size == 4)
+ val = *((t_u32 *)d[i].addr);
+ else {
+ unsigned int j;
+ seq_printf(sfp, "%s=", d[i].name);
+ for (j = 0; j < d[i].size; j += 2) {
+ val = *(t_u16 *)(d[i].addr + j);
+ seq_printf(sfp, "0x%x ", val);
+ }
+ seq_printf(sfp, "\n");
+ continue;
+ }
+ if (strstr(d[i].name, "id") || strstr(d[i].name, "bitmap")
+#ifdef PCIE
+ || strstr(d[i].name, "ptr")
+#endif
+ )
+ seq_printf(sfp, "%s=0x%x\n", d[i].name, val);
+ else
+ seq_printf(sfp, "%s=%d\n", d[i].name, val);
+ }
+#ifdef SDIO
+ if (IS_SD(priv->phandle->card_type)) {
+ mp_aggr_pkt_limit = info->mp_aggr_pkt_limit;
+ seq_printf(sfp, "last_recv_wr_bitmap=0x%x last_mp_index=%d\n",
+ info->last_recv_wr_bitmap, info->last_mp_index);
+ for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
+ seq_printf(
+ sfp,
+ "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n",
+ info->last_mp_wr_bitmap[i],
+ info->last_mp_wr_ports[i],
+ info->last_mp_wr_len[i],
+ info->last_curr_wr_port[i]);
+ for (j = 0; j < mp_aggr_pkt_limit; j++) {
+ seq_printf(sfp, "0x%02x ",
+ info->last_mp_wr_info
+ [i * mp_aggr_pkt_limit + j]);
+ }
+ seq_printf(sfp, "\n");
+ }
+ seq_printf(sfp, "SDIO MPA Tx: ");
+ for (i = 0; i < mp_aggr_pkt_limit; i++)
+ seq_printf(sfp, "%d ", info->mpa_tx_count[i]);
+ seq_printf(sfp, "\n");
+ seq_printf(sfp, "SDIO MPA Rx: ");
+ for (i = 0; i < mp_aggr_pkt_limit; i++)
+ seq_printf(sfp, "%d ", info->mpa_rx_count[i]);
+ seq_printf(sfp, "\n");
+ seq_printf(sfp, "SDIO MP Update: ");
+ for (i = 0; i < (mp_aggr_pkt_limit * 2); i++)
+ seq_printf(sfp, "%d ", info->mp_update[i]);
+ seq_printf(sfp, "\n");
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ seq_printf(sfp, "last_wr_index:%d\n",
+ info->txbd_wrptr & (MLAN_MAX_TXRX_BD - 1));
+ seq_printf(sfp, "Tx pkt size:\n");
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ seq_printf(sfp, "%04d ", info->last_tx_pkt_size[i]);
+ if ((i + 1) % 16 == 0)
+ seq_printf(sfp, "\n");
+ }
+ }
+#endif
+ seq_printf(sfp, "tcp_ack_drop_cnt=%d\n", priv->tcp_ack_drop_cnt);
+ seq_printf(sfp, "tcp_ack_cnt=%d\n", priv->tcp_ack_cnt);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ for (i = 0; i < 4; i++)
+ seq_printf(sfp, "wmm_tx_pending[%d]:%d\n", i,
+ atomic_read(&priv->wmm_tx_pending[i]));
+#endif
+ if (info->tx_tbl_num) {
+ seq_printf(sfp, "Tx BA stream table:\n");
+ for (i = 0; i < info->tx_tbl_num; i++) {
+ seq_printf(
+ sfp,
+ "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x amsdu=%d\n",
+ (int)info->tx_tbl[i].tid, info->tx_tbl[i].ra[0],
+ info->tx_tbl[i].ra[1], info->tx_tbl[i].ra[2],
+ info->tx_tbl[i].ra[3], info->tx_tbl[i].ra[4],
+ info->tx_tbl[i].ra[5],
+ (int)info->tx_tbl[i].amsdu);
+ }
+ }
+ if (info->rx_tbl_num) {
+ seq_printf(sfp, "Rx reorder table:\n");
+ for (i = 0; i < info->rx_tbl_num; i++) {
+ unsigned int j;
+
+ seq_printf(
+ sfp,
+ "tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, "
+ "win_size = %d, amsdu=%d\n",
+ (int)info->rx_tbl[i].tid, info->rx_tbl[i].ta[0],
+ info->rx_tbl[i].ta[1], info->rx_tbl[i].ta[2],
+ info->rx_tbl[i].ta[3], info->rx_tbl[i].ta[4],
+ info->rx_tbl[i].ta[5],
+ (int)info->rx_tbl[i].start_win,
+ (int)info->rx_tbl[i].win_size,
+ (int)info->rx_tbl[i].amsdu);
+ seq_printf(sfp, "buffer: ");
+ for (j = 0; j < info->rx_tbl[i].win_size; j++) {
+ if (info->rx_tbl[i].buffer[j] == MTRUE)
+ seq_printf(sfp, "1 ");
+ else
+ seq_printf(sfp, "0 ");
+ }
+ seq_printf(sfp, "\n");
+ }
+ }
+ for (i = 0; i < info->ralist_num; i++) {
+ seq_printf(
+ sfp,
+ "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
+ info->ralist[i].ra[0], info->ralist[i].ra[1],
+ info->ralist[i].ra[2], info->ralist[i].ra[3],
+ info->ralist[i].ra[4], info->ralist[i].ra[5],
+ info->ralist[i].tid, info->ralist[i].total_pkts,
+ info->ralist[i].tx_pause);
+ }
+
+exit:
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param count data number to write
+ * @param off Offset
+ *
+ * @return number of data
+ */
+static ssize_t woal_debug_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct seq_file *sfp = f->private_data;
+ struct debug_data_priv *items_priv =
+ (struct debug_data_priv *)sfp->private;
+ struct debug_data *d = items_priv->items;
+ moal_private *priv = items_priv->priv;
+ mlan_debug_info *info = &(priv->phandle->debug_info);
+#ifdef DEBUG_LEVEL1
+ t_u32 last_drvdbg = drvdbg;
+#endif
+ gfp_t flag;
+
+ ENTER();
+
+ if (MODULE_GET == 0) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ pdata = kzalloc(count + 1, flag);
+ if (pdata == NULL) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ if (copy_from_user(pdata, buf, count)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+ pdata[count] = '\0';
+
+ if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
+ kfree(pdata);
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < items_priv->num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = woal_string_to_number(p2);
+ if (d[i].size == 1)
+ *((t_u8 *)d[i].addr) = (t_u8)r;
+ else if (d[i].size == 2)
+ *((t_u16 *)d[i].addr) = (t_u16)r;
+ else if (d[i].size == 4)
+ *((t_u32 *)d[i].addr) = (t_u32)r;
+ break;
+ } while (MTRUE);
+ }
+ kfree(pdata);
+
+#ifdef DEBUG_LEVEL1
+ if (last_drvdbg != drvdbg)
+ woal_set_drvdbg(priv, drvdbg);
+#endif
+
+ MODULE_PUT;
+ LEAVE();
+ return count;
+}
+
+static int woal_debug_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_debug_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_debug_read, PDE(inode)->data);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops debug_proc_fops = {
+ .proc_open = woal_debug_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = woal_debug_write,
+};
+#else
+static const struct file_operations debug_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_debug_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = woal_debug_write,
+};
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops histogram_proc_fops = {
+ .proc_open = woal_histogram_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = woal_histogram_write,
+};
+#else
+static const struct file_operations histogram_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_histogram_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = woal_histogram_write,
+};
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops log_proc_fops = {
+ .proc_open = woal_log_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+#else
+static const struct file_operations log_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_log_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Create debug proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void woal_debug_entry(moal_private *priv)
+{
+ struct proc_dir_entry *r;
+ int i;
+ char hist_entry[50];
+ struct debug_data *d = NULL;
+
+ ENTER();
+
+ if (priv->proc_entry == NULL) {
+ LEAVE();
+ return;
+ }
+
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->items_priv.items = kmalloc(sizeof(items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR,
+ "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ moal_memcpy_ext(priv->phandle, priv->items_priv.items, items,
+ sizeof(items), sizeof(items));
+ priv->items_priv.num_of_items = ARRAY_SIZE(items);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->items_priv.items = kmalloc(sizeof(uap_items), GFP_KERNEL);
+ if (!priv->items_priv.items) {
+ PRINTM(MERROR,
+ "Failed to allocate memory for debug data\n");
+ LEAVE();
+ return;
+ }
+ moal_memcpy_ext(priv->phandle, priv->items_priv.items,
+ uap_items, sizeof(uap_items),
+ sizeof(uap_items));
+ priv->items_priv.num_of_items = ARRAY_SIZE(uap_items);
+ }
+#endif
+
+ priv->items_priv.priv = priv;
+
+ d = priv->items_priv.items;
+ for (i = 0; i < priv->items_priv.num_of_items; i++) {
+ if (IS_INFO_ADDR(d[i].attr))
+ d[i].addr += (t_ptr) & (priv->phandle->debug_info);
+ else if (IS_HANDLE_ADDR(d[i].attr))
+ d[i].addr += (t_ptr)(priv->phandle);
+ else if (IS_PRIV_ADDR(d[i].attr))
+ d[i].addr += (t_ptr)(priv);
+ else if (IS_CARD_ADDR(d[i].attr))
+ d[i].addr += (t_ptr)(priv->phandle->card);
+ }
+
+ /* Create proc entry */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ r = proc_create_data("debug", 0644, priv->proc_entry, &debug_proc_fops,
+ &priv->items_priv);
+ if (r == NULL)
+#else
+ r = create_proc_entry("debug", 0644, priv->proc_entry);
+ if (r) {
+ r->data = &priv->items_priv;
+ r->proc_fops = &debug_proc_fops;
+ } else
+#endif
+ {
+ PRINTM(MMSG, "Fail to create proc debug entry\n");
+ LEAVE();
+ return;
+ }
+ if (priv->bss_type == MLAN_BSS_TYPE_STA ||
+ priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ priv->hist_entry = proc_mkdir("histogram", priv->proc_entry);
+ if (!priv->hist_entry) {
+ PRINTM(MERROR, "Fail to mkdir histogram!\n");
+ LEAVE();
+ return;
+ }
+ for (i = 0; i < priv->phandle->card_info->histogram_table_num;
+ i++) {
+ priv->hist_proc[i].ant_idx = i;
+ priv->hist_proc[i].priv = priv;
+ snprintf(hist_entry, sizeof(hist_entry), "wlan-ant%d",
+ i);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ r = proc_create_data(hist_entry, 0644, priv->hist_entry,
+ &histogram_proc_fops,
+ &priv->hist_proc[i]);
+ if (r == NULL)
+#else
+ r = create_proc_entry("histogram", 0644,
+ priv->hist_entry);
+ if (r) {
+ r->data = &priv->hist_proc[i];
+ r->proc_fops = &histogram_proc_fops;
+ } else
+#endif
+ {
+ PRINTM(MMSG,
+ "Fail to create proc histogram entry %s\n",
+ hist_entry);
+ LEAVE();
+ return;
+ }
+ }
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ r = proc_create_data("log", 0644, priv->proc_entry, &log_proc_fops,
+ priv);
+ if (r == NULL)
+#else
+ r = create_proc_entry("log", 0644, priv->proc_entry);
+ if (r) {
+ r->data = priv;
+ r->proc_fops = &log_proc_fops;
+ } else
+#endif
+ {
+ PRINTM(MMSG, "Fail to create proc log entry\n");
+ LEAVE();
+ return;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv A pointer to a moal_private structure
+ *
+ * @return N/A
+ */
+void woal_debug_remove(moal_private *priv)
+{
+ char hist_entry[50];
+ int i;
+ ENTER();
+
+ kfree(priv->items_priv.items);
+ /* Remove proc entry */
+ remove_proc_entry("debug", priv->proc_entry);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA ||
+ priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ for (i = 0; i < priv->phandle->card_info->histogram_table_num;
+ i++) {
+ snprintf(hist_entry, sizeof(hist_entry), "wlan-ant%d",
+ i);
+ remove_proc_entry(hist_entry, priv->hist_entry);
+ }
+ remove_proc_entry("histogram", priv->proc_entry);
+ }
+ remove_proc_entry("log", priv->proc_entry);
+
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.c
new file mode 100644
index 000000000000..60d229b2abbe
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.c
@@ -0,0 +1,16895 @@
+
+/** @file moal_eth_ioctl.c
+ *
+ * @brief This file contains private ioctl functions
+
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 01/05/2012: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_eth_ioctl.h"
+#include "mlan_ioctl.h"
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include "moal_priv.h"
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#ifdef USB
+#include "moal_usb.h"
+#endif
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif
+#ifdef PCIE
+#include "moal_pcie.h"
+#endif
+#ifdef STA_CFG80211
+#include "moal_sta_cfg80211.h"
+#endif
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#include "moal_cfg80211_util.h"
+#endif
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Bands supported in Infra mode */
+static t_u16 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G,
+ BAND_G,
+ BAND_GN,
+ BAND_B | BAND_G | BAND_GN,
+ BAND_G | BAND_GN,
+ BAND_A,
+ BAND_B | BAND_A,
+ BAND_B | BAND_G | BAND_A,
+ BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_AN,
+ BAND_GN | BAND_GAC,
+ BAND_B | BAND_G | BAND_GN | BAND_GAC,
+ BAND_G | BAND_GN | BAND_GAC,
+ BAND_GN | BAND_GAC | BAND_GAX,
+ BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
+ BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC,
+ BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
+ BAND_A | BAND_AN | BAND_AAC,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC |
+ BAND_AAX,
+ BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
+ BAND_A | BAND_AN | BAND_AAC | BAND_AAX,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B,
+ BAND_B | BAND_G,
+ BAND_G,
+ BAND_A,
+};
+
+/********************************************************
+ Global Variables
+********************************************************/
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Parse a string to extract numerical arguments
+ *
+ * @param pos Pointer to the arguments string
+ * @param data Pointer to the arguments buffer
+ * @param datalen Length of the arguments buffer
+ * @param user_data_len Pointer to the number of arguments extracted
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status parse_arguments(t_u8 *pos, int *data, int datalen,
+ int *user_data_len)
+{
+ unsigned int i, j, k;
+ char cdata[10];
+ int is_hex = 0;
+
+ if (strlen(pos) == 0) {
+ *user_data_len = 0;
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ memset(cdata, 0, sizeof(cdata));
+ for (i = 0, j = 0, k = 0; i <= strlen(pos); i++) {
+ if ((k == 0) && (i <= (strlen(pos) - 2))) {
+ if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
+ is_hex = 1;
+ i = i + 2;
+ }
+ }
+ if (pos[i] == '\0' || pos[i] == ' ') {
+ if (j >= datalen) {
+ j++;
+ break;
+ }
+ if (is_hex) {
+ data[j] = woal_atox(cdata);
+ is_hex = 0;
+ } else {
+ woal_atoi(&data[j], cdata);
+ }
+ j++;
+ k = 0;
+ memset(cdata, 0, sizeof(cdata));
+ if (pos[i] == '\0')
+ break;
+ } else {
+ if (k >= sizeof(cdata)) {
+ PRINTM(MERROR, "Invalid numerical arguments\n");
+ break;
+ }
+ cdata[k] = pos[i];
+ k++;
+ }
+ }
+
+ *user_data_len = j;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/** Convert character to integer */
+#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0'))
+/**
+ * @brief Converts a string to hex value
+ *
+ * @param str A pointer to the string
+ * @param raw A pointer to the raw data buffer
+ * @param raw_size raw data buffer size
+ * @return Number of bytes read
+ **/
+int string2raw(unsigned char *str, unsigned char *raw, int raw_size)
+{
+ int len = (strlen(str) + 1) / 2;
+ int i = 0;
+
+ do {
+ if (strlen(str) < 2)
+ return -1;
+ if (!isxdigit(*str) || !isxdigit(*(str + 1)))
+ return -1;
+ *str = toupper(*str);
+ *raw = CHAR2INT(*str) << 4;
+ ++str;
+ *str = toupper(*str);
+ *raw |= CHAR2INT(*str);
+ ++raw;
+ i++;
+ } while (*++str != '\0' && i < raw_size);
+ return len;
+}
+
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+/**
+ * @brief Set wps & p2p ie in AP mode
+ *
+ * @param priv Pointer to priv stucture
+ * @param ie Pointer to ies data
+ * @param len Length of data
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = ie;
+ int ie_len;
+
+ ENTER();
+
+ ie_len = len - 2;
+ if (ie_len <= 0) {
+ PRINTM(MERROR, "IE len error: %d\n", ie_len);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Android cmd format:
+ * "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ * "SET_AP_WPS_P2P_IE 2" -- proberesp IE
+ * "SET_AP_WPS_P2P_IE 4" -- assocresp IE
+ */
+ if (*pos == '1') {
+ /* set the beacon wps/p2p ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(
+ priv, pos, ie_len, NULL, 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (*pos == '2') {
+ /* set the probe resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(
+ priv, NULL, 0, pos, ie_len, NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_RESP, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Failed to set probe resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (*pos == '4') {
+ /* set the assoc resp ies */
+ pos += 2;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(
+ priv, NULL, 0, NULL, 0, pos, ie_len, NULL, 0,
+ MGMT_MASK_ASSOC_RESP, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Failed to set assoc resp ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/**
+ * @brief Set miracast mode
+ *
+ * @param priv Pointer to priv stucture
+ * @param pdata Pointer to cmd buffer
+ * @param len Length of data
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_miracast_mode(moal_private *priv, t_u8 *pdata, size_t len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = pdata;
+
+ ENTER();
+ if (!pos || (len == 0)) {
+ PRINTM(MERROR, "%s: Null buf!\n", __func__);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ while (!isdigit(*pos) && --len > 0)
+ pos++;
+ switch (*pos) {
+ case '0':
+ /* disable miracast mode */
+ priv->phandle->miracast_mode = 0;
+ break;
+ case '1':
+ /* Source */
+ priv->phandle->miracast_mode = 1;
+ break;
+ case '2':
+ /* Sink */
+ priv->phandle->miracast_mode = 2;
+ break;
+ default:
+ PRINTM(MERROR, "%s: Unknown miracast mode (%c)\n",
+ priv->netdev->name, *pos);
+ ret = MLAN_STATUS_FAILURE;
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_get_priv_driver_version(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int len = 0, ret = -1;
+ char buf[MLAN_MAX_VER_STR_LEN];
+
+ ENTER();
+
+ if (!respbuf) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Get version string to local buffer */
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+ len = strlen(buf);
+
+ if (len) {
+ /* Copy back the retrieved version string */
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ ret = MIN(len, (respbuflen - 1));
+ moal_memcpy_ext(priv->phandle, respbuf, buf, ret,
+ respbuflen - 1);
+ } else {
+ ret = -1;
+ PRINTM(MERROR, "Get version failed!\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Hostcmd interface from application
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ * @param wait_option Wait option
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
+ t_u8 wait_option)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD));
+ buf_len = *((t_u32 *)data_ptr);
+ moal_memcpy_ext(priv->phandle, &cmd_header, data_ptr + sizeof(buf_len),
+ sizeof(HostCmd_Header), sizeof(HostCmd_Header));
+
+ PRINTM(MINFO, "Host command len = %d\n",
+ woal_le16_to_cpu(cmd_header.size));
+ if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+ /* get the whole command */
+ moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
+ data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.len,
+ MRVDRV_SIZE_OF_CMD_BUFFER);
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ ret = misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_HOSTCMD);
+ if (ret > respbuflen) {
+ ret = -EFAULT;
+ goto error;
+ }
+ moal_memcpy_ext(
+ priv->phandle, data_ptr + sizeof(buf_len),
+ misc_cfg->param.hostcmd.cmd, misc_cfg->param.hostcmd.len,
+ respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD) +
+ sizeof(buf_len)));
+ moal_memcpy_ext(priv->phandle, data_ptr,
+ (t_u8 *)&misc_cfg->param.hostcmd.len, sizeof(t_u32),
+ sizeof(t_u32));
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure 11ax HE capability or HE operation
+ *
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param len length used
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_setget_priv_11axcmdcfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ax_cmd_cfg *cfg = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int header_len = 0, user_data_len = 0;
+ int data[3] = {0};
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cmd_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_11AX_CFG;
+ req->action = MLAN_ACT_SET;
+
+ cfg = (mlan_ds_11ax_cmd_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_11AX_CMD_CFG;
+
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ PRINTM(MINFO, "data_len=%d,data=%d,%d,%d\n", user_data_len, data[0],
+ data[1], data[2]);
+
+ if (user_data_len > 3 || user_data_len == 0) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EFAULT;
+ goto done;
+ } else if (user_data_len == 1) {
+ req->action = MLAN_ACT_GET;
+ }
+
+ switch (data[0]) {
+ case MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET:
+ cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
+ cfg->param.sr_cfg.type = MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID;
+ cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_obss_pd_offset);
+ cfg->param.sr_cfg.param.obss_pd_offset.offset[0] = data[1];
+ cfg->param.sr_cfg.param.obss_pd_offset.offset[1] = data[2];
+ break;
+ case MLAN_11AXCMD_CFG_ID_SR_ENABLE:
+ cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
+ cfg->param.sr_cfg.type = MRVL_DOT11AX_ENABLE_SR_TLV_ID;
+ cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_sr_control);
+ cfg->param.sr_cfg.param.sr_control.control = data[1];
+ break;
+ case MLAN_11AXCMD_CFG_ID_BEAM_CHANGE:
+ cfg->sub_id = MLAN_11AXCMD_BEAM_SUBID;
+ cfg->param.beam_cfg.value = data[1];
+ break;
+ case MLAN_11AXCMD_CFG_ID_HTC_ENABLE:
+ cfg->sub_id = MLAN_11AXCMD_HTC_SUBID;
+ cfg->param.htc_cfg.value = data[1];
+ break;
+ case MLAN_11AXCMD_CFG_ID_TXOP_RTS:
+ cfg->sub_id = MLAN_11AXCMD_TXOPRTS_SUBID;
+ cfg->param.txop_cfg.rts_thres = data[1];
+ break;
+ case MLAN_11AXCMD_CFG_ID_TX_OMI:
+ cfg->sub_id = MLAN_11AXCMD_TXOMI_SUBID;
+ cfg->param.txomi_cfg.omi = data[1];
+ break;
+ case MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME:
+ cfg->sub_id = MLAN_11AXCMD_OBSS_TOLTIME_SUBID;
+ cfg->param.toltime_cfg.tol_time = data[1];
+ break;
+ default:
+ PRINTM(MERROR, "unknown 11axcmd\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, respbuf, &req->action,
+ sizeof(req->action), sizeof(req->action));
+ respbuf += sizeof(req->action);
+
+ cfg = (mlan_ds_11ax_cmd_cfg *)respbuf;
+ moal_memcpy_ext(priv->phandle, cfg, req->pbuf,
+ sizeof(mlan_ds_11ax_cmd_cfg), respbuflen);
+
+ ret = sizeof(req->action) + sizeof(mlan_ds_11ax_cmd_cfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get range ext mode
+ *
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param len length used
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_setget_priv_range_ext(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[1];
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RANGE_EXT);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RANGE_EXT;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid Parameter\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[0] < 0 || data[0] > 2) {
+ PRINTM(MERROR,
+ "Invalid Parameter: range_ext mode 0-2\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.range_ext_mode = (t_u8)data[0];
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.range_ext_mode;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Custom IE setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_customie(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE));
+
+ custom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, custom_ie,
+ sizeof(mlan_ds_misc_custom_ie),
+ sizeof(mlan_ds_misc_custom_ie));
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ custom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
+ moal_memcpy_ext(priv->phandle, custom_ie, &misc->param.cust_ie,
+ sizeof(mlan_ds_misc_custom_ie),
+ respbuflen -
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE)));
+ ret = sizeof(mlan_ds_misc_custom_ie);
+ if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[3];
+ int user_data_len = 0;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_ds_band_cfg *band_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BANDCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_BANDCFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (user_data_len == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values
+ * from MLAN
+ */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* To support only <b/bg/bgn/n/aac/gac> */
+ infra_band = data[0];
+ for (i = 0; i < (sizeof(SupportedInfraBand) /
+ sizeof(SupportedInfraBand[0]));
+ i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero
+ */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ band_cfg = (mlan_ds_band_cfg *)respbuf;
+
+ moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
+ sizeof(mlan_ds_band_cfg), respbuflen);
+
+ ret = sizeof(mlan_ds_band_cfg);
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_httxcfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTTXCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_HTTXCFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (user_data_len == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A &&
+ data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+
+ if (req->action == MLAN_ACT_GET) {
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, data, sizeof(data), respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n capability information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_htcapinfo(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ woal_ht_cap_info *ht_cap = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTCAPINFO))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_HTCAPINFO),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ cfg_11n->param.htcap_cfg.htcap = data[0];
+ PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (user_data_len == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A &&
+ data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.htcap_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);
+
+ if (req->action == MLAN_ACT_GET) {
+ cfg_11n->param.htcap_cfg.htcap = 0;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[1] = cfg_11n->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
+ }
+
+ ht_cap = (woal_ht_cap_info *)respbuf;
+ ht_cap->ht_cap_info_bg = data[0];
+ ht_cap->ht_cap_info_a = data[1];
+ ret = sizeof(woal_ht_cap_info);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_addbapara(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[5];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ woal_addba *addba = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAPARA))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_ADDBAPARA),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (user_data_len != ARRAY_SIZE(data)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
+ PRINTM(MERROR, "Incorrect addba timeout value.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
+ data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
+ PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
+ PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get add BA parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ cfg_11n->param.addba_param.timeout = data[0];
+ cfg_11n->param.addba_param.txwinsize = data[1];
+ cfg_11n->param.addba_param.rxwinsize = data[2];
+ cfg_11n->param.addba_param.txamsdu = data[3];
+ cfg_11n->param.addba_param.rxamsdu = data[4];
+ PRINTM(MINFO,
+ "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ /* Update add BA parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ addba = (woal_addba *)respbuf;
+
+ addba->time_out = cfg_11n->param.addba_param.timeout;
+ addba->tx_win_size = cfg_11n->param.addba_param.txwinsize;
+ addba->rx_win_size = cfg_11n->param.addba_param.rxwinsize;
+ addba->tx_amsdu = cfg_11n->param.addba_param.txamsdu;
+ addba->rx_amsdu = cfg_11n->param.addba_param.rxamsdu;
+ PRINTM(MINFO,
+ "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
+ addba->time_out, addba->tx_win_size, addba->rx_win_size,
+ addba->tx_amsdu, addba->rx_amsdu);
+
+ ret = sizeof(woal_addba);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Delete selective BA based on parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_delba(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ t_u32 data[2] = {0xFF, 0xFF};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ds_11n_delba *del_ba = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ int header_len = 0;
+ t_u8 *mac_pos = NULL;
+ t_u8 peer_mac[ETH_ALEN] = {0};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELBA);
+
+ if (strlen(respbuf) == header_len) {
+ /* Incorrect number of arguments */
+ PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mac_pos = strstr(respbuf + header_len, " ");
+ if (mac_pos)
+ mac_pos = strstr(mac_pos + 1, " ");
+ if (mac_pos) {
+#define MAC_STRING_LENGTH 17
+ if (strlen(mac_pos + 1) != MAC_STRING_LENGTH) {
+ PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
+ ret = -EINVAL;
+ goto done;
+ }
+ woal_mac2u8(peer_mac, mac_pos + 1);
+ *mac_pos = '\0';
+ }
+
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (mac_pos)
+ user_data_len++;
+
+ if (user_data_len > 3 || (!(data[0] & (DELBA_TX | DELBA_RX))) ||
+ (data[1] != DELBA_ALL_TIDS && !(data[1] <= 7))) {
+ /* Incorrect number of arguments */
+ PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA;
+
+ del_ba = &cfg_11n->param.del_ba;
+ memset(del_ba, 0, sizeof(mlan_ds_11n_delba));
+ del_ba->direction = (t_u8)data[0];
+ del_ba->tid = DELBA_ALL_TIDS;
+ if (user_data_len > 1)
+ del_ba->tid = (t_u8)data[1];
+ if (user_data_len > 2)
+ moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, peer_mac,
+ ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sprintf(respbuf, "OK. BA deleted successfully.\n") + 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get the reject addba requst conditions
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_rejectaddbareq(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[1];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_REJECTADDBAREQ))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_REJECTADDBAREQ),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_REJECT_ADDBA_REQ;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get the reject addba req conditions*/
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set the reject addba req conditions */
+ cfg_11n->param.reject_addba_req.conditions = data[0];
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (req->action == MLAN_ACT_GET) {
+ sprintf(respbuf, "0x%x",
+ cfg_11n->param.reject_addba_req.conditions);
+ ret = strlen(respbuf) + 1;
+ } else {
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get the addba reject setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param addba_reject A pointer to addba_reject array.
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_ioctl_addba_reject(moal_private *priv, t_u32 action,
+ t_u8 *addba_reject)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, cfg_11n->param.addba_reject,
+ addba_reject,
+ sizeof(cfg_11n->param.addba_reject),
+ sizeof(cfg_11n->param.addba_reject));
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, addba_reject,
+ cfg_11n->param.addba_reject,
+ sizeof(cfg_11n->param.addba_reject),
+ MAX_NUM_TID);
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get addba prio_tbl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param aggr_prio_tbl A pointer to mlan_ds_11n_aggr_prio_tbl.
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action,
+ mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &cfg_11n->param.aggr_prio_tbl,
+ aggr_prio_tbl,
+ sizeof(mlan_ds_11n_aggr_prio_tbl),
+ sizeof(mlan_ds_11n_aggr_prio_tbl));
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, aggr_prio_tbl,
+ &cfg_11n->param.aggr_prio_tbl,
+ sizeof(mlan_ds_11n_aggr_prio_tbl),
+ sizeof(mlan_ds_11n_aggr_prio_tbl));
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get addba_param
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param addba_param A pointer to mlan_ds_11n_addba_param.
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_ioctl_addba_param(moal_private *priv, t_u32 action,
+ mlan_ds_11n_addba_param *addba_param)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &cfg_11n->param.addba_param,
+ addba_param, sizeof(mlan_ds_11n_addba_param),
+ sizeof(mlan_ds_11n_addba_param));
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, addba_param,
+ &cfg_11n->param.addba_param,
+ sizeof(mlan_ds_11n_addba_param),
+ sizeof(mlan_ds_11n_addba_param));
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configuring rx block-ack window size
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise failure
+ */
+int woal_set_rx_ba_winsize(moal_private *priv, t_u8 *respbuf, int respbuflen)
+{
+ int data[2];
+ t_u8 addba_reject[MAX_NUM_TID];
+ mlan_ds_11n_addba_param addba_param;
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ memset((char *)data, 0, sizeof(data));
+ if (respbuf && strlen(respbuf) > 0)
+ parse_arguments(respbuf, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len != 2) {
+ PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] > 7 || data[0] < 0) {
+ PRINTM(MERROR, "Invalid tid %d\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[1] < 0) {
+ PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(addba_reject, 0, sizeof(addba_reject));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_reject(priv, MLAN_ACT_GET, addba_reject)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* disable tx ba */
+ if (data[1] == 0) {
+ addba_reject[data[0]] = MTRUE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_reject(priv, MLAN_ACT_SET, addba_reject))
+ ret = -EFAULT;
+ } else {
+ if (addba_reject[data[0]] == MTRUE) {
+ addba_reject[data[0]] = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_reject(priv, MLAN_ACT_SET,
+ addba_reject)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ memset(&addba_param, 0, sizeof(addba_param));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[1] != addba_param.rxwinsize) {
+ addba_param.rxwinsize = data[1];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_param(priv, MLAN_ACT_SET,
+ &addba_param))
+ ret = -EFAULT;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Configuring trx block-ack window size
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise failure
+ */
+int woal_set_tx_ba_winsize(moal_private *priv, t_u8 *respbuf, int respbuflen)
+{
+ int data[2];
+ mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
+ mlan_ds_11n_addba_param addba_param;
+ t_u8 tos_to_tid_inv[] = {0x02, 0x00, 0x01, 0x03,
+ 0x04, 0x05, 0x06, 0x07};
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ memset((char *)data, 0, sizeof(data));
+ if (respbuf && strlen(respbuf) > 0)
+ parse_arguments(respbuf, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len != 2) {
+ PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] > 7 || data[0] < 0) {
+ PRINTM(MERROR, "Invalid tid %d\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[1] < 0) {
+ PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* disable tx ba */
+ if (data[1] == 0) {
+ if (aggr_prio_tbl.ampdu[data[0]] != 0xff) {
+ aggr_prio_tbl.ampdu[data[0]] = 0xff;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
+ &aggr_prio_tbl))
+ ret = -EFAULT;
+ }
+ } else {
+ if (aggr_prio_tbl.ampdu[data[0]] == 0xff) {
+ aggr_prio_tbl.ampdu[data[0]] = tos_to_tid_inv[data[0]];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
+ &aggr_prio_tbl)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ memset(&addba_param, 0, sizeof(addba_param));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[1] != addba_param.txwinsize) {
+ addba_param.txwinsize = data[1];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_ioctl_addba_param(priv, MLAN_ACT_SET,
+ &addba_param))
+ ret = -EFAULT;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get aggregation priority table configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_aggrpriotbl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[MAX_NUM_TID * 2], i, j;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRPRIOTBL))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_AGGRPRIOTBL),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (user_data_len != ARRAY_SIZE(data)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
+ if ((data[i] > 7 && data[i] != 0xff) ||
+ (data[i + 1] > 7 && data[i + 1] != 0xff)) {
+ PRINTM(MERROR,
+ "Invalid priority, valid value 0-7 or 0xff.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
+ }
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ for (i = 0, j = 0; i < (MAX_NUM_TID * 2); i = i + 2, ++j) {
+ respbuf[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
+ respbuf[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
+ }
+
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Add BA reject configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_addbareject(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[MAX_NUM_TID], i;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAREJECT))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_ADDBAREJECT),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (user_data_len != ARRAY_SIZE(data)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0; i < user_data_len; i++) {
+ if (data[i] != 0 && data[i] != 1) {
+ PRINTM(MERROR,
+ "addba reject only takes argument as 0 or 1\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (user_data_len == 0) {
+ /* Get add BA reject configuration from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ for (i = 0; i < user_data_len; i++)
+ cfg_11n->param.addba_reject[i] = data[i];
+ /* Update add BA reject configuration in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ respbuf[i] = cfg_11n->param.addba_reject[i];
+
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11AC configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_vhtcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data[6];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ac_cfg *cfg_11ac = NULL;
+ mlan_ds_11ac_vht_cfg *vhtcfg = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG))) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if ((user_data_len > 6) || (user_data_len < 2)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
+ cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
+ req->req_id = MLAN_IOCTL_11AC_CFG;
+
+ /* Band */
+ if ((data[0] < 0) || (data[0] > 2)) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ if (data[0] == BAND_SELECT_BOTH) {
+ cfg_11ac->param.vht_cfg.band =
+ (BAND_SELECT_BG | BAND_SELECT_A);
+ } else {
+ cfg_11ac->param.vht_cfg.band = data[0];
+ }
+ PRINTM(MINFO, "GET/SET: vhtcfg band: 0x%x\n", data[0]);
+ }
+
+ /* Tx/Rx */
+ if ((data[1] <= 0) || (data[1] > 3)) {
+ PRINTM(MERROR, "Invalid Tx/Rx selection\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ cfg_11ac->param.vht_cfg.txrx = data[1];
+ PRINTM(MINFO, "GET/SET: vhtcfg txrx: 0x%x\n", data[1]);
+ }
+
+ if (user_data_len == 2) {
+ /* GET operation */
+ if (data[0] == BAND_SELECT_BOTH) {
+ /* if get both bands, get BG first */
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
+ }
+ if (priv->bss_role == MLAN_BSS_ROLE_UAP)
+ cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
+
+ req->action = MLAN_ACT_GET;
+ } else {
+ if (user_data_len == 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len >= 4) {
+ /* BW cfg */
+ if ((data[2] < 0) || (data[2] > 1) ||
+ ((data[2] == 1) && (data[0] & BAND_SELECT_BG))) {
+ PRINTM(MERROR, "Invalid BW cfg selection\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ cfg_11ac->param.vht_cfg.bwcfg = data[2];
+ PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
+ data[2]);
+ }
+
+ cfg_11ac->param.vht_cfg.vht_cap_info = data[3];
+ PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
+ data[3]);
+ }
+ if (user_data_len == 4) {
+ data[4] = 0xffffffff;
+ data[5] = 0xffffffff;
+ }
+ if (user_data_len == 5) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len >= 4) {
+ cfg_11ac->param.vht_cfg.vht_tx_mcs = data[4];
+ cfg_11ac->param.vht_cfg.vht_rx_mcs = data[5];
+ }
+ /* Update 11AC parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* number of vhtcfg entries */
+ *respbuf = 1;
+ vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
+ moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
+ sizeof(mlan_ds_11ac_vht_cfg), respbuflen - 1);
+ ret = 1 + sizeof(mlan_ds_11ac_vht_cfg);
+
+ if ((req->action == MLAN_ACT_GET) && (data[0] == BAND_SELECT_BOTH)) {
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* number of vhtcfg entries */
+ *respbuf = 2;
+ vhtcfg++;
+ moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
+ sizeof(mlan_ds_11ac_vht_cfg),
+ respbuflen - 1 - sizeof(mlan_ds_11ac_vht_cfg));
+ ret += sizeof(mlan_ds_11ac_vht_cfg);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11AC Operating Mode Notification configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_opermodecfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ac_cfg *cfg_11ac = NULL;
+ mlan_ds_11ac_opermode_cfg *opermodecfg = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_OPERMODECFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if ((user_data_len != 0) && (user_data_len != 2)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len == 2) {
+ /* Channel width */
+ if ((data[0] < 1) || (data[0] > 4)) {
+ PRINTM(MERROR, "Invalid channel width: 0x%x\n",
+ data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ /* nss */
+ if ((data[1] < 1) || (data[1] > 8)) {
+ PRINTM(MERROR, "Invalid nss: 0x%x\n", data[1]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
+ cfg_11ac->sub_command = MLAN_OID_11AC_OPERMODE_CFG;
+ req->req_id = MLAN_IOCTL_11AC_CFG;
+
+ if (user_data_len == 0) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ req->action = MLAN_ACT_SET;
+ cfg_11ac->param.opermode_cfg.bw = data[0];
+ cfg_11ac->param.opermode_cfg.nss = data[1];
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ opermodecfg = (mlan_ds_11ac_opermode_cfg *)respbuf;
+ moal_memcpy_ext(priv->phandle, opermodecfg,
+ &(cfg_11ac->param.opermode_cfg), sizeof(*opermodecfg),
+ respbuflen);
+ ret = sizeof(*opermodecfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11AC configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_get_priv_datarate(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ mlan_data_rate *data_rate = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_rate = (mlan_data_rate *)respbuf;
+
+ moal_memcpy_ext(priv->phandle, data_rate, &rate->param.data_rate,
+ sizeof(mlan_data_rate), respbuflen);
+
+ ret = sizeof(mlan_data_rate);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get tx rate configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[4];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ woal_tx_rate_cfg *ratecfg = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ txrate_setting *rate_setting = NULL;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_TXRATECFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 4) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_RATE;
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* format */
+ if ((data[0] != AUTO_RATE) && (data[0] >= 4)) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == AUTO_RATE) {
+ /* auto */
+ rate->param.rate_cfg.is_rate_auto = 1;
+ } else {
+ /* fixed rate */
+ PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
+ if ((data[0] != AUTO_RATE) &&
+ (data[0] > MLAN_RATE_FORMAT_HE)) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ rate->param.rate_cfg.rate_format = data[0];
+
+ if (user_data_len >= 2) {
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
+ data[1]);
+ /* sanity check */
+ if (((data[0] == MLAN_RATE_FORMAT_LG) &&
+ (data[1] > MLAN_RATE_INDEX_OFDM7)) ||
+ ((data[0] == MLAN_RATE_FORMAT_HT) &&
+ (data[1] != 32) && (data[1] > 15)) ||
+ ((data[0] == MLAN_RATE_FORMAT_VHT) &&
+ (data[1] > MLAN_RATE_INDEX_MCS9)) ||
+ ((data[0] == MLAN_RATE_FORMAT_HE) &&
+ (data[1] > MLAN_RATE_INDEX_MCS11))) {
+ PRINTM(MERROR,
+ "Invalid index selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
+ data[1]);
+ rate->param.rate_cfg.rate = data[1];
+ }
+
+ if (data[0] == 2 || data[0] == 3) {
+ PRINTM(MINFO, "SET: txratefg nss: 0x%x\n",
+ data[2]);
+ /* NSS is supported up to 2 */
+ if ((data[2] <= 0) || (data[2] >= 3)) {
+ PRINTM(MERROR,
+ "Invalid nss selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ rate->param.rate_cfg.nss = data[2];
+ }
+ if (user_data_len == 4) {
+ rate->param.rate_cfg.rate_setting =
+ data[3] & ~0x0C00;
+ PRINTM(MIOCTL,
+ "SET: txratefg HE Rate Setting: 0x%x\n",
+ data[3]);
+
+/* HE Preamble type */
+#define HE_SU_PREAMBLE 0
+#define HE_ER_PREAMBLE 1
+
+/* HE ER SU Type */
+#define HE_ER_SU_BANDWIDTH_TONE242 0
+#define HE_ER_SU_BANDWIDTH_TONE106 1
+
+ rate_setting = (txrate_setting *)&data[3];
+
+ if (data[0] == MLAN_RATE_FORMAT_HE) {
+ if (rate_setting->preamble ==
+ HE_ER_PREAMBLE) {
+ if (rate_setting->bandwidth ==
+ HE_ER_SU_BANDWIDTH_TONE242) {
+ if ((data[1] >
+ MLAN_RATE_INDEX_MCS4) ||
+ data[2] >
+ MLAN_RATE_NSS1) {
+ PRINTM(MERROR,
+ "Invalid rate and MCS or NSS configuration for 242 tone\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (rate_setting
+ ->bandwidth ==
+ HE_ER_SU_BANDWIDTH_TONE106) {
+ if ((data[1] !=
+ MLAN_RATE_INDEX_MCS0) ||
+ data[2] !=
+ MLAN_RATE_NSS1) {
+ PRINTM(MERROR,
+ "Invalid rate and MCS or NSS configuration\n for 106 tone");
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR,
+ "Invalid Bandwidth for HE ER Preamble\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (rate_setting->dcm) {
+ if ((data[1] ==
+ MLAN_RATE_INDEX_MCS2) ||
+ (data[1] >
+ MLAN_RATE_INDEX_MCS4)) {
+ PRINTM(MERROR,
+ "Invalid MCS configuration if DCM is supported\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ } else {
+ rate->param.rate_cfg.rate_setting = 0xffff;
+ }
+ }
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ratecfg = (woal_tx_rate_cfg *)respbuf;
+ if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
+ ratecfg->rate_format = 0xFF;
+ } else {
+ /* fixed rate */
+ ratecfg->rate_format = rate->param.rate_cfg.rate_format;
+ ratecfg->rate_index = rate->param.rate_cfg.rate;
+ if (rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_VHT ||
+ rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_HE)
+ ratecfg->nss = rate->param.rate_cfg.nss;
+ ratecfg->rate_setting = rate->param.rate_cfg.rate_setting;
+ }
+
+ ret = sizeof(woal_tx_rate_cfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
+/**
+ * @brief Get statistics information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param stats A pointer to mlan_ds_get_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_stats_info(moal_private *priv, t_u8 wait_option,
+ mlan_ds_get_stats *stats)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ info->sub_command = MLAN_OID_GET_STATS;
+ else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ info->sub_command = MLAN_OID_GET_UAP_STATS_LOG;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (stats)
+ moal_memcpy_ext(priv->phandle, stats,
+ &info->param.stats,
+ sizeof(mlan_ds_get_stats),
+ sizeof(mlan_ds_get_stats));
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+#endif
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get wireless stats information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_get_priv_getlog(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_get_stats *stats;
+ ENTER();
+
+ if (respbuflen < sizeof(*stats)) {
+ PRINTM(MERROR, "Get log: respbuflen (%d) too small!",
+ (int)respbuflen);
+ ret = -EFAULT;
+ goto done;
+ }
+ stats = (mlan_ds_get_stats *)respbuf;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, stats)) {
+ PRINTM(MERROR, "Get log: Failed to get stats info!");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->phandle->fw_getlog_enable)
+ ret = sizeof(mlan_ds_get_stats);
+ else
+ ret = sizeof(mlan_ds_get_stats_org);
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get esupplicant mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_esuppmode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[3];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ woal_esuppmode_cfg *esupp_mode = NULL;
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ PRINTM(MERROR, "Not supported cmd on this card\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ESUPPMODE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_ESUPPMODE),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+
+ if (user_data_len == 0) {
+ /* Get operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Set operation */
+ req->action = MLAN_ACT_SET;
+ /* RSN mode */
+ sec->param.esupp_mode.rsn_mode = data[0];
+ /* Pairwise cipher */
+ sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
+ /* Group cipher */
+ sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ esupp_mode = (woal_esuppmode_cfg *)respbuf;
+ esupp_mode->rsn_mode =
+ (t_u16)((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
+ esupp_mode->pairwise_cipher =
+ (t_u8)((sec->param.esupp_mode.act_paircipher) & 0xFF);
+ esupp_mode->group_cipher =
+ (t_u8)((sec->param.esupp_mode.act_groupcipher) & 0xFF);
+
+ ret = sizeof(woal_esuppmode_cfg);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get esupplicant passphrase configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_setget_priv_passphrase(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0, action = -1, i = 0;
+ char *begin, *end, *opt;
+ t_u16 len = 0;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ t_u8 *mac = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ PRINTM(MERROR, "Not supported cmd on this card\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE))) {
+ PRINTM(MERROR, "No arguments provided\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Parse the buf to get the cmd_action */
+ begin = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE);
+ end = woal_strsep(&begin, ';', '/');
+ if (end)
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR,
+ "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ moal_memcpy_ext(priv->phandle,
+ sec->param.passphrase.ssid.ssid, end,
+ strlen(end), MLAN_MAX_SSID_LENGTH);
+ PRINTM(MINFO, "ssid=%s, len=%d\n",
+ sec->param.passphrase.ssid.ssid,
+ (int)sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8((t_u8 *)&sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex(
+ (t_u8 *)(sec->param.passphrase.psk.pmk.pmk),
+ end, MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR,
+ "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ moal_memcpy_ext(
+ priv->phandle,
+ sec->param.passphrase.psk.passphrase.passphrase,
+ end,
+ sizeof(sec->param.passphrase.psk.passphrase
+ .passphrase),
+ sizeof(sec->param.passphrase.psk.passphrase
+ .passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len =
+ strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int)sec->param.passphrase.psk.passphrase
+ .passphrase_len);
+ } else if (!strnicmp(opt, "sae_password", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_SAE_PASSWORD_LENGTH ||
+ strlen(end) > MLAN_MAX_SAE_PASSWORD_LENGTH) {
+ PRINTM(MERROR,
+ "Invalid length for sae password\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD;
+ moal_memcpy_ext(
+ priv->phandle,
+ sec->param.passphrase.psk.sae_password
+ .sae_password,
+ end,
+ sizeof(sec->param.passphrase.psk.sae_password
+ .sae_password),
+ sizeof(sec->param.passphrase.psk.sae_password
+ .sae_password));
+ sec->param.passphrase.psk.sae_password.sae_password_len =
+ strlen(end);
+ PRINTM(MINFO, "sae_password=%s, len=%d\n",
+ sec->param.passphrase.psk.sae_password
+ .sae_password,
+ (int)sec->param.passphrase.psk.sae_password
+ .sae_password_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+ else if (action == 0)
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(respbuf, 0, respbuflen);
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(respbuf + len, "ssid:");
+ moal_memcpy_ext(priv->phandle, respbuf + len,
+ sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len,
+ respbuflen - len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(respbuf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
+ mac = (t_u8 *)&sec->param.passphrase.bssid;
+ len += sprintf(respbuf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(respbuf + len, "%02x:", mac[i]);
+ len += sprintf(respbuf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(respbuf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len += sprintf(respbuf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(respbuf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE)
+ len += sprintf(respbuf + len, "passphrase:%s\n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ if (sec->param.passphrase.psk_type == MLAN_PSK_SAE_PASSWORD)
+ len += sprintf(
+ respbuf + len, "sae_password:%s\n",
+ sec->param.passphrase.psk.sae_password.sae_password);
+
+ ret = len;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 mac[ETH_ALEN];
+
+ ENTER();
+
+ if (strlen(respbuf) > (strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH))) {
+ /* Deauth mentioned BSSID */
+ woal_mac2u8(mac, respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_DEAUTH));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, mac,
+ DEF_DEAUTH_REASON_CODE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE))
+ ret = -EFAULT;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef UAP_SUPPORT
+/**
+ * @brief uap station deauth ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_ap_deauth(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u8 *data_ptr;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_deauth_param deauth_param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH));
+ memset(&deauth_param, 0, sizeof(mlan_deauth_param));
+ moal_memcpy_ext(priv->phandle, &deauth_param, data_ptr,
+ sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
+
+ PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
+ MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
+ sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(
+ priv->phandle, data_ptr, &ioctl_req->status_code, sizeof(t_u32),
+ respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH)));
+ ret = sizeof(t_u32);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get station list handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_get_sta_list(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ds_sta_list *sta_list = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ sta_list = (mlan_ds_sta_list *)(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_GET_STA_LIST));
+ moal_memcpy_ext(
+ priv->phandle, sta_list, &info->param.sta_list,
+ sizeof(mlan_ds_sta_list),
+ respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_STA_LIST)));
+ ret = sizeof(mlan_ds_sta_list);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap bss_config handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_bss_config(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ t_u32 action = 0;
+ int offset = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ offset = strlen(CMD_NXP) + strlen(PRIV_CMD_BSS_CONFIG);
+ moal_memcpy_ext(priv->phandle, (u8 *)&action, respbuf + offset,
+ sizeof(action), sizeof(action));
+ offset += sizeof(action);
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (action == 1) {
+ ioctl_req->action = MLAN_ACT_SET;
+ /* Get the BSS config from user */
+ moal_memcpy_ext(priv->phandle, &bss->param.bss_config,
+ respbuf + offset, sizeof(mlan_uap_bss_param),
+ sizeof(mlan_uap_bss_param));
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, respbuf + offset,
+ &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param),
+ respbuflen - (t_u32)offset);
+ }
+ ret = sizeof(mlan_uap_bss_param);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_bssrole(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ memset((char *)data, 0, sizeof(data));
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BSSROLE))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_BSSROLE),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (user_data_len == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ if ((data[0] != MLAN_BSS_ROLE_STA &&
+ data[0] != MLAN_BSS_ROLE_UAP) ||
+ priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (data[0] == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, (t_u8 *)data)) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ if (user_data_len) {
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+done:
+ memset(respbuf, 0, respbuflen);
+ respbuf[0] = (t_u8)data[0];
+ ret = 1;
+
+error:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_setuserscan(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ wlan_user_scan_cfg scan_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Create the scan_cfg structure */
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+
+ /* We expect the scan_cfg structure to be passed in respbuf */
+ moal_memcpy_ext(priv->phandle, (char *)&scan_cfg,
+ respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_SETUSERSCAN),
+ sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg));
+ moal_memcpy_ext(priv->phandle, scan_cfg.random_mac, priv->random_mac,
+ ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
+ /* Call for scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get channel statistics
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_get_chanstats(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_scan_resp scan_resp;
+ chan_stats *stats = NULL;
+ int ret = 0;
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(respbuf, 0, respbuflen);
+ stats = (chan_stats *)respbuf;
+ stats->num_in_chan_stats = scan_resp.num_in_chan_stats;
+ ret = sizeof(ChanStatistics_t) * stats->num_in_chan_stats;
+ moal_memcpy_ext(priv->phandle, (t_u8 *)stats->stats,
+ (t_u8 *)scan_resp.pchan_stats, ret, respbuflen);
+ ret += sizeof(stats->num_in_chan_stats);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Retrieve the scan response/beacon table
+ *
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ * @param scan_start Argument
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int moal_ret_get_scan_table_ioctl(t_u8 *respbuf, t_u32 respbuflen,
+ mlan_scan_resp *scan_resp, t_u32 scan_start)
+{
+ pBSSDescriptor_t pbss_desc, scan_table;
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ int ret_code;
+ int ret_len;
+ int space_left;
+ t_u8 *pcurrent;
+ t_u8 *pbuffer_end;
+ t_u32 num_scans_done;
+
+ ENTER();
+
+ num_scans_done = 0;
+ ret_code = MLAN_STATUS_SUCCESS;
+
+ prsp_info = (wlan_ioctl_get_scan_table_info *)respbuf;
+ pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;
+
+ pbuffer_end = respbuf + respbuflen - 1;
+ space_left = pbuffer_end - pcurrent;
+ scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);
+
+ PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
+ PRINTM(MINFO, "GetScanTable: length avail = %d\n", respbuflen);
+
+ if (!scan_start) {
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
+
+ /* Use to get current association saved descriptor */
+ pbss_desc = scan_table;
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent,
+ &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS)
+ num_scans_done = 1;
+
+ } else {
+ scan_start--;
+
+ while (space_left &&
+ (scan_start + num_scans_done <
+ scan_resp->num_in_scan_table) &&
+ (ret_code == MLAN_STATUS_SUCCESS)) {
+ pbss_desc =
+ (scan_table + (scan_start + num_scans_done));
+
+ PRINTM(MINFO,
+ "GetScanTable: get current BSS Descriptor [%d]\n",
+ scan_start + num_scans_done);
+
+ ret_code = wlan_get_scan_table_ret_entry(
+ pbss_desc, &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS)
+ num_scans_done++;
+ }
+ }
+
+ prsp_info->scan_number = num_scans_done;
+ ret_len = pcurrent - respbuf;
+
+ LEAVE();
+ return ret_len;
+}
+
+/**
+ * @brief Get scan table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_getscantable(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ t_u32 scan_start;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+
+ /* First make sure scanning is not in progress */
+ if (handle->scan_pending_on_block == MTRUE) {
+ ret = -EAGAIN;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *)req->pbuf;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+
+ /* Get the whole command from user */
+ moal_memcpy_ext(handle, &scan_start,
+ respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_GETSCANTABLE),
+ sizeof(scan_start), sizeof(scan_start));
+ if (scan_start)
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ else
+ scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ ret = moal_ret_get_scan_table_ioctl(respbuf, respbuflen,
+ &scan->param.scan_resp,
+ scan_start);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Extended capabilities configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_extcapcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret, header;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ IEEEtypes_Header_t *ie;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ LEAVE();
+ return 0;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ header = strlen(CMD_NXP) + strlen(PRIV_CMD_EXTCAPCFG);
+ if (strlen(respbuf) == header)
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ else {
+ /* SET operation */
+ ie = (IEEEtypes_Header_t *)(respbuf + header);
+ if (ie->len > sizeof(ExtCap_t)) {
+ PRINTM(MERROR,
+ "Extended Capability lenth is invalid\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ memset(&cfg->param.ext_cap, 0, sizeof(ExtCap_t));
+ moal_memcpy_ext(priv->phandle, &cfg->param.ext_cap, ie + 1,
+ ie->len, sizeof(ExtCap_t));
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(respbuf, 0, respbuflen);
+ ie = (IEEEtypes_Header_t *)respbuf;
+ ie->element_id = EXT_CAPABILITY;
+ ie->len = sizeof(ExtCap_t);
+ moal_memcpy_ext(priv->phandle, ie + 1, &cfg->param.ext_cap,
+ sizeof(ExtCap_t),
+ respbuflen - sizeof(IEEEtypes_Header_t));
+
+ ret = sizeof(IEEEtypes_Header_t) + ie->len;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get deep sleep mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_setgetdeepsleep(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[2];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DEEPSLEEP))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_DEEPSLEEP),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len >= 3) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sprintf(respbuf, "%d %d", data[0], data[1]);
+ ret = strlen(respbuf) + 1;
+ } else {
+ if (data[0] == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
+ 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (data[0] == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (user_data_len != 2)
+ data[1] = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
+ data[1]);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IP address configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_setgetipaddr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = 0, header = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (priv->bss_type != MLAN_BSS_TYPE_STA) {
+ PRINTM(MIOCTL, "Bss type[%d]: Not STA, ignore it\n",
+ priv->bss_type);
+ ret = sprintf(respbuf, "OK\n") + 1;
+ goto done;
+ }
+
+ header = strlen(CMD_NXP) + strlen(PRIV_CMD_IPADDR);
+ data_length = strlen(respbuf) - header;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+
+ if (data_length < 1) { /* GET */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && respbuf[header + 1] != ';') {
+ PRINTM(MERROR,
+ "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ respbuf[header + 1] = '\0';
+ }
+ req->action = MLAN_ACT_SET;
+
+ /* Only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ if (data_length > 2)
+ in4_pton(&respbuf[header + 2],
+ MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+
+ if (woal_atoi(&op_code, &respbuf[header]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
+ }
+
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ ret = IPADDR_MAX_BUF + 1;
+ } else {
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WPS session configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_setwpssession(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wps_cfg *pwps = NULL;
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset((char *)data, 0, sizeof(data));
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_WPSSESSION))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_WPSSESSION),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pwps = (mlan_ds_wps_cfg *)req->pbuf;
+
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+
+ if (data[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sprintf(respbuf, "OK\n") + 1;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get OTP user data
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_otpuserdata(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data[1];
+ int user_data_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_otp_user_data *otp = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_OTPUSERDATA))) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_OTPUSERDATA),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
+ misc->param.otp_user_data.user_data_length = data[0];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ otp = (mlan_ds_misc_otp_user_data *)req->pbuf;
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = MIN(otp->user_data_length, data[0]);
+ moal_memcpy_ext(priv->phandle, respbuf, otp->user_data, ret,
+ respbuflen);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set / Get country code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_countrycode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ /* char data[COUNTRY_CODE_LEN] = {0, 0, 0}; */
+ int header = 0, data_length = 0; /* wrq->u.data.length; */
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_ds_misc_country_code *country_code = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header = strlen(CMD_NXP) + strlen(PRIV_CMD_COUNTRYCODE);
+ data_length = strlen(respbuf) - header;
+
+ if (data_length > COUNTRY_CODE_LEN) {
+ PRINTM(MERROR, "Invalid argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ country_code = &pcfg_misc->param.country_code;
+ pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (data_length <= 1) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
+ moal_memcpy_ext(priv->phandle, country_code->country_code,
+ respbuf + header, COUNTRY_CODE_LEN,
+ COUNTRY_CODE_LEN);
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ ret = data_length = COUNTRY_CODE_LEN;
+ memset(respbuf + header, 0, COUNTRY_CODE_LEN);
+ moal_memcpy_ext(priv->phandle, respbuf,
+ country_code->country_code, COUNTRY_CODE_LEN,
+ respbuflen);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get cfp information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfp_misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int header = 0, data_length = 0;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header = strlen(CMD_NXP) + strlen(PRIV_CMD_CFPINFO);
+ data_length = strlen(respbuf) - header;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (respbuflen < req->data_read_written) {
+ PRINTM(MERROR, "response buffer length is too short!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)req->pbuf,
+ req->data_read_written, respbuflen);
+ ret = req->data_read_written;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TCP Ack enhancement configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_setgettcpackenh(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u32 data[1];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TCPACKENH))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_TCPACKENH),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ /* get operation */
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ } else {
+ /* set operation */
+ if (data[0] == MTRUE) {
+ PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MTRUE;
+ } else if (data[0] == MFALSE) {
+ PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
+ priv->enable_tcp_ack_enh = MFALSE;
+ /* release the tcp sessions if any */
+ woal_flush_tcp_sess_queue(priv);
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ respbuf[0] = priv->enable_tcp_ack_enh;
+ }
+ ret = 1;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief Set Asynced ESSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ * @param bBSSID A variable that bssid is set or not
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_assocessid(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
+ t_u8 bBSSID)
+{
+ mlan_ssid_bssid ssid_bssid;
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int header_len = 0;
+ int copy_len = 0;
+ char buf[64];
+ t_u8 buflen = 0;
+ t_u8 i = 0;
+ t_u8 mac_idx = 0;
+
+ ENTER();
+
+ if (bBSSID)
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCBSSID);
+ else
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCESSID);
+
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "No argument, invalid operation!\n");
+ ret = -EINVAL;
+ LEAVE();
+ return ret;
+ }
+ copy_len = strlen(respbuf) - header_len;
+ buflen = MIN(copy_len, (sizeof(buf) - 1));
+ memset(buf, 0, sizeof(buf));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ moal_memcpy_ext(handle, buf, respbuf + header_len, buflen, sizeof(buf));
+ priv->assoc_with_mac = MFALSE;
+
+ /* check if has parameter BSSID */
+ if (bBSSID) {
+ if (buflen < (3 * ETH_ALEN) + 2) {
+ PRINTM(MERROR,
+ "Associate: Insufficient length in IOCTL input\n");
+ /* buffer should be at least 3 characters per BSSID
+ *octet "00:"
+ ** plus a space separater and at least 1 char in the
+ *SSID
+ */
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+ for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' ');
+ i++) {
+ if (buf[i] == ':') {
+ mac_idx++;
+ } else {
+ ssid_bssid.bssid[mac_idx] =
+ (t_u8)woal_atox(buf + i);
+ while ((i < buflen) && isxdigit(buf[i + 1]))
+ /* Skip entire hex value */
+ i++;
+ }
+ }
+ /* Skip one space between the BSSID and start of the SSID */
+ i++;
+ PRINTM(MMSG, "Trying to associate AP BSSID = [" MACSTR "]\n",
+ MAC2STR(ssid_bssid.bssid));
+ priv->assoc_with_mac = MTRUE;
+ }
+
+ ssid_bssid.ssid.ssid_len = buflen - i;
+ /* Check the size of the ssid_len */
+ if (ssid_bssid.ssid.ssid_len > MLAN_MAX_SSID_LENGTH + 1) {
+ PRINTM(MERROR, "ssid_bssid.ssid.ssid_len = %d\n",
+ ssid_bssid.ssid.ssid_len);
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+
+ /* Copy the SSID */
+ moal_memcpy_ext(handle, ssid_bssid.ssid.ssid, buf + i,
+ ssid_bssid.ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
+
+ if (!ssid_bssid.ssid.ssid_len ||
+ (MFALSE == woal_ssid_valid(&ssid_bssid.ssid))) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+
+ PRINTM(MMSG, "Trying to associate AP SSID = %s\n",
+ (char *)ssid_bssid.ssid.ssid);
+
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ ret = -EBUSY;
+ LEAVE();
+ return ret;
+ }
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+
+ if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
+ PRINTM(MIOCTL, "Already connect to the network\n");
+ ret = sprintf(respbuf,
+ "Has already connected to this ESSID!\n") +
+ 1;
+ goto setessid_ret;
+ }
+ moal_memcpy_ext(handle, &priv->prev_ssid_bssid, &ssid_bssid,
+ sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
+ /* disconnect before driver assoc */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL, DEF_DEAUTH_REASON_CODE);
+ priv->set_asynced_essid_flag = MTRUE;
+ priv->reassoc_required = MTRUE;
+ priv->phandle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->reassoc_timer, 0);
+ ret = sprintf(respbuf, "%s\n", buf) + 1;
+
+setessid_ret:
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get wakeup reason
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_getwakeupreason(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ t_u32 data;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_WAKEUPREASON))) {
+ /* GET operation */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ goto done;
+ } else {
+ data = pm_cfg->param.wakeup_reason.hs_wakeup_reason;
+ sprintf(respbuf, " %d", data);
+ ret = strlen(respbuf) + 1;
+ kfree(req);
+ }
+ } else {
+ PRINTM(MERROR, "Not need argument, invalid operation!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set / Get listen interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_listeninterval(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[1];
+ int user_data_len = 0;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *pcfg_bss = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_LISTENINTERVAL))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_LISTENINTERVAL),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_bss = (mlan_ds_bss *)req->pbuf;
+ pcfg_bss->sub_command = MLAN_OID_BSS_LISTEN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ if (user_data_len) {
+ pcfg_bss->param.listen_interval = (t_u16)data[0];
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (req->action == MLAN_ACT_GET) {
+ sprintf(respbuf, "%d", pcfg_bss->param.listen_interval);
+ ret = strlen(respbuf) + 1;
+ } else {
+ ret = sprintf(respbuf, "OK\n") + 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set / Get driver debug level
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[4];
+ int user_data_len = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DRVDBG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_DRVDBG),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len) {
+ /* Get the driver debug bit masks from user */
+ drvdbg = data[0];
+ /* Set the driver debug bit masks into mlan */
+ if (woal_set_drvdbg(priv, drvdbg)) {
+ PRINTM(MERROR, "Set drvdbg failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ ret = sizeof(drvdbg);
+
+ moal_memcpy_ext(priv->phandle, respbuf, &drvdbg, sizeof(drvdbg),
+ respbuflen);
+
+ printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+ printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO,
+ (drvdbg & MINFO) ? "X" : "");
+ printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN,
+ (drvdbg & MWARN) ? "X" : "");
+ printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
+ (drvdbg & MENTRY) ? "X" : "");
+#endif
+ printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
+ (drvdbg & MMPA_D) ? "X" : "");
+ printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D,
+ (drvdbg & MIF_D) ? "X" : "");
+ printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D,
+ (drvdbg & MFW_D) ? "X" : "");
+ printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
+ (drvdbg & MEVT_D) ? "X" : "");
+ printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
+ (drvdbg & MCMD_D) ? "X" : "");
+ printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
+ (drvdbg & MDAT_D) ? "X" : "");
+ printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D,
+ (drvdbg & MREG_D) ? "X" : "");
+ printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
+ (drvdbg & MIOCTL) ? "X" : "");
+ printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR,
+ (drvdbg & MINTR) ? "X" : "");
+ printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
+ (drvdbg & MEVENT) ? "X" : "");
+ printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND,
+ (drvdbg & MCMND) ? "X" : "");
+ printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA,
+ (drvdbg & MDATA) ? "X" : "");
+ printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
+ (drvdbg & MERROR) ? "X" : "");
+ printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
+ (drvdbg & MFATAL) ? "X" : "");
+ printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG,
+ (drvdbg & MMSG) ? "X" : "");
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#endif
+
+/**
+ * @brief management frame filter wakeup config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_mgmt_filter(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int header_len = 0, data_len = 0;
+ int ret = 0;
+ t_u16 action;
+ t_u8 *argument;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_MGMT_FILTER;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+
+ header_len = strlen(PRIV_CMD_MGMT_FILTER) + strlen(CMD_NXP);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ argument = (t_u8 *)(respbuf + header_len);
+ data_len = respbuflen - header_len;
+ if (data_len >
+ MAX_MGMT_FRAME_FILTER * sizeof(mlan_mgmt_frame_wakeup)) {
+ PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
+ ret = -EINVAL;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle,
+ (t_u8 *)pm_cfg->param.mgmt_filter, argument,
+ data_len, sizeof(pm_cfg->param.mgmt_filter));
+ action = MLAN_ACT_SET;
+ }
+
+ ioctl_req->action = action;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+#define PARAMETER_GPIO_INDICATION 1
+#define PARAMETER_EXTEND_HSCFG 2
+#define PARAMETER_HS_WAKEUP_INTERVAL 3
+/**
+ * @brief Set/Get Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_hscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
+ BOOLEAN invoke_hostcmd)
+{
+ int data[13] = {0};
+ int *temp_data, type;
+ int user_data_len = 0;
+ int ret = 0;
+ mlan_ds_hs_cfg hscfg, hscfg_temp;
+ t_u16 action;
+ mlan_bss_info bss_info;
+ int is_negative = MFALSE;
+ t_u8 *arguments = NULL;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ memset(&hscfg_temp, 0, sizeof(mlan_ds_hs_cfg));
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ arguments = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG);
+ if (*arguments == '-') {
+ is_negative = MTRUE;
+ arguments += 1;
+ }
+ parse_arguments(arguments, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (is_negative == MTRUE) {
+ if (data[0] == 1) {
+ data[0] = -1;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ if (user_data_len >= 1 && user_data_len <= 13) {
+ action = MLAN_ACT_SET;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* HS config is blocked if HS is already activated */
+ if (user_data_len &&
+ (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Do a GET first if some arguments are not provided */
+ if (user_data_len >= 1 && user_data_len < 11) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
+ &hscfg_temp);
+ }
+ hscfg.conditions = hscfg_temp.conditions;
+ hscfg.gpio = hscfg_temp.gpio;
+ hscfg.gap = hscfg_temp.gap;
+
+ if (user_data_len)
+ hscfg.conditions = data[0];
+ if (user_data_len >= 2)
+ hscfg.gpio = data[1];
+ if (user_data_len >= 3)
+ hscfg.gap = data[2];
+ user_data_len = user_data_len - 3;
+ if (user_data_len > 0) {
+ temp_data = data + 3;
+ while ((user_data_len > 0) && temp_data) {
+ type = *temp_data;
+ switch (type) {
+ case PARAMETER_GPIO_INDICATION:
+ if (user_data_len >= 2)
+ hscfg.ind_gpio = *(++temp_data);
+ else {
+ PRINTM(MERROR,
+ "Invaild number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len >= 3) {
+ hscfg.level = *(++temp_data);
+ if (hscfg.level != 0 &&
+ hscfg.level != 1) {
+ PRINTM(MERROR,
+ "Invalid indication gpio arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ hscfg.param_type_ind = type;
+ user_data_len = user_data_len - 3;
+ temp_data++;
+ break;
+ case PARAMETER_EXTEND_HSCFG:
+ if (user_data_len >= 4) {
+ hscfg.event_force_ignore =
+ *(++temp_data);
+ hscfg.event_use_ext_gap =
+ *(++temp_data);
+ hscfg.ext_gap = *(++temp_data);
+ hscfg.gpio_wave = *(++temp_data);
+ } else {
+ PRINTM(MERROR,
+ "Invaild number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Force_ignore_gpio and ext_gap_gpio should not
+ * set the same bit(s)*/
+ if ((hscfg.event_force_ignore &
+ hscfg.event_use_ext_gap) ||
+ (hscfg.gpio_wave != 1 &&
+ hscfg.gpio_wave != 0)) {
+ PRINTM(MERROR,
+ "Invalid arguments for extend hscfg\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ hscfg.param_type_ext = type;
+ user_data_len = user_data_len - 5;
+ temp_data++;
+ break;
+ case PARAMETER_HS_WAKEUP_INTERVAL:
+ if (user_data_len >= 2)
+ hscfg.hs_wake_interval = *(++temp_data);
+ else {
+ PRINTM(MERROR,
+ "Invaild number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ user_data_len = user_data_len - 2;
+ temp_data++;
+ break;
+ default:
+ PRINTM(MERROR, "Unsupported type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+
+ if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
+ /* Need to issue an extra IOCTL first to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ /* Return the current driver host sleep configurations */
+ moal_memcpy_ext(priv->phandle, respbuf, &hscfg,
+ sizeof(mlan_ds_hs_cfg), respbuflen);
+ ret = sizeof(mlan_ds_hs_cfg);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data[13] = {0};
+ int user_data_len = 0;
+ int ret = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))) {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_HSSETPARA),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len >= 1 && user_data_len <= 13) {
+ sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG,
+ respbuf +
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA)));
+ respbuflen = strlen(respbuf);
+ ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE);
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get scan configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_set_get_scancfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0;
+ int data[9];
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_SCANCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_SCANCFG),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+
+ if (user_data_len) {
+ if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
+ PRINTM(MERROR, "Invalid argument for scan type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
+ PRINTM(MERROR, "Invalid argument for scan mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
+ PRINTM(MERROR, "Invalid argument for scan probes\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (((data[3] < 0) ||
+ (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[4] < 0) ||
+ (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[5] < 0) ||
+ (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
+ PRINTM(MERROR, "Invalid argument for scan time\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[6] < 0) || (data[6] > MLAN_PASS_TO_ACT_SCAN_DIS)) {
+ PRINTM(MERROR,
+ "Invalid argument for Passive to Active Scan\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[7] < 0) || (data[7] > 3)) {
+ PRINTM(MERROR, "Invalid argument for extended scan\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[8] < 0) ||
+ (data[8] > MRVDRV_MAX_SCAN_CHAN_GAP_TIME)) {
+ PRINTM(MERROR,
+ "Invalid argument for scan channel gap\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
+ sizeof(data), sizeof(scan->param.scan_cfg));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, respbuf, &scan->param.scan_cfg,
+ sizeof(mlan_scan_cfg), respbuflen);
+ ret = sizeof(mlan_scan_cfg);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Netlink Number
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_getnlnum(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ int data = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null in %s\n", __FUNCTION__);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = priv->phandle->netlink_num;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set / Get packet aggregation control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_aggrctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[1];
+ int user_data_len = 0;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ moal_handle *handle = priv->phandle;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!handle || !handle->card) {
+ PRINTM(MERROR, "Handle or card is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset((char *)data, 0, sizeof(data));
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRCTRL))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ if (woal_is_any_interface_active(priv->phandle)) {
+ PRINTM(MERROR,
+ "aggrctrl are not allowed to change after BSS active!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* SET operation */
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_AGGRCTRL),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if user had modified
+ * them */
+ if (user_data_len == 0)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ pcfg_misc->param.aggr_params.tx.enable = (t_u16)data[0];
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ /* MLAN will return CMD_INVALID if FW does not support this
+ * feature */
+ if (MLAN_ERROR_CMD_INVALID == req->status_code)
+ ret = -EOPNOTSUPP;
+ else
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(handle, respbuf, (t_u8 *)&pcfg_misc->param.aggr_params,
+ sizeof(mlan_ds_misc_aggr_ctrl), respbuflen);
+ ret = sizeof(mlan_ds_misc_aggr_ctrl);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef USB
+/**
+ * @brief Set / Get USB packet aggregation control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_usbaggrctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[8];
+ int user_data_len = 0;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ moal_handle *handle = priv->phandle;
+ struct usb_card_rec *cardp = NULL;
+ int i = 0, usb_resubmit_urbs = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!handle || !handle->card) {
+ PRINTM(MERROR, "Handle or card is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cardp = (struct usb_card_rec *)handle->card;
+
+ memset((char *)data, 0, sizeof(data));
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_USBAGGRCTRL))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_USBAGGRCTRL),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if user had modified
+ * them */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ /* MLAN will return CMD_INVALID if FW does not support this
+ * feature */
+ if (MLAN_ERROR_CMD_INVALID == req->status_code)
+ ret = -EOPNOTSUPP;
+ else
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ moal_memcpy_ext(handle, respbuf,
+ (t_u8 *)&pcfg_misc->param.usb_aggr_params,
+ sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
+ ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
+ goto done;
+ }
+
+ switch (user_data_len) {
+ case 8:
+ if (data[7] < 0) {
+ PRINTM(MERROR, "Invalid Rx timeout value (%d)\n",
+ data[7]);
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_tmo =
+ (t_u16)data[7];
+ /* fall through */
+ case 7:
+ if (data[6] < 0 || (data[6] > 10000 &&
+ data[6] != MLAN_USB_TX_AGGR_TIMEOUT_DYN)) {
+ PRINTM(MERROR, "Invalid Tx timeout value (%d)\n",
+ data[6]);
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_tmo =
+ (t_u16)data[6];
+ /* fall through */
+ case 6:
+ if ((data[5] < 512) || ((data[5] % 512) != 0)) {
+ PRINTM(MERROR, "Invalid Rx alignment value (%d)\n",
+ data[5]);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (cardp->rx_deaggr_ctrl.enable &&
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align !=
+ (t_u16)data[5])
+ usb_resubmit_urbs = 1;
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align =
+ (t_u16)data[5];
+ /* fall through */
+ case 5:
+ if ((data[4] < 2048) || ((data[4] % 2048) != 0)) {
+ PRINTM(MERROR, "Invalid Tx alignment value (%d)\n",
+ data[4]);
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_align =
+ (t_u16)data[4];
+ /* fall through */
+ case 4:
+ if ((data[3] == 2) || (data[3] == 4) || (data[3] == 8) ||
+ (data[3] == 16)) {
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
+ .aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ } else if ((data[3] == 4096) || (data[3] == 8192) ||
+ (data[3] == 16384) || (data[3] == 32768)) {
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
+ .aggr_mode = MLAN_USB_AGGR_MODE_LEN;
+ } else {
+ PRINTM(MERROR, "Invalid Rx max size/num value (%d)\n",
+ data[3]);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (cardp->rx_deaggr_ctrl.enable &&
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max !=
+ (t_u16)data[3])
+ usb_resubmit_urbs = 1;
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max =
+ (t_u16)data[3];
+ /* fall through */
+ case 3:
+ if ((data[2] == 2) || (data[2] == 4) || (data[2] == 8) ||
+ (data[2] == 16)) {
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
+ MLAN_USB_AGGR_MODE_NUM;
+ } else if ((data[2] == 4096) || (data[2] == 8192) ||
+ (data[2] == 16384) || (data[2] == 32768)) {
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
+ MLAN_USB_AGGR_MODE_LEN;
+ } else {
+ PRINTM(MERROR, "Invalid Tx max size/num value (%d)\n",
+ data[2]);
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_max =
+ (t_u16)data[2];
+ /* fall through */
+ case 2:
+ if ((data[1] != 0) && (data[1] != 1)) {
+ PRINTM(MERROR, "Invalid Rx enable value (%d)\n",
+ data[1]);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable !=
+ (t_u16)data[1])
+ usb_resubmit_urbs = 1;
+ pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable =
+ (t_u16)data[1];
+ /* fall through */
+ case 1:
+ if ((data[0] != 0) && (data[0] != 1)) {
+ PRINTM(MERROR, "Invalid Tx enable value (%d)\n",
+ data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.enable =
+ (t_u16)data[0];
+ default:
+ break;
+ }
+
+ pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(handle, respbuf,
+ (t_u8 *)&pcfg_misc->param.usb_aggr_params,
+ sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
+ ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
+
+ /* Keep a copy of the latest Tx aggregation parameters in MOAL */
+ moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl,
+ &pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl,
+ sizeof(usb_aggr_ctrl), sizeof(usb_aggr_ctrl));
+
+ if (usb_resubmit_urbs) {
+ /* Indicate resubmition from here */
+ cardp->resubmit_urbs = 1;
+ /* Rx SG parameters has changed or disabled, kill the URBs, they
+ will be resubmitted after saving the parameters to USB card
+ */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_kill_urb(
+ cardp->rx_data_list[i].urb);
+ usb_init_urb(
+ cardp->rx_data_list[i].urb);
+ }
+ }
+ }
+ }
+
+ /* Keep a copy of the latest Rx deaggregation parameters in MOAL */
+ moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl,
+ &pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl,
+ sizeof(usb_aggr_ctrl), sizeof(usb_aggr_ctrl));
+
+ if (usb_resubmit_urbs) {
+ /* Ensure the next data URBs will use the modified parameters */
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ cardp->resubmit_urbs = 0;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set AP settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful, otherwise fail
+ */
+static int woal_priv_set_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u8 *data_ptr;
+ const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+ mlan_ssid_bssid ssid_bssid;
+ mlan_bss_info bss_info;
+ struct mwreq *mwr;
+ struct sockaddr *awrq;
+
+ ENTER();
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AP));
+
+ mwr = (struct mwreq *)data_ptr;
+
+ if (mwr->u.ap_addr.sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ awrq = (struct sockaddr *)&(mwr->u.ap_addr);
+
+ PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
+ MAC2STR((t_u8 *)awrq->sa_data));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+#endif
+
+ /* zero_mac means disconnect */
+ if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE);
+ goto done;
+ }
+
+ /* Broadcast MAC means search for best network */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ /* Check if we are already assoicated to the AP */
+ if (bss_info.media_connected == MTRUE) {
+ if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
+ ETH_ALEN, sizeof(mlan_802_11_mac_addr));
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ PRINTM(MERROR,
+ "ASSOC: WAP: MAC address not found in BSSID List\n");
+ ret = -ENETUNREACH;
+ goto done;
+ }
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(mlan_802_11_mac_addr));
+#endif /* REASSOCIATION */
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set BSS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful, otherwise fail
+ */
+static int woal_priv_set_bss_mode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+ t_u32 mode;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_BSS_MODE));
+
+ mwr = (struct mwreq *)data_ptr;
+ mode = mwr->u.mode;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (mode) {
+ case MW_MODE_INFRA:
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ break;
+ case MW_MODE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ break;
+ case MW_MODE_AUTO:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set power management
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful, otherwise fail
+ */
+static int woal_priv_set_power(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+ int ret = 0, disabled;
+
+ ENTER();
+
+ if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
+ PRINTM(MIOCTL, "block set power in hw_test mode\n");
+ LEAVE();
+ return ret;
+ }
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_POWER));
+
+ mwr = (struct mwreq *)data_ptr;
+ disabled = mwr->u.power.disabled;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled,
+ mwr->u.power.flags, MOAL_IOCTL_WAIT)) {
+ return -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful, otherwise fail
+ */
+static int woal_priv_set_essid(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+#endif
+ int ret = 0;
+ t_u32 mode = 0;
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_ESSID));
+
+ mwr = (struct mwreq *)data_ptr;
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ /* Check the size of the string */
+ if (mwr->u.essid.length > MW_ESSID_MAX_SIZE - 1) {
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ req_ssid.ssid_len = mwr->u.essid.length;
+
+ /* Check if we asked for 'any' or 'particular' */
+ if (!mwr->u.essid.flags) {
+#ifdef REASSOCIATION
+ if (!req_ssid.ssid_len) {
+ memset(&priv->prev_ssid_bssid.ssid, 0x00,
+ sizeof(mlan_802_11_ssid));
+ memset(&priv->prev_ssid_bssid.bssid, 0x00,
+ MLAN_MAC_ADDR_LENGTH);
+ goto setessid_ret;
+ }
+#endif
+ /* Do normal SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else {
+ /* Set the SSID */
+ moal_memcpy_ext(handle, req_ssid.ssid, mwr->u.essid.pointer,
+ req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
+ if (!req_ssid.ssid_len ||
+ (MFALSE == woal_ssid_valid(&req_ssid))) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (char *)req_ssid.ssid);
+ moal_memcpy_ext(handle, &ssid_bssid.ssid, &req_ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
+ PRINTM(MIOCTL, "Already connect to the network\n");
+ goto setessid_ret;
+ }
+
+ if (mwr->u.essid.flags != 0xFFFF) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_essid(priv, &ssid_bssid,
+ MOAL_IOCTL_WAIT)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT,
+ &req_ssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+ }
+ }
+
+ mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+
+ if (mode != MW_MODE_ADHOC) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+#ifdef UAP_SUPPORT
+ else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
+#endif
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ moal_memcpy_ext(handle, &priv->prev_ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(handle, &priv->prev_ssid_bssid.bssid, &bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH, sizeof(mlan_802_11_mac_addr));
+#endif /* REASSOCIATION */
+
+setessid_ret:
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set authentication mode parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful, otherwise fail
+ */
+static int woal_priv_set_auth(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+ int ret = 0;
+ t_u32 auth_mode = 0;
+ t_u32 encrypt_mode = 0;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AUTH));
+
+ mwr = (struct mwreq *)data_ptr;
+
+ switch (mwr->u.param.flags & MW_AUTH_INDEX) {
+ case MW_AUTH_CIPHER_PAIRWISE:
+ case MW_AUTH_CIPHER_GROUP:
+ if (mwr->u.param.value & MW_AUTH_CIPHER_NONE)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP40)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP104)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ else if (mwr->u.param.value & MW_AUTH_CIPHER_TKIP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ else if (mwr->u.param.value & MW_AUTH_CIPHER_CCMP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+ break;
+ case MW_AUTH_80211_AUTH_ALG:
+ switch (mwr->u.param.value) {
+ case MW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case MW_AUTH_ALG_LEAP:
+ PRINTM(MINFO, "Auth mode LEAP!\n");
+ auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
+ break;
+ case MW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ case MW_AUTH_ALG_SHARED_KEY | MW_AUTH_ALG_OPEN_SYSTEM:
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ break;
+ case MW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT,
+ mwr->u.param.value))
+ ret = -EFAULT;
+ break;
+#define MW_AUTH_WAPI_ENABLED 0x20
+ case MW_AUTH_WAPI_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT,
+ mwr->u.param.value))
+ ret = -EFAULT;
+ break;
+ case MW_AUTH_WPA_VERSION:
+ /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
+ priv->wpa_version = mwr->u.param.value;
+ break;
+ case MW_AUTH_KEY_MGMT:
+ /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
+ priv->key_mgmt = mwr->u.param.value;
+ break;
+ case MW_AUTH_TKIP_COUNTERMEASURES:
+ case MW_AUTH_DROP_UNENCRYPTED:
+ case MW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case MW_AUTH_ROAMING_CONTROL:
+ case MW_AUTH_PRIVACY_INVOKED:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_get_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+ int ret = 0;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP));
+
+ mwr = (struct mwreq *)data_ptr;
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret != MLAN_STATUS_SUCCESS)
+ return -EFAULT;
+
+ if (bss_info.media_connected == MTRUE) {
+ moal_memcpy_ext(priv->phandle, mwr->u.ap_addr.sa_data,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(mwr->u.ap_addr.sa_data));
+ } else {
+ memset(mwr->u.ap_addr.sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ mwr->u.ap_addr.sa_family = ARPHRD_ETHER;
+ ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP) + sizeof(struct mwreq);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power management
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_get_power(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ struct mwreq *mwr;
+ t_u8 *data_ptr;
+ int ret = 0, ps_mode;
+
+ ENTER();
+
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER));
+
+ mwr = (struct mwreq *)data_ptr;
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
+ &ps_mode, 0,
+ MOAL_IOCTL_WAIT)) {
+ return -EFAULT;
+ }
+
+ if (ps_mode)
+ mwr->u.power.disabled = 0;
+ else
+ mwr->u.power.disabled = 1;
+
+ mwr->u.power.value = 0;
+ ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER) +
+ sizeof(struct mwreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get power save mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_set_get_psmode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ t_u32 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSMODE);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ action = MLAN_ACT_SET;
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Flip the value */
+ data = !data;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, action, &data, 0, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET)
+ data = !data;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief Performs warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_warmreset(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ moal_handle *handle = priv->phandle;
+ moal_handle *ref_handle;
+ moal_private *ref_priv;
+ ENTER();
+ ret = woal_pre_warmreset(priv);
+ if (ret)
+ goto done;
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
+ if (ref_priv) {
+ ret = woal_pre_warmreset(ref_priv);
+ if (ret)
+ goto done;
+ ret = woal_warmreset(ref_priv);
+ if (ret)
+ goto done;
+ }
+ }
+ ret = woal_warmreset(priv);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_txpowercfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[5];
+ int user_data_len;
+ int ret = 0;
+ mlan_bss_info bss_info;
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 *arguments = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (strlen(respbuf) ==
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ arguments =
+ respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG);
+ parse_arguments(arguments, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *)req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+
+ if (!user_data_len)
+ req->action = MLAN_ACT_GET;
+ else {
+ /* SET operation */
+ req->action = MLAN_ACT_SET;
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (user_data_len) {
+ case 1:
+ if (data[0] == 0xFF)
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = TX_PWR_CFG_AUTO_CTRL_OFF;
+ else
+ ret = -EINVAL;
+ break;
+ case 3:
+ case 5:
+ switch (data[0]) {
+ case 0: /* LG */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_LG;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ break;
+ case 1: /* 20 MHz HT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_HT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ break;
+ case 2: /* 40 MHz HT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_HT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW40;
+ break;
+ case 3: /* 1 NSS 20 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ pcfg->param.power_ext.power_group[0].nss = 1;
+ break;
+ case 4: /* 2 NSS 20 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ pcfg->param.power_ext.power_group[0].nss = 2;
+ break;
+ case 5: /* 1 NSS 40 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW40;
+ pcfg->param.power_ext.power_group[0].nss = 1;
+ break;
+ case 6: /* 2 NSS 40 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW40;
+ pcfg->param.power_ext.power_group[0].nss = 2;
+ break;
+ case 7: /* 1 NSS 80 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_VHT_BW80;
+ pcfg->param.power_ext.power_group[0].nss = 1;
+ break;
+ case 8: /* 2 NSS 80 MHZ VHT */
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_VHT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_VHT_BW80;
+ pcfg->param.power_ext.power_group[0].nss = 2;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ pcfg->param.power_ext.power_group[0].first_rate_ind =
+ data[1];
+ pcfg->param.power_ext.power_group[0].last_rate_ind =
+ data[1];
+ if (data[2] < bss_info.min_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2], (int)bss_info.min_power_level,
+ (int)bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (data[2] > bss_info.max_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2], (int)bss_info.min_power_level,
+ (int)bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ pcfg->param.power_ext.power_group[0].power_min =
+ data[2];
+ pcfg->param.power_ext.power_group[0].power_max =
+ data[2];
+ pcfg->param.power_ext.power_group[0].power_step = 0;
+ pcfg->param.power_ext.num_pwr_grp = 1;
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ /* GET operation */
+ moal_memcpy_ext(priv->phandle, respbuf,
+ (t_u8 *)&pcfg->param.power_ext,
+ sizeof(pcfg->param.power_ext.num_pwr_grp) +
+ (MIN(pcfg->param.power_ext.num_pwr_grp,
+ MAX_POWER_GROUP) *
+ sizeof(mlan_power_group)),
+ respbuflen);
+ ret = sizeof(pcfg->param.power_ext.num_pwr_grp) +
+ (MIN(pcfg->param.power_ext.num_pwr_grp, MAX_POWER_GROUP) *
+ sizeof(mlan_power_group));
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_pscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data[7] = {0}, ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 3;
+ int i = 3;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ allowed++; /* For beacon missing timeout parameter */
+ allowed += 2; /* For delay to PS and PS mode parameters */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSCFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ if (user_data_len && user_data_len > allowed) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if (user_data_len) {
+ if ((data[0] < PS_NULL_DISABLE)) {
+ PRINTM(MERROR,
+ "Invalid argument for PS null interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) &&
+ (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) &&
+ ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) ||
+ (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
+ PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) &&
+ (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
+ PRINTM(MERROR,
+ "Invalid argument for listen interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[i] != DISABLE_BCN_MISS_TO) &&
+ ((data[i] < MIN_BCN_MISS_TO) ||
+ (data[i] > MAX_BCN_MISS_TO))) {
+ PRINTM(MERROR,
+ "Invalid argument for beacon miss timeout\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if (user_data_len < allowed - 1)
+ data[i] = DELAY_TO_PS_UNCHANGED;
+ else if ((data[i] < MIN_DELAY_TO_PS) ||
+ (data[i] > MAX_DELAY_TO_PS)) {
+ PRINTM(MERROR, "Invalid argument for delay to PS\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != PS_MODE_UNCHANGED) &&
+ (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) &&
+ (data[i] != PS_MODE_NULL)) {
+ PRINTM(MERROR, "Invalid argument for PS mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data,
+ sizeof(data), sizeof(pm_cfg->param.ps_cfg));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg,
+ MIN((sizeof(int) * allowed),
+ sizeof(pm_cfg->param.ps_cfg)),
+ sizeof(data));
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(int) * allowed, respbuflen);
+ ret = sizeof(int) * allowed;
+ if (req->action == MLAN_ACT_SET) {
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ pm_cfg->param.ps_mode = 1;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_bcntimeoutcfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[4] = {0}, ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 4;
+ int i = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCNTIMEOUTCFG);
+
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != allowed) {
+ PRINTM(MERROR, "Invalid args num: input=%d allowed=%d\n",
+ user_data_len, allowed);
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0; i < allowed; i++) {
+ if (data[i] <= 0) {
+ PRINTM(MERROR, "Invalid data[%d]=%d\n", i, data[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_BCN_TIMEOUT;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.bcn_timeout.bcn_miss_tmo_window = (t_u16)data[0];
+ pm_cfg->param.bcn_timeout.bcn_miss_tmo_period = (t_u16)data[1];
+ pm_cfg->param.bcn_timeout.bcn_rq_tmo_window = (t_u16)data[2];
+ pm_cfg->param.bcn_timeout.bcn_rq_tmo_period = (t_u16)data[3];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_sleeppd(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEPPD);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len) {
+ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+ (data == 0) || (data == SLEEP_PERIOD_RESERVED_FF)) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = data;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ data = pm_cfg->param.sleep_period;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx control flag
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_txcontrol(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_TXCONTROL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXCONTROL);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len) {
+ req->action = MLAN_ACT_SET;
+ misc_cfg->param.tx_control = (t_u32)data;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ data = misc_cfg->param.tx_control;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write adapter registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_regrdwr(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[3];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int user_data_len = 0, header_len = 0;
+ t_u8 *arguments = NULL, *space_ind = NULL;
+ t_u32 is_negative_val = MFALSE;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ gfp_t flag;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *)req->pbuf;
+ reg_mem->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGRDWR);
+
+ if (strlen(respbuf) == header_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ arguments = kzalloc(strlen(respbuf) * sizeof(char), flag);
+ if (arguments == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ strcpy(arguments, respbuf + header_len);
+ space_ind = strstr((char *)arguments, " ");
+ if (space_ind)
+ space_ind = strstr(space_ind + 1, " ");
+ if (space_ind) {
+ if (*(char *)(space_ind + 1) == '-') {
+ is_negative_val = MTRUE;
+ arguments[space_ind + 1 - arguments] = '\0';
+ strcat(arguments, space_ind + 2);
+ }
+ }
+ parse_arguments(arguments, data, ARRAY_SIZE(data), &user_data_len);
+ if (is_negative_val == MTRUE)
+ data[2] *= -1;
+
+ if (user_data_len == 2) {
+ req->action = MLAN_ACT_GET;
+ } else if (user_data_len == 3) {
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reg_mem->param.reg_rw.type = (t_u32)data[0];
+ reg_mem->param.reg_rw.offset = (t_u32)data[1];
+ if (user_data_len == 3)
+ reg_mem->param.reg_rw.value = (t_u32)data[2];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.reg_rw,
+ sizeof(reg_mem->param.reg_rw), respbuflen);
+ ret = sizeof(reg_mem->param.reg_rw);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ kfree(arguments);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_rdeeprom(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *)req->pbuf;
+ reg_mem->sub_command = MLAN_OID_EEPROM_RD;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RDEEPROM);
+
+ if (strlen(respbuf) == header_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len == 2) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reg_mem->param.rd_eeprom.offset = (t_u16)data[0];
+ reg_mem->param.rd_eeprom.byte_count = (t_u16)data[1];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ &reg_mem->param.rd_eeprom,
+ sizeof(reg_mem->param.rd_eeprom), respbuflen);
+ ret = sizeof(reg_mem->param.rd_eeprom);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write device memory value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_memrdwr(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *)req->pbuf;
+ reg_mem->sub_command = MLAN_OID_MEM_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MEMRDWR);
+
+ if (strlen(respbuf) == header_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len == 1) {
+ PRINTM(MINFO, "MEM_RW: GET\n");
+ req->action = MLAN_ACT_GET;
+ } else if (user_data_len == 2) {
+ PRINTM(MINFO, "MEM_RW: SET\n");
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reg_mem->param.mem_rw.addr = (t_u32)data[0];
+ if (user_data_len == 2)
+ reg_mem->param.mem_rw.value = (t_u32)data[1];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, respbuf, &reg_mem->param.mem_rw,
+ sizeof(reg_mem->param.mem_rw), respbuflen);
+ ret = sizeof(reg_mem->param.mem_rw);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief Cmd52 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_priv_sdcmd52rw(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ t_u8 rw = 0, func, data = 0;
+ int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDCMD52RW);
+ memset((t_u8 *)buf, 0, sizeof(buf));
+
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ parse_arguments(respbuf + header_len, buf, ARRAY_SIZE(buf),
+ &user_data_len);
+
+ if (user_data_len < 2 || user_data_len > 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ func = (t_u8)buf[0];
+ if (func > 7) {
+ PRINTM(MERROR, "Invalid function number!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ reg = (t_u32)buf[1];
+ if (user_data_len == 2) {
+ rw = 0; /* CMD52 read */
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ }
+ if (user_data_len == 3) {
+ rw = 1; /* CMD52 write */
+ data = (t_u8)buf[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
+ func, reg, data);
+ }
+
+ if (!rw) {
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ data = sdio_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ else
+ data = sdio_f0_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_readb: reading register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_read_ioreg: reading register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif /* SDIO_MMC */
+ } else {
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_writeb: writing register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_write_ioreg: writing register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif /* SDIO_MMC */
+ }
+
+ /* Action = GET */
+ buf[0] = data;
+
+ moal_memcpy_ext(priv->phandle, respbuf, &buf, sizeof(int), respbuflen);
+ ret = sizeof(int);
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO */
+
+/**
+ * @brief Set / Get Auto ARP Response configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_get_auto_arp(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[4];
+ int user_data_len = 0;
+ int ret = 0;
+ moal_handle *handle = NULL;
+
+ ENTER();
+
+ if (priv == NULL) {
+ PRINTM(MERROR, "Invalid priv\n");
+ goto done;
+ }
+ handle = priv->phandle;
+
+ if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_ARP))) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_AUTO_ARP),
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len) {
+ /* Get the enable/disable value from user */
+ handle->hs_auto_arp = data[0];
+ PRINTM(MIOCTL, "Auto ARP : %s\n",
+ handle->hs_auto_arp ? "enable" : "disable");
+ }
+
+ moal_memcpy_ext(handle, respbuf, &handle->hs_auto_arp,
+ sizeof(handle->hs_auto_arp), respbuflen);
+ ret = sizeof(handle->hs_auto_arp);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set deauth control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_deauth_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ds_snmp_mib *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0, header_len = 0, data = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_snmp_mib *)req->pbuf;
+ cfg->sub_command = MLAN_OID_SNMP_MIB_CTRL_DEAUTH;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH_CTRL);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args! %d\n",
+ user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.deauthctrl = (t_u8)data;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = (int)cfg->param.deauthctrl;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#define MRVL_TLV_HEADER_SIZE 4
+/**
+ * @brief Get/Set per packet Txctl and Rxinfo configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_per_pkt_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u8 *pos = NULL;
+ int left_len, header_len = 0;
+ mlan_per_pkt_cfg *perpkt = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PER_PKT_CFG);
+ pos = respbuf + header_len;
+ left_len = respbuflen - header_len;
+
+ if (priv->phandle->card_info->per_pkt_cfg_support == 0) {
+ PRINTM(MERROR, "Device not support per packet configuration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_PER_PKT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (*pos == 0) {
+ /* GET operation */
+ pos++;
+ if (priv->tx_protocols.protocol_num) {
+ perpkt = (mlan_per_pkt_cfg *)pos;
+ perpkt->type = TLV_TYPE_PER_PKT_CFG;
+ perpkt->tx_rx_control = TX_PKT_CTRL;
+ perpkt->proto_type_num =
+ priv->tx_protocols.protocol_num;
+ moal_memcpy_ext(priv->phandle, perpkt->ether_type,
+ priv->tx_protocols.protocols,
+ perpkt->proto_type_num * sizeof(t_u16),
+ MAX_NUM_ETHER_TYPE * sizeof(t_u16));
+ perpkt->len =
+ (perpkt->proto_type_num + 1) * sizeof(t_u16);
+ pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
+ }
+ if (priv->rx_protocols.protocol_num) {
+ perpkt = (mlan_per_pkt_cfg *)pos;
+ perpkt->type = TLV_TYPE_PER_PKT_CFG;
+ perpkt->tx_rx_control = RX_PKT_INFO;
+ perpkt->proto_type_num =
+ priv->rx_protocols.protocol_num;
+ moal_memcpy_ext(priv->phandle, perpkt->ether_type,
+ priv->rx_protocols.protocols,
+ perpkt->proto_type_num * sizeof(t_u16),
+ MAX_NUM_ETHER_TYPE * sizeof(t_u16));
+ perpkt->len =
+ (perpkt->proto_type_num + 1) * sizeof(t_u16);
+ pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
+ }
+ ret = pos - respbuf;
+ goto done;
+ } else if (*pos == 1) {
+ /* SET operation */
+ req->action = MLAN_ACT_SET;
+ pos++;
+ left_len--;
+ while (*pos == TLV_TYPE_PER_PKT_CFG && (left_len > 2)) {
+ perpkt = (mlan_per_pkt_cfg *)pos;
+ if (perpkt->tx_rx_control & TX_PKT_CTRL) {
+ priv->tx_protocols.protocol_num =
+ perpkt->proto_type_num;
+ if (perpkt->proto_type_num <=
+ MAX_NUM_ETHER_TYPE)
+ moal_memcpy_ext(
+ priv->phandle,
+ priv->tx_protocols.protocols,
+ perpkt->ether_type,
+ perpkt->proto_type_num *
+ sizeof(t_u16),
+ MAX_NUM_ETHER_TYPE *
+ sizeof(t_u16));
+ }
+ if (perpkt->tx_rx_control & RX_PKT_INFO) {
+ priv->rx_protocols.protocol_num =
+ perpkt->proto_type_num;
+ if (perpkt->proto_type_num <=
+ MAX_NUM_ETHER_TYPE)
+ moal_memcpy_ext(
+ priv->phandle,
+ priv->rx_protocols.protocols,
+ perpkt->ether_type,
+ perpkt->proto_type_num *
+ sizeof(t_u16),
+ MAX_NUM_ETHER_TYPE *
+ sizeof(t_u16));
+ }
+ if (!perpkt->tx_rx_control) {
+ memset(&priv->tx_protocols, 0,
+ sizeof(dot11_protocol));
+ memset(&priv->rx_protocols, 0,
+ sizeof(dot11_protocol));
+ }
+ pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
+ left_len -= (perpkt->len + MRVL_TLV_HEADER_SIZE);
+ }
+ } else
+ goto done;
+
+ if (perpkt != NULL)
+ misc->param.txrx_pkt_ctrl = perpkt->tx_rx_control;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Region Channel Power
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_chnrgpwr(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int header_len = 0;
+ t_u8 *pos = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ header_len = strlen(PRIV_CMD_GET_CHNRGPWR);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GET_REGIONPWR_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ ret = header_len + sizeof(t_u16) + misc->param.rgchnpwr_cfg.length;
+ pos = respbuf + header_len;
+ moal_memcpy_ext(priv->phandle, pos, &misc->param.rgchnpwr_cfg,
+ sizeof(t_u16) + misc->param.rgchnpwr_cfg.length,
+ respbuflen - header_len);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get TX/RX histogram statistic
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_chan_trpc_cfg *trpc_cfg = NULL;
+ int header_len = 0;
+ t_u8 *pos = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ header_len = strlen(PRIV_CMD_GET_TXPWR_LIMIT);
+ trpc_cfg = (mlan_ds_misc_chan_trpc_cfg *)(respbuf + header_len);
+ if ((trpc_cfg->sub_band != 0) && (trpc_cfg->sub_band != 0x10) &&
+ (trpc_cfg->sub_band != 0x11) && (trpc_cfg->sub_band != 0x12)) {
+ PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GET_CHAN_TRPC_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ misc->param.trpc_cfg.sub_band = trpc_cfg->sub_band;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ ret = header_len + sizeof(t_u16) + sizeof(t_u16) +
+ misc->param.trpc_cfg.length;
+ pos = respbuf + header_len;
+ moal_memcpy_ext(priv->phandle, pos, &misc->param.trpc_cfg,
+ sizeof(t_u16) + sizeof(t_u16) +
+ misc->param.trpc_cfg.length,
+ respbuflen - header_len);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/**
+ * @brief Get TX/RX histogram statistic
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_getcfgchanlist(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int num_chan = 0;
+ wlan_ieee80211_chan_list *plist = NULL;
+ struct ieee80211_supported_band *sband;
+ struct wiphy *wiphy = NULL;
+ int i;
+
+ ENTER();
+ if (priv && priv->wdev)
+ wiphy = priv->wdev->wiphy;
+ if (!wiphy) {
+ PRINTM(MERROR, "wiphy is NULL\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ plist = (wlan_ieee80211_chan_list *)respbuf;
+ sband = wiphy->bands[NL80211_BAND_2GHZ];
+ if (sband) {
+ num_chan += sband->n_channels;
+ for (i = 0; i < sband->n_channels; i++) {
+ plist->chan_list[i].center_freq =
+ sband->channels[i].center_freq;
+ plist->chan_list[i].hw_value =
+ sband->channels[i].hw_value;
+ plist->chan_list[i].flags = sband->channels[i].flags;
+ plist->chan_list[i].max_power =
+ sband->channels[i].max_power;
+ }
+ }
+ sband = wiphy->bands[NL80211_BAND_5GHZ];
+ if (sband) {
+ for (i = 0; i < sband->n_channels; i++) {
+ plist->chan_list[i + num_chan].center_freq =
+ sband->channels[i].center_freq;
+ plist->chan_list[i + num_chan].hw_value =
+ sband->channels[i].hw_value;
+ plist->chan_list[i + num_chan].flags =
+ sband->channels[i].flags;
+ plist->chan_list[i + num_chan].max_power =
+ sband->channels[i].max_power;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
+ plist->chan_list[i + num_chan].dfs_state =
+ sband->channels[i].dfs_state;
+#endif
+ }
+ num_chan += sband->n_channels;
+ }
+ plist->num_chan = num_chan;
+ ret = sizeof(wlan_ieee80211_chan_list) +
+ sizeof(wlan_ieee80211_chan) * num_chan;
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get TX/RX histogram statistic
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_rx_tx_histogram(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ tx_rx_histogram *tx_rx_info = NULL;
+ int header_len = 0;
+ t_u8 *pos = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ header_len = strlen(PRIV_CMD_TX_RX_HISTOGRAM);
+ tx_rx_info = (tx_rx_histogram *)(respbuf + header_len);
+ if (tx_rx_info->enable > 2 ||
+ (tx_rx_info->enable == GET_TX_RX_HISTOGRAM &&
+ (tx_rx_info->action > 3 || tx_rx_info->action <= 0))) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GET_TX_RX_HISTOGRAM;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (tx_rx_info->enable == GET_TX_RX_HISTOGRAM) {
+ misc->param.tx_rx_histogram.enable = ENABLE_TX_RX_HISTOGRAM;
+ misc->param.tx_rx_histogram.action = (t_u16)tx_rx_info->action;
+ } else {
+ misc->param.tx_rx_histogram.enable = tx_rx_info->enable;
+ misc->param.tx_rx_histogram.action |=
+ FLAG_TX_HISTOGRAM | FLAG_RX_HISTOGRAM;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = header_len + 2 * sizeof(t_u8);
+ if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) {
+ pos = respbuf + header_len + 2 * sizeof(t_u8);
+ /* Save tx/rx histogram size */
+ moal_memcpy_ext(priv->phandle, pos,
+ &misc->param.tx_rx_histogram.size,
+ sizeof(misc->param.tx_rx_histogram.size),
+ respbuflen - (header_len + 2 * sizeof(t_u8)));
+ ret += sizeof(misc->param.tx_rx_histogram.size);
+ pos += sizeof(misc->param.tx_rx_histogram.size);
+ moal_memcpy_ext(
+ priv->phandle, pos, &misc->param.tx_rx_histogram.value,
+ misc->param.tx_rx_histogram.size,
+ respbuflen - (header_len + 2 * sizeof(t_u8)) -
+ sizeof(misc->param.tx_rx_histogram.size));
+ ret += misc->param.tx_rx_histogram.size;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get hotspot mode configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_hotspotcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOTSPOTCFG);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ }
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ if (user_data_len == 0) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ cfg->param.hotspot_cfg = data;
+ req->action = MLAN_ACT_SET;
+ }
+ }
+ cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data = cfg->param.hotspot_cfg;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Mgmt Frame passthru mask
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_mgmt_frame_passthru_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *mgmt_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MGMT_FRAME_CTRL);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ }
+
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+
+ if (user_data_len == 0) { /* Get */
+ req->action = MLAN_ACT_GET;
+ } else { /* Set */
+ mgmt_cfg->param.mgmt_subtype_mask = data;
+ req->action = MLAN_ACT_SET;
+ }
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = mgmt_cfg->param.mgmt_subtype_mask;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ * Receive a ADDTS command from the application. The command structure
+ * contains a TSPEC and timeout in milliseconds. The timeout is performed
+ * in the firmware after the ADDTS command frame is sent.
+ *
+ * The TSPEC is received in the API as an opaque block. The firmware will
+ * send the entire data block, including the bytes after the TSPEC. This
+ * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
+ * action frame.
+ *
+ * The IOCTL structure contains two return fields:
+ * - The firmware command result, which indicates failure and timeouts
+ * - The IEEE Status code which contains the corresponding value from
+ * any ADDTS response frame received.
+ *
+ * In addition, the opaque TSPEC data block passed in is replaced with the
+ * TSPEC received in the ADDTS response frame. In case of failure, the
+ * AP may modify the TSPEC on return and in the case of success, the
+ * medium time is returned as calculated by the AP. Along with the TSPEC,
+ * any IEs that are sent in the ADDTS response are also returned and can be
+ * parsed using the IOCTL length as an indicator of extra elements.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure or AP negotiation failure via the commandResult field copied
+ * back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_wmm_addts_req_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_addts_req_t addts_ioctl;
+ int ret = 0, header_len = 0, copy_len = sizeof(addts_ioctl);
+ t_u8 *data_ptr;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ADDTS);
+ data_ptr = respbuf + header_len;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
+
+ memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
+
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&addts_ioctl, data_ptr,
+ sizeof(addts_ioctl), sizeof(addts_ioctl));
+
+ cfg->param.addts.timeout = addts_ioctl.timeout_ms;
+ cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;
+
+ moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data,
+ addts_ioctl.ie_data, cfg->param.addts.ie_data_len,
+ MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ addts_ioctl.cmd_result = cfg->param.addts.result;
+ addts_ioctl.ieee_status_code = (t_u8)cfg->param.addts.status_code;
+ addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
+
+ moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data,
+ cfg->param.addts.ie_data, cfg->param.addts.ie_data_len,
+ MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
+
+ copy_len = (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) +
+ cfg->param.addts.ie_data_len);
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&addts_ioctl, copy_len,
+ respbuflen);
+ ret = copy_len;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ * Receive a DELTS command from the application. The command structure
+ * contains a TSPEC and reason code along with space for a command result
+ * to be returned. The information is packaged is sent to the wlan_cmd.c
+ * firmware command prep and send routines for execution in the firmware.
+ *
+ * The reason code is not used for WMM implementations but is indicated in
+ * the 802.11e specification.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure via the cmd_result field copied back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_wmm_delts_req_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_delts_req_t delts_ioctl;
+ int ret = 0, header_len = 0, copy_len = 0;
+ t_u8 *data_ptr;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELTS);
+ data_ptr = respbuf + header_len;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
+
+ memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
+
+ if (strlen(respbuf) > header_len) {
+ copy_len = MIN(strlen(data_ptr), sizeof(delts_ioctl));
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&delts_ioctl, data_ptr,
+ copy_len, sizeof(delts_ioctl));
+
+ cfg->param.delts.status_code =
+ (t_u32)delts_ioctl.ieee_reason_code;
+ cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;
+
+ moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data,
+ delts_ioctl.ie_data,
+ cfg->param.delts.ie_data_len,
+ MLAN_WMM_TSPEC_SIZE);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Return the firmware command result back to the application
+ * layer */
+ delts_ioctl.cmd_result = cfg->param.delts.result;
+ copy_len = sizeof(delts_ioctl);
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&delts_ioctl,
+ copy_len, respbuflen);
+ ret = copy_len;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ * Receive a AC Queue configuration command which is used to get, set, or
+ * default the parameters associated with a specific WMM AC Queue.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_qconfig(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_config *pqcfg = NULL;
+ wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
+ t_u8 *data_ptr;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
+
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
+ data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG));
+
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&qcfg_ioctl, data_ptr,
+ sizeof(qcfg_ioctl), sizeof(qcfg_ioctl));
+ pqcfg->action = qcfg_ioctl.action;
+ pqcfg->access_category = qcfg_ioctl.access_category;
+ pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ qcfg_ioctl.action = pqcfg->action;
+ qcfg_ioctl.access_category = pqcfg->access_category;
+ qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
+ moal_memcpy_ext(priv->phandle, data_ptr, (t_u8 *)&qcfg_ioctl,
+ sizeof(qcfg_ioctl),
+ respbuflen -
+ (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG)));
+ ret = strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG) + sizeof(qcfg_ioctl);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ * Return the following information for each WMM AC:
+ * - WMM IE Acm Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ * - Firmware Delivery Enabled
+ * - Firmware Trigger Enabled
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_wmm_queue_status_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
+ int ret = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_QSTATUS);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
+
+ if (strlen(respbuf) == header_len) {
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
+ moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl,
+ (void *)&pwmm->param.q_status,
+ sizeof(qstatus_ioctl), sizeof(qstatus_ioctl));
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&qstatus_ioctl,
+ sizeof(qstatus_ioctl), respbuflen);
+ ret = sizeof(qstatus_ioctl);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_wmm_ts_status_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+ int ret = 0, header_len = 0;
+ t_u8 *data_ptr;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TS_STATUS);
+ data_ptr = respbuf + header_len;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&ts_status_ioctl, data_ptr,
+ sizeof(ts_status_ioctl), sizeof(ts_status_ioctl));
+
+ memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
+ pwmm->param.ts_status.tid = ts_status_ioctl.tid;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+ moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl,
+ (void *)&pwmm->param.ts_status, sizeof(ts_status_ioctl),
+ sizeof(ts_status_ioctl));
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&ts_status_ioctl,
+ sizeof(ts_status_ioctl), respbuflen);
+ ret = sizeof(ts_status_ioctl);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get MAC control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_macctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MAC_CTRL);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (user_data_len == 0)
+ req->action = MLAN_ACT_GET;
+ else {
+ cfg->param.mac_ctrl = (t_u32)data;
+ req->action = MLAN_ACT_SET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.mac_ctrl,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get connection status
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_getwap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int ret = 0;
+#ifdef STA_SUPPORT
+ mlan_bss_info bss_info;
+#endif
+
+ ENTER();
+
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (bss_info.media_connected == MTRUE) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ (t_u8 *)&bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH, respbuflen);
+ } else {
+ memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (priv->bss_started) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ priv->current_addr,
+ MLAN_MAC_ADDR_LENGTH, respbuflen);
+ } else {
+ memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
+ }
+ }
+#endif
+ ret = MLAN_MAC_ADDR_LENGTH;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Region Code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_region_code(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGION_CODE);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (user_data_len == 0)
+ req->action = MLAN_ACT_GET;
+ else {
+ cfg->param.region_code = (t_u32)data;
+ req->action = MLAN_ACT_SET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.region_code,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef RX_PACKET_COALESCE
+/**
+ * @brief Set/Get RX packet coalesceing setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_rx_pkt_coalesce_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ t_u32 data[2];
+ int user_data_len = 0, header_len = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ t_u8 *data_ptr;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((user_data_len != 0) && (user_data_len != 2)) {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_RX_PACKET_COALESCE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (user_data_len == 0) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ req->action = MLAN_ACT_SET;
+ cfg->param.rx_coalesce.packet_threshold = data[0];
+ cfg->param.rx_coalesce.delay = data[1];
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(
+ priv->phandle, respbuf,
+ (mlan_ds_misc_rx_packet_coalesce *)&cfg->param.rx_coalesce,
+ req->buf_len, respbuflen);
+ ret = req->buf_len;
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+/**
+ * @brief Set/Get FW side mac address
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_fwmacaddr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ t_u8 data[ETH_ALEN];
+ int ret = 0;
+ int header_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FWMACADDR);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ req->action = MLAN_ACT_SET;
+ memset(data, 0, sizeof(data));
+ woal_mac2u8(data, respbuf + header_len);
+ moal_memcpy_ext(priv->phandle, bss->param.mac_addr, data,
+ ETH_ALEN, sizeof(mlan_802_11_mac_addr));
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, bss->param.mac_addr,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ HEXDUMP("FW MAC Addr:", respbuf, ETH_ALEN);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+/**
+ * @brief Set offchannel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_offchannel(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int data[4];
+ int ret = 0;
+ t_u8 status = 1;
+ t_u8 chan_type = CHAN_NO_HT;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFFCHANNEL);
+
+ if (header_len == strlen(respbuf)) {
+ /* Query current remain on channel status */
+ if (priv->phandle->remain_on_channel)
+ ret = sprintf(respbuf,
+ "There is pending remain on channel from bss %d\n",
+ priv->phandle->remain_bss_index) +
+ 1;
+ else
+ ret = sprintf(respbuf,
+ "There is no pending remain on channel\n") +
+ 1;
+ goto done;
+ } else
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (user_data_len >= 1) {
+ if ((data[0] != 0) && (data[0] != 1)) {
+ PRINTM(MERROR, "action (%d) must be either 0 or 1\n",
+ data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (user_data_len == 2) {
+ if (data[0] == 1) {
+ PRINTM(MERROR,
+ "channel and duration must both the mentioned\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ PRINTM(MWARN,
+ "extra arguments are ignored since action is 'cancel'\n");
+ }
+ }
+ if (user_data_len >= 3) {
+ if (data[0] == 1) {
+ if (data[1] < 0) {
+ PRINTM(MERROR, "channel cannot be negative\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[2] < 0) {
+ PRINTM(MERROR, "duration cannot be negative\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len == 4) {
+ if (data[3] &&
+ (data[3] != CHANNEL_BW_40MHZ_ABOVE) &&
+ (data[3] != CHANNEL_BW_40MHZ_BELOW) &&
+ (data[3] != CHANNEL_BW_80MHZ)) {
+ PRINTM(MERROR, "invalid bandwidth");
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (data[3]) {
+ case CHANNEL_BW_40MHZ_ABOVE:
+ chan_type = CHAN_HT40PLUS;
+ break;
+ case CHANNEL_BW_40MHZ_BELOW:
+ chan_type = CHAN_HT40MINUS;
+ break;
+ case CHANNEL_BW_80MHZ:
+ chan_type = CHAN_VHT80;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (data[0] == 0) {
+ if (!priv->phandle->remain_on_channel) {
+ ret = sprintf(respbuf,
+ "There is no pending remain on channel to be canceled\n") +
+ 1;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
+ MTRUE, &status, NULL, 0,
+ 0)) {
+ PRINTM(MERROR, "remain_on_channel: Failed to cancel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (status == MLAN_STATUS_SUCCESS)
+ priv->phandle->remain_on_channel = MFALSE;
+ } else if (data[0] == 1) {
+ if (woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE, &status,
+ ieee80211_get_channel(
+ priv->wdev->wiphy,
+ ieee80211_channel_to_frequency(
+ data[1]
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ ,
+ (data[1] <= 14 ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ)
+#endif
+ )),
+ chan_type, (t_u32)data[2])) {
+ PRINTM(MERROR, "remain_on_channel: Failed to start\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->remain_bss_index = priv->bss_index;
+ }
+ }
+
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+ else
+ ret = sprintf(respbuf, "OK\n") + 1;
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief Set/Get dscp map
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_priv_set_get_dscp_map(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = NULL;
+ int copy_size = 0, header_len = 0;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DSCP_MAP);
+ if (strlen(respbuf) != header_len) {
+ /* SET operation */
+ pos = respbuf + header_len;
+ moal_memcpy_ext(priv->phandle, priv->dscp_map, pos,
+ sizeof(priv->dscp_map), sizeof(priv->dscp_map));
+ }
+
+ copy_size = MIN(sizeof(priv->dscp_map), respbuflen);
+ moal_memcpy_ext(priv->phandle, respbuf, priv->dscp_map, copy_size,
+ respbuflen);
+ ret = copy_size;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get extended driver version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_get_driver_verext(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int copy_size = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_VEREXT);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ info->param.ver_ext.version_str_sel = data;
+ if (((t_s32)(info->param.ver_ext.version_str_sel)) < 0) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /*
+ * Set the amount to copy back to the application as the minimum of the
+ * available assoc resp data or the buffer provided by the application
+ */
+ copy_size = MIN(strlen(info->param.ver_ext.version_str), respbuflen);
+ moal_memcpy_ext(priv->phandle, respbuf, info->param.ver_ext.version_str,
+ copy_size, respbuflen);
+ ret = copy_size;
+ PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
+ info->param.ver_ext.version_str);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+/**
+ * @brief This function makes USB device to suspend.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_enter_usb_suspend(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+
+ ENTER();
+ ret = woal_enter_usb_suspend(priv->phandle);
+ moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
+ ret = sizeof(int);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function makes USB device to resume.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_exit_usb_suspend(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+
+ ENTER();
+ ret = woal_exit_usb_suspend(priv->phandle);
+ moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
+ ret = sizeof(int);
+
+ LEAVE();
+ return ret;
+}
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+
+#if defined(STA_SUPPORT) && defined(STA_WEXT)
+/**
+ * @brief SET/Get radio
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_radio_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0, option = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RADIO_CTRL);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &option, 1,
+ &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len == 1) {
+ /* Set radio */
+ if (option < 0 || option > 1) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
+ ret = -EFAULT;
+ goto done;
+ } else {
+ /* Get radio status */
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ moal_memcpy_ext(priv->phandle, respbuf, &bss_info.radio_on,
+ sizeof(bss_info.radio_on), respbuflen);
+ ret = sizeof(bss_info.radio_on);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Implement WMM enable command
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_wmm_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_wmm_cfg *wmm = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ wmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WMM_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ /* Set wmm */
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ wmm->param.wmm_enable = MFALSE;
+ else
+ wmm->param.wmm_enable = MTRUE;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, &wmm->param.wmm_enable,
+ sizeof(wmm->param.wmm_enable), respbuflen);
+ ret = sizeof(wmm->param.wmm_enable);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement Mininum BA Threshold cfg command
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_min_ba_threshold_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MIN_BA_THRESHOLD;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIN_BA_THRESH_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ /* Set minimum BA Threshold */
+ if ((data < 0) || (data > 16)) {
+ PRINTM(MERROR,
+ "Error: Valid minimum BA threshold range (0-16)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg_11n->param.min_ba_threshold = data;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf,
+ &cfg_11n->param.min_ba_threshold,
+ sizeof(cfg_11n->param.min_ba_threshold), respbuflen);
+ ret = sizeof(cfg_11n->param.min_ba_threshold);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_SUPPORT)
+/**
+ * @brief Implement 802.11D enable command
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_11d_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ pcfg_11d->param.enable_11d = MFALSE;
+ else
+ pcfg_11d->param.enable_11d = MTRUE;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, &pcfg_11d->param.enable_11d,
+ sizeof(pcfg_11d->param.enable_11d), respbuflen);
+ ret = sizeof(pcfg_11d->param.enable_11d);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D clear chan table command
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_priv_11d_clr_chan_tbl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CLR_TBL);
+
+ if (strlen(respbuf) != header_len) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ req->action = MLAN_ACT_SET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifndef OPCHAN
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_wws_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_misc_cfg *wws = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ wws = (mlan_ds_misc_cfg *)req->pbuf;
+ wws->sub_command = MLAN_OID_MISC_WWS;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WWS_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ PRINTM(MERROR,
+ "Invalid arguments, WWS config not changed!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ wws->param.wws_cfg = (t_u16)data;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, &wws->param.wws_cfg,
+ sizeof(wws->param.wws_cfg), respbuflen);
+ ret = sizeof(wws->param.wws_cfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if defined(REASSOCIATION)
+/**
+ * @brief Set/Get reassociation settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_set_get_reassoc(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ moal_handle *handle = priv->phandle;
+ int data = 0;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REASSOCTRL);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ data = (int)(priv->reassoc_on);
+ moal_memcpy_ext(handle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ if (data == 0) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ priv->reassoc_required = MFALSE;
+ if (!handle->reassoc_on &&
+ handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(
+ &handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ } else if (data == 1) {
+ handle->reassoc_on |= MBIT(priv->bss_index);
+ priv->reassoc_on = MTRUE;
+ } else {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ }
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief Get Transmit buffer size
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_txbuf_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int buf_size = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXBUF_CFG);
+
+ if (strlen(respbuf) != header_len) {
+ PRINTM(MERROR,
+ "Don't support set Tx buffer size after driver loaded!\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ /* Get Tx buffer size from MLAN */
+ req->action = MLAN_ACT_GET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ buf_size = cfg_11n->param.tx_buf_size;
+ moal_memcpy_ext(priv->phandle, respbuf, &buf_size, sizeof(buf_size),
+ respbuflen);
+ ret = sizeof(buf_size);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set/Get auth type
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_auth_type(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int auth_type = 0;
+ t_u32 auth_mode;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_TYPE);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ user_data_len = 0;
+ auth_type = auth_mode;
+ moal_memcpy_ext(priv->phandle, respbuf, &auth_type,
+ sizeof(auth_type), respbuflen);
+ ret = sizeof(auth_type);
+ goto done;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &auth_type, 1,
+ &user_data_len);
+ if (user_data_len == 1) {
+ PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
+ if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
+ (auth_type > MLAN_AUTH_MODE_SAE)) &&
+ (auth_type != MLAN_AUTH_MODE_AUTO)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ auth_mode = auth_type;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
+ auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/get user provisioned local power constraint
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_11h_local_pwr_constraint(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_POWER_CONS);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ req->action = MLAN_ACT_SET;
+ ds_11hcfg->param.usr_local_power_constraint =
+ (t_s8)data;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ data = (int)ds_11hcfg->param.usr_local_power_constraint;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_ht_stream_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_11n_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HT_STREAM_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ if (data != HT_STREAM_MODE_1X1 &&
+ data != HT_STREAM_MODE_2X2) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.stream_cfg = data;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = ((mlan_ds_11n_cfg *)req->pbuf)->param.stream_cfg;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set mimo switch configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_mimo_switch(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2] = {0};
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_MIMO_SWITCH;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIMO_SWITCH);
+
+ if (strlen(respbuf) > header_len) {
+ /* SET operation */
+ req->action = MLAN_ACT_SET;
+ parse_arguments(respbuf + header_len, data, 2, &user_data_len);
+ if (user_data_len == 2) {
+ radio->param.mimo_switch_cfg.txpath_antmode = data[0];
+ radio->param.mimo_switch_cfg.rxpath_antmode = data[1];
+ } else {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get thermal reading
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_thermal(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0, header_len = 0, data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_THERMAL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_THERMAL);
+
+ if (strlen(respbuf) != header_len) {
+ PRINTM(MERROR, "Set is not supported for this command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = (int)cfg->param.thermal;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_beacon_interval(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCN_INTERVAL);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+ if (user_data_len == 1) {
+ if ((data < MLAN_MIN_BEACON_INTERVAL) ||
+ (data > MLAN_MAX_BEACON_INTERVAL)) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ bss->param.bcn_interval = data;
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = ((mlan_ds_bss *)req->pbuf)->param.bcn_interval;
+ moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_signal(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+/** Input data size */
+#define IN_DATA_SIZE 2
+/** Output data size */
+#define OUT_DATA_SIZE 12
+ int ret = 0;
+ int in_data[IN_DATA_SIZE];
+ int out_data[OUT_DATA_SIZE];
+ mlan_ds_get_signal signal;
+ int data_length = 0;
+ int buflen = 0;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ memset(in_data, 0, sizeof(in_data));
+ memset(out_data, 0, sizeof(out_data));
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL);
+
+ if (strlen(respbuf) != header_len)
+ parse_arguments(respbuf + header_len, in_data, IN_DATA_SIZE,
+ &user_data_len);
+ buflen = MIN(user_data_len, IN_DATA_SIZE);
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ if (user_data_len) {
+ if (user_data_len > IN_DATA_SIZE) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ switch (user_data_len) {
+ case 0: /* No checking, get everything */
+ break;
+ case 2: /* Check subtype range */
+ if (in_data[1] < 1 || in_data[1] > 4) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Fall through */
+ case 1: /* Check type range */
+ if (in_data[0] < 1 || in_data[0] > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int)signal.bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n", (int)signal.data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n", (int)signal.data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n", (int)signal.bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n", (int)signal.data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n", (int)signal.data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n", (int)signal.bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n", (int)signal.bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n", (int)signal.data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n", (int)signal.data_nf_avg);
+
+ /* Check type */
+ switch (in_data[0]) {
+ case 0: /* Send everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* RSSI */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_rssi_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* SNR */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_snr_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_snr_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_snr_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* NF */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_nf_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_nf_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_nf_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, out_data,
+ (data_length * sizeof(int)), respbuflen);
+ ret = data_length * sizeof(int);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int woal_signal_ext_enable(moal_private *priv, t_u8 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snmp = (mlan_ds_snmp_mib *)req->pbuf;
+ snmp->sub_command = MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = MLAN_ACT_SET;
+ snmp->param.signalext_enable = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_signal_ext(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+#define PATH_SIZE 13
+ int ret = 0;
+ int data = 0, path = 0, data_len = 0;
+ int user_data_len = 0, header_len = 0;
+ int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_ds_get_signal signal_get[MAX_PATH_NUM];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int path_num;
+ t_u8 enable = 1;
+
+ ENTER();
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT);
+
+ if (strlen(respbuf) != header_len) {
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data < PATH_ALL || data > PATH_AB) {
+ PRINTM(MERROR, "Wrong arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /** Enable signalext feature in firmware */
+ if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_sched_timeout(1000);
+ enable = 0;
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->param.path_id = (t_u16)data;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ woal_signal_ext_enable(priv, enable);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ path_num = 1;
+ if (data == PATH_ALL) {
+ moal_memcpy_ext(priv->phandle, signal_get,
+ info->param.signal_ext, sizeof(signal_get),
+ sizeof(signal_get));
+ path_num = MAX_PATH_NUM;
+ } else
+ moal_memcpy_ext(priv->phandle, signal_get,
+ info->param.signal_ext,
+ sizeof(mlan_ds_get_signal), sizeof(signal_get));
+
+ for (path = 0; path < path_num; path++) {
+ if (signal_get[path].selector == PATH_AB)
+ PRINTM(MINFO, "PATH A+B:\n");
+ else if (signal_get[path].selector == PATH_A)
+ PRINTM(MINFO, "PATH A:\n");
+ else if (signal_get[path].selector == PATH_B)
+ PRINTM(MINFO, "PATH B:\n");
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n",
+ (int)signal_get[path].bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n",
+ (int)signal_get[path].bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n",
+ (int)signal_get[path].data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n",
+ (int)signal_get[path].data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n",
+ (int)signal_get[path].bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n",
+ (int)signal_get[path].bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n",
+ (int)signal_get[path].data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n",
+ (int)signal_get[path].data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n",
+ (int)signal_get[path].bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n",
+ (int)signal_get[path].bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n",
+ (int)signal_get[path].data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n",
+ (int)signal_get[path].data_nf_avg);
+ out_data[data_len++] = (int)signal_get[path].selector;
+ out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
+ out_data[data_len++] = (int)signal_get[path].data_rssi_last;
+ out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
+ out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
+ out_data[data_len++] = (int)signal_get[path].data_snr_last;
+ out_data[data_len++] = (int)signal_get[path].data_snr_avg;
+ out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
+ out_data[data_len++] = (int)signal_get[path].data_nf_last;
+ out_data[data_len++] = (int)signal_get[path].data_nf_avg;
+ }
+ moal_memcpy_ext(
+ priv->phandle, respbuf, out_data,
+ (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
+ respbuflen);
+ ret = data_len * sizeof(int);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signalext v2
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_signal_ext_v2(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+#define PATH_SIZE 13
+ int ret = 0;
+ int data = 0, path = 0, data_len = 0;
+ int user_data_len = 0, header_len = 0;
+ int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_ds_get_signal signal_get[MAX_PATH_NUM];
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int path_num;
+
+ ENTER();
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT_V2);
+ if (strlen(respbuf) != header_len) {
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ }
+
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data < PATH_ALL || data > PATH_AB) {
+ PRINTM(MERROR, "Wrong arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->param.path_id = (t_u16)data;
+
+ /* Send IOCTL request to MLAN */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR,
+ "Enable signalextcfg: mlanutl mlanX signalextcfg 1"
+ " before issuing this command\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ path_num = 1;
+
+ if (data == PATH_ALL) {
+ moal_memcpy_ext(priv->phandle, signal_get,
+ info->param.signal_ext, sizeof(signal_get),
+ sizeof(signal_get));
+ path_num = MAX_PATH_NUM;
+ } else
+ moal_memcpy_ext(priv->phandle, signal_get,
+ info->param.signal_ext,
+ sizeof(mlan_ds_get_signal), sizeof(signal_get));
+
+ PRINTM(MMSG, "data=%d path_num=%d\n", data, path_num);
+
+ for (path = 0; path < path_num; path++) {
+ if (signal_get[path].selector == PATH_AB)
+ PRINTM(MINFO, "PATH A+B:\n");
+ else if (signal_get[path].selector == PATH_A)
+ PRINTM(MINFO, "PATH A:\n");
+ else if (signal_get[path].selector == PATH_B)
+ PRINTM(MINFO, "PATH B:\n");
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n",
+ (int)signal_get[path].bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n",
+ (int)signal_get[path].bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n",
+ (int)signal_get[path].data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n",
+ (int)signal_get[path].data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n",
+ (int)signal_get[path].bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n",
+ (int)signal_get[path].bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n",
+ (int)signal_get[path].data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n",
+ (int)signal_get[path].data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n",
+ (int)signal_get[path].bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n",
+ (int)signal_get[path].bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n",
+ (int)signal_get[path].data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n",
+ (int)signal_get[path].data_nf_avg);
+ out_data[data_len++] = (int)signal_get[path].selector;
+ out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
+ out_data[data_len++] = (int)signal_get[path].data_rssi_last;
+ out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
+ out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
+ out_data[data_len++] = (int)signal_get[path].data_snr_last;
+ out_data[data_len++] = (int)signal_get[path].data_snr_avg;
+ out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
+ out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
+ out_data[data_len++] = (int)signal_get[path].data_nf_last;
+ out_data[data_len++] = (int)signal_get[path].data_nf_avg;
+ }
+ moal_memcpy_ext(
+ priv->phandle, respbuf, out_data,
+ (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
+ respbuflen);
+ ret = data_len * sizeof(int);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set signalext cfg
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return The result of this processing.
+ */
+static int woal_priv_signalext_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int enable = 0;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ ENTER();
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SIGNALEXT_CFG);
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &enable, 1,
+ &user_data_len);
+ if (user_data_len == 1) {
+ if (enable != 0x0 && enable != 0x1) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = woal_signal_ext_enable(priv, enable);
+ } else {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* #ifdef STA_SUPPORT */
+
+#if defined(STA_SUPPORT)
+/**
+ * @brief Make PMF bit required/optional
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_priv_set_get_pmfcfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[2] = {0, 0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ds_misc_pmfcfg *pmfcfg;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ PRINTM(MERROR, "Not supported cmd on this card\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PMFCFG);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ pmfcfg = (mlan_ds_misc_pmfcfg *)&cfg->param.pmfcfg;
+ cfg->sub_command = MLAN_OID_MISC_PMFCFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (user_data_len == 0)
+ req->action = MLAN_ACT_GET;
+ else {
+ pmfcfg->mfpc = (t_u8)data[0];
+ pmfcfg->mfpr = (t_u8)data[1];
+ req->action = MLAN_ACT_SET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.pmfcfg,
+ sizeof(mlan_ds_misc_pmfcfg), respbuflen);
+ ret = sizeof(mlan_ds_misc_pmfcfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get/Set inactivity timeout extend
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_inactivity_timeout_ext(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[4];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ pmlan_ds_inactivity_to inac_to = NULL;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_INACTIVITYTO);
+ memset(data, 0, sizeof(data));
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ if (user_data_len != 0 && user_data_len != 3 && user_data_len != 4) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (user_data_len) {
+ inac_to->timeout_unit = data[0];
+ inac_to->unicast_timeout = data[1];
+ inac_to->mcast_timeout = data[2];
+ if (user_data_len == 4)
+ inac_to->ps_entry_timeout = data[3];
+ req->action = MLAN_ACT_SET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ data[0] = inac_to->timeout_unit;
+ data[1] = inac_to->unicast_timeout;
+ data[2] = inac_to->mcast_timeout;
+ data[3] = inac_to->ps_entry_timeout;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable amsdu_aggr_ctrl
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_11n_amsdu_aggr_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0, data[2] = {0};
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AMSDU_AGGR_CTRL);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, 1, &user_data_len);
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
+ data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming capabilities
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_tx_bf_cap_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+ int ret = 0, bf_cap = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CAP);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &bf_cap, 1,
+ &user_data_len);
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ bf_cfg->param.tx_bf_cap = bf_cap;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bf_cap = bf_cfg->param.tx_bf_cap;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&bf_cap, sizeof(bf_cap),
+ respbuflen);
+ ret = sizeof(bf_cap);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief Turn on/off the sdio clock
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_sdio_clock_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int data = 2;
+ int user_data_len = 0, header_len = 0;
+ /* Initialize the clock state as on */
+ static int clock_state = 1;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDIO_CLOCK);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&clock_state,
+ sizeof(clock_state), respbuflen);
+ ret = sizeof(clock_state);
+ goto done;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
+
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ switch (data) {
+ case CMD_DISABLED:
+ PRINTM(MINFO, "SDIO clock is turned off\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
+ clock_state = data;
+ break;
+ case CMD_ENABLED:
+ PRINTM(MINFO, "SDIO clock is turned on\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
+ clock_state = data;
+ break;
+ default:
+ ret = -EINVAL;
+ PRINTM(MINFO, "sdioclock: wrong parameter\n");
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef SDIO
+/**
+ * @brief Set SDIO Multi-point aggregation control parameters
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_sdio_mpa_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, data[6];
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MPA_CTRL);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len > 6) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ /* Get the values first, then modify these values if
+ * user had modified them */
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (user_data_len == 0) {
+ data[0] = misc->param.mpa_ctrl.tx_enable;
+ data[1] = misc->param.mpa_ctrl.rx_enable;
+ data[2] = misc->param.mpa_ctrl.tx_buf_size;
+ data[3] = misc->param.mpa_ctrl.rx_buf_size;
+ data[4] = misc->param.mpa_ctrl.tx_max_ports;
+ data[5] = misc->param.mpa_ctrl.rx_max_ports;
+
+ PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
+ data[1], data[2], data[3], data[4], data[5]);
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ goto done;
+ }
+
+ switch (user_data_len) {
+ case 6:
+ misc->param.mpa_ctrl.rx_max_ports = data[5];
+ /* fall through */
+ case 5:
+ misc->param.mpa_ctrl.tx_max_ports = data[4];
+ /* fall through */
+ case 4:
+ misc->param.mpa_ctrl.rx_buf_size = data[3];
+ /* fall through */
+ case 3:
+ misc->param.mpa_ctrl.tx_buf_size = data[2];
+ /* fall through */
+ case 2:
+ misc->param.mpa_ctrl.rx_enable = data[1];
+ /* fall through */
+ case 1:
+ /* Set cmd */
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
+ data[1], data[2], data[3], data[4], data[5]);
+
+ misc->param.mpa_ctrl.tx_enable = data[0];
+ break;
+ default:
+ PRINTM(MERROR, "Default case error\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Configure sleep parameters
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_sleep_params_ioctl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_ds_sleep_params *psleep_params = NULL;
+ int data[6] = {0}, i;
+ int user_data_len = 0, header_len = 0;
+#ifdef DEBUG_LEVEL1
+ char err_str[][36] = {{"sleep clock error in ppm"},
+ {"wakeup offset in usec"},
+ {"clock stabilization time in usec"},
+ {"control periodic calibration(0-2)"},
+ {"control of external sleepClock(0-2)"},
+ {"value of reserved for debug"}};
+#endif
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm = (mlan_ds_pm_cfg *)req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEP_PARAMS);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != 6) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+#define MIN_VAL 0x0000
+#define MAX_VAL 0xFFFF
+ for (i = 0; i < 6; i++) {
+ if ((i == 3) || (i == 4)) {
+ /* These two cases are handled below the loop */
+ continue;
+ }
+ if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
+ PRINTM(MERROR, "Invalid %s (0-65535)!\n",
+ err_str[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (data[3] < 0 || data[3] > 2) {
+ PRINTM(MERROR,
+ "Invalid control periodic calibration (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[4] < 0 || data[4] > 2) {
+ PRINTM(MERROR,
+ "Invalid control of external sleep clock (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ psleep_params->error = data[0];
+ psleep_params->offset = data[1];
+ psleep_params->stable_time = data[2];
+ psleep_params->cal_control = data[3];
+ psleep_params->ext_sleep_clk = data[4];
+ psleep_params->reserved = data[5];
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = psleep_params->error;
+ data[1] = psleep_params->offset;
+ data[2] = psleep_params->stable_time;
+ data[3] = psleep_params->cal_control;
+ data[4] = psleep_params->ext_sleep_clk;
+ data[5] = psleep_params->reserved;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get DFS Testing settings
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_dfs_testing(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ int ret = 0;
+ int data[5] = {0};
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_TESTING);
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != 5) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[0] > 1800) {
+ PRINTM(MERROR,
+ "The maximum user CAC is 1800 seconds (30 mins).\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[1] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[3] > 0xFF) {
+ PRINTM(MERROR,
+ "The maximum user fixed channel is 255.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[4] != 0 && ((unsigned)data[4] != 1)) {
+ PRINTM(MERROR, "CAC restart should be 0/1\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
+ (t_u32)data[0] * 1000;
+ ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
+ (t_u16)data[1];
+ ds_11hcfg->param.dfs_testing.usr_no_chan_change =
+ data[2] ? 1 : 0;
+ ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
+ ds_11hcfg->param.dfs_testing.usr_cac_restart = (t_u8)data[4];
+ priv->phandle->cac_restart = (t_u8)data[4];
+ priv->phandle->cac_period_jiffies = (t_u32)data[0] * HZ / 1000;
+ priv->phandle->usr_nop_period_sec = (t_u16)data[1];
+ req->action = MLAN_ACT_SET;
+#ifdef UAP_SUPPORT
+ priv->user_cac_period_msec =
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
+#endif
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ data[0] =
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec / 1000;
+ data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
+ data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
+ data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
+ data[4] = ds_11hcfg->param.dfs_testing.usr_cac_restart;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get DFS W53 settings
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_dfs53cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ int ret = 0;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS53_CFG);
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_DFS_W53_CFG;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args !\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data > DFS_W53_OLD) {
+ PRINTM(MERROR, "Invalid config !\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ds_11hcfg->param.dfs_w53_cfg.dfs53cfg = (t_u8)data;
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ (t_u8 *)&ds_11hcfg->param.dfs_w53_cfg.dfs53cfg,
+ sizeof(ds_11hcfg->param.dfs_w53_cfg.dfs53cfg),
+ respbuflen);
+ ret = sizeof(t_u8);
+ }
+
+ PRINTM(MIOCTL, "dfs w53 cfg %d\n",
+ ds_11hcfg->param.dfs_w53_cfg.dfs53cfg);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief determine the center frquency center index for bandwidth
+ * of 80 MHz and 160 MHz
+ *
+ ** @param priv Pointer to moal_private structure
+ * @param band band
+ * @param pri_chan primary channel
+ * @param chan_bw channel bandwidth
+ *
+ * @return channel center frequency center, if found; O, otherwise
+ */
+
+t_u8 woal_get_center_freq_idx(moal_private *priv, t_u8 band, t_u32 pri_chan,
+ t_u8 chan_bw)
+{
+ t_u8 center_freq_idx = 0;
+
+ if (band & BAND_AAC) {
+ switch (pri_chan) {
+ case 36:
+ case 40:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 38;
+ break;
+ }
+ /* fall through */
+ case 44:
+ case 48:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 46;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 42;
+ break;
+ }
+ /* fall through */
+ case 52:
+ case 56:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 54;
+ break;
+ }
+ /* fall through */
+ case 60:
+ case 64:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 62;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 58;
+ break;
+ } else if (chan_bw == CHANNEL_BW_160MHZ) {
+ center_freq_idx = 50;
+ break;
+ }
+ /* fall through */
+ case 68:
+ case 72:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 70;
+ break;
+ }
+ /* fall through */
+ case 76:
+ case 80:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 78;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 74;
+ break;
+ }
+ /* fall through */
+ case 84:
+ case 88:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 86;
+ break;
+ }
+ /* fall through */
+ case 92:
+ case 96:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 94;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 90;
+ break;
+ }
+ /* fall through */
+ case 100:
+ case 104:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 102;
+ break;
+ }
+ /* fall through */
+ case 108:
+ case 112:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 110;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 106;
+ break;
+ }
+ /* fall through */
+ case 116:
+ case 120:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 118;
+ break;
+ }
+ /* fall through */
+ case 124:
+ case 128:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 126;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 122;
+ } else if (chan_bw == CHANNEL_BW_160MHZ) {
+ center_freq_idx = 114;
+ }
+ break;
+ case 132:
+ case 136:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 134;
+ break;
+ }
+ /* fall through */
+ case 140:
+ case 144:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 126;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 138;
+ }
+ break;
+ case 149:
+ case 153:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 151;
+ break;
+ }
+ /* fall through */
+ case 157:
+ case 161:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 159;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 155;
+ break;
+ }
+ /* fall through */
+ case 165:
+ case 169:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 167;
+ break;
+ }
+ /* fall through */
+ case 173:
+ case 177:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 175;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 171;
+ break;
+ }
+ /* fall through */
+ case 184:
+ case 188:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 186;
+ break;
+ }
+ /* fall through */
+ case 192:
+ case 196:
+ if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
+ chan_bw == CHANNEL_BW_40MHZ_BELOW) {
+ center_freq_idx = 194;
+ break;
+ } else if (chan_bw == CHANNEL_BW_80MHZ) {
+ center_freq_idx = 190;
+ break;
+ }
+ /* fall through */
+ default: /* error. go to the default */
+ center_freq_idx = 42;
+ }
+ }
+ return center_freq_idx;
+}
+
+/**
+ * @brief determine the center frquency center index for bandwidth
+ * of 80 MHz and 160 MHz
+ *
+ ** @param priv Pointer to moal_private structure
+ * @param block_tx 0-no need block traffic 1- need block traffic
+ * @param oper_class oper_class
+ * @param channel channel
+ * @param switch count how many csa/ecsa beacon will send out
+ * @param band_width 1-40Mhz above, 3-40Mhz below, 4-80Mhz, 5-160Mhz
+ * @param ecsa MTRUE/MFALSE;
+ *
+ * @return channel center frequency center, if found; O, otherwise
+ */
+
+static int woal_channel_switch(moal_private *priv, t_u8 block_tx,
+ t_u8 oper_class, t_u8 channel, t_u8 switch_count,
+ t_u8 band_width, t_u8 ecsa)
+{
+ IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
+ IEEEtypes_ChanSwitchAnn_t *chan_switch = NULL;
+ custom_ie *pcust_chansw_ie = NULL;
+ t_u8 center_freq_idx = 0;
+ IEEEtypes_Header_t *pChanSwWrap_ie = NULL;
+ IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = NULL;
+ IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u8 bw;
+ t_u8 new_oper_class = oper_class;
+ int ret = 0;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
+ misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
+
+ pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
+ pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
+ pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
+ pcust_chansw_ie->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
+ BEACON/probe resp*/
+ chan_switch = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
+ chan_switch->element_id = CHANNEL_SWITCH_ANN;
+ chan_switch->len = 3;
+ chan_switch->chan_switch_mode = block_tx;
+ chan_switch->new_channel_num = channel;
+ chan_switch->chan_switch_count = switch_count;
+ DBG_HEXDUMP(MCMD_D, "CSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
+ pcust_chansw_ie->ie_length);
+ switch (band_width) {
+ case CHANNEL_BW_40MHZ_ABOVE:
+ case CHANNEL_BW_40MHZ_BELOW:
+ bw = 40;
+ break;
+ case CHANNEL_BW_80MHZ:
+ bw = 80;
+ break;
+ case CHANNEL_BW_160MHZ:
+ bw = 160;
+ break;
+ default:
+ bw = 20;
+ break;
+ }
+ if (!new_oper_class && ecsa)
+ woal_priv_get_nonglobal_operclass_by_bw_channel(
+ priv, bw, channel, &new_oper_class);
+ if (new_oper_class) {
+ pcust_chansw_ie->ie_length +=
+ sizeof(IEEEtypes_ExtChanSwitchAnn_t);
+ ext_chan_switch =
+ (IEEEtypes_ExtChanSwitchAnn_t
+ *)(pcust_chansw_ie->ie_buffer +
+ sizeof(IEEEtypes_ChanSwitchAnn_t));
+ ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
+ ext_chan_switch->len = 4;
+ ext_chan_switch->chan_switch_mode = block_tx;
+ ext_chan_switch->new_oper_class = new_oper_class;
+ ext_chan_switch->new_channel_num = channel;
+ ext_chan_switch->chan_switch_count = switch_count;
+ DBG_HEXDUMP(MCMD_D, "ECSA IE",
+ (t_u8 *)(pcust_chansw_ie->ie_buffer +
+ sizeof(IEEEtypes_ChanSwitchAnn_t)),
+ pcust_chansw_ie->ie_length -
+ sizeof(IEEEtypes_ChanSwitchAnn_t));
+ }
+ /* bandwidth 40/80/160 should set channel switch wrapper ie for 11ac 5G
+ * channel*/
+ if (band_width && channel > 14) {
+ pChanSwWrap_ie =
+ (IEEEtypes_Header_t *)(pcust_chansw_ie->ie_buffer +
+ pcust_chansw_ie->ie_length);
+ pChanSwWrap_ie->element_id = EXT_POWER_CONSTR;
+ pChanSwWrap_ie->len = sizeof(IEEEtypes_WideBWChanSwitch_t);
+
+ pbwchansw_ie = (IEEEtypes_WideBWChanSwitch_t
+ *)((t_u8 *)pChanSwWrap_ie +
+ sizeof(IEEEtypes_Header_t));
+ pbwchansw_ie->ieee_hdr.element_id = BW_CHANNEL_SWITCH;
+ pbwchansw_ie->ieee_hdr.len =
+ sizeof(IEEEtypes_WideBWChanSwitch_t) -
+ sizeof(IEEEtypes_Header_t);
+
+ center_freq_idx = woal_get_center_freq_idx(priv, BAND_AAC,
+ channel, band_width);
+ if (band_width == CHANNEL_BW_40MHZ_ABOVE ||
+ band_width == CHANNEL_BW_40MHZ_BELOW) {
+ pbwchansw_ie->new_channel_width = 0;
+ pbwchansw_ie->new_channel_center_freq0 =
+ center_freq_idx;
+ } else if (band_width == CHANNEL_BW_80MHZ) {
+ pbwchansw_ie->new_channel_width = 1;
+ pbwchansw_ie->new_channel_center_freq0 =
+ center_freq_idx - 4;
+ pbwchansw_ie->new_channel_center_freq1 =
+ center_freq_idx + 4;
+ } else if (band_width == CHANNEL_BW_160MHZ) {
+ pbwchansw_ie->new_channel_width = 2;
+ pbwchansw_ie->new_channel_center_freq0 =
+ center_freq_idx - 8;
+ pbwchansw_ie->new_channel_center_freq1 =
+ center_freq_idx + 8;
+ } else
+ PRINTM(MERROR,
+ "Invalid bandwidth.Support value 1/3/4/5 for 40+/40-/80/160MHZ\n");
+
+ /*prepare the VHT Transmit Power Envelope IE*/
+ pvhttpcEnv_ie =
+ (IEEEtypes_VhtTpcEnvelope_t
+ *)((t_u8 *)pChanSwWrap_ie +
+ sizeof(IEEEtypes_Header_t) +
+ sizeof(IEEEtypes_WideBWChanSwitch_t));
+ pvhttpcEnv_ie->ieee_hdr.element_id = VHT_TX_POWER_ENV;
+ pvhttpcEnv_ie->ieee_hdr.len =
+ sizeof(IEEEtypes_VhtTpcEnvelope_t) -
+ sizeof(IEEEtypes_Header_t);
+ /* Local Max TX Power Count= 3,
+ * Local TX Power Unit Inter=EIP(0) */
+ pvhttpcEnv_ie->tpc_info = 3;
+ pvhttpcEnv_ie->local_max_tp_20mhz = 0xff;
+ pvhttpcEnv_ie->local_max_tp_40mhz = 0xff;
+ pvhttpcEnv_ie->local_max_tp_80mhz = 0xff;
+ pChanSwWrap_ie->len += sizeof(IEEEtypes_VhtTpcEnvelope_t);
+ pcust_chansw_ie->ie_length +=
+ pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t);
+ DBG_HEXDUMP(MCMD_D, "Channel switch wrapper IE",
+ (t_u8 *)pChanSwWrap_ie,
+ pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t));
+ }
+ if (block_tx) {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ woal_stop_queue(priv->netdev);
+ priv->uap_tx_blocked = MTRUE;
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to set ECSA IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->phandle->chsw_wait_q_woken = MFALSE;
+ /* wait for channel switch to complete */
+ wait_event_interruptible_timeout(
+ priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
+ (u32)HZ * (switch_count + 2) * 110 / 1000);
+
+ pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
+ pcust_chansw_ie->mgmt_subtype_mask = 0;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to clear ECSA IE\n");
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get CFP table codes
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_cfp_code(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ int data[2] = {0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ds_misc_cfp_code *cfp_code = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFP_CODE);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfp_code = &misc_cfg->param.cfp_code;
+ misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfp_code->cfp_code_bg = data[0];
+ if (user_data_len == 2)
+ cfp_code->cfp_code_a = data[1];
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ data[0] = cfp_code->cfp_code_bg;
+ data[1] = cfp_code->cfp_code_a;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx/Rx antenna
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data[3] = {0};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ struct wiphy *wiphy = priv->phandle->wiphy;
+#endif
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ANT_CFG);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ radio->param.ant_cfg.tx_antenna = data[0];
+ radio->param.ant_cfg.rx_antenna = data[0];
+ if (user_data_len == 2)
+ radio->param.ant_cfg.rx_antenna = data[1];
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_CARD9098(priv->phandle->card_type) ||
+ IS_CARD9097(priv->phandle->card_type)) {
+ if (IS_STA_OR_UAP_CFG80211(
+ priv->phandle->params
+ .cfg80211_wext) &&
+ wiphy) {
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ if (((radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF) != 3 &&
+ (radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF) != 0) ||
+ ((radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF) != 3 &&
+ (radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF) != 0))
+ wiphy->bands[IEEE80211_BAND_2GHZ]
+ ->ht_cap.mcs
+ .rx_mask[1] = 0;
+ else if ((radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF) == 3 ||
+ (radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF) == 3)
+ wiphy->bands[IEEE80211_BAND_2GHZ]
+ ->ht_cap.mcs
+ .rx_mask[1] =
+ 0xff;
+ wiphy->bands[IEEE80211_BAND_2GHZ]
+ ->ht_cap.mcs.rx_mask[4] =
+ 0;
+ }
+ if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
+ if (((radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF00) != 0x300 &&
+ (radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF00) != 0) ||
+ ((radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF00) != 0x300 &&
+ (radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF00) != 0)) {
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->ht_cap.mcs
+ .rx_mask[1] = 0;
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->vht_cap
+ .vht_mcs
+ .rx_mcs_map =
+ 0xfffe;
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->vht_cap
+ .vht_mcs
+ .tx_mcs_map =
+ 0xfffe;
+ } else if ((radio->param.ant_cfg
+ .tx_antenna &
+ 0xFF00) == 0x300 ||
+ (radio->param.ant_cfg
+ .rx_antenna &
+ 0xFF00) == 0x300) {
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->ht_cap.mcs
+ .rx_mask[1] =
+ 0xff;
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->vht_cap
+ .vht_mcs
+ .rx_mcs_map =
+ 0xfffa;
+ wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->vht_cap
+ .vht_mcs
+ .tx_mcs_map =
+ 0xfffa;
+ }
+ }
+ }
+ }
+#endif
+ } else {
+ radio->param.ant_cfg_1x1.antenna = data[0];
+ if (user_data_len == 2)
+ radio->param.ant_cfg_1x1.evaluate_time =
+ data[1];
+ }
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ data[0] = radio->param.ant_cfg.tx_antenna;
+ data[1] = radio->param.ant_cfg.rx_antenna;
+ if (data[0] && data[1])
+ ret = sizeof(int) * 2;
+ else
+ ret = sizeof(int) * 1;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ } else {
+ data[0] = (int)radio->param.ant_cfg_1x1.antenna;
+ data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
+ data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/*
+ * @brief Set/Get CWMode
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_set_get_cwmode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_cw_mode_ctrl *cwmode;
+ int ret = 0;
+ int header_len = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CWMODE_CTRL;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CWMODE);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ ioctl_req->action = MLAN_ACT_SET;
+
+ cwmode = (mlan_ds_cw_mode_ctrl *)(respbuf + header_len +
+ sizeof(t_u8));
+ misc->param.cwmode.mode = cwmode->mode;
+ misc->param.cwmode.txPower = cwmode->txPower;
+ misc->param.cwmode.rateInfo = cwmode->rateInfo;
+ misc->param.cwmode.channel = cwmode->channel;
+ misc->param.cwmode.chanInfo = cwmode->chanInfo;
+ misc->param.cwmode.pktLength = cwmode->pktLength;
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.cwmode,
+ sizeof(misc->param.cwmode), respbuflen);
+ ret = sizeof(misc->param.cwmode);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get out band independent reset
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_ind_rst_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data[2] = {0};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_IND_RST_CFG);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+ misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((user_data_len == 1) || (user_data_len == 2)) {
+ req->action = MLAN_ACT_SET;
+
+ /* ir_mode */
+ if (data[0] < 0 || data[0] > 2) {
+ PRINTM(MERROR, "Invalid ir mode parameter!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ind_rst_cfg.ir_mode = data[0];
+
+ /* gpio_pin */
+ if (user_data_len == 2) {
+ if ((data[1] != 0xFF) && (data[1] < 0)) {
+ PRINTM(MERROR,
+ "Invalid gpio pin no!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ind_rst_cfg.gpio_pin = data[1];
+ }
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = (int)misc->param.ind_rst_cfg.ir_mode;
+ data[1] = (int)misc->param.ind_rst_cfg.gpio_pin;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set system clock
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_sysclock(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int data[65];
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int ret = 0, i = 0;
+ int user_data_len = 0, header_len = 0;
+ int data_length = 0, length_index = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SYSCLOCK);
+ memset(data, 0, sizeof(data));
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ }
+
+ if (user_data_len > MLAN_MAX_CLK_NUM) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (user_data_len) {
+ /* SET operation */
+ req->action = MLAN_ACT_SET;
+
+ /* Set configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ cfg->param.sys_clock.sys_clk_num =
+ MIN(MLAN_MAX_CLK_NUM, user_data_len);
+ for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
+ cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /* GET operation */
+ req->action = MLAN_ACT_GET;
+
+ /* Get configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Current system clock */
+ data[1] = (int)cfg->param.sys_clock.cur_sys_clk;
+ data_length = 1;
+
+ length_index =
+ MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Configurable clocks */
+ for (i = 1; i <= length_index; i++)
+ data[i + data_length] =
+ (int)cfg->param.sys_clock.sys_clk[i - 1];
+
+ data_length += length_index;
+
+ /* Get supported clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ length_index =
+ MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Supported clocks */
+ for (i = 1; i <= length_index; i++)
+ data[i + data_length] =
+ (int)cfg->param.sys_clock.sys_clk[i - 1];
+
+ data_length += length_index;
+
+ /* Send length as first element */
+ data[0] = data_length;
+ data_length++;
+
+ moal_memcpy_ext(priv->phandle, respbuf, data,
+ sizeof(int) * data_length, respbuflen);
+ ret = data_length * sizeof(int);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get GTK/PTK
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_key(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0, copy_len = 0;
+ int header_len = 0;
+ unsigned int i;
+ t_u8 key_ascii[256];
+ t_u8 *tmp;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_KEY);
+ if (strlen(respbuf) != header_len) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(key_ascii, 0x00, sizeof(key_ascii));
+ tmp = key_ascii;
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can't get key in un-associated state\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Get Unicast Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = 0;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "PTK: ");
+ tmp += 5;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ /* Get Multicase Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "GTK: ");
+ tmp += 5;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ /* Get IGTK Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK;
+ memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "IGTK: ");
+ tmp += 6;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ copy_len = tmp - key_ascii;
+ moal_memcpy_ext(priv->phandle, respbuf, &key_ascii, copy_len,
+ respbuflen);
+ ret = copy_len;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Associate to a specific indexed entry in the ScanTable
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_associate_ssid_bssid(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0, copy_len = 0;
+ int header_len = 0;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ mlan_bss_info bss_info;
+#endif
+ char buf[64];
+ t_u8 buflen;
+ t_u8 mac_idx;
+ t_u8 i;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCIATE);
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = strlen(respbuf) - header_len;
+ mac_idx = 0;
+ buflen = MIN(copy_len, (sizeof(buf) - 1));
+ memset(buf, 0, sizeof(buf));
+ memset(&ssid_bssid, 0, sizeof(ssid_bssid));
+
+ if (buflen < (3 * ETH_ALEN) + 2) {
+ PRINTM(MERROR,
+ "Associate: Insufficient length in IOCTL input\n");
+
+ /* buffer should be at least 3 characters per BSSID octet "00:"
+ ** plus a space separater and at least 1 char in the SSID
+ */
+ ret = -EINVAL;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, buflen,
+ sizeof(buf));
+
+ /* Skip white space */
+ for (i = 0; (i < buflen) && (buf[i] == ' '); i++)
+ ;
+
+ /* Copy/Convert the BSSID */
+ for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
+ if (buf[i] == ':') {
+ mac_idx++;
+ } else {
+ ssid_bssid.bssid[mac_idx] = (t_u8)woal_atox(buf + i);
+
+ while (((i < buflen) && isxdigit(buf[i + 1])))
+ /* Skip entire hex value */
+ i++;
+ }
+ }
+
+ /* Skip one space between the BSSID and start of the SSID */
+ i++;
+
+ /* Copy the SSID */
+ ssid_bssid.ssid.ssid_len = buflen - i;
+ moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i,
+ sizeof(ssid_bssid.ssid.ssid),
+ sizeof(ssid_bssid.ssid.ssid));
+
+ PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
+ MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len,
+ ssid_bssid.ssid.ssid);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0x00, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(mlan_802_11_mac_addr));
+ }
+#endif /* REASSOCIATION */
+
+done:
+ LEAVE();
+ return 0;
+}
+
+/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
+#define MAX_IN_OUT_CHAR 256
+/** Tx BF Global conf argument index */
+#define BF_ENABLE_PARAM 1
+#define SOUND_ENABLE_PARAM 2
+#define FB_TYPE_PARAM 3
+#define SNR_THRESHOLD_PARAM 4
+#define SOUND_INTVL_PARAM 5
+#define BF_MODE_PARAM 6
+#define MAX_TX_BF_GLOBAL_ARGS 6
+#define BF_CFG_ACT_GET 0
+#define BF_CFG_ACT_SET 1
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_tx_bf_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0;
+ int ret = 0, copy_len = 0;
+ int bf_action = 0, interval = 0;
+ int snr = 0, i, tmp_val = 0;
+ t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
+ t_u8 *str, *token, *pos;
+ t_u16 action = 0;
+
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ mlan_trigger_sound_args *bf_sound = NULL;
+ mlan_tx_bf_peer_args *tx_bf_peer = NULL;
+ mlan_snr_thr_args *bf_snr = NULL;
+ mlan_bf_periodicity_args *bf_periodicity = NULL;
+ mlan_bf_global_cfg_args *bf_global = NULL;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CFG);
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+ /* Pointer to corresponding buffer */
+ bf_sound = bf_cfg.body.bf_sound;
+ tx_bf_peer = bf_cfg.body.tx_bf_peer;
+ bf_snr = bf_cfg.body.bf_snr;
+ bf_periodicity = bf_cfg.body.bf_periodicity;
+ bf_global = &bf_cfg.body.bf_global_cfg;
+
+ /* Total characters in buffer */
+ char_count = strlen(respbuf) - header_len;
+ copy_len = char_count;
+ memset(buf, 0, sizeof(buf));
+ if (char_count) {
+ if (copy_len > sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, buf, respbuf + header_len,
+ copy_len, sizeof(buf));
+
+ if (char_count > 1 && buf[1] != ';') {
+ PRINTM(MERROR,
+ "No action argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Replace ';' with NULL in the string to separate args */
+ for (i = 0; i < char_count; i++) {
+ if (buf[i] == ';')
+ buf[i] = '\0';
+ }
+ /* The first byte represents the beamforming action */
+ if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ /* Eliminate action field */
+ token = &buf[2];
+ for (i = 1, str = &buf[2]; token != NULL; i++) {
+ token = strstr(str, " ");
+ pos = str;
+ if (token != NULL) {
+ *token = '\0';
+ str = token + 1;
+ }
+ woal_atoi(&tmp_val, pos);
+ switch (i) {
+ case BF_ENABLE_PARAM:
+ bf_global->bf_enbl =
+ (t_u8)tmp_val;
+ break;
+ case SOUND_ENABLE_PARAM:
+ bf_global->sounding_enbl =
+ (t_u8)tmp_val;
+ break;
+ case FB_TYPE_PARAM:
+ bf_global->fb_type =
+ (t_u8)tmp_val;
+ break;
+ case SNR_THRESHOLD_PARAM:
+ bf_global->snr_threshold =
+ (t_u8)tmp_val;
+ break;
+ case SOUND_INTVL_PARAM:
+ bf_global->sounding_interval =
+ (t_u16)tmp_val;
+ break;
+ case BF_MODE_PARAM:
+ bf_global->bf_mode =
+ (t_u8)tmp_val;
+ break;
+ default:
+ PRINTM(MERROR,
+ "Invalid Argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ /* First arg = 2 BfAction
+ * Second arg = 17 MAC "00:50:43:20:BF:64" */
+ if (char_count != 19) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ woal_mac2u8(bf_sound->peer_mac, &buf[2]);
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ /* First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 1 (min char) TX BF interval
+ * 10 (max char) u32 maximum value
+ * 4294967295 */
+ if (char_count < 19 || char_count > 30) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
+ if (char_count == 19) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ if (woal_atoi(&interval, &buf[20]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_periodicity->interval = interval;
+ }
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ /* Handle only SET operation here
+ * First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 2 enable/disable bf
+ * Fourth arg = 2 enable/disable sounding
+ * Fifth arg = 1 FB Type */
+ if (char_count != 25 && char_count != 1) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
+ woal_atoi(&tmp_val, &buf[20]);
+ tx_bf_peer->bf_enbl = (t_u8)tmp_val;
+ woal_atoi(&tmp_val, &buf[22]);
+ tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
+ woal_atoi(&tmp_val, &buf[24]);
+ tx_bf_peer->fb_type = (t_u8)tmp_val;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ /* First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 1/2 SNR u8 - can be 1/2 charerters */
+ if (char_count != 1 &&
+ !(char_count == 21 || char_count == 22)) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(bf_snr->peer_mac, &buf[2]);
+ if (woal_atoi(&snr, &buf[20]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_snr->snr = snr;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Save the value */
+ bf_cfg.bf_action = bf_action;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ moal_memcpy_ext(priv->phandle, respbuf, bf_global,
+ sizeof(mlan_bf_global_cfg_args), respbuflen);
+ ret = sizeof(mlan_bf_global_cfg_args);
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ moal_memcpy_ext(priv->phandle, respbuf, bf_sound,
+ sizeof(mlan_bf_global_cfg_args), respbuflen);
+ ret = sizeof(mlan_bf_global_cfg_args);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ moal_memcpy_ext(priv->phandle, respbuf, bf_periodicity,
+ sizeof(mlan_bf_periodicity_args), respbuflen);
+ ret = sizeof(mlan_bf_periodicity_args);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ moal_memcpy_ext(priv->phandle, respbuf, tx_bf_peer,
+ sizeof(mlan_tx_bf_peer_args), respbuflen);
+ ret = sizeof(mlan_tx_bf_peer_args);
+ break;
+ case SET_SNR_THR_PEER:
+ moal_memcpy_ext(priv->phandle, respbuf, bf_snr,
+ sizeof(mlan_snr_thr_args), respbuflen);
+ ret = sizeof(mlan_snr_thr_args);
+ break;
+ default:
+ ret = 0;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief Cmd53 read/write register
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_cmd53rdwr(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0;
+ int ret = 0;
+ t_u8 *buf = NULL;
+ t_u8 *data = NULL;
+ t_u8 rw, func, mode;
+ t_u16 blklen = 0, blknum = 0;
+ int reg = 0;
+ t_u32 pattern_len = 0, total_len = 0;
+ t_u16 cmd_len;
+ gfp_t flag;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SD_CMD53_RW);
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ data = kzalloc(WOAL_2K_BYTES, flag);
+ if (!data) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, &cmd_len, respbuf + header_len,
+ sizeof(cmd_len), sizeof(cmd_len));
+ buf = respbuf + header_len + sizeof(cmd_len);
+
+ rw = buf[0]; /* read/write (0/1) */
+ func = buf[1]; /* func (0/1/2) */
+ reg = buf[5]; /* address */
+ reg = (reg << 8) | buf[4];
+ reg = (reg << 8) | buf[3];
+ reg = (reg << 8) | buf[2];
+ mode = buf[6]; /* byte mode/block mode (0/1) */
+ blklen = buf[8]; /* block size */
+ blklen = (blklen << 8) | buf[7];
+ blknum = buf[10]; /* block number or byte number */
+ blknum = (blknum << 8) | buf[9];
+
+ if (mode == BYTE_MODE)
+ blklen = 1;
+ else
+ mode = BLOCK_MODE;
+
+ total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
+ if (total_len > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Total data length is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO,
+ "CMD53 read/write, func = %d, addr = %#x, mode = %d, "
+ "block size = %d, block(byte) number = %d\n",
+ func, reg, mode, blklen, blknum);
+
+ if (!rw) {
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (sdio_readsb(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func,
+ respbuf, reg, total_len)) {
+ PRINTM(MERROR,
+ "sdio_readsb: reading memory 0x%x failed\n",
+ reg);
+ goto done;
+ }
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ ret = total_len;
+ } else {
+ int pos = 0;
+ pattern_len = cmd_len - 11;
+ if (pattern_len > total_len)
+ pattern_len = total_len;
+
+ /* Copy/duplicate the pattern to data buffer */
+ for (pos = 0; pos < total_len; pos++)
+ data[pos] = buf[11 + (pos % pattern_len)];
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (sdio_writesb(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func,
+ reg, data, total_len))
+ PRINTM(MERROR,
+ "sdio_writesb: writing memory 0x%x failed\n",
+ reg);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ }
+
+done:
+ kfree(data);
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO */
+
+/**
+ * @brief Set/Get Port Control mode
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_port_ctrl(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0, user_data_len = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0, data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PORT_CTRL);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len == 1) {
+ sec->param.port_ctrl_enabled = data;
+ req->action = MLAN_ACT_SET;
+ } else {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ &sec->param.port_ctrl_enabled, sizeof(int),
+ respbuflen);
+ ret = sizeof(int);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the By-passed TX packet from
+ * upper layer
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0;
+ int ret = 0;
+ struct sk_buff *skb = NULL;
+ struct ethhdr *eth;
+ t_u16 moreLen = 0, copyLen = 0;
+ ENTER();
+
+#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PB_BYPASS);
+ copyLen = strlen(respbuf) - header_len;
+ moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET +
+ sizeof(mlan_buffer);
+
+ skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
+ if (skb == NULL) {
+ PRINTM(MERROR, "kmalloc no memory !!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, moreLen);
+
+ moal_memcpy_ext(priv->phandle, skb_put(skb, copyLen),
+ respbuf + header_len, copyLen, copyLen);
+
+ eth = (struct ethhdr *)skb->data;
+ eth->h_proto = __constant_htons(eth->h_proto);
+ skb->dev = priv->netdev;
+
+ HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
+
+ woal_hard_start_xmit(skb, priv->netdev);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Robustcoex gpiocfg
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_robustcoex(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0, user_data_len = 0;
+ int ret = 0, data[3] = {0};
+ mlan_ds_misc_cfg *robust_coex_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ robust_coex_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ while (respbuf[0] == ' ') {
+ /** skip space */
+ respbuf++;
+ }
+
+ if (strncmp(respbuf, "gpiocfg", strlen("gpiocfg")) == 0) {
+ header_len = strlen("gpiocfg") + 1;
+ parse_arguments(respbuf + header_len, data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len > 3) {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] != ROBUSTCOEX_GPIOCFG_ENABLE &&
+ data[0] != ROBUSTCOEX_GPIOCFG_DISABLE) {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == ROBUSTCOEX_GPIOCFG_ENABLE) {
+ if (user_data_len != 3) {
+ PRINTM(MMSG,
+ "Please provide gpio num and gpio polarity for ROBUSTCOEX_GPIOCFG_ENABLE\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ robust_coex_cfg->param.robustcoexparams.method =
+ ROBUSTCOEX_GPIO_CFG;
+ robust_coex_cfg->param.robustcoexparams.enable =
+ ROBUSTCOEX_GPIOCFG_ENABLE;
+ robust_coex_cfg->param.robustcoexparams.gpio_num =
+ data[1];
+ robust_coex_cfg->param.robustcoexparams.gpio_polarity =
+ data[2];
+ } else {
+ robust_coex_cfg->param.robustcoexparams.method =
+ ROBUSTCOEX_GPIO_CFG;
+ robust_coex_cfg->param.robustcoexparams.enable =
+ ROBUSTCOEX_GPIOCFG_DISABLE;
+ robust_coex_cfg->param.robustcoexparams.gpio_num = 0;
+ robust_coex_cfg->param.robustcoexparams.gpio_polarity =
+ 0;
+ }
+ req->action = MLAN_ACT_SET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ robust_coex_cfg->sub_command = MLAN_OID_MISC_ROBUSTCOEX;
+ } else {
+ PRINTM(MERROR, "Invalid parameter\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set DMCS mapping policy or get DMCS status
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_dmcs(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int header_len = 0, user_data_len = 0;
+ int ret = 0, data[2] = {0};
+ mlan_ds_misc_cfg *dmcs_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DMCS);
+ dmcs_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ dmcs_cfg->sub_command = MLAN_OID_MISC_DMCS_CONFIG;
+ dmcs_cfg->param.dmcs_policy.subcmd = data[0];
+ switch (data[0]) {
+ case 0:
+ if (user_data_len != 2) {
+ PRINTM(MERROR, "Please provide mapping policy\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ dmcs_cfg->param.dmcs_policy.mapping_policy = data[1];
+ break;
+ case 1:
+ req->action = MLAN_ACT_GET;
+ break;
+ default:
+ break;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (req->action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ &dmcs_cfg->param.dmcs_status,
+ sizeof(mlan_ds_misc_dmcs_status), respbuflen);
+ }
+ ret = sizeof(mlan_ds_misc_dmcs_status);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set and get boot sleep configure
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_bootsleep(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ int user_data_len = 0;
+ int header_len = 0;
+ int allowed = 1;
+ int data[1] = {0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_BOOT_SLEEP;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BOOTSLEEP);
+
+ if (strlen(respbuf) == header_len) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ req->action = MLAN_ACT_SET;
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != allowed) {
+ PRINTM(MERROR, "Invalid number of args! %d\n",
+ user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.boot_sleep = data[0] ? 1 : 0;
+ PRINTM(MIOCTL, "boot sleep cfg:%u\n", misc->param.boot_sleep);
+ }
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, &misc->param.boot_sleep,
+ sizeof(misc->param.boot_sleep), respbuflen);
+ ret = sizeof(misc->param.boot_sleep);
+
+ PRINTM(MIOCTL, "boot sleep cfg: %u\n", misc->param.boot_sleep);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(PCIE)
+/**
+ * @brief Enable SSU support
+ * @param priv Pointer to moal_private structure
+ * @param used_len used length
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_ssu_cmd(moal_private *priv, t_u8 used_len, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *ssu_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ ssu_params_cfg *ssu_params;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ssu_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ memset(&ssu_cfg->param.ssu_params, 0, sizeof(mlan_ds_ssu_params));
+ if (!used_len) {
+ req->action = MLAN_ACT_SET;
+ ssu_cfg->param.ssu_params.nskip = 0;
+ ssu_cfg->param.ssu_params.nsel = 1;
+ ssu_cfg->param.ssu_params.adcdownsample = 3;
+ ssu_cfg->param.ssu_params.mask_adc_pkt = 0;
+ ssu_cfg->param.ssu_params.out_16bits = 1;
+ } else {
+ ssu_params = (ssu_params_cfg *)respbuf;
+ DBG_HEXDUMP(MCMD_D, "User SSU params:", respbuf,
+ sizeof(mlan_ds_ssu_params));
+ if (ssu_params->ssu_mode == 2)
+ req->action = MLAN_ACT_DEFAULT;
+ else {
+ req->action = MLAN_ACT_SET;
+ ssu_cfg->param.ssu_params.nskip = ssu_params->nskip;
+ ssu_cfg->param.ssu_params.nsel = ssu_params->nsel;
+ ssu_cfg->param.ssu_params.adcdownsample =
+ ssu_params->adcdownsample;
+ ssu_cfg->param.ssu_params.mask_adc_pkt =
+ ssu_params->mask_adc_pkt;
+ ssu_cfg->param.ssu_params.out_16bits =
+ ssu_params->out_16bits;
+ ssu_cfg->param.ssu_params.spec_pwr_enable =
+ ssu_params->spec_pwr_enable;
+ ssu_cfg->param.ssu_params.rate_deduction =
+ ssu_params->rate_deduction;
+ ssu_cfg->param.ssu_params.n_pkt_avg =
+ ssu_params->n_pkt_avg;
+ }
+ }
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ ssu_cfg->sub_command = MLAN_OID_MISC_SSU;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief configure 11ax HE capability or HE operation
+ *
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param len length used
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative value
+ */
+static int woal_priv_11axcfg_cmd(moal_private *priv, t_u8 *respbuf, t_u8 len,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ax_cfg *cfg = NULL;
+ mlan_ds_11ax_he_cfg *data_ptr = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ data_ptr = (mlan_ds_11ax_he_cfg *)respbuf;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_11AX_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg = (mlan_ds_11ax_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_11AX_HE_CFG;
+ if (len)
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.he_cfg,
+ respbuf, len, sizeof(mlan_ds_11ax_he_cfg));
+ else
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.he_cfg,
+ sizeof(mlan_ds_11ax_he_cfg), respbuflen);
+ ret = sizeof(mlan_ds_11ax_he_cfg);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Configure TWT Setup parameters
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param len Length used
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative
+ * value
+ */
+static int woal_priv_twt_setup(moal_private *priv, t_u8 *respbuf, t_u8 len,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_twtcfg *cfg = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_11AX_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg = (mlan_ds_twtcfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
+ cfg->sub_id = MLAN_11AX_TWT_SETUP_SUBID;
+
+ if (len) {
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_setup,
+ respbuf, len, sizeof(mlan_ds_twt_setup));
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sizeof(mlan_ds_twt_setup);
+done:
+ if (status != MLAN_STATUS_PENDING) {
+ kfree(req);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure TWT Tear down parameters
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param respbuf A pointer to response buffer
+ * @param len Length used
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written if successful else negative
+ * value
+ */
+static int woal_priv_twt_teardown(moal_private *priv, t_u8 *respbuf, t_u8 len,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_twtcfg *cfg = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_11AX_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg = (mlan_ds_twtcfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
+ cfg->sub_id = MLAN_11AX_TWT_TEARDOWN_SUBID;
+
+ if (len) {
+ moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_teardown,
+ respbuf, len, sizeof(mlan_ds_twt_teardown));
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sizeof(mlan_ds_twt_teardown);
+done:
+ if (status != MLAN_STATUS_PENDING) {
+ kfree(req);
+ }
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(UAP_CFG80211)
+/**
+ * @brief Set/Get P2P NoA (Notice of Absence) parameters
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_cfg_noa(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0, user_data_len = 0;
+ int ret = 0, data[7];
+ mlan_ds_wifi_direct_config noa_cfg;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_NOA);
+ memset(&noa_cfg, 0, sizeof(noa_cfg));
+
+ memset(data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len > 5) {
+ PRINTM(MERROR, "invalid parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ noa_cfg.flags |= WIFI_DIRECT_NOA;
+
+ if (woal_p2p_config(priv, MLAN_ACT_GET, &noa_cfg) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not get P2P noa config\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ moal_memcpy_ext(priv->phandle, respbuf, &noa_cfg,
+ sizeof(noa_cfg), respbuflen);
+ ret = sizeof(noa_cfg);
+ } else {
+ switch (user_data_len) {
+ case 5:
+ noa_cfg.noa_interval = (t_u32)data[4];
+ /* fall through */
+ case 4:
+ noa_cfg.noa_duration = (t_u32)data[3];
+ /* fall through */
+ case 3:
+ if (data[2] < 1 || data[2] > 255) {
+ PRINTM(MERROR,
+ "Invalid number of absence intervals\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ noa_cfg.noa_count = (t_u8)data[2];
+ /* fall through */
+ case 2:
+ if (data[1] < 0 || data[1] > 255) {
+ PRINTM(MERROR, "Invalid Index\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ noa_cfg.index = (t_u16)data[1];
+ /* fall through */
+ case 1:
+ if (data[0] < 0 || data[0] > 1) {
+ PRINTM(MERROR, "Invalid noa enable\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ noa_cfg.noa_enable = (t_u8)data[0];
+ noa_cfg.flags |= WIFI_DIRECT_NOA;
+ break;
+ default:
+ break;
+ }
+ woal_p2p_config(priv, MLAN_ACT_SET, &noa_cfg);
+ }
+
+done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get P2P OPP-PS parameters
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_cfg_opp_ps(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int header_len = 0, user_data_len = 0;
+ int ret = 0, data[7];
+ mlan_ds_wifi_direct_config opp_ps_cfg;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_OPP_PS);
+ memset(&opp_ps_cfg, 0, sizeof(opp_ps_cfg));
+
+ memset(data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "invalid parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
+
+ if (woal_p2p_config(priv, MLAN_ACT_GET, &opp_ps_cfg) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not get P2P opp ps config\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ moal_memcpy_ext(priv->phandle, respbuf, &opp_ps_cfg,
+ sizeof(opp_ps_cfg), respbuflen);
+ ret = sizeof(opp_ps_cfg);
+ } else {
+ switch (user_data_len) {
+ case 2:
+ opp_ps_cfg.ct_window = (t_u8)data[1];
+ /* fall through */
+ case 1:
+ if (data[0] < 0 || data[0] > 1) {
+ PRINTM(MERROR, "Invalid ps enable\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ opp_ps_cfg.opp_ps_enable = (t_u8)data[0];
+ opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
+ /* fall through */
+ default:
+ break;
+ }
+ woal_p2p_config(priv, MLAN_ACT_SET, &opp_ps_cfg);
+ }
+
+done:
+
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+#define DEF_NOA_INTERVAL 100
+/**
+ ** @brief Set/Get P2P NoA (Notice of Absence) parameters
+ ** @param priv Pointer to moal_private structure
+ ** @param respbuf Pointer to response buffer
+ ** @param resplen Response buffer length
+ **
+ ** @return Number of bytes written, negative for failure.
+ **/
+static int woal_p2p_ps_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ int user_data_len = 0;
+ int ret = 0, data[2];
+ u32 duration = priv->phandle->noa_duration;
+ u32 interval = 0;
+
+ ENTER();
+ if (strlen(respbuf) > strlen("P2P_PERIODIC_SLEEP")) {
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen("P2P_PERIODIC_SLEEP") + 1,
+ data, ARRAY_SIZE(data), &user_data_len);
+ }
+ if ((user_data_len != 1) && (user_data_len != 2)) {
+ PRINTM(MERROR,
+ " Invalid parameter number for P2P_PERIODIC_SLEEP");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] < DEF_NOA_INTERVAL)
+ interval = DEF_NOA_INTERVAL;
+ else
+ interval = (data[0] + DEF_NOA_INTERVAL - 1) / DEF_NOA_INTERVAL *
+ DEF_NOA_INTERVAL;
+
+ if (user_data_len == 2)
+ duration = data[1];
+ if (duration >= interval) {
+ PRINTM(MERROR,
+ " Invalid noa duration/interval! duration=%d interval=%d\n",
+ duration, interval);
+ ret = -EINVAL;
+ goto done;
+ }
+ priv->phandle->noa_interval = interval;
+ priv->phandle->noa_duration = duration;
+ PRINTM(MIOCTL, "configure noa interval=%d, duration=%d\n",
+ priv->phandle->noa_interval, priv->phandle->noa_duration);
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief Set/Get DFS repeater mode
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_dfs_repeater_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0, data[1] = {0};
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ds_misc_dfs_repeater *dfs_repeater = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_REPEATER_CFG);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
+ dfs_repeater =
+ (mlan_ds_misc_dfs_repeater *)&misc_cfg->param.dfs_repeater;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args! %d\n",
+ user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
+ PRINTM(MERROR, "Invalid DFS repeater mode %d\n",
+ data[0]);
+ ret = -EINVAL;
+ goto done;
+ }
+ dfs_repeater->mode = (t_u16)data[0];
+
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)dfs_repeater,
+ sizeof(mlan_ds_misc_dfs_repeater), respbuflen);
+ ret = sizeof(mlan_ds_misc_dfs_repeater);
+ }
+
+ /* Store current value of DFS repeater mode for futher references. eg.,
+ * for avoiding CAC timers
+ */
+ priv->phandle->dfs_repeater_mode = dfs_repeater->mode;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/**
+ * @brief Set/Get MIRACAST configuration parameters
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_miracast_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0, data[3] = {0, 0, 0};
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIRACAST_CFG);
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ data[0] = priv->phandle->miracast_mode;
+ data[1] = priv->phandle->miracast_scan_time;
+ data[2] = priv->phandle->scan_chan_gap;
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ } else {
+ /* SET operation */
+ memset(data, 0, sizeof(data));
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len > 3) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] < 0 || data[0] > 2 || data[1] < 0 || data[2] < 0) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (user_data_len >= 1)
+ priv->phandle->miracast_mode = (t_u8)data[0];
+ if (user_data_len >= 2)
+ priv->phandle->miracast_scan_time = (t_u16)data[1];
+ if (user_data_len == 3)
+ priv->phandle->scan_chan_gap = (t_u16)data[2];
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configuring scan gap for miracast mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return 0 --success, otherwise failure
+ */
+int woal_set_scan_chan_gap(moal_private *priv, t_u8 *respbuf, int respbuflen)
+{
+ t_u32 data[2];
+ int ret = 0;
+ int user_data_len = 0;
+
+ ENTER();
+
+ if (strlen(respbuf) > strlen("SCAN_TIMING")) {
+ memset((char *)data, 0, sizeof(data));
+ parse_arguments(respbuf + strlen("SCAN_TIMING") + 1, data,
+ ARRAY_SIZE(data), &user_data_len);
+ }
+
+ if (user_data_len != 2) {
+ PRINTM(MERROR, "Invalid arguments for scan timing\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ priv->phandle->miracast_scan_time = (t_u16)data[0];
+ priv->phandle->scan_chan_gap = (t_u16)data[1];
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief Set/Get control to coex RX window size configuration
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_coex_rx_winsize(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_COEX_RX_WINSIZE);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_COEX_RX_WINSIZE;
+
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args! %d\n",
+ user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data != MTRUE) && (data != MFALSE)) {
+ PRINTM(MERROR,
+ "Invalid coex RX window size parameter %d\n",
+ data);
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.coex_rx_winsize = data;
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!user_data_len) {
+ moal_memcpy_ext(priv->phandle, respbuf,
+ (t_u8 *)&cfg_11n->param.coex_rx_winsize,
+ sizeof(t_u32), respbuflen);
+ ret = sizeof(t_u32);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef PCIE
+/**
+ * @brief Read/Write PCIE register
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_pcie_reg_rw(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ moal_handle *handle = priv->phandle;
+ int data[3];
+ t_u32 reg;
+ t_u32 value;
+ int ret = MLAN_STATUS_SUCCESS;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_REG_RW);
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if ((user_data_len != 1) && (user_data_len != 2)) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reg = (t_u32)data[0];
+ if (user_data_len == 1) {
+ if (moal_read_reg(handle, reg, &value)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[1] = value;
+ } else {
+ value = data[1];
+ if (moal_write_reg(handle, reg, value)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write PCIE register/memory from BAR0
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_pcie_bar0_reg_rw(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ moal_handle *handle = priv->phandle;
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ int data[3];
+ t_u32 reg;
+ t_u32 value;
+ int ret = MLAN_STATUS_SUCCESS;
+ int user_data_len = 0, header_len = 0;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_BAR0_REG_RW);
+ if (strlen(respbuf) == header_len) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if ((user_data_len != 1) && (user_data_len != 2)) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ reg = (t_u32)data[0];
+ if (user_data_len == 1) {
+ value = ioread32(card->pci_mmap + reg);
+ if (value == MLAN_STATUS_FAILURE) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[1] = value;
+ } else {
+ value = data[1];
+ iowrite32(value, card->pci_mmap + reg);
+ }
+ moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get SOC temperature
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_get_sensor_temp(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg->sub_command = MLAN_OID_MISC_GET_SENSOR_TEMP;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(respbuf, 0, respbuflen);
+ moal_memcpy_ext(priv->phandle, respbuf,
+ &pcfg->param.sensor_temp.temperature, sizeof(t_u32),
+ respbuflen);
+
+ ret = sizeof(t_u32);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/**
+ * @brief Enable/disable DFS offload
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_dfs_offload_enable(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ struct wiphy *wiphy = NULL;
+ int ret = 0, dfs_offload_en = 0, user_data_len = 0, header_len = 0,
+ dfs_offload;
+
+ ENTER();
+
+ if (priv && priv->wdev)
+ wiphy = priv->wdev->wiphy;
+ if (!wiphy) {
+ PRINTM(MERROR, "wiphy is NULL\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ dfs_offload = moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD);
+ if (woal_is_any_interface_active(priv->phandle)) {
+ PRINTM(MERROR,
+ "DFS offload enable/disable do not allowed after BSS started!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_OFFLOAD);
+ parse_arguments(respbuf + header_len, &dfs_offload_en,
+ sizeof(dfs_offload_en) / sizeof(int), &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (dfs_offload_en != 0 && dfs_offload_en != 1) {
+ PRINTM(MERROR, "Invalid args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (dfs_offload != dfs_offload_en) {
+ dfs_offload = dfs_offload_en;
+ if (dfs_offload)
+ moal_extflg_set(priv->phandle, EXT_DFS_OFFLOAD);
+ else
+ moal_extflg_clear(priv->phandle, EXT_DFS_OFFLOAD);
+ woal_update_radar_chans_dfs_state(wiphy);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief Set/Get dynamic bandwidth
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_config_dyn_bw(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+ int user_data_len = 0, header_len = 0, data = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DYN_BW;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DYN_BW);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data,
+ sizeof(data) / sizeof(int), &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid number of args! %d\n",
+ user_data_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.dyn_bw = (t_u16)data;
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.dyn_bw,
+ sizeof(t_u16), respbuflen);
+ ret = sizeof(t_u16);
+
+ PRINTM(MIOCTL, "Dynamic bandwidth %d\n", misc->param.dyn_bw);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief Check validation of channel and oper class
+ *
+ * @param priv Pointer to moal_private structure
+ * @param channel channel
+ * @param oper_class oper_class
+
+ * @return SUCCESS/FAIL
+ */
+static int woal_check_valid_channel_operclass(moal_private *priv, int channel,
+ int oper_class)
+{
+ int ret = 0;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_OPER_CLASS_CHECK;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_GET;
+ misc->param.bw_chan_oper.oper_class = (t_u8)oper_class;
+ misc->param.bw_chan_oper.channel = (t_u8)channel;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ ** @brief Set extended channel switch ie
+ **
+ ** @param priv Pointer to moal_private structure
+ ** @param respbuf Pointer to response buffer
+ ** @param resplen Response buffer length
+ **
+ ** @return Number of bytes written, negative for failure.
+ **/
+static int woal_priv_extend_channel_switch(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0;
+ int data[5] = {0};
+ ENTER();
+
+ if (!priv || !priv->phandle || (priv->bss_role != MLAN_BSS_ROLE_UAP) ||
+ (priv->bss_started != MTRUE)) {
+ PRINTM(MERROR,
+ "priv or handle is null or interface is not AP/GO"
+ "or AP is not started\n");
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+ }
+
+ parse_arguments(respbuf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_EXTEND_CHAN_SWITCH),
+ data, ARRAY_SIZE(data), &user_data_len);
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ LEAVE();
+ return ret;
+ }
+
+ if (data[1]) {
+ if (woal_check_valid_channel_operclass(priv, data[2],
+ data[1])) {
+ PRINTM(MERROR, "Wrong channel switch parameters!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ woal_channel_switch(priv, data[0], data[1], data[2], data[3], data[4],
+ MFALSE);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief P2P extended channel switch
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_p2p_ecsa(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int user_data_len = 0, header_len = 0;
+ int data[2] = {0};
+ t_u8 bw = 0, oper_class = 0, channel = 0;
+ IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
+ custom_ie *pcust_chansw_ie = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->bss_role != MLAN_BSS_ROLE_UAP) {
+ PRINTM(MERROR,
+ "Extended Channel Switch is only allowed for AP/GO mode\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->bss_started != MTRUE) {
+ PRINTM(MERROR, "AP is not started!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
+ misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
+
+ pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
+ pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
+ pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ExtChanSwitchAnn_t);
+ pcust_chansw_ie->mgmt_subtype_mask =
+ MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
+ BEACON/probe resp*/
+ ext_chan_switch =
+ (IEEEtypes_ExtChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
+
+ header_len = strlen("P2P_ECSA");
+ parse_arguments(respbuf + header_len + 1, data, ARRAY_SIZE(data),
+ &user_data_len);
+
+ if (user_data_len != 2) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ channel = data[0];
+ /* bandwidth 20:20M 40:40M 80:80M*/
+ bw = data[1];
+ if (bw != 20 && bw != 40 && bw != 80) {
+ PRINTM(MERROR, "Unsupported bandwidth\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (channel >= 52 && channel <= 144) {
+ PRINTM(MERROR, "Switch to DFS channel is not allowed!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, channel,
+ &oper_class);
+ if (oper_class == 0) {
+ PRINTM(MERROR, "Wrong parameters!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
+ ext_chan_switch->len = 4;
+ ext_chan_switch->chan_switch_mode = 1;
+ ext_chan_switch->new_oper_class = oper_class;
+ ext_chan_switch->new_channel_num = channel;
+ ext_chan_switch->chan_switch_count = DEF_CHAN_SWITCH_COUNT;
+
+ if (ext_chan_switch->chan_switch_mode) {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ woal_stop_queue(priv->netdev);
+ priv->uap_tx_blocked = MTRUE;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
+ pcust_chansw_ie->ie_length);
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->phandle->chsw_wait_q_woken = MFALSE;
+ /* wait for channel switch to complete */
+ wait_event_interruptible_timeout(
+ priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
+ (u32)HZ * (ext_chan_switch->chan_switch_count + 2) * 110 /
+ 1000);
+
+ pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
+ pcust_chansw_ie->mgmt_subtype_mask = 0;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to clear ECSA IE\n");
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+* @brief Set random mac configure value (ON/OFF)
+*
+* @param priv Pointer to moal_private structure
+* @param respbuf Pointer to response buffer
+* @param resplen Response buffer length
+
+* @return Number of bytes written, negative for failure.
+*/
+static int woal_priv_config_random_mac(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ int header_len = 0, space_len = 0, i;
+ t_u8 rand_data[3];
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+ char fakemac_sts[16];
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ header_len = strlen("FAKEMAC");
+ if (strlen(respbuf) >= header_len) {
+ for (i = 0; i < (strlen(respbuf) - header_len - 1); i++) {
+ if (respbuf[header_len + 1 + i] != ' ')
+ break;
+ }
+ space_len = i;
+
+ if (strncmp(respbuf + header_len + 1 + space_len, "On",
+ strlen("On")) == 0) {
+ if (memcmp(priv->random_mac, zero_mac,
+ MLAN_MAC_ADDR_LENGTH)) {
+ ret = sprintf(respbuf,
+ "FAKEMAC has been On\n") +
+ 1;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, priv->random_mac,
+ priv->current_addr, ETH_ALEN,
+ MLAN_MAC_ADDR_LENGTH);
+ get_random_bytes(rand_data, 3);
+ moal_memcpy_ext(priv->phandle, priv->random_mac + 3,
+ rand_data, 3, 3);
+ } else if (strncmp(respbuf + header_len + 1 + space_len, "Off",
+ strlen("Off")) == 0) {
+ memset(priv->random_mac, 0, ETH_ALEN);
+ } else {
+ PRINTM(MERROR, "Invalid parameter!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid parameter!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(fakemac_sts, 0, sizeof(fakemac_sts));
+ snprintf(fakemac_sts, sizeof(fakemac_sts), "%s",
+ (respbuf + header_len + 1 + space_len));
+ ret = snprintf(respbuf, respbuflen, "FAKEMAC parameter is %s\n",
+ fakemac_sts) +
+ 1;
+ PRINTM(MMSG, "FAKEMAC parameter is %s\n",
+ (t_u8 *)(respbuf + header_len + 1 + space_len));
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Download start keep alive parameters
+ *
+ * @param priv Pointer to moal_private structure
+ * @param mkeep_alive_id keep alive ID number
+ * @param ip_pke IP packet from host
+ * @param ip_pke_len IP packet length from host
+ * @param src_mac Source MAC address
+ * @param dst_mac Destination MAC address
+ * @param period_msec Send keep alive packet interval
+
+ * @return 0: success fail otherwise
+ */
+int woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id,
+ t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
+ t_u8 *dst_mac, t_u32 period_msec,
+ t_u32 retry_interval, t_u8 retry_cnt)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* SET operation */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
+ misc->param.keep_alive.enable = true;
+ misc->param.keep_alive.send_interval = period_msec;
+ misc->param.keep_alive.retry_interval = retry_interval;
+ misc->param.keep_alive.retry_count = retry_cnt;
+ moal_memcpy_ext(priv->phandle, misc->param.keep_alive.dst_mac, dst_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ moal_memcpy_ext(priv->phandle, misc->param.keep_alive.src_mac, src_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ misc->param.keep_alive.pkt_len =
+ MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
+ moal_memcpy_ext(priv->phandle, misc->param.keep_alive.packet, ip_pkt,
+ ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Download stop keep alive parameters
+ *
+ * @param priv Pointer to moal_private structure
+ * @param mkeep_alive_id keep alive ID number
+ * @param ip_pkt Last packet
+ * @param ip_pkt_len Last packet length
+
+ * @return 0: success fail otherwise
+ */
+int woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset,
+ t_u8 *ip_pkt, t_u8 *pkt_len)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_keep_alive *misc_keep_alive = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc_keep_alive = &misc->param.keep_alive;
+
+ if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* GET operation */
+ ioctl_req->action = MLAN_ACT_GET;
+ misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
+ misc_keep_alive->enable = false;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!misc_keep_alive->enable) {
+ PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id);
+ goto done;
+ }
+
+ if (reset)
+ ioctl_req->action = MLAN_ACT_RESET;
+ else
+ /* SET operation */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
+ misc_keep_alive->enable = false;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
+ ret = woal_mkeep_alive_vendor_event(priv,
+ &misc->param.keep_alive);
+ if (ret)
+ PRINTM(MERROR,
+ "Keep alive vendor event upload failed\n");
+ }
+#endif
+#endif
+ if (pkt_len) {
+ *pkt_len = MIN(misc_keep_alive->pkt_len,
+ (MKEEP_ALIVE_IP_PKT_MAX - 1));
+ PRINTM(MINFO, "keep alive stop pkt_len is %d\n", *pkt_len);
+ }
+ if (*pkt_len && ip_pkt)
+ moal_memcpy_ext(priv->phandle, ip_pkt, misc_keep_alive->packet,
+ *pkt_len, *pkt_len);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Save cloud keep alive params in driver handle
+ *
+ * @param priv Pointer to moal_private structure
+ * @params Other params for keep alive
+
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_save_cloud_keep_alive_params(moal_private *priv,
+ t_u8 mkeep_alive_id, t_u8 enable,
+ t_u16 ether_type, t_u8 *ip_pkt,
+ t_u16 ip_pkt_len, t_u8 *src_mac,
+ t_u8 *dst_mac, t_u32 period_msec,
+ t_u32 retry_interval, t_u8 retry_cnt)
+
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ mlan_ds_misc_keep_alive *keep_alive = NULL;
+ moal_handle *phandle = NULL;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is null\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ phandle = priv->phandle;
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
+ PRINTM(MERROR, "Invalid parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* GET operation */
+ ioctl_req->action = MLAN_ACT_GET;
+ misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
+ misc->param.keep_alive.enable = true;
+
+ ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (misc->param.keep_alive.enable) {
+ PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ keep_alive = &phandle->keep_alive[mkeep_alive_id];
+ keep_alive->mkeep_alive_id = mkeep_alive_id;
+ keep_alive->enable = enable;
+ if (enable) {
+ keep_alive->cached = true;
+ keep_alive->send_interval = period_msec;
+ keep_alive->retry_interval = retry_interval;
+ keep_alive->retry_count = retry_cnt;
+ moal_memcpy_ext(phandle, keep_alive->dst_mac, dst_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ moal_memcpy_ext(phandle, keep_alive->src_mac, src_mac,
+ MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
+ keep_alive->pkt_len = MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
+ moal_memcpy_ext(phandle, keep_alive->packet, ip_pkt, ip_pkt_len,
+ MKEEP_ALIVE_IP_PKT_MAX);
+ if (ether_type)
+ keep_alive->ether_type = ether_type;
+ else
+ keep_alive->ether_type = 0;
+ }
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cloud keep alive feature
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_cloud_keep_alive(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ cloud_keep_alive *keep_alive = NULL;
+ int header_len = 0;
+
+ ENTER();
+
+ header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE);
+
+ keep_alive = (cloud_keep_alive *)(respbuf + header_len);
+
+ if (keep_alive->enable) {
+ ret = woal_priv_save_cloud_keep_alive_params(
+ priv, keep_alive->mkeep_alive_id, keep_alive->enable, 0,
+ keep_alive->pkt, keep_alive->pkt_len,
+ keep_alive->src_mac, keep_alive->dst_mac,
+ keep_alive->sendInterval, keep_alive->retryInterval,
+ keep_alive->retryCount);
+ } else {
+ if (0 != woal_stop_mkeep_alive(priv, keep_alive->mkeep_alive_id,
+ keep_alive->reset,
+ keep_alive->pkt,
+ &keep_alive->pkt_len)) {
+ ret = -EFAULT;
+ return ret;
+ }
+ ret = respbuflen;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get static rx abort config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_rx_abort_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[2] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2 ||
+ (data[0] == MTRUE && user_data_len != 2)) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == MTRUE && data[1] > 0x7f) {
+ PRINTM(MERROR, "Invalid threshold value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.rx_abort_cfg.enable = (t_u8)data[0];
+ if (user_data_len == 2)
+ misc->param.rx_abort_cfg.rssi_threshold = (t_s8)data[1];
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.rx_abort_cfg.enable;
+ data[1] = misc->param.rx_abort_cfg.rssi_threshold;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get dynamic rx abort config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_rx_abort_cfg_ext(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[3] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG_EXT);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG_EXT;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 3 ||
+ (data[0] == MTRUE && user_data_len != 3)) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == MTRUE) {
+ if (data[1] > 0x7f) {
+ PRINTM(MERROR, "Invalid margin value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[2] > 0x7f) {
+ PRINTM(MERROR,
+ "Invalid ceil threshold value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ misc->param.rx_abort_cfg_ext.enable = (t_u8)data[0];
+ if (user_data_len > 1) {
+ misc->param.rx_abort_cfg_ext.rssi_margin =
+ (t_s8)data[1];
+ misc->param.rx_abort_cfg_ext.ceil_rssi_threshold =
+ (t_s8)data[2];
+ }
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.rx_abort_cfg_ext.enable;
+ data[1] = misc->param.rx_abort_cfg_ext.rssi_margin;
+ data[2] = misc->param.rx_abort_cfg_ext.ceil_rssi_threshold;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable Un-associated Dot11mc FTM Frame exchanges
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_dot11mc_unassoc_ftm_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[1] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
+ PRINTM(MERROR, "Invalid state for unassoc ftm\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.dot11mc_unassoc_ftm_cfg.state = (t_u16)data[0];
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.dot11mc_unassoc_ftm_cfg.state;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx AMPDU protection mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_tx_ampdu_prot_mode(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[1] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AMPDU_PROT_MODE);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TX_AMPDU_PROT_MODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 1) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] > TX_AMPDU_DYNAMIC_RTS_CTS) {
+ PRINTM(MERROR, "Invalid protection mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.tx_ampdu_prot_mode.mode = (t_u16)data[0];
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.tx_ampdu_prot_mode.mode;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx rate adapt config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_rate_adapt_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[4] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RATE_ADAPT_CFG);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RATE_ADAPT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len < 1) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] > RATEADAPT_ALGO_SR) {
+ PRINTM(MERROR, "Invalid Rateadapt Algorithm\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
+ if ((data[1] & data[2]) == 0xff) {
+ /* dynamic CCA noise based rate adapation enable
+ * request nothing to do here
+ */
+ } else if (data[1] > 100 || data[2] > 100) {
+ PRINTM(MERROR,
+ "Invalid success rate threshold value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[3] < 10 || data[3] > 0xffff) {
+ PRINTM(MERROR, "Invalid interval value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ misc->param.rate_adapt_cfg.sr_rateadapt = (t_u8)data[0];
+ if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
+ misc->param.rate_adapt_cfg.ra_low_thresh =
+ (t_u8)data[1];
+ misc->param.rate_adapt_cfg.ra_high_thresh =
+ (t_u8)data[2];
+ misc->param.rate_adapt_cfg.ra_interval = (t_u16)data[3];
+ }
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = misc->param.rate_adapt_cfg.sr_rateadapt;
+ data[1] = misc->param.rate_adapt_cfg.ra_low_thresh;
+ data[2] = misc->param.rate_adapt_cfg.ra_high_thresh;
+ data[3] = misc->param.rate_adapt_cfg.ra_interval;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get global cck desense config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_cck_desense_cfg(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[5] = {0};
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CCK_DESENSE_CFG);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CCK_DESENSE_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 5) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[0] > CCK_DESENSE_MODE_DYN_ENH) {
+ PRINTM(MERROR, "Invalid cck desense mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[0] == CCK_DESENSE_MODE_DISABLED &&
+ user_data_len > 1) ||
+ (data[0] == CCK_DESENSE_MODE_DYNAMIC &&
+ user_data_len != 3) ||
+ (data[0] == CCK_DESENSE_MODE_DYN_ENH &&
+ (user_data_len < 3 || user_data_len == 4))) {
+ PRINTM(MERROR,
+ "Invalid number of args for requested mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len > 1) {
+ if (data[1] > 0x7f) {
+ PRINTM(MERROR, "Invalid margin value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[2] > 0x7f) {
+ PRINTM(MERROR,
+ "Invalid ceil threshold value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (user_data_len > 3) {
+ if (data[3] > 0xff || data[4] > 0xff) {
+ PRINTM(MERROR,
+ "Invalid ON/OFF intervals value\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ misc->param.cck_desense_cfg.mode = (t_u8)data[0];
+ if (user_data_len > 1) {
+ misc->param.cck_desense_cfg.margin = (t_s8)data[1];
+ misc->param.cck_desense_cfg.ceil_thresh = (t_s8)data[2];
+ }
+ if (data[0] == CCK_DESENSE_MODE_DYN_ENH) {
+ if (user_data_len > 3) {
+ misc->param.cck_desense_cfg.num_on_intervals =
+ (t_u8)data[3];
+ misc->param.cck_desense_cfg.num_off_intervals =
+ (t_u8)data[4];
+ } else {
+ /* set these to 0xff. This will indicate the FW
+ * to use previously set values.
+ */
+ misc->param.cck_desense_cfg.num_on_intervals =
+ 0xff;
+ misc->param.cck_desense_cfg.num_off_intervals =
+ 0xff;
+ }
+ }
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.cck_desense_cfg.mode;
+ data[1] = misc->param.cck_desense_cfg.margin;
+ data[2] = misc->param.cck_desense_cfg.ceil_thresh;
+ data[3] = misc->param.cck_desense_cfg.num_on_intervals;
+ data[4] = misc->param.cck_desense_cfg.num_off_intervals;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set/get low power mode
+ *
+ * @param priv Pointer to moal_private structure
+ * @param respbuf Pointer to response buffer
+ * @param resplen Response buffer length
+
+ * @return Number of bytes written, negative for failure.
+ */
+static int woal_priv_set_get_lpm(moal_private *priv, t_u8 *respbuf,
+ t_u32 respbuflen)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_power_cfg *cfg = NULL;
+ int data = 0;
+ int user_data_len = 0, header_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (IS_CARD9098(priv->phandle->card_type) ||
+ IS_CARD9097(priv->phandle->card_type)) {
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_LPM);
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, &data, 1,
+ &user_data_len);
+ }
+ if (user_data_len >= 2) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ req = woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_power_cfg *)req->pbuf;
+ if (user_data_len == 0) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ cfg->param.lpm = data;
+ req->action = MLAN_ACT_SET;
+ }
+ }
+ cfg->sub_command = MLAN_OID_POWER_LOW_POWER_MODE;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data = cfg->param.lpm;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
+ sizeof(data), respbuflen);
+ ret = sizeof(data);
+ } else
+ PRINTM(MERROR, "Low power mode command is not supported!\n");
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get HW ARB config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_arbcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+ int data[1];
+ int header_len = 0, user_data_len = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ARB_CFG);
+ user_data_len = strlen(respbuf) - header_len;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_ARB_CONFIG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (strlen(respbuf) == header_len) {
+ /* GET operation */
+ user_data_len = 0;
+ req->action = MLAN_ACT_GET;
+ } else {
+ /* SET operation */
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len != 1) {
+ PRINTM(MERROR, "Invalid Parameter\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data[0] < 0 || data[0] > 4) {
+ PRINTM(MERROR, "Invalid Parameter: arb mode 0-4\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.arb_cfg.arb_mode = (t_u32)data[0];
+ req->action = MLAN_ACT_SET;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.arb_cfg.arb_mode;
+ moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
+ respbuflen);
+ ret = sizeof(data);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Timer function for TP state command.
+ *
+ * @param data pointer to a buffer
+ *
+ * @return N/A
+ */
+void woal_tp_acnt_timer_func(void *context)
+{
+ moal_handle *phandle = (moal_handle *)context;
+ int i = 0;
+
+ if (phandle == NULL)
+ return;
+ PRINTM(MDATA, "####### CPU%d: tp acnt timer\n", smp_processor_id());
+ /* Tx TP accounting */
+ for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
+ phandle->tp_acnt.tx_bytes_rate[i] =
+ phandle->tp_acnt.tx_bytes[i] -
+ phandle->tp_acnt.tx_bytes_last[i];
+ phandle->tp_acnt.tx_bytes_last[i] =
+ phandle->tp_acnt.tx_bytes[i];
+ }
+ phandle->tp_acnt.tx_pending = atomic_read(&phandle->tx_pending);
+ /* Tx Interrupt accounting */
+ phandle->tp_acnt.tx_intr_rate =
+ phandle->tp_acnt.tx_intr_cnt - phandle->tp_acnt.tx_intr_last;
+ phandle->tp_acnt.tx_intr_last = phandle->tp_acnt.tx_intr_cnt;
+
+ /* Rx TP accounting */
+ for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
+ phandle->tp_acnt.rx_bytes_rate[i] =
+ phandle->tp_acnt.rx_bytes[i] -
+ phandle->tp_acnt.rx_bytes_last[i];
+ phandle->tp_acnt.rx_bytes_last[i] =
+ phandle->tp_acnt.rx_bytes[i];
+ }
+ phandle->tp_acnt.rx_pending = atomic_read(&phandle->rx_pending);
+ // Interrupt accounting, RX
+ phandle->tp_acnt.rx_intr_rate =
+ phandle->tp_acnt.rx_intr_cnt - phandle->tp_acnt.rx_intr_last;
+ phandle->tp_acnt.rx_intr_last = phandle->tp_acnt.rx_intr_cnt;
+
+ /* re-arm timer */
+ woal_mod_timer(&phandle->tp_acnt.timer, 1000);
+}
+
+/**
+ * @brief set tp state to mlan
+ *
+ * @param priv pointer to moal_private
+ *
+ * @return N/A
+ */
+void woal_set_tp_state(moal_private *priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ moal_handle *handle = priv->phandle;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL)
+ return;
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TP_STATE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->param.tp_state.on = handle->tp_acnt.on;
+ misc->param.tp_state.drop_point = handle->tp_acnt.drop_point;
+ req->action = MLAN_ACT_SET;
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ return;
+}
+
+/**
+ * @brief Set/Get TP statistics.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param respbuf A pointer to response buffer
+ * @param respbuflen Available length of response buffer
+ *
+ * @return Number of bytes written, negative for failure.
+ */
+int woal_priv_set_tp_state(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int data[2];
+ int header_len = 0, user_data_len = 0;
+
+ ENTER();
+
+ if (!respbuf) {
+ PRINTM(MERROR, "response buffer is not available!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TP_STATE);
+ user_data_len = strlen(respbuf) - header_len;
+ parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
+ &user_data_len);
+ if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (user_data_len) {
+ handle->tp_acnt.on = data[0];
+ /* Enable TP statistics collection */
+ if (data[0] == 1) {
+ handle->tp_acnt.drop_point = data[1];
+ if (handle->is_tp_acnt_timer_set == MFALSE) {
+ woal_initialize_timer(&handle->tp_acnt.timer,
+ woal_tp_acnt_timer_func,
+ handle);
+ handle->is_tp_acnt_timer_set = MTRUE;
+ woal_mod_timer(&handle->tp_acnt.timer, 1000);
+ }
+ } else {
+ if (handle->is_tp_acnt_timer_set) {
+ woal_cancel_timer(&handle->tp_acnt.timer);
+ handle->is_tp_acnt_timer_set = MFALSE;
+ }
+ memset((void *)&handle->tp_acnt, 0,
+ sizeof(moal_tp_acnt_t));
+ }
+ woal_set_tp_state(priv);
+ }
+ /* Get command results */
+ if (user_data_len == 0) {
+ moal_memcpy_ext(handle, respbuf, (t_u8 *)(&handle->tp_acnt),
+ sizeof(handle->tp_acnt), respbuflen);
+ ret = sizeof(handle->tp_acnt);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set priv command for Android
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ android_wifi_priv_cmd priv_cmd;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ char *buf = NULL;
+ char *pdata;
+#ifdef STA_SUPPORT
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ int copy_len = 0;
+#endif
+ int len = 0;
+ gfp_t flag;
+ char *cmd_buf = NULL;
+ int cfg80211_wext;
+
+ ENTER();
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is NULL\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg80211_wext = priv->phandle->params.cfg80211_wext;
+ if (copy_from_user(&priv_cmd, req->ifr_data,
+ sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto done;
+ }
+#define CMD_BUF_LEN 3072
+ if (priv_cmd.used_len < 0 || priv_cmd.total_len <= 0 ||
+ priv_cmd.used_len > priv_cmd.total_len) {
+ PRINTM(MERROR,
+ "Invalid Android priv cmd len. used_len: %d, total_len: %d\n",
+ priv_cmd.used_len, priv_cmd.total_len);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (priv_cmd.total_len + 1 > CMD_BUF_LEN)
+ priv_cmd.total_len = CMD_BUF_LEN - 1;
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ buf = kzalloc(CMD_BUF_LEN, flag);
+ if (!buf) {
+ PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto done;
+ }
+#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
+ moal_memcpy_ext(priv->phandle, &cmd_buf, &priv_cmd.buf, sizeof(cmd_buf),
+ sizeof(cmd_buf));
+#else
+ cmd_buf = priv_cmd.buf;
+#endif
+ if (copy_from_user(buf, cmd_buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[CMD_BUF_LEN - 1] = '\0';
+
+ PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);
+
+ if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) &&
+ woal_check_driver_status(priv->phandle)) {
+ PRINTM(MERROR, "%s fail when driver hang\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) == 0) {
+ /* This command has come from mlanutl app */
+
+ /* Check command */
+ if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VERSION,
+ strlen(PRIV_CMD_VERSION)) == 0) {
+ /* Get version */
+ len = woal_get_priv_driver_version(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BANDCFG,
+ strlen(PRIV_CMD_BANDCFG)) == 0) {
+ /* Set/Get band configuration */
+ len = woal_setget_priv_bandcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOSTCMD,
+ strlen(PRIV_CMD_HOSTCMD)) == 0) {
+ /* hostcmd configuration */
+ len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len,
+ MOAL_IOCTL_WAIT);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCMDCFG,
+ strlen(PRIV_CMD_11AXCMDCFG)) == 0) {
+ /* 11ax command */
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_11AXCMDCFG);
+ len = priv_cmd.total_len - strlen(CMD_NXP) +
+ strlen(PRIV_CMD_11AXCMDCFG);
+ len = woal_setget_priv_11axcmdcfg(priv, pdata, len,
+ MOAL_IOCTL_WAIT);
+ len += strlen(CMD_NXP) + strlen(PRIV_CMD_11AXCMDCFG);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RANGE_EXT,
+ strlen(PRIV_CMD_RANGE_EXT)) == 0) {
+ len = woal_setget_priv_range_ext(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTTXCFG,
+ strlen(PRIV_CMD_HTTXCFG)) == 0) {
+ /* Set/Get HT Tx configuration */
+ len = woal_setget_priv_httxcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTCAPINFO,
+ strlen(PRIV_CMD_HTCAPINFO)) == 0) {
+ /* Set/Get HT Capability information */
+ len = woal_setget_priv_htcapinfo(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAPARA,
+ strlen(PRIV_CMD_ADDBAPARA)) == 0) {
+ /* Set/Get Add BA parameters */
+ len = woal_setget_priv_addbapara(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRPRIOTBL,
+ strlen(PRIV_CMD_AGGRPRIOTBL)) == 0) {
+ /* Set/Get Aggregation priority table parameters */
+ len = woal_setget_priv_aggrpriotbl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAREJECT,
+ strlen(PRIV_CMD_ADDBAREJECT)) == 0) {
+ /* Set/Get Add BA reject parameters */
+ len = woal_setget_priv_addbareject(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELBA,
+ strlen(PRIV_CMD_DELBA)) == 0) {
+ /* Delete selective BA based on parameters */
+ len = woal_priv_delba(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_REJECTADDBAREQ,
+ strlen(PRIV_CMD_REJECTADDBAREQ)) == 0) {
+ /* Set/Get the reject addba requst conditions*/
+ len = woal_priv_rejectaddbareq(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VHTCFG,
+ strlen(PRIV_CMD_VHTCFG)) == 0) {
+ /* Set/Get 11AC configuration */
+ len = woal_setget_priv_vhtcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OPERMODECFG,
+ strlen(PRIV_CMD_OPERMODECFG)) == 0) {
+ /* Set/Get 11AC configuration */
+ len = woal_setget_priv_opermodecfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DATARATE,
+ strlen(PRIV_CMD_DATARATE)) == 0) {
+ /* Get data rate */
+ len = woal_get_priv_datarate(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXRATECFG,
+ strlen(PRIV_CMD_TXRATECFG)) == 0) {
+ /* Set/Get tx rate cfg */
+ len = woal_setget_priv_txratecfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETLOG,
+ strlen(PRIV_CMD_GETLOG)) == 0) {
+ /* Get wireless stats information */
+ len = woal_get_priv_getlog(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CUSTOMIE,
+ strlen(PRIV_CMD_CUSTOMIE)) == 0) {
+ /* Custom IE configuration */
+ len = woal_priv_customie(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ESUPPMODE,
+ strlen(PRIV_CMD_ESUPPMODE)) == 0) {
+ /* Esupplicant mode configuration */
+ len = woal_setget_priv_esuppmode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PASSPHRASE,
+ strlen(PRIV_CMD_PASSPHRASE)) == 0) {
+ /* Esupplicant passphrase configuration */
+ len = woal_setget_priv_passphrase(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH,
+ strlen(PRIV_CMD_DEAUTH)) == 0) {
+ /* Deauth */
+ len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
+ goto handled;
+#ifdef UAP_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AP_DEAUTH,
+ strlen(PRIV_CMD_AP_DEAUTH)) == 0) {
+ /* AP Deauth */
+ len = woal_priv_ap_deauth(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GET_STA_LIST,
+ strlen(PRIV_CMD_GET_STA_LIST)) == 0) {
+ /* Get STA list */
+ len = woal_priv_get_sta_list(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSS_CONFIG,
+ strlen(PRIV_CMD_BSS_CONFIG)) == 0) {
+ /* BSS config */
+ len = woal_priv_bss_config(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSSROLE,
+ strlen(PRIV_CMD_BSSROLE)) == 0) {
+ /* BSS Role */
+ len = woal_priv_bssrole(priv, buf,
+ (t_u32)priv_cmd.total_len);
+ goto handled;
+#endif
+#endif
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SETUSERSCAN,
+ strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
+ /* Set user scan */
+ len = woal_priv_setuserscan(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GETSCANTABLE,
+ strlen(PRIV_CMD_GETSCANTABLE)) == 0) {
+ /* Get scan table */
+ len = woal_priv_getscantable(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GETCHANSTATS,
+ strlen(PRIV_CMD_GETCHANSTATS)) == 0) {
+ /* Get channel statistics */
+ len = woal_priv_get_chanstats(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_EXTCAPCFG,
+ strlen(PRIV_CMD_EXTCAPCFG)) == 0) {
+ /* Extended capabilities configure */
+ len = woal_priv_extcapcfg(priv, buf,
+ (t_u32)priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CANCELSCAN,
+ strlen(PRIV_CMD_CANCELSCAN)) == 0) {
+ /* Cancel scan */
+ len = woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEEPSLEEP,
+ strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
+ /* Deep sleep */
+ len = woal_priv_setgetdeepsleep(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPADDR,
+ strlen(PRIV_CMD_IPADDR)) == 0) {
+ /* IP address */
+ len = woal_priv_setgetipaddr(priv, buf,
+ (t_u32)priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WPSSESSION,
+ strlen(PRIV_CMD_WPSSESSION)) == 0) {
+ /* WPS Session */
+ len = woal_priv_setwpssession(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OTPUSERDATA,
+ strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
+ /* OTP user data */
+ len = woal_priv_otpuserdata(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_COUNTRYCODE,
+ strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
+ /* Country code */
+ len = woal_priv_set_get_countrycode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFPINFO,
+ strlen(PRIV_CMD_CFPINFO)) == 0) {
+ /* CFP info */
+ len = woal_priv_get_cfpinfo(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TCPACKENH,
+ strlen(PRIV_CMD_TCPACKENH)) == 0) {
+ /* TCP ack enhancement */
+ len = woal_priv_setgettcpackenh(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef REASSOCIATION
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCBSSID,
+ strlen(PRIV_CMD_ASSOCBSSID)) == 0) {
+ /* Associate to essid */
+ len = woal_priv_assocessid(priv, buf,
+ priv_cmd.total_len, 1);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCESSID,
+ strlen(PRIV_CMD_ASSOCESSID)) == 0) {
+ /* Associate to essid */
+ len = woal_priv_assocessid(priv, buf,
+ priv_cmd.total_len, 0);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_WAKEUPREASON,
+ strlen(PRIV_CMD_WAKEUPREASON)) == 0) {
+ /* wakeup reason */
+ len = woal_priv_getwakeupreason(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_LISTENINTERVAL,
+ strlen(PRIV_CMD_LISTENINTERVAL)) == 0) {
+ /* Listen Interval */
+ len = woal_priv_set_get_listeninterval(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+#ifdef DEBUG_LEVEL1
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRVDBG,
+ strlen(PRIV_CMD_DRVDBG)) == 0) {
+ /* Driver debug bit mask */
+ len = woal_priv_set_get_drvdbg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSCFG,
+ strlen(PRIV_CMD_HSCFG)) == 0) {
+ /* HS configuration */
+ len = woal_priv_hscfg(priv, buf, priv_cmd.total_len,
+ MTRUE);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSSETPARA,
+ strlen(PRIV_CMD_HSSETPARA)) == 0) {
+ /* Set HS parameter */
+ len = woal_priv_hssetpara(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MGMT_FILTER,
+ strlen(PRIV_CMD_MGMT_FILTER)) == 0) {
+ /* Management frame filter wakeup */
+ len = woal_priv_mgmt_filter(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SCANCFG,
+ strlen(PRIV_CMD_SCANCFG)) == 0) {
+ /* Scan configuration */
+ len = woal_priv_set_get_scancfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM,
+ strlen(PRIV_CMD_GETNLNUM)) == 0) {
+ /* Scan configuration */
+ len = woal_priv_getnlnum(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRCTRL,
+ strlen(PRIV_CMD_AGGRCTRL)) == 0) {
+ /* aggregation control */
+ len = woal_priv_set_get_aggrctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef USB
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USBAGGRCTRL,
+ strlen(PRIV_CMD_USBAGGRCTRL)) == 0) {
+ /* USB aggregation control */
+ len = woal_priv_set_get_usbaggrctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_SET_BSS_MODE,
+ strlen(PRIV_CMD_SET_BSS_MODE)) == 0) {
+ /* Set bss mode */
+ len = woal_priv_set_bss_mode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AP,
+ strlen(PRIV_CMD_SET_AP)) == 0) {
+ /* Set AP */
+ len = woal_priv_set_ap(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_POWER,
+ strlen(PRIV_CMD_SET_POWER)) == 0) {
+ /* Set power management parameters */
+ len = woal_priv_set_power(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_ESSID,
+ strlen(PRIV_CMD_SET_ESSID)) == 0) {
+ /* Set essid */
+ len = woal_priv_set_essid(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AUTH,
+ strlen(PRIV_CMD_SET_AUTH)) == 0) {
+ /* Set authentication mode parameters */
+ len = woal_priv_set_auth(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_AP,
+ strlen(PRIV_CMD_GET_AP)) == 0) {
+ /* Get AP */
+ len = woal_priv_get_ap(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_POWER,
+ strlen(PRIV_CMD_GET_POWER)) == 0) {
+ /* Get power management parameters */
+ len = woal_priv_get_power(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSMODE,
+ strlen(PRIV_CMD_PSMODE)) == 0) {
+ /* Set/Get PS mode */
+ len = woal_priv_set_get_psmode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WARMRESET,
+ strlen(PRIV_CMD_WARMRESET)) == 0) {
+ /* Performs warm reset */
+ len = woal_priv_warmreset(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXPOWERCFG,
+ strlen(PRIV_CMD_TXPOWERCFG)) == 0) {
+ /* TX power configurations */
+ len = woal_priv_txpowercfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_RX_ABORT_CFG_EXT,
+ strlen(PRIV_CMD_RX_ABORT_CFG_EXT)) == 0) {
+ /* dynamic Rx Abort config */
+ len = woal_priv_rx_abort_cfg_ext(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_RX_ABORT_CFG,
+ strlen(PRIV_CMD_RX_ABORT_CFG)) == 0) {
+ /* static Rx Abort config */
+ len = woal_priv_rx_abort_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_TX_AMPDU_PROT_MODE,
+ strlen(PRIV_CMD_TX_AMPDU_PROT_MODE)) == 0) {
+ /* tx ampdu protection mode setting */
+ len = woal_priv_tx_ampdu_prot_mode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG,
+ strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG)) ==
+ 0) {
+ /* setting for dot11mc un-associated case FTM frame
+ * exchange */
+ len = woal_priv_dot11mc_unassoc_ftm_cfg(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_RATE_ADAPT_CFG,
+ strlen(PRIV_CMD_RATE_ADAPT_CFG)) == 0) {
+ /* rate adapt config */
+ len = woal_priv_rate_adapt_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_CCK_DESENSE_CFG,
+ strlen(PRIV_CMD_CCK_DESENSE_CFG)) == 0) {
+ /* cck desense config */
+ len = woal_priv_cck_desense_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSCFG,
+ strlen(PRIV_CMD_PSCFG)) == 0) {
+ /* PS configurations */
+ len = woal_priv_pscfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_BCNTIMEOUTCFG,
+ strlen(PRIV_CMD_BCNTIMEOUTCFG)) == 0) {
+ /* Beacon timeout configurations */
+ len = woal_priv_bcntimeoutcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SLEEPPD,
+ strlen(PRIV_CMD_SLEEPPD)) == 0) {
+ /* Sleep period */
+ len = woal_priv_sleeppd(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXCONTROL,
+ strlen(PRIV_CMD_TXCONTROL)) == 0) {
+ /* Tx control */
+ len = woal_priv_txcontrol(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGRDWR,
+ strlen(PRIV_CMD_REGRDWR)) == 0) {
+ /* Register Read/Write */
+ len = woal_priv_regrdwr(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RDEEPROM,
+ strlen(PRIV_CMD_RDEEPROM)) == 0) {
+ /* Read the EEPROM contents of the card */
+ len = woal_priv_rdeeprom(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MEMRDWR,
+ strlen(PRIV_CMD_MEMRDWR)) == 0) {
+ /* Memory Read/Write */
+ len = woal_priv_memrdwr(priv, buf, priv_cmd.total_len);
+ goto handled;
+#ifdef SDIO
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDCMD52RW,
+ strlen(PRIV_CMD_SDCMD52RW)) == 0) {
+ /* Cmd52 read/write register */
+ len = woal_priv_sdcmd52rw(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDIO_CLOCK,
+ strlen(PRIV_CMD_SDIO_CLOCK)) == 0) {
+ /* Turn on/off the sdio clock */
+ len = woal_priv_sdio_clock_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MPA_CTRL,
+ strlen(PRIV_CMD_MPA_CTRL)) == 0) {
+ /* Set SDIO Multi-point aggregation
+ * control parameters */
+ len = woal_priv_sdio_mpa_ctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SD_CMD53_RW,
+ strlen(PRIV_CMD_SD_CMD53_RW)) == 0) {
+ /* Cmd53 read/write register */
+ len = woal_priv_cmd53rdwr(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ROBUSTCOEX,
+ strlen(PRIV_CMD_ROBUSTCOEX)) == 0) {
+ /* Set Robustcoex GPIOcfg */
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_ROBUSTCOEX);
+ len = priv_cmd.total_len - strlen(PRIV_CMD_ROBUSTCOEX) -
+ strlen(CMD_NXP);
+ len = woal_priv_robustcoex(priv, pdata, len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DMCS,
+ strlen(PRIV_CMD_DMCS)) == 0) {
+ /* Set/Get DMCS config */
+ len = woal_priv_dmcs(priv, buf, priv_cmd.total_len);
+ goto handled;
+#if defined(PCIE)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SSU,
+ strlen(PRIV_CMD_SSU)) == 0) {
+ /* Set SSU config */
+ pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_SSU);
+ len = priv_cmd.used_len - strlen(PRIV_CMD_SSU) -
+ strlen(CMD_NXP);
+ len = woal_priv_ssu_cmd(priv, len, pdata,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_ARP,
+ strlen(PRIV_CMD_AUTO_ARP)) == 0) {
+ /* Auto ARP enable/disable */
+ len = woal_priv_set_get_auto_arp(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOTSPOTCFG,
+ strlen(PRIV_CMD_HOTSPOTCFG)) == 0) {
+ /* Hotspot CFG */
+ len = woal_priv_hotspotcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef RX_PACKET_COALESCE
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RX_COAL_CFG,
+ strlen(PRIV_CMD_RX_COAL_CFG)) == 0) {
+ /* RX packet coalescing Configuration */
+ len = woal_priv_rx_pkt_coalesce_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_MGMT_FRAME_CTRL,
+ strlen(PRIV_CMD_MGMT_FRAME_CTRL)) == 0) {
+ /* Mgmt Frame Passthrough Ctrl */
+ len = woal_priv_mgmt_frame_passthru_ctrl(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QCONFIG,
+ strlen(PRIV_CMD_QCONFIG)) == 0) {
+ /* Queue config */
+ len = woal_priv_qconfig(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDTS,
+ strlen(PRIV_CMD_ADDTS)) == 0) {
+ /* Send an ADDTS TSPEC */
+ len = woal_priv_wmm_addts_req_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELTS,
+ strlen(PRIV_CMD_DELTS)) == 0) {
+ /* Send a DELTS TSPE */
+ len = woal_priv_wmm_delts_req_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QSTATUS,
+ strlen(PRIV_CMD_QSTATUS)) == 0) {
+ /* Get the status of the WMM queues */
+ len = woal_priv_wmm_queue_status_ioctl(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TS_STATUS,
+ strlen(PRIV_CMD_TS_STATUS)) == 0) {
+ /* Get the status of the WMM Traffic Streams */
+ len = woal_priv_wmm_ts_status_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QOS_CFG,
+ strlen(PRIV_CMD_QOS_CFG)) == 0) {
+ t_u32 action = MLAN_ACT_GET;
+ if (strlen(buf) ==
+ strlen(CMD_NXP) + strlen(PRIV_CMD_QOS_CFG)) {
+ pdata = buf; /* GET operation */
+ } else {
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_QOS_CFG);
+ action = MLAN_ACT_SET; /* SET operation */
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_priv_qos_cfg(priv, action, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (action == MLAN_ACT_GET)
+ len = sizeof(t_u8);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MAC_CTRL,
+ strlen(PRIV_CMD_MAC_CTRL)) == 0) {
+ /* MAC CTRL */
+ len = woal_priv_macctrl(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETWAP,
+ strlen(PRIV_CMD_GETWAP)) == 0) {
+ /* Get WAP */
+ len = woal_priv_getwap(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGION_CODE,
+ strlen(PRIV_CMD_REGION_CODE)) == 0) {
+ /* Region Code */
+ len = woal_priv_region_code(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FWMACADDR,
+ strlen(PRIV_CMD_FWMACADDR)) == 0) {
+ /* Set FW MAC address */
+ len = woal_priv_fwmacaddr(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OFFCHANNEL,
+ strlen(PRIV_CMD_OFFCHANNEL)) == 0) {
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ /* Set offchannel */
+ len = woal_priv_offchannel(priv, buf,
+ priv_cmd.total_len);
+ } else
+ len = sprintf(buf,
+ "CFG80211 is not enabled\n") +
+ 1;
+ goto handled;
+#endif
+#endif
+
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DSCP_MAP,
+ strlen(PRIV_CMD_DSCP_MAP)) == 0) {
+ /* Set/Get DSCP Map */
+ len = woal_priv_set_get_dscp_map(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VEREXT,
+ strlen(PRIV_CMD_VEREXT)) == 0) {
+ /* Get Extended version */
+ len = woal_priv_get_driver_verext(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_SUSPEND,
+ strlen(PRIV_CMD_USB_SUSPEND)) == 0) {
+ /* Makes USB device to suspend */
+ len = woal_priv_enter_usb_suspend(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_RESUME,
+ strlen(PRIV_CMD_USB_RESUME)) == 0) {
+ /* Makes USB device to resume */
+ len = woal_priv_exit_usb_suspend(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+#if defined(STA_SUPPORT) && defined(STA_WEXT)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RADIO_CTRL,
+ strlen(PRIV_CMD_RADIO_CTRL)) == 0) {
+ /* Set/Get radio */
+ len = woal_priv_radio_ctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WMM_CFG,
+ strlen(PRIV_CMD_WMM_CFG)) == 0) {
+ /* Implement WMM enable command */
+ len = woal_priv_wmm_cfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_MIN_BA_THRESH_CFG,
+ strlen(PRIV_CMD_MIN_BA_THRESH_CFG)) == 0) {
+ /* Implement Minimum BA threshold configuration command
+ */
+ len = woal_priv_min_ba_threshold_cfg(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+#if defined(STA_SUPPORT)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CFG,
+ strlen(PRIV_CMD_11D_CFG)) == 0) {
+ /* Implement 802.11D enable command */
+ len = woal_priv_11d_cfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CLR_TBL,
+ strlen(PRIV_CMD_11D_CLR_TBL)) == 0) {
+ /* Implement 802.11D clear chan table command */
+ len = woal_priv_11d_clr_chan_tbl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+#ifndef OPCHAN
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WWS_CFG,
+ strlen(PRIV_CMD_WWS_CFG)) == 0) {
+ /* Set/Get WWS configuration */
+ len = woal_priv_wws_cfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+#if defined(REASSOCIATION)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REASSOCTRL,
+ strlen(PRIV_CMD_REASSOCTRL)) == 0) {
+ /* Set/Get reassociation settings */
+ len = woal_priv_set_get_reassoc(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXBUF_CFG,
+ strlen(PRIV_CMD_TXBUF_CFG)) == 0) {
+ /* Get Transmit buffer size */
+ len = woal_priv_txbuf_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTH_TYPE,
+ strlen(PRIV_CMD_AUTH_TYPE)) == 0) {
+ /* Set/Get auth type */
+ len = woal_priv_auth_type(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_POWER_CONS,
+ strlen(PRIV_CMD_POWER_CONS)) == 0) {
+ /* Set/get user provisioned local power constraint */
+ len = woal_priv_11h_local_pwr_constraint(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_HT_STREAM_CFG,
+ strlen(PRIV_CMD_HT_STREAM_CFG)) == 0) {
+ /* Set/get HT stream configurations */
+ len = woal_priv_ht_stream_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MIMO_SWITCH,
+ strlen(PRIV_CMD_MIMO_SWITCH)) == 0) {
+ /* Set mimo switch configurations */
+ len = woal_priv_mimo_switch(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_THERMAL,
+ strlen(PRIV_CMD_THERMAL)) == 0) {
+ /* Get thermal reading */
+ len = woal_priv_thermal(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_BCN_INTERVAL,
+ strlen(PRIV_CMD_BCN_INTERVAL)) == 0) {
+ /* Set/Get beacon interval */
+ len = woal_priv_beacon_interval(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef STA_SUPPORT
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_SIGNALEXT_CFG,
+ strlen(PRIV_CMD_SIGNALEXT_CFG)) == 0) {
+ /* Set signalext flag */
+ len = woal_priv_signalext_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GET_SIGNAL_EXT_V2,
+ strlen(PRIV_CMD_GET_SIGNAL_EXT_V2)) == 0) {
+ /* Get signal info */
+ len = woal_priv_get_signal_ext_v2(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GET_SIGNAL_EXT,
+ strlen(PRIV_CMD_GET_SIGNAL_EXT)) == 0) {
+ /* Get signal info */
+ len = woal_priv_get_signal_ext(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SIGNAL,
+ strlen(PRIV_CMD_GET_SIGNAL)) == 0) {
+ /* Get signal */
+ len = woal_priv_get_signal(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+#if defined(STA_SUPPORT)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PMFCFG,
+ strlen(PRIV_CMD_PMFCFG)) == 0) {
+ /* Configure PMF */
+ len = woal_priv_set_get_pmfcfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_INACTIVITYTO,
+ strlen(PRIV_CMD_INACTIVITYTO)) == 0) {
+ /* Get/Set inactivity timeout extend */
+ len = woal_priv_inactivity_timeout_ext(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_AMSDU_AGGR_CTRL,
+ strlen(PRIV_CMD_AMSDU_AGGR_CTRL)) == 0) {
+ /* Enable/Disable amsdu_aggr_ctrl */
+ len = woal_priv_11n_amsdu_aggr_ctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CAP,
+ strlen(PRIV_CMD_TX_BF_CAP)) == 0) {
+ /* Set/Get Transmit beamforming capabilities */
+ len = woal_priv_tx_bf_cap_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_SLEEP_PARAMS,
+ strlen(PRIV_CMD_SLEEP_PARAMS)) == 0) {
+ /* Configure sleep parameters */
+ len = woal_priv_sleep_params_ioctl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_TESTING,
+ strlen(PRIV_CMD_DFS_TESTING)) == 0) {
+ /* Set/Get DFS Testing settings */
+ len = woal_priv_dfs_testing(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS53_CFG,
+ strlen(PRIV_CMD_DFS53_CFG)) == 0) {
+ /* Set/Get DFS W53 settings */
+ len = woal_priv_dfs53cfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARB_CFG,
+ strlen(PRIV_CMD_ARB_CFG)) == 0) {
+ /* Set/Get CFP table codes */
+ len = woal_priv_arbcfg(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFP_CODE,
+ strlen(PRIV_CMD_CFP_CODE)) == 0) {
+ /* Set/Get CFP table codes */
+ len = woal_priv_cfp_code(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CWMODE,
+ strlen(PRIV_CMD_CWMODE)) == 0) {
+ /* Set/Get Tx CWMode */
+ len = woal_priv_set_get_cwmode(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ANT_CFG,
+ strlen(PRIV_CMD_ANT_CFG)) == 0) {
+ /* Set/Get Tx/Rx antenna */
+ len = woal_priv_set_get_tx_rx_ant(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SYSCLOCK,
+ strlen(PRIV_CMD_SYSCLOCK)) == 0) {
+ /* Get/Set system clock */
+ len = woal_priv_sysclock(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_KEY,
+ strlen(PRIV_CMD_GET_KEY)) == 0) {
+ /* Get GTK/PTK */
+ len = woal_priv_get_key(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCIATE,
+ strlen(PRIV_CMD_ASSOCIATE)) == 0) {
+ /* Associate to a specific indexed entry in the
+ * ScanTable */
+ len = woal_priv_associate_ssid_bssid(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CFG,
+ strlen(PRIV_CMD_TX_BF_CFG)) == 0) {
+ /* Set/Get Transmit beamforming configuration */
+ len = woal_priv_tx_bf_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BOOTSLEEP,
+ strlen(PRIV_CMD_BOOTSLEEP)) == 0) {
+ len = woal_priv_bootsleep(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PORT_CTRL,
+ strlen(PRIV_CMD_PORT_CTRL)) == 0) {
+ /* Set/Get Port Control mode */
+ len = woal_priv_port_ctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PB_BYPASS,
+ strlen(PRIV_CMD_PB_BYPASS)) == 0) {
+ /* Private IOCTL entry to get the By-passed TX packet
+ * from upper layer */
+ len = woal_priv_bypassed_packet(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(UAP_CFG80211)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA,
+ strlen(PRIV_CMD_CFG_NOA)) == 0) {
+ /* Set/Get P2P NoA (Notice of Absence) parameters */
+ len = woal_priv_cfg_noa(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_OPP_PS,
+ strlen(PRIV_CMD_CFG_OPP_PS)) == 0) {
+ /* Set/Get P2P OPP-PS parameters */
+ len = woal_priv_cfg_opp_ps(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_DFS_REPEATER_CFG,
+ strlen(PRIV_CMD_DFS_REPEATER_CFG)) == 0) {
+ /* Set/Get DFS_REPEATER mode */
+ len = woal_priv_dfs_repeater_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_MIRACAST_CFG,
+ strlen(PRIV_CMD_MIRACAST_CFG)) == 0) {
+ /* Set/Get MIRACAST configuration parameters */
+ len = woal_priv_miracast_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_COEX_RX_WINSIZE,
+ strlen(PRIV_CMD_COEX_RX_WINSIZE)) == 0) {
+ /* Set/Get control to coex RX window size */
+ len = woal_priv_coex_rx_winsize(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#ifdef PCIE
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PCIE_REG_RW,
+ strlen(PRIV_CMD_PCIE_REG_RW)) == 0) {
+ /* Read/Write PCIE register */
+ len = woal_priv_pcie_reg_rw(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_PCIE_BAR0_REG_RW,
+ strlen(PRIV_CMD_PCIE_BAR0_REG_RW)) == 0) {
+ /* Read/Write PCIE register/memory from BAR0 */
+ len = woal_priv_pcie_bar0_reg_rw(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GET_SENSOR_TEMP,
+ strlen(PRIV_CMD_GET_SENSOR_TEMP)) == 0) {
+ /* Get SOC temperature */
+ len = woal_priv_get_sensor_temp(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_OFFLOAD,
+ strlen(PRIV_CMD_DFS_OFFLOAD)) == 0) {
+ /* Enable/disable DFS offload */
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
+ len = woal_priv_dfs_offload_enable(
+ priv, buf, priv_cmd.total_len);
+ else
+ len = sprintf(buf,
+ "CFG80211 is not enabled\n") +
+ 1;
+ goto handled;
+#endif
+#endif
+#if defined(UAP_SUPPORT)
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_EXTEND_CHAN_SWITCH,
+ strlen(PRIV_CMD_EXTEND_CHAN_SWITCH)) == 0) {
+ /* Extended channel switch */
+ len = woal_priv_extend_channel_switch(
+ priv, buf, priv_cmd.total_len);
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DYN_BW,
+ strlen(PRIV_CMD_DYN_BW)) == 0) {
+ /* Set/Get dynamic bandwidth */
+ len = woal_priv_config_dyn_bw(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IND_RST_CFG,
+ strlen(PRIV_CMD_IND_RST_CFG)) == 0) {
+ /* Set/Get out band independent reset */
+ len = woal_priv_ind_rst_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PER_PKT_CFG,
+ strlen(PRIV_CMD_PER_PKT_CFG)) == 0) {
+ /* Get/Set per packet Txctl and Rxinfo configuration */
+ len = woal_priv_per_pkt_cfg(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH_CTRL,
+ strlen(PRIV_CMD_DEAUTH_CTRL)) == 0) {
+ len = woal_priv_deauth_ctrl(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCFG,
+ strlen(PRIV_CMD_11AXCFG)) == 0) {
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_11AXCFG);
+ len = priv_cmd.used_len - strlen(PRIV_CMD_11AXCFG) -
+ strlen(CMD_NXP);
+ len = woal_priv_11axcfg_cmd(priv, pdata, len,
+ priv_cmd.total_len);
+ len += strlen(PRIV_CMD_11AXCFG) + strlen(CMD_NXP);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_SETUP,
+ strlen(PRIV_CMD_TWT_SETUP)) == 0) {
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_TWT_SETUP);
+ len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_SETUP) -
+ strlen(CMD_NXP);
+ len = woal_priv_twt_setup(priv, pdata, len,
+ priv_cmd.total_len);
+ len += strlen(PRIV_CMD_TWT_SETUP) + strlen(CMD_NXP);
+ goto handled;
+
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_TWT_TEARDOWN,
+ strlen(PRIV_CMD_TWT_TEARDOWN)) == 0) {
+ pdata = buf + strlen(CMD_NXP) +
+ strlen(PRIV_CMD_TWT_TEARDOWN);
+ len = priv_cmd.used_len -
+ strlen(PRIV_CMD_TWT_TEARDOWN) - strlen(CMD_NXP);
+ len = woal_priv_twt_teardown(priv, pdata, len,
+ priv_cmd.total_len);
+ len += strlen(PRIV_CMD_TWT_TEARDOWN) + strlen(CMD_NXP);
+ goto handled;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ } else if (strnicmp(buf + strlen(CMD_NXP),
+ PRIV_CMD_GET_CFG_CHAN_LIST,
+ strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) {
+ /* Get txpwrlimit */
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
+ len = woal_priv_getcfgchanlist(
+ priv, buf, priv_cmd.total_len);
+ else
+ len = sprintf(buf,
+ "CFG80211 is not enabled\n") +
+ 1;
+ goto handled;
+#endif
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_LPM,
+ strlen(PRIV_CMD_LPM)) == 0) {
+ /* Set/Get low power mode */
+ len = woal_priv_set_get_lpm(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TP_STATE,
+ strlen(PRIV_CMD_TP_STATE)) == 0) {
+ /* Set/Get TP accounting state */
+ len = woal_priv_set_tp_state(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else {
+ PRINTM(MERROR,
+ "Unknown NXP PRIVATE command %s, ignored\n",
+ buf);
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#ifdef STA_SUPPORT
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
+ 0) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_rssi_low_threshold(priv, pdata, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-CFG", strlen("SCAN-CFG")) == 0) {
+ PRINTM(MIOCTL, "Set SCAN CFG\n");
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_cfg(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
+ &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "%.32s rssi %d\n",
+ bss_info.ssid.ssid, signal.bcn_rssi_avg) +
+ 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
+ len = sprintf(buf, "LinkSpeed %d\n",
+ (int)(rate.rate * 500000 / 1000000)) +
+ 1;
+ } else
+#endif
+ if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) +
+ 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SETROAMING", strlen("SETROAMING")) == 0) {
+ pdata = buf + strlen("SETROAMING") + 1;
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ goto done;
+#endif
+#endif
+#ifdef STA_CFG80211
+ if (*pdata == '1') {
+ priv->roaming_enabled = MTRUE;
+ PRINTM(MIOCTL, "Roaming enabled\n");
+ } else if (*pdata == '0') {
+ priv->roaming_enabled = MFALSE;
+ PRINTM(MIOCTL, "Roaming disabled\n");
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "ROAM", strlen("ROAM")) == 0) {
+ pdata = buf + strlen("ROAM") + 1;
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ goto done;
+#endif
+#endif
+#ifdef STA_CFG80211
+ if (*pdata == '1') {
+ priv->roaming_enabled = MTRUE;
+ PRINTM(MIOCTL, "Roaming enabled\n");
+ } else if (*pdata == '0') {
+ priv->roaming_enabled = MFALSE;
+ PRINTM(MIOCTL, "Roaming disabled\n");
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ copy_len = strlen(buf) - strlen("COUNTRY") - 1;
+ if (copy_len > COUNTRY_CODE_LEN || copy_len <= 0) {
+ PRINTM(MERROR, "Invalid country length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(country_code, 0, sizeof(country_code));
+ moal_memcpy_ext(priv->phandle, country_code,
+ buf + strlen("COUNTRY") + 1, copy_len,
+ COUNTRY_CODE_LEN);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (moal_extflg_isset(priv->phandle, EXT_CNTRY_TXPWR)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_country_power_table(priv,
+ country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ PRINTM(MIOCTL, "Notify country code=%s\n",
+ country_code);
+ if (!moal_extflg_isset(priv->phandle,
+ EXT_DISABLE_REGD_BY_DRIVER))
+ regulatory_hint(priv->wdev->wiphy,
+ country_code);
+ len = sprintf(buf, "OK\n") + 1;
+ goto done;
+ }
+#endif
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ==
+ 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_combo_scan(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef UAP_SUPPORT
+ else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ if (ret)
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ if (ret)
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
+ if (priv_cmd.total_len <= strlen("AP_SET_CFG") + 1)
+ goto done;
+ pdata = buf + strlen("AP_SET_CFG") + 1;
+ ret = woal_uap_set_ap_cfg(priv, pdata,
+ priv_cmd.total_len -
+ strlen("AP_SET_CFG") - 1);
+ if (ret)
+ goto done;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) ==
+ 0) {
+ /* TODO Add STA list support */
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SETSUSPENDMODE", strlen("SETSUSPENDMODE")) ==
+ 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START",
+ strlen("BTCOEXSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
+ 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_stop_bg_scan(priv, MOAL_NO_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
+ 0) {
+#ifdef MEF_CFG_RX_FILTER
+ ret = woal_set_rxfilter(priv, MTRUE);
+ if (ret)
+ goto done;
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
+ 0) {
+#ifdef MEF_CFG_RX_FILTER
+ ret = woal_set_rxfilter(priv, MFALSE);
+ if (ret)
+ goto done;
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#ifdef STA_CFG80211
+ else if (strncmp(buf, "GET_EVENT", strlen("GET_EVENT")) == 0) {
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->last_event & EVENT_BG_SCAN_REPORT)
+ woal_inform_bss_from_scan_result(
+ priv, NULL, MOAL_IOCTL_WAIT);
+ }
+ len = sprintf(buf, "EVENT=%d\n", priv->last_event) + 1;
+ priv->last_event = 0;
+ } else if (strncmp(buf, "GET_802_11W", strlen("GET_802_11W")) == 0) {
+ len = sprintf(buf, "802_11W=ENABLED\n") + 1;
+ }
+#endif /* STA_CFG80211 */
+ else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
+ 0) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ pdata = buf + strlen("QOSINFO") + 1;
+#ifdef STA_SUPPORT
+ if (MLAN_STATUS_SUCCESS !=
+ woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
+ strlen("SET_AP_WPS_P2P_IE")) == 0) {
+ pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
+ /* Android cmd format:
+ * "SET_AP_WPS_P2P_IE 1" -- beacon IE
+ * "SET_AP_WPS_P2P_IE 2" -- proberesp IE
+ * "SET_AP_WPS_P2P_IE 4" -- assocresp IE
+ */
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_ap_wps_p2p_ie(priv, (t_u8 *)pdata,
+ priv_cmd.used_len -
+ strlen("SET_AP_WPS_P2P_IE") -
+ 1)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+ else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
+ memset(buf, 0x0, (size_t)priv_cmd.total_len);
+ moal_memcpy_ext(priv->phandle, buf, priv->current_addr,
+ ETH_ALEN, (t_u32)priv_cmd.total_len);
+ len = ETH_ALEN;
+ } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
+ /* TODO
+ * Just return '\0'
+ */
+ memset(buf, 0x0, (size_t)priv_cmd.total_len);
+ *buf = 0;
+ len = 1;
+ } else if (strnicmp(buf, "MIRACAST", strlen("MIRACAST")) == 0) {
+ pdata = buf + strlen("MIRACAST");
+ /* Android cmd format:
+ * "MIRACAST 0" -- disabled
+ * "MIRACAST 1" -- operating as source
+ * "MIRACAST 2" -- operating as sink
+ */
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_miracast_mode(priv, (t_u8 *)pdata,
+ priv_cmd.used_len -
+ strlen("MIRACAST"))) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strnicmp(buf, "SCAN_TIMING", strlen("SCAN_TIMING")) == 0) {
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_chan_gap(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#endif
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strnicmp(buf, "BA_WSIZE_RX", strlen("BA_WSIZE_RX")) == 0) {
+ pdata = buf + strlen("BA_WSIZE_RX") + 1;
+ len = priv_cmd.total_len - strlen("BA_WSIZE_RX") - 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_rx_ba_winsize(priv, pdata, len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strnicmp(buf, "BA_WSIZE_TX", strlen("BA_WSIZE_TX")) == 0) {
+ pdata = buf + strlen("BA_WSIZE_TX") + 1;
+ len = priv_cmd.total_len - strlen("BA_WSIZE_TX") - 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_tx_ba_winsize(priv, pdata, len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "FAKE_SCAN_COMPLETE",
+ strlen("FAKE_SCAN_COMPLETE")) == 0) {
+ pdata = buf + strlen("FAKE_SCAN_COMPLETE") + 1;
+#ifdef STA_CFG80211
+ if (*pdata == '1') {
+ priv->fake_scan_complete = MTRUE;
+ PRINTM(MIOCTL, "fake scan complete enabled\n");
+ } else if (*pdata == '0') {
+ priv->fake_scan_complete = MFALSE;
+ PRINTM(MIOCTL, "fake scan complete disabled\n");
+ }
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (strncmp(buf, "P2P_PERIODIC_SLEEP",
+ strlen("P2P_PERIODIC_SLEEP")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_p2p_ps_cfg(priv, buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#endif
+#endif
+ else if (strncmp(buf, "WLS_BATCHING", strlen("WLS_BATCHING")) == 0) {
+ /* TODO */
+ len = sprintf(buf, "OK\n") + 1;
+ }
+#if defined(UAP_SUPPORT)
+ else if (strncmp(buf, "P2P_ECSA", strlen("P2P_ECSA")) == 0) {
+ len = woal_priv_p2p_ecsa(priv, buf, priv_cmd.total_len);
+ }
+#endif
+ else if (strncmp(buf, "FAKEMAC", strlen("FAKEMAC")) == 0) {
+ len = woal_priv_config_random_mac(priv, buf,
+ priv_cmd.total_len);
+ } else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE,
+ strlen(PRIV_CMD_CLOUD_KEEP_ALIVE)) == 0) {
+ len = woal_priv_cloud_keep_alive(priv, buf, priv_cmd.total_len);
+ } else if (strnicmp(buf, PRIV_CMD_TX_RX_HISTOGRAM,
+ strlen(PRIV_CMD_TX_RX_HISTOGRAM)) == 0) {
+ /* Get TX/RX histogram statistic */
+ len = woal_priv_get_rx_tx_histogram(priv, buf,
+ priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf, PRIV_CMD_GET_CHNRGPWR,
+ strlen(PRIV_CMD_GET_CHNRGPWR)) == 0) {
+ /* Get chnrgpwr */
+ len = woal_priv_get_chnrgpwr(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else if (strnicmp(buf, PRIV_CMD_GET_TXPWR_LIMIT,
+ strlen(PRIV_CMD_GET_TXPWR_LIMIT)) == 0) {
+ /* Get txpwrlimit */
+ len = woal_priv_get_txpwrlimit(priv, buf, priv_cmd.total_len);
+ goto handled;
+ } else {
+ PRINTM(MIOCTL, "Unknown PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+
+handled:
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+
+ if (len > 0) {
+ priv_cmd.used_len = len;
+ if (priv_cmd.used_len <= priv_cmd.total_len) {
+ memset(buf + priv_cmd.used_len, 0,
+ (size_t)(CMD_BUF_LEN - priv_cmd.used_len));
+ if (copy_to_user(cmd_buf, buf, priv_cmd.total_len)) {
+ PRINTM(MERROR,
+ "%s: failed to copy data to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user(req->ifr_data, &priv_cmd,
+ sizeof(android_wifi_priv_cmd))) {
+ PRINTM(MERROR,
+ "%s: failed to copy command header to user buffer\n",
+ __FUNCTION__);
+ ret = -EFAULT;
+ }
+ } else {
+ PRINTM(MERROR,
+ "%s: the buffer supplied by appl is too small (supplied: %d, used: %d)\n",
+ __FUNCTION__, priv_cmd.total_len,
+ priv_cmd.used_len);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = len;
+ }
+
+done:
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ * When the beacon/probe response has not been buffered, use the saved BSS
+ * information available to provide a minimum response for the application
+ * ioctl retrieval routines. Include:
+ * - Timestamp
+ * - Beacon Period
+ * - Capabilities (including WMM Element if available)
+ * - SSID
+ *
+ * @param ppbuffer Output parameter: Buffer used to create basic scan rsp
+ * @param pbss_desc Pointer to a BSS entry in the scan table to create
+ * scan response from for delivery to the application layer
+ *
+ * @return N/A
+ */
+void wlan_scan_create_brief_table_entry(t_u8 **ppbuffer,
+ BSSDescriptor_t *pbss_desc)
+{
+ t_u8 *ptmp_buf = *ppbuffer;
+ t_u8 tmp_ssid_hdr[2];
+ t_u8 ie_len = 0;
+
+ ENTER();
+
+ moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->time_stamp,
+ sizeof(pbss_desc->time_stamp),
+ sizeof(pbss_desc->time_stamp));
+ ptmp_buf += sizeof(pbss_desc->time_stamp);
+
+ moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->beacon_period,
+ sizeof(pbss_desc->beacon_period),
+ sizeof(pbss_desc->beacon_period));
+ ptmp_buf += sizeof(pbss_desc->beacon_period);
+
+ moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->cap_info,
+ sizeof(pbss_desc->cap_info),
+ sizeof(pbss_desc->cap_info));
+ ptmp_buf += sizeof(pbss_desc->cap_info);
+
+ tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
+ tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
+ moal_memcpy_ext(NULL, ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr),
+ sizeof(tmp_ssid_hdr));
+ ptmp_buf += sizeof(tmp_ssid_hdr);
+
+ moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->ssid.ssid,
+ pbss_desc->ssid.ssid_len, pbss_desc->ssid.ssid_len);
+ ptmp_buf += pbss_desc->ssid.ssid_len;
+
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) +
+ pbss_desc->wmm_ie.vend_hdr.len;
+ moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->wmm_ie, ie_len,
+ ie_len);
+ ptmp_buf += ie_len;
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->pwpa_ie)).vend_hdr.len;
+ moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->pwpa_ie,
+ ie_len, ie_len);
+ }
+
+ ptmp_buf += ie_len;
+ }
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
+ ie_len = sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->prsn_ie)).ieee_hdr.len;
+ moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->prsn_ie,
+ ie_len, ie_len);
+ }
+
+ ptmp_buf += ie_len;
+ }
+ *ppbuffer = ptmp_buf;
+ LEAVE();
+}
+
+/**
+ * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
+ * Descriptor for inclusion in the ioctl response to the user space
+ * application.
+ *
+ *
+ * @param pbss_desc Pointer to a BSS entry in the scan table to form
+ * scan response from for delivery to the application layer
+ * @param ppbuffer Output parameter: Buffer used to output scan return
+ * struct
+ * @param pspace_left Output parameter: Number of bytes available in the
+ * response buffer.
+ *
+ * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+int wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer,
+ int *pspace_left)
+{
+ wlan_ioctl_get_scan_table_entry *prsp_entry;
+ wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
+ int space_needed;
+ t_u8 *pcurrent;
+ int variable_size;
+
+ const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);
+
+ ENTER();
+
+ pcurrent = *ppbuffer;
+
+ /* The variable size returned is the stored beacon size */
+ variable_size = pbss_desc->beacon_buf_size;
+
+ /* If we stored a beacon and its size was zero, set the variable
+ * size return value to the size of the brief scan response
+ * wlan_scan_create_brief_table_entry creates. Also used if
+ * we are not configured to store beacons in the first place
+ */
+ if (!variable_size) {
+ variable_size = pbss_desc->ssid.ssid_len + 2;
+ variable_size += (sizeof(pbss_desc->beacon_period) +
+ sizeof(pbss_desc->time_stamp) +
+ sizeof(pbss_desc->cap_info));
+ if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
+ variable_size += (sizeof(IEEEtypes_Header_t) +
+ pbss_desc->wmm_ie.vend_hdr.len);
+ }
+
+ if (pbss_desc->pwpa_ie) {
+ if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
+ WPA_IE) {
+ variable_size +=
+ (sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->pwpa_ie)).vend_hdr.len);
+ }
+ }
+
+ if (pbss_desc->prsn_ie) {
+ if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
+ RSN_IE) {
+ variable_size +=
+ (sizeof(IEEEtypes_Header_t) +
+ (*(pbss_desc->prsn_ie)).ieee_hdr.len);
+ }
+ }
+ }
+
+ space_needed = fixed_size + variable_size;
+
+ PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", space_needed,
+ *pspace_left);
+
+ if (space_needed >= *pspace_left) {
+ *pspace_left = 0;
+ LEAVE();
+ return -E2BIG;
+ }
+
+ *pspace_left -= space_needed;
+
+ tmp_rsp_entry.fixed_field_length =
+ (sizeof(tmp_rsp_entry) -
+ sizeof(tmp_rsp_entry.fixed_field_length) -
+ sizeof(tmp_rsp_entry.bss_info_length));
+
+ moal_memcpy_ext(NULL, tmp_rsp_entry.fixed_fields.bssid,
+ pbss_desc->mac_address,
+ sizeof(prsp_entry->fixed_fields.bssid),
+ sizeof(prsp_entry->fixed_fields.bssid));
+
+ tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
+ tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
+ tmp_rsp_entry.fixed_fields.chan_load = pbss_desc->chan_load;
+ tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
+ tmp_rsp_entry.bss_info_length = variable_size;
+
+ /*
+ * Copy fixed fields to user space
+ */
+ moal_memcpy_ext(NULL, pcurrent, &tmp_rsp_entry, fixed_size, fixed_size);
+ pcurrent += fixed_size;
+
+ if (pbss_desc->pbeacon_buf) {
+ /*
+ * Copy variable length elements to user space
+ */
+ moal_memcpy_ext(NULL, pcurrent, pbss_desc->pbeacon_buf,
+ pbss_desc->beacon_buf_size,
+ pbss_desc->beacon_buf_size);
+
+ pcurrent += pbss_desc->beacon_buf_size;
+ } else {
+ wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
+ }
+
+ *ppbuffer = pcurrent;
+
+ LEAVE();
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WOAL_ANDROID_DEF_CMD:
+ /** android default ioctl ID is SIOCDEVPRIVATE + 1 */
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ case WOAL_CUSTOM_IE_CFG:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case WOAL_MGMT_FRAME_TX:
+ ret = woal_send_host_packet(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ case WOAL_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ default:
+#if defined(STA_WEXT)
+#ifdef STA_SUPPORT
+ ret = woal_wext_do_ioctl(dev, req, cmd);
+#else
+ ret = -EINVAL;
+#endif
+#else
+ ret = -EINVAL;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.h
new file mode 100644
index 000000000000..57b203e833dd
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_eth_ioctl.h
@@ -0,0 +1,675 @@
+
+/** @file moal_eth_ioctl.h
+ *
+ * @brief This file contains definition for private IOCTL call.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 01/05/2012: initial version
+********************************************************/
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+#ifndef _WOAL_ETH_PRIV_H_
+#define _WOAL_ETH_PRIV_H_
+
+/** Command disabled */
+#define CMD_DISABLED 0
+/** Command enabled */
+#define CMD_ENABLED 1
+/** Command get */
+#define CMD_GET 2
+
+/** 2K bytes */
+#define WOAL_2K_BYTES 2000
+
+/** NXP private command identifier string */
+#define CMD_NXP "MRVL_CMD"
+
+/** Private command: Version */
+#define PRIV_CMD_VERSION "version"
+/** Private command: Band cfg */
+#define PRIV_CMD_BANDCFG "bandcfg"
+/** Private command: Host cmd */
+#define PRIV_CMD_HOSTCMD "hostcmd"
+/** Private command: Custom IE config*/
+#define PRIV_CMD_CUSTOMIE "customie"
+/** Private command: HT Tx Cfg */
+#define PRIV_CMD_HTTXCFG "httxcfg"
+/** Private command: HT Cap Info */
+#define PRIV_CMD_HTCAPINFO "htcapinfo"
+/** Private command: Add BA para */
+#define PRIV_CMD_ADDBAPARA "addbapara"
+/** Private command: Aggragation priority table */
+#define PRIV_CMD_AGGRPRIOTBL "aggrpriotbl"
+/** Private command: Add BA reject cfg */
+#define PRIV_CMD_ADDBAREJECT "addbareject"
+/** Private command: Delete BA */
+#define PRIV_CMD_DELBA "delba"
+/** Private command: Reject Addba Req */
+#define PRIV_CMD_REJECTADDBAREQ "rejectaddbareq"
+/** Private command: 11AC Cfg */
+#define PRIV_CMD_VHTCFG "vhtcfg"
+/** Private command: 11AC Oper Mode Cfg */
+#define PRIV_CMD_OPERMODECFG "opermodecfg"
+#define PRIV_CMD_DATARATE "getdatarate"
+#define PRIV_CMD_TXRATECFG "txratecfg"
+#define PRIV_CMD_GETLOG "getlog"
+#define PRIV_CMD_ESUPPMODE "esuppmode"
+#define PRIV_CMD_PASSPHRASE "passphrase"
+#define PRIV_CMD_DEAUTH "deauth"
+#ifdef UAP_SUPPORT
+#define PRIV_CMD_AP_DEAUTH "apdeauth"
+#define PRIV_CMD_GET_STA_LIST "getstalist"
+#define PRIV_CMD_BSS_CONFIG "bssconfig"
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#define PRIV_CMD_BSSROLE "bssrole"
+#endif
+#endif
+#ifdef STA_SUPPORT
+#define PRIV_CMD_GETSCANTABLE "getscantable"
+#define PRIV_CMD_GETCHANSTATS "getchanstats"
+typedef struct _chan_stats {
+ /** Number of records in the chan_stats */
+ t_u32 num_in_chan_stats;
+ /** channel statistics */
+ ChanStatistics_t stats[];
+} chan_stats;
+#define PRIV_CMD_SETUSERSCAN "setuserscan"
+#define PRIV_CMD_EXTCAPCFG "extcapcfg"
+#define PRIV_CMD_CANCELSCAN "cancelscan"
+#endif
+#define PRIV_CMD_DEEPSLEEP "deepsleep"
+#define PRIV_CMD_IPADDR "ipaddr"
+#define PRIV_CMD_WPSSESSION "wpssession"
+#define PRIV_CMD_OTPUSERDATA "otpuserdata"
+#define PRIV_CMD_COUNTRYCODE "countrycode"
+#define PRIV_CMD_TCPACKENH "tcpackenh"
+#ifdef REASSOCIATION
+#define PRIV_CMD_ASSOCESSID "assocessid"
+#define PRIV_CMD_ASSOCBSSID "assocessid_bssid"
+#endif
+#define PRIV_CMD_WAKEUPREASON "wakeupreason"
+#ifdef STA_SUPPORT
+#define PRIV_CMD_LISTENINTERVAL "listeninterval"
+#endif
+#ifdef DEBUG_LEVEL1
+#define PRIV_CMD_DRVDBG "drvdbg"
+#endif
+#define PRIV_CMD_HSCFG "hscfg"
+#define PRIV_CMD_HSSETPARA "hssetpara"
+#define PRIV_CMD_MGMT_FILTER "mgmtfilter"
+#define PRIV_CMD_SCANCFG "scancfg"
+#define PRIV_CMD_GETNLNUM "getnlnum"
+#define PRIV_CMD_AGGRCTRL "aggrctrl"
+#ifdef USB
+#define PRIV_CMD_USBAGGRCTRL "usbaggrctrl"
+#endif
+#define PRIV_CMD_SET_BSS_MODE "setbssmode"
+#ifdef STA_SUPPORT
+#define PRIV_CMD_SET_AP "setap"
+#define PRIV_CMD_SET_POWER "setpower"
+#define PRIV_CMD_SET_ESSID "setessid"
+#define PRIV_CMD_SET_AUTH "setauth"
+#define PRIV_CMD_GET_AP "getap"
+#define PRIV_CMD_GET_POWER "getpower"
+#define PRIV_CMD_PSMODE "psmode"
+#endif
+#define PRIV_CMD_WARMRESET "warmreset"
+#define PRIV_CMD_TXPOWERCFG "txpowercfg"
+#define PRIV_CMD_PSCFG "pscfg"
+#define PRIV_CMD_BCNTIMEOUTCFG "bcntimeoutcfg"
+#define PRIV_CMD_SLEEPPD "sleeppd"
+#define PRIV_CMD_TXCONTROL "txcontrol"
+#define PRIV_CMD_REGRDWR "regrdwr"
+#define PRIV_CMD_RDEEPROM "rdeeprom"
+#define PRIV_CMD_MEMRDWR "memrdwr"
+#ifdef SDIO
+#define PRIV_CMD_SDCMD52RW "sdcmd52rw"
+#endif
+#define PRIV_CMD_HOTSPOTCFG "hotspotcfg"
+#define PRIV_CMD_MGMT_FRAME_CTRL "mgmtframectrl"
+#define PRIV_CMD_QCONFIG "qconfig"
+#define PRIV_CMD_ADDTS "addts"
+#define PRIV_CMD_DELTS "delts"
+#define PRIV_CMD_QSTATUS "qstatus"
+#define PRIV_CMD_TS_STATUS "ts_status"
+#define PRIV_CMD_QOS_CFG "qoscfg"
+#define PRIV_CMD_MAC_CTRL "macctrl"
+#define PRIV_CMD_GETWAP "getwap"
+#define PRIV_CMD_REGION_CODE "regioncode"
+#define PRIV_CMD_CFPINFO "cfpinfo"
+#define PRIV_CMD_FWMACADDR "fwmacaddr"
+#define PRIV_CMD_OFFCHANNEL "offchannel"
+#define PRIV_CMD_DSCP_MAP "dscpmap"
+/** Private command: Verext */
+#define PRIV_CMD_VEREXT "verext"
+#ifdef CONFIG_USB_SUSPEND
+#define PRIV_CMD_USB_SUSPEND "usbsuspend"
+#define PRIV_CMD_USB_RESUME "usbresume"
+#endif /* CONFIG_USB_SUSPEND */
+#if defined(STA_SUPPORT) && defined(STA_WEXT)
+#define PRIV_CMD_RADIO_CTRL "radioctrl"
+#endif
+#define PRIV_CMD_WMM_CFG "wmmcfg"
+#define PRIV_CMD_MIN_BA_THRESH_CFG "min_ba_threshold"
+#if defined(STA_SUPPORT)
+#define PRIV_CMD_11D_CFG "11dcfg"
+#define PRIV_CMD_11D_CLR_TBL "11dclrtbl"
+#endif
+#ifndef OPCHAN
+#define PRIV_CMD_WWS_CFG "wwscfg"
+#endif
+#if defined(REASSOCIATION)
+#define PRIV_CMD_REASSOCTRL "reassoctrl"
+#endif
+#define PRIV_CMD_TXBUF_CFG "txbufcfg"
+#ifdef STA_SUPPORT
+#define PRIV_CMD_AUTH_TYPE "authtype"
+#endif
+#define PRIV_CMD_POWER_CONS "powercons"
+#define PRIV_CMD_HT_STREAM_CFG "htstreamcfg"
+#define PRIV_CMD_MIMO_SWITCH "mimoswitch"
+#define PRIV_CMD_THERMAL "thermal"
+#define PRIV_CMD_BCN_INTERVAL "bcninterval"
+#ifdef STA_SUPPORT
+#define PRIV_CMD_GET_SIGNAL "getsignal"
+#define PRIV_CMD_SIGNALEXT_CFG "signalextcfg"
+#define PRIV_CMD_GET_SIGNAL_EXT_V2 "getsignalextv2"
+#define PRIV_CMD_GET_SIGNAL_EXT "getsignalext"
+#endif
+#if defined(STA_SUPPORT)
+#define PRIV_CMD_PMFCFG "pmfcfg"
+#endif
+#define PRIV_CMD_INACTIVITYTO "inactivityto"
+#define PRIV_CMD_AMSDU_AGGR_CTRL "amsduaggrctrl"
+#define PRIV_CMD_TX_BF_CAP "httxbfcap"
+#ifdef SDIO
+#define PRIV_CMD_SDIO_CLOCK "sdioclock"
+#endif
+#ifdef SDIO
+#define PRIV_CMD_MPA_CTRL "mpactrl"
+#endif
+#define PRIV_CMD_SLEEP_PARAMS "sleepparams"
+#define PRIV_CMD_DFS_TESTING "dfstesting"
+#define PRIV_CMD_DFS53_CFG "dfs53cfg"
+#define PRIV_CMD_CFP_CODE "cfpcode"
+#define PRIV_CMD_CWMODE "cwmode"
+#define PRIV_CMD_ANT_CFG "antcfg"
+#define PRIV_CMD_SYSCLOCK "sysclock"
+#define PRIV_CMD_GET_KEY "getkey"
+#define PRIV_CMD_ASSOCIATE "associate"
+#define PRIV_CMD_TX_BF_CFG "httxbfcfg"
+#define PRIV_CMD_PORT_CTRL "port_ctrl"
+#define PRIV_CMD_PB_BYPASS "pb_bypass"
+#ifdef SDIO
+#define PRIV_CMD_SD_CMD53_RW "sdcmd53rw"
+#endif
+#ifdef RX_PACKET_COALESCE
+#define PRIV_CMD_RX_COAL_CFG "rxpktcoal_cfg"
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(UAP_CFG80211)
+#define PRIV_CMD_CFG_NOA "cfg_noa"
+#define PRIV_CMD_CFG_OPP_PS "cfg_opp_ps"
+#endif
+#endif
+#define PRIV_CMD_DFS_REPEATER_CFG "dfs_repeater"
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#define PRIV_CMD_MIRACAST_CFG "miracastcfg"
+#endif
+#endif
+#define PRIV_CMD_COEX_RX_WINSIZE "coex_rx_winsize"
+
+#ifdef PCIE
+#define PRIV_CMD_PCIE_REG_RW "pcieregrw"
+#define PRIV_CMD_PCIE_BAR0_REG_RW "pciebar0regrw"
+#endif
+
+#define PRIV_CMD_GET_SENSOR_TEMP "get_sensor_temp"
+
+#define PRIV_CMD_GET_CHNRGPWR "get_chnrgpwr"
+#define PRIV_CMD_GET_TXPWR_LIMIT "get_txpwrlimit"
+#define PRIV_CMD_GET_CFG_CHAN_LIST "getcfgchanlist"
+#if defined(UAP_SUPPORT)
+#define PRIV_CMD_EXTEND_CHAN_SWITCH "channel_switch"
+#endif
+
+#define PRIV_CMD_DYN_BW "dyn_bw"
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#define PRIV_CMD_DFS_OFFLOAD "dfs_offload"
+#endif
+
+#define PRIV_CMD_AUTO_ARP "auto_arp"
+
+#define PRIV_CMD_PER_PKT_CFG "per_pkt_cfg"
+
+#define PRIV_CMD_DEAUTH_CTRL "ctrldeauth"
+
+#define PRIV_CMD_TX_RX_HISTOGRAM "txrxhistogram"
+
+/**Private command ID to set/get independent reset*/
+#define PRIV_CMD_IND_RST_CFG "indrstcfg"
+
+#define PRIV_CMD_ARB_CFG "arb"
+
+/**Private command to configure static rx abort config */
+#define PRIV_CMD_RX_ABORT_CFG "rx_abort_cfg"
+/**Private command to configure dynamic rx abort config */
+#define PRIV_CMD_RX_ABORT_CFG_EXT "rx_abort_cfg_ext"
+#define TX_AMPDU_RTS_CTS 0
+#define TX_AMPDU_CTS_2_SELF 1
+#define TX_AMPDU_DISABLE_PROTECTION 2
+#define TX_AMPDU_DYNAMIC_RTS_CTS 3
+/**Private command to set tx ampdu protection mode */
+#define PRIV_CMD_TX_AMPDU_PROT_MODE "tx_ampdu_prot_mode"
+/**Private command to configure tx rate adapt config */
+#define PRIV_CMD_RATE_ADAPT_CFG "rate_adapt_cfg"
+#define CCK_DESENSE_MODE_DISABLED 0
+#define CCK_DESENSE_MODE_DYNAMIC 1
+#define CCK_DESENSE_MODE_DYN_ENH 2
+/**Private command to configure cck desense config */
+#define PRIV_CMD_CCK_DESENSE_CFG "cck_desense_cfg"
+#define PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG "dot11mc_unassoc_ftm_cfg"
+
+/** Private command ID for Android default commands */
+#define WOAL_ANDROID_DEF_CMD (SIOCDEVPRIVATE + 1)
+
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX WOAL_MGMT_FRAME_TX_IOCTL
+
+/** Private command ID to pass custom IE list */
+#define WOAL_CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13)
+
+/** Private command ID for Android ICS priv CMDs */
+#define WOAL_ANDROID_PRIV_CMD (SIOCDEVPRIVATE + 14)
+
+/** Private command ID to get BSS type */
+#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+/** Private command ID for robustcoex */
+#define PRIV_CMD_ROBUSTCOEX "robustcoex"
+
+#define PRIV_CMD_DMCS "dmcs"
+
+#if defined(PCIE)
+#define PRIV_CMD_SSU "ssu"
+/** ssu_params_ctrl */
+typedef struct _ssu_params_cfg {
+ /* ssu mode */
+ t_u8 ssu_mode;
+ /* 0-3; # of FFT samples to skip*/
+ t_u32 nskip;
+ /* 0-3: # of FFT samples selected to dump */
+ t_u32 nsel;
+ /* 0-3: Down sample ADC input for buffering*/
+ t_u32 adcdownsample;
+ /* 0-1: Mask out ADC Data from spectral packet */
+ t_u32 mask_adc_pkt;
+ /* 0-1: Enable 16-Bit FFT output data precision in spectral packet */
+ t_u32 out_16bits;
+ /* 0-1: Enable power spectrum in dB for spectral packe */
+ t_u32 spec_pwr_enable;
+ /* 0-1: Enable spectral packet rate reduction in DB output format */
+ t_u32 rate_deduction;
+ /* 0-7: Number of spectral packets over which spectral data is to be
+ * averaged. */
+ t_u32 n_pkt_avg;
+} __attribute__((packed)) ssu_params_cfg;
+#endif
+
+#define PRIV_CMD_BOOTSLEEP "bootsleep"
+
+/** Private command: 11AX Cfg */
+#define PRIV_CMD_11AXCFG "11axcfg"
+/** Private command: 11AX Cmd */
+#define PRIV_CMD_11AXCMDCFG "11axcmd"
+/** Private command: Range ext Cmd */
+#define PRIV_CMD_RANGE_EXT "range_ext"
+/** Private command: TWT Setup Cfg */
+#define PRIV_CMD_TWT_SETUP "twt_setup"
+/** Private command: TWT Teardown Cfg */
+#define PRIV_CMD_TWT_TEARDOWN "twt_teardown"
+
+#define PRIV_CMD_LPM "lpm"
+
+int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+
+/*
+ * For android private commands, fixed value of ioctl is used.
+ * Internally commands are differentiated using strings.
+ *
+ * application needs to specify "total_len" of data for copy_from_user
+ * kernel updates "used_len" during copy_to_user
+ */
+/** Private command structure from app */
+#ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
+typedef struct _android_wifi_priv_cmd {
+ /** Buffer pointer */
+ t_u64 buf;
+ /** buffer updated by driver */
+ int used_len;
+ /** buffer sent by application */
+ int total_len;
+} __attribute__((packed)) android_wifi_priv_cmd;
+#else
+typedef struct _android_wifi_priv_cmd {
+ /** Buffer pointer */
+ char *buf;
+ /** buffer updated by driver */
+ int used_len;
+ /** buffer sent by application */
+ int total_len;
+} android_wifi_priv_cmd;
+#endif
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+/* Maximum size of the ESSID and NICKN strings */
+#define MW_ESSID_MAX_SIZE 32
+
+/* Modes of operation */
+#define MW_MODE_AUTO 0 /* Let the driver decides */
+#define MW_MODE_ADHOC 1 /* Single cell network */
+#define MW_MODE_INFRA 2 /* Multi cell network, roaming, ... */
+#define MW_MODE_MASTER 3 /* Synchronisation master or Access Point */
+#define MW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
+#define MW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
+#define MW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+#define MW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */
+
+#define MW_POWER_TYPE 0xF000 /* Type of parameter */
+#define MW_POWER_PERIOD 0x1000 /* Value is a period/duration of */
+#define MW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */
+
+#define MW_AUTH_INDEX 0x0FFF
+#define MW_AUTH_FLAGS 0xF000
+#define MW_AUTH_WPA_VERSION 0
+#define MW_AUTH_CIPHER_PAIRWISE 1
+#define MW_AUTH_CIPHER_GROUP 2
+#define MW_AUTH_KEY_MGMT 3
+#define MW_AUTH_TKIP_COUNTERMEASURES 4
+#define MW_AUTH_DROP_UNENCRYPTED 5
+#define MW_AUTH_80211_AUTH_ALG 6
+#define MW_AUTH_WPA_ENABLED 7
+#define MW_AUTH_RX_UNENCRYPTED_EAPOL 8
+#define MW_AUTH_ROAMING_CONTROL 9
+#define MW_AUTH_PRIVACY_INVOKED 10
+#define MW_AUTH_CIPHER_GROUP_MGMT 11
+#define MW_AUTH_MFP 12
+
+#define MW_AUTH_CIPHER_NONE 0x00000001
+#define MW_AUTH_CIPHER_WEP40 0x00000002
+#define MW_AUTH_CIPHER_TKIP 0x00000004
+#define MW_AUTH_CIPHER_CCMP 0x00000008
+#define MW_AUTH_CIPHER_WEP104 0x00000010
+#define MW_AUTH_CIPHER_AES_CMAC 0x00000020
+
+#define MW_AUTH_ALG_OPEN_SYSTEM 0x00000001
+#define MW_AUTH_ALG_SHARED_KEY 0x00000002
+#define MW_AUTH_ALG_LEAP 0x00000004
+
+/* Generic format for most parameters that fit in an int */
+struct mw_param {
+ t_s32 value; /* The value of the parameter itself */
+ t_u8 fixed; /* Hardware should not use auto select */
+ t_u8 disabled; /* Disable the feature */
+ t_u16 flags; /* Various specifc flags (if any) */
+};
+
+/*
+ * For all data larger than 16 octets, we need to use a
+ * pointer to memory allocated in user space.
+ */
+struct mw_point {
+ t_u8 *pointer; /* Pointer to the data (in user space) */
+ t_u16 length; /* number of fields or size in bytes */
+ t_u16 flags; /* Optional params */
+};
+
+/*
+ * This structure defines the payload of an ioctl, and is used
+ * below.
+ */
+union mwreq_data {
+ /* Config - generic */
+ char name[IFNAMSIZ];
+
+ struct mw_point essid; /* Extended network name */
+ t_u32 mode; /* Operation mode */
+ struct mw_param power; /* PM duration/timeout */
+ struct sockaddr ap_addr; /* Access point address */
+ struct mw_param param; /* Other small parameters */
+ struct mw_point data; /* Other large parameters */
+};
+
+/* The structure to exchange data for ioctl */
+struct mwreq {
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
+ } ifr_ifrn;
+
+ /* Data part */
+ union mwreq_data u;
+};
+
+typedef struct woal_priv_ht_cap_info {
+ t_u32 ht_cap_info_bg;
+ t_u32 ht_cap_info_a;
+} woal_ht_cap_info;
+
+typedef struct woal_priv_addba {
+ t_u32 time_out;
+ t_u32 tx_win_size;
+ t_u32 rx_win_size;
+ t_u32 tx_amsdu;
+ t_u32 rx_amsdu;
+} woal_addba;
+
+typedef struct _txrate_setting {
+ t_u16 preamble : 2; /*BIT1-BIT0:
+ * For legacy 11b: preamble type
+ * 00 = long
+ * 01 = short
+ * 10/11 = reserved
+ * For legacy 11g: reserved
+ * For 11n: Green field PPDU indicator
+ * 00 = HT-mix
+ * 01 = HT-GF
+ * 10/11 = reserved.
+ * For 11ac: reserved.
+ * For 11ax:
+ * 00 = HE-SU
+ * 01 = HE-EXT-SU
+ * 10 = HE-MU
+ * 11 = HE trigger based
+ */
+ t_u16 bandwidth : 3; /* BIT2- BIT4
+ * For 11n and 11ac traffic: Bandwidth
+ * 0 = 20Mhz
+ * 1 = 40Mhz
+ * 2 = 80 Mhz
+ * 3 = 160 Mhz
+ * 4-7 = reserved
+ * For legacy rate : BW>0 implies non-HT
+ * duplicates. For HE SU PPDU: 0 = 20Mhz 1 = 40Mhz
+ * 2 = 80 Mhz
+ * 3 = 160 Mhz
+ * 4-7 = reserved
+ * For HE ER SU PPDU:
+ * 0 = 242-tone RU
+ * 1 = upper frequency 106 tone RU within the
+ * primary 20 Mhz. For HE MU PPDU: 0 = 20Mhz. 1 =
+ * 40Mhz. 2 = 80Mhz non-preamble puncturing mode 3
+ * = 160Mhz and 80+80 Mhz non-preamble. 4 = for
+ * preemble puncturing in 80 Mhz , where in the
+ * preamble only the secondary 20Mhz is punctured.
+ * 5 = for preemble puncturing in 80 Mhz ,
+ * where in the preamble only one of the two
+ * 20Mhz subchannels in the secondary 40Mhz is
+ * punctured. 6 = for preemble puncturing in 160
+ * Mhz or 80 Mhz + 80 Mhz, where in the primary 80
+ * Mhz of the preamble only the secondary 20 Mhz is
+ * punctured. 7 = for preemble puncturing in 160
+ * Mhz or 80 Mhz + 80 Mhz, where in the primary 80
+ * Mhz of the preamble the primary 40 Mhz is
+ * present.
+ */
+ t_u16 shortGI : 2; /*BIT5- BIT6
+ * For legacy: not used
+ * For 11n: 00 = normal, 01 =shortGI, 10/11 =
+ * reserved For 11ac: SGI map to VHT-SIG-A2[0]
+ * VHT-SIG-A2[1] is set to 1 if short guard
+ * interval is used and NSYM mod 10 = 9, otherwise
+ * set to 0. For 11ax: 00 = 1xHELTF+GI0.8usec 01 =
+ * 2xHELTF+GI0.8usec 10 = 2xHELTF+GI1.6usec 11 =
+ * 4xHELTF+GI0.8 usec if both DCM and STBC are 1
+ * 4xHELTF+GI3.2 usec otherwise
+ */
+ t_u16 stbc : 1; // BIT7, 0: no STBC; 1: STBC
+ t_u16 dcm : 1; // BIT8, 0: no DCM; 1: DCM used.
+ t_u16 adv_coding : 1; // BIT9, 0: BCC; 1: LDPC.
+ t_u16 doppler : 2; /* BIT11-BIT10,
+ 00: Doppler0
+ 01: Doppler 1 with Mma =10
+ 10: Doppler 1 with Mma =20
+ */
+ t_u16 max_pktext : 2; /*BIT12-BIT13:
+ * Max packet extension
+ * 0 - 0 usec
+ * 1 - 8 usec
+ * 2 - 16 usec.
+ */
+ t_u16 reserverd : 2; // BIT14-BIT15
+} __ATTRIB_PACK__ txrate_setting;
+
+/** data structure for cmd txratecfg */
+typedef struct woal_priv_tx_rate_cfg {
+ /* LG rate: 0, HT rate: 1, VHT rate: 2 */
+ t_u32 rate_format;
+ /** Rate/MCS index (0xFF: auto) */
+ t_u32 rate_index;
+ /** Data rate */
+ t_u32 rate;
+ /** NSS */
+ t_u32 nss;
+ /** Rate Setting */
+ t_u16 rate_setting;
+} woal_tx_rate_cfg;
+
+typedef struct woal_priv_esuppmode_cfg {
+ /* RSN mode */
+ t_u16 rsn_mode;
+ /* Pairwise cipher */
+ t_u8 pairwise_cipher;
+ /* Group cipher */
+ t_u8 group_cipher;
+} woal_esuppmode_cfg;
+
+mlan_status woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len);
+mlan_status woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action,
+ mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl);
+
+int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req);
+
+#define PRIV_CMD_CLOUD_KEEP_ALIVE "cloud_keep_alive"
+/** cloud keep alive parameters */
+typedef struct _cloud_keep_alive {
+ /** id */
+ t_u8 mkeep_alive_id;
+ /** enable/disable of this id */
+ t_u8 enable;
+ /** enable/disable reset*/
+ t_u8 reset;
+ /** Reserved */
+ t_u8 reserved;
+ /** Destination MAC address */
+ t_u8 dst_mac[ETH_ALEN];
+ /** Source MAC address */
+ t_u8 src_mac[ETH_ALEN];
+ /** packet send period */
+ t_u32 sendInterval;
+ /** packet retry interval */
+ t_u32 retryInterval;
+ /** packet retry count */
+ t_u8 retryCount;
+ /** packet length */
+ t_u8 pkt_len;
+ /** packet content */
+ t_u8 pkt[255];
+} __ATTRIB_PACK__ cloud_keep_alive;
+
+#define TLV_TYPE_PER_PKT_CFG 0x0001
+#define TX_PKT_CTRL MBIT(0)
+#define RX_PKT_INFO MBIT(1)
+
+#define FLAG_TX_HISTOGRAM 0x01
+#define FLAG_RX_HISTOGRAM 0x02
+#define DISABLE_TX_RX_HISTOGRAM 0x00
+#define ENABLE_TX_RX_HISTOGRAM 0x01
+#define GET_TX_RX_HISTOGRAM 0x02
+#define PRIV_CMD_TX_RX_HISTOGRAM "txrxhistogram"
+/** TX and RX histogram statistic parameters*/
+typedef struct _tx_rx_histogram {
+ /** Enable or disable get tx/rx histogram statistic */
+ t_u8 enable;
+ /** Choose to get TX, RX or both histogram statistic */
+ t_u8 action;
+} __ATTRIB_PACK__ tx_rx_histogram;
+
+/* Enum for different CW mode type */
+typedef enum _cw_modes_e {
+ CWMODE_DISABLE,
+ CWMODE_TXCONTPKT,
+ CWMODE_TXCONTWAVE,
+} cw_modes_e;
+
+/** wlan_ieee80211_chan */
+typedef struct {
+ /** center freq */
+ t_u16 center_freq;
+ /** chan num */
+ t_u16 hw_value;
+ /** chan flags */
+ t_u32 flags;
+ /** max power */
+ int max_power;
+ /** dfs_state */
+ t_u8 dfs_state;
+} __ATTRIB_PACK__ wlan_ieee80211_chan;
+
+/** wlan_ieee80211_chan_list*/
+typedef struct {
+ /** num of chan */
+ t_u8 num_chan;
+ /** chan_list */
+ wlan_ieee80211_chan chan_list[];
+} __ATTRIB_PACK__ wlan_ieee80211_chan_list;
+
+#define PRIV_CMD_TP_STATE "tp_state"
+#endif /* _WOAL_ETH_PRIV_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_init.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_init.c
new file mode 100644
index 000000000000..c57303951a04
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_init.c
@@ -0,0 +1,2355 @@
+/** @file moal_init.c
+ *
+ * @brief This file contains the major functions in WLAN
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "moal_main.h"
+
+/** Global moal_handle array */
+extern pmoal_handle m_handle[];
+
+/** Firmware name */
+char *fw_name;
+int req_fw_nowait;
+int fw_reload;
+
+/** MAC address */
+char *mac_addr;
+/** Module param cfg file */
+char *mod_para;
+
+#ifdef MFG_CMD_SUPPORT
+/** Mfg mode */
+int mfg_mode;
+#endif
+
+#if defined(SDIO)
+/** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */
+int intmode = INT_MODE_SDIO;
+/** GPIO interrupt pin number */
+int gpiopin;
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+int disable_regd_by_driver = 1;
+/** Region alpha2 string */
+char *reg_alpha2;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+int country_ie_ignore;
+int beacon_hints;
+#endif
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+int host_mlme;
+#endif
+#endif
+
+/** Auto deep sleep */
+int auto_ds;
+
+/** IEEE PS mode */
+int ps_mode;
+/** passive to active scan */
+int p2a_scan;
+/** scan chan gap */
+int scan_chan_gap;
+/** Max Tx buffer size */
+int max_tx_buf;
+
+#ifdef STA_SUPPORT
+/** Max STA interfaces */
+int max_sta_bss = DEF_STA_BSS;
+/** STA interface name */
+char *sta_name;
+#endif
+
+#ifdef UAP_SUPPORT
+/** Max uAP interfaces */
+int max_uap_bss = DEF_UAP_BSS;
+/** uAP interface name */
+char *uap_name;
+/** Max uAP station number */
+int uap_max_sta;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+/** Max WIFIDIRECT interfaces */
+int max_wfd_bss = DEF_WIFIDIRECT_BSS;
+/** WIFIDIRECT interface name */
+char *wfd_name;
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+/** max VIRTUAL bss */
+int max_vir_bss = DEF_VIRTUAL_BSS;
+#endif
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+/** PM keep power */
+int pm_keep_power = 1;
+/** HS when shutdown */
+int shutdown_hs;
+#endif
+
+#if defined(SDIO)
+/** SDIO slew rate */
+int slew_rate = 3;
+#endif
+int tx_work = 0;
+
+#if defined(STA_SUPPORT)
+/** 802.11d configuration */
+int cfg_11d;
+#endif
+
+/** fw serial download check */
+int fw_serial = 1;
+
+/** napi support*/
+int napi;
+
+/** DPD data config file */
+char *dpd_data_cfg;
+
+/** CAL data config file */
+char *cal_data_cfg;
+/** Init config file (MAC address, register etc.) */
+char *init_cfg;
+
+/** Set configuration data of Tx power limitation */
+char *txpwrlimit_cfg;
+/** Allow setting tx power table of country */
+int cntry_txpwr;
+
+/** Init hostcmd file */
+char *init_hostcmd_cfg;
+char *band_steer_cfg;
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/** CFG80211 and WEXT mode */
+int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK;
+#else
+/** CFG80211 mode */
+int cfg80211_wext = STA_CFG80211_MASK | UAP_CFG80211_MASK;
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+int fw_region = 1;
+#endif
+#endif
+
+/** Work queue priority */
+int wq_sched_prio;
+/** Work queue scheduling policy */
+int wq_sched_policy = SCHED_NORMAL;
+/** rx_work flag */
+int rx_work;
+
+#if defined(USB)
+int skip_fwdnld;
+#endif
+
+/* Enable/disable aggrctrl */
+int aggrctrl;
+
+#ifdef USB
+/* Enable/disable USB aggregation feature */
+int usb_aggr;
+#endif
+
+#ifdef PCIE
+/* Enable/disable Message Signaled Interrupt (MSI) */
+int pcie_int_mode = PCIE_INT_MODE_MSI;
+#endif /* PCIE */
+
+int low_power_mode_enable;
+
+int hw_test;
+
+#ifdef CONFIG_OF
+int dts_enable = 1;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+int dfs_offload;
+#endif
+
+#ifdef ANDROID_KERNEL
+int wakelock_timeout = WAKE_LOCK_TIMEOUT;
+#endif
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#ifdef WIFI_DIRECT_SUPPORT
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT);
+#else
+int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP);
+#endif /* WIFI_DIRECT_SUPPORT */
+#else
+#ifdef STA_SUPPORT
+int drv_mode = DRV_MODE_STA;
+#else
+int drv_mode = DRV_MODE_UAP;
+#endif /* STA_SUPPORT */
+#endif /* STA_SUPPORT & UAP_SUPPORT */
+
+int gtk_rekey_offload = GTK_REKEY_OFFLOAD_DISABLE;
+
+int pmic;
+
+int antcfg;
+
+t_u32 uap_oper_ctrl;
+
+int hs_wake_interval = 400;
+int indication_gpio = 0xff;
+int disconnect_on_suspend;
+int hs_mimo_switch;
+
+int indrstcfg = 0xffffffff;
+
+/** all the feature are enabled */
+#define DEFAULT_DEV_CAP_MASK 0xffffffff
+t_u32 dev_cap_mask = DEFAULT_DEV_CAP_MASK;
+#ifdef SDIO
+int sdio_rx_aggr = MTRUE;
+#endif
+
+/** The global variable of scan beacon buffer **/
+int fixed_beacon_buffer;
+
+#ifdef WIFI_DIRECT_SUPPORT
+int GoAgeoutTime;
+#endif
+
+t_u16 multi_dtim;
+
+t_u16 inact_tmo;
+
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define DEFAULT_DEBUG_MASK (0xffffffff)
+#else
+#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR | MREG_D)
+#endif /* DEBUG_LEVEL2 */
+t_u32 drvdbg = DEFAULT_DEBUG_MASK;
+
+#endif /* DEBUG_LEVEL1 */
+
+static card_type_entry card_type_map_tbl[] = {
+#ifdef SD8887
+ {CARD_TYPE_SD8887, 0, CARD_SD8887},
+#endif
+#ifdef SD8897
+ {CARD_TYPE_SD8897, 0, CARD_SD8897},
+#endif
+#ifdef SD8977
+ {CARD_TYPE_SD8977, 0, CARD_SD8977},
+#endif
+#ifdef SD8978
+ {CARD_TYPE_SD8978, 0, CARD_SD8978},
+#endif
+#ifdef SD8997
+ {CARD_TYPE_SD8997, 0, CARD_SD8997},
+#endif
+#ifdef SD8987
+ {CARD_TYPE_SD8987, 0, CARD_SD8987},
+#endif
+#ifdef SD9097
+ {CARD_TYPE_SD9097, 0, CARD_SD9097},
+#endif
+#ifdef SD9098
+ {CARD_TYPE_SD9098, 0, CARD_SD9098},
+#endif
+#ifdef PCIE8897
+ {CARD_TYPE_PCIE8897, 0, CARD_PCIE8897},
+#endif
+#ifdef PCIE8997
+ {CARD_TYPE_PCIE8997, 0, CARD_PCIE8997},
+#endif
+#ifdef PCIE9097
+ {CARD_TYPE_PCIE9097, 0, CARD_PCIE9097},
+#endif
+#ifdef PCIE9098
+ {CARD_TYPE_PCIE9098, 0, CARD_PCIE9098},
+#endif
+#ifdef USB8897
+ {CARD_TYPE_USB8897, 0, CARD_USB8897},
+#endif
+#ifdef USB8997
+ {CARD_TYPE_USB8997, 0, CARD_USB8997},
+#endif
+#ifdef USB8978
+ {CARD_TYPE_USB8978, 0, CARD_USB8978},
+#endif
+#ifdef USB9098
+ {CARD_TYPE_USB9098, 0, CARD_USB9098},
+#endif
+#ifdef USB9097
+ {CARD_TYPE_USB9097, 0, CARD_USB9097},
+#endif
+};
+
+int dfs53cfg = DFS_W53_DEFAULT_FW;
+
+/**
+ * @brief This function read a line in module parameter file
+ *
+ * @param data A pointer to module parameter data buffer
+ * @param size module parameter file size
+ * @param line_pos A pointer to offset of current line
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static t_size parse_cfg_get_line(t_u8 *data, t_size size, t_u8 *line_pos)
+{
+ t_u8 *src, *dest;
+ static t_s32 pos;
+
+ ENTER();
+
+ if (pos >= size) { /* reach the end */
+ pos = 0; /* Reset position for rfkill */
+ LEAVE();
+ return -1;
+ }
+ memset(line_pos, 0, MAX_LINE_LEN);
+ src = data + pos;
+ dest = line_pos;
+
+ while (pos < size && *src != '\x0A' && *src != '\0') {
+ if (*src != ' ' && *src != '\t') /* parse space */
+ *dest++ = *src++;
+ else
+ src++;
+ pos++;
+ }
+ /* parse new line */
+ pos++;
+ *dest = '\0';
+ LEAVE();
+ return strlen(line_pos);
+}
+
+/**
+ * @brief This function duplicate a string
+ *
+ * @param dst A pointer to destination string
+ * @param src A pointer to source string
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static void woal_dup_string(char **dst, char *src)
+{
+ size_t len = 0;
+ if (src) {
+ len = strlen(src);
+ if (len != 0) {
+ if (*dst != NULL)
+ kfree(*dst);
+ *dst = kzalloc(len + 1, GFP_KERNEL);
+ if (*dst == NULL) {
+ PRINTM(MERROR,
+ "Failed to alloc mem for param: %s\n",
+ src);
+ return;
+ }
+ moal_memcpy_ext(NULL, *dst, src, len, len);
+ }
+ }
+}
+
+/**
+ * @brief This function read an integer value in module parameter file
+ *
+ * @param line A pointer to a line
+ * @param out_data A pointer to parsed integer value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status parse_line_read_int(t_u8 *line, int *out_data)
+{
+ t_u8 *p = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ if (line == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ p = strstr(line, "=");
+ if (p == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ p++;
+ ret = woal_atoi(out_data, p);
+out:
+ if (ret != MLAN_STATUS_SUCCESS)
+ *out_data = 0;
+ return ret;
+}
+
+/**
+ * @brief This function read a string in module parameter file
+ *
+ * @param line A pointer to a line
+ * @param out_str A pointer to parsed string
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status parse_line_read_string(t_u8 *line, char **out_str)
+{
+ t_u8 *p = NULL, *pstr = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ if (line == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ p = strstr(line, "=");
+ if (p == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ p++;
+ pstr = p;
+ while (*pstr) {
+ if (*pstr == '\"')
+ *pstr = '\0';
+ pstr++;
+ }
+ if (*p == '\0')
+ p++;
+ *out_str = p;
+out:
+ return ret;
+}
+
+/**
+ * @brief This function read card info in module parameter file
+ *
+ * @param line A pointer to a line
+ * @param type A pointer to card type
+ * @param if_id A pointer to interface id
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status parse_line_read_card_info(t_u8 *line, char **type,
+ char **if_id)
+{
+ t_u8 *p = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ if (line == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+
+ p = strstr(line, "=");
+ if (p == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ *p = '\0';
+
+ p = strstr(line, "_");
+ if (p != NULL) {
+ *p++ = '\0';
+ *if_id = p;
+ } else {
+ *if_id = NULL;
+ }
+ *type = line;
+out:
+ return ret;
+}
+
+/**
+ * @brief This function read blocks in module parameter file
+ *
+ * @param data A pointer to a line
+ * @param size line size
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status parse_cfg_read_block(t_u8 *data, t_u32 size,
+ moal_handle *handle)
+{
+ int out_data = 0, end = 0;
+ char *out_str = NULL;
+ t_u8 line[MAX_LINE_LEN];
+ moal_mod_para *params = &handle->params;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ while (parse_cfg_get_line(data, size, line) != -1) {
+ if (strncmp(line, "}", strlen("}")) == 0) {
+ end = 1;
+ break;
+ }
+ if (end == 0 && strstr(line, "{") != 0)
+ break;
+ if (strncmp(line, "hw_test", strlen("hw_test")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_HW_TEST);
+ else
+ moal_extflg_clear(handle, EXT_HW_TEST);
+ PRINTM(MMSG, "hw_test %s\n",
+ moal_extflg_isset(handle, EXT_HW_TEST) ? "on" :
+ "off");
+ }
+#ifdef CONFIG_OF
+ else if (strncmp(line, "dts_enable", strlen("dts_enable")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_DTS_ENABLE);
+ else
+ moal_extflg_clear(handle, EXT_DTS_ENABLE);
+ PRINTM(MMSG, "dts_enable %s\n",
+ moal_extflg_isset(handle, EXT_DTS_ENABLE) ?
+ "on" :
+ "off");
+ }
+#endif
+ else if (strncmp(line, "fw_name", strlen("fw_name")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->fw_name, out_str);
+ PRINTM(MMSG, "fw_name=%s\n", params->fw_name);
+ } else if (strncmp(line, "req_fw_nowait",
+ strlen("req_fw_nowait")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_REQ_FW_NOWAIT);
+ else
+ moal_extflg_clear(handle, EXT_REQ_FW_NOWAIT);
+ PRINTM(MMSG, "req fw nowait %s\n",
+ moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "fw_reload", strlen("fw_reload")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->fw_reload = out_data;
+ PRINTM(MMSG, "fw_reload %d\n", params->fw_reload);
+ } else if (strncmp(line, "fw_serial", strlen("fw_serial")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_FW_SERIAL);
+ else
+ moal_extflg_clear(handle, EXT_FW_SERIAL);
+ PRINTM(MMSG, "fw_serial %s\n",
+ moal_extflg_isset(handle, EXT_FW_SERIAL) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "mac_addr", strlen("mac_addr")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->mac_addr, out_str);
+ PRINTM(MMSG, "mac_addr=%s\n", params->mac_addr);
+ }
+#ifdef MFG_CMD_SUPPORT
+ else if (strncmp(line, "mfg_mode", strlen("mfg_mode")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->mfg_mode = out_data;
+ PRINTM(MMSG, "mfg_mode = %d\n", params->mfg_mode);
+ }
+#endif
+ else if (strncmp(line, "drv_mode", strlen("drv_mode")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->drv_mode = out_data;
+ PRINTM(MMSG, "drv_mode = %d\n", params->drv_mode);
+ }
+#ifdef STA_SUPPORT
+ else if (strncmp(line, "max_sta_bss", strlen("max_sta_bss")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->max_sta_bss = out_data;
+ PRINTM(MMSG, "max_sta_bss = %d\n", params->max_sta_bss);
+ } else if (strncmp(line, "sta_name", strlen("sta_name")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->sta_name, out_str);
+ PRINTM(MMSG, "sta_name=%s\n", params->sta_name);
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ else if (strncmp(line, "max_uap_bss", strlen("max_uap_bss")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->max_uap_bss = out_data;
+ PRINTM(MMSG, "max_uap_bss = %d\n", params->max_uap_bss);
+ } else if (strncmp(line, "uap_name", strlen("uap_name")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->uap_name, out_str);
+ PRINTM(MMSG, "uap_name=%s\n", params->uap_name);
+ }
+#endif /* UAP_SUPPORT */
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (strncmp(line, "wfd_name", strlen("wfd_name")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->wfd_name, out_str);
+ PRINTM(MMSG, "wfd_name=%s\n", params->wfd_name);
+ }
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ else if (strncmp(line, "max_vir_bss", strlen("max_vir_bss")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->max_vir_bss = out_data;
+ PRINTM(MMSG, "max_vir_bss=%d\n", params->max_vir_bss);
+ }
+#endif
+#endif
+ else if (strncmp(line, "auto_ds", strlen("auto_ds")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->auto_ds = out_data;
+ PRINTM(MMSG, "auto_ds = %d\n", params->auto_ds);
+ } else if (strncmp(line, "ps_mode", strlen("ps_mode")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->ps_mode = out_data;
+ PRINTM(MMSG, "ps_mode = %d\n", params->ps_mode);
+ } else if (strncmp(line, "p2a_scan", strlen("p2a_scan")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->p2a_scan = out_data;
+ PRINTM(MMSG, "p2a_scan = %d\n", params->p2a_scan);
+ } else if (strncmp(line, "scan_chan_gap",
+ strlen("scan_chan_gap")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->scan_chan_gap = out_data;
+ PRINTM(MMSG, "scan_chan_gap = %d\n",
+ params->scan_chan_gap);
+ } else if (strncmp(line, "max_tx_buf", strlen("max_tx_buf")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->max_tx_buf = out_data;
+ PRINTM(MMSG, "max_tx_buf = %d\n", params->max_tx_buf);
+ }
+#if defined(SDIO)
+ else if (strncmp(line, "intmode", strlen("intmode")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_INTMODE);
+ else
+ moal_extflg_clear(handle, EXT_INTMODE);
+ PRINTM(MMSG, "intmode %s\n",
+ moal_extflg_isset(handle, EXT_INTMODE) ? "on" :
+ "off");
+ } else if (strncmp(line, "gpiopin", strlen("gpiopin")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->gpiopin = out_data;
+ PRINTM(MMSG, "gpiopin = %d\n", params->gpiopin);
+ }
+#endif
+#if defined(SDIO) && defined(SDIO_SUSPEND_RESUME)
+ else if (strncmp(line, "pm_keep_power",
+ strlen("pm_keep_power")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_PM_KEEP_POWER);
+ else
+ moal_extflg_clear(handle, EXT_PM_KEEP_POWER);
+ PRINTM(MMSG, "pm_keep_power %s\n",
+ moal_extflg_isset(handle, EXT_PM_KEEP_POWER) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "shutdown_hs",
+ strlen("shutdown_hs")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_SHUTDOWN_HS);
+ else
+ moal_extflg_clear(handle, EXT_SHUTDOWN_HS);
+ PRINTM(MMSG, "shutdown_hs %s\n",
+ moal_extflg_isset(handle, EXT_SHUTDOWN_HS) ?
+ "on" :
+ "off");
+ }
+#endif
+#if defined(STA_SUPPORT)
+ else if (strncmp(line, "cfg_11d", strlen("cfg_11d")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->cfg_11d = out_data;
+ PRINTM(MMSG, "cfg_11d = %d\n", params->cfg_11d);
+ }
+#endif
+#if defined(SDIO)
+ else if (strncmp(line, "slew_rate", strlen("slew_rate")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->slew_rate = out_data;
+ PRINTM(MMSG, "slew_rate = %d\n", params->slew_rate);
+ }
+#endif
+ else if (strncmp(line, "dpd_data_cfg",
+ strlen("dpd_data_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->dpd_data_cfg, out_str);
+ PRINTM(MMSG, "dpd_data_cfg=%s\n", params->dpd_data_cfg);
+ } else if (strncmp(line, "init_cfg", strlen("init_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->init_cfg, out_str);
+ PRINTM(MMSG, "init_cfg=%s\n", params->init_cfg);
+ } else if (strncmp(line, "cal_data_cfg",
+ strlen("cal_data_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->cal_data_cfg, out_str);
+ PRINTM(MMSG, "cal_data_cfg=%s\n", params->cal_data_cfg);
+ } else if (strncmp(line, "txpwrlimit_cfg",
+ strlen("txpwrlimit_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->txpwrlimit_cfg, out_str);
+ PRINTM(MMSG, "txpwrlimit_cfg=%s\n",
+ params->txpwrlimit_cfg);
+ } else if (strncmp(line, "cntry_txpwr",
+ strlen("cntry_txpwr")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_CNTRY_TXPWR);
+ else
+ moal_extflg_clear(handle, EXT_CNTRY_TXPWR);
+ PRINTM(MMSG, "cntry_txpwr %s\n",
+ moal_extflg_isset(handle, EXT_CNTRY_TXPWR) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "init_hostcmd_cfg",
+ strlen("init_hostcmd_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->init_hostcmd_cfg, out_str);
+ PRINTM(MMSG, "init_hostcmd_cfg=%s\n",
+ params->init_hostcmd_cfg);
+ } else if (strncmp(line, "band_steer_cfg",
+ strlen("band_steer_cfg")) == 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->band_steer_cfg, out_str);
+ PRINTM(MMSG, "band_steer_cfg=%s\n",
+ params->band_steer_cfg);
+ } else if (strncmp(line, "cfg80211_wext",
+ strlen("cfg80211_wext")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->cfg80211_wext = out_data;
+ PRINTM(MMSG, "cfg80211_wext=0x%x\n",
+ params->cfg80211_wext);
+ }
+#if defined(USB)
+ else if (IS_USB(handle->card_type) &&
+ strncmp(line, "skip_fwdnld", strlen("skip_fwdnld")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_SKIP_FWDNLD);
+ else
+ moal_extflg_clear(handle, EXT_SKIP_FWDNLD);
+ PRINTM(MMSG, "skip_fwdnld %s\n",
+ moal_extflg_isset(handle, EXT_SKIP_FWDNLD) ?
+ "on" :
+ "off");
+ }
+#endif
+ else if (strncmp(line, "wq_sched_prio",
+ strlen("wq_sched_prio")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->wq_sched_prio = out_data;
+ PRINTM(MMSG, "wq_sched_prio=0x%x\n",
+ params->wq_sched_prio);
+ } else if (strncmp(line, "wq_sched_policy",
+ strlen("wq_sched_policy")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->wq_sched_policy = out_data;
+ PRINTM(MMSG, "wq_sched_policy=0x%x\n",
+ params->wq_sched_policy);
+ } else if (strncmp(line, "rx_work", strlen("rx_work")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->rx_work = out_data;
+ PRINTM(MMSG, "rx_work=0x%x\n", params->rx_work);
+ } else if (strncmp(line, "aggrctrl", strlen("aggrctrl")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_AGGR_CTRL);
+ else
+ moal_extflg_clear(handle, EXT_AGGR_CTRL);
+ PRINTM(MMSG, "aggrctrl %s\n",
+ moal_extflg_isset(handle, EXT_AGGR_CTRL) ?
+ "on" :
+ "off");
+ }
+#ifdef USB
+ else if (IS_USB(handle->card_type) &&
+ strncmp(line, "usb_aggr", strlen("usb_aggr")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->usb_aggr = out_data;
+ PRINTM(MMSG, "usb_aggr=0x%x\n", params->usb_aggr);
+ }
+#endif
+#ifdef PCIE
+ else if (IS_PCIE(handle->card_type) &&
+ strncmp(line, "pcie_int_mode",
+ strlen("pcie_int_mode")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->pcie_int_mode = out_data;
+ PRINTM(MMSG, "pcie_int_mode=%d\n",
+ params->pcie_int_mode);
+ }
+#endif
+ else if (strncmp(line, "low_power_mode_enable",
+ strlen("low_power_mode_enable")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_LOW_PW_MODE);
+ else
+ moal_extflg_clear(handle, EXT_LOW_PW_MODE);
+ PRINTM(MMSG, "low_power_mode_enable %s\n",
+ moal_extflg_isset(handle, EXT_LOW_PW_MODE) ?
+ "on" :
+ "off");
+ }
+#ifdef ANDROID_KERNEL
+ else if (strncmp(line, "wakelock_timeout",
+ strlen("wakelock_timeout")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->wakelock_timeout = out_data;
+ PRINTM(MMSG, "wakelock_timeout=%d\n",
+ params->wakelock_timeout);
+ }
+#endif
+ else if (strncmp(line, "dev_cap_mask",
+ strlen("dev_cap_mask")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->dev_cap_mask = out_data;
+ PRINTM(MMSG, "dev_cap_mask=%d\n", params->dev_cap_mask);
+ }
+#ifdef SDIO
+ else if (strncmp(line, "sdio_rx_aggr",
+ strlen("sdio_rx_aggr")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_SDIO_RX_AGGR);
+ else
+ moal_extflg_clear(handle, EXT_SDIO_RX_AGGR);
+ PRINTM(MMSG, "sdio_rx_aggr %s\n",
+ moal_extflg_isset(handle, EXT_SDIO_RX_AGGR) ?
+ "on" :
+ "off");
+ }
+#endif
+#if defined(SD8997) || defined(PCIE8997) || defined(USB8997) || \
+ defined(SD8977) || defined(SD8987) || defined(SD9098) || \
+ defined(USB9098) || defined(PCIE9098) || defined(SD9097) || \
+ defined(USB9097) || defined(PCIE9097) || defined(SD8978) || \
+ defined(USB8978)
+ else if (strncmp(line, "pmic", strlen("pmic")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_PMIC);
+ else
+ moal_extflg_clear(handle, EXT_PMIC);
+ PRINTM(MMSG, "pmic %s\n",
+ moal_extflg_isset(handle, EXT_PMIC) ? "on" :
+ "off");
+ }
+#endif
+ else if (strncmp(line, "antcfg", strlen("antcfg")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->antcfg = out_data;
+ PRINTM(MMSG, "antcfg=%d\n", params->antcfg);
+ } else if (strncmp(line, "uap_oper_ctrl",
+ strlen("uap_oper_ctrl")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->uap_oper_ctrl = out_data;
+ PRINTM(MMSG, "uap_oper_ctrl=%d\n",
+ params->uap_oper_ctrl);
+ } else if (strncmp(line, "hs_wake_interval",
+ strlen("hs_wake_interval")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->hs_wake_interval = out_data;
+ PRINTM(MMSG, "hs_wake_interval=%d\n",
+ params->hs_wake_interval);
+ } else if (strncmp(line, "indication_gpio",
+ strlen("indication_gpio")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->indication_gpio = out_data;
+ PRINTM(MMSG, "indication_gpio=%d\n",
+ params->indication_gpio);
+ } else if (strncmp(line, "disconnect_on_suspend",
+ strlen("disconnect_on_suspend")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle,
+ EXT_DISCONNECT_ON_SUSPEND);
+ else
+ moal_extflg_clear(handle,
+ EXT_DISCONNECT_ON_SUSPEND);
+ PRINTM(MMSG, "disconnect_on_suspend %s\n",
+ moal_extflg_isset(handle,
+ EXT_DISCONNECT_ON_SUSPEND) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "hs_mimo_switch",
+ strlen("hs_mimo_switch")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_HS_MIMO_SWITCH);
+ else
+ moal_extflg_clear(handle, EXT_HS_MIMO_SWITCH);
+ PRINTM(MMSG, "hs_mimo_switch %s\n",
+ moal_extflg_isset(handle, EXT_HS_MIMO_SWITCH) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "indrstcfg", strlen("indrstcfg")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->indrstcfg = out_data;
+ PRINTM(MMSG, "indrstcfg=%d\n", params->indrstcfg);
+ } else if (strncmp(line, "fixed_beacon_buffer",
+ strlen("fixed_beacon_buffer")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_FIX_BCN_BUF);
+ else
+ moal_extflg_clear(handle, EXT_FIX_BCN_BUF);
+ PRINTM(MMSG, "fixed_beacon_buffer %s\n",
+ moal_extflg_isset(handle, EXT_FIX_BCN_BUF) ?
+ "on" :
+ "off");
+ }
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (strncmp(line, "GoAgeoutTime",
+ strlen("GoAgeoutTime")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->GoAgeoutTime = out_data;
+ PRINTM(MMSG, "GoAgeoutTime=%d\n", params->GoAgeoutTime);
+ }
+#endif
+ else if (strncmp(line, "gtk_rekey_offload",
+ strlen("gtk_rekey_offload")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->gtk_rekey_offload = out_data;
+ PRINTM(MMSG, "gtk_rekey_offload=%d\n",
+ params->gtk_rekey_offload);
+ } else if (strncmp(line, "multi_dtim", strlen("multi_dtim")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->multi_dtim = out_data;
+ PRINTM(MMSG, "multi_dtim=%d\n", params->multi_dtim);
+ } else if (strncmp(line, "inact_tmo", strlen("inact_tmo")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->inact_tmo = out_data;
+ PRINTM(MMSG, "inact_tmo=%d\n", params->inact_tmo);
+ } else if (strncmp(line, "napi", strlen("napi")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_NAPI);
+ else
+ moal_extflg_clear(handle, EXT_NAPI);
+ PRINTM(MMSG, "napi %s\n",
+ moal_extflg_isset(handle, EXT_NAPI) ? "on" :
+ "off");
+ } else if (strncmp(line, "tx_work", strlen("tx_work")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_TX_WORK);
+ else
+ moal_extflg_clear(handle, EXT_TX_WORK);
+ PRINTM(MMSG, "tx_work %s\n",
+ moal_extflg_isset(handle, EXT_TX_WORK) ? "on" :
+ "off");
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ else if (strncmp(line, "dfs_offload", strlen("dfs_offload")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_DFS_OFFLOAD);
+ else
+ moal_extflg_clear(handle, EXT_DFS_OFFLOAD);
+ PRINTM(MMSG, "dfs_offload %s\n",
+ moal_extflg_isset(handle, EXT_DFS_OFFLOAD) ?
+ "on" :
+ "off");
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ else if (strncmp(line, "disable_regd_by_driver",
+ strlen("disable_regd_by_driver")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle,
+ EXT_DISABLE_REGD_BY_DRIVER);
+ else
+ moal_extflg_clear(handle,
+ EXT_DISABLE_REGD_BY_DRIVER);
+ PRINTM(MMSG, "reg domain set by driver=%s\n",
+ moal_extflg_isset(handle,
+ EXT_DISABLE_REGD_BY_DRIVER) ?
+ "enable" :
+ "disable");
+ } else if (strncmp(line, "reg_alpha2", strlen("reg_alpha2")) ==
+ 0) {
+ if (parse_line_read_string(line, &out_str) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ woal_dup_string(&params->reg_alpha2, out_str);
+ PRINTM(MMSG, "reg_alpha2=%s\n", params->reg_alpha2);
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ else if (strncmp(line, "country_ie_ignore",
+ strlen("country_ie_ignore")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_COUNTRY_IE_IGNORE);
+ else
+ moal_extflg_clear(handle,
+ EXT_COUNTRY_IE_IGNORE);
+ PRINTM(MMSG, "country_ie_ignore=%s\n",
+ moal_extflg_isset(handle,
+ EXT_COUNTRY_IE_IGNORE) ?
+ "on" :
+ "off");
+ } else if (strncmp(line, "beacon_hints",
+ strlen("beacon_hints")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_BEACON_HINTS);
+ else
+ moal_extflg_clear(handle, EXT_BEACON_HINTS);
+ PRINTM(MMSG, "beacon_hints=%s\n",
+ moal_extflg_isset(handle, EXT_BEACON_HINTS) ?
+ "enable" :
+ "disable");
+ }
+#endif
+#endif
+#ifdef UAP_SUPPORT
+ else if (strncmp(line, "uap_max_sta", strlen("uap_max_sta")) ==
+ 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->uap_max_sta = out_data;
+ PRINTM(MMSG, "uap_max_sta=%d\n", params->uap_max_sta);
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ else if (strncmp(line, "host_mlme", strlen("host_mlme")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ if (out_data)
+ moal_extflg_set(handle, EXT_HOST_MLME);
+ else
+ moal_extflg_clear(handle, EXT_HOST_MLME);
+ PRINTM(MMSG, "host_mlme=%s\n",
+ moal_extflg_isset(handle, EXT_HOST_MLME) ?
+ "enable" :
+ "disable");
+ }
+#endif
+#endif
+ else if (strncmp(line, "dfs53cfg", strlen("dfs53cfg")) == 0) {
+ if (parse_line_read_int(line, &out_data) !=
+ MLAN_STATUS_SUCCESS)
+ goto err;
+ params->dfs53cfg = out_data;
+ PRINTM(MMSG, "dfs53cfg= %d\n", params->dfs53cfg);
+ }
+ }
+ if (end)
+ return ret;
+err:
+ PRINTM(MMSG, "Invalid line: %s\n", line);
+ ret = MLAN_STATUS_FAILURE;
+ return ret;
+}
+
+/**
+ * @brief This function initialize module parameter
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param params A pointer to moal_mod_para structure
+ *
+ * @return N/A
+ */
+static void woal_setup_module_param(moal_handle *handle, moal_mod_para *params)
+{
+ if (hw_test)
+ moal_extflg_set(handle, EXT_HW_TEST);
+#ifdef CONFIG_OF
+ if (dts_enable)
+ moal_extflg_set(handle, EXT_DTS_ENABLE);
+#endif
+ woal_dup_string(&handle->params.fw_name, fw_name);
+ if (params && params->fw_name)
+ woal_dup_string(&handle->params.fw_name, params->fw_name);
+ if (req_fw_nowait)
+ moal_extflg_set(handle, EXT_REQ_FW_NOWAIT);
+ handle->params.fw_reload = fw_reload;
+ if (fw_reload == FW_RELOAD_WITH_EMULATION) {
+ if (!IS_USB(handle->card_type))
+ handle->params.fw_reload = 0;
+ else
+ fw_reload = 0;
+ }
+ if (params)
+ handle->params.fw_reload = params->fw_reload;
+ if (fw_serial)
+ moal_extflg_set(handle, EXT_FW_SERIAL);
+ woal_dup_string(&handle->params.mac_addr, mac_addr);
+ if (params && params->mac_addr)
+ woal_dup_string(&handle->params.mac_addr, params->mac_addr);
+#ifdef MFG_CMD_SUPPORT
+ handle->params.mfg_mode = mfg_mode;
+ if (params)
+ handle->params.mfg_mode = params->mfg_mode;
+#endif
+ handle->params.drv_mode = drv_mode;
+ if (params)
+ handle->params.drv_mode = params->drv_mode;
+#ifdef STA_SUPPORT
+ handle->params.max_sta_bss = max_sta_bss;
+ woal_dup_string(&handle->params.sta_name, sta_name);
+ if (params) {
+ handle->params.max_sta_bss = params->max_sta_bss;
+ woal_dup_string(&handle->params.sta_name, params->sta_name);
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ handle->params.max_uap_bss = max_uap_bss;
+ woal_dup_string(&handle->params.uap_name, uap_name);
+ handle->params.uap_max_sta = uap_max_sta;
+ if (params) {
+ handle->params.max_uap_bss = params->max_uap_bss;
+ woal_dup_string(&handle->params.uap_name, params->uap_name);
+ handle->params.uap_max_sta = params->uap_max_sta;
+ }
+#endif /* UAP_SUPPORT */
+#ifdef WIFI_DIRECT_SUPPORT
+ handle->params.max_wfd_bss = max_wfd_bss;
+ woal_dup_string(&handle->params.wfd_name, wfd_name);
+ if (params) {
+ handle->params.max_wfd_bss = params->max_wfd_bss;
+ woal_dup_string(&handle->params.wfd_name, params->wfd_name);
+ }
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ handle->params.max_vir_bss = max_vir_bss;
+ if (params)
+ handle->params.max_vir_bss = params->max_vir_bss;
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+ handle->params.auto_ds = auto_ds;
+ if (params)
+ handle->params.auto_ds = params->auto_ds;
+ handle->params.ps_mode = ps_mode;
+ handle->params.p2a_scan = p2a_scan;
+ handle->params.scan_chan_gap = scan_chan_gap;
+ handle->params.max_tx_buf = max_tx_buf;
+ if (params) {
+ handle->params.ps_mode = params->ps_mode;
+ handle->params.max_tx_buf = params->max_tx_buf;
+ handle->params.p2a_scan = params->p2a_scan;
+ handle->params.scan_chan_gap = params->scan_chan_gap;
+ }
+#if defined(SDIO)
+ if (intmode)
+ moal_extflg_set(handle, EXT_INTMODE);
+ handle->params.gpiopin = gpiopin;
+ if (params)
+ handle->params.gpiopin = params->gpiopin;
+#endif
+#if defined(SDIO) && defined(SDIO_SUSPEND_RESUME)
+ if (pm_keep_power)
+ moal_extflg_set(handle, EXT_PM_KEEP_POWER);
+ if (shutdown_hs)
+ moal_extflg_set(handle, EXT_SHUTDOWN_HS);
+#endif
+#if defined(STA_SUPPORT)
+ handle->params.cfg_11d = cfg_11d;
+ if (params)
+ handle->params.cfg_11d = params->cfg_11d;
+#endif
+#if defined(SDIO)
+ handle->params.slew_rate = slew_rate;
+#endif
+ woal_dup_string(&handle->params.dpd_data_cfg, dpd_data_cfg);
+ if (params)
+ woal_dup_string(&handle->params.dpd_data_cfg,
+ params->dpd_data_cfg);
+ woal_dup_string(&handle->params.init_cfg, init_cfg);
+ woal_dup_string(&handle->params.cal_data_cfg, cal_data_cfg);
+ if (params) {
+ woal_dup_string(&handle->params.init_cfg, params->init_cfg);
+ woal_dup_string(&handle->params.cal_data_cfg,
+ params->cal_data_cfg);
+ }
+ woal_dup_string(&handle->params.txpwrlimit_cfg, txpwrlimit_cfg);
+ if (params)
+ woal_dup_string(&handle->params.txpwrlimit_cfg,
+ params->txpwrlimit_cfg);
+ if (cntry_txpwr)
+ moal_extflg_set(handle, EXT_CNTRY_TXPWR);
+ woal_dup_string(&handle->params.init_hostcmd_cfg, init_hostcmd_cfg);
+ if (params)
+ woal_dup_string(&handle->params.init_hostcmd_cfg,
+ params->init_hostcmd_cfg);
+
+ woal_dup_string(&handle->params.band_steer_cfg, band_steer_cfg);
+ if (params)
+ woal_dup_string(&handle->params.band_steer_cfg,
+ params->band_steer_cfg);
+ handle->params.cfg80211_wext = cfg80211_wext;
+ if (params)
+ handle->params.cfg80211_wext = params->cfg80211_wext;
+#if defined(USB)
+ if (skip_fwdnld)
+ moal_extflg_set(handle, EXT_SKIP_FWDNLD);
+#endif
+ handle->params.wq_sched_prio = wq_sched_prio;
+ handle->params.wq_sched_policy = wq_sched_policy;
+ handle->params.rx_work = rx_work;
+ if (params) {
+ handle->params.wq_sched_prio = params->wq_sched_prio;
+ handle->params.wq_sched_policy = params->wq_sched_policy;
+ handle->params.rx_work = params->rx_work;
+ }
+ if (aggrctrl)
+ moal_extflg_set(handle, EXT_AGGR_CTRL);
+#ifdef USB
+ handle->params.usb_aggr = usb_aggr;
+ if (params)
+ handle->params.usb_aggr = params->usb_aggr;
+#endif
+#ifdef PCIE
+ handle->params.pcie_int_mode = pcie_int_mode;
+ if (params)
+ handle->params.pcie_int_mode = params->pcie_int_mode;
+#endif /* PCIE */
+ if (low_power_mode_enable)
+ moal_extflg_set(handle, EXT_LOW_PW_MODE);
+
+#ifdef ANDROID_KERNEL
+ handle->params.wakelock_timeout = wakelock_timeout;
+ if (params)
+ handle->params.wakelock_timeout = params->wakelock_timeout;
+#endif
+ handle->params.dev_cap_mask = dev_cap_mask;
+ if (params)
+ handle->params.dev_cap_mask = params->dev_cap_mask;
+#ifdef SDIO
+ if (sdio_rx_aggr)
+ moal_extflg_set(handle, EXT_SDIO_RX_AGGR);
+#endif
+#if defined(SD8997) || defined(PCIE8997) || defined(USB8997) || \
+ defined(SD8977) || defined(SD8987) || defined(SD9098) || \
+ defined(USB9098) || defined(PCIE9098) || defined(SD9097) || \
+ defined(USB9097) || defined(PCIE9097) || defined(SD8978) || \
+ defined(USB8978)
+ if (pmic)
+ moal_extflg_set(handle, EXT_PMIC);
+#endif
+ handle->params.antcfg = antcfg;
+ if (params)
+ handle->params.antcfg = params->antcfg;
+ handle->params.uap_oper_ctrl = uap_oper_ctrl;
+ if (params)
+ handle->params.uap_oper_ctrl = params->uap_oper_ctrl;
+ handle->params.hs_wake_interval = hs_wake_interval;
+ handle->params.indication_gpio = indication_gpio;
+ if (params) {
+ handle->params.hs_wake_interval = params->hs_wake_interval;
+ handle->params.indication_gpio = params->indication_gpio;
+ }
+ if (disconnect_on_suspend)
+ moal_extflg_set(handle, EXT_DISCONNECT_ON_SUSPEND);
+ if (hs_mimo_switch)
+ moal_extflg_set(handle, EXT_HS_MIMO_SWITCH);
+ handle->params.indrstcfg = indrstcfg;
+ if (params)
+ handle->params.indrstcfg = params->indrstcfg;
+ if (fixed_beacon_buffer)
+ moal_extflg_set(handle, EXT_FIX_BCN_BUF);
+#ifdef WIFI_DIRECT_SUPPORT
+ handle->params.GoAgeoutTime = GoAgeoutTime;
+ if (params)
+ handle->params.GoAgeoutTime = params->GoAgeoutTime;
+#endif
+ handle->params.gtk_rekey_offload = gtk_rekey_offload;
+ if (params)
+ handle->params.gtk_rekey_offload = params->gtk_rekey_offload;
+ handle->params.multi_dtim = multi_dtim;
+ handle->params.inact_tmo = inact_tmo;
+ if (params) {
+ handle->params.multi_dtim = params->multi_dtim;
+ handle->params.inact_tmo = params->inact_tmo;
+ }
+ if (napi)
+ moal_extflg_set(handle, EXT_NAPI);
+ if (tx_work)
+ moal_extflg_set(handle, EXT_TX_WORK);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (dfs_offload)
+ moal_extflg_set(handle, EXT_DFS_OFFLOAD);
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (host_mlme)
+ moal_extflg_set(handle, EXT_HOST_MLME);
+#endif
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (disable_regd_by_driver)
+ moal_extflg_set(handle, EXT_DISABLE_REGD_BY_DRIVER);
+ if (reg_alpha2)
+ woal_dup_string(&handle->params.reg_alpha2, reg_alpha2);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (country_ie_ignore)
+ moal_extflg_set(handle, EXT_COUNTRY_IE_IGNORE);
+ if (beacon_hints)
+ moal_extflg_set(handle, EXT_BEACON_HINTS);
+#endif
+#endif
+ if (params && params->reg_alpha2)
+ woal_dup_string(&handle->params.reg_alpha2, params->reg_alpha2);
+ if (params)
+ moal_memcpy_ext(handle, handle->params.ext_flgs,
+ params->ext_flgs, sizeof(params->ext_flgs),
+ sizeof(handle->params.ext_flgs));
+
+ /* do some special handle for MFG mode */
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode) {
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ handle->params.cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK;
+#else
+ handle->params.cfg80211_wext = 0;
+#endif
+ handle->params.drv_mode = DRV_MODE_STA;
+ }
+#endif
+ if (dfs53cfg > DFS_W53_OLD) {
+ PRINTM(MERROR, "Invalid value for dfs53cfg !\n");
+ handle->params.dfs53cfg = DFS_W53_DEFAULT_FW;
+ } else {
+ handle->params.dfs53cfg = dfs53cfg;
+ if (params)
+ handle->params.dfs53cfg = params->dfs53cfg;
+ }
+}
+
+/**
+ * @brief This function free module parameter memory
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_free_module_param(moal_handle *handle)
+{
+ moal_mod_para *params = &handle->params;
+ PRINTM(MMSG, "Free module params\n");
+ if (params->fw_name) {
+ kfree(params->fw_name);
+ params->fw_name = NULL;
+ }
+ if (params->mac_addr) {
+ kfree(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+#ifdef STA_SUPPORT
+ if (params->sta_name) {
+ kfree(params->sta_name);
+ params->sta_name = NULL;
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ if (params->uap_name) {
+ kfree(params->uap_name);
+ params->uap_name = NULL;
+ }
+#endif /* UAP_SUPPORT */
+#ifdef WIFI_DIRECT_SUPPORT
+ if (params->wfd_name) {
+ kfree(params->wfd_name);
+ params->wfd_name = NULL;
+ }
+#endif /* WIFI_DIRECT_SUPPORT */
+ if (params->dpd_data_cfg) {
+ kfree(params->dpd_data_cfg);
+ params->dpd_data_cfg = NULL;
+ }
+ if (params->init_cfg) {
+ kfree(params->init_cfg);
+ params->init_cfg = NULL;
+ }
+ if (params->cal_data_cfg) {
+ kfree(params->cal_data_cfg);
+ params->cal_data_cfg = NULL;
+ }
+ if (params->txpwrlimit_cfg) {
+ kfree(params->txpwrlimit_cfg);
+ params->txpwrlimit_cfg = NULL;
+ }
+ if (params->init_hostcmd_cfg) {
+ kfree(params->init_hostcmd_cfg);
+ params->init_hostcmd_cfg = NULL;
+ }
+ if (params->band_steer_cfg) {
+ kfree(params->band_steer_cfg);
+ params->band_steer_cfg = NULL;
+ }
+ if (params->reg_alpha2) {
+ kfree(params->reg_alpha2);
+ params->reg_alpha2 = NULL;
+ }
+}
+
+/**
+ * @brief This function request module parameter data from user space
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param mod_file A pointer to module parameter file path
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_req_mod_param(moal_handle *handle, char *mod_file)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct device *dev = handle->hotplug_device;
+
+ if (dev == NULL) {
+ PRINTM(MERROR, "No device attached\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+
+ ret = request_firmware(&handle->param_data, mod_file, dev);
+ if (ret < 0)
+ PRINTM(MERROR, "Request firmware: %s failed, error: %d\n",
+ mod_file, ret);
+out:
+ return ret;
+}
+
+#ifdef CONFIG_OF
+/**
+ * @brief This function read the initial parameter from device tress
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_init_from_dev_tree(void)
+{
+ struct device_node *dt_node = NULL;
+ struct property *prop;
+ t_u32 data;
+ const char *string_data;
+
+ ENTER();
+
+ if (!dts_enable) {
+ PRINTM(MIOCTL, "DTS is disabled!");
+ return;
+ }
+
+ dt_node = of_find_node_by_name(NULL, "sdxxx-wlan");
+ if (!dt_node) {
+ LEAVE();
+ return;
+ }
+ for_each_property_of_node (dt_node, prop) {
+ if (!strncmp(prop->name, "drv_mode", strlen("drv_mode"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "drv_mode=0x%x\n", data);
+ drv_mode = data;
+ }
+ }
+#ifdef DEBUG_LEVEL1
+ else if (!strncmp(prop->name, "drvdbg", strlen("drvdbg"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "drvdbg=0x%x\n", data);
+ drvdbg = data;
+ }
+ }
+#endif
+ else if (!strncmp(prop->name, "dev_cap_mask",
+ strlen("dev_cap_mask"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "dev_cap_mask=0x%x\n", data);
+ dev_cap_mask = data;
+ }
+ } else if (!strncmp(prop->name, "hw_test", strlen("hw_test"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "hw_test=0x%x\n", data);
+ hw_test = data;
+ }
+ }
+#if defined(SDIO)
+ else if (!strncmp(prop->name, "slew_rate",
+ strlen("slew_rate"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "slew_rate=0x%x\n", data);
+ slew_rate = data;
+ }
+ }
+#endif
+ else if (!strncmp(prop->name, "tx_work", strlen("tx_work"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "tx_work=0x%x\n", data);
+ tx_work = data;
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ else if (!strncmp(prop->name, "mfg_mode", strlen("mfg_mode"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "mfg_mode=0x%x\n", data);
+ mfg_mode = data;
+ }
+ }
+#endif
+ else if (!strncmp(prop->name, "mac_addr", strlen("mac_addr"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ mac_addr = (char *)string_data;
+ PRINTM(MIOCTL, "mac_addr=%s\n", mac_addr);
+ }
+ } else if (!strncmp(prop->name, "fw_name", strlen("fw_name"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ fw_name = (char *)string_data;
+ PRINTM(MIOCTL, "fw_name=%s\n", fw_name);
+ }
+ }
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ else if (!strncmp(prop->name, "cfg80211_wext",
+ strlen("cfg80211_wext"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "cfg80211_wext=0x%x\n", data);
+ cfg80211_wext = data;
+ }
+ }
+#endif
+#ifdef STA_SUPPORT
+ else if (!strncmp(prop->name, "sta_name", strlen("sta_name"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ sta_name = (char *)string_data;
+ PRINTM(MIOCTL, "sta_name=%s\n", sta_name);
+ }
+ }
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (!strncmp(prop->name, "wfd_name", strlen("wfd_name"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ wfd_name = (char *)string_data;
+ PRINTM(MIOCTL, "wfd_name=%s\n", wfd_name);
+ }
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ else if (!strncmp(prop->name, "disable_regd_by_driver",
+ strlen("disable_regd_by_driver"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "disable_regd_by_driver=0x%x\n",
+ data);
+ disable_regd_by_driver = data;
+ }
+ } else if (!strncmp(prop->name, "reg_alpha2",
+ strlen("reg_alpha2"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ reg_alpha2 = (char *)string_data;
+ PRINTM(MIOCTL, "reg_alpha2=%s\n", reg_alpha2);
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ else if (!strncmp(prop->name, "country_ie_ignore",
+ strlen("country_ie_ignore"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "country_ie_ignore=0x%x\n",
+ data);
+ country_ie_ignore = data;
+ }
+ } else if (!strncmp(prop->name, "beacon_hints",
+ strlen("beacon_hints"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "beacon_hints=0x%x\n", data);
+ beacon_hints = data;
+ }
+ }
+#endif
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ else if (!strncmp(prop->name, "max_vir_bss",
+ strlen("max_vir_bss"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "max_vir_bss=0x%x\n", data);
+ max_vir_bss = data;
+ }
+ }
+#endif
+#endif
+ else if (!strncmp(prop->name, "dpd_data_cfg",
+ strlen("dpd_data_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ dpd_data_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "dpd_data_cfg=%s\n",
+ dpd_data_cfg);
+ }
+ } else if (!strncmp(prop->name, "init_cfg",
+ strlen("init_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ init_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "init_cfg=%s\n", init_cfg);
+ }
+ } else if (!strncmp(prop->name, "cal_data_cfg",
+ strlen("cal_data_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ cal_data_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "cal_data_cfg=%s\n",
+ cal_data_cfg);
+ }
+ } else if (!strncmp(prop->name, "txpwrlimit_cfg",
+ strlen("txpwrlimit_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ txpwrlimit_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "txpwrlimit_cfg=%s\n",
+ txpwrlimit_cfg);
+ }
+ } else if (!strncmp(prop->name, "cntry_txpwr",
+ strlen("cntry_txpwr"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ cntry_txpwr = data;
+ PRINTM(MIOCTL, "cntry_txpwr=%d\n", cntry_txpwr);
+ }
+ } else if (!strncmp(prop->name, "init_hostcmd_cfg",
+ strlen("init_hostcmd_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ init_hostcmd_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "init_hostcmd_cfg=%s\n",
+ init_hostcmd_cfg);
+ }
+ } else if (!strncmp(prop->name, "band_steer_cfg",
+ strlen("band_steer_cfg"))) {
+ if (!of_property_read_string(dt_node, prop->name,
+ &string_data)) {
+ band_steer_cfg = (char *)string_data;
+ PRINTM(MIOCTL, "band_steer_cfg=%s\n",
+ band_steer_cfg);
+ }
+ } else if (!strncmp(prop->name, "pmic", strlen("pmic"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ pmic = data;
+ PRINTM(MIOCTL, "pmic=%d\n", pmic);
+ }
+ } else if (!strncmp(prop->name, "antcfg", strlen("antcfg"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ antcfg = data;
+ PRINTM(MIOCTL, "antcfg=%d\n", antcfg);
+ }
+ } else if (!strncmp(prop->name, "hs_wake_interval",
+ strlen("hs_wake_interval"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ hs_wake_interval = data;
+ PRINTM(MIOCTL, "hs_wake_interval=%d\n",
+ hs_wake_interval);
+ }
+ } else if (!strncmp(prop->name, "indication_gpio",
+ strlen("indication_gpio"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ indication_gpio = (t_u8)data;
+ PRINTM(MIOCTL, "indication_gpio=%d\n",
+ indication_gpio);
+ }
+ } else if (!strncmp(prop->name, "hs_mimo_switch",
+ strlen("hs_mimo_switch"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ hs_mimo_switch = data;
+ PRINTM(MIOCTL, "hs_mimo_switch=%d\n",
+ hs_mimo_switch);
+ }
+ }
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (!strncmp(prop->name, "GoAgeoutTime",
+ strlen("GoAgeoutTime"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ GoAgeoutTime = data;
+ PRINTM(MIOCTL, "GoAgeoutTime=%d\n",
+ GoAgeoutTime);
+ }
+ }
+#endif
+ else if (!strncmp(prop->name, "indrstcfg",
+ strlen("indrstcfg"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ indrstcfg = data;
+ PRINTM(MIOCTL, "indrstcfg=%d\n", indrstcfg);
+ }
+ } else if (!strncmp(prop->name, "fixed_beacon_buffer",
+ strlen("fixed_beacon_buffer"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ fixed_beacon_buffer = data;
+ PRINTM(MIOCTL, "fixed_beacon_buffer=%d\n",
+ fixed_beacon_buffer);
+ }
+ } else if (!strncmp(prop->name, "multi_dtim",
+ strlen("multi_dtim"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ multi_dtim = data;
+ PRINTM(MIOCTL, "multi_dtim=%d\n", multi_dtim);
+ }
+ } else if (!strncmp(prop->name, "inact_tmo",
+ strlen("inact_tmo"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ inact_tmo = data;
+ PRINTM(MIOCTL, "inact_tmo=%d\n", inact_tmo);
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ else if (!strncmp(prop->name, "dfs_offload",
+ strlen("dfs_offload"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ dfs_offload = data;
+ PRINTM(MIOCTL, "dfs_offload=%d\n", dfs_offload);
+ }
+ }
+#endif
+ else if (!strncmp(prop->name, "gtk_rekey_offload",
+ strlen("gtk_rekey_offload"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ gtk_rekey_offload = data;
+ PRINTM(MIOCTL, "gtk_rekey_offload=%d\n",
+ gtk_rekey_offload);
+ }
+ }
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ else if (!strncmp(prop->name, "host_mlme",
+ strlen("host_mlme"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MIOCTL, "host_mlme=0x%x\n", data);
+ host_mlme = data;
+ }
+ }
+#endif
+#endif
+#ifdef UAP_SUPPORT
+ else if (!strncmp(prop->name, "uap_max_sta",
+ strlen("uap_max_sta"))) {
+ if (!of_property_read_u32(dt_node, prop->name, &data)) {
+ PRINTM(MERROR, "uap_max_sta=0x%x\n", data);
+ uap_max_sta = data;
+ }
+ }
+#endif
+ }
+ LEAVE();
+ return;
+}
+#endif
+
+/**
+ * @brief This function check if configuration block id could be used
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_validate_cfg_id(moal_handle *handle)
+{
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ for (i = 0; i < MAX_MLAN_ADAPTER; i++) {
+ if (m_handle[i] == NULL || m_handle[i] == handle)
+ continue;
+ if (m_handle[i]->card_type == handle->card_type) {
+ if (m_handle[i]->blk_id == handle->blk_id) {
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief This function skip current configuration block
+ *
+ * @param data A pointer to buffer of module configuration file
+ * @param size Size of module configuration file
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status parse_skip_cfg_block(t_u8 *data, t_u32 size)
+{
+ int end = 0;
+ t_u8 line[MAX_LINE_LEN];
+ while (parse_cfg_get_line(data, size, line) != -1) {
+ if (strncmp(line, "}", strlen("}")) == 0) {
+ end = 1;
+ break;
+ }
+ if (end == 0 && strstr(line, "{") != 0)
+ break;
+ }
+ return (end == 1) ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function handle fallback processing for invalid
+ * block id with same card type
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_cfg_fallback_process(moal_handle *handle)
+{
+ int i, blk_id = 0x7fffffff, idx = -1;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ PRINTM(MMSG, "Configuration block, fallback processing\n");
+ for (i = 0; i < MAX_MLAN_ADAPTER; i++) {
+ if (m_handle[i] == NULL || m_handle[i] == handle ||
+ m_handle[i]->card_type != handle->card_type)
+ continue;
+ /* use configuratino with lowest blk_id value */
+ if (m_handle[i]->blk_id >= 0 && m_handle[i]->blk_id <= blk_id) {
+ idx = i;
+ blk_id = m_handle[i]->blk_id;
+ }
+ }
+ if (idx >= 0 && idx < MAX_MLAN_ADAPTER) {
+ ret = MLAN_STATUS_SUCCESS;
+ handle->blk_id = m_handle[idx]->blk_id;
+ PRINTM(MMSG,
+ "Configuration fallback to, card_type: 0x%x, blk_id: 0x%x\n",
+ handle->card_type, handle->blk_id);
+ woal_setup_module_param(handle, &m_handle[idx]->params);
+ }
+ return ret;
+}
+
+/**
+ * @brief This function parse and initialize module parameters
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_init_module_param(moal_handle *handle)
+{
+ int no_match = 1;
+ t_u32 size, i, tbl_size;
+ t_u8 line[MAX_LINE_LEN], *data = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ char *card_type = NULL, *blk_id = NULL;
+
+ memset(line, 0, MAX_LINE_LEN);
+ woal_setup_module_param(handle, NULL);
+ if (mod_para == NULL) {
+ PRINTM(MMSG, "No module param cfg file specified\n");
+ goto out;
+ }
+ if (woal_req_mod_param(handle, mod_para)) {
+ PRINTM(MERROR, "Failed to get module param file\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ tbl_size = sizeof(card_type_map_tbl) / sizeof(card_type_map_tbl[0]);
+ for (i = 0; i < tbl_size; i++)
+ if (handle->card_type == card_type_map_tbl[i].card_type)
+ break;
+ if (i >= tbl_size) {
+ PRINTM(MERROR, "No card type entry found for card type: 0x%x\n",
+ handle->card_type);
+ ret = MLAN_STATUS_FAILURE;
+ goto out;
+ }
+ PRINTM(MMSG, "%s: init module param from usr cfg\n",
+ card_type_map_tbl[i].name);
+ size = handle->param_data->size;
+ data = (t_u8 *)handle->param_data->data;
+ while (parse_cfg_get_line(data, size, line) != -1) {
+ if (line[0] == '#')
+ continue;
+ if (strstr(line, "={")) {
+ ret = parse_line_read_card_info(line, &card_type,
+ &blk_id);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto out;
+ PRINTM(MINFO,
+ "Traverse, card_type: %s, config block: %s\n",
+ card_type, blk_id);
+ if (strcmp(card_type_map_tbl[i].name, card_type) == 0) {
+ /* parse config block id */
+ if (blk_id == NULL)
+ handle->blk_id = 0;
+ else
+ woal_atoi(&handle->blk_id, blk_id);
+ PRINTM(MINFO,
+ "Validation check, %s, config block: %d\n",
+ card_type, handle->blk_id);
+ /* check validation of config id */
+ if (woal_validate_cfg_id(handle) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = parse_skip_cfg_block(data, size);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MMSG,
+ "failed to skip block\n");
+ goto out;
+ }
+ continue;
+ }
+ no_match = 0;
+ PRINTM(MMSG,
+ "card_type: %s, config block: %d\n",
+ card_type, handle->blk_id);
+ /* parse config block */
+ ret = parse_cfg_read_block(data, size, handle);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto out;
+ break;
+ }
+ }
+ }
+ if (no_match)
+ ret = woal_cfg_fallback_process(handle);
+out:
+ if (handle->param_data) {
+ release_firmware(handle->param_data);
+ /* rewind pos */
+ parse_cfg_get_line(NULL, 0, NULL);
+ }
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Invalid block: %s\n", line);
+ woal_free_module_param(handle);
+ woal_setup_module_param(handle, NULL);
+ }
+ return ret;
+}
+
+module_param(mod_para, charp, 0);
+MODULE_PARM_DESC(mod_para, "Module parameters configuration file");
+module_param(hw_test, int, 0660);
+MODULE_PARM_DESC(hw_test, "0: Disable hardware test; 1: Enable hardware test");
+#ifdef CONFIG_OF
+module_param(dts_enable, int, 0);
+MODULE_PARM_DESC(dts_enable, "0: Disable DTS; 1: Enable DTS");
+#endif
+module_param(fw_name, charp, 0660);
+MODULE_PARM_DESC(fw_name, "Firmware name");
+module_param(req_fw_nowait, int, 0);
+MODULE_PARM_DESC(
+ req_fw_nowait,
+ "0: Use request_firmware API; 1: Use request_firmware_nowait API");
+module_param(fw_reload, int, 0);
+MODULE_PARM_DESC(fw_reload,
+ "0: disable fw_reload; 1: enable fw reload feature");
+module_param(fw_serial, int, 0);
+MODULE_PARM_DESC(
+ fw_serial,
+ "0: support parallel download FW; 1: support serial download FW");
+module_param(mac_addr, charp, 0660);
+MODULE_PARM_DESC(mac_addr, "MAC address");
+#ifdef MFG_CMD_SUPPORT
+module_param(mfg_mode, int, 0660);
+MODULE_PARM_DESC(mfg_mode,
+ "0: Download normal firmware; 1: Download MFG firmware");
+#endif /* MFG_CMD_SUPPORT */
+module_param(drv_mode, int, 0660);
+MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT");
+
+#ifdef STA_SUPPORT
+module_param(max_sta_bss, int, 0);
+MODULE_PARM_DESC(max_sta_bss, "Number of STA interfaces (1)");
+module_param(sta_name, charp, 0);
+MODULE_PARM_DESC(sta_name, "STA interface name");
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+module_param(max_uap_bss, int, 0);
+MODULE_PARM_DESC(max_uap_bss, "Number of uAP interfaces (1)");
+module_param(uap_name, charp, 0);
+MODULE_PARM_DESC(uap_name, "uAP interface name");
+#endif /* UAP_SUPPORT */
+#ifdef WIFI_DIRECT_SUPPORT
+module_param(max_wfd_bss, int, 0);
+MODULE_PARM_DESC(max_wfd_bss, "Number of WIFIDIRECT interfaces (1)");
+module_param(wfd_name, charp, 0);
+MODULE_PARM_DESC(wfd_name, "WIFIDIRECT interface name");
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+module_param(max_vir_bss, int, 0);
+MODULE_PARM_DESC(max_vir_bss, "Number of Virtual interfaces (0)");
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+#ifdef DEBUG_LEVEL1
+module_param(drvdbg, uint, 0660);
+MODULE_PARM_DESC(drvdbg, "Driver debug");
+#endif /* DEBUG_LEVEL1 */
+module_param(auto_ds, int, 0660);
+MODULE_PARM_DESC(
+ auto_ds,
+ "0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep");
+module_param(ps_mode, int, 0660);
+MODULE_PARM_DESC(
+ ps_mode,
+ "0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode");
+module_param(p2a_scan, int, 0660);
+MODULE_PARM_DESC(
+ p2a_scan,
+ "0: MLAN default; 1: Enable passive to active scan for DFS channel; 2: Disable passive to active scan for DFS channel");
+module_param(scan_chan_gap, int, 0660);
+MODULE_PARM_DESC(
+ scan_chan_gap,
+ "Time gap between two scans in milliseconds when connected to AP(max value 500ms)");
+module_param(max_tx_buf, int, 0);
+MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)");
+
+#if defined(SDIO)
+module_param(intmode, int, 0);
+MODULE_PARM_DESC(intmode, "0: INT_MODE_SDIO, 1: INT_MODE_GPIO");
+module_param(gpiopin, int, 0);
+MODULE_PARM_DESC(gpiopin, "255:new GPIO int mode, other vlue: gpio pin number");
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+module_param(pm_keep_power, int, 0);
+MODULE_PARM_DESC(pm_keep_power, "1: PM keep power; 0: PM no power");
+module_param(shutdown_hs, int, 0);
+MODULE_PARM_DESC(shutdown_hs,
+ "1: Enable HS when shutdown; 0: No HS when shutdown");
+#endif
+#if defined(STA_SUPPORT)
+module_param(cfg_11d, int, 0);
+MODULE_PARM_DESC(cfg_11d,
+ "0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d");
+#endif
+#if defined(SDIO)
+module_param(slew_rate, int, 0);
+MODULE_PARM_DESC(
+ slew_rate,
+ "0:has the slowest slew rate, then 01, then 02, and 03 has the highest slew rate");
+#endif
+module_param(tx_work, uint, 0660);
+MODULE_PARM_DESC(tx_work, "1: Enable tx_work; 0: Disable tx_work");
+module_param(dpd_data_cfg, charp, 0);
+MODULE_PARM_DESC(dpd_data_cfg, "DPD data file name");
+module_param(init_cfg, charp, 0);
+MODULE_PARM_DESC(init_cfg, "Init config file name");
+module_param(cal_data_cfg, charp, 0);
+MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name");
+module_param(txpwrlimit_cfg, charp, 0);
+MODULE_PARM_DESC(txpwrlimit_cfg,
+ "Set configuration data of Tx power limitation");
+module_param(cntry_txpwr, int, 0);
+MODULE_PARM_DESC(
+ cntry_txpwr,
+ "Allow setting tx power table of country; 0: disable (default), 1: enable.");
+module_param(init_hostcmd_cfg, charp, 0);
+MODULE_PARM_DESC(init_hostcmd_cfg, "Init hostcmd file name");
+module_param(band_steer_cfg, charp, 0);
+MODULE_PARM_DESC(band_steer_cfg, "band steer cfg file name");
+module_param(cfg80211_wext, int, 0660);
+MODULE_PARM_DESC(cfg80211_wext,
+#ifdef STA_WEXT
+ "Bit 0: STA WEXT; "
+#endif
+#ifdef UAP_WEXT
+ "Bit 1: UAP WEXT; "
+#endif
+#ifdef STA_CFG80211
+ "Bit 2: STA CFG80211; "
+#endif
+#ifdef UAP_CFG80211
+ "Bit 3: UAP CFG80211;"
+#endif
+);
+#if defined(USB)
+module_param(skip_fwdnld, int, 0);
+MODULE_PARM_DESC(skip_fwdnld, "0: Enable FW download; 1: Disable FW download");
+#endif
+module_param(wq_sched_prio, int, 0);
+module_param(wq_sched_policy, int, 0);
+MODULE_PARM_DESC(wq_sched_prio, "Priority of work queue");
+MODULE_PARM_DESC(
+ wq_sched_policy,
+ "0: SCHED_NORMAL; 1: SCHED_FIFO; 2: SCHED_RR; 3: SCHED_BATCH; 5: SCHED_IDLE");
+module_param(rx_work, int, 0);
+MODULE_PARM_DESC(
+ rx_work,
+ "0: default; 1: Enable rx_work_queue; 2: Disable rx_work_queue");
+module_param(aggrctrl, int, 0);
+MODULE_PARM_DESC(aggrctrl,
+ "1: Enable Tx aggregation; 0: Disable Tx aggregation");
+#ifdef USB
+module_param(usb_aggr, int, 0);
+MODULE_PARM_DESC(usb_aggr,
+ "0: MLAN default; 1: Enable USB aggr; 2: Disable USB aggr");
+#endif
+#ifdef PCIE
+module_param(pcie_int_mode, int, 0);
+MODULE_PARM_DESC(pcie_int_mode, "0: Legacy mode; 1: MSI mode; 2: MSI-X mode");
+#endif /* PCIE */
+module_param(low_power_mode_enable, int, 0);
+MODULE_PARM_DESC(low_power_mode_enable, "0/1: Disable/Enable Low Power Mode");
+
+#ifdef ANDROID_KERNEL
+module_param(wakelock_timeout, int, 0);
+MODULE_PARM_DESC(wakelock_timeout, "set wakelock_timeout value (ms)");
+#endif
+
+module_param(dev_cap_mask, uint, 0);
+MODULE_PARM_DESC(dev_cap_mask, "Device capability mask");
+
+#ifdef SDIO
+module_param(sdio_rx_aggr, int, 0);
+MODULE_PARM_DESC(sdio_rx_aggr,
+ "1: Enable SDIO rx aggr; 0: Disable SDIO rx aggr");
+#endif
+
+module_param(pmic, int, 0);
+MODULE_PARM_DESC(
+ pmic,
+ "1: Send pmic configure cmd to firmware; 0: No pmic configure cmd sent to firmware");
+
+module_param(antcfg, int, 0660);
+MODULE_PARM_DESC(
+ antcfg,
+ "0:default; SD8887/SD8987-[1:Tx/Rx antenna 1, 2:Tx/Rx antenna 2, 0xffff:enable antenna diversity];SD8897/SD8997-[Bit0:Rx Path A, Bit1:Rx Path B, Bit 4:Tx Path A, Bit 5:Tx Path B];9098/9097-[Bit 0: 2G Tx/Rx path A, Bit 1: 2G Tx/Rx path B,Bit 8: 5G Tx/Rx path A, Bit 9: 5G Tx/Rx path B]");
+
+module_param(uap_oper_ctrl, uint, 0);
+MODULE_PARM_DESC(uap_oper_ctrl, "0:default; 0x20001:uap restarts on channel 6");
+
+module_param(hs_wake_interval, int, 0660);
+MODULE_PARM_DESC(
+ hs_wake_interval,
+ "Host sleep wakeup interval,it will round to nearest multiple dtim*beacon_period in fw");
+module_param(indication_gpio, int, 0);
+MODULE_PARM_DESC(
+ indication_gpio,
+ "GPIO to indicate wakeup source; high four bits: level for normal wakeup; low four bits: GPIO pin number.");
+module_param(disconnect_on_suspend, int, 0);
+MODULE_PARM_DESC(
+ disconnect_on_suspend,
+ "1: Enable disconnect wifi on suspend; 0: Disable disconnect wifi on suspend");
+module_param(hs_mimo_switch, int, 0660);
+MODULE_PARM_DESC(
+ hs_mimo_switch,
+ "Dynamic MIMO-SISO switch during host sleep; 0: disable (default), 1: enable");
+
+module_param(indrstcfg, int, 0);
+MODULE_PARM_DESC(
+ indrstcfg,
+ "Independent reset configuration; high byte: GPIO pin number; low byte: IR mode");
+
+module_param(fixed_beacon_buffer, int, 0);
+MODULE_PARM_DESC(
+ fixed_beacon_buffer,
+ "0: allocate default buffer size; 1: allocate max buffer size.");
+
+#ifdef WIFI_DIRECT_SUPPORT
+module_param(GoAgeoutTime, int, 0);
+MODULE_PARM_DESC(GoAgeoutTime,
+ "0: use default ageout time; set Go age out time (TU 100ms)");
+#endif
+
+module_param(gtk_rekey_offload, int, 0);
+MODULE_PARM_DESC(
+ gtk_rekey_offload,
+ "0: disable gtk_rekey_offload; 1: enable gtk_rekey_offload (default); 2: enable gtk_rekey_offload in suspend mode only;");
+
+module_param(multi_dtim, ushort, 0);
+MODULE_PARM_DESC(multi_dtim, "DTIM interval");
+
+module_param(inact_tmo, ushort, 0);
+MODULE_PARM_DESC(inact_tmo, "IEEE ps inactivity timout value");
+
+module_param(napi, int, 0);
+MODULE_PARM_DESC(napi, "1: enable napi api; 0: disable napi");
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+module_param(dfs_offload, int, 0);
+MODULE_PARM_DESC(dfs_offload, "1: enable dfs offload; 0: disable dfs offload.");
+#endif
+
+#ifdef UAP_SUPPORT
+module_param(uap_max_sta, int, 0);
+MODULE_PARM_DESC(uap_max_sta, "Maximum station number for UAP/GO.");
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+module_param(host_mlme, int, 0);
+MODULE_PARM_DESC(host_mlme,
+ "1: Enable Host MLME Support; 0: Disable Host MLME support");
+#endif
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+module_param(disable_regd_by_driver, int, 0);
+MODULE_PARM_DESC(
+ disable_regd_by_driver,
+ "0: reg domain set by driver enable(default); 1: reg domain set by driver disable");
+module_param(reg_alpha2, charp, 0660);
+MODULE_PARM_DESC(reg_alpha2, "Regulatory alpha2");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+module_param(country_ie_ignore, int, 0);
+MODULE_PARM_DESC(
+ country_ie_ignore,
+ "0: Follow countryIE from AP and beacon hint enable; 1: Ignore countryIE from AP and beacon hint disable");
+module_param(beacon_hints, int, 0);
+MODULE_PARM_DESC(beacon_hints,
+ "0: enable beacon hints(default); 1: disable beacon hints");
+#endif
+#endif
+
+module_param(dfs53cfg, int, 0);
+MODULE_PARM_DESC(dfs53cfg, "0: fw default; 1: new w53 dfs; 2: old w53 dfs");
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_ioctl.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_ioctl.c
new file mode 100644
index 000000000000..8cb4af25d096
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_ioctl.c
@@ -0,0 +1,6979 @@
+/** @file moal_ioctl.c
+ *
+ * @brief This file contains ioctl function to MLAN
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_eth_ioctl.h"
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif
+#ifdef USB
+#include "moal_usb.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#include "moal_cfg80211_util.h"
+#endif
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+#define MRVL_TLV_HEADER_SIZE 4
+/* NXP Channel config TLV ID */
+#define MRVL_CHANNELCONFIG_TLV_ID (0x0100 + 0x2a) /* 0x012a */
+
+typedef struct _hostcmd_header {
+ /** Command Header : Command */
+ t_u16 command;
+ /** Command Header : Size */
+ t_u16 size;
+ /** Command Header : Sequence number */
+ t_u16 seq_num;
+ /** Command Header : Result */
+ t_u16 result;
+ /** Command action */
+ t_u16 action;
+} hostcmd_header, *phostcmd_header;
+
+/** Region code mapping */
+typedef struct _region_code_mapping_t {
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+ /** Code */
+ t_u8 code;
+} region_code_mapping_t;
+
+#define EU_REGION_CODE 0x30
+
+/** Region code mapping table */
+static region_code_mapping_t region_code_mapping[] = {
+ {"US", 0x10}, /* US FCC */
+ {"CA", 0x20}, /* IC Canada */
+ {"SG", 0x10}, /* Singapore */
+ {"EU", 0x30}, /* ETSI */
+ {"AU", 0x30}, /* Australia */
+ {"KR", 0x30}, /* Republic Of Korea */
+ {"JP", 0x40}, /* Japan */
+ {"CN", 0x50}, /* China */
+ {"BR", 0x09}, /* Brazil */
+ {"RU", 0x0f}, /* Russia */
+ {"IN", 0x06}, /* India */
+ {"MY", 0x06}, /* Malaysia */
+ {"MX", 0x07}, /* Mexico */
+ {"NE", 0x30}, /* New Zeland */
+};
+
+/** EEPROM Region code mapping table */
+static region_code_mapping_t hw_region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* IC Canada */
+ {"KR ", 0x30}, /* Korea */
+ {"CN ", 0x50}, /* China */
+ {"ES ", 0x31}, /* Spain */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ {"JP ", 0x41}, /* Japan */
+};
+
+/** Country code for ETSI */
+static t_u8 eu_country_code_table[][COUNTRY_CODE_LEN] = {
+ "AL", "AD", "AT", "AU", "BY", "BE", "BA", "BG", "HR", "CY", "CZ", "DK",
+ "EE", "FI", "FR", "MK", "DE", "GR", "HU", "IS", "IE", "IT", "KR", "LV",
+ "LI", "LT", "LU", "MT", "MD", "MC", "ME", "NL", "NO", "PL", "RO", "RU",
+ "SM", "RS", "SI", "SK", "ES", "SE", "CH", "TR", "UA", "UK", "GB", "NE"};
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+#ifdef UAP_SUPPORT
+/** Network device handlers for uAP */
+extern const struct net_device_ops woal_uap_netdev_ops;
+#endif
+#ifdef STA_SUPPORT
+/** Network device handlers for STA */
+extern const struct net_device_ops woal_netdev_ops;
+#endif
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+/** Mfg mode */
+extern int mfg_mode;
+#endif
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param country_code Region string
+ *
+ * @return Region code
+ */
+t_bool woal_is_country_code_supported(t_u8 *country_code)
+{
+ t_u8 i;
+ ENTER();
+
+ for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
+ if (!memcmp(country_code, region_code_mapping[i].region,
+ COUNTRY_CODE_LEN - 1)) {
+ PRINTM(MIOCTL,
+ "found country code in region_code table\n");
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param region_string Region string
+ *
+ * @return Region code
+ */
+t_u8 region_string_2_region_code(char *region_string)
+{
+ t_u8 i;
+
+ ENTER();
+ for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
+ if (!memcmp(region_string, region_code_mapping[i].region,
+ strlen(region_string))) {
+ LEAVE();
+ return region_code_mapping[i].code;
+ }
+ }
+
+ /* If still not found, look for code in EU country code table */
+ for (i = 0; i < ARRAY_SIZE(eu_country_code_table); i++) {
+ if (!memcmp(region_string, eu_country_code_table[i],
+ COUNTRY_CODE_LEN - 1)) {
+ PRINTM(MIOCTL, "found region code=%d in EU table\n",
+ EU_REGION_CODE);
+ LEAVE();
+ return EU_REGION_CODE;
+ }
+ }
+
+ /* Default is US */
+ LEAVE();
+ return region_code_mapping[0].code;
+}
+
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param country_code Region string
+ *
+ * @return Region code
+ */
+t_bool woal_is_etsi_country(t_u8 *country_code)
+{
+ t_u8 i;
+ ENTER();
+
+ for (i = 0; i < ARRAY_SIZE(eu_country_code_table); i++) {
+ if (!memcmp(country_code, eu_country_code_table[i],
+ COUNTRY_CODE_LEN - 1)) {
+ PRINTM(MIOCTL, "found region code=%d in EU table\n",
+ EU_REGION_CODE);
+ LEAVE();
+ return MTRUE;
+ }
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief This function converts region string to region code
+ *
+ * @param region_code region code
+ *
+ * @return Region string or NULL
+ */
+char *region_code_2_string(t_u8 region_code)
+{
+ t_u8 i;
+
+ ENTER();
+ for (i = 0; i < ARRAY_SIZE(hw_region_code_mapping); i++) {
+ if (hw_region_code_mapping[i].code == region_code) {
+ LEAVE();
+ return hw_region_code_mapping[i].region;
+ }
+ }
+ LEAVE();
+ return NULL;
+}
+
+t_u8 woal_is_valid_alpha2(char *alpha2)
+{
+ if (!alpha2 || strlen(alpha2) < 2)
+ return MFALSE;
+ if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
+ return MTRUE;
+ return MFALSE;
+}
+
+/**
+ * @brief Get second channel offset
+ *
+ * @param chan channel num
+ * @return second channel offset
+ */
+t_u8 woal_get_second_channel_offset(int chan)
+{
+ t_u8 chan2Offset = SEC_CHAN_NONE;
+
+ switch (chan) {
+ case 36:
+ case 44:
+ case 52:
+ case 60:
+ case 100:
+ case 108:
+ case 116:
+ case 124:
+ case 132:
+ case 140:
+ case 149:
+ case 157:
+ chan2Offset = SEC_CHAN_ABOVE;
+ break;
+ case 40:
+ case 48:
+ case 56:
+ case 64:
+ case 104:
+ case 112:
+ case 120:
+ case 128:
+ case 136:
+ case 144:
+ case 153:
+ case 161:
+ chan2Offset = SEC_CHAN_BELOW;
+ break;
+ case 165:
+ /* Special Case: 20Mhz-only Channel */
+ chan2Offset = SEC_CHAN_NONE;
+ break;
+ }
+ return chan2Offset;
+}
+
+/**
+ * @brief Copy mc address to the mlist
+ *
+ * @param mlist A pointer to mlan_multicast_list structure
+ * @param mac mc address
+ *
+ * @return N/A
+ */
+static inline void woal_copy_mc_addr(mlan_multicast_list *mlist,
+ mlan_802_11_mac_addr mac)
+{
+ int i = 0;
+ for (i = 0; i < mlist->num_multicast_addr; i++) {
+ if (!memcmp(&mlist->mac_list[i], mac, ETH_ALEN))
+ return;
+ }
+ if (mlist->num_multicast_addr < MLAN_MAX_MULTICAST_LIST_SIZE)
+ moal_memcpy_ext(NULL,
+ &mlist->mac_list[mlist->num_multicast_addr],
+ mac, ETH_ALEN, sizeof(mlan_802_11_mac_addr));
+ mlist->num_multicast_addr++;
+ return;
+}
+
+/**
+ * @brief Copy multicast table
+ *
+ * @param mlist A pointer to mlan_multicast_list structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return Number of multicast addresses
+ */
+static inline int woal_copy_mcast_addr(mlan_multicast_list *mlist,
+ struct net_device *dev)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ struct dev_mc_list *mcptr = dev->mc_list;
+ int i = 0;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+#endif /* < 2.6.35 */
+
+ ENTER();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ for (i = 0; i < dev->mc_count && mcptr; i++) {
+ woal_copy_mc_addr(mlist, mcptr->dmi_addr);
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr (mcptr, dev)
+ woal_copy_mc_addr(mlist, mcptr->addr);
+#endif /* < 2.6.35 */
+ LEAVE();
+ return mlist->num_multicast_addr;
+}
+
+/**
+ * @brief copy mc list from all the active interface
+ *
+ * @param handle A pointer to moal_handle
+ * @param mlist A pointer to multicast list
+ *
+ * @return total_mc_count
+ */
+static int woal_copy_all_mc_list(moal_handle *handle,
+ mlan_multicast_list *mlist)
+{
+ int i;
+ moal_private *priv = NULL;
+#ifdef STA_SUPPORT
+ int mc_count = 0;
+#endif
+ ENTER();
+ for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ mc_count = priv->netdev->mc_count;
+#else
+ mc_count = netdev_mc_count(priv->netdev);
+#endif
+ if (mc_count)
+ woal_copy_mcast_addr(mlist,
+ priv->netdev);
+ }
+ }
+#endif
+ }
+ PRINTM(MIOCTL, "total mc_count=%d\n", mlist->num_multicast_addr);
+ LEAVE();
+ return mlist->num_multicast_addr;
+}
+
+/**
+ * @brief Fill in wait queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait A pointer to wait_queue structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline void woal_fill_wait_queue(moal_private *priv, wait_queue *wait,
+ t_u8 wait_option)
+{
+ ENTER();
+ wait->start_time = jiffies;
+ wait->condition = MFALSE;
+ wait->wait_timeout = MFALSE;
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ init_waitqueue_head(&wait->wait);
+ break;
+ case MOAL_IOCTL_WAIT_TIMEOUT:
+ init_waitqueue_head(&wait->wait);
+ wait->wait_timeout = MTRUE;
+ break;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Wait mlan ioctl complete
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+static inline mlan_status woal_wait_ioctl_complete(moal_private *priv,
+ mlan_ioctl_req *req,
+ t_u8 wait_option)
+{
+ mlan_status status;
+ wait_queue *wait = (wait_queue *)req->reserved_1;
+ unsigned long flags;
+
+ ENTER();
+
+ priv->phandle->ioctl_timeout = MFALSE;
+
+ switch (wait_option) {
+ case MOAL_NO_WAIT:
+ break;
+ case MOAL_IOCTL_WAIT:
+ while (wait_event_interruptible_exclusive(
+ wait->wait, wait->condition) == -ERESTARTSYS &&
+ wait->retry < MAX_RETRY_CNT) {
+ wait->retry++;
+ }
+ break;
+ case MOAL_IOCTL_WAIT_TIMEOUT:
+ wait_event_timeout(wait->wait, wait->condition,
+ MOAL_IOCTL_TIMEOUT);
+ break;
+ }
+ spin_lock_irqsave(&priv->phandle->driver_lock, flags);
+ if (wait->condition == MFALSE) {
+ if (wait_option == MOAL_IOCTL_WAIT_TIMEOUT) {
+ priv->phandle->ioctl_timeout = MTRUE;
+ PRINTM(MMSG,
+ "wlan: IOCTL timeout %p id=0x%x, sub_id=0x%x, wait_option=%d, action=%d\n",
+ req, req->req_id, (*(t_u32 *)req->pbuf),
+ wait_option, (int)req->action);
+ } else {
+ PRINTM(MMSG,
+ "wlan: IOCTL by signal %p id=0x%x, sub_id=0x%x, wait_option=%d, action=%d\n",
+ req, req->req_id, (*(t_u32 *)req->pbuf),
+ wait_option, (int)req->action);
+ }
+ req->reserved_1 = 0;
+ status = MLAN_STATUS_PENDING;
+ } else {
+ status = wait->status;
+ }
+ spin_unlock_irqrestore(&priv->phandle->driver_lock, flags);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief CAC period block cmd handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ *
+ * @return MTRUE/MFALSE
+ */
+static inline t_bool woal_cac_period_block_cmd(moal_private *priv,
+ pmlan_ioctl_req req)
+{
+ mlan_status ret = MFALSE;
+ t_u32 sub_command;
+
+ ENTER();
+ if (req == NULL || req->pbuf == NULL)
+ goto done;
+
+ sub_command = *(t_u32 *)req->pbuf;
+
+ switch (req->req_id) {
+ case MLAN_IOCTL_SCAN:
+ if (sub_command == MLAN_OID_SCAN_NORMAL ||
+ sub_command == MLAN_OID_SCAN_SPECIFIC_SSID ||
+ sub_command == MLAN_OID_SCAN_USER_CONFIG)
+ ret = MTRUE;
+ break;
+ case MLAN_IOCTL_BSS:
+ if (sub_command == MLAN_OID_BSS_STOP ||
+ sub_command == MLAN_OID_BSS_CHANNEL
+ /* sub_command == MLAN_OID_BSS_ROLE */)
+ ret = MTRUE;
+#ifdef UAP_SUPPORT
+ else if (sub_command == MLAN_OID_UAP_BSS_CONFIG) {
+ mlan_ds_bss *bss = (mlan_ds_bss *)req->pbuf;
+ if (bss->param.bss_config.channel)
+ ret = MTRUE;
+ else
+ ret = MFALSE;
+ }
+#endif
+ break;
+ case MLAN_IOCTL_RADIO_CFG:
+ if (sub_command == MLAN_OID_BAND_CFG ||
+ sub_command == MLAN_OID_REMAIN_CHAN_CFG)
+ ret = MTRUE;
+ break;
+ case MLAN_IOCTL_SNMP_MIB:
+ if (sub_command == MLAN_OID_SNMP_MIB_DOT11D)
+ ret = MTRUE;
+#if defined(UAP_SUPPORT)
+ if (sub_command == MLAN_OID_SNMP_MIB_DOT11H)
+ ret = MTRUE;
+#endif
+ break;
+ case MLAN_IOCTL_11D_CFG:
+#ifdef STA_SUPPORT
+ if (sub_command == MLAN_OID_11D_CFG_ENABLE)
+ ret = MTRUE;
+#endif
+#ifdef UAP_SUPPORT
+ if (sub_command == MLAN_OID_11D_DOMAIN_INFO)
+ ret = MTRUE;
+#endif
+ if (sub_command == MLAN_OID_11D_DOMAIN_INFO_EXT)
+ ret = MTRUE;
+ break;
+ case MLAN_IOCTL_MISC_CFG:
+ if (sub_command == MLAN_OID_MISC_REGION)
+ ret = MTRUE;
+ if (sub_command == MLAN_OID_MISC_HOST_CMD) {
+ phostcmd_header phostcmd;
+ t_u8 *ptlv_buf;
+ t_u16 tag, length;
+
+ phostcmd =
+ (phostcmd_header)((pmlan_ds_misc_cfg)req->pbuf)
+ ->param.hostcmd.cmd;
+ ptlv_buf = (t_u8 *)phostcmd + sizeof(hostcmd_header);
+ if (phostcmd->action == MLAN_ACT_SET) {
+ while (ptlv_buf <
+ (t_u8 *)phostcmd + phostcmd->size) {
+ tag = *(t_u16 *)ptlv_buf;
+ length = *(t_u16 *)(ptlv_buf + 2);
+ /* Check Blocking TLV here, should add
+ * more... */
+ if (tag == MRVL_CHANNELCONFIG_TLV_ID) {
+ ret = MTRUE;
+ break;
+ }
+ ptlv_buf +=
+ (length + MRVL_TLV_HEADER_SIZE);
+ }
+ }
+ }
+ break;
+ case MLAN_IOCTL_11H_CFG:
+ /* Prevent execute more than once */
+ if (sub_command == MLAN_OID_11H_CHANNEL_CHECK)
+ ret = MTRUE;
+ break;
+ default:
+ ret = MFALSE;
+ break;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief Send ioctl request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to mlan_ioctl_req buffer
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING
+ * -- success, otherwise fail
+ */
+mlan_status woal_request_ioctl(moal_private *priv, mlan_ioctl_req *req,
+ t_u8 wait_option)
+{
+ wait_queue *wait = NULL;
+ mlan_status status;
+ unsigned long flags;
+ t_u32 sub_command = 0;
+
+ ENTER();
+
+ if (!priv || !priv->phandle || !priv->phandle->pmlan_adapter || !req) {
+ PRINTM(MINFO,
+ "priv or priv->phandle or priv->phandle->pmlan_adapter or req is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ sub_command = *(t_u32 *)req->pbuf;
+
+ if (sub_command != MLAN_OID_GET_DEBUG_INFO) {
+ if (priv->phandle->surprise_removed == MTRUE ||
+ priv->phandle->driver_status) {
+ PRINTM(MCMND,
+ "IOCTL is not allowed while the device is not present or hang\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (priv->phandle->is_suspended == MTRUE) {
+ PRINTM(MCMND, "IOCTL is not allowed while suspended\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode && sub_command != MLAN_OID_MISC_HOST_CMD) {
+ PRINTM(MCMND, "IOCTL is not allowed while suspended\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif
+ }
+ /* For MLAN_OID_MISC_HOST_CMD, action is 0, "action set" is checked
+ * later */
+ if ((req->action == MLAN_ACT_SET || req->action == 0) &&
+ priv->phandle->cac_period == MTRUE) {
+ /* CAC checking period left to complete jiffies */
+ long cac_left_jiffies;
+
+ /* cac_left_jiffies will be negative if and only if
+ * event MLAN_EVENT_ID_DRV_MEAS_REPORT recieved from FW
+ * after CAC measure period ends,
+ * usually this could be considered as a FW bug
+ */
+ cac_left_jiffies =
+ priv->phandle->cac_timer_jiffies -
+ (jiffies - priv->phandle->meas_start_jiffies);
+ if (priv->phandle->cac_period_jiffies) {
+ cac_left_jiffies =
+ priv->phandle->cac_period_jiffies -
+ (jiffies - priv->phandle->meas_start_jiffies);
+ }
+ if (priv->phandle->cac_restart)
+ cac_left_jiffies = DEF_CAC_DWELL_TIME * HZ / 1000;
+ if (cac_left_jiffies < 0) {
+ /* Avoid driver hang in FW died during CAC measure
+ * period */
+ priv->phandle->cac_period = MFALSE;
+ PRINTM(MERROR,
+ "CAC measure period spends longer than scheduled time "
+ "or meas done event never received\n");
+ status = MLAN_STATUS_FAILURE;
+#ifdef UAP_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (priv->uap_host_based &&
+ moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cfg80211_dfs_vendor_event(
+ priv, event_dfs_cac_aborted,
+ &priv->chan);
+#endif
+#endif
+#endif
+
+ goto done;
+ }
+
+ /* Check BSS START first */
+ if (sub_command == MLAN_OID_BSS_START) {
+ mlan_ds_bss *bss;
+ bss = (mlan_ds_bss *)req->pbuf;
+ /*
+ * Bss delay start after channel report received,
+ * not block the driver by delay executing. This is
+ * because a BSS_START cmd is always executed right
+ * after channel check issued.
+ */
+ if (priv->phandle->delay_bss_start == MFALSE) {
+ PRINTM(MMSG,
+ "Received BSS Start command during CAC period, delay executing %ld seconds\n",
+ cac_left_jiffies / HZ);
+ priv->phandle->delay_bss_start = MTRUE;
+ moal_memcpy_ext(
+ priv->phandle,
+ &priv->phandle->delay_ssid_bssid,
+ &bss->param.ssid_bssid,
+ sizeof(mlan_ssid_bssid),
+ sizeof(mlan_ssid_bssid));
+ /* TODO: return success to allow the half below
+ * of routines of which calling BSS start to
+ * execute
+ */
+ status = MLAN_STATUS_SUCCESS;
+ goto done;
+ } else {
+ /* TODO: not blocking it, just return failure */
+ PRINTM(MMSG,
+ "Only one BSS Start command allowed for delay executing!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (woal_cac_period_block_cmd(priv, req)) {
+ priv->phandle->meas_wait_q_woken = MFALSE;
+ PRINTM(MMSG,
+ "CAC check is on going... Blocking Command %ld seconds\n",
+ cac_left_jiffies / HZ);
+ /* blocking timeout set to 1.5 * CAC checking period
+ * left time */
+ wait_event_interruptible_timeout(
+ priv->phandle->meas_wait_q,
+ priv->phandle->meas_wait_q_woken,
+ cac_left_jiffies * 3 / 2);
+ }
+ }
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ else if (priv->phandle->is_cac_timer_set &&
+ (req->action == MLAN_ACT_SET || req->action == 0)) {
+ if (woal_cac_period_block_cmd(priv, req)) {
+ PRINTM(MMSG,
+ "CAC check is on going... Blocking Command\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#endif
+#endif
+ else if (priv->phandle->cac_period) {
+ PRINTM(MINFO, "Operation during CAC check period.\n");
+ }
+ wait = (wait_queue *)req->reserved_1;
+ req->bss_index = priv->bss_index;
+ if (wait_option)
+ woal_fill_wait_queue(priv, wait, wait_option);
+ else
+ req->reserved_1 = 0;
+
+ /* Call MLAN ioctl handle */
+ atomic_inc(&priv->phandle->ioctl_pending);
+ spin_lock_irqsave(&priv->phandle->ioctl_lock, flags);
+ status = mlan_ioctl(priv->phandle->pmlan_adapter, req);
+ spin_unlock_irqrestore(&priv->phandle->ioctl_lock, flags);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ if (wait_option == MOAL_NO_WAIT)
+ PRINTM(MIOCTL, "IOCTL MOAL_NO_WAIT: %p\n", req);
+ else
+ PRINTM(MIOCTL,
+ "IOCTL pending: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d\n",
+ req, req->req_id, (*(t_u32 *)req->pbuf),
+ wait_option, (int)req->action);
+ /* Status pending, wake up main process */
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+
+ /* Wait for completion */
+ if (wait_option)
+ status = woal_wait_ioctl_complete(priv, req,
+ wait_option);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ case MLAN_STATUS_FAILURE:
+ case MLAN_STATUS_RESOURCE:
+ if (req)
+ PRINTM(MIOCTL,
+ "IOCTL: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d status=%d\n",
+ req, req->req_id, (*(t_u32 *)req->pbuf),
+ wait_option, (int)req->action, status);
+ atomic_dec(&priv->phandle->ioctl_pending);
+ break;
+ default:
+ atomic_dec(&priv->phandle->ioctl_pending);
+ break;
+ }
+
+done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send set MAC address request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING
+ * -- success, otherwise fail
+ */
+mlan_status woal_request_set_mac_address(moal_private *priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
+ moal_memcpy_ext(priv->phandle, &bss->param.mac_addr, priv->current_addr,
+ sizeof(mlan_802_11_mac_addr),
+ sizeof(mlan_802_11_mac_addr));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "set mac address failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ } else {
+ moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr,
+ priv->current_addr, ETH_ALEN, ETH_ALEN);
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send multicast list request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void woal_request_set_multicast_list(moal_private *priv, struct net_device *dev)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+ int mc_count = 0;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ PRINTM(MERROR, "%s:Fail to allocate ioctl req buffer\n",
+ __func__);
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ if (dev->flags & IFF_PROMISC) {
+ bss->param.multicast_list.mode = MLAN_PROMISC_MODE;
+ } else if (dev->flags & IFF_ALLMULTI) {
+ bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE;
+ } else {
+ bss->param.multicast_list.mode = MLAN_MULTICAST_MODE;
+ mc_count = woal_copy_all_mc_list(priv->phandle,
+ &bss->param.multicast_list);
+ if (mc_count > MLAN_MAX_MULTICAST_LIST_SIZE)
+ bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_NO_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Send deauth command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param mac MAC address to deauthenticate
+ * @param reason code reason code to deauthenticate
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_disconnect(moal_private *priv, t_u8 wait_option, t_u8 *mac,
+ t_u16 reason_code)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ if (mac)
+ moal_memcpy_ext(priv->phandle,
+ &bss->param.deauth_param.mac_addr, mac,
+ sizeof(mlan_802_11_mac_addr),
+ sizeof(bss->param.deauth_param.mac_addr));
+ bss->param.deauth_param.reason_code = reason_code;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+#ifdef REASSOCIATION
+ priv->reassoc_required = MFALSE;
+#endif /* REASSOCIATION */
+ LEAVE();
+ return status;
+}
+
+#if defined(UAP_SUPPORT)
+/**
+ * @brief Get non-global oper class
+ *
+ * @param priv Pointer to moal_private structure
+ * @param bw bandwidth
+ * @param channel channel
+ * @param oper_class pointer to oper_class
+
+ * @return non-global operclass
+ */
+int woal_priv_get_nonglobal_operclass_by_bw_channel(moal_private *priv,
+ t_u8 bandwidth,
+ t_u8 channel,
+ t_u8 *oper_class)
+{
+ int ret = 0;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_OPER_CLASS;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_GET;
+ misc->param.bw_chan_oper.bandwidth = bandwidth;
+ misc->param.bw_chan_oper.channel = channel;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *oper_class = misc->param.bw_chan_oper.oper_class;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Send bss_start command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A point to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_bss_start(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Stop the O.S. TX queue When we are roaming */
+ woal_stop_queue(priv->netdev);
+ if (priv->media_connected == MFALSE) {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_START;
+ if (ssid_bssid)
+ moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid,
+ ssid_bssid, sizeof(mlan_ssid_bssid),
+ sizeof(mlan_ssid_bssid));
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (ssid_bssid)
+ moal_memcpy_ext(priv->phandle, ssid_bssid,
+ &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid),
+ sizeof(mlan_ssid_bssid));
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ priv->assoc_status = req->status_code;
+#endif
+#endif
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get BSS info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param bss_info A pointer to mlan_bss_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_bss_info(moal_private *priv, t_u8 wait_option,
+ mlan_bss_info *bss_info)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ PRINTM(MERROR,
+ "Fail to allocate the buffer for get bss_info\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_BSS_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (bss_info)
+ moal_memcpy_ext(priv->phandle, bss_info,
+ &info->param.bss_info,
+ sizeof(mlan_bss_info),
+ sizeof(mlan_bss_info));
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get generic IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param ie Information element
+ * @param ie_len Length of the IE
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_get_gen_ie(moal_private *priv, t_u32 action, t_u8 *ie,
+ int *ie_len, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ if ((action == MLAN_ACT_GET) && (ie == NULL || ie_len == NULL)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_SET && *ie_len > MAX_IE_SIZE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+
+ if (action == MLAN_ACT_SET) {
+ misc->param.gen_ie.len = *ie_len;
+ if (*ie_len)
+ moal_memcpy_ext(priv->phandle,
+ misc->param.gen_ie.ie_data, ie, *ie_len,
+ MAX_IE_SIZE);
+ }
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (action == MLAN_ACT_GET) {
+ *ie_len = misc->param.gen_ie.len;
+ if (*ie_len)
+ moal_memcpy_ext(priv->phandle, ie,
+ misc->param.gen_ie.ie_data, *ie_len,
+ *ie_len);
+ }
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Set/Get retry count
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Retry value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_get_retry(moal_private *priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *)req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_TX_RETRY_MIN || *value > MLAN_TX_RETRY_MAX) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.retry_count = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *value = mib->param.retry_count;
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig,
+ * wiphy retry count should be updated as well */
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext) &&
+ priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (action == MLAN_ACT_SET)) {
+ priv->wdev->wiphy->retry_long = (t_u8)*value;
+ priv->wdev->wiphy->retry_short = (t_u8)*value;
+ }
+#endif
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Performs pre-warm-reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0 if successful else negative value
+ */
+int woal_pre_warmreset(moal_private *priv)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int intf_num;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ t_u8 bss_role = MLAN_BSS_ROLE_STA;
+#endif
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+
+ ENTER();
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+ if (IS_USB(handle->card_type) && handle->is_suspended &&
+ woal_exit_usb_suspend(handle)) {
+ PRINTM(MERROR, "Failed to resume the suspended device\n");
+ LEAVE();
+ return -EFAULT;
+ }
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+ woal_cancel_cac_block(priv);
+ /* Reset all interfaces */
+ ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
+ /* Initialize private structures */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if ((handle->priv[intf_num]->bss_type ==
+ MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (GET_BSS_ROLE(handle->priv[intf_num]) ==
+ MLAN_BSS_ROLE_UAP)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(handle->priv[intf_num],
+ MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT */
+ }
+ woal_shutdown_fw(priv, MOAL_IOCTL_WAIT);
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+done:
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT */
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0 success, otherwise failure
+ */
+int woal_warmreset(moal_private *priv)
+{
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+ int intf_num;
+
+ /* Restart the firmware */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_WARM_RESET;
+ misc->param.fw_reload = MTRUE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "warm reset failure!\n");
+ ret = -EFAULT;
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ goto done;
+ }
+ kfree(req);
+ }
+#ifdef USB
+ if (IS_USB(handle->card_type) && handle->params.usb_aggr == 1) {
+ /* Enable USB aggregation in FW */
+ if (woal_usb_aggr_init(handle)) {
+ PRINTM(MERROR, "usb aggr init fail\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+#endif
+
+ if (moal_extflg_isset(handle, EXT_AGGR_CTRL)) {
+ /* Enable aggregation in FW */
+ if (woal_init_aggr_ctrl(handle, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Fail to init aggr ctrl\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Enable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_device_attach(handle->priv[intf_num]->netdev);
+ woal_start_queue(handle->priv[intf_num]->netdev);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RTS threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value RTS threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_get_rts(moal_private *priv, t_u32 action, t_u8 wait_option,
+ int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *)req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_RTS_MIN_VALUE ||
+ *value > MLAN_RTS_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.rts_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *value = mib->param.rts_threshold;
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig,
+ * wiphy RTS threshold should be updated as well */
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext) &&
+ priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->rts_threshold = *value;
+#endif
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Fragment threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value Fragment threshold value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_get_frag(moal_private *priv, t_u32 action,
+ t_u8 wait_option, int *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *)req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ if (*value < MLAN_FRAG_MIN_VALUE ||
+ *value > MLAN_FRAG_MAX_VALUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ mib->param.frag_threshold = *value;
+ }
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *value = mib->param.frag_threshold;
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig,
+ * wiphy fragment threshold should be updated as well */
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext) &&
+ priv->wdev && priv->wdev->wiphy &&
+ (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (action == MLAN_ACT_SET))
+ priv->wdev->wiphy->frag_threshold = *value;
+#endif
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param power_cfg A pinter to mlan_power_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_get_tx_power(moal_private *priv, t_u32 action,
+ mlan_power_cfg_t *power_cfg)
+{
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *)req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET && power_cfg)
+ moal_memcpy_ext(priv->phandle, &pcfg->param.power_cfg,
+ power_cfg, sizeof(mlan_power_cfg_t),
+ sizeof(mlan_power_cfg_t));
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (ret == MLAN_STATUS_SUCCESS && power_cfg)
+ moal_memcpy_ext(priv->phandle, power_cfg,
+ &pcfg->param.power_cfg,
+ sizeof(mlan_power_cfg_t),
+ sizeof(mlan_power_cfg_t));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get IEEE power management
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param disabled A pointer to disabled flag
+ * @param power_type IEEE power type
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_get_power_mgmt(moal_private *priv, t_u32 action,
+ int *disabled, int power_type,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ PRINTM(MINFO, "PS_MODE set power disabled=%d power type=%#x\n",
+ *disabled, power_type);
+ if (*disabled)
+ pm_cfg->param.ps_mode = 0;
+ else {
+ /* Check not support case only (vwrq->disabled == FALSE)
+ */
+ if ((power_type & MW_POWER_TYPE) == MW_POWER_TIMEOUT) {
+ PRINTM(MERROR,
+ "Setting power timeout is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else if ((power_type & MW_POWER_TYPE) ==
+ MW_POWER_PERIOD) {
+ PRINTM(MERROR,
+ "Setting power period is not supported\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg->param.ps_mode = 1;
+ }
+ }
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *disabled = pm_cfg->param.ps_mode;
+
+#ifdef STA_CFG80211
+ /* If set is invoked from other than iw i.e iwconfig,
+ * wiphy IEEE power save mode should be updated */
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext) &&
+ priv->wdev && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (action == MLAN_ACT_SET)) {
+ if (*disabled)
+ priv->wdev->ps = MFALSE;
+ else
+ priv->wdev->ps = MTRUE;
+ }
+#endif
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Country Code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param region A pointer to region string
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
+ * fail
+ */
+int woal_set_countrycode(moal_private *priv, char *country)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_ds_misc_country_code *country_code = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ country_code = &pcfg_misc->param.country_code;
+ pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
+ moal_memcpy_ext(priv->phandle, country_code->country_code, country,
+ COUNTRY_CODE_LEN - 1, COUNTRY_CODE_LEN - 1);
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param region A pointer to region string
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
+ * fail
+ */
+mlan_status woal_set_region_code(moal_private *priv, char *region)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+ if (woal_is_country_code_supported(region))
+ return woal_set_countrycode(priv, region);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region_string_2_region_code(region);
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param datarate A pointer to mlan_rate_cfg_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_get_data_rate(moal_private *priv, t_u8 action,
+ mlan_rate_cfg_t *datarate)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = action;
+
+ if (datarate && (action == MLAN_ACT_SET))
+ moal_memcpy_ext(priv->phandle, &rate->param.rate_cfg, datarate,
+ sizeof(mlan_rate_cfg_t),
+ sizeof(mlan_rate_cfg_t));
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS && datarate && action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, datarate, &rate->param.rate_cfg,
+ sizeof(mlan_rate_cfg_t),
+ sizeof(mlan_rate_cfg_t));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get assoc_resp buffer
+ *
+ * @param priv A pointer to moal_private structure
+ * @param assoc_rsp A pointer to mlan_ds_misc_assoc_rsp structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_get_assoc_rsp(moal_private *priv,
+ mlan_ds_misc_assoc_rsp *assoc_rsp,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Fail to allocate buffer for get assoc resp\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc = (pmlan_ds_misc_cfg)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_ASSOC_RSP;
+ req->action = MLAN_ACT_GET;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && assoc_rsp)
+ moal_memcpy_ext(priv->phandle, assoc_rsp,
+ &misc->param.assoc_resp,
+ sizeof(mlan_ds_misc_assoc_rsp),
+ sizeof(mlan_ds_misc_assoc_rsp));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Send get FW info request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param fw_info FW information
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_request_get_fw_info(moal_private *priv, t_u8 wait_option,
+ mlan_fw_info *fw_info)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info;
+ mlan_status status;
+ ENTER();
+ memset(priv->current_addr, 0xff, ETH_ALEN);
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ info->sub_command = MLAN_OID_GET_FW_INFO;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->fw_release_number = info->param.fw_info.fw_ver;
+ priv->phandle->fw_ecsa_enable = info->param.fw_info.ecsa_enable;
+ priv->phandle->fw_getlog_enable =
+ info->param.fw_info.getlog_enable;
+ if (priv->current_addr[0] == 0xff)
+ moal_memcpy_ext(priv->phandle, priv->current_addr,
+ &info->param.fw_info.mac_addr,
+ sizeof(mlan_802_11_mac_addr), ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr,
+ priv->current_addr, ETH_ALEN, ETH_ALEN);
+ if (fw_info)
+ moal_memcpy_ext(priv->phandle, fw_info,
+ &info->param.fw_info,
+ sizeof(mlan_fw_info),
+ sizeof(mlan_fw_info));
+ DBG_HEXDUMP(MCMD_D, "mac", priv->current_addr, 6);
+ } else
+ PRINTM(MERROR,
+ "get fw info failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get current channel of active interface
+ *
+ * @param priv A pointer to moal_private
+ * @param channel A pointer to chan_band_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_get_active_intf_channel(moal_private *priv,
+ chan_band_info *channel)
+{
+ moal_handle *handle = priv->phandle;
+ int i;
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE)
+ return woal_get_sta_channel(handle->priv[i],
+ MOAL_IOCTL_WAIT,
+ channel);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
+ if (handle->priv[i]->bss_started == MTRUE)
+ return woal_set_get_ap_channel(handle->priv[i],
+ MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ channel);
+ }
+#endif
+ }
+ return MLAN_STATUS_FAILURE;
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Send get ext cap info request to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf data buffer
+ * @param len data buffer length
+ *
+ * @return number of bytes of extended capability -- success,
+ * otherwise error
+ */
+int woal_request_extcap(moal_private *priv, t_u8 *buf, t_u8 len)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (buf == NULL || len <= 0 || len < sizeof(ExtCap_t)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto out;
+ }
+ memset(buf, 0, len);
+ moal_memcpy_ext(priv->phandle, buf, &cfg->param.ext_cap,
+ sizeof(ExtCap_t), len);
+ ret = sizeof(ExtCap_t);
+out:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get debug info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param debug_info A pointer to mlan_debug_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_debug_info(moal_private *priv, t_u8 wait_option,
+ mlan_debug_info *debug_info)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_get_info *info = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) +
+ sizeof(mlan_debug_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_DEBUG_INFO;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (debug_info) {
+ moal_memcpy_ext(priv->phandle, debug_info,
+ &info->param.debug_info,
+ sizeof(mlan_debug_info),
+ sizeof(mlan_debug_info));
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+int woal_host_command(moal_private *priv, struct iwreq *wrq)
+{
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (wrq->u.data.pointer == NULL) {
+ PRINTM(MERROR, "hostcmd IOCTL corrupt data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user(&cmd_header, wrq->u.data.pointer,
+ sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "copy from user failed: Host command header\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ PRINTM(MINFO, "Host command len = %u\n", misc->param.hostcmd.len);
+
+ if (!misc->param.hostcmd.len ||
+ misc->param.hostcmd.len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ PRINTM(MERROR, "Invalid data buffer length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* get the whole command from user */
+ if (copy_from_user(misc->param.hostcmd.cmd, wrq->u.data.pointer,
+ woal_le16_to_cpu(cmd_header.size))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user(wrq->u.data.pointer, (t_u8 *)misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = misc->param.hostcmd.len;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/**
+ * @brief host command ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+/********* format of ifr_data *************/
+/* buf_len + Hostcmd_body */
+/* buf_len: 4 bytes */
+/* the length of the buf which */
+/* can be used to return data */
+/* to application */
+/* Hostcmd_body */
+/*******************************************/
+int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u32 buf_len = 0;
+ HostCmd_Header cmd_header;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hostcmd_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&cmd_header, 0, sizeof(cmd_header));
+
+ /* get command header */
+ if (copy_from_user(&cmd_header, req->ifr_data + sizeof(buf_len),
+ sizeof(HostCmd_Header))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MINFO, "Host command len = %d\n",
+ woal_le16_to_cpu(cmd_header.size));
+
+ if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+
+ misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
+
+ /* get the whole command from user */
+ if (copy_from_user(misc->param.hostcmd.cmd,
+ req->ifr_data + sizeof(buf_len),
+ misc->param.hostcmd.len)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ misc->sub_command = MLAN_OID_MISC_HOST_CMD;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (misc->param.hostcmd.len > buf_len) {
+ PRINTM(MERROR,
+ "buf_len is too small, resp_len=%d, buf_len=%d\n",
+ (int)misc->param.hostcmd.len, (int)buf_len);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_to_user(req->ifr_data + sizeof(buf_len),
+ (t_u8 *)misc->param.hostcmd.cmd,
+ misc->param.hostcmd.len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief CUSTOM_IE ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *custom_ie = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ gfp_t flag;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_custom_ie_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ custom_ie = kzalloc(sizeof(mlan_ds_misc_custom_ie), flag);
+ if (!custom_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(custom_ie, req->ifr_data,
+ sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ if ((custom_ie->len == 0) ||
+ (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index)))
+ ioctl_req->action = MLAN_ACT_GET;
+ else
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, custom_ie,
+ sizeof(mlan_ds_misc_custom_ie),
+ sizeof(mlan_ds_misc_custom_ie));
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ if (copy_to_user(req->ifr_data, &misc->param.cust_ie,
+ sizeof(mlan_ds_misc_custom_ie))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
+ /* send a separate error code to indicate error from driver */
+ ret = EFAULT;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ kfree(custom_ie);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send raw data packet ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int woal_send_host_packet(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u32 packet_len = 0;
+ int ret = 0;
+ pmlan_buffer pmbuf = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is NULL\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_send_host_packet() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&packet_len, req->ifr_data, sizeof(packet_len))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+#define PACKET_HEADER_LEN 8
+#define MV_ETH_FRAME_LEN 1514
+ if (packet_len > MV_ETH_FRAME_LEN) {
+ PRINTM(MERROR, "Invalid packet length %d\n", packet_len);
+ ret = -EFAULT;
+ goto done;
+ }
+ pmbuf = woal_alloc_mlan_buffer(
+ priv->phandle, (int)(MLAN_MIN_DATA_HEADER_LEN +
+ (int)packet_len + PACKET_HEADER_LEN));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+
+ /* get whole packet and header */
+ if (copy_from_user(pmbuf->pbuf + pmbuf->data_offset,
+ req->ifr_data + sizeof(packet_len),
+ PACKET_HEADER_LEN + packet_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = PACKET_HEADER_LEN + packet_len;
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+#if defined(UAP_WEXT)
+/**
+ * @brief Set/Get CUSTOM_IE ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param mask Mask to set or clear from caller
+ * @param ie IE buffer to set for beacon
+ * @param ie_len Length of the IE
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_get_custom_ie(moal_private *priv, t_u16 mask, t_u8 *ie, int ie_len)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_custom_ie *misc_ie = NULL;
+ int ret = 0;
+ custom_ie *pcust_bcn_ie = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ misc_ie = &misc->param.cust_ie;
+
+ misc_ie->type = TLV_TYPE_MGMT_IE;
+ misc_ie->len = (sizeof(custom_ie) - MAX_IE_SIZE) + ie_len;
+ pcust_bcn_ie = misc_ie->ie_data_list;
+ pcust_bcn_ie->ie_index = 0xffff;
+ pcust_bcn_ie->mgmt_subtype_mask = mask;
+ pcust_bcn_ie->ie_length = ie_len;
+ moal_memcpy_ext(priv->phandle, pcust_bcn_ie->ie_buffer, ie, ie_len,
+ MAX_IE_SIZE);
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */
+
+/**
+ * @brief ioctl function get BSS type
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+int woal_get_bss_type(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int bss_type;
+
+ ENTER();
+
+ bss_type = (int)priv->bss_type;
+ if (copy_to_user(req->ifr_data, &bss_type, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/**
+ * @brief Swithces BSS role of interface
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param bss_role A pointer to bss role
+ *
+ * @return 0 --success, otherwise fail
+ */
+mlan_status woal_bss_role_cfg(moal_private *priv, t_u8 action, t_u8 wait_option,
+ t_u8 *bss_role)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ struct net_device *dev = priv->netdev;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_ROLE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+ if (action == MLAN_ACT_SET) {
+ if (priv->bss_role == *bss_role) {
+ PRINTM(MWARN, "BSS is in desired role already\n");
+ goto done;
+ } else {
+ bss->param.bss_role = *bss_role;
+ }
+ }
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ *bss_role = bss->param.bss_role;
+ } else {
+ /* Update moal_private */
+ priv->bss_role = *bss_role;
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_type = MLAN_BSS_TYPE_STA;
+ else if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_type = MLAN_BSS_TYPE_UAP;
+
+ if (*bss_role == MLAN_BSS_ROLE_UAP) {
+ /* Switch: STA -> uAP */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(priv->phandle->params.cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats =
+ woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def
+ *)&woal_uap_handler_def;
+ }
+#endif /* UAP_WEXT */
+ } else if (*bss_role == MLAN_BSS_ROLE_STA) {
+ /* Switch: uAP -> STA */
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats =
+ woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def
+ *)&woal_handler_def;
+ }
+#endif /* STA_WEXT */
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Set/Get BSS role
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_get_bss_role(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int bss_role = 0;
+ t_u8 action = MLAN_ACT_GET;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bss_role, wrq->u.data.pointer,
+ sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bss_role != MLAN_BSS_ROLE_STA &&
+ bss_role != MLAN_BSS_ROLE_UAP)
+#ifdef WIFI_DIRECT_SUPPORT
+ || (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)
+#endif
+ ) {
+ PRINTM(MWARN, "Invalid BSS role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (bss_role == GET_BSS_ROLE(priv)) {
+ PRINTM(MWARN, "Already BSS is in desired role\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ action = MLAN_ACT_SET;
+ /* Reset interface */
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv, action,
+ MOAL_IOCTL_WAIT,
+ (t_u8 *)&bss_role)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext))
+ woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
+#endif
+ /* Initialize private structures */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+ /* Enable interfaces */
+ netif_device_attach(priv->netdev);
+ woal_start_queue(priv->netdev);
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+
+/**
+ * @brief Set/Get DTIM period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param wait_option Wait option
+ * @param value DTIM period
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_get_dtim_period(moal_private *priv, t_u32 action,
+ t_u8 wait_option, t_u8 *value)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *mib = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mib = (mlan_ds_snmp_mib *)req->pbuf;
+ mib->sub_command = MLAN_OID_SNMP_MIB_DTIM_PERIOD;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET)
+ mib->param.dtim_period = *value;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET)
+ *value = (t_u8)mib->param.dtim_period;
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param hscfg A pointer to mlan_ds_hs_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_set_get_hs_params(moal_private *priv, t_u16 action,
+ t_u8 wait_option, mlan_ds_hs_cfg *hscfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &pmcfg->param.hs_cfg, hscfg,
+ sizeof(mlan_ds_hs_cfg), sizeof(mlan_ds_hs_cfg));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (hscfg && action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, hscfg,
+ &pmcfg->param.hs_cfg,
+ sizeof(mlan_ds_hs_cfg),
+ sizeof(mlan_ds_hs_cfg));
+ }
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wakeup reason
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wakeup_reason A pointer to mlan_ds_hs_wakeup_reason structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_wakeup_reason(moal_private *priv,
+ mlan_ds_hs_wakeup_reason *wakeup_reason)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ wakeup_reason->hs_wakeup_reason =
+ pmcfg->param.wakeup_reason.hs_wakeup_reason;
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set or Get wowlan config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: action to config wowlan
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param mefcfg A pointer to mlan_ds_misc_mef_flt_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_get_wowlan_config(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ mlan_ds_misc_mef_flt_cfg *mefcfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_cfg *misccfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /** Allocate an IOCTL request buffer*/
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ /** Fill request buffer */
+ misccfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misccfg->sub_command = MLAN_OID_MISC_MEF_FLT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ moal_memcpy_ext(priv->phandle, &misccfg->param.mef_flt_cfg, mefcfg,
+ sizeof(mlan_ds_misc_mef_flt_cfg),
+ sizeof(mlan_ds_misc_mef_flt_cfg));
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (mefcfg && action == MLAN_ACT_GET) {
+ moal_memcpy_ext(priv->phandle, mefcfg,
+ &misccfg->param.mef_flt_cfg,
+ sizeof(mlan_ds_misc_mef_flt_cfg),
+ sizeof(mlan_ds_misc_mef_flt_cfg));
+ }
+ }
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING)
+ PRINTM(MIOCTL, "Set Get wowlan IOCTL failed!\n");
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING,
+ * or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_cancel_hs(moal_private *priv, t_u8 wait_option)
+{
+ moal_handle *handle = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_hs_cfg hscfg;
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ int i;
+#endif
+#endif
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle = priv->phandle;
+ /* Cancel Host Sleep */
+
+ hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.is_invoke_hostcmd = MTRUE;
+ ret = woal_set_get_hs_params(priv, MLAN_ACT_SET, wait_option, &hscfg);
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ if (GTK_REKEY_OFFLOAD_SUSPEND == handle->params.gtk_rekey_offload) {
+ PRINTM(MIOCTL,
+ "Cancel Host Sleep... clear gtk rekey offload of FW\n");
+ for (i = 0; i < handle->priv_num; i++) {
+ if (handle->priv[i] &&
+ handle->priv[i]->gtk_data_ready) {
+ PRINTM(MCMND, "clear GTK in resume\n");
+ woal_set_rekey_data(handle->priv[i], NULL,
+ MLAN_ACT_CLEAR,
+ wait_option);
+ }
+ }
+ }
+#endif
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function enables the host sleep
+ *
+ * @param priv A Pointer to the moal_private structure
+ * @return MTRUE or MFALSE
+ */
+int woal_enable_hs(moal_private *priv)
+{
+ mlan_ds_hs_cfg hscfg;
+ moal_handle *handle = NULL;
+ int hs_actived = MFALSE;
+ int timeout = 0;
+ int i;
+#ifdef SDIO_SUSPEND_RESUME
+ mlan_ds_ps_info pm_info;
+#endif
+ pmlan_ds_misc_keep_alive keep_alive = NULL;
+
+ ENTER();
+
+ if (priv == NULL) {
+ PRINTM(MERROR, "Invalid priv\n");
+ goto done;
+ }
+ handle = priv->phandle;
+ if (handle->hs_activated == MTRUE) {
+ PRINTM(MIOCTL, "HS Already actived\n");
+ hs_actived = MTRUE;
+ goto done;
+ }
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (moal_extflg_isset(handle,
+ EXT_DISCONNECT_ON_SUSPEND) &&
+ handle->priv[i]->media_connected == MTRUE) {
+ PRINTM(MIOCTL, "disconnect on suspend\n");
+ woal_disconnect(handle->priv[i], MOAL_NO_WAIT,
+ NULL, DEF_DEAUTH_REASON_CODE);
+ }
+ }
+ if (handle->priv[i]) {
+ PRINTM(MIOCTL, "woal_delba_all on priv[%d]\n", i);
+ woal_delba_all(handle->priv[i], MOAL_NO_WAIT);
+ }
+ }
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ if (priv->phandle->is_remain_timer_set) {
+ woal_cancel_timer(&priv->phandle->remain_timer);
+ woal_remain_timer_func(priv->phandle);
+ }
+ /* cancel pending remain on channel */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ moal_private *remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (remain_priv) {
+ woal_cfg80211_remain_on_channel_cfg(remain_priv,
+ MOAL_NO_WAIT, MTRUE,
+ &channel_status,
+ NULL, 0, 0);
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+#endif
+#endif
+
+#ifdef STA_SUPPORT
+ woal_reconfig_bgscan(priv->phandle);
+#endif
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ if (GTK_REKEY_OFFLOAD_SUSPEND == handle->params.gtk_rekey_offload) {
+ PRINTM(MIOCTL,
+ "Host Sleep enabled... set gtk rekey offload to FW\n");
+ for (i = 0; i < handle->priv_num; i++) {
+ if (handle->priv[i] &&
+ handle->priv[i]->gtk_data_ready) {
+ PRINTM(MCMND, "set GTK before suspend\n");
+ woal_set_rekey_data(
+ handle->priv[i],
+ &handle->priv[i]->gtk_rekey_data,
+ MLAN_ACT_SET, MOAL_NO_WAIT);
+ }
+ }
+ }
+#endif
+#endif
+
+ for (i = 0; i < MAX_KEEP_ALIVE_ID; i++) {
+ keep_alive = &handle->keep_alive[i];
+ if (keep_alive && keep_alive->cached && keep_alive->enable) {
+ keep_alive->cached = false;
+ woal_start_mkeep_alive(
+ woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ keep_alive->mkeep_alive_id, keep_alive->packet,
+ keep_alive->pkt_len, keep_alive->src_mac,
+ keep_alive->dst_mac, keep_alive->send_interval,
+ keep_alive->retry_interval,
+ keep_alive->retry_count);
+ keep_alive->pkt_len = 0;
+ memset(keep_alive->packet, 0, MKEEP_ALIVE_IP_PKT_MAX);
+ }
+ }
+ /* Enable Host Sleep */
+ handle->hs_activate_wait_q_woken = MFALSE;
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ hscfg.is_invoke_hostcmd = MTRUE;
+ if (woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_NO_WAIT, &hscfg) ==
+ MLAN_STATUS_FAILURE) {
+ PRINTM(MIOCTL, "IOCTL request HS enable failed\n");
+ goto done;
+ }
+ timeout = wait_event_timeout(handle->hs_activate_wait_q,
+ handle->hs_activate_wait_q_woken,
+ HS_ACTIVE_TIMEOUT);
+#ifdef SDIO_MMC
+ if (IS_SD(handle->card_type)) {
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ }
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+ memset(&pm_info, 0, sizeof(mlan_ds_ps_info));
+#endif
+ if ((handle->hs_activated == MTRUE) ||
+ (handle->is_suspended == MTRUE)) {
+ PRINTM(MCMND, "suspend success! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+#ifdef SDIO_SUSPEND_RESUME
+ else if (IS_SD(handle->card_type)) {
+ handle->suspend_fail = MTRUE;
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ handle->hs_force_count++;
+ PRINTM(MCMND, "suspend allowed! force=%u skip=%u\n",
+ handle->hs_force_count, handle->hs_skip_count);
+ hs_actived = MTRUE;
+ }
+ }
+#endif /* SDIO_SUSPEND_RESUME*/
+#ifdef SDIO_MMC
+ if (IS_SD(handle->card_type)) {
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ }
+#endif
+ if (hs_actived != MTRUE) {
+ handle->hs_skip_count++;
+#ifdef SDIO_SUSPEND_RESUME
+ if (IS_SD(handle->card_type)) {
+ PRINTM(MCMND,
+ "suspend skipped! timeout=%d allow=%d force=%u skip=%u\n",
+ timeout, (int)pm_info.is_suspend_allowed,
+ handle->hs_force_count, handle->hs_skip_count);
+ }
+#else
+ PRINTM(MCMND, "suspend skipped! timeout=%d skip=%u\n", timeout,
+ handle->hs_skip_count);
+#endif
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+ }
+done:
+ LEAVE();
+ return hs_actived;
+}
+
+#ifdef CONFIG_PROC_FS
+/**
+ * @brief This function send soft_reset command to firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success,
+ * otherwise failure code
+ */
+mlan_status woal_request_soft_reset(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_SOFT_RESET;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ ret = woal_request_ioctl(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ req, MOAL_IOCTL_WAIT);
+ }
+
+ handle->surprise_removed = MTRUE;
+ woal_sched_timeout(5);
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* CONFIG_PROC_FS */
+
+/**
+ * @brief Set wapi enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_wapi_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WAPI_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wapi_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void woal_get_version(moal_handle *handle, char *version, int max_len)
+{
+ union {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+ char fw_ver[32];
+
+ ENTER();
+
+ ver.l = handle->fw_release_number;
+ snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u", ver.c[2], ver.c[1],
+ ver.c[0], ver.c[3]);
+
+ snprintf(version, max_len, handle->driver_version, fw_ver);
+
+ LEAVE();
+}
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/**
+ * @brief Get Driver Version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_get_driver_version(moal_private *priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ int len;
+ char buf[MLAN_MAX_VER_STR_LEN];
+ ENTER();
+
+ woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
+
+ len = strlen(buf);
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ wrq->u.data.length = len;
+ }
+ PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get extended driver version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ireq A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_get_driver_verext(moal_private *priv, struct ifreq *ireq)
+{
+ struct iwreq *wrq = (struct iwreq *)ireq;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ if (!wrq->u.data.flags) {
+ info->param.ver_ext.version_str_sel =
+ *((int *)(wrq->u.name + SUBCMD_OFFSET));
+ } else {
+ if (copy_from_user(
+ &info->param.ver_ext.version_str_sel,
+ wrq->u.data.pointer,
+ sizeof(info->param.ver_ext.version_str_sel))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (((t_s32)(info->param.ver_ext.version_str_sel)) <
+ 0) {
+ PRINTM(MERROR, "Invalid arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ info->param.ver_ext.version_str,
+ strlen(info->param.ver_ext.version_str))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = strlen(info->param.ver_ext.version_str);
+ }
+
+ PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
+ info->param.ver_ext.version_str);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Set driver debug bit masks to mlan in order to enhance performance
+ *
+ * @param priv A pointer to moal_private structure
+ * @param drvdbg Driver debug level
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_drvdbg(moal_private *priv, t_u32 drvdbg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DRVDBG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc->param.drvdbg = drvdbg;
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Mgmt frame forward registration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param pmgmt_subtype_mask A Pointer to mgmt frame subtype mask
+ * @param wait_option wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_reg_rx_mgmt_ind(moal_private *priv, t_u16 action,
+ t_u32 *pmgmt_subtype_mask, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ misc->param.mgmt_subtype_mask = *pmgmt_subtype_mask;
+ if (req->action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &misc->param.mgmt_subtype_mask,
+ pmgmt_subtype_mask,
+ sizeof(misc->param.mgmt_subtype_mask),
+ sizeof(misc->param.mgmt_subtype_mask));
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+ if (req->action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, pmgmt_subtype_mask,
+ &misc->param.mgmt_subtype_mask,
+ sizeof(misc->param.mgmt_subtype_mask),
+ sizeof(misc->param.mgmt_subtype_mask));
+
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming capabilities
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param tx_bf_cap A pointer to tx_buf_cap buffer
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_get_tx_bf_cap(moal_private *priv, t_u16 action,
+ t_u32 *tx_bf_cap)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!tx_bf_cap) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ bf_cfg->param.tx_bf_cap = *tx_bf_cap;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET)
+ *tx_bf_cap = bf_cfg->param.tx_bf_cap;
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action: set or get
+ * @param tx_bf_cfg A pointer to tx_bf_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_get_tx_bf_cfg(moal_private *priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg *tx_bf_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+
+ ENTER();
+
+ /* Sanity test */
+ if (tx_bf_cfg == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CFG;
+
+ req->action = action;
+ moal_memcpy_ext(priv->phandle, &bf_cfg->param.tx_bf, tx_bf_cfg,
+ sizeof(mlan_ds_11n_tx_bf_cfg),
+ sizeof(mlan_ds_11n_tx_bf_cfg));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, tx_bf_cfg, &bf_cfg->param.tx_bf,
+ sizeof(mlan_ds_11n_tx_bf_cfg),
+ sizeof(mlan_ds_11n_tx_bf_cfg));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle ioctl resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param req Pointer to mlan_ioctl_req structure
+ *
+ * @return N/A
+ */
+void woal_process_ioctl_resp(moal_private *priv, mlan_ioctl_req *req)
+{
+ int cfg80211_wext;
+
+ ENTER();
+
+ if (priv == NULL) {
+ LEAVE();
+ return;
+ }
+ cfg80211_wext = priv->phandle->params.cfg80211_wext;
+ switch (req->req_id) {
+ case MLAN_IOCTL_GET_INFO:
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_info_resp(priv,
+ (mlan_ds_get_info *)req->pbuf);
+#endif
+#endif
+#ifdef UAP_WEXT
+#ifdef UAP_SUPPORT
+ if (IS_UAP_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ woal_ioctl_get_uap_info_resp(
+ priv, (mlan_ds_get_info *)req->pbuf);
+#endif
+#endif
+ break;
+#ifdef STA_WEXT
+#ifdef STA_SUPPORT
+ case MLAN_IOCTL_BSS:
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ woal_ioctl_get_bss_resp(priv, (mlan_ds_bss *)req->pbuf);
+ break;
+#endif
+#endif
+ case MLAN_IOCTL_MISC_CFG:
+ woal_ioctl_get_misc_conf(priv, (mlan_ds_misc_cfg *)req->pbuf);
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get PM info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pm_info A pointer to mlan_ds_ps_info structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_pm_info(moal_private *priv, mlan_ds_ps_info *pm_info)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Fail to alloc mlan_ds_pm_cfg buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pmcfg->sub_command = MLAN_OID_PM_INFO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (pm_info) {
+ moal_memcpy_ext(priv->phandle, pm_info,
+ &pmcfg->param.ps_info,
+ sizeof(mlan_ds_ps_info),
+ sizeof(mlan_ds_ps_info));
+ }
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param data Pointer to return deep_sleep setting
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_get_deep_sleep(moal_private *priv, t_u32 *data)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *)req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ *data = pm->param.auto_deep_sleep.auto_ds;
+ *(data + 1) = pm->param.auto_deep_sleep.idletime;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Deep Sleep
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ * @param bdeep_sleep TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ * @param idletime Idle time for optimized PS API
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_deep_sleep(moal_private *priv, t_u8 wait_option,
+ BOOLEAN bdeep_sleep, t_u16 idletime)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *)req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ req->action = MLAN_ACT_SET;
+ if (bdeep_sleep == MTRUE) {
+ PRINTM(MIOCTL, "Deep Sleep: sleep\n");
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ if (idletime)
+ pm->param.auto_deep_sleep.idletime = idletime;
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MIOCTL, "%lu : Deep Sleep: wakeup\n", jiffies);
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel CAC period block
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void woal_cancel_cac_block(moal_private *priv)
+{
+ ENTER();
+ /* if during CAC period, wake up wait queue */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ /* Make sure Chan Report is cancelled */
+ woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT);
+ priv->phandle->meas_start_jiffies = 0;
+ if (priv->phandle->delay_bss_start == MTRUE)
+ priv->phandle->delay_bss_start = MFALSE;
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->meas_wait_q);
+ }
+#ifdef UAP_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (priv->uap_host_based &&
+ moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cfg80211_dfs_vendor_event(
+ priv, event_dfs_cac_aborted, &priv->chan);
+#endif
+#endif
+#endif
+ }
+ LEAVE();
+}
+
+/** MEAS report timeout value in seconds */
+
+/**
+ * @brief Issue MLAN_OID_11H_CHANNEL_CHECK ioctl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_11h_channel_check_ioctl(moal_private *priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+#ifdef UAP_SUPPORT
+ if (priv->skip_cac) {
+ LEAVE();
+ return ret;
+ }
+#endif
+
+ /* Skip sending request/report query when DFS_REPEATER_MODE is on. This
+ * would get rid of CAC timers before starting BSSes in
+ * DFS_REPEATER_MODE
+ */
+ if (priv->phandle->dfs_repeater_mode) {
+ LEAVE();
+ return ret;
+ }
+
+ if (woal_is_any_interface_active(priv->phandle)) {
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
+ ds_11hcfg->param.chan_rpt_req.host_based = MFALSE;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+ /* Send Channel Check command and wait until the report is ready */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /* set flag from here */
+ priv->phandle->cac_period = MTRUE;
+ priv->phandle->meas_start_jiffies = jiffies;
+ priv->phandle->cac_timer_jiffies =
+ ds_11hcfg->param.chan_rpt_req.millisec_dwell_time * HZ / 1000;
+
+#ifdef UAP_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (priv->uap_host_based &&
+ moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cfg80211_dfs_vendor_event(priv, event_dfs_cac_started,
+ &priv->chan);
+#endif
+#endif
+#endif
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Issue MLAN_OID_11H_CHAN_REPORT_REQUEST ioctl to cancel dozer
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wait_option wait option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_11h_cancel_chan_report_ioctl(moal_private *priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_REPORT_REQUEST;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+ ds_11hcfg->param.chan_rpt_req.millisec_dwell_time = 0;
+ /* Send Channel Check command and wait until the report is ready */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set remain channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param pchan A pointer to mlan_ds_remain_chan structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_remain_channel_ioctl(moal_private *priv, t_u8 wait_option,
+ mlan_ds_remain_chan *pchan)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_REMAIN_CHAN_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &radio_cfg->param.remain_chan, pchan,
+ sizeof(mlan_ds_remain_chan),
+ sizeof(mlan_ds_remain_chan));
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ moal_memcpy_ext(priv->phandle, pchan,
+ &radio_cfg->param.remain_chan,
+ sizeof(mlan_ds_remain_chan),
+ sizeof(mlan_ds_remain_chan));
+ PRINTM(MCMND,
+ "Remain_chan_cfg: remove=%d, channel=%d, remain_period=%d\n",
+ pchan->remove, pchan->channel, pchan->remain_period);
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+/**
+ * @brief set/get wifi direct mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action set or get
+ * @param mode A pointer to wifi direct mode
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_wifi_direct_mode_cfg(moal_private *priv, t_u16 action,
+ t_u16 *mode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_WIFI_DIRECT_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+
+ req->action = action;
+ if (action == MLAN_ACT_SET)
+ bss->param.wfd_mode = *mode;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ *mode = bss->param.wfd_mode;
+ PRINTM(MIOCTL, "ACT=%d, wifi_direct_mode=%d\n", action, *mode);
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set p2p config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param p2p_config A pointer to mlan_ds_wifi_direct_config structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_p2p_config(moal_private *priv, t_u32 action,
+ mlan_ds_wifi_direct_config *p2p_config)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+
+ ENTER();
+ if (!p2p_config) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_WIFI_DIRECT_CONFIG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = action;
+ moal_memcpy_ext(priv->phandle, &misc_cfg->param.p2p_config, p2p_config,
+ sizeof(mlan_ds_wifi_direct_config),
+ sizeof(mlan_ds_wifi_direct_config));
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, p2p_config,
+ &misc_cfg->param.p2p_config,
+ sizeof(mlan_ds_wifi_direct_config),
+ sizeof(mlan_ds_wifi_direct_config));
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief Get STA Channel Info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param channel A pointer to channel info
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_sta_channel(moal_private *priv, t_u8 wait_option,
+ chan_band_info *channel)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ PRINTM(MERROR, "woal_get_sta_channel req alloc fail\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHAN_INFO;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && channel)
+ moal_memcpy_ext(priv->phandle, channel,
+ &(bss->param.sta_channel),
+ sizeof(chan_band_info), sizeof(chan_band_info));
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get RSSI info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param signal A pointer tp mlan_ds_get_signal structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_signal_info(moal_private *priv, t_u8 wait_option,
+ mlan_ds_get_signal *signal)
+{
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_SIGNAL;
+ info->param.signal.selector = ALL_RSSI_INFO_MASK;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (signal)
+ moal_memcpy_ext(priv->phandle, signal,
+ &info->param.signal,
+ sizeof(mlan_ds_get_signal),
+ sizeof(mlan_ds_get_signal));
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level =
+ info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise =
+ info->param.signal.bcn_nf_avg;
+ }
+#endif
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get scan table
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_scan_table(moal_private *priv, t_u8 wait_option,
+ mlan_scan_resp *scan_resp)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (!scan_resp) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+ moal_memcpy_ext(priv->phandle, (void *)&scan->param.scan_resp,
+ (void *)scan_resp, sizeof(mlan_scan_resp),
+ sizeof(mlan_scan_resp));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (scan_resp) {
+ moal_memcpy_ext(priv->phandle, scan_resp,
+ &scan->param.scan_resp,
+ sizeof(mlan_scan_resp),
+ sizeof(mlan_scan_resp));
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request a scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param req_ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_request_scan(moal_private *priv, t_u8 wait_option,
+ mlan_802_11_ssid *req_ssid)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+ handle->scan_priv = priv;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *)ioctl_req->pbuf;
+
+ if (req_ssid && req_ssid->ssid_len != 0) {
+ /* Specific SSID scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID;
+
+ moal_memcpy_ext(handle, scan->param.scan_req.scan_ssid.ssid,
+ req_ssid->ssid, req_ssid->ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ scan->param.scan_req.scan_ssid.ssid_len =
+ MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len);
+ } else {
+ /* Normal scan */
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ }
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ handle->scan_priv = NULL;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change Adhoc Channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param channel The channel to be set.
+ * @param wait_option wait_option
+ *
+ * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail
+ */
+mlan_status woal_change_adhoc_chan(moal_private *priv, int channel,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ /* Get BSS information */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, wait_option, &bss_info)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (bss_info.bss_mode == MLAN_BSS_MODE_INFRA) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get current channel */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (bss->param.bss_chan.channel == (unsigned int)channel) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+ PRINTM(MINFO, "Updating Channel from %d to %d\n",
+ (int)bss->param.bss_chan.channel, channel);
+
+ if (bss_info.media_connected != MTRUE) {
+ ret = MLAN_STATUS_SUCCESS;
+ goto done;
+ }
+
+ /* Do disonnect*/
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ memset((t_u8 *)&bss->param.bssid, 0, ETH_ALEN);
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, wait_option, &bss_info.ssid)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Start/Join Adhoc network */
+ bss->sub_command = MLAN_OID_BSS_START;
+ memset(&bss->param.ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Find the best network to associate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_find_best_network(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *mac = 0;
+
+ ENTER();
+
+ if (!ssid_bssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_FIND_BSS;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid, ssid_bssid,
+ sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ moal_memcpy_ext(priv->phandle, ssid_bssid,
+ &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid),
+ sizeof(mlan_ssid_bssid));
+ mac = (t_u8 *)&ssid_bssid->bssid;
+ PRINTM(MINFO, "Find network: ssid=%s, " MACSTR ", idx=%d\n",
+ ssid_bssid->ssid.ssid, MAC2STR(mac),
+ (int)ssid_bssid->idx);
+ }
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Find the best network to associate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param bssid A pointer to bssid
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_find_bssid(moal_private *priv, mlan_802_11_mac_addr bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_FIND_BSSID;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.bssid, bssid,
+ sizeof(mlan_802_11_mac_addr),
+ sizeof(mlan_802_11_mac_addr));
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check if AP channel is valid for STA Region
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_11d_check_ap_channel(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *mac = 0;
+
+ ENTER();
+
+ if (!ssid_bssid) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ bss->sub_command = MLAN_OID_BSS_11D_CHECK_CHANNEL;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid, ssid_bssid,
+ sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
+
+ mac = (t_u8 *)&ssid_bssid->bssid;
+ PRINTM(MINFO, "ssid=%s, " MACSTR ", idx=%d\n", ssid_bssid->ssid.ssid,
+ MAC2STR(mac), (int)ssid_bssid->idx);
+
+ /* Send IOCTL request to MLAN */
+ ret = woal_request_ioctl(priv, req, wait_option);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode A pointer to authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_auth_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 *auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && auth_mode)
+ *auth_mode = sec->param.auth_mode;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode A pointer to encrypt mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_encrypt_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 *encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && encrypt_mode)
+ *encrypt_mode = sec->param.encrypt_mode;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get WPA enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable A pointer to wpa enable status
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_get_wpa_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 *enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS && enable)
+ *enable = sec->param.wpa_enabled;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set authentication mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param auth_mode Authentication mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_auth_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 auth_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.auth_mode = auth_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encrypt mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param encrypt_mode Encryption mode
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_encrypt_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 encrypt_mode)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_mode = encrypt_mode;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set wpa enable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable MTRUE or MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_wpa_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.wpa_enabled = enable;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief enable wep key
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_enable_wep_key(moal_private *priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_disable = MFALSE;
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_user_scan_config structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_request_userscan(moal_private *priv, t_u8 wait_option,
+ wlan_user_scan_cfg *scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+ handle->scan_priv = priv;
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_user_scan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *)ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(handle, scan->param.user_scan.scan_cfg_buf, scan_cfg,
+ sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg));
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ else if (wait_option != MOAL_NO_WAIT) {
+ PRINTM(MMSG, "scan interrupted by Signal, Cancel it...");
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT_TIMEOUT);
+ }
+ if (ret == MLAN_STATUS_FAILURE) {
+ handle->scan_pending_on_block = MFALSE;
+ handle->scan_priv = NULL;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief woal_get_scan_config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_cfg A pointer to scan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_get_scan_config(moal_private *priv, mlan_scan_cfg *scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret == MLAN_STATUS_SUCCESS && scan_cfg)
+ moal_memcpy_ext(priv->phandle, scan_cfg, &scan->param.scan_cfg,
+ sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan time
+ *
+ * @param priv A pointer to moal_private structure
+ * @param active_scan_time Active scan time
+ * @param passive_scan_time Passive scan time
+ * @param specific_scan_time Specific scan time
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_scan_time(moal_private *priv, t_u16 active_scan_time,
+ t_u16 passive_scan_time,
+ t_u16 specific_scan_time)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_scan_cfg scan_cfg;
+
+ ENTER();
+
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan_cfg.scan_time.active_scan_time = active_scan_time;
+ scan_cfg.scan_time.specific_scan_time = specific_scan_time;
+ scan_cfg.scan_time.passive_scan_time = passive_scan_time;
+ PRINTM(MIOCTL, "Set specific=%d, active=%d, passive=%d\n",
+ (int)active_scan_time, (int)passive_scan_time,
+ (int)specific_scan_time);
+ moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg,
+ sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg));
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief request scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_cfg A pointer to wlan_user_scan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_do_scan(moal_private *priv, wlan_user_scan_cfg *scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+
+ if (!scan_cfg)
+ ret = woal_request_scan(priv, MOAL_NO_WAIT, NULL);
+ else
+ ret = woal_request_userscan(priv, MOAL_NO_WAIT, scan_cfg);
+
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cancel pending scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_cancel_scan(moal_private *priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ moal_private *scan_priv = handle->scan_priv;
+#ifdef STA_CFG80211
+ unsigned long flags;
+#endif
+ /* If scan is in process, cancel the scan command */
+ if (!handle->scan_pending_on_block || !scan_priv)
+ return ret;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ ((mlan_ds_scan *)req->pbuf)->sub_command = MLAN_OID_SCAN_CANCEL;
+ ret = woal_request_ioctl(scan_priv, req, wait_option);
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+#ifdef STA_CFG80211
+ spin_lock_irqsave(&handle->scan_req_lock, flags);
+ if (IS_STA_CFG80211(handle->params.cfg80211_wext) &&
+ handle->scan_request) {
+ /** some supplicant can not handle SCAN abort event */
+ if (scan_priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_cfg80211_scan_done(handle->scan_request, MTRUE);
+ else
+ woal_cfg80211_scan_done(handle->scan_request, MFALSE);
+ handle->scan_request = NULL;
+ }
+ spin_unlock_irqrestore(&handle->scan_req_lock, flags);
+#endif
+ /* add 10ms delay, incase firmware delay 0x7f event after scan cancel
+ * command response */
+ woal_sched_timeout(10);
+ handle->scan_priv = NULL;
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ return ret;
+}
+
+/**
+ * @brief find ssid in scan_table
+ *
+ * @param priv A pointer to moal_private
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
+ */
+int woal_find_essid(moal_private *priv, mlan_ssid_bssid *ssid_bssid,
+ t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_scan_resp scan_resp;
+ wifi_timeval t;
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, wait_option, &scan_resp)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#ifdef STA_CFG80211
+ if (priv->ft_pre_connect || priv->ft_ie_len) {
+ /** skip check the scan age out */
+ ret = woal_find_best_network(priv, wait_option, ssid_bssid);
+ LEAVE();
+ return ret;
+ }
+#endif
+ woal_get_monotonic_time(&t);
+/** scan result timeout value */
+#define SCAN_RESULT_AGEOUT 10
+ if (t.time_sec > (scan_resp.age_in_secs + SCAN_RESULT_AGEOUT)) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = woal_find_best_network(priv, wait_option, ssid_bssid);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param scan_cfg A pointer to wlan_bgscan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_request_bgscan(moal_private *priv, t_u8 wait_option,
+ wlan_bgscan_cfg *scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ sizeof(wlan_bgscan_cfg));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ scan = (mlan_ds_scan *)ioctl_req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_BGSCAN_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_SCAN;
+ ioctl_req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, scan->param.user_scan.scan_cfg_buf,
+ scan_cfg, sizeof(wlan_bgscan_cfg),
+ sizeof(wlan_bgscan_cfg));
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, ioctl_req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_bg_scan(moal_private *priv, char *buf, int length)
+{
+ t_u8 *ptr = buf + strlen("BGSCAN-CONFIG") + 1;
+ int buf_left = length - (strlen("BGSCAN-CONFIG") + 1);
+ int band = 0;
+ int num_ssid = 0;
+ int ssid_len = 0;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+
+ ENTER();
+ memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
+ priv->scan_cfg.report_condition =
+ BG_SCAN_SSID_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE;
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR,
+ "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len &&
+ (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(priv->scan_cfg.ssid_list[num_ssid].ssid,
+ ptr + 2, ssid_len);
+ priv->scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "BG scan: ssid=%s\n",
+ priv->scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_BGSCAN_RSSI_SECTION:
+ priv->scan_cfg.report_condition =
+ BG_SCAN_SSID_RSSI_MATCH |
+ BG_SCAN_WAIT_ALL_CHAN_DONE;
+ priv->scan_cfg.rssi_threshold = ptr[1];
+ PRINTM(MIOCTL, "BG scan: rssi_threshold=%d\n",
+ (int)priv->scan_cfg.rssi_threshold);
+ ptr += 2;
+ buf_left -= 2;
+ break;
+ case WEXT_BGSCAN_REPEAT_SECTION:
+ priv->scan_cfg.repeat_count = (t_u16)ptr[1];
+ PRINTM(MIOCTL, "BG scan: repeat_count=%d\n",
+ (int)priv->scan_cfg.repeat_count);
+ ptr += 2;
+ buf_left -= 2;
+ break;
+ case WEXT_BGSCAN_INTERVAL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid scan_interval, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ priv->scan_cfg.scan_interval =
+ (ptr[2] << 8 | ptr[1]) * 1000;
+ PRINTM(MIOCTL, "BG scan: scan_interval=%d\n",
+ (int)priv->scan_cfg.scan_interval);
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ /** set bgscan when ssid_num > 0 */
+ if (num_ssid) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ switch (band) {
+ case WIFI_FREQUENCY_BAND_2GHZ:
+ priv->scan_cfg.chan_list[0].radio_type =
+ 0 | BAND_SPECIFIED;
+ break;
+ case WIFI_FREQUENCY_BAND_5GHZ:
+ priv->scan_cfg.chan_list[0].radio_type =
+ 1 | BAND_SPECIFIED;
+ break;
+ default:
+ break;
+ }
+ priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
+ priv->scan_cfg.action = BG_SCAN_ACT_SET;
+ priv->scan_cfg.enable = MTRUE;
+ moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac,
+ priv->random_mac, ETH_ALEN,
+ sizeof(priv->scan_cfg.random_mac));
+ ret = woal_request_bgscan(priv, MOAL_IOCTL_WAIT,
+ &priv->scan_cfg);
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_CFG80211
+/**
+ * @brief set bgscan and new rssi_low_threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param set_rssi flag for set rssi_low_threshold
+ *
+ * @return N/A
+ */
+void woal_config_bgscan_and_rssi(moal_private *priv, t_u8 set_rssi)
+{
+ char rssi_low[11];
+ mlan_bss_info bss_info;
+ int band = 0;
+
+ ENTER();
+ if (!priv->rssi_low) {
+ LEAVE();
+ return;
+ }
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (!bss_info.media_connected) {
+ PRINTM(MIOCTL, "We already lost connection\n");
+ LEAVE();
+ return;
+ }
+ memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
+ strncpy(priv->scan_cfg.ssid_list[0].ssid, bss_info.ssid.ssid,
+ bss_info.ssid.ssid_len);
+ priv->scan_cfg.ssid_list[0].max_len = 0;
+
+ priv->scan_cfg.report_condition =
+ BG_SCAN_SSID_RSSI_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE;
+ priv->scan_cfg.rssi_threshold = priv->rssi_low - RSSI_HYSTERESIS;
+ priv->scan_cfg.repeat_count = DEF_REPEAT_COUNT;
+ priv->scan_cfg.scan_interval = MIN_BGSCAN_INTERVAL;
+ woal_get_band(priv, &band);
+ switch (band) {
+ case WIFI_FREQUENCY_BAND_2GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 0 | BAND_SPECIFIED;
+ break;
+ case WIFI_FREQUENCY_BAND_5GHZ:
+ priv->scan_cfg.chan_list[0].radio_type = 1 | BAND_SPECIFIED;
+ break;
+ default:
+ break;
+ }
+ priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
+ priv->scan_cfg.action = BG_SCAN_ACT_SET;
+ priv->scan_cfg.enable = MTRUE;
+ moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac,
+ priv->random_mac, ETH_ALEN,
+ sizeof(priv->scan_cfg.random_mac));
+ woal_request_bgscan(priv, MOAL_NO_WAIT, &priv->scan_cfg);
+ if (set_rssi &&
+ ((priv->rssi_low + RSSI_HYSTERESIS) <= LOWEST_RSSI_THRESHOLD)) {
+ priv->rssi_low += RSSI_HYSTERESIS;
+ snprintf(rssi_low, sizeof(rssi_low), "%d", priv->rssi_low);
+ woal_set_rssi_low_threshold(priv, rssi_low, MOAL_NO_WAIT);
+ }
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief stop bg scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_stop_bg_scan(moal_private *priv, t_u8 wait_option)
+{
+ wlan_bgscan_cfg scan_cfg;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ scan_cfg.action = BG_SCAN_ACT_SET;
+ scan_cfg.enable = MFALSE;
+ ret = woal_request_bgscan(priv, wait_option, &scan_cfg);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set bgscan config
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+void woal_reconfig_bgscan(moal_handle *handle)
+{
+ int i;
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (handle->priv[i]->bg_scan_start &&
+ handle->priv[i]->bg_scan_reported) {
+ PRINTM(MIOCTL, "Reconfig BGSCAN\n");
+ woal_request_bgscan(handle->priv[i],
+ MOAL_NO_WAIT,
+ &handle->priv[i]->scan_cfg);
+ handle->priv[i]->bg_scan_reported = MFALSE;
+ }
+ }
+ }
+}
+
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rssi A pointer to low rssi
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_rssi_low_threshold(moal_private *priv, char *rssi,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int low_rssi = 0;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ misc->param.subscribe_event.evt_action = SUBSCRIBE_EVT_ACT_BITWISE_SET;
+ misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW;
+ misc->param.subscribe_event.evt_bitmap |= SUBSCRIBE_EVT_PRE_BEACON_LOST;
+ misc->param.subscribe_event.pre_beacon_miss = DEFAULT_PRE_BEACON_MISS;
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef STA_CFG80211
+ priv->mrvl_rssi_low = low_rssi;
+#endif
+ misc->param.subscribe_event.low_rssi = low_rssi;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR, "request set rssi_low_threshold fail!\n");
+ goto done;
+ }
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(STA_CFG80211)
+/**
+ * @brief set rssi low threshold
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event_id event id.
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_rssi_threshold(moal_private *priv, t_u32 event_id,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+
+ ENTER();
+ if (priv->media_connected == MFALSE)
+ goto done;
+ if (priv->mrvl_rssi_low || !priv->cqm_rssi_thold)
+ goto done;
+ if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_LOW) {
+ if (priv->last_rssi_low < 100)
+ priv->last_rssi_low += priv->cqm_rssi_hyst;
+ priv->last_rssi_high = abs(priv->cqm_rssi_high_thold);
+ } else if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_HIGH) {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ if (priv->last_rssi_high > priv->cqm_rssi_hyst)
+ priv->last_rssi_high -= priv->cqm_rssi_hyst;
+ } else {
+ priv->last_rssi_low = abs(priv->cqm_rssi_thold);
+ priv->last_rssi_high = abs(priv->cqm_rssi_high_thold);
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT;
+ req->action = MLAN_ACT_SET;
+ if (!event_id && !priv->cqm_rssi_thold && !priv->cqm_rssi_hyst)
+ misc->param.subscribe_event.evt_action =
+ SUBSCRIBE_EVT_ACT_BITWISE_CLR;
+ else
+ misc->param.subscribe_event.evt_action =
+ SUBSCRIBE_EVT_ACT_BITWISE_SET;
+ misc->param.subscribe_event.evt_bitmap =
+ SUBSCRIBE_EVT_RSSI_LOW | SUBSCRIBE_EVT_RSSI_HIGH;
+ misc->param.subscribe_event.low_rssi_freq = 0;
+ misc->param.subscribe_event.low_rssi = priv->last_rssi_low;
+ misc->param.subscribe_event.high_rssi_freq = 0;
+ misc->param.subscribe_event.high_rssi = priv->last_rssi_high;
+ PRINTM(MIOCTL, "rssi_low=%d, rssi_high=%d action=%d\n",
+ (int)priv->last_rssi_low, (int)priv->last_rssi_high,
+ misc->param.subscribe_event.evt_action);
+ ret = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Get power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_get_powermode(moal_private *priv, int *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int ps_mode;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
+ &ps_mode, 0,
+ MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (ps_mode)
+ *powermode = MFALSE;
+ else
+ *powermode = MTRUE;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set scan type
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_scan_type(moal_private *priv, t_u32 scan_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_scan_cfg scan_cfg;
+
+ ENTER();
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan_cfg.scan_type = scan_type;
+ PRINTM(MIOCTL, "Set scan_type=%d\n", (int)scan_type);
+ moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg,
+ sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg));
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief enable/disable ext_scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE -- enable, MFALSE --disable
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_enable_ext_scan(moal_private *priv, t_u8 enable)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_scan_cfg scan_cfg;
+
+ ENTER();
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+ memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg));
+ scan_cfg.ext_scan = enable;
+ PRINTM(MIOCTL, "Set ext_scan=%d\n", (int)enable);
+ moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg,
+ sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg));
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param powermode A pointer to powermode string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_powermode(moal_private *priv, char *powermode)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int disabled;
+
+ ENTER();
+
+ if (*powermode == '1') {
+ PRINTM(MIOCTL, "Disable power save\n");
+ disabled = 1;
+ } else if (*powermode == '0') {
+ PRINTM(MIOCTL, "Enable power save\n");
+ disabled = 0;
+ } else {
+ PRINTM(MERROR, "unsupported power mode\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_SET,
+ &disabled, 0,
+ MOAL_IOCTL_WAIT))
+ ret = MLAN_STATUS_FAILURE;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set combo scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_set_combo_scan(moal_private *priv, char *buf, int length)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_cfg;
+ t_u8 *ptr = buf + WEXT_CSCAN_HEADER_SIZE;
+ int buf_left = length - WEXT_CSCAN_HEADER_SIZE;
+ int num_ssid = 0;
+ int num_chan = 0;
+ int ssid_len = 0;
+ int i = 0;
+ t_u16 passive_scan_time = 0;
+ t_u16 specific_scan_time = 0;
+
+ ENTER();
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case WEXT_CSCAN_SSID_SECTION:
+ ssid_len = *(ptr + 1);
+ if ((buf_left < (ssid_len + 2)) ||
+ (ssid_len > MLAN_MAX_SSID_LENGTH)) {
+ PRINTM(MERROR,
+ "Invalid ssid, buf_left=%d, ssid_len=%d\n",
+ buf_left, ssid_len);
+ buf_left = 0;
+ break;
+ }
+ if (ssid_len &&
+ (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) {
+ strncpy(scan_cfg.ssid_list[num_ssid].ssid,
+ ptr + 2, ssid_len);
+ scan_cfg.ssid_list[num_ssid].max_len = 0;
+ PRINTM(MIOCTL, "Combo scan: ssid=%s\n",
+ scan_cfg.ssid_list[num_ssid].ssid);
+ num_ssid++;
+ }
+ buf_left -= ssid_len + 2;
+ ptr += ssid_len + 2;
+ break;
+ case WEXT_CSCAN_CHANNEL_SECTION:
+ num_chan = ptr[1];
+ if ((buf_left < (num_chan + 2)) ||
+ (num_chan > WLAN_USER_SCAN_CHAN_MAX)) {
+ PRINTM(MERROR,
+ "Invalid channel list, buf_left=%d, num_chan=%d\n",
+ buf_left, num_chan);
+ buf_left = 0;
+ break;
+ }
+ for (i = 0; i < num_chan; i++) {
+ scan_cfg.chan_list[i].chan_number = ptr[2 + i];
+ PRINTM(MIOCTL, "Combo scan: chan=%d\n",
+ scan_cfg.chan_list[i].chan_number);
+ }
+ buf_left -= 2 + num_chan;
+ ptr += 2 + num_chan;
+ break;
+ case WEXT_CSCAN_PASV_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid PASV_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ passive_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ case WEXT_CSCAN_HOME_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid HOME_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ specific_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+ if (passive_scan_time || specific_scan_time) {
+ PRINTM(MIOCTL,
+ "Set passive_scan_time=%d specific_scan_time=%d\n",
+ passive_scan_time, specific_scan_time);
+ if (MLAN_STATUS_FAILURE ==
+ woal_set_scan_time(priv, 0, passive_scan_time,
+ specific_scan_time)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (num_ssid || num_chan) {
+ if (num_ssid) {
+ /* Add broadcast scan to ssid_list */
+ scan_cfg.ssid_list[num_ssid].max_len = 0xff;
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg))
+ ret = -EFAULT;
+ if (num_ssid && (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE))
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+ } else {
+ /* request broadcast scan */
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, NULL))
+ ret = -EFAULT;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param band A pointer to band buf
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_get_band(moal_private *priv, int *band)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ int support_band = 0;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN
+ */
+ req->action = MLAN_ACT_GET;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (radio_cfg->param.band_cfg.config_bands &
+ (BAND_B | BAND_G | BAND_GN))
+ support_band |= WIFI_FREQUENCY_BAND_2GHZ;
+ if (radio_cfg->param.band_cfg.config_bands & (BAND_A | BAND_AN))
+ support_band |= WIFI_FREQUENCY_BAND_5GHZ;
+ *band = support_band;
+ if (support_band == WIFI_FREQUENCY_ALL_BAND)
+ *band = WIFI_FREQUENCY_BAND_AUTO;
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set band
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pband A pointer to band string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_band(moal_private *priv, char *pband)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int band = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ int cfg80211_wext = priv->phandle->params.cfg80211_wext;
+#endif
+
+ ENTER();
+ if (priv->media_connected == MTRUE) {
+ PRINTM(MERROR, "Set band is not allowed in connected state\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ /* Get fw supported values from MLAN */
+ req->action = MLAN_ACT_GET;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (*pband == '0') {
+ PRINTM(MIOCTL, "Set band to AUTO\n");
+ band = radio_cfg->param.band_cfg.fw_bands;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ if (radio_cfg->param.band_cfg.fw_bands & BAND_A)
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &cfg80211_band_2ghz;
+ }
+#endif
+ } else if (*pband == '1') {
+ PRINTM(MIOCTL, "Set band to 5G\n");
+ if (!(radio_cfg->param.band_cfg.fw_bands & BAND_A)) {
+ PRINTM(MERROR, "Don't support 5G band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = BAND_A;
+ if (radio_cfg->param.band_cfg.fw_bands & BAND_AN)
+ band |= BAND_AN;
+ if (radio_cfg->param.band_cfg.fw_bands & BAND_AAC)
+ band |= BAND_AAC;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &cfg80211_band_5ghz;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ }
+#endif
+ } else if (*pband == '2') {
+ PRINTM(MIOCTL, "Set band to 2G\n");
+ band = BAND_B | BAND_G;
+ band |= BAND_GN;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev &&
+ priv->wdev->wiphy) {
+ priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+ priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &cfg80211_band_2ghz;
+ }
+#endif
+ } else {
+ PRINTM(MERROR, "unsupported band\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* Set config_bands to MLAN */
+ req->action = MLAN_ACT_SET;
+ memset(&radio_cfg->param.band_cfg, 0, sizeof(mlan_ds_band_cfg));
+ radio_cfg->param.band_cfg.config_bands = band;
+ radio_cfg->param.band_cfg.adhoc_start_band = band;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Add RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_add_rxfilter(moal_private *priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ /* Android command:
+ "DRIVER RXFILTER-ADD 0"
+ "DRIVER RXFILTER-ADD 1"
+ "DRIVER RXFILTER-ADD 3" */
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Add IPV4 multicast filter\n");
+ priv->rx_filter |= RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Add broadcast filter\n");
+ priv->rx_filter |= RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Add unicast filter\n");
+ priv->rx_filter |= RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Add IPV6 multicast fitler\n");
+ priv->rx_filter |= RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Remove RX Filter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param rxfilter A pointer to rxfilter string.
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_remove_rxfilter(moal_private *priv, char *rxfilter)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (*rxfilter == '0') {
+ PRINTM(MIOCTL, "Remove IPV4 multicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_IPV4_MULTICAST;
+ } else if (*rxfilter == '1') {
+ PRINTM(MIOCTL, "Remove broadcast filter\n");
+ priv->rx_filter &= ~RX_FILTER_BROADCAST;
+ } else if (*rxfilter == '2') {
+ PRINTM(MIOCTL, "Remove unicast filter\n");
+ priv->rx_filter &= ~RX_FILTER_UNICAST;
+ } else if (*rxfilter == '3') {
+ PRINTM(MIOCTL, "Remove IPV6 multicast fitler\n");
+ priv->rx_filter &= ~RX_FILTER_IPV6_MULTICAST;
+ } else {
+ PRINTM(MERROR, "unsupported rx fitler\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get WMM IE QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param qos_cfg A pointer to QoS configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_priv_qos_cfg(moal_private *priv, t_u32 action, char *qos_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int qosinfo = 0;
+
+ ENTER();
+
+ if (qos_cfg == NULL) {
+ PRINTM(MERROR, "QOS info buffer is null\n");
+ return MLAN_STATUS_FAILURE;
+ }
+ if ((action == MLAN_ACT_SET) &&
+ (MLAN_STATUS_SUCCESS != woal_atoi(&qosinfo, qos_cfg))) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ req->action = action;
+ if (action == MLAN_ACT_SET) {
+ cfg->param.qos_cfg = (t_u8)qosinfo;
+ PRINTM(MIOCTL, "set qosinfo=%d\n", qosinfo);
+ }
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (action == MLAN_ACT_GET)
+ *qos_cfg = cfg->param.qos_cfg;
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param psleeppd A pointer to sleep period configuration structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_set_sleeppd(moal_private *priv, char *psleeppd)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int sleeppd = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&sleeppd, psleeppd)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MIOCTL, "set sleeppd=%d\n", sleeppd);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if ((sleeppd <= MAX_SLEEP_PERIOD && sleeppd >= MIN_SLEEP_PERIOD) ||
+ (sleeppd == 0) || (sleeppd == SLEEP_PERIOD_RESERVED_FF)) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = sleeppd;
+ } else {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set scan period function
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to scan command buf
+ * @param length buf length
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+int woal_set_scan_cfg(moal_private *priv, char *buf, int length)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *ptr = buf + NL80211_SCANCFG_HEADER_SIZE;
+ int buf_left = length - NL80211_SCANCFG_HEADER_SIZE;
+ t_u16 active_scan_time = 0;
+ t_u16 passive_scan_time = 0;
+ t_u16 specific_scan_time = 0;
+
+ ENTER();
+ while (buf_left >= 2) {
+ switch (*ptr) {
+ case NL80211_SCANCFG_ACTV_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid ACTV_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ active_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ case NL80211_SCANCFG_PASV_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid PASV_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ passive_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ case NL80211_SCANCFG_SPCF_DWELL_SECTION:
+ if (buf_left < 3) {
+ PRINTM(MERROR,
+ "Invalid SPCF_DWELL_SECTION, buf_left=%d\n",
+ buf_left);
+ buf_left = 0;
+ break;
+ }
+ specific_scan_time = ptr[2] << 8 | ptr[1];
+ ptr += 3;
+ buf_left -= 3;
+ break;
+ default:
+ buf_left = 0;
+ break;
+ }
+ }
+
+ if (active_scan_time || passive_scan_time || specific_scan_time) {
+ PRINTM(MIOCTL,
+ "Set active_scan_time= %d passive_scan_time=%d specific_scan_time=%d\n",
+ active_scan_time, passive_scan_time, specific_scan_time);
+ if (MLAN_STATUS_FAILURE ==
+ woal_set_scan_time(priv, active_scan_time,
+ passive_scan_time, specific_scan_time)) {
+ ret = -EFAULT;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to moal_private structure
+ * @param option Radio Option
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_radio(moal_private *priv, t_u8 option)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if ((option != 0) && (option != 1)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = option;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#endif /* STA_SUPPORT */
+
+#ifdef USB
+/**
+ * @brief Initialize USB packet aggregation control
+ *
+ * @param handle A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_usb_aggr_init(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_ds_misc_usb_aggr_ctrl *aggr_param = NULL;
+ t_u8 usb_aggr_enable;
+ struct usb_card_rec *cardp = NULL;
+ int i = 0, resubmit_urbs = 0;
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MERROR, "Handle is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
+ if (!priv) {
+ PRINTM(MERROR, "STA priv is null\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (handle->card == NULL) {
+ PRINTM(MERROR, "Card is null in %s()\n", __func__);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cardp = (struct usb_card_rec *)handle->card;
+
+ /* Check module parameter */
+ if (handle->params.usb_aggr == 0 || handle->params.usb_aggr == 2) {
+ usb_aggr_enable = MFALSE;
+ } else if (handle->params.usb_aggr == 1) {
+ usb_aggr_enable = MTRUE;
+ } else {
+ PRINTM(MWARN,
+ "Invalid module param (usb_aggr) value %d, "
+ "using MLAN default\n",
+ handle->params.usb_aggr);
+ handle->params.usb_aggr = 0;
+ usb_aggr_enable = MFALSE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ aggr_param = &pcfg_misc->param.usb_aggr_params;
+ /* Initialize TX aggr default values */
+ aggr_param->tx_aggr_ctrl.enable = usb_aggr_enable;
+ aggr_param->tx_aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ aggr_param->tx_aggr_ctrl.aggr_align =
+ MAX(handle->params.max_tx_buf, MLAN_USB_TX_AGGR_ALIGN);
+ aggr_param->tx_aggr_ctrl.aggr_max = MLAN_USB_TX_MAX_AGGR_NUM;
+ aggr_param->tx_aggr_ctrl.aggr_tmo =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
+
+ /* Initialize RX deaggr default values */
+ aggr_param->rx_deaggr_ctrl.enable = usb_aggr_enable;
+ aggr_param->rx_deaggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ aggr_param->rx_deaggr_ctrl.aggr_align = MLAN_USB_RX_ALIGN_SIZE;
+ aggr_param->rx_deaggr_ctrl.aggr_max = MLAN_USB_RX_MAX_AGGR_NUM;
+ aggr_param->rx_deaggr_ctrl.aggr_tmo = MLAN_USB_RX_DEAGGR_TIMEOUT_USEC;
+
+ /* Do not fail driver init due to command failure */
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ /* Disable the feature if FW return failure/unsupported */
+ if (req->status_code)
+ cardp->tx_aggr_ctrl.enable = MFALSE;
+ else
+ moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl,
+ &aggr_param->tx_aggr_ctrl,
+ sizeof(usb_aggr_ctrl), sizeof(usb_aggr_ctrl));
+
+ if (req->status_code) {
+ /* Disable the feature if FW return failure/unsupported */
+ cardp->rx_deaggr_ctrl.enable = MFALSE;
+ } else {
+ /* Default is disable, resubmit URBs only for enable */
+ if (cardp->rx_deaggr_ctrl.enable != usb_aggr_enable)
+ resubmit_urbs = 1;
+ }
+ if (resubmit_urbs) {
+ /* Indicate resubmition from here */
+ cardp->resubmit_urbs = 1;
+ /* Rx SG feature is disabled due to FW failure/unsupported,
+ * kill the URBs, they will be resubmitted after saving the
+ * parameters to USB card */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_kill_urb(
+ cardp->rx_data_list[i].urb);
+ usb_init_urb(
+ cardp->rx_data_list[i].urb);
+ }
+ }
+ }
+
+ /* Default is disable, update only for enable case */
+ moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl,
+ &aggr_param->rx_deaggr_ctrl,
+ sizeof(usb_aggr_ctrl), sizeof(usb_aggr_ctrl));
+
+ /* Ensure the next data URBs will use the modified parameters */
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ cardp->resubmit_urbs = 0;
+ }
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set hotspot configuration value to mlan layer
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ * @param hotspotcfg Hotspot configuration value
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_set_hotspotcfg(moal_private *priv, t_u8 wait_option,
+ t_u32 hotspotcfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->param.hotspot_cfg = hotspotcfg;
+ req->action = MLAN_ACT_SET;
+
+ cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send delelte all BA command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_delba_all(moal_private *priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ds_11n_delba *del_ba = NULL;
+ t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int ret = 0;
+
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA;
+
+ del_ba = &cfg_11n->param.del_ba;
+ memset(del_ba, 0, sizeof(mlan_ds_11n_delba));
+ del_ba->direction = DELBA_RX | DELBA_TX;
+ del_ba->tid = DELBA_ALL_TIDS;
+ moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, zero_mac,
+ ETH_ALEN, sizeof(del_ba->peer_mac_addr));
+
+ status = woal_request_ioctl(priv, req, wait_option);
+
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Send 11d enable/disable command to firmware.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param enable Enable/Disable 11d
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_set_11d(moal_private *priv, t_u8 wait_option, t_u8 enable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ req->action = MLAN_ACT_SET;
+ req->req_id = MLAN_IOCTL_SNMP_MIB;
+
+ snmp = (mlan_ds_snmp_mib *)req->pbuf;
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
+ snmp->param.oid_value = enable;
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle miscellaneous ioctls for asynchronous command response
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_misc_cfg structure
+ *
+ * @return N/A
+ */
+void woal_ioctl_get_misc_conf(moal_private *priv, mlan_ds_misc_cfg *info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ default:
+ break;
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+#define TX_PWR_STR_LEN 20
+#define TX_CONT_STR_LEN 50
+#define TX_FRAME_STR_LEN 80
+/*
+ * @brief Parse mfg cmd tx pwr string
+ *
+ * @param s A pointer to user buffer
+ * @param len Length of user buffer
+ * @param d A pointer to mfg_cmd_generic_cfg struct
+ * @return 0 on success, -EINVAL otherwise
+ */
+static int parse_tx_pwr_string(const char *s, size_t len,
+ struct mfg_cmd_generic_cfg *d)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *tmp = NULL;
+ char *pos = NULL;
+ gfp_t flag;
+
+ ENTER();
+ if (!s || !d) {
+ LEAVE();
+ return -EINVAL;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ string = kzalloc(TX_PWR_STR_LEN, flag);
+ if (string == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ moal_memcpy_ext(NULL, string, s + strlen("tx_power="),
+ len - strlen("tx_power="), TX_PWR_STR_LEN - 1);
+
+ tmp = string;
+ string = strstrip(string);
+
+ /* tx power value */
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->data1 = (t_u32)woal_string_to_number(pos);
+
+ /* modulation */
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->data2 = (t_u32)woal_string_to_number(pos);
+
+ /* path id */
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->data3 = (t_u32)woal_string_to_number(pos);
+
+ if ((d->data1 > 24) || (d->data2 > 2))
+ ret = -EINVAL;
+
+ kfree(tmp);
+ LEAVE();
+ return ret;
+}
+/*
+ * @brief Parse mfg cmd tx cont string
+ *
+ * @param s A pointer to user buffer
+ * @param len Length of user buffer
+ * @param d A pointer to mfg_cmd_tx_cont struct
+ * @return 0 on success, -EINVAL otherwise
+ */
+static int parse_tx_cont_string(const char *s, size_t len,
+ struct mfg_cmd_tx_cont *d)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *tmp = NULL;
+ char *pos = NULL;
+ gfp_t flag;
+
+ ENTER();
+ if (!s || !d) {
+ LEAVE();
+ return -EINVAL;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ string = kzalloc(TX_CONT_STR_LEN, flag);
+ if (string == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ moal_memcpy_ext(NULL, string, s + strlen("tx_continuous="),
+ len - strlen("tx_continuous="), TX_CONT_STR_LEN - 1);
+
+ tmp = string;
+ string = strstrip(string);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->enable_tx = (t_u32)woal_string_to_number(pos);
+
+ if (d->enable_tx == MFALSE)
+ goto done;
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->cw_mode = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->payload_pattern = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->cs_mode = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->act_sub_ch = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->tx_rate = (t_u32)woal_string_to_number(pos);
+
+ if ((d->enable_tx > 1) || (d->cw_mode > 1) || (d->cs_mode > 1) ||
+ (d->act_sub_ch == 2 || d->act_sub_ch > 3))
+ ret = -EINVAL;
+done:
+ kfree(tmp);
+ LEAVE();
+ return ret;
+}
+
+/*
+ * @brief Parse mfg cmd tx frame string
+ *
+ * @param s A pointer to user buffer
+ * @param len Length of user buffer
+ * @param d A pointer to mfg_cmd_tx_frame2 struct
+ * @return 0 on success, -EINVAL otherwise
+ */
+static int parse_tx_frame_string(const char *s, size_t len,
+ struct mfg_cmd_tx_frame2 *d)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *tmp = NULL;
+ char *pos = NULL;
+ int i;
+ gfp_t flag;
+
+ ENTER();
+ if (!s || !d) {
+ LEAVE();
+ return -EINVAL;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ string = kzalloc(TX_FRAME_STR_LEN, flag);
+ if (string == NULL)
+ return -ENOMEM;
+
+ moal_memcpy_ext(NULL, string, s + strlen("tx_frame="),
+ len - strlen("tx_frame="), TX_FRAME_STR_LEN - 1);
+
+ tmp = string;
+ string = strstrip(string);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->enable = (t_u32)woal_string_to_number(pos);
+
+ if (d->enable == MFALSE)
+ goto done;
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->data_rate = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->frame_pattern = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->frame_length = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->adjust_burst_sifs = (t_u16)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->burst_sifs_in_us = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->short_preamble = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->act_sub_ch = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->short_gi = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->adv_coding = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->tx_bf = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->gf_mode = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos)
+ d->stbc = (t_u32)woal_string_to_number(pos);
+
+ pos = strsep(&string, " \t");
+ if (pos) {
+ for (i = 0; i < ETH_ALEN; i++) {
+ pos = strsep(&string, ":");
+ if (pos)
+ d->bssid[i] = woal_atox(pos);
+ }
+ }
+
+ if ((d->enable > 1) || (d->frame_length == 0) ||
+ (d->adjust_burst_sifs > 1) || (d->burst_sifs_in_us > 255) ||
+ (d->short_preamble > 1) ||
+ (d->act_sub_ch == 2 || d->act_sub_ch > 3) || (d->short_gi > 1) ||
+ (d->adv_coding > 1) || (d->tx_bf > 1) || (d->gf_mode > 1) ||
+ (d->stbc > 1))
+ ret = -EINVAL;
+done:
+ kfree(tmp);
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief This function enables/disables RF test mode in firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success,
+ * otherwise failure code
+ */
+mlan_status woal_process_rf_test_mode(moal_handle *handle, t_u32 mode)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ t_u32 flag = 0;
+
+ ENTER();
+#ifdef MFG_CMD_SUPPORT
+ if (mfg_mode) {
+ LEAVE();
+ return ret;
+ }
+#endif
+ if (mode != MFG_CMD_SET_TEST_MODE && mode != MFG_CMD_UNSET_TEST_MODE) {
+ LEAVE();
+ return ret;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_RF_TEST_GENERIC;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ if (mode == MFG_CMD_SET_TEST_MODE)
+ misc->param.mfg_generic_cfg.mfg_cmd =
+ MFG_CMD_SET_TEST_MODE;
+ ret = woal_request_ioctl(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ req, MOAL_IOCTL_WAIT);
+ }
+
+ if (ret == MLAN_STATUS_SUCCESS && mode == MFG_CMD_SET_TEST_MODE &&
+ handle->rf_data == NULL) {
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC :
+ GFP_KERNEL;
+ /* Allocate memory to hold RF test mode data */
+ handle->rf_data =
+ kzalloc(sizeof(struct rf_test_mode_data), flag);
+ if (!handle->rf_data)
+ PRINTM(MERROR,
+ "Couldn't allocate memory for RF test mode\n");
+ handle->rf_test_mode = MTRUE;
+ if (handle->rf_data) {
+ /* antenna is set to 1 by default */
+ handle->rf_data->tx_antenna = 1;
+ handle->rf_data->rx_antenna = 1;
+ }
+ } else if (mode == MFG_CMD_UNSET_TEST_MODE) {
+ if (handle->rf_data) {
+ /* Free RF test mode data memory */
+ kfree(handle->rf_data);
+ handle->rf_data = NULL;
+ }
+ handle->rf_test_mode = MFALSE;
+ }
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends RF test mode command in firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success,
+ * otherwise failure code
+ */
+mlan_status woal_process_rf_test_mode_cmd(moal_handle *handle, t_u32 cmd,
+ const char *buffer, size_t len,
+ t_u32 action, t_u32 val)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int err = MFALSE;
+ int i;
+
+ ENTER();
+
+ if (!handle->rf_test_mode || !handle->rf_data)
+ goto done;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (!req)
+ goto done;
+
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_RF_TEST_GENERIC;
+ req->action = action;
+
+ switch (cmd) {
+ case MFG_CMD_TX_ANT:
+ if (val != 1 && val != 2 && val != 3)
+ err = MTRUE;
+ break;
+ case MFG_CMD_RX_ANT:
+ if (val != 1 && val != 2 && val != 3)
+ err = MTRUE;
+ break;
+ case MFG_CMD_RF_BAND_AG:
+ if (val != 0 && val != 1)
+ err = MTRUE;
+ break;
+ case MFG_CMD_RF_CHANNELBW:
+ if (val != 0 && val != 1 &&
+ (val != 4 ||
+ (val == 4 && handle->rf_data->band == BAND_2GHZ)))
+ err = MTRUE;
+ break;
+ case MFG_CMD_RF_CHAN:
+ break;
+ case MFG_CMD_CLR_RX_ERR:
+ break;
+ case MFG_CMD_RFPWR:
+ if (parse_tx_pwr_string(buffer, len,
+ &misc->param.mfg_generic_cfg))
+ err = MTRUE;
+ break;
+ case MFG_CMD_TX_CONT:
+ misc->sub_command = MLAN_OID_MISC_RF_TEST_TX_CONT;
+ if (parse_tx_cont_string(buffer, len, &misc->param.mfg_tx_cont))
+ err = MTRUE;
+ break;
+ case MFG_CMD_TX_FRAME:
+ misc->sub_command = MLAN_OID_MISC_RF_TEST_TX_FRAME;
+ if (parse_tx_frame_string(buffer, len,
+ &misc->param.mfg_tx_frame2))
+ err = MTRUE;
+ break;
+ default:
+ err = MTRUE;
+ }
+
+ if (!err) {
+ misc->param.mfg_generic_cfg.mfg_cmd = (t_u32)cmd;
+ if (cmd != MFG_CMD_RFPWR &&
+ misc->sub_command == MLAN_OID_MISC_RF_TEST_GENERIC)
+ misc->param.mfg_generic_cfg.data1 = val;
+
+ ret = woal_request_ioctl(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ req, MOAL_IOCTL_WAIT);
+ }
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ switch (cmd) {
+ case MFG_CMD_TX_ANT:
+ handle->rf_data->tx_antenna = misc->param.mfg_generic_cfg.data1;
+ break;
+ case MFG_CMD_RX_ANT:
+ handle->rf_data->rx_antenna = misc->param.mfg_generic_cfg.data1;
+ break;
+ case MFG_CMD_RF_BAND_AG:
+ handle->rf_data->band = misc->param.mfg_generic_cfg.data1;
+ /* set fw default bw and channel config on band change */
+ handle->rf_data->bandwidth = CHANNEL_BW_20MHZ;
+ if (handle->rf_data->band == BAND_2GHZ)
+ handle->rf_data->channel = 6;
+ else if (handle->rf_data->band == BAND_5GHZ)
+ handle->rf_data->channel = 36;
+ break;
+ case MFG_CMD_RF_CHANNELBW:
+ handle->rf_data->bandwidth = misc->param.mfg_generic_cfg.data1;
+ break;
+ case MFG_CMD_RF_CHAN:
+ handle->rf_data->channel = misc->param.mfg_generic_cfg.data1;
+ break;
+ case MFG_CMD_CLR_RX_ERR:
+ handle->rf_data->rx_tot_pkt_count =
+ misc->param.mfg_generic_cfg.data1;
+ handle->rf_data->rx_mcast_bcast_pkt_count =
+ misc->param.mfg_generic_cfg.data2;
+ handle->rf_data->rx_pkt_fcs_err_count =
+ misc->param.mfg_generic_cfg.data3;
+ break;
+ case MFG_CMD_RFPWR:
+ handle->rf_data->tx_power_data[0] =
+ misc->param.mfg_generic_cfg.data1;
+ handle->rf_data->tx_power_data[1] =
+ misc->param.mfg_generic_cfg.data2;
+ handle->rf_data->tx_power_data[2] =
+ misc->param.mfg_generic_cfg.data3;
+ break;
+ case MFG_CMD_TX_CONT:
+ handle->rf_data->tx_cont_data[0] =
+ misc->param.mfg_tx_cont.enable_tx;
+ handle->rf_data->tx_cont_data[1] =
+ misc->param.mfg_tx_cont.cw_mode;
+ handle->rf_data->tx_cont_data[2] =
+ misc->param.mfg_tx_cont.payload_pattern;
+ handle->rf_data->tx_cont_data[3] =
+ misc->param.mfg_tx_cont.cs_mode;
+ handle->rf_data->tx_cont_data[4] =
+ misc->param.mfg_tx_cont.act_sub_ch;
+ handle->rf_data->tx_cont_data[5] =
+ misc->param.mfg_tx_cont.tx_rate;
+ break;
+ case MFG_CMD_TX_FRAME:
+ handle->rf_data->tx_frame_data[0] =
+ misc->param.mfg_tx_frame2.enable;
+ handle->rf_data->tx_frame_data[1] =
+ misc->param.mfg_tx_frame2.data_rate;
+ handle->rf_data->tx_frame_data[2] =
+ misc->param.mfg_tx_frame2.frame_pattern;
+ handle->rf_data->tx_frame_data[3] =
+ misc->param.mfg_tx_frame2.frame_length;
+ handle->rf_data->tx_frame_data[4] =
+ misc->param.mfg_tx_frame2.adjust_burst_sifs;
+ handle->rf_data->tx_frame_data[5] =
+ misc->param.mfg_tx_frame2.burst_sifs_in_us;
+ handle->rf_data->tx_frame_data[6] =
+ misc->param.mfg_tx_frame2.short_preamble;
+ handle->rf_data->tx_frame_data[7] =
+ misc->param.mfg_tx_frame2.act_sub_ch;
+ handle->rf_data->tx_frame_data[8] =
+ misc->param.mfg_tx_frame2.short_gi;
+ handle->rf_data->tx_frame_data[9] =
+ misc->param.mfg_tx_frame2.adv_coding;
+ handle->rf_data->tx_frame_data[10] =
+ misc->param.mfg_tx_frame2.tx_bf;
+ handle->rf_data->tx_frame_data[11] =
+ misc->param.mfg_tx_frame2.gf_mode;
+ handle->rf_data->tx_frame_data[12] =
+ misc->param.mfg_tx_frame2.stbc;
+ for (i = 0; i < ETH_ALEN; i++) {
+ handle->rf_data->bssid[i] =
+ misc->param.mfg_tx_frame2.bssid[i];
+ }
+ break;
+ }
+done:
+ if (err || ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif /* RF_TEST_MODE */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.c
new file mode 100644
index 000000000000..2bd60785c8cb
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.c
@@ -0,0 +1,9625 @@
+/** @file moal_main.c
+ *
+ * @brief This file contains the major functions in WLAN
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#ifdef USB
+#include "moal_usb.h"
+#endif
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif
+#ifdef PCIE
+#include "moal_pcie.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#include "moal_cfg80211_util.h"
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+#include "moal_sta_cfg80211.h"
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+#include "moal_uap_cfg80211.h"
+#endif
+#endif
+#include "moal_eth_ioctl.h"
+
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <net/dsfield.h>
+
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#endif
+
+/********************************************************
+ Global Variables
+ ********************************************************/
+/** the pointer of new fwdump fname for each dump**/
+char *fwdump_fname;
+/** Semaphore for add/remove card */
+struct semaphore AddRemoveCardSem;
+/**
+ * The global variable of a pointer to moal_handle
+ * structure variable
+ **/
+moal_handle *m_handle[MAX_MLAN_ADAPTER];
+/** Global veriable for usb independent reset */
+extern int fw_reload;
+
+extern int wifi_status;
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+extern int fw_region;
+#endif
+#endif
+/********************************************************
+ Local Variables
+********************************************************/
+
+#ifdef SD8887
+static struct _card_info card_info_SD8887 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 0,
+ .pmic = 0,
+ .cal_data_cfg = 1,
+ .low_power_enable = 1,
+ .rx_rate_max = 196,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
+ .rev_id_reg = 0xc8,
+ .fw_name = SD8887_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8887_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V2,
+ .dump_fw_ctrl_reg = 0xa2,
+ .dump_fw_start_reg = 0xa3,
+ .dump_fw_end_reg = 0xaa,
+ .dump_fw_host_ready = 0xee,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0x90,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0B6,
+ .fw_reset_val = 1,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 0,
+};
+#endif
+
+#ifdef SD8897
+static struct _card_info card_info_SD8897 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 0,
+ .pmic = 0,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .histogram_table_num = 1,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0xbc,
+ .fw_name = SD8897_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8897_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V2,
+ .dump_fw_ctrl_reg = 0xe2,
+ .dump_fw_start_reg = 0xe3,
+ .dump_fw_end_reg = 0xea,
+ .dump_fw_host_ready = 0xee,
+ .dump_reg.reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58, 0x59, 0x5c, 0x5d},
+ .dump_reg.reg_table_size = 8,
+ .scratch_reg = 0xc0,
+ .func1_reg_start = 0x04,
+ .func1_reg_end = 0x0b,
+ .fw_reset_reg = 0x0E8,
+ .fw_reset_val = 1,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 0,
+};
+#endif
+
+#ifdef PCIE8897
+static struct _card_info card_info_PCIE8897 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 0,
+ .pmic = 0,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .histogram_table_num = 1,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0x0c58,
+ .fw_name = PCIE8897_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = PCIE8897_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 0,
+};
+#endif
+
+#ifdef USB8897
+static struct _card_info card_info_USB8897 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 0,
+ .pmic = 0,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .histogram_table_num = 1,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .fw_name = USB8897_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = USB8897_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 0,
+};
+#endif
+
+#ifdef SD8977
+static struct _card_info card_info_SD8977 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 76,
+ .histogram_table_num = 1,
+ .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
+ .rev_id_reg = 0xc8,
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .fw_name = SD8977_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8977_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef SD8978
+static struct _card_info card_info_SD8978 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 76,
+ .histogram_table_num = 1,
+ .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
+ .rev_id_reg = 0xc8,
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .fw_name = SD8978_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8978_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef SD8997
+static struct _card_info card_info_SD8997 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0xc8,
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .fw_name = SD8997_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8997_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef SD9098
+static struct _card_info card_info_SD9098 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0xc8,
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .fw_name = SD9098_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD9098_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x90002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef SD9097
+static struct _card_info card_info_SD9097 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0xc8,
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .fw_name = SD9097_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD9097_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x90002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef PCIE8997
+static struct _card_info card_info_PCIE8997 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0x8,
+ .host_strap_reg = 0x0cd0,
+ .magic_reg = 0x0cd4,
+ .fw_name = PCIE8997_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = PCIE8997_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef PCIE9097
+static struct _card_info card_info_PCIE9097 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0x8,
+ .host_strap_reg = 0x1c70,
+ .magic_reg = 0x1c74,
+ .fw_name = PCIE9097_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = PCIE9097_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef PCIE9098
+static struct _card_info card_info_PCIE9098 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .histogram_table_num = 3,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .rev_id_reg = 0x8,
+ .host_strap_reg = 0x1c70,
+ .magic_reg = 0x1c74,
+ .fw_name = PCIE9098_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = PCIE9098_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef USB8978
+static struct _card_info card_info_USB8978 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 76,
+ .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
+ .histogram_table_num = 1,
+ .fw_name = USB8978_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = USB8978_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef USB8997
+static struct _card_info card_info_USB8997 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 0,
+ .rx_rate_max = 196,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .histogram_table_num = 3,
+ .fw_name = USB8997_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = USB8997_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef USB9098
+static struct _card_info card_info_USB9098 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .histogram_table_num = 3,
+ .fw_name = USB9098_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = USB9098_DEFAULT_WLAN_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+#ifdef USB9097
+static struct _card_info card_info_USB9097 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 1,
+ .v16_fw_api = 1,
+ .v17_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 0,
+ .low_power_enable = 0,
+ .rx_rate_max = 412,
+ .feature_control = FEATURE_CTRL_DEFAULT,
+ .histogram_table_num = 3,
+ .fw_name = USBUSB9097_COMBO_V1_FW_NAME,
+ .fw_name_wlan = USB9097_WLAN_V1_FW_NAME,
+ .per_pkt_cfg_support = 1,
+};
+#endif
+#ifdef SD8987
+static struct _card_info card_info_SD8987 = {
+ .embedded_supp = 1,
+ .drcs = 1,
+ .go_noa = 0,
+ .v16_fw_api = 1,
+ .pmic = 1,
+ .cal_data_cfg = 1,
+ .low_power_enable = 1,
+ .rx_rate_max = 196,
+ .feature_control = FEATURE_CTRL_DEFAULT & (~FEATURE_CTRL_STREAM_2X2),
+ .host_strap_reg = 0xf4,
+ .magic_reg = 0xf0,
+ .histogram_table_num = 3,
+ .fw_name = SD8987_DEFAULT_COMBO_FW_NAME,
+ .fw_name_wlan = SD8987_DEFAULT_WLAN_FW_NAME,
+#ifdef SDIO
+ .dump_fw_info = DUMP_FW_SDIO_V3,
+ .dump_fw_ctrl_reg = 0xf9,
+ .dump_fw_start_reg = 0xf1,
+ .dump_fw_end_reg = 0xf8,
+ .dump_fw_host_ready = 0xcc,
+ .dump_reg.reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 0x61, 0x62, 0x64,
+ 0x65, 0x66, 0x68, 0x69, 0x6a},
+ .dump_reg.reg_table_size = 13,
+ .scratch_reg = 0xe8,
+ .func1_reg_start = 0x10,
+ .func1_reg_end = 0x17,
+ .fw_reset_reg = 0x0EE,
+ .fw_reset_val = 0x99,
+ .slew_rate_reg = 0x80002328,
+ .slew_rate_bit_offset = 12,
+#endif
+ .per_pkt_cfg_support = 1,
+};
+#endif
+
+/** Driver version */
+char driver_version[] =
+ INTF_CARDTYPE KERN_VERSION "--" MLAN_RELEASE_VERSION "-GPL"
+ "-("
+ "FP" FPNUM ")"
+#ifdef DEBUG_LEVEL2
+ "-dbg"
+#endif
+ " ";
+
+/** woal_callbacks */
+static mlan_callbacks woal_callbacks = {
+ .moal_get_fw_data = moal_get_fw_data,
+ .moal_get_vdll_data = moal_get_vdll_data,
+ .moal_get_hw_spec_complete = moal_get_hw_spec_complete,
+ .moal_init_fw_complete = moal_init_fw_complete,
+ .moal_shutdown_fw_complete = moal_shutdown_fw_complete,
+ .moal_send_packet_complete = moal_send_packet_complete,
+ .moal_recv_packet = moal_recv_packet,
+ .moal_recv_event = moal_recv_event,
+ .moal_ioctl_complete = moal_ioctl_complete,
+ .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer,
+ .moal_free_mlan_buffer = moal_free_mlan_buffer,
+#ifdef USB
+ .moal_recv_complete = moal_recv_complete,
+ .moal_write_data_async = moal_write_data_async,
+#endif /* USB */
+
+#if defined(SDIO) || defined(PCIE)
+ .moal_write_reg = moal_write_reg,
+ .moal_read_reg = moal_read_reg,
+#endif /* SDIO || PCIE */
+ .moal_write_data_sync = moal_write_data_sync,
+ .moal_read_data_sync = moal_read_data_sync,
+ .moal_malloc = moal_malloc,
+ .moal_mfree = moal_mfree,
+ .moal_vmalloc = moal_vmalloc,
+ .moal_vfree = moal_vfree,
+#ifdef PCIE
+ .moal_malloc_consistent = moal_malloc_consistent,
+ .moal_mfree_consistent = moal_mfree_consistent,
+ .moal_map_memory = moal_map_memory,
+ .moal_unmap_memory = moal_unmap_memory,
+#endif /* PCIE */
+ .moal_memset = moal_memset,
+ .moal_memcpy = moal_memcpy,
+ .moal_memcpy_ext = moal_memcpy_ext,
+ .moal_memmove = moal_memmove,
+ .moal_memcmp = moal_memcmp,
+ .moal_udelay = moal_udelay,
+ .moal_usleep_range = moal_usleep_range,
+ .moal_get_system_time = moal_get_system_time,
+ .moal_get_boot_ktime = moal_get_boot_ktime,
+ .moal_init_timer = moal_init_timer,
+ .moal_free_timer = moal_free_timer,
+ .moal_start_timer = moal_start_timer,
+ .moal_stop_timer = moal_stop_timer,
+ .moal_init_lock = moal_init_lock,
+ .moal_free_lock = moal_free_lock,
+ .moal_spin_lock = moal_spin_lock,
+ .moal_spin_unlock = moal_spin_unlock,
+ .moal_print = moal_print,
+ .moal_print_netintf = moal_print_netintf,
+ .moal_assert = moal_assert,
+ .moal_hist_data_add = moal_hist_data_add,
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ .moal_wait_hostcmd_complete = moal_wait_hostcmd_complete,
+ .moal_notify_hostcmd_complete = moal_notify_hostcmd_complete,
+#endif
+ .moal_tp_accounting = moal_tp_accounting,
+ .moal_tp_accounting_rx_param = moal_tp_accounting_rx_param,
+};
+
+int woal_open(struct net_device *dev);
+int woal_close(struct net_device *dev);
+int woal_set_mac_address(struct net_device *dev, void *addr);
+void woal_tx_timeout(struct net_device *dev
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+ ,
+ unsigned int txqueue
+#endif
+);
+struct net_device_stats *woal_get_stats(struct net_device *dev);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev);
+#else
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback);
+#endif
+#else
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback);
+#endif
+#else
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv);
+#endif
+#else
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb);
+#endif
+#endif
+
+static moal_handle *reset_handle;
+/** Hang workqueue */
+static struct workqueue_struct *hang_workqueue;
+/** Hang work */
+static struct work_struct hang_work;
+
+/**
+ * @brief This function process FW hang
+ *
+ * @param handle Pointer to structure moal_handle
+ *
+ * @return N/A
+ */
+static void woal_hang_work_queue(struct work_struct *work)
+{
+ int i;
+ ENTER();
+ if (!reset_handle) {
+ LEAVE();
+ return;
+ }
+ for (i = 0; i < reset_handle->priv_num; i++) {
+ if (reset_handle->priv[i] && reset_handle->priv[i]->netdev) {
+ PRINTM(MMSG, "Close netdev %s\n",
+ reset_handle->priv[i]->netdev->name);
+ rtnl_lock();
+ dev_close(reset_handle->priv[i]->netdev);
+ rtnl_unlock();
+ break;
+ }
+ }
+ reset_handle = NULL;
+ LEAVE();
+}
+
+/**
+ * @brief This function process FW hang
+ *
+ * @param handle Pointer to structure moal_handle
+ *
+ * @return N/A
+ */
+void woal_process_hang(moal_handle *handle)
+{
+ ENTER();
+ if (reset_handle == NULL) {
+ PRINTM(MMSG, "Start to process hanging\n");
+ reset_handle = handle;
+ mlan_ioctl(handle->pmlan_adapter, NULL);
+ queue_work(hang_workqueue, &hang_work);
+#ifdef ANDROID_KERNEL
+#define WAKE_LOCK_HANG 5000
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ __pm_wakeup_event(&reset_handle->ws, WAKE_LOCK_HANG);
+#else
+ wake_lock_timeout(&reset_handle->wake_lock,
+ msecs_to_jiffies(WAKE_LOCK_HANG));
+#endif
+#endif
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Check if any interface is active
+ *
+ * @param handle A pointer to moal_handle
+ *
+ *
+ * @return MTRUE/MFALSE;
+ */
+t_u8 woal_is_any_interface_active(moal_handle *handle)
+{
+ int i;
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE)
+ return MTRUE;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
+ if (handle->priv[i]->bss_started == MTRUE)
+ return MTRUE;
+ }
+#endif
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return MTRUE or MFALSE
+ */
+BOOLEAN woal_ssid_valid(mlan_802_11_ssid *pssid)
+{
+#ifdef ASCII_SSID_CHECK
+ unsigned int ssid_idx;
+
+ ENTER();
+
+ for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) {
+ if ((pssid->ssid[ssid_idx] < 0x20) ||
+ (pssid->ssid[ssid_idx] > 0x7e)) {
+ LEAVE();
+ return MFALSE;
+ }
+ }
+ LEAVE();
+#endif
+ return MTRUE;
+}
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+/**
+ * @brief Remain on Channel timeout function
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void woal_remain_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *)context;
+ moal_private *priv = handle->priv[handle->remain_bss_index];
+
+ ENTER();
+
+ PRINTM(MEVENT, "remain_timer fired.\n");
+ if (handle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ priv->netdev,
+#else
+ priv->wdev,
+#endif
+ handle->cookie, &handle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ handle->channel_type,
+#endif
+ GFP_ATOMIC);
+ handle->cookie = 0;
+ }
+ handle->is_remain_timer_set = MFALSE;
+
+ LEAVE();
+ return;
+}
+#endif
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+/**
+ * @brief GO timeout function
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void woal_go_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *)context;
+
+ ENTER();
+
+ PRINTM(MEVENT, "go_timer fired.\n");
+ handle->is_go_timer_set = MFALSE;
+
+ LEAVE();
+ return;
+}
+
+#endif
+#endif
+
+/**
+ * @brief check if we already connect to the AP.
+ * @param priv A pointer to moal_private structure
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MTRUE/MFALSE;
+ */
+int woal_is_connected(moal_private *priv, mlan_ssid_bssid *ssid_bssid)
+{
+ mlan_bss_info bss_info;
+ int ret = MFALSE;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ ENTER();
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info))
+ goto done;
+ if (bss_info.media_connected) {
+ if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
+ if (ssid_bssid->ssid.ssid_len) { /* compare ssid and
+ bssid */
+ if ((ssid_bssid->ssid.ssid_len ==
+ bss_info.ssid.ssid_len) &&
+ !memcmp(ssid_bssid->ssid.ssid,
+ bss_info.ssid.ssid,
+ bss_info.ssid.ssid_len) &&
+ !memcmp(ssid_bssid->bssid, bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH))
+ ret = MTRUE;
+ } else { /* compare bssid */
+ if (!memcmp(ssid_bssid->bssid, bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH)) {
+ moal_memcpy_ext(
+ priv->phandle,
+ &ssid_bssid->ssid,
+ &bss_info.ssid,
+ sizeof(bss_info.ssid),
+ sizeof(ssid_bssid->ssid));
+ ret = MTRUE;
+ }
+ }
+ } else { /* compare ssid */
+ if (ssid_bssid->ssid.ssid_len &&
+ (ssid_bssid->ssid.ssid_len ==
+ bss_info.ssid.ssid_len) &&
+ !memcmp(ssid_bssid->ssid.ssid, bss_info.ssid.ssid,
+ bss_info.ssid.ssid_len)) {
+ moal_memcpy_ext(priv->phandle,
+ &ssid_bssid->bssid,
+ &bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(ssid_bssid->bssid));
+ ret = MTRUE;
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Look up specific IE in a buf
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param id Element id to lookup
+ *
+ * @return Pointer of the specific IE -- success, NULL -- fail
+ */
+const t_u8 *woal_parse_ie_tlv(const t_u8 *ie, int len, t_u8 id)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+
+ /* IE format:
+ * | u8 | id |
+ * | u8 | len |
+ * | var | data |
+ */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ if ((*pos == id) && (length + 2) <= left_len)
+ return pos;
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Look up specific IE in Extension IE
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ * @param ext_id Extended Element id to lookup
+ *
+ * @return Pointer of the specific Extended IE -- success, NULL
+ * -- fail
+ */
+const t_u8 *woal_parse_ext_ie_tlv(const t_u8 *ie, int len, t_u8 ext_id)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ int length;
+
+ /* Extension IE format:
+ * | u8 | id |
+ * | u8 | len |
+ * | u8 | ext_id |
+ * | var | data |
+ */
+ while (left_len >= 2) {
+ length = *(pos + 1);
+ if ((*pos == EXTENSION) && (length + 2) <= left_len) {
+ if (*(pos + 2) == ext_id)
+ return pos;
+ }
+ pos += (length + 2);
+ left_len -= (length + 2);
+ }
+ return NULL;
+}
+
+/**
+ * @brief Get mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ *
+ * @return Wireless mode
+ */
+t_u32 woal_get_mode(moal_private *priv, t_u8 wait_option)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 mode = 0;
+
+ ENTER();
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ mode = priv->w_stats.status;
+#endif
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ switch (bss->param.bss_mode) {
+ case MLAN_BSS_MODE_INFRA:
+ mode = MW_MODE_INFRA;
+ break;
+ case MLAN_BSS_MODE_IBSS:
+ mode = MW_MODE_ADHOC;
+ break;
+ default:
+ mode = MW_MODE_AUTO;
+ break;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return mode;
+}
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief This function update the default firmware name
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_update_firmware_name(moal_handle *handle)
+{
+ if (handle->params.fw_name) {
+ handle->drv_mode.fw_name = handle->params.fw_name;
+ } else {
+ if (!moal_extflg_isset(handle, EXT_FW_SERIAL) ||
+ handle->fw_reload || handle->params.fw_reload) {
+ handle->drv_mode.fw_name =
+ handle->card_info->fw_name_wlan;
+ } else
+ handle->drv_mode.fw_name = handle->card_info->fw_name;
+ }
+}
+/**
+ * @brief This function dynamically populates the driver mode table
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param drv_mode_local Driver mode
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_update_drv_tbl(moal_handle *handle, int drv_mode_local)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int intf_num = 0;
+ int i = 0, j = 0;
+ mlan_bss_attr *bss_tbl = NULL;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ int last_wfd_index = 0;
+ int max_vir_bss = handle->params.max_vir_bss;
+#endif
+#endif
+#ifdef STA_SUPPORT
+ int max_sta_bss = handle->params.max_sta_bss;
+#endif
+#ifdef UAP_SUPPORT
+ int max_uap_bss = handle->params.max_uap_bss;
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ int max_wfd_bss = handle->params.max_wfd_bss;
+#endif
+
+ ENTER();
+
+ /* Calculate number of interfaces */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) {
+ PRINTM(MWARN,
+ "Unsupported max_sta_bss (%d), setting to default\n",
+ max_sta_bss);
+ max_sta_bss = DEF_STA_BSS;
+ }
+ intf_num += max_sta_bss;
+ handle->params.max_sta_bss = max_sta_bss;
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) {
+ PRINTM(MWARN,
+ "Unsupported max_uap_bss (%d), setting to default\n",
+ max_uap_bss);
+ max_uap_bss = DEF_UAP_BSS;
+ }
+ intf_num += max_uap_bss;
+ handle->params.max_uap_bss = max_uap_bss;
+ }
+#endif /* UAP_SUPPORT */
+
+#ifdef WIFI_DIRECT_SUPPORT
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) {
+ PRINTM(MWARN,
+ "Unsupported max_wfd_bss (%d), setting to default\n",
+ max_wfd_bss);
+ max_wfd_bss = DEF_WIFIDIRECT_BSS;
+ }
+ intf_num += max_wfd_bss;
+ handle->params.max_wfd_bss = max_wfd_bss;
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ intf_num += max_vir_bss;
+#endif
+ }
+
+#endif /* WIFI_DIRECT_SUPPORT */
+
+ /* Create BSS attribute table */
+ if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) {
+ PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ } else {
+ /* Create new table */
+ bss_tbl = kmalloc(sizeof(mlan_bss_attr) * intf_num, GFP_KERNEL);
+ if (!bss_tbl) {
+ PRINTM(MERROR,
+ "Could not create BSS attribute table\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Populate BSS attribute table */
+#ifdef STA_SUPPORT
+ if (drv_mode_local & DRV_MODE_STA) {
+ for (j = 0; j < max_sta_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ bss_tbl[i].bss_virtual = MFALSE;
+ i++;
+ }
+ }
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+ if (drv_mode_local & DRV_MODE_UAP) {
+ for (j = 0; j < max_uap_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ bss_tbl[i].bss_virtual = MFALSE;
+ i++;
+ }
+ }
+#endif /* UAP_SUPPORT */
+
+#ifdef WIFI_DIRECT_SUPPORT
+ if (drv_mode_local & DRV_MODE_WIFIDIRECT) {
+ for (j = 0; j < max_wfd_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j;
+ bss_tbl[i].bss_virtual = MFALSE;
+ i++;
+ }
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ last_wfd_index = j;
+#endif
+ }
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ /** append virtual interface at the end of table */
+ for (j = 0; j < max_vir_bss; j++) {
+ if (i >= intf_num)
+ break;
+ bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT;
+ bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II;
+ bss_tbl[i].active = MTRUE;
+ bss_tbl[i].bss_priority = 0;
+ bss_tbl[i].bss_num = j + last_wfd_index;
+ bss_tbl[i].bss_virtual = MTRUE;
+ i++;
+ }
+#endif
+#endif
+
+ /* Clear existing table, if any */
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+
+ /* Create moal_drv_mode entry */
+ handle->drv_mode.drv_mode = handle->params.drv_mode;
+ handle->drv_mode.intf_num = intf_num;
+ handle->drv_mode.bss_attr = bss_tbl;
+
+ /* update default firmware name */
+ woal_update_firmware_name(handle);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes software
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_init_sw(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ unsigned int i;
+ mlan_device device;
+ t_void *pmlan;
+ int cfg80211_wext = handle->params.cfg80211_wext;
+
+ ENTER();
+
+ /* Initialize moal_handle structure */
+ handle->hardware_status = HardwareStatusInitializing;
+ handle->main_state = MOAL_STATE_IDLE;
+
+#ifdef STA_SUPPORT
+ if ((handle->params.drv_mode & DRV_MODE_STA)
+#ifdef STA_WEXT
+ && !IS_STA_WEXT(cfg80211_wext)
+#endif
+#ifdef STA_CFG80211
+ && !IS_STA_CFG80211(cfg80211_wext)
+#endif
+#ifdef MFG_CMD_SUPPORT
+ && !handle->params.mfg_mode
+#endif
+ ) {
+ PRINTM(MERROR,
+ "STA without WEXT or CFG80211 bit definition!\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#endif /* STA_SUPPORT */
+
+#if defined(STA_CFG80211) && defined(STA_SUPPORT)
+ if (IS_STA_CFG80211(cfg80211_wext))
+ cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
+#endif
+
+#if defined(UAP_CFG80211) && defined(UAP_SUPPORT)
+ if (IS_UAP_CFG80211(cfg80211_wext))
+ cfg80211_wext |= STA_CFG80211_MASK | UAP_CFG80211_MASK;
+#endif
+ handle->params.cfg80211_wext = cfg80211_wext;
+ moal_memcpy_ext(handle, handle->driver_version, driver_version,
+ strlen(driver_version), MLAN_MAX_VER_STR_LEN - 1);
+
+ if (woal_update_drv_tbl(handle, handle->params.drv_mode) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /** user config file */
+ init_waitqueue_head(&handle->init_user_conf_wait_q);
+
+ /* PnP and power profile */
+ handle->surprise_removed = MFALSE;
+ init_waitqueue_head(&handle->init_wait_q);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ spin_lock_init(&handle->queue_lock);
+#endif
+ spin_lock_init(&handle->driver_lock);
+ spin_lock_init(&handle->ioctl_lock);
+ spin_lock_init(&handle->scan_req_lock);
+
+ handle->is_suspended = MFALSE;
+ handle->hs_activated = MFALSE;
+ handle->hs_auto_arp = MTRUE;
+ handle->suspend_fail = MFALSE;
+ handle->hs_skip_count = 0;
+ handle->hs_force_count = 0;
+#ifdef SDIO
+ if (IS_SD(handle->card_type)) {
+#ifdef SDIO_SUSPEND_RESUME
+ handle->suspend_notify_req = MFALSE;
+#endif
+ handle->cmd52_func = 0;
+ handle->cmd52_reg = 0;
+ handle->cmd52_val = 0;
+ }
+#endif
+
+ if (handle->params.scan_chan_gap &&
+ (handle->params.scan_chan_gap <= MRVDRV_MAX_SCAN_CHAN_GAP_TIME))
+ handle->scan_chan_gap = handle->params.scan_chan_gap;
+ else
+ handle->scan_chan_gap = DEF_SCAN_CHAN_GAP;
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+ handle->miracast_scan_time = DEF_MIRACAST_SCAN_TIME;
+#define DEF_NOA_DURATION 0
+#define DEF_NOA_INTERVAL 100
+ handle->noa_duration = DEF_NOA_DURATION;
+ handle->noa_interval = DEF_NOA_INTERVAL;
+#endif
+#endif
+
+ if (IS_USB(handle->card_type))
+ init_waitqueue_head(&handle->suspend_wait_q);
+ init_waitqueue_head(&handle->hs_activate_wait_q);
+
+ /* Initialize measurement wait queue */
+ handle->meas_wait_q_woken = MFALSE;
+ handle->meas_start_jiffies = 0;
+ handle->cac_period = MFALSE;
+ handle->delay_bss_start = MFALSE;
+ init_waitqueue_head(&handle->meas_wait_q);
+#if defined(UAP_SUPPORT)
+ handle->chsw_wait_q_woken = MFALSE;
+ init_waitqueue_head(&handle->chsw_wait_q);
+#endif
+
+ handle->cac_period_jiffies = 0;
+ handle->usr_nop_period_sec = 0;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ memset(&handle->dfs_channel, 0, sizeof(struct cfg80211_chan_def));
+ woal_initialize_timer(&handle->cac_timer, woal_cac_timer_func, handle);
+ handle->is_cac_timer_set = MFALSE;
+ handle->cac_bss_index = 0xff;
+#endif
+#endif
+
+#ifdef REASSOCIATION
+ MOAL_INIT_SEMAPHORE(&handle->reassoc_sem);
+ handle->reassoc_on = 0;
+
+ /* Initialize the timer for the reassociation */
+ woal_initialize_timer(&handle->reassoc_timer, woal_reassoc_timer_func,
+ handle);
+
+ handle->is_reassoc_timer_set = MFALSE;
+#endif /* REASSOCIATION */
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ /* Initialize the timer for GO timeout */
+ woal_initialize_timer(&handle->go_timer, woal_go_timer_func, handle);
+
+ handle->is_go_timer_set = MFALSE;
+#endif
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ handle->remain_on_channel = MFALSE;
+
+ /* Initialize the timer for remain on channel */
+ woal_initialize_timer(&handle->remain_timer, woal_remain_timer_func,
+ handle);
+
+ handle->is_remain_timer_set = MFALSE;
+#endif
+#endif
+
+ /* Register to MLAN */
+ memset(&device, 0, sizeof(mlan_device));
+ device.pmoal_handle = handle;
+ device.card_type = handle->card_type;
+ device.card_rev = handle->card_rev;
+#ifdef USB
+ if (IS_USB(handle->card_type)) {
+ struct usb_card_rec *cardp = handle->card;
+ device.tx_cmd_ep = cardp->tx_cmd_ep;
+ device.rx_cmd_ep = cardp->rx_cmd_ep;
+ device.tx_data_ep = cardp->tx_data_ep;
+ device.rx_data_ep = cardp->rx_data_ep;
+ }
+#endif
+#ifdef MFG_CMD_SUPPORT
+ device.mfg_mode = (t_u32)handle->params.mfg_mode;
+#endif
+#ifdef DEBUG_LEVEL1
+ device.drvdbg = drvdbg;
+#endif
+ device.fixed_beacon_buffer =
+ (t_u32)moal_extflg_isset(handle, EXT_FIX_BCN_BUF);
+ device.auto_ds = (t_u32)handle->params.auto_ds;
+ device.ps_mode = (t_u32)handle->params.ps_mode;
+ device.passive_to_active_scan = (t_u8)handle->params.p2a_scan;
+ device.max_tx_buf = (t_u32)handle->params.max_tx_buf;
+#if defined(STA_SUPPORT)
+ device.cfg_11d = (t_u32)handle->params.cfg_11d;
+#endif
+ device.indrstcfg = (t_u32)handle->params.indrstcfg;
+#ifdef SDIO
+ if (IS_SD(handle->card_type)) {
+ device.sdio_rx_aggr_enable =
+ moal_extflg_isset(handle, EXT_SDIO_RX_AGGR);
+ device.int_mode = (t_u32)moal_extflg_isset(handle, EXT_INTMODE);
+ device.gpio_pin = (t_u32)handle->params.gpiopin;
+#ifdef SDIO_MMC
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
+ device.max_segs = ((struct sdio_mmc_card *)handle->card)
+ ->func->card->host->max_segs;
+ device.max_seg_size = ((struct sdio_mmc_card *)handle->card)
+ ->func->card->host->max_seg_size;
+#endif
+ PRINTM(MMSG, "SDIO: max_segs=%d max_seg_size=%d\n",
+ device.max_segs, device.max_seg_size);
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
+ device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
+#else
+ device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED;
+ device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED;
+#endif
+#else
+ device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED;
+ device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED;
+#endif /* SDIO_MMC */
+ }
+#endif /* SDIO */
+ device.feature_control = handle->card_info->feature_control;
+ handle->feature_control = device.feature_control;
+
+ if (handle->params.rx_work == MLAN_INIT_PARA_ENABLED)
+ device.rx_work = MTRUE;
+ else if (handle->params.rx_work == MLAN_INIT_PARA_DISABLED)
+ device.rx_work = MFALSE;
+ else {
+ if (num_possible_cpus() > 1)
+ device.rx_work = MTRUE;
+ else
+ device.rx_work = MFALSE;
+ }
+ PRINTM(MMSG, "rx_work=%d cpu_num=%d\n", device.rx_work,
+ num_possible_cpus());
+ if (moal_extflg_isset(handle, EXT_NAPI))
+ device.rx_work = MTRUE;
+
+ device.dev_cap_mask = handle->params.dev_cap_mask;
+
+ device.multi_dtim = handle->params.multi_dtim;
+
+ device.inact_tmo = handle->params.inact_tmo;
+#ifdef UAP_SUPPORT
+ device.uap_max_sta = handle->params.uap_max_sta;
+#endif
+ device.hs_wake_interval = handle->params.hs_wake_interval;
+ device.indication_gpio = handle->params.indication_gpio;
+ device.hs_mimo_switch = moal_extflg_isset(handle, EXT_HS_MIMO_SWITCH);
+
+ device.dfs53cfg = handle->params.dfs53cfg;
+
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ device.bss_attr[i].bss_type =
+ handle->drv_mode.bss_attr[i].bss_type;
+ device.bss_attr[i].frame_type =
+ handle->drv_mode.bss_attr[i].frame_type;
+ device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active;
+ device.bss_attr[i].bss_priority =
+ handle->drv_mode.bss_attr[i].bss_priority;
+ device.bss_attr[i].bss_num =
+ handle->drv_mode.bss_attr[i].bss_num;
+ device.bss_attr[i].bss_virtual =
+ handle->drv_mode.bss_attr[i].bss_virtual;
+ }
+ moal_memcpy_ext(handle, &device.callbacks, &woal_callbacks,
+ sizeof(mlan_callbacks), sizeof(mlan_callbacks));
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ device.fw_region = fw_region;
+#endif
+#endif
+ device.drv_mode = handle->params.drv_mode;
+ if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan))
+ handle->pmlan_adapter = pmlan;
+ else
+ ret = MLAN_STATUS_FAILURE;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the structure of moal_handle
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_free_moal_handle(moal_handle *handle)
+{
+ moal_handle *ref_handle = NULL;
+
+ ENTER();
+ if (!handle) {
+ PRINTM(MERROR, "The handle is NULL\n");
+ LEAVE();
+ return;
+ }
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (handle->wiphy) {
+ wiphy_unregister(handle->wiphy);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ woal_cfg80211_free_iftype_data(handle->wiphy);
+#endif
+ wiphy_free(handle->wiphy);
+ handle->wiphy = NULL;
+ }
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+ if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) {
+ sock_release((handle->nl_sk)->sk_socket);
+ handle->nl_sk = NULL;
+ }
+#else
+ netlink_kernel_release(handle->nl_sk);
+#endif
+
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ handle->pmlan_adapter = NULL;
+ }
+
+ /* Free BSS attribute table */
+ kfree(handle->drv_mode.bss_attr);
+ handle->drv_mode.bss_attr = NULL;
+ PRINTM(MINFO, "Free Adapter\n");
+ if (atomic_read(&handle->lock_count) ||
+ atomic_read(&handle->malloc_count) ||
+ atomic_read(&handle->mbufalloc_count)) {
+ PRINTM(MERROR,
+ "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
+ atomic_read(&handle->lock_count),
+ atomic_read(&handle->malloc_count),
+ atomic_read(&handle->mbufalloc_count));
+ }
+#ifdef PCIE
+ if (IS_PCIE(handle->card_type) &&
+ atomic_read(&handle->malloc_cons_count)) {
+ PRINTM(MERROR, "mlan has memory leak: malloc_cons_count=%d\n",
+ atomic_read(&handle->malloc_cons_count));
+ }
+#endif
+
+ /* Free allocated memory for fwdump filename */
+ kfree(handle->fwdump_fname);
+ if (fwdump_fname) {
+ kfree(fwdump_fname);
+ fwdump_fname = NULL;
+ }
+ /* Free module params */
+ woal_free_module_param(handle);
+ /** clear pref_mac to avoid later crash */
+ if (handle->pref_mac) {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle->pref_mac && (ref_handle->pref_mac == handle))
+ ref_handle->pref_mac = NULL;
+ }
+ /* Free the moal handle itself */
+ kfree(handle);
+ LEAVE();
+}
+
+/**
+ * @brief WOAL get one line data from ASCII format data
+ *
+ * @param data Source data
+ * @param size Source data length
+ * @param line_pos Destination data
+ * @return routnine status
+ */
+static t_size parse_cfg_get_line(t_u8 *data, t_size size, t_u8 *line_pos)
+{
+ t_u8 *src, *dest;
+ static t_s32 pos;
+
+ ENTER();
+
+ if (pos >= size) { /* reach the end */
+ pos = 0; /* Reset position for rfkill */
+ LEAVE();
+ return -1;
+ }
+ memset(line_pos, 0, MAX_LINE_LEN);
+ src = data + pos;
+ dest = line_pos;
+
+ while ((dest - line_pos < MAX_LINE_LEN - 1) && pos < size &&
+ *src != '\x0A' && *src != '\0') {
+ if (*src != ' ' && *src != '\t') /* parse space */
+ *dest++ = *src++;
+ else
+ src++;
+ pos++;
+ }
+ /* parse new line */
+ pos++;
+ *dest = '\0';
+ LEAVE();
+ return strlen(line_pos);
+}
+
+/**
+ * @brief Process register access request
+ * @param type_string String format Register type
+ * @param offset_string String format Register offset
+ * @param value_string String format Pointer to value
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 woal_process_regrdwr(moal_handle *handle, t_u8 *type_string,
+ t_u8 *offset_string, t_u8 *value_string)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ int type, offset, value;
+ pmlan_ioctl_req ioctl_req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+
+ ENTER();
+
+ /* Alloc ioctl_req */
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+
+ if (ioctl_req == NULL) {
+ PRINTM(MERROR, "Can't alloc memory\n");
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string))
+ goto done;
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string))
+ goto done;
+ if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string))
+ goto done;
+
+ ioctl_req->req_id = MLAN_IOCTL_REG_MEM;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ reg = (mlan_ds_reg_mem *)ioctl_req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ if (type < 5) {
+ reg->param.reg_rw.type = type;
+ } else {
+ PRINTM(MERROR, "Unsupported Type\n");
+ goto done;
+ }
+ reg->param.reg_rw.offset = offset;
+ reg->param.reg_rw.value = value;
+
+ /* request ioctl for STA */
+ ret = woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type,
+ offset, value);
+ ret = MLAN_STATUS_SUCCESS;
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(SDIO)
+/**
+ * @brief Read/Write registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action get / set action
+ * @param type type of register
+ * @param offset offset of register
+ * @param value value of registere
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_getset_regrdwr(moal_private *priv, t_u32 action, t_u32 type,
+ t_u32 offset, t_u32 *value)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *)req->pbuf;
+ reg_mem->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+ req->action = action;
+
+ reg_mem->param.reg_rw.type = type;
+ reg_mem->param.reg_rw.offset = offset;
+ if (req->action == MLAN_ACT_SET)
+ reg_mem->param.reg_rw.value = *value;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ *value = reg_mem->param.reg_rw.value;
+ PRINTM(MINFO, "woal_getset_regrdwr value=%x\n", *value);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set slew rate mode
+ *
+ * @param handle MOAL handle
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 woal_set_sdio_slew_rate(moal_handle *handle)
+{
+ t_u32 value = 0;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ t_u32 new_value = 0;
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv)
+ return MLAN_STATUS_FAILURE;
+
+ if ((handle->card_info->slew_rate_reg != 0) &&
+ (handle->params.slew_rate > 3 || handle->params.slew_rate < 0))
+ return MLAN_STATUS_FAILURE;
+
+ ret = woal_getset_regrdwr(priv, MLAN_ACT_GET, MLAN_REG_MAC,
+ handle->card_info->slew_rate_reg, &value);
+ if (ret < 0) {
+ PRINTM(MERROR, "woal_getset_regrdwr get REG_MAC failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ new_value = value & ~(0x3 << handle->card_info->slew_rate_bit_offset);
+ new_value |= (t_u32)handle->params.slew_rate
+ << handle->card_info->slew_rate_bit_offset;
+
+ if (value != new_value) {
+ PRINTM(MMSG, "Set REG 0x%8x: 0x%x slew_rate=%d\n",
+ handle->card_info->slew_rate_reg, new_value,
+ handle->params.slew_rate);
+ ret = woal_getset_regrdwr(priv, MLAN_ACT_SET, MLAN_REG_MAC,
+ handle->card_info->slew_rate_reg,
+ &new_value);
+ if (ret < 0) {
+ PRINTM(MERROR,
+ "woal_getset_regrdwr get REG_MAC failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ }
+done:
+ return ret;
+}
+#endif /* SDIO */
+
+#ifdef UAP_SUPPORT
+/**
+ * @brief set uap operation contrl value
+ *
+ * @param handle MOAL handle
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_set_uap_operation_ctrl(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int uap_oper_ctrl;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_UAP);
+ if (!priv) {
+ PRINTM(MERROR,
+ "woal_set_uap_operation_ctrl failed, no uap interface\n");
+ LEAVE();
+ return ret;
+ }
+ uap_oper_ctrl = handle->params.uap_oper_ctrl;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_OPER_CTRL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ bss->param.ap_oper_ctrl.ctrl_value =
+ (t_u16)((uap_oper_ctrl & 0xffff0000) >> 16);
+ bss->param.ap_oper_ctrl.chan_opt = (t_u16)(uap_oper_ctrl & 0xffff);
+ PRINTM(MMSG, "Uap oper_ctrl=0x%x chan_opt=0x%x\n",
+ bss->param.ap_oper_ctrl.ctrl_value,
+ bss->param.ap_oper_ctrl.chan_opt);
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief WOAL parse ASCII format data to MAC address
+ *
+ * @param handle MOAL handle
+ * @param data Source data
+ * @param size data length
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 woal_process_init_cfg(moal_handle *handle, t_u8 *data, t_size size)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *pos;
+ t_u8 *intf_s, *intf_e;
+ t_u8 s[MAX_LINE_LEN]; /* 1 line data */
+ t_size line_len;
+ t_u8 index = 0;
+ t_u32 i;
+ t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN];
+ t_u8 bss_mac_name[MAX_PARAM_LEN];
+ t_u8 type[MAX_PARAM_LEN];
+ t_u8 offset[MAX_PARAM_LEN];
+ t_u8 value[MAX_PARAM_LEN];
+
+ ENTER();
+
+ while ((line_len = parse_cfg_get_line(data, size, s)) != -1) {
+ pos = s;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') ||
+ *pos == '\n' || *pos == '\0')
+ continue; /* Needn't process this line */
+
+ /* Process MAC addr */
+ if (strncmp(pos, "mac_addr", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ':');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ strncpy(bss_mac_addr, intf_e + 1,
+ MAX_MAC_ADDR_LEN - 1);
+ bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0';
+ if ((intf_e - intf_s) > MAX_PARAM_LEN) {
+ PRINTM(MERROR,
+ "Too long interface name %d\n",
+ __LINE__);
+ goto done;
+ }
+ strncpy(bss_mac_name, intf_s + 1,
+ intf_e - intf_s - 1);
+ bss_mac_name[intf_e - intf_s - 1] = '\0';
+ for (i = 0; i < handle->priv_num; i++) {
+ if (strcmp(bss_mac_name,
+ handle->priv[i]
+ ->netdev->name) ==
+ 0) {
+ memset(handle->priv[i]
+ ->current_addr,
+ 0, ETH_ALEN);
+ PRINTM(MINFO,
+ "Interface name: %s mac: %s\n",
+ bss_mac_name,
+ bss_mac_addr);
+ woal_mac2u8(
+ handle->priv[i]
+ ->current_addr,
+ bss_mac_addr);
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (handle->priv[i]->bss_type ==
+ MLAN_BSS_TYPE_WIFIDIRECT) {
+ handle->priv[i]
+ ->current_addr[0] |=
+ 0x02;
+ PRINTM(MCMND,
+ "Set WFD device addr: " MACSTR
+ "\n",
+ MAC2STR(handle->priv[i]
+ ->current_addr));
+ }
+#endif
+#endif
+#endif
+ /* Set WLAN MAC addresses */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_set_mac_address(
+ handle->priv[i],
+ MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR,
+ "Set MAC address failed\n");
+ goto done;
+ }
+ moal_memcpy_ext(
+ handle,
+ handle->priv[i]
+ ->netdev
+ ->dev_addr,
+ handle->priv[i]
+ ->current_addr,
+ ETH_ALEN, ETH_ALEN);
+ index++; /* Mark found one
+ interface matching
+ */
+ }
+ }
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n",
+ __LINE__);
+ goto done;
+ }
+ }
+ /* Process REG value */
+ else if (strncmp(pos, "wlan_reg", 8) == 0) {
+ intf_s = strchr(pos, '=');
+ if (intf_s != NULL)
+ intf_e = strchr(intf_s, ',');
+ else
+ intf_e = NULL;
+ if (intf_s != NULL && intf_e != NULL) {
+ /* Copy type */
+ strncpy(type, intf_s + 1, 1);
+ type[1] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n",
+ __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ intf_e = strchr(intf_s, ',');
+ if (intf_e != NULL) {
+ if ((intf_e - intf_s) >= MAX_PARAM_LEN) {
+ PRINTM(MERROR,
+ "Regsier offset is too long %d\n",
+ __LINE__);
+ goto done;
+ }
+ /* Copy offset */
+ strncpy(offset, intf_s, intf_e - intf_s);
+ offset[intf_e - intf_s] = '\0';
+ } else {
+ PRINTM(MERROR, "Wrong config file format %d\n",
+ __LINE__);
+ goto done;
+ }
+ intf_s = intf_e + 1;
+ if ((strlen(intf_s) >= MAX_PARAM_LEN)) {
+ PRINTM(MERROR, "Regsier value is too long %d\n",
+ __LINE__);
+ goto done;
+ }
+ /* Copy value */
+ strncpy(value, intf_s,
+ MIN((MAX_PARAM_LEN - 1), strlen(intf_s)));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_process_regrdwr(handle, type, offset, value)) {
+ PRINTM(MERROR, "Access Reg failed\n");
+ goto done;
+ }
+ PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n",
+ type, offset, value);
+ }
+ }
+
+ if (index == 0)
+ PRINTM(MINFO, "Can't find any matching MAC Address");
+ ret = MLAN_STATUS_SUCCESS;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief WOAL parse ASCII format raw data to hex format
+ *
+ * @param handle MOAL handle
+ * @param data Source data
+ * @param size data length
+ * @param wait_option wait option
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 woal_process_hostcmd_cfg(moal_handle *handle, t_u8 *data,
+ t_size size, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 *pos = data;
+ t_u8 *intf_s, *intf_e;
+ t_u8 *buf = NULL;
+ t_u8 *ptr = NULL;
+ t_u32 cmd_len = 0;
+ t_u8 start_raw = MFALSE;
+ gfp_t flag;
+
+#define CMD_STR "MRVL_CMDhostcmd"
+#define CMD_BUF_LEN 2048
+
+ ENTER();
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ buf = kzalloc(CMD_BUF_LEN, flag);
+ if (!buf) {
+ PRINTM(MERROR, "Could not allocate buffer space!\n");
+ goto done;
+ }
+ ptr = buf;
+ strcpy(ptr, CMD_STR);
+ ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
+ while ((pos - data) < size) {
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '#') { /* Line comment */
+ while (*pos != '\n')
+ pos++;
+ pos++;
+ }
+ if ((*pos == '\r' && *(pos + 1) == '\n') || *pos == '\n' ||
+ *pos == '\0') {
+ pos++;
+ continue; /* Needn't process this line */
+ }
+
+ if (*pos == '}') {
+ cmd_len = *((t_u16 *)(buf + strlen(CMD_STR) +
+ sizeof(t_u32) + sizeof(t_u16)));
+ moal_memcpy_ext(handle, buf + strlen(CMD_STR), &cmd_len,
+ sizeof(t_u32),
+ CMD_BUF_LEN - strlen(CMD_STR));
+
+ /* fire the hostcommand from here */
+ woal_priv_hostcmd(handle->priv[0], buf, CMD_BUF_LEN,
+ wait_option);
+ memset(buf + strlen(CMD_STR), 0,
+ CMD_BUF_LEN - strlen(CMD_STR));
+ ptr = buf + strlen(CMD_STR) + sizeof(t_u32);
+ start_raw = MFALSE;
+ pos++;
+ continue;
+ }
+
+ if (start_raw == MFALSE) {
+ intf_s = strchr(pos, '=');
+ if (intf_s)
+ intf_e = strchr(intf_s, '{');
+ else
+ intf_e = NULL;
+
+ if (intf_s && intf_e) {
+ start_raw = MTRUE;
+ pos = intf_e + 1;
+ continue;
+ }
+ }
+
+ if (start_raw) {
+ /* Raw data block exists */
+ while (*pos != '\n') {
+ if ((*pos <= 'f' && *pos >= 'a') ||
+ (*pos <= 'F' && *pos >= 'A') ||
+ (*pos <= '9' && *pos >= '0')) {
+ *ptr++ = woal_atox(pos);
+ pos += 2;
+ } else
+ pos++;
+ }
+ }
+ }
+
+done:
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+#define INIT_CFG_DATA 0x00
+#define INIT_HOSTCMD_CFG_DATA 0x02
+#define COUNTRY_POWER_TABLE 0x04
+#define BAND_STEER_CFG_DATA 0x08
+
+/**
+ * @brief Request init conf firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_request_init_user_conf_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ if (!handle) {
+ LEAVE();
+ return;
+ }
+ if (firmware)
+ handle->user_data = firmware;
+ else
+ PRINTM(MERROR, "User init config request firmware failed\n");
+
+ handle->init_user_conf_wait_flag = MTRUE;
+ wake_up_interruptible(&handle->init_user_conf_wait_q);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Request init conf firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void woal_request_init_dpd_conf_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ if (!handle) {
+ LEAVE();
+ return;
+ }
+ if (firmware && handle)
+ handle->dpd_data = firmware;
+ else
+ PRINTM(MERROR, "User init cfg data request firmware failed\n");
+
+ handle->init_user_conf_wait_flag = MTRUE;
+ wake_up_interruptible(&handle->init_user_conf_wait_q);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Request init conf firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void woal_request_vdll_fw_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ if (!handle) {
+ LEAVE();
+ return;
+ }
+ if (firmware && handle)
+ handle->firmware = firmware;
+ else
+ PRINTM(MERROR, "VDLL: Request firmware failed\n");
+
+ handle->init_user_conf_wait_flag = MTRUE;
+ wake_up_interruptible(&handle->init_user_conf_wait_q);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Request firmware image for VDLL
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_vdll_req_fw(moal_handle *handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+ char *vdll_fw = handle->drv_mode.fw_name;
+
+ ENTER();
+ if (vdll_fw) {
+ PRINTM(MMSG, "VDLL: Request firmware: %s\n", vdll_fw);
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG, vdll_fw,
+ handle->hotplug_device, GFP_KERNEL, handle,
+ woal_request_vdll_fw_callback)) < 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG, vdll_fw,
+ handle->hotplug_device, handle,
+ woal_request_vdll_fw_callback)) < 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, vdll_fw,
+ handle->hotplug_device, handle,
+ woal_request_vdll_fw_callback)) < 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "VDLL: request_firmware_nowait() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->firmware, vdll_fw,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR,
+ "VDLL: request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request init conf firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void
+woal_request_init_txpwr_conf_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ if (!handle) {
+ LEAVE();
+ return;
+ }
+ if (firmware && handle)
+ handle->txpwr_data = firmware;
+ else
+ PRINTM(MERROR, "User init cfg data request firmware failed\n");
+
+ handle->init_user_conf_wait_flag = MTRUE;
+ wake_up_interruptible(&handle->init_user_conf_wait_q);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Request init conf firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void woal_request_init_cfg_data_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ if (!handle) {
+ LEAVE();
+ return;
+ }
+ if (firmware && handle)
+ handle->init_cfg_data = firmware;
+ else
+ PRINTM(MERROR, "User init cfg data request firmware failed\n");
+
+ handle->init_user_conf_wait_flag = MTRUE;
+ wake_up_interruptible(&handle->init_user_conf_wait_q);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief WOAL set user defined init data and param
+ *
+ * @param handle MOAL handle structure
+ * @param type type argument
+ * @param wait_option wait option
+ * @param country_txpwrlimit Configure Tx Power Limit
+ * @return MLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static t_u32 woal_set_user_init_data(moal_handle *handle, int type,
+ t_u8 wait_option, char *country_txpwrlimit)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *cfg_data = NULL;
+ t_size len;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+ char *init_cfg = handle->params.init_cfg;
+ char *init_hostcmd_cfg = handle->params.init_hostcmd_cfg;
+ char *band_steer_cfg = handle->params.band_steer_cfg;
+
+ ENTER();
+
+ if (type == INIT_CFG_DATA) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
+ handle->hotplug_device, GFP_KERNEL, handle,
+ woal_request_init_cfg_data_callback)) < 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG, init_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_cfg_data_callback)) < 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, init_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_cfg_data_callback)) < 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "Init config file request_firmware_nowait() failed\n");
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->init_cfg_data, init_cfg,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR,
+ "Init config file request_firmware() failed\n");
+ goto done;
+ }
+ }
+ } else if (type == COUNTRY_POWER_TABLE) {
+ if (country_txpwrlimit == NULL) {
+ PRINTM(MERROR,
+ "The parameter 'country_txpwrlimit' is NULL\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ /* 'country_txpwrlimit' holds the value of Configured Tx Power
+ * Limit */
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ country_txpwrlimit, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ country_txpwrlimit, handle->hotplug_device,
+ handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, country_txpwrlimit,
+ handle->hotplug_device, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "country txpwrlimit config file request_firmware_nowait() failed\n");
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ int status = request_firmware(&handle->user_data,
+ country_txpwrlimit,
+ handle->hotplug_device);
+ /* File does not exist, skip download */
+ if (status == -ENOENT) {
+ ret = MLAN_STATUS_FILE_ERR;
+ PRINTM(MIOCTL,
+ "Country power table file does not exist\n");
+ goto done;
+ } else if (status) {
+ PRINTM(MERROR,
+ "country txpwrlimit config file request_firmware() failed\n");
+ goto done;
+ }
+ }
+ } else if (type == INIT_HOSTCMD_CFG_DATA) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ init_hostcmd_cfg, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ init_hostcmd_cfg, handle->hotplug_device,
+ handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, init_hostcmd_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "Init hostcmd config file request_firmware_nowait() failed\n");
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->user_data,
+ init_hostcmd_cfg,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR,
+ "Init hostcmd config file request_firmware() failed\n");
+ goto done;
+ }
+ }
+ }
+ if (type == BAND_STEER_CFG_DATA) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ band_steer_cfg, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ band_steer_cfg, handle->hotplug_device,
+ handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, band_steer_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "band_steer_cfg request_firmware_nowait() failed\n");
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->user_data,
+ band_steer_cfg,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR,
+ "band_steer_cfg file request_firmware() failed\n");
+ goto done;
+ }
+ }
+ }
+ if (handle->user_data) {
+ cfg_data = (t_u8 *)(handle->user_data)->data;
+ len = (handle->user_data)->size;
+ if (type == INIT_HOSTCMD_CFG_DATA ||
+ type == BAND_STEER_CFG_DATA ||
+ type == COUNTRY_POWER_TABLE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_process_hostcmd_cfg(handle, cfg_data, len,
+ wait_option)) {
+ PRINTM(MERROR,
+ "Can't process hostcmd config file\n");
+ goto done;
+ }
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ } else if (type == INIT_CFG_DATA && handle->init_cfg_data) {
+ PRINTM(MIOCTL, "Load init_cfg success\n");
+ ret = MLAN_STATUS_SUCCESS;
+ }
+done:
+ if (handle->user_data) {
+ release_firmware(handle->user_data);
+ handle->user_data = NULL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure aggrctrl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_init_aggr_ctrl(moal_handle *handle, t_u8 wait_option)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ req->action = MLAN_ACT_SET;
+ pcfg_misc->param.aggr_params.tx.enable = MTRUE;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Add interfaces DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_add_card_dpc(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int i;
+ char str_buf[MLAN_MAX_VER_STR_LEN];
+ ENTER();
+
+#if defined(USB)
+ if (IS_USB(handle->card_type) && handle->boot_state == USB_FW_DNLD) {
+ /* Return now */
+ LEAVE();
+ return ret;
+ }
+#endif /* USB_NEW_FW_DNLD */
+
+#ifdef CONFIG_PROC_FS
+ /* Initialize proc fs */
+ woal_proc_init(handle);
+#endif /* CONFIG_PROC_FS */
+
+ /* Add interfaces */
+ for (i = 0; i < handle->drv_mode.intf_num; i++) {
+ if (handle->drv_mode.bss_attr[i].bss_virtual)
+ continue;
+ if (!woal_add_interface(handle, handle->priv_num,
+ handle->drv_mode.bss_attr[i].bss_type)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+ woal_get_version(handle, str_buf, sizeof(str_buf) - 1);
+ PRINTM(MMSG, "wlan: version = %s\n", str_buf);
+
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode == MLAN_INIT_PARA_ENABLED)
+ goto done;
+#endif
+
+ if (handle->params.init_cfg && handle->init_cfg_data) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_process_init_cfg(handle,
+ (t_u8 *)(handle->init_cfg_data)->data,
+ (handle->init_cfg_data)->size)) {
+ PRINTM(MERROR, "Can't process init config file\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+ if (moal_extflg_isset(handle, EXT_AGGR_CTRL)) {
+ /* Enable aggregation in FW */
+ if (woal_init_aggr_ctrl(handle, MOAL_IOCTL_WAIT)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+#ifdef USB
+ if (handle->params.usb_aggr == 1) {
+ /* Enable USB aggregation in FW */
+ if (woal_usb_aggr_init(handle)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+#endif
+ /* Add low power mode check */
+ if (moal_extflg_isset(handle, EXT_LOW_PW_MODE) &&
+ handle->card_info->low_power_enable &&
+ woal_set_low_pwr_mode(handle, MOAL_IOCTL_WAIT)) {
+ /* Proceed with Warning */
+ PRINTM(MERROR, "Unable to set Low Power Mode\n");
+ }
+
+#if defined(SDIO)
+ if (IS_SD(handle->card_type))
+ woal_set_sdio_slew_rate(handle);
+#endif
+
+ if (moal_extflg_isset(handle, EXT_PMIC) && handle->card_info->pmic) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_pmic_configure(handle, MOAL_IOCTL_WAIT)) {
+ PRINTM(MFATAL, "Failed to configure PMIC\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+ if (handle->params.antcfg) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_user_antcfg(handle, MOAL_IOCTL_WAIT)) {
+ PRINTM(MFATAL, "Set user antcfg data failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ }
+
+#ifdef UAP_SUPPORT
+ if (handle->params.uap_oper_ctrl)
+ woal_set_uap_operation_ctrl(handle);
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+done:
+#endif
+err:
+ if (handle->params.init_cfg && handle->init_cfg_data) {
+ release_firmware(handle->init_cfg_data);
+ handle->init_cfg_data = NULL;
+ }
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to add interface\n");
+
+ for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
+ woal_remove_interface(handle, i);
+ handle->priv_num = 0;
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request dpd data
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_req_dpd_data(moal_handle *handle,
+ mlan_init_param *param)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+ char *dpd_data_cfg = handle->params.dpd_data_cfg;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (dpd_data_cfg && strncmp(dpd_data_cfg, "none", strlen("none"))) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ dpd_data_cfg, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_dpd_conf_callback)) < 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ dpd_data_cfg, handle->hotplug_device,
+ handle,
+ woal_request_init_dpd_conf_callback)) < 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, dpd_data_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_dpd_conf_callback)) < 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "DPD data request_firmware_nowait() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ status = request_firmware(&handle->dpd_data,
+ dpd_data_cfg,
+ handle->hotplug_device);
+ if (status < 0 && status != -ENOENT) {
+ PRINTM(MERROR,
+ "DPD data request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (handle->dpd_data) {
+ param->pdpd_data_buf = (t_u8 *)handle->dpd_data->data;
+ param->dpd_data_len = handle->dpd_data->size;
+ } else {
+ param->dpd_data_len = UNKNOW_DPD_LENGTH;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request TX Power data
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_req_txpwr_data(moal_handle *handle,
+ mlan_init_param *param)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+ char *txpwrlimit_cfg = handle->params.txpwrlimit_cfg;
+
+ ENTER();
+
+ if (txpwrlimit_cfg && strncmp(txpwrlimit_cfg, "none", strlen("none"))) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ txpwrlimit_cfg, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_txpwr_conf_callback)) <
+ 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ txpwrlimit_cfg, handle->hotplug_device,
+ handle,
+ woal_request_init_txpwr_conf_callback)) <
+ 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, txpwrlimit_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_txpwr_conf_callback)) <
+ 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "Region txpwrlimit cfg data "
+ "request_firmware_nowait() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->txpwr_data,
+ txpwrlimit_cfg,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR, "Region txpwrlimit cfg data "
+ "request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ if (handle->txpwr_data) {
+ param->ptxpwr_data_buf =
+ (t_u8 *)handle->txpwr_data->data;
+ param->txpwr_data_len = handle->txpwr_data->size;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request Cal data
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_req_cal_data(moal_handle *handle,
+ mlan_init_param *param)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+ char *cal_data_cfg = handle->params.cal_data_cfg;
+
+ ENTER();
+ /** Cal data request */
+ if (cal_data_cfg && strncmp(cal_data_cfg, "none", strlen("none"))) {
+ if (req_fw_nowait) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ cal_data_cfg, handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ if ((request_firmware_nowait(
+ THIS_MODULE, FW_ACTION_HOTPLUG,
+ cal_data_cfg, handle->hotplug_device,
+ handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#else
+ if ((request_firmware_nowait(
+ THIS_MODULE, cal_data_cfg,
+ handle->hotplug_device, handle,
+ woal_request_init_user_conf_callback)) <
+ 0) {
+#endif
+#endif
+ PRINTM(MERROR,
+ "Cal data request_firmware_nowait() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ handle->init_user_conf_wait_flag = MFALSE;
+ wait_event_interruptible(
+ handle->init_user_conf_wait_q,
+ handle->init_user_conf_wait_flag);
+ } else {
+ if ((request_firmware(&handle->user_data, cal_data_cfg,
+ handle->hotplug_device)) < 0) {
+ PRINTM(MERROR,
+ "Cal data request_firmware() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+ } else if (!cal_data_cfg && handle->card_info->cal_data_cfg) {
+ PRINTM(MERROR,
+ "Please add cal_data_cfg for 8887/8977/8997/8987/8978\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (handle->user_data) {
+ param->pcal_data_buf = (t_u8 *)handle->user_data->data;
+ param->cal_data_len = handle->user_data->size;
+ }
+done:
+ return ret;
+}
+
+#if defined(USB)
+/**
+ * @brief Download and Initialize firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_reset_usb_dev(moal_handle *handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
+ int usbRstDev_ret = 0;
+
+ ENTER();
+
+ /* Return now */
+ PRINTM(MMSG, "WLAN FW is downloaded\n");
+
+ /* Reset USB device to get re-enumeration */
+ if (udev) {
+#define USB_WAIT_FW_READY (500)
+ mdelay(USB_WAIT_FW_READY);
+ usbRstDev_ret = usb_reset_device(udev);
+ if ((usbRstDev_ret == 0) ||
+ (usbRstDev_ret == -ENODEV) || /* expected
+ since
+ chip
+ re-enumerates
+ */
+ (usbRstDev_ret == -EINVAL)) { /* expected if USB FW detaches
+ first */
+ PRINTM(MMSG, "usb_reset_device() successful.\n");
+ } else {
+ PRINTM(MERROR,
+ "usb_reset_device() failed with error code =%d\n",
+ usbRstDev_ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ PRINTM(MERROR, "ERR: No handle to call usb_reset_device()!\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Download and Initialize firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_init_fw_dpc(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_fw_image fw;
+ mlan_init_param param;
+
+ ENTER();
+
+ if (handle->firmware) {
+ memset(&fw, 0, sizeof(mlan_fw_image));
+ fw.pfw_buf = (t_u8 *)handle->firmware->data;
+ fw.fw_len = handle->firmware->size;
+ if (handle->params.fw_reload == FW_RELOAD_SDIO_INBAND_RESET)
+ fw.fw_reload = handle->params.fw_reload;
+ else
+ fw.fw_reload = 0;
+ wifi_status = 0;
+ ret = mlan_dnld_fw(handle->pmlan_adapter, &fw);
+ if (ret == MLAN_STATUS_FAILURE) {
+ wifi_status = 1;
+ PRINTM(MERROR,
+ "WLAN: Fail download FW with nowwait: %u\n",
+ moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT));
+ if (handle->ops.reg_dbg)
+ handle->ops.reg_dbg(handle);
+ goto done;
+ }
+ wifi_status = 0;
+
+#if defined(USB)
+ if (handle->boot_state == USB_FW_DNLD) {
+ if (!IS_USB8997(handle->card_type) &&
+ !IS_USB9098(handle->card_type) &&
+ !IS_USB9097(handle->card_type) &&
+ !IS_USB8978(handle->card_type))
+ ret = woal_reset_usb_dev(handle);
+ goto done;
+ }
+#endif /* USB_NEW_FW_DNLD */
+ PRINTM(MMSG, "WLAN FW is active\n");
+ handle->driver_status = MFALSE;
+ }
+
+ moal_get_boot_ktime(handle, &handle->on_time);
+ PRINTM(MMSG, "on_time is %llu\n", handle->on_time);
+
+ /** data request */
+ memset(&param, 0, sizeof(mlan_init_param));
+
+ ret = woal_req_dpd_data(handle, &param);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ ret = woal_req_txpwr_data(handle, &param);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ ret = woal_req_cal_data(handle, &param);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ handle->hardware_status = HardwareStatusFwReady;
+#ifdef USB
+ if (IS_USB(handle->card_type) && !handle->fw_reload) {
+ if (handle->skip_fw_dnld != MTRUE) {
+ ret = woal_usb_rx_init(handle);
+ if (ret == MLAN_STATUS_SUCCESS)
+ ret = woal_usb_tx_init(handle);
+ }
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ }
+#endif /* USB */
+ if (handle->fw_reload)
+ goto done;
+ handle->init_wait_q_woken = MFALSE;
+
+ ret = mlan_set_init_param(handle->pmlan_adapter, &param);
+ ret = mlan_init_fw(handle->pmlan_adapter);
+ if (ret == MLAN_STATUS_FAILURE) {
+ wifi_status = 2;
+ goto done;
+ } else if (ret == MLAN_STATUS_SUCCESS) {
+ handle->hardware_status = HardwareStatusReady;
+ goto done;
+ }
+ /* Wait for mlan_init to complete */
+ wait_event_timeout(handle->init_wait_q, handle->init_wait_q_woken,
+ 5 * HZ);
+ if (handle->hardware_status != HardwareStatusReady) {
+ woal_moal_debug_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ handle, MTRUE);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+done:
+ if (handle->dpd_data) {
+ release_firmware(handle->dpd_data);
+ handle->dpd_data = NULL;
+ }
+ if (handle->txpwr_data) {
+ release_firmware(handle->txpwr_data);
+ handle->txpwr_data = NULL;
+ }
+ if (handle->user_data) {
+ release_firmware(handle->user_data);
+ handle->user_data = NULL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware DPC
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param firmware A pointer to firmware image
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_request_fw_dpc(moal_handle *handle,
+ const struct firmware *firmware)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ wifi_timeval tstamp;
+ ENTER();
+
+ if (!firmware) {
+ woal_get_monotonic_time(&tstamp);
+ if (tstamp.time_sec >
+ (handle->req_fw_time.time_sec + REQUEST_FW_TIMEOUT)) {
+ PRINTM(MERROR,
+ "No firmware image found. Skipping download\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MERROR,
+ "request_firmware_nowait failed for %s. Retrying..\n",
+ handle->drv_mode.fw_name);
+ woal_sched_timeout(MOAL_TIMER_1S);
+ woal_request_fw(handle);
+ LEAVE();
+ return ret;
+ }
+ handle->firmware = firmware;
+
+ ret = woal_init_fw_dpc(handle);
+ if (ret)
+ goto done;
+ ret = woal_add_card_dpc(handle);
+ if (ret)
+ goto done;
+
+done:
+ /* We should hold the semaphore until callback finishes execution */
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request firmware callback
+ * This function is invoked by request_firmware_nowait system call
+ *
+ * @param firmware A pointer to firmware image
+ * @param context A pointer to moal_handle structure
+ *
+ * @return N/A
+ */
+static void woal_request_fw_callback(const struct firmware *firmware,
+ void *context)
+{
+ moal_handle *handle;
+
+ ENTER();
+
+ handle = (moal_handle *)context;
+ handle->firmware = firmware;
+ woal_request_fw_dpc((moal_handle *)context, firmware);
+ if (firmware) {
+ release_firmware(firmware);
+ handle->firmware = NULL;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Download firmware using helper
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_request_fw(moal_handle *handle)
+{
+ int err;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u8 req_fw_nowait = moal_extflg_isset(handle, EXT_REQ_FW_NOWAIT);
+
+ ENTER();
+
+ PRINTM(MMSG, "Request firmware: %s\n", handle->drv_mode.fw_name);
+
+ if (req_fw_nowait && !handle->fw_reload) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+ err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device,
+ GFP_KERNEL, handle,
+ woal_request_fw_callback);
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
+ err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback);
+#else
+ err = request_firmware_nowait(THIS_MODULE,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device, handle,
+ woal_request_fw_callback);
+#endif
+#endif
+ if (err < 0) {
+ PRINTM(MFATAL,
+ "WLAN: request_firmware_nowait() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ } else {
+ err = request_firmware(&handle->firmware,
+ handle->drv_mode.fw_name,
+ handle->hotplug_device);
+ if (err < 0) {
+ PRINTM(MFATAL,
+ "WLAN: request_firmware() failed, error code = %d\n",
+ err);
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (handle->fw_reload)
+ ret = woal_init_fw_dpc(handle);
+ else
+ ret = woal_request_fw_dpc(handle,
+ handle->firmware);
+ release_firmware(handle->firmware);
+ handle->firmware = NULL;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initializes firmware
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_init_fw(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+#ifdef USB
+ if (IS_USB(handle->card_type)) {
+ if (MFALSE || (handle->skip_fw_dnld == MTRUE)
+#if defined(USB)
+ || (handle->boot_state == USB_FW_READY)
+#endif /* USB_NEW_FW_DNLD */
+ ) {
+ PRINTM(MMSG, "WLAN FW is active\n");
+ /* Set it to NULL to skip downloading firmware to card
+ */
+ handle->firmware = NULL;
+ ret = woal_init_fw_dpc(handle);
+ if (ret)
+ goto done;
+ ret = woal_add_card_dpc(handle);
+ if (ret)
+ goto done;
+ /* Release semaphore if download is not required */
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ done:
+ LEAVE();
+ return ret;
+ }
+ }
+#endif /* USB */
+
+ woal_get_monotonic_time(&handle->req_fw_time);
+ ret = woal_request_fw(handle);
+ if (ret == MLAN_STATUS_FAILURE) {
+ PRINTM(MFATAL, "woal_request_fw failed\n");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function will fill in the mlan_buffer
+ *
+ * @param pmbuf A pointer to mlan_buffer
+ * @param skb A pointer to struct sk_buff
+ *
+ * @return N/A
+ */
+void woal_fill_mlan_buffer(moal_private *priv, mlan_buffer *pmbuf,
+ struct sk_buff *skb)
+{
+ wifi_timeval tstamp;
+ struct ethhdr *eth;
+ t_u8 tid = 0;
+ dot11_txcontrol *txcontrol;
+ t_u8 tx_ctrl_flag = MFALSE;
+ int i = 0;
+ ENTER();
+ /*
+ * skb->priority values from 256->263 are magic values to
+ * directly indicate a specific 802.1d priority. This is used
+ * to allow 802.1d priority to be passed directly in from VLAN
+ * tags, etc.
+ */
+ if (IS_SKB_MAGIC_VLAN(skb)) {
+ tid = GET_VLAN_PRIO(skb);
+ } else {
+ eth = (struct ethhdr *)skb->data;
+
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+ tid = priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET];
+ if (tid == 0xFF)
+ tid = (IPTOS_PREC(SKB_TOS(skb)) >>
+ IPTOS_OFFSET);
+ PRINTM(MDAT_D,
+ "packet type ETH_P_IP: dscp[%x], map[%x], tid=%d\n",
+ SKB_TOS(skb) >> DSCP_OFFSET,
+ priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET],
+ tid);
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ tid = SKB_TIDV6(skb);
+ PRINTM(MDAT_D,
+ "packet type ETH_P_IPV6: %04x, tid=%#x prio=%#x\n",
+ eth->h_proto, tid, skb->priority);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ tid = 0;
+ PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto);
+ break;
+ default:
+ tid = 0;
+ if (priv->tx_protocols.protocol_num) {
+ for (i = 0; i < priv->tx_protocols.protocol_num;
+ i++) {
+ if (eth->h_proto ==
+ __constant_htons(
+ priv->tx_protocols
+ .protocols[i]))
+ tx_ctrl_flag = MTRUE;
+ }
+ }
+ if (tx_ctrl_flag) {
+ txcontrol = (dot11_txcontrol
+ *)(skb->data +
+ sizeof(struct ethhdr));
+ pmbuf->u.tx_info.data_rate =
+ txcontrol->datarate;
+ pmbuf->u.tx_info.channel = txcontrol->channel;
+ pmbuf->u.tx_info.bw = txcontrol->bw;
+ pmbuf->u.tx_info.tx_power.val =
+ txcontrol->power;
+ pmbuf->u.tx_info.retry_limit =
+ txcontrol->retry_limit;
+ tid = txcontrol->priority;
+ memmove(skb->data + sizeof(dot11_txcontrol),
+ skb->data, sizeof(struct ethhdr));
+ skb_pull(skb, sizeof(dot11_txcontrol));
+ pmbuf->flags |= MLAN_BUF_FLAG_TX_CTRL;
+ }
+ break;
+ }
+ }
+
+ skb->priority = tid;
+
+ /* Record the current time the packet was queued; used to determine
+ * the amount of time the packet was queued in the driver before it
+ * was sent to the firmware. The delay is then sent along with the
+ * packet to the firmware for aggregate delay calculation for stats
+ * and MSDU lifetime expiry.
+ */
+ woal_get_monotonic_time(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+ skb->tstamp = ktime_get_raw();
+#else
+ skb->tstamp = timeval_to_ktime(tstamp);
+#endif
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
+ skb_set_timestamp(skb, &tstamp);
+#else
+ moal_memcpy_ext(priv->phandle, &skb->stamp, &tstamp, sizeof(skb->stamp),
+ sizeof(skb->stamp));
+#endif
+
+ pmbuf->pdesc = skb;
+ pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ pmbuf->buf_pa = 0;
+ }
+#endif
+ pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
+ pmbuf->data_len = skb->len;
+ pmbuf->priority = skb->priority;
+ pmbuf->buf_type = 0;
+ pmbuf->in_ts_sec = tstamp.time_sec;
+ pmbuf->in_ts_usec = tstamp.time_usec;
+
+ LEAVE();
+ return;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
+static struct device_type wlan_type = {
+ .name = "wlan",
+};
+#endif
+
+#ifdef STA_SUPPORT
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+/** Network device handlers */
+const struct net_device_ops woal_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .ndo_set_rx_mode = woal_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_set_multicast_list,
+#endif
+ .ndo_select_queue = woal_select_queue,
+ .ndo_validate_addr = eth_validate_addr,
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for station mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status woal_init_sta_dev(struct net_device *dev, moal_private *priv)
+{
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->do_ioctl = woal_do_ioctl;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->set_multicast_list = woal_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len;
+#else
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len;
+#endif
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *)&woal_handler_def;
+ }
+#endif
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext))
+ init_waitqueue_head(&priv->ft_wait_q);
+#endif
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* STA_SUPPORT */
+
+#ifdef UAP_SUPPORT
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+/** Network device handlers */
+const struct net_device_ops woal_uap_netdev_ops = {
+ .ndo_open = woal_open,
+ .ndo_start_xmit = woal_hard_start_xmit,
+ .ndo_stop = woal_close,
+ .ndo_do_ioctl = woal_uap_do_ioctl,
+ .ndo_set_mac_address = woal_set_mac_address,
+ .ndo_tx_timeout = woal_tx_timeout,
+ .ndo_get_stats = woal_get_stats,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .ndo_set_rx_mode = woal_uap_set_multicast_list,
+#else
+ .ndo_set_multicast_list = woal_uap_set_multicast_list,
+#endif
+ .ndo_select_queue = woal_select_queue,
+ .ndo_validate_addr = eth_validate_addr,
+};
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and dev structure for uap mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status woal_init_uap_dev(struct net_device *dev, moal_private *priv)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Setup the OS Interface to our functions */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
+ dev->open = woal_open;
+ dev->hard_start_xmit = woal_hard_start_xmit;
+ dev->stop = woal_close;
+ dev->set_mac_address = woal_set_mac_address;
+ dev->tx_timeout = woal_tx_timeout;
+ dev->get_stats = woal_get_stats;
+ dev->do_ioctl = woal_uap_do_ioctl;
+ dev->set_multicast_list = woal_uap_set_multicast_list;
+#else
+ dev->netdev_ops = &woal_uap_netdev_ops;
+#endif
+ dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ dev->needed_headroom += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len;
+#else
+ dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len;
+#endif
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(priv->phandle->params.cfg80211_wext)) {
+#if WIRELESS_EXT < 21
+ dev->get_wireless_stats = woal_get_uap_wireless_stats;
+#endif
+ dev->wireless_handlers =
+ (struct iw_handler_def *)&woal_uap_handler_def;
+ }
+#endif /* UAP_WEXT */
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ LEAVE();
+ return status;
+}
+#endif /* UAP_SUPPORT */
+
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_index BSS index number
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *woal_add_interface(moal_handle *handle, t_u8 bss_index,
+ t_u8 bss_type)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ char name[256];
+ int i = 0;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ char csa_str[256];
+#endif
+#endif
+ ENTER();
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+#define MAX_WMM_QUEUE 4
+ /* Allocate an Ethernet device */
+ dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE);
+#else
+ dev = alloc_etherdev(sizeof(moal_private));
+#endif
+ if (!dev) {
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ goto error;
+ }
+ /* Allocate device name */
+#ifdef STA_SUPPORT
+ memset(name, 0, sizeof(name));
+ if (handle->params.sta_name)
+ snprintf(name, sizeof(name), "%s%%d", handle->params.sta_name);
+ else if (handle->second_mac)
+ snprintf(name, sizeof(name), "m%s", default_mlan_name);
+ else
+ snprintf(name, sizeof(name), "%s", default_mlan_name);
+
+ if ((bss_type == MLAN_BSS_TYPE_STA) &&
+ (dev_alloc_name(dev, name) < 0)) {
+ PRINTM(MERROR, "Could not allocate mlan device name\n");
+ goto error;
+ }
+#endif
+#ifdef UAP_SUPPORT
+ memset(name, 0, sizeof(name));
+ if (handle->params.uap_name)
+ snprintf(name, sizeof(name), "%s%%d", handle->params.uap_name);
+ else if (handle->second_mac)
+ snprintf(name, sizeof(name), "m%s", default_uap_name);
+ else
+ snprintf(name, sizeof(name), "%s", default_uap_name);
+ if ((bss_type == MLAN_BSS_TYPE_UAP) &&
+ (dev_alloc_name(dev, name) < 0)) {
+ PRINTM(MERROR, "Could not allocate uap device name\n");
+ goto error;
+ }
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ memset(name, 0, sizeof(name));
+ if (handle->params.wfd_name)
+ snprintf(name, sizeof(name), "%s%%d", handle->params.wfd_name);
+ else if (handle->second_mac)
+ snprintf(name, sizeof(name), "m%s", default_wfd_name);
+ else
+ snprintf(name, sizeof(name), "%s", default_wfd_name);
+ if ((bss_type == MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (dev_alloc_name(dev, name) < 0)) {
+ PRINTM(MERROR, "Could not allocate wifidirect device name\n");
+ goto error;
+ }
+#endif
+ priv = (moal_private *)netdev_priv(dev);
+ /* Save the priv to handle */
+ handle->priv[bss_index] = priv;
+
+ /* Use the same handle structure */
+ priv->phandle = handle;
+ priv->netdev = dev;
+ priv->bss_index = bss_index;
+ priv->bss_type = bss_type;
+ priv->extra_tx_head_len = 0;
+ if (bss_type == MLAN_BSS_TYPE_STA)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+ else if (bss_type == MLAN_BSS_TYPE_UAP)
+ priv->bss_role = MLAN_BSS_ROLE_UAP;
+#ifdef WIFI_DIRECT_SUPPORT
+ else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+#endif
+
+ INIT_LIST_HEAD(&priv->tcp_sess_queue);
+ spin_lock_init(&priv->tcp_sess_lock);
+
+ INIT_LIST_HEAD(&priv->tx_stat_queue);
+ spin_lock_init(&priv->tx_stat_lock);
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ spin_lock_init(&priv->connect_lock);
+#endif
+#endif
+
+#ifdef STA_SUPPORT
+ INIT_LIST_HEAD(&priv->pmksa_cache_list);
+ if (bss_type == MLAN_BSS_TYPE_STA) {
+ init_waitqueue_head(&priv->okc_wait_q);
+ spin_lock_init(&priv->pmksa_list_lock);
+ priv->okc_roaming_ie = NULL;
+ priv->okc_ie_len = 0;
+ }
+#endif
+#if defined(DRV_EMBEDDED_AUTHENTICATOR)
+ init_waitqueue_head(&priv->hostcmd_wait_q);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ SET_MODULE_OWNER(dev);
+#endif
+#ifdef STA_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_STA
+#ifdef WIFI_DIRECT_SUPPORT
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ )
+ woal_init_sta_dev(dev, priv);
+#endif
+#ifdef UAP_SUPPORT
+ if (bss_type == MLAN_BSS_TYPE_UAP) {
+ if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv))
+ goto error;
+ }
+#endif
+ if (!handle->priv_num
+#ifdef MFG_CMD_SUPPORT
+ && (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ ) {
+ if (handle->params.init_cfg) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_user_init_data(handle, INIT_CFG_DATA,
+ MOAL_IOCTL_WAIT, NULL)) {
+ PRINTM(MFATAL,
+ "Set user init data and param failed\n");
+ goto error;
+ }
+ }
+ if (handle->params.init_hostcmd_cfg) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_user_init_data(handle,
+ INIT_HOSTCMD_CFG_DATA,
+ MOAL_IOCTL_WAIT, NULL)) {
+ PRINTM(MFATAL,
+ "Set user init hostcmd data and param failed\n");
+ goto error;
+ }
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED) {
+#endif
+ if (bss_type == MLAN_BSS_TYPE_UAP &&
+ priv->phandle->params.band_steer_cfg) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_user_init_data(priv->phandle,
+ BAND_STEER_CFG_DATA,
+ MOAL_IOCTL_WAIT, NULL)) {
+ PRINTM(MFATAL,
+ "Set band steering configure param failed\n");
+ }
+ }
+#ifdef MFG_CMD_SUPPORT
+ }
+#endif
+
+ handle->priv_num++;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (!priv->phandle->wiphy &&
+ IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext)) {
+ if (woal_register_cfg80211(priv)) {
+ PRINTM(MERROR, "Cannot register with cfg80211\n");
+ goto error;
+ }
+ }
+#endif
+
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_STA) &&
+ IS_STA_CFG80211(handle->params.cfg80211_wext)) {
+ if (bss_type == MLAN_BSS_TYPE_STA
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ || bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+#endif
+ )
+ /* Register cfg80211 for STA or Wifi direct */
+ if (woal_register_sta_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR,
+ "Cannot register STA with cfg80211\n");
+ goto error;
+ }
+ }
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+ if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
+ IS_UAP_CFG80211(handle->params.cfg80211_wext)) {
+ /* Register cfg80211 for UAP */
+ if (woal_register_uap_cfg80211(dev, bss_type)) {
+ PRINTM(MERROR, "Cannot register UAP with cfg80211\n");
+ goto error;
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ strcpy(csa_str, "CSA");
+ strcat(csa_str, name);
+ priv->csa_workqueue = alloc_workqueue(
+ csa_str, WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+ if (!priv->csa_workqueue) {
+ PRINTM(MERROR, "cannot alloc csa workqueue \n");
+ goto error;
+ }
+ INIT_DELAYED_WORK(&priv->csa_work, woal_csa_work_queue);
+#endif
+#endif
+#endif /*UAP_CFG80211 */
+
+ /* Initialize priv structure */
+ woal_init_priv(priv, MOAL_IOCTL_WAIT);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ SET_NETDEV_DEV(dev, handle->hotplug_device);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
+ SET_NETDEV_DEVTYPE(dev, &wlan_type);
+#endif
+
+ /* Register network device */
+ if (register_netdev(dev)) {
+ PRINTM(MERROR, "Cannot register virtual network device\n");
+ goto error;
+ }
+ netif_carrier_off(dev);
+ woal_stop_queue(dev);
+
+ PRINTM(MINFO, "%s: NXP 802.11 Adapter\n", dev->name);
+
+ if (bss_type == MLAN_BSS_TYPE_STA ||
+ priv->bss_type == MLAN_BSS_TYPE_UAP) {
+#if defined(SD8887) || defined(SD8987)
+ mlan_fw_info fw_info;
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if (MFALSE
+#ifdef SD8887
+ || IS_SD8887(handle->card_type)
+#endif
+#ifdef SD8987
+ || IS_SD8987(handle->card_type)
+#endif
+ ) {
+ if ((fw_info.antinfo & ANT_DIVERSITY_2G) &&
+ (fw_info.antinfo & ANT_DIVERSITY_5G))
+ handle->card_info->histogram_table_num = 4;
+ }
+#endif
+
+ for (i = 0; i < handle->card_info->histogram_table_num; i++) {
+ priv->hist_data[i] =
+ kmalloc(sizeof(hgm_data) +
+ handle->card_info->rx_rate_max *
+ sizeof(atomic_t),
+ GFP_KERNEL);
+ if (!(priv->hist_data[i])) {
+ PRINTM(MERROR,
+ "kmalloc priv->hist_data[%d] failed\n",
+ i);
+ goto error;
+ }
+ }
+ woal_hist_data_reset(priv);
+ }
+#ifdef CONFIG_PROC_FS
+ woal_create_proc_entry(priv);
+ woal_debug_entry(priv);
+#endif /* CONFIG_PROC_FS */
+
+ LEAVE();
+ return priv;
+error:
+ handle->priv_num = bss_index;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv) {
+ if (priv->wdev &&
+ IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
+ priv->wdev = NULL;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->csa_workqueue) {
+ destroy_workqueue(priv->csa_workqueue);
+ priv->csa_workqueue = NULL;
+ }
+#endif
+#endif
+ }
+#endif
+ if (dev && dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+ if (dev)
+ free_netdev(dev);
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes an interface.
+ *
+ * @param handle A pointer to the moal_handle structure
+ * @param bss_index BSS index number
+ *
+ * @return N/A
+ */
+void woal_remove_interface(moal_handle *handle, t_u8 bss_index)
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = handle->priv[bss_index];
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ union iwreq_data wrqu;
+#endif
+ int i = 0;
+ ENTER();
+
+ if (!priv || !priv->netdev)
+ goto error;
+ dev = priv->netdev;
+
+ if (priv->media_connected == MTRUE) {
+ priv->media_connected = MFALSE;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if (IS_STA_OR_UAP_WEXT(handle->params.cfg80211_wext) &&
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu,
+ NULL);
+ }
+#endif
+ }
+ woal_flush_tcp_sess_queue(priv);
+
+ woal_flush_tx_stat_queue(priv);
+
+#ifdef STA_CFG80211
+ if (priv->bss_type == MLAN_BSS_TYPE_STA &&
+ IS_STA_CFG80211(handle->params.cfg80211_wext)) {
+ woal_flush_pmksa_list(priv);
+ if (priv->okc_roaming_ie) {
+ kfree(priv->okc_roaming_ie);
+ priv->okc_roaming_ie = NULL;
+ priv->okc_ie_len = 0;
+ }
+ }
+#endif
+
+ if (priv->bss_type == MLAN_BSS_TYPE_STA ||
+ priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ for (i = 0; i < handle->card_info->histogram_table_num; i++) {
+ kfree(priv->hist_data[i]);
+ priv->hist_data[i] = NULL;
+ }
+ }
+#ifdef CONFIG_PROC_FS
+ /* Remove proc debug */
+ woal_debug_remove(priv);
+ woal_proc_remove(priv);
+#endif /* CONFIG_PROC_FS */
+ /* Last reference is our one */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+ PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+#else
+ PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
+#endif
+
+ PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /* Unregister wiphy device and free */
+ if (priv->wdev && IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
+ priv->wdev = NULL;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->csa_workqueue) {
+ flush_workqueue(priv->csa_workqueue);
+ destroy_workqueue(priv->csa_workqueue);
+ priv->csa_workqueue = NULL;
+ }
+#endif
+#endif
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA ||
+ GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ woal_deinit_wifi_hal(priv);
+#endif
+
+ /* Clear the priv in handle */
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
+ if (IS_STA_OR_UAP_CFG80211(handle->params.cfg80211_wext))
+ priv->phandle->wiphy->extended_capabilities = NULL;
+#endif
+#endif
+ priv->phandle->priv[priv->bss_index] = NULL;
+ priv->phandle = NULL;
+ priv->netdev = NULL;
+ free_netdev(dev);
+error:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Configure pmic in firmware
+ *
+ * @param handle A pointer to moal_handle
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_pmic_configure(moal_handle *handle, t_u8 wait_option)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_PMIC_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Configure antcfg
+ *
+ * @param handle A pointer to moal_handle
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_set_user_antcfg(moal_handle *handle, t_u8 wait_option)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_status status;
+ int antcfg;
+
+ ENTER();
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ antcfg = handle->params.antcfg;
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_SET;
+
+ if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ if (IS_CARD9098(handle->card_type) ||
+ IS_CARD9097(handle->card_type))
+ radio->param.ant_cfg.tx_antenna =
+ radio->param.ant_cfg.rx_antenna = antcfg;
+ else {
+ radio->param.ant_cfg.tx_antenna =
+ (antcfg & 0x0030) >> 4;
+ radio->param.ant_cfg.rx_antenna = antcfg & 0x0003;
+ }
+ } else
+ radio->param.ant_cfg_1x1.antenna = antcfg;
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Configure MLAN for low power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_set_low_pwr_mode(moal_handle *handle, t_u8 wait_option)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_LOW_PWR_MODE;
+ misc->param.low_pwr_mode = moal_extflg_isset(handle, EXT_LOW_PW_MODE);
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+done:
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Send FW shutdown command to MLAN
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_shutdown_fw(moal_private *priv, t_u8 wait_option)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN;
+ misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ /* add 100 ms delay to avoid back to back init/shutdown */
+ mdelay(100);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Return hex value of a give character
+ *
+ * @param chr Character to be converted
+ *
+ * @return The converted character if chr is a valid hex, else 0
+ */
+int woal_hexval(char chr)
+{
+ if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ if (chr >= 'A' && chr <= 'F')
+ return chr - 'A' + 10;
+ if (chr >= 'a' && chr <= 'f')
+ return chr - 'a' + 10;
+
+ return 0;
+}
+
+#ifdef STA_SUPPORT
+#endif
+
+/**
+ * @brief This function flush event queue
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void woal_flush_evt_queue(moal_handle *handle)
+{
+ struct woal_event *evt = NULL, *tmp_node;
+ unsigned long flags;
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ list_for_each_entry_safe (evt, tmp_node, &handle->evt_queue, link) {
+ list_del(&evt->link);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ kfree(evt);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ }
+ INIT_LIST_HEAD(&handle->evt_queue);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+}
+
+/**
+ * @brief This function cancel all works in the queue
+ * and destroy the main workqueue.
+ *
+ * @param handle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_terminate_workqueue(moal_handle *handle)
+{
+ ENTER();
+
+ /* Terminate main workqueue */
+ if (handle->workqueue) {
+ flush_workqueue(handle->workqueue);
+ destroy_workqueue(handle->workqueue);
+ handle->workqueue = NULL;
+ }
+ if (handle->rx_workqueue) {
+ flush_workqueue(handle->rx_workqueue);
+ destroy_workqueue(handle->rx_workqueue);
+ handle->rx_workqueue = NULL;
+ }
+ if (handle->evt_workqueue) {
+ woal_flush_evt_queue(handle);
+ flush_workqueue(handle->evt_workqueue);
+ destroy_workqueue(handle->evt_workqueue);
+ handle->evt_workqueue = NULL;
+ }
+ if (handle->tx_workqueue) {
+ flush_workqueue(handle->tx_workqueue);
+ destroy_workqueue(handle->tx_workqueue);
+ handle->tx_workqueue = NULL;
+ }
+ LEAVE();
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function opens the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_open(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+#if defined(USB)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)priv->phandle->card)->intf;
+#endif /* < 2.6.34 */
+#endif /* USB_SUSPEND_RESUME */
+ t_u8 carrier_on = MFALSE;
+
+ ENTER();
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ PRINTM(MERROR,
+ "open is not allowed in surprise remove state.\n");
+ LEAVE();
+ return -EFAULT;
+ }
+#if defined(USB)
+ if (IS_USB(priv->phandle->card_type)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 1;
+#else
+ atomic_set(&intf->pm_usage_cnt, 1);
+#endif /* < 2.6.32 */
+ usb_autopm_put_interface(intf);
+#else
+ struct usb_device *udev =
+ ((struct usb_card_rec *)(priv->phandle->card))->udev;
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 1);
+ usb_enable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+ }
+#endif /* USB_SUSPEND_RESUME */
+
+#if defined(USB) || defined(SYSKT)
+ /* On some systems the device open handler will be called before HW
+ ready.
+ Use the following flag check and wait function to work around
+ the issue. */
+ if (MTRUE
+#ifdef SDIO
+ && !IS_SD(priv->phandle->card_type)
+#endif
+#ifdef PCIE
+ && !IS_PCIE(priv->phandle->card_type)
+#endif
+ ) {
+ int i = 0;
+
+ while ((priv->phandle->hardware_status !=
+ HardwareStatusReady) &&
+ (i < MAX_WAIT_DEVICE_READY_COUNT)) {
+ i++;
+ woal_sched_timeout(100);
+ }
+ if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
+ PRINTM(MFATAL,
+ "HW not ready, wlan_open() return failure\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ }
+#endif /* USB || SYSKT || SYSKT_MULTI */
+ if (!MODULE_GET) {
+ LEAVE();
+ return -EFAULT;
+ }
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
+ (priv->media_connected))
+ carrier_on = MTRUE;
+#endif
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
+ (priv->media_connected || priv->is_adhoc_link_sensed))
+ carrier_on = MTRUE;
+#endif
+ if (carrier_on == MTRUE) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ } else {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the network device
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0
+ */
+int woal_close(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+#if defined(USB)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)priv->phandle->card)->intf;
+#endif /* < 2.6.34 */
+#endif /* USB_SUSPEND_RESUME */
+#ifdef STA_CFG80211
+ int cfg80211_wext = priv->phandle->params.cfg80211_wext;
+#endif
+ ENTER();
+
+ woal_flush_tx_stat_queue(priv);
+
+#ifdef STA_SUPPORT
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext) &&
+ (priv->bss_type == MLAN_BSS_TYPE_STA))
+ woal_clear_conn_params(priv);
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev->current_bss) {
+ priv->cfg_disconnect = MTRUE;
+ cfg80211_disconnected(priv->netdev, 0, NULL, 0,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ true,
+#endif
+ GFP_KERNEL);
+ }
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (IS_STA_CFG80211(cfg80211_wext) && priv->sched_scanning) {
+ woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT);
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ cfg80211_sched_scan_stopped(priv->wdev->wiphy
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ priv->bg_scan_reqid
+#endif
+ );
+ priv->sched_scanning = MFALSE;
+ }
+#endif
+#endif
+#endif
+ if (!priv->bss_virtual)
+ woal_stop_queue(priv->netdev);
+ MODULE_PUT;
+#if defined(USB)
+ if (IS_USB(priv->phandle->card_type)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 0;
+#else
+ atomic_set(&intf->pm_usage_cnt, 0);
+#endif /* < 2.6.32 */
+ usb_autopm_get_interface(intf);
+#else
+ struct usb_device *udev =
+ ((struct usb_card_rec *)(priv->phandle->card))->udev;
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 0);
+ usb_disable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+ }
+#endif /* USB_SUSPEND_RESUME */
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function sets the MAC address to firmware.
+ *
+ * @param dev A pointer to mlan_private structure
+ * @param addr MAC address to set
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct sockaddr *phw_addr = (struct sockaddr *)addr;
+ t_u8 prev_addr[ETH_ALEN];
+
+ ENTER();
+
+ if (priv->phandle->surprise_removed == MTRUE) {
+ PRINTM(MERROR,
+ "Set mac address is not allowed in surprise remove state.\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ moal_memcpy_ext(priv->phandle, prev_addr, priv->current_addr, ETH_ALEN,
+ ETH_ALEN);
+ memset(priv->current_addr, 0, ETH_ALEN);
+ /* dev->dev_addr is 6 bytes */
+ HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ HEXDUMP("addr:", (t_u8 *)phw_addr->sa_data, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, priv->current_addr, phw_addr->sa_data,
+ ETH_ALEN, ETH_ALEN);
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ priv->current_addr[0] |= 0x02;
+ PRINTM(MCMND, "Set WFD device addr: " MACSTR "\n",
+ MAC2STR(priv->current_addr));
+ }
+#endif
+#endif
+#endif
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ /* For failure restore the MAC address */
+ moal_memcpy_ext(priv->phandle, priv->current_addr, prev_addr,
+ ETH_ALEN, ETH_ALEN);
+ ret = -EFAULT;
+ goto done;
+ }
+ HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, dev->dev_addr, priv->current_addr,
+ ETH_ALEN, ETH_ALEN);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Check driver status
+ *
+ * @param handle A pointer to moal_handle
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 woal_check_driver_status(moal_handle *handle)
+{
+ moal_private *priv = NULL;
+ wifi_timeval t;
+ int i = 0;
+ mlan_debug_info *info = &(handle->debug_info);
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv || woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
+ PRINTM(MERROR,
+ "Could not retrieve debug information from MLAN\n");
+ LEAVE();
+ return MTRUE;
+ }
+#define MOAL_CMD_TIMEOUT_MAX 9
+#define MOAL_CMD_TIMEOUT 20
+ woal_get_monotonic_time(&t);
+ if (info->dnld_cmd_in_secs && info->pending_cmd &&
+ (t.time_sec > (info->dnld_cmd_in_secs + MOAL_CMD_TIMEOUT_MAX))) {
+ if (t.time_sec > (info->dnld_cmd_in_secs + MOAL_CMD_TIMEOUT) &&
+ !info->num_cmd_timeout) {
+ PRINTM(MERROR, "Ignore invalid time, wait=%d\n",
+ (int)(t.time_sec - info->dnld_cmd_in_secs));
+ } else {
+ PRINTM(MERROR, "Timeout cmd id = 0x%x wait=%d\n",
+ info->pending_cmd,
+ (int)(t.time_sec - info->dnld_cmd_in_secs));
+ LEAVE();
+ return MTRUE;
+ }
+ }
+ if (info->num_cmd_timeout) {
+ PRINTM(MERROR, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
+ PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
+ info->timeout_cmd_id, info->timeout_cmd_act);
+ LEAVE();
+ return MTRUE;
+ }
+ if (info->num_cmd_host_to_card_failure) {
+ PRINTM(MERROR, "num_cmd_host_to_card_failure = %d\n",
+ info->num_cmd_host_to_card_failure);
+ LEAVE();
+ return MTRUE;
+ }
+ if (info->num_no_cmd_node) {
+ PRINTM(MERROR, "num_no_cmd_node = %d\n", info->num_no_cmd_node);
+ LEAVE();
+ return MTRUE;
+ }
+ for (i = 0; i < handle->priv_num; i++) {
+ priv = handle->priv[i];
+ if (priv) {
+ if (priv->num_tx_timeout >= NUM_TX_TIMEOUT_THRESHOLD) {
+ PRINTM(MERROR, "num_tx_timeout = %d\n",
+ priv->num_tx_timeout);
+ LEAVE();
+ return MTRUE;
+ }
+ }
+ }
+ if (info->pm_wakeup_card_req && info->pm_wakeup_fw_try) {
+#define MAX_WAIT_TIME 3
+ if (t.time_sec > (info->pm_wakeup_in_secs + MAX_WAIT_TIME)) {
+ PRINTM(MERROR,
+ "wakeup_dev_req=%d wakeup_tries=%d wait=%d\n",
+ info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
+ (int)(t.time_sec - info->pm_wakeup_in_secs));
+ LEAVE();
+ return MTRUE;
+ }
+ }
+ if (info->fw_hang_report) {
+ PRINTM(MERROR, "fw_hang_report = %d\n", info->fw_hang_report);
+ LEAVE();
+ return MTRUE;
+ }
+
+ if (priv && priv->phandle->driver_status) {
+ LEAVE();
+ return MTRUE;
+ }
+
+ LEAVE();
+ return MFALSE;
+}
+
+/**
+ * @brief Display MLAN debug information
+ *
+ * @param priv A pointer to moal_private
+ *
+ * @return N/A
+ */
+void woal_mlan_debug_info(moal_private *priv)
+{
+ int i;
+#ifdef SDIO
+ int j;
+ t_u8 mp_aggr_pkt_limit = 0;
+#endif
+ char str[512] = {0};
+ char *s;
+ mlan_debug_info *info = NULL;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or priv->phandle is null\n");
+ LEAVE();
+ return;
+ }
+
+ info = &(priv->phandle->debug_info);
+
+ if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
+ PRINTM(MERROR,
+ "Could not retrieve debug information from MLAN\n");
+ LEAVE();
+ return;
+ }
+ PRINTM(MERROR, "------------mlan_debug_info-------------\n");
+ PRINTM(MERROR, "mlan_processing =%d\n", info->mlan_processing);
+ PRINTM(MERROR, "main_lock_flag =%d\n", info->main_lock_flag);
+ PRINTM(MERROR, "main_process_cnt =%d\n", info->main_process_cnt);
+ PRINTM(MERROR, "delay_task_flag =%d\n", info->delay_task_flag);
+ PRINTM(MERROR, "mlan_rx_processing =%d\n", info->mlan_rx_processing);
+ PRINTM(MERROR, "rx_pkts_queued=%d\n", info->rx_pkts_queued);
+ PRINTM(MERROR, "tx_pkts_queued=%d\n", info->tx_pkts_queued);
+ PRINTM(MERROR, "fw_hang_report = %d\n", info->fw_hang_report);
+ PRINTM(MERROR, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
+ PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x\n",
+ info->timeout_cmd_id, info->timeout_cmd_act);
+
+ PRINTM(MERROR, "last_cmd_index = %d\n", info->last_cmd_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_id[i]);
+ PRINTM(MERROR, "last_cmd_id = %s\n", str);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_act[i]);
+ PRINTM(MERROR, "last_cmd_act = %s\n", str);
+ PRINTM(MERROR, "last_cmd_resp_index = %d\n", info->last_cmd_resp_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_resp_id[i]);
+ PRINTM(MERROR, "last_cmd_resp_id = %s\n", str);
+ PRINTM(MERROR, "last_event_index = %d\n", info->last_event_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_event[i]);
+ PRINTM(MERROR, "last_event = %s", str);
+
+ PRINTM(MERROR, "num_data_h2c_failure = %d\n",
+ info->num_tx_host_to_card_failure);
+ PRINTM(MERROR, "num_cmd_h2c_failure = %d\n",
+ info->num_cmd_host_to_card_failure);
+ PRINTM(MERROR, "num_alloc_buffer_failure = %d\n",
+ info->num_alloc_buffer_failure);
+ PRINTM(MERROR, "num_pkt_dropped = %d\n", info->num_pkt_dropped);
+
+#ifdef SDIO
+ if (IS_SD(priv->phandle->card_type)) {
+ PRINTM(MERROR, "num_data_c2h_failure = %d\n",
+ info->num_rx_card_to_host_failure);
+ PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n",
+ info->num_cmdevt_card_to_host_failure);
+ PRINTM(MERROR, "num_int_read_failure = %d\n",
+ info->num_int_read_failure);
+ PRINTM(MERROR, "last_int_status = %d\n", info->last_int_status);
+
+ PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ (unsigned int)info->mp_rd_bitmap, info->curr_rd_port);
+ PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ (unsigned int)info->mp_wr_bitmap, info->curr_wr_port);
+ PRINTM(MERROR, "mp_invalid_update=%d\n",
+ info->mp_invalid_update);
+ mp_aggr_pkt_limit = info->mp_aggr_pkt_limit;
+ PRINTM(MERROR, "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
+ info->last_recv_wr_bitmap, info->last_mp_index);
+ for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
+ for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
+ s += sprintf(
+ s, "0x%02x ",
+ info->last_mp_wr_info
+ [i * mp_aggr_pkt_limit + j]);
+
+ PRINTM(MERROR,
+ "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
+ info->last_mp_wr_bitmap[i],
+ info->last_mp_wr_ports[i],
+ info->last_mp_wr_len[i],
+ info->last_curr_wr_port[i], str);
+ }
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ PRINTM(MERROR, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n",
+ info->txbd_rdptr, info->txbd_wrptr);
+ PRINTM(MERROR, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n",
+ info->rxbd_rdptr, info->rxbd_wrptr);
+ PRINTM(MERROR, "eventbd_rdptr=0x%x event_wrptr=0x%x\n",
+ info->eventbd_rdptr, info->eventbd_wrptr);
+ PRINTM(MERROR, "last_wr_index:%d\n",
+ info->txbd_wrptr & (MLAN_MAX_TXRX_BD - 1));
+ PRINTM(MERROR, "Tx pkt size:\n");
+ for (s = str, i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ s += sprintf(s, "%d ", info->last_tx_pkt_size[i]);
+ if (((i + 1) % 16) == 0) {
+ PRINTM(MERROR, "%s\n", str);
+ s = str;
+ }
+ }
+ }
+#endif
+ PRINTM(MERROR, "num_event_deauth = %d\n", info->num_event_deauth);
+ PRINTM(MERROR, "num_event_disassoc = %d\n", info->num_event_disassoc);
+ PRINTM(MERROR, "num_event_link_lost = %d\n", info->num_event_link_lost);
+ PRINTM(MERROR, "num_cmd_deauth = %d\n", info->num_cmd_deauth);
+ PRINTM(MERROR, "num_cmd_assoc_success = %d\n",
+ info->num_cmd_assoc_success);
+ PRINTM(MERROR, "num_cmd_assoc_failure = %d\n",
+ info->num_cmd_assoc_failure);
+ PRINTM(MERROR, "num_cons_assoc_failure = %d\n",
+ info->num_cons_assoc_failure);
+ PRINTM(MERROR, "cmd_resp_received = %d\n", info->cmd_resp_received);
+ PRINTM(MERROR, "event_received = %d\n", info->event_received);
+
+ PRINTM(MERROR, "max_tx_buf_size = %d\n", info->max_tx_buf_size);
+ PRINTM(MERROR, "tx_buf_size = %d\n", info->tx_buf_size);
+ PRINTM(MERROR, "curr_tx_buf_size = %d\n", info->curr_tx_buf_size);
+
+ PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info->data_sent,
+ info->cmd_sent);
+
+ PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info->ps_mode,
+ info->ps_state);
+ PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d wakeup_timeout=%d\n",
+ info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
+ info->pm_wakeup_timeout);
+ PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n",
+ info->is_hs_configured, info->hs_activated);
+ PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n", info->pps_uapsd_mode,
+ info->sleep_pd);
+ PRINTM(MERROR, "tx_lock_flag = %d\n", info->tx_lock_flag);
+ PRINTM(MERROR, "port_open = %d\n", info->port_open);
+ PRINTM(MERROR, "scan_processing = %d\n", info->scan_processing);
+ for (i = 0; i < info->ralist_num; i++) {
+ PRINTM(MERROR,
+ "ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d\n",
+ info->ralist[i].ra[0], info->ralist[i].ra[1],
+ info->ralist[i].ra[2], info->ralist[i].ra[3],
+ info->ralist[i].ra[4], info->ralist[i].ra[5],
+ info->ralist[i].tid, info->ralist[i].total_pkts,
+ info->ralist[i].tx_pause);
+ }
+
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ PRINTM(MERROR, "txbd: rdptr=0x%x wrptr=0x%x\n",
+ info->txbd_rdptr, info->txbd_wrptr);
+ PRINTM(MERROR, "rxbd: rdptr=0x%x wrptr=0x%x\n",
+ info->rxbd_rdptr, info->rxbd_wrptr);
+ PRINTM(MERROR, "eventbd: rdptr=0x%x wrptr=0x%x\n",
+ info->eventbd_rdptr, info->eventbd_wrptr);
+ }
+#endif
+ PRINTM(MERROR, "------------mlan_debug_info End-------------\n");
+ LEAVE();
+}
+
+/**
+ * @brief This function handle the shutdown timeout issue
+ *
+ * @param handle Pointer to structure moal_handle
+ *
+ * @return N/A
+ */
+void woal_ioctl_timeout(moal_handle *handle)
+{
+ moal_private *priv = NULL;
+
+ ENTER();
+
+ PRINTM(MMSG, "woal_ioctl_timout.\n");
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (priv) {
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function handles the timeout of packet
+ * transmission
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void woal_tx_timeout(struct net_device *dev
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+ ,
+ unsigned int txqueue
+#endif
+)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ priv->num_tx_timeout++;
+ PRINTM(MERROR, "%lu : %s (bss=%d): Tx timeout (%d)\n", jiffies,
+ dev->name, priv->bss_index, priv->num_tx_timeout);
+ woal_set_trans_start(dev);
+
+ if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD) {
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ woal_broadcast_event(priv, CUS_EVT_DRIVER_HANG,
+ strlen(CUS_EVT_DRIVER_HANG));
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext))
+ woal_cfg80211_vendor_event(priv, event_hang,
+ CUS_EVT_DRIVER_HANG,
+ strlen(CUS_EVT_DRIVER_HANG));
+#endif
+#endif
+ priv->phandle->driver_status = MTRUE;
+ woal_process_hang(priv->phandle);
+
+ wifi_status = 3;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to net_device_stats structure
+ */
+struct net_device_stats *woal_get_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ return &priv->stats;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+/**
+ * @brief This function handles wmm queue select
+ *
+ * @param dev A pointer to net_device structure
+ * @param skb A pointer to sk_buff structure
+ *
+ * @return tx_queue index (0-3)
+ */
+u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+ ,
+ struct net_device *sb_dev
+#else
+ ,
+ void *accel_priv
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && \
+ LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
+ ,
+ select_queue_fallback_t fallback
+#endif
+#endif
+)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct ethhdr *eth = NULL;
+ t_u8 tid = 0;
+ t_u8 index = 0;
+
+ ENTER();
+ if (priv->phandle->surprise_removed == MTRUE) {
+ LEAVE();
+ return index;
+ }
+ /*
+ * skb->priority values from 256->263 are magic values to
+ * directly indicate a specific 802.1d priority. This is used
+ * to allow 802.1d priority to be passed directly in from VLAN
+ * tags, etc.
+ */
+ if (IS_SKB_MAGIC_VLAN(skb)) {
+ tid = GET_VLAN_PRIO(skb);
+ } else {
+ eth = (struct ethhdr *)skb->data;
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+ tid = priv->dscp_map[SKB_TOS(skb) >> DSCP_OFFSET];
+ if (tid == 0xFF)
+ tid = (IPTOS_PREC(SKB_TOS(skb)) >>
+ IPTOS_OFFSET);
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ tid = SKB_TIDV6(skb);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ default:
+ break;
+ }
+ }
+
+ index = mlan_select_wmm_queue(priv->phandle->pmlan_adapter,
+ priv->bss_index, tid);
+ PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index);
+ LEAVE();
+ return index;
+}
+#endif
+
+/**
+ * @brief This function flush tx status queue
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void woal_flush_tx_stat_queue(moal_private *priv)
+{
+ struct tx_status_info *tx_info = NULL, *tmp_node;
+ unsigned long flags;
+ struct sk_buff *skb = NULL;
+ spin_lock_irqsave(&priv->tx_stat_lock, flags);
+ list_for_each_entry_safe (tx_info, tmp_node, &priv->tx_stat_queue,
+ link) {
+ list_del(&tx_info->link);
+ spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
+ skb = (struct sk_buff *)tx_info->tx_skb;
+ if (tx_info->tx_cookie) {
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ cfg80211_mgmt_tx_status(priv->netdev,
+ tx_info->tx_cookie, skb->data,
+ skb->len, true, GFP_ATOMIC);
+#else
+ cfg80211_mgmt_tx_status(priv->wdev, tx_info->tx_cookie,
+ skb->data, skb->len, true,
+ GFP_ATOMIC);
+#endif
+#endif
+#endif
+ }
+ dev_kfree_skb_any(skb);
+ kfree(tx_info);
+ spin_lock_irqsave(&priv->tx_stat_lock, flags);
+ }
+ INIT_LIST_HEAD(&priv->tx_stat_queue);
+ spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
+ spin_lock_bh(&(priv->tx_q.lock));
+ __skb_queue_purge(&priv->tx_q);
+ spin_unlock_bh(&(priv->tx_q.lock));
+}
+
+/**
+ * @brief This function gets tx info from tx_stat_queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param tx_seq_num tx seq number
+ *
+ * @return A pointer to the tcp tx_status_info structure, if found.
+ * Otherwise, null
+ */
+struct tx_status_info *woal_get_tx_info(moal_private *priv, t_u8 tx_seq_num)
+{
+ struct tx_status_info *tx_info = NULL;
+ ENTER();
+
+ list_for_each_entry (tx_info, &priv->tx_stat_queue, link) {
+ if (tx_info->tx_seq_num == tx_seq_num) {
+ LEAVE();
+ return tx_info;
+ }
+ }
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function remove tx info from queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param tx_seq_num tx seq number
+ *
+ * @return N/A
+ */
+void woal_remove_tx_info(moal_private *priv, t_u8 tx_seq_num)
+{
+ struct tx_status_info *tx_info, *tmp = NULL;
+ unsigned long flags;
+ ENTER();
+
+ spin_lock_irqsave(&priv->tx_stat_lock, flags);
+ list_for_each_entry_safe (tx_info, tmp, &priv->tx_stat_queue, link) {
+ if (tx_info->tx_seq_num == tx_seq_num) {
+ list_del(&tx_info->link);
+ dev_kfree_skb_any((struct sk_buff *)tx_info->tx_skb);
+ kfree(tx_info);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_stat_lock, flags);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function flush tcp session queue
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void woal_flush_tcp_sess_queue(moal_private *priv)
+{
+ struct tcp_sess *tcp_sess = NULL, *tmp_node;
+ unsigned long flags;
+ struct sk_buff *skb;
+ spin_lock_irqsave(&priv->tcp_sess_lock, flags);
+ list_for_each_entry_safe (tcp_sess, tmp_node, &priv->tcp_sess_queue,
+ link) {
+ list_del(&tcp_sess->link);
+ if (tcp_sess->is_timer_set)
+ woal_cancel_timer(&tcp_sess->ack_timer);
+ skb = (struct sk_buff *)tcp_sess->ack_skb;
+ if (skb)
+ dev_kfree_skb_any(skb);
+ kfree(tcp_sess);
+ }
+ INIT_LIST_HEAD(&priv->tcp_sess_queue);
+ priv->tcp_ack_drop_cnt = 0;
+ priv->tcp_ack_cnt = 0;
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+}
+
+/**
+ * @brief This function gets tcp session from the tcp session queue
+ *
+ * @param priv A pointer to moal_private structure
+ * @param src_ip IP address of the device
+ * @param src_port TCP port of the device
+ * @param dst_ip IP address of the client
+ * @param dst_port TCP port of the client
+ *
+ * @return A pointer to the tcp session data structure, if found.
+ * Otherwise, null
+ */
+static inline struct tcp_sess *woal_get_tcp_sess(moal_private *priv,
+ t_u32 src_ip, t_u16 src_port,
+ t_u32 dst_ip, t_u16 dst_port)
+{
+ struct tcp_sess *tcp_sess = NULL;
+ ENTER();
+
+ list_for_each_entry (tcp_sess, &priv->tcp_sess_queue, link) {
+ if ((tcp_sess->src_ip_addr == src_ip) &&
+ (tcp_sess->src_tcp_port == src_port) &&
+ (tcp_sess->dst_ip_addr == dst_ip) &&
+ (tcp_sess->dst_tcp_port == dst_port)) {
+ LEAVE();
+ return tcp_sess;
+ }
+ }
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function send the holding tcp ack packet
+ * re-assoc thread.
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void woal_tcp_ack_timer_func(void *context)
+{
+ struct tcp_sess *tcp_session = (struct tcp_sess *)context;
+ moal_private *priv = (moal_private *)tcp_session->priv;
+ unsigned long flags;
+ mlan_buffer *pmbuf;
+ struct sk_buff *skb;
+ mlan_status status;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ t_u32 index = 0;
+#endif
+ ENTER();
+ spin_lock_irqsave(&priv->tcp_sess_lock, flags);
+ tcp_session->is_timer_set = MFALSE;
+ skb = (struct sk_buff *)tcp_session->ack_skb;
+ pmbuf = (mlan_buffer *)tcp_session->pmbuf;
+ tcp_session->ack_skb = NULL;
+ tcp_session->pmbuf = NULL;
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+ if (skb && pmbuf) {
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ index = skb_get_queue_mapping(skb);
+ atomic_inc(&priv->wmm_tx_pending[index]);
+ if (atomic_read(&priv->wmm_tx_pending[index]) >=
+ MAX_TX_PENDING) {
+ struct netdev_queue *txq = netdev_get_tx_queue(
+ priv->netdev, index);
+ netif_tx_stop_queue(txq);
+ PRINTM(MINFO, "Stop Kernel Queue : %d\n",
+ index);
+ }
+#else
+ if (atomic_read(&priv->phandle->tx_pending) >=
+ MAX_TX_PENDING)
+ woal_stop_queue(priv->netdev);
+#endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
+ queue_work(priv->phandle->workqueue,
+ &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function send the tcp ack
+ *
+ *
+ * @param priv A pointer to moal_private structure
+ * @param tcp_session A pointer to tcp_session
+ * @return N/A
+ */
+void woal_send_tcp_ack(moal_private *priv, struct tcp_sess *tcp_session)
+{
+ mlan_status status;
+ struct sk_buff *skb = (struct sk_buff *)tcp_session->ack_skb;
+ mlan_buffer *pmbuf = (mlan_buffer *)tcp_session->pmbuf;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ t_u32 index = 0;
+#endif
+ ENTER();
+ if (tcp_session->is_timer_set) {
+ woal_cancel_timer(&tcp_session->ack_timer);
+ tcp_session->is_timer_set = MFALSE;
+ }
+ tcp_session->ack_skb = NULL;
+ tcp_session->pmbuf = NULL;
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ index = skb_get_queue_mapping(skb);
+ atomic_inc(&priv->wmm_tx_pending[index]);
+ if (atomic_read(&priv->wmm_tx_pending[index]) >=
+ MAX_TX_PENDING) {
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(priv->netdev, index);
+ netif_tx_stop_queue(txq);
+ PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
+ }
+#else
+ if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
+ woal_stop_queue(priv->netdev);
+#endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function get the tcp ack session node
+ *
+ * @param priv A pointer to moal_private structure
+ * @param pmbuf A pointer to mlan_buffer associated with a skb
+ *
+ * @return 1, if it's dropped; 0, if not dropped
+ */
+int woal_process_tcp_ack(moal_private *priv, mlan_buffer *pmbuf)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct tcp_sess *tcp_session;
+ struct ethhdr *ethh = NULL;
+ struct iphdr *iph = NULL;
+ struct tcphdr *tcph = NULL;
+ t_u32 ack_seq;
+ struct sk_buff *skb;
+
+ ENTER();
+
+ /** check the tcp packet */
+ ethh = (struct ethhdr *)(pmbuf->pbuf + pmbuf->data_offset);
+ if (ntohs(ethh->h_proto) != ETH_P_IP) {
+ LEAVE();
+ return 0;
+ }
+ iph = (struct iphdr *)((t_u8 *)ethh + sizeof(struct ethhdr));
+ if (iph->protocol != IPPROTO_TCP) {
+ LEAVE();
+ return 0;
+ }
+ tcph = (struct tcphdr *)((t_u8 *)iph + iph->ihl * 4);
+
+ if (*((t_u8 *)tcph + 13) == 0x10) {
+ /* Only replace ACK */
+ if (ntohs(iph->tot_len) > (iph->ihl + tcph->doff) * 4) {
+ /* Don't drop ACK with payload */
+ /* TODO: should we delete previous TCP session */
+ LEAVE();
+ return ret;
+ }
+ priv->tcp_ack_cnt++;
+ spin_lock_irqsave(&priv->tcp_sess_lock, flags);
+ tcp_session = woal_get_tcp_sess(priv, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ if (!tcp_session) {
+ tcp_session =
+ kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC);
+ if (!tcp_session) {
+ PRINTM(MERROR, "Fail to allocate tcp_sess.\n");
+ spin_unlock_irqrestore(&priv->tcp_sess_lock,
+ flags);
+ goto done;
+ }
+ tcp_session->ack_skb = pmbuf->pdesc;
+ tcp_session->pmbuf = pmbuf;
+ pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
+ tcp_session->src_ip_addr = iph->saddr;
+ tcp_session->dst_ip_addr = iph->daddr;
+ tcp_session->src_tcp_port = tcph->source;
+ tcp_session->dst_tcp_port = tcph->dest;
+ tcp_session->ack_seq = ntohl(tcph->ack_seq);
+ tcp_session->priv = (void *)priv;
+ skb = (struct sk_buff *)pmbuf->pdesc;
+ skb->cb[0] = 0;
+ /* Initialize the timer for tcp ack */
+ woal_initialize_timer(&tcp_session->ack_timer,
+ woal_tcp_ack_timer_func,
+ tcp_session);
+ tcp_session->is_timer_set = MTRUE;
+ woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
+ list_add_tail(&tcp_session->link,
+ &priv->tcp_sess_queue);
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+ ret = HOLD_TCP_ACK;
+ LEAVE();
+ return ret;
+ } else if (!tcp_session->ack_skb) {
+ tcp_session->ack_skb = pmbuf->pdesc;
+ tcp_session->pmbuf = pmbuf;
+ pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
+ tcp_session->ack_seq = ntohl(tcph->ack_seq);
+ tcp_session->priv = (void *)priv;
+ skb = (struct sk_buff *)pmbuf->pdesc;
+ skb->cb[0] = 0;
+ tcp_session->is_timer_set = MTRUE;
+ woal_mod_timer(&tcp_session->ack_timer, MOAL_TIMER_1MS);
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+ ret = HOLD_TCP_ACK;
+ LEAVE();
+ return ret;
+ }
+ ack_seq = ntohl(tcph->ack_seq);
+ skb = (struct sk_buff *)tcp_session->ack_skb;
+ if (likely(ack_seq > tcp_session->ack_seq) &&
+ (skb->len == pmbuf->data_len)) {
+ moal_memcpy_ext(priv->phandle, skb->data,
+ pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len, skb->len);
+ tcp_session->ack_seq = ack_seq;
+ ret = DROP_TCP_ACK;
+ skb->cb[0]++;
+// We will drop 90% tcp ack
+#define TCP_ACK_MAX_HOLD 9
+ if (skb->cb[0] >= TCP_ACK_MAX_HOLD)
+ woal_send_tcp_ack(priv, tcp_session);
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+ skb = (struct sk_buff *)pmbuf->pdesc;
+ dev_kfree_skb_any(skb);
+ priv->tcp_ack_drop_cnt++;
+ } else {
+ pmbuf->flags |= MLAN_BUF_FLAG_TCP_ACK;
+ spin_unlock_irqrestore(&priv->tcp_sess_lock, flags);
+ LEAVE();
+ return ret;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles packet transmission
+ *
+ * @param skb A pointer to sk_buff structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success
+ */
+int woal_start_xmit(moal_private *priv, struct sk_buff *skb)
+{
+ mlan_buffer *pmbuf = NULL;
+ mlan_status status;
+ struct sk_buff *new_skb = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ t_u32 index = 0;
+#endif
+ int ret = 0;
+
+ ENTER();
+
+ priv->num_tx_timeout = 0;
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
+ ETH_FRAME_LEN);
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (skb->cloned || (skb_headroom(skb) <
+ (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len))) {
+ PRINTM(MWARN,
+ "Tx: skb cloned %d or Insufficient skb headroom %d\n",
+ skb->cloned, skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb = skb_realloc_headroom(
+ skb, MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
+ priv->extra_tx_head_len);
+ if (unlikely(!new_skb)) {
+ PRINTM(MERROR, "Tx: Cannot allocate skb\n");
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (new_skb != skb)
+ dev_kfree_skb_any(skb);
+ skb = new_skb;
+ PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb));
+ }
+ pmbuf = (mlan_buffer *)skb->head;
+ memset((t_u8 *)pmbuf, 0, sizeof(mlan_buffer));
+ pmbuf->bss_index = priv->bss_index;
+ woal_fill_mlan_buffer(priv, pmbuf, skb);
+ if (priv->enable_tcp_ack_enh == MTRUE) {
+ ret = woal_process_tcp_ack(priv, pmbuf);
+ if (ret)
+ goto done;
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ index = skb_get_queue_mapping(skb);
+#endif
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ if (is_zero_timeval(priv->phandle->tx_time_start)) {
+ priv->phandle->tx_time_start.time_sec =
+ pmbuf->in_ts_sec;
+ priv->phandle->tx_time_start.time_usec =
+ pmbuf->in_ts_usec;
+ PRINTM(MINFO, "%s : start_timeval=%d:%d \n", __func__,
+ priv->phandle->tx_time_start.time_sec,
+ priv->phandle->tx_time_start.time_usec);
+ }
+ atomic_inc(&priv->phandle->tx_pending);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ atomic_inc(&priv->wmm_tx_pending[index]);
+ if (atomic_read(&priv->wmm_tx_pending[index]) >=
+ MAX_TX_PENDING) {
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(priv->netdev, index);
+ netif_tx_stop_queue(txq);
+ PRINTM(MINFO, "Stop Kernel Queue : %d\n", index);
+ }
+#else
+ if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING)
+ woal_stop_queue(priv->netdev);
+#endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
+ if (!mlan_is_main_process_running(priv->phandle->pmlan_adapter))
+ queue_work(priv->phandle->workqueue,
+ &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ priv->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ break;
+ }
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles packet transmission
+ *
+ * @param skb A pointer to sk_buff structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 --success
+ */
+netdev_tx_t woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ ENTER();
+ PRINTM(MDATA, "%lu : %s (bss=%d): Data <= kernel\n", jiffies, dev->name,
+ priv->bss_index);
+
+ /* Collect TP statistics */
+ if (priv->phandle->tp_acnt.on)
+ moal_tp_accounting(priv->phandle, skb, 1);
+ /* Drop Tx packets at drop point 1 */
+ if (priv->phandle->tp_acnt.drop_point == 1) {
+ dev_kfree_skb_any(skb);
+ LEAVE();
+ return 0;
+ }
+ if (priv->phandle->surprise_removed == MTRUE) {
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+ if (moal_extflg_isset(priv->phandle, EXT_TX_WORK)) {
+ spin_lock_bh(&(priv->tx_q.lock));
+ __skb_queue_tail(&(priv->tx_q), skb);
+ spin_unlock_bh(&(priv->tx_q.lock));
+
+ queue_work(priv->phandle->tx_workqueue,
+ &priv->phandle->tx_work);
+ goto done;
+ }
+ woal_start_xmit(priv, skb);
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Convert ascii string to Hex integer
+ *
+ * @param d A pointer to integer buf
+ * @param s A pointer to ascii string
+ * @param dlen The byte number of ascii string in hex
+ *
+ * @return Number of integer
+ */
+int woal_ascii2hex(t_u8 *d, char *s, t_u32 dlen)
+{
+ unsigned int i;
+ t_u8 n;
+
+ ENTER();
+
+ memset(d, 0x00, dlen);
+
+ for (i = 0; i < dlen * 2; i++) {
+ if ((s[i] >= 48) && (s[i] <= 57))
+ n = s[i] - 48;
+ else if ((s[i] >= 65) && (s[i] <= 70))
+ n = s[i] - 55;
+ else if ((s[i] >= 97) && (s[i] <= 102))
+ n = s[i] - 87;
+ else
+ break;
+ if (!(i % 2))
+ n = n * 16;
+ d[i / 2] += n;
+ }
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Return integer value of a given ascii string
+ *
+ * @param data Converted data to be returned
+ * @param a String to be converted
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_atoi(int *data, char *a)
+{
+ int i, val = 0, len;
+ int mul = 1;
+
+ ENTER();
+
+ len = strlen(a);
+ if (len > 2) {
+ if (!strncmp(a, "0x", 2)) {
+ a = a + 2;
+ len -= 2;
+ *data = woal_atox(a);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ }
+ for (i = 0; i < len; i++) {
+ if (isdigit(a[i])) {
+ val = val * 10 + (a[i] - '0');
+ } else {
+ if ((i == 0) && (a[i] == '-')) {
+ mul = -1;
+ } else {
+ PRINTM(MERROR, "Invalid char %c in string %s\n",
+ a[i], a);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ }
+ }
+ *data = (mul * val);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Return hex value of a given ascii string
+ *
+ * @param a String to be converted to ascii
+ *
+ * @return The converted character if a is a valid hex, else 0
+ */
+int woal_atox(char *a)
+{
+ int i = 0;
+
+ ENTER();
+
+ while (isxdigit(*a))
+ i = i * 16 + woal_hexval(*a++);
+
+ LEAVE();
+ return i;
+}
+
+/**
+ * @brief Extension of strsep lib command. This function will also take care
+ * escape character
+ *
+ * @param s A pointer to array of chars to process
+ * @param delim The delimiter character to end the string
+ * @param esc The escape character to ignore for delimiter
+ *
+ * @return Pointer to the separated string if delim found, else NULL
+ */
+char *woal_strsep(char **s, char delim, char esc)
+{
+ char *se = *s, *sb;
+
+ ENTER();
+
+ if (!(*s) || (*se == '\0')) {
+ LEAVE();
+ return NULL;
+ }
+
+ for (sb = *s; *sb != '\0'; ++sb) {
+ if (*sb == esc && *(sb + 1) == esc) {
+ /*
+ * We get a esc + esc seq then keep the one esc
+ * and chop off the other esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == esc && *(sb + 1) == delim) {
+ /*
+ * We get a delim + esc seq then keep the delim
+ * and chop off the esc character
+ */
+ memmove(sb, sb + 1, strlen(sb));
+ continue;
+ }
+ if (*sb == delim)
+ break;
+ }
+
+ if (*sb == '\0')
+ sb = NULL;
+ else
+ *sb++ = '\0';
+
+ *s = sb;
+
+ LEAVE();
+ return se;
+}
+
+/**
+ * @brief Convert mac address from string to t_u8 buffer.
+ *
+ * @param mac_addr The buffer to store the mac address in.
+ * @param buf The source of mac address which is a string.
+ *
+ * @return N/A
+ */
+void woal_mac2u8(t_u8 *mac_addr, char *buf)
+{
+ char *begin, *end, *mac_buff;
+ int i;
+
+ ENTER();
+
+ if (!buf) {
+ LEAVE();
+ return;
+ }
+
+ mac_buff = kzalloc(strlen(buf) + 1, GFP_KERNEL);
+ if (!mac_buff) {
+ LEAVE();
+ return;
+ }
+ moal_memcpy_ext(NULL, mac_buff, buf, strlen(buf), strlen(buf) + 1);
+
+ begin = mac_buff;
+ for (i = 0; i < ETH_ALEN; ++i) {
+ end = woal_strsep(&begin, ':', '/');
+ if (end)
+ mac_addr[i] = woal_atox(end);
+ }
+
+ kfree(mac_buff);
+ LEAVE();
+}
+
+#ifdef STA_SUPPORT
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+void woal_set_multicast_list(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ ENTER();
+ woal_request_set_multicast_list(priv, dev);
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief This function initializes the private structure
+ * and set default value to the member of moal_private.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return N/A
+ */
+void woal_init_priv(moal_private *priv, t_u8 wait_option)
+{
+ ENTER();
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ priv->current_key_index = 0;
+ priv->rate_index = AUTO_RATE;
+ priv->is_adhoc_link_sensed = MFALSE;
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ priv->rx_filter = 0;
+
+#ifdef REASSOCIATION
+ priv->reassoc_on = MFALSE;
+ priv->set_asynced_essid_flag = MFALSE;
+#endif
+#ifdef STA_CFG80211
+ memset(&priv->sme_current, 0,
+ sizeof(struct cfg80211_connect_params));
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_init_wifi_hal(priv);
+#endif
+ }
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ priv->bss_started = MFALSE;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ memset(&priv->chan, 0, sizeof(struct cfg80211_chan_def));
+ memset(&priv->csa_chan, 0, sizeof(struct cfg80211_chan_def));
+ priv->uap_tx_blocked = MFALSE;
+ memset(&priv->beacon_after, 0,
+ sizeof(struct cfg80211_beacon_data));
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_init_wifi_hal(priv);
+#endif
+#endif
+ }
+#endif
+
+ skb_queue_head_init(&priv->tx_q);
+ memset(&priv->tx_protocols, 0, sizeof(dot11_protocol));
+ memset(&priv->rx_protocols, 0, sizeof(dot11_protocol));
+ priv->media_connected = MFALSE;
+
+ memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+ priv->beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
+#endif
+#ifdef STA_SUPPORT
+#endif
+
+ priv->enable_tcp_ack_enh = MTRUE;
+
+ priv->gtk_data_ready = MFALSE;
+ memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
+
+ woal_request_get_fw_info(priv, wait_option, NULL);
+
+ /* Set MAC address from the insmod command line */
+ if (priv->phandle->set_mac_addr) {
+ memset(priv->current_addr, 0, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, priv->current_addr,
+ priv->phandle->mac_addr, ETH_ALEN, ETH_ALEN);
+ }
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+#ifdef MFG_CMD_SUPPORT
+ if (priv->phandle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (priv->bss_virtual) {
+ if (priv->pa_netdev) {
+ moal_memcpy_ext(
+ priv->phandle,
+ priv->current_addr,
+ priv->pa_netdev->dev_addr,
+ ETH_ALEN, ETH_ALEN);
+ priv->current_addr[4] ^= 0x80;
+ if (priv->phandle->second_mac)
+ priv->current_addr[5] ^= 0x80;
+ PRINTM(MCMND,
+ "Set WFD interface addr: " MACSTR
+ "\n",
+ MAC2STR(priv->current_addr));
+ }
+ } else {
+ priv->current_addr[0] |= 0x02;
+ PRINTM(MCMND,
+ "Set WFD device addr: " MACSTR "\n",
+ MAC2STR(priv->current_addr));
+ }
+ }
+#endif
+#endif
+#endif
+
+ /* Set MAC address for UAPx/MLANx/WFDx/OCBx and let them
+ * different with each other */
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)
+#endif
+ {
+ priv->current_addr[4] += priv->bss_index;
+ PRINTM(MCMND, "Set %s interface addr: " MACSTR "\n",
+ priv->netdev->name, MAC2STR(priv->current_addr));
+ }
+
+ woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT);
+ moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr,
+ priv->current_addr, ETH_ALEN, ETH_ALEN);
+
+#ifdef UAP_SUPPORT
+ priv->user_cac_period_msec = 0;
+#endif
+ LEAVE();
+}
+
+/**
+ * @brief Reset all interfaces if all_intf flag is TRUE,
+ * otherwise specified interface only
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param all_intf TRUE : all interfaces
+ * FALSE : current interface only
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int woal_reset_intf(moal_private *priv, t_u8 wait_option, int all_intf)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ int intf_num;
+ moal_handle *handle = NULL;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle = priv->phandle;
+
+ if (handle->rf_test_mode)
+ woal_process_rf_test_mode(handle, MFG_CMD_UNSET_TEST_MODE);
+#ifdef STA_SUPPORT
+ woal_cancel_scan(priv, wait_option);
+#endif
+
+ /* Stop queue and detach device */
+ if (!all_intf) {
+ woal_stop_queue(priv->netdev);
+ netif_device_detach(priv->netdev);
+ } else {
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_stop_queue(handle->priv[intf_num]->netdev);
+ netif_device_detach(handle->priv[intf_num]->netdev);
+ }
+ }
+
+ /* Get BSS info */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, wait_option, &bss_info);
+
+ /* Cancel host sleep */
+ if (bss_info.is_hs_configured) {
+ if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect from network */
+ if (!all_intf) {
+ /* Disconnect specified interface only */
+ if ((priv->media_connected == MTRUE)
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(priv, wait_option, NULL,
+ DEF_DEAUTH_REASON_CODE);
+ priv->media_connected = MFALSE;
+ }
+ } else {
+ /* Disconnect all interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ if (handle->priv[intf_num]->media_connected == MTRUE
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(handle->priv[intf_num]) ==
+ MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ woal_disconnect(handle->priv[intf_num],
+ wait_option, NULL,
+ DEF_DEAUTH_REASON_CODE);
+ handle->priv[intf_num]->media_connected =
+ MFALSE;
+ }
+ }
+ }
+
+#ifdef REASSOCIATION
+ /* Reset the reassoc timer and status */
+ if (!all_intf) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ priv->set_asynced_essid_flag = MFALSE;
+ } else {
+ handle->reassoc_on = 0;
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ handle->priv[intf_num]->reassoc_on = MFALSE;
+ handle->priv[intf_num]->set_asynced_essid_flag = MFALSE;
+ }
+ }
+ if (!handle->reassoc_on && handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+#endif /* REASSOCIATION */
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ if (handle->is_go_timer_set) {
+ woal_cancel_timer(&handle->go_timer);
+ handle->is_go_timer_set = MFALSE;
+ }
+#endif
+#endif
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ if (handle->is_remain_timer_set) {
+ woal_cancel_timer(&handle->remain_timer);
+ woal_remain_timer_func(handle);
+ }
+#endif
+#endif
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function return the point to structure moal_private
+ *
+ * @param handle Pointer to structure moal_handle
+ * @param bss_index BSS index number
+ *
+ * @return moal_private pointer or NULL
+ */
+moal_private *woal_bss_index_to_priv(moal_handle *handle, t_u8 bss_index)
+{
+ int i;
+
+ ENTER();
+ if (!handle) {
+ LEAVE();
+ return NULL;
+ }
+ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
+ if (handle->priv[i] &&
+ (handle->priv[i]->bss_index == bss_index)) {
+ LEAVE();
+ return handle->priv[i];
+ }
+ }
+
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function alloc mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param size buffer size to allocate
+ *
+ * @return mlan_buffer pointer or NULL
+ */
+pmlan_buffer woal_alloc_mlan_buffer(moal_handle *handle, int size)
+{
+ mlan_buffer *pmbuf = NULL;
+ struct sk_buff *skb;
+ gfp_t flag;
+
+ ENTER();
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ if (size <= 0) {
+ PRINTM(MERROR, "Buffer size must be positive\n");
+ LEAVE();
+ return NULL;
+ }
+
+ skb = __dev_alloc_skb(size + sizeof(mlan_buffer), flag);
+ if (!skb) {
+ PRINTM(MERROR, "%s: No free skb\n", __func__);
+ LEAVE();
+ return NULL;
+ }
+ skb_reserve(skb, sizeof(mlan_buffer));
+ pmbuf = (mlan_buffer *)skb->head;
+ memset((u8 *)pmbuf, 0, sizeof(mlan_buffer));
+ pmbuf->pdesc = (t_void *)skb;
+ pmbuf->pbuf = (t_u8 *)skb->data;
+ atomic_inc(&handle->mbufalloc_count);
+ LEAVE();
+ return pmbuf;
+}
+
+/**
+ * @brief This function alloc mlan_ioctl_req.
+ *
+ * @param size buffer size to allocate
+ *
+ * @return mlan_ioctl_req pointer or NULL
+ */
+pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size)
+{
+ mlan_ioctl_req *req = NULL;
+ gfp_t flag;
+
+ ENTER();
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ req = kzalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) +
+ sizeof(wait_queue)),
+ flag);
+ if (!req) {
+ PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __func__);
+ LEAVE();
+ return NULL;
+ }
+ req->pbuf = (t_u8 *)req + sizeof(mlan_ioctl_req) + sizeof(wait_queue);
+ req->buf_len = (t_u32)size;
+ req->reserved_1 = (t_ptr)((t_u8 *)req + sizeof(mlan_ioctl_req));
+
+ LEAVE();
+ return req;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ * @param handle A pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer
+ *
+ * @return N/A
+ */
+void woal_free_mlan_buffer(moal_handle *handle, pmlan_buffer pmbuf)
+{
+ ENTER();
+ if (!pmbuf) {
+ LEAVE();
+ return;
+ }
+ if (pmbuf->pdesc)
+ dev_kfree_skb_any((struct sk_buff *)pmbuf->pdesc);
+ else
+ PRINTM(MERROR, "free mlan buffer without pdesc\n");
+ atomic_dec(&handle->mbufalloc_count);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function get card info from card type
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static int woal_get_card_info(moal_handle *phandle)
+{
+ int ret = 0;
+
+ ENTER();
+
+ switch (phandle->card_type) {
+#ifdef SD8887
+ case CARD_TYPE_SD8887:
+ phandle->card_info = &card_info_SD8887;
+ break;
+#endif
+#if defined(SD8897)
+ case CARD_TYPE_SD8897:
+ phandle->card_info = &card_info_SD8897;
+ break;
+#endif
+#if defined(PCIE8897)
+ case CARD_TYPE_PCIE8897:
+ phandle->card_info = &card_info_PCIE8897;
+ break;
+#endif
+#if defined(USB8897)
+ case CARD_TYPE_USB8897:
+ phandle->card_info = &card_info_USB8897;
+ break;
+#endif
+#ifdef SD8977
+ case CARD_TYPE_SD8977:
+ phandle->card_info = &card_info_SD8977;
+ break;
+#endif
+#ifdef SD8978
+ case CARD_TYPE_SD8978:
+ phandle->card_info = &card_info_SD8978;
+ break;
+#endif
+#ifdef SD8997
+ case CARD_TYPE_SD8997:
+ phandle->card_info = &card_info_SD8997;
+ break;
+#endif
+#ifdef SD9098
+ case CARD_TYPE_SD9098:
+ phandle->card_info = &card_info_SD9098;
+ break;
+#endif
+#ifdef SD9097
+ case CARD_TYPE_SD9097:
+ phandle->card_info = &card_info_SD9097;
+ break;
+#endif
+#ifdef PCIE8997
+ case CARD_TYPE_PCIE8997:
+ phandle->card_info = &card_info_PCIE8997;
+ break;
+#endif
+#ifdef PCIE9097
+ case CARD_TYPE_PCIE9097:
+ phandle->card_info = &card_info_PCIE9097;
+ break;
+#endif
+#ifdef PCIE9098
+ case CARD_TYPE_PCIE9098:
+ phandle->card_info = &card_info_PCIE9098;
+ phandle->event_fw_dump = MTRUE;
+ break;
+#endif
+#ifdef USB8997
+ case CARD_TYPE_USB8997:
+ phandle->card_info = &card_info_USB8997;
+ break;
+#endif
+#ifdef USB8978
+ case CARD_TYPE_USB8978:
+ phandle->card_info = &card_info_USB8978;
+ break;
+#endif
+#ifdef USB9098
+ case CARD_TYPE_USB9098:
+ phandle->card_info = &card_info_USB9098;
+ break;
+#endif
+#ifdef USB9097
+ case CARD_TYPE_USB9097:
+ phandle->card_info = &card_info_USB9097;
+ break;
+#endif
+#ifdef SD8987
+ case CARD_TYPE_SD8987:
+ phandle->card_info = &card_info_SD8987;
+ break;
+#endif
+ default:
+ PRINTM(MERROR,
+ "woal_get_card_info can't get right card type \n");
+ ret = -1;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef STA_SUPPORT
+#endif /* STA_SUPPORT */
+
+/**
+ * @brief This function handles events generated by firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param payload A pointer to payload buffer
+ * @param len Length of the payload
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_broadcast_event(moal_private *priv, t_u8 *payload, t_u32 len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ moal_handle *handle = priv->phandle;
+ struct net_device *netdev = priv->netdev;
+ struct sock *sk = handle->nl_sk;
+
+ ENTER();
+
+ /* interface name to be prepended to event */
+ if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD
+#ifdef WIFI_DIRECT_SUPPORT
+ * 2
+#endif
+ ) {
+ PRINTM(MERROR, "event size is too big, len=%d\n", (int)len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (sk) {
+ /* Allocate skb */
+#ifdef WIFI_DIRECT_SUPPORT
+ if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) {
+ skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD * 2),
+ GFP_ATOMIC);
+ if (!skb) {
+ PRINTM(MERROR,
+ "Could not allocate skb for netlink\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ } else {
+#endif
+ skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD),
+ GFP_ATOMIC);
+ if (!skb) {
+ PRINTM(MERROR,
+ "Could not allocate skb for netlink\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#ifdef WIFI_DIRECT_SUPPORT
+ }
+#endif
+ memset(skb->data, 0, NLMSG_SPACE(NL_MAX_PAYLOAD));
+
+ nlh = (struct nlmsghdr *)skb->data;
+ nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ);
+
+ /* From kernel */
+ nlh->nlmsg_pid = 0;
+ nlh->nlmsg_flags = 0;
+
+ /* Data */
+ skb_put(skb, nlh->nlmsg_len);
+ moal_memcpy_ext(handle, NLMSG_DATA(nlh), netdev->name, IFNAMSIZ,
+ nlh->nlmsg_len - NLMSG_LENGTH(0));
+ moal_memcpy_ext(handle, ((t_u8 *)(NLMSG_DATA(nlh))) + IFNAMSIZ,
+ payload, len,
+ nlh->nlmsg_len - NLMSG_LENGTH(IFNAMSIZ));
+
+ /* From Kernel */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
+ NETLINK_CB(skb).pid = 0;
+#else
+ NETLINK_CB(skb).portid = 0;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ /* Multicast message */
+ NETLINK_CB(skb).dst_pid = 0;
+#endif
+
+ /* Multicast group number */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP;
+#else
+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
+#endif
+
+ /* Send message */
+ ret = netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP,
+ GFP_ATOMIC);
+ if (ret) {
+ PRINTM(MWARN, "netlink_broadcast failed: ret=%d\n",
+ ret);
+ goto done;
+ }
+
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR,
+ "Could not send event through NETLINK. Link down.\n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef REASSOCIATION
+/**
+ * @brief This function handles re-association. it is triggered
+ * by re-assoc timer.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int woal_reassociation_thread(void *data)
+{
+ moal_thread *pmoal_thread = data;
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)pmoal_thread->handle;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
+ wait_queue_t wait;
+#else
+ wait_queue_entry_t wait;
+#endif
+ int i;
+ BOOLEAN reassoc_timer_req;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_status status;
+ mlan_bss_info bss_info;
+ t_u32 timer_val = MOAL_TIMER_10S;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ ENTER();
+
+ woal_activate_thread(pmoal_thread);
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&pmoal_thread->wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&pmoal_thread->wait_q, &wait);
+#if defined(USB)
+ if (IS_USB(handle->card_type)) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+ try_to_freeze(0); /* Argument is not used by the kernel
+ */
+#else
+ try_to_freeze();
+#endif
+ }
+#endif
+
+ /* Cancel re-association timer */
+ if (handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+
+ if (handle->surprise_removed)
+ break;
+ if (kthread_should_stop())
+ break;
+
+ if (handle->hardware_status != HardwareStatusReady) {
+ PRINTM(MINFO,
+ "Reassoc: Hardware status is not correct\n");
+ continue;
+ }
+
+ PRINTM(MEVENT, "Reassoc: Thread waking up...\n");
+ reassoc_timer_req = MFALSE;
+#ifdef STA_CFG80211
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
+ (priv = handle->priv[i]);
+ i++) {
+ if (priv->roaming_required) {
+ priv->roaming_required = MFALSE;
+ PRINTM(MEVENT, "Try to roaming......\n");
+ woal_start_roaming(priv);
+ break;
+ }
+ }
+#endif
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM) &&
+ (priv = handle->priv[i]);
+ i++) {
+ if (priv->reassoc_required == MFALSE) {
+ priv->set_asynced_essid_flag = MFALSE;
+ continue;
+ }
+
+ memset(&bss_info, 0x00, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ PRINTM(MINFO, "Ressoc: Fail to get bss info\n");
+ priv->reassoc_required = MFALSE;
+ priv->set_asynced_essid_flag = MFALSE;
+ continue;
+ }
+
+ if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA ||
+ priv->media_connected != MFALSE) {
+ PRINTM(MINFO,
+ "Reassoc: ad-hoc mode or media connected\n");
+ priv->reassoc_required = MFALSE;
+ priv->set_asynced_essid_flag = MFALSE;
+ continue;
+ }
+ /** avoid on going scan from other thread */
+ if (handle->scan_pending_on_block) {
+ reassoc_timer_req = MTRUE;
+ break;
+ }
+
+ /* The semaphore is used to avoid reassociation
+ thread and wlan_set_scan/wlan_set_essid
+ interrupting each other. Reassociation should
+ be disabled completely by application if
+ wlan_set_user_scan_ioctl/wlan_set_wap is
+ used.
+ */
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR,
+ "Acquire semaphore error, reassociation thread\n");
+ reassoc_timer_req = MTRUE;
+ break;
+ }
+
+ PRINTM(MINFO, "Reassoc: Required ESSID: %s\n",
+ priv->prev_ssid_bssid.ssid.ssid);
+ PRINTM(MINFO, "Reassoc: Performing Active Scan\n");
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(priv->phandle, &req_ssid,
+ &priv->prev_ssid_bssid.ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT,
+ &req_ssid)) {
+ PRINTM(MERROR,
+ "Reassoc: Fail to do specific scan\n");
+ reassoc_timer_req = MTRUE;
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ if (handle->surprise_removed) {
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ break;
+ }
+
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (priv->set_asynced_essid_flag == MTRUE) {
+ if (priv->assoc_with_mac &&
+ memcmp(priv->prev_ssid_bssid.bssid,
+ zero_mac, MLAN_MAC_ADDR_LENGTH)) {
+ /* Search AP by BSSID & SSID */
+ PRINTM(MINFO,
+ "Reassoc: Search AP by BSSID & SSID\n");
+ moal_memcpy_ext(
+ priv->phandle,
+ &ssid_bssid.bssid,
+ &priv->prev_ssid_bssid.bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(mlan_802_11_mac_addr));
+ } else {
+ /* Search AP by ESSID for asynced essid
+ * setting */
+ PRINTM(MINFO,
+ "Set asynced essid: Search AP by ESSID\n");
+ }
+
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid,
+ &priv->prev_ssid_bssid.ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ } else {
+ /* Search AP by BSSID first */
+ PRINTM(MINFO,
+ "Reassoc: Search AP by BSSID first\n");
+ moal_memcpy_ext(priv->phandle,
+ &ssid_bssid.bssid,
+ &priv->prev_ssid_bssid.bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(mlan_802_11_mac_addr));
+ }
+
+ status = woal_find_best_network(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid);
+#ifdef STA_WEXT
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_11d_check_ap_channel(priv,
+ MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR,
+ "Reassoc: The AP's channel is invalid for current region\n");
+ status = MLAN_STATUS_FAILURE;
+ }
+ }
+#endif
+ /** The find AP without ssid, we need re-search
+ */
+ if (status == MLAN_STATUS_SUCCESS &&
+ !ssid_bssid.ssid.ssid_len) {
+ PRINTM(MINFO,
+ "Reassoc: Skip AP without ssid\n");
+ status = MLAN_STATUS_FAILURE;
+ }
+
+ if (priv->set_asynced_essid_flag != MTRUE &&
+ MLAN_STATUS_SUCCESS != status) {
+ PRINTM(MINFO,
+ "Reassoc: AP not found in scan list\n");
+ PRINTM(MINFO, "Reassoc: Search AP by SSID\n");
+ /* Search AP by SSID */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid,
+ &priv->prev_ssid_bssid.ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ status = woal_find_best_network(
+ priv, MOAL_IOCTL_WAIT, &ssid_bssid);
+#ifdef STA_WEXT
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_11d_check_ap_channel(
+ priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR,
+ "Reassoc: The AP's channel is invalid for current region\n");
+ status = MLAN_STATUS_FAILURE;
+ }
+ }
+#endif
+ }
+
+ if (status == MLAN_STATUS_SUCCESS) {
+ /* set the wep key */
+ if (bss_info.wep_status)
+ woal_enable_wep_key(priv,
+ MOAL_IOCTL_WAIT);
+ /* Zero SSID implies use BSSID to
+ * connect */
+ memset(&ssid_bssid.ssid, 0,
+ sizeof(mlan_802_11_ssid));
+ status = woal_bss_start(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid);
+ }
+
+ if (priv->media_connected == MFALSE)
+ reassoc_timer_req = MTRUE;
+ else {
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ reassoc_timer_req = MFALSE;
+ if (priv->set_asynced_essid_flag == MTRUE) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv,
+ MOAL_IOCTL_WAIT,
+ &bss_info)) {
+ PRINTM(MINFO,
+ "Set asynced essid: Fail to get bss info after assoc\n");
+ } else {
+ moal_memcpy_ext(
+ priv->phandle,
+ &priv->prev_ssid_bssid
+ .ssid,
+ &bss_info.ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(
+ priv->phandle,
+ &priv->prev_ssid_bssid
+ .bssid,
+ &bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->prev_ssid_bssid
+ .bssid));
+ }
+ priv->set_asynced_essid_flag = MFALSE;
+ }
+ if (priv->rate_index != AUTO_RATE) {
+ req = woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_rate));
+
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->param.rate_cfg.rate_type =
+ MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+
+ req->action = MLAN_ACT_SET;
+
+ rate->param.rate_cfg.rate =
+ priv->rate_index;
+
+ status = woal_request_ioctl(
+ priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ if (status !=
+ MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ kfree(req);
+ }
+ }
+
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+ }
+
+ if (handle->surprise_removed)
+ break;
+
+ if (reassoc_timer_req == MTRUE) {
+ handle->is_reassoc_timer_set = MTRUE;
+ if (priv && (priv->set_asynced_essid_flag == MTRUE)) {
+ PRINTM(MERROR,
+ "Set Async ESSID: No AP found or assoc failed.\n");
+ priv->set_asynced_essid_flag = MFALSE;
+ } else {
+ PRINTM(MEVENT,
+ "Reassoc: No AP found or assoc failed. "
+ "Restarting re-assoc Timer: %d\n",
+ (int)timer_val);
+ woal_mod_timer(&handle->reassoc_timer,
+ timer_val);
+ }
+ } else {
+ if (priv) {
+ priv->set_asynced_essid_flag = MFALSE;
+ }
+ }
+ }
+ woal_deactivate_thread(pmoal_thread);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function triggers re-association by waking up
+ * re-assoc thread.
+ *
+ * @param context A pointer to context
+ * @return N/A
+ */
+void woal_reassoc_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *)context;
+
+ ENTER();
+
+ PRINTM(MINFO, "reassoc_timer fired.\n");
+ handle->is_reassoc_timer_set = MFALSE;
+
+ PRINTM(MINFO, "Waking Up the Reassoc Thread\n");
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ LEAVE();
+ return;
+}
+#endif /* REASSOCIATION */
+
+#ifdef STA_SUPPORT
+/**
+ * @brief update dscp mapping from assoc_resp/reassoc_resp
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ *
+ * @return N/A
+ */
+void woal_update_dscp_mapping(moal_private *priv)
+{
+ mlan_ds_misc_assoc_rsp assoc_rsp;
+ IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
+ IEEEtypes_Header_t *qos_mapping_ie = NULL;
+ DSCP_Range_t *pdscp_range = NULL;
+ t_u8 dscp_except_num = 0;
+ DSCP_Exception_t dscp_except[MAX_DSCP_EXCEPTION_NUM];
+ int i, j;
+ ENTER();
+
+ memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
+ woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_NO_WAIT);
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp.assoc_resp_buf;
+ memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
+ qos_mapping_ie = (IEEEtypes_Header_t *)woal_parse_ie_tlv(
+ passoc_rsp->ie_buffer,
+ assoc_rsp.assoc_resp_len - ASSOC_RESP_FIXED_SIZE, QOS_MAPPING);
+ if (qos_mapping_ie &&
+ (qos_mapping_ie->len >= (sizeof(DSCP_Range_t) * MAX_NUM_TID))) {
+ dscp_except_num = (qos_mapping_ie->len -
+ sizeof(DSCP_Range_t) * MAX_NUM_TID) /
+ sizeof(DSCP_Exception_t);
+ if (dscp_except_num > MAX_DSCP_EXCEPTION_NUM) {
+ PRINTM(MERROR, "dscp_except_num exceeds MAX limit\n");
+ LEAVE();
+ return;
+ }
+ moal_memcpy_ext(priv->phandle, dscp_except,
+ (t_u8 *)qos_mapping_ie +
+ sizeof(IEEEtypes_Header_t),
+ dscp_except_num * sizeof(DSCP_Exception_t),
+ sizeof(dscp_except));
+ pdscp_range =
+ (DSCP_Range_t *)((t_u8 *)qos_mapping_ie +
+ sizeof(IEEEtypes_Header_t) +
+ dscp_except_num *
+ sizeof(DSCP_Exception_t));
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ PRINTM(MEVENT, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
+ pdscp_range->dscp_low_value,
+ pdscp_range->dscp_high_value);
+ if (pdscp_range->dscp_low_value != 0xff &&
+ pdscp_range->dscp_high_value != 0xff &&
+ pdscp_range->dscp_high_value <= 63) {
+ for (j = pdscp_range->dscp_low_value;
+ j <= pdscp_range->dscp_high_value; j++)
+ priv->dscp_map[j] = i;
+ }
+ pdscp_range++;
+ }
+ for (i = 0; i < dscp_except_num; i++) {
+ if ((dscp_except[i].dscp_value <= 63) &&
+ (dscp_except[i].user_priority <= 7)) {
+ PRINTM(MEVENT,
+ "dscp excpt: value=%d priority=%d\n",
+ dscp_except[i].dscp_value,
+ dscp_except[i].user_priority);
+ priv->dscp_map[dscp_except[i].dscp_value] =
+ dscp_except[i].user_priority;
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Sends disconnect event
+ *
+ * @param priv A pointer to moal_private struct
+ * @param disconnect_reason disconnect reason code
+ * @return N/A
+ */
+t_void woal_send_disconnect_to_system(moal_private *priv,
+ t_u16 disconnect_reason)
+{
+ int custom_len = 0;
+ t_u8 event_buf[32];
+#ifdef STA_WEXT
+ union iwreq_data wrqu;
+#endif
+#ifdef STA_CFG80211
+ unsigned long flags;
+#endif
+ int cfg80211_wext = priv->phandle->params.cfg80211_wext;
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ mlan_ds_misc_gtk_rekey_data zero_gtk;
+#endif
+#endif
+ t_u16 reason_code = 0;
+
+ ENTER();
+ priv->media_connected = MFALSE;
+ if (!disconnect_reason)
+ reason_code = MLAN_REASON_DEAUTH_LEAVING;
+ else
+ reason_code = disconnect_reason;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ woal_flush_tcp_sess_queue(priv);
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ priv->gtk_data_ready = MFALSE;
+ memset(&zero_gtk, 0x00, sizeof(zero_gtk));
+ if (priv->phandle->params.gtk_rekey_offload ==
+ GTK_REKEY_OFFLOAD_ENABLE &&
+ memcmp(&priv->gtk_rekey_data, &zero_gtk,
+ sizeof(priv->gtk_rekey_data)) != 0) {
+ PRINTM(MCMND, "clear GTK in woal_send_disconnect_to_system\n");
+ woal_set_rekey_data(priv, NULL, MLAN_ACT_CLEAR, MOAL_NO_WAIT);
+ }
+ memset(&priv->gtk_rekey_data, 0, sizeof(mlan_ds_misc_gtk_rekey_data));
+#endif
+#endif
+
+#ifdef STA_CFG80211
+ if (priv->bss_type == MLAN_BSS_TYPE_STA &&
+ IS_STA_CFG80211(cfg80211_wext)) {
+ woal_flush_pmksa_list(priv);
+ if (priv->okc_roaming_ie) {
+ kfree(priv->okc_roaming_ie);
+ priv->okc_roaming_ie = NULL;
+ priv->okc_ie_len = 0;
+ }
+ }
+#endif
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_hist_data_reset(priv);
+
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ spin_lock_irqsave(&priv->connect_lock, flags);
+ if (!priv->cfg_disconnect && !priv->cfg_connect && priv->wdev &&
+ priv->wdev->current_bss) {
+ PRINTM(MMSG,
+ "wlan: Disconnected from " MACSTR
+ ": Reason code %d\n",
+ MAC2STR(priv->cfg_bssid), reason_code);
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ priv->cfg_disconnect = MTRUE;
+ /* This function must be called only when
+ disconnect issued by the FW, i.e.
+ disconnected by AP. For IBSS mode this call
+ is not valid */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (priv->host_mlme)
+ woal_host_mlme_disconnect(priv, reason_code,
+ NULL);
+ else
+#endif
+ cfg80211_disconnected(priv->netdev, reason_code,
+ NULL, 0,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ false,
+#endif
+ GFP_KERNEL);
+ } else {
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ }
+ if (!woal_is_any_interface_active(priv->phandle))
+ woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ SPECIFIC_SCAN_CHAN_TIME);
+ priv->ft_ie_len = 0;
+ priv->ft_pre_connect = MFALSE;
+ priv->ft_md = 0;
+ priv->ft_cap = 0;
+ memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
+ }
+#endif /* STA_CFG80211 */
+
+ memset(event_buf, 0, sizeof(event_buf));
+ custom_len = strlen(CUS_EVT_AP_CONNECTED);
+ strncpy(event_buf, CUS_EVT_AP_CONNECTED,
+ MIN((sizeof(event_buf) - 1), custom_len));
+ woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
+ LEAVE();
+}
+#endif /* STA_SUPPORT */
+
+#if defined(PCIE)
+/**
+ * @brief This function stores the SSU dumps in a file
+ *
+ * @param phandle A pointer to moal_handle
+ * @param pmevent A pointer to mlan_event structure
+ *
+ * @return N/A
+ */
+t_void woal_store_ssu_dump(moal_handle *phandle, mlan_event *pmevent)
+{
+ struct dentry *dentry;
+ struct path path;
+ struct file *pfile_ssudump = NULL;
+ char dw_string[10];
+ loff_t pos = 0;
+ t_u32 i;
+ t_u32 *tmpbuf;
+
+ ENTER();
+ dentry = kern_path_create(AT_FDCWD, "/data", &path, 1);
+ if (IS_ERR(dentry)) {
+ goto save_ssudump;
+ }
+ vfs_mkdir(path.dentry->d_inode, dentry, 0777);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
+ mutex_unlock(&path.dentry->d_inode->i_mutex);
+#else
+ inode_unlock(path.dentry->d_inode);
+#endif
+
+save_ssudump:
+ pfile_ssudump = filp_open("/data/ssudump.txt",
+ O_CREAT | O_WRONLY | O_APPEND, 0644);
+ if (IS_ERR(pfile_ssudump)) {
+ PRINTM(MERROR, "Cannot create ssu dump file\n");
+ LEAVE();
+ return;
+ }
+ DBG_HEXDUMP(MEVT_D, "SSU addr", pmevent->event_buf, 8);
+ moal_memcpy_ext(phandle, &tmpbuf, pmevent->event_buf, sizeof(t_ptr),
+ sizeof(t_ptr));
+ PRINTM(MEVENT, "woal_store_ssu_dump: tmpbuf %p\n", tmpbuf);
+ for (i = 0; i < pmevent->event_len / 4; i++) {
+ if ((i + 1) % 8 == 0)
+ snprintf(dw_string, sizeof(dw_string), "%08x\n",
+ *tmpbuf);
+ else
+ snprintf(dw_string, sizeof(dw_string), "%08x ",
+ *tmpbuf);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ vfs_write(pfile_ssudump, dw_string, 9, &pos);
+#else
+ kernel_write(pfile_ssudump, dw_string, 9, &pos);
+#endif
+ tmpbuf++;
+ }
+ filp_close(pfile_ssudump, NULL);
+ LEAVE();
+ return;
+}
+#endif /* SSU_SUPPORT */
+
+#define OFFSET_SEQNUM 4
+#define OFFSET_TYPE 8
+#define DUMP_TYPE_ENDE 2
+t_void woal_store_firmware_dump(moal_handle *phandle, mlan_event *pmevent)
+{
+ struct file *pfile_fwdump = NULL;
+ loff_t pos = 0;
+ t_u16 seqnum;
+ t_u16 type = 0;
+ t_u8 path_name[64];
+ moal_handle *ref_handle = NULL;
+
+ ENTER();
+ if (phandle->fwdump_fname)
+ pfile_fwdump = filp_open(phandle->fwdump_fname,
+ O_CREAT | O_WRONLY | O_APPEND, 0644);
+ else {
+ seqnum = woal_le16_to_cpu(
+ *(t_u16 *)(pmevent->event_buf + OFFSET_SEQNUM));
+ type = woal_le16_to_cpu(
+ *(t_u16 *)(pmevent->event_buf + OFFSET_TYPE));
+
+ if (seqnum == 1) {
+ if (drvdbg & MFW_D)
+ drvdbg &= ~MFW_D;
+ phandle->fw_dump_len = 0;
+ PRINTM(MMSG,
+ "==== Start Receive FW dump event ====\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ /** Create dump directort*/
+ woal_create_dump_dir(phandle, path_name,
+ sizeof(path_name));
+#else
+ memset(path_name, 0, sizeof(path_name));
+ strcpy(path_name, "/data");
+#endif
+ PRINTM(MMSG, "Firmware Dump directory name is %s\n",
+ path_name);
+ ref_handle = (moal_handle *)phandle->pref_mac;
+ if (ref_handle)
+ woal_dump_drv_info(ref_handle, path_name);
+ woal_dump_drv_info(phandle, path_name);
+ if (fwdump_fname) {
+ memset(fwdump_fname, 0, 64);
+ } else {
+ gfp_t flag;
+ flag = (in_atomic() || irqs_disabled()) ?
+ GFP_ATOMIC :
+ GFP_KERNEL;
+ fwdump_fname = kzalloc(64, flag);
+ }
+ sprintf(fwdump_fname, "%s/file_fwdump", path_name);
+ pfile_fwdump =
+ filp_open(fwdump_fname,
+ O_CREAT | O_WRONLY | O_APPEND, 0644);
+ if (IS_ERR(pfile_fwdump)) {
+ memset(fwdump_fname, 0, 64);
+ sprintf(fwdump_fname, "%s/%s", "/var",
+ "file_fwdump");
+ pfile_fwdump =
+ filp_open(fwdump_fname,
+ O_CREAT | O_WRONLY | O_APPEND,
+ 0644);
+ }
+ } else
+ pfile_fwdump =
+ filp_open(fwdump_fname,
+ O_CREAT | O_WRONLY | O_APPEND, 0644);
+ }
+ if (IS_ERR(pfile_fwdump)) {
+ PRINTM(MERROR, "Cannot create firmware dump file\n");
+ LEAVE();
+ return;
+ }
+ phandle->fw_dump_len += pmevent->event_len - OFFSET_SEQNUM;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ vfs_write(pfile_fwdump, pmevent->event_buf + OFFSET_SEQNUM,
+ pmevent->event_len - OFFSET_SEQNUM, &pos);
+#else
+ kernel_write(pfile_fwdump, pmevent->event_buf + OFFSET_SEQNUM,
+ pmevent->event_len - OFFSET_SEQNUM, &pos);
+#endif
+ filp_close(pfile_fwdump, NULL);
+ if (type == DUMP_TYPE_ENDE)
+ PRINTM(MMSG, "==== FW DUMP END: %ld bytes ====\n",
+ (long int)phandle->fw_dump_len);
+ LEAVE();
+ return;
+}
+
+#define DRV_INFO_SIZE 0x60000
+#define DRV_INFO_PER_INTF 0x11000
+#define ROW_SIZE_16 16
+#define ROW_SIZE_32 32
+
+/**
+ * @brief This function dump hex to file
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer to buffer to dump
+ * @param len lengh of buf
+ * @param ascii Whether add ascii at the end
+ * @param save_buf Buffer which is saved to
+ *
+ * @return The length of this log
+ */
+static int woal_save_hex_dump(int rowsize, const void *buf, size_t len,
+ bool ascii, t_u8 *save_buf)
+{
+ const u8 *ptr = buf;
+ int i, linelen, remaining = len;
+ unsigned char linebuf[ROW_SIZE_32 * 3 + 2 + ROW_SIZE_32 + 1];
+ char *pos = (char *)save_buf;
+
+ if (rowsize != ROW_SIZE_16 && rowsize != ROW_SIZE_32)
+ rowsize = ROW_SIZE_16;
+
+ for (i = 0; i < len; i += rowsize) {
+ linelen = min(remaining, rowsize);
+ remaining -= rowsize;
+
+ hex_dump_to_buffer(ptr + i, linelen, rowsize, 1, linebuf,
+ sizeof(linebuf), false);
+
+ pos += sprintf(pos, "%s\n", linebuf);
+ }
+
+ return pos - (char *)save_buf;
+}
+
+/**
+ * @brief This function save moal_priv's debug log
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer buffer saving log
+ *
+ * @return The length of this log
+ */
+static int woal_dump_priv_drv_info(moal_handle *handle, t_u8 *buf)
+{
+ char *ptr = (char *)buf;
+ int index;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ int i = 0;
+#endif
+ moal_private *priv;
+
+ ENTER();
+ if (!handle || !buf) {
+ PRINTM(MMSG, "%s: can't retreive info\n", __func__);
+ LEAVE();
+ return 0;
+ }
+ for (index = 0; index < MIN(handle->priv_num, MLAN_MAX_BSS_NUM);
+ index++) {
+ priv = handle->priv[index];
+ if (priv) {
+ ptr += sprintf(ptr, "[Interface : %s]\n",
+ priv->proc_entry_name);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ ptr += sprintf(ptr, "wmm_tx_pending[0] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[0]));
+ ptr += sprintf(ptr, "wmm_tx_pending[1] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[1]));
+ ptr += sprintf(ptr, "wmm_tx_pending[2] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[2]));
+ ptr += sprintf(ptr, "wmm_tx_pending[3] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[3]));
+#endif
+ ptr += sprintf(ptr, "Media state = \"%s\"\n",
+ ((priv->media_connected == MFALSE) ?
+ "Disconnected" :
+ "Connected"));
+ ptr += sprintf(ptr, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ?
+ "on" :
+ "off"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
+ ptr += sprintf(
+ ptr, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped(
+ netdev_get_tx_queue(
+ priv->netdev, i))) ?
+ "stopped" :
+ "started"));
+ }
+#else
+ ptr += sprintf(ptr, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ?
+ "stopped" :
+ "started"));
+#endif
+ ptr += sprintf(ptr, "%s: num_tx_timeout = %d\n",
+ priv->netdev->name,
+ priv->num_tx_timeout);
+ }
+ }
+
+ LEAVE();
+ return ptr - (char *)buf;
+}
+
+/**
+ * @brief This function save moal_handle's info
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer buffer saving log
+ *
+ * @return The length of this log
+ */
+static int woal_dump_moal_drv_info(moal_handle *phandle, t_u8 *buf)
+{
+ char *ptr;
+#ifdef USB
+ struct usb_card_rec *cardp = NULL;
+#endif
+ char str_buf[MLAN_MAX_VER_STR_LEN];
+
+ ENTER();
+ if (!phandle || !buf) {
+ PRINTM(MMSG, "%s: can't retreive info\n", __func__);
+ LEAVE();
+ return 0;
+ }
+#ifdef USB
+ if (IS_USB(phandle->card_type))
+ cardp = (struct usb_card_rec *)phandle->card;
+#endif
+ ptr = (char *)buf;
+ ptr += sprintf(ptr, "------------moal_debug_info-------------\n");
+ woal_get_version(phandle, str_buf, sizeof(str_buf) - 1);
+ ptr += sprintf(ptr, "Driver version = %s\n", str_buf);
+ ptr += sprintf(ptr, "main_state = %d\n", phandle->main_state);
+#ifdef USB
+ if (IS_USB(phandle->card_type)) {
+ ptr += sprintf(ptr, "tx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->tx_cmd_urb_pending));
+ ptr += sprintf(ptr, "tx_data_urb_pending = %d\n",
+ atomic_read(&cardp->tx_data_urb_pending));
+#ifdef USB_CMD_DATA_EP
+ ptr += sprintf(ptr, "rx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->rx_cmd_urb_pending));
+#endif
+ ptr += sprintf(ptr, "rx_data_urb_pending = %d\n",
+ atomic_read(&cardp->rx_data_urb_pending));
+ }
+#endif
+ ptr += sprintf(ptr, "ioctl_pending = %d\n",
+ atomic_read(&phandle->ioctl_pending));
+ ptr += sprintf(ptr, "tx_pending = %d\n",
+ atomic_read(&phandle->tx_pending));
+ ptr += sprintf(ptr, "rx_pending = %d\n",
+ atomic_read(&phandle->rx_pending));
+ ptr += sprintf(ptr, "lock_count = %d\n",
+ atomic_read(&phandle->lock_count));
+ ptr += sprintf(ptr, "malloc_count = %d\n",
+ atomic_read(&phandle->malloc_count));
+ ptr += sprintf(ptr, "mbufalloc_count = %d\n",
+ atomic_read(&phandle->mbufalloc_count));
+#ifdef PCIE
+ if (IS_PCIE(phandle->card_type)) {
+ ptr += sprintf(ptr, "malloc_cons_count = %d\n",
+ atomic_read(&phandle->malloc_cons_count));
+ }
+#endif
+ ptr += sprintf(ptr, "hs_skip_count = %u\n", phandle->hs_skip_count);
+ ptr += sprintf(ptr, "hs_force_count = %u\n", phandle->hs_force_count);
+
+ ptr += woal_dump_priv_drv_info(phandle, ptr);
+ ptr += sprintf(ptr, "------------moal_debug_info End-------------\n");
+
+ if (phandle->ops.dump_reg_info)
+ ptr += phandle->ops.dump_reg_info(phandle, ptr);
+
+ LEAVE();
+ return ptr - (char *)buf;
+}
+
+/**
+ * @brief This function save mlan's info
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer buffer saving log
+ *
+ * @return The length of this log
+ */
+static int woal_dump_mlan_drv_info(moal_private *priv, t_u8 *buf)
+{
+ char *ptr = (char *)buf;
+ int i;
+#ifdef SDIO
+ int j;
+ t_u8 mp_aggr_pkt_limit = 0;
+#endif
+ char str[11 * DBG_CMD_NUM + 1] = {0};
+ char *s;
+ mlan_debug_info *info = NULL;
+
+ ENTER();
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or priv->phandle is null\n");
+ LEAVE();
+ return 0;
+ }
+ info = &(priv->phandle->debug_info);
+ if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
+ PRINTM(MERROR,
+ "Could not retrieve debug information from MLAN\n");
+ LEAVE();
+ return 0;
+ }
+ ptr += sprintf(ptr, "------------mlan_debug_info-------------\n");
+ ptr += sprintf(ptr, "mlan_processing =%d\n", info->mlan_processing);
+ ptr += sprintf(ptr, "main_lock_flag =%d\n", info->main_lock_flag);
+ ptr += sprintf(ptr, "main_process_cnt =%d\n", info->main_process_cnt);
+ ptr += sprintf(ptr, "delay_task_flag =%d\n", info->delay_task_flag);
+ ptr += sprintf(ptr, "mlan_rx_processing =%d\n",
+ info->mlan_rx_processing);
+ ptr += sprintf(ptr, "rx_pkts_queued =%d\n", info->rx_pkts_queued);
+ ptr += sprintf(ptr, "tx_pkts_queued =%d\n", info->tx_pkts_queued);
+ ptr += sprintf(ptr, "fw_hang_report = %d\n", info->fw_hang_report);
+ ptr += sprintf(ptr, "num_cmd_timeout = %d\n", info->num_cmd_timeout);
+ ptr += sprintf(ptr, "Timeout cmd id = 0x%x, act = 0x%x\n",
+ info->timeout_cmd_id, info->timeout_cmd_act);
+ ptr += sprintf(ptr, "last_cmd_index = %d\n", info->last_cmd_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_id[i]);
+ ptr += sprintf(ptr, "last_cmd_id = %s\n", str);
+
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_act[i]);
+
+ ptr += sprintf(ptr, "last_cmd_act = %s\n", str);
+ ptr += sprintf(ptr, "last_cmd_resp_index = %d\n",
+ info->last_cmd_resp_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_cmd_resp_id[i]);
+
+ ptr += sprintf(ptr, "last_cmd_resp_id = %s\n", str);
+ ptr += sprintf(ptr, "last_event_index = %d\n", info->last_event_index);
+ for (s = str, i = 0; i < DBG_CMD_NUM; i++)
+ s += sprintf(s, "0x%x ", info->last_event[i]);
+
+ ptr += sprintf(ptr, "last_event = %s\n", str);
+ ptr += sprintf(ptr, "num_data_h2c_failure = %d\n",
+ info->num_tx_host_to_card_failure);
+ ptr += sprintf(ptr, "num_cmd_h2c_failure = %d\n",
+ info->num_cmd_host_to_card_failure);
+ ptr += sprintf(ptr, "num_alloc_buffer_failure = %d\n",
+ info->num_alloc_buffer_failure);
+ ptr += sprintf(ptr, "num_pkt_dropped = %d\n", info->num_pkt_dropped);
+#ifdef SDIO
+ if (IS_SD(priv->phandle->card_type)) {
+ ptr += sprintf(ptr, "num_data_c2h_failure = %d\n",
+ info->num_rx_card_to_host_failure);
+ ptr += sprintf(ptr, "num_cmdevt_c2h_failure = %d\n",
+ info->num_cmdevt_card_to_host_failure);
+ ptr += sprintf(ptr, "num_int_read_failure = %d\n",
+ info->num_int_read_failure);
+ ptr += sprintf(ptr, "last_int_status = %d\n",
+ info->last_int_status);
+ ptr += sprintf(ptr, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ (unsigned int)info->mp_rd_bitmap,
+ info->curr_rd_port);
+ ptr += sprintf(ptr, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ (unsigned int)info->mp_wr_bitmap,
+ info->curr_wr_port);
+ ptr += sprintf(ptr, "mp_invalid_update=%d\n",
+ info->mp_invalid_update);
+ mp_aggr_pkt_limit = info->mp_aggr_pkt_limit;
+ ptr += sprintf(ptr,
+ "last_recv_wr_bitmap=0x%x last_mp_index = %d\n",
+ info->last_recv_wr_bitmap, info->last_mp_index);
+ for (i = 0; i < SDIO_MP_DBG_NUM; i++) {
+ for (s = str, j = 0; j < mp_aggr_pkt_limit; j++)
+ s += sprintf(
+ s, "0x%02x ",
+ info->last_mp_wr_info
+ [i * mp_aggr_pkt_limit + j]);
+
+ ptr += sprintf(
+ ptr,
+ "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n%s\n",
+ info->last_mp_wr_bitmap[i],
+ info->last_mp_wr_ports[i],
+ info->last_mp_wr_len[i],
+ info->last_curr_wr_port[i], str);
+ }
+ }
+#endif
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ ptr += sprintf(ptr, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n",
+ info->txbd_rdptr, info->txbd_wrptr);
+ ptr += sprintf(ptr, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n",
+ info->rxbd_rdptr, info->rxbd_wrptr);
+ ptr += sprintf(ptr, "eventbd_rdptr=0x%x event_wrptr=0x%x\n",
+ info->eventbd_rdptr, info->eventbd_wrptr);
+ ptr += sprintf(ptr, "last_wr_index:%d\n",
+ info->txbd_wrptr & (MLAN_MAX_TXRX_BD - 1));
+ ptr += sprintf(ptr, "Tx pkt size:\n");
+ for (i = 0; i < MLAN_MAX_TXRX_BD; i++) {
+ ptr += sprintf(ptr, "%04d ", info->last_tx_pkt_size[i]);
+ if (((i + 1) % 16) == 0)
+ ptr += sprintf(ptr, "\n");
+ }
+ }
+#endif
+ ptr += sprintf(ptr, "num_event_deauth = %d\n", info->num_event_deauth);
+ ptr += sprintf(ptr, "num_event_disassoc = %d\n",
+ info->num_event_disassoc);
+ ptr += sprintf(ptr, "num_event_link_lost = %d\n",
+ info->num_event_link_lost);
+ ptr += sprintf(ptr, "num_cmd_deauth = %d\n", info->num_cmd_deauth);
+ ptr += sprintf(ptr, "num_cmd_assoc_success = %d\n",
+ info->num_cmd_assoc_success);
+ ptr += sprintf(ptr, "num_cmd_assoc_failure = %d\n",
+ info->num_cmd_assoc_failure);
+ ptr += sprintf(ptr, "num_cons_assoc_failure = %d\n",
+ info->num_cons_assoc_failure);
+ ptr += sprintf(ptr, "cmd_resp_received = %d\n",
+ info->cmd_resp_received);
+ ptr += sprintf(ptr, "event_received = %d\n", info->event_received);
+ ptr += sprintf(ptr, "max_tx_buf_size = %d\n", info->max_tx_buf_size);
+ ptr += sprintf(ptr, "tx_buf_size = %d\n", info->tx_buf_size);
+ ptr += sprintf(ptr, "curr_tx_buf_size = %d\n", info->curr_tx_buf_size);
+
+ ptr += sprintf(ptr, "data_sent=%d cmd_sent=%d\n", info->data_sent,
+ info->cmd_sent);
+ ptr += sprintf(ptr, "ps_mode=%d ps_state=%d\n", info->ps_mode,
+ info->ps_state);
+ ptr += sprintf(
+ ptr, "wakeup_dev_req=%d wakeup_tries=%d pm_wakeup_timeout=%d\n",
+ info->pm_wakeup_card_req, info->pm_wakeup_fw_try,
+ info->pm_wakeup_timeout);
+ ptr += sprintf(ptr, "hs_configured=%d hs_activated=%d\n",
+ info->is_hs_configured, info->hs_activated);
+ ptr += sprintf(ptr, "pps_uapsd_mode=%d sleep_pd=%d\n",
+ info->pps_uapsd_mode, info->sleep_pd);
+ ptr += sprintf(ptr, "tx_lock_flag = %d\n", info->tx_lock_flag);
+ ptr += sprintf(ptr, "port_open = %d\n", info->port_open);
+ ptr += sprintf(ptr, "scan_processing = %d\n", info->scan_processing);
+
+#ifdef PCIE
+ if (IS_PCIE(priv->phandle->card_type)) {
+ ptr += sprintf(ptr, "txbd: rdptr=0x%x wrptr=0x%x\n",
+ info->txbd_rdptr, info->txbd_wrptr);
+ ptr += sprintf(ptr, "rxbd: rdptr=0x%x wrptr=0x%x\n",
+ info->rxbd_rdptr, info->rxbd_wrptr);
+ ptr += sprintf(ptr, "eventbd: rdptr=0x%x wrptr=0x%x\n",
+ info->eventbd_rdptr, info->eventbd_wrptr);
+ ptr += sprintf(ptr, "TXBD Ring:\n");
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->txbd_ring_vbase,
+ info->txbd_ring_size, MTRUE, ptr);
+ ptr += sprintf(ptr, "RXBD Ring:\n");
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->rxbd_ring_vbase,
+ info->rxbd_ring_size, MTRUE, ptr);
+ ptr += sprintf(ptr, "EVTBD Ring:\n");
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->evtbd_ring_vbase,
+ info->evtbd_ring_size, MTRUE, ptr);
+ }
+#endif
+ ptr += sprintf(ptr, "------------mlan_debug_info End-------------\n");
+
+ LEAVE();
+ return ptr - (char *)buf;
+}
+#define HostCmd_CMD_CFG_DATA 0x008f
+#define DEF_FW_PATH "/lib/firmware/"
+#define DEF_HOSTCMD_PATH "/lib/firmware/nxp/hostcmd.conf"
+/**
+ * @brief This function save the hostcmd response to file
+ *
+ * @param phandle A pointer to moal_handle
+ * @param pevent A pointer to mlan_cmdresp_event
+ *
+ * @return N/A
+ */
+t_void woal_save_host_cmdresp(moal_handle *phandle, mlan_cmdresp_event *pevent)
+{
+ HostCmd_DS_GEN *resp;
+ char file_path[256];
+ struct file *pfile = NULL;
+ char *dpd_data_cfg = phandle->params.dpd_data_cfg;
+ int ret;
+ t_u8 *buf;
+ t_u16 command;
+ int len = 0;
+ char *ptr;
+ loff_t pos = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ mm_segment_t fs;
+#endif
+
+ resp = (HostCmd_DS_GEN *)pevent->resp;
+ command = woal_le16_to_cpu(resp->command);
+ memset(file_path, 0, sizeof(file_path));
+ ret = moal_vmalloc(phandle, pevent->event_len * 5, &buf);
+ if (ret != MLAN_STATUS_SUCCESS || !buf) {
+ PRINTM(MERROR, "Fail to allocate memory to save hostcmd\n");
+ return;
+ }
+ memset(buf, 0, pevent->event_len * 5);
+ ptr = (char *)buf;
+ switch (command) {
+ case HostCmd_CMD_CFG_DATA:
+ if (dpd_data_cfg)
+ sprintf(file_path, "%s%s", DEF_FW_PATH, dpd_data_cfg);
+ else
+ sprintf(file_path, "%s", DEF_HOSTCMD_PATH);
+ break;
+ default:
+ sprintf(file_path, "%s", DEF_HOSTCMD_PATH);
+ break;
+ }
+ pfile = filp_open(file_path, O_CREAT | O_WRONLY | O_APPEND, 0644);
+ if (IS_ERR(pfile)) {
+ PRINTM(MERROR, "Cannot create file %s\n", file_path);
+ moal_vfree(phandle, buf);
+ return;
+ }
+ ptr += sprintf(ptr, "hostcmd_%02x=={\n", command);
+ ptr += woal_save_hex_dump(ROW_SIZE_16, resp, pevent->event_len, MFALSE,
+ ptr);
+ ptr += sprintf(ptr, "}\n");
+ len = ptr - (char *)buf;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ vfs_write(pfile, buf, len, &pos);
+ set_fs(fs);
+#else
+ kernel_write(pfile, buf, len, &pos);
+#endif
+ PRINTM(MMSG, "Save hostcmd 0x%02x, cmd len=%d file len=%d to file %s\n",
+ command, pevent->event_len, len, file_path);
+ if (buf)
+ moal_vfree(phandle, buf);
+ filp_close(pfile, NULL);
+ return;
+}
+
+/**
+ * @brief This function dump moal hex to file
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer to buffer
+ *
+ * @return The length of this log
+ */
+static int woal_dump_moal_hex(moal_handle *phandle, t_u8 *buf)
+{
+ char *ptr = (char *)buf;
+ int i;
+ ENTER();
+
+ if (!phandle || !buf) {
+ PRINTM(MMSG, "%s: can't retreive info\n", __func__);
+ LEAVE();
+ return 0;
+ }
+
+ ptr += sprintf(ptr, "<--moal_handle-->\n");
+ ptr += sprintf(ptr, "moal_handle=%p, size=%ld(0x%lx)\n", phandle,
+ (long int)sizeof(*phandle),
+ (long unsigned int)sizeof(*phandle));
+ ptr += woal_save_hex_dump(ROW_SIZE_16, phandle, sizeof(*phandle), MTRUE,
+ ptr);
+ ptr += sprintf(ptr, "<--moal_handle End-->\n");
+
+ for (i = 0; i < phandle->priv_num; i++) {
+ ptr += sprintf(ptr, "<--moal_private(%d)-->\n", i);
+ ptr += sprintf(ptr, "moal_private=%p, size=%ld(0x%lx)\n",
+ phandle->priv[i],
+ (long int)sizeof(*(phandle->priv[i])),
+ (long unsigned int)sizeof(*(phandle->priv[i])));
+ ptr += woal_save_hex_dump(ROW_SIZE_16, phandle->priv[i],
+ sizeof(*(phandle->priv[i])), MTRUE,
+ ptr);
+ ptr += sprintf(ptr, "<--moal_private(%d) End-->\n", i);
+ }
+ LEAVE();
+ return ptr - (char *)buf;
+}
+
+/**
+ * @brief This function dump mlan hex to file
+ *
+ * @param priv A pointer to moal_private structure
+ * @param buf A pointer to buffer
+ *
+ * @return The length of this log
+ */
+static int woal_dump_mlan_hex(moal_private *priv, t_u8 *buf)
+{
+ char *ptr = (char *)buf;
+ int i;
+ mlan_debug_info *info = NULL;
+
+ ENTER();
+
+ if (!buf || !priv || !priv->phandle) {
+ PRINTM(MERROR, "buf priv or priv->phandle is null\n");
+ LEAVE();
+ return 0;
+ }
+ info = &(priv->phandle->debug_info);
+ if (woal_get_debug_info(priv, MOAL_IOCTL_WAIT, info)) {
+ PRINTM(MMSG, "%s: can't retreive info\n", __func__);
+ LEAVE();
+ return 0;
+ }
+
+ ptr += sprintf(ptr, "<--mlan_adapter-->\n");
+ ptr += sprintf(ptr, "mlan_adapter=%p, size=%d(0x%x)\n",
+ info->mlan_adapter, info->mlan_adapter_size,
+ info->mlan_adapter_size);
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->mlan_adapter,
+ info->mlan_adapter_size, MTRUE, ptr);
+ ptr += sprintf(ptr, "<--mlan_adapter End-->\n");
+#ifdef SDIO
+ if (IS_SD(priv->phandle->card_type) && info->mpa_buf &&
+ info->mpa_buf_size) {
+ ptr += sprintf(ptr, "<--mlan_mpa_buf-->\n");
+ ptr += sprintf(ptr, "mlan_mpa_buf=%p, size=%d(0x%x)\n",
+ info->mpa_buf, info->mpa_buf_size,
+ info->mpa_buf_size);
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->mpa_buf,
+ info->mpa_buf_size, MTRUE, ptr);
+ ptr += sprintf(ptr, "<--mlan_mpa_buf End-->\n");
+ }
+#endif
+ for (i = 0; i < info->mlan_priv_num; i++) {
+ ptr += sprintf(ptr, "<--mlan_private(%d)-->\n", i);
+ ptr += sprintf(ptr, "mlan_private=%p, size=%d(0x%x)\n",
+ info->mlan_priv[i], info->mlan_priv_size[i],
+ info->mlan_priv_size[i]);
+ ptr += woal_save_hex_dump(ROW_SIZE_16, info->mlan_priv[i],
+ info->mlan_priv_size[i], MTRUE, ptr);
+ ptr += sprintf(ptr, "<--mlan_private(%d) End-->\n", i);
+ }
+
+ LEAVE();
+ return ptr - (char *)buf;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+/**
+ * @brief This function create dump directory
+ *
+ * @param phandle A pointer to moal_handle
+ * @param dir_buf A pointer to dir_buf buffer
+ * @param buf_size Size of dir_buf buffer
+ *
+ * @return N/A
+ */
+void woal_create_dump_dir(moal_handle *phandle, char *dir_buf, int buf_size)
+{
+ struct dentry *dentry;
+ struct path path;
+ t_u32 sec, usec;
+ int ret;
+
+ ENTER();
+
+ if (!phandle || !dir_buf) {
+ PRINTM(MERROR, "Can't create directory\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ moal_get_system_time(phandle, &sec, &usec);
+ memset(dir_buf, 0, buf_size);
+ sprintf(dir_buf, "%s%u", "/data/dump_", sec);
+
+ dentry = kern_path_create(AT_FDCWD, dir_buf, &path, 1);
+ if (IS_ERR(dentry)) {
+ PRINTM(MERROR,
+ "Create directory %s error, try create dir in /var",
+ dir_buf);
+ memset(dir_buf, 0, buf_size);
+ sprintf(dir_buf, "%s%u", "/var/dump_", sec);
+ dentry = kern_path_create(AT_FDCWD, dir_buf, &path, 1);
+ }
+ if (IS_ERR(dentry)) {
+ PRINTM(MERROR, "Create directory %s error, use default folder",
+ dir_buf);
+ goto default_dir;
+ }
+ ret = vfs_mkdir(path.dentry->d_inode, dentry, 0777);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
+ mutex_unlock(&path.dentry->d_inode->i_mutex);
+#else
+ inode_unlock(path.dentry->d_inode);
+#endif
+
+ if (ret < 0) {
+ PRINTM(MERROR,
+ "Create directory failure, use default folder\n");
+ PRINTM(MERROR, "Create directory failure, ret = %d\n", ret);
+ goto default_dir;
+ } else {
+ PRINTM(MMSG, "Create directory %s successfully\n", dir_buf);
+ goto done;
+ }
+
+default_dir:
+ memset(dir_buf, 0, buf_size);
+ sprintf(dir_buf, "%s", "/data");
+done:
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief This function save dump buf to file
+ *
+ * @param dir_name A pointer to directory name
+ * @param file_name A pointer to file name
+ * @param buf A pointer to dump data
+ * @param buf_len The length of dump buf
+ *
+ * @return SUCCESS OR FAILURE
+ */
+mlan_status woal_save_dump_info_to_file(char *dir_name, char *file_name,
+ t_u8 *buf, t_u32 buf_len)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct file *pfile = NULL;
+ t_u8 name[64];
+ loff_t pos;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ mm_segment_t fs;
+#endif
+
+ ENTER();
+
+ if (!dir_name || !file_name || !buf) {
+ PRINTM(MERROR, "Can't save dump info to file\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s/%s", dir_name, file_name);
+ pfile = filp_open(name, O_CREAT | O_RDWR, 0644);
+ if (IS_ERR(pfile)) {
+ PRINTM(MMSG,
+ "Create file %s error, try to save dump file in /var\n",
+ name);
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s/%s", "/var", file_name);
+ pfile = filp_open(name, O_CREAT | O_RDWR, 0644);
+ }
+ if (IS_ERR(pfile)) {
+ PRINTM(MERROR, "Create Dump file for %s error\n", name);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ PRINTM(MMSG, "Dump data %s saved in %s\n", file_name, name);
+
+ pos = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ vfs_write(pfile, buf, buf_len, &pos);
+ set_fs(fs);
+#else
+ kernel_write(pfile, buf, buf_len, &pos);
+#endif
+ filp_close(pfile, NULL);
+
+ PRINTM(MMSG, "Dump data %s saved in %s successfully\n", file_name,
+ name);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function dump drv info to file
+ *
+ * @param phandle A pointer to moal_handle
+ * @param dir_name A pointer to directory name
+ *
+ * @return N/A
+ */
+void woal_dump_drv_info(moal_handle *phandle, t_u8 *dir_name)
+{
+ int ret = 0;
+ struct file *pfile = NULL;
+ t_u8 *drv_buf = NULL;
+ t_u8 file_name[64];
+ t_u32 len = 0;
+ t_u32 total_len = 0;
+ moal_private *woal_handle = NULL;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ mm_segment_t fs;
+#endif
+ t_u32 drv_info_size = DRV_INFO_SIZE;
+
+ ENTER();
+
+ PRINTM(MMSG, "=== START DRIVER INFO DUMP===");
+ memset(file_name, 0, sizeof(file_name));
+ if (phandle->second_mac)
+ sprintf(file_name, "%s/%s", dir_name, "file_drv_info_2");
+ else
+ sprintf(file_name, "%s/%s", dir_name, "file_drv_info");
+ pfile = filp_open(file_name, O_CREAT | O_RDWR, 0644);
+ if (IS_ERR(pfile)) {
+ PRINTM(MMSG,
+ "Create file %s error, try create /var/file_drv_info",
+ file_name);
+ pfile = filp_open("/var/file_drv_info", O_CREAT | O_RDWR, 0644);
+ } else {
+ PRINTM(MMSG, "DRV dump data in %s\n", file_name);
+ }
+ if (IS_ERR(pfile)) {
+ PRINTM(MMSG, "Create file_drv_info file failed\n");
+ goto done;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+#endif
+ woal_handle = woal_get_priv(phandle, MLAN_BSS_ROLE_ANY);
+
+ if (woal_handle != NULL) {
+ if (phandle->priv_num > 3)
+ drv_info_size +=
+ (phandle->priv_num - 3) * DRV_INFO_PER_INTF;
+ ret = moal_vmalloc(phandle, drv_info_size, &drv_buf);
+ if ((ret != MLAN_STATUS_SUCCESS) || !drv_buf) {
+ PRINTM(MERROR, "Error: vmalloc drv buffer failed!\n");
+ goto done;
+ }
+ len = woal_dump_moal_drv_info(phandle, drv_buf);
+ total_len += len;
+ len = woal_dump_mlan_drv_info(woal_handle, drv_buf + total_len);
+ total_len += len;
+ len = woal_dump_moal_hex(phandle, drv_buf + total_len);
+ total_len += len;
+ len = woal_dump_mlan_hex(woal_handle, drv_buf + total_len);
+ total_len += len;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ vfs_write(pfile, drv_buf, total_len, &pfile->f_pos);
+#else
+ kernel_write(pfile, drv_buf, total_len, &pfile->f_pos);
+#endif
+ }
+ PRINTM(MMSG, "Drv info total bytes = %ld (0x%lx)\n",
+ (long int)total_len, (long unsigned int)total_len);
+ filp_close(pfile, NULL);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
+ set_fs(fs);
+#endif
+ PRINTM(MMSG, "=== DRIVER INFO DUMP END===");
+done:
+ if (drv_buf)
+ moal_vfree(phandle, drv_buf);
+ LEAVE();
+}
+
+/**
+ * @brief This function displays extra MOAL debug information
+ *
+ * @param priv A pointer to moal_private
+ * @param handle A pointer to moal_handle
+ * @param flag Indicates whether register read can be done directly
+ *
+ * @return N/A
+ */
+void woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag)
+{
+ moal_handle *phandle = NULL;
+#ifdef USB
+ struct usb_card_rec *cardp = NULL;
+#endif
+ char buf[MLAN_MAX_VER_STR_LEN];
+ int i = 0;
+
+ ENTER();
+
+ if (!priv) {
+ if (handle) {
+ phandle = handle;
+ } else {
+ PRINTM(MERROR,
+ "Could not retrieve debug information from MOAL\n");
+ LEAVE();
+ return;
+ }
+ } else {
+ phandle = priv->phandle;
+ }
+#ifdef USB
+ if (IS_USB(phandle->card_type)) {
+ cardp = (struct usb_card_rec *)phandle->card;
+ PRINTM(MERROR, "tx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->tx_cmd_urb_pending));
+ PRINTM(MERROR, "tx_data_urb_pending = %d\n",
+ atomic_read(&cardp->tx_data_urb_pending));
+#ifdef USB_CMD_DATA_EP
+ PRINTM(MERROR, "rx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->rx_cmd_urb_pending));
+#endif
+ PRINTM(MERROR, "rx_data_urb_pending = %d\n",
+ atomic_read(&cardp->rx_data_urb_pending));
+ }
+#endif
+
+ woal_get_version(phandle, buf, sizeof(buf) - 1);
+ PRINTM(MERROR, "Driver version = %s\n", buf);
+ PRINTM(MERROR, "main_state = %d\n", phandle->main_state);
+ PRINTM(MERROR, "ioctl_pending = %d\n",
+ atomic_read(&phandle->ioctl_pending));
+ PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ if (priv) {
+ PRINTM(MERROR, "wmm_tx_pending[0] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[0]));
+ PRINTM(MERROR, "wmm_tx_pending[1] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[1]));
+ PRINTM(MERROR, "wmm_tx_pending[2] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[2]));
+ PRINTM(MERROR, "wmm_tx_pending[3] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[3]));
+ }
+#endif
+ PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending));
+ PRINTM(MERROR, "lock_count = %d\n", atomic_read(&phandle->lock_count));
+ PRINTM(MERROR, "malloc_count = %d\n",
+ atomic_read(&phandle->malloc_count));
+ PRINTM(MERROR, "mbufalloc_count = %d\n",
+ atomic_read(&phandle->mbufalloc_count));
+#ifdef PCIE
+ if (IS_PCIE(phandle->card_type)) {
+ PRINTM(MERROR, "malloc_cons_count = %d\n",
+ atomic_read(&phandle->malloc_cons_count));
+ }
+#endif
+ PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count);
+ PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count);
+
+ if (priv && priv->netdev) {
+ PRINTM(MERROR, "Media state = \"%s\"\n",
+ ((priv->media_connected == MFALSE) ? "Disconnected" :
+ "Connected"));
+ PRINTM(MERROR, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ for (i = 0; i < (priv->netdev->num_tx_queues); i++) {
+ PRINTM(MERROR, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped(
+ netdev_get_tx_queue(priv->netdev, i))) ?
+ "stopped" :
+ "started"));
+ }
+#else
+ PRINTM(MERROR, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" :
+ "started"));
+#endif
+ }
+
+ for (i = 0; i < phandle->priv_num; i++) {
+ priv = phandle->priv[i];
+ if (priv && priv->netdev)
+ PRINTM(MERROR, "%s: num_tx_timeout = %d\n",
+ priv->netdev->name, priv->num_tx_timeout);
+ }
+
+ if (phandle->is_suspended == MTRUE) {
+ LEAVE();
+ return;
+ }
+
+#ifdef PCIE
+ if (IS_PCIE(phandle->card_type)) {
+ if (phandle->ops.reg_dbg && (drvdbg & (MREG_D | MFW_D)))
+ phandle->ops.reg_dbg(phandle);
+ }
+#endif
+#ifdef SDIO
+ if (IS_SD(phandle->card_type)) {
+ if (flag && ((phandle->main_state == MOAL_END_MAIN_PROCESS) ||
+ (phandle->main_state == MOAL_STATE_IDLE))) {
+ if (phandle->ops.reg_dbg && (drvdbg & (MREG_D | MFW_D)))
+ phandle->ops.reg_dbg(phandle);
+ } else {
+ if (drvdbg & (MREG_D | MFW_D)) {
+ phandle->reg_dbg = MTRUE;
+ queue_work(phandle->workqueue,
+ &phandle->main_work);
+ }
+ }
+ }
+#endif
+#ifdef DEBUG_LEVEL1
+ if (drvdbg & MFW_D) {
+ drvdbg &= ~MFW_D;
+ phandle->fw_dbg = MTRUE;
+ queue_work(phandle->workqueue, &phandle->main_work);
+ }
+#endif
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Download power table to firmware for a specific country
+ *
+ * @param priv A pointer to moal_private
+ * @param country ISO 3166-1 alpha-2 country code
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_request_country_power_table(moal_private *priv, char *country)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = NULL;
+ char country_name[] = "txpower_XX.bin";
+ char file_path[256];
+ char *last_slash = NULL;
+ char *fw_name = NULL;
+
+ ENTER();
+
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "Priv or handle is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (!country) {
+ PRINTM(MERROR, "Country is null\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (fw_region)
+ strncpy(country_name, "rgpower_XX.bin",
+ strlen("rgpower_XX.bin"));
+#endif
+#endif
+ handle = priv->phandle;
+
+ /* Replace XX with ISO 3166-1 alpha-2 country code */
+ strncpy(strstr(country_name, "XX"), country, strlen(country));
+ fw_name = handle->params.fw_name;
+ memset(file_path, 0, sizeof(file_path));
+ /* file_path should be Null terminated */
+ if (fw_name) {
+ strncpy(file_path, fw_name, sizeof(file_path) - 1);
+ last_slash = strrchr(file_path, '/');
+ if (last_slash)
+ memset(last_slash + 1, 0,
+ sizeof(file_path) - 1 -
+ (last_slash - file_path));
+ else
+ memset(file_path, 0, sizeof(file_path));
+ } else {
+ strncpy(file_path, "nxp/",
+ MIN((sizeof(file_path) - 1), strlen("nxp/")));
+ }
+
+ if ((strlen(file_path) + strlen(country_name)) <
+ (sizeof(file_path) - 1))
+ strncpy(file_path + strlen(file_path), country_name,
+ sizeof(file_path) - strlen(file_path));
+ else {
+ PRINTM(MERROR,
+ "file path buffer too small, fail to dnld power table\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ PRINTM(MMSG, "Trying download country_power_tble: %s\n", file_path);
+ ret = woal_set_user_init_data(handle, COUNTRY_POWER_TABLE,
+ MOAL_IOCTL_WAIT, file_path);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ /* Try download WW rgpowertable */
+ if (fw_region && (ret == MLAN_STATUS_FILE_ERR)) {
+ strncpy(country_name, "rgpower_WW.bin",
+ strlen("rgpower_WW.bin"));
+ last_slash = strrchr(file_path, '/');
+ if (last_slash)
+ memset(last_slash + 1, 0,
+ sizeof(file_path) - 1 -
+ (last_slash - file_path));
+ else
+ memset(file_path, 0, sizeof(file_path));
+ strncpy(file_path + strlen(file_path), country_name,
+ strlen(country_name));
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ handle->country_code[0] = '0';
+ handle->country_code[1] = '0';
+#endif
+ PRINTM(MMSG, "Trying again download country_power_tble: %s\n",
+ file_path);
+ ret = woal_set_user_init_data(handle, COUNTRY_POWER_TABLE,
+ MOAL_IOCTL_WAIT, file_path);
+ }
+#endif
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief napi polling call back function.
+ *
+ * @param napi A pointer to napi_struct
+ * @param budget the limit of packets driver should poll
+ *
+ * @return packets received
+ */
+int woal_netdev_poll_rx(struct napi_struct *napi, int budget)
+{
+ moal_handle *handle = container_of(napi, moal_handle, napi_rx);
+ t_u8 recv = budget;
+
+ ENTER();
+ if (handle->surprise_removed == MTRUE) {
+ napi_complete(napi);
+ LEAVE();
+ return 0;
+ }
+ mlan_rx_process(handle->pmlan_adapter, &recv);
+ if (recv < budget)
+ napi_complete(napi);
+ LEAVE();
+ return recv;
+}
+
+/**
+ * @brief This workqueue function handles woal event queue
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void woal_evt_work_queue(struct work_struct *work)
+{
+ moal_handle *handle = container_of(work, moal_handle, evt_work);
+ struct woal_event *evt;
+ unsigned long flags;
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ moal_private *priv;
+#endif
+#endif
+ ENTER();
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ while (!list_empty(&handle->evt_queue)) {
+ evt = list_first_entry(&handle->evt_queue, struct woal_event,
+ link);
+ list_del(&evt->link);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ switch (evt->type) {
+ case WOAL_EVENT_CHAN_SWITCH:
+#if defined(UAP_SUPPORT) || defined(STA_SUPPORT)
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ woal_cfg80211_notify_channel((moal_private *)evt->priv,
+ &evt->chan_info);
+#endif
+#endif
+#endif
+ break;
+ case WOAL_EVENT_BGSCAN_STOP:
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ woal_cfg80211_notify_sched_scan_stop(
+ (moal_private *)evt->priv);
+#endif
+#endif
+ break;
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ case WOAL_EVENT_DEAUTH:
+ priv = evt->priv;
+ woal_host_mlme_disconnect(evt->priv, evt->reason_code,
+ priv->cfg_bssid);
+ break;
+
+ case WOAL_EVENT_ASSOC_RESP:
+ woal_host_mlme_process_assoc_resp(
+ (moal_private *)evt->priv, &evt->assoc_resp);
+ break;
+#endif
+#endif
+ }
+ kfree(evt);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ }
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ LEAVE();
+}
+/**
+ * @brief This workqueue function handles rx_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void woal_rx_work_queue(struct work_struct *work)
+{
+ moal_handle *handle = container_of(work, moal_handle, rx_work);
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 14, 6)
+ moal_private *priv;
+#endif
+#endif
+#endif
+ wifi_timeval start_timeval;
+ wifi_timeval end_timeval;
+
+ ENTER();
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ woal_get_monotonic_time(&start_timeval);
+ mlan_rx_process(handle->pmlan_adapter, NULL);
+
+ woal_get_monotonic_time(&end_timeval);
+ handle->rx_time += (t_u64)(timeval_to_usec(end_timeval) -
+ timeval_to_usec(start_timeval));
+ PRINTM(MINFO,
+ "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu rx_time=%llu\n",
+ __func__, start_timeval.time_sec, start_timeval.time_usec,
+ end_timeval.time_sec, end_timeval.time_usec,
+ (t_u64)(timeval_to_usec(end_timeval) -
+ timeval_to_usec(start_timeval)),
+ handle->rx_time);
+ LEAVE();
+}
+
+/**
+ * @brief This function dequeue pkt from list
+ *
+ * @param list A pointer to struct sk_buff_head
+ *
+ * @return skb buffer
+ */
+
+struct sk_buff *woal_skb_dequeue_spinlock(struct sk_buff_head *list)
+{
+ struct sk_buff *result;
+
+ spin_lock_bh(&list->lock);
+ result = __skb_dequeue(list);
+ spin_unlock_bh(&list->lock);
+ return result;
+}
+
+/**
+ * @brief This workqueue function handles rx_work_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void woal_tx_work_handler(struct work_struct *work)
+{
+ moal_handle *handle = container_of(work, moal_handle, tx_work);
+ moal_private *priv = NULL;
+ int i = 0;
+ struct sk_buff *skb = NULL;
+
+ ENTER();
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ priv = handle->priv[i];
+ while ((skb = woal_skb_dequeue_spinlock(&priv->tx_q)) != NULL) {
+ woal_start_xmit(priv, skb);
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This workqueue function handles main_process
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+t_void woal_main_work_queue(struct work_struct *work)
+{
+ moal_handle *handle = container_of(work, moal_handle, main_work);
+#ifdef USB
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ struct sched_param sp = {.sched_priority = wq_sched_prio};
+#endif
+
+ ENTER();
+
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ if (handle->reg_dbg == MTRUE) {
+ handle->reg_dbg = MFALSE;
+ if (handle->ops.reg_dbg)
+ handle->ops.reg_dbg(handle);
+ }
+ if (handle->fw_dbg == MTRUE) {
+ handle->fw_dbg = MFALSE;
+ handle->ops.dump_fw_info(handle);
+ LEAVE();
+ return;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ /* Change the priority and scheduling policy of main work queue
+ */
+ if ((handle->params.wq_sched_prio != current->rt_priority) ||
+ (handle->params.wq_sched_policy != current->policy)) {
+ PRINTM(MMSG,
+ "Set work queue priority %d and scheduling policy %d\n",
+ handle->params.wq_sched_prio,
+ handle->params.wq_sched_policy);
+ sched_setscheduler(current, handle->params.wq_sched_policy,
+ &sp);
+ }
+#endif
+
+ handle->main_state = MOAL_ENTER_WORK_QUEUE;
+#ifdef USB
+ /* WAR for no free skb issue */
+ if (IS_USB(handle->card_type) && !atomic_read(&handle->rx_pending) &&
+ atomic_read(&cardp->rx_data_urb_pending) < MVUSB_RX_DATA_URB) {
+ PRINTM(MWARN, "Try to resubmit Rx data URBs\n");
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+#endif
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the mlan_private and initialize the device.
+ *
+ * @param card A pointer to card
+ * @param dev A pointer to device structure
+ * @param if_ops A pointer to interface ops
+ * @param card_type card type id
+ *
+ * @return A pointer to moal_handle structure
+ */
+moal_handle *woal_add_card(void *card, struct device *dev, moal_if_ops *if_ops,
+ t_u16 card_type)
+{
+ moal_handle *handle = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int netlink_num = NETLINK_NXP;
+ int index = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct netlink_kernel_cfg cfg = {
+ .groups = NL_MULTICAST_GROUP,
+ };
+#endif
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == NULL)
+ break;
+ }
+ if (index >= MAX_MLAN_ADAPTER)
+ goto err_handle;
+
+ /* Allocate buffer for moal_handle */
+ handle = kzalloc(sizeof(moal_handle), GFP_KERNEL);
+ if (!handle) {
+ PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
+ goto err_handle;
+ }
+
+ /* Init moal_handle */
+ handle->card = card;
+
+ /* Save the handle */
+ m_handle[index] = handle;
+ handle->handle_idx = index;
+
+ handle->hotplug_device = dev;
+ handle->card_type = card_type;
+ /* Attach moal handle ops */
+ PRINTM(MMSG, "Attach moal handle ops, card interface type: 0x%x\n",
+ handle->card_type);
+ moal_memcpy_ext(handle, &handle->ops, if_ops, sizeof(*if_ops),
+ sizeof(handle->ops));
+ handle->second_mac = handle->ops.is_second_mac(handle);
+ if (handle->second_mac) {
+ if ((index >= 1) && m_handle[index - 1]) {
+ handle->pref_mac = (void *)m_handle[index - 1];
+ m_handle[index - 1]->pref_mac = (void *)handle;
+ }
+ }
+
+ /* Init module parameters */
+ woal_init_module_param(handle);
+
+ if (handle->params.mac_addr
+#ifdef MFG_CMD_SUPPORT
+ && handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED
+#endif
+ ) {
+ t_u8 temp[20];
+ t_u8 len = strlen(handle->params.mac_addr) + 1;
+ if (len < sizeof(temp)) {
+ moal_memcpy_ext(handle, temp, handle->params.mac_addr,
+ len, sizeof(temp));
+ handle->set_mac_addr = 1;
+ /* note: the following function overwrites the
+ * temp buffer */
+ woal_mac2u8(handle->mac_addr, temp);
+ }
+ }
+
+ /* Get card info */
+ woal_get_card_info(handle);
+ /** Get card revision */
+ handle->ops.get_fw_name(handle);
+#ifdef STA_SUPPORT
+ handle->scan_pending_on_block = MFALSE;
+ MOAL_INIT_SEMAPHORE(&handle->async_sem);
+#endif
+
+#if defined(USB)
+ if (IS_USB(handle->card_type))
+ handle->boot_state = ((struct usb_card_rec *)card)->boot_state;
+#endif /* USB_NEW_FW_DNLD */
+ /* Init SW */
+ if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto err_kmalloc;
+ }
+
+ do {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ handle->nl_sk = netlink_kernel_create(netlink_num, NULL);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ handle->nl_sk = netlink_kernel_create(
+ netlink_num, NL_MULTICAST_GROUP, NULL, THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ handle->nl_sk =
+ netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP,
+ NULL, NULL, THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ handle->nl_sk = netlink_kernel_create(&init_net, netlink_num,
+ NL_MULTICAST_GROUP, NULL,
+ NULL, THIS_MODULE);
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
+ handle->nl_sk = netlink_kernel_create(&init_net, netlink_num,
+ THIS_MODULE, &cfg);
+#else
+ handle->nl_sk =
+ netlink_kernel_create(&init_net, netlink_num, &cfg);
+#endif
+#endif
+#endif
+#endif
+#endif
+ if (handle->nl_sk) {
+ PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
+ handle->netlink_num = netlink_num;
+ break;
+ }
+ netlink_num--;
+ } while (netlink_num > 0);
+
+ if (handle->nl_sk == NULL) {
+ PRINTM(MERROR,
+ "Could not initialize netlink event passing mechanism!\n");
+ goto err_kmalloc;
+ }
+
+ /* Create workqueue for main process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ /* For kernel less than 2.6.14 name can not be
+ * greater than 10 characters */
+ handle->workqueue = create_workqueue("MOAL_WORKQ");
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ handle->workqueue = alloc_workqueue(
+ "MOAL_WORK_QUEUE", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+#else
+ handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
+#endif
+#endif
+ if (!handle->workqueue)
+ goto err_kmalloc;
+
+ MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
+
+ /* Create workqueue for event process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ /* For kernel less than 2.6.14 name can not be
+ * greater than 10 characters */
+ handle->evt_workqueue = create_workqueue("MOAL_EVT_WORKQ");
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ handle->evt_workqueue =
+ alloc_workqueue("MOAL_EVT_WORK_QUEUE",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+#else
+ handle->evt_workqueue = create_workqueue("MOAL_EVT_WORK_QUEUE");
+#endif
+#endif
+ if (!handle->evt_workqueue) {
+ woal_terminate_workqueue(handle);
+ goto err_kmalloc;
+ }
+
+ MLAN_INIT_WORK(&handle->evt_work, woal_evt_work_queue);
+ INIT_LIST_HEAD(&handle->evt_queue);
+ spin_lock_init(&handle->evt_lock);
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ MLAN_INIT_WORK(&handle->host_mlme_work, woal_host_mlme_work_queue);
+#endif
+#endif
+
+ if (!moal_extflg_isset(handle, EXT_NAPI)) {
+ /* Create workqueue for rx process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ /* For kernel less than 2.6.14 name can not be
+ * greater than 10 characters */
+ handle->rx_workqueue = create_workqueue("MOAL_RX_WORKQ");
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ handle->rx_workqueue = alloc_workqueue(
+ "MOAL_RX_WORK_QUEUE",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+#else
+ handle->rx_workqueue = create_workqueue("MOAL_RX_WORK_QUEUE");
+#endif
+#endif
+ if (!handle->rx_workqueue) {
+ woal_terminate_workqueue(handle);
+ goto err_kmalloc;
+ }
+ MLAN_INIT_WORK(&handle->rx_work, woal_rx_work_queue);
+ }
+#define NAPI_BUDGET 64
+ if (moal_extflg_isset(handle, EXT_NAPI)) {
+ init_dummy_netdev(&handle->napi_dev);
+ netif_napi_add(&handle->napi_dev, &handle->napi_rx,
+ woal_netdev_poll_rx, NAPI_BUDGET);
+ napi_enable(&handle->napi_rx);
+ }
+
+ if (moal_extflg_isset(handle, EXT_TX_WORK)) {
+ /* Create workqueue for tx process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ handle->tx_workqueue = create_workqueue("MOAL_TX_WORKQ");
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ handle->tx_workqueue = alloc_workqueue(
+ "MOAL_TX_WORK_QUEUE",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+#else
+ handle->tx_workqueue = create_workqueue("MOAL_TX_WORK_QUEUE");
+#endif
+#endif
+ if (!handle->tx_workqueue) {
+ woal_terminate_workqueue(handle);
+ goto err_kmalloc;
+ }
+ MLAN_INIT_WORK(&handle->tx_work, woal_tx_work_handler);
+ }
+
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Starting re-association thread...\n");
+ handle->reassoc_thread.handle = handle;
+ woal_create_thread(woal_reassociation_thread, &handle->reassoc_thread,
+ "woal_reassoc_service");
+
+ while (!handle->reassoc_thread.pid)
+ woal_sched_timeout(2);
+#endif /* REASSOCIATION */
+
+ /* Register the device. Fill up the private data structure with
+ * relevant information from the card and request for the
+ * required IRQ.
+ */
+ if (handle->ops.register_dev(handle) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+ woal_update_firmware_name(handle);
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ wakeup_source_init(&handle->ws, "mwlan");
+#else
+ wake_lock_init(&handle->wake_lock, WAKE_LOCK_SUSPEND, "mwlan");
+#endif
+#endif
+
+ /* Init FW and HW */
+ if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto err_init_fw;
+ }
+
+#ifdef SD8887
+ if (IS_SD8887(handle->card_type)) {
+ union {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+ ver.l = handle->fw_release_number;
+ if (ver.c[1] == 75) {
+ handle->card_info->embedded_supp = 0;
+ PRINTM(MMSG,
+ "Disable EMBEDED Supplicant for SD8887-FP75\n");
+ }
+ }
+#endif
+ LEAVE();
+ return handle;
+
+err_init_fw:
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ PRINTM(MINFO, "shutdown mlan\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ }
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ wakeup_source_trash(&handle->ws);
+#else
+ wake_lock_destroy(&handle->wake_lock);
+#endif
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ handle->ops.unregister_dev(handle);
+err_registerdev:
+ handle->surprise_removed = MTRUE;
+#ifdef REASSOCIATION
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid)
+ woal_sched_timeout(2);
+#endif /* REASSOCIATION */
+ if (moal_extflg_isset(handle, EXT_NAPI))
+ netif_napi_del(&handle->napi_rx);
+ woal_terminate_workqueue(handle);
+err_kmalloc:
+ woal_free_moal_handle(handle);
+ if (index < MAX_MLAN_ADAPTER)
+ m_handle[index] = NULL;
+err_handle:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+exit_sem_err:
+ LEAVE();
+ return NULL;
+}
+
+/**
+ * @brief This function removes the card.
+ *
+ * @param card A pointer to card
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status woal_remove_card(void *card)
+{
+ moal_handle *handle = NULL;
+ moal_private *priv = NULL;
+ mlan_status status;
+ int i;
+ int index = 0;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ /* Find the correct handle */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] && (m_handle[index]->card == card)) {
+ handle = m_handle[index];
+ break;
+ }
+ }
+ if (!handle)
+ goto exit_remove;
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode == MLAN_INIT_PARA_ENABLED
+#if defined(USB)
+ && handle->boot_state == USB_FW_READY
+#endif
+ ) {
+ if (handle->params.fw_name) {
+ kfree(handle->params.fw_name);
+ handle->params.fw_name = NULL;
+ }
+ }
+#endif
+ if (handle->rf_test_mode)
+ woal_process_rf_test_mode(handle, MFG_CMD_UNSET_TEST_MODE);
+ handle->surprise_removed = MTRUE;
+
+ flush_workqueue(handle->workqueue);
+ flush_workqueue(handle->evt_workqueue);
+ if (handle->rx_workqueue)
+ flush_workqueue(handle->rx_workqueue);
+ if (handle->tx_workqueue)
+ flush_workqueue(handle->tx_workqueue);
+
+ if (moal_extflg_isset(handle, EXT_NAPI)) {
+ napi_disable(&handle->napi_rx);
+ netif_napi_del(&handle->napi_rx);
+ }
+
+ /* Stop data */
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ priv = handle->priv[i];
+ if (priv) {
+ if (priv->netdev) {
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+ }
+ }
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ }
+ /* Unregister mlan */
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ handle->pmlan_adapter = NULL;
+ }
+ if (atomic_read(&handle->rx_pending) ||
+ atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR,
+ "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ if (handle->is_remain_timer_set) {
+ woal_cancel_timer(&handle->remain_timer);
+ woal_remain_timer_func(handle);
+ }
+#endif
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ if (handle->is_go_timer_set) {
+ woal_cancel_timer(&handle->go_timer);
+ handle->is_go_timer_set = MFALSE;
+ }
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ /* Remove virtual interface */
+ woal_remove_virtual_interface(handle);
+#endif
+#endif
+#endif
+ if (handle->tp_acnt.on) {
+ handle->tp_acnt.on = 0;
+ handle->tp_acnt.drop_point = 0;
+ if (handle->is_tp_acnt_timer_set) {
+ woal_cancel_timer(&handle->tp_acnt.timer);
+ handle->is_tp_acnt_timer_set = MFALSE;
+ }
+ }
+
+ /* Remove interface */
+ for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
+ woal_remove_interface(handle, i);
+
+ woal_terminate_workqueue(handle);
+
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (handle->is_cac_timer_set) {
+ woal_cancel_timer(&handle->cac_timer);
+ handle->is_cac_timer_set = MFALSE;
+ }
+#endif
+#endif
+#ifdef REASSOCIATION
+ PRINTM(MINFO, "Free reassoc_timer\n");
+ if (handle->is_reassoc_timer_set) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid)
+ woal_sched_timeout(2);
+#endif /* REASSOCIATION */
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ handle->ops.unregister_dev(handle);
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ wakeup_source_trash(&handle->ws);
+#else
+ wake_lock_destroy(&handle->wake_lock);
+#endif
+#endif
+ /* Free adapter structure */
+ PRINTM(MINFO, "Free Adapter\n");
+ woal_free_moal_handle(handle);
+
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == handle) {
+ m_handle[index] = NULL;
+ break;
+ }
+ }
+exit_remove:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+exit_sem_err:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef CONFIG_PROC_FS
+/**
+ * @brief This function switch the drv_mode
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param mode new drv_mode to switch.
+ *
+ * @return MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE
+ * /MLAN_STATUS_PENDING
+ */
+mlan_status woal_switch_drv_mode(moal_handle *handle, t_u32 mode)
+{
+ unsigned int i;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+
+ ENTER();
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not update driver mode table!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+
+ /* Reset all interfaces */
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
+
+ status = woal_shutdown_fw(priv, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "func shutdown failed!\n");
+ goto exit;
+ }
+#ifdef USB
+ handle->skip_fw_dnld = MTRUE;
+#endif
+
+ /* Shutdown firmware */
+ PRINTM(MIOCTL, "mlan_shutdown_fw.....\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ PRINTM(MIOCTL, "mlan_shutdown_fw done!\n");
+ /* Unregister mlan */
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ handle->pmlan_adapter = NULL;
+ }
+ if (atomic_read(&handle->rx_pending) ||
+ atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR,
+ "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < MIN(MLAN_MAX_BSS_NUM, handle->priv_num); i++)
+ woal_remove_interface(handle, i);
+
+ if (atomic_read(&handle->lock_count) ||
+ atomic_read(&handle->malloc_count) ||
+ atomic_read(&handle->mbufalloc_count)) {
+ PRINTM(MERROR,
+ "mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d\n",
+ atomic_read(&handle->lock_count),
+ atomic_read(&handle->malloc_count),
+ atomic_read(&handle->mbufalloc_count));
+ }
+#ifdef PCIE
+ if (IS_PCIE(handle->card_type) &&
+ atomic_read(&handle->malloc_cons_count)) {
+ PRINTM(MERROR, "mlan has memory leak: malloc_cons_count=%d\n",
+ atomic_read(&handle->malloc_cons_count));
+ }
+#endif
+
+ handle->priv_num = 0;
+ handle->params.drv_mode = mode;
+ /* Init SW */
+ if (woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto exit;
+ }
+ /* Init FW and HW */
+ if (woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ goto exit;
+ }
+ LEAVE();
+ return status;
+exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+exit_sem_err:
+ LEAVE();
+ return status;
+}
+#endif
+
+#ifdef SDIO_MMC
+#define FW_POLL_TRIES 100
+
+/**
+ * @brief This function reload fw
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0--success, otherwise failure
+ */
+static int woal_reset_and_reload_fw(moal_handle *handle)
+{
+ int ret = 0, tries = 0;
+ t_u32 value = 1;
+ t_u32 reset_reg = handle->card_info->fw_reset_reg;
+ t_u8 reset_val = handle->card_info->fw_reset_val;
+
+ ENTER();
+
+ if (!IS_SD9098(handle->card_type) && !IS_SD9097(handle->card_type)) {
+ mlan_pm_wakeup_card(handle->pmlan_adapter, MTRUE);
+ /** wait SOC fully wake up */
+ for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
+ ret = handle->ops.write_reg(handle, reset_reg, 0xba);
+ if (ret == MLAN_STATUS_SUCCESS) {
+ handle->ops.read_reg(handle, reset_reg, &value);
+ if (value == 0xba) {
+ PRINTM(MMSG, "FW wake up\n");
+ break;
+ }
+ }
+ udelay(1000);
+ }
+ }
+ /* Write register to notify FW */
+ if (handle->ops.write_reg(handle, reset_reg, reset_val) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to write register.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+#if defined(SD9098) || defined(SD9097)
+ if (IS_SD9098(handle->card_type) || IS_SD9097(handle->card_type))
+ handle->ops.write_reg(handle, 0x00, 0x10);
+#endif
+ /* Poll register around 100 ms */
+ for (tries = 0; tries < FW_POLL_TRIES; ++tries) {
+ handle->ops.read_reg(handle, reset_reg, &value);
+ if (value == 0)
+ /* FW is ready */
+ break;
+ udelay(1000);
+ }
+
+ if (value) {
+ PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
+ reset_reg, value);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!IS_SD9098(handle->card_type) && !IS_SD9097(handle->card_type))
+ mlan_pm_wakeup_card(handle->pmlan_adapter, MFALSE);
+ /* Download FW */
+ ret = woal_request_fw(handle);
+ if (ret) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MMSG, "FW Reload successfully.");
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function reload fw
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0--success, otherwise failure
+ */
+static int woal_reload_fw(moal_handle *handle)
+{
+ int ret = 0;
+ ENTER();
+ /* Download FW */
+ ret = woal_request_fw(handle);
+ if (ret) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MMSG, "FW Reload successfully.");
+done:
+ LEAVE();
+ return ret;
+}
+
+void woal_pre_reset(moal_handle *handle)
+{
+ int intf_num;
+ ENTER();
+ /** detach network interface */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_stop_queue(handle->priv[intf_num]->netdev);
+ netif_device_detach(handle->priv[intf_num]->netdev);
+ }
+ handle->fw_reload = MTRUE;
+ woal_update_firmware_name(handle);
+#ifdef USB
+ if (IS_USB(handle->card_type))
+ woal_kill_urbs(handle);
+#endif
+ LEAVE();
+}
+
+void woal_post_reset(moal_handle *handle)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int intf_num;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ t_u8 bss_role = MLAN_BSS_ROLE_STA;
+#endif
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+
+ ENTER();
+ /** un-block IOCTL */
+ handle->fw_reload = MFALSE;
+ handle->driver_status = MFALSE;
+ /* Restart the firmware */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req) {
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_WARM_RESET;
+ misc->param.fw_reload = MTRUE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ req, MOAL_IOCTL_WAIT)) {
+ kfree(req);
+ goto done;
+ }
+ kfree(req);
+ }
+ handle->hardware_status = HardwareStatusReady;
+ /* Reset all interfaces */
+ woal_reset_intf(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_IOCTL_WAIT, MTRUE);
+ /* Initialize private structures */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT);
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ if ((handle->priv[intf_num]->bss_type ==
+ MLAN_BSS_TYPE_WIFIDIRECT) &&
+ (GET_BSS_ROLE(handle->priv[intf_num]) ==
+ MLAN_BSS_ROLE_UAP)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_role_cfg(handle->priv[intf_num],
+ MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &bss_role)) {
+ goto done;
+ }
+ }
+#endif /* STA_WEXT || UAP_WEXT */
+#endif /* STA_SUPPORT && UAP_SUPPORT */
+#endif /* WIFI_DIRECT_SUPPORT */
+ }
+
+ /* Enable interfaces */
+ for (intf_num = 0; intf_num < handle->priv_num; intf_num++) {
+ netif_device_attach(handle->priv[intf_num]->netdev);
+ woal_start_queue(handle->priv[intf_num]->netdev);
+ }
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function reload fw
+ *
+ * @param phandle A pointer to moal_handle structure
+ * @param mode FW reload mode
+ *
+ * @return 0--success, otherwise failure
+ */
+void woal_request_fw_reload(moal_handle *phandle, t_u8 mode)
+{
+ int ret = 0;
+
+#ifdef PCIE
+ ppcie_service_card card = NULL;
+ struct pci_dev *pdev = NULL;
+#endif
+ moal_handle *handle = phandle;
+ moal_handle *ref_handle = NULL;
+
+ ENTER();
+#ifdef PCIE
+ if (mode == FW_RELOAD_PCIE_RESET) {
+ card = (pcie_service_card *)handle->card;
+ pdev = card->dev;
+ pci_reset_function(pdev);
+ LEAVE();
+ return;
+ }
+#endif
+
+ // handle-> mac0 , ref_handle->second mac
+ if (handle->pref_mac) {
+ if (phandle->second_mac) {
+ handle = (moal_handle *)handle->pref_mac;
+ ref_handle = phandle;
+ } else {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ }
+ ref_handle->driver_status = MTRUE;
+ }
+ /** start block IOCTL */
+ handle->driver_status = MTRUE;
+
+ if (mode == FW_RELOAD_WITH_EMULATION) {
+ fw_reload = FW_RELOAD_WITH_EMULATION;
+ PRINTM(MMSG, "FW reload with re-emulation...\n");
+ LEAVE();
+ return;
+ }
+ woal_pre_reset(handle);
+ if (ref_handle)
+ woal_pre_reset(ref_handle);
+ if (mode == FW_RELOAD_NO_EMULATION) {
+ ret = woal_reload_fw(handle);
+ if (ref_handle)
+ woal_reload_fw(ref_handle);
+ }
+#ifdef SDIO_MMC
+ else if (mode == FW_RELOAD_SDIO_INBAND_RESET &&
+ IS_SD(handle->card_type)) {
+ ret = woal_reset_and_reload_fw(handle);
+ if (ref_handle)
+ woal_reload_fw(ref_handle);
+ }
+#endif
+ else
+ ret = -EFAULT;
+ if (ret) {
+ PRINTM(MERROR, "FW reload fail\n");
+ goto done;
+ }
+ woal_post_reset(handle);
+ if (ref_handle)
+ woal_post_reset(ref_handle);
+done:
+ LEAVE();
+ return;
+}
+
+/** Register to bus driver function */
+static mlan_status woal_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef SDIO
+#ifdef SDIO_MMC
+ /* Register SDIO driver */
+ ret = woal_sdiommc_bus_register();
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to register sdio_mmc bus driver\n");
+ goto out;
+ }
+#else
+ ret = woal_sdio_bus_register();
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to register sdio_mmc bus driver\n");
+ goto out;
+ }
+#endif
+#endif
+#ifdef USB
+ /* Register USB driver */
+ ret = woal_usb_bus_register();
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to register usb bus driver\n");
+ goto out;
+ }
+#endif
+#ifdef PCIE
+ /* Register PCIE driver */
+ ret = woal_pcie_bus_register();
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Failed to register pcie bus driver\n");
+ goto out;
+ }
+#endif
+out:
+ return ret;
+}
+
+/** Unregister from bus driver function */
+static void woal_bus_unregister(void)
+{
+#ifdef SDIO
+#ifdef SDIO_MMC
+ /* Unregister SDIO driver */
+ woal_sdiommc_bus_unregister();
+#else
+ woal_sdio_bus_unregister();
+#endif
+#endif
+#ifdef USB
+ /* Unregister USB driver */
+ woal_usb_bus_unregister();
+#endif
+#ifdef PCIE
+ /* Unregister PCIE driver */
+ woal_pcie_bus_unregister();
+#endif
+}
+
+/**
+ * @brief This function initializes module.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static int woal_init_module(void)
+{
+ int ret = (int)MLAN_STATUS_SUCCESS;
+ int index = 0;
+
+ ENTER();
+
+ PRINTM(MMSG, "wlan: Loading MWLAN driver\n");
+ /* Init the wlan_private pointer array first */
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++)
+ m_handle[index] = NULL;
+ /* Init mutex */
+ MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
+
+ if (woal_root_proc_init() != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "woal_init_module: Unable to create /proc/mwlan/ directory\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+#ifdef CONFIG_OF
+ woal_init_from_dev_tree();
+#endif
+
+ /* Create workqueue for hang process */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
+ /* For kernel less than 2.6.14 name can not be greater than 10
+ characters */
+ hang_workqueue = create_workqueue("MOAL_HANG_WORKQ");
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ hang_workqueue =
+ alloc_workqueue("MOAL_HANG_WORK_QUEUE",
+ WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+#else
+ hang_workqueue = create_workqueue("MOAL_HANG_WORK_QUEUE");
+#endif
+#endif
+ MLAN_INIT_WORK(&hang_work, woal_hang_work_queue);
+
+ /* Register with bus */
+ ret = woal_bus_register();
+ if (ret == MLAN_STATUS_SUCCESS)
+ PRINTM(MMSG, "wlan: Driver loaded successfully\n");
+ else
+ PRINTM(MMSG, "wlan: Driver loading failed\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans module
+ *
+ * @return N/A
+ */
+static void woal_cleanup_module(void)
+{
+ moal_handle *handle = NULL;
+ int index = 0;
+ int i;
+#if defined(STA_SUPPORT) && defined(STA_CFG80211)
+ unsigned long flags;
+#endif
+
+ ENTER();
+
+ PRINTM(MMSG, "wlan: Unloading MWLAN driver\n");
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ handle = m_handle[index];
+ if (!handle)
+ continue;
+ if (!handle->priv_num)
+ goto exit;
+ if (MTRUE == woal_check_driver_status(handle))
+ goto exit;
+
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+ if (IS_USB(handle->card_type) &&
+ handle->is_suspended == MTRUE) {
+ woal_exit_usb_suspend(handle);
+ }
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+
+#ifdef SDIO
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ if (handle->is_suspended == MTRUE) {
+ woal_sdio_resume(
+ &(((struct sdio_mmc_card *)handle->card)->func)
+ ->dev);
+ }
+#endif /* MMC_PM_KEEP_POWER */
+#endif /* SDIO_SUSPEND_RESUME */
+#endif
+
+ if (handle->rf_test_mode)
+ woal_process_rf_test_mode(handle,
+ MFG_CMD_UNSET_TEST_MODE);
+
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) ==
+ MLAN_BSS_ROLE_STA) {
+ if (handle->priv[i]->media_connected == MTRUE) {
+ woal_disconnect(handle->priv[i],
+ MOAL_IOCTL_WAIT_TIMEOUT,
+ NULL,
+ DEF_DEAUTH_REASON_CODE);
+ if (handle->ioctl_timeout) {
+ woal_ioctl_timeout(handle);
+ goto exit;
+ }
+ }
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(
+ handle->params.cfg80211_wext) &&
+ (handle->priv[i]->bss_type ==
+ MLAN_BSS_TYPE_STA))
+ woal_clear_conn_params(handle->priv[i]);
+ spin_lock_irqsave(&handle->scan_req_lock,
+ flags);
+ if (IS_STA_CFG80211(
+ handle->params.cfg80211_wext) &&
+ handle->scan_request) {
+ woal_cfg80211_scan_done(
+ handle->scan_request, MTRUE);
+ handle->scan_request = NULL;
+ handle->scan_priv = NULL;
+ }
+ spin_unlock_irqrestore(&handle->scan_req_lock,
+ flags);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (IS_STA_CFG80211(
+ handle->params.cfg80211_wext) &&
+ handle->priv[i]->sched_scanning) {
+ woal_stop_bg_scan(
+ handle->priv[i],
+ MOAL_IOCTL_WAIT_TIMEOUT);
+ if (handle->ioctl_timeout) {
+ woal_ioctl_timeout(handle);
+ goto exit;
+ }
+ handle->priv[i]->bg_scan_start = MFALSE;
+ handle->priv[i]->bg_scan_reported =
+ MFALSE;
+ cfg80211_sched_scan_stopped(
+ handle->priv[i]->wdev->wiphy
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ handle->priv[i]->bg_scan_reqid
+#endif
+ );
+ handle->priv[i]->sched_scanning =
+ MFALSE;
+ }
+#endif
+#endif
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(handle->priv[i]) ==
+ MLAN_BSS_ROLE_UAP) {
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode !=
+ MLAN_INIT_PARA_ENABLED)
+#endif
+ {
+ woal_disconnect(handle->priv[i],
+ MOAL_IOCTL_WAIT_TIMEOUT,
+ NULL,
+ DEF_DEAUTH_REASON_CODE);
+ if (handle->ioctl_timeout) {
+ woal_ioctl_timeout(handle);
+ goto exit;
+ }
+ }
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ woal_clear_all_mgmt_ies(handle->priv[i],
+ MOAL_IOCTL_WAIT_TIMEOUT);
+ if (handle->ioctl_timeout) {
+ woal_ioctl_timeout(handle);
+ goto exit;
+ }
+ woal_flush_tx_stat_queue(handle->priv[i]);
+#endif
+ }
+
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ {
+ woal_set_deep_sleep(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ MOAL_IOCTL_WAIT_TIMEOUT, MFALSE, 0);
+ }
+
+#ifdef MFG_CMD_SUPPORT
+ if (handle->params.mfg_mode != MLAN_INIT_PARA_ENABLED)
+#endif
+ {
+ woal_shutdown_fw(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ MOAL_IOCTL_WAIT_TIMEOUT);
+ if (handle->ioctl_timeout) {
+ woal_ioctl_timeout(handle);
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+exit_sem_err:
+ /* Unregister from bus */
+ woal_bus_unregister();
+ PRINTM(MMSG, "wlan: Driver unloaded\n");
+ if (hang_workqueue) {
+ flush_workqueue(hang_workqueue);
+ destroy_workqueue(hang_workqueue);
+ hang_workqueue = NULL;
+ }
+ woal_root_proc_remove();
+
+ LEAVE();
+}
+
+#ifndef MODULE
+#ifdef MFG_CMD_SUPPORT
+/**
+ * @brief This function handle the mfg_mode from kernel boot command
+ *
+ * @param str buffer for mfg_mode
+ * @return N/A
+ */
+static int __init mfg_mode_setup(char *str)
+{
+ int val = -1;
+ get_option(&str, &val);
+ if (val > 0)
+ mfg_mode = 1;
+ PRINTM(MMSG, "mfg_mode=%d\n", mfg_mode);
+ return 1;
+}
+__setup("mfg_mode=", mfg_mode_setup);
+#endif
+#endif
+
+module_init(woal_init_module);
+module_exit(woal_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("NXP");
+MODULE_VERSION(MLAN_RELEASE_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.h
new file mode 100644
index 000000000000..5f9a2956b274
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_main.h
@@ -0,0 +1,3150 @@
+/** @file moal_main.h
+ *
+ * @brief This file contains wlan driver specific defines etc.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _MOAL_MAIN_H
+#define _MOAL_MAIN_H
+
+/* warnfix for FS redefination if any? */
+#ifdef FS
+#undef FS
+#endif
+
+/* Linux header files */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/irqreturn.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+#include <linux/namei.h>
+#include <linux/fs.h>
+#endif
+#include <linux/of.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+#include <linux/config.h>
+#endif
+
+#ifdef USB
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+#include <linux/freezer.h>
+#endif
+#include <linux/usb.h>
+#endif /* USB */
+
+/* ASM files */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+#include <asm/switch_to.h>
+#else
+#include <asm/system.h>
+#endif
+
+#include <linux/spinlock.h>
+
+/* Net header files */
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/inetdevice.h>
+
+#include <linux/firmware.h>
+
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+#include <linux/pm_wakeup.h>
+#include <linux/device.h>
+#else
+#include <linux/wakelock.h>
+#endif
+#endif
+
+#include "mlan.h"
+#include "moal_shim.h"
+/* Wireless header */
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include <net/lib80211.h>
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include "moal_wext.h"
+#endif
+#ifdef STA_WEXT
+#include "moal_priv.h"
+#endif
+
+#ifndef MIN
+/** Find minimum */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define COMPAT_VERSION_CODE KERNEL_VERSION(0, 0, 0)
+#define CFG80211_VERSION_CODE MAX(LINUX_VERSION_CODE, COMPAT_VERSION_CODE)
+
+/**
+ * Reason Code 3: STA is leaving (or has left) IBSS or ESS
+ */
+#define DEF_DEAUTH_REASON_CODE (0x3)
+
+/**
+ * 802.1 Local Experimental 1.
+ */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24)
+#define REFDATA __refdata
+#else
+#define REFDATA
+#endif
+
+/**
+ * Linux Kernels later 3.9 use CONFIG_PM_RUNTIME instead of
+ * CONFIG_USB_SUSPEND
+ * Linux Kernels later 3.19 use CONFIG_PM instead of
+ * CONFIG_PM_RUNTIME
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+#ifdef CONFIG_PM
+#ifndef CONFIG_USB_SUSPEND
+#define CONFIG_USB_SUSPEND
+#endif
+#ifndef CONFIG_PM_RUNTIME
+#define CONFIG_PM_RUNTIME
+#endif
+#endif
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+#ifdef CONFIG_PM_RUNTIME
+#ifndef CONFIG_USB_SUSPEND
+#define CONFIG_USB_SUSPEND
+#endif
+#endif
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+#endif
+
+/**
+ * Linux kernel later 3.10 use strncasecmp instead of strnicmp
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+#define strnicmp strncasecmp
+#endif
+
+/**
+ * Linux kernel later 4.7 use nl80211_band instead of ieee80211_band
+ * Linux kernel later 4.7 use new macro
+ */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
+#define ieee80211_band nl80211_band
+#define IEEE80211_BAND_2GHZ NL80211_BAND_2GHZ
+#define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ
+#define IEEE80211_NUM_BANDS NUM_NL80211_BANDS
+#endif
+
+/**
+ * interface name
+ */
+#define default_mlan_name "mlan%d"
+#define default_uap_name "uap%d"
+#define default_wfd_name "wfd%d"
+#define default_nan_name "nan%d"
+#define default_mpl_name "mpl%d"
+#define default_11p_name "ocb%d"
+#define mwiphy_name "mwiphy%d"
+
+/** Define BOOLEAN */
+typedef t_u8 BOOLEAN;
+
+#define INTF_CARDTYPE "---------%s-MXM"
+
+#define KERN_VERSION "5X"
+
+#define V15 "15"
+#define V16 "16"
+#define V17 "17"
+
+/** Chip Magic Value */
+#define CHIP_MAGIC_VALUE 0x24
+/** card type SD_UART */
+#define CARD_TYPE_SD_UART 0
+/** card type SD_SD */
+#define CARD_TYPE_SD_SD 1
+/** card type PCIE_PCIE */
+#define CARD_TYPE_PCIE_PCIE 2
+/** card type PCIE_UART */
+#define CARD_TYPE_PCIE_UART 3
+/** card type USB_UART */
+#define CARD_TYPE_USB_UART 4
+/** card type USB_USB */
+#define CARD_TYPE_USB_USB 6
+/** card type PCIE_USB */
+#define CARD_TYPE_PCIE_USB 7
+
+/** Driver version */
+extern char driver_version[];
+
+/** Private structure for MOAL */
+typedef struct _moal_private moal_private, *pmoal_private;
+/** Handle data structure for MOAL */
+typedef struct _moal_handle moal_handle, *pmoal_handle;
+
+/** Hardware status codes */
+typedef enum _MOAL_HARDWARE_STATUS {
+ HardwareStatusReady,
+ HardwareStatusInitializing,
+ HardwareStatusFwReady,
+ HardwareStatusReset,
+ HardwareStatusClosing,
+ HardwareStatusNotReady
+} MOAL_HARDWARE_STATUS;
+
+/** fw cap info 11p */
+#define FW_CAPINFO_80211P MBIT(24)
+/** fw cap info disable nan */
+#define FW_CAPINFO_DISABLE_NAN MBIT(29)
+/** fw cap info BGA */
+#define FW_CAPINFO_80211BGA (MBIT(8) | MBIT(9) | MBIT(10))
+
+/** moal_wait_option */
+enum { MOAL_NO_WAIT, MOAL_IOCTL_WAIT, MOAL_IOCTL_WAIT_TIMEOUT };
+
+/** moal_main_state */
+enum { MOAL_STATE_IDLE,
+ MOAL_RECV_INT,
+ MOAL_ENTER_WORK_QUEUE,
+ MOAL_START_MAIN_PROCESS,
+ MOAL_END_MAIN_PROCESS };
+
+/** HostCmd_Header */
+typedef struct _HostCmd_Header {
+ /** Command */
+ t_u16 command;
+ /** Size */
+ t_u16 size;
+} HostCmd_Header;
+
+/*
+ * OS timer specific
+ */
+
+/** Timer structure */
+typedef struct _moal_drv_timer {
+ /** Timer list */
+ struct timer_list tl;
+ /** Timer function */
+ void (*timer_function)(void *context);
+ /** Timer function context */
+ void *function_context;
+ /** Time period */
+ t_u32 time_period;
+ /** Is timer periodic ? */
+ t_u32 timer_is_periodic;
+ /** Is timer cancelled ? */
+ t_u32 timer_is_canceled;
+} moal_drv_timer, *pmoal_drv_timer;
+
+/**
+ * @brief Timer handler
+ *
+ * @param fcontext Timer context
+ *
+ * @return N/A
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+static inline void woal_timer_handler(struct timer_list *t)
+{
+ pmoal_drv_timer timer = from_timer(timer, t, tl);
+#else
+static inline void woal_timer_handler(unsigned long fcontext)
+{
+ pmoal_drv_timer timer = (pmoal_drv_timer)fcontext;
+#endif
+
+ timer->timer_function(timer->function_context);
+
+ if (timer->timer_is_periodic == MTRUE) {
+ mod_timer(&timer->tl,
+ jiffies + ((timer->time_period * HZ) / 1000));
+ } else {
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ }
+}
+
+/**
+ * @brief Initialize timer
+ *
+ * @param timer Timer structure
+ * @param TimerFunction Timer function
+ * @param FunctionContext Timer function context
+ *
+ * @return N/A
+ */
+static inline void woal_initialize_timer(pmoal_drv_timer timer,
+ void (*TimerFunction)(void *context),
+ void *FunctionContext)
+{
+ /* First, setup the timer to trigger the wlan_timer_handler proxy */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+ timer_setup(&timer->tl, woal_timer_handler, 0);
+#else
+ init_timer(&timer->tl);
+ timer->tl.function = woal_timer_handler;
+ timer->tl.data = (t_ptr)timer;
+#endif
+
+ /* Then tell the proxy which function to call and what to pass it */
+ timer->timer_function = TimerFunction;
+ timer->function_context = FunctionContext;
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+ timer->timer_is_periodic = MFALSE;
+}
+
+/**
+ * @brief Modify timer
+ *
+ * @param timer Timer structure
+ * @param millisecondperiod Time period in millisecond
+ *
+ * @return N/A
+ */
+static inline void woal_mod_timer(pmoal_drv_timer timer,
+ t_u32 millisecondperiod)
+{
+ timer->time_period = millisecondperiod;
+ mod_timer(&timer->tl, jiffies + (millisecondperiod * HZ) / 1000);
+ timer->timer_is_canceled = MFALSE;
+}
+
+/**
+ * @brief Cancel timer
+ *
+ * @param timer Timer structure
+ *
+ * @return N/A
+ */
+static inline void woal_cancel_timer(moal_drv_timer *timer)
+{
+ if (timer->timer_is_periodic || in_atomic() || irqs_disabled())
+ del_timer(&timer->tl);
+ else
+ del_timer_sync(&timer->tl);
+ timer->timer_is_canceled = MTRUE;
+ timer->time_period = 0;
+}
+
+#ifdef REASSOCIATION
+/*
+ * OS Thread Specific
+ */
+
+#include <linux/kthread.h>
+
+/** Kernel thread structure */
+typedef struct _moal_thread {
+ /** Task control structrue */
+ struct task_struct *task;
+ /** Pointer to wait_queue_head */
+ wait_queue_head_t wait_q;
+ /** PID */
+ pid_t pid;
+ /** Pointer to moal_handle */
+ void *handle;
+} moal_thread;
+
+/**
+ * @brief Activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void woal_activate_thread(moal_thread *thr)
+{
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->wait_q);
+
+ /** Record the thread pid */
+ thr->pid = current->pid;
+}
+
+/**
+ * @brief De-activate thread
+ *
+ * @param thr Thread structure
+ * @return N/A
+ */
+static inline void woal_deactivate_thread(moal_thread *thr)
+{
+ /* Reset the pid */
+ thr->pid = 0;
+}
+
+/**
+ * @brief Create and run the thread
+ *
+ * @param threadfunc Thread function
+ * @param thr Thread structure
+ * @param name Thread name
+ * @return N/A
+ */
+static inline void woal_create_thread(int (*threadfunc)(void *),
+ moal_thread *thr, char *name)
+{
+ /* Create and run the thread */
+ thr->task = kthread_run(threadfunc, thr, "%s", name);
+}
+#endif /* REASSOCIATION */
+
+/* The following macros are neccessary to retain compatibility
+ * around the workqueue chenges happened in kernels >= 2.6.20:
+ * - INIT_WORK changed to take 2 arguments and let the work function
+ * get its own data through the container_of macro
+ * - delayed works have been split from normal works to save some
+ * memory usage in struct work_struct
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK(_work, _fun) \
+ INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK(_work, _fun) \
+ INIT_WORK(_work, ((void (*)(void *))_fun), _work)
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+/** Work_queue work initialization */
+#define MLAN_INIT_WORK INIT_WORK
+/** Work_queue delayed work initialization */
+#define MLAN_INIT_DELAYED_WORK INIT_DELAYED_WORK
+/** Work_queue container parameter */
+#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) \
+ container_of(_ptr, _type, _m.work)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
+
+/**
+ * @brief Schedule timeout
+ *
+ * @param millisec Timeout duration in milli second
+ *
+ * @return N/A
+ */
+static inline void woal_sched_timeout(t_u32 millisec)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout((millisec * HZ) / 1000);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+#define IN6PTON_XDIGIT 0x00010000
+#define IN6PTON_DIGIT 0x00020000
+#define IN6PTON_COLON_MASK 0x00700000
+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
+#define IN6PTON_DOT 0x00800000 /* . */
+#define IN6PTON_DELIM 0x10000000
+#define IN6PTON_NULL 0x20000000 /* first/tail */
+#define IN6PTON_UNKNOWN 0x40000000
+
+static inline int xdigit2bin(char c, int delim)
+{
+ if (c == delim || c == '\0')
+ return IN6PTON_DELIM;
+ if (c == ':')
+ return IN6PTON_COLON_MASK;
+ if (c == '.')
+ return IN6PTON_DOT;
+ if (c >= '0' && c <= '9')
+ return IN6PTON_XDIGIT | IN6PTON_DIGIT | (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return IN6PTON_XDIGIT | (c - 'a' + 10);
+ if (c >= 'A' && c <= 'F')
+ return IN6PTON_XDIGIT | (c - 'A' + 10);
+ if (delim == -1)
+ return IN6PTON_DELIM;
+ return IN6PTON_UNKNOWN;
+}
+
+static inline int in4_pton(const char *src, int srclen, u8 *dst, int delim,
+ const char **end)
+{
+ const char *s;
+ u8 *d;
+ u8 dbuf[4];
+ int ret = 0;
+ int i;
+ int w = 0;
+
+ if (srclen < 0)
+ srclen = strlen(src);
+ s = src;
+ d = dbuf;
+ i = 0;
+ while (1) {
+ int c;
+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
+ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
+ IN6PTON_COLON_MASK))) {
+ goto out;
+ }
+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (w == 0)
+ goto out;
+ *d++ = w & 0xff;
+ w = 0;
+ i++;
+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (i != 4)
+ goto out;
+ break;
+ }
+ goto cont;
+ }
+ w = (w * 10) + c;
+ if ((w & 0xffff) > 255)
+ goto out;
+ cont:
+ if (i >= 4)
+ goto out;
+ s++;
+ srclen--;
+ }
+ ret = 1;
+ moal_memcpy_ext(NULL, dst, dbuf, sizeof(dbuf), sizeof(dbuf));
+out:
+ if (end)
+ *end = s;
+ return ret;
+}
+#endif /* < 2.6.19 */
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__((packed))
+#endif
+
+/** Get module */
+#define MODULE_GET try_module_get(THIS_MODULE)
+/** Put module */
+#define MODULE_PUT module_put(THIS_MODULE)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) init_MUTEX(x)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) init_MUTEX_LOCKED(x)
+#else
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE(x) sema_init(x, 1)
+/** Initialize semaphore */
+#define MOAL_INIT_SEMAPHORE_LOCKED(x) sema_init(x, 0)
+#endif
+
+/** Acquire semaphore and with blocking */
+#define MOAL_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
+/** Acquire semaphore without blocking */
+#define MOAL_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
+/** Release semaphore */
+#define MOAL_REL_SEMAPHORE(x) up(x)
+
+/** Request FW timeout in second */
+#define REQUEST_FW_TIMEOUT 30
+
+#if defined(USB) || defined(SYSKT)
+/** Max loop count (* 100ms) for waiting device ready at init time */
+#define MAX_WAIT_DEVICE_READY_COUNT 50
+#endif
+
+/** Default watchdog timeout */
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (10 * HZ)
+
+#ifdef UAP_SUPPORT
+/** Default watchdog timeout
+ Increase the value to avoid kernel Tx timeout message in case
+ station in PS mode or left.
+ The default value of PS station ageout timer is 40 seconds.
+ Hence, the watchdog timer is set to a value higher than it.
+*/
+#define MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT (41 * HZ)
+#endif
+
+/* IOCTL Timeout */
+#define MOAL_IOCTL_TIMEOUT (20 * HZ)
+
+#ifdef ANDROID_KERNEL
+/** Wake lock timeout in msec */
+#define WAKE_LOCK_TIMEOUT 3000
+/** Roaming Wake lock timeout in msec */
+#define ROAMING_WAKE_LOCK_TIMEOUT 10000
+#endif
+
+/** Threshold value of number of times the Tx timeout happened */
+/* WAR For EDMAC Test */
+#define NUM_TX_TIMEOUT_THRESHOLD 10
+/** Custom event : DRIVER HANG */
+#define CUS_EVT_DRIVER_HANG "EVENT=DRIVER_HANG"
+
+/** AP connected event */
+#define CUS_EVT_AP_CONNECTED "EVENT=AP_CONNECTED"
+
+/** Custom event : BW changed */
+#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED"
+/** Custom event : OBSS scan parameter */
+#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM"
+
+/** Custom event : AdHoc link sensed */
+#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED"
+/** Custom event : AdHoc link lost */
+#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST"
+/** Custom event : MIC failure, unicast */
+#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast"
+/** Custom event : MIC failure, multicast */
+#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast"
+/** Custom event : Beacon RSSI low */
+#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW"
+/** Custom event : Beacon SNR low */
+#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW"
+/** Custom event : Beacon RSSI high */
+#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH"
+/** Custom event : Beacon SNR high */
+#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
+/** Custom event : Max fail */
+#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
+/** Custom event : Data RSSI low */
+#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
+/** Custom event : Data SNR low */
+#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW"
+/** Custom event : Data RSSI high */
+#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH"
+/** Custom event : Data SNR high */
+#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH"
+/** Custom event : Link Quality */
+#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY"
+/** Custom event : Port Release */
+#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE"
+/** Custom event : Pre-Beacon Lost */
+#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST"
+
+/** Custom event : Deep Sleep awake */
+#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE"
+
+/** Custom event : Host Sleep activated */
+#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED"
+/** Custom event : Host Sleep deactivated */
+#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED"
+/** Custom event : Host Sleep wakeup */
+#define CUS_EVT_HS_WAKEUP "HS_WAKEUP"
+
+/** Wakeup Reason */
+typedef enum {
+ NO_HSWAKEUP_REASON = 0, // 0.unknown
+ BCAST_DATA_MATCHED, // 1. Broadcast data matched
+ MCAST_DATA_MATCHED, // 2. Multicast data matched
+ UCAST_DATA_MATCHED, // 3. Unicast data matched
+ MASKTABLE_EVENT_MATCHED, // 4. Maskable event matched
+ NON_MASKABLE_EVENT_MATCHED, // 5. Non-maskable event matched
+ NON_MASKABLE_CONDITION_MATCHED, // 6. Non-maskable condition matched
+ // (EAPoL rekey)
+ MAGIC_PATTERN_MATCHED, // 7. Magic pattern matched
+ CONTROL_FRAME_MATCHED, // 8. Control frame matched
+ MANAGEMENT_FRAME_MATCHED, // 9. Management frame matched
+ GTK_REKEY_FAILURE, // 10. GTK rekey failure
+ RESERVED // Others: reserved
+} HSWakeupReason_t;
+
+/** Custom event : WEP ICV error */
+#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR"
+
+/** Custom event : Channel Switch Announcment */
+#define CUS_EVT_CHANNEL_SWITCH_ANN "EVENT=CHANNEL_SWITCH_ANN"
+
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication"
+
+#ifdef UAP_SUPPORT
+/** Custom event : STA connected */
+#define CUS_EVT_STA_CONNECTED "EVENT=STA_CONNECTED"
+/** Custom event : STA disconnected */
+#define CUS_EVT_STA_DISCONNECTED "EVENT=STA_DISCONNECTED"
+#endif
+#define FW_DEBUG_INFO "EVENT=FW_DEBUG_INFO"
+
+/** 10 seconds */
+#define MOAL_TIMER_10S 10000
+/** 5 seconds */
+#define MOAL_TIMER_5S 5000
+/** 1 second */
+#define MOAL_TIMER_1S 1000
+/** 1 milisecond */
+#define MOAL_TIMER_1MS 1
+
+/** passive scan time */
+#define PASSIVE_SCAN_CHAN_TIME 110
+/** active scan time */
+#define ACTIVE_SCAN_CHAN_TIME 110
+/** specific scan time */
+#define SPECIFIC_SCAN_CHAN_TIME 110
+/** passive scan time */
+#define INIT_PASSIVE_SCAN_CHAN_TIME 80
+/** active scan time */
+#define INIT_ACTIVE_SCAN_CHAN_TIME 80
+/** specific scan time */
+#define INIT_SPECIFIC_SCAN_CHAN_TIME 80
+/** specific scan time after connected */
+#define MIN_SPECIFIC_SCAN_CHAN_TIME 40
+
+/** Default value of re-assoc timer */
+#define REASSOC_TIMER_DEFAULT 500
+
+/** Netlink protocol number */
+#define NETLINK_NXP (MAX_LINKS - 1)
+/** Netlink maximum payload size */
+#define NL_MAX_PAYLOAD 1024
+/** Netlink multicast group number */
+#define NL_MULTICAST_GROUP 1
+
+#define MAX_RX_PENDING_THRHLD 50
+
+/** high rx pending packets */
+#define HIGH_RX_PENDING 100
+/** low rx pending packets */
+#define LOW_RX_PENDING 80
+
+/** MAX Tx Pending count */
+#define MAX_TX_PENDING 400
+
+/** LOW Tx Pending count */
+#define LOW_TX_PENDING 380
+
+/** Offset for subcommand */
+#define SUBCMD_OFFSET 4
+
+/** default scan channel gap */
+#define DEF_SCAN_CHAN_GAP 50
+/** default scan time per channel in miracast mode */
+#define DEF_MIRACAST_SCAN_TIME 20
+/** GAP value is optional */
+#define GAP_FLAG_OPTIONAL MBIT(15)
+
+/** Macro to extract the TOS field from a skb */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+#define SKB_TOS(skb) (ip_hdr(skb)->tos)
+#else
+#define SKB_TOS(skb) (skb->nh.iph->tos)
+#endif
+#define SKB_TIDV6(skb) (ipv6_get_dsfield(ipv6_hdr(skb)))
+#define IS_SKB_MAGIC_VLAN(skb) (skb->priority >= 256 && skb->priority <= 263)
+#define GET_VLAN_PRIO(skb) (skb->priority - 256)
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/** Offset for DSCP in the tos field */
+#define DSCP_OFFSET 2
+
+/** max retry count for wait_event_interupptible_xx while loop */
+#define MAX_RETRY_CNT 100
+/** wait_queue structure */
+typedef struct _wait_queue {
+ /** wait_queue_head */
+ wait_queue_head_t wait;
+ /** Wait condition */
+ BOOLEAN condition;
+ /** Start time */
+ long start_time;
+ /** Status from MLAN */
+ mlan_status status;
+ /** flag for wait_timeout */
+ t_u8 wait_timeout;
+ /** retry count */
+ t_u8 retry;
+} wait_queue, *pwait_queue;
+
+/** Auto Rate */
+#define AUTO_RATE 0xFF
+
+#define STA_WEXT_MASK MBIT(0)
+#define UAP_WEXT_MASK MBIT(1)
+#define STA_CFG80211_MASK MBIT(2)
+#define UAP_CFG80211_MASK MBIT(3)
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+/** Is STA CFG80211 enabled in module param */
+#define IS_STA_CFG80211(x) (x & STA_CFG80211_MASK)
+#endif
+#endif
+#ifdef UAP_CFG80211
+#ifdef UAP_SUPPORT
+/** Is UAP CFG80211 enabled in module param */
+#define IS_UAP_CFG80211(x) (x & UAP_CFG80211_MASK)
+#endif
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+/** Is UAP or STA CFG80211 enabled in module param */
+#define IS_STA_OR_UAP_CFG80211(x) (x & (STA_CFG80211_MASK | UAP_CFG80211_MASK))
+#endif
+
+#ifdef STA_WEXT
+/** Is STA WEXT enabled in module param */
+#define IS_STA_WEXT(x) (x & STA_WEXT_MASK)
+#endif /* STA_WEXT */
+#ifdef UAP_WEXT
+/** Is UAP WEXT enabled in module param */
+#define IS_UAP_WEXT(x) (x & UAP_WEXT_MASK)
+#endif /* UAP_WEXT */
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+/** Is UAP or STA WEXT enabled in module param */
+#define IS_STA_OR_UAP_WEXT(x) (x & (STA_WEXT_MASK | UAP_WEXT_MASK))
+#endif
+
+#ifdef STA_SUPPORT
+/** Driver mode STA bit */
+#define DRV_MODE_STA MBIT(0)
+/** Maximum STA BSS */
+#define MAX_STA_BSS 1
+/** Default STA BSS */
+#define DEF_STA_BSS 1
+#endif
+#ifdef UAP_SUPPORT
+/** Driver mode uAP bit */
+#define DRV_MODE_UAP MBIT(1)
+/** Maximum uAP BSS */
+#define MAX_UAP_BSS 1
+/** Default uAP BSS */
+#define DEF_UAP_BSS 1
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+/** Driver mode WIFIDIRECT bit */
+#define DRV_MODE_WIFIDIRECT MBIT(2)
+/** Maximum WIFIDIRECT BSS */
+#define MAX_WIFIDIRECT_BSS 2
+/** Default WIFIDIRECT BSS */
+#define DEF_WIFIDIRECT_BSS 1
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#define DEF_VIRTUAL_BSS 0
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+
+#define DRV_MODE_WLAN (MBIT(0) | MBIT(1) | MBIT(2) | MBIT(3) | MBIT(4))
+
+/**
+ * the maximum number of adapter supported
+ **/
+#define MAX_MLAN_ADAPTER 3
+
+typedef struct _moal_drv_mode {
+ /** driver mode */
+ t_u16 drv_mode;
+ /** total number of interfaces */
+ t_u16 intf_num;
+ /** attribute of bss */
+ mlan_bss_attr *bss_attr;
+ /** name of firmware image */
+ char *fw_name;
+} moal_drv_mode;
+
+/** Indicate if handle->info's address */
+#define INFO_ADDR BIT(0)
+#define IS_INFO_ADDR(attr) (attr & INFO_ADDR)
+/** Indicate if handle's address */
+#define HANDLE_ADDR BIT(1)
+#define IS_HANDLE_ADDR(attr) (attr & HANDLE_ADDR)
+/** Indicate if card's address */
+#define CARD_ADDR BIT(2)
+#define IS_CARD_ADDR(attr) (attr & CARD_ADDR)
+/** indicate if priv's address */
+#define PRIV_ADDR BIT(3)
+#define IS_PRIV_ADDR(attr) (attr & PRIV_ADDR)
+
+/** Debug data */
+struct debug_data {
+ /** Name */
+ char name[32];
+ /** Size */
+ t_u32 size;
+ /** Address */
+ t_ptr addr;
+ /** Attribute:
+ 0-7bit: start address for addr to add to, 0 means common(no specific)
+ 8-15bit: interface type, 0 means common(no interface specific)
+ other: unused
+ */
+ t_u32 attr;
+};
+
+/** Private debug data */
+struct debug_data_priv {
+ /** moal_private handle */
+ moal_private *priv;
+ /** Debug items */
+ struct debug_data *items;
+ /** numbre of item */
+ int num_of_items;
+};
+
+/** Maximum IP address buffer length */
+#define IPADDR_MAX_BUF 20
+/** IP address operation: Remove */
+#define IPADDR_OP_REMOVE 0
+
+#define DROP_TCP_ACK 1
+#define HOLD_TCP_ACK 2
+struct tcp_sess {
+ struct list_head link;
+ /** tcp session info */
+ t_u32 src_ip_addr;
+ t_u32 dst_ip_addr;
+ t_u16 src_tcp_port;
+ t_u16 dst_tcp_port;
+ /** tx ack packet info */
+ t_u32 ack_seq;
+ /** tcp ack buffer */
+ void *ack_skb;
+ /** priv structure */
+ void *priv;
+ /** pmbuf */
+ void *pmbuf;
+ /** timer for ack */
+ moal_drv_timer ack_timer __ATTRIB_ALIGN__;
+ /** timer is set */
+ BOOLEAN is_timer_set;
+};
+
+struct tx_status_info {
+ struct list_head link;
+ /** cookie */
+ t_u64 tx_cookie;
+ /** seq_num */
+ t_u8 tx_seq_num;
+ /** cancel remain on channel when receive tx status */
+ t_u8 cancel_remain_on_channel;
+ /** skb */
+ void *tx_skb;
+};
+
+/** woal event type */
+enum woal_event_type {
+ WOAL_EVENT_CHAN_SWITCH,
+ WOAL_EVENT_BGSCAN_STOP,
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ WOAL_EVENT_DEAUTH,
+ WOAL_EVENT_ASSOC_RESP,
+#endif
+#endif
+};
+
+/** woal event */
+struct woal_event {
+ /*list head */
+ struct list_head link;
+ /** type */
+ enum woal_event_type type;
+ /** priv pointer */
+ void *priv;
+ union {
+ chan_band_info chan_info;
+ mlan_ds_misc_assoc_rsp assoc_resp;
+ int reason_code;
+ };
+};
+
+#define MAX_NUM_ETHER_TYPE 8
+typedef struct {
+ /** number of protocols in protocol array*/
+ t_u8 protocol_num;
+ /** protocols supported */
+ t_u16 protocols[MAX_NUM_ETHER_TYPE];
+} __ATTRIB_PACK__ dot11_protocol;
+typedef struct {
+ /** Data rate in unit of 0.5Mbps */
+ t_u16 datarate;
+ /** Channel number to transmit the frame */
+ t_u8 channel;
+ /** Bandwidth to transmit the frame */
+ t_u8 bw;
+ /** Power to be used for transmission */
+ t_u8 power;
+ /** Priority of the packet to be transmitted */
+ t_u8 priority;
+ /** retry time of tx transmission*/
+ t_u8 retry_limit;
+ /** Reserved fields*/
+ t_u8 reserved[1];
+} __ATTRIB_PACK__ dot11_txcontrol;
+
+typedef struct {
+ /** Data rate of received paccket*/
+ t_u16 datarate;
+ /** Channel on which packet was received*/
+ t_u8 channel;
+ /** Rx antenna*/
+ t_u8 antenna;
+ /** RSSI */
+ t_u8 rssi;
+ /** Reserved */
+ t_u8 reserved[3];
+} __ATTRIB_PACK__ dot11_rxcontrol;
+
+#define OKC_WAIT_TARGET_PMKSA_TIMEOUT (4 * HZ / 1000)
+#define PMKID_LEN 16
+struct pmksa_entry {
+ struct list_head link;
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[PMKID_LEN];
+};
+
+struct rf_test_mode_data {
+ /* tx antenna num */
+ t_u32 tx_antenna;
+ /* rx antenna num */
+ t_u32 rx_antenna;
+ /* RF band */
+ t_u32 band;
+ /* RF bandwidth */
+ t_u32 bandwidth;
+ /* RF channel */
+ t_u32 channel;
+ /* Total Rx ucast/mcast/bcast pkt count */
+ t_u32 rx_tot_pkt_count;
+ /* Rx mcast/bcast pkt count */
+ t_u32 rx_mcast_bcast_pkt_count;
+ /* Rx fcs error count */
+ t_u32 rx_pkt_fcs_err_count;
+ /* Tx power config values */
+ t_u32 tx_power_data[3];
+ /* Tx continuous config values */
+ t_u32 tx_cont_data[6];
+ /* Tx frame config values */
+ t_u32 tx_frame_data[13];
+ /* BSSID */
+ t_u8 bssid[ETH_ALEN];
+};
+
+/** Number of samples in histogram (/proc/mwlan/adapterX/mlan0/histogram).*/
+#define HIST_MAX_SAMPLES 1048576
+#define RX_RATE_MAX 196
+
+/** SRN MAX */
+#define SNR_MAX 256
+/** NOISE FLR MAX */
+#define NOISE_FLR_MAX 256
+/** SIG STRENTGH MAX */
+#define SIG_STRENGTH_MAX 256
+/** historgram data */
+typedef struct _hgm_data {
+ /** snr */
+ atomic_t snr[SNR_MAX];
+ /** noise flr */
+ atomic_t noise_flr[NOISE_FLR_MAX];
+ /** sig_str */
+ atomic_t sig_str[SIG_STRENGTH_MAX];
+ /** num sample */
+ atomic_t num_samples;
+ /** rx rate */
+ atomic_t rx_rate[];
+} hgm_data, *phgm_data;
+
+/** max antenna number */
+#define MAX_ANTENNA_NUM 4
+
+/* wlan_hist_proc_data */
+typedef struct _wlan_hist_proc_data {
+ /** antenna */
+ u8 ant_idx;
+ /** Private structure */
+ struct _moal_private *priv;
+} wlan_hist_proc_data;
+
+enum ring_id {
+ VERBOSE_RING_ID,
+ EVENT_RING_ID,
+ RING_ID_MAX,
+};
+
+/** Private structure for MOAL */
+struct _moal_private {
+ /** Handle structure */
+ moal_handle *phandle;
+ /** Tx timeout count */
+ t_u32 num_tx_timeout;
+ /** BSS index */
+ t_u8 bss_index;
+ /** BSS type */
+ t_u8 bss_type;
+ /** BSS role */
+ t_u8 bss_role;
+ /** bss virtual flag */
+ t_u8 bss_virtual;
+ /** MAC address information */
+ t_u8 current_addr[ETH_ALEN];
+ /** Media connection status */
+ BOOLEAN media_connected;
+ /** Statistics of tcp ack tx dropped */
+ t_u32 tcp_ack_drop_cnt;
+ /** Statistics of tcp ack tx in total from kernel */
+ t_u32 tcp_ack_cnt;
+#ifdef UAP_SUPPORT
+ /** uAP started or not */
+ BOOLEAN bss_started;
+ /** host based uap flag */
+ BOOLEAN uap_host_based;
+ /** uAP skip CAC*/
+ BOOLEAN skip_cac;
+ /** tx block flag */
+ BOOLEAN uap_tx_blocked;
+ /** user cac period */
+ t_u32 user_cac_period_msec;
+ /** channel under nop */
+ BOOLEAN chan_under_nop;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /** current working channel */
+ struct cfg80211_chan_def chan;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ /** switch channel */
+ struct cfg80211_chan_def csa_chan;
+ /** beacon after channel switch */
+ struct cfg80211_beacon_data beacon_after;
+ /** CSA work queue */
+ struct workqueue_struct *csa_workqueue;
+ /** csa work */
+ struct delayed_work csa_work;
+#endif
+#endif
+#endif
+#ifdef STA_SUPPORT
+ /** scan type */
+ t_u8 scan_type;
+ /** extended capabilities */
+ ExtCap_t extended_capabilities;
+ /** bg_scan_start */
+ t_u8 bg_scan_start;
+ /** bg_scan reported */
+ t_u8 bg_scan_reported;
+ /** bg_scan config */
+ wlan_bgscan_cfg scan_cfg;
+ /** sched scaning flag */
+ t_u8 sched_scanning;
+ /** bgscan request id */
+ t_u64 bg_scan_reqid;
+#ifdef STA_CFG80211
+ /** roaming enabled flag */
+ t_u8 roaming_enabled;
+ /** roaming required flag */
+ t_u8 roaming_required;
+#endif
+#ifdef STA_CFG80211
+ /** rssi low threshold */
+ int rssi_low;
+ /** channel for connect */
+ struct ieee80211_channel conn_chan;
+ /** bssid for connect */
+ t_u8 conn_bssid[ETH_ALEN];
+ /** ssid for connect */
+ t_u8 conn_ssid[MLAN_MAX_SSID_LENGTH];
+ /** length of ssid for connect */
+ t_u8 conn_ssid_len;
+ /** key data */
+ t_u8 conn_wep_key[MAX_WEP_KEY_SIZE];
+ /** connection param */
+ struct cfg80211_connect_params sme_current;
+#endif
+ t_u8 wait_target_ap_pmkid;
+ wait_queue_head_t okc_wait_q __ATTRIB_ALIGN__;
+ struct list_head pmksa_cache_list;
+ spinlock_t pmksa_list_lock;
+ struct pmksa_entry *target_ap_pmksa;
+ t_u8 okc_ie_len;
+ t_u8 *okc_roaming_ie;
+#endif
+ /** Net device pointer */
+ struct net_device *netdev;
+ /** Net device statistics structure */
+ struct net_device_stats stats;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ /** Wireless device pointer */
+ struct wireless_dev *wdev;
+ /** Wireless device */
+ struct wireless_dev w_dev;
+ /** Net device pointer */
+ struct net_device *pa_netdev;
+ /** channel parameter for UAP/GO */
+ t_u16 channel;
+#ifdef UAP_SUPPORT
+ /** wep key */
+ wep_key uap_wep_key[4];
+ /** cipher */
+ t_u32 cipher;
+#endif
+ /** beacon ie index */
+ t_u16 beacon_index;
+ /** proberesp ie index */
+ t_u16 proberesp_index;
+ /** proberesp_p2p_index */
+ t_u16 proberesp_p2p_index;
+ /** assocresp ie index */
+ t_u16 assocresp_index;
+ /** assocresp qos map ie index */
+ t_u16 assocresp_qos_map_index;
+ /** probereq index for mgmt ie */
+ t_u16 probereq_index;
+ /** mgmt_subtype_mask */
+ t_u32 mgmt_subtype_mask;
+ /** beacon wps index for mgmt ie */
+ t_u16 beacon_wps_index;
+ /** beacon/proberesp vendor ie index */
+ t_u16 beacon_vendor_index;
+#endif
+#ifdef STA_CFG80211
+#ifdef STA_SUPPORT
+ /** CFG80211 association description */
+ t_u8 cfg_bssid[ETH_ALEN];
+ /** Disconnect request from CFG80211 */
+ bool cfg_disconnect;
+ /** connect request from CFG80211 */
+ bool cfg_connect;
+ /** lock for cfg connect */
+ spinlock_t connect_lock;
+ /** assoc status */
+ t_u32 assoc_status;
+ /** rssi_threshold */
+ s32 cqm_rssi_thold;
+ /** rssi_high_threshold */
+ s32 cqm_rssi_high_thold;
+ /** rssi hysteresis */
+ u32 cqm_rssi_hyst;
+ /** last rssi_low */
+ u8 last_rssi_low;
+ /** last rssi_high */
+ u8 last_rssi_high;
+ /** mrvl rssi threshold */
+ u8 mrvl_rssi_low;
+ /** last event */
+ u32 last_event;
+ /** fake scan flag */
+ u8 fake_scan_complete;
+ /**ft ie*/
+ t_u8 ft_ie[MAX_IE_SIZE];
+ /**ft ie len*/
+ t_u8 ft_ie_len;
+ /**ft ie*/
+ t_u8 pre_ft_ie[MAX_IE_SIZE];
+ /**ft ie len*/
+ t_u8 pre_ft_ie_len;
+ /**mobility domain value*/
+ t_u16 ft_md;
+ /**ft capability*/
+ t_u8 ft_cap;
+ /** set true when receive ft auth or action ft roaming */
+ t_bool ft_pre_connect;
+ /**ft roaming triggered by driver or not*/
+ t_bool ft_roaming_triggered_by_driver;
+ /**target ap mac address for Fast Transition*/
+ t_u8 target_ap_bssid[ETH_ALEN];
+ /** IOCTL wait queue for FT*/
+ wait_queue_head_t ft_wait_q __ATTRIB_ALIGN__;
+ /** ft wait condition */
+ t_bool ft_wait_condition;
+#endif /* STA_SUPPORT */
+#endif /* STA_CFG80211 */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /** flag for host_mlme */
+ t_u8 host_mlme;
+ /** flag for auth */
+ t_u8 auth_flag;
+ /** flag for auth algorithm */
+ t_u16 auth_alg;
+#endif
+#ifdef CONFIG_PROC_FS
+ /** Proc entry */
+ struct proc_dir_entry *proc_entry;
+ /** Proc entry name */
+ char proc_entry_name[IFNAMSIZ];
+ /** proc entry for hist */
+ struct proc_dir_entry *hist_entry;
+ /** ant_hist_proc_data */
+ wlan_hist_proc_data hist_proc[MAX_ANTENNA_NUM];
+#endif /* CONFIG_PROC_FS */
+#ifdef STA_SUPPORT
+ /** Nickname */
+ t_u8 nick_name[16];
+ /** AdHoc link sensed flag */
+ BOOLEAN is_adhoc_link_sensed;
+ /** Current WEP key index */
+ t_u16 current_key_index;
+#ifdef REASSOCIATION
+ mlan_ssid_bssid prev_ssid_bssid;
+ /** Re-association required */
+ BOOLEAN reassoc_required;
+ /** Flag of re-association on/off */
+ BOOLEAN reassoc_on;
+ /** Set asynced essid flag */
+ BOOLEAN set_asynced_essid_flag;
+#endif /* REASSOCIATION */
+ /** Report scan result */
+ t_u8 report_scan_result;
+ /** wpa_version */
+ t_u8 wpa_version;
+ /** key mgmt */
+ t_u8 key_mgmt;
+ /** rx_filter */
+ t_u8 rx_filter;
+#endif /* STA_SUPPORT */
+ /** Rate index */
+ t_u16 rate_index;
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+ /** IW statistics */
+ struct iw_statistics w_stats;
+#endif
+#ifdef UAP_WEXT
+ /** Pairwise Cipher used for WPA/WPA2 mode */
+ t_u16 pairwise_cipher;
+ /** Group Cipher */
+ t_u16 group_cipher;
+ /** Protocol stored during uap wext configuratoin */
+ t_u16 uap_protocol;
+ /** Key Mgmt whether PSK or 1x */
+ t_u16 uap_key_mgmt;
+ /** Beacon IE length from hostapd */
+ t_u16 bcn_ie_len;
+ /** Beacon IE buffer from hostapd */
+ t_u8 bcn_ie_buf[MAX_IE_SIZE];
+#endif
+
+ /** dscp mapping */
+ t_u8 dscp_map[64];
+ /** MLAN debug info */
+ struct debug_data_priv items_priv;
+
+ /** tcp session queue */
+ struct list_head tcp_sess_queue;
+ /** TCP Ack enhance flag */
+ t_u8 enable_tcp_ack_enh;
+ /** TCP session spin lock */
+ spinlock_t tcp_sess_lock;
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ atomic_t wmm_tx_pending[4];
+#endif
+ struct sk_buff_head tx_q;
+ /** per interface extra headroom */
+ t_u16 extra_tx_head_len;
+ /** TX status spin lock */
+ spinlock_t tx_stat_lock;
+ /** tx_seq_num */
+ t_u8 tx_seq_num;
+ /** tx status queue */
+ struct list_head tx_stat_queue;
+ /** rx hgm data */
+ phgm_data hist_data[MAX_ANTENNA_NUM];
+ t_u8 random_mac[MLAN_MAC_ADDR_LENGTH];
+ BOOLEAN assoc_with_mac;
+ t_u8 gtk_data_ready;
+ mlan_ds_misc_gtk_rekey_data gtk_rekey_data;
+ dot11_protocol tx_protocols;
+ dot11_protocol rx_protocols;
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+ /** hostcmd_wait_q */
+ wait_queue_head_t hostcmd_wait_q __ATTRIB_ALIGN__;
+ /** hostcmd_wait_condition */
+ t_bool hostcmd_wait_condition;
+#endif
+ void *rings[RING_ID_MAX];
+ t_u8 pkt_fate_monitor_enable;
+ void *packet_filter;
+};
+
+#ifdef SDIO
+#define DUMP_FW_SDIO_V2 2
+#define DUMP_FW_SDIO_V3 3
+
+#define DUMP_REG_MAX 13
+
+typedef struct _dump_reg_t {
+ t_u8 reg_table[DUMP_REG_MAX];
+ t_u8 reg_table_size;
+} dump_reg_t;
+#endif
+
+#define FW_NAMW_MAX_LEN 64
+
+/** card info */
+typedef struct _card_info {
+ /** support embeded supp */
+ t_bool embedded_supp;
+ /** support drcs */
+ t_bool drcs;
+ /** support Go NOA*/
+ t_bool go_noa;
+ /** support V16_FW_API*/
+ t_bool v16_fw_api;
+ /** support V17_FW_API*/
+ t_bool v17_fw_api;
+ /** support pmic */
+ t_bool pmic;
+ /** support antcfg */
+ t_bool antcfg;
+ /** support cal_data_cfg */
+ t_bool cal_data_cfg;
+ /** support WLAN_LOW_POWER_ENABLE */
+ t_bool low_power_enable;
+ /** rx_rate_max for hist_data: 11N: 76 11AC:196 11AX: 412 */
+ t_u16 rx_rate_max;
+ t_u8 histogram_table_num;
+ /* feature_control */
+ t_u32 feature_control;
+ /* Revision id register */
+ t_u32 rev_id_reg;
+ /* host interface selection reg*/
+ t_u32 host_strap_reg;
+ /* Chip Magic Register */
+ t_u32 magic_reg;
+ /* FW Name */
+ char fw_name[FW_NAMW_MAX_LEN];
+ char fw_name_wlan[FW_NAMW_MAX_LEN];
+#ifdef SDIO
+ t_u8 dump_fw_info;
+ t_u8 dump_fw_ctrl_reg;
+ t_u8 dump_fw_start_reg;
+ t_u8 dump_fw_end_reg;
+ t_u8 dump_fw_host_ready;
+ dump_reg_t dump_reg;
+ t_u8 scratch_reg;
+ t_u8 func1_reg_start;
+ t_u8 func1_reg_end;
+ t_u32 fw_reset_reg;
+ t_u8 fw_reset_val;
+ t_u32 slew_rate_reg;
+ t_u8 slew_rate_bit_offset;
+#endif
+ t_u8 per_pkt_cfg_support;
+} card_info;
+
+#define GTK_REKEY_OFFLOAD_DISABLE 0
+#define GTK_REKEY_OFFLOAD_ENABLE 1
+#define GTK_REKEY_OFFLOAD_SUSPEND 2
+
+#define MAX_KEEP_ALIVE_ID 4
+
+/** Operation data structure for MOAL bus interfaces */
+typedef struct _moal_if_ops {
+ mlan_status (*register_dev)(moal_handle *handle);
+ void (*unregister_dev)(moal_handle *handle);
+ mlan_status (*read_reg)(moal_handle *handle, t_u32 reg, t_u32 *data);
+ mlan_status (*write_reg)(moal_handle *handle, t_u32 reg, t_u32 data);
+ mlan_status (*read_data_sync)(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u32 port, t_u32 timeout);
+ mlan_status (*write_data_sync)(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u32 port, t_u32 timeout);
+ mlan_status (*get_fw_name)(moal_handle *handle);
+ void (*dump_fw_info)(moal_handle *handle);
+ int (*dump_reg_info)(moal_handle *handle, t_u8 *buf);
+ void (*reg_dbg)(moal_handle *handle);
+ t_u8 (*is_second_mac)(moal_handle *handle);
+} moal_if_ops;
+
+#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2, 6, 39)
+
+/** Extended flags */
+enum ext_mod_params {
+ EXT_HW_TEST,
+#ifdef CONFIG_OF
+ EXT_DTS_ENABLE,
+#endif
+ EXT_REQ_FW_NOWAIT,
+ EXT_FW_SERIAL,
+#ifdef SDIO
+ EXT_INTMODE,
+#ifdef SDIO_SUSPEND_RESUME
+ EXT_PM_KEEP_POWER,
+ EXT_SHUTDOWN_HS,
+#endif
+#endif
+ EXT_CNTRY_TXPWR,
+#if defined(USB)
+ EXT_SKIP_FWDNLD,
+#endif
+ EXT_AGGR_CTRL,
+ EXT_LOW_PW_MODE,
+#ifdef SDIO
+ EXT_SDIO_RX_AGGR,
+#endif
+ EXT_PMIC,
+ EXT_DISCONNECT_ON_SUSPEND,
+ EXT_HS_MIMO_SWITCH,
+ EXT_FIX_BCN_BUF,
+ EXT_NAPI,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ EXT_DFS_OFFLOAD,
+#endif
+ EXT_DISABLE_REGD_BY_DRIVER,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ EXT_COUNTRY_IE_IGNORE,
+ EXT_BEACON_HINTS,
+#endif
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ EXT_HOST_MLME,
+#endif
+#endif
+ EXT_TX_WORK,
+ EXT_MAX_PARAM,
+};
+
+/** Module parameter data structure for MOAL */
+typedef struct _moal_mod_para {
+ t_u8 ext_flgs[DIV_ROUND_UP(EXT_MAX_PARAM, 8)];
+ /* BIT24 ~ BIT32 reserved */
+ t_u8 flag;
+ char *fw_name;
+ int fw_reload;
+ char *mac_addr;
+#ifdef MFG_CMD_SUPPORT
+ int mfg_mode;
+#endif /* MFG_CMD_SUPPORT */
+ int drv_mode;
+#ifdef STA_SUPPORT
+ int max_sta_bss;
+ char *sta_name;
+#endif /* STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ int max_uap_bss;
+ char *uap_name;
+ int uap_max_sta;
+#endif /* UAP_SUPPORT */
+#ifdef WIFI_DIRECT_SUPPORT
+ int max_wfd_bss;
+ char *wfd_name;
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+ int max_vir_bss;
+#endif
+#endif /* WIFI_DIRECT_SUPPORT */
+ int auto_ds;
+ int ps_mode;
+ int p2a_scan;
+ /** scan chan gap */
+ int scan_chan_gap;
+ int max_tx_buf;
+#if defined(SDIO)
+ int gpiopin;
+#endif
+#if defined(STA_SUPPORT)
+ int cfg_11d;
+#endif
+#if defined(SDIO)
+ int slew_rate;
+#endif
+ char *dpd_data_cfg;
+ char *init_cfg;
+ char *cal_data_cfg;
+ char *txpwrlimit_cfg;
+ char *init_hostcmd_cfg;
+ char *band_steer_cfg;
+ int cfg80211_wext;
+ int wq_sched_prio;
+ int wq_sched_policy;
+ int rx_work;
+#ifdef USB
+ int usb_aggr;
+#endif
+#ifdef PCIE
+ int pcie_int_mode;
+#endif /* PCIE */
+#ifdef ANDROID_KERNEL
+ int wakelock_timeout;
+#endif
+ unsigned int dev_cap_mask;
+#if defined(SD8997) || defined(PCIE8997) || defined(USB8997) || \
+ defined(SD8977) || defined(SD8987) || defined(SD9098) || \
+ defined(USB9098) || defined(PCIE9098) || defined(SD9097) || \
+ defined(USB9097) || defined(PCIE9097) || defined(SD8978) || \
+ defined(USB8978)
+ int pmic;
+#endif
+ int antcfg;
+ unsigned int uap_oper_ctrl;
+ int hs_wake_interval;
+ int indication_gpio;
+ int indrstcfg;
+#ifdef WIFI_DIRECT_SUPPORT
+ int GoAgeoutTime;
+#endif
+ int gtk_rekey_offload;
+ t_u16 multi_dtim;
+ t_u16 inact_tmo;
+ char *reg_alpha2;
+ int dfs53cfg;
+} moal_mod_para;
+
+void woal_tp_acnt_timer_func(void *context);
+void woal_set_tp_state(moal_private *priv);
+#define MAX_TP_ACCOUNT_DROP_POINT_NUM 5
+#define RX_DROP_P1 (MAX_TP_ACCOUNT_DROP_POINT_NUM)
+#define RX_DROP_P2 (MAX_TP_ACCOUNT_DROP_POINT_NUM + 1)
+#define RX_DROP_P3 (MAX_TP_ACCOUNT_DROP_POINT_NUM + 2)
+#define RX_DROP_P4 (MAX_TP_ACCOUNT_DROP_POINT_NUM + 3)
+#define RX_DROP_P5 (MAX_TP_ACCOUNT_DROP_POINT_NUM + 4)
+typedef struct _moal_tp_acnt_t {
+ /* TX accounting */
+ unsigned long tx_packets[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_packets_last[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_packets_rate[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_bytes[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_bytes_last[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_bytes_rate[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long tx_intr_cnt;
+ unsigned long tx_intr_last;
+ unsigned long tx_intr_rate;
+ unsigned long tx_pending;
+ /** RX accounting */
+ unsigned long rx_packets[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_packets_last[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_packets_rate[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_bytes[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_bytes_last[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_bytes_rate[MAX_TP_ACCOUNT_DROP_POINT_NUM];
+ unsigned long rx_intr_cnt;
+ unsigned long rx_intr_last;
+ unsigned long rx_intr_rate;
+ unsigned long rx_pending;
+ unsigned long rx_paused_cnt;
+ /* TP account mode 0-disable 1-enable */
+ unsigned int on;
+ /* drop point */
+ unsigned int drop_point;
+ /* periodic timer */
+ moal_drv_timer timer;
+} moal_tp_acnt_t;
+
+/** Handle data structure for MOAL */
+struct _moal_handle {
+ /** MLAN adapter structure */
+ t_void *pmlan_adapter;
+ /** Private pointer */
+ moal_private *priv[MLAN_MAX_BSS_NUM];
+ /** Priv number */
+ t_u8 priv_num;
+ /** Bss attr */
+ moal_drv_mode drv_mode;
+
+ /** set mac address flag */
+ t_u8 set_mac_addr;
+ /** MAC address */
+ t_u8 mac_addr[ETH_ALEN];
+#ifdef CONFIG_PROC_FS
+ /** Proc top level directory entry */
+ struct proc_dir_entry *proc_wlan;
+ /** Proc top level directory entry name */
+ char proc_wlan_name[32];
+#endif
+#ifdef USB
+ /** Firmware download skip flag */
+ t_u8 skip_fw_dnld;
+#endif /* USB */
+ /** Firmware */
+ const struct firmware *firmware;
+ /** Firmware request start time */
+ wifi_timeval req_fw_time;
+ /** Init config file */
+ const struct firmware *init_cfg_data;
+ /** Init config file */
+ const struct firmware *user_data;
+ /** Init user configure wait queue token */
+ t_u16 init_user_conf_wait_flag;
+ /** Init user configure file wait queue */
+ wait_queue_head_t init_user_conf_wait_q __ATTRIB_ALIGN__;
+ /** dpd config file */
+ const struct firmware *dpd_data;
+ /** txpwr data file */
+ const struct firmware *txpwr_data;
+ /** Hotplug device */
+ struct device *hotplug_device;
+ /** STATUS variables */
+ MOAL_HARDWARE_STATUS hardware_status;
+ BOOLEAN fw_reload;
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ BOOLEAN surprise_removed;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** ECSA support */
+ t_u8 fw_ecsa_enable;
+ /** Getlog support */
+ t_u8 fw_getlog_enable;
+ /** Init wait queue token */
+ t_u16 init_wait_q_woken;
+ /** Init wait queue */
+ wait_queue_head_t init_wait_q __ATTRIB_ALIGN__;
+ /** Device suspend flag */
+ BOOLEAN is_suspended;
+#ifdef SDIO_SUSPEND_RESUME
+ /** suspend notify flag */
+ BOOLEAN suspend_notify_req;
+ /** hs_shutdown in process flag */
+ BOOLEAN shutdown_hs_in_process;
+#endif
+ /** Suspend wait queue token */
+ t_u16 suspend_wait_q_woken;
+ /** Suspend wait queue */
+ wait_queue_head_t suspend_wait_q __ATTRIB_ALIGN__;
+ /** Host Sleep activated flag */
+ t_u8 hs_activated;
+ /** Host Sleep activated event wait queue token */
+ t_u16 hs_activate_wait_q_woken;
+ /** Host Sleep activated event wait queue */
+ wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__;
+ /** auto_arp and ipv6 offload enable/disable flag */
+ t_u8 hs_auto_arp;
+ /** Card pointer */
+ t_void *card;
+ /** Rx pending in MLAN */
+ atomic_t rx_pending;
+ /** Tx packet pending count in mlan */
+ atomic_t tx_pending;
+ /** IOCTL pending count in mlan */
+ atomic_t ioctl_pending;
+ /** lock count */
+ atomic_t lock_count;
+ /** Malloc count */
+ atomic_t malloc_count;
+ /** vmalloc count */
+ atomic_t vmalloc_count;
+ /** mlan buffer alloc count */
+ atomic_t mbufalloc_count;
+#ifdef PCIE
+ /** Malloc consistent count */
+ atomic_t malloc_cons_count;
+#endif
+ /** hs skip count */
+ t_u32 hs_skip_count;
+ /** hs force count */
+ t_u32 hs_force_count;
+ /** suspend_fail flag */
+ BOOLEAN suspend_fail;
+#ifdef REASSOCIATION
+ /** Re-association thread */
+ moal_thread reassoc_thread;
+ /** Re-association timer set flag */
+ BOOLEAN is_reassoc_timer_set;
+ /** Re-association timer */
+ moal_drv_timer reassoc_timer __ATTRIB_ALIGN__;
+ /** */
+ struct semaphore reassoc_sem;
+ /** Bitmap for re-association on/off */
+ t_u8 reassoc_on;
+#endif /* REASSOCIATION */
+ /** Driver workqueue */
+ struct workqueue_struct *workqueue;
+ /** main work */
+ struct work_struct main_work;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /** host_mlme_priv */
+ moal_private *host_mlme_priv;
+ /** Host Mlme Work struct**/
+ struct work_struct host_mlme_work;
+#endif
+ /** Driver workqueue */
+ struct workqueue_struct *rx_workqueue;
+ /** main work */
+ struct work_struct rx_work;
+ /** Driver event workqueue */
+ struct workqueue_struct *evt_workqueue;
+ /** event work */
+ struct work_struct evt_work;
+ /** event spin lock */
+ spinlock_t evt_lock;
+ /** event queue */
+ struct list_head evt_queue;
+ /** tx workqueue */
+ struct workqueue_struct *tx_workqueue;
+ /** tx work */
+ struct work_struct tx_work;
+ /** remain on channel flag */
+ t_u8 remain_on_channel;
+ /** bss index for remain on channel */
+ t_u8 remain_bss_index;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ struct wiphy *wiphy;
+ /** Country code for regulatory domain */
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ /** band */
+ enum ieee80211_band band;
+ /** first scan done flag */
+ t_u8 first_scan_done;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ /** remain_on_channel timer set flag */
+ BOOLEAN is_remain_timer_set;
+ /** remani_on_channel_timer */
+ moal_drv_timer remain_timer __ATTRIB_ALIGN__;
+ /** ieee802_11_channel */
+ struct ieee80211_channel chan;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ /** channel type */
+ enum nl80211_channel_type channel_type;
+#endif
+ /** cookie */
+ t_u64 cookie;
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+ /** NoA duration */
+ t_u32 noa_duration;
+ /** NoA interval */
+ t_u32 noa_interval;
+ /** miracast mode */
+ t_u8 miracast_mode;
+ /** scan time in miracast mode */
+ t_u16 miracast_scan_time;
+ /** GO timer set flag */
+ BOOLEAN is_go_timer_set;
+ /** GO timer */
+ moal_drv_timer go_timer __ATTRIB_ALIGN__;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ /** cfg80211_suspend status */
+ t_u8 cfg80211_suspend;
+#endif
+#endif
+ /** FW debug flag */
+ t_u8 fw_dbg;
+ /** reg debug flag */
+ t_u8 reg_dbg;
+#ifdef SDIO
+#endif /* SDIO */
+ /** Netlink kernel socket */
+ struct sock *nl_sk;
+ /** Netlink kernel socket number */
+ t_u32 netlink_num;
+ /** w_stats wait queue token */
+ BOOLEAN meas_wait_q_woken;
+ /** w_stats wait queue */
+ wait_queue_head_t meas_wait_q __ATTRIB_ALIGN__;
+ /** Measurement start jiffes */
+ long meas_start_jiffies;
+ /** CAC checking period flag */
+ BOOLEAN cac_period;
+ /** CAC timer jiffes */
+ long cac_timer_jiffies;
+ /** User NOP Period in sec */
+ t_u16 usr_nop_period_sec;
+ /** BSS START command delay executing flag */
+ BOOLEAN delay_bss_start;
+ /** SSID,BSSID parameter of delay executing */
+ mlan_ssid_bssid delay_ssid_bssid;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ /* CAC channel info */
+ struct cfg80211_chan_def dfs_channel;
+ /* time set flag*/
+ BOOLEAN is_cac_timer_set;
+ /** cac_timer */
+ moal_drv_timer cac_timer __ATTRIB_ALIGN__;
+ /** cac bss index */
+ t_u8 cac_bss_index;
+#endif
+#endif
+#if defined(UAP_SUPPORT)
+ /** channel switch wait queue token */
+ BOOLEAN chsw_wait_q_woken;
+ /** channel switch wait queue */
+ wait_queue_head_t chsw_wait_q __ATTRIB_ALIGN__;
+#endif
+ /** cac period length, valid only when dfs testing is enabled */
+ long cac_period_jiffies;
+ /** cac restart*/
+ t_u8 cac_restart;
+ /** handle index - for multiple card supports */
+ t_u8 handle_idx;
+#if defined(USB)
+ /** Flag to indicate boot state */
+ t_u8 boot_state;
+#endif /* USB_NEW_FW_DNLD */
+#ifdef SDIO_MMC_DEBUG
+ /** cmd53 write state */
+ u8 cmd53w;
+ /** cmd53 read state */
+ u8 cmd53r;
+#endif
+#ifdef STA_SUPPORT
+ /** Scan pending on blocked flag */
+ t_u8 scan_pending_on_block;
+ /** Scan Private pointer */
+ moal_private *scan_priv;
+ /** Async scan semaphore */
+ struct semaphore async_sem;
+ /** scan channel gap */
+ t_u16 scan_chan_gap;
+#ifdef STA_CFG80211
+ /** CFG80211 scan request description */
+ struct cfg80211_scan_request *scan_request;
+#endif
+#endif
+ /** main state */
+ t_u8 main_state;
+ /** driver status */
+ t_u8 driver_status;
+ /** driver state */
+ t_u8 driver_state;
+ /** ioctl timeout */
+ t_u8 ioctl_timeout;
+ /** FW dump state */
+ t_u8 fw_dump;
+ /** event fw dump */
+ t_u8 event_fw_dump;
+ /** fw dump buffer total len */
+ t_u64 fw_dump_len;
+ /** FW dump full name */
+ t_u8 firmware_dump_file[128];
+#ifdef SDIO
+ /** cmd52 function */
+ t_u8 cmd52_func;
+ /** cmd52 register */
+ t_u8 cmd52_reg;
+ /** cmd52 value */
+ t_u8 cmd52_val;
+#endif
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ /** spinlock to stop_queue/wake_queue*/
+ spinlock_t queue_lock;
+#endif
+ /** Driver spin lock */
+ spinlock_t driver_lock;
+ /** Driver ioctl spin lock */
+ spinlock_t ioctl_lock;
+ /** lock for scan_request */
+ spinlock_t scan_req_lock;
+ /** Interface type: 1 byte, Card type: 1 byte */
+ t_u16 card_type;
+ /** card revsion */
+ t_u8 card_rev;
+ /** card info */
+ card_info *card_info;
+ /** Card specific driver version */
+ t_s8 driver_version[MLAN_MAX_VER_STR_LEN];
+ char *fwdump_fname;
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ struct wakeup_source ws;
+#else
+ struct wake_lock wake_lock;
+#endif
+#endif
+ t_u16 dfs_repeater_mode;
+ /* feature_control */
+ t_u32 feature_control;
+ struct notifier_block woal_notifier;
+ mlan_ds_misc_keep_alive keep_alive[MAX_KEEP_ALIVE_ID];
+ struct net_device napi_dev;
+ struct napi_struct napi_rx;
+ /* bus interface operations */
+ moal_if_ops ops;
+ /* module parameter data */
+ const struct firmware *param_data;
+ /* wrapped module parameters */
+ moal_mod_para params;
+ /* debug info */
+ mlan_debug_info debug_info;
+ /* block id in module param config file */
+ int blk_id;
+ /** time when FW is active, time is get from boot time, in Nanosecond */
+ t_u64 on_time;
+ /** tx time, in usecs */
+ t_u64 tx_time;
+ /** systime when tx start */
+ wifi_timeval tx_time_start;
+ /** systime when tx end */
+ wifi_timeval tx_time_end;
+ /** rx time, in usecs */
+ t_u64 rx_time;
+ /** scan time, in usecs */
+ t_u64 scan_time;
+ /** systime when scan cmd response return success */
+ wifi_timeval scan_time_start;
+ /** systime when scan event has no more event */
+ wifi_timeval scan_time_end;
+ /** seecond mac flag */
+ t_u8 second_mac;
+ /** moal handle for another mac */
+ void *pref_mac;
+ /** RF test mode status */
+ t_u8 rf_test_mode;
+ /** pointer to rf test mode data struct */
+ struct rf_test_mode_data *rf_data;
+ /** TP accounting parameters */
+ moal_tp_acnt_t tp_acnt;
+ BOOLEAN is_tp_acnt_timer_set;
+
+ t_u8 request_pm;
+};
+
+/**
+ * @brief set extended flag in bitmap
+ *
+ * @param dev A pointer to moal_handle structure
+ * @param idx extended flags id
+ * @return N/A
+ */
+static inline void moal_extflg_set(moal_handle *handle, enum ext_mod_params idx)
+{
+ t_u8 *ext_fbyte;
+ ext_fbyte = &handle->params.ext_flgs[idx / 8];
+ *ext_fbyte |= MBIT(idx % 8);
+}
+
+/**
+ * @brief clear extended flag in bitmap
+ *
+ * @param dev A pointer to moal_handle structure
+ * @param idx extended flags id
+ * @return N/A
+ */
+static inline void moal_extflg_clear(moal_handle *handle,
+ enum ext_mod_params idx)
+{
+ t_u8 *ext_fbyte;
+ ext_fbyte = &handle->params.ext_flgs[idx / 8];
+ *ext_fbyte &= ~MBIT(idx % 8);
+}
+
+/**
+ * @brief check value of extended flag in bitmap
+ *
+ * @param dev A pointer to moal_handle structure
+ * @param idx extended flags id
+ * @return value of extended flag
+ */
+static inline t_u8 moal_extflg_isset(moal_handle *handle,
+ enum ext_mod_params idx)
+{
+ t_u8 ext_fbyte;
+ ext_fbyte = handle->params.ext_flgs[idx / 8];
+ return (ext_fbyte & MBIT(idx % 8)) != 0;
+}
+
+/**
+ * @brief set trans_start for each TX queue.
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void woal_set_trans_start(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+ unsigned int i;
+ for (i = 0; i < dev->num_tx_queues; i++)
+ netdev_get_tx_queue(dev, i)->trans_start = jiffies;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
+ dev->trans_start = jiffies;
+#else
+ netif_trans_update(dev);
+#endif
+}
+
+/**
+ * @brief Start queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void woal_start_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
+ netif_start_queue(dev);
+#else
+ if (dev->reg_state == NETREG_REGISTERED)
+ netif_tx_wake_all_queues(dev);
+ else
+ netif_tx_start_all_queues(dev);
+#endif
+}
+
+/**
+ * @brief Stop queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void woal_stop_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ unsigned long flags;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_tx_stop_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ woal_set_trans_start(dev);
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+#endif
+}
+
+/**
+ * @brief wake queue
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return N/A
+ */
+static inline void woal_wake_queue(struct net_device *dev)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ unsigned long flags;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ spin_lock_irqsave(&priv->phandle->queue_lock, flags);
+ if (netif_queue_stopped(dev))
+ netif_tx_wake_all_queues(dev);
+ spin_unlock_irqrestore(&priv->phandle->queue_lock, flags);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+}
+
+/** Debug Macro definition*/
+#ifdef DEBUG_LEVEL1
+extern t_u32 drvdbg;
+
+#define LOG_CTRL(level) (0)
+
+#ifdef DEBUG_LEVEL2
+#define PRINTM_MINFO(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MINFO) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MWARN(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MWARN) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MENTRY(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MENTRY) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#else
+#define PRINTM_MINFO(level, msg...) \
+ do { \
+ } while (0)
+#define PRINTM_MWARN(level, msg...) \
+ do { \
+ } while (0)
+#define PRINTM_MENTRY(level, msg...) \
+ do { \
+ } while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define PRINTM_MFW_D(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MFW_D) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MCMD_D(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MCMD_D) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MDAT_D(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MDAT_D) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MIF_D(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MIF_D) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+
+#define PRINTM_MIOCTL(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MIOCTL) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MINTR(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MINTR) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MEVENT(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MEVENT) \
+ printk(msg); \
+ } while (0)
+#define PRINTM_MCMND(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MCMND) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MDATA(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MDATA) \
+ printk(KERN_DEBUG msg); \
+ } while (0)
+#define PRINTM_MERROR(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MERROR) \
+ printk(KERN_ERR msg); \
+ } while (0)
+#define PRINTM_MFATAL(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MFATAL) \
+ printk(KERN_ERR msg); \
+ } while (0)
+#define PRINTM_MMSG(level, msg...) \
+ do { \
+ woal_print(level, msg); \
+ if (drvdbg & MMSG) \
+ printk(KERN_ALERT msg); \
+ } while (0)
+
+static inline void woal_print(t_u32 level, char *fmt, ...)
+{
+}
+
+#define PRINTM(level, msg...) PRINTM_##level(level, msg)
+
+#else
+
+#define PRINTM(level, msg...) \
+ do { \
+ } while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Wait until a condition becomes true */
+#define MASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ PRINTM(MFATAL, "ASSERT: %s: %i\n", __func__, \
+ __LINE__); \
+ panic("Assert failed: Panic!"); \
+ } \
+ } while (0)
+
+/** Log entry point for debugging */
+#define ENTER() PRINTM(MENTRY, "Enter: %s\n", __func__)
+/** Log exit point for debugging */
+#define LEAVE() PRINTM(MENTRY, "Leave: %s\n", __func__)
+
+#ifdef DEBUG_LEVEL1
+#define DBG_DUMP_BUF_LEN 64
+#define MAX_DUMP_PER_LINE 16
+
+static inline void hexdump(t_u32 level, char *prompt, t_u8 *buf, int len)
+{
+ int i;
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+ char *ptr = dbgdumpbuf;
+
+ if (drvdbg & level)
+ printk(KERN_DEBUG "%s:\n", prompt);
+ for (i = 1; i <= len; i++) {
+ ptr += snprintf(ptr, 4, "%02x ", *buf);
+ buf++;
+ if (i % MAX_DUMP_PER_LINE == 0) {
+ *ptr = 0;
+ if (drvdbg & level)
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ ptr = dbgdumpbuf;
+ }
+ }
+ if (len % MAX_DUMP_PER_LINE) {
+ *ptr = 0;
+ if (drvdbg & level)
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+ }
+}
+
+#define DBG_HEXDUMP_MERROR(x, y, z) \
+ do { \
+ if ((drvdbg & MERROR) || LOG_CTRL(MERROR)) \
+ hexdump(MERROR, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP_MCMD_D(x, y, z) \
+ do { \
+ if ((drvdbg & MCMD_D) || LOG_CTRL(MCMD_D)) \
+ hexdump(MCMD_D, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP_MDAT_D(x, y, z) \
+ do { \
+ if ((drvdbg & MDAT_D) || LOG_CTRL(MDAT_D)) \
+ hexdump(MDAT_D, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP_MIF_D(x, y, z) \
+ do { \
+ if ((drvdbg & MIF_D) || LOG_CTRL(MIF_D)) \
+ hexdump(MIF_D, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP_MEVT_D(x, y, z) \
+ do { \
+ if ((drvdbg & MEVT_D) || LOG_CTRL(MEVT_D)) \
+ hexdump(MEVT_D, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP_MFW_D(x, y, z) \
+ do { \
+ if ((drvdbg & MFW_D) || LOG_CTRL(MFW_D)) \
+ hexdump(MFW_D, x, y, z); \
+ } while (0)
+#define DBG_HEXDUMP(level, x, y, z) DBG_HEXDUMP_##level(x, y, z)
+
+#else
+/** Do nothing since debugging is not turned on */
+#define DBG_HEXDUMP(level, x, y, z) \
+ do { \
+ } while (0)
+#endif
+
+#ifdef DEBUG_LEVEL2
+#define HEXDUMP(x, y, z) \
+ do { \
+ if ((drvdbg & MINFO) || LOG_CTRL(MINFO)) \
+ hexdump(MINFO, x, y, z); \
+ } while (0)
+#else
+/** Do nothing since debugging is not turned on */
+#define HEXDUMP(x, y, z) \
+ do { \
+ } while (0)
+#endif
+
+#ifdef BIG_ENDIAN_SUPPORT
+/** Convert from 16 bit little endian format to CPU format */
+#define woal_le16_to_cpu(x) le16_to_cpu(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define woal_le32_to_cpu(x) le32_to_cpu(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define woal_le64_to_cpu(x) le64_to_cpu(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define woal_cpu_to_le16(x) cpu_to_le16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define woal_cpu_to_le32(x) cpu_to_le32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define woal_cpu_to_le64(x) cpu_to_le64(x)
+#else
+/** Do nothing */
+#define woal_le16_to_cpu(x) x
+/** Do nothing */
+#define woal_le32_to_cpu(x) x
+/** Do nothing */
+#define woal_le64_to_cpu(x) x
+/** Do nothing */
+#define woal_cpu_to_le16(x) x
+/** Do nothing */
+#define woal_cpu_to_le32(x) x
+/** Do nothing */
+#define woal_cpu_to_le64(x) x
+#endif
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS role
+ *
+ * @param handle A pointer to moal_handle
+ * @param bss_role BSS role or MLAN_BSS_ROLE_ANY
+ *
+ * @return Pointer to moal_private
+ */
+static inline moal_private *woal_get_priv(moal_handle *handle,
+ mlan_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (bss_role == MLAN_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(handle->priv[i]) == bss_role)
+ return handle->priv[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief This function returns first available priv
+ * based on the BSS type
+ *
+ * @param handle A pointer to moal_handle
+ * @param bss_type BSS type or MLAN_BSS_TYPE_ANY
+ *
+ * @return Pointer to moal_private
+ */
+static inline moal_private *woal_get_priv_bss_type(moal_handle *handle,
+ mlan_bss_type bss_type)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (bss_type == MLAN_BSS_TYPE_ANY ||
+ handle->priv[i]->bss_type == bss_type)
+ return handle->priv[i];
+ }
+ }
+ return NULL;
+}
+
+static inline moal_private *woal_get_vir_priv_bss_type(moal_handle *handle,
+ mlan_bss_type bss_type)
+{
+ int i;
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (handle->priv[i]->bss_type == bss_type &&
+ handle->priv[i]->bss_virtual)
+ return handle->priv[i];
+ }
+ }
+ return NULL;
+}
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#endif
+
+static inline void woal_get_monotonic_time(wifi_timeval *tv)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+ struct timespec64 ts;
+#else
+ struct timespec ts;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+ ktime_get_raw_ts64(&ts);
+#else
+ getrawmonotonic(&ts);
+#endif
+ if (tv) {
+ tv->time_sec = (t_u32)ts.tv_sec;
+ tv->time_usec = (t_u32)ts.tv_nsec / 1000;
+ }
+}
+
+/* CAC Measure report default time 60 seconds */
+#define MEAS_REPORT_TIME (60 * HZ)
+
+/** Max line length allowed in init config file */
+#define MAX_LINE_LEN 256
+/** Max MAC address string length allowed */
+#define MAX_MAC_ADDR_LEN 18
+/** Max register type/offset/value etc. parameter length allowed */
+#define MAX_PARAM_LEN 12
+
+/** HostCmd_CMD_CFG_DATA for CAL data */
+#define HostCmd_CMD_CFG_DATA 0x008f
+/** HostCmd action set */
+#define HostCmd_ACT_GEN_SET 0x0001
+/** HostCmd CAL data header length */
+#define CFG_DATA_HEADER_LEN 6
+
+typedef struct _HostCmd_DS_GEN {
+ t_u16 command;
+ t_u16 size;
+ t_u16 seq_num;
+ t_u16 result;
+} HostCmd_DS_GEN;
+
+typedef struct _HostCmd_DS_802_11_CFG_DATA {
+ /** Action */
+ t_u16 action;
+ /** Type */
+ t_u16 type;
+ /** Data length */
+ t_u16 data_len;
+ /** Data */
+ t_u8 data[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA;
+
+/** combo scan header */
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+/** combo scan header size */
+#define WEXT_CSCAN_HEADER_SIZE 12
+/** combo scan ssid section */
+#define WEXT_CSCAN_SSID_SECTION 'S'
+/** commbo scan channel section */
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+/** commbo scan passive dwell section */
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+/** commbo scan home dwell section */
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+/** BGSCAN RSSI section */
+#define WEXT_BGSCAN_RSSI_SECTION 'R'
+/** BGSCAN SCAN INTERVAL SECTION */
+#define WEXT_BGSCAN_INTERVAL_SECTION 'T'
+/** BGSCAN REPEAT SECTION */
+#define WEXT_BGSCAN_REPEAT_SECTION 'E'
+/** Min BGSCAN interval 30 second */
+#define MIN_BGSCAN_INTERVAL 30000
+/** default repeat count */
+#define DEF_REPEAT_COUNT 6
+
+/** default rssi low threshold */
+#define DEFAULT_RSSI_LOW_THRESHOLD 70
+/** RSSI HYSTERSIS */
+#define RSSI_HYSTERESIS 6
+/** lowest rssi threshold */
+#define LOWEST_RSSI_THRESHOLD 82
+/** delta rssi */
+#define DELTA_RSSI 10
+
+/** NL80211 scan configuration header */
+#define NL80211_SCANCFG_HEADER "SCAN-CFG "
+/** NL80211 scan configuration header length */
+#define NL80211_SCANCFG_HEADER_SIZE 9
+/** NL80211 scan configuration active scan section */
+#define NL80211_SCANCFG_ACTV_DWELL_SECTION 'A'
+/** NL80211 scan configuration passive scan section */
+#define NL80211_SCANCFG_PASV_DWELL_SECTION 'P'
+/** NL80211 scan configuration specific scan section */
+#define NL80211_SCANCFG_SPCF_DWELL_SECTION 'S'
+
+/** band AUTO */
+#define WIFI_FREQUENCY_BAND_AUTO 0
+/** band 5G */
+#define WIFI_FREQUENCY_BAND_5GHZ 1
+/** band 2G */
+#define WIFI_FREQUENCY_BAND_2GHZ 2
+/** All band */
+#define WIFI_FREQUENCY_ALL_BAND 3
+
+/** Rx filter: IPV4 multicast */
+#define RX_FILTER_IPV4_MULTICAST 1
+/** Rx filter: broadcast */
+#define RX_FILTER_BROADCAST 2
+/** Rx filter: unicast */
+#define RX_FILTER_UNICAST 4
+/** Rx filter: IPV6 multicast */
+#define RX_FILTER_IPV6_MULTICAST 8
+
+/** Convert ASCII string to hex value */
+int woal_ascii2hex(t_u8 *d, char *s, t_u32 dlen);
+/** parse ie */
+const t_u8 *woal_parse_ie_tlv(const t_u8 *ie, int len, t_u8 id);
+/** parse extension ie */
+const t_u8 *woal_parse_ext_ie_tlv(const t_u8 *ie, int len, t_u8 ext_id);
+/** Convert mac address from string to t_u8 buffer */
+void woal_mac2u8(t_u8 *mac_addr, char *buf);
+/** Extract token from string */
+char *woal_strsep(char **s, char delim, char esc);
+/** Return int value of a given ASCII string */
+mlan_status woal_atoi(int *data, char *a);
+/** Return hex value of a given ASCII string */
+int woal_atox(char *a);
+/** Allocate buffer */
+pmlan_buffer woal_alloc_mlan_buffer(moal_handle *handle, int size);
+/** Allocate IOCTL request buffer */
+pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size);
+/** Free buffer */
+void woal_free_mlan_buffer(moal_handle *handle, pmlan_buffer pmbuf);
+/** Get private structure of a BSS by index */
+moal_private *woal_bss_index_to_priv(moal_handle *handle, t_u8 bss_index);
+/* Functions in init module */
+/** init module parameters */
+mlan_status woal_init_module_param(moal_handle *handle);
+/** free module parameters */
+void woal_free_module_param(moal_handle *handle);
+/** init module parameters from device tree */
+void woal_init_from_dev_tree(void);
+/** initializes software */
+mlan_status woal_init_sw(moal_handle *handle);
+/** update the default firmware name */
+void woal_update_firmware_name(moal_handle *handle);
+/** cancel all works in the queue */
+void woal_terminate_workqueue(moal_handle *handle);
+/** initializes firmware */
+mlan_status woal_init_fw(moal_handle *handle);
+/** frees the structure of moal_handle */
+void woal_free_moal_handle(moal_handle *handle);
+/** shutdown fw */
+mlan_status woal_shutdown_fw(moal_private *priv, t_u8 wait_option);
+/* Functions in interface module */
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+static inline void wakeup_source_init(struct wakeup_source *ws,
+ const char *name)
+{
+ ENTER();
+
+ if (ws) {
+ memset(ws, 0, sizeof(*ws));
+ ws->name = name;
+ }
+ wakeup_source_add(ws);
+
+ LEAVE();
+}
+
+static inline void wakeup_source_trash(struct wakeup_source *ws)
+{
+ ENTER();
+
+ if (!ws) {
+ PRINTM(MERROR, "ws is null!\n");
+ return;
+ }
+ wakeup_source_remove(ws);
+ __pm_relax(ws);
+
+ LEAVE();
+}
+#endif
+#endif
+/** Add card */
+moal_handle *woal_add_card(void *card, struct device *dev, moal_if_ops *if_ops,
+ t_u16 card_type);
+/** Remove card */
+mlan_status woal_remove_card(void *card);
+/** broadcast event */
+mlan_status woal_broadcast_event(moal_private *priv, t_u8 *payload, t_u32 len);
+#ifdef CONFIG_PROC_FS
+/** switch driver mode */
+mlan_status woal_switch_drv_mode(moal_handle *handle, t_u32 mode);
+#endif
+
+/** check if any interface is up */
+t_u8 woal_is_any_interface_active(moal_handle *handle);
+/** Get version */
+void woal_get_version(moal_handle *handle, char *version, int maxlen);
+/** Get Driver Version */
+int woal_get_driver_version(moal_private *priv, struct ifreq *req);
+/** Get extended driver version */
+int woal_get_driver_verext(moal_private *priv, struct ifreq *ireq);
+/** check driver status */
+t_u8 woal_check_driver_status(moal_handle *handle);
+/** Mgmt frame forward registration */
+int woal_reg_rx_mgmt_ind(moal_private *priv, t_u16 action,
+ t_u32 *pmgmt_subtype_mask, t_u8 wait_option);
+#ifdef DEBUG_LEVEL1
+/** Set driver debug bit masks */
+int woal_set_drvdbg(moal_private *priv, t_u32 drvdbg);
+#endif
+
+mlan_status woal_set_get_tx_bf_cap(moal_private *priv, t_u16 action,
+ t_u32 *tx_bf_cap);
+/** Set/Get TX beamforming configurations */
+mlan_status woal_set_get_tx_bf_cfg(moal_private *priv, t_u16 action,
+ mlan_ds_11n_tx_bf_cfg *bf_cfg);
+/** Request MAC address setting */
+mlan_status woal_request_set_mac_address(moal_private *priv, t_u8 wait_option);
+/** Request multicast list setting */
+void woal_request_set_multicast_list(moal_private *priv,
+ struct net_device *dev);
+/** Request IOCTL action */
+mlan_status woal_request_ioctl(moal_private *priv, mlan_ioctl_req *req,
+ t_u8 wait_option);
+/** Set/Get generic element */
+mlan_status woal_set_get_gen_ie(moal_private *priv, t_u32 action, t_u8 *ie,
+ int *ie_len, t_u8 wait_option);
+#ifdef CONFIG_PROC_FS
+mlan_status woal_request_soft_reset(moal_handle *handle);
+#endif
+void woal_request_fw_reload(moal_handle *phandle, t_u8 mode);
+
+/** Get debug information */
+mlan_status woal_get_debug_info(moal_private *priv, t_u8 wait_option,
+ mlan_debug_info *debug_info);
+/** Set debug information */
+mlan_status woal_set_debug_info(moal_private *priv, t_u8 wait_option,
+ mlan_debug_info *debug_info);
+/** Disconnect */
+mlan_status woal_disconnect(moal_private *priv, t_u8 wait_option, t_u8 *mac,
+ t_u16 reason_code);
+/** associate */
+mlan_status woal_bss_start(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid);
+/** Request firmware information */
+mlan_status woal_request_get_fw_info(moal_private *priv, t_u8 wait_option,
+ mlan_fw_info *fw_info);
+/** Get channel of active intf */
+mlan_status woal_get_active_intf_channel(moal_private *priv,
+ chan_band_info *channel);
+#ifdef STA_SUPPORT
+/** Request Exented Capability information */
+int woal_request_extcap(moal_private *priv, t_u8 *buf, t_u8 len);
+#endif
+mlan_status woal_set_get_dtim_period(moal_private *priv, t_u32 action,
+ t_u8 wait_option, t_u8 *value);
+/** Set/get Host Sleep parameters */
+mlan_status woal_set_get_hs_params(moal_private *priv, t_u16 action,
+ t_u8 wait_option, mlan_ds_hs_cfg *hscfg);
+/** Cancel Host Sleep configuration */
+mlan_status woal_cancel_hs(moal_private *priv, t_u8 wait_option);
+/** Enable Host Sleep configuration */
+int woal_enable_hs(moal_private *priv);
+/** hs active timeout 2 second */
+#define HS_ACTIVE_TIMEOUT (2 * HZ)
+/** Get wakeup reason */
+mlan_status woal_get_wakeup_reason(moal_private *priv,
+ mlan_ds_hs_wakeup_reason *wakeup_reason);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+void woal_create_dump_dir(moal_handle *phandle, char *dir_buf, int buf_size);
+#endif
+mlan_status woal_save_dump_info_to_file(char *dir_name, char *file_name,
+ t_u8 *buf, t_u32 buf_len);
+void woal_dump_drv_info(moal_handle *phandle, t_u8 *dir_name);
+
+#define FW_DUMP_TYPE_ENDED 0x002
+#define FW_DUMP_TYPE_MEM_ITCM 0x004
+#define FW_DUMP_TYPE_MEM_DTCM 0x005
+#define FW_DUMP_TYPE_MEM_SQRAM 0x006
+#define FW_DUMP_TYPE_MEM_IRAM 0x007
+#define FW_DUMP_TYPE_REG_MAC 0x009
+#define FW_DUMP_TYPE_REG_CIU 0x00E
+#define FW_DUMP_TYPE_REG_APU 0x00F
+#define FW_DUMP_TYPE_REG_ICU 0x014
+#ifdef SDIO_MMC
+void woal_dump_firmware_info(moal_handle *phandle);
+void woal_dump_firmware_info_v2(moal_handle *phandle);
+void woal_dump_firmware_info_v3(moal_handle *phandle);
+#endif /* SDIO_MMC */
+/* Store the FW dumps received from events in a file */
+void woal_store_firmware_dump(moal_handle *phandle, pmlan_event pmevent);
+
+#if defined(PCIE)
+void woal_store_ssu_dump(moal_handle *phandle, pmlan_event pmevent);
+#endif /* SSU_SUPPORT */
+
+/** save hostcmd response to file */
+t_void woal_save_host_cmdresp(moal_handle *phandle, mlan_cmdresp_event *pevent);
+int woal_pre_warmreset(moal_private *priv);
+int woal_warmreset(moal_private *priv);
+
+/** get deep sleep */
+int woal_get_deep_sleep(moal_private *priv, t_u32 *data);
+/** set deep sleep */
+int woal_set_deep_sleep(moal_private *priv, t_u8 wait_option,
+ BOOLEAN bdeep_sleep, t_u16 idletime);
+/** process hang */
+void woal_process_hang(moal_handle *handle);
+/** Get BSS information */
+mlan_status woal_get_bss_info(moal_private *priv, t_u8 wait_option,
+ mlan_bss_info *bss_info);
+void woal_process_ioctl_resp(moal_private *priv, mlan_ioctl_req *req);
+char *region_code_2_string(t_u8 region_code);
+t_bool woal_is_etsi_country(t_u8 *country_code);
+t_u8 woal_is_valid_alpha2(char *alpha2);
+#ifdef STA_SUPPORT
+void woal_send_disconnect_to_system(moal_private *priv, t_u16 reason_code);
+void woal_send_mic_error_event(moal_private *priv, t_u32 event);
+void woal_ioctl_get_bss_resp(moal_private *priv, mlan_ds_bss *bss);
+void woal_ioctl_get_info_resp(moal_private *priv, mlan_ds_get_info *info);
+mlan_status woal_get_assoc_rsp(moal_private *priv,
+ mlan_ds_misc_assoc_rsp *assoc_rsp,
+ t_u8 wait_option);
+/** Get signal information */
+mlan_status woal_get_signal_info(moal_private *priv, t_u8 wait_option,
+ mlan_ds_get_signal *signal);
+/** Get mode */
+t_u32 woal_get_mode(moal_private *priv, t_u8 wait_option);
+mlan_status woal_get_sta_channel(moal_private *priv, t_u8 wait_option,
+ chan_band_info *channel);
+#ifdef STA_WEXT
+/** Get data rates */
+mlan_status woal_get_data_rates(moal_private *priv, t_u8 wait_option,
+ pmoal_802_11_rates m_rates);
+void woal_send_iwevcustom_event(moal_private *priv, char *str);
+/** Get channel list */
+mlan_status woal_get_channel_list(moal_private *priv, t_u8 wait_option,
+ mlan_chan_list *chanlist);
+mlan_status woal_11d_check_ap_channel(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid);
+#endif
+/** Set/Get retry count */
+mlan_status woal_set_get_retry(moal_private *priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get RTS threshold */
+mlan_status woal_set_get_rts(moal_private *priv, t_u32 action, t_u8 wait_option,
+ int *value);
+/** Set/Get fragment threshold */
+mlan_status woal_set_get_frag(moal_private *priv, t_u32 action,
+ t_u8 wait_option, int *value);
+/** Set/Get TX power */
+mlan_status woal_set_get_tx_power(moal_private *priv, t_u32 action,
+ mlan_power_cfg_t *pwr);
+/** Set/Get power IEEE management */
+mlan_status woal_set_get_power_mgmt(moal_private *priv, t_u32 action,
+ int *disabled, int type, t_u8 wait_option);
+/** Get data rate */
+mlan_status woal_set_get_data_rate(moal_private *priv, t_u8 action,
+ mlan_rate_cfg_t *datarate);
+/** Request a network scan */
+mlan_status woal_request_scan(moal_private *priv, t_u8 wait_option,
+ mlan_802_11_ssid *req_ssid);
+/** Set radio on/off */
+int woal_set_radio(moal_private *priv, t_u8 option);
+/** Set region code */
+mlan_status woal_set_region_code(moal_private *priv, char *region);
+/** Set authentication mode */
+mlan_status woal_set_auth_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 auth_mode);
+/** Set encryption mode */
+mlan_status woal_set_encrypt_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 encrypt_mode);
+/** Enable wep key */
+mlan_status woal_enable_wep_key(moal_private *priv, t_u8 wait_option);
+/** Set WPA enable */
+mlan_status woal_set_wpa_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 enable);
+/** cancel scan command */
+mlan_status woal_cancel_scan(moal_private *priv, t_u8 wait_option);
+/** Find best network to connect */
+mlan_status woal_find_best_network(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid);
+/** Set Ad-Hoc channel */
+mlan_status woal_change_adhoc_chan(moal_private *priv, int channel,
+ t_u8 wait_option);
+
+/** Get scan table */
+mlan_status woal_get_scan_table(moal_private *priv, t_u8 wait_option,
+ mlan_scan_resp *scanresp);
+/** Get authentication mode */
+mlan_status woal_get_auth_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 *auth_mode);
+/** Get encryption mode */
+mlan_status woal_get_encrypt_mode(moal_private *priv, t_u8 wait_option,
+ t_u32 *encrypt_mode);
+/** Get WPA state */
+mlan_status woal_get_wpa_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 *enable);
+#endif /**STA_SUPPORT */
+
+mlan_status woal_set_11d(moal_private *priv, t_u8 wait_option, t_u8 enable);
+
+mlan_status woal_process_rf_test_mode(moal_handle *handle, t_u32 mode);
+mlan_status woal_process_rf_test_mode_cmd(moal_handle *handle, t_u32 cmd,
+ const char *buffer, size_t len,
+ t_u32 action, t_u32 val);
+#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
+/** Get statistics information */
+mlan_status woal_get_stats_info(moal_private *priv, t_u8 wait_option,
+ pmlan_ds_get_stats stats);
+#endif /**STA_SUPPORT||UAP_SUPPORT*/
+
+mlan_status woal_set_wapi_enable(moal_private *priv, t_u8 wait_option,
+ t_u32 enable);
+
+/** Initialize priv */
+void woal_init_priv(moal_private *priv, t_u8 wait_option);
+/** Reset interface(s) */
+int woal_reset_intf(moal_private *priv, t_u8 wait_option, int all_intf);
+#define TLV_TYPE_MGMT_IE (0x169)
+#define MGMT_MASK_ASSOC_REQ 0x01
+#define MGMT_MASK_REASSOC_REQ 0x04
+#define MGMT_MASK_ASSOC_RESP 0x02
+#define MGMT_MASK_REASSOC_RESP 0x08
+#define MGMT_MASK_PROBE_REQ 0x10
+#define MGMT_MASK_PROBE_RESP 0x20
+#define MGMT_MASK_BEACON 0x100
+#define MGMT_MASK_ASSOC_RESP_QOS_MAP 0x4000
+#define MGMT_MASK_BEACON_WPS_P2P 0x8000
+#define MLAN_CUSTOM_IE_DELETE_MASK 0x0
+/** common ioctl for uap, station */
+int woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req);
+#ifdef UAP_SUPPORT
+int woal_priv_get_nonglobal_operclass_by_bw_channel(moal_private *priv,
+ t_u8 bandwidth,
+ t_u8 channel,
+ t_u8 *oper_class);
+#endif
+int woal_send_host_packet(struct net_device *dev, struct ifreq *req);
+/** Private command ID to pass mgmt frame */
+#define WOAL_MGMT_FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12)
+
+int woal_get_bss_type(struct net_device *dev, struct ifreq *req);
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_host_command(moal_private *priv, struct iwreq *wrq);
+#endif
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+mlan_status woal_bss_role_cfg(moal_private *priv, t_u8 action, t_u8 wait_option,
+ t_u8 *bss_role);
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+void woal_go_timer_func(void *context);
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_set_get_bss_role(moal_private *priv, struct iwreq *wrq);
+#endif
+#endif
+#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT)
+/** hostcmd ioctl for uap, wifidirect */
+int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req);
+#endif
+
+mlan_status woal_set_remain_channel_ioctl(moal_private *priv, t_u8 wait_option,
+ pmlan_ds_remain_chan pchan);
+void woal_remain_timer_func(void *context);
+#ifdef WIFI_DIRECT_SUPPORT
+mlan_status woal_wifi_direct_mode_cfg(moal_private *priv, t_u16 action,
+ t_u16 *mode);
+mlan_status woal_p2p_config(moal_private *priv, t_u32 action,
+ mlan_ds_wifi_direct_config *p2p_config);
+#endif /* WIFI_DIRECT_SUPPORT */
+
+int woal_11h_cancel_chan_report_ioctl(moal_private *priv, t_u8 wait_option);
+
+#ifdef CONFIG_PROC_FS
+/** Initialize /proc/mwlan */
+mlan_status woal_root_proc_init(void);
+/** Remove /proc/mwlan */
+void woal_root_proc_remove(void);
+/** Initialize proc fs */
+void woal_proc_init(moal_handle *handle);
+/** Clean up proc fs */
+void woal_proc_exit(moal_handle *handle);
+/** Create proc entry */
+void woal_create_proc_entry(moal_private *priv);
+/** Remove proc entry */
+void woal_proc_remove(moal_private *priv);
+/** string to number */
+int woal_string_to_number(char *s);
+#endif
+
+/** Create debug proc fs */
+void woal_debug_entry(moal_private *priv);
+/** Remove debug proc fs */
+void woal_debug_remove(moal_private *priv);
+
+/** check pm info */
+mlan_status woal_get_pm_info(moal_private *priv, mlan_ds_ps_info *pm_info);
+/** get mlan debug info */
+void woal_mlan_debug_info(moal_private *priv);
+
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+/** Enter USB Suspend */
+int woal_enter_usb_suspend(moal_handle *handle);
+/** Exit from USB Suspend */
+int woal_exit_usb_suspend(moal_handle *handle);
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+
+#ifdef REASSOCIATION
+int woal_reassociation_thread(void *data);
+void woal_reassoc_timer_func(void *context);
+#endif /* REASSOCIATION */
+
+t_void woal_main_work_queue(struct work_struct *work);
+t_void woal_rx_work_queue(struct work_struct *work);
+t_void woal_evt_work_queue(struct work_struct *work);
+
+netdev_tx_t woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+#ifdef STA_SUPPORT
+mlan_status woal_init_sta_dev(struct net_device *dev, moal_private *priv);
+#endif
+#ifdef UAP_SUPPORT
+mlan_status woal_init_uap_dev(struct net_device *dev, moal_private *priv);
+#endif
+mlan_status woal_update_drv_tbl(moal_handle *handle, int drv_mode_local);
+moal_private *woal_add_interface(moal_handle *handle, t_u8 bss_num,
+ t_u8 bss_type);
+void woal_remove_interface(moal_handle *handle, t_u8 bss_index);
+void woal_set_multicast_list(struct net_device *dev);
+mlan_status woal_request_fw(moal_handle *handle);
+int woal_11h_channel_check_ioctl(moal_private *priv, t_u8 wait_option);
+void woal_cancel_cac_block(moal_private *priv);
+void woal_moal_debug_info(moal_private *priv, moal_handle *handle, u8 flag);
+
+#ifdef STA_SUPPORT
+mlan_status woal_get_powermode(moal_private *priv, int *powermode);
+mlan_status woal_set_scan_type(moal_private *priv, t_u32 scan_type);
+mlan_status woal_get_scan_config(moal_private *priv, mlan_scan_cfg *scan_cfg);
+mlan_status woal_enable_ext_scan(moal_private *priv, t_u8 enable);
+mlan_status woal_set_powermode(moal_private *priv, char *powermode);
+int woal_find_essid(moal_private *priv, mlan_ssid_bssid *ssid_bssid,
+ t_u8 wait_option);
+mlan_status woal_find_bssid(moal_private *priv, mlan_802_11_mac_addr bssid);
+mlan_status woal_request_userscan(moal_private *priv, t_u8 wait_option,
+ wlan_user_scan_cfg *scan_cfg);
+mlan_status woal_do_scan(moal_private *priv, wlan_user_scan_cfg *scan_cfg);
+int woal_set_combo_scan(moal_private *priv, char *buf, int length);
+mlan_status woal_set_scan_time(moal_private *priv, t_u16 active_scan_time,
+ t_u16 passive_scan_time,
+ t_u16 specific_scan_time);
+mlan_status woal_get_band(moal_private *priv, int *band);
+mlan_status woal_set_band(moal_private *priv, char *pband);
+mlan_status woal_add_rxfilter(moal_private *priv, char *rxfilter);
+mlan_status woal_remove_rxfilter(moal_private *priv, char *rxfilter);
+mlan_status woal_priv_qos_cfg(moal_private *priv, t_u32 action, char *qos_cfg);
+mlan_status woal_set_sleeppd(moal_private *priv, char *psleeppd);
+int woal_set_scan_cfg(moal_private *priv, char *buf, int length);
+void woal_update_dscp_mapping(moal_private *priv);
+
+/* EVENT: BCN_RSSI_LOW */
+#define EVENT_BCN_RSSI_LOW 0x0001
+/* EVENT: PRE_BCN_LOST */
+#define EVENT_PRE_BCN_LOST 0x0002
+mlan_status woal_set_rssi_low_threshold(moal_private *priv, char *rssi,
+ t_u8 wait_option);
+mlan_status woal_set_rssi_threshold(moal_private *priv, t_u32 event_id,
+ t_u8 wait_option);
+/* EVENT: BG_SCAN_REPORT */
+#define EVENT_BG_SCAN_REPORT 0x0004
+mlan_status woal_set_bg_scan(moal_private *priv, char *buf, int length);
+mlan_status woal_stop_bg_scan(moal_private *priv, t_u8 wait_option);
+void woal_reconfig_bgscan(moal_handle *handle);
+#ifdef STA_CFG80211
+void woal_config_bgscan_and_rssi(moal_private *priv, t_u8 set_rssi);
+void woal_start_roaming(moal_private *priv);
+#endif
+mlan_status woal_request_bgscan(moal_private *priv, t_u8 wait_option,
+ wlan_bgscan_cfg *scan_cfg);
+#endif
+#ifdef STA_CFG80211
+void woal_save_conn_params(moal_private *priv,
+ struct cfg80211_connect_params *sme);
+void woal_clear_conn_params(moal_private *priv);
+#endif
+
+void woal_flush_tcp_sess_queue(moal_private *priv);
+void wlan_scan_create_brief_table_entry(t_u8 **ppbuffer,
+ BSSDescriptor_t *pbss_desc);
+int wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer,
+ int *pspace_left);
+BOOLEAN woal_ssid_valid(mlan_802_11_ssid *pssid);
+int woal_is_connected(moal_private *priv, mlan_ssid_bssid *ssid_bssid);
+int woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
+ t_u8 wait_option);
+void woal_flush_tx_stat_queue(moal_private *priv);
+struct tx_status_info *woal_get_tx_info(moal_private *priv, t_u8 tx_seq_num);
+void woal_remove_tx_info(moal_private *priv, t_u8 tx_seq_num);
+
+mlan_status woal_request_country_power_table(moal_private *priv, char *region);
+#ifdef RX_PACKET_COALESCE
+mlan_status woal_rx_pkt_coalesce_cfg(moal_private *priv, t_u16 *enable,
+ t_u8 wait_option, t_u8 action);
+#endif
+mlan_status woal_set_low_pwr_mode(moal_handle *handle, t_u8 wait_option);
+int woal_hexval(char chr);
+mlan_status woal_pmic_configure(moal_handle *handle, t_u8 wait_option);
+mlan_status woal_set_user_antcfg(moal_handle *handle, t_u8 wait_option);
+void woal_hist_data_reset(moal_private *priv);
+void woal_hist_do_reset(moal_private *priv, void *data);
+void woal_hist_reset_table(moal_private *priv, t_u8 antenna);
+void woal_hist_data_add(moal_private *priv, t_u16 rx_rate, t_s8 snr, t_s8 nflr,
+ t_u8 antenna);
+mlan_status woal_set_hotspotcfg(moal_private *priv, t_u8 wait_option,
+ t_u32 hotspotcfg);
+mlan_status woal_set_get_wowlan_config(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ mlan_ds_misc_mef_flt_cfg *mefcfg);
+mlan_status woal_set_auto_arp_ext(moal_handle *handle, t_u8 enable);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+mlan_status woal_do_flr(moal_handle *handle, bool prepare);
+#endif
+mlan_status woal_delba_all(moal_private *priv, t_u8 wait_option);
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+int woal_mkeep_alive_vendor_event(moal_private *priv,
+ pmlan_ds_misc_keep_alive mkeep_alive);
+#endif
+#endif
+int woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id,
+ t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
+ t_u8 *dst_mac, t_u32 period_msec,
+ t_u32 retry_interval, t_u8 retry_cnt);
+int woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset,
+ t_u8 *ip_pkt, t_u8 *pkt_len);
+int woal_priv_save_cloud_keep_alive_params(
+ moal_private *priv, t_u8 mkeep_alive_id, t_u8 enable, t_u16 ether_type,
+ t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac, t_u8 *dst_mac,
+ t_u32 period_msec, t_u32 retry_interval, t_u8 retry_cnt);
+mlan_status woal_init_aggr_ctrl(moal_handle *handle, t_u8 wait_option);
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+mlan_status woal_set_rekey_data(moal_private *priv,
+ mlan_ds_misc_gtk_rekey_data *gtk_rekey,
+ t_u8 action, t_u8 wait_option);
+#endif
+#endif
+
+mlan_status woal_vdll_req_fw(moal_handle *handle);
+
+void woal_ioctl_get_misc_conf(moal_private *priv, mlan_ds_misc_cfg *info);
+t_u8 woal_get_second_channel_offset(int chan);
+#endif /* _MOAL_MAIN_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.c
new file mode 100644
index 000000000000..ee820768d5b0
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.c
@@ -0,0 +1,2447 @@
+/** @file moal_pcie.c
+ *
+ * @brief This file contains PCIE IF (interface) module
+ * related functions.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/01/2012: initial version
+********************************************************/
+
+#include <linux/firmware.h>
+
+#include "moal_pcie.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+#include <linux/pm_qos.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70)
+#ifdef IMX_SUPPORT
+#include <linux/busfreq-imx.h>
+#endif
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+#define DRV_NAME "NXP mdriver PCIe"
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 6, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+static struct pm_qos_request woal_pcie_pm_qos_req;
+#endif
+#endif
+
+/* PCIE resume handler */
+static int woal_pcie_resume(struct pci_dev *pdev);
+static void woal_pcie_reg_dbg(moal_handle *phandle);
+static void woal_pcie_unregister_dev(moal_handle *handle);
+static void woal_pcie_cleanup(pcie_service_card *card);
+static mlan_status woal_pcie_init(pcie_service_card *card);
+extern int pcie_int_mode;
+extern struct semaphore AddRemoveCardSem;
+extern moal_handle **m_handle;
+
+/** WLAN IDs */
+static const struct pci_device_id wlan_ids[] = {
+#ifdef PCIE8897
+ {
+ PCIE_VENDOR_ID_NXP,
+ PCIE_DEVICE_ID_NXP_88W8897P,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+#endif
+#ifdef PCIE8997
+ {
+ PCIE_VENDOR_ID_NXP,
+ PCIE_DEVICE_ID_NXP_88W8997P,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+ {
+ PCIE_VENDOR_ID_V2_NXP,
+ PCIE_DEVICE_ID_NXP_88W8997P,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+#endif
+#ifdef PCIE9097
+ {
+ PCIE_VENDOR_ID_V2_NXP,
+ PCIE_DEVICE_ID_NXP_88W9097,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+#endif
+#ifdef PCIE9098
+ {
+ PCIE_VENDOR_ID_V2_NXP,
+ PCIE_DEVICE_ID_NXP_88W9098P_FN0,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+ {
+ PCIE_VENDOR_ID_V2_NXP,
+ PCIE_DEVICE_ID_NXP_88W9098P_FN1,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ },
+#endif
+ {},
+};
+/* moal interface ops */
+static moal_if_ops pcie_ops;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+void woal_request_pmqos_busfreq_high()
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 6, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ pm_qos_add_request(&woal_pcie_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70)
+#ifdef IMX_SUPPORT
+ request_bus_freq(BUS_FREQ_HIGH);
+#endif
+#endif
+}
+
+void woal_release_pmqos_busfreq_high()
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 70)
+#ifdef IMX_SUPPORT
+ release_bus_freq(BUS_FREQ_HIGH);
+#endif
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 6, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ pm_qos_remove_request(&woal_pcie_pm_qos_req);
+#endif
+#endif
+}
+
+static mlan_status woal_pcie_preinit(struct pci_dev *pdev);
+
+/** @brief This function updates the card types
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param card A Pointer to card
+ *
+ * @return N/A
+ */
+static t_u16 woal_update_card_type(t_void *card)
+{
+ pcie_service_card *cardp_pcie = (pcie_service_card *)card;
+ t_u16 card_type = 0;
+
+ /* Update card type */
+#ifdef PCIE8897
+ if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W8897P) {
+ card_type = CARD_TYPE_PCIE8897;
+ moal_memcpy_ext(NULL, driver_version, CARD_PCIE8897,
+ strlen(CARD_PCIE8897), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V15, strlen(V15),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef PCIE8997
+ if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W8997P) {
+ card_type = CARD_TYPE_PCIE8997;
+ moal_memcpy_ext(NULL, driver_version, CARD_PCIE8997,
+ strlen(CARD_PCIE8997), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef PCIE9097
+ if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9097) {
+ card_type = CARD_TYPE_PCIE9097;
+ moal_memcpy_ext(NULL, driver_version, CARD_PCIE9097,
+ strlen(CARD_PCIE9097), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef PCIE9098
+ if (cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN0 ||
+ cardp_pcie->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1) {
+ card_type = CARD_TYPE_PCIE9098;
+ moal_memcpy_ext(NULL, driver_version, CARD_PCIE9098,
+ strlen(CARD_PCIE9098), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+ return card_type;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+/**
+ * @brief Function to process pre/post PCIe function level reset
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param prepare True :- its a pre FLR call from the kernel
+ * False :- its a post FLR call from the kernel
+ *
+ * Note: This function is mix of woal_switch_drv_mode() and
+ * remove_card(). Idea is to cleanup the software only without
+ * touching the PCIe specific code. Likewise, during init init
+ * everything, including hw, but do not reinitiate PCIe stack
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_do_flr(moal_handle *handle, bool prepare)
+{
+ unsigned int i;
+ int index = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ pcie_service_card *card = NULL;
+ int fw_serial_bkp;
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MINFO, "\n Handle null during prepare=%d\n", prepare);
+ LEAVE();
+ return status;
+ }
+
+ card = (pcie_service_card *)handle->card;
+
+ if (card == NULL) {
+ PRINTM(MERROR, "The parameter 'card' is NULL\n");
+ LEAVE();
+ return (mlan_status)MLAN_STATUS_FAILURE;
+ }
+
+ if (!IS_PCIE8997(handle->card_type) &&
+ !IS_PCIE9097(handle->card_type) &&
+ !IS_PCIE9098(handle->card_type)) {
+ LEAVE();
+ return status;
+ }
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
+ goto exit_sem_err;
+
+ if (!prepare)
+ goto perform_init;
+
+ /* Reset all interfaces */
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE);
+
+ /* Shutdown firmware */
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+
+ if (atomic_read(&handle->rx_pending) ||
+ atomic_read(&handle->tx_pending) ||
+ atomic_read(&handle->ioctl_pending)) {
+ PRINTM(MERROR,
+ "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n",
+ atomic_read(&handle->rx_pending),
+ atomic_read(&handle->tx_pending),
+ atomic_read(&handle->ioctl_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < handle->priv_num; i++)
+ woal_remove_interface(handle, i);
+
+ /* Unregister mlan */
+ if (handle->pmlan_adapter) {
+ mlan_unregister(handle->pmlan_adapter);
+ if (atomic_read(&handle->lock_count) ||
+ atomic_read(&handle->malloc_count) ||
+ atomic_read(&handle->mbufalloc_count)) {
+ PRINTM(MERROR,
+ "mlan has memory leak: lock_count=%d,"
+ " malloc_count=%d, mbufalloc_count=%d\n",
+ atomic_read(&handle->lock_count),
+ atomic_read(&handle->malloc_count),
+ atomic_read(&handle->mbufalloc_count));
+ }
+ if (atomic_read(&handle->malloc_cons_count)) {
+ PRINTM(MERROR,
+ "mlan has memory leak: malloc_cons_count=%d\n",
+ atomic_read(&handle->malloc_cons_count));
+ }
+ handle->pmlan_adapter = NULL;
+ }
+
+ goto exit;
+
+perform_init:
+ handle->priv_num = 0;
+
+ /* Init SW */
+ if (woal_init_sw(handle)) {
+ PRINTM(MFATAL, "Software Init Failed\n");
+ goto err_init_fw;
+ }
+
+#ifdef PCIE9098
+ if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
+ mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 1);
+ else
+#endif
+ /* Update pcie_int_mode in mlan adapter */
+ mlan_set_int_mode(handle->pmlan_adapter,
+ handle->params.pcie_int_mode, 0);
+
+ /* Init FW and HW */
+ /* Load wlan only binary */
+ fw_serial_bkp = moal_extflg_isset(handle, EXT_FW_SERIAL);
+ moal_extflg_clear(handle, EXT_FW_SERIAL);
+ woal_update_firmware_name(handle);
+ if (woal_init_fw(handle)) {
+ PRINTM(MFATAL, "Firmware Init Failed\n");
+ woal_pcie_reg_dbg(handle);
+ if (fw_serial_bkp)
+ moal_extflg_set(handle, EXT_FW_SERIAL);
+ goto err_init_fw;
+ }
+ if (fw_serial_bkp)
+ moal_extflg_set(handle, EXT_FW_SERIAL);
+exit:
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+
+exit_sem_err:
+ LEAVE();
+ return status;
+
+err_init_fw:
+ if ((handle->hardware_status == HardwareStatusFwReady) ||
+ (handle->hardware_status == HardwareStatusReady)) {
+ PRINTM(MINFO, "shutdown mlan\n");
+ handle->init_wait_q_woken = MFALSE;
+ status = mlan_shutdown_fw(handle->pmlan_adapter);
+ if (status == MLAN_STATUS_PENDING)
+ wait_event_interruptible(handle->init_wait_q,
+ handle->init_wait_q_woken);
+ }
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ wakeup_source_trash(&handle->ws);
+#else
+ wake_lock_destroy(&handle->wake_lock);
+#endif
+#endif
+#ifdef CONFIG_PROC_FS
+ woal_proc_exit(handle);
+#endif
+ /* Unregister device */
+ PRINTM(MINFO, "unregister device\n");
+ woal_pcie_unregister_dev(handle);
+ handle->surprise_removed = MTRUE;
+#ifdef REASSOCIATION
+ if (handle->reassoc_thread.pid)
+ wake_up_interruptible(&handle->reassoc_thread.wait_q);
+ /* waiting for main thread quit */
+ while (handle->reassoc_thread.pid)
+ woal_sched_timeout(2);
+#endif /* REASSOCIATION */
+ woal_terminate_workqueue(handle);
+ woal_free_moal_handle(handle);
+
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == handle)
+ break;
+ }
+ if (index < MAX_MLAN_ADAPTER)
+ m_handle[index] = NULL;
+ card->handle = NULL;
+ MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
+ LEAVE();
+ return (mlan_status)MLAN_STATUS_FAILURE;
+}
+#endif
+
+/**
+ * @brief This function handles PCIE driver probe
+ *
+ * @param pdev A pointer to pci_dev structure
+ * @param id A pointer to pci_device_id structure
+ *
+ * @return error code
+ */
+int woal_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ pcie_service_card *card = NULL;
+ t_u16 card_type = 0;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X rev=%d\n", pdev->vendor,
+ pdev->device, pdev->revision);
+
+ /* Preinit PCIE device so allocate PCIE memory can be successful */
+ if (woal_pcie_preinit(pdev)) {
+ PRINTM(MFATAL, "MOAL PCIE preinit failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ card = kzalloc(sizeof(pcie_service_card), GFP_KERNEL);
+ if (!card) {
+ PRINTM(MERROR, "%s: failed to alloc memory\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ card->dev = pdev;
+
+ card_type = woal_update_card_type(card);
+ if (!card_type) {
+ PRINTM(MERROR, "pcie probe: woal_update_card_type() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+ woal_pcie_init(card);
+
+ if (woal_add_card(card, &card->dev->dev, &pcie_ops, card_type) ==
+ NULL) {
+ woal_pcie_cleanup(card);
+ PRINTM(MERROR, "%s: failed\n", __func__);
+ ret = -EFAULT;
+ goto err;
+ }
+
+ LEAVE();
+ return ret;
+err:
+ kfree(card);
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function handles PCIE driver remove
+ *
+ * @param pdev A pointer to pci_dev structure
+ *
+ * @return error code
+ */
+static void woal_pcie_remove(struct pci_dev *dev)
+{
+ pcie_service_card *card;
+ moal_handle *handle;
+
+ ENTER();
+ card = pci_get_drvdata(dev);
+ if (!card) {
+ PRINTM(MINFO, "PCIE card removed from slot\n");
+ LEAVE();
+ return;
+ }
+
+ handle = card->handle;
+ if (!handle || !handle->priv_num) {
+ PRINTM(MINFO, "PCIE card handle removed\n");
+ LEAVE();
+ return;
+ }
+ handle->surprise_removed = MTRUE;
+ woal_remove_card(card);
+ woal_pcie_cleanup(card);
+ kfree(card);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Handle suspend
+ *
+ * @param pdev A pointer to pci_dev structure
+ * @param state PM state message
+ *
+ * @return error code
+ */
+static int woal_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pcie_service_card *cardp;
+ moal_handle *handle = NULL;
+ int i;
+ int ret = MLAN_STATUS_SUCCESS;
+ int hs_actived;
+ mlan_ds_ps_info pm_info;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_pcie_suspend --->\n");
+ if (pdev) {
+ cardp = (pcie_service_card *)pci_get_drvdata(pdev);
+ if (!cardp || !cardp->handle) {
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "PCIE device is not specified\n");
+ LEAVE();
+ return -ENOSYS;
+ }
+
+ handle = cardp->handle;
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (handle->fw_dump) {
+ PRINTM(MMSG, "suspend not allowed while FW dump!");
+ ret = -EBUSY;
+ goto done;
+ }
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
+ woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
+ }
+ handle->suspend_fail = MFALSE;
+ memset(&pm_info, 0, sizeof(pm_info));
+#define MAX_RETRY_NUM 8
+ for (i = 0; i < MAX_RETRY_NUM; i++) {
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ &pm_info)) {
+ if (pm_info.is_suspend_allowed == MTRUE)
+ break;
+ else
+ PRINTM(MMSG,
+ "Suspend not allowed and retry again\n");
+ }
+ woal_sched_timeout(100);
+ }
+ if (pm_info.is_suspend_allowed == MFALSE) {
+ PRINTM(MMSG, "Suspend not allowed\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_detach(handle->priv[i]->netdev);
+
+ /* Enable Host Sleep */
+ hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+ if (hs_actived == MTRUE) {
+ /* Indicate device suspended */
+ handle->is_suspended = MTRUE;
+ } else {
+ PRINTM(MMSG, "HS not actived, suspend fail!");
+ handle->suspend_fail = MTRUE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+ ret = -EBUSY;
+ goto done;
+ }
+ flush_workqueue(handle->workqueue);
+ flush_workqueue(handle->evt_workqueue);
+ if (handle->rx_workqueue)
+ flush_workqueue(handle->rx_workqueue);
+ if (handle->tx_workqueue)
+ flush_workqueue(handle->tx_workqueue);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+done:
+ PRINTM(MCMND, "<--- Leave woal_pcie_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle resume
+ *
+ * @param pdev A pointer to pci_dev structure
+ *
+ * @return error code
+ */
+static int woal_pcie_resume(struct pci_dev *pdev)
+{
+ moal_handle *handle;
+ pcie_service_card *card;
+ int i;
+
+ ENTER();
+
+ PRINTM(MCMND, "<--- Enter woal_pcie_resume --->\n");
+ if (pdev) {
+ card = (pcie_service_card *)pci_get_drvdata(pdev);
+ if (!card || !card->handle) {
+ PRINTM(MERROR, "Card or handle is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ } else {
+ PRINTM(MERROR, "PCIE device is not specified\n");
+ LEAVE();
+ return -ENOSYS;
+ }
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
+
+ handle = card->handle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ goto done;
+ }
+
+ handle->is_suspended = MFALSE;
+
+ if (woal_check_driver_status(handle)) {
+ PRINTM(MERROR, "Resuem, device is in hang state\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_pcie_resume --->\n");
+ LEAVE();
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
+/**
+ * @brief Pcie reset prepare handler
+ *
+ * @param pdev A pointer to pci_dev structure
+ */
+static void woal_pcie_reset_prepare(struct pci_dev *pdev)
+{
+ pcie_service_card *card;
+ moal_handle *handle;
+ moal_handle *ref_handle = NULL;
+
+ ENTER();
+
+ card = pci_get_drvdata(pdev);
+ if (!card) {
+ PRINTM(MINFO, "PCIE card removed from slot\n");
+ LEAVE();
+ return;
+ }
+
+ handle = card->handle;
+
+ if (!handle) {
+ PRINTM(MINFO, "Invalid handle\n");
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d Pre-FLR\n",
+ __func__, pdev->vendor, pdev->device, pdev->revision);
+
+ /* Kernel would be performing FLR after this notification.
+ * Cleanup up all software withouth cleaning anything related to
+ * PCIe and HW.
+ * Note. FW might not be healthy.
+ */
+ // handle-> mac0 , ref_handle->second mac
+ if (handle->pref_mac) {
+ if (handle->second_mac) {
+ handle = (moal_handle *)handle->pref_mac;
+ ref_handle = (moal_handle *)handle->pref_mac;
+ } else {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ }
+ }
+ handle->surprise_removed = MTRUE;
+ woal_do_flr(handle, true);
+ if (ref_handle) {
+ ref_handle->surprise_removed = MTRUE;
+ woal_do_flr(ref_handle, true);
+ }
+
+ LEAVE();
+}
+/**
+ * @brief Pcie reset done handler
+ *
+ * @param pdev A pointer to pci_dev structure
+ */
+static void woal_pcie_reset_done(struct pci_dev *pdev)
+{
+ pcie_service_card *card;
+ moal_handle *handle;
+ moal_handle *ref_handle = NULL;
+ ENTER();
+
+ card = pci_get_drvdata(pdev);
+ if (!card) {
+ PRINTM(MINFO, "PCIE card removed from slot\n");
+ LEAVE();
+ return;
+ }
+
+ handle = card->handle;
+ if (!handle) {
+ PRINTM(MINFO, "Invalid handle\n");
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d Post-FLR\n",
+ __func__, pdev->vendor, pdev->device, pdev->revision);
+
+ /* Kernel stores and restores PCIe function context before and
+ * after performing FLR, respectively.
+ *
+ * Reconfigure the sw and fw including fw redownload
+ */
+ // handle-> mac0 , ref_handle->second mac
+ if (handle->pref_mac) {
+ if (handle->second_mac) {
+ handle = (moal_handle *)handle->pref_mac;
+ ref_handle = (moal_handle *)handle->pref_mac;
+ } else {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ }
+ }
+ handle->surprise_removed = MFALSE;
+ woal_do_flr(handle, false);
+ if (ref_handle) {
+ ref_handle->surprise_removed = MFALSE;
+ woal_do_flr(ref_handle, false);
+ }
+
+ LEAVE();
+}
+#else
+void woal_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
+{
+ pcie_service_card *card;
+ moal_handle *handle;
+ moal_handle *ref_handle = NULL;
+
+ ENTER();
+
+ card = pci_get_drvdata(pdev);
+ if (!card) {
+ PRINTM(MINFO, "PCIE card removed from slot\n");
+ LEAVE();
+ return;
+ }
+
+ handle = card->handle;
+ if (!handle) {
+ PRINTM(MINFO, "Invalid handle\n");
+ LEAVE();
+ return;
+ }
+
+ PRINTM(MMSG, "%s: vendor=0x%4.04X device=0x%4.04X rev=%d %s\n",
+ __func__, pdev->vendor, pdev->device, pdev->revision,
+ prepare ? "Pre-FLR" : "Post-FLR");
+
+ // handle-> mac0 , ref_handle->second mac
+ if (handle->pref_mac) {
+ if (handle->second_mac) {
+ handle = (moal_handle *)handle->pref_mac;
+ ref_handle = (moal_handle *)handle->pref_mac;
+ } else {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ }
+ }
+
+ if (prepare) {
+ /* Kernel would be performing FLR after this notification.
+ * Cleanup up all software withouth cleaning anything related to
+ * PCIe and HW.
+ * Note. FW might not be healthy.
+ */
+ handle->surprise_removed = MTRUE;
+ woal_do_flr(handle, prepare);
+ if (ref_handle) {
+ ref_handle->surprise_removed = MTRUE;
+ woal_do_flr(ref_handle, prepare);
+ }
+ } else {
+ /* Kernel stores and restores PCIe function context before and
+ * after performing FLR, respectively.
+ *
+ * Reconfigure the sw and fw including fw redownload
+ */
+ handle->surprise_removed = MFALSE;
+ woal_do_flr(handle, prepare);
+ if (ref_handle) {
+ ref_handle->surprise_removed = MFALSE;
+ woal_do_flr(ref_handle, prepare);
+ }
+ }
+ LEAVE();
+}
+#endif
+
+static const struct pci_error_handlers woal_pcie_err_handler[] = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
+ {
+ .reset_prepare = woal_pcie_reset_prepare,
+ .reset_done = woal_pcie_reset_done,
+ },
+#else
+ {
+ .reset_notify = woal_pcie_reset_notify,
+ },
+#endif
+};
+#endif // KERNEL_VERSION(3.18.0)
+
+/* PCI Device Driver */
+static struct pci_driver REFDATA wlan_pcie = {
+ .name = "wlan_pcie",
+ .id_table = wlan_ids,
+ .probe = woal_pcie_probe,
+ .remove = woal_pcie_remove,
+#ifdef CONFIG_PM
+ /* Power Management Hooks */
+ .suspend = woal_pcie_suspend,
+ .resume = woal_pcie_resume,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ .err_handler = woal_pcie_err_handler,
+#endif
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_pcie_write_reg(moal_handle *handle, t_u32 reg,
+ t_u32 data)
+{
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+
+ iowrite32(data, card->pci_mmap1 + reg);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_pcie_read_reg(moal_handle *handle, t_u32 reg,
+ t_u32 *data)
+{
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ *data = ioread32(card->pci_mmap1 + reg);
+
+ if (*data == MLAN_STATUS_FAILURE)
+ return MLAN_STATUS_FAILURE;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function writes multiple bytes into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_pcie_write_data_sync(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u32 port, t_u32 timeout)
+{
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function reads multiple bytes from card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_pcie_read_data_sync(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u32 port, t_u32 timeout)
+{
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param irq The irq no. of PCIE device
+ * @param dev_id A pointer to the pci_dev structure
+ *
+ * @return IRQ_HANDLED
+ */
+static irqreturn_t woal_pcie_interrupt(int irq, void *dev_id)
+{
+ struct pci_dev *pdev;
+ pcie_service_card *card;
+ moal_handle *handle;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ pdev = (struct pci_dev *)dev_id;
+ if (!pdev) {
+ PRINTM(MFATAL, "%s: pdev is NULL\n", (t_u8 *)pdev);
+ goto exit;
+ }
+
+ card = (pcie_service_card *)pci_get_drvdata(pdev);
+ if (!card || !card->handle) {
+ PRINTM(MFATAL, "%s: card=%p handle=%p\n", __func__, card,
+ card ? card->handle : NULL);
+ goto exit;
+ }
+ handle = card->handle;
+ if (handle->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ PRINTM(MINFO, "*** IN PCIE IRQ ***\n");
+ handle->main_state = MOAL_RECV_INT;
+ PRINTM(MINTR, "*\n");
+
+ ret = mlan_interrupt(0xffff, handle->pmlan_adapter);
+ queue_work(handle->workqueue, &handle->main_work);
+
+exit:
+ if (ret == MLAN_STATUS_SUCCESS)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+/**
+ * @brief This function handles the MSI-X interrupt.
+ *
+ * @param irq The irq no. of PCIE device
+ * @param dev_id A pointer to the msix_context structure
+ *
+ * @return IRQ_HANDLED
+ */
+static irqreturn_t woal_pcie_msix_interrupt(int irq, void *dev_id)
+{
+ struct pci_dev *pdev;
+ pcie_service_card *card;
+ moal_handle *handle;
+ msix_context *ctx = (msix_context *)dev_id;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ if (!ctx) {
+ PRINTM(MFATAL, "%s: ctx=%p is NULL\n", __func__, ctx);
+ goto exit;
+ }
+
+ pdev = ctx->dev;
+
+ if (!pdev) {
+ PRINTM(MFATAL, "%s: pdev is NULL\n", (t_u8 *)pdev);
+ goto exit;
+ }
+
+ card = (pcie_service_card *)pci_get_drvdata(pdev);
+ if (!card || !card->handle) {
+ PRINTM(MFATAL, "%s: card=%p handle=%p\n", __func__, card,
+ card ? card->handle : NULL);
+ goto exit;
+ }
+ handle = card->handle;
+ if (handle->surprise_removed == MTRUE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto exit;
+ }
+ PRINTM(MINFO, "*** IN PCIE IRQ ***\n");
+ handle->main_state = MOAL_RECV_INT;
+ PRINTM(MINTR, "*\n");
+ ret = mlan_interrupt(ctx->msg_id, handle->pmlan_adapter);
+ queue_work(handle->workqueue, &handle->main_work);
+
+exit:
+ if (ret == MLAN_STATUS_SUCCESS)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+/**
+ * @brief This function pre-initializes the PCI-E host
+ * memory space, etc.
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_pcie_preinit(struct pci_dev *pdev)
+{
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_enable_dev;
+
+ pci_set_master(pdev);
+
+ PRINTM(MINFO, "Try set_consistent_dma_mask(32)\n");
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ PRINTM(MERROR, "set_dma_mask(32) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ PRINTM(MERROR, "set_consistent_dma_mask(64) failed\n");
+ goto err_set_dma_mask;
+ }
+ return MLAN_STATUS_SUCCESS;
+
+err_set_dma_mask:
+ pci_disable_device(pdev);
+err_enable_dev:
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function initializes the PCI-E host
+ * memory space, etc.
+ *
+ * @param card A pointer to pcie_service_card structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_pcie_init(pcie_service_card *card)
+{
+ struct pci_dev *pdev = NULL;
+ int ret;
+
+ pdev = card->dev;
+ pci_set_drvdata(pdev, card);
+#if 0
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_enable_dev;
+
+ pci_set_master(pdev);
+
+ PRINTM(MINFO, "Try set_consistent_dma_mask(32)\n");
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ PRINTM(MERROR, "set_dma_mask(32) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ PRINTM(MERROR, "set_consistent_dma_mask(64) failed\n");
+ goto err_set_dma_mask;
+ }
+#endif
+
+ ret = pci_request_region(pdev, 0, DRV_NAME);
+ if (ret) {
+ PRINTM(MERROR, "req_reg(0) error\n");
+ goto err_req_region0;
+ }
+ card->pci_mmap = pci_iomap(pdev, 0, 0);
+ if (!card->pci_mmap) {
+ PRINTM(MERROR, "iomap(0) error\n");
+ goto err_iomap0;
+ }
+ ret = pci_request_region(pdev, 2, DRV_NAME);
+ if (ret) {
+ PRINTM(MERROR, "req_reg(2) error\n");
+ goto err_req_region2;
+ }
+ card->pci_mmap1 = pci_iomap(pdev, 2, 0);
+ if (!card->pci_mmap1) {
+ PRINTM(MERROR, "iomap(2) error\n");
+ goto err_iomap2;
+ }
+
+ PRINTM(MINFO,
+ "PCI memory map Virt0: %p PCI memory map Virt2: "
+ "%p\n",
+ card->pci_mmap, card->pci_mmap1);
+
+ return MLAN_STATUS_SUCCESS;
+
+err_iomap2:
+ pci_release_region(pdev, 2);
+err_req_region2:
+ pci_iounmap(pdev, card->pci_mmap);
+err_iomap0:
+ pci_release_region(pdev, 0);
+err_req_region0:
+#if 0
+err_set_dma_mask:
+#endif
+
+#if 0
+err_enable_dev:
+#endif
+ pci_set_drvdata(pdev, NULL);
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function registers the PCIE device
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_pcie_register_dev(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pcie_service_card *card = NULL;
+ struct pci_dev *pdev = NULL;
+ unsigned char nvec;
+ unsigned char i, j;
+ ENTER();
+
+ if (!handle || !handle->card) {
+ PRINTM(MINFO, "%s: handle=%p card=%p\n", __FUNCTION__, handle,
+ handle ? handle->card : NULL);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ card = (pcie_service_card *)handle->card;
+ pdev = card->dev;
+ /* save adapter pointer in card */
+ card->handle = handle;
+
+ switch (pcie_int_mode) {
+ case PCIE_INT_MODE_MSIX:
+ pcie_int_mode = PCIE_INT_MODE_MSIX;
+ nvec = PCIE_NUM_MSIX_VECTORS;
+
+ for (i = 0; i < nvec; i++) {
+ card->msix_entries[i].entry = i;
+ }
+
+ /* Try to enable msix */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ ret = pci_enable_msix_exact(pdev, card->msix_entries, nvec);
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */
+ ret = pci_enable_msix(pdev, card->msix_entries, nvec);
+#endif
+
+ if (ret == 0) {
+ for (i = 0; i < nvec; i++) {
+ card->msix_contexts[i].dev = pdev;
+ card->msix_contexts[i].msg_id = i;
+ ret = request_irq(card->msix_entries[i].vector,
+ woal_pcie_msix_interrupt, 0,
+ "mrvl_pcie_msix",
+ &(card->msix_contexts[i]));
+
+ if (ret) {
+ PRINTM(MFATAL,
+ "request_irq failed: ret=%d\n",
+ ret);
+ for (j = 0; j < i; j++)
+ free_irq(card->msix_entries[j]
+ .vector,
+ &(card->msix_contexts
+ [i]));
+ pci_disable_msix(pdev);
+ break;
+ }
+ }
+ if (i == nvec)
+ break;
+ }
+ // follow through
+
+ /* fall through */
+ case PCIE_INT_MODE_MSI:
+ pcie_int_mode = PCIE_INT_MODE_MSI;
+ ret = pci_enable_msi(pdev);
+ if (ret == 0) {
+ ret = request_irq(pdev->irq, woal_pcie_interrupt, 0,
+ "mrvl_pcie_msi", pdev);
+ if (ret) {
+ PRINTM(MFATAL, "request_irq failed: ret=%d\n",
+ ret);
+ pci_disable_msi(pdev);
+ } else {
+ break;
+ }
+ }
+ // follow through
+
+ /* fall through */
+ case PCIE_INT_MODE_LEGACY:
+ pcie_int_mode = PCIE_INT_MODE_LEGACY;
+ ret = request_irq(pdev->irq, woal_pcie_interrupt, IRQF_SHARED,
+ "mrvl_pcie", pdev);
+ if (ret) {
+ PRINTM(MFATAL, "request_irq failed: ret=%d\n", ret);
+ handle->card = NULL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ break;
+
+ default:
+ PRINTM(MFATAL, "pcie_int_mode %d failed\n", pcie_int_mode);
+ handle->card = NULL;
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ break;
+ }
+
+#ifdef PCIE9098
+ if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
+ mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 1);
+ else
+#endif
+ mlan_set_int_mode(handle->pmlan_adapter, pcie_int_mode, 0);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function cleans up the host memory spaces
+ *
+ * @param card A pointer to pcie_service_card structure
+ *
+ * @return N/A
+ */
+void woal_pcie_cleanup(pcie_service_card *card)
+{
+ struct pci_dev *pdev = NULL;
+ pdev = card->dev;
+ PRINTM(MINFO, "Clearing driver ready signature\n");
+
+ if (pdev) {
+ pci_iounmap(pdev, card->pci_mmap);
+ pci_iounmap(pdev, card->pci_mmap1);
+
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
+
+ pci_release_region(pdev, 0);
+ pci_release_region(pdev, 2);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+/**
+ * @brief This function unregisters the PCIE device
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static void woal_pcie_unregister_dev(moal_handle *handle)
+{
+ pcie_service_card *card =
+ handle ? (pcie_service_card *)handle->card : NULL;
+ struct pci_dev *pdev = NULL;
+ unsigned char i;
+ unsigned char nvec;
+ ENTER();
+
+ if (card) {
+ pdev = card->dev;
+ PRINTM(MINFO, "%s(): calling free_irq()\n", __func__);
+
+ switch (pcie_int_mode) {
+ case PCIE_INT_MODE_MSIX:
+ nvec = PCIE_NUM_MSIX_VECTORS;
+
+ for (i = 0; i < nvec; i++)
+ synchronize_irq(card->msix_entries[i].vector);
+
+ for (i = 0; i < nvec; i++)
+ free_irq(card->msix_entries[i].vector,
+ &(card->msix_contexts[i]));
+
+ pci_disable_msix(pdev);
+
+ break;
+
+ case PCIE_INT_MODE_MSI:
+ free_irq(card->dev->irq, pdev);
+ pci_disable_msi(pdev);
+ break;
+
+ case PCIE_INT_MODE_LEGACY:
+ free_irq(card->dev->irq, pdev);
+ break;
+
+ default:
+ PRINTM(MFATAL, "pcie_int_mode %d failed\n",
+ pcie_int_mode);
+ break;
+ }
+ card->handle = NULL;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the IF module in bus driver
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_pcie_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* API registers the NXP PCIE driver */
+ if (pci_register_driver(&wlan_pcie)) {
+ PRINTM(MFATAL, "PCIE Driver Registration Failed \n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the IF module in bus driver
+ *
+ * @return N/A
+ */
+void woal_pcie_bus_unregister(void)
+{
+ ENTER();
+
+ /* PCIE Driver Unregistration */
+ pci_unregister_driver(&wlan_pcie);
+
+ LEAVE();
+}
+
+#if defined(PCIE9098) || defined(PCIE9097)
+#define PCIE9098_DUMP_CTRL_REG 0x1C94
+#define PCIE9098_DUMP_START_REG 0x1C98
+#define PCIE9098_DUMP_END_REG 0x1C9F
+#endif
+#if defined(PCIE8897) || defined(PCIE8997)
+#define DEBUG_DUMP_CTRL_REG 0xCF4
+#define DEBUG_DUMP_START_REG 0xCF8
+#define DEBUG_DUMP_END_REG 0xCFF
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+#define PCIE9098_SCRATCH_12_REG 0x1C90
+#define PCIE9098_SCRATCH_14_REG 0x1C98
+#define PCIE9098_SCRATCH_15_REG 0x1C9C
+#define PCIE9098_DUMP_REG_START 0x1C20
+#define PCIE9098_DUMP_REG_END 0x1C9C
+#endif
+
+#if defined(PCIE8997) || defined(PCIE8897)
+#define PCIE_SCRATCH_12_REG 0x0CF0;
+#define PCIE_SCRATCH_14_REG 0x0CF8;
+#define PCIE_SCRATCH_15_REG 0x0CFC;
+#define PCIE_DUMP_START_REG 0xC00
+#define PCIE_DUMP_END_REG 0xCFC
+#endif
+/**
+ * @brief This function save the log of pcie register value
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buffer A pointer to buffer saving log
+ *
+ * @return The length of this log
+ */
+int woal_pcie_dump_reg_info(moal_handle *phandle, t_u8 *buffer)
+{
+ char *drv_ptr = (char *)buffer;
+ t_u32 reg = 0, value = 0;
+ t_u8 i;
+ char buf[256], *ptr;
+ pcie_service_card *card = (pcie_service_card *)phandle->card;
+ int config_reg_table[] = {0x00, 0x04, 0x10, 0x18, 0x2c,
+ 0x3c, 0x44, 0x80, 0x98, 0x170};
+ t_u32 dump_start_reg = 0;
+ t_u32 dump_end_reg = 0;
+ t_u32 scratch_14_reg = 0;
+ t_u32 scratch_15_reg = 0;
+#if defined(PCIE9098) || defined(PCIE9097)
+ /* Tx/Rx/Event AMDA start address */
+ t_u32 adma_reg_table[] = {0x10000, 0x10800, 0x10880, 0x11000, 0x11080};
+ t_u8 j;
+#endif
+ ENTER();
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+ drv_ptr += sprintf(drv_ptr,
+ "------------PCIe Registers dump-------------\n");
+ drv_ptr += sprintf(drv_ptr, "Config Space Registers:\n");
+ for (i = 0; i < ARRAY_SIZE(config_reg_table); i++) {
+ pci_read_config_dword(card->dev, config_reg_table[i], &value);
+ drv_ptr += sprintf(drv_ptr, "reg:0x%02x value=0x%08x\n",
+ config_reg_table[i], value);
+ }
+ drv_ptr += sprintf(drv_ptr, "FW Scrach Registers:\n");
+
+#if defined(PCIE8897) || defined(PCIE8997)
+ if (IS_PCIE8897(phandle->card_type) ||
+ IS_PCIE8997(phandle->card_type)) {
+ reg = PCIE_SCRATCH_12_REG;
+ dump_start_reg = PCIE_DUMP_START_REG;
+ dump_end_reg = PCIE_DUMP_END_REG;
+ scratch_14_reg = PCIE_SCRATCH_14_REG;
+ scratch_15_reg = PCIE_SCRATCH_15_REG;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ reg = PCIE9098_SCRATCH_12_REG;
+ dump_start_reg = PCIE9098_DUMP_REG_START;
+ dump_end_reg = PCIE9098_DUMP_REG_END;
+ scratch_14_reg = PCIE9098_SCRATCH_14_REG;
+ scratch_15_reg = PCIE9098_SCRATCH_15_REG;
+ }
+#endif
+
+ woal_pcie_read_reg(phandle, reg, &value);
+ drv_ptr += sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
+ for (i = 0; i < 2; i++) {
+ reg = scratch_14_reg;
+ woal_pcie_read_reg(phandle, reg, &value);
+ drv_ptr +=
+ sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
+
+ reg = scratch_15_reg;
+ woal_pcie_read_reg(phandle, reg, &value);
+ drv_ptr +=
+ sprintf(drv_ptr, "reg:0x%x value=0x%x\n", reg, value);
+
+ mdelay(100);
+ }
+ drv_ptr +=
+ sprintf(drv_ptr,
+ "Interface registers dump from offset 0x%x to 0x%x\n",
+ dump_start_reg, dump_end_reg);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = dump_start_reg; reg <= dump_end_reg; reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ drv_ptr += sprintf(drv_ptr, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ drv_ptr += sprintf(
+ drv_ptr,
+ "PCIE registers from offset 0x1c20 to 0x1c9c:\n");
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = 0x1c20; reg <= 0x1c9c; reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ drv_ptr += sprintf(drv_ptr, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+ drv_ptr += sprintf(drv_ptr, "%s\n", buf);
+ }
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ drv_ptr += sprintf(drv_ptr,
+ "ADMA Tx/Rx/Event/Cmd/CmdResp registers:\n");
+ for (j = 0; j < ARRAY_SIZE(adma_reg_table); j++) {
+ drv_ptr += sprintf(
+ drv_ptr,
+ "ADMA registers dump from offset 0x%x to 0x%x\n",
+ adma_reg_table[j], adma_reg_table[j] + 0x68);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = adma_reg_table[j];
+ reg <= (adma_reg_table[j] + 0x68); reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ drv_ptr +=
+ sprintf(drv_ptr, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+ drv_ptr += sprintf(drv_ptr, "%s\n", buf);
+ }
+ }
+#endif
+ drv_ptr += sprintf(drv_ptr,
+ "-----------PCIe Registers dump End-----------\n");
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+ LEAVE();
+ return drv_ptr - (char *)buffer;
+}
+
+/**
+ * @brief This function reads and displays PCIE scratch registers for debugging
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void woal_pcie_reg_dbg(moal_handle *phandle)
+{
+ t_u32 reg = 0, value = 0;
+ t_u8 i;
+ char buf[256], *ptr;
+ pcie_service_card *card = (pcie_service_card *)phandle->card;
+ int config_reg_table[] = {0x00, 0x04, 0x10, 0x18, 0x2c,
+ 0x3c, 0x44, 0x80, 0x98, 0x170};
+ t_u32 dump_start_reg = 0;
+ t_u32 dump_end_reg = 0;
+ t_u32 scratch_14_reg = 0;
+ t_u32 scratch_15_reg = 0;
+#if defined(PCIE9098) || defined(PCIE9097)
+ /* Tx/Rx/Event AMDA start address */
+ t_u32 adma_reg_table[] = {0x10000, 0x10800, 0x10880, 0x11000, 0x11080};
+ t_u8 j;
+#endif
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+ PRINTM(MMSG, "Config Space Registers:\n");
+ for (i = 0; i < ARRAY_SIZE(config_reg_table); i++) {
+ pci_read_config_dword(card->dev, config_reg_table[i], &value);
+ PRINTM(MERROR, "reg:0x%02x value=0x%08x\n", config_reg_table[i],
+ value);
+ }
+ PRINTM(MMSG, "FW Scrach Registers:\n");
+#if defined(PCIE8897) || defined(PCIE8997)
+ if (IS_PCIE8897(phandle->card_type) ||
+ IS_PCIE8997(phandle->card_type)) {
+ reg = PCIE_SCRATCH_12_REG;
+ dump_start_reg = PCIE_DUMP_START_REG;
+ dump_end_reg = PCIE_DUMP_END_REG;
+ scratch_14_reg = PCIE_SCRATCH_14_REG;
+ scratch_15_reg = PCIE_SCRATCH_15_REG;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ reg = PCIE9098_SCRATCH_12_REG;
+ dump_start_reg = PCIE9098_DUMP_START_REG;
+ dump_end_reg = PCIE9098_DUMP_END_REG;
+ scratch_14_reg = PCIE9098_SCRATCH_14_REG;
+ scratch_15_reg = PCIE9098_SCRATCH_15_REG;
+ }
+#endif
+ woal_pcie_read_reg(phandle, reg, &value);
+ PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
+ for (i = 0; i < 2; i++) {
+ reg = scratch_14_reg;
+ woal_pcie_read_reg(phandle, reg, &value);
+ PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
+
+ reg = scratch_15_reg;
+ woal_pcie_read_reg(phandle, reg, &value);
+ PRINTM(MERROR, "reg:0x%x value=0x%x\n", reg, value);
+
+ mdelay(100);
+ }
+ PRINTM(MMSG, "Interface registers dump from offset 0x%x to 0x%x\n",
+ dump_start_reg, dump_end_reg);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = dump_start_reg; reg <= dump_end_reg; reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ PRINTM(MMSG, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ PRINTM(MMSG, "PCIE registers from offset 0x1c20 to 0x1c9c:\n");
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = 0x1c20; reg <= 0x1c9c; reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ PRINTM(MMSG, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+ PRINTM(MMSG, "%s\n", buf);
+ }
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ PRINTM(MMSG, "ADMA Tx/Rx/Event/Cmd/CmdResp registers:\n");
+ for (j = 0; j < ARRAY_SIZE(adma_reg_table); j++) {
+ PRINTM(MMSG,
+ "ADMA registers dump from offset 0x%x to 0x%x\n",
+ adma_reg_table[j], adma_reg_table[j] + 0x68);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ i = 1;
+ for (reg = adma_reg_table[j];
+ reg <= (adma_reg_table[j] + 0x68); reg += 4) {
+ woal_pcie_read_reg(phandle, reg, &value);
+ ptr += sprintf(ptr, "%08x ", value);
+ if (!(i % 8)) {
+ PRINTM(MMSG, "%s\n", buf);
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ }
+ i++;
+ }
+ PRINTM(MMSG, "%s\n", buf);
+ }
+ }
+#endif
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+}
+
+#define DEBUG_FW_DONE 0xFF
+#define MAX_POLL_TRIES 100
+
+typedef enum {
+ DUMP_TYPE_ITCM = 0,
+ DUMP_TYPE_DTCM = 1,
+ DUMP_TYPE_SQRAM = 2,
+ DUMP_TYPE_IRAM = 3,
+ DUMP_TYPE_APU = 4,
+ DUMP_TYPE_CIU = 5,
+ DUMP_TYPE_ICU = 6,
+ DUMP_TYPE_MAC = 7,
+} dumped_mem_type;
+
+#define MAX_NAME_LEN 8
+#define MAX_FULL_NAME_LEN 32
+t_u8 *name_prefix = "/data/file_";
+
+typedef struct {
+ t_u8 mem_name[MAX_NAME_LEN];
+ t_u8 *mem_Ptr;
+ struct file *pfile_mem;
+ t_u8 done_flag;
+ t_u8 type;
+} memory_type_mapping;
+
+typedef enum {
+ RDWR_STATUS_SUCCESS = 0,
+ RDWR_STATUS_FAILURE = 1,
+ RDWR_STATUS_DONE = 2
+} rdwr_status;
+
+#ifdef PCIE8897
+#define DEBUG_HOST_READY_8897 0xEE
+#define DEBUG_MEMDUMP_FINISH_8897 0xFE
+memory_type_mapping mem_type_mapping_tbl_8897[] = {
+ {"ITCM", NULL, NULL, 0xF0, FW_DUMP_TYPE_MEM_ITCM},
+ {"DTCM", NULL, NULL, 0xF1, FW_DUMP_TYPE_MEM_DTCM},
+ {"SQRAM", NULL, NULL, 0xF2, FW_DUMP_TYPE_MEM_SQRAM},
+ {"IRAM", NULL, NULL, 0xF3, FW_DUMP_TYPE_MEM_IRAM},
+ {"APU", NULL, NULL, 0xF4, FW_DUMP_TYPE_REG_APU},
+ {"CIU", NULL, NULL, 0xF5, FW_DUMP_TYPE_REG_CIU},
+ {"ICU", NULL, NULL, 0xF6, FW_DUMP_TYPE_REG_ICU},
+ {"MAC", NULL, NULL, 0xF7, FW_DUMP_TYPE_REG_MAC},
+};
+#endif
+
+#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
+#define DEBUG_HOST_READY_8997 0xCC
+#define DEBUG_HOST_EVENT_READY 0xAA
+#define DEBUG_MEMDUMP_FINISH_8997 0xDD
+memory_type_mapping mem_type_mapping_tbl_8997 = {"DUMP", NULL, NULL, 0xDD,
+ 0x00};
+
+#endif
+
+#if defined(PCIE8897) || defined(PCIE8997) || defined(PCIE9098) || \
+ defined(PCIE9097)
+/**
+ * @brief This function reads data by 8 bit from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_read_reg_eight_bit(moal_handle *handle, t_u32 reg, t_u8 *data)
+{
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ *data = ioread8(card->pci_mmap1 + reg);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function read/write firmware
+ *
+ * @param phandle A pointer to moal_handle
+ * @param doneflag done flag
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+rdwr_status woal_pcie_rdwr_firmware(moal_handle *phandle, t_u8 doneflag)
+{
+ int ret = 0;
+ int tries = 0;
+ t_u8 ctrl_data = 0;
+ t_u32 reg_data = 0;
+ t_u32 debug_host_ready = 0;
+ t_u32 dump_ctrl_reg = 0;
+
+#ifdef PCIE8897
+ if (IS_PCIE8897(phandle->card_type)) {
+ debug_host_ready = DEBUG_HOST_READY_8897;
+ dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
+ }
+#endif
+#if defined(PCIE8997)
+ if (IS_PCIE8997(phandle->card_type)) {
+ debug_host_ready = DEBUG_HOST_READY_8997;
+ dump_ctrl_reg = DEBUG_DUMP_CTRL_REG;
+ }
+#endif
+
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ if (phandle->event_fw_dump)
+ debug_host_ready = DEBUG_HOST_EVENT_READY;
+ else
+ debug_host_ready = DEBUG_HOST_READY_8997;
+ dump_ctrl_reg = PCIE9098_DUMP_CTRL_REG;
+ }
+#endif
+
+ ret = woal_pcie_write_reg(phandle, dump_ctrl_reg, debug_host_ready);
+ if (ret) {
+ PRINTM(MERROR, "PCIE Write ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ ret = woal_pcie_read_reg(phandle, dump_ctrl_reg, &reg_data);
+ if (ret) {
+ PRINTM(MERROR, "PCIE Read DEBUG_DUMP_CTRL_REG fail\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = woal_read_reg_eight_bit(phandle, dump_ctrl_reg,
+ &ctrl_data);
+ if (ret) {
+ PRINTM(MERROR, "PCIE READ ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ if (ctrl_data == DEBUG_FW_DONE)
+ break;
+ if (doneflag && ctrl_data == doneflag)
+ return RDWR_STATUS_DONE;
+ if (ctrl_data != debug_host_ready) {
+ PRINTM(MMSG, "The ctrl reg was changed, try again!\n");
+ ret = woal_pcie_write_reg(phandle, dump_ctrl_reg,
+ debug_host_ready);
+ if (ret) {
+ PRINTM(MERROR, "PCIE Write ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ usleep_range(99, 100);
+#else
+ udelay(100);
+#endif
+ }
+ if (ctrl_data == debug_host_ready) {
+ PRINTM(MERROR, "Fail to pull ctrl_data\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ return RDWR_STATUS_SUCCESS;
+}
+#endif
+
+#ifdef PCIE8897
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_pcie_dump_fw_info_v1(moal_handle *phandle)
+{
+ int ret = 0;
+ unsigned int reg, reg_start, reg_end;
+ t_u8 *dbg_ptr = NULL;
+ t_u32 sec, usec;
+ t_u8 dump_num = 0;
+ t_u8 idx = 0;
+ t_u8 doneflag = 0;
+ rdwr_status stat;
+ t_u8 i = 0;
+ t_u8 read_reg = 0;
+ t_u32 memory_size = 0, DEBUG_MEMDUMP_FINISH;
+ t_u8 path_name[64], file_name[32], firmware_dump_file[128];
+ t_u8 *end_ptr = NULL;
+ memory_type_mapping *mem_type_mapping_tbl = mem_type_mapping_tbl_8897;
+
+ if (!phandle) {
+ PRINTM(MERROR, "Could not dump firmwware info\n");
+ return;
+ }
+ DEBUG_MEMDUMP_FINISH = DEBUG_MEMDUMP_FINISH_8897;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ /** Create dump directory*/
+ woal_create_dump_dir(phandle, path_name, sizeof(path_name));
+#else
+ memset(path_name, 0, sizeof(path_name));
+ strcpy(path_name, "/data");
+#endif
+ PRINTM(MMSG, "Directory name is %s\n", path_name);
+ woal_dump_drv_info(phandle, path_name);
+ /* start dump fw memory */
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT START: %u.%06u ====\n", sec,
+ usec);
+ /* read the number of the memories which will dump */
+ if (RDWR_STATUS_FAILURE == woal_pcie_rdwr_firmware(phandle, doneflag))
+ goto done;
+ reg = DEBUG_DUMP_START_REG;
+ ret = woal_read_reg_eight_bit(phandle, reg, &dump_num);
+ if (ret) {
+ PRINTM(MMSG, "PCIE READ MEM NUM ERR\n");
+ goto done;
+ }
+
+ /* read the length of every memory which will dump */
+ for (idx = 0;
+ idx < dump_num && idx < ARRAY_SIZE(mem_type_mapping_tbl_8897);
+ idx++) {
+ if (RDWR_STATUS_FAILURE ==
+ woal_pcie_rdwr_firmware(phandle, doneflag))
+ goto done;
+ memory_size = 0;
+ reg = DEBUG_DUMP_START_REG;
+ for (i = 0; i < 4; i++) {
+ ret = woal_read_reg_eight_bit(phandle, reg, &read_reg);
+ if (ret) {
+ PRINTM(MMSG, "PCIE READ ERR\n");
+ goto done;
+ }
+ memory_size |= (read_reg << i * 8);
+ reg++;
+ }
+ if (memory_size == 0) {
+ PRINTM(MMSG, "Firmware Dump Finished!\n");
+ ret = woal_pcie_write_reg(phandle, DEBUG_DUMP_CTRL_REG,
+ DEBUG_MEMDUMP_FINISH);
+ if (ret) {
+ PRINTM(MERROR,
+ "PCIE Write MEMDUMP_FINISH ERR\n");
+ goto done;
+ }
+ break;
+ } else {
+ PRINTM(MMSG, "%s_SIZE=0x%x\n",
+ mem_type_mapping_tbl[idx].mem_name, memory_size);
+ ret = moal_vmalloc(
+ phandle, memory_size + 1,
+ (t_u8 **)&mem_type_mapping_tbl[idx].mem_Ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) ||
+ !mem_type_mapping_tbl[idx].mem_Ptr) {
+ PRINTM(MERROR,
+ "Error: vmalloc %s buffer failed!!!\n",
+ mem_type_mapping_tbl[idx].mem_name);
+ goto done;
+ }
+ dbg_ptr = mem_type_mapping_tbl[idx].mem_Ptr;
+ end_ptr = dbg_ptr + memory_size;
+ }
+ doneflag = mem_type_mapping_tbl[idx].done_flag;
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
+ mem_type_mapping_tbl[idx].mem_name, sec, usec);
+ do {
+ stat = woal_pcie_rdwr_firmware(phandle, doneflag);
+ if (RDWR_STATUS_FAILURE == stat)
+ goto done;
+
+ reg_start = DEBUG_DUMP_START_REG;
+ reg_end = DEBUG_DUMP_END_REG;
+ for (reg = reg_start; reg <= reg_end; reg++) {
+ ret = woal_read_reg_eight_bit(phandle, reg,
+ dbg_ptr);
+ if (ret) {
+ PRINTM(MMSG, "PCIE READ ERR\n");
+ goto done;
+ }
+ if (dbg_ptr < end_ptr)
+ dbg_ptr++;
+ else
+ PRINTM(MINFO,
+ "pre-allocced buf is not enough\n");
+ }
+ if (RDWR_STATUS_DONE == stat) {
+ PRINTM(MMSG, "%s done: size=0x%x\n",
+ mem_type_mapping_tbl[idx].mem_name,
+ (unsigned int)(dbg_ptr -
+ mem_type_mapping_tbl[idx]
+ .mem_Ptr));
+ memset(file_name, 0, sizeof(file_name));
+ sprintf(file_name, "%s%s", "file_pcie_",
+ mem_type_mapping_tbl[idx].mem_name);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_save_dump_info_to_file(
+ path_name, file_name,
+ mem_type_mapping_tbl[idx].mem_Ptr,
+ memory_size))
+ PRINTM(MMSG,
+ "Can't save dump file %s in %s\n",
+ file_name, path_name);
+ moal_vfree(phandle,
+ mem_type_mapping_tbl[idx].mem_Ptr);
+ mem_type_mapping_tbl[idx].mem_Ptr = NULL;
+ break;
+ }
+ } while (1);
+ }
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT END: %u.%06u ====\n", sec,
+ usec);
+ /* end dump fw memory */
+ memset(firmware_dump_file, 0, sizeof(firmware_dump_file));
+ sprintf(firmware_dump_file, "%s/%s", path_name, file_name);
+ moal_memcpy_ext(phandle, phandle->firmware_dump_file,
+ firmware_dump_file, sizeof(firmware_dump_file),
+ sizeof(phandle->firmware_dump_file));
+done:
+ for (idx = 0;
+ idx < dump_num && idx < ARRAY_SIZE(mem_type_mapping_tbl_8897);
+ idx++) {
+ if (mem_type_mapping_tbl[idx].mem_Ptr) {
+ moal_vfree(phandle, mem_type_mapping_tbl[idx].mem_Ptr);
+ mem_type_mapping_tbl[idx].mem_Ptr = NULL;
+ }
+ }
+
+ return;
+}
+#endif
+
+#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_pcie_dump_fw_info_v2(moal_handle *phandle)
+{
+ int ret = 0;
+ unsigned int reg, reg_start, reg_end;
+ t_u8 *dbg_ptr = NULL;
+ t_u8 *tmp_ptr = NULL;
+ t_u32 sec, usec;
+ t_u8 dump_num = 0;
+ t_u8 doneflag = 0;
+ rdwr_status stat;
+ t_u32 memory_size = 0;
+ t_u8 path_name[64], file_name[32], firmware_dump_file[128];
+ moal_handle *ref_handle;
+ t_u8 *end_ptr = NULL;
+ memory_type_mapping *mem_type_mapping_tbl = &mem_type_mapping_tbl_8997;
+ t_u32 dump_start_reg = 0;
+ t_u32 dump_end_reg = 0;
+
+ if (!phandle) {
+ PRINTM(MERROR, "Could not dump firmwware info\n");
+ return;
+ }
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ if (phandle->event_fw_dump) {
+ if (RDWR_STATUS_FAILURE !=
+ woal_pcie_rdwr_firmware(phandle, doneflag))
+ PRINTM(MMSG,
+ "====PCIE FW DUMP EVENT MODE START ====\n");
+ phandle->event_fw_dump = MFALSE;
+ return;
+ }
+ }
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ /** Create dump directory*/
+ woal_create_dump_dir(phandle, path_name, sizeof(path_name));
+#else
+ memset(path_name, 0, sizeof(path_name));
+ strcpy(path_name, "/data");
+#endif
+ PRINTM(MMSG, "Create DUMP directory success:dir_name=%s\n", path_name);
+ ref_handle = (moal_handle *)phandle->pref_mac;
+ if (ref_handle)
+ woal_dump_drv_info(ref_handle, path_name);
+ woal_dump_drv_info(phandle, path_name);
+
+ /* start dump fw memory */
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT START: %u.%06u ====\n", sec,
+ usec);
+ /* read the number of the memories which will dump */
+ if (RDWR_STATUS_FAILURE == woal_pcie_rdwr_firmware(phandle, doneflag))
+ goto done;
+#if defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE9098(phandle->card_type) ||
+ IS_PCIE9097(phandle->card_type)) {
+ dump_start_reg = PCIE9098_DUMP_START_REG;
+ dump_end_reg = PCIE9098_DUMP_END_REG;
+ }
+#endif
+#ifdef PCIE8997
+ if (IS_PCIE8997(phandle->card_type)) {
+ dump_start_reg = DEBUG_DUMP_START_REG;
+ dump_end_reg = DEBUG_DUMP_END_REG;
+ }
+#endif
+ reg = dump_start_reg;
+ ret = woal_read_reg_eight_bit(phandle, reg, &dump_num);
+ if (ret) {
+ PRINTM(MMSG, "PCIE READ MEM NUM ERR\n");
+ goto done;
+ }
+
+ memory_size = 0x80000;
+ ret = moal_vmalloc(phandle, memory_size + 1,
+ (t_u8 **)&mem_type_mapping_tbl->mem_Ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) || !mem_type_mapping_tbl->mem_Ptr) {
+ PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n",
+ mem_type_mapping_tbl->mem_name);
+ goto done;
+ }
+ dbg_ptr = mem_type_mapping_tbl->mem_Ptr;
+ end_ptr = dbg_ptr + memory_size;
+
+ doneflag = mem_type_mapping_tbl->done_flag;
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
+ mem_type_mapping_tbl->mem_name, sec, usec);
+ do {
+ stat = woal_pcie_rdwr_firmware(phandle, doneflag);
+ if (RDWR_STATUS_FAILURE == stat)
+ goto done;
+
+ reg_start = dump_start_reg;
+ reg_end = dump_end_reg;
+ for (reg = reg_start; reg <= reg_end; reg++) {
+ ret = woal_read_reg_eight_bit(phandle, reg, dbg_ptr);
+ if (ret) {
+ PRINTM(MMSG, "PCIE READ ERR\n");
+ goto done;
+ }
+ dbg_ptr++;
+ if (dbg_ptr >= end_ptr) {
+ PRINTM(MINFO,
+ "pre-allocced buf is not enough\n");
+ ret = moal_vmalloc(phandle,
+ memory_size + 0x4000 + 1,
+ (t_u8 **)&tmp_ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) || !tmp_ptr) {
+ PRINTM(MERROR,
+ "Error: vmalloc buffer failed!!!\n");
+ goto done;
+ }
+ moal_memcpy_ext(phandle, tmp_ptr,
+ mem_type_mapping_tbl->mem_Ptr,
+ memory_size,
+ memory_size + 0x4000);
+ moal_vfree(phandle,
+ mem_type_mapping_tbl->mem_Ptr);
+ mem_type_mapping_tbl->mem_Ptr = tmp_ptr;
+ tmp_ptr = NULL;
+ dbg_ptr = mem_type_mapping_tbl->mem_Ptr +
+ memory_size;
+ memory_size += 0x4000;
+ end_ptr = mem_type_mapping_tbl->mem_Ptr +
+ memory_size;
+ }
+ }
+ if (RDWR_STATUS_DONE == stat) {
+ PRINTM(MMSG,
+ "%s done:"
+#ifdef MLAN_64BIT
+ "size = 0x%lx\n",
+#else
+ "size = 0x%x\n",
+#endif
+ mem_type_mapping_tbl->mem_name,
+ dbg_ptr - mem_type_mapping_tbl->mem_Ptr);
+ memset(file_name, 0, sizeof(file_name));
+ sprintf(file_name, "%s%s", "file_pcie_",
+ mem_type_mapping_tbl->mem_name);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_save_dump_info_to_file(
+ path_name, file_name,
+ mem_type_mapping_tbl->mem_Ptr,
+ dbg_ptr - mem_type_mapping_tbl->mem_Ptr))
+ PRINTM(MMSG, "Can't save dump file %s in %s\n",
+ file_name, path_name);
+ moal_vfree(phandle, mem_type_mapping_tbl->mem_Ptr);
+ mem_type_mapping_tbl->mem_Ptr = NULL;
+ break;
+ }
+ } while (1);
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "====PCIE DEBUG MODE OUTPUT END: %u.%06u ====\n", sec,
+ usec);
+ /* end dump fw memory */
+ memset(firmware_dump_file, 0, sizeof(firmware_dump_file));
+ sprintf(firmware_dump_file, "%s/%s", path_name, file_name);
+ moal_memcpy_ext(phandle, phandle->firmware_dump_file,
+ firmware_dump_file, sizeof(firmware_dump_file),
+ sizeof(phandle->firmware_dump_file));
+done:
+ if (mem_type_mapping_tbl->mem_Ptr) {
+ moal_vfree(phandle, mem_type_mapping_tbl->mem_Ptr);
+ mem_type_mapping_tbl->mem_Ptr = NULL;
+ }
+
+ return;
+}
+#endif
+
+/**
+ * @brief This function check if this is second mac
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MTRUE/MFALSE
+ *
+ */
+static t_u8 woal_pcie_is_second_mac(moal_handle *handle)
+{
+#ifdef PCIE9098
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN1)
+ return MTRUE;
+#endif
+ return MFALSE;
+}
+
+void woal_pcie_dump_fw_info(moal_handle *phandle)
+{
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+ phandle->fw_dump = MTRUE;
+#ifdef PCIE8897
+ if (IS_PCIE8897(phandle->card_type))
+ woal_pcie_dump_fw_info_v1(phandle);
+#endif
+#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
+ if (IS_PCIE8997(phandle->card_type) ||
+ IS_PCIE9098(phandle->card_type) || IS_PCIE9097(phandle->card_type))
+ woal_pcie_dump_fw_info_v2(phandle);
+#endif
+ phandle->fw_dump = MFALSE;
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+ queue_work(phandle->workqueue, &phandle->main_work);
+}
+
+static mlan_status woal_pcie_get_fw_name(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef PCIE9098
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ moal_handle *ref_handle = NULL;
+#endif
+
+#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
+ t_u32 rev_id_reg = handle->card_info->rev_id_reg;
+ t_u32 revision_id = 0;
+#endif
+
+#if defined(PCIE8997) || defined(PCIE9098) || defined(PCIE9097)
+ t_u32 host_strap_reg = handle->card_info->host_strap_reg;
+ t_u32 magic_reg = handle->card_info->magic_reg;
+ t_u32 strap = 0;
+ t_u32 magic = 0;
+#endif
+
+ ENTER();
+
+ if (handle->params.fw_name) {
+#ifdef PCIE9097
+ if (IS_PCIE9097(handle->card_type)) {
+ woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
+ revision_id &= 0xff;
+ PRINTM(MCMND, "revision_id=0x%x\n", revision_id);
+ switch (revision_id) {
+ case PCIE9097_A0:
+ break;
+ case PCIE9097_B0:
+ case PCIE9097_B1:
+ handle->card_rev = CHIP_9097_REV_B0;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ goto done;
+ }
+
+#ifdef PCIE8997
+ if (IS_PCIE8997(handle->card_type)) {
+ woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
+ woal_pcie_read_reg(handle, host_strap_reg, &strap);
+ woal_pcie_read_reg(handle, magic_reg, &magic);
+ revision_id &= 0xff;
+ strap &= 0x7;
+ magic &= 0xff;
+ PRINTM(MCMND, "magic=0x%x, strap=0x%x, revision_id=0x%x\n",
+ magic, strap, revision_id);
+ if ((revision_id == PCIE8997_A1) &&
+ (magic == CHIP_MAGIC_VALUE)) {
+ if (strap == CARD_TYPE_PCIE_UART)
+ strcpy(handle->card_info->fw_name,
+ PCIEUART8997_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ PCIEUSB8997_DEFAULT_COMBO_FW_NAME);
+ }
+ }
+#endif
+#ifdef PCIE9098
+ if (IS_PCIE9098(handle->card_type)) {
+ if (card->dev->device == PCIE_DEVICE_ID_NXP_88W9098P_FN0) {
+ woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
+ woal_pcie_read_reg(handle, host_strap_reg, &strap);
+ woal_pcie_read_reg(handle, magic_reg, &magic);
+ revision_id &= 0xff;
+ strap &= 0x7;
+ magic &= 0xff;
+ PRINTM(MCMND,
+ "magic=0x%x, strap=0x%x, revision_id=0x%x\n",
+ magic, strap, revision_id);
+ switch (revision_id) {
+ case PCIE9098_Z1Z2:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_PCIE_UART)
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEUART9098_DEFAULT_COMBO_FW_NAME);
+ else if (strap == CARD_TYPE_PCIE_PCIE)
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEPCIE9098_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEUSB9098_DEFAULT_COMBO_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ PCIE9098_DEFAULT_WLAN_FW_NAME);
+ break;
+ case PCIE9098_A0:
+ case PCIE9098_A1:
+ case PCIE9098_A2:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_PCIE_UART)
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEUART9098_COMBO_V1_FW_NAME);
+ else if (strap == CARD_TYPE_PCIE_PCIE)
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEPCIE9098_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info
+ ->fw_name,
+ PCIEUSB9098_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ PCIE9098_WLAN_V1_FW_NAME);
+ break;
+ default:
+ break;
+ }
+ } else {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ strcpy(handle->card_info->fw_name,
+ ref_handle->card_info->fw_name);
+ strcpy(handle->card_info->fw_name_wlan,
+ ref_handle->card_info->fw_name_wlan);
+ }
+ }
+ }
+#endif
+#ifdef PCIE9097
+ if (IS_PCIE9097(handle->card_type)) {
+ woal_pcie_read_reg(handle, rev_id_reg, &revision_id);
+ woal_pcie_read_reg(handle, host_strap_reg, &strap);
+ woal_pcie_read_reg(handle, magic_reg, &magic);
+ revision_id &= 0xff;
+ strap &= 0x7;
+ magic &= 0xff;
+ PRINTM(MCMND, "magic=0x%x, strap=0x%x, revision_id=0x%x\n",
+ magic, strap, revision_id);
+ switch (revision_id) {
+ case PCIE9097_A0:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_PCIE_UART)
+ strcpy(handle->card_info->fw_name,
+ PCIEUART9097_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ PCIEUSB9097_DEFAULT_COMBO_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ PCIE9097_DEFAULT_WLAN_FW_NAME);
+ break;
+ case PCIE9097_B0:
+ case PCIE9097_B1:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_PCIE_UART)
+ strcpy(handle->card_info->fw_name,
+ PCIEUART9097_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ PCIEUSB9097_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ PCIE9097_WLAN_V1_FW_NAME);
+ handle->card_rev = CHIP_9097_REV_B0;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+done:
+ PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
+ handle->card_info->fw_name_wlan);
+ LEAVE();
+ return ret;
+}
+
+static moal_if_ops pcie_ops = {
+ .register_dev = woal_pcie_register_dev,
+ .unregister_dev = woal_pcie_unregister_dev,
+ .read_reg = woal_pcie_read_reg,
+ .write_reg = woal_pcie_write_reg,
+ .read_data_sync = woal_pcie_read_data_sync,
+ .write_data_sync = woal_pcie_write_data_sync,
+ .get_fw_name = woal_pcie_get_fw_name,
+ .dump_fw_info = woal_pcie_dump_fw_info,
+ .reg_dbg = woal_pcie_reg_dbg,
+ .dump_reg_info = woal_pcie_dump_reg_info,
+ .is_second_mac = woal_pcie_is_second_mac,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.h
new file mode 100644
index 000000000000..1f3fd7196b83
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_pcie.h
@@ -0,0 +1,148 @@
+/** @file moal_pcie.h
+ *
+ * @brief This file contains definitions for PCIE interface.
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/01/2012: initial version
+********************************************************/
+
+#ifndef _MOAL_PCIE_H_
+#define _MOAL_PCIE_H_
+
+#define PCIE_VENDOR_ID_NXP (0x11ab)
+#define PCIE_VENDOR_ID_V2_NXP (0x1b4b)
+#ifdef PCIE8997
+/** PCIE device ID for 8997 card */
+#define PCIE_DEVICE_ID_NXP_88W8997P (0x2b42)
+#endif
+#ifdef PCIE8897
+/** PCIE device ID for 8897 card */
+#define PCIE_DEVICE_ID_NXP_88W8897P (0x2b38)
+#endif
+
+#ifdef PCIE9097
+/** PCIE device ID for 9097 card */
+#define PCIE_DEVICE_ID_NXP_88W9097 (0x2b56)
+#endif
+
+#ifdef PCIE9098
+/** PCIE device ID for 9098 card FN0 */
+#define PCIE_DEVICE_ID_NXP_88W9098P_FN0 (0x2b43)
+/** PCIE device ID for 9098 card FN1 */
+#define PCIE_DEVICE_ID_NXP_88W9098P_FN1 (0x2b44)
+#endif
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
+#include <linux/pcieport_if.h>
+#endif
+#include <linux/interrupt.h>
+
+#include "moal_main.h"
+
+/** Default firmware name */
+#ifdef PCIE8997
+#define PCIE8997_DEFAULT_COMBO_FW_NAME "nxp/pcieusb8997_combo_v4.bin"
+#define PCIEUART8997_DEFAULT_COMBO_FW_NAME "nxp/pcieuart8997_combo_v4.bin"
+#define PCIEUSB8997_DEFAULT_COMBO_FW_NAME "nxp/pcieusb8997_combo_v4.bin"
+#define PCIE8997_DEFAULT_WLAN_FW_NAME "nxp/pcie8997_wlan_v4.bin"
+/** PCIE8997 chip revision ID */
+#define PCIE8997_A0 0x10
+#define PCIE8997_A1 0x11
+#endif /* PCIE8997 */
+
+#ifdef PCIE8897
+#define PCIE8897_DEFAULT_COMBO_FW_NAME "nxp/pcie8897_uapsta.bin"
+#define PCIE8897_DEFAULT_WLAN_FW_NAME "nxp/pcie8897_wlan.bin"
+#endif /* PCIE8897*/
+
+#ifdef PCIE9098
+#define PCIE9098_Z1Z2 0x00
+#define PCIE9098_A0 0x01
+#define PCIE9098_A1 0x02
+#define PCIE9098_A2 0x03
+#define PCIE9098_DEFAULT_COMBO_FW_NAME "nxp/pcieusb9098_combo.bin"
+#define PCIEUART9098_DEFAULT_COMBO_FW_NAME "nxp/pcieuart9098_combo.bin"
+#define PCIEUSB9098_DEFAULT_COMBO_FW_NAME "nxp/pcieusb9098_combo.bin"
+#define PCIEPCIE9098_DEFAULT_COMBO_FW_NAME "nxp/pciepcie9098_combo.bin"
+#define PCIEUART9098_COMBO_V1_FW_NAME "nxp/pcieuart9098_combo_v1.bin"
+#define PCIEUSB9098_COMBO_V1_FW_NAME "nxp/pcieusb9098_combo_v1.bin"
+#define PCIEPCIE9098_COMBO_V1_FW_NAME "nxp/pciepcie9098_combo_v1.bin"
+#define PCIE9098_DEFAULT_WLAN_FW_NAME "nxp/pcie9098_wlan.bin"
+#define PCIE9098_WLAN_V1_FW_NAME "nxp/pcie9098_wlan_v1.bin"
+#endif /* PCIE9098 */
+
+#ifdef PCIE9097
+#define PCIE9097_A0 0x00
+#define PCIE9097_B0 0x01
+#define PCIE9097_B1 0x02
+#define PCIE9097_DEFAULT_COMBO_FW_NAME "nxp/pcieusb9097_combo.bin"
+#define PCIEUART9097_DEFAULT_COMBO_FW_NAME "nxp/pcieuart9097_combo.bin"
+#define PCIEUSB9097_DEFAULT_COMBO_FW_NAME "nxp/pcieusb9097_combo.bin"
+#define PCIEUART9097_COMBO_V1_FW_NAME "nxp/pcieuart9097_combo_v1.bin"
+#define PCIEUSB9097_COMBO_V1_FW_NAME "nxp/pcieusb9097_combo_v1.bin"
+#define PCIE9097_DEFAULT_WLAN_FW_NAME "nxp/pcie9097_wlan.bin"
+#define PCIE9097_WLAN_V1_FW_NAME "nxp/pcie9097_wlan_v1.bin"
+#endif /* PCIE9097 */
+
+#if defined(PCIE9098) || defined(PCIE9097)
+#define PCIE_NUM_MSIX_VECTORS 32
+#else
+#define PCIE_NUM_MSIX_VECTORS 4
+#endif
+
+typedef struct _msix_context {
+ /** pci_dev structure pointer */
+ struct pci_dev *dev;
+ /** message id related to msix vector */
+ t_u16 msg_id;
+} msix_context;
+
+/** Structure: PCIE service card */
+typedef struct _pcie_service_card {
+ /** pci_dev structure pointer */
+ struct pci_dev *dev;
+ /** moal_handle structure pointer */
+ moal_handle *handle;
+ /** I/O memory regions pointer to the bus */
+ void __iomem *pci_mmap;
+ /** I/O memory regions pointer to the bus */
+ void __iomem *pci_mmap1;
+#if defined(PCIE)
+ struct msix_entry msix_entries[PCIE_NUM_MSIX_VECTORS];
+ msix_context msix_contexts[PCIE_NUM_MSIX_VECTORS];
+#endif
+} pcie_service_card, *ppcie_service_card;
+
+/** Register to bus driver function */
+mlan_status woal_pcie_bus_register(void);
+/** Unregister from bus driver function */
+void woal_pcie_bus_unregister(void);
+
+/* pmqos busfreq request handler*/
+void woal_request_pmqos_busfreq_high(void);
+/* pmqos busfreq release handler*/
+void woal_release_pmqos_busfreq_high(void);
+
+#endif /* _MOAL_PCIE_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.c
new file mode 100644
index 000000000000..8397ab666bb1
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.c
@@ -0,0 +1,6863 @@
+/** @file moal_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/30/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif /* SDIO */
+
+#include "moal_eth_ioctl.h"
+#ifdef USB
+#include "moal_usb.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** Bands supported in Infra mode */
+static t_u8 SupportedInfraBand[] = {
+ BAND_B,
+ BAND_B | BAND_G,
+ BAND_G,
+ BAND_GN,
+ BAND_B | BAND_G | BAND_GN,
+ BAND_G | BAND_GN,
+ BAND_A,
+ BAND_B | BAND_A,
+ BAND_B | BAND_G | BAND_A,
+ BAND_G | BAND_A,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_G | BAND_AN | BAND_GN,
+ BAND_A | BAND_AN,
+ BAND_GN | BAND_GAC,
+ BAND_B | BAND_G | BAND_GN | BAND_GAC,
+ BAND_G | BAND_GN | BAND_GAC,
+ BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
+ BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
+ BAND_A | BAND_AN | BAND_AAC,
+};
+
+/** Bands supported in Ad-Hoc mode */
+static t_u8 SupportedAdhocBand[] = {
+ BAND_B,
+ BAND_B | BAND_G,
+ BAND_G,
+ BAND_A,
+};
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Associated to a specific indexed entry in the ScanTable
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_associate_ssid_bssid(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ mlan_bss_info bss_info;
+#endif
+ char buf[64];
+ t_u8 buflen;
+ t_u8 mac_idx;
+ t_u8 i;
+
+ ENTER();
+
+ memset(&ssid_bssid, 0, sizeof(ssid_bssid));
+ mac_idx = 0;
+ buflen = MIN(wrq->u.data.length, (sizeof(buf) - 1));
+ memset(buf, 0, sizeof(buf));
+
+ if (buflen < (3 * ETH_ALEN) + 2) {
+ PRINTM(MERROR,
+ "Associate: Insufficient length in IOCTL input\n");
+
+ /* buffer should be at least 3 characters per BSSID octet "00:"
+ ** plus a space separater and at least 1 char in the SSID
+ */
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer, buflen) != 0) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "Associate: copy from user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ for (i = 0; (i < buflen) && (buf[i] == ' '); i++) {
+ /* Skip white space */
+ }
+
+ /* Copy/Convert the BSSID */
+ for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
+ if (buf[i] == ':') {
+ mac_idx++;
+ } else {
+ if (mac_idx < ETH_ALEN)
+ ssid_bssid.bssid[mac_idx] =
+ (t_u8)woal_atox(buf + i);
+
+ while ((i < buflen) && (isxdigit(buf[i + 1]))) {
+ /* Skip entire hex value */
+ i++;
+ }
+ }
+ }
+
+ /* Skip one space between the BSSID and start of the SSID */
+ i++;
+
+ /* Copy the SSID */
+ ssid_bssid.ssid.ssid_len = buflen - i - 1;
+ moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i,
+ sizeof(ssid_bssid.ssid.ssid),
+ sizeof(ssid_bssid.ssid.ssid));
+
+ PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
+ MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len,
+ ssid_bssid.ssid.ssid);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0x00, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(mlan_802_11_ssid));
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(mlan_802_11_mac_addr));
+ }
+#endif /* REASSOCIATION */
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Copy Rates
+ *
+ * @param dest A pointer to destination buffer
+ * @param pos The position for copy
+ * @param src A pointer to source buffer
+ * @param len Length of the source buffer
+ *
+ * @return Number of rates copied
+ */
+static inline int woal_copy_rates(t_u8 *dest, int pos, t_u8 *src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= MLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+ return pos;
+}
+
+/**
+ * @brief Performs warm reset
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_warm_reset(moal_private *priv)
+{
+ int ret = 0;
+ moal_handle *handle = priv->phandle;
+ moal_handle *ref_handle;
+ moal_private *ref_priv;
+ ENTER();
+ ret = woal_pre_warmreset(priv);
+ if (ret)
+ goto done;
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
+ if (ref_priv) {
+ ret = woal_pre_warmreset(ref_priv);
+ if (ret)
+ goto done;
+ ret = woal_warmreset(ref_priv);
+ if (ret)
+ goto done;
+ }
+ }
+ ret = woal_warmreset(priv);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get signal
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_signal(moal_private *priv, struct iwreq *wrq)
+{
+/** Input data size */
+#define IN_DATA_SIZE 2
+/** Output data size */
+#define OUT_DATA_SIZE 12
+ int ret = 0;
+ int in_data[IN_DATA_SIZE];
+ int out_data[OUT_DATA_SIZE];
+ mlan_ds_get_signal signal;
+ int data_length = 0;
+ int buflen = 0;
+
+ ENTER();
+
+ memset(in_data, 0, sizeof(in_data));
+ memset(out_data, 0, sizeof(out_data));
+ buflen = MIN(wrq->u.data.length, IN_DATA_SIZE);
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ if (wrq->u.data.length) {
+ if (sizeof(int) * wrq->u.data.length > sizeof(in_data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(in_data, wrq->u.data.pointer,
+ sizeof(int) * buflen)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ switch (wrq->u.data.length) {
+ case 0: /* No checking, get everything */
+ break;
+ case 2: /* Check subtype range */
+ if (in_data[1] < 1 || in_data[1] > 4) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Fall through */
+ case 1: /* Check type range */
+ if (in_data[0] < 1 || in_data[0] > 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int)signal.bcn_rssi_last);
+ PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
+ PRINTM(MINFO, "RSSI Data Last : %d\n", (int)signal.data_rssi_last);
+ PRINTM(MINFO, "RSSI Data Average : %d\n", (int)signal.data_rssi_avg);
+ PRINTM(MINFO, "SNR Beacon Last : %d\n", (int)signal.bcn_snr_last);
+ PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
+ PRINTM(MINFO, "SNR Data Last : %d\n", (int)signal.data_snr_last);
+ PRINTM(MINFO, "SNR Data Average : %d\n", (int)signal.data_snr_avg);
+ PRINTM(MINFO, "NF Beacon Last : %d\n", (int)signal.bcn_nf_last);
+ PRINTM(MINFO, "NF Beacon Average : %d\n", (int)signal.bcn_nf_avg);
+ PRINTM(MINFO, "NF Data Last : %d\n", (int)signal.data_nf_last);
+ PRINTM(MINFO, "NF Data Average : %d\n", (int)signal.data_nf_avg);
+
+ /* Check type */
+ switch (in_data[0]) {
+ case 0: /* Send everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* RSSI */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ out_data[data_length++] = signal.data_rssi_last;
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_rssi_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_rssi_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_rssi_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_rssi_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* SNR */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_snr_last;
+ out_data[data_length++] = signal.bcn_snr_avg;
+ out_data[data_length++] = signal.data_snr_last;
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_snr_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_snr_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_snr_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_snr_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3: /* NF */
+ /* Check subtype */
+ switch (in_data[1]) {
+ case 0: /* Everything */
+ out_data[data_length++] = signal.bcn_nf_last;
+ out_data[data_length++] = signal.bcn_nf_avg;
+ out_data[data_length++] = signal.data_nf_last;
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ case 1: /* bcn last */
+ out_data[data_length++] = signal.bcn_nf_last;
+ break;
+ case 2: /* bcn avg */
+ out_data[data_length++] = signal.bcn_nf_avg;
+ break;
+ case 3: /* data last */
+ out_data[data_length++] = signal.data_nf_last;
+ break;
+ case 4: /* data avg */
+ out_data[data_length++] = signal.data_nf_avg;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, out_data,
+ wrq->u.data.length * sizeof(out_data[0]))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set DeepSleep mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wreq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_deep_sleep_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int user_data_len;
+ t_u32 deep_sleep = DEEP_SLEEP_OFF;
+ t_u32 data[2] = {0};
+ int copy_len;
+ t_u16 idletime = DEEP_SLEEP_IDLE_TIME;
+
+ ENTER();
+
+ user_data_len = wrq->u.data.length;
+ copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
+ if (user_data_len == 1 || user_data_len == 2) {
+ if (copy_from_user(&data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ deep_sleep = data[0];
+ if (deep_sleep == DEEP_SLEEP_OFF) {
+ PRINTM(MINFO, "Exit Deep Sleep Mode\n");
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
+ 0);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (deep_sleep == DEEP_SLEEP_ON) {
+ PRINTM(MINFO, "Enter Deep Sleep Mode\n");
+ if (user_data_len == 2)
+ idletime = data[1];
+ else
+ idletime = 0;
+ ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
+ idletime);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ LEAVE();
+ return -EINVAL;
+ }
+ } else {
+ PRINTM(MERROR, "Unknown option = %u\n", deep_sleep);
+ LEAVE();
+ return -EINVAL;
+ }
+ } else if (user_data_len > 2) {
+ PRINTM(MERROR, "Invalid number of arguments %d\n",
+ user_data_len);
+ LEAVE();
+ return -EINVAL;
+ } else { /* Display Deep Sleep settings */
+ PRINTM(MINFO, "Get Deep Sleep Mode\n");
+ if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
+ LEAVE();
+ return -EFAULT;
+ }
+ if (data[0] == 0)
+ wrq->u.data.length = 1;
+ else
+ wrq->u.data.length = 2;
+ }
+
+ /* Copy the Deep Sleep setting to user */
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get Usr 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11n_htcap_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int data[2], copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ if (data_length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.htcap_cfg.htcap = data[0];
+ PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A &&
+ data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.htcap_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.htcap_cfg.htcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.htcap_cfg.htcap = 0;
+ cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.htcap_cfg.htcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.htcap_cfg.htcap;
+ PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n",
+ data[0]);
+ PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n",
+ data[1]);
+ } else
+ PRINTM(MINFO, "GET: htcapinfo:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wrq->u.data.length = data_length;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable amsdu_aggr_ctrl
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11n_amsdu_aggr_ctrl(moal_private *priv, struct iwreq *wrq)
+{
+ int data[2], copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((data_length != 0) && (data_length != 1)) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 1) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
+ data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configuration request
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11n_tx_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int data[2], copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get 11n tx parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg_11n->param.tx_cfg.httxcap = data[0];
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
+ if (data_length == 2) {
+ if (data[1] != BAND_SELECT_BG &&
+ data[1] != BAND_SELECT_A &&
+ data[1] != BAND_SELECT_BOTH) {
+ PRINTM(MERROR, "Invalid band selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg_11n->param.tx_cfg.misc_cfg = data[1];
+ PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
+ }
+ /* Update 11n tx parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ data[0] = cfg_11n->param.tx_cfg.httxcap;
+
+ if (req->action == MLAN_ACT_GET) {
+ data_length = 1;
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (cfg_11n->param.tx_cfg.httxcap != data[0]) {
+ data_length = 2;
+ data[1] = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n",
+ data[0]);
+ PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
+ } else
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable TX Aggregation
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11n_prio_tbl(moal_private *priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID * 2], i, j, copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if ((wrq->u.data.pointer == NULL)) {
+ LEAVE();
+ return -EINVAL;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ wrq->u.data.length = MAX_NUM_TID * 2;
+ for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) {
+ data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
+ data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (data_length == 16) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0, j = 0; i < (data_length); i = i + 2, ++j) {
+ if ((data[i] > 7 && data[i] != 0xff) ||
+ (data[i + 1] > 7 && data[i + 1] != 0xff)) {
+ PRINTM(MERROR,
+ "Invalid priority, valid value 0-7 or 0xff.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA Reject parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_addba_reject(moal_private *priv, struct iwreq *wrq)
+{
+ int data[MAX_NUM_TID], ret = 0, i, copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ PRINTM(MERROR, "Addba reject moal\n");
+ /* Get aggr priority table from MLAN */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+
+ wrq->u.data.length = MAX_NUM_TID;
+ for (i = 0; i < (wrq->u.data.length); ++i)
+ data[i] = cfg_11n->param.addba_reject[i];
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (data_length == 8) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ for (i = 0; i < (data_length); ++i) {
+ if (data[i] != 0 && data[i] != 1) {
+ PRINTM(MERROR,
+ "addba reject only takes argument as 0 or 1\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_reject[i] = data[i];
+ }
+
+ /* Update aggr priority table in MLAN */
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get add BA parameters
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_addba_para_updt(moal_private *priv, struct iwreq *wrq)
+{
+ int data[5], ret = 0, copy_len;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (data_length == 0) {
+ /* Get Add BA parameters from MLAN */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ data[0] = cfg_11n->param.addba_param.timeout;
+ data[1] = cfg_11n->param.addba_param.txwinsize;
+ data[2] = cfg_11n->param.addba_param.rxwinsize;
+ data[3] = cfg_11n->param.addba_param.txamsdu;
+ data[4] = cfg_11n->param.addba_param.rxamsdu;
+ PRINTM(MINFO,
+ "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ wrq->u.data.length = 5;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (data_length == 5) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
+ PRINTM(MERROR, "Incorrect addba timeout value.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
+ data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
+ PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.timeout = data[0];
+ cfg_11n->param.addba_param.txwinsize = data[1];
+ cfg_11n->param.addba_param.rxwinsize = data[2];
+ if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
+ PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
+ ret = -EFAULT;
+ goto error;
+ }
+ cfg_11n->param.addba_param.txamsdu = data[3];
+ cfg_11n->param.addba_param.rxamsdu = data[4];
+ PRINTM(MINFO,
+ "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
+ data[0], data[1], data[2], data[3], data[4]);
+ /* Update Add BA parameters in MLAN */
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ goto error;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit buffer size
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_txbuf_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int buf_size;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get Tx buffer size from MLAN */
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ PRINTM(MERROR,
+ "Don't support set Tx buffer size after driver loaded!\n");
+ goto done;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf_size = cfg_11n->param.tx_buf_size;
+ if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Host Sleep configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_hs_cfg(moal_private *priv, struct iwreq *wrq,
+ BOOLEAN invoke_hostcmd)
+{
+ int data[3], copy_len;
+ int ret = 0;
+ mlan_ds_hs_cfg hscfg;
+ t_u16 action;
+ mlan_bss_info bss_info;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ if (data_length == 0) {
+ action = MLAN_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ if (data_length >= 1 && data_length <= 3) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* HS config is blocked if HS is already activated */
+ if (data_length &&
+ (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Do a GET first if some arguments are not provided */
+ if (data_length >= 1 && data_length < 3) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
+ &hscfg);
+ }
+
+ if (data_length)
+ hscfg.conditions = data[0];
+ if (data_length >= 2)
+ hscfg.gpio = data[1];
+ if (data_length == 3)
+ hscfg.gap = data[2];
+
+ if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
+ /* Need to issue an extra IOCTL first to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data[0] = hscfg.conditions;
+ data[1] = hscfg.gpio;
+ data[2] = hscfg.gap;
+ wrq->u.data.length = 3;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_hs_setpara(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length >= 1 && data_length <= 3) {
+ ret = woal_hs_cfg(priv, wrq, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout extend
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_inactivity_timeout_ext(moal_private *priv, struct iwreq *wrq)
+{
+ int data[4], copy_len;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pmcfg = NULL;
+ pmlan_ds_inactivity_to inac_to = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ memset(data, 0, sizeof(data));
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
+ inac_to = &pmcfg->param.inactivity_to;
+ pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if ((data_length != 0 && data_length != 3 && data_length != 4) ||
+ sizeof(int) * data_length > sizeof(data)) {
+ PRINTM(MERROR, "Invalid number of parameters\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req->action = MLAN_ACT_GET;
+ if (data_length) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ inac_to->timeout_unit = data[0];
+ inac_to->unicast_timeout = data[1];
+ inac_to->mcast_timeout = data[2];
+ inac_to->ps_entry_timeout = data[3];
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy back current values regardless of GET/SET */
+ data[0] = inac_to->timeout_unit;
+ data[1] = inac_to->unicast_timeout;
+ data[2] = inac_to->mcast_timeout;
+ data[3] = inac_to->ps_entry_timeout;
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = 4;
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_ecl_sys_clock(moal_private *priv, struct iwreq *wrq)
+{
+ int data[64], copy_len;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int data_length = wrq->u.data.length;
+ int i = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length)
+ req->action = MLAN_ACT_GET;
+ else if (data_length <= MLAN_MAX_CLK_NUM) {
+ req->action = MLAN_ACT_SET;
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MERROR, "Invalid arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ /* Get configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Current system clock */
+ data[0] = (int)cfg->param.sys_clock.cur_sys_clk;
+ wrq->u.data.length = 1;
+
+ data_length =
+ MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Configurable clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int)cfg->param.sys_clock.sys_clk[i];
+ }
+ wrq->u.data.length += data_length;
+
+ /* Get supported clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data_length =
+ MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
+
+ /* Supported clocks */
+ for (i = 0; i < data_length; i++) {
+ data[i + wrq->u.data.length] =
+ (int)cfg->param.sys_clock.sys_clk[i];
+ }
+
+ wrq->u.data.length += data_length;
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /* Set configurable clocks */
+ cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
+ cfg->param.sys_clock.sys_clk_num =
+ MIN(MLAN_MAX_CLK_NUM, data_length);
+ for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
+ cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Band and Adhoc-band setting
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_band_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ unsigned int i;
+ int data[3];
+ int user_data_len = wrq->u.data.length, copy_len;
+ t_u32 infra_band = 0;
+ t_u32 adhoc_band = 0;
+ t_u32 adhoc_channel = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ if (user_data_len > 0) {
+ if (priv->media_connected == MTRUE) {
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ }
+
+ copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+
+ if (wrq->u.data.length == 0) {
+ /* Get config_bands, adhoc_start_band and adhoc_channel values
+ * from MLAN */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ /* Infra Band */
+ data[0] = radio_cfg->param.band_cfg.config_bands;
+ /* Adhoc Band */
+ data[1] = radio_cfg->param.band_cfg.adhoc_start_band;
+ /* Adhoc Channel */
+ data[2] = radio_cfg->param.band_cfg.adhoc_channel;
+ wrq->u.data.length = 3;
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto error;
+ }
+
+ /* To support only <b/bg/bgn/n> */
+ infra_band = data[0];
+ for (i = 0; i < sizeof(SupportedInfraBand); i++)
+ if (infra_band == SupportedInfraBand[i])
+ break;
+ if (i == sizeof(SupportedInfraBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set Adhoc band */
+ if (user_data_len >= 2) {
+ adhoc_band = data[1];
+ for (i = 0; i < sizeof(SupportedAdhocBand); i++)
+ if (adhoc_band == SupportedAdhocBand[i])
+ break;
+ if (i == sizeof(SupportedAdhocBand)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Set Adhoc channel */
+ if (user_data_len >= 3) {
+ adhoc_channel = data[2];
+ if (adhoc_channel == 0) {
+ /* Check if specified adhoc channel is non-zero
+ */
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ /* Set config_bands and adhoc_start_band values to MLAN */
+ req->action = MLAN_ACT_SET;
+ radio_cfg->param.band_cfg.config_bands = infra_band;
+ radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
+ radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write adapter registers value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_reg_read_write(moal_private *priv, struct iwreq *wrq)
+{
+ int data[3], copy_len;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *)req->pbuf;
+ reg->sub_command = MLAN_OID_REG_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 3) {
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ reg->param.reg_rw.type = (t_u32)data[0];
+ reg->param.reg_rw.offset = (t_u32)data[1];
+ if (data_length == 3)
+ reg->param.reg_rw.value = (t_u32)data[2];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user(wrq->u.data.pointer, &reg->param.reg_rw.value,
+ sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read the EEPROM contents of the card
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_read_eeprom(moal_private *priv, struct iwreq *wrq)
+{
+ int data[2], copy_len;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg = (mlan_ds_reg_mem *)req->pbuf;
+ reg->sub_command = MLAN_OID_EEPROM_RD;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 2) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg->param.rd_eeprom.offset = (t_u16)data[0];
+ reg->param.rd_eeprom.byte_count = (t_u16)data[1];
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ wrq->u.data.length = reg->param.rd_eeprom.byte_count;
+ if (copy_to_user(wrq->u.data.pointer,
+ reg->param.rd_eeprom.value,
+ MIN(wrq->u.data.length, MAX_EEPROM_DATA))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Read/Write device memory value
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_mem_read_write(moal_private *priv, struct iwreq *wrq)
+{
+ t_u32 data[2];
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_reg_mem *reg_mem = NULL;
+ int data_length = wrq->u.data.length, copy_len;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(data, 0, sizeof(data));
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ reg_mem = (mlan_ds_reg_mem *)req->pbuf;
+ reg_mem->sub_command = MLAN_OID_MEM_RW;
+ req->req_id = MLAN_IOCTL_REG_MEM;
+
+ if (data_length == 1) {
+ PRINTM(MINFO, "MEM_RW: GET\n");
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 2) {
+ PRINTM(MINFO, "MEM_RW: SET\n");
+ req->action = MLAN_ACT_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ reg_mem->param.mem_rw.addr = (t_u32)data[0];
+ if (data_length == 2)
+ reg_mem->param.mem_rw.value = (t_u32)data[1];
+
+ PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n",
+ (int)reg_mem->param.mem_rw.addr,
+ (int)reg_mem->param.mem_rw.value);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->action == MLAN_ACT_GET) {
+ if (copy_to_user(wrq->u.data.pointer,
+ &reg_mem->param.mem_rw.value, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get LOG
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_log(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_get_stats stats;
+ char *buf = NULL;
+ int i = 0;
+
+ ENTER();
+
+ PRINTM(MINFO, " GET STATS\n");
+ buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL);
+ if (!buf) {
+ PRINTM(MERROR, "kmalloc failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf,
+ "\n"
+ "mcasttxframe %u\n"
+ "failed %u\n"
+ "retry %u\n"
+ "multiretry %u\n"
+ "framedup %u\n"
+ "rtssuccess %u\n"
+ "rtsfailure %u\n"
+ "ackfailure %u\n"
+ "rxfrag %u\n"
+ "mcastrxframe %u\n"
+ "fcserror %u\n"
+ "txframe %u\n"
+ "wepicverrcnt-1 %u\n"
+ "wepicverrcnt-2 %u\n"
+ "wepicverrcnt-3 %u\n"
+ "wepicverrcnt-4 %u\n"
+ "beacon_rcnt %u\n"
+ "beacon_mcnt %u\n",
+ stats.mcast_tx_frame, stats.failed, stats.retry,
+ stats.multi_retry, stats.frame_dup, stats.rts_success,
+ stats.rts_failure, stats.ack_failure, stats.rx_frag,
+ stats.mcast_rx_frame, stats.fcs_error, stats.tx_frame,
+ stats.wep_icv_error[0], stats.wep_icv_error[1],
+ stats.wep_icv_error[2], stats.wep_icv_error[3],
+ stats.bcn_rcv_cnt, stats.bcn_miss_cnt);
+ if (priv->phandle->fw_getlog_enable) {
+ sprintf(buf + strlen(buf), "tx_frag_cnt %u\n",
+ stats.tx_frag_cnt);
+ sprintf(buf + strlen(buf), "qos_tx_frag_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_tx_frag_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_failed_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_failed_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_retry_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_retry_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_multi_retry_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_multi_retry_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_frm_dup_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_frm_dup_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_rts_suc_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_rts_suc_cnt[i]);
+ }
+ sprintf(buf + strlen(buf),
+ "\nqos_rts_failure_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_rts_failure_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_ack_failure_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_ack_failure_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_rx_frag_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_rx_frag_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_tx_frm_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_tx_frm_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_discarded_frm_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_discarded_frm_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_mpdus_rx_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_mpdus_rx_cnt[i]);
+ }
+ sprintf(buf + strlen(buf), "\nqos_retries_rx_cnt ");
+ for (i = 0; i < 8; i++) {
+ sprintf(buf + strlen(buf), "%u ",
+ stats.qos_retries_rx_cnt[i]);
+ }
+ sprintf(buf + strlen(buf),
+ "\nmgmt_ccmp_replays %u\n"
+ "tx_amsdu_cnt %u\n"
+ "failed_amsdu_cnt %u\n"
+ "retry_amsdu_cnt %u\n"
+ "multi_retry_amsdu_cnt %u\n"
+ "tx_octets_in_amsdu_cnt %llu\n"
+ "amsdu_ack_failure_cnt %u\n"
+ "rx_amsdu_cnt %u\n"
+ "rx_octets_in_amsdu_cnt %llu\n"
+ "tx_ampdu_cnt %u\n"
+ "tx_mpdus_in_ampdu_cnt %u\n"
+ "tx_octets_in_ampdu_cnt %llu\n"
+ "ampdu_rx_cnt %u\n"
+ "mpdu_in_rx_ampdu_cnt %u\n"
+ "rx_octets_in_ampdu_cnt %llu\n"
+ "ampdu_delimiter_crc_error_cnt %u\n",
+ stats.mgmt_ccmp_replays, stats.tx_amsdu_cnt,
+ stats.failed_amsdu_cnt, stats.retry_amsdu_cnt,
+ stats.multi_retry_amsdu_cnt,
+ stats.tx_octets_in_amsdu_cnt,
+ stats.amsdu_ack_failure_cnt, stats.rx_amsdu_cnt,
+ stats.rx_octets_in_amsdu_cnt,
+ stats.tx_ampdu_cnt, stats.tx_mpdus_in_ampdu_cnt,
+ stats.tx_octets_in_ampdu_cnt,
+ stats.ampdu_rx_cnt, stats.mpdu_in_rx_ampdu_cnt,
+ stats.rx_octets_in_ampdu_cnt,
+ stats.ampdu_delimiter_crc_error_cnt);
+ }
+ wrq->u.data.length = MIN(GETLOG_BUFSIZE - 1, strlen(buf) + 1);
+ if (copy_to_user(wrq->u.data.pointer, buf,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Deauthenticate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_deauth(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sockaddr saddr;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ /* Deauth mentioned BSSID */
+ if (copy_from_user(&saddr, wrq->u.data.pointer,
+ sizeof(saddr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT,
+ (t_u8 *)saddr.sa_data,
+ DEF_DEAUTH_REASON_CODE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE))
+ ret = -EFAULT;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX power configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_tx_power_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int data[5], user_data_len, copy_len;
+ int ret = 0;
+ mlan_bss_info bss_info;
+ mlan_ds_power_cfg *pcfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int power_data[MAX_POWER_TABLE_SIZE];
+ int i, power_ext_len = 0;
+ int *ptr = power_data;
+ mlan_power_group *pwr_grp = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ memset(data, 0, sizeof(data));
+ user_data_len = wrq->u.data.length;
+ copy_len = MIN(sizeof(data), sizeof(int) * user_data_len);
+
+ if (user_data_len) {
+ if (sizeof(int) * user_data_len > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ switch (user_data_len) {
+ case 1:
+ if (data[0] != 0xFF)
+ ret = -EINVAL;
+ break;
+ case 2:
+ case 4:
+ if (data[0] == 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ if (data[1] < bss_info.min_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[1], (int)bss_info.min_power_level,
+ (int)bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (user_data_len == 4) {
+ if (data[1] > data[2]) {
+ PRINTM(MERROR,
+ "Min power should be less than maximum!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] < 0) {
+ PRINTM(MERROR,
+ "Step should not less than 0!\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (data[2] > bss_info.max_power_level) {
+ PRINTM(MERROR,
+ "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
+ data[2],
+ (int)bss_info.min_power_level,
+ (int)bss_info.max_power_level);
+ ret = -EINVAL;
+ break;
+ }
+ if (data[3] > data[2] - data[1]) {
+ PRINTM(MERROR,
+ "Step should not greater than power difference!\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pcfg = (mlan_ds_power_cfg *)req->pbuf;
+ pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
+ req->req_id = MLAN_IOCTL_POWER_CFG;
+ if (!user_data_len)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ if (data[0] == 0xFF)
+ pcfg->param.power_ext.power_group[0].rate_format =
+ TX_PWR_CFG_AUTO_CTRL_OFF;
+ else {
+ pcfg->param.power_ext.power_group[0].power_step = 0;
+ pcfg->param.power_ext.power_group[0].first_rate_ind =
+ data[0];
+ pcfg->param.power_ext.power_group[0].last_rate_ind =
+ data[0];
+ if (data[0] <= 11) {
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_LG;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ } else if (data[0] <= 27) {
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_HT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW20;
+ pcfg->param.power_ext.power_group[0]
+ .first_rate_ind -= 12;
+ pcfg->param.power_ext.power_group[0]
+ .last_rate_ind -= 12;
+ } else if ((140 <= data[0]) && (data[0] <= 155)) {
+ pcfg->param.power_ext.power_group[0]
+ .rate_format = MLAN_RATE_FORMAT_HT;
+ pcfg->param.power_ext.power_group[0].bandwidth =
+ MLAN_HT_BW40;
+ pcfg->param.power_ext.power_group[0]
+ .first_rate_ind -= 140;
+ pcfg->param.power_ext.power_group[0]
+ .last_rate_ind -= 140;
+ }
+ if (user_data_len == 2) {
+ pcfg->param.power_ext.power_group[0].power_min =
+ data[1];
+ pcfg->param.power_ext.power_group[0].power_max =
+ data[1];
+ } else if (user_data_len == 4) {
+ pcfg->param.power_ext.power_group[0].power_min =
+ data[1];
+ pcfg->param.power_ext.power_group[0].power_max =
+ data[2];
+ pcfg->param.power_ext.power_group[0].power_step =
+ data[3];
+ }
+ pcfg->param.power_ext.num_pwr_grp = 1;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!user_data_len) {
+ /* GET operation */
+ i = 0;
+ power_ext_len = 0;
+ ptr = power_data;
+ while ((i < pcfg->param.power_ext.num_pwr_grp) &&
+ ((power_ext_len + 5) < MAX_POWER_TABLE_SIZE)) {
+ pwr_grp = &pcfg->param.power_ext.power_group[i];
+ if (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT) {
+ if (pwr_grp->bandwidth == MLAN_HT_BW20) {
+ pwr_grp->first_rate_ind += 12;
+ pwr_grp->last_rate_ind += 12;
+ } else if (pwr_grp->bandwidth == MLAN_HT_BW40) {
+ pwr_grp->first_rate_ind += 140;
+ pwr_grp->last_rate_ind += 140;
+ }
+ }
+
+ if ((pwr_grp->rate_format == MLAN_RATE_FORMAT_LG) ||
+ (pwr_grp->rate_format == MLAN_RATE_FORMAT_HT)) {
+ *ptr = pwr_grp->first_rate_ind;
+ ptr++;
+ *ptr = pwr_grp->last_rate_ind;
+ ptr++;
+ *ptr = pwr_grp->power_min;
+ ptr++;
+ *ptr = pwr_grp->power_max;
+ ptr++;
+ *ptr = pwr_grp->power_step;
+ ptr++;
+ power_ext_len += 5;
+ }
+ i++;
+ }
+ if (copy_to_user(wrq->u.data.pointer, (t_u8 *)power_data,
+ sizeof(int) * power_ext_len)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = power_ext_len;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx/Rx data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_txrx_rate(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, (t_u8 *)&rate->param.data_rate,
+ sizeof(int) * 2)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 2;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief Turn on/off the sdio clock
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_sdio_clock_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data = 2;
+ /* Initialize the clock state as on */
+ static int clock_state = 1;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ wrq->u.data.length = sizeof(clock_state) / sizeof(int);
+ if (copy_to_user(wrq->u.data.pointer, &clock_state,
+ sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ goto done;
+ }
+ switch (data) {
+ case CMD_DISABLED:
+ PRINTM(MINFO, "SDIO clock is turned off\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
+ clock_state = data;
+ break;
+ case CMD_ENABLED:
+ PRINTM(MINFO, "SDIO clock is turned on\n");
+ ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
+ clock_state = data;
+ break;
+ default:
+ ret = -EINVAL;
+ PRINTM(MINFO, "sdioclock: wrong parameter\n");
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO */
+
+/**
+ * @brief Set/Get beacon interval
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_beacon_interval(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ int bcn = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((bcn < MLAN_MIN_BEACON_INTERVAL) ||
+ (bcn > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ req->req_id = MLAN_IOCTL_BSS;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ bss->param.bcn_interval = bcn;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, (t_u8 *)&bss->param.bcn_interval,
+ sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get TX data rate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_txrate(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ int rateindex = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (wrq->u.data.length) {
+ if (copy_from_user(&rateindex, wrq->u.data.pointer,
+ sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ req->req_id = MLAN_IOCTL_RATE;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ if (rateindex == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((rateindex != MLAN_RATE_INDEX_MCS32) &&
+ ((rateindex < 0) ||
+ (rateindex > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = rateindex;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ } else {
+ if (wrq->u.data.length)
+ priv->rate_index = rateindex;
+ }
+ if (!wrq->u.data.length) {
+ if (rate->param.rate_cfg.is_rate_auto)
+ rateindex = AUTO_RATE;
+ else
+ rateindex = rate->param.rate_cfg.rate;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int)))
+ ret = -EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get region code
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_regioncode(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int region = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&region, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_MISC_REGION;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (!wrq->u.data.length)
+ req->action = MLAN_ACT_GET;
+ else {
+ req->action = MLAN_ACT_SET;
+ cfg->param.region_code = region;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &cfg->param.region_code,
+ sizeof(int)))
+ ret = -EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_radio(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_bss_info bss_info;
+ int option = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (wrq->u.data.length) {
+ /* Set radio */
+ if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
+ ret = -EFAULT;
+ } else {
+ /* Get radio status */
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, &bss_info.radio_on,
+ sizeof(bss_info.radio_on))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/**
+ * @brief Get/Set the bit mask of driver debug message control
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to wrq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_drv_dbg(moal_private *priv, struct iwreq *wrq)
+{
+ int data[4], copy_len;
+ int ret = 0;
+ int data_length = wrq->u.data.length;
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ if (!data_length) {
+ data[0] = drvdbg;
+ /* Return the current driver debug bit masks */
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ wrq->u.data.length = 1;
+ } else if (data_length < 3) {
+ /* Get the driver debug bit masks from user */
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto drvdbgexit;
+ }
+ drvdbg = data[0];
+ /* Set the driver debug bit masks into mlan */
+ woal_set_drvdbg(priv, drvdbg);
+ } else {
+ PRINTM(MERROR, "Invalid parameter number\n");
+ goto drvdbgexit;
+ }
+
+ printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+ printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO,
+ (drvdbg & MINFO) ? "X" : "");
+ printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN,
+ (drvdbg & MWARN) ? "X" : "");
+ printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
+ (drvdbg & MENTRY) ? "X" : "");
+#endif
+ printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
+ (drvdbg & MMPA_D) ? "X" : "");
+ printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D,
+ (drvdbg & MIF_D) ? "X" : "");
+ printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D,
+ (drvdbg & MFW_D) ? "X" : "");
+ printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
+ (drvdbg & MEVT_D) ? "X" : "");
+ printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
+ (drvdbg & MCMD_D) ? "X" : "");
+ printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
+ (drvdbg & MDAT_D) ? "X" : "");
+ printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D,
+ (drvdbg & MREG_D) ? "X" : "");
+ printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
+ (drvdbg & MIOCTL) ? "X" : "");
+ printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR,
+ (drvdbg & MINTR) ? "X" : "");
+ printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
+ (drvdbg & MEVENT) ? "X" : "");
+ printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND,
+ (drvdbg & MCMND) ? "X" : "");
+ printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA,
+ (drvdbg & MDATA) ? "X" : "");
+ printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
+ (drvdbg & MERROR) ? "X" : "");
+ printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
+ (drvdbg & MFATAL) ? "X" : "");
+ printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG,
+ (drvdbg & MMSG) ? "X" : "");
+
+drvdbgexit:
+ LEAVE();
+ return ret;
+}
+#endif /* DEBUG_LEVEL1 */
+
+/**
+ * @brief Set/Get QoS configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_qos_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_QOS;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ cfg->param.qos_cfg = (t_u8)data;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ data = (int)cfg->param.qos_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#ifndef OPCHAN
+/**
+ * @brief Set/Get WWS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_wws_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_misc_cfg *wws = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wws = (mlan_ds_misc_cfg *)req->pbuf;
+ wws->sub_command = MLAN_OID_MISC_WWS;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != CMD_DISABLED && data != CMD_ENABLED) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ wws->param.wws_cfg = data;
+ } else
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = wws->param.wws_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get sleep period
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_sleep_pd(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+ (data == 0) || (data == SLEEP_PERIOD_RESERVED_FF)) {
+ req->action = MLAN_ACT_SET;
+ pm_cfg->param.sleep_period = data;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ data = pm_cfg->param.sleep_period;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_sleep_params_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ mlan_ds_sleep_params *psleep_params = NULL;
+ int data[6] = {0}, i, copy_len;
+ int data_length = wrq->u.data.length;
+#ifdef DEBUG_LEVEL1
+ char err_str[][36] = {{"sleep clock error in ppm"},
+ {"wakeup offset in usec"},
+ {"clock stabilization time in usec"},
+ {"control periodic calibration(0-2)"},
+ {"control of external sleepClock(0-2)"},
+ {"value of reserved for debug"}};
+#endif
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm = (mlan_ds_pm_cfg *)req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;
+
+ if (data_length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 6) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+#define MIN_VAL 0x0000
+#define MAX_VAL 0xFFFF
+ for (i = 0; i < 6; i++) {
+ if ((i == 3) || (i == 4)) {
+ /* These two cases are handled below the loop */
+ continue;
+ }
+ if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
+ PRINTM(MERROR, "Invalid %s (0-65535)!\n",
+ err_str[i]);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ if (data[3] < 0 || data[3] > 2) {
+ PRINTM(MERROR,
+ "Invalid control periodic calibration (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data[4] < 0 || data[4] > 2) {
+ PRINTM(MERROR,
+ "Invalid control of external sleep clock (0-2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ psleep_params->error = data[0];
+ psleep_params->offset = data[1];
+ psleep_params->stable_time = data[2];
+ psleep_params->cal_control = data[3];
+ psleep_params->ext_sleep_clk = data[4];
+ psleep_params->reserved = data[5];
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = psleep_params->error;
+ data[1] = psleep_params->offset;
+ data[2] = psleep_params->stable_time;
+ data[3] = psleep_params->cal_control;
+ data[4] = psleep_params->ext_sleep_clk;
+ data[5] = psleep_params->reserved;
+ wrq->u.data.length = 6;
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get user provisioned local power constraint
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_11h_local_pwr_constraint(moal_private *priv,
+ struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ds_11hcfg->param.usr_local_power_constraint = (t_s8)data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ if (req->action == MLAN_ACT_GET) {
+ data = (int)ds_11hcfg->param.usr_local_power_constraint;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get HT stream configurations
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_ht_stream_cfg_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data != HT_STREAM_MODE_1X1 && data != HT_STREAM_MODE_2X2) {
+ PRINTM(MINFO, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ cfg->param.stream_cfg = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int)cfg->param.stream_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get MAC control configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_mac_control_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Validation will be done later */
+ cfg->param.mac_ctrl = data;
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int)cfg->param.mac_ctrl;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get thermal reading
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_thermal_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ if (wrq->u.data.length) {
+ PRINTM(MERROR, "Set is not supported for this command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_GET;
+
+ cfg->sub_command = MLAN_OID_MISC_THERMAL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy response to user */
+ data = (int)cfg->param.thermal;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get hotspot enable state
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_cfg_hotspot(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *cfg = NULL;
+ int config;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (wrq->u.data.length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ if (wrq->u.data.length == 0)
+ req->action = MLAN_ACT_GET;
+ else {
+ if (copy_from_user(&config, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfg->param.hotspot_cfg = config;
+ req->action = MLAN_ACT_SET;
+ }
+
+ cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ config = cfg->param.hotspot_cfg;
+ if (copy_to_user(wrq->u.data.pointer, &config, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(REASSOCIATION)
+/**
+ * @brief Set/Get reassociation settings
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_reassoc(moal_private *priv, struct iwreq *wrq)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ int data = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data == 0) {
+ handle->reassoc_on &= ~MBIT(priv->bss_index);
+ priv->reassoc_on = MFALSE;
+ priv->reassoc_required = MFALSE;
+ if (!handle->reassoc_on &&
+ handle->is_reassoc_timer_set == MTRUE) {
+ woal_cancel_timer(&handle->reassoc_timer);
+ handle->is_reassoc_timer_set = MFALSE;
+ }
+ } else {
+ handle->reassoc_on |= MBIT(priv->bss_index);
+ priv->reassoc_on = MTRUE;
+ }
+ } else {
+ data = (int)(priv->reassoc_on);
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* REASSOCIATION */
+
+/**
+ * @brief implement WMM enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_wmm_enable_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wmm_cfg *wmm = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ wmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
+
+ if (wrq->u.data.length) {
+ /* Set WMM configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ if (data == CMD_DISABLED)
+ wmm->param.wmm_enable = MFALSE;
+ else
+ wmm->param.wmm_enable = MTRUE;
+ } else {
+ /* Get WMM status */
+ req->action = MLAN_ACT_GET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &wmm->param.wmm_enable,
+ sizeof(wmm->param.wmm_enable))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D enable command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11d_enable_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
+ if (wrq->u.data.length) {
+ /* Set 11D configuration */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (data == CMD_DISABLED)
+ pcfg_11d->param.enable_11d = MFALSE;
+ else
+ pcfg_11d->param.enable_11d = MTRUE;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ &pcfg_11d->param.enable_11d,
+ sizeof(pcfg_11d->param.enable_11d))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Implement 802.11D clear chan table command
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_11d_clr_chan_table(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_11d_cfg *pcfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
+ req->action = MLAN_ACT_SET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq Pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_wps_cfg_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ char buf[8];
+ struct iwreq *wreq = (struct iwreq *)wrq;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, wreq->u.data.pointer,
+ MIN(sizeof(buf) - 1, wreq->u.data.length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (buf[0] == 1)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set WPA passphrase and SSID
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_passphrase(moal_private *priv, struct iwreq *wrq)
+{
+ t_u16 len = 0;
+ char buf[256];
+ char *begin = NULL, *end = NULL, *opt = NULL;
+ int ret = 0, action = -1, i;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
+ t_u8 *mac = NULL;
+ int data_length = wrq->u.data.length, copy_len;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ PRINTM(MERROR, "Not supported cmd on this card\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+ if (!data_length || data_length >= sizeof(buf) - 1) {
+ PRINTM(MERROR,
+ "Argument missing or too long for setpassphrase\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ memset(buf, 0, sizeof(buf));
+ copy_len = data_length;
+
+ if (copy_from_user(buf, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[copy_len] = '\0';
+
+ /* Parse the buf to get the cmd_action */
+ begin = buf;
+ end = woal_strsep(&begin, ';', '/');
+ if (!end) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ action = woal_atox(end);
+ if (action < 0 || action > 2 || end[1] != '\0') {
+ PRINTM(MERROR, "Invalid action argument %s\n", end);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ if (action == 0)
+ req->action = MLAN_ACT_GET;
+ else
+ req->action = MLAN_ACT_SET;
+ while (begin) {
+ end = woal_strsep(&begin, ';', '/');
+ opt = woal_strsep(&end, '=', '/');
+ if (!opt || !end || !end[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ break;
+ } else if (!strnicmp(opt, "ssid", strlen(opt))) {
+ if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR,
+ "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ break;
+ }
+ sec->param.passphrase.ssid.ssid_len = strlen(end);
+ moal_memcpy_ext(priv->phandle,
+ sec->param.passphrase.ssid.ssid, end,
+ strlen(end), MLAN_MAX_SSID_LENGTH);
+ PRINTM(MINFO, "ssid=%s, len=%d\n",
+ sec->param.passphrase.ssid.ssid,
+ (int)sec->param.passphrase.ssid.ssid_len);
+ } else if (!strnicmp(opt, "bssid", strlen(opt))) {
+ woal_mac2u8(sec->param.passphrase.bssid, end);
+ } else if (!strnicmp(opt, "psk", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PMK length\n");
+ ret = -EINVAL;
+ break;
+ }
+ woal_ascii2hex(
+ (t_u8 *)(sec->param.passphrase.psk.pmk.pmk),
+ end, MLAN_PMK_HEXSTR_LENGTH / 2);
+ sec->param.passphrase.psk_type = MLAN_PSK_PMK;
+ } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
+ req->action == MLAN_ACT_SET) {
+ if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
+ PRINTM(MERROR,
+ "Invalid length for passphrase\n");
+ ret = -EINVAL;
+ break;
+ }
+ sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
+ moal_memcpy_ext(
+ priv->phandle,
+ sec->param.passphrase.psk.passphrase.passphrase,
+ end,
+ sizeof(sec->param.passphrase.psk.passphrase
+ .passphrase),
+ sizeof(sec->param.passphrase.psk.passphrase
+ .passphrase));
+ sec->param.passphrase.psk.passphrase.passphrase_len =
+ strlen(end);
+ PRINTM(MINFO, "passphrase=%s, len=%d\n",
+ sec->param.passphrase.psk.passphrase.passphrase,
+ (int)sec->param.passphrase.psk.passphrase
+ .passphrase_len);
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ if (ret)
+ goto done;
+
+ if (action == 2)
+ sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
+ else if (action == 0)
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (action == 0) {
+ memset(buf, 0, sizeof(buf));
+ if (sec->param.passphrase.ssid.ssid_len) {
+ len += sprintf(buf + len, "ssid:");
+ moal_memcpy_ext(priv->phandle, buf + len,
+ sec->param.passphrase.ssid.ssid,
+ sec->param.passphrase.ssid.ssid_len,
+ sizeof(buf) - len);
+ len += sec->param.passphrase.ssid.ssid_len;
+ len += sprintf(buf + len, " ");
+ }
+ if (memcmp(&sec->param.passphrase.bssid, zero_mac,
+ sizeof(zero_mac))) {
+ mac = (t_u8 *)&sec->param.passphrase.bssid;
+ len += sprintf(buf + len, "bssid:");
+ for (i = 0; i < ETH_ALEN - 1; ++i)
+ len += sprintf(buf + len, "%02x:", mac[i]);
+ len += sprintf(buf + len, "%02x ", mac[i]);
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
+ len += sprintf(buf + len, "psk:");
+ for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
+ len += sprintf(
+ buf + len, "%02x",
+ sec->param.passphrase.psk.pmk.pmk[i]);
+ len += sprintf(buf + len, "\n");
+ }
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ len += sprintf(
+ buf + len, "passphrase:%s\n",
+ sec->param.passphrase.psk.passphrase.passphrase);
+ }
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, buf,
+ MIN(len, sizeof(buf)))) {
+ PRINTM(MERROR, "Copy to user failed, len %d\n",
+ len);
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = len;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get esupp mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_esupp_mode(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ PRINTM(MERROR, "Not supported cmd on this card\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, (t_u8 *)&sec->param.esupp_mode,
+ sizeof(int) * 3)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 3;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get GTK/PTK
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_key_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ unsigned int i;
+ t_u8 key_ascii[256];
+ t_u8 *tmp;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(key_ascii, 0x00, sizeof(key_ascii));
+ tmp = key_ascii;
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MERROR, "Can't get key in un-associated state\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Get Unicast Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = 0;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "PTK: ");
+ tmp += 5;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ /* Get Multicase Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "GTK: ");
+ tmp += 5;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ /* Get IGTK Key */
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
+ sec->param.encrypt_key.key_index = 0;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK;
+ memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (sec->param.encrypt_key.key_len) {
+ sprintf((char *)tmp, "\n%s", "IGTK: ");
+ tmp += 6;
+ for (i = 0; i < sec->param.encrypt_key.key_len; i++)
+ tmp += sprintf((char *)tmp, "%02x",
+ sec->param.encrypt_key.key_material[i]);
+ }
+
+ wrq->u.data.length = sizeof(key_ascii) + 1;
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &key_ascii,
+ tmp - key_ascii)) {
+ PRINTM(MERROR, "copy_to_user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/get IP address
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_ip_addr(moal_private *priv, struct iwreq *wrq)
+{
+ char buf[IPADDR_MAX_BUF];
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ int ret = 0, op_code = 0, data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(buf, 0, IPADDR_MAX_BUF);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+
+ if (data_length <= 1) { /* GET */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user(buf, wrq->u.data.pointer,
+ MIN(IPADDR_MAX_BUF - 1, data_length))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Make sure we have the operation argument */
+ if (data_length > 2 && buf[1] != ';') {
+ PRINTM(MERROR,
+ "No operation argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ buf[1] = '\0';
+ }
+ ioctl_req->action = MLAN_ACT_SET;
+ /* only one IP is supported in current firmware */
+ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
+ in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
+ misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
+ /* only one IP is supported in current firmware */
+ misc->param.ipaddr_cfg.ip_addr_num = 1;
+ misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
+ }
+ if (woal_atoi(&op_code, buf) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_IP_ADDR;
+
+ /* Send ioctl to mlan */
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ snprintf(buf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
+ misc->param.ipaddr_cfg.op_code,
+ misc->param.ipaddr_cfg.ip_addr[0][0],
+ misc->param.ipaddr_cfg.ip_addr[0][1],
+ misc->param.ipaddr_cfg.ip_addr[0][2],
+ misc->param.ipaddr_cfg.ip_addr[0][3]);
+ wrq->u.data.length = IPADDR_MAX_BUF;
+ if (copy_to_user(wrq->u.data.pointer, buf, IPADDR_MAX_BUF)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Transmit beamforming capabilities
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_tx_bf_cap_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11n_cfg *bf_cfg = NULL;
+ int bf_cap = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
+ req->action = MLAN_ACT_GET;
+ if (data_length) { /* SET */
+ if (copy_from_user(&bf_cap, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ bf_cfg->param.tx_bf_cap = bf_cap;
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ bf_cap = bf_cfg->param.tx_bf_cap;
+ if (copy_to_user(wrq->u.data.pointer, &bf_cap, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
+#define MAX_IN_OUT_CHAR 256
+/** Tx BF Global conf argument index */
+#define BF_ENABLE_PARAM 1
+#define SOUND_ENABLE_PARAM 2
+#define FB_TYPE_PARAM 3
+#define SNR_THRESHOLD_PARAM 4
+#define SOUND_INTVL_PARAM 5
+#define BF_MODE_PARAM 6
+#define MAX_TX_BF_GLOBAL_ARGS 6
+#define BF_CFG_ACT_GET 0
+#define BF_CFG_ACT_SET 1
+
+/**
+ * @brief Set/Get Transmit beamforming configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_tx_bf_cfg_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ int bf_action = 0, interval = 0;
+ int snr = 0, i, tmp_val = 0;
+ t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
+ t_u8 *str, *token, *pos;
+ t_u16 action = 0;
+
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ mlan_trigger_sound_args *bf_sound = NULL;
+ mlan_tx_bf_peer_args *tx_bf_peer = NULL;
+ mlan_snr_thr_args *bf_snr = NULL;
+ mlan_bf_periodicity_args *bf_periodicity = NULL;
+ mlan_bf_global_cfg_args *bf_global = NULL;
+
+ ENTER();
+
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+ /* Pointer to corresponding buffer */
+ bf_sound = bf_cfg.body.bf_sound;
+ tx_bf_peer = bf_cfg.body.tx_bf_peer;
+ bf_snr = bf_cfg.body.bf_snr;
+ bf_periodicity = bf_cfg.body.bf_periodicity;
+ bf_global = &bf_cfg.body.bf_global_cfg;
+
+ /* Total characters in buffer */
+ char_count = data_length - 1;
+ memset(buf, 0, sizeof(buf));
+ if (char_count) {
+ if (data_length > sizeof(buf)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, data_length)) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (char_count > 1 && buf[1] != ';') {
+ PRINTM(MERROR,
+ "No action argument. Separate with ';'\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Replace ';' with NULL in the string to separate args */
+ for (i = 0; i < char_count; i++) {
+ if (buf[i] == ';')
+ buf[i] = '\0';
+ }
+ /* The first byte represents the beamforming action */
+ if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ /* Eliminate action field */
+ token = &buf[2];
+ for (i = 1, str = &buf[2]; token != NULL; i++) {
+ token = strstr(str, " ");
+ pos = str;
+ if (token != NULL) {
+ *token = '\0';
+ str = token + 1;
+ }
+ woal_atoi(&tmp_val, pos);
+ switch (i) {
+ case BF_ENABLE_PARAM:
+ bf_global->bf_enbl =
+ (t_u8)tmp_val;
+ break;
+ case SOUND_ENABLE_PARAM:
+ bf_global->sounding_enbl =
+ (t_u8)tmp_val;
+ break;
+ case FB_TYPE_PARAM:
+ bf_global->fb_type =
+ (t_u8)tmp_val;
+ break;
+ case SNR_THRESHOLD_PARAM:
+ bf_global->snr_threshold =
+ (t_u8)tmp_val;
+ break;
+ case SOUND_INTVL_PARAM:
+ bf_global->sounding_interval =
+ (t_u16)tmp_val;
+ break;
+ case BF_MODE_PARAM:
+ bf_global->bf_mode =
+ (t_u8)tmp_val;
+ break;
+ default:
+ PRINTM(MERROR,
+ "Invalid Argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ break;
+ case TRIGGER_SOUNDING_FOR_PEER:
+ /*
+ * First arg = 2 BfAction
+ * Second arg = 17 MAC "00:50:43:20:BF:64"
+ */
+ if (char_count != 19) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ woal_mac2u8(bf_sound->peer_mac, &buf[2]);
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ break;
+ case SET_GET_BF_PERIODICITY:
+ /*
+ * First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 1 (min char) TX BF interval
+ * 10 (max char) u32 maximum value
+ * 4294967295
+ */
+ if (char_count < 19 || char_count > 30) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
+ if (char_count == 19) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ if (woal_atoi(&interval, &buf[20]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_periodicity->interval = interval;
+ }
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ /*
+ * Handle only SET operation here
+ * First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 2 enable/disable bf
+ * Fourth arg = 2 enable/disable sounding
+ * Fifth arg = 1 FB Type
+ */
+ if (char_count != 25 && char_count != 1) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
+ woal_atoi(&tmp_val, &buf[20]);
+ tx_bf_peer->bf_enbl = (t_u8)tmp_val;
+ woal_atoi(&tmp_val, &buf[22]);
+ tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
+ woal_atoi(&tmp_val, &buf[24]);
+ tx_bf_peer->fb_type = (t_u8)tmp_val;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ /*
+ * First arg = 2 BfAction
+ * Second arg = 18 MAC "00:50:43:20:BF:64;"
+ * Third arg = 1/2 SNR u8 - can be 1/2 charerters
+ */
+ if (char_count != 1 &&
+ !(char_count == 21 || char_count == 22)) {
+ PRINTM(MERROR, "Invalid argument\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (char_count == 1) {
+ action = MLAN_ACT_GET;
+ bf_cfg.action = BF_CFG_ACT_GET;
+ } else {
+ woal_mac2u8(bf_snr->peer_mac, &buf[2]);
+ if (woal_atoi(&snr, &buf[20]) !=
+ MLAN_STATUS_SUCCESS) {
+ ret = -EINVAL;
+ goto done;
+ }
+ bf_snr->snr = snr;
+ action = MLAN_ACT_SET;
+ bf_cfg.action = BF_CFG_ACT_SET;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Save the value */
+ bf_cfg.bf_action = bf_action;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ data_length = 0;
+ memset(buf, 0, sizeof(buf));
+ switch (bf_action) {
+ case BF_GLOBAL_CONFIGURATION:
+ data_length += sprintf(buf + data_length, "%d ",
+ (int)bf_global->bf_enbl);
+ data_length += sprintf(buf + data_length, "%d ",
+ (int)bf_global->sounding_enbl);
+ data_length += sprintf(buf + data_length, "%d ",
+ (int)bf_global->fb_type);
+ data_length += sprintf(buf + data_length, "%d ",
+ (int)bf_global->snr_threshold);
+ data_length +=
+ sprintf(buf + data_length, "%d ",
+ (int)bf_global->sounding_interval);
+ data_length += sprintf(buf + data_length, "%d ",
+ (int)bf_global->bf_mode);
+ break;
+ case SET_GET_BF_PERIODICITY:
+ data_length += sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_periodicity->peer_mac[0],
+ bf_periodicity->peer_mac[1],
+ bf_periodicity->peer_mac[2],
+ bf_periodicity->peer_mac[3],
+ bf_periodicity->peer_mac[4],
+ bf_periodicity->peer_mac[5]);
+ data_length += sprintf(buf + data_length, "%c", ' ');
+ data_length += sprintf(buf + data_length, "%d",
+ bf_periodicity->interval);
+ break;
+ case TX_BF_FOR_PEER_ENBL:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length +=
+ sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ tx_bf_peer->peer_mac[0],
+ tx_bf_peer->peer_mac[1],
+ tx_bf_peer->peer_mac[2],
+ tx_bf_peer->peer_mac[3],
+ tx_bf_peer->peer_mac[4],
+ tx_bf_peer->peer_mac[5]);
+ data_length +=
+ sprintf(buf + data_length, "%c", ' ');
+ data_length += sprintf(buf + data_length, "%d;",
+ tx_bf_peer->bf_enbl);
+ data_length +=
+ sprintf(buf + data_length, "%d;",
+ tx_bf_peer->sounding_enbl);
+ data_length += sprintf(buf + data_length, "%d ",
+ tx_bf_peer->fb_type);
+ tx_bf_peer++;
+ }
+ break;
+ case SET_SNR_THR_PEER:
+ for (i = 0; i < bf_cfg.no_of_peers; i++) {
+ data_length +=
+ sprintf(buf + data_length,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ bf_snr->peer_mac[0],
+ bf_snr->peer_mac[1],
+ bf_snr->peer_mac[2],
+ bf_snr->peer_mac[3],
+ bf_snr->peer_mac[4],
+ bf_snr->peer_mac[5]);
+ data_length +=
+ sprintf(buf + data_length, "%c", ';');
+ data_length += sprintf(buf + data_length, "%d",
+ bf_snr->snr);
+ data_length +=
+ sprintf(buf + data_length, "%c", ' ');
+ bf_snr++;
+ }
+ break;
+ }
+ buf[data_length] = '\0';
+ }
+
+ wrq->u.data.length = data_length;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Retrieve the scan response/beacon table
+ *
+ * @param wrq A pointer to iwreq structure
+ * @param scan_resp A pointer to mlan_scan_resp structure
+ * @param scan_start argument
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int moal_ret_get_scan_table_ioctl(struct iwreq *wrq,
+ mlan_scan_resp *scan_resp,
+ t_u32 scan_start)
+{
+ pBSSDescriptor_t pbss_desc, scan_table;
+ wlan_ioctl_get_scan_table_info *prsp_info;
+ int ret_code;
+ int ret_len;
+ int space_left;
+ t_u8 *pcurrent;
+ t_u8 *pbuffer_end;
+ t_u32 num_scans_done;
+
+ ENTER();
+
+ num_scans_done = 0;
+ ret_code = MLAN_STATUS_SUCCESS;
+
+ prsp_info = (wlan_ioctl_get_scan_table_info *)wrq->u.data.pointer;
+ pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;
+
+ pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1;
+ space_left = pbuffer_end - pcurrent;
+ scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);
+
+ PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
+ PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+ if (!scan_start) {
+ PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
+
+ /* Use to get current association saved descriptor */
+ pbss_desc = scan_table;
+
+ ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent,
+ &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS)
+ num_scans_done = 1;
+ } else {
+ scan_start--;
+
+ while (space_left &&
+ (scan_start + num_scans_done <
+ scan_resp->num_in_scan_table) &&
+ (ret_code == MLAN_STATUS_SUCCESS)) {
+ pbss_desc =
+ (scan_table + (scan_start + num_scans_done));
+
+ PRINTM(MINFO,
+ "GetScanTable: get current BSS Descriptor [%d]\n",
+ scan_start + num_scans_done);
+
+ ret_code = wlan_get_scan_table_ret_entry(
+ pbss_desc, &pcurrent, &space_left);
+
+ if (ret_code == MLAN_STATUS_SUCCESS)
+ num_scans_done++;
+ }
+ }
+
+ prsp_info->scan_number = num_scans_done;
+ ret_len = pcurrent - (t_u8 *)wrq->u.data.pointer;
+
+ wrq->u.data.length = ret_len;
+
+ /* Return ret_code (EFAULT or E2BIG) in the case where no scan results
+ * were successfully encoded.
+ */
+ LEAVE();
+ return num_scans_done ? MLAN_STATUS_SUCCESS : ret_code;
+}
+
+/**
+ * @brief Get scan table ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+static mlan_status woal_get_scan_table_ioctl(moal_private *priv,
+ struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ int scan_start = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *)req->pbuf;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_GET;
+
+ /* get the whole command from user */
+ if (copy_from_user(&scan_start, wrq->u.data.pointer,
+ sizeof(scan_start))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (scan_start > 0)
+ scan->sub_command = MLAN_OID_SCAN_NORMAL;
+ else
+ scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ status = moal_ret_get_scan_table_ioctl(
+ wrq, &scan->param.scan_resp, scan_start);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set user scan ext -- Async mode, without wait
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_set_user_scan_ext_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_user_scan_cfg scan_req;
+ ENTER();
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ if (copy_from_user(&scan_req, wrq->u.data.pointer,
+ MIN(wrq->u.data.length, sizeof(scan_req)))) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_req))
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set user scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+static mlan_status woal_set_user_scan_ioctl(moal_private *priv,
+ struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_scan *scan = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ union iwreq_data wrqu;
+ moal_handle *handle = priv->phandle;
+
+ ENTER();
+
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, request_scan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ handle->scan_pending_on_block = MTRUE;
+ handle->scan_priv = priv;
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) +
+ wrq->u.data.length);
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_USER_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ req->action = MLAN_ACT_SET;
+
+ if (copy_from_user(scan->param.user_scan.scan_cfg_buf,
+ wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+
+done:
+ handle->scan_pending_on_block = MFALSE;
+ handle->scan_priv = NULL;
+ MOAL_REL_SEMAPHORE(&handle->async_sem);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+#ifdef SDIO
+/**
+ * @brief Cmd52 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_cmd52rdwr_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ t_u8 rw = 0, func, data = 0;
+ int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
+ int data_length = wrq->u.data.length;
+
+ ENTER();
+
+ if (data_length < 2 || data_length > 3) {
+ PRINTM(MERROR, "Invalid number of arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, wrq->u.data.pointer,
+ sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8)buf[0];
+ if (func > 7) {
+ PRINTM(MERROR, "Invalid function number!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ reg = (t_u32)buf[1];
+ if (data_length == 2) {
+ rw = 0; /* CMD52 read */
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ }
+ if (data_length == 3) {
+ rw = 1; /* CMD52 write */
+ data = (t_u8)buf[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
+ func, reg, data);
+ }
+
+ if (!rw) {
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ data = sdio_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ else
+ data = sdio_f0_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_readb: reading register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_read_ioreg: reading register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+ } else {
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_writeb: writing register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_write_ioreg: writing register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+ }
+
+ buf[0] = data;
+ wrq->u.data.length = 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, sizeof(int))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Cmd53 read/write register
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_cmd53rdwr_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ t_u8 *buf = NULL;
+ t_u8 rw, func, mode;
+ t_u16 blklen = 0, blknum = 0;
+ int reg = 0, pattern_len = 0, pos = 0, ret = MLAN_STATUS_SUCCESS;
+ t_u32 total_len = 0;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ buf = kmalloc(WOAL_2K_BYTES, GFP_KERNEL);
+ if (!buf) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ data = kmalloc(WOAL_2K_BYTES, GFP_KERNEL);
+ if (!data) {
+ PRINTM(MERROR, "Cannot allocate buffer for command!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (wrq->u.data.length > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Data lengh is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ rw = buf[0]; /* read/write (0/1) */
+ func = buf[1]; /* func (0/1/2) */
+ reg = buf[5]; /* address */
+ reg = (reg << 8) + buf[4];
+ reg = (reg << 8) + buf[3];
+ reg = (reg << 8) + buf[2];
+ mode = buf[6]; /* byte mode/block mode (0/1) */
+ blklen = buf[8]; /* block size */
+ blklen = (blklen << 8) + buf[7];
+ blknum = buf[10]; /* block number or byte number */
+ blknum = (blknum << 8) + buf[9];
+
+ if (mode != BYTE_MODE)
+ mode = BLOCK_MODE;
+ total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
+ if (total_len > WOAL_2K_BYTES) {
+ PRINTM(MERROR, "Total data length is too large!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO,
+ "CMD53 read/write, func = %d, addr = %#x, mode = %d, block size = %d, block(byte) number = %d\n",
+ func, reg, mode, blklen, blknum);
+
+ if (!rw) {
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (sdio_readsb(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func,
+ data, reg, total_len))
+ PRINTM(MERROR,
+ "sdio_readsb: reading memory 0x%x failed\n",
+ reg);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+
+ if (copy_to_user(wrq->u.data.pointer, data, total_len)) {
+ PRINTM(MINFO, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = total_len;
+ } else {
+ pattern_len = wrq->u.data.length - 11;
+ if (pattern_len > total_len)
+ pattern_len = total_len;
+ memset(data, 0, WOAL_2K_BYTES);
+
+ /* Copy/duplicate the pattern to data buffer */
+ for (pos = 0; pos < total_len; pos++)
+ data[pos] = buf[11 + (pos % pattern_len)];
+
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (sdio_writesb(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func,
+ reg, data, total_len))
+ PRINTM(MERROR,
+ "sdio_writesb: writing memory 0x%x failed\n",
+ reg);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ }
+
+done:
+ kfree(buf);
+ kfree(data);
+ LEAVE();
+ return ret;
+}
+#endif /* SDIO */
+
+#ifdef SDIO
+/**
+ * @brief Set SDIO Multi-point aggregation control parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0/MLAN_STATUS_PENDING --success, otherwise fail
+ */
+static int woal_do_sdio_mpa_ctrl(moal_private *priv, struct iwreq *wrq)
+{
+ int data[6], data_length = wrq->u.data.length, copy_len;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+
+ misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ /* Get the values first, then modify these values if
+ * user had modified them */
+
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data_length == 0) {
+ data[0] = misc->param.mpa_ctrl.tx_enable;
+ data[1] = misc->param.mpa_ctrl.rx_enable;
+ data[2] = misc->param.mpa_ctrl.tx_buf_size;
+ data[3] = misc->param.mpa_ctrl.rx_buf_size;
+ data[4] = misc->param.mpa_ctrl.tx_max_ports;
+ data[5] = misc->param.mpa_ctrl.rx_max_ports;
+
+ PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
+ data[1], data[2], data[3], data[4], data[5]);
+
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = ARRAY_SIZE(data);
+ goto done;
+ }
+
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MINFO, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ switch (data_length) {
+ case 6:
+ misc->param.mpa_ctrl.rx_max_ports = data[5];
+ /* fall through */
+ case 5:
+ misc->param.mpa_ctrl.tx_max_ports = data[4];
+ /* fall through */
+ case 4:
+ misc->param.mpa_ctrl.rx_buf_size = data[3];
+ /* fall through */
+ case 3:
+ misc->param.mpa_ctrl.tx_buf_size = data[2];
+ /* fall through */
+ case 2:
+ misc->param.mpa_ctrl.rx_enable = data[1];
+ /* fall through */
+ case 1:
+ /* Set cmd */
+ req->action = MLAN_ACT_SET;
+
+ PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
+ data[1], data[2], data[3], data[4], data[5]);
+
+ misc->param.mpa_ctrl.tx_enable = data[0];
+ break;
+ default:
+ PRINTM(MERROR, "Default case error\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set/Get scan configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_scan_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data[7], copy_len;
+ mlan_ds_scan *scan = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int arg_len = 0;
+
+ ENTER();
+ arg_len = 7;
+ if (data_length > arg_len) {
+ PRINTM(MERROR, "Too much arguments\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ copy_len = sizeof(int) * data_length;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ scan = (mlan_ds_scan *)req->pbuf;
+ scan->sub_command = MLAN_OID_SCAN_CONFIG;
+ req->req_id = MLAN_IOCTL_SCAN;
+ memset(data, 0, sizeof(data));
+
+ if (data_length) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) {
+ PRINTM(MERROR, "Invalid argument for scan type\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) {
+ PRINTM(MERROR, "Invalid argument for scan mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[2] < 0) || (data[2] > MAX_PROBES)) {
+ PRINTM(MERROR, "Invalid argument for scan probes\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if (((data[3] < 0) ||
+ (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[4] < 0) ||
+ (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) ||
+ ((data[5] < 0) ||
+ (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) {
+ PRINTM(MERROR, "Invalid argument for scan time\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[6] < 0) || (data[6] > 1)) {
+ PRINTM(MERROR, "Invalid argument for extended scan\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
+ sizeof(data), sizeof(scan->param.scan_cfg));
+ } else
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!data_length) {
+ moal_memcpy_ext(priv->phandle, data, &scan->param.scan_cfg,
+ sizeof(scan->param.scan_cfg), sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = arg_len;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get PS configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_ps_cfg(moal_private *priv, struct iwreq *wrq)
+{
+ int data[7], copy_len, ret = 0;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ioctl_req *req = NULL;
+ int allowed = 3;
+ int i = 3;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ allowed++; /* For beacon missing timeout parameter */
+ allowed += 2; /* For delay to PS and PS mode parameters */
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (data_length > allowed) {
+ ret = -EINVAL;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ memset(data, 0, sizeof(data));
+
+ if (data_length) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((data[0] < PS_NULL_DISABLE)) {
+ PRINTM(MERROR,
+ "Invalid argument for PS null interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) &&
+ (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) &&
+ ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) ||
+ (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
+ PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) &&
+ (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
+ PRINTM(MERROR,
+ "Invalid argument for listen interval\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((data[i] != DISABLE_BCN_MISS_TO) &&
+ ((data[i] < MIN_BCN_MISS_TO) ||
+ (data[i] > MAX_BCN_MISS_TO))) {
+ PRINTM(MERROR,
+ "Invalid argument for beacon miss timeout\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if (data_length < allowed - 1)
+ data[i] = DELAY_TO_PS_UNCHANGED;
+ else if ((data[i] < MIN_DELAY_TO_PS) ||
+ (data[i] > MAX_DELAY_TO_PS)) {
+ PRINTM(MERROR, "Invalid argument for delay to PS\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ if ((data[i] != PS_MODE_UNCHANGED) &&
+ (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) &&
+ (data[i] != PS_MODE_NULL)) {
+ PRINTM(MERROR, "Invalid argument for PS mode\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ i++;
+ req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data,
+ sizeof(data), sizeof(pm_cfg->param.ps_cfg));
+ } else
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg,
+ MIN((sizeof(int) * allowed),
+ sizeof(pm_cfg->param.ps_cfg)),
+ sizeof(data));
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = allowed;
+
+ if (req->action == MLAN_ACT_SET) {
+ pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
+ pm_cfg->param.ps_mode = 1;
+ req->req_id = MLAN_IOCTL_PM_CFG;
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ * Receive a ADDTS command from the application. The command structure
+ * contains a TSPEC and timeout in milliseconds. The timeout is performed
+ * in the firmware after the ADDTS command frame is sent.
+ *
+ * The TSPEC is received in the API as an opaque block. The firmware will
+ * send the entire data block, including the bytes after the TSPEC. This
+ * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
+ * action frame.
+ *
+ * The IOCTL structure contains two return fields:
+ * - The firmware command result, which indicates failure and timeouts
+ * - The IEEE Status code which contains the corresponding value from
+ * any ADDTS response frame received.
+ *
+ * In addition, the opaque TSPEC data block passed in is replaced with the
+ * TSPEC received in the ADDTS response frame. In case of failure, the
+ * AP may modify the TSPEC on return and in the case of success, the
+ * medium time is returned as calculated by the AP. Along with the TSPEC,
+ * any IEs that are sent in the ADDTS response are also returned and can be
+ * parsed using the IOCTL length as an indicator of extra elements.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure or AP negotiation failure via the commandResult field copied
+ * back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_addts_req_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_addts_req_t addts_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
+
+ memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&addts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length,
+ sizeof(addts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.addts.timeout = addts_ioctl.timeout_ms;
+ cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;
+
+ if (cfg->param.addts.ie_data_len >
+ sizeof(cfg->param.addts.ie_data)) {
+ PRINTM(MERROR, "IE data length too large\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data,
+ addts_ioctl.ie_data,
+ cfg->param.addts.ie_data_len,
+ sizeof(cfg->param.addts.ie_data));
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ addts_ioctl.cmd_result = cfg->param.addts.result;
+ addts_ioctl.ieee_status_code =
+ (t_u8)cfg->param.addts.status_code;
+ addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
+
+ moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data,
+ cfg->param.addts.ie_data,
+ cfg->param.addts.ie_data_len,
+ sizeof(addts_ioctl.ie_data));
+
+ wrq->u.data.length =
+ (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) +
+ cfg->param.addts.ie_data_len);
+
+ if (copy_to_user(wrq->u.data.pointer, &addts_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ * Receive a DELTS command from the application. The command structure
+ * contains a TSPEC and reason code along with space for a command result
+ * to be returned. The information is packaged is sent to the wlan_cmd.c
+ * firmware command prep and send routines for execution in the firmware.
+ *
+ * The reason code is not used for WMM implementations but is indicated in
+ * the 802.11e specification.
+ *
+ * The return value to the application layer indicates a driver execution
+ * success or failure. A successful return could still indicate a firmware
+ * failure via the cmd_result field copied back to the application.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_delts_req_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *cfg = NULL;
+ wlan_ioctl_wmm_delts_req_t delts_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ cfg = (mlan_ds_wmm_cfg *)req->pbuf;
+ cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
+
+ memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&delts_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length,
+ sizeof(delts_ioctl)))) {
+ PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ cfg->param.delts.status_code =
+ (t_u32)delts_ioctl.ieee_reason_code;
+ cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;
+
+ if ((cfg->param.delts.ie_data_len) >
+ sizeof(cfg->param.delts.ie_data)) {
+ PRINTM(MERROR, "IE data length too large\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data,
+ delts_ioctl.ie_data,
+ cfg->param.delts.ie_data_len,
+ sizeof(cfg->param.delts.ie_data));
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Return the firmware command result back to the application
+ * layer */
+ delts_ioctl.cmd_result = cfg->param.delts.result;
+ wrq->u.data.length = sizeof(delts_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &delts_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ * Receive a AC Queue configuration command which is used to get, set, or
+ * default the parameters associated with a specific WMM AC Queue.
+ *
+ * @param priv Pointer to the mlan_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_config_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_queue_config_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_config *pqcfg = NULL;
+ wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
+
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length,
+ sizeof(qcfg_ioctl)))) {
+ PRINTM(MERROR, "QCONFIG: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pqcfg->action = qcfg_ioctl.action;
+ pqcfg->access_category = qcfg_ioctl.access_category;
+ pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
+ qcfg_ioctl.action = pqcfg->action;
+ qcfg_ioctl.access_category = pqcfg->access_category;
+ qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
+ wrq->u.data.length = sizeof(qcfg_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &qcfg_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ * Receive a AC Queue statistics command from the application for a specific
+ * WMM AC. The command can:
+ * - Turn stats on
+ * - Turn stats off
+ * - Collect and clear the stats
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_stats_t struct
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_queue_stats_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ mlan_ds_wmm_queue_stats *pqstats = NULL;
+ wlan_ioctl_wmm_queue_stats_t qstats_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS;
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ pqstats = (mlan_ds_wmm_queue_stats *)&pwmm->param.q_stats;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length,
+ sizeof(qstats_ioctl)))) {
+ PRINTM(MERROR, "QSTATS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, (void *)pqstats,
+ (void *)&qstats_ioctl, sizeof(qstats_ioctl),
+ sizeof(qstats_ioctl));
+ PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action,
+ qstats_ioctl.user_priority);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl));
+ moal_memcpy_ext(priv->phandle, (void *)&qstats_ioctl,
+ (void *)pqstats, sizeof(qstats_ioctl),
+ sizeof(qstats_ioctl));
+ wrq->u.data.length = sizeof(qstats_ioctl);
+
+ if (copy_to_user(wrq->u.data.pointer, &qstats_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ * Return the following information for each WMM AC:
+ * - WMM IE Acm Required
+ * - Firmware Flow Required
+ * - Firmware Flow Established
+ * - Firmware Queue Enabled
+ * - Firmware Delivery Enabled
+ * - Firmware Trigger Enabled
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_queue_status_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
+
+ if (wrq->u.data.length == sizeof(qstatus_ioctl)) {
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
+ moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl,
+ (void *)&pwmm->param.q_status,
+ sizeof(qstatus_ioctl), sizeof(qstatus_ioctl));
+ wrq->u.data.length = sizeof(qstatus_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &qstatus_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "QSTATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the
+ * wlan_ioctl_wmm_ts_status_t struct for request
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_wmm_ts_status_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_wmm_cfg *pwmm = NULL;
+ wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_WMM_CFG;
+ pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
+ pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+
+ if (wrq->u.data.length == sizeof(ts_status_ioctl)) {
+ if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer,
+ MIN(wrq->u.data.length,
+ sizeof(ts_status_ioctl)))) {
+ PRINTM(MERROR, "TS_STATUS: copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
+ pwmm->param.ts_status.tid = ts_status_ioctl.tid;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
+ moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl,
+ (void *)&pwmm->param.ts_status,
+ sizeof(ts_status_ioctl),
+ sizeof(ts_status_ioctl));
+ wrq->u.data.length = sizeof(ts_status_ioctl);
+ } else {
+ wrq->u.data.length = 0;
+ }
+
+ if (copy_to_user(wrq->u.data.pointer, &ts_status_ioctl,
+ wrq->u.data.length)) {
+ PRINTM(MERROR, "TS_STATUS: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Private IOCTL entry to get the By-passed TX packet from upper layer
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure containing the packet
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int woal_bypassed_packet_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ struct sk_buff *skb = NULL;
+ struct ethhdr *eth;
+ t_u16 moreLen = 0, copyLen = 0;
+ ENTER();
+
+#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
+
+ copyLen = wrq->u.data.length;
+ moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET +
+ sizeof(mlan_buffer);
+
+ skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
+ if (skb == NULL) {
+ PRINTM(MERROR, "kmalloc no memory !!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, moreLen);
+
+ if (copy_from_user(skb_put(skb, copyLen), wrq->u.data.pointer,
+ copyLen)) {
+ PRINTM(MERROR, "PortBlock: copy from user failed\n");
+ dev_kfree_skb_any(skb);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ eth = (struct ethhdr *)skb->data;
+ eth->h_proto = __constant_htons(eth->h_proto);
+ skb->dev = priv->netdev;
+
+ HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
+
+ woal_hard_start_xmit(skb, priv->netdev);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get auth type
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_auth_type(moal_private *priv, struct iwreq *wrq)
+{
+ int auth_type;
+ t_u32 auth_mode;
+ int ret = 0;
+
+ ENTER();
+ if (wrq->u.data.length == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ auth_type = auth_mode;
+ if (copy_to_user(wrq->u.data.pointer, &auth_type,
+ sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ } else {
+ if (copy_from_user(&auth_type, wrq->u.data.pointer,
+ sizeof(auth_type))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
+ if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
+ (auth_type > MLAN_AUTH_MODE_SHARED)) &&
+ (auth_type != MLAN_AUTH_MODE_AUTO)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ auth_mode = auth_type;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Port Control mode
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_port_ctrl(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+
+ if (wrq->u.data.length) {
+ if (copy_from_user(&sec->param.port_ctrl_enabled,
+ wrq->u.data.pointer, sizeof(int)) != 0) {
+ PRINTM(MERROR, "port_ctrl:Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!wrq->u.data.length) {
+ if (copy_to_user(wrq->u.data.pointer,
+ &sec->param.port_ctrl_enabled, sizeof(int))) {
+ PRINTM(MERROR, "port_ctrl:Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get DFS Testing settings
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_dfs_testing(moal_private *priv, struct iwreq *wrq)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+ int ret = 0;
+ int data[4], copy_len;
+ int data_length = wrq->u.data.length;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else if (data_length == 4) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if ((unsigned)data[0] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user CAC is 65535 msec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[1] > 0xFFFF) {
+ PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((unsigned)data[3] > 0xFF) {
+ PRINTM(MERROR,
+ "The maximum user fixed channel is 255.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
+ (t_u16)data[0];
+ ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
+ (t_u16)data[1];
+ ds_11hcfg->param.dfs_testing.usr_no_chan_change =
+ data[2] ? 1 : 0;
+ ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
+ priv->phandle->cac_period_jiffies = (t_u16)data[0] * HZ / 1000;
+ req->action = MLAN_ACT_SET;
+ } else {
+ PRINTM(MERROR, "Invalid number of args!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
+ data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
+ data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
+ data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * 4)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 4;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Mgmt Frame passthru mask
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_mgmt_frame_passthru_ctrl(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0, data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *mgmt_cfg = NULL;
+ int mask = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (data_length > 1) {
+ PRINTM(MERROR, "Invalid no of arguments!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
+
+ if (data_length) { /* SET */
+ if (copy_from_user(&mask, wrq->u.data.pointer, sizeof(int))) {
+ PRINTM(MERROR, "copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mgmt_cfg->param.mgmt_subtype_mask = mask;
+ req->action = MLAN_ACT_SET;
+ } else {
+ req->action = MLAN_ACT_GET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mask = mgmt_cfg->param.mgmt_subtype_mask;
+ if (copy_to_user(wrq->u.data.pointer, &mask, sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = 1;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get CFP table codes
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_cfp_code(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ int data[2], copy_len;
+ int data_length = wrq->u.data.length;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_ds_misc_cfp_code *cfp_code = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (data_length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ cfp_code = &misc_cfg->param.cfp_code;
+ misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!data_length) {
+ req->action = MLAN_ACT_GET;
+ } else {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ cfp_code->cfp_code_bg = data[0];
+ if (data_length == 2)
+ cfp_code->cfp_code_a = data[1];
+ req->action = MLAN_ACT_SET;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!data_length) {
+ data[0] = cfp_code->cfp_code_bg;
+ data[1] = cfp_code->cfp_code_a;
+ data_length = 2;
+ if (copy_to_user(wrq->u.data.pointer, &data,
+ sizeof(int) * data_length)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ wrq->u.data.length = data_length;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Tx/Rx antenna
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_get_tx_rx_ant(moal_private *priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *req = NULL;
+ int data[3] = {0};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ int copy_len;
+
+ ENTER();
+
+ if (wrq->u.data.length > 2) {
+ PRINTM(MERROR, "Invalid number of argument!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (wrq->u.data.length * sizeof(int) > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), wrq->u.data.length * sizeof(int));
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (wrq->u.data.length) {
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ radio->param.ant_cfg.tx_antenna = data[0];
+ radio->param.ant_cfg.rx_antenna = data[0];
+ if (wrq->u.data.length == 2)
+ radio->param.ant_cfg.rx_antenna = data[1];
+ } else {
+ radio->param.ant_cfg_1x1.antenna = data[0];
+ if (wrq->u.data.length == 2)
+ radio->param.ant_cfg_1x1.evaluate_time =
+ data[1];
+ }
+ req->action = MLAN_ACT_SET;
+ } else
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!wrq->u.data.length) {
+ wrq->u.data.length = 1;
+ if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
+ data[0] = radio->param.ant_cfg.tx_antenna;
+ data[1] = radio->param.ant_cfg.rx_antenna;
+ if (data[0] && data[1] && (data[0] != data[1]))
+ wrq->u.data.length = 2;
+ } else {
+ data[0] = (int)radio->param.ant_cfg_1x1.antenna;
+ data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
+ data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
+ if (data[0] == 0xffff && data[2] > 0)
+ wrq->u.data.length = 3;
+ else if (data[0] == 0xffff)
+ wrq->u.data.length = 2;
+ }
+ if (copy_to_user(wrq->u.data.pointer, data,
+ wrq->u.data.length * sizeof(int))) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure gpio independent reset
+ *
+ * @param priv A pointer to moal_private structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_ind_rst_ioctl(moal_private *priv, struct iwreq *wrq)
+{
+ int data[2], data_length = wrq->u.data.length, copy_len;
+ int ret = 0;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (sizeof(int) * wrq->u.data.length > sizeof(data)) {
+ PRINTM(MERROR, "Too many arguments\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ copy_len = MIN(sizeof(data), sizeof(int) * data_length);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ memset(misc, 0, sizeof(mlan_ds_misc_cfg));
+
+ misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (data_length == 0) {
+ req->action = MLAN_ACT_GET;
+ } else if ((data_length == 1) || (data_length == 2)) {
+ req->action = MLAN_ACT_SET;
+
+ if (copy_from_user(data, wrq->u.data.pointer, copy_len)) {
+ /* copy_from_user failed */
+ PRINTM(MERROR, "S_PARAMS: copy from user failed\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* ir_mode */
+ if (data[0] < 0 || data[0] > 2) {
+ PRINTM(MERROR, "Invalid ir mode parameter (0/1/2)!\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ind_rst_cfg.ir_mode = data[0];
+
+ /* gpio_pin */
+ if (data_length == 2) {
+ if ((data[1] != 0xFF) && (data[1] < 0)) {
+ PRINTM(MERROR, "Invalid gpio pin no !\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ misc->param.ind_rst_cfg.gpio_pin = data[1];
+ }
+
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ data[0] = misc->param.ind_rst_cfg.ir_mode;
+ data[1] = misc->param.ind_rst_cfg.gpio_pin;
+ wrq->u.data.length = 2;
+
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) * wrq->u.data.length)) {
+ PRINTM(MERROR, "QCONFIG: copy to user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *)req;
+ int ret = 0;
+
+ if (!IS_STA_WEXT(priv->phandle->params.cfg80211_wext))
+ return -EOPNOTSUPP;
+
+ ENTER();
+
+ PRINTM(MINFO, "woal_wext_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WOAL_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_VERSION: /* Get driver version */
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_VEREXT: /* Get extended driver version */
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_WARMRESET:
+ ret = woal_warm_reset(priv);
+ break;
+#ifdef USB
+#ifdef CONFIG_USB_SUSPEND
+ case WOAL_USB_SUSPEND:
+ ret = woal_enter_usb_suspend(priv->phandle);
+ break;
+ case WOAL_USB_RESUME:
+ ret = woal_exit_usb_suspend(priv->phandle);
+ break;
+#endif /* CONFIG_USB_SUSPEND */
+#endif
+ case WOAL_11D_CLR_CHAN_TABLE:
+ ret = woal_11d_clr_chan_table(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_SET_GET_TXRATE:
+ ret = woal_set_get_txrate(priv, wrq);
+ break;
+ case WOAL_SET_GET_REGIONCODE:
+ ret = woal_set_get_regioncode(priv, wrq);
+ break;
+ case WOAL_SET_RADIO:
+ ret = woal_set_get_radio(priv, wrq);
+ break;
+ case WOAL_WMM_ENABLE:
+ ret = woal_wmm_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_11D_ENABLE:
+ ret = woal_11d_enable_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_GET_QOS_CFG:
+ ret = woal_set_get_qos_cfg(priv, wrq);
+ break;
+#if defined(REASSOCIATION)
+ case WOAL_SET_GET_REASSOC:
+ ret = woal_set_get_reassoc(priv, wrq);
+ break;
+#endif /* REASSOCIATION */
+ case WOAL_TXBUF_CFG:
+ ret = woal_txbuf_cfg(priv, wrq);
+ break;
+#ifndef OPCHAN
+ case WOAL_SET_GET_WWS_CFG:
+ ret = woal_wws_cfg(priv, wrq);
+ break;
+#endif
+ case WOAL_SLEEP_PD:
+ ret = woal_sleep_pd(priv, wrq);
+ break;
+ case WOAL_AUTH_TYPE:
+ ret = woal_auth_type(priv, wrq);
+ break;
+ case WOAL_PORT_CTRL:
+ ret = woal_port_ctrl(priv, wrq);
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+#endif
+#endif
+ case WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT:
+ ret = woal_set_get_11h_local_pwr_constraint(priv, wrq);
+ break;
+ case WOAL_HT_STREAM_CFG:
+ ret = woal_ht_stream_cfg_ioctl(priv, wrq);
+ break;
+ case WOAL_MAC_CONTROL:
+ ret = woal_mac_control_ioctl(priv, wrq);
+ break;
+ case WOAL_THERMAL:
+ ret = woal_thermal_ioctl(priv, wrq);
+ break;
+ case WOAL_CFG_HOTSPOT:
+ ret = woal_cfg_hotspot(priv, wrq);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_SIXTEEN_INT:
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_TX_POWERCFG:
+ ret = woal_tx_power_cfg(priv, wrq);
+ break;
+#ifdef DEBUG_LEVEL1
+ case WOAL_DRV_DBG:
+ ret = woal_drv_dbg(priv, wrq);
+ break;
+#endif
+ case WOAL_BEACON_INTERVAL:
+ ret = woal_beacon_interval(priv, wrq);
+ break;
+ case WOAL_SIGNAL:
+ ret = woal_get_signal(priv, wrq);
+ break;
+ case WOAL_DEEP_SLEEP:
+ ret = woal_deep_sleep_ioctl(priv, wrq);
+ break;
+ case WOAL_11N_TX_CFG:
+ ret = woal_11n_tx_cfg(priv, wrq);
+ break;
+ case WOAL_11N_AMSDU_AGGR_CTRL:
+ ret = woal_11n_amsdu_aggr_ctrl(priv, wrq);
+ break;
+ case WOAL_11N_HTCAP_CFG:
+ ret = woal_11n_htcap_cfg(priv, wrq);
+ break;
+ case WOAL_PRIO_TBL:
+ ret = woal_11n_prio_tbl(priv, wrq);
+ break;
+ case WOAL_ADDBA_UPDT:
+ ret = woal_addba_para_updt(priv, wrq);
+ break;
+ case WOAL_ADDBA_REJECT:
+ ret = woal_addba_reject(priv, wrq);
+ break;
+ case WOAL_TX_BF_CAP:
+ ret = woal_tx_bf_cap_ioctl(priv, wrq);
+ break;
+ case WOAL_HS_CFG:
+ ret = woal_hs_cfg(priv, wrq, MTRUE);
+ break;
+ case WOAL_HS_SETPARA:
+ ret = woal_hs_setpara(priv, wrq);
+ break;
+ case WOAL_REG_READ_WRITE:
+ ret = woal_reg_read_write(priv, wrq);
+ break;
+ case WOAL_INACTIVITY_TIMEOUT_EXT:
+ ret = woal_inactivity_timeout_ext(priv, wrq);
+ break;
+#ifdef SDIO
+ case WOAL_SDIO_CLOCK:
+ ret = woal_sdio_clock_ioctl(priv, wrq);
+ break;
+ case WOAL_CMD_52RDWR:
+ ret = woal_cmd52rdwr_ioctl(priv, wrq);
+ break;
+ case WOAL_SDIO_MPA_CTRL:
+ ret = woal_do_sdio_mpa_ctrl(priv, wrq);
+ break;
+#endif
+ case WOAL_BAND_CFG:
+ ret = woal_band_cfg(priv, wrq);
+ break;
+ case WOAL_SCAN_CFG:
+ ret = woal_set_get_scan_cfg(priv, wrq);
+ break;
+ case WOAL_PS_CFG:
+ ret = woal_set_get_ps_cfg(priv, wrq);
+ break;
+ case WOAL_MEM_READ_WRITE:
+ ret = woal_mem_read_write(priv, wrq);
+ break;
+ case WOAL_SLEEP_PARAMS:
+ ret = woal_sleep_params_ioctl(priv, wrq);
+ break;
+ case WOAL_DFS_TESTING:
+ ret = woal_dfs_testing(priv, wrq);
+ break;
+ case WOAL_MGMT_FRAME_CTRL:
+ ret = woal_mgmt_frame_passthru_ctrl(priv, wrq);
+ break;
+ case WOAL_CFP_CODE:
+ ret = woal_cfp_code(priv, wrq);
+ break;
+ case WOAL_SET_GET_TX_RX_ANT:
+ ret = woal_set_get_tx_rx_ant(priv, wrq);
+ break;
+ case WOAL_IND_RST_CFG:
+ ret = woal_ind_rst_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOALGETLOG:
+ ret = woal_get_log(priv, wrq);
+ break;
+
+ case WOAL_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_PASSPHRASE:
+ ret = woal_passphrase(priv, wrq);
+ break;
+ case WOAL_GET_KEY:
+ ret = woal_get_key_ioctl(priv, wrq);
+ break;
+ case WOAL_ASSOCIATE:
+ ret = woal_associate_ssid_bssid(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATUS:
+ ret = woal_wmm_queue_status_ioctl(priv, wrq);
+ break;
+
+ case WOAL_WMM_TS_STATUS:
+ ret = woal_wmm_ts_status_ioctl(priv, wrq);
+ break;
+ case WOAL_IP_ADDRESS:
+ ret = woal_set_get_ip_addr(priv, wrq);
+ break;
+ case WOAL_TX_BF_CFG:
+ ret = woal_tx_bf_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETADDR_GETNONE:
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_DEAUTH:
+ ret = woal_deauth(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SETNONE_GETTWELVE_CHAR:
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_WPS_SESSION:
+ ret = woal_wps_cfg_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_SETNONE_GET_FOUR_INT:
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_DATA_RATE:
+ ret = woal_get_txrx_rate(priv, wrq);
+ break;
+ case WOAL_ESUPP_MODE:
+ ret = woal_get_esupp_mode(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+ case WOAL_SET_GET_64_INT:
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_ECL_SYS_CLOCK:
+ ret = woal_ecl_sys_clock(priv, wrq);
+ break;
+ }
+
+ break;
+
+ case WOAL_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_SET_INTS_GET_CHARS:
+ switch ((int)wrq->u.data.flags) {
+ case WOAL_READ_EEPROM:
+ ret = woal_read_eeprom(priv, wrq);
+ break;
+ }
+ break;
+ case WOAL_SET_GET_2K_BYTES:
+ switch ((int)wrq->u.data.flags) {
+#ifdef SDIO
+ case WOAL_CMD_53RDWR:
+ ret = woal_cmd53rdwr_ioctl(priv, wrq);
+ break;
+#endif
+ case WOAL_SET_USER_SCAN:
+ ret = woal_set_user_scan_ioctl(priv, wrq);
+ break;
+ case WOAL_GET_SCAN_TABLE:
+ ret = woal_get_scan_table_ioctl(priv, wrq);
+ break;
+ case WOAL_SET_USER_SCAN_EXT:
+ ret = woal_set_user_scan_ext_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_ADDTS:
+ ret = woal_wmm_addts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_DELTS:
+ ret = woal_wmm_delts_req_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_CONFIG:
+ ret = woal_wmm_queue_config_ioctl(priv, wrq);
+ break;
+ case WOAL_WMM_QUEUE_STATS:
+ ret = woal_wmm_queue_stats_ioctl(priv, wrq);
+ break;
+ case WOAL_BYPASSED_PACKET:
+ ret = woal_bypassed_packet_ioctl(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+
+#ifdef UAP_WEXT
+ case WOAL_FROYO_START:
+ break;
+ case WOAL_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_FROYO_STOP:
+ if (IS_UAP_WEXT(priv->phandle->params.cfg80211_wext) &&
+ MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE)) {
+ ret = -EFAULT;
+ }
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rates
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param m_rates A pointer to moal_802_11_rates structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_data_rates(moal_private *priv, t_u8 wait_option,
+ moal_802_11_rates *m_rates)
+{
+ int ret = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->sub_command = MLAN_OID_SUPPORTED_RATES;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (m_rates)
+ m_rates->num_of_rates = woal_copy_rates(
+ m_rates->rates, m_rates->num_of_rates,
+ rate->param.rates, MLAN_SUPPORTED_RATES);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Get channel list
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param chan_list A pointer to mlan_chan_list structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_get_channel_list(moal_private *priv, t_u8 wait_option,
+ mlan_chan_list *chan_list)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (chan_list) {
+ moal_memcpy_ext(priv->phandle, chan_list,
+ &bss->param.chanlist,
+ sizeof(mlan_chan_list),
+ sizeof(mlan_chan_list));
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void woal_ioctl_get_info_resp(moal_private *priv, mlan_ds_get_info *info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment = info->param.stats.fcs_error;
+ priv->w_stats.discard.retries = info->param.stats.retry;
+ priv->w_stats.discard.misc = info->param.stats.ack_failure;
+ break;
+ case MLAN_OID_GET_SIGNAL:
+ if (info->param.signal.selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level =
+ info->param.signal.bcn_rssi_avg;
+ if (info->param.signal.selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise =
+ info->param.signal.bcn_nf_avg;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Handle get BSS resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param bss Pointer to mlan_ds_bss structure
+ *
+ * @return N/A
+ */
+void woal_ioctl_get_bss_resp(moal_private *priv, mlan_ds_bss *bss)
+{
+ t_u32 mode = 0;
+
+ ENTER();
+
+ switch (bss->sub_command) {
+ case MLAN_OID_BSS_MODE:
+ if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA)
+ mode = IW_MODE_INFRA;
+ else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS)
+ mode = IW_MODE_ADHOC;
+ else
+ mode = IW_MODE_AUTO;
+ priv->w_stats.status = mode;
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.h
new file mode 100644
index 000000000000..22355f73809f
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_priv.h
@@ -0,0 +1,485 @@
+
+/** @file moal_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/31/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_PRIV_H_
+#define _WOAL_PRIV_H_
+
+/** 2K bytes */
+#define WOAL_2K_BYTES 2000
+
+/** PRIVATE CMD ID */
+#define WOAL_IOCTL (SIOCIWFIRSTPRIV) /* 0x8BE0 defined in wireless.h */
+
+/** Private command ID to set one int/get word char */
+#define WOAL_SETONEINT_GETWORDCHAR (WOAL_IOCTL + 1)
+/** Private command ID to get version */
+#define WOAL_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_VEREXT 2
+
+/** Private command ID to set/get none */
+#define WOAL_SETNONE_GETNONE (WOAL_IOCTL + 2)
+/** Private command ID for warm reset */
+#define WOAL_WARMRESET 1
+
+/**
+ * Linux Kernels later 3.9 use CONFIG_PM_RUNTIME instead of
+ * CONFIG_USB_SUSPEND
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+#ifdef CONFIG_PM
+#ifndef CONFIG_USB_SUSPEND
+#define CONFIG_USB_SUSPEND
+#endif
+#endif
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+#ifdef CONFIG_PM_RUNTIME
+#ifndef CONFIG_USB_SUSPEND
+#define CONFIG_USB_SUSPEND
+#endif
+#endif
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
+#endif
+
+#ifdef CONFIG_USB_SUSPEND
+/** Private command ID for usb suspend */
+#define WOAL_USB_SUSPEND 2
+/** Private command ID for usb resume */
+#define WOAL_USB_RESUME 3
+#endif /* CONFIG_USB_SUSPEND */
+/** Private command ID to clear 11d chan table */
+#define WOAL_11D_CLR_CHAN_TABLE 4
+
+/** Private command ID to set/get sixteen int */
+#define WOAL_SET_GET_SIXTEEN_INT (WOAL_IOCTL + 3)
+/** Private command ID to set/get TX power configurations */
+#define WOAL_TX_POWERCFG 1
+#ifdef DEBUG_LEVEL1
+/** Private command ID to set/get driver debug */
+#define WOAL_DRV_DBG 2
+#endif
+/** Private command ID to set/get beacon interval */
+#define WOAL_BEACON_INTERVAL 3
+/** Private command ID to get RSSI */
+#define WOAL_SIGNAL 5
+/** Private command ID to set/get Deep Sleep mode */
+#define WOAL_DEEP_SLEEP 7
+/** Private command ID for 11n ht configration */
+#define WOAL_11N_TX_CFG 8
+/** Private command ID for 11n usr ht configration */
+#define WOAL_11N_HTCAP_CFG 9
+/** Private command ID for TX Aggregation */
+#define WOAL_PRIO_TBL 10
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_UPDT 11
+/** Private command ID to set/get Host Sleep configuration */
+#define WOAL_HS_CFG 12
+/** Private command ID to set Host Sleep parameters */
+#define WOAL_HS_SETPARA 13
+/** Private command ID to read/write registers */
+#define WOAL_REG_READ_WRITE 14
+/** Private command ID to set/get band/adhocband */
+#define WOAL_BAND_CFG 15
+/** Private command ID for TX Aggregation */
+#define WOAL_11N_AMSDU_AGGR_CTRL 17
+/** Private command ID to set/get Inactivity timeout */
+#define WOAL_INACTIVITY_TIMEOUT_EXT 18
+#ifdef SDIO
+/** Private command ID to turn on/off sdio clock */
+#define WOAL_SDIO_CLOCK 19
+/** Private command ID to read/write Command 52 */
+#define WOAL_CMD_52RDWR 20
+#endif
+/** Private command ID to set/get scan configuration parameter */
+#define WOAL_SCAN_CFG 21
+/** Private command ID to set/get PS configuration parameter */
+#define WOAL_PS_CFG 22
+/** Private command ID to read/write memory */
+#define WOAL_MEM_READ_WRITE 23
+#ifdef SDIO
+/** Private command ID to control SDIO MP-A */
+#define WOAL_SDIO_MPA_CTRL 25
+#endif
+/** Private command ID for Updating ADDBA variables */
+#define WOAL_ADDBA_REJECT 27
+/** Private command ID to set/get sleep parameters */
+#define WOAL_SLEEP_PARAMS 28
+/** Private command ID to set/get TX BF capabilities */
+#define WOAL_TX_BF_CAP 31
+/** Private command ID to set/get dfs testing settings */
+#define WOAL_DFS_TESTING 33
+/** Private command ID to set/get CFP table codes */
+#define WOAL_CFP_CODE 34
+/** Private command ID to set/get tx/rx antenna */
+#define WOAL_SET_GET_TX_RX_ANT 35
+/** Private command ID to set/get management frame passthru mask */
+#define WOAL_MGMT_FRAME_CTRL 36
+
+/** Private command ID to configure gpio independent reset */
+#define WOAL_IND_RST_CFG 37
+
+/** Private command ID to set one int/get one int */
+#define WOAL_SETONEINT_GETONEINT (WOAL_IOCTL + 5)
+/** Private command ID to set/get Tx rate */
+#define WOAL_SET_GET_TXRATE 1
+/** Private command ID to set/get region code */
+#define WOAL_SET_GET_REGIONCODE 2
+/** Private command ID to turn on/off radio */
+#define WOAL_SET_RADIO 3
+/** Private command ID to enable WMM */
+#define WOAL_WMM_ENABLE 4
+/** Private command ID to enable 802.11D */
+#define WOAL_11D_ENABLE 5
+/** Private command ID to set/get QoS configuration */
+#define WOAL_SET_GET_QOS_CFG 7
+#if defined(REASSOCIATION)
+/** Private command ID to set/get reassociation setting */
+#define WOAL_SET_GET_REASSOC 9
+#endif /* REASSOCIATION */
+/** Private command ID for Updating Transmit buffer configration */
+#define WOAL_TXBUF_CFG 10
+/** Private command ID to set/get WWS mode */
+#define WOAL_SET_GET_WWS_CFG 12
+/** Private command ID to set/get sleep period */
+#define WOAL_SLEEP_PD 13
+/** Private command ID to set/get auth type */
+#define WOAL_AUTH_TYPE 18
+/** Private command ID to set/get port control */
+#define WOAL_PORT_CTRL 19
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID for set/get BSS role */
+#define WOAL_SET_GET_BSS_ROLE 21
+#endif
+#endif
+/** Private command ID for set/get 11h local power constraint */
+#define WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT 22
+/** Private command ID to set/get 11N HT stream configuration */
+#define WOAL_HT_STREAM_CFG 23
+/** Private command ID to set/get MAC control */
+#define WOAL_MAC_CONTROL 24
+/** Private command ID to get thermal value */
+#define WOAL_THERMAL 25
+/** Private command ID to set/get hs cfg param */
+#define WOAL_CFG_HOTSPOT 26
+
+/** Private command ID to get log */
+#define WOALGETLOG (WOAL_IOCTL + 7)
+
+/** Private command ID to set a wext address variable */
+#define WOAL_SETADDR_GETNONE (WOAL_IOCTL + 8)
+/** Private command ID to send deauthentication */
+#define WOAL_DEAUTH 1
+
+/** Private command to get/set 256 chars */
+#define WOAL_SET_GET_256_CHAR (WOAL_IOCTL + 9)
+/** Private command to read/write passphrase */
+#define WOAL_PASSPHRASE 1
+#define WOAL_ASSOCIATE 3
+/** Private command ID to get WMM queue status */
+#define WOAL_WMM_QUEUE_STATUS 4
+/** Private command ID to get Traffic stream status */
+#define WOAL_WMM_TS_STATUS 5
+#define WOAL_IP_ADDRESS 7
+/** Private command ID to set/get TX bemaforming */
+#define WOAL_TX_BF_CFG 8
+/** Private command ID to get PTK/GTK */
+#define WOAL_GET_KEY 9
+
+/** Get log buffer size */
+#define GETLOG_BUFSIZE 1500
+
+/** Private command ID to set none/get twelve chars*/
+#define WOAL_SETNONE_GETTWELVE_CHAR (WOAL_IOCTL + 11)
+/** Private command ID for WPS session */
+#define WOAL_WPS_SESSION 1
+
+/** Private command ID to set none/get four int */
+#define WOAL_SETNONE_GET_FOUR_INT (WOAL_IOCTL + 13)
+/** Private command ID to get data rates */
+#define WOAL_DATA_RATE 1
+/** Private command ID to get E-Supplicant mode */
+#define WOAL_ESUPP_MODE 2
+
+/** Private command to get/set 64 ints */
+#define WOAL_SET_GET_64_INT (WOAL_IOCTL + 15)
+/** Private command ID to set/get ECL system clock */
+#define WOAL_ECL_SYS_CLOCK 1
+
+/** Private command ID for hostcmd */
+#define WOAL_HOST_CMD (WOAL_IOCTL + 17)
+
+/** Private command ID to set ints and get chars */
+#define WOAL_SET_INTS_GET_CHARS (WOAL_IOCTL + 21)
+/** Private command ID to read EEPROM data */
+#define WOAL_READ_EEPROM 1
+
+/** Private command ID to set/get 2K bytes */
+#define WOAL_SET_GET_2K_BYTES (WOAL_IOCTL + 23)
+
+#ifdef SDIO
+/** Private command ID to read/write Command 53 */
+#define WOAL_CMD_53RDWR 2
+#endif
+
+/** Private command ID for setuserscan */
+#define WOAL_SET_USER_SCAN 3
+/** Private command ID for getscantable */
+#define WOAL_GET_SCAN_TABLE 4
+/** Private command ID for setuserscanext: async without wait */
+#define WOAL_SET_USER_SCAN_EXT 5
+
+/** Private command ID to request ADDTS */
+#define WOAL_WMM_ADDTS 7
+/** Private command ID to request DELTS */
+#define WOAL_WMM_DELTS 8
+/** Private command ID to queue configuration */
+#define WOAL_WMM_QUEUE_CONFIG 9
+/** Private command ID to queue stats */
+#define WOAL_WMM_QUEUE_STATS 10
+/** Private command ID to Bypass auth packet */
+#define WOAL_BYPASSED_PACKET 11
+
+#ifdef UAP_WEXT
+/** The following command IDs are for Froyo app */
+/** Private command ID to start driver */
+#define WOAL_FROYO_START (WOAL_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_FROYO_WL_FW_RELOAD (WOAL_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_FROYO_STOP (WOAL_IOCTL + 30)
+#endif
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_private_args[] = {
+ {WOAL_SETONEINT_GETWORDCHAR, IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128, ""},
+ {WOAL_VERSION, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {WOAL_VEREXT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128, "verext"},
+ {WOAL_SETNONE_GETNONE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, ""},
+ {WOAL_WARMRESET, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "warmreset"},
+#ifdef CONFIG_USB_SUSPEND
+ {WOAL_USB_SUSPEND, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "usbsuspend"},
+ {WOAL_USB_RESUME, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "usbresume"},
+#endif /* CONFIG_USB_SUSPEND */
+ {WOAL_SETONEINT_GETONEINT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ ""},
+ {WOAL_SET_GET_TXRATE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "txratecfg"},
+ {WOAL_SET_GET_REGIONCODE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "regioncode"},
+ {WOAL_SET_RADIO, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "radioctrl"},
+ {WOAL_WMM_ENABLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "wmmcfg"},
+ {WOAL_11D_ENABLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "11dcfg"},
+ {WOAL_11D_CLR_CHAN_TABLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
+ "11dclrtbl"},
+ {WOAL_SET_GET_QOS_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "qoscfg"},
+#ifndef OPCHAN
+ {WOAL_SET_GET_WWS_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "wwscfg"},
+#endif
+#if defined(REASSOCIATION)
+ {WOAL_SET_GET_REASSOC, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "reassoctrl"},
+#endif
+ {WOAL_TXBUF_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "txbufcfg"},
+ {WOAL_SLEEP_PD, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "sleeppd"},
+ {WOAL_AUTH_TYPE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "authtype"},
+ {WOAL_PORT_CTRL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "port_ctrl"},
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {WOAL_SET_GET_BSS_ROLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT, IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1, "powercons"},
+ {WOAL_HT_STREAM_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "htstreamcfg"},
+ {WOAL_MAC_CONTROL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "macctrl"},
+ {WOAL_THERMAL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "thermal"},
+ {WOAL_CFG_HOTSPOT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "hotspotcfg"},
+ {WOAL_SET_GET_SIXTEEN_INT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ ""},
+ {WOAL_TX_POWERCFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "txpowercfg"},
+#ifdef DEBUG_LEVEL1
+ {WOAL_DRV_DBG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "drvdbg"},
+#endif
+ {WOAL_BEACON_INTERVAL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "bcninterval"},
+ {WOAL_SIGNAL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "getsignal"},
+ {
+ WOAL_DEEP_SLEEP,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "deepsleep",
+ },
+ {WOAL_11N_TX_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "httxcfg"},
+ {WOAL_11N_HTCAP_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "htcapinfo"},
+ {WOAL_PRIO_TBL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "aggrpriotbl"},
+ {WOAL_11N_AMSDU_AGGR_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "amsduaggrctrl"},
+ {WOAL_ADDBA_UPDT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "addbapara"},
+ {WOAL_ADDBA_REJECT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "addbareject"},
+ {WOAL_TX_BF_CAP, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "httxbfcap"},
+ {WOAL_HS_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "hscfg"},
+ {WOAL_HS_SETPARA, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "hssetpara"},
+ {WOAL_REG_READ_WRITE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "regrdwr"},
+ {WOAL_BAND_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "bandcfg"},
+ {WOAL_INACTIVITY_TIMEOUT_EXT, IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16, "inactivityto"},
+#ifdef SDIO
+ {WOAL_SDIO_CLOCK, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "sdioclock"},
+ {WOAL_CMD_52RDWR, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "sdcmd52rw"},
+#endif
+ {WOAL_SCAN_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "scancfg"},
+ {WOAL_PS_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "pscfg"},
+ {WOAL_MEM_READ_WRITE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "memrdwr"},
+#ifdef SDIO
+ {WOAL_SDIO_MPA_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "mpactrl"},
+#endif
+ {WOAL_SLEEP_PARAMS, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "sleepparams"},
+ {WOAL_DFS_TESTING, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "dfstesting"},
+ {WOAL_MGMT_FRAME_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "mgmtframectrl"},
+ {WOAL_CFP_CODE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "cfpcode"},
+ {WOAL_SET_GET_TX_RX_ANT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "antcfg"},
+ {WOAL_IND_RST_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
+ "indrstcfg"},
+ {WOALGETLOG, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {WOAL_SETADDR_GETNONE, IW_PRIV_TYPE_ADDR | 1, IW_PRIV_TYPE_NONE, ""},
+ {WOAL_DEAUTH, IW_PRIV_TYPE_ADDR | 1, IW_PRIV_TYPE_NONE, "deauth"},
+ {WOAL_SET_GET_256_CHAR, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, ""},
+ {WOAL_PASSPHRASE, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "passphrase"},
+ {WOAL_GET_KEY, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "getkey"},
+ {WOAL_ASSOCIATE, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "associate"},
+ {WOAL_WMM_QUEUE_STATUS, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, "qstatus"},
+ {WOAL_WMM_TS_STATUS, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "ts_status"},
+ {WOAL_IP_ADDRESS, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "ipaddr"},
+ {WOAL_TX_BF_CFG, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "httxbfcfg"},
+ {WOAL_SETNONE_GETTWELVE_CHAR, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {WOAL_WPS_SESSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | 12,
+ "wpssession"},
+ {WOAL_SETNONE_GET_FOUR_INT, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4,
+ ""},
+ {WOAL_DATA_RATE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4,
+ "getdatarate"},
+ {WOAL_ESUPP_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4, "esuppmode"},
+ {WOAL_SET_GET_64_INT, IW_PRIV_TYPE_INT | 64, IW_PRIV_TYPE_INT | 64, ""},
+ {WOAL_ECL_SYS_CLOCK, IW_PRIV_TYPE_INT | 64, IW_PRIV_TYPE_INT | 64,
+ "sysclock"},
+ {WOAL_HOST_CMD, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {WOAL_SET_INTS_GET_CHARS, IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_BYTE | 256, ""},
+ {WOAL_READ_EEPROM, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_BYTE | 256,
+ "rdeeprom"},
+ {WOAL_SET_GET_2K_BYTES, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, ""},
+#if defined(SDIO)
+ {WOAL_CMD_53RDWR, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "sdcmd53rw"},
+#endif
+ {WOAL_SET_USER_SCAN, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "setuserscan"},
+ {WOAL_GET_SCAN_TABLE, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "getscantable"},
+ {WOAL_SET_USER_SCAN_EXT, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "setuserscanext"},
+ {WOAL_WMM_ADDTS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "addts"},
+ {WOAL_WMM_DELTS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "delts"},
+ {WOAL_WMM_QUEUE_CONFIG, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "qconfig"},
+ {WOAL_WMM_QUEUE_STATS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "qstats"},
+ {WOAL_BYPASSED_PACKET, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
+ IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "pb_bypass"},
+#ifdef UAP_WEXT
+ {WOAL_FROYO_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "START"},
+ {WOAL_FROYO_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "STOP"},
+ {WOAL_FROYO_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, "WL_FW_RELOAD"},
+#endif
+};
+
+/** moal_802_11_rates */
+typedef struct _moal_802_11_rates {
+ /** Num of rates */
+ t_u8 num_of_rates;
+ /** Rates */
+ t_u8 rates[MLAN_SUPPORTED_RATES];
+} moal_802_11_rates, *pmoal_802_11_rates;
+
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+
+#endif /* _WOAL_PRIV_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_proc.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_proc.c
new file mode 100644
index 000000000000..d60ae7f64b4d
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_proc.c
@@ -0,0 +1,1099 @@
+/** @file moal_proc.c
+ *
+ * @brief This file contains functions for proc file.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+#ifdef CONFIG_PROC_FS
+#define STATUS_PROC "wifi_status"
+#define MWLAN_PROC "mwlan"
+#define WLAN_PROC "adapter%d"
+/** Proc mwlan directory entry */
+struct proc_dir_entry *proc_mwlan;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+#define PROC_DIR NULL
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#define PROC_DIR (&proc_root)
+#else
+#define PROC_DIR proc_net
+#endif
+
+#ifdef STA_SUPPORT
+static char *szModes[] = {
+ "Unknown",
+ "Managed",
+ "Ad-hoc",
+ "Auto",
+};
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+int wifi_status;
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief Proc read function for info
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return Number of output data
+ */
+static int woal_info_proc_read(struct seq_file *sfp, void *data)
+{
+ struct net_device *netdev = (struct net_device *)sfp->private;
+ char fmt[MLAN_MAX_VER_STR_LEN];
+ moal_private *priv = (moal_private *)netdev_priv(netdev);
+#ifdef STA_SUPPORT
+ int i = 0;
+ moal_handle *handle = NULL;
+ mlan_bss_info info;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ struct dev_mc_list *mcptr = netdev->mc_list;
+ int mc_count = netdev->mc_count;
+#else
+ struct netdev_hw_addr *mcptr = NULL;
+ int mc_count = netdev_mc_count(netdev);
+#endif /* < 2.6.35 */
+#else
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ int i = 0;
+#endif /* >= 2.6.29 */
+#endif
+#ifdef UAP_SUPPORT
+ mlan_ds_uap_stats ustats;
+#endif
+ union {
+ t_u32 l;
+ t_u8 c[4];
+ } ver;
+
+ ENTER();
+
+ if (priv == NULL)
+ goto exit;
+#ifdef STA_SUPPORT
+ handle = priv->phandle;
+ if (handle == NULL)
+ goto exit;
+#endif
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ memset(fmt, 0, sizeof(fmt));
+#ifdef UAP_SUPPORT
+ memset(&ustats, 0, sizeof(ustats));
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ seq_printf(sfp, "driver_name = "
+ "\"uap\"\n");
+ woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_get_stats(priv, MOAL_IOCTL_WAIT, &ustats)) {
+ MODULE_PUT;
+ LEAVE();
+ return -EFAULT;
+ }
+ }
+#endif /* UAP_SUPPORT*/
+#ifdef STA_SUPPORT
+ memset(&info, 0, sizeof(info));
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ woal_get_version(handle, fmt, sizeof(fmt) - 1);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &info)) {
+ MODULE_PUT;
+ LEAVE();
+ return -EFAULT;
+ }
+ seq_printf(sfp, "driver_name = "
+ "\"wlan\"\n");
+ }
+#endif
+ seq_printf(sfp, "driver_version = %s", fmt);
+ seq_printf(sfp, "\ninterface_name=\"%s\"\n", netdev->name);
+ ver.l = handle->fw_release_number;
+ seq_printf(sfp, "firmware_major_version=%u.%u.%u\n", ver.c[2], ver.c[1],
+ ver.c[0]);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
+ seq_printf(sfp, "bss_mode = \"WIFIDIRECT-Client\"\n");
+ else
+ seq_printf(sfp, "bss_mode = \"WIFIDIRECT-GO\"\n");
+ }
+#endif
+#ifdef STA_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ seq_printf(sfp, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
+#endif
+ seq_printf(sfp, "media_state=\"%s\"\n",
+ ((priv->media_connected == MFALSE) ? "Disconnected" :
+ "Connected"));
+ seq_printf(sfp, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3],
+ netdev->dev_addr[4], netdev->dev_addr[5]);
+#ifdef STA_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ seq_printf(sfp, "multicast_count=\"%d\"\n", mc_count);
+ seq_printf(sfp, "essid=\"%s\"\n", info.ssid.ssid);
+ seq_printf(sfp, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ info.bssid[0], info.bssid[1], info.bssid[2],
+ info.bssid[3], info.bssid[4], info.bssid[5]);
+ seq_printf(sfp, "channel=\"%d\"\n", (int)info.bss_chan);
+ seq_printf(sfp, "region_code = \"%02x\"\n",
+ (t_u8)info.region_code);
+
+ /*
+ * Put out the multicast list
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ for (i = 0; i < netdev->mc_count; i++) {
+ seq_printf(
+ sfp,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i, mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+ mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+ mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+ mcptr = mcptr->next;
+ }
+#else
+ netdev_for_each_mc_addr (mcptr, netdev)
+ seq_printf(
+ sfp,
+ "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ i++, mcptr->addr[0], mcptr->addr[1],
+ mcptr->addr[2], mcptr->addr[3], mcptr->addr[4],
+ mcptr->addr[5]);
+#endif /* < 2.6.35 */
+ }
+#endif
+ seq_printf(sfp, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+ seq_printf(sfp, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+ seq_printf(sfp, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+ seq_printf(sfp, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+ seq_printf(sfp, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+ seq_printf(sfp, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+ seq_printf(sfp, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+ seq_printf(sfp, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+ seq_printf(sfp, "carrier %s\n",
+ ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ seq_printf(sfp, "tx queue %d: %s\n", i,
+ ((netif_tx_queue_stopped(
+ netdev_get_tx_queue(netdev, 0))) ?
+ "stopped" :
+ "started"));
+ }
+#else
+ seq_printf(sfp, "tx queue %s\n",
+ ((netif_queue_stopped(priv->netdev)) ? "stopped" :
+ "started"));
+#endif
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ seq_printf(sfp, "tkip_mic_failures = %u\n",
+ ustats.tkip_mic_failures);
+ seq_printf(sfp, "ccmp_decrypt_errors = %u\n",
+ ustats.ccmp_decrypt_errors);
+ seq_printf(sfp, "wep_undecryptable_count = %u\n",
+ ustats.wep_undecryptable_count);
+ seq_printf(sfp, "wep_icv_error_count = %u\n",
+ ustats.wep_icv_error_count);
+ seq_printf(sfp, "decrypt_failure_count = %u\n",
+ ustats.decrypt_failure_count);
+ seq_printf(sfp, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
+ seq_printf(sfp, "failed_count = %u\n", ustats.failed_count);
+ seq_printf(sfp, "retry_count = %u\n", ustats.retry_count);
+ seq_printf(sfp, "multiple_retry_count = %u\n",
+ ustats.multi_retry_count);
+ seq_printf(sfp, "frame_duplicate_count = %u\n",
+ ustats.frame_dup_count);
+ seq_printf(sfp, "rts_success_count = %u\n",
+ ustats.rts_success_count);
+ seq_printf(sfp, "rts_failure_count = %u\n",
+ ustats.rts_failure_count);
+ seq_printf(sfp, "ack_failure_count = %u\n",
+ ustats.ack_failure_count);
+ seq_printf(sfp, "rx_fragment_count = %u\n",
+ ustats.rx_fragment_count);
+ seq_printf(sfp, "mcast_rx_frame_count = %u\n",
+ ustats.mcast_rx_frame_count);
+ seq_printf(sfp, "fcs_error_count = %u\n",
+ ustats.fcs_error_count);
+ seq_printf(sfp, "tx_frame_count = %u\n", ustats.tx_frame_count);
+ seq_printf(sfp, "rsna_tkip_cm_invoked = %u\n",
+ ustats.rsna_tkip_cm_invoked);
+ seq_printf(sfp, "rsna_4way_hshk_failures = %u\n",
+ ustats.rsna_4way_hshk_failures);
+ }
+#endif /* UAP_SUPPORT */
+ seq_printf(sfp, "=== tp_acnt.on:%d drop_point:%d ===\n",
+ handle->tp_acnt.on, handle->tp_acnt.drop_point);
+ seq_printf(sfp, "====Tx accounting====\n");
+ for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
+ seq_printf(sfp, "[%d] Tx packets : %lu\n", i,
+ handle->tp_acnt.tx_packets[i]);
+ seq_printf(sfp, "[%d] Tx packets last: %lu\n", i,
+ handle->tp_acnt.tx_packets_last[i]);
+ seq_printf(sfp, "[%d] Tx packets rate: %lu\n", i,
+ handle->tp_acnt.tx_packets_rate[i]);
+ seq_printf(sfp, "[%d] Tx bytes : %lu\n", i,
+ handle->tp_acnt.tx_bytes[i]);
+ seq_printf(sfp, "[%d] Tx bytes last : %lu\n", i,
+ handle->tp_acnt.tx_bytes_last[i]);
+ seq_printf(sfp, "[%d] Tx bytes rate : %luMbps\n", i,
+ handle->tp_acnt.tx_bytes_rate[i] * 8 / 1024 / 1024);
+ }
+ seq_printf(sfp, "Tx intr cnt : %lu\n",
+ handle->tp_acnt.tx_intr_cnt);
+ seq_printf(sfp, "Tx intr last : %lu\n",
+ handle->tp_acnt.tx_intr_last);
+ seq_printf(sfp, "Tx intr rate : %lu\n",
+ handle->tp_acnt.tx_intr_rate);
+ seq_printf(sfp, "Tx pending : %lu\n",
+ handle->tp_acnt.tx_pending);
+ seq_printf(sfp, "====Rx accounting====\n");
+ for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
+ seq_printf(sfp, "[%d] Rx packets : %lu\n", i,
+ handle->tp_acnt.rx_packets[i]);
+ seq_printf(sfp, "[%d] Rx packets last: %lu\n", i,
+ handle->tp_acnt.rx_packets_last[i]);
+ seq_printf(sfp, "[%d] Rx packets rate: %lu\n", i,
+ handle->tp_acnt.rx_packets_rate[i]);
+ seq_printf(sfp, "[%d] Rx bytes : %lu\n", i,
+ handle->tp_acnt.rx_bytes[i]);
+ seq_printf(sfp, "[%d] Rx bytes last : %lu\n", i,
+ handle->tp_acnt.rx_bytes_last[i]);
+ seq_printf(sfp, "[%d] Rx bytes rate : %luMbps\n", i,
+ handle->tp_acnt.rx_bytes_rate[i] * 8 / 1024 / 1024);
+ }
+ seq_printf(sfp, "Rx intr cnt : %lu\n",
+ handle->tp_acnt.rx_intr_cnt);
+ seq_printf(sfp, "Rx intr last : %lu\n",
+ handle->tp_acnt.rx_intr_last);
+ seq_printf(sfp, "Rx intr rate : %lu\n",
+ handle->tp_acnt.rx_intr_rate);
+ seq_printf(sfp, "Rx pending : %lu\n",
+ handle->tp_acnt.rx_pending);
+ seq_printf(sfp, "Rx pause : %lu\n",
+ handle->tp_acnt.rx_paused_cnt);
+exit:
+ LEAVE();
+ MODULE_PUT;
+ return 0;
+}
+
+static int woal_info_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_info_proc_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_info_proc_read, PDE(inode)->data);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops info_proc_fops = {
+ .proc_open = woal_info_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+#else
+static const struct file_operations info_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_info_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+#ifdef SDIO
+#define CMD52_STR_LEN 50
+/*
+ * @brief Parse cmd52 string
+ *
+ * @param buffer A pointer user buffer
+ * @param len Length user buffer
+ * @param func Parsed func number
+ * @param reg Parsed reg value
+ * @param val Parsed value to set
+ * @return BT_STATUS_SUCCESS
+ */
+static int parse_cmd52_string(const char *buffer, size_t len, int *func,
+ int *reg, int *val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ char *string = NULL;
+ char *pos = NULL;
+ gfp_t flag;
+
+ ENTER();
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ string = kzalloc(CMD52_STR_LEN, flag);
+ if (string == NULL)
+ return -ENOMEM;
+
+ moal_memcpy_ext(NULL, string, buffer + strlen("sdcmd52rw="),
+ len - strlen("sdcmd52rw="), CMD52_STR_LEN - 1);
+ string = strstrip(string);
+
+ *func = -1;
+ *reg = -1;
+ *val = -1;
+
+ /* Get func */
+ pos = strsep(&string, " \t");
+ if (pos)
+ *func = woal_string_to_number(pos);
+
+ /* Get reg */
+ pos = strsep(&string, " \t");
+ if (pos)
+ *reg = woal_string_to_number(pos);
+
+ /* Get val (optional) */
+ pos = strsep(&string, " \t");
+ if (pos)
+ *val = woal_string_to_number(pos);
+ kfree(string);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief config proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param count data number to write
+ * @param off Offset
+ *
+ * @return number of data
+ */
+static ssize_t woal_config_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ char databuf[101];
+ char *line = NULL;
+ t_u32 config_data = 0;
+ struct seq_file *sfp = f->private_data;
+ moal_handle *handle = (moal_handle *)sfp->private;
+
+#ifdef SDIO
+ int func = 0, reg = 0, val = 0;
+#endif
+ moal_handle *ref_handle = NULL;
+ t_u32 cmd = 0;
+ int copy_len;
+ moal_private *priv = NULL;
+
+ ENTER();
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ if (count >= sizeof(databuf)) {
+ MODULE_PUT;
+ LEAVE();
+ return (int)count;
+ }
+ memset(databuf, 0, sizeof(databuf));
+ copy_len = MIN((sizeof(databuf) - 1), count);
+ if (copy_from_user(databuf, buf, copy_len)) {
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+ }
+ line = databuf;
+ if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
+ line += strlen("soft_reset") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ PRINTM(MINFO, "soft_reset: %d\n", (int)config_data);
+ if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS)
+ handle->hardware_status = HardwareStatusReset;
+ else
+ PRINTM(MERROR, "Could not perform soft reset\n");
+ }
+ if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
+ line += strlen("drv_mode") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ PRINTM(MINFO, "drv_mode: %d\n", (int)config_data);
+ if (config_data != (t_u32)handle->params.drv_mode)
+ if (woal_switch_drv_mode(handle, config_data) !=
+ MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Could not switch drv mode\n");
+ }
+ }
+#ifdef SDIO
+ if (IS_SD(handle->card_type)) {
+ if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw=")) &&
+ count > strlen("sdcmd52rw=")) {
+ parse_cmd52_string((const char *)databuf, (size_t)count,
+ &func, &reg, &val);
+ woal_sdio_read_write_cmd52(handle, func, reg, val);
+ }
+ }
+#endif /* SD */
+ if (!strncmp(databuf, "debug_dump", strlen("debug_dump"))) {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
+ if (priv) {
+#ifdef DEBUG_LEVEL1
+ drvdbg &= ~MFW_D;
+#endif
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ }
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (priv) {
+ PRINTM(MERROR, "Recevie debug_dump command\n");
+#ifdef DEBUG_LEVEL1
+ drvdbg &= ~MFW_D;
+#endif
+ woal_mlan_debug_info(priv);
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ handle->ops.dump_fw_info(handle);
+ }
+ }
+
+ if (!strncmp(databuf, "fwdump_file=", strlen("fwdump_file="))) {
+ int len = copy_len - strlen("fwdump_file=");
+ gfp_t flag;
+ if (len) {
+ kfree(handle->fwdump_fname);
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC :
+ GFP_KERNEL;
+ handle->fwdump_fname = kzalloc(len, flag);
+ if (handle->fwdump_fname)
+ moal_memcpy_ext(handle, handle->fwdump_fname,
+ databuf +
+ strlen("fwdump_file="),
+ len - 1, len - 1);
+ }
+ }
+ if (!strncmp(databuf, "fw_reload", strlen("fw_reload"))) {
+ if (!strncmp(databuf, "fw_reload=", strlen("fw_reload="))) {
+ line += strlen("fw_reload") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ }
+#ifdef SDIO_MMC
+ else if (IS_SD(handle->card_type))
+ config_data = FW_RELOAD_SDIO_INBAND_RESET;
+#endif
+ PRINTM(MMSG, "Request fw_reload=%d\n", config_data);
+ woal_request_fw_reload(handle, config_data);
+ }
+ if (!strncmp(databuf, "drop_point=", strlen("drop_point="))) {
+ line += strlen("drop_point") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ if (config_data) {
+ handle->tp_acnt.on = 1;
+ handle->tp_acnt.drop_point = config_data;
+ if (handle->is_tp_acnt_timer_set == MFALSE) {
+ woal_initialize_timer(&handle->tp_acnt.timer,
+ woal_tp_acnt_timer_func,
+ handle);
+ handle->is_tp_acnt_timer_set = MTRUE;
+ woal_mod_timer(&handle->tp_acnt.timer, 1000);
+ }
+ } else {
+ if (handle->is_tp_acnt_timer_set) {
+ woal_cancel_timer(&handle->tp_acnt.timer);
+ handle->is_tp_acnt_timer_set = MFALSE;
+ }
+ memset((void *)&handle->tp_acnt, 0,
+ sizeof(moal_tp_acnt_t));
+ }
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (priv)
+ woal_set_tp_state(priv);
+ PRINTM(MMSG, "on=%d drop_point=%d\n", handle->tp_acnt.on,
+ handle->tp_acnt.drop_point);
+ }
+ if (!strncmp(databuf, "rf_test_mode", strlen("rf_test_mode"))) {
+ line += strlen("rf_test_mode") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ PRINTM(MINFO, "RF test mode: %d\n", (int)config_data);
+ if (config_data != (t_u32)handle->rf_test_mode)
+ if (woal_process_rf_test_mode(handle, config_data) !=
+ MLAN_STATUS_SUCCESS)
+ PRINTM(MERROR, "Could not set RF test mode\n");
+ }
+ if (!strncmp(databuf, "tx_antenna", strlen("tx_antenna"))) {
+ line += strlen("tx_antenna") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ cmd = MFG_CMD_TX_ANT;
+ }
+ if (!strncmp(databuf, "rx_antenna", strlen("rx_antenna"))) {
+ line += strlen("rx_antenna") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ cmd = MFG_CMD_RX_ANT;
+ }
+ if (!strncmp(databuf, "channel", strlen("channel"))) {
+ line += strlen("channel") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ cmd = MFG_CMD_RF_CHAN;
+ }
+ if (!strncmp(databuf, "band", strlen("band"))) {
+ line += strlen("band") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ cmd = MFG_CMD_RF_BAND_AG;
+ }
+ if (!strncmp(databuf, "bw", strlen("bw"))) {
+ line += strlen("bw") + 1;
+ config_data = (t_u32)woal_string_to_number(line);
+ cmd = MFG_CMD_RF_CHANNELBW;
+ }
+ if (!strncmp(databuf, "get_and_reset_per", strlen("get_and_reset_per")))
+ cmd = MFG_CMD_CLR_RX_ERR;
+ if (!strncmp(databuf, "tx_power=", strlen("tx_power=")) &&
+ count > strlen("tx_power="))
+ cmd = MFG_CMD_RFPWR;
+ if (!strncmp(databuf, "tx_frame=", strlen("tx_frame=")) &&
+ count > strlen("tx_frame="))
+ cmd = MFG_CMD_TX_FRAME;
+ if (!strncmp(databuf, "tx_continuous=", strlen("tx_continuous=")) &&
+ count > strlen("tx_continuous="))
+ cmd = MFG_CMD_TX_CONT;
+
+ if (cmd && handle->rf_test_mode &&
+ (woal_process_rf_test_mode_cmd(
+ handle, cmd, (const char *)databuf, (size_t)count,
+ MLAN_ACT_SET, config_data) != MLAN_STATUS_SUCCESS)) {
+ PRINTM(MERROR, "RF test mode cmd error\n");
+ }
+ if (cmd && !handle->rf_test_mode)
+ PRINTM(MERROR, "RF test mode is disabled\n");
+ MODULE_PUT;
+ LEAVE();
+ return (int)count;
+}
+
+/**
+ * @brief config proc read function
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return number of output data
+ */
+static int woal_config_read(struct seq_file *sfp, void *data)
+{
+ moal_handle *handle = (moal_handle *)sfp->private;
+ int i;
+
+ ENTER();
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ seq_printf(sfp, "hardware_status=%d\n", (int)handle->hardware_status);
+ seq_printf(sfp, "netlink_num=%d\n", (int)handle->netlink_num);
+ seq_printf(sfp, "drv_mode=%d\n", (int)handle->params.drv_mode);
+#ifdef SDIO
+ if (IS_SD(handle->card_type)) {
+ seq_printf(sfp, "sdcmd52rw=%d 0x%0x 0x%02X\n",
+ handle->cmd52_func, handle->cmd52_reg,
+ handle->cmd52_val);
+ }
+#endif /* SD */
+ seq_printf(sfp, "rf_test_mode=%u\n", handle->rf_test_mode);
+ if (handle->rf_test_mode && handle->rf_data) {
+ seq_printf(sfp, "tx_antenna=%u\n", handle->rf_data->tx_antenna);
+ seq_printf(sfp, "rx_antenna=%u\n", handle->rf_data->rx_antenna);
+ seq_printf(sfp, "band=%u\n", handle->rf_data->band);
+ seq_printf(sfp, "bw=%u\n", handle->rf_data->bandwidth);
+ if (handle->rf_data->channel)
+ seq_printf(sfp, "channel=%u\n",
+ handle->rf_data->channel);
+ else
+ seq_printf(sfp, "channel=\n");
+ seq_printf(sfp, "total rx pkt count=%u\n",
+ handle->rf_data->rx_tot_pkt_count);
+ seq_printf(sfp, "rx multicast/broadcast pkt count=%u\n",
+ handle->rf_data->rx_mcast_bcast_pkt_count);
+ seq_printf(sfp, "rx fcs error pkt count=%u\n",
+ handle->rf_data->rx_pkt_fcs_err_count);
+ if (handle->rf_data->tx_power_data[0]) {
+ seq_printf(sfp, "tx_power=%u",
+ handle->rf_data->tx_power_data[0]);
+ seq_printf(sfp, " %u",
+ handle->rf_data->tx_power_data[1]);
+ seq_printf(sfp, " %u\n",
+ handle->rf_data->tx_power_data[2]);
+ } else
+ seq_printf(sfp, "tx_power=\n");
+ seq_printf(sfp, "tx_continuous=%u",
+ handle->rf_data->tx_cont_data[0]);
+ if (handle->rf_data->tx_cont_data[0] == MTRUE) {
+ seq_printf(sfp, " %u",
+ handle->rf_data->tx_cont_data[1]);
+ seq_printf(sfp, " 0x%x",
+ handle->rf_data->tx_cont_data[2]);
+ for (i = 3; i < 6; i++)
+ seq_printf(sfp, " %u",
+ handle->rf_data->tx_cont_data[i]);
+ }
+ seq_printf(sfp, "\n");
+ seq_printf(sfp, "tx_frame=%u",
+ handle->rf_data->tx_frame_data[0]);
+ if (handle->rf_data->tx_frame_data[0] == MTRUE) {
+ seq_printf(sfp, " %u",
+ handle->rf_data->tx_frame_data[1]);
+ seq_printf(sfp, " 0x%x",
+ handle->rf_data->tx_frame_data[2]);
+ for (i = 3; i < 13; i++)
+ seq_printf(sfp, " %u",
+ handle->rf_data->tx_frame_data[i]);
+ seq_printf(sfp, " %02x:%02x:%02x:%02x:%02x:%02x",
+ handle->rf_data->bssid[0],
+ handle->rf_data->bssid[1],
+ handle->rf_data->bssid[2],
+ handle->rf_data->bssid[3],
+ handle->rf_data->bssid[4],
+ handle->rf_data->bssid[5]);
+ }
+ seq_printf(sfp, "\n");
+ }
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+}
+
+static int woal_config_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_config_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_config_read, PDE(inode)->data);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops config_proc_fops = {
+ .proc_open = woal_config_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = woal_config_write,
+};
+#else
+static const struct file_operations config_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_config_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = woal_config_write,
+};
+#endif
+
+/**
+ * @brief wifi status proc read function
+ *
+ * @param sfp pointer to seq_file structure
+ * @param data
+ *
+ * @return number of output data
+ */
+static int woal_wifi_status_read(struct seq_file *sfp, void *data)
+{
+ ENTER();
+
+ if (!MODULE_GET) {
+ LEAVE();
+ return 0;
+ }
+
+ seq_printf(sfp, "%d\n", wifi_status);
+
+ MODULE_PUT;
+ LEAVE();
+ return 0;
+}
+
+static int woal_wifi_status_proc_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ return single_open(file, woal_wifi_status_read, PDE_DATA(inode));
+#else
+ return single_open(file, woal_wifi_status_read, PDE(inode)->data);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops wifi_status_proc_fops = {
+ .proc_open = woal_wifi_status_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+#else
+static const struct file_operations wifi_status_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = woal_wifi_status_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Convert string to number
+ *
+ * @param s Pointer to numbered string
+ *
+ * @return Converted number from string s
+ */
+int woal_string_to_number(char *s)
+{
+ int r = 0;
+ int base = 0;
+ int pn = 1;
+
+ if (!strncmp(s, "-", 1)) {
+ pn = -1;
+ s++;
+ }
+ if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
+ base = 16;
+ s += 2;
+ } else
+ base = 10;
+
+ for (s = s; *s; s++) {
+ if ((*s >= '0') && (*s <= '9'))
+ r = (r * base) + (*s - '0');
+ else if ((*s >= 'A') && (*s <= 'F'))
+ r = (r * base) + (*s - 'A' + 10);
+ else if ((*s >= 'a') && (*s <= 'f'))
+ r = (r * base) + (*s - 'a' + 10);
+ else
+ break;
+ }
+
+ return r * pn;
+}
+
+/**
+ * @brief This function creates proc mwlan directory
+ * directory structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_root_proc_init(void)
+{
+ ENTER();
+
+ PRINTM(MINFO, "Create /proc/mwlan directory\n");
+
+ proc_mwlan = proc_mkdir(MWLAN_PROC, PROC_DIR);
+ if (!proc_mwlan) {
+ PRINTM(MERROR,
+ "woal_root_proc_init: Cannot create /proc/mwlan\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ /* create /proc/mwlan/wifi_status */
+ proc_create_data(STATUS_PROC, 0644, proc_mwlan, &wifi_status_proc_fops,
+ NULL);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function removes proc mwlan directory
+ * directory structure
+ *
+ * @return N/A
+ */
+void woal_root_proc_remove(void)
+{
+ ENTER();
+
+ remove_proc_entry(STATUS_PROC, proc_mwlan);
+
+ remove_proc_entry(MWLAN_PROC, PROC_DIR);
+ proc_mwlan = NULL;
+
+ LEAVE();
+}
+
+/**
+ * @brief Create the top level proc directory
+ *
+ * @param handle Pointer to woal_handle
+ *
+ * @return N/A
+ */
+void woal_proc_init(moal_handle *handle)
+{
+ struct proc_dir_entry *r;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ struct proc_dir_entry *pde = proc_mwlan;
+#endif
+ char config_proc_dir[20];
+
+ ENTER();
+
+ if (handle->proc_wlan) {
+ PRINTM(MMSG, "woal_proc_init: proc_wlan is already exist %s\n",
+ handle->proc_wlan_name);
+ goto done;
+ }
+
+ snprintf(handle->proc_wlan_name, sizeof(handle->proc_wlan_name),
+ WLAN_PROC, handle->handle_idx);
+ PRINTM(MINFO, "Create Proc Interface %s\n", handle->proc_wlan_name);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ /* Check if directory already exists */
+ for (pde = pde->subdir; pde; pde = pde->next) {
+ if (pde->namelen &&
+ !strcmp(handle->proc_wlan_name, pde->name)) {
+ /* Directory exists */
+ PRINTM(MWARN, "proc interface already exists!\n");
+ handle->proc_wlan = pde;
+ break;
+ }
+ }
+ if (pde == NULL) {
+ handle->proc_wlan =
+ proc_mkdir(handle->proc_wlan_name, proc_mwlan);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ if (handle->proc_wlan)
+ atomic_set(&handle->proc_wlan->count, 1);
+#endif
+ }
+#else
+ handle->proc_wlan = proc_mkdir(handle->proc_wlan_name, proc_mwlan);
+#endif
+ if (!handle->proc_wlan) {
+ PRINTM(MERROR, "Cannot create proc interface %s!\n",
+ handle->proc_wlan_name);
+ goto done;
+ }
+
+ strcpy(config_proc_dir, "config");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ r = proc_create_data(config_proc_dir, 0644, handle->proc_wlan,
+ &config_proc_fops, handle);
+#else
+ r = create_proc_entry(config_proc_dir, 0644, handle->proc_wlan);
+ if (r) {
+ r->data = handle;
+ r->proc_fops = &config_proc_fops;
+ }
+#endif
+ if (!r)
+ PRINTM(MERROR, "Fail to create proc config\n");
+
+done:
+ LEAVE();
+}
+
+/**
+ * @brief Remove the top level proc directory
+ *
+ * @param handle pointer moal_handle
+ *
+ * @return N/A
+ */
+void woal_proc_exit(moal_handle *handle)
+{
+ char config_proc_dir[20];
+
+ ENTER();
+
+ PRINTM(MINFO, "Remove Proc Interface %s\n", handle->proc_wlan_name);
+ if (handle->proc_wlan) {
+ strcpy(config_proc_dir, "config");
+ remove_proc_entry(config_proc_dir, handle->proc_wlan);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ /* Remove only if we are the only instance using this */
+ if (atomic_read(&(handle->proc_wlan->count)) > 1) {
+ PRINTM(MWARN, "More than one interface using proc!\n");
+ } else {
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ atomic_dec(&(handle->proc_wlan->count));
+#endif
+ remove_proc_entry(handle->proc_wlan_name, proc_mwlan);
+
+ handle->proc_wlan = NULL;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ }
+#endif
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Create proc file for interface
+ *
+ * @param priv pointer moal_private
+ *
+ * @return N/A
+ */
+void woal_create_proc_entry(moal_private *priv)
+{
+ struct proc_dir_entry *r;
+ struct net_device *dev = priv->netdev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ char proc_dir_name[22];
+#endif
+
+ ENTER();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ if (!priv->proc_entry) {
+ memset(proc_dir_name, 0, sizeof(proc_dir_name));
+ strncpy(proc_dir_name, priv->phandle->proc_wlan_name,
+ sizeof(proc_dir_name) - 2);
+ proc_dir_name[strlen(proc_dir_name)] = '/';
+
+ if (strlen(dev->name) >
+ ((sizeof(proc_dir_name) - 1) - (strlen(proc_dir_name)))) {
+ PRINTM(MERROR,
+ "Failed to create proc entry, device name is too long\n");
+ LEAVE();
+ return;
+ }
+ strcat(proc_dir_name, dev->name);
+ /* Try to create adapterX/dev_name directory first under
+ * /proc/mwlan/ */
+ priv->proc_entry = proc_mkdir(proc_dir_name, proc_mwlan);
+ if (priv->proc_entry) {
+ /* Success. Continue normally */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ if (!priv->phandle->proc_wlan) {
+ priv->phandle->proc_wlan =
+ priv->proc_entry->parent;
+ }
+ atomic_inc(&(priv->phandle->proc_wlan->count));
+#endif
+ } else {
+ /* Failure. adapterX/ may not exist. Try to create that
+ * first */
+ priv->phandle->proc_wlan = proc_mkdir(
+ priv->phandle->proc_wlan_name, proc_mwlan);
+ if (!priv->phandle->proc_wlan) {
+ /* Failure. Something broken */
+ LEAVE();
+ return;
+ } else {
+ /* Success. Now retry creating mlanX */
+ priv->proc_entry =
+ proc_mkdir(proc_dir_name, proc_mwlan);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ atomic_inc(&(priv->phandle->proc_wlan->count));
+#endif
+ }
+ }
+#else
+ if (priv->phandle->proc_wlan && !priv->proc_entry) {
+ priv->proc_entry =
+ proc_mkdir(dev->name, priv->phandle->proc_wlan);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ atomic_inc(&(priv->phandle->proc_wlan->count));
+#endif /* < 3.10.0 */
+#endif /* < 2.6.26 */
+ strcpy(priv->proc_entry_name, dev->name);
+ if (priv->proc_entry) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ r = proc_create_data("info", 0, priv->proc_entry,
+ &info_proc_fops, dev);
+#else
+ r = create_proc_entry("info", 0, priv->proc_entry);
+ if (r) {
+ r->data = dev;
+ r->proc_fops = &info_proc_fops;
+ }
+#endif
+ if (!r)
+ PRINTM(MMSG, "Fail to create proc info\n");
+ }
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief Remove proc file
+ *
+ * @param priv Pointer moal_private
+ *
+ * @return N/A
+ */
+void woal_proc_remove(moal_private *priv)
+{
+ ENTER();
+ if (priv->phandle->proc_wlan && priv->proc_entry) {
+ remove_proc_entry("info", priv->proc_entry);
+ remove_proc_entry(priv->proc_entry_name,
+ priv->phandle->proc_wlan);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ atomic_dec(&(priv->phandle->proc_wlan->count));
+#endif
+ priv->proc_entry = NULL;
+ }
+ LEAVE();
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio.h
new file mode 100644
index 000000000000..1453dbb6e8e1
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio.h
@@ -0,0 +1,174 @@
+/** @file moal_sdio.h
+ *
+ * @brief This file contains definitions for SDIO interface.
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/****************************************************
+Change log:
+****************************************************/
+
+#ifndef _MOAL_SDIO_H
+#define _MOAL_SDIO_H
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "moal_main.h"
+
+#ifndef BLOCK_MODE
+/** Block mode */
+#define BLOCK_MODE 1
+#endif
+
+#ifndef BYTE_MODE
+/** Byte Mode */
+#define BYTE_MODE 0
+#endif
+
+#ifndef FIXED_ADDRESS
+/** Fixed address mode */
+#define FIXED_ADDRESS 0
+#endif
+
+#if defined(SD8977)
+#define SD8977_V0 0x0
+#define SD8977_V1 0x8
+#define SD8977_V2 0x9
+#define SD8977_V0_FW_NAME "nxp/sdsd8977_combo.bin"
+#define SD8977_V1_FW_NAME "nxp/sdsd8977_combo_v1.bin"
+#define SD8977_V2_FW_NAME "nxp/sdsd8977_combo_v2.bin"
+#define SD8977_WLAN_V2_FW_NAME "nxp/sd8977_wlan_v2.bin"
+#define SD8977_WLAN_V1_FW_NAME "nxp/sd8977_wlan_v1.bin"
+#define SD8977_WLAN_V0_FW_NAME "nxp/sd8977_wlan.bin"
+#endif /* SD8977_MULTI_FW */
+
+#if defined(SD8887)
+/** SD8887 chip revision ID */
+#define SD8887_A0 0x0
+#define SD8887_A2 0x2
+
+#define SD8887_A0_FW_NAME "nxp/sd8887_uapsta.bin"
+#define SD8887_A2_FW_NAME "nxp/sd8887_uapsta_a2.bin"
+#define SD8887_WLAN_A2_FW_NAME "nxp/sd8887_wlan_a2.bin"
+#define SD8887_WLAN_A0_FW_NAME "nxp/sd8887_wlan.bin"
+#endif /* SD8887_MULTI_FW */
+
+/** Default firmware name */
+#ifdef SD8887
+#define SD8887_DEFAULT_COMBO_FW_NAME "nxp/sd8887_uapsta_a2.bin"
+#define SD8887_DEFAULT_WLAN_FW_NAME "nxp/sd8887_wlan_a2.bin"
+#endif /* SD8887 */
+
+#ifdef SD8977
+#define SD8977_DEFAULT_COMBO_FW_NAME "nxp/sdsd8977_combo_v2.bin"
+#define SD8977_DEFAULT_WLAN_FW_NAME "nxp/sd8977_wlan_v2.bin"
+#endif /* SD8977 */
+
+#ifdef SD8997
+#define SD8997_DEFAULT_COMBO_FW_NAME "nxp/sdsd8997_combo_v4.bin"
+#define SDUART8997_DEFAULT_COMBO_FW_NAME "nxp/sduart8997_combo_v4.bin"
+#define SDSD8997_DEFAULT_COMBO_FW_NAME "nxp/sdsd8997_combo_v4.bin"
+#define SD8997_DEFAULT_WLAN_FW_NAME "nxp/sd8997_wlan_v4.bin"
+#endif /* SD8997 */
+
+#ifdef SD8987
+#define SD8987_DEFAULT_COMBO_FW_NAME "nxp/sdsd8987_combo.bin"
+#define SDUART8987_DEFAULT_COMBO_FW_NAME "nxp/sduart8987_combo.bin"
+#define SDSD8987_DEFAULT_COMBO_FW_NAME "nxp/sdsd8987_combo.bin"
+#define SD8987_DEFAULT_WLAN_FW_NAME "nxp/sd8987_wlan.bin"
+#endif /* SD8987 */
+
+#ifdef SD8897
+#define SD8897_DEFAULT_COMBO_FW_NAME "nxp/sdsd8897_uapsta.bin"
+#define SD8897_DEFAULT_WLAN_FW_NAME "nxp/sd8897_wlan.bin"
+#endif /* SD8897 */
+
+#ifdef SD8978
+#define SD8978_DEFAULT_COMBO_FW_NAME "nxp/sdsd8978_combo.bin"
+#define SDUART8978_DEFAULT_COMBO_FW_NAME "nxp/sduart8978_combo.bin"
+#define SDSD8978_DEFAULT_COMBO_FW_NAME "nxp/sdsd8978_combo.bin"
+#define SD8978_DEFAULT_WLAN_FW_NAME "nxp/sd8978_wlan.bin"
+#endif /* SD8978 */
+
+#ifdef SD9098
+#define SD9098_Z1Z2 0x00
+#define SD9098_A0 0x01
+#define SD9098_A1 0x02
+#define SD9098_A2 0x03
+#define SD9098_DEFAULT_COMBO_FW_NAME "nxp/sdsd9098_combo.bin"
+#define SDUART9098_DEFAULT_COMBO_FW_NAME "nxp/sduart9098_combo.bin"
+#define SDSD9098_DEFAULT_COMBO_FW_NAME "nxp/sdsd9098_combo.bin"
+#define SD9098_DEFAULT_WLAN_FW_NAME "nxp/sd9098_wlan.bin"
+#define SDUART9098_COMBO_V1_FW_NAME "nxp/sduart9098_combo_v1.bin"
+#define SDSD9098_COMBO_V1_FW_NAME "nxp/sdsd9098_combo_v1.bin"
+#define SD9098_WLAN_V1_FW_NAME "nxp/sd9098_wlan_v1.bin"
+#endif /* SD9098 */
+
+#ifdef SD9097
+#define SD9097_B0 0x01
+#define SD9097_B1 0x02
+#define SD9097_DEFAULT_COMBO_FW_NAME "nxp/sdsd9097_combo_v1.bin"
+
+#define SD9097_DEFAULT_WLAN_FW_NAME "nxp/sd9097_wlan_v1.bin"
+#define SDUART9097_COMBO_V1_FW_NAME "nxp/sduart9097_combo_v1.bin"
+#define SDSD9097_COMBO_V1_FW_NAME "nxp/sdsd9097_combo_v1.bin"
+#define SD9097_WLAN_V1_FW_NAME "nxp/sd9097_wlan_v1.bin"
+#endif /* SD9097 */
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/** Register to bus driver function */
+mlan_status woal_sdiommc_bus_register(void);
+/** Unregister from bus driver function */
+void woal_sdiommc_bus_unregister(void);
+
+int woal_sdio_set_bus_clock(moal_handle *handle, t_u8 option);
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** Notify SDIO bus driver that WLAN is suspended */
+void woal_wlan_is_suspended(moal_handle *handle);
+#endif
+/** SDIO Suspend */
+int woal_sdio_suspend(struct device *dev);
+/** SDIO Resume */
+int woal_sdio_resume(struct device *dev);
+#endif /* SDIO_SUSPEND_RESUME */
+
+#ifdef SDIO_MMC
+/** Structure: SDIO MMC card */
+struct sdio_mmc_card {
+ /** sdio_func structure pointer */
+ struct sdio_func *func;
+ /** moal_handle structure pointer */
+ moal_handle *handle;
+ /** saved host clock value */
+ unsigned int host_clock;
+};
+#endif /* SDIO_MMC */
+
+/** cmd52 read write */
+int woal_sdio_read_write_cmd52(moal_handle *handle, int func, int reg, int val);
+#endif /* _MOAL_SDIO_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c
new file mode 100644
index 000000000000..4312b452f689
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c
@@ -0,0 +1,2106 @@
+/** @file moal_sdio_mmc.c
+ *
+ * @brief This file contains SDIO MMC IF (interface) module
+ * related functions.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/****************************************************
+Change log:
+ 02/25/09: Initial creation -
+ This file supports SDIO MMC only
+****************************************************/
+
+#include <linux/firmware.h>
+
+#include "moal_sdio.h"
+
+/** define nxp vendor id */
+#define NXP_VENDOR_ID 0x02df
+
+/********************************************************
+ Local Variables
+********************************************************/
+/* moal interface ops */
+static moal_if_ops sdiommc_ops;
+/********************************************************
+ Global Variables
+********************************************************/
+
+#ifdef SD8887
+/** Device ID for SD8887 */
+#define SD_DEVICE_ID_8887 (0x9135)
+#endif
+#ifdef SD8897
+/** Device ID for SD8897 */
+#define SD_DEVICE_ID_8897 (0x912d)
+#endif
+#ifdef SD8977
+/** Device ID for SD8977 */
+#define SD_DEVICE_ID_8977 (0x9145)
+#endif
+#ifdef SD8978
+/** Device ID for SD8978 */
+#define SD_DEVICE_ID_8978 (0x9159)
+#endif
+#ifdef SD8997
+/** Device ID for SD8997 */
+#define SD_DEVICE_ID_8997 (0x9141)
+#endif
+#ifdef SD8987
+/** Device ID for SD8987 */
+#define SD_DEVICE_ID_8987 (0x9149)
+#endif
+#ifdef SD9098
+/** Device ID for SD9098 */
+#define SD_DEVICE_ID_9098_FN1 (0x914D)
+/** Device ID for SD9098 */
+#define SD_DEVICE_ID_9098_FN2 (0x914E)
+#endif
+#ifdef SD9097
+/** Device ID for SD9097 */
+#define SD_DEVICE_ID_9097 (0x9155)
+#endif
+/** Device ID any */
+#ifndef SD_DEVICE_ANY
+#define SD_DEVICE_ANY (0xffff)
+#endif /* SD_DEVICE_ANY */
+
+/** WLAN IDs */
+static const struct sdio_device_id wlan_ids[] = {
+#ifdef SD8887
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8887)},
+#endif
+#ifdef SD8897
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8897)},
+#endif
+#ifdef SD8977
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8977)},
+#endif
+#ifdef SD8978
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8978)},
+#endif
+#ifdef SD8997
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8997)},
+#endif
+#ifdef SD8987
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8987)},
+#endif
+#ifdef SD9098
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9098_FN1)},
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9098_FN2)},
+#endif
+#ifdef SD9097
+ {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9097)},
+#endif
+ {},
+};
+
+int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
+void woal_sdio_remove(struct sdio_func *func);
+#ifdef SDIO
+static void woal_sdiommc_reg_dbg(pmoal_handle handle);
+#endif
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+int woal_sdio_suspend(struct device *dev);
+int woal_sdio_resume(struct device *dev);
+
+static struct dev_pm_ops wlan_sdio_pm_ops = {
+ .suspend = woal_sdio_suspend,
+ .resume = woal_sdio_resume,
+};
+
+void woal_sdio_shutdown(struct device *dev);
+#endif
+#endif
+
+// clang-format off
+static struct sdio_driver REFDATA wlan_sdio = {
+ .name = "wlan_sdio",
+ .id_table = wlan_ids,
+ .probe = woal_sdio_probe,
+ .remove = woal_sdio_remove,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ .drv = {
+ .owner = THIS_MODULE,
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .pm = &wlan_sdio_pm_ops,
+ .shutdown = woal_sdio_shutdown,
+#endif
+#endif
+
+ }
+#else
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+ .drv = {
+ .pm = &wlan_sdio_pm_ops,
+ .shutdown = woal_sdio_shutdown,
+ }
+#endif
+#endif
+#endif
+};
+// clang-format on
+
+/********************************************************
+ Local Functions
+********************************************************/
+static void woal_sdiommc_dump_fw_info(moal_handle *phandle);
+
+/** @brief This function dump the sdio register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void woal_dump_sdio_reg(moal_handle *handle)
+{
+ int ret = 0;
+ t_u8 data, i;
+ int fun0_reg[] = {0x05, 0x04};
+ t_u8 array_size = 0;
+#ifdef SD8897
+ int fun1_reg_8897[] = {0x03, 0x04, 0x05, 0x06, 0x07, 0xC0, 0xC1};
+#endif
+ int fun1_reg_other[] = {0x03, 0x04, 0x05, 0x60, 0x61};
+ int *fun1_reg = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fun0_reg); i++) {
+ data = sdio_f0_readb(
+ ((struct sdio_mmc_card *)handle->card)->func,
+ fun0_reg[i], &ret);
+ PRINTM(MMSG, "fun0: reg 0x%02x=0x%02x ret=%d\n", fun0_reg[i],
+ data, ret);
+ }
+
+#ifdef SD8897
+ if (IS_SD8897(handle->card_type)) {
+ fun1_reg = fun1_reg_8897;
+ array_size = sizeof(fun1_reg_8897) / sizeof(int);
+ } else {
+#endif
+ fun1_reg = fun1_reg_other;
+ array_size = sizeof(fun1_reg_other) / sizeof(int);
+#ifdef SD8897
+ }
+#endif
+ for (i = 0; i < array_size; i++) {
+ data = sdio_readb(((struct sdio_mmc_card *)handle->card)->func,
+ fun1_reg[i], &ret);
+ PRINTM(MMSG, "fun1: reg 0x%02x=0x%02x ret=%d\n", fun1_reg[i],
+ data, ret);
+ }
+ return;
+}
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief This function handles the interrupt.
+ *
+ * @param func A pointer to the sdio_func structure
+ * @return N/A
+ */
+static void woal_sdio_interrupt(struct sdio_func *func)
+{
+ moal_handle *handle;
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->handle) {
+ PRINTM(MINFO,
+ "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
+ func, card);
+ LEAVE();
+ return;
+ }
+ handle = card->handle;
+ if (handle->surprise_removed == MTRUE) {
+ LEAVE();
+ return;
+ }
+ handle->main_state = MOAL_RECV_INT;
+ PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
+ PRINTM(MINTR, "*\n");
+
+ /* call mlan_interrupt to read int status */
+ mlan_interrupt(0, handle->pmlan_adapter);
+#ifdef SDIO_SUSPEND_RESUME
+ if (handle->is_suspended) {
+ PRINTM(MINTR, "Receive interrupt in hs_suspended\n");
+ LEAVE();
+ return;
+ }
+#endif
+ handle->main_state = MOAL_START_MAIN_PROCESS;
+ /* Call MLAN main process */
+ mlan_main_process(handle->pmlan_adapter);
+ handle->main_state = MOAL_END_MAIN_PROCESS;
+ LEAVE();
+}
+
+/** @brief This function updates the card types
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param card A Pointer to card
+ *
+ * @return N/A
+ */
+static t_u16 woal_update_card_type(t_void *card)
+{
+ struct sdio_mmc_card *cardp_sd = (struct sdio_mmc_card *)card;
+ t_u16 card_type = 0;
+
+ /* Update card type */
+#ifdef SD8887
+ if (cardp_sd->func->device == SD_DEVICE_ID_8887) {
+ card_type = CARD_TYPE_SD8887;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8887,
+ strlen(CARD_SD8887), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V15, strlen(V15),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD8897
+ if (cardp_sd->func->device == SD_DEVICE_ID_8897) {
+ card_type = CARD_TYPE_SD8897;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8897,
+ strlen(CARD_SD8897), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V15, strlen(V15),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD8977
+ if (cardp_sd->func->device == SD_DEVICE_ID_8977) {
+ card_type = CARD_TYPE_SD8977;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8977,
+ strlen(CARD_SD8977), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD8978
+ if (cardp_sd->func->device == SD_DEVICE_ID_8978) {
+ card_type = CARD_TYPE_SD8978;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8978,
+ strlen(CARD_SD8978), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD8997
+ if (cardp_sd->func->device == SD_DEVICE_ID_8997) {
+ card_type = CARD_TYPE_SD8997;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8997,
+ strlen(CARD_SD8997), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD8987
+ if (cardp_sd->func->device == SD_DEVICE_ID_8987) {
+ card_type = CARD_TYPE_SD8987;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD8987,
+ strlen(CARD_SD8987), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD9097
+ if (cardp_sd->func->device == SD_DEVICE_ID_9097) {
+ card_type = CARD_TYPE_SD9097;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD9097,
+ strlen(CARD_SD9097), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+#ifdef SD9098
+ if (cardp_sd->func->device == SD_DEVICE_ID_9098_FN1 ||
+ cardp_sd->func->device == SD_DEVICE_ID_9098_FN2) {
+ card_type = CARD_TYPE_SD9098;
+ moal_memcpy_ext(NULL, driver_version, CARD_SD9098,
+ strlen(CARD_SD9098), strlen(driver_version));
+ moal_memcpy_ext(
+ NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) -
+ (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
+ }
+#endif
+ return card_type;
+}
+
+/** @brief This function handles client driver probe.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @param id A pointer to sdio_device_id structure.
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code
+ */
+int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = NULL;
+ t_u16 card_type = 0;
+
+ ENTER();
+
+ PRINTM(MMSG, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+ func->vendor, func->device, func->class, func->num);
+
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ PRINTM(MFATAL,
+ "Failed to allocate memory in probe function!\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ card->func = func;
+
+#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
+ /* The byte mode patch is available in kernel MMC driver
+ * which fixes one issue in MP-A transfer.
+ * bit1: use func->cur_blksize for byte mode
+ */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ /* wait for chip fully wake up */
+ if (!func->enable_timeout)
+ func->enable_timeout = 200;
+#endif
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ sdio_release_host(func);
+ PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+ ret = -EIO;
+ goto err;
+ }
+ sdio_release_host(func);
+
+ card_type = woal_update_card_type(card);
+ if (!card_type) {
+ PRINTM(MERROR, "sdmmc probe: woal_update_card_type() failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+
+ if (NULL ==
+ woal_add_card(card, &card->func->dev, &sdiommc_ops, card_type)) {
+ PRINTM(MERROR, "woal_add_card failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err;
+ }
+
+ LEAVE();
+ return ret;
+err:
+ kfree(card);
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver remove.
+ *
+ * @param func A pointer to sdio_func structure.
+ * @return N/A
+ */
+void woal_sdio_remove(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ ENTER();
+
+ if (func) {
+ PRINTM(MINFO, "SDIO func=%d\n", func->num);
+ card = sdio_get_drvdata(func);
+ if (card) {
+ woal_remove_card(card);
+ kfree(card);
+ }
+ }
+
+ LEAVE();
+}
+
+#ifdef SDIO_SUSPEND_RESUME
+#ifdef MMC_PM_KEEP_POWER
+#ifdef MMC_PM_FUNC_SUSPENDED
+/** @brief This function tells lower driver that WLAN is suspended
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @return N/A
+ */
+void woal_wlan_is_suspended(moal_handle *handle)
+{
+ ENTER();
+ if (handle->suspend_notify_req == MTRUE) {
+ handle->is_suspended = MTRUE;
+ sdio_func_suspended(
+ ((struct sdio_mmc_card *)handle->card)->func);
+ }
+ LEAVE();
+}
+#endif
+
+#define SHUTDOWN_HOST_SLEEP_DEF_GAP 100
+#define SHUTDOWN_HOST_SLEEP_DEF_GPIO 0x3
+#define SHUTDOWN_HOST_SLEEP_DEF_COND 0x0
+
+/** @brief This function handles client driver shutdown
+ *
+ * @param dev A pointer to device structure
+ * @return N/A
+ */
+void woal_sdio_shutdown(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ mlan_ds_ps_info pm_info;
+ int timeout = 0;
+ int i, retry_num = 8;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_shutdown --->\n");
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return;
+ }
+ handle = cardp->handle;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_detach(handle->priv[i]->netdev);
+
+ if (moal_extflg_isset(handle, EXT_SHUTDOWN_HS)) {
+ handle->shutdown_hs_in_process = MTRUE;
+ memset(&pm_info, 0, sizeof(pm_info));
+ for (i = 0; i < retry_num; i++) {
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_pm_info(woal_get_priv(handle,
+ MLAN_BSS_ROLE_ANY),
+ &pm_info)) {
+ if (pm_info.is_suspend_allowed == MTRUE)
+ break;
+ else
+ PRINTM(MMSG,
+ "Shutdown not allowed and retry again\n");
+ }
+ woal_sched_timeout(100);
+ }
+ if (pm_info.is_suspend_allowed == MFALSE) {
+ PRINTM(MMSG, "Shutdown not allowed\n");
+ goto done;
+ }
+ woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+
+ timeout = wait_event_interruptible_timeout(
+ handle->hs_activate_wait_q,
+ handle->hs_activate_wait_q_woken, HS_ACTIVE_TIMEOUT);
+ if (handle->hs_activated == MTRUE)
+ PRINTM(MMSG, "HS actived in shutdown\n");
+ else
+ PRINTM(MMSG, "Fail to enable HS in shutdown\n");
+ } else {
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i]) {
+ if (handle->priv[i]->media_connected == MTRUE
+#ifdef UAP_SUPPORT
+ || (GET_BSS_ROLE(handle->priv[i]) ==
+ MLAN_BSS_ROLE_UAP)
+#endif
+ ) {
+ PRINTM(MIOCTL,
+ "disconnect on suspend\n");
+ woal_disconnect(handle->priv[i],
+ MOAL_NO_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE);
+ }
+ }
+ }
+ }
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_sdio_shutdown --->\n");
+ LEAVE();
+ return;
+}
+
+/** @brief This function handles client driver suspend
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS or error code
+ */
+int woal_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i, retry_num = 8;
+ int ret = MLAN_STATUS_SUCCESS;
+ int hs_actived = 0;
+ mlan_ds_ps_info pm_info;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n");
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ handle = cardp->handle;
+
+ if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER) &&
+ !(pm_flags & MMC_PM_KEEP_POWER)) {
+ PRINTM(MERROR,
+ "%s: cannot remain alive while host is suspended\n",
+ sdio_func_id(func));
+ LEAVE();
+ return -ENOSYS;
+ }
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ if (handle->fw_dump) {
+ PRINTM(MMSG, "suspend not allowed while FW dump!");
+ ret = -EBUSY;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
+ woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
+ }
+#endif
+ handle->suspend_fail = MFALSE;
+ memset(&pm_info, 0, sizeof(pm_info));
+ for (i = 0; i < retry_num; i++) {
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ &pm_info)) {
+ if (pm_info.is_suspend_allowed == MTRUE)
+ break;
+ else
+ PRINTM(MMSG,
+ "Suspend not allowed and retry again\n");
+ }
+ woal_sched_timeout(100);
+ }
+ if (pm_info.is_suspend_allowed == MFALSE) {
+ PRINTM(MMSG, "Suspend not allowed\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_detach(handle->priv[i]->netdev);
+
+ if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER)) {
+ /* Enable the Host Sleep */
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MTRUE;
+#endif
+ hs_actived = woal_enable_hs(
+ woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+#ifdef MMC_PM_FUNC_SUSPENDED
+ handle->suspend_notify_req = MFALSE;
+#endif
+ if (hs_actived) {
+#ifdef MMC_PM_SKIP_RESUME_PROBE
+ PRINTM(MCMND,
+ "suspend with MMC_PM_KEEP_POWER and MMC_PM_SKIP_RESUME_PROBE\n");
+ ret = sdio_set_host_pm_flags(
+ func,
+ MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE);
+#else
+ PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+#endif
+ } else {
+ PRINTM(MMSG, "HS not actived, suspend fail!");
+ handle->suspend_fail = MTRUE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+ ret = -EBUSY;
+ goto done;
+ }
+ }
+
+ /* Indicate device suspended */
+ handle->is_suspended = MTRUE;
+done:
+ PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/** @brief This function handles client driver resume
+ *
+ * @param dev A pointer to device structure
+ * @return MLAN_STATUS_SUCCESS
+ */
+int woal_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ mmc_pm_flag_t pm_flags = 0;
+ moal_handle *handle = NULL;
+ struct sdio_mmc_card *cardp;
+ int i;
+
+ ENTER();
+ PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n");
+ pm_flags = sdio_get_host_pm_caps(func);
+ PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func),
+ pm_flags);
+ cardp = sdio_get_drvdata(func);
+ if (!cardp || !cardp->handle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ handle = cardp->handle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ handle->is_suspended = MFALSE;
+ if (woal_check_driver_status(handle)) {
+ PRINTM(MERROR, "Resuem, device is in hang state\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+ for (i = 0; i < handle->priv_num; i++)
+ netif_device_attach(handle->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
+ PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n");
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+#endif
+#endif /* SDIO_SUSPEND_RESUME */
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_sdiommc_write_reg(moal_handle *handle, t_u32 reg,
+ t_u32 data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data,
+ reg, (int *)&ret);
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_sdiommc_read_reg(moal_handle *handle, t_u32 reg,
+ t_u32 *data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
+ (int *)&ret);
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function writes data into card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_sdio_writeb(moal_handle *handle, t_u32 reg, t_u8 data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data,
+ reg, (int *)&ret);
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_sdio_readb(moal_handle *handle, t_u32 reg, t_u8 *data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
+ (int *)&ret);
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register FN0
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param reg Register offset
+ * @param data Value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_sdio_f0_readb(moal_handle *handle, t_u32 reg, t_u8 *data)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 val;
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ val = sdio_f0_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
+ (int *)&ret);
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ *data = val;
+
+ return ret;
+}
+
+/**
+ * @brief This function use SG mode to read/write data into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf_list Pointer to a linked list of mlan_buffer structure
+ * @param port Port
+ * @param write write flag
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_sdio_rw_mb(moal_handle *handle, pmlan_buffer pmbuf_list,
+ t_u32 port, t_u8 write)
+{
+ struct scatterlist sg_list[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
+ int num_sg = pmbuf_list->use_count;
+ int i = 0;
+ mlan_buffer *pmbuf = NULL;
+ struct mmc_request mmc_req;
+ struct mmc_command mmc_cmd;
+ struct mmc_data mmc_dat;
+ struct sdio_func *func = ((struct sdio_mmc_card *)handle->card)->func;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+ t_u32 blkcnt = pmbuf_list->data_len / MLAN_SDIO_BLOCK_SIZE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ int status;
+#endif
+
+ if (num_sg > SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX) {
+ PRINTM(MERROR, "ERROR: num_sg=%d", num_sg);
+ return MLAN_STATUS_FAILURE;
+ }
+ sg_init_table(sg_list, num_sg);
+ pmbuf = pmbuf_list->pnext;
+ for (i = 0; i < num_sg; i++) {
+ if (pmbuf == pmbuf_list)
+ break;
+ sg_set_buf(&sg_list[i], pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ pmbuf = pmbuf->pnext;
+ }
+ memset(&mmc_req, 0, sizeof(struct mmc_request));
+ memset(&mmc_cmd, 0, sizeof(struct mmc_command));
+ memset(&mmc_dat, 0, sizeof(struct mmc_data));
+
+ mmc_dat.sg = sg_list;
+ mmc_dat.sg_len = num_sg;
+ mmc_dat.blksz = MLAN_SDIO_BLOCK_SIZE;
+ mmc_dat.blocks = blkcnt;
+ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+
+ mmc_cmd.opcode = SD_IO_RW_EXTENDED;
+ mmc_cmd.arg = write ? 1 << 31 : 0;
+ mmc_cmd.arg |= (func->num & 0x7) << 28;
+ mmc_cmd.arg |= 1 << 27; /* block basic */
+ mmc_cmd.arg |= 0; /* fix address */
+ mmc_cmd.arg |= (ioport & 0x1FFFF) << 9;
+ mmc_cmd.arg |= blkcnt & 0x1FF;
+ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ mmc_req.cmd = &mmc_cmd;
+ mmc_req.data = &mmc_dat;
+
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ mmc_set_data_timeout(
+ &mmc_dat, ((struct sdio_mmc_card *)handle->card)->func->card);
+ mmc_wait_for_req(
+ ((struct sdio_mmc_card *)handle->card)->func->card->host,
+ &mmc_req);
+
+ if (mmc_cmd.error || mmc_dat.error) {
+ PRINTM(MERROR, "CMD53 %s cmd_error = %d data_error=%d\n",
+ write ? "write" : "read", mmc_cmd.error, mmc_dat.error);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ /* issue abort cmd52 command through F0*/
+ sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
+ 0x01, SDIO_CCCR_ABORT, &status);
+#endif
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ return MLAN_STATUS_FAILURE;
+ }
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function writes multiple bytes into card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_sdiommc_write_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode =
+ (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt = (blkmode == BLOCK_MODE) ?
+ (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) :
+ pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+ int status = 0;
+ if (pmbuf->use_count > 1)
+ return woal_sdio_rw_mb(handle, pmbuf, port, MTRUE);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 1;
+#endif
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ status = sdio_writesb(((struct sdio_mmc_card *)handle->card)->func,
+ ioport, buffer, blkcnt * blksz);
+ if (!status)
+ ret = MLAN_STATUS_SUCCESS;
+ else {
+ PRINTM(MERROR, "cmd53 write error=%d\n", status);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ /* issue abort cmd52 command through F0*/
+ sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
+ 0x01, SDIO_CCCR_ABORT, &status);
+#endif
+ }
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53w = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function reads multiple bytes from card memory
+ *
+ * @param handle A Pointer to the moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param port Port
+ * @param timeout Time out value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_sdiommc_read_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 port,
+ t_u32 timeout)
+{
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 blkmode =
+ (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
+ t_u32 blkcnt = (blkmode == BLOCK_MODE) ?
+ (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) :
+ pmbuf->data_len;
+ t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
+ int status = 0;
+ if (pmbuf->use_count > 1)
+ return woal_sdio_rw_mb(handle, pmbuf, port, MFALSE);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 1;
+#endif
+ sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
+ status = sdio_readsb(((struct sdio_mmc_card *)handle->card)->func,
+ buffer, ioport, blkcnt * blksz);
+ if (!status) {
+ ret = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "cmd53 read error=%d\n", status);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ /* issue abort cmd52 command through F0*/
+ sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
+ 0x01, SDIO_CCCR_ABORT, &status);
+#endif
+ }
+ sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
+#ifdef SDIO_MMC_DEBUG
+ handle->cmd53r = 2;
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function registers the IF module in bus driver
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_sdiommc_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* SDIO Driver Registration */
+ if (sdio_register_driver(&wlan_sdio)) {
+ PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function de-registers the IF module in bus driver
+ *
+ * @return N/A
+ */
+void woal_sdiommc_bus_unregister(void)
+{
+ ENTER();
+
+ /* SDIO Driver Unregistration */
+ sdio_unregister_driver(&wlan_sdio);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function de-registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return N/A
+ */
+static void woal_sdiommc_unregister_dev(moal_handle *handle)
+{
+ ENTER();
+ if (handle->card) {
+ struct sdio_mmc_card *card = handle->card;
+ /* Release the SDIO IRQ */
+ sdio_claim_host(card->func);
+ sdio_release_irq(card->func);
+ sdio_disable_func(card->func);
+ sdio_release_host(card->func);
+
+ sdio_set_drvdata(card->func, NULL);
+
+ PRINTM(MWARN, "Making the sdio dev card as NULL\n");
+ card->handle = NULL;
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function registers the device
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_sdiommc_register_dev(moal_handle *handle)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = handle->card;
+ struct sdio_func *func;
+
+ ENTER();
+
+ /* save adapter pointer in card */
+ card->handle = handle;
+ func = card->func;
+ sdio_claim_host(func);
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, woal_sdio_interrupt);
+ if (ret) {
+ PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+ goto release_host;
+ }
+
+ /* Set block size */
+ ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_set_block_seize(): cannot set SDIO block size\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto release_irq;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+
+release_irq:
+ sdio_release_irq(func);
+release_host:
+ sdio_release_host(func);
+ handle->card = NULL;
+
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+}
+
+/**
+ * @brief This function set bus clock on/off
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param option TRUE--on , FALSE--off
+ * @return MLAN_STATUS_SUCCESS
+ */
+int woal_sdio_set_bus_clock(moal_handle *handle, t_u8 option)
+{
+ struct sdio_mmc_card *cardp = (struct sdio_mmc_card *)handle->card;
+ struct mmc_host *host = cardp->func->card->host;
+
+ ENTER();
+ if (option == MTRUE) {
+ /* restore value if non-zero */
+ if (cardp->host_clock)
+ host->ios.clock = cardp->host_clock;
+ } else {
+ /* backup value if non-zero, then clear */
+ if (host->ios.clock)
+ cardp->host_clock = host->ios.clock;
+ host->ios.clock = 0;
+ }
+
+ host->ops->set_ios(host, &host->ios);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function updates card reg based on the Cmd52 value in dev
+ * structure
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param func A pointer to store func variable
+ * @param reg A pointer to store reg variable
+ * @param val A pointer to store val variable
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+int woal_sdio_read_write_cmd52(moal_handle *handle, int func, int reg, int val)
+{
+ int ret = MLAN_STATUS_SUCCESS;
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
+
+ ENTER();
+ /* Save current func and reg for read */
+ handle->cmd52_func = func;
+ handle->cmd52_reg = reg;
+ sdio_claim_host(card->func);
+ if (val >= 0) {
+ /* Perform actual write only if val is provided */
+ if (func)
+ sdio_writeb(card->func, val, reg, &ret);
+ else
+ sdio_f0_writeb(card->func, val, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR,
+ "Cannot write value (0x%x) to func %d reg 0x%x\n",
+ val, func, reg);
+ } else {
+ PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n",
+ (u8)val, func, reg);
+ handle->cmd52_val = val;
+ }
+ } else {
+ if (func)
+ val = sdio_readb(card->func, reg, &ret);
+ else
+ val = sdio_f0_readb(card->func, reg, &ret);
+ if (ret) {
+ PRINTM(MERROR,
+ "Cannot read value from func %d reg 0x%x\n",
+ func, reg);
+ } else {
+ PRINTM(MMSG,
+ "read value (0x%x) from func %d reg 0x%x\n",
+ (u8)val, func, reg);
+ handle->cmd52_val = val;
+ }
+ }
+ sdio_release_host(card->func);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function check if this is second mac
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MTRUE/MFALSE
+ *
+ */
+static t_u8 woal_sdiommc_is_second_mac(moal_handle *handle)
+{
+#ifdef SD9098
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
+ if (card->func->device == SD_DEVICE_ID_9098_FN2)
+ return MTRUE;
+#endif
+ return MFALSE;
+}
+
+static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#ifdef SD9098
+ struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
+#endif
+ t_u32 revision_id = 0;
+ t_u32 rev_id_reg = handle->card_info->rev_id_reg;
+
+#if defined(SD8987) || defined(SD8997) || defined(SD9098) || \
+ defined(SD9097) || defined(SD8978)
+ t_u32 magic_reg = handle->card_info->magic_reg;
+ t_u32 magic = 0;
+ t_u32 host_strap_reg = handle->card_info->host_strap_reg;
+ t_u32 strap = 0;
+#endif
+
+ ENTER();
+
+ if (handle->params.fw_name)
+ goto done;
+ /** Revision ID register */
+ woal_sdiommc_read_reg(handle, rev_id_reg, &revision_id);
+ PRINTM(MCMND, "revision_id=0x%x\n", revision_id);
+
+#if defined(SD8987) || defined(SD8997) || defined(SD9098) || \
+ defined(SD9097) || defined(SD8978)
+ /** Revision ID register */
+ woal_sdiommc_read_reg(handle, magic_reg, &magic);
+ /** Revision ID register */
+ woal_sdiommc_read_reg(handle, host_strap_reg, &strap);
+ strap &= 0x1;
+ magic &= 0xFF;
+ /* 1 = SDSD, 0 --SD UART */
+ PRINTM(MCMND, "magic=0x%x strap=0x%x\n", magic, strap);
+#endif
+#if defined(SD8977)
+ if (IS_SD8977(handle->card_type)) {
+ switch (revision_id) {
+ case SD8977_V0:
+ strcpy(handle->card_info->fw_name, SD8977_V0_FW_NAME);
+ strcpy(handle->card_info->fw_name_wlan,
+ SD8977_WLAN_V0_FW_NAME);
+ break;
+ case SD8977_V1:
+ strcpy(handle->card_info->fw_name, SD8977_V1_FW_NAME);
+ strcpy(handle->card_info->fw_name_wlan,
+ SD8977_WLAN_V1_FW_NAME);
+ break;
+ case SD8977_V2:
+ strcpy(handle->card_info->fw_name, SD8977_V2_FW_NAME);
+ strcpy(handle->card_info->fw_name_wlan,
+ SD8977_WLAN_V2_FW_NAME);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+#if defined(SD8887)
+ if (IS_SD8887(handle->card_type)) {
+ /* Check revision ID */
+ switch (revision_id) {
+ case SD8887_A0:
+ strcpy(handle->card_info->fw_name, SD8887_A0_FW_NAME);
+ strcpy(handle->card_info->fw_name_wlan,
+ SD8887_WLAN_A0_FW_NAME);
+ break;
+ case SD8887_A2:
+ strcpy(handle->card_info->fw_name, SD8887_A2_FW_NAME);
+ strcpy(handle->card_info->fw_name_wlan,
+ SD8887_WLAN_A2_FW_NAME);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
+#ifdef SD8997
+ if (IS_SD8997(handle->card_type)) {
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART8997_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD8997_DEFAULT_COMBO_FW_NAME);
+ }
+ }
+#endif
+
+#ifdef SD8987
+ if (IS_SD8987(handle->card_type)) {
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART8987_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD8987_DEFAULT_COMBO_FW_NAME);
+ }
+ }
+#endif
+
+#ifdef SD8978
+ if (IS_SD8978(handle->card_type)) {
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART8978_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD8978_DEFAULT_COMBO_FW_NAME);
+ }
+ }
+#endif
+
+#ifdef SD9098
+ if (IS_SD9098(handle->card_type) &&
+ (card->func->device == SD_DEVICE_ID_9098_FN1)) {
+ switch (revision_id) {
+ case SD9098_Z1Z2:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART9098_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD9098_DEFAULT_COMBO_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ SD9098_DEFAULT_WLAN_FW_NAME);
+ break;
+ case SD9098_A0:
+ case SD9098_A1:
+ case SD9098_A2:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART9098_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD9098_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ SD9098_WLAN_V1_FW_NAME);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+#ifdef SD9097
+ if (IS_SD9097(handle->card_type)) {
+ switch (revision_id) {
+ case SD9097_B0:
+ case SD9097_B1:
+ if (magic == CHIP_MAGIC_VALUE) {
+ if (strap == CARD_TYPE_SD_UART)
+ strcpy(handle->card_info->fw_name,
+ SDUART9097_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ SDSD9097_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ SD9097_WLAN_V1_FW_NAME);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+done:
+ PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
+ handle->card_info->fw_name_wlan);
+ LEAVE();
+ return ret;
+}
+
+#define DEBUG_FW_DONE 0xFF
+#define DEBUG_MEMDUMP_FINISH 0xFE
+#define MAX_POLL_TRIES 100
+
+typedef enum {
+ DUMP_TYPE_ITCM = 0,
+ DUMP_TYPE_DTCM = 1,
+ DUMP_TYPE_SQRAM = 2,
+ DUMP_TYPE_APU_REGS = 3,
+ DUMP_TYPE_CIU_REGS = 4,
+ DUMP_TYPE_ICU_REGS = 5,
+ DUMP_TYPE_MAC_REGS = 6,
+ DUMP_TYPE_EXTEND_7 = 7,
+ DUMP_TYPE_EXTEND_8 = 8,
+ DUMP_TYPE_EXTEND_9 = 9,
+ DUMP_TYPE_EXTEND_10 = 10,
+ DUMP_TYPE_EXTEND_11 = 11,
+ DUMP_TYPE_EXTEND_12 = 12,
+ DUMP_TYPE_EXTEND_13 = 13,
+ DUMP_TYPE_EXTEND_LAST = 14
+} dumped_mem_type;
+
+#define MAX_NAME_LEN 8
+#define MAX_FULL_NAME_LEN 32
+
+typedef struct {
+ t_u8 mem_name[MAX_NAME_LEN];
+ t_u8 *mem_Ptr;
+ struct file *pfile_mem;
+ t_u8 done_flag;
+ t_u8 type;
+} memory_type_mapping;
+
+memory_type_mapping mem_type_mapping_tbl[] = {
+ {"ITCM", NULL, NULL, 0xF0, FW_DUMP_TYPE_MEM_ITCM},
+ {"DTCM", NULL, NULL, 0xF1, FW_DUMP_TYPE_MEM_DTCM},
+ {"SQRAM", NULL, NULL, 0xF2, FW_DUMP_TYPE_MEM_SQRAM},
+ {"APU", NULL, NULL, 0xF3, FW_DUMP_TYPE_REG_APU},
+ {"CIU", NULL, NULL, 0xF4, FW_DUMP_TYPE_REG_CIU},
+ {"ICU", NULL, NULL, 0xF5, FW_DUMP_TYPE_REG_ICU},
+ {"MAC", NULL, NULL, 0xF6, FW_DUMP_TYPE_REG_MAC},
+ {"EXT7", NULL, NULL, 0xF7, 0},
+ {"EXT8", NULL, NULL, 0xF8, 0},
+ {"EXT9", NULL, NULL, 0xF9, 0},
+ {"EXT10", NULL, NULL, 0xFA, 0},
+ {"EXT11", NULL, NULL, 0xFB, 0},
+ {"EXT12", NULL, NULL, 0xFC, 0},
+ {"EXT13", NULL, NULL, 0xFD, 0},
+ {"EXTLAST", NULL, NULL, 0xFE, 0},
+};
+memory_type_mapping mem_type_mapping_tbl_8977_8997 = {"DUMP", NULL, NULL, 0xDD,
+ 0};
+
+typedef enum {
+ RDWR_STATUS_SUCCESS = 0,
+ RDWR_STATUS_FAILURE = 1,
+ RDWR_STATUS_DONE = 2
+} rdwr_status;
+
+/**
+ * @brief This function read/write firmware via cmd52
+ *
+ * @param phandle A pointer to moal_handle
+ * @param doneflag A flag
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+rdwr_status woal_cmd52_rdwr_firmware(moal_handle *phandle, t_u8 doneflag)
+{
+ int ret = 0;
+ int tries = 0;
+ t_u8 ctrl_data = 0;
+ t_u8 dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg;
+ t_u8 debug_host_ready = phandle->card_info->dump_fw_host_ready;
+
+ ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg, debug_host_ready);
+ if (ret) {
+ PRINTM(MERROR, "SDIO Write ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = woal_sdio_readb(phandle, dbg_dump_ctrl_reg, &ctrl_data);
+ if (ret) {
+ PRINTM(MERROR, "SDIO READ ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ if (ctrl_data == DEBUG_FW_DONE)
+ break;
+ if (doneflag && ctrl_data == doneflag)
+ return RDWR_STATUS_DONE;
+ if (ctrl_data != debug_host_ready) {
+ PRINTM(MMSG,
+ "The ctrl reg was changed, re-try again!\n");
+ ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg,
+ debug_host_ready);
+ if (ret) {
+ PRINTM(MERROR, "SDIO Write ERR\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ }
+ udelay(100);
+ }
+ if (ctrl_data == debug_host_ready) {
+ PRINTM(MERROR, "Fail to pull ctrl_data\n");
+ return RDWR_STATUS_FAILURE;
+ }
+ return RDWR_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_dump_firmware_info_v2(moal_handle *phandle)
+{
+ int ret = 0;
+ unsigned int reg, reg_start, reg_end;
+ t_u8 *dbg_ptr = NULL;
+ t_u32 sec, usec;
+ t_u8 dump_num = 0;
+ t_u8 idx = 0;
+ t_u8 doneflag = 0;
+ rdwr_status stat;
+ t_u8 i = 0;
+ t_u8 read_reg = 0;
+ t_u32 memory_size = 0;
+ t_u8 path_name[64], file_name[32], firmware_dump_file[128];
+ t_u8 *end_ptr = NULL;
+ t_u8 dbg_dump_start_reg = 0;
+ t_u8 dbg_dump_end_reg = 0;
+ t_u8 dbg_dump_ctrl_reg = 0;
+
+ if (!phandle) {
+ PRINTM(MERROR, "Could not dump firmwware info\n");
+ return;
+ }
+
+ dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg;
+ dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg;
+ dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ /** Create dump directort*/
+ woal_create_dump_dir(phandle, path_name, sizeof(path_name));
+#else
+ memset(path_name, 0, sizeof(path_name));
+ strcpy(path_name, "/data");
+#endif
+ PRINTM(MMSG, "Directory name is %s\n", path_name);
+
+ woal_dump_drv_info(phandle, path_name);
+
+ /* start dump fw memory */
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
+ /* read the number of the memories which will dump */
+ if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag))
+ goto done;
+ reg = dbg_dump_start_reg;
+ ret = woal_sdio_readb(phandle, reg, &dump_num);
+ if (ret) {
+ PRINTM(MMSG, "SDIO READ MEM NUM ERR\n");
+ goto done;
+ }
+
+ /* read the length of every memory which will dump */
+ for (idx = 0; idx < dump_num; idx++) {
+ if (RDWR_STATUS_FAILURE ==
+ woal_cmd52_rdwr_firmware(phandle, doneflag))
+ goto done;
+ memory_size = 0;
+ reg = dbg_dump_start_reg;
+ for (i = 0; i < 4; i++) {
+ ret = woal_sdio_readb(phandle, reg, &read_reg);
+ if (ret) {
+ PRINTM(MMSG, "SDIO READ ERR\n");
+ goto done;
+ }
+ memory_size |= (read_reg << i * 8);
+ reg++;
+ }
+ if (memory_size == 0) {
+ PRINTM(MMSG, "Firmware Dump Finished!\n");
+ ret = woal_sdiommc_write_reg(phandle, dbg_dump_ctrl_reg,
+ DEBUG_MEMDUMP_FINISH);
+ if (ret) {
+ PRINTM(MERROR,
+ "SDIO Write MEMDUMP_FINISH ERR\n");
+ goto done;
+ }
+ break;
+ } else {
+ PRINTM(MMSG, "%s_SIZE=0x%x\n",
+ mem_type_mapping_tbl[idx].mem_name, memory_size);
+ ret = moal_vmalloc(
+ phandle, memory_size + 1,
+ (t_u8 **)&mem_type_mapping_tbl[idx].mem_Ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) ||
+ !mem_type_mapping_tbl[idx].mem_Ptr) {
+ PRINTM(MERROR,
+ "Error: vmalloc %s buffer failed!!!\n",
+ mem_type_mapping_tbl[idx].mem_name);
+ goto done;
+ }
+ dbg_ptr = mem_type_mapping_tbl[idx].mem_Ptr;
+ end_ptr = dbg_ptr + memory_size;
+ }
+ doneflag = mem_type_mapping_tbl[idx].done_flag;
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
+ mem_type_mapping_tbl[idx].mem_name, sec, usec);
+ do {
+ stat = woal_cmd52_rdwr_firmware(phandle, doneflag);
+ if (RDWR_STATUS_FAILURE == stat)
+ goto done;
+ reg_start = dbg_dump_start_reg;
+ reg_end = dbg_dump_end_reg;
+ for (reg = reg_start; reg <= reg_end; reg++) {
+ ret = woal_sdio_readb(phandle, reg, dbg_ptr);
+ if (ret) {
+ PRINTM(MMSG, "SDIO READ ERR\n");
+ goto done;
+ }
+ if (dbg_ptr < end_ptr)
+ dbg_ptr++;
+ else
+ PRINTM(MMSG,
+ "pre-allocced buf is not enough\n");
+ }
+ if (RDWR_STATUS_DONE == stat) {
+ PRINTM(MMSG,
+ "%s done:"
+#ifdef MLAN_64BIT
+ "size = 0x%lx\n",
+#else
+ "size = 0x%x\n",
+#endif
+ mem_type_mapping_tbl[idx].mem_name,
+ dbg_ptr - mem_type_mapping_tbl[idx]
+ .mem_Ptr);
+ memset(file_name, 0, sizeof(file_name));
+ sprintf(file_name, "%s%s", "file_sdio_",
+ mem_type_mapping_tbl[idx].mem_name);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_save_dump_info_to_file(
+ path_name, file_name,
+ mem_type_mapping_tbl[idx].mem_Ptr,
+ memory_size))
+ PRINTM(MERROR,
+ "Can't save dump file %s in %s\n",
+ file_name, path_name);
+ moal_vfree(phandle,
+ mem_type_mapping_tbl[idx].mem_Ptr);
+ mem_type_mapping_tbl[idx].mem_Ptr = NULL;
+ break;
+ }
+ } while (1);
+ }
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
+ /* end dump fw memory */
+ memset(firmware_dump_file, 0, sizeof(firmware_dump_file));
+ sprintf(firmware_dump_file, "%s/%s", path_name, file_name);
+ moal_memcpy_ext(phandle, phandle->firmware_dump_file,
+ firmware_dump_file, sizeof(firmware_dump_file),
+ sizeof(phandle->firmware_dump_file));
+done:
+ for (idx = 0; idx < dump_num; idx++) {
+ if (mem_type_mapping_tbl[idx].mem_Ptr) {
+ moal_vfree(phandle, mem_type_mapping_tbl[idx].mem_Ptr);
+ mem_type_mapping_tbl[idx].mem_Ptr = NULL;
+ }
+ }
+ PRINTM(MMSG, "==== DEBUG MODE END ====\n");
+ return;
+}
+
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_dump_firmware_info_v3(moal_handle *phandle)
+{
+ int ret = 0;
+ int tries = 0;
+ unsigned int reg, reg_start, reg_end;
+ t_u8 *dbg_ptr = NULL;
+ t_u8 *temp_Ptr = NULL;
+ t_u32 sec, usec;
+ t_u8 start_flag = 0;
+ t_u8 doneflag = 0;
+ rdwr_status stat;
+ t_u32 memory_size = 0;
+ t_u8 path_name[64], file_name[32], firmware_dump_file[128];
+ moal_handle *ref_handle;
+ t_u8 *end_ptr = NULL;
+ t_u8 dbg_dump_start_reg = 0;
+ t_u8 dbg_dump_end_reg = 0;
+ memory_type_mapping *pmem_type_mapping_tbl =
+ &mem_type_mapping_tbl_8977_8997;
+
+ if (!phandle) {
+ PRINTM(MERROR, "Could not dump firmwware info\n");
+ return;
+ }
+
+ dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg;
+ dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ /** Create dump directort*/
+ woal_create_dump_dir(phandle, path_name, sizeof(path_name));
+#else
+ memset(path_name, 0, sizeof(path_name));
+ strcpy(path_name, "/data");
+#endif
+ PRINTM(MMSG, "Directory name is %s\n", path_name);
+ ref_handle = (moal_handle *)phandle->pref_mac;
+ if (ref_handle)
+ woal_dump_drv_info(ref_handle, path_name);
+ woal_dump_drv_info(phandle, path_name);
+
+ /* start dump fw memory */
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
+ /* read the number of the memories which will dump */
+ if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag))
+ goto done;
+
+ /** check the reg which indicate dump starting */
+ for (reg = dbg_dump_start_reg; reg <= dbg_dump_end_reg; reg++) {
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = woal_sdio_readb(phandle, reg, &start_flag);
+ if (ret) {
+ PRINTM(MMSG, "SDIO READ ERR\n");
+ goto done;
+ }
+ /** 0 means dump starting*/
+ if (start_flag == 0)
+ break;
+ udelay(100);
+ }
+ if (tries == MAX_POLL_TRIES) {
+ PRINTM(MMSG, "FW not ready to dump\n");
+ goto done;
+ }
+ }
+ memory_size = 0xF0000;
+ PRINTM(MMSG, "%s_SIZE=0x%x\n", pmem_type_mapping_tbl->mem_name,
+ memory_size);
+ ret = moal_vmalloc(phandle, memory_size + 1,
+ (t_u8 **)&pmem_type_mapping_tbl->mem_Ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) || !pmem_type_mapping_tbl->mem_Ptr) {
+ PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n",
+ pmem_type_mapping_tbl->mem_name);
+ goto done;
+ }
+ dbg_ptr = pmem_type_mapping_tbl->mem_Ptr;
+ end_ptr = dbg_ptr + memory_size;
+ doneflag = pmem_type_mapping_tbl->done_flag;
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
+ pmem_type_mapping_tbl->mem_name, sec, usec);
+ do {
+ stat = woal_cmd52_rdwr_firmware(phandle, doneflag);
+ if (RDWR_STATUS_FAILURE == stat)
+ goto done;
+ reg_start = dbg_dump_start_reg;
+ reg_end = dbg_dump_end_reg;
+ for (reg = reg_start; reg <= reg_end; reg++) {
+ ret = woal_sdio_readb(phandle, reg, dbg_ptr);
+ if (ret) {
+ PRINTM(MMSG, "SDIO READ ERR\n");
+ goto done;
+ }
+ dbg_ptr++;
+ if (dbg_ptr >= end_ptr) {
+ PRINTM(MMSG,
+ "pre-allocced buf is not enough\n");
+ ret = moal_vmalloc(phandle,
+ memory_size + 0x4000 + 1,
+ (t_u8 **)&temp_Ptr);
+ if ((ret != MLAN_STATUS_SUCCESS) || !temp_Ptr) {
+ PRINTM(MERROR,
+ "Error: vmalloc buffer failed!!!\n");
+ goto done;
+ }
+ moal_memcpy_ext(phandle, temp_Ptr,
+ pmem_type_mapping_tbl->mem_Ptr,
+ memory_size,
+ memory_size + 0x4000);
+ moal_vfree(phandle,
+ pmem_type_mapping_tbl->mem_Ptr);
+ pmem_type_mapping_tbl->mem_Ptr = temp_Ptr;
+ temp_Ptr = NULL;
+ dbg_ptr = pmem_type_mapping_tbl->mem_Ptr +
+ memory_size;
+ memory_size += 0x4000;
+ end_ptr = pmem_type_mapping_tbl->mem_Ptr +
+ memory_size;
+ }
+ }
+ if (RDWR_STATUS_DONE == stat) {
+ PRINTM(MMSG,
+ "%s done:"
+#ifdef MLAN_64BIT
+ "size = 0x%lx\n",
+#else
+ "size = 0x%x\n",
+#endif
+ pmem_type_mapping_tbl->mem_name,
+ dbg_ptr - pmem_type_mapping_tbl->mem_Ptr);
+ memset(file_name, 0, sizeof(file_name));
+ sprintf(file_name, "%s%s", "file_sdio_",
+ pmem_type_mapping_tbl->mem_name);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_save_dump_info_to_file(
+ path_name, file_name,
+ pmem_type_mapping_tbl->mem_Ptr,
+ dbg_ptr - pmem_type_mapping_tbl->mem_Ptr))
+ PRINTM(MERROR,
+ "Can't save dump file %s in %s\n",
+ file_name, path_name);
+ moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr);
+ pmem_type_mapping_tbl->mem_Ptr = NULL;
+ break;
+ }
+ } while (1);
+ moal_get_system_time(phandle, &sec, &usec);
+ PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
+ /* end dump fw memory */
+ memset(firmware_dump_file, 0, sizeof(firmware_dump_file));
+ sprintf(firmware_dump_file, "%s/%s", path_name, file_name);
+ moal_memcpy_ext(phandle, phandle->firmware_dump_file,
+ firmware_dump_file, sizeof(firmware_dump_file),
+ sizeof(phandle->firmware_dump_file));
+done:
+ if (pmem_type_mapping_tbl->mem_Ptr) {
+ moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr);
+ pmem_type_mapping_tbl->mem_Ptr = NULL;
+ }
+ PRINTM(MMSG, "==== DEBUG MODE END ====\n");
+ return;
+}
+
+/**
+ * @brief This function reads and displays SDIO registers for debugging
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void woal_sdiommc_reg_dbg(moal_handle *phandle)
+{
+ int ret = 0;
+ t_u8 loop, index = 0, func, data;
+ unsigned int reg, reg_start, reg_end;
+ unsigned int scratch_reg = phandle->card_info->scratch_reg;
+ t_u8 *reg_table = phandle->card_info->dump_reg.reg_table;
+ t_u8 reg_table_size = phandle->card_info->dump_reg.reg_table_size;
+ char buf[256], *ptr;
+
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+ for (loop = 0; loop < 5; loop++) {
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ if (loop == 0) {
+ /* Read the registers of SDIO function0 */
+ func = loop;
+ reg_start = 0;
+ reg_end = 9;
+ } else if (loop == 1) {
+ /* Read the registers of SDIO function1 */
+ func = loop;
+ reg_start = phandle->card_info->func1_reg_start;
+ reg_end = phandle->card_info->func1_reg_end;
+ } else if (loop == 2) {
+ /* Read specific registers of SDIO function1 */
+ index = 0;
+ func = 1;
+ reg_start = reg_table[index++];
+ reg_end = reg_table[reg_table_size - 1];
+ } else {
+ /* Read the scratch registers of SDIO function1 */
+ if (loop == 4)
+ mdelay(100);
+ func = 1;
+ reg_start = scratch_reg;
+ reg_end = scratch_reg + 10;
+ }
+ if (loop != 2)
+ ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
+ reg_start, reg_end);
+ else
+ ptr += sprintf(ptr, "SDIO Func%d: ", func);
+ for (reg = reg_start; reg <= reg_end;) {
+ if (func == 0)
+ ret = woal_sdio_f0_readb(phandle, reg, &data);
+ else
+ ret = woal_sdio_readb(phandle, reg, &data);
+ if (loop == 2)
+ ptr += sprintf(ptr, "(%#x) ", reg);
+ if (!ret)
+ ptr += sprintf(ptr, "%02x ", data);
+ else {
+ ptr += sprintf(ptr, "ERR");
+ break;
+ }
+ if (loop == 2 && reg < reg_end)
+ reg = reg_table[index++];
+ else
+ reg++;
+ }
+ PRINTM(MMSG, "%s\n", buf);
+ }
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+}
+
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+static void woal_sdiommc_dump_fw_info(moal_handle *phandle)
+{
+ if (!phandle) {
+ PRINTM(MERROR, "Could not dump firmwware info\n");
+ return;
+ }
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+ phandle->fw_dump = MTRUE;
+ if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V2) {
+ woal_dump_firmware_info_v2(phandle);
+ } else if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V3) {
+ woal_dump_firmware_info_v3(phandle);
+ }
+ phandle->fw_dump = MFALSE;
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+ queue_work(phandle->workqueue, &phandle->main_work);
+ return;
+}
+
+/**
+ * @brief This function save sdio reg info
+ *
+ * @param phandle A pointer to moal_handle
+ * @param buf A pointer buffer saving log
+ *
+ * @return The length of this log
+ */
+static int woal_sdiommc_dump_reg_info(moal_handle *phandle, t_u8 *drv_buf)
+{
+ char *drv_ptr = (char *)drv_buf;
+ int ret = 0;
+ t_u8 loop, index = 0, func, data;
+ unsigned int reg, reg_start, reg_end;
+ unsigned int scratch_reg = 0;
+ t_u8 *reg_table = NULL;
+ t_u8 reg_table_size = 0;
+ char buf[256], *ptr;
+
+ ENTER();
+
+ if (!phandle || !drv_buf) {
+ PRINTM(MMSG, "%s: can't retreive info\n", __func__);
+ LEAVE();
+ return 0;
+ }
+
+ scratch_reg = phandle->card_info->scratch_reg;
+ reg_table = phandle->card_info->dump_reg.reg_table;
+ reg_table_size = phandle->card_info->dump_reg.reg_table_size;
+
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
+
+ drv_ptr += sprintf(drv_ptr, "--------sdio_reg_debug_info---------\n");
+ for (loop = 0; loop < 5; loop++) {
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ if (loop == 0) {
+ /* Read the registers of SDIO function0 */
+ func = loop;
+ reg_start = 0;
+ reg_end = 9;
+
+ } else if (loop == 1) {
+ /* Read the registers of SDIO function1 */
+ func = loop;
+ reg_start = phandle->card_info->func1_reg_start;
+ reg_end = phandle->card_info->func1_reg_end;
+ } else if (loop == 2) {
+ /* Read specific registers of SDIO function1 */
+ index = 0;
+ func = 1;
+ reg_start = reg_table[index++];
+ reg_end = reg_table[reg_table_size - 1];
+ } else {
+ /* Read the scratch registers of SDIO function1 */
+ if (loop == 4)
+ mdelay(100);
+ func = 1;
+ reg_start = scratch_reg;
+ reg_end = scratch_reg + 10;
+ }
+ if (loop != 2)
+ ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
+ reg_start, reg_end);
+ else
+ ptr += sprintf(ptr, "SDIO Func%d: ", func);
+ for (reg = reg_start; reg <= reg_end;) {
+ if (func == 0)
+ ret = woal_sdio_f0_readb(phandle, reg, &data);
+ else
+ ret = woal_sdio_readb(phandle, reg, &data);
+
+ if (loop == 2)
+ ptr += sprintf(ptr, "(%#x) ", reg);
+ if (!ret)
+ ptr += sprintf(ptr, "%02x ", data);
+ else {
+ ptr += sprintf(ptr, "ERR");
+ break;
+ }
+ if (loop == 2 && reg < reg_end)
+ reg = reg_table[index++];
+ else
+ reg++;
+ }
+ drv_ptr += sprintf(drv_ptr, "%s\n", buf);
+ }
+
+ drv_ptr +=
+ sprintf(drv_ptr, "--------sdio_reg_debug_info End---------\n");
+ mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
+
+ LEAVE();
+ return drv_ptr - (char *)drv_buf;
+}
+
+static moal_if_ops sdiommc_ops = {
+ .register_dev = woal_sdiommc_register_dev,
+ .unregister_dev = woal_sdiommc_unregister_dev,
+ .read_reg = woal_sdiommc_read_reg,
+ .write_reg = woal_sdiommc_write_reg,
+ .read_data_sync = woal_sdiommc_read_data_sync,
+ .write_data_sync = woal_sdiommc_write_data_sync,
+ .get_fw_name = woal_sdiommc_get_fw_name,
+ .dump_fw_info = woal_sdiommc_dump_fw_info,
+ .dump_reg_info = woal_sdiommc_dump_reg_info,
+ .reg_dbg = woal_sdiommc_reg_dbg,
+ .is_second_mac = woal_sdiommc_is_second_mac,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.c
new file mode 100644
index 000000000000..ff3b593e9c1c
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.c
@@ -0,0 +1,3284 @@
+/** @file moal_shim.c
+ *
+ * @brief This file contains the callback functions registered to MLAN
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#ifdef USB
+#include "moal_usb.h"
+#endif
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif
+#ifdef PCIE
+#include "moal_pcie.h"
+#endif
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#include "moal_cfg80211_util.h"
+#endif
+#include <asm/div64.h>
+
+/********************************************************
+ Local Variables
+********************************************************/
+/** moal_lock */
+typedef struct _moal_lock {
+ /** Lock */
+ spinlock_t lock;
+ /** Flags */
+ unsigned long flags;
+} moal_lock;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern int wifi_status;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Alloc a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size The size of the buffer to be allocated
+ * @param flag The type of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store buffer pointer
+ * allocated
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_malloc(t_void *pmoal_handle, t_u32 size, t_u32 flag,
+ t_u8 **ppbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ t_u32 mem_flag =
+ (in_interrupt() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+
+#ifdef USB
+ if (!IS_USB(handle->card_type))
+#endif
+ {
+ if (flag & MLAN_MEM_DMA)
+ mem_flag |= GFP_DMA;
+ }
+ *ppbuf = kzalloc(size, mem_flag);
+ if (*ppbuf == NULL) {
+ PRINTM(MERROR, "%s: allocate memory (%d bytes) failed!\n",
+ __func__, (int)size);
+ return MLAN_STATUS_FAILURE;
+ }
+ atomic_inc(&handle->malloc_count);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_mfree(t_void *pmoal_handle, t_u8 *pbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+ kfree(pbuf);
+ atomic_dec(&handle->malloc_count);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Alloc a vitual-address-continuous buffer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size The size of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store buffer pointer
+ * allocated
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_vmalloc(t_void *pmoal_handle, t_u32 size, t_u8 **ppbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+
+ *ppbuf = vmalloc(size);
+ if (*ppbuf == NULL) {
+ PRINTM(MERROR, "%s: vmalloc (%d bytes) failed!", __func__,
+ (int)size);
+ return MLAN_STATUS_FAILURE;
+ }
+ atomic_inc(&handle->vmalloc_count);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a buffer allocated by vmalloc
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_vfree(t_void *pmoal_handle, t_u8 *pbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+ vfree(pbuf);
+ atomic_dec(&handle->vmalloc_count);
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef PCIE
+/**
+ * @brief Alloc a consistent block of memory
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size The size of the buffer to be allocated
+ * @param ppbuf Pointer to a buffer location to store memory allocated
+ * @param pbuf_pa Pointer to a buffer location to store physical address
+ * of above memory
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_malloc_consistent(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf, t_pu64 pbuf_pa)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+ *pbuf_pa = 0;
+ *ppbuf = (t_u8 *)pci_alloc_consistent(card->dev, size,
+ (dma_addr_t *)pbuf_pa);
+ if (*ppbuf == NULL) {
+ PRINTM(MERROR,
+ "%s: allocate consistent memory (%d bytes) failed!\n",
+ __func__, (int)size);
+ return MLAN_STATUS_FAILURE;
+ }
+ atomic_inc(&handle->malloc_cons_count);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free a consistent block of memory
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size Size of them memory to be freed
+ * @param pbuf Pointer to the memory to be freed
+ * @param buf_pa Physical address of the memory to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_mfree_consistent(t_void *pmoal_handle, t_u32 size, t_u8 *pbuf,
+ t_u64 buf_pa)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ pcie_service_card *card = handle->card;
+
+ if (!pbuf)
+ return MLAN_STATUS_FAILURE;
+
+ pci_free_consistent(card->dev, size, pbuf, buf_pa);
+ atomic_dec(&handle->malloc_cons_count);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Map a block of memory to device
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to be mapped
+ * @param pbuf_pa Pointer to store the physical address of buffer
+ * @param size Size of the buffer to be mapped
+ * @param flag Flags for mapping IO
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_map_memory(t_void *pmoal_handle, t_u8 *pbuf, t_u64 *pbuf_pa,
+ t_u32 size, t_u32 flag)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+
+ dma_addr_t dma;
+
+ /* Init memory to device */
+ dma = pci_map_single(card->dev, pbuf, size, flag);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ if (pci_dma_mapping_error(card->dev, dma)) {
+#else
+ if (pci_dma_mapping_error(dma)) {
+#endif
+ PRINTM(MERROR, "Tx ring: failed to pci_map_single\n");
+ return MLAN_STATUS_FAILURE;
+ }
+
+ *pbuf_pa = dma;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Unmap a block of memory from device
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pbuf Pointer to the buffer to unmap
+ * @param buf_pa Physical address of buffer to unmap
+ * @param size Size of the buffer to unmap
+ * @param flag Flags for mapping IO
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_unmap_memory(t_void *pmoal_handle, t_u8 *pbuf, t_u64 buf_pa,
+ t_u32 size, t_u32 flag)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ pcie_service_card *card = (pcie_service_card *)handle->card;
+
+ pci_unmap_single(card->dev, buf_pa, size, flag);
+
+ return MLAN_STATUS_SUCCESS;
+}
+#endif /* PCIE */
+
+/**
+ * @brief Fill memory with constant byte
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem Pointer to the memory area
+ * @param byte A constant byte
+ * @param num Number of bytes to fill
+ *
+ * @return Pointer to the memory area
+ */
+t_void *moal_memset(t_void *pmoal_handle, t_void *pmem, t_u8 byte, t_u32 num)
+{
+ t_void *p = pmem;
+
+ if (pmem && num)
+ p = memset(pmem, byte, num);
+
+ return p;
+}
+
+/**
+ * @brief Copy memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *moal_memcpy(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memcpy(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Copy memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ * @param dest_size size of dest memory.
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *moal_memcpy_ext(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num, t_u32 dest_size)
+{
+ t_void *p = pdest;
+ if (pdest && psrc && num && dest_size)
+ p = memcpy(pdest, psrc, MIN(num, dest_size));
+
+ return p;
+}
+
+/**
+ * @brief Move memory from one area to another
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pdest Pointer to the dest memory
+ * @param psrc Pointer to the src memory
+ * @param num Number of bytes to move
+ *
+ * @return Pointer to the dest memory
+ */
+t_void *moal_memmove(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num)
+{
+ t_void *p = pdest;
+
+ if (pdest && psrc && num)
+ p = memmove(pdest, psrc, num);
+
+ return p;
+}
+
+/**
+ * @brief Compare two memory areas
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmem1 Pointer to the first memory
+ * @param pmem2 Pointer to the second memory
+ * @param num Number of bytes to compare
+ *
+ * @return Compare result returns by memcmp
+ */
+t_s32 moal_memcmp(t_void *pmoal_handle, const t_void *pmem1,
+ const t_void *pmem2, t_u32 num)
+{
+ t_s32 result;
+
+ result = memcmp(pmem1, pmem2, num);
+
+ return result;
+}
+
+/**
+ * @brief Delay function
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param delay delay in micro-second
+ *
+ * @return N/A
+ */
+t_void moal_udelay(t_void *pmoal_handle, t_u32 delay)
+{
+ if (delay >= 1000)
+ msleep(delay / 1000);
+ if (delay % 1000)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ usleep_range(delay % 1000 - 1, delay % 1000);
+#else
+ udelay(delay % 1000);
+#endif
+}
+
+/**
+ * @brief usleep_range function
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param min_delay minimal delay in micro-second
+ * @param max_delay delay in micro-second
+ *
+ * @return N/A
+ */
+t_void moal_usleep_range(t_void *pmoal_handle, t_u32 min_delay, t_u32 max_delay)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+ usleep_range(min_delay, max_delay);
+#endif
+}
+/**
+ * @brief Retrieves the current system time
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param psec Pointer to buf for the seconds of system time
+ * @param pusec Pointer to buf the micro seconds of system time
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_get_system_time(t_void *pmoal_handle, t_u32 *psec,
+ t_u32 *pusec)
+{
+ wifi_timeval t;
+
+ woal_get_monotonic_time(&t);
+ *psec = t.time_sec;
+ *pusec = t.time_usec;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Retrieves the current boot time
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pnsec Pointer to buf for the Nanoseconds of boot time
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_get_boot_ktime(t_void *pmoal_handle, t_u64 *pnsec)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+ ktime_t time;
+
+ time = ktime_get_with_offset(TK_OFFS_BOOT);
+ *pnsec = *(t_u64 *)&(time);
+#endif
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pptimer Pointer to the timer
+ * @param callback Pointer to callback function
+ * @param pcontext Pointer to context
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_init_timer(t_void *pmoal_handle, t_void **pptimer,
+ IN t_void (*callback)(t_void *pcontext),
+ t_void *pcontext)
+{
+ moal_drv_timer *timer = NULL;
+ t_u32 mem_flag =
+ (in_interrupt() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+
+ timer = kmalloc(sizeof(moal_drv_timer), mem_flag);
+ if (timer == NULL)
+ return MLAN_STATUS_FAILURE;
+ woal_initialize_timer(timer, callback, pcontext);
+ *pptimer = (t_void *)timer;
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_free_timer(t_void *pmoal_handle, t_void *ptimer)
+{
+ moal_drv_timer *timer = (moal_drv_timer *)ptimer;
+
+ if (timer) {
+ if ((timer->timer_is_canceled == MFALSE) &&
+ timer->time_period) {
+ PRINTM(MWARN,
+ "mlan try to free timer without stop timer!\n");
+ woal_cancel_timer(timer);
+ }
+ kfree(timer);
+ }
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Start the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ * @param periodic Periodic timer
+ * @param msec Timer value in milliseconds
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_start_timer(t_void *pmoal_handle, t_void *ptimer,
+ t_u8 periodic, t_u32 msec)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+
+ ((moal_drv_timer *)ptimer)->timer_is_periodic = periodic;
+ woal_mod_timer((moal_drv_timer *)ptimer, msec);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Stop the timer
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param ptimer Pointer to the timer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_stop_timer(t_void *pmoal_handle, t_void *ptimer)
+{
+ if (!ptimer)
+ return MLAN_STATUS_FAILURE;
+ woal_cancel_timer((moal_drv_timer *)ptimer);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Initializes the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pplock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_init_lock(t_void *pmoal_handle, t_void **pplock)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ moal_lock *mlock = NULL;
+
+ mlock = kmalloc(sizeof(moal_lock), GFP_ATOMIC);
+ if (!mlock)
+ return MLAN_STATUS_FAILURE;
+ spin_lock_init(&mlock->lock);
+ *pplock = (t_void *)mlock;
+
+ atomic_inc(&handle->lock_count);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Free the lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Lock
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_free_lock(t_void *pmoal_handle, t_void *plock)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ moal_lock *mlock = plock;
+
+ kfree(mlock);
+ if (mlock)
+ atomic_dec(&handle->lock_count);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief Request a spin lock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_spin_lock(t_void *pmoal_handle, t_void *plock)
+{
+ moal_lock *mlock = plock;
+ unsigned long flags = 0;
+
+ if (mlock) {
+ spin_lock_irqsave(&mlock->lock, flags);
+ mlock->flags = flags;
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief This function collects TP statistics.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param buf pointer to the buffer of a packet
+ * @param drop_point Drop pointer user set
+ *
+ * @return N/A
+ */
+void moal_tp_accounting(t_void *pmoal_handle, void *buf, t_u32 drop_point)
+{
+ struct sk_buff *skb = NULL;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ pmlan_buffer pmbuf = (pmlan_buffer)buf;
+
+ if (drop_point < MAX_TP_ACCOUNT_DROP_POINT_NUM) {
+ if (drop_point == 4) {
+ handle->tp_acnt.tx_bytes[drop_point] += pmbuf->data_len;
+ } else {
+ skb = (struct sk_buff *)buf;
+ handle->tp_acnt.tx_bytes[drop_point] += skb->len;
+ }
+ handle->tp_acnt.tx_packets[drop_point]++;
+ } else if (drop_point <= RX_DROP_P5) {
+ t_u16 rx_len = 0;
+ if (drop_point == RX_DROP_P1 || drop_point == RX_DROP_P2)
+ rx_len = pmbuf->data_len -
+ *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset) +
+ 2); // remove rx_pkt_offset
+ else if (drop_point == RX_DROP_P3) // aggr pkt
+ rx_len = pmbuf->data_len;
+ else if (drop_point == RX_DROP_P4) { // before to kernel
+ skb = (struct sk_buff *)buf;
+ rx_len = skb->len;
+ }
+ handle->tp_acnt
+ .rx_bytes[drop_point - MAX_TP_ACCOUNT_DROP_POINT_NUM] +=
+ rx_len;
+ handle->tp_acnt.rx_packets[drop_point -
+ MAX_TP_ACCOUNT_DROP_POINT_NUM]++;
+ }
+}
+
+void moal_tp_accounting_rx_param(t_void *pmoal_handle, unsigned int type,
+ unsigned int rsvd1)
+{
+ moal_handle *phandle = (moal_handle *)pmoal_handle;
+ switch (type) {
+ case 0: // Rx interrupt
+ phandle->tp_acnt.rx_intr_cnt++;
+ break;
+ case 1: // rx_pkts_queued
+ phandle->tp_acnt.rx_pending = rsvd1;
+ break;
+ case 2: // paused
+ phandle->tp_acnt.rx_paused_cnt++;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief Request a spin_unlock
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param plock Pointer to the lock
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_spin_unlock(t_void *pmoal_handle, t_void *plock)
+{
+ moal_lock *mlock = (moal_lock *)plock;
+
+ if (mlock) {
+ spin_unlock_irqrestore(&mlock->lock, mlock->flags);
+
+ return MLAN_STATUS_SUCCESS;
+ } else {
+ return MLAN_STATUS_FAILURE;
+ }
+}
+
+/**
+ * @brief This function reads one block of firmware data from MOAL
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param offset Offset from where the data will be copied
+ * @param len Length to be copied
+ * @param pbuf Buffer where the data will be copied
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_get_fw_data(t_void *pmoal_handle, t_u32 offset, t_u32 len,
+ t_u8 *pbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+
+ if (!pbuf || !len || !handle->firmware)
+ return MLAN_STATUS_FAILURE;
+
+ if (offset + len > handle->firmware->size)
+ return MLAN_STATUS_FAILURE;
+
+ moal_memcpy_ext(handle, pbuf, handle->firmware->data + offset, len,
+ len);
+
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function get vdll data from moal
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param len Length to be copied
+ * @param pbuf Buffer where the data will be copied
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_get_vdll_data(t_void *pmoal_handle, t_u32 len, t_u8 *pbuf)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ mlan_status status = MLAN_STATUS_FAILURE;
+ t_u32 offset = 0;
+ t_u8 req_fw = MFALSE;
+
+ if (!handle->firmware) {
+ req_fw = MTRUE;
+ woal_vdll_req_fw(handle);
+ }
+
+ if (handle->firmware) {
+ if (len < handle->firmware->size) {
+ offset = handle->firmware->size - len;
+ moal_memcpy_ext(handle, pbuf,
+ handle->firmware->data + offset, len,
+ len);
+ status = MLAN_STATUS_SUCCESS;
+ } else {
+ PRINTM(MERROR, "Invalid VDLL length = %d, fw_len=%d\n",
+ len, (int)handle->firmware->size);
+ }
+ if (req_fw) {
+ release_firmware(handle->firmware);
+ handle->firmware = NULL;
+ }
+ }
+ return status;
+}
+
+/**
+ * @brief This function is called when MLAN completes the initialization
+ * firmware.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_init_fw request
+ * @param phw pointer to mlan_hw_info
+ * @param ptbl pointer to mplan_bss_tbl
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_get_hw_spec_complete(t_void *pmoal_handle, mlan_status status,
+ mlan_hw_info *phw, pmlan_bss_tbl ptbl)
+{
+ ENTER();
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MCMND, "Get Hw Spec done, fw_cap=0x%x\n", phw->fw_cap);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN completes the initialization
+ * firmware.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_init_fw request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_init_fw_complete(t_void *pmoal_handle, mlan_status status)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ ENTER();
+ if (status == MLAN_STATUS_SUCCESS)
+ handle->hardware_status = HardwareStatusReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN shutdown firmware is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param status The status code for mlan_shutdown request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_shutdown_fw_complete(t_void *pmoal_handle, mlan_status status)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ ENTER();
+ handle->hardware_status = HardwareStatusNotReady;
+ handle->init_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->init_wait_q);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when an MLAN IOCTL is completed.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pioctl_req pointer to structure mlan_ioctl_req
+ * @param status The status code for mlan_ioctl request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_ioctl_complete(t_void *pmoal_handle,
+ pmlan_ioctl_req pioctl_req, mlan_status status)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ moal_private *priv = NULL;
+ wait_queue *wait;
+ unsigned long flags = 0;
+ ENTER();
+
+ if (!atomic_read(&handle->ioctl_pending))
+ PRINTM(MERROR, "ERR: Unexpected IOCTL completed: %p\n",
+ pioctl_req);
+ else
+ atomic_dec(&handle->ioctl_pending);
+ priv = woal_bss_index_to_priv(handle, pioctl_req->bss_index);
+ if (!priv) {
+ PRINTM(MERROR,
+ "IOCTL %p complete with NULL priv, bss_index=%d\n",
+ pioctl_req, pioctl_req->bss_index);
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+ }
+
+ if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_COMPLETE)
+ PRINTM(MERROR,
+ "IOCTL failed: %p id=0x%x, sub_id=0x%x action=%d, status_code=0x%x\n",
+ pioctl_req, pioctl_req->req_id,
+ (*(t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action,
+ pioctl_req->status_code);
+ else
+ PRINTM(MIOCTL,
+ "IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n",
+ pioctl_req, pioctl_req->req_id,
+ (*(t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action,
+ status, pioctl_req->status_code);
+
+ spin_lock_irqsave(&handle->driver_lock, flags);
+ wait = (wait_queue *)pioctl_req->reserved_1;
+ if (wait) {
+ wait->condition = MTRUE;
+ wait->status = status;
+ if (wait->wait_timeout) {
+ wake_up(&wait->wait);
+ } else {
+ if ((status != MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->status_code ==
+ MLAN_ERROR_CMD_TIMEOUT)) {
+ PRINTM(MERROR, "IOCTL: command timeout\n");
+ } else {
+ wake_up_interruptible(&wait->wait);
+ }
+ }
+ spin_unlock_irqrestore(&handle->driver_lock, flags);
+ } else {
+ spin_unlock_irqrestore(&handle->driver_lock, flags);
+ if ((status == MLAN_STATUS_SUCCESS) &&
+ (pioctl_req->action == MLAN_ACT_GET))
+ woal_process_ioctl_resp(priv, pioctl_req);
+ kfree(pioctl_req);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function allocates mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param size allocation size requested
+ * @param pmbuf pointer to pointer to the allocated buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_alloc_mlan_buffer(t_void *pmoal_handle, t_u32 size,
+ pmlan_buffer *pmbuf)
+{
+ *pmbuf = woal_alloc_mlan_buffer((moal_handle *)pmoal_handle, size);
+ if (NULL == *pmbuf)
+ return MLAN_STATUS_FAILURE;
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function frees mlan_buffer.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf pointer to buffer to be freed
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_free_mlan_buffer(t_void *pmoal_handle, pmlan_buffer pmbuf)
+{
+ if (!pmbuf)
+ return MLAN_STATUS_FAILURE;
+ woal_free_mlan_buffer((moal_handle *)pmoal_handle, pmbuf);
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function is called when MLAN complete send data packet.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param status The status code for mlan_send_packet request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_send_packet_complete(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ struct sk_buff *skb = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ t_u32 index = 0;
+#endif
+
+ ENTER();
+ if (pmbuf && pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
+ woal_free_mlan_buffer(handle, pmbuf);
+ atomic_dec(&handle->tx_pending);
+ goto done;
+ }
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *)pmbuf->pdesc;
+ if (priv) {
+ woal_set_trans_start(priv->netdev);
+ if (skb) {
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(
+ priv, PACKET_TYPE_TX,
+ TX_PKT_FATE_SENT,
+ FRAME_TYPE_ETHERNET_II, 0, 0,
+ skb->data, skb->data_len);
+#endif
+ } else {
+ priv->stats.tx_errors++;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(
+ priv, PACKET_TYPE_TX,
+ TX_PKT_FATE_DRV_DROP_OTHER,
+ FRAME_TYPE_ETHERNET_II, 0, 0,
+ skb->data, skb->data_len);
+#endif
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ index = skb_get_queue_mapping(skb);
+ atomic_dec(&handle->tx_pending);
+ if (atomic_dec_return(
+ &priv->wmm_tx_pending[index]) ==
+ LOW_TX_PENDING) {
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(
+ priv->netdev, index);
+ if (netif_tx_queue_stopped(txq)) {
+ netif_tx_wake_queue(txq);
+ PRINTM(MINFO,
+ "Wakeup Kernel Queue:%d\n",
+ index);
+ }
+ }
+#else /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
+ if (atomic_dec_return(&handle->tx_pending) <
+ LOW_TX_PENDING) {
+ int i;
+ for (i = 0; i < handle->priv_num; i++) {
+#ifdef STA_SUPPORT
+ if ((GET_BSS_ROLE(
+ handle->priv[i]) ==
+ MLAN_BSS_ROLE_STA) &&
+ (handle->priv[i]
+ ->media_connected ||
+ priv->is_adhoc_link_sensed)) {
+ woal_wake_queue(
+ handle->priv[i]
+ ->netdev);
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if ((GET_BSS_ROLE(
+ handle->priv[i]) ==
+ MLAN_BSS_ROLE_UAP) &&
+ (handle->priv[i]
+ ->media_connected)) {
+ woal_wake_queue(
+ handle->priv[i]
+ ->netdev);
+ }
+#endif
+ }
+ }
+#endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)*/
+ }
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+
+done:
+ if ((atomic_read(&handle->tx_pending) == 0) &&
+ !is_zero_timeval(handle->tx_time_start)) {
+ woal_get_monotonic_time(&handle->tx_time_end);
+ handle->tx_time +=
+ (t_u64)(timeval_to_usec(handle->tx_time_end) -
+ timeval_to_usec(handle->tx_time_start));
+ PRINTM(MINFO,
+ "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu tx_time=%llu\n",
+ __func__, handle->tx_time_start.time_sec,
+ handle->tx_time_start.time_usec,
+ handle->tx_time_end.time_sec,
+ handle->tx_time_end.time_usec,
+ (t_u64)(timeval_to_usec(handle->tx_time_end) -
+ timeval_to_usec(handle->tx_time_start)),
+ handle->tx_time);
+ handle->tx_time_start.time_sec = 0;
+ handle->tx_time_start.time_usec = 0;
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+#ifdef USB
+/**
+ * @brief This function is called when MLAN complete receiving
+ * data/event/command
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for receive
+ * @param status The status code for mlan_receive request
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_recv_complete(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, mlan_status status)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ ENTER();
+
+ if ((pmbuf && (pmbuf->flags & MLAN_BUF_FLAG_RX_DEAGGR)) || !pmbuf)
+ atomic_dec(&handle->rx_pending);
+
+ if (pmbuf) {
+ priv = woal_bss_index_to_priv(handle, pmbuf->bss_index);
+ if (priv && (pmbuf->buf_type == MLAN_BUF_TYPE_DATA) &&
+ (status == MLAN_STATUS_FAILURE)) {
+ priv->stats.rx_dropped++;
+ }
+ /* Reuse the buffer in case of command/event */
+ if (port == cardp->rx_cmd_ep)
+ woal_submit_rx_urb(handle, port);
+ else {
+ woal_free_mlan_buffer(handle, pmbuf);
+ if ((atomic_read(&handle->rx_pending) <
+ LOW_RX_PENDING) &&
+ atomic_read(&cardp->rx_data_urb_pending) <
+ MVUSB_RX_DATA_URB)
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ } else if (port == cardp->rx_data_ep) {
+ if ((atomic_read(&handle->rx_pending) < LOW_RX_PENDING) &&
+ atomic_read(&cardp->rx_data_urb_pending) <
+ MVUSB_RX_DATA_URB)
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function write a command/data packet to card.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for sent
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or
+ * MLAN_STATUS_PENDING or MLAN_STATUS_RESOURCE
+ */
+mlan_status moal_write_data_async(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MERROR,
+ "write_data_async is not allowed while suspended\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ ret = woal_write_data_async((moal_handle *)pmoal_handle, pmbuf,
+ (t_u8)port);
+ LEAVE();
+ return ret;
+}
+#endif /* USB */
+
+/**
+ * @brief This function write a command/data packet to card.
+ * This function blocks the call until it finishes
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for sent
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_write_data_sync(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, t_u32 timeout)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ return handle->ops.write_data_sync(handle, pmbuf, port, timeout);
+}
+
+/**
+ * @brief This function read data packet/event/command from card.
+ * This function blocks the call until it finish
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ * @param port Port number for read
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_read_data_sync(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, t_u32 timeout)
+{
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ return handle->ops.read_data_sync(handle, pmbuf, port, timeout);
+}
+
+#if defined(SDIO) || defined(PCIE)
+/**
+ * @brief This function writes data into card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_write_reg(t_void *pmoal_handle, t_u32 reg, t_u32 data)
+{
+ int ret = MLAN_STATUS_FAILURE;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ if (handle->ops.write_reg)
+ ret = handle->ops.write_reg(handle, reg, data);
+ return ret;
+}
+
+/**
+ * @brief This function reads data from card register.
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param reg register offset
+ * @param data value
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_read_reg(t_void *pmoal_handle, t_u32 reg, t_u32 *data)
+{
+ int ret = MLAN_STATUS_FAILURE;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ if (handle->ops.read_reg)
+ ret = handle->ops.read_reg(handle, reg, data);
+ return ret;
+}
+
+#endif /* SDIO || PCIE */
+
+/**
+ * @brief This function uploads the packet to the network stack
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmbuf Pointer to the mlan buffer structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status moal_recv_packet(t_void *pmoal_handle, pmlan_buffer pmbuf)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_private *priv = NULL;
+ struct sk_buff *skb = NULL;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+#if defined(USB) || defined(PCIE)
+ t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE;
+#endif
+ dot11_rxcontrol rxcontrol;
+ t_u8 rx_info_flag = MFALSE;
+ int j;
+ struct ethhdr *ethh = NULL;
+
+ ENTER();
+ if (pmbuf) {
+#ifdef USB
+#ifdef STA_SUPPORT
+ if (IS_USB(handle->card_type)) {
+ struct usb_card_rec *cardp =
+ (struct usb_card_rec *)handle->card;
+ if (cardp->rx_deaggr_ctrl.enable) {
+ max_rx_data_size =
+ cardp->rx_deaggr_ctrl.aggr_max;
+ if (cardp->rx_deaggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_NUM) {
+ max_rx_data_size *=
+ MAX(MLAN_USB_MAX_PKT_SIZE,
+ cardp->rx_deaggr_ctrl
+ .aggr_align);
+ max_rx_data_size =
+ MAX(max_rx_data_size,
+ MLAN_RX_DATA_BUF_SIZE);
+ }
+ }
+ }
+#endif
+#endif
+
+ priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index);
+ skb = (struct sk_buff *)pmbuf->pdesc;
+ if (priv) {
+ if (skb) {
+ skb_reserve(skb, pmbuf->data_offset);
+ if (skb_tailroom(skb) < pmbuf->data_len) {
+ PRINTM(MERROR,
+ "skb overflow: tail room=%d, data_len=%d\n",
+ skb_tailroom(skb),
+ pmbuf->data_len);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ goto done;
+ }
+ skb_put(skb, pmbuf->data_len);
+ pmbuf->pdesc = NULL;
+ pmbuf->pbuf = NULL;
+ pmbuf->data_offset = pmbuf->data_len = 0;
+ /* pkt been submit to kernel, no need to
+ * free by mlan*/
+ status = MLAN_STATUS_PENDING;
+ atomic_dec(&handle->mbufalloc_count);
+ } else {
+ PRINTM(MERROR, "%s without skb attach!!!\n",
+ __func__);
+ skb = dev_alloc_skb(pmbuf->data_len +
+ MLAN_NET_IP_ALIGN);
+ if (!skb) {
+ PRINTM(MERROR, "%s fail to alloc skb\n",
+ __func__);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(
+ priv, PACKET_TYPE_RX,
+ RX_PKT_FATE_DRV_DROP_NOBUFS,
+ FRAME_TYPE_ETHERNET_II, 0, 0,
+ (t_u8 *)(pmbuf->pbuf +
+ pmbuf->data_offset),
+ pmbuf->data_len);
+#endif
+ goto done;
+ }
+ skb_reserve(skb, MLAN_NET_IP_ALIGN);
+ moal_memcpy_ext(handle, skb->data,
+ (t_u8 *)(pmbuf->pbuf +
+ pmbuf->data_offset),
+ pmbuf->data_len,
+ pmbuf->data_len);
+ skb_put(skb, pmbuf->data_len);
+ }
+ ethh = (struct ethhdr *)(skb->data);
+ if (ntohs(ethh->h_proto) == ETH_P_PAE)
+ PRINTM(MEVENT,
+ "wlan: %s Rx EAPOL pkt from " MACSTR
+ "\n",
+ priv->netdev->name,
+ MAC2STR(ethh->h_source));
+ skb->dev = priv->netdev;
+ skb->protocol = eth_type_trans(skb, priv->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+#if defined(USB) || defined(PCIE)
+ /* This is only required only in case of 11n and
+ USB as we alloc if(skb_tailroom(skb) <
+ pmbuf->data_len){ PRINTM(MERROR,"skb overflow:
+ tail room=%d, data_len\n", skb_tailroom(skb),
+ pmbuf->data_len); status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ goto done;
+ }
+ * a buffer of 4K only if its 11N (to be able to
+ receive 4K AMSDU
+ * packets). In case of SD we allocate buffers
+ based on the size
+ * of packet and hence this is not needed.
+ */
+ /* Modifying the truesize here as our allocation
+ * for each skb is 4K but we only receive 2K
+ * packets and this cause the kernel to start
+ * dropping packets in case where application
+ * has allocated buffer based on 2K size i.e. if
+ * there a 64K packet received (in IP fragments
+ * and application allocates 64K to receive this
+ * packet but this packet would almost double up
+ * because we allocate each 1.5K fragment in 4K
+ * and pass it up. As soon as the 64K limit hits
+ * kernel will start to drop rest of the
+ * fragments. Currently we fail the
+ * Filesndl-ht.scr script for UDP, hence this
+ * fix
+ */
+ if (!IS_SD(priv->phandle->card_type)) {
+ if (skb->truesize > max_rx_data_size)
+ skb->truesize +=
+ (skb->len - max_rx_data_size);
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (!woal_filter_packet(priv, skb->data, skb->len, 0)) {
+ PRINTM(MEVENT, "drop filtered packet %s\n",
+ priv->netdev->name);
+ status = MLAN_STATUS_FAILURE;
+ priv->stats.rx_dropped++;
+ woal_packet_fate_monitor(
+ priv, PACKET_TYPE_RX,
+ RX_PKT_FATE_DRV_DROP_FILTER,
+ FRAME_TYPE_ETHERNET_II, 0, 0, skb->data,
+ skb->len);
+ dev_kfree_skb(skb);
+ goto done;
+ }
+#endif
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(priv, PACKET_TYPE_RX,
+ RX_PKT_FATE_SUCCESS,
+ FRAME_TYPE_ETHERNET_II, 0, 0,
+ skb->data, skb->len);
+#endif
+#ifdef ANDROID_KERNEL
+ if (handle->params.wakelock_timeout) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ __pm_wakeup_event(
+ &handle->ws,
+ handle->params.wakelock_timeout);
+#else
+ wake_lock_timeout(
+ &handle->wake_lock,
+ msecs_to_jiffies(
+ handle->params
+ .wakelock_timeout));
+#endif
+ }
+#endif
+ if (priv->rx_protocols.protocol_num) {
+ for (j = 0; j < priv->rx_protocols.protocol_num;
+ j++) {
+ if (htons(skb->protocol) ==
+ priv->rx_protocols.protocols[j])
+ rx_info_flag = MTRUE;
+ }
+ }
+ if (rx_info_flag &&
+ (skb_tailroom(skb) > sizeof(rxcontrol))) {
+ memset(&rxcontrol, 0, sizeof(dot11_rxcontrol));
+ rxcontrol.datarate = pmbuf->u.rx_info.data_rate;
+ rxcontrol.channel = pmbuf->u.rx_info.channel;
+ rxcontrol.antenna = pmbuf->u.rx_info.antenna;
+ rxcontrol.rssi = pmbuf->u.rx_info.rssi;
+ skb_put(skb, sizeof(dot11_rxcontrol));
+ memmove(skb->data + sizeof(dot11_rxcontrol),
+ skb->data,
+ skb->len - sizeof(dot11_rxcontrol));
+ moal_memcpy_ext(handle, skb->data, &rxcontrol,
+ sizeof(dot11_rxcontrol),
+ sizeof(dot11_rxcontrol));
+ }
+ // rx_trace 8
+ if (priv->phandle->tp_acnt.on)
+ moal_tp_accounting(handle, skb, RX_DROP_P4);
+ if (priv->phandle->tp_acnt.drop_point == RX_DROP_P4) {
+ status = MLAN_STATUS_PENDING;
+ dev_kfree_skb(skb);
+ } else if (in_interrupt())
+ netif_rx(skb);
+ else {
+ if (atomic_read(&handle->rx_pending) >
+ MAX_RX_PENDING_THRHLD)
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+ }
+ }
+ }
+done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function checks media_connected state for
+ * BSS types UAP/STA/P2P_GO/GC
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ *
+ */
+int woal_check_media_connected(t_void *pmoal_handle)
+{
+ int i;
+ moal_handle *pmhandle = (moal_handle *)pmoal_handle;
+ moal_private *pmpriv = NULL;
+ for (i = 0; i < pmhandle->priv_num && (pmpriv = pmhandle->priv[i]);
+ i++) {
+ if ((pmpriv->media_connected == MTRUE)) {
+ return MTRUE;
+ }
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief This function checks connect and disconnect
+ * events for BSS types UAP/STA/P2P_GO/GC
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ *
+ */
+void moal_connection_status_check_pmqos(t_void *pmoal_handle)
+{
+ moal_handle *pmhandle = (moal_handle *)pmoal_handle;
+ if ((woal_check_media_connected(pmoal_handle) == MTRUE)) {
+ if ((pmhandle->request_pm == MFALSE)) {
+ pmhandle->request_pm = MTRUE;
+#ifdef PCIE
+ if (IS_PCIE(pmhandle->card_type))
+ woal_request_pmqos_busfreq_high();
+#endif
+ }
+ } else {
+ if (pmhandle->request_pm == MTRUE) {
+ pmhandle->request_pm = MFALSE;
+#ifdef PCIE
+ if (IS_PCIE(pmhandle->card_type))
+ woal_release_pmqos_busfreq_high();
+#endif
+ }
+ }
+}
+
+/**
+ * @brief This function handles event receive
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param pmevent Pointer to the mlan event structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_recv_event(t_void *pmoal_handle, pmlan_event pmevent)
+{
+#ifdef STA_SUPPORT
+ int custom_len = 0;
+#ifdef STA_CFG80211
+ unsigned long flags;
+#endif
+#endif
+ moal_private *priv = NULL;
+#if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
+ moal_private *pmpriv = NULL;
+#endif
+#if defined(STA_WEXT) || defined(UAP_WEXT)
+#if defined(STA_SUPPORT) || defined(UAP_WEXT)
+#if defined(UAP_SUPPORT) || defined(STA_WEXT)
+ union iwreq_data wrqu;
+#endif
+#endif
+#endif
+ mlan_ds_ps_info pm_info;
+ t_u8 hw_test;
+ int cfg80211_wext;
+
+#ifdef STA_CFG80211
+ t_u8 channel_status;
+ moal_private *remain_priv = NULL;
+#endif
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+ pchan_band_info pchan_info = NULL;
+#endif
+ t_u8 radar_detected;
+
+ ENTER();
+ if (pmevent->event_id == MLAN_EVENT_ID_FW_DUMP_INFO) {
+ woal_store_firmware_dump(pmoal_handle, pmevent);
+ goto done;
+ }
+ if ((pmevent->event_id != MLAN_EVENT_ID_DRV_DEFER_RX_WORK) &&
+ (pmevent->event_id != MLAN_EVENT_ID_DRV_DEFER_HANDLING) &&
+ (pmevent->event_id != MLAN_EVENT_ID_DRV_MGMT_FRAME))
+ PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id);
+#if defined(PCIE)
+ if (pmevent->event_id == MLAN_EVENT_ID_SSU_DUMP_FILE) {
+ woal_store_ssu_dump(pmoal_handle, pmevent);
+ goto done;
+ }
+#endif /* SSU_SUPPORT */
+ if (pmevent->event_id == MLAN_EVENT_ID_STORE_HOST_CMD_RESP) {
+ woal_save_host_cmdresp((moal_handle *)pmoal_handle,
+ (mlan_cmdresp_event *)pmevent);
+ goto done;
+ }
+ priv = woal_bss_index_to_priv(pmoal_handle, pmevent->bss_index);
+ if (priv == NULL) {
+ PRINTM(MERROR, "%s: priv is null\n", __func__);
+ goto done;
+ }
+ if (priv->netdev == NULL) {
+ PRINTM(MERROR, "%s: netdev is null\n", __func__);
+ goto done;
+ }
+
+ cfg80211_wext = priv->phandle->params.cfg80211_wext;
+ hw_test = moal_extflg_isset(pmoal_handle, EXT_HW_TEST);
+ switch (pmevent->event_id) {
+#ifdef STA_SUPPORT
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED:
+ priv->is_adhoc_link_sensed = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_ADHOC_LINK_SENSED);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_ADHOC_LINK_SENSED,
+ strlen(CUS_EVT_ADHOC_LINK_SENSED));
+ break;
+
+ case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ priv->is_adhoc_link_sensed = MFALSE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_ADHOC_LINK_LOST);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_ADHOC_LINK_LOST,
+ strlen(CUS_EVT_ADHOC_LINK_LOST));
+ break;
+
+ case MLAN_EVENT_ID_DRV_CONNECTED:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) &&
+ pmevent->event_len == ETH_ALEN) {
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, wrqu.ap_addr.sa_data,
+ pmevent->event_buf, ETH_ALEN,
+ sizeof(wrqu.ap_addr.sa_data));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu,
+ NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ moal_memcpy_ext(priv->phandle, priv->cfg_bssid,
+ pmevent->event_buf, ETH_ALEN, ETH_ALEN);
+ woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ MIN_SPECIFIC_SCAN_CHAN_TIME);
+ }
+#endif
+ custom_len = strlen(CUS_EVT_AP_CONNECTED);
+ memmove(pmevent->event_buf + custom_len, pmevent->event_buf,
+ pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ CUS_EVT_AP_CONNECTED, custom_len, custom_len);
+ pmevent->event_len += custom_len;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ woal_update_dscp_mapping(priv);
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ moal_connection_status_check_pmqos(pmoal_handle);
+ break;
+
+ case MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER:
+ case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER:
+ case MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER:
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (IS_STA_CFG80211(cfg80211_wext))
+ woal_ring_event_logger(priv, VERBOSE_RING_ID, pmevent);
+#endif
+#endif
+ break;
+
+ case MLAN_EVENT_ID_DRV_SCAN_REPORT:
+ PRINTM(MINFO, "Scan report\n");
+
+ if (priv->report_scan_result) {
+ priv->report_scan_result = MFALSE;
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->phandle->scan_request) {
+ PRINTM(MINFO,
+ "Reporting scan results\n");
+ woal_inform_bss_from_scan_result(
+ priv, NULL, MOAL_NO_WAIT);
+ if (!priv->phandle->first_scan_done) {
+ priv->phandle->first_scan_done =
+ MTRUE;
+ woal_set_scan_time(
+ priv,
+ ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ SPECIFIC_SCAN_CHAN_TIME);
+ }
+ spin_lock_irqsave(
+ &priv->phandle->scan_req_lock,
+ flags);
+ if (priv->phandle->scan_request) {
+ woal_cfg80211_scan_done(
+ priv->phandle
+ ->scan_request,
+ MFALSE);
+ priv->phandle->scan_request =
+ NULL;
+ }
+ spin_unlock_irqrestore(
+ &priv->phandle->scan_req_lock,
+ flags);
+ }
+ }
+#endif /* STA_CFG80211 */
+
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN,
+ &wrqu, NULL);
+ }
+#endif
+ woal_broadcast_event(priv, (t_u8 *)&pmevent->event_id,
+ sizeof(mlan_event_id));
+ }
+
+ if (!is_zero_timeval(priv->phandle->scan_time_start)) {
+ woal_get_monotonic_time(&priv->phandle->scan_time_end);
+ priv->phandle->scan_time += (t_u64)(
+ timeval_to_usec(priv->phandle->scan_time_end) -
+ timeval_to_usec(
+ priv->phandle->scan_time_start));
+ PRINTM(MINFO,
+ "%s : start_timeval=%d:%d end_timeval=%d:%d inter=%llu scan_time=%llu\n",
+ __func__,
+ priv->phandle->scan_time_start.time_sec,
+ priv->phandle->scan_time_start.time_usec,
+ priv->phandle->scan_time_end.time_sec,
+ priv->phandle->scan_time_end.time_usec,
+ (t_u64)(timeval_to_usec(
+ priv->phandle->scan_time_end) -
+ timeval_to_usec(
+ priv->phandle->scan_time_start)),
+ priv->phandle->scan_time);
+ priv->phandle->scan_time_start.time_sec = 0;
+ priv->phandle->scan_time_start.time_usec = 0;
+ }
+
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ priv->phandle->scan_pending_on_block = MFALSE;
+ priv->phandle->scan_priv = NULL;
+ MOAL_REL_SEMAPHORE(&priv->phandle->async_sem);
+ }
+ break;
+
+ case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM:
+ memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) +
+ 1),
+ pmevent->event_buf, pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ (t_u8 *)CUS_EVT_OBSS_SCAN_PARAM,
+ strlen(CUS_EVT_OBSS_SCAN_PARAM),
+ strlen(CUS_EVT_OBSS_SCAN_PARAM));
+ pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len +
+ strlen(CUS_EVT_OBSS_SCAN_PARAM));
+
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length = pmevent->event_len +
+ strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BW_CHANGED:
+ memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ (t_u8 *)CUS_EVT_BW_CHANGED,
+ strlen(CUS_EVT_BW_CHANGED),
+ strlen(CUS_EVT_BW_CHANGED));
+ pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len +
+ strlen(CUS_EVT_BW_CHANGED));
+
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length = pmevent->event_len +
+ strlen(CUS_EVT_BW_CHANGED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif
+ break;
+
+ case MLAN_EVENT_ID_FW_DISCONNECTED:
+ woal_send_disconnect_to_system(priv,
+ (t_u16)*pmevent->event_buf);
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ priv->auth_flag = 0;
+ priv->host_mlme = MFALSE;
+ priv->auth_alg = 0xFFFF;
+#endif
+#endif
+#ifdef STA_WEXT
+ /* Reset wireless stats signal info */
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.qual.noise = 0;
+ }
+#endif
+#ifdef REASSOCIATION
+ if (priv->reassoc_on == MTRUE) {
+ PRINTM(MINFO, "Reassoc: trigger the timer\n");
+ priv->reassoc_required = MTRUE;
+ priv->phandle->is_reassoc_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->reassoc_timer,
+ REASSOC_TIMER_DEFAULT);
+ } else {
+ priv->rate_index = AUTO_RATE;
+ }
+#endif /* REASSOCIATION */
+ moal_connection_status_check_pmqos(pmoal_handle);
+ break;
+
+ case MLAN_EVENT_ID_FW_MIC_ERR_UNI:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv,
+ MLAN_EVENT_ID_FW_MIC_ERR_UNI);
+#else
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+ }
+#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev,
+ priv->cfg_bssid,
+ NL80211_KEYTYPE_PAIRWISE,
+ -1, NULL, GFP_KERNEL);
+ }
+#endif
+ woal_broadcast_event(priv, CUS_EVT_MLME_MIC_ERR_UNI,
+ strlen(CUS_EVT_MLME_MIC_ERR_UNI));
+ break;
+ case MLAN_EVENT_ID_FW_MIC_ERR_MUL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+#if WIRELESS_EXT >= 18
+ woal_send_mic_error_event(priv,
+ MLAN_EVENT_ID_FW_MIC_ERR_MUL);
+#else
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_MLME_MIC_ERR_MUL);
+#endif
+ }
+#endif /* STA_WEXT */
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ cfg80211_michael_mic_failure(priv->netdev,
+ priv->cfg_bssid,
+ NL80211_KEYTYPE_GROUP, -1,
+ NULL, GFP_KERNEL);
+ }
+#endif
+ woal_broadcast_event(priv, CUS_EVT_MLME_MIC_ERR_MUL,
+ strlen(CUS_EVT_MLME_MIC_ERR_MUL));
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_BEACON_RSSI_LOW);
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+ cfg80211_cqm_rssi_notify(
+ priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ *(t_s16 *)pmevent->event_buf,
+#endif
+ GFP_KERNEL);
+ priv->last_event |= EVENT_BCN_RSSI_LOW;
+#endif
+ if (!hw_test && priv->roaming_enabled)
+ woal_config_bgscan_and_rssi(priv, MTRUE);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_cfg80211_rssi_monitor_event(
+ priv, *(t_s16 *)pmevent->event_buf);
+#endif
+ }
+#endif
+ woal_broadcast_event(priv, CUS_EVT_BEACON_RSSI_LOW,
+ strlen(CUS_EVT_BEACON_RSSI_LOW));
+ break;
+ case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_BEACON_RSSI_HIGH);
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (!priv->mrvl_rssi_low) {
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+ cfg80211_cqm_rssi_notify(
+ priv->netdev,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ *(t_s16 *)pmevent->event_buf,
+#endif
+ GFP_KERNEL);
+#endif
+ woal_set_rssi_threshold(
+ priv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH,
+ MOAL_NO_WAIT);
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_cfg80211_rssi_monitor_event(
+ priv, *(t_s16 *)pmevent->event_buf);
+#endif
+ }
+#endif
+ woal_broadcast_event(priv, CUS_EVT_BEACON_RSSI_HIGH,
+ strlen(CUS_EVT_BEACON_RSSI_HIGH));
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_BEACON_SNR_LOW);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_BEACON_SNR_LOW,
+ strlen(CUS_EVT_BEACON_SNR_LOW));
+ break;
+ case MLAN_EVENT_ID_FW_BCN_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_BEACON_SNR_HIGH);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_BEACON_SNR_HIGH,
+ strlen(CUS_EVT_BEACON_SNR_HIGH));
+ break;
+ case MLAN_EVENT_ID_FW_MAX_FAIL:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_MAX_FAIL,
+ strlen(CUS_EVT_MAX_FAIL));
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_DATA_RSSI_LOW,
+ strlen(CUS_EVT_DATA_RSSI_LOW));
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_LOW:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_DATA_SNR_LOW,
+ strlen(CUS_EVT_DATA_SNR_LOW));
+ break;
+ case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_DATA_RSSI_HIGH);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_DATA_RSSI_HIGH,
+ strlen(CUS_EVT_DATA_RSSI_HIGH));
+ break;
+ case MLAN_EVENT_ID_FW_DATA_SNR_HIGH:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_DATA_SNR_HIGH,
+ strlen(CUS_EVT_DATA_SNR_HIGH));
+ break;
+ case MLAN_EVENT_ID_FW_LINK_QUALITY:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_LINK_QUALITY,
+ strlen(CUS_EVT_LINK_QUALITY));
+ break;
+ case MLAN_EVENT_ID_FW_PORT_RELEASE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_PORT_RELEASE,
+ strlen(CUS_EVT_PORT_RELEASE));
+ break;
+ case MLAN_EVENT_ID_FW_PRE_BCN_LOST:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_PRE_BEACON_LOST);
+#endif
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ struct cfg80211_bss *bss = NULL;
+ bss = cfg80211_get_bss(priv->wdev->wiphy, NULL,
+ priv->cfg_bssid, NULL, 0,
+ WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+ if (bss)
+ cfg80211_unlink_bss(priv->wdev->wiphy, bss);
+ if (!hw_test && priv->roaming_enabled)
+ woal_config_bgscan_and_rssi(priv, MFALSE);
+ priv->last_event |= EVENT_PRE_BCN_LOST;
+ }
+#endif
+#endif
+ woal_broadcast_event(priv, CUS_EVT_PRE_BEACON_LOST,
+ strlen(CUS_EVT_PRE_BEACON_LOST));
+ break;
+ case MLAN_EVENT_ID_FW_DEBUG_INFO:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, pmevent->event_buf);
+#endif
+ memmove((pmevent->event_buf + strlen(FW_DEBUG_INFO) + 1),
+ pmevent->event_buf, pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ (t_u8 *)FW_DEBUG_INFO, strlen(FW_DEBUG_INFO),
+ strlen(FW_DEBUG_INFO));
+ pmevent->event_buf[strlen(FW_DEBUG_INFO)] = 0;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len +
+ strlen(FW_DEBUG_INFO) + 1);
+ break;
+ case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(
+ priv, WMM_CONFIG_CHANGE_INDICATION);
+#endif
+ woal_broadcast_event(priv, WMM_CONFIG_CHANGE_INDICATION,
+ strlen(WMM_CONFIG_CHANGE_INDICATION));
+ break;
+
+ case MLAN_EVENT_ID_DRV_REPORT_STRING:
+ PRINTM(MINFO, "Report string %s\n", pmevent->event_buf);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, pmevent->event_buf);
+#endif
+ woal_broadcast_event(priv, pmevent->event_buf,
+ strlen(pmevent->event_buf));
+ break;
+ case MLAN_EVENT_ID_FW_WEP_ICV_ERR:
+ DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf,
+ pmevent->event_len);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_WEP_ICV_ERR,
+ strlen(CUS_EVT_WEP_ICV_ERR));
+ break;
+
+ case MLAN_EVENT_ID_DRV_DEFER_HANDLING:
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_EVENT_ID_DRV_FLUSH_RX_WORK:
+ if (moal_extflg_isset(priv->phandle, EXT_NAPI)) {
+ napi_synchronize(&priv->phandle->napi_rx);
+ break;
+ }
+ flush_workqueue(priv->phandle->rx_workqueue);
+ break;
+ case MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK:
+ flush_workqueue(priv->phandle->workqueue);
+ break;
+ case MLAN_EVENT_ID_DRV_DEFER_RX_WORK:
+ if (moal_extflg_isset(priv->phandle, EXT_NAPI)) {
+ napi_schedule(&priv->phandle->napi_rx);
+ break;
+ }
+ queue_work(priv->phandle->rx_workqueue,
+ &priv->phandle->rx_work);
+ break;
+ case MLAN_EVENT_ID_DRV_DBG_DUMP:
+ priv->phandle->driver_status = MTRUE;
+ woal_moal_debug_info(priv, NULL, MFALSE);
+ woal_broadcast_event(priv, CUS_EVT_DRIVER_HANG,
+ strlen(CUS_EVT_DRIVER_HANG));
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
+ woal_cfg80211_vendor_event(priv, event_hang,
+ CUS_EVT_DRIVER_HANG,
+ strlen(CUS_EVT_DRIVER_HANG));
+#endif
+#endif
+ woal_process_hang(priv->phandle);
+ wifi_status = 2;
+ break;
+ case MLAN_EVENT_ID_DRV_WIFI_STATUS:
+ wifi_status = *(t_u16 *)(pmevent->event_buf + sizeof(t_u32));
+ break;
+ case MLAN_EVENT_ID_FW_BG_SCAN:
+ if (priv->media_connected == MTRUE)
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MTRUE;
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu,
+ NULL);
+ }
+#endif
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ priv->last_event |= EVENT_BG_SCAN_REPORT;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (priv->sched_scanning &&
+ !priv->phandle->cfg80211_suspend) {
+ mlan_scan_resp scan_resp;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_scan_table(priv, MOAL_NO_WAIT,
+ &scan_resp))
+ PRINTM(MIOCTL,
+ "Triggered mlan get bgscan result\n");
+ }
+#endif
+ if (!hw_test && priv->roaming_enabled
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ && !priv->phandle->cfg80211_suspend
+#endif
+ ) {
+ priv->roaming_required = MTRUE;
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ __pm_wakeup_event(&priv->phandle->ws,
+ ROAMING_WAKE_LOCK_TIMEOUT);
+#else
+ wake_lock_timeout(
+ &priv->phandle->wake_lock,
+ msecs_to_jiffies(
+ ROAMING_WAKE_LOCK_TIMEOUT));
+#endif
+#endif
+ wake_up_interruptible(
+ &priv->phandle->reassoc_thread.wait_q);
+ }
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_BG_SCAN_STOPPED:
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->sched_scanning)
+ woal_bgscan_stop_event(priv);
+ }
+#endif
+#endif
+ break;
+ case MLAN_EVENT_ID_DRV_BGSCAN_RESULT:
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ if (priv->sched_scanning &&
+ !priv->phandle->cfg80211_suspend) {
+ woal_inform_bss_from_scan_result(priv, NULL,
+ MOAL_NO_WAIT);
+ cfg80211_sched_scan_results(priv->wdev->wiphy
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ priv->bg_scan_reqid
+#endif
+ );
+ priv->last_event = 0;
+ woal_bgscan_stop_event(priv);
+ PRINTM(MEVENT,
+ "Reporting Sched_Scan results\n");
+ }
+ }
+#endif
+#endif
+ break;
+#endif /* STA_SUPPORT */
+
+ case MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY:
+ radar_detected = pmevent->event_buf[0];
+
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (!IS_STA_OR_UAP_CFG80211(cfg80211_wext))
+ break;
+
+ if (priv->phandle->is_cac_timer_set) {
+ PRINTM(MEVENT, "%s radar found when CAC \n",
+ radar_detected ? "" : "No");
+ moal_stop_timer(priv->phandle,
+ &priv->phandle->cac_timer);
+ priv->phandle->is_cac_timer_set = MFALSE;
+ if (radar_detected) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev,
+ &priv->phandle->dfs_channel,
+ NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev,
+ NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#endif
+ cfg80211_radar_event(
+ priv->wdev->wiphy,
+ &priv->phandle->dfs_channel,
+ GFP_KERNEL);
+ } else {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev,
+ &priv->phandle->dfs_channel,
+ NL80211_RADAR_CAC_FINISHED,
+ GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev,
+ NL80211_RADAR_CAC_FINISHED,
+ GFP_KERNEL);
+#endif
+ }
+ memset(&priv->phandle->dfs_channel, 0,
+ sizeof(struct cfg80211_chan_def));
+ priv->phandle->cac_bss_index = 0xff;
+ }
+#endif /* CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
+#endif /* UAP_CFG80211 */
+ break;
+ case MLAN_EVENT_ID_FW_RADAR_DETECTED:
+
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (!IS_STA_OR_UAP_CFG80211(cfg80211_wext))
+ break;
+ if (priv->phandle->is_cac_timer_set) {
+ if (priv->bss_index == priv->phandle->cac_bss_index) {
+ PRINTM(MEVENT, "radar detected during CAC \n");
+ woal_cancel_timer(&priv->phandle->cac_timer);
+ priv->phandle->is_cac_timer_set = MFALSE;
+ /* downstream: cancel the unfinished CAC in
+ * Firmware*/
+ woal_11h_cancel_chan_report_ioctl(priv,
+ MOAL_NO_WAIT);
+ /* upstream: inform cfg80211 */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev,
+ &priv->phandle->dfs_channel,
+ NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev,
+ NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#endif
+ cfg80211_radar_event(
+ priv->wdev->wiphy,
+ &priv->phandle->dfs_channel,
+ GFP_KERNEL);
+
+ memset(&priv->phandle->dfs_channel, 0,
+ sizeof(priv->phandle->dfs_channel));
+ priv->phandle->cac_bss_index = 0xff;
+ } else {
+ PRINTM(MERROR,
+ " Radar event for incorrect inferface \n");
+ }
+ } else {
+ PRINTM(MEVENT, "radar detected during BSS active \n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cfg80211_dfs_vendor_event(
+ priv, event_dfs_radar_detected,
+ &priv->chan);
+ else {
+#endif
+ if (priv->uap_host_based && priv->bss_started)
+ cfg80211_radar_event(priv->wdev->wiphy,
+ &priv->chan,
+ GFP_KERNEL);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ }
+#endif
+ }
+#endif /* CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0 */
+#endif /* UAP_CFG80211 */
+ break;
+ case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN:
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext))
+ woal_send_iwevcustom_event(priv,
+ CUS_EVT_CHANNEL_SWITCH_ANN);
+#endif
+ woal_broadcast_event(priv, CUS_EVT_CHANNEL_SWITCH_ANN,
+ strlen(CUS_EVT_CHANNEL_SWITCH_ANN));
+ break;
+
+ case MLAN_EVENT_ID_FW_CHAN_SWITCH_COMPLETE:
+#if defined(UAP_CFG80211) || defined(STA_CFG80211)
+ pchan_info = (chan_band_info *)pmevent->event_buf;
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ PRINTM(MMSG,
+ "CSA/ECSA: Switch to new channel %d complete!\n",
+ pchan_info->channel);
+ priv->channel = pchan_info->channel;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->csa_chan.chan &&
+ (pchan_info->channel ==
+ priv->csa_chan.chan->hw_value)) {
+ moal_memcpy_ext(
+ priv->phandle, &priv->chan,
+ &priv->csa_chan,
+ sizeof(struct cfg80211_chan_def),
+ sizeof(struct cfg80211_chan_def));
+ }
+#endif
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (MFALSE
+#ifdef UAP_CFG80211
+ || priv->uap_host_based
+#endif
+#ifdef STA_CFG80211
+ || priv->sme_current.ssid_len
+#endif
+ ) {
+ PRINTM(MEVENT,
+ "CHAN_SWITCH: 11n=%d, chan=%d, center_chan=%d, band=%d, width=%d, 2Offset=%d\n",
+ pchan_info->is_11n_enabled,
+ pchan_info->channel,
+ pchan_info->center_chan,
+ pchan_info->bandcfg.chanBand,
+ pchan_info->bandcfg.chanWidth,
+ pchan_info->bandcfg.chan2Offset);
+ woal_cfg80211_notify_channel(priv, pchan_info);
+ }
+#endif
+ }
+#endif
+#ifdef UAP_SUPPORT
+ if (priv->bss_role == MLAN_BSS_ROLE_UAP) {
+ if (priv->uap_tx_blocked) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_start_queue(priv->netdev);
+ priv->uap_tx_blocked = MFALSE;
+ }
+ priv->phandle->chsw_wait_q_woken = MTRUE;
+ wake_up_interruptible(&priv->phandle->chsw_wait_q);
+ }
+#endif
+ break;
+ case MLAN_EVENT_ID_FW_STOP_TX:
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_START_TX:
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ break;
+ case MLAN_EVENT_ID_FW_HS_WAKEUP:
+ /* simulate HSCFG_CANCEL command */
+ woal_cancel_hs(priv, MOAL_NO_WAIT);
+#ifdef STA_SUPPORT
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_STA);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
+ woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_WAKEUP);
+#endif /* STA_WEXT */
+ if (pmpriv)
+ woal_broadcast_event(pmpriv, CUS_EVT_HS_WAKEUP,
+ strlen(CUS_EVT_HS_WAKEUP));
+#endif /*STA_SUPPORT */
+#ifdef UAP_SUPPORT
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_UAP);
+ if (pmpriv) {
+ pmevent->event_id = UAP_EVENT_ID_HS_WAKEUP;
+ woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif /* UAP_SUPPORT */
+ break;
+ case MLAN_EVENT_ID_DRV_HS_ACTIVATED:
+#ifdef STA_SUPPORT
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_STA);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
+ woal_send_iwevcustom_event(pmpriv,
+ CUS_EVT_HS_ACTIVATED);
+#endif /* STA_WEXT */
+ if (pmpriv)
+ woal_broadcast_event(pmpriv, CUS_EVT_HS_ACTIVATED,
+ strlen(CUS_EVT_HS_ACTIVATED));
+#endif /* STA_SUPPORT */
+#if defined(UAP_SUPPORT)
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_UAP);
+ if (pmpriv) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_ACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+ memset(&pm_info, 0, sizeof(mlan_ds_ps_info));
+ if (priv->phandle->suspend_fail == MFALSE) {
+ woal_get_pm_info(priv, &pm_info);
+ if (pm_info.is_suspend_allowed == MTRUE) {
+ priv->phandle->hs_activated = MTRUE;
+#ifdef MMC_PM_FUNC_SUSPENDED
+ woal_wlan_is_suspended(priv->phandle);
+#endif
+ }
+ priv->phandle->hs_activate_wait_q_woken = MTRUE;
+ wake_up(&priv->phandle->hs_activate_wait_q);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_HS_DEACTIVATED:
+#ifdef STA_SUPPORT
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_STA);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(cfg80211_wext) && pmpriv)
+ woal_send_iwevcustom_event(pmpriv,
+ CUS_EVT_HS_DEACTIVATED);
+#endif /* STA_WEXT */
+ if (pmpriv)
+ woal_broadcast_event(pmpriv, CUS_EVT_HS_DEACTIVATED,
+ strlen(CUS_EVT_HS_DEACTIVATED));
+#endif /* STA_SUPPORT */
+#if defined(UAP_SUPPORT)
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_UAP);
+ if (pmpriv) {
+ pmevent->event_id = UAP_EVENT_ID_DRV_HS_DEACTIVATED;
+ woal_broadcast_event(pmpriv, (t_u8 *)&pmevent->event_id,
+ sizeof(t_u32));
+ }
+#endif
+ priv->phandle->hs_activated = MFALSE;
+ break;
+#ifdef UAP_SUPPORT
+ case MLAN_EVENT_ID_UAP_FW_BSS_START:
+ woal_hist_data_reset(priv);
+ priv->bss_started = MTRUE;
+ priv->skip_cac = MFALSE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_start_queue(priv->netdev);
+ moal_memcpy_ext(priv->phandle, priv->current_addr,
+ pmevent->event_buf + 6, ETH_ALEN, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr,
+ priv->current_addr, ETH_ALEN, ETH_ALEN);
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+#ifdef STA_SUPPORT
+#ifdef STA_CFG80211
+ pmpriv = woal_get_priv((moal_handle *)pmoal_handle,
+ MLAN_BSS_ROLE_STA);
+ if (IS_STA_CFG80211(cfg80211_wext) && pmpriv)
+ woal_set_scan_time(pmpriv, ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ MIN_SPECIFIC_SCAN_CHAN_TIME);
+#endif
+#endif
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->chan_under_nop) {
+ PRINTM(MMSG,
+ "Channel Under Nop: notify cfg80211 new channel=%d\n",
+ priv->channel);
+ cfg80211_ch_switch_notify(priv->netdev, &priv->chan);
+ priv->chan_under_nop = MFALSE;
+ }
+#endif
+#endif
+ break;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ case MLAN_EVENT_ID_DRV_UAP_CHAN_INFO:
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext)) {
+ chan_band_info *pchan_info =
+ (chan_band_info *)pmevent->event_buf;
+ PRINTM(MEVENT,
+ "UAP: 11n=%d, chan=%d, center_chan=%d, band=%d, width=%d, 2Offset=%d\n",
+ pchan_info->is_11n_enabled, pchan_info->channel,
+ pchan_info->center_chan,
+ pchan_info->bandcfg.chanBand,
+ pchan_info->bandcfg.chanWidth,
+ pchan_info->bandcfg.chan2Offset);
+ if (priv->uap_host_based &&
+ (priv->channel != pchan_info->channel))
+ woal_channel_switch_event(priv, pchan_info);
+ }
+#endif
+ break;
+#endif
+ case MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE:
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ moal_connection_status_check_pmqos(pmoal_handle);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_BSS_IDLE:
+ priv->media_connected = MFALSE;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ moal_connection_status_check_pmqos(pmoal_handle);
+ break;
+ case MLAN_EVENT_ID_UAP_FW_MIC_COUNTERMEASURES: {
+ t_u16 status = 0;
+ status = *(t_u16 *)(pmevent->event_buf + 4);
+ if (status) {
+ priv->media_connected = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ } else {
+ priv->media_connected = MTRUE;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_wake_queue(priv->netdev);
+ }
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ } break;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ case MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED:
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ PRINTM(MEVENT,
+ "FW_REMAIN_ON_CHANNEL_EXPIRED cookie = %#llx\n",
+ priv->phandle->cookie);
+ if (priv->host_mlme &&
+ (priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
+ priv->auth_flag = 0;
+ priv->host_mlme = MFALSE;
+ priv->auth_alg = 0xFFFF;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie &&
+ !priv->phandle->is_remain_timer_set) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ priv->netdev,
+#else
+ priv->wdev,
+#endif
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ }
+ break;
+#endif
+#endif
+ case MLAN_EVENT_ID_UAP_FW_STA_CONNECT:
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+ struct station_info sinfo = {0};
+ t_u8 addr[ETH_ALEN];
+
+ sinfo.filled = 0;
+ sinfo.generation = 0;
+ /* copy the station mac address */
+ memset(addr, 0xFF, ETH_ALEN);
+ moal_memcpy_ext(priv->phandle, addr, pmevent->event_buf,
+ ETH_ALEN, ETH_ALEN);
+ /** these field add in kernel 3.2, but some
+ * kernel do have the pacth to support it,
+ * like T3T and pxa978T 3.0.31 JB, these
+ * patch are needed to support
+ * wpa_supplicant 2.x */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 31)
+ if (pmevent->event_len > ETH_ALEN) {
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
+ /* set station info filled flag */
+ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
+ sinfo.pertid = NULL;
+#endif
+ /* get the assoc request ies and length */
+ sinfo.assoc_req_ies =
+ (const t_u8 *)(pmevent->event_buf +
+ ETH_ALEN);
+ sinfo.assoc_req_ies_len =
+ pmevent->event_len - ETH_ALEN;
+ }
+#endif /* KERNEL_VERSION */
+ if (priv->netdev && priv->wdev)
+ cfg80211_new_sta(priv->netdev, (t_u8 *)addr,
+ &sinfo, GFP_KERNEL);
+ }
+#endif /* UAP_CFG80211 */
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) +
+ 1),
+ pmevent->event_buf, pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ (t_u8 *)CUS_EVT_STA_CONNECTED,
+ strlen(CUS_EVT_STA_CONNECTED),
+ strlen(CUS_EVT_STA_CONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_CONNECTED)] = 0;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len +
+ strlen(CUS_EVT_STA_CONNECTED));
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wrqu.data.pointer = pmevent->event_buf;
+ if ((pmevent->event_len +
+ strlen(CUS_EVT_STA_CONNECTED) + 1) > IW_CUSTOM_MAX)
+ wrqu.data.length =
+ ETH_ALEN +
+ strlen(CUS_EVT_STA_CONNECTED) + 1;
+ else
+ wrqu.data.length =
+ pmevent->event_len +
+ strlen(CUS_EVT_STA_CONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT:
+#ifdef UAP_CFG80211
+ if (IS_UAP_CFG80211(cfg80211_wext)) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /**Forward Deauth, Auth and disassoc frame to Host*/
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
+ t_u16 reason_code = woal_le16_to_cpu(
+ *(t_u16 *)pmevent->event_buf);
+ PRINTM(MCMND, "deauth reason code =0x%x\n",
+ reason_code);
+ /** BIT 14 indicate deauth is initiated by FW */
+ if (reason_code & MBIT(14))
+ woal_host_mlme_disconnect(
+ priv, 0,
+ pmevent->event_buf + 2);
+ } else
+#endif
+ if (priv->netdev && priv->wdev)
+ cfg80211_del_sta(priv->netdev,
+ pmevent->event_buf + 2,
+ GFP_KERNEL);
+
+#endif /* KERNEL_VERSION */
+ }
+#endif /* UAP_CFG80211 */
+ memmove((pmevent->event_buf + strlen(CUS_EVT_STA_DISCONNECTED) +
+ 1),
+ pmevent->event_buf, pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, pmevent->event_buf,
+ (t_u8 *)CUS_EVT_STA_DISCONNECTED,
+ strlen(CUS_EVT_STA_DISCONNECTED),
+ strlen(CUS_EVT_STA_DISCONNECTED));
+ pmevent->event_buf[strlen(CUS_EVT_STA_DISCONNECTED)] = 0;
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len +
+ strlen(CUS_EVT_STA_DISCONNECTED));
+
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wrqu.data.pointer = pmevent->event_buf;
+ wrqu.data.length = pmevent->event_len +
+ strlen(CUS_EVT_STA_DISCONNECTED) + 1;
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu,
+ pmevent->event_buf);
+ }
+#endif /* UAP_WEXT */
+ break;
+ case MLAN_EVENT_ID_DRV_MGMT_FRAME:
+#ifdef UAP_WEXT
+ if (IS_UAP_WEXT(cfg80211_wext)) {
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ }
+#endif /* UAP_WEXT */
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ if (priv->netdev &&
+ priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes &&
+ priv->mgmt_subtype_mask) {
+ /* frmctl + durationid + addr1 + addr2 + addr3 +
+ * seqctl */
+#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
+ t_u8 *pkt;
+ int freq =
+ priv->phandle->remain_on_channel ?
+ priv->phandle->chan.center_freq :
+ woal_get_active_intf_freq(priv);
+ if (!freq) {
+ if (!priv->phandle->chan.center_freq) {
+ PRINTM(MINFO,
+ "Skip to report mgmt packet to cfg80211\n");
+ break;
+ }
+ freq = priv->phandle->chan.center_freq;
+ }
+
+ pkt = ((t_u8 *)pmevent->event_buf +
+ sizeof(pmevent->event_id));
+
+ /* move addr4 */
+ memmove(pkt + PACKET_ADDR4_POS,
+ pkt + PACKET_ADDR4_POS + ETH_ALEN,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ PACKET_ADDR4_POS - ETH_ALEN);
+#ifdef WIFI_DIRECT_SUPPORT
+ if (ieee80211_is_action(
+ ((struct ieee80211_mgmt *)pkt)
+ ->frame_control))
+ woal_cfg80211_display_p2p_actframe(
+ pkt,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH,
+ ieee80211_get_channel(
+ priv->wdev->wiphy,
+ freq),
+ MFALSE);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /**Forward Deauth, Auth and disassoc frame to
+ * Host*/
+ if (priv->host_mlme &&
+ (GET_BSS_ROLE(priv) != MLAN_BSS_ROLE_UAP) &&
+ (ieee80211_is_deauth(
+ ((struct ieee80211_mgmt *)pkt)
+ ->frame_control) ||
+ ieee80211_is_auth(
+ ((struct ieee80211_mgmt *)pkt)
+ ->frame_control) ||
+ ieee80211_is_disassoc(
+ ((struct ieee80211_mgmt *)pkt)
+ ->frame_control))) {
+ if (ieee80211_is_auth(
+ ((struct ieee80211_mgmt *)
+ pkt)
+ ->frame_control)) {
+ PRINTM(MEVENT,
+ "HostMlme %s: Received auth frame type = 0x%x\n",
+ priv->netdev->name,
+ priv->auth_alg);
+
+ if (priv->auth_flag &
+ HOST_MLME_AUTH_PENDING) {
+ if (priv->auth_alg !=
+ WLAN_AUTH_SAE) {
+ priv->auth_flag &=
+ ~HOST_MLME_AUTH_PENDING;
+ priv->auth_flag |=
+ HOST_MLME_AUTH_DONE;
+ priv->phandle
+ ->host_mlme_priv =
+ priv;
+ queue_work(
+ priv->phandle
+ ->evt_workqueue,
+ &priv->phandle
+ ->host_mlme_work);
+ }
+ } else {
+ PRINTM(MERROR,
+ "HostMlme %s: Drop auth frame, auth_flag=0x%x auth_alg=0x%x\n",
+ priv->netdev
+ ->name,
+ priv->auth_flag,
+ priv->auth_alg);
+ break;
+ }
+ } else {
+ PRINTM(MEVENT,
+ "HostMlme %s: Receive deauth/disassociate\n",
+ priv->netdev->name);
+ priv->cfg_disconnect = MTRUE;
+ woal_mgmt_frame_register(
+ priv,
+ IEEE80211_STYPE_DEAUTH,
+ MFALSE);
+ woal_mgmt_frame_register(
+ priv,
+ IEEE80211_STYPE_DISASSOC,
+ MFALSE);
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ priv->auth_alg = 0xFFFF;
+ if (!priv->wdev->current_bss) {
+ PRINTM(MEVENT,
+ "HostMlme: Drop deauth/disassociate, we already disconnected\n");
+ break;
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ mutex_lock(&priv->wdev->mtx);
+ cfg80211_rx_mlme_mgmt(
+ priv->netdev, pkt,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH);
+ mutex_unlock(&priv->wdev->mtx);
+#else
+ if (ieee80211_is_deauth(
+ ((struct ieee80211_mgmt *)
+ pkt)
+ ->frame_control))
+ cfg80211_send_deauth(
+ priv->netdev, pkt,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH);
+ else if (ieee80211_is_auth(
+ ((struct ieee80211_mgmt
+ *)pkt)
+ ->frame_control))
+ cfg80211_send_rx_auth(
+ priv->netdev, pkt,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH);
+ else if (ieee80211_is_disassoc(
+ ((struct ieee80211_mgmt
+ *)pkt)
+ ->frame_control))
+ cfg80211_send_disassoc(
+ priv->netdev, pkt,
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH);
+
+#endif
+ } else
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ cfg80211_rx_mgmt(
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ priv->wdev,
+#else
+ priv->netdev,
+#endif
+ freq, 0,
+ ((const t_u8 *)
+ pmevent->event_buf) +
+ sizeof(pmevent->event_id),
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ ,
+ 0
+#endif
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
+ ,
+ GFP_ATOMIC
+#endif
+ );
+#else
+ cfg80211_rx_mgmt(
+ priv->netdev, freq,
+ ((const t_u8 *)pmevent->event_buf) +
+ sizeof(pmevent->event_id),
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH,
+ GFP_ATOMIC);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(
+ priv, PACKET_TYPE_RX,
+ RX_PKT_FATE_SUCCESS,
+ FRAME_TYPE_80211_MGMT, 0, 0,
+ ((t_u8 *)pmevent->event_buf) +
+ sizeof(pmevent->event_id),
+ pmevent->event_len -
+ sizeof(pmevent->event_id) -
+ MLAN_MAC_ADDR_LENGTH);
+#endif
+ }
+#endif /* KERNEL_VERSION */
+ }
+#endif /* STA_CFG80211 || UAP_CFG80211 */
+ break;
+#endif /* UAP_SUPPORT */
+ case MLAN_EVENT_ID_DRV_PASSTHRU:
+ woal_broadcast_event(priv, pmevent->event_buf,
+ pmevent->event_len);
+ break;
+ case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_REPORT:
+ PRINTM(MINFO, "Assoc result\n");
+
+ if (priv->media_connected) {
+ PRINTM(MINFO, "Assoc_Rpt: Media Connected\n");
+ if (!netif_carrier_ok(priv->netdev)) {
+ PRINTM(MINFO, "Assoc_Rpt: Carrier On\n");
+ netif_carrier_on(priv->netdev);
+ }
+ PRINTM(MINFO, "Assoc_Rpt: Queue Start\n");
+ woal_wake_queue(priv->netdev);
+ }
+ break;
+ case MLAN_EVENT_ID_DRV_MEAS_REPORT:
+ /* We have received measurement report, wakeup measurement wait
+ * queue */
+ PRINTM(MINFO, "Measurement Report\n");
+ /* Going out of CAC checking period */
+ if (priv->phandle->cac_period == MTRUE) {
+ priv->phandle->cac_period = MFALSE;
+ if (priv->phandle->meas_wait_q_woken == MFALSE) {
+ priv->phandle->meas_wait_q_woken = MTRUE;
+ wake_up_interruptible(
+ &priv->phandle->meas_wait_q);
+ }
+
+ /* Execute delayed BSS START command */
+ if (priv->phandle->delay_bss_start == MTRUE) {
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+
+ /* Clear flag */
+ priv->phandle->delay_bss_start = MFALSE;
+
+ PRINTM(MMSG,
+ "Now CAC measure period end. Execute delayed BSS Start command.\n");
+
+ req = woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_bss));
+ if (!req) {
+ PRINTM(MERROR,
+ "Failed to allocate ioctl request buffer\n");
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_BSS_START;
+ moal_memcpy_ext(
+ priv->phandle, &bss->param.ssid_bssid,
+ &priv->phandle->delay_ssid_bssid,
+ sizeof(mlan_ssid_bssid),
+ sizeof(mlan_ssid_bssid));
+
+ if (woal_request_ioctl(priv, req,
+ MOAL_NO_WAIT) !=
+ MLAN_STATUS_PENDING) {
+ PRINTM(MERROR,
+ "Delayed BSS Start operation failed!\n");
+ kfree(req);
+ }
+
+ PRINTM(MMSG, "BSS START Complete!\n");
+ }
+#ifdef UAP_SUPPORT
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (priv->uap_host_based &&
+ moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cfg80211_dfs_vendor_event(
+ priv, event_dfs_cac_finished,
+ &priv->chan);
+#endif
+#endif
+#endif
+ }
+ break;
+ case MLAN_EVENT_ID_FW_TX_STATUS: {
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ unsigned long flag;
+ tx_status_event *tx_status =
+ (tx_status_event *)(pmevent->event_buf + 4);
+ struct tx_status_info *tx_info = NULL;
+ PRINTM(MINFO,
+ "Receive Tx status: tx_token=%d, pkt_type=0x%x, status=%d tx_seq_num=%d\n",
+ tx_status->tx_token_id, tx_status->packet_type,
+ tx_status->status, priv->tx_seq_num);
+ spin_lock_irqsave(&priv->tx_stat_lock, flag);
+ tx_info = woal_get_tx_info(priv, tx_status->tx_token_id);
+ if (tx_info) {
+ bool ack;
+ struct sk_buff *skb = (struct sk_buff *)tx_info->tx_skb;
+ list_del(&tx_info->link);
+ spin_unlock_irqrestore(&priv->tx_stat_lock, flag);
+ if (!tx_status->status)
+ ack = true;
+ else
+ ack = false;
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (priv->phandle->remain_on_channel &&
+ tx_info->cancel_remain_on_channel) {
+ remain_priv =
+ priv->phandle->priv
+ [priv->phandle->remain_bss_index];
+ if (remain_priv) {
+ woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_NO_WAIT,
+ MTRUE, &channel_status, NULL, 0,
+ 0);
+ priv->phandle->remain_on_channel =
+ MFALSE;
+ }
+ }
+#endif
+ PRINTM(MEVENT, "Wlan: Tx status=%d\n", ack);
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+ if (tx_info->tx_cookie) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ cfg80211_mgmt_tx_status(priv->netdev,
+ tx_info->tx_cookie,
+ skb->data, skb->len,
+ ack, GFP_ATOMIC);
+#else
+ cfg80211_mgmt_tx_status(priv->wdev,
+ tx_info->tx_cookie,
+ skb->data, skb->len,
+ ack, GFP_ATOMIC);
+#endif
+#endif
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_packet_fate_monitor(priv, PACKET_TYPE_TX,
+ ack ? TX_PKT_FATE_ACKED :
+ TX_PKT_FATE_SENT,
+ FRAME_TYPE_80211_MGMT, 0, 0,
+ skb->data, skb->len);
+#endif
+#endif
+ dev_kfree_skb_any(skb);
+ kfree(tx_info);
+ } else
+ spin_unlock_irqrestore(&priv->tx_stat_lock, flag);
+#endif
+ } break;
+ case MLAN_EVENT_ID_DRV_FT_RESPONSE:
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(cfg80211_wext)) {
+ struct cfg80211_ft_event_params ft_event;
+ if (priv->ft_pre_connect)
+ break;
+ memset(&ft_event, 0,
+ sizeof(struct cfg80211_ft_event_params));
+ PRINTM(MMSG,
+ "wlan : FT response target AP " MACSTR "\n",
+ MAC2STR((t_u8 *)pmevent->event_buf));
+ DBG_HEXDUMP(MDAT_D, "FT-event ", pmevent->event_buf,
+ pmevent->event_len);
+ moal_memcpy_ext(priv->phandle, priv->target_ap_bssid,
+ pmevent->event_buf, ETH_ALEN, ETH_ALEN);
+ ft_event.target_ap = priv->target_ap_bssid;
+ ft_event.ies = pmevent->event_buf + ETH_ALEN;
+ ft_event.ies_len = pmevent->event_len - ETH_ALEN;
+ /*TSPEC info is needed by RIC, However the TS operation
+ * is configured by mlanutl*/
+ /*So do not add RIC temporally*/
+ /*when add RIC, 1. query TS status, 2. copy tspec from
+ * addts command*/
+ ft_event.ric_ies = NULL;
+ ft_event.ric_ies_len = 0;
+
+ cfg80211_ft_event(priv->netdev, &ft_event);
+ priv->ft_pre_connect = MTRUE;
+
+ if (priv->ft_roaming_triggered_by_driver ||
+ !(priv->ft_cap & MBIT(0))) {
+ priv->ft_wait_condition = MTRUE;
+ wake_up(&priv->ft_wait_q);
+ }
+ }
+#endif
+#endif
+ break;
+ default:
+ break;
+ }
+done:
+ LEAVE();
+ return MLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function prints the debug message in mlan
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param level debug level
+ * @param pformat point to string format buf
+ *
+ * @return N/A
+ */
+t_void moal_print(t_void *pmoal_handle, t_u32 level, char *pformat, IN...)
+{
+#ifdef DEBUG_LEVEL1
+ va_list args;
+
+ if (level & MHEX_DUMP) {
+ t_u8 *buf = NULL;
+ int len = 0;
+
+ va_start(args, pformat);
+ buf = (t_u8 *)va_arg(args, t_u8 *);
+ len = (int)va_arg(args, int);
+ va_end(args);
+
+#ifdef DEBUG_LEVEL2
+ if (level & MINFO)
+ HEXDUMP((char *)pformat, buf, len);
+ else
+#endif /* DEBUG_LEVEL2 */
+ {
+ if (level & MERROR)
+ DBG_HEXDUMP(MERROR, (char *)pformat, buf, len);
+ if (level & MCMD_D)
+ DBG_HEXDUMP(MCMD_D, (char *)pformat, buf, len);
+ if (level & MDAT_D)
+ DBG_HEXDUMP(MDAT_D, (char *)pformat, buf, len);
+ if (level & MIF_D)
+ DBG_HEXDUMP(MIF_D, (char *)pformat, buf, len);
+ if (level & MFW_D)
+ DBG_HEXDUMP(MFW_D, (char *)pformat, buf, len);
+ if (level & MEVT_D)
+ DBG_HEXDUMP(MEVT_D, (char *)pformat, buf, len);
+ }
+ } else {
+ if (drvdbg & level) {
+ va_start(args, pformat);
+ vprintk(pformat, args);
+ va_end(args);
+ }
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function prints the network interface name
+ *
+ * @param pmoal_handle Pointer to the MOAL context
+ * @param bss_index BSS index
+ * @param level debug level
+ *
+ * @return N/A
+ */
+t_void moal_print_netintf(t_void *pmoal_handle, t_u32 bss_index, t_u32 level)
+{
+#ifdef DEBUG_LEVEL1
+ moal_handle *phandle = (moal_handle *)pmoal_handle;
+
+ if (phandle) {
+ if ((bss_index < MLAN_MAX_BSS_NUM) &&
+ phandle->priv[bss_index] &&
+ phandle->priv[bss_index]->netdev) {
+ if (drvdbg & level)
+ printk("%s: ",
+ phandle->priv[bss_index]->netdev->name);
+ }
+ }
+#endif /* DEBUG_LEVEL1 */
+}
+
+/**
+ * @brief This function asserts the existence of the passed argument
+ *
+ * @param pmoal_handle A pointer to moal_private structure
+ * @param cond Condition to check
+ *
+ * @return N/A
+ */
+t_void moal_assert(t_void *pmoal_handle, t_u32 cond)
+{
+ if (!cond) {
+ panic("Assert failed: Panic!");
+ }
+}
+
+/**
+ * @brief This function save the histogram data
+ *
+ * @param pmoal_handle A pointer to moal_private structure
+ * @param bss_index BSS index
+ * @param rx_rate rx rate index
+ * @param snr snr
+ * @param nflr noise floor
+ * @param antenna antenna
+ *
+ * @return N/A
+ */
+t_void moal_hist_data_add(t_void *pmoal_handle, t_u32 bss_index, t_u16 rx_rate,
+ t_s8 snr, t_s8 nflr, t_u8 antenna)
+{
+ moal_private *priv = NULL;
+ priv = woal_bss_index_to_priv(pmoal_handle, bss_index);
+ if (priv && antenna >= priv->phandle->card_info->histogram_table_num)
+ antenna = 0;
+ if (priv && priv->hist_data[antenna])
+ woal_hist_data_add(priv, rx_rate, snr, nflr, antenna);
+}
+
+/**
+ * @brief Performs division of 64-bit num with base
+ * @brief do_div does two things
+ * @brief 1. modifies the 64-bit num in place with
+ * @brief the quotient, i.e., num becomes quotient
+ * @brief 2. do_div() returns the 32-bit reminder
+ *
+ * @param num dividend
+ * @param base divisor
+ * @return returns 64-bit quotient
+ */
+t_u64 moal_do_div(t_u64 num, t_u32 base)
+{
+ t_u64 val = num;
+ do_div(val, base);
+ return val;
+}
+
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+/**
+ * @brief Performs wait event
+ *
+ * @param pmoal_handle t_void
+ * @param bss_index index of priv
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_wait_hostcmd_complete(t_void *pmoal_handle, t_u32 bss_index)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ moal_private *priv = woal_bss_index_to_priv(handle, bss_index);
+ long time_left = 0;
+
+ ENTER();
+
+ if (!priv) {
+ PRINTM(MERROR, "moal_wait_event: priv is null!\n");
+ goto done;
+ }
+
+ priv->hostcmd_wait_condition = MFALSE;
+ time_left = wait_event_timeout(priv->hostcmd_wait_q,
+ priv->hostcmd_wait_condition,
+ MOAL_IOCTL_TIMEOUT);
+
+ if (!time_left) {
+ PRINTM(MERROR, "moal_wait_event: wait timeout ");
+ status = MLAN_STATUS_FAILURE;
+ }
+
+done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief wake up esa wait_q
+ *
+ * @param pmoal_handle t_void
+ * @param bss_index index of priv
+ * @return MLAN_STATUS_SUCCESS
+ */
+mlan_status moal_notify_hostcmd_complete(t_void *pmoal_handle, t_u32 bss_index)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = (moal_handle *)pmoal_handle;
+ moal_private *priv = woal_bss_index_to_priv(handle, bss_index);
+
+ ENTER();
+
+ priv->hostcmd_wait_condition = MTRUE;
+ wake_up(&priv->hostcmd_wait_q);
+
+ LEAVE();
+ return status;
+}
+#endif
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.h
new file mode 100644
index 000000000000..ddcf9c075c8e
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_shim.h
@@ -0,0 +1,122 @@
+/** @file moal_shim.h
+ *
+ * @brief This file contains declaration referring to
+ * functions defined in moal module
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/*************************************************************
+ * Change Log:
+ * 10/21/2008: initial version
+ ************************************************************/
+
+#ifndef _MOAL_H
+#define _MOAL_H
+
+mlan_status moal_get_fw_data(t_void *pmoal_handle, t_u32 offset, t_u32 len,
+ t_u8 *pbuf);
+mlan_status moal_get_vdll_data(t_void *pmoal_handle, t_u32 len, t_u8 *pbuf);
+mlan_status moal_get_hw_spec_complete(t_void *pmoal_handle, mlan_status status,
+ mlan_hw_info *phw, pmlan_bss_tbl ptbl);
+mlan_status moal_init_fw_complete(t_void *pmoal_handle, mlan_status status);
+mlan_status moal_shutdown_fw_complete(t_void *pmoal_handle, mlan_status status);
+mlan_status moal_ioctl_complete(t_void *pmoal_handle,
+ pmlan_ioctl_req pioctl_req, mlan_status status);
+mlan_status moal_alloc_mlan_buffer(t_void *pmoal_handle, t_u32 size,
+ pmlan_buffer *pmbuf);
+mlan_status moal_free_mlan_buffer(t_void *pmoal_handle, pmlan_buffer pmbuf);
+mlan_status moal_send_packet_complete(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ mlan_status status);
+#ifdef USB
+mlan_status moal_recv_complete(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, mlan_status status);
+mlan_status moal_write_data_async(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port);
+#endif
+
+#if defined(SDIO) || defined(PCIE)
+/** moal_write_reg */
+mlan_status moal_write_reg(t_void *pmoal_handle, t_u32 reg, t_u32 data);
+/** moal_read_reg */
+mlan_status moal_read_reg(t_void *pmoal_handle, t_u32 reg, t_u32 *data);
+#endif /* SDIO || PCIE */
+mlan_status moal_write_data_sync(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, t_u32 timeout);
+mlan_status moal_read_data_sync(t_void *pmoal_handle, pmlan_buffer pmbuf,
+ t_u32 port, t_u32 timeout);
+mlan_status moal_recv_packet(t_void *pmoal_handle, pmlan_buffer pmbuf);
+mlan_status moal_recv_event(t_void *pmoal_handle, pmlan_event pmevent);
+mlan_status moal_malloc(t_void *pmoal_handle, t_u32 size, t_u32 flag,
+ t_u8 **ppbuf);
+mlan_status moal_mfree(t_void *pmoal_handle, t_u8 *pbuf);
+mlan_status moal_vmalloc(t_void *pmoal_handle, t_u32 size, t_u8 **ppbuf);
+mlan_status moal_vfree(t_void *pmoal_handle, t_u8 *pbuf);
+#ifdef PCIE
+mlan_status moal_malloc_consistent(t_void *pmoal_handle, t_u32 size,
+ t_u8 **ppbuf, t_pu64 pbuf_pa);
+mlan_status moal_mfree_consistent(t_void *pmoal_handle, t_u32 size, t_u8 *pbuf,
+ t_u64 buf_pa);
+mlan_status moal_map_memory(t_void *pmoal_handle, t_u8 *pbuf, t_u64 *pbuf_pa,
+ t_u32 size, t_u32 flag);
+mlan_status moal_unmap_memory(t_void *pmoal_handle, t_u8 *pbuf, t_u64 buf_pa,
+ t_u32 size, t_u32 flag);
+#endif /* PCIE */
+t_void *moal_memset(t_void *pmoal_handle, t_void *pmem, t_u8 byte, t_u32 num);
+t_void *moal_memcpy(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num);
+t_void *moal_memcpy_ext(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num, t_u32 dest_size);
+
+t_void *moal_memmove(t_void *pmoal_handle, t_void *pdest, const t_void *psrc,
+ t_u32 num);
+t_s32 moal_memcmp(t_void *pmoal_handle, const t_void *pmem1,
+ const t_void *pmem2, t_u32 num);
+/** moal_udelay */
+t_void moal_udelay(t_void *pmoal_handle, t_u32 udelay);
+t_void moal_usleep_range(t_void *pmoal_handle, t_u32 min_delay,
+ t_u32 max_delay);
+mlan_status moal_get_boot_ktime(t_void *pmoal_handle, t_u64 *pnsec);
+mlan_status moal_get_system_time(t_void *pmoal_handle, t_u32 *psec,
+ t_u32 *pusec);
+mlan_status moal_init_lock(t_void *pmoal_handle, t_void **pplock);
+mlan_status moal_free_lock(t_void *pmoal_handle, t_void *plock);
+mlan_status moal_spin_lock(t_void *pmoal_handle, t_void *plock);
+mlan_status moal_spin_unlock(t_void *pmoal_handle, t_void *plock);
+#if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
+mlan_status moal_wait_hostcmd_complete(t_void *pmoal_handle, t_u32 bss_index);
+mlan_status moal_notify_hostcmd_complete(t_void *pmoal_handle, t_u32 bss_index);
+#endif
+t_void moal_print(t_void *pmoal_handle, t_u32 level, char *pformat, IN...);
+t_void moal_print_netintf(t_void *pmoal_handle, t_u32 bss_index, t_u32 level);
+t_void moal_assert(t_void *pmoal_handle, t_u32 cond);
+t_void moal_hist_data_add(t_void *pmoal_handle, t_u32 bss_index, t_u16 rx_rate,
+ t_s8 snr, t_s8 nflr, t_u8 antenna);
+
+t_u64 moal_do_div(t_u64 num, t_u32 base);
+
+mlan_status moal_init_timer(t_void *pmoal_handle, t_void **pptimer,
+ IN t_void (*callback)(t_void *pcontext),
+ t_void *pcontext);
+mlan_status moal_free_timer(t_void *pmoal_handle, t_void *ptimer);
+mlan_status moal_start_timer(t_void *pmoal_handle, t_void *ptimer,
+ t_u8 periodic, t_u32 msec);
+mlan_status moal_stop_timer(t_void *pmoal_handle, t_void *ptimer);
+void moal_tp_accounting(t_void *pmoal_handle, void *buf, t_u32 drop_point);
+void moal_tp_accounting_rx_param(t_void *pmoal_handle, unsigned int type,
+ unsigned int rsvd1);
+#endif /*_MOAL_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.c
new file mode 100644
index 000000000000..72f70404d85c
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.c
@@ -0,0 +1,7893 @@
+/** @file moal_sta_cfg80211.c
+ *
+ * @brief This file contains the functions for STA CFG80211.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "moal_cfg80211.h"
+#include "moal_cfg80211_util.h"
+#include "moal_sta_cfg80211.h"
+#include "moal_eth_ioctl.h"
+#ifdef UAP_SUPPORT
+#include "moal_uap.h"
+#endif
+#include <linux/sort.h>
+
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+extern int fw_region;
+#endif
+#endif
+/* Supported crypto cipher suits to be advertised to cfg80211 */
+const u32 cfg80211_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_SMS4, WLAN_CIPHER_SUITE_AES_CMAC,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ WLAN_CIPHER_SUITE_BIP_GMAC_256,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ WLAN_CIPHER_SUITE_GCMP,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ WLAN_CIPHER_SUITE_GCMP_256,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ WLAN_CIPHER_SUITE_CCMP_256,
+#endif
+};
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+static void
+#else
+static int
+#endif
+woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+static int woal_cfg80211_scan(struct wiphy *wiphy,
+ struct cfg80211_scan_request *request);
+#else
+static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+static void woal_cfg80211_abort_scan(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
+#endif
+static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+
+static int woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code);
+
+static int woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_info *sinfo);
+
+static int woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 *mac, struct station_info *sinfo);
+
+static int woal_cfg80211_dump_survey(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ struct survey_info *survey);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+static int woal_cfg80211_get_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef);
+#endif
+static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ int timeout);
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+static int woal_cfg80211_get_tx_power(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct wireless_dev *wdev,
+#endif
+ int *dbm);
+
+static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct wireless_dev *wdev,
+#endif
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct wireless_dev *wdev,
+#else
+ struct net_device *dev,
+#endif
+ u64 cookie);
+
+static int
+woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct wireless_dev *wdev,
+#else
+ struct net_device *dev,
+#endif
+ struct ieee80211_channel *chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ enum nl80211_channel_type channel_type,
+#endif
+ unsigned int duration, u64 *cookie);
+
+static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct wireless_dev *wdev,
+#else
+ struct net_device *dev,
+#endif
+ u64 cookie);
+#endif /* KERNEL_VERSION */
+
+#ifdef CONFIG_NL80211_TESTMODE
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+static int woal_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int len);
+#else
+static int woal_testmode_cmd(struct wiphy *wiphy, void *data, int len);
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+int woal_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_sched_scan_request *request);
+int woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ u64 reqid
+#endif
+);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+int woal_cfg80211_resume(struct wiphy *wiphy);
+int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static void woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+static int woal_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_parameters *params);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+int woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_update_ft_ies_params *ftie);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+static int woal_cfg80211_authenticate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_auth_request *req);
+
+static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_assoc_request *req);
+#ifdef UAP_SUPPORT
+int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params);
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#ifdef UAP_SUPPORT
+static int woal_cfg80211_add_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_parameters *params);
+#endif
+#endif
+
+static int woal_cfg80211_deauthenticate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_deauth_request *req);
+
+static int woal_cfg80211_disassociate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_disassoc_request *req);
+
+/** cfg80211 operations */
+static struct cfg80211_ops woal_cfg80211_ops = {
+ .change_virtual_intf = woal_cfg80211_change_virtual_intf,
+ .scan = woal_cfg80211_scan,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ .abort_scan = woal_cfg80211_abort_scan,
+#endif
+ .connect = woal_cfg80211_connect,
+ .disconnect = woal_cfg80211_disconnect,
+ .deauth = woal_cfg80211_deauthenticate,
+ .disassoc = woal_cfg80211_disassociate,
+ .get_station = woal_cfg80211_get_station,
+ .dump_station = woal_cfg80211_dump_station,
+ .dump_survey = woal_cfg80211_dump_survey,
+ .set_wiphy_params = woal_cfg80211_set_wiphy_params,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ .set_channel = woal_cfg80211_set_channel,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ .get_channel = woal_cfg80211_get_channel,
+#endif
+ .add_key = woal_cfg80211_add_key,
+ .del_key = woal_cfg80211_del_key,
+ .set_default_key = woal_cfg80211_set_default_key,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ .set_default_mgmt_key = woal_cfg80211_set_default_mgmt_key,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ .set_rekey_data = woal_cfg80211_set_rekey_data,
+#endif
+ .set_pmksa = woal_cfg80211_set_pmksa,
+ .del_pmksa = woal_cfg80211_del_pmksa,
+ .flush_pmksa = woal_cfg80211_flush_pmksa,
+ .set_power_mgmt = woal_cfg80211_set_power_mgmt,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+ .set_tx_power = woal_cfg80211_set_tx_power,
+ .get_tx_power = woal_cfg80211_get_tx_power,
+#endif
+ .set_bitrate_mask = woal_cfg80211_set_bitrate_mask,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .sched_scan_start = woal_cfg80211_sched_scan_start,
+ .sched_scan_stop = woal_cfg80211_sched_scan_stop,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .suspend = woal_cfg80211_suspend,
+ .resume = woal_cfg80211_resume,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ .set_wakeup = woal_cfg80211_set_wakeup,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
+ .set_antenna = woal_cfg80211_set_antenna,
+ .get_antenna = woal_cfg80211_get_antenna,
+#endif
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+ .set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .change_station = woal_cfg80211_change_station,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ .update_ft_ies = woal_cfg80211_update_ft_ies,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ .set_qos_map = woal_cfg80211_set_qos_map,
+#endif
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ .set_coalesce = woal_cfg80211_set_coalesce,
+#endif
+ .add_virtual_intf = woal_cfg80211_add_virtual_intf,
+ .del_virtual_intf = woal_cfg80211_del_virtual_intf,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ .start_ap = woal_cfg80211_add_beacon,
+ .change_beacon = woal_cfg80211_set_beacon,
+ .stop_ap = woal_cfg80211_del_beacon,
+#else
+ .add_beacon = woal_cfg80211_add_beacon,
+ .set_beacon = woal_cfg80211_set_beacon,
+ .del_beacon = woal_cfg80211_del_beacon,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ .change_bss = woal_cfg80211_change_bss,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ .add_station = woal_cfg80211_add_station,
+#endif
+ .del_station = woal_cfg80211_del_station,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+ .set_txq_params = woal_cfg80211_set_txq_params,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ .set_mac_acl = woal_cfg80211_set_mac_acl,
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ .start_radar_detection = woal_cfg80211_start_radar_detection,
+
+ .channel_switch = woal_cfg80211_channel_switch,
+#endif
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+ .update_mgmt_frame_registrations = woal_cfg80211_mgmt_frame_register,
+#else
+ .mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
+#endif
+ .mgmt_tx = woal_cfg80211_mgmt_tx,
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ .mgmt_tx_cancel_wait = woal_cfg80211_mgmt_tx_cancel_wait,
+ .remain_on_channel = woal_cfg80211_remain_on_channel,
+ .cancel_remain_on_channel = woal_cfg80211_cancel_remain_on_channel,
+#endif
+
+#ifdef CONFIG_NL80211_TESTMODE
+ .testmode_cmd = woal_testmode_cmd,
+#endif
+};
+
+/** Region code mapping */
+typedef struct _region_code_t {
+ /** Region */
+ t_u8 region[COUNTRY_CODE_LEN];
+} region_code_t;
+
+static const struct ieee80211_regdomain mrvl_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150 - 10, 5350 + 10, 80, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470 - 10, 5850 + 10, 80, 6, 20, 0),
+ }};
+/********************************************************
+ Local Variables
+********************************************************/
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+// clang-format off
+static const struct ieee80211_txrx_stypes
+ ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = MBIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ MBIT(IEEE80211_STYPE_AUTH >> 4) |
+ MBIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ MBIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
+ MBIT(IEEE80211_STYPE_AUTH >> 4) |
+ MBIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
+ MBIT(IEEE80211_STYPE_REASSOC_RESP >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = MBIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ MBIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ MBIT(IEEE80211_STYPE_AUTH >> 4) |
+ MBIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ MBIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+#endif
+#endif
+ [NL80211_IFTYPE_MESH_POINT] = {
+ .tx = 0x0000,
+ .rx = 0x0000,
+ },
+
+};
+// clang-format on
+#endif
+
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 0, 0)
+/**
+ * NOTE: types in all the sets must be equals to the
+ * initial value of wiphy->interface_modes
+ */
+static const struct ieee80211_iface_limit cfg80211_ap_sta_limits[] = {
+ {.max = 4,
+ .types = MBIT(NL80211_IFTYPE_STATION)
+#ifdef UAP_CFG80211
+ | MBIT(NL80211_IFTYPE_AP)
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ | MBIT(NL80211_IFTYPE_P2P_GO) |
+ MBIT(NL80211_IFTYPE_P2P_CLIENT)
+#endif
+#endif
+ }};
+
+static struct ieee80211_iface_combination cfg80211_iface_comb_ap_sta = {
+ .limits = cfg80211_ap_sta_limits,
+ .num_different_channels = 1,
+ .n_limits = ARRAY_SIZE(cfg80211_ap_sta_limits),
+ .max_interfaces = 4,
+ .beacon_int_infra_match = MTRUE,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ .radar_detect_widths =
+ MBIT(NL80211_CHAN_WIDTH_20_NOHT) | MBIT(NL80211_CHAN_WIDTH_20),
+#endif
+};
+#endif
+
+extern pmoal_handle m_handle[];
+
+#ifdef CONFIG_PM
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static const struct wiphy_wowlan_support wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT,
+ .n_patterns = MAX_NUM_FILTERS,
+ .pattern_min_len = 1,
+ .pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
+ .max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
+};
+static const struct wiphy_wowlan_support wowlan_support_with_gtk = {
+ .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE,
+ .n_patterns = MAX_NUM_FILTERS,
+ .pattern_min_len = 1,
+ .pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
+ .max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
+};
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+static const struct wiphy_coalesce_support coalesce_support = {
+ .n_rules = COALESCE_MAX_RULES,
+ .max_delay = MAX_COALESCING_DELAY,
+ .n_patterns = COALESCE_MAX_FILTERS,
+ .pattern_min_len = 1,
+ .pattern_max_len = MAX_PATTERN_LEN,
+ .max_pkt_offset = MAX_OFFSET_LEN,
+};
+#endif
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief This function check cfg80211 special region code.
+ *
+ * @param region_string Region string
+ *
+ * @return MTRUE/MFALSE
+ */
+t_u8 is_cfg80211_special_region_code(t_u8 *region_string)
+{
+ t_u8 i;
+ region_code_t cfg80211_special_region_code[] = {
+ {"00 "}, {"99 "}, {"98 "}, {"97 "}};
+
+ for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++)
+ region_string[i] = toupper(region_string[i]);
+
+ for (i = 0; i < ARRAY_SIZE(cfg80211_special_region_code); i++) {
+ if (!memcmp(region_string,
+ cfg80211_special_region_code[i].region,
+ COUNTRY_CODE_LEN)) {
+ PRINTM(MIOCTL, "special region code=%s\n",
+ region_string);
+ return MTRUE;
+ }
+ }
+ return MFALSE;
+}
+
+/**
+ * @brief Get the encryption mode from cipher
+ *
+ * @param cipher Cipher cuite
+ * @param wpa_enabled WPA enable or disable
+ *
+ * @return MLAN_ENCRYPTION_MODE_*
+ */
+static int woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled)
+{
+ int encrypt_mode;
+
+ ENTER();
+
+ *wpa_enabled = 0;
+ switch (cipher) {
+ case MW_AUTH_CIPHER_NONE:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ *wpa_enabled = 1;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ *wpa_enabled = 1;
+ break;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP_256;
+ *wpa_enabled = 1;
+ break;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ case WLAN_CIPHER_SUITE_GCMP:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_GCMP;
+ *wpa_enabled = 1;
+ break;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ encrypt_mode = MLAN_ENCRYPTION_MODE_GCMP_256;
+ *wpa_enabled = 1;
+ break;
+#endif
+ default:
+ encrypt_mode = -1;
+ }
+
+ LEAVE();
+ return encrypt_mode;
+}
+
+/**
+ * @brief get associate failure status code
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ *
+ * @return IEEE status code
+ */
+static int woal_get_assoc_status(moal_private *priv)
+{
+ int ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ t_u16 status = (t_u16)(priv->assoc_status & 0xffff);
+ t_u16 cap = (t_u16)(priv->assoc_status >> 16);
+
+ switch (cap) {
+ case 0xfffd:
+ case 0xfffe:
+ ret = status;
+ break;
+ case 0xfffc:
+ ret = WLAN_STATUS_AUTH_TIMEOUT;
+ break;
+ default:
+ break;
+ }
+ PRINTM(MCMND, "Assoc fail: status=%d, cap=0x%x, IEEE status=%d\n",
+ status, cap, ret);
+ return ret;
+}
+
+/**
+ * @brief Check the pairwise or group cipher for
+ * WEP enabled or not
+ *
+ * @param cipher MLAN Cipher cuite
+ *
+ * @return 1 -- enable or 0 -- disable
+ */
+static int woal_cfg80211_is_alg_wep(t_u32 cipher)
+{
+ int alg = 0;
+ ENTER();
+
+ if (cipher == MLAN_ENCRYPTION_MODE_WEP40 ||
+ cipher == MLAN_ENCRYPTION_MODE_WEP104)
+ alg = 1;
+
+ LEAVE();
+ return alg;
+}
+
+/**
+ * @brief Convert NL80211 interface type to MLAN_BSS_MODE_*
+ *
+ * @param iftype Interface type of NL80211
+ *
+ * @return Driver bss mode
+ */
+static t_u32 woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)
+{
+ switch (iftype) {
+ case NL80211_IFTYPE_STATION:
+ return MLAN_BSS_MODE_INFRA;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ return MLAN_BSS_MODE_AUTO;
+ }
+}
+
+/**
+ * @brief Control WPS Session Enable/Disable
+ *
+ * @param priv Pointer to the moal_private driver data struct
+ * @param enable enable/disable flag
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_wps_cfg(moal_private *priv, int enable)
+{
+ int ret = 0;
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ PRINTM(MINFO, "WOAL_WPS_SESSION\n");
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ if (enable)
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+ else
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure ASSOC IE
+ *
+ * @param priv A pointer to moal private structure
+ * @param ie A pointer to ie data
+ * @param ie_len The length of ie data
+ * @param wait_option wait option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_assoc_ies_cfg(moal_private *priv, t_u8 *ie, int ie_len,
+ t_u8 wait_option)
+{
+ int bytes_left = ie_len;
+ t_u8 *pcurrent_ptr = ie;
+ int total_ie_len;
+ t_u8 element_len;
+ int ret = MLAN_STATUS_SUCCESS;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ t_u8 wps_oui[] = {0x00, 0x50, 0xf2, 0x04};
+ t_u8 hs20_oui[] = {0x50, 0x6f, 0x9a, 0x10};
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR,
+ "InterpretIE: Error in processing IE, bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set RSN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set RSN IE\n");
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ (pvendor_ie->vend_hdr.oui_type == wps_oui[3])) {
+ PRINTM(MIOCTL, "Enable WPS session\n");
+ woal_wps_cfg(priv, MTRUE);
+ }
+ if (!memcmp(pvendor_ie->vend_hdr.oui, hs20_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ (pvendor_ie->vend_hdr.oui_type == hs20_oui[3])) {
+ PRINTM(MIOCTL,
+ "Hotspot2.0 is enabled for this bss\n");
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_hotspotcfg(priv, wait_option,
+ (HOTSPOT_BY_SUPPLICANT |
+ HOTSPOT_ENABLED))) {
+ PRINTM(MERROR,
+ "Fail to enable hotspot 2.0\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR,
+ "Fail to Set VENDOR SPECIFIC IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n",
+ pvendor_ie->vend_hdr.oui[0],
+ pvendor_ie->vend_hdr.oui[1],
+ pvendor_ie->vend_hdr.oui[2],
+ pvendor_ie->vend_hdr.oui_type);
+ break;
+ case MOBILITY_DOMAIN:
+ break;
+ case FAST_BSS_TRANSITION:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set"
+ "FAST_BSS_TRANSITION IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set FAST_BSS_TRANSITION IE\n");
+ break;
+ case RIC:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR,
+ "Fail to set"
+ "RESOURCE INFORMATION CONTAINER IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "Set RESOURCE INFORMATION CONTAINER IE\n");
+ break;
+ case EXT_CAPABILITY:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR,
+ "Fail to set Extended Capabilites IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set Extended Capabilities IE\n");
+ break;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ case EXTENSION:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set Extension IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set Extension IE\n");
+ break;
+ case FRAGMENT:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set Fragmented IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set Fragmented IE\n");
+ break;
+#endif
+ default:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ pcurrent_ptr, &total_ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Fail to set GEN IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Set GEN IE\n");
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+done:
+ return ret;
+}
+
+#ifdef CONFIG_NL80211_TESTMODE
+enum moal_tm_attr {
+ __MOAL_TM_ATTR_INVALID = 0,
+ MOAL_TM_ATTR_CMD = 1,
+ MOAL_TM_ATTR_DATA = 2,
+
+ /* keep last */
+ __MOAL_TM_ATTR_AFTER_LAST,
+ MOAL_TM_ATTR_MAX = __MOAL_TM_ATTR_AFTER_LAST - 1,
+};
+
+static const struct nla_policy moal_tm_policy[MOAL_TM_ATTR_MAX + 1] = {
+ [MOAL_TM_ATTR_CMD] = {.type = NLA_U32},
+ [MOAL_TM_ATTR_DATA] = {.type = NLA_BINARY,
+ .len = MRVDRV_SIZE_OF_CMD_BUFFER},
+};
+
+enum moal_tm_command {
+ MOAL_TM_CMD_HOSTCMD = 0,
+};
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+static int woal_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int len)
+#else
+static int woal_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+#endif
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv =
+ (moal_private *)woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ struct nlattr *tb[MOAL_TM_ATTR_MAX + 1];
+ struct sk_buff *skb;
+ int err;
+
+ if (!priv)
+ return -EINVAL;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ err = nla_parse(tb, MOAL_TM_ATTR_MAX, data, len, moal_tm_policy, NULL);
+#else
+ err = nla_parse(tb, MOAL_TM_ATTR_MAX, data, len, moal_tm_policy);
+#endif
+ if (err)
+ return err;
+
+ if (!tb[MOAL_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[MOAL_TM_ATTR_CMD])) {
+ case MOAL_TM_CMD_HOSTCMD:
+ if (!tb[MOAL_TM_ATTR_DATA])
+ return -EINVAL;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL)
+ return -ENOMEM;
+ misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
+ misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+ misc_cfg->param.hostcmd.len = nla_len(tb[MOAL_TM_ATTR_DATA]);
+ moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
+ nla_data(tb[MOAL_TM_ATTR_DATA]),
+ misc_cfg->param.hostcmd.len,
+ MRVDRV_SIZE_OF_CMD_BUFFER);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ err = -EFAULT;
+ goto error;
+ }
+ /* process hostcmd response*/
+ skb = cfg80211_testmode_alloc_reply_skb(
+ wiphy, misc_cfg->param.hostcmd.len);
+ if (!skb) {
+ kfree(req);
+ return -ENOMEM;
+ }
+ err = nla_put(skb, MOAL_TM_ATTR_DATA,
+ misc_cfg->param.hostcmd.len,
+ misc_cfg->param.hostcmd.cmd);
+ if (err) {
+ kfree(req);
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+ err = cfg80211_testmode_reply(skb);
+ kfree(req);
+ return err;
+ default:
+ return -EOPNOTSUPP;
+ }
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ return err;
+}
+#endif
+
+/**
+ * @brief Send domain info command to FW
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_send_domain_info_cmd_fw(moal_private *priv,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband = NULL;
+ struct ieee80211_channel *channel = NULL;
+ t_u8 no_of_sub_band = 0;
+ t_u8 no_of_parsed_chan = 0;
+ t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ t_u8 i, flag = 0;
+ mlan_ds_11d_cfg *cfg_11d = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ PRINTM(MERROR, "No wdev or wiphy in priv\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ band = priv->phandle->band;
+ if (!priv->wdev->wiphy->bands[band]) {
+ PRINTM(MERROR, "11D: setting domain info in FW failed band=%d",
+ band);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (MTRUE ==
+ is_cfg80211_special_region_code(priv->phandle->country_code)) {
+ PRINTM(MIOCTL,
+ "skip region code config, cfg80211 special region code: %s\n",
+ priv->phandle->country_code);
+ goto done;
+ }
+ PRINTM(MIOCTL, "Send domain info: country=%c%c band=%d\n",
+ priv->phandle->country_code[0], priv->phandle->country_code[1],
+ band);
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO_EXT;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Set country code */
+ cfg_11d->param.domain_info.country_code[0] =
+ priv->phandle->country_code[0];
+ cfg_11d->param.domain_info.country_code[1] =
+ priv->phandle->country_code[1];
+ cfg_11d->param.domain_info.country_code[2] = ' ';
+ cfg_11d->param.domain_info.band = band;
+
+ sband = priv->wdev->wiphy->bands[band];
+ for (i = 0; (i < sband->n_channels) &&
+ (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D);
+ i++) {
+ channel = &sband->channels[i];
+ if (channel->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_chan = (t_u32)channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (channel->hw_value == next_chan + 1 &&
+ channel->max_power == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .first_chan = first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .no_of_chan = no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band]
+ .max_tx_pwr = max_pwr;
+ no_of_sub_band++;
+ next_chan = first_chan = (t_u32)channel->hw_value;
+ max_pwr = channel->max_power;
+ no_of_parsed_chan = 1;
+ }
+ }
+
+ if (flag && (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D)) {
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band].first_chan =
+ first_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band].no_of_chan =
+ no_of_parsed_chan;
+ cfg_11d->param.domain_info.sub_band[no_of_sub_band].max_tx_pwr =
+ max_pwr;
+ no_of_sub_band++;
+ }
+ cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band;
+
+ PRINTM(MCMND, "CFG80211: Country=%c%c, band=%d, no_of_sub_band=%d\n",
+ priv->phandle->country_code[0], priv->phandle->country_code[1],
+ priv->phandle->band, cfg_11d->param.domain_info.no_of_sub_band);
+ /* Send domain info command to FW */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to change the channel and
+ * change domain info according to that channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type of nl80211_channel_type
+ * @param wait_option wait option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_set_rf_channel(moal_private *priv, struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ t_u8 wait_option)
+{
+ int ret = 0;
+ t_u32 mode, config_bands = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!chan) {
+ LEAVE();
+ return -EINVAL;
+ }
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ /* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN
+ */
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ req->action = MLAN_ACT_SET;
+ priv->phandle->band = chan->band;
+ /* Set appropriate bands */
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ config_bands = BAND_B | BAND_G | BAND_GN;
+ else {
+ config_bands = BAND_AN | BAND_A;
+ }
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ radio_cfg->param.band_cfg.adhoc_start_band = config_bands;
+ radio_cfg->param.band_cfg.adhoc_channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+ }
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_send_domain_info_cmd_fw(priv, wait_option);
+
+ PRINTM(MINFO, "Setting band %d, and mode = %d channel=%d\n",
+ config_bands, mode,
+ ieee80211_frequency_to_channel(chan->center_freq));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(
+ priv, ieee80211_frequency_to_channel(chan->center_freq),
+ wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set ewpa mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_set_ewpa_mode(moal_private *priv, t_u8 wait_option,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!priv->phandle->card_info->embedded_supp) {
+ ret = -EOPNOTSUPP;
+ goto error;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ /* Fill request buffer */
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Try Get All */
+ memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
+ moal_memcpy_ext(priv->phandle, &sec->param.passphrase.ssid,
+ &ssid_bssid->ssid, sizeof(sec->param.passphrase.ssid),
+ sizeof(sec->param.passphrase.ssid));
+ moal_memcpy_ext(priv->phandle, &sec->param.passphrase.bssid,
+ &ssid_bssid->bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(sec->param.passphrase.bssid));
+ sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS)
+ goto error;
+ sec->param.ewpa_enabled = MFALSE;
+ if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
+ if (sec->param.passphrase.psk.passphrase.passphrase_len > 0)
+ sec->param.ewpa_enabled = MTRUE;
+ } else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
+ sec->param.ewpa_enabled = MTRUE;
+
+ sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
+ req->action = MLAN_ACT_SET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, wait_option);
+
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set encryption mode and enable WPA
+ *
+ * @param priv A pointer to moal_private structure
+ * @param encrypt_mode Encryption mode
+ * @param wpa_enabled WPA enable or not
+ * @param wait_option wait option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_set_auth(moal_private *priv, int encrypt_mode,
+ int wpa_enabled, t_u8 wait_option)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, wait_option, encrypt_mode))
+ ret = -EFAULT;
+
+ if (wpa_enabled) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, wait_option, 1))
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new BSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new BSS connection. If we do not register the new BSS,
+ * a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ssid_bssid A pointer to A pointer to mlan_ssid_bssid structure
+ * @param wait_option wait_option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_inform_bss_from_scan_result(moal_private *priv,
+ mlan_ssid_bssid *ssid_bssid,
+ t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct ieee80211_channel *chan;
+ mlan_scan_resp scan_resp;
+ BSSDescriptor_t *scan_table;
+ t_u64 ts = 0;
+ u16 cap_info = 0;
+ int i = 0;
+ struct cfg80211_bss *pub = NULL;
+
+ ENTER();
+ if (!priv->wdev || !priv->wdev->wiphy) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, wait_option, &scan_resp)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (scan_resp.num_in_scan_table) {
+ scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
+ for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ if (ssid_bssid) {
+ /* Inform specific BSS only */
+ if (memcmp(ssid_bssid->ssid.ssid,
+ scan_table[i].ssid.ssid,
+ ssid_bssid->ssid.ssid_len) ||
+ memcmp(ssid_bssid->bssid,
+ scan_table[i].mac_address, ETH_ALEN))
+ continue;
+ }
+ if (!scan_table[i].freq) {
+ scan_table[i].freq =
+ ieee80211_channel_to_frequency(
+ (int)scan_table[i].channel
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ ,
+ woal_band_cfg_to_ieee_band(
+ scan_table[i].bss_band)
+#endif
+ );
+ }
+ chan = ieee80211_get_channel(priv->wdev->wiphy,
+ scan_table[i].freq);
+ if (!chan) {
+ PRINTM(MCMND,
+ "Fail to get chan with freq: channel=%d freq=%d\n",
+ (int)scan_table[i].channel,
+ (int)scan_table[i].freq);
+ continue;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ !ssid_bssid) {
+ if (!strncmp(scan_table[i].ssid.ssid, "DIRECT-",
+ strlen("DIRECT-"))) {
+ PRINTM(MCMND,
+ "wlan: P2P device " MACSTR
+ " found, channel=%d\n",
+ MAC2STR(scan_table[i]
+ .mac_address),
+ (int)chan->hw_value);
+ }
+ }
+#endif
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ /** Andorid's Location service is expecting timestamp to
+ * be local time (in microsecond) since boot; and not
+ * the TSF found in the beacon. */
+ ts = ktime_to_us(ktime_get_boottime());
+#else
+ moal_memcpy_ext(priv->phandle, &ts,
+ scan_table[i].time_stamp, sizeof(ts),
+ sizeof(ts));
+#endif
+ moal_memcpy_ext(priv->phandle, &cap_info,
+ &scan_table[i].cap_info,
+ sizeof(cap_info), sizeof(cap_info));
+ pub = cfg80211_inform_bss(
+ priv->wdev->wiphy, chan,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ CFG80211_BSS_FTYPE_UNKNOWN,
+#endif
+ scan_table[i].mac_address, ts, cap_info,
+ scan_table[i].beacon_period,
+ scan_table[i].pbeacon_buf +
+ WLAN_802_11_FIXED_IE_SIZE,
+ scan_table[i].beacon_buf_size -
+ WLAN_802_11_FIXED_IE_SIZE,
+ -RSSI_DBM_TO_MDM(scan_table[i].rssi),
+ GFP_KERNEL);
+ if (pub) {
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ pub->len_information_elements =
+ pub->len_beacon_ies;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(priv->wdev->wiphy, pub);
+#else
+ cfg80211_put_bss(pub);
+#endif
+ }
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Informs the CFG802.11 subsystem of a new IBSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new IBSS connection. If we do not register the
+ * new IBSS, a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ *
+ * @param priv A pointer to moal_private structure
+ * @param cahn A pointer to ieee80211_channel structure
+ * @param beacon_interval Beacon interval
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_cfg80211_inform_ibss_bss(moal_private *priv,
+ struct ieee80211_channel *chan,
+ t_u16 beacon_interval)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
+ int ie_len = 0;
+ struct cfg80211_bss *bss = NULL;
+
+ ENTER();
+
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+
+ memset(ie_buf, 0, sizeof(ie_buf));
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = bss_info.ssid.ssid_len;
+
+ moal_memcpy_ext(priv->phandle, &ie_buf[sizeof(IEEEtypes_Header_t)],
+ &bss_info.ssid.ssid, bss_info.ssid.ssid_len,
+ sizeof(ie_buf) - sizeof(IEEEtypes_Header_t));
+ ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ CFG80211_BSS_FTYPE_UNKNOWN,
+#endif
+ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+ beacon_interval, ie_buf, ie_len,
+ signal.bcn_rssi_avg, GFP_KERNEL);
+ if (bss)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Process country IE before assoicate
+ *
+ * @param priv A pointer to moal_private structure
+ * @param bss A pointer to cfg80211_bss structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_process_country_ie(moal_private *priv, struct cfg80211_bss *bss)
+{
+ u8 *country_ie, country_ie_len;
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11d_cfg *cfg_11d = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+ if (!country_ie) {
+ PRINTM(MIOCTL, "No country IE found!\n");
+ woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+ }
+
+ country_ie_len = country_ie[1];
+ if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
+ PRINTM(MIOCTL, "Wrong Country IE length!\n");
+ woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+ }
+ priv->phandle->country_code[0] = country_ie[2];
+ priv->phandle->country_code[1] = country_ie[3];
+ priv->phandle->country_code[2] = ' ';
+ if (is_cfg80211_special_region_code(priv->phandle->country_code)) {
+ PRINTM(MIOCTL, "Skip special region code in CountryIE");
+ LEAVE();
+ return 0;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_region_code(priv, priv->phandle->country_code))
+ PRINTM(MERROR, "Set country code failed!\n");
+
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "Fail to allocate mlan_ds_11d_cfg buffer\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
+ cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO_EXT;
+ req->req_id = MLAN_IOCTL_11D_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Set country code */
+ cfg_11d->param.domain_info.country_code[0] =
+ priv->phandle->country_code[0];
+ cfg_11d->param.domain_info.country_code[1] =
+ priv->phandle->country_code[1];
+ cfg_11d->param.domain_info.country_code[2] = ' ';
+
+ /** IEEE80211_BAND_2GHZ or IEEE80211_BAND_5GHZ */
+ cfg_11d->param.domain_info.band = priv->phandle->band;
+
+ country_ie_len -= COUNTRY_CODE_LEN;
+ cfg_11d->param.domain_info.no_of_sub_band = MIN(
+ MRVDRV_MAX_SUBBAND_802_11D,
+ (country_ie_len / sizeof(struct ieee80211_country_ie_triplet)));
+ moal_memcpy_ext(priv->phandle,
+ (u8 *)cfg_11d->param.domain_info.sub_band,
+ &country_ie[2] + COUNTRY_CODE_LEN,
+ cfg_11d->param.domain_info.no_of_sub_band *
+ sizeof(mlan_ds_subband_set_t),
+ sizeof(cfg_11d->param.domain_info.sub_band));
+
+ PRINTM(MCMND, "11D: Country IE: %c%c band=%d no_of_sub_band=%d\n",
+ country_ie[2], country_ie[3], priv->phandle->band,
+ cfg_11d->param.domain_info.no_of_sub_band);
+ /* Send domain info command to FW */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = MLAN_STATUS_FAILURE;
+ PRINTM(MERROR, "11D: Error setting domain info in FW\n");
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request scan based on connect parameter
+ *
+ * @param priv A pointer to moal_private structure
+ * @param conn_param A pointer to connect parameters
+ * @param wait_option wait option
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_connect_scan(moal_private *priv,
+ struct cfg80211_connect_params *conn_param,
+ t_u8 wait_option)
+{
+ moal_handle *handle = priv->phandle;
+ int ret = 0;
+ wlan_user_scan_cfg scan_req;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ int chan_idx = 0, i;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+ memset(&scan_req, 0x00, sizeof(scan_req));
+ moal_memcpy_ext(priv->phandle, scan_req.ssid_list[0].ssid,
+ conn_param->ssid, conn_param->ssid_len,
+ sizeof(scan_req.ssid_list[0].ssid));
+ scan_req.ssid_list[0].max_len = 0;
+ if (conn_param->channel) {
+ scan_req.chan_list[0].chan_number =
+ conn_param->channel->hw_value;
+ scan_req.chan_list[0].radio_type = conn_param->channel->band;
+ if (conn_param->channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ scan_req.chan_list[0].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE;
+ else if (conn_param->channel->flags & IEEE80211_CHAN_RADAR)
+ scan_req.chan_list[0].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
+ else
+ scan_req.chan_list[0].scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ scan_req.chan_list[0].scan_time = 0;
+ } else {
+ for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
+ if (!priv->wdev->wiphy->bands[band])
+ continue;
+ sband = priv->wdev->wiphy->bands[band];
+ for (i = 0; (i < sband->n_channels); i++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+ scan_req.chan_list[chan_idx].radio_type = band;
+ if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ scan_req.chan_list[chan_idx].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE;
+ else if (ch->flags & IEEE80211_CHAN_RADAR)
+ scan_req.chan_list[chan_idx].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
+ else
+ scan_req.chan_list[chan_idx].scan_type =
+ MLAN_SCAN_TYPE_ACTIVE;
+ scan_req.chan_list[chan_idx].chan_number =
+ (u32)ch->hw_value;
+ chan_idx++;
+ }
+ }
+ }
+ moal_memcpy_ext(priv->phandle, scan_req.random_mac, priv->random_mac,
+ ETH_ALEN, sizeof(scan_req.random_mac));
+ ret = woal_request_userscan(priv, wait_option, &scan_req);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+/**
+ * @brief Save assoc parameters for roaming
+ *
+ * @param priv A pointer to moal_private
+ * @param req A pointer to cfg80211_assoc_request structure
+ */
+void woal_save_assoc_params(moal_private *priv,
+ struct cfg80211_assoc_request *req,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ ENTER();
+
+ if (req->bss->channel) {
+ priv->sme_current.channel = &priv->conn_chan;
+ moal_memcpy_ext(priv->phandle, priv->sme_current.channel,
+ req->bss->channel,
+ sizeof(struct ieee80211_channel),
+ sizeof(struct ieee80211_channel));
+ }
+ priv->sme_current.bssid = priv->conn_bssid;
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
+ req->bss->bssid, MLAN_MAC_ADDR_LENGTH,
+ MLAN_MAC_ADDR_LENGTH);
+ if (req->ie && req->ie_len) {
+ priv->sme_current.ie = kzalloc(req->ie_len, GFP_KERNEL);
+ priv->sme_current.ie_len = req->ie_len;
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie,
+ req->ie, req->ie_len, priv->sme_current.ie_len);
+ }
+ moal_memcpy_ext(priv->phandle, &priv->sme_current.crypto, &req->crypto,
+ sizeof(struct cfg80211_crypto_settings),
+ sizeof(struct cfg80211_crypto_settings));
+ priv->sme_current.flags = req->flags;
+ moal_memcpy_ext(priv->phandle, &priv->sme_current.ht_capa,
+ &req->ht_capa, sizeof(struct ieee80211_ht_cap),
+ sizeof(struct ieee80211_ht_cap));
+ moal_memcpy_ext(priv->phandle, &priv->sme_current.ht_capa_mask,
+ &req->ht_capa_mask, sizeof(struct ieee80211_ht_cap),
+ sizeof(struct ieee80211_ht_cap));
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ moal_memcpy_ext(priv->phandle, &priv->sme_current.vht_capa,
+ &req->vht_capa, sizeof(struct ieee80211_vht_cap),
+ sizeof(struct ieee80211_vht_cap));
+ moal_memcpy_ext(priv->phandle, &priv->sme_current.vht_capa_mask,
+ &req->vht_capa_mask, sizeof(struct ieee80211_vht_cap),
+ sizeof(struct ieee80211_vht_cap));
+#endif
+ if (ssid_bssid && ssid_bssid->ssid.ssid_len) {
+ priv->sme_current.ssid = priv->conn_ssid;
+ memset(priv->conn_ssid, 0, MLAN_MAX_SSID_LENGTH);
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ssid,
+ ssid_bssid->ssid.ssid,
+ ssid_bssid->ssid.ssid_len,
+ sizeof(priv->conn_ssid));
+ priv->conn_ssid_len = ssid_bssid->ssid.ssid_len;
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Save auth parameters for roaming
+ *
+ * @param priv A pointer to moal_private
+ * @param req A pointer to struct cfg80211_auth_request
+ */
+void woal_save_auth_params(moal_private *priv,
+ struct cfg80211_auth_request *req)
+{
+ ENTER();
+ woal_clear_conn_params(priv);
+ priv->sme_current.auth_type = req->auth_type;
+ priv->sme_current.key_idx = req->key_idx;
+ priv->sme_current.key_len = req->key_len;
+ if (req->key && req->key_len && (req->key_len <= MAX_WEP_KEY_SIZE)) {
+ priv->sme_current.key = priv->conn_wep_key;
+ moal_memcpy_ext(priv->phandle, (t_u8 *)priv->sme_current.key,
+ req->key, req->key_len,
+ sizeof(priv->conn_wep_key));
+ }
+ LEAVE();
+}
+
+/**
+ * @brief This function is authentication handler when host MLME
+ * enable.
+ * In this case driver will prepare and send Auth Req.
+ *
+ * @param wiphy A pointer to wiphy.
+ *
+ * @param dev A pointer to net_device
+ *
+ * @param req A pointer to cfg80211_auth_request
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_authenticate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_auth_request *req)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ IEEE80211_MGMT *mgmt = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = NULL;
+ t_u32 pkt_type, tx_control;
+ t_u16 packet_len = 0, auth_alg;
+ t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ int ret = 0;
+
+ t_u8 trans = 1, status_code = 0;
+ t_u8 *varptr = NULL;
+ mlan_ssid_bssid *ssid_bssid;
+ moal_handle *handle = priv->phandle;
+ int i;
+
+ ENTER();
+
+ priv->cfg_disconnect = MFALSE;
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return -EFAULT;
+ }
+#endif
+ if (priv->wdev->iftype != NL80211_IFTYPE_STATION
+#ifdef WIFI_DIRECT_SUPPORT
+ && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+
+#endif /* WIFI_DIRECT_SUPPORT */
+ ) {
+ PRINTM(MERROR,
+ "Received infra auth request when interface not in infra mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+
+ ssid_bssid = kzalloc(sizeof(mlan_ssid_bssid), GFP_ATOMIC);
+ if (!ssid_bssid) {
+ PRINTM(MERROR, "Fail to allocate ssid_bssid buffer\n");
+ LEAVE();
+ return -ENOMEM;
+ }
+ moal_memcpy_ext(priv->phandle, ssid_bssid->bssid, req->bss->bssid,
+ ETH_ALEN, sizeof(ssid_bssid->bssid));
+ /* Not allowed to connect to the same AP which is already connected
+ with other interface */
+ for (i = 0; i < handle->priv_num; i++) {
+ if (handle->priv[i] != priv &&
+ MTRUE == woal_is_connected(handle->priv[i], ssid_bssid)) {
+ PRINTM(MMSG,
+ "wlan: already connected with other interface, bssid " MACSTR
+ "\n",
+ MAC2STR(handle->priv[i]->cfg_bssid));
+ kfree(ssid_bssid);
+ LEAVE();
+ return -EINVAL;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS != woal_find_bssid(priv, req->bss->bssid)) {
+ PRINTM(MMSG, "bssid not find in scan list\n");
+ kfree(ssid_bssid);
+ LEAVE();
+ return -EFAULT;
+ }
+ kfree(ssid_bssid);
+
+ if ((priv->auth_alg != WLAN_AUTH_SAE) &&
+ (priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
+ PRINTM(MERROR, "pending auth on going\n");
+ LEAVE();
+ return -EBUSY;
+ }
+
+ /** cancel pending scan */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if bsstype == wifi direct, and iftype == station or p2p
+ * client, that means wpa_supplicant wants to enable wifi direct
+ * functionality, so we should init p2p client.
+ *
+ * Note that due to kernel iftype check, ICS wpa_supplicant
+ * could not updaet iftype to init p2p client, so we have to
+ * done it here.
+ * */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_init_p2p_client(priv)) {
+ PRINTM(MERROR,
+ "Init p2p client for wpa_supplicant failed.\n");
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+ }
+ }
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ /* WAR for P2P connection with vendor TV */
+ woal_sched_timeout(200);
+ }
+#endif
+
+ /*enable auth register frame*/
+ if (priv->auth_flag == 0) {
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MTRUE);
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_DEAUTH, MTRUE);
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_DISASSOC, MTRUE);
+ }
+
+#define HEADER_SIZE 8
+ // frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4
+#define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
+ // 6 = auth_alg + auth_transaction +auth_status
+#define AUTH_BODY_LEN 6
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
+ packet_len = (t_u16)req->ie_len + req->auth_data_len + MGMT_HEADER_LEN +
+ AUTH_BODY_LEN;
+#else
+ packet_len = (t_u16)req->ie_len + req->sae_data_len + MGMT_HEADER_LEN +
+ AUTH_BODY_LEN;
+#endif
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
+ KEY_INDEX_CLEAR_ALL, NULL, 1,
+ MOAL_IOCTL_WAIT)) {
+ /* Disable keys and clear all previous security settings */
+ ret = -EFAULT;
+ goto done;
+ }
+
+ switch (req->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ auth_alg = WLAN_AUTH_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ auth_alg = WLAN_AUTH_SHARED_KEY;
+ break;
+ case NL80211_AUTHTYPE_FT:
+ auth_alg = WLAN_AUTH_FT;
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ auth_alg = WLAN_AUTH_LEAP;
+ break;
+ case NL80211_AUTHTYPE_SAE:
+ auth_alg = WLAN_AUTH_SAE;
+ break;
+ default:
+ PRINTM(MERROR, "Unsupported auth type=%d\n", req->auth_type);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ if (ret)
+ goto done;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_alg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (req->key && ((auth_alg == WLAN_AUTH_OPEN) ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY))) {
+ PRINTM(MMSG, "Setting wep encryption with key len %d\n",
+ req->key_len);
+ /* Set the WEP key */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, req->key, req->key_len,
+ req->key_idx, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Enable the WEP key by key index */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(priv, NULL, 0, req->key_idx,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+#define AUTH_TX_DEFAULT_WAIT_TIME 1200
+ if (priv->auth_flag == 0) {
+ if (woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MFALSE, (t_u8 *)&status,
+ req->bss->channel, 0, AUTH_TX_DEFAULT_WAIT_TIME)) {
+ PRINTM(MERROR, "Fail to configure remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (status == MLAN_STATUS_SUCCESS) {
+ priv->phandle->remain_on_channel = MTRUE;
+ moal_memcpy_ext(priv->phandle, &(priv->phandle->chan),
+ req->bss->channel,
+ sizeof(struct ieee80211_channel),
+ sizeof(priv->phandle->chan));
+ } else {
+ PRINTM(MERROR,
+ "HostMlme %s: Set remain on Channel: with status=%d\n",
+ dev->name, status);
+ }
+ }
+
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ /* Add pkt_type and tx_control */
+ moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
+ &pkt_type, sizeof(pkt_type), sizeof(pkt_type));
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ &tx_control, sizeof(tx_control), sizeof(tx_control));
+
+ mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
+ HEADER_SIZE + sizeof(packet_len));
+ memset(mgmt, 0, MGMT_HEADER_LEN);
+ /**Authentication Frame: Frame Control*/
+ mgmt->frame_control =
+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+ /**Authentication Frame: Destination Address*/
+ moal_memcpy_ext(priv->phandle, mgmt->da, req->bss->bssid, ETH_ALEN,
+ sizeof(mgmt->da));
+ /**Authentication Frame: Source Address*/
+ moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
+ sizeof(mgmt->sa));
+ /**Authentication Frame: BSSID*/
+ moal_memcpy_ext(priv->phandle, mgmt->bssid, req->bss->bssid, ETH_ALEN,
+ sizeof(mgmt->bssid));
+ moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
+ sizeof(mgmt->addr4));
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
+ if (req->auth_data_len >= 4) {
+ if (req->auth_type == NL80211_AUTHTYPE_SAE) {
+ __le16 *pos = (__le16 *)req->auth_data;
+
+ trans = le16_to_cpu(pos[0]);
+ status_code = le16_to_cpu(pos[1]);
+ }
+ moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
+ req->auth_data + 4, req->auth_data_len - 4,
+ req->auth_data_len - 4);
+ varptr = (t_u8 *)&mgmt->u.auth.variable +
+ (req->auth_data_len - 4);
+ packet_len -= 4;
+ }
+#else
+ if (req->sae_data_len >= 4) {
+ if (req->auth_type == NL80211_AUTHTYPE_SAE) {
+ __le16 *pos = (__le16 *)req->sae_data;
+
+ trans = le16_to_cpu(pos[0]);
+ status_code = le16_to_cpu(pos[1]);
+ }
+ moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
+ req->sae_data + 4, req->sae_data_len - 4,
+ req->sae_data_len - 4);
+ varptr = (t_u8 *)&mgmt->u.auth.variable +
+ (req->sae_data_len - 4);
+ packet_len -= 4;
+ }
+#endif
+ /*Add packet len*/
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
+ &packet_len, sizeof(packet_len), sizeof(packet_len));
+
+ /**Authentication Frame: Authentication Alg*/
+ mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
+ mgmt->u.auth.auth_transaction = trans;
+ /**Authentication Frame: Status code*/
+ mgmt->u.auth.status_code = status_code;
+
+ if (req->ie && req->ie_len) {
+ if (!varptr) {
+ varptr = (t_u8 *)&mgmt->u.auth.variable;
+ }
+ moal_memcpy_ext(priv->phandle, (t_u8 *)varptr, req->ie,
+ req->ie_len, req->ie_len);
+ }
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->priority = 7;
+
+ priv->host_mlme = MTRUE;
+ priv->auth_flag = HOST_MLME_AUTH_PENDING;
+ priv->auth_alg = cpu_to_le16(auth_alg);
+
+ PRINTM(MCMND, "wlan: HostMlme %s send auth to bssid " MACSTR "\n",
+ dev->name, MAC2STR(req->bss->bssid));
+ DBG_HEXDUMP(MDAT_D, "Auth:", pmbuf->pbuf + pmbuf->data_offset,
+ pmbuf->data_len);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_save_auth_params(priv, req);
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ priv->auth_alg = 0xFFFF;
+ ret = -EFAULT;
+ break;
+ }
+done:
+ if (ret) {
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
+ if (priv->phandle->remain_on_channel) {
+ woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MTRUE, (t_u8 *)&status,
+ NULL, 0, 0);
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This workqueue function handles association response in host mlme
+ * case
+ *
+ * @param work A pointer to work_struct
+ *
+ * @return N/A
+ */
+void woal_host_mlme_work_queue(struct work_struct *work)
+{
+ moal_handle *handle = container_of(work, moal_handle, host_mlme_work);
+ moal_private *priv = (moal_private *)handle->host_mlme_priv;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ if (priv) {
+ if (priv->auth_flag & HOST_MLME_AUTH_DONE) {
+ priv->auth_flag = 0;
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH,
+ MFALSE);
+
+ if (priv->phandle->remain_on_channel) {
+ woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MTRUE,
+ (t_u8 *)&status, NULL, 0, 0);
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ PRINTM(MCMND, "wlan: HostMlme %s auth success\n",
+ priv->netdev->name);
+ }
+ }
+}
+
+/**
+ * @brief This workqueue function handles association response in event queue
+ * case
+ *
+ * @param priv pointer to moal_private
+ * @param assoc_rsp pointer to mlan_ds_misc_assoc_rsp
+ *
+ * @return N/A
+ */
+void woal_host_mlme_process_assoc_resp(moal_private *priv,
+ mlan_ds_misc_assoc_rsp *assoc_rsp)
+{
+ struct cfg80211_bss *bss = NULL;
+ unsigned long flags;
+
+ if (priv) {
+ if (priv->auth_flag & HOST_MLME_ASSOC_DONE) {
+ priv->auth_flag = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ bss = cfg80211_get_bss(
+ priv->wdev->wiphy, NULL, priv->conn_bssid,
+ priv->conn_ssid, priv->conn_ssid_len,
+ IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
+#else
+ bss = cfg80211_get_bss(
+ priv->wdev->wiphy, NULL, priv->conn_bssid,
+ priv->conn_ssid, priv->conn_ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+#endif
+ if (!bss) {
+ PRINTM(MERROR, "HostMlme %s:Fail to get bss\n",
+ priv->netdev->name);
+ return;
+ }
+
+ if (assoc_rsp->assoc_resp_len) {
+ PRINTM(MCMND,
+ "HostMlme: %s assoc_resp_len=%d, frame_control=0x%x\n",
+ priv->netdev->name,
+ assoc_rsp->assoc_resp_len,
+ ((struct ieee80211_mgmt *)
+ assoc_rsp->assoc_resp_buf)
+ ->frame_control);
+ if (ieee80211_is_assoc_resp(
+ ((struct ieee80211_mgmt *)
+ assoc_rsp->assoc_resp_buf)
+ ->frame_control) ||
+ ieee80211_is_reassoc_resp(
+ ((struct ieee80211_mgmt *)
+ assoc_rsp->assoc_resp_buf)
+ ->frame_control)) {
+ spin_lock_irqsave(&priv->connect_lock,
+ flags);
+ if (le16_to_cpu(
+ ((struct ieee80211_mgmt
+ *)assoc_rsp
+ ->assoc_resp_buf)
+ ->u.assoc_resp
+ .status_code) !=
+ WLAN_STATUS_SUCCESS) {
+ memset(priv->cfg_bssid, 0,
+ ETH_ALEN);
+ if (priv->bss_type ==
+ MLAN_BSS_TYPE_STA)
+ woal_clear_conn_params(
+ priv);
+ }
+ spin_unlock_irqrestore(
+ &priv->connect_lock, flags);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+ cfg80211_rx_assoc_resp(
+ priv->netdev, bss,
+ assoc_rsp->assoc_resp_buf,
+ assoc_rsp->assoc_resp_len, -1,
+ NULL, 0);
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
+ cfg80211_rx_assoc_resp(
+ priv->netdev, bss,
+ assoc_rsp->assoc_resp_buf,
+ assoc_rsp->assoc_resp_len, -1);
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ cfg80211_rx_assoc_resp(
+ priv->netdev, bss,
+ assoc_rsp->assoc_resp_buf,
+ assoc_rsp->assoc_resp_len);
+#else
+ cfg80211_send_rx_assoc(
+ priv->netdev, bss,
+ assoc_rsp->assoc_resp_buf,
+ assoc_rsp->assoc_resp_len);
+#endif
+#endif
+#endif
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+ }
+ }
+}
+
+/**
+ * @brief Handle assoc response event
+ *
+ * @param priv A pointer moal_private structure
+ * @param pchan_info A pointer to mlan_ds_misc_assoc_rsp structure
+ *
+ * @return N/A
+ */
+
+void woal_assoc_resp_event(moal_private *priv,
+ mlan_ds_misc_assoc_rsp *passoc_rsp)
+{
+ struct woal_event *evt;
+ unsigned long flags;
+ moal_handle *handle = priv->phandle;
+
+ evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
+ if (evt) {
+ evt->priv = priv;
+ evt->type = WOAL_EVENT_ASSOC_RESP;
+ moal_memcpy_ext(priv->phandle, &evt->assoc_resp, passoc_rsp,
+ sizeof(mlan_ds_misc_assoc_rsp),
+ sizeof(mlan_ds_misc_assoc_rsp));
+ INIT_LIST_HEAD(&evt->link);
+ spin_lock_irqsave(&handle->evt_lock, flags);
+ list_add_tail(&evt->link, &handle->evt_queue);
+ spin_unlock_irqrestore(&handle->evt_lock, flags);
+ queue_work(handle->evt_workqueue, &handle->evt_work);
+ }
+}
+
+/**
+ * @brief This function is association handler when host MLME
+ * enable.
+ * In this case driver will prepare and send Assoc Req.
+ *
+ * @param wiphy A pointer to wiphy.
+ *
+ * @param dev A pointer to net_device
+ *
+ * @param req A pointer to cfg80211_assoc_request
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_assoc_request *req)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+ mlan_ssid_bssid ssid_bssid;
+ unsigned long flags;
+ const u8 *ssid_ie;
+ int wpa_enabled = 0, group_enc_mode = 0, pairwise_enc_mode = 0;
+ mlan_bss_info bss_info;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (priv->auth_alg == WLAN_AUTH_SAE) {
+ priv->auth_flag = HOST_MLME_AUTH_DONE;
+
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
+ PRINTM(MINFO, "wlan: HostMlme %s auth exchange successful\n",
+ priv->netdev->name);
+
+ if (priv->phandle->remain_on_channel) {
+ if (woal_cfg80211_remain_on_channel_cfg(
+ priv, MOAL_IOCTL_WAIT, MTRUE,
+ (t_u8 *)&status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "Failed to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ }
+
+ if (priv->auth_flag && !(priv->auth_flag & HOST_MLME_AUTH_DONE)) {
+ LEAVE();
+ return -EBUSY;
+ }
+
+ priv->cfg_connect = MTRUE;
+ priv->assoc_status = 0;
+ priv->auth_alg = 0xFFFF;
+
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ ssid_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+ moal_memcpy_ext(priv->phandle, ssid_bssid.bssid, req->bss->bssid,
+ ETH_ALEN, sizeof(ssid_bssid.bssid));
+
+ if (!ssid_ie) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, ssid_ie + 2,
+ ssid_ie[1], sizeof(ssid_bssid.ssid.ssid));
+ ssid_bssid.ssid.ssid_len = ssid_ie[1];
+
+ if (ssid_bssid.ssid.ssid_len > MW_ESSID_MAX_SIZE) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!ssid_bssid.ssid.ssid_len || ssid_bssid.ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
+ switch (req->crypto.wpa_versions) {
+ case NL80211_WPA_VERSION_2:
+ priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2;
+ break;
+ case NL80211_WPA_VERSION_1:
+ priv->wpa_version = IW_AUTH_WPA_VERSION_WPA;
+ break;
+ default:
+ priv->wpa_version = 0;
+ break;
+ }
+ if (req->crypto.n_akm_suites) {
+ switch (req->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_PSK:
+ priv->key_mgmt = IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case WLAN_AKM_SUITE_8021X:
+ priv->key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
+ break;
+ default:
+ priv->key_mgmt = 0;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (req->ie && req->ie_len) { /* Set the IE */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_assoc_ies_cfg(priv, (t_u8 *)req->ie,
+ req->ie_len, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (req->crypto.n_ciphers_pairwise) {
+ pairwise_enc_mode = woal_cfg80211_get_encryption_mode(
+ req->crypto.ciphers_pairwise[0], &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode,
+ wpa_enabled, MOAL_IOCTL_WAIT);
+ if (ret)
+ goto done;
+ }
+
+ if (req->crypto.cipher_group) {
+ group_enc_mode = woal_cfg80211_get_encryption_mode(
+ req->crypto.cipher_group, &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, group_enc_mode, wpa_enabled,
+ MOAL_IOCTL_WAIT);
+ if (ret)
+ goto done;
+ }
+ ssid_bssid.host_mlme = priv->host_mlme;
+
+ if (req->bss->channel) {
+ ssid_bssid.channel_flags = req->bss->channel->flags;
+ ssid_bssid.channel_flags |= CHAN_FLAGS_MAX;
+ PRINTM(MCMND, "channel flags=0x%x\n", req->bss->channel->flags);
+ }
+
+ PRINTM(MCMND, "wlan: HostMlme %s send assoicate to bssid " MACSTR "\n",
+ priv->netdev->name, MAC2STR(req->bss->bssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT_TIMEOUT, &ssid_bssid)) {
+ PRINTM(MERROR, "HostMlme %s: bss_start Fails\n",
+ priv->netdev->name);
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ ret = -EFAULT;
+ }
+
+done:
+
+ if (!ret) {
+ priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
+ if (priv->bss_type == MLAN_BSS_TYPE_STA
+#ifdef WIFI_DIRECT_SUPPORT
+ || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ )
+ woal_save_assoc_params(priv, req, &ssid_bssid);
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ priv->channel = bss_info.bss_chan;
+ }
+
+ spin_lock_irqsave(&priv->connect_lock, flags);
+ priv->cfg_connect = MFALSE;
+ if (!ret && priv->media_connected) {
+ PRINTM(MMSG,
+ "wlan: HostMlme %s Connected to bssid " MACSTR
+ " successfully\n",
+ priv->netdev->name, MAC2STR(priv->cfg_bssid));
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ } else {
+ PRINTM(MERROR,
+ "wlan: HostMlme %s Failed to connect to bssid " MACSTR
+ "\n",
+ priv->netdev->name, MAC2STR(req->bss->bssid));
+ if (ssid_bssid.assoc_rsp.assoc_resp_len &&
+ ssid_bssid.assoc_rsp.assoc_resp_len >
+ sizeof(IEEEtypes_MgmtHdr_t)) {
+ // save the connection param when send assoc_resp to
+ // kernel
+ woal_save_assoc_params(priv, req, &ssid_bssid);
+ ret = 0;
+ } else {
+ ssid_bssid.assoc_rsp.assoc_resp_len = 0;
+ ret = -EFAULT;
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_clear_conn_params(priv);
+ }
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ }
+ /*Association Response should also be send when ret is non-zero.
+ We also need to return success when we have association response
+ available*/
+ if (ssid_bssid.assoc_rsp.assoc_resp_len) {
+ priv->auth_flag |= HOST_MLME_ASSOC_DONE;
+ woal_assoc_resp_event(priv, &ssid_bssid.assoc_rsp);
+ }
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Request the driver for (re)association
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sme A pointer to connect parameters
+ * @param wait_option wait option
+ * @param assoc_resp A pointer to assoc_rsp structure;
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_assoc(moal_private *priv, void *sme, t_u8 wait_option,
+ mlan_ds_misc_assoc_rsp *assoc_rsp)
+{
+ struct cfg80211_ibss_params *ibss_param = NULL;
+ struct cfg80211_connect_params *conn_param = NULL;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ t_u32 auth_type = 0, mode;
+ int wpa_enabled = 0;
+ int group_enc_mode = 0, pairwise_enc_mode = 0;
+ int alg_is_wep = 0;
+
+ t_u8 *ssid, ssid_len = 0, *bssid;
+ t_u8 *ie = NULL;
+ int ie_len = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct cfg80211_chan_def *chan_def = NULL;
+#endif
+ struct ieee80211_channel *channel = NULL;
+ t_u16 beacon_interval = 0;
+ bool privacy;
+ struct cfg80211_bss *bss = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!sme) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ ibss_param = (struct cfg80211_ibss_params *)sme;
+ ssid = (t_u8 *)ibss_param->ssid;
+ ssid_len = ibss_param->ssid_len;
+ bssid = (t_u8 *)ibss_param->bssid;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ channel = ibss_param->channel;
+#else
+ chan_def = &ibss_param->chandef;
+ channel = ibss_param->chandef.chan;
+#endif
+ if (channel)
+ priv->phandle->band = channel->band;
+ if (ibss_param->ie_len)
+ ie = (t_u8 *)ibss_param->ie;
+ ie_len = ibss_param->ie_len;
+ beacon_interval = ibss_param->beacon_interval;
+ privacy = ibss_param->privacy;
+
+ } else {
+ conn_param = (struct cfg80211_connect_params *)sme;
+ ssid = (t_u8 *)conn_param->ssid;
+ ssid_len = conn_param->ssid_len;
+ bssid = (t_u8 *)conn_param->bssid;
+ channel = conn_param->channel;
+ if (channel)
+ priv->phandle->band = channel->band;
+ if (conn_param->ie_len)
+ ie = (t_u8 *)conn_param->ie;
+ ie_len = conn_param->ie_len;
+ privacy = conn_param->privacy;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ bss = cfg80211_get_bss(priv->wdev->wiphy, channel, bssid, ssid,
+ ssid_len, IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
+#else
+ bss = cfg80211_get_bss(priv->wdev->wiphy, channel, bssid, ssid,
+ ssid_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+#endif
+ if (bss) {
+ if ((!priv->phandle->params.reg_alpha2 ||
+ strncmp(priv->phandle->params.reg_alpha2, "99",
+ strlen("99")))
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ && (!moal_extflg_isset(priv->phandle,
+ EXT_COUNTRY_IE_IGNORE))
+#endif
+ )
+ woal_process_country_ie(priv, bss);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+ } else
+ woal_send_domain_info_cmd_fw(priv, wait_option);
+#ifdef STA_WEXT
+ if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
+ switch (conn_param->crypto.wpa_versions) {
+ case NL80211_WPA_VERSION_2:
+ priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2;
+ break;
+ case NL80211_WPA_VERSION_1:
+ priv->wpa_version = IW_AUTH_WPA_VERSION_WPA;
+ break;
+ default:
+ priv->wpa_version = 0;
+ break;
+ }
+ if (conn_param->crypto.n_akm_suites) {
+ switch (conn_param->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_PSK:
+ priv->key_mgmt = IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case WLAN_AKM_SUITE_8021X:
+ priv->key_mgmt =
+ IW_AUTH_KEY_MGMT_802_1X;
+ break;
+ default:
+ priv->key_mgmt = 0;
+ break;
+ }
+ }
+ }
+#endif
+ }
+
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ req_ssid.ssid_len = ssid_len;
+ if (ssid_len > MW_ESSID_MAX_SIZE) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, req_ssid.ssid, ssid, ssid_len,
+ sizeof(req_ssid.ssid));
+ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (priv->phandle->card_info->embedded_supp)
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_ewpa_mode(priv, wait_option, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
+ KEY_INDEX_CLEAR_ALL, NULL, 1, wait_option)) {
+ /* Disable keys and clear all previous security settings */
+ ret = -EFAULT;
+ goto done;
+ }
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
+ /** Check if current roaming support OKC offload roaming */
+ if (conn_param && conn_param->crypto.n_akm_suites &&
+ conn_param->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X) {
+ if (priv->okc_roaming_ie && priv->okc_ie_len) {
+ ie = priv->okc_roaming_ie;
+ ie_len = priv->okc_ie_len;
+ }
+ }
+ }
+#endif
+
+ if ((priv->ft_pre_connect ||
+ (conn_param && conn_param->auth_type == NL80211_AUTHTYPE_FT)) &&
+ priv->ft_ie_len) {
+ ie = priv->ft_ie;
+ ie_len = priv->ft_ie_len;
+ priv->ft_ie_len = 0;
+ }
+ if (ie && ie_len) { /* Set the IE */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len,
+ wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (conn_param && mode != MLAN_BSS_MODE_IBSS) {
+ /* These parameters are only for managed mode */
+ if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+ auth_type = MLAN_AUTH_MODE_OPEN;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ auth_type = MLAN_AUTH_MODE_SHARED;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP)
+ auth_type = MLAN_AUTH_MODE_NETWORKEAP;
+ else if (conn_param->auth_type == NL80211_AUTHTYPE_FT)
+ auth_type = MLAN_AUTH_MODE_FT;
+ else
+ auth_type = MLAN_AUTH_MODE_AUTO;
+ if (priv->ft_pre_connect)
+ auth_type = MLAN_AUTH_MODE_FT;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, wait_option, auth_type)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (conn_param->crypto.n_ciphers_pairwise) {
+ pairwise_enc_mode = woal_cfg80211_get_encryption_mode(
+ conn_param->crypto.ciphers_pairwise[0],
+ &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode,
+ wpa_enabled, wait_option);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->crypto.cipher_group) {
+ group_enc_mode = woal_cfg80211_get_encryption_mode(
+ conn_param->crypto.cipher_group, &wpa_enabled);
+ ret = woal_cfg80211_set_auth(priv, group_enc_mode,
+ wpa_enabled, wait_option);
+ if (ret)
+ goto done;
+ }
+
+ if (conn_param->key) {
+ alg_is_wep =
+ woal_cfg80211_is_alg_wep(pairwise_enc_mode) |
+ woal_cfg80211_is_alg_wep(group_enc_mode);
+ if (alg_is_wep) {
+ PRINTM(MINFO,
+ "Setting wep encryption with key len %d\n",
+ conn_param->key_len);
+ /* Set the WEP key */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(
+ priv, conn_param->key,
+ conn_param->key_len,
+ conn_param->key_idx, wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Enable the WEP key by key index */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_wep_keys(
+ priv, NULL, 0, conn_param->key_idx,
+ wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ mlan_ds_bss *bss = NULL;
+ /* Change beacon interval */
+ if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) ||
+ (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ kfree(req);
+ req = NULL;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
+ bss->param.bcn_interval = beacon_interval;
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* "privacy" is set only for ad-hoc mode */
+ if (privacy) {
+ /*
+ * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that
+ * the firmware can find a matching network from the
+ * scan. cfg80211 does not give us the encryption
+ * mode at this stage so just setting it to wep here
+ */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, wait_option,
+ MLAN_AUTH_MODE_OPEN)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ wpa_enabled = 0;
+ ret = woal_cfg80211_set_auth(
+ priv, MLAN_ENCRYPTION_MODE_WEP104, wpa_enabled,
+ wait_option);
+ if (ret)
+ goto done;
+ }
+ }
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid, &req_ssid,
+ sizeof(mlan_802_11_ssid), sizeof(ssid_bssid.ssid));
+ if (bssid)
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, bssid,
+ ETH_ALEN, sizeof(ssid_bssid.bssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_essid(priv, &ssid_bssid, wait_option)) {
+ /* Do specific SSID scanning */
+ if (mode != MLAN_BSS_MODE_IBSS)
+ ret = woal_cfg80211_connect_scan(priv, conn_param,
+ wait_option);
+ else
+ ret = woal_request_scan(priv, wait_option, &req_ssid);
+ if (ret) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ /* Disconnect before try to associate */
+ if (mode == MLAN_BSS_MODE_IBSS)
+ woal_disconnect(priv, wait_option, NULL,
+ DEF_DEAUTH_REASON_CODE);
+
+ if (mode != MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, wait_option, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Inform the BSS information to kernel, otherwise
+ * kernel will give a panic after successful assoc */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_inform_bss_from_scan_result(priv, &ssid_bssid,
+ wait_option)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, wait_option, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv, wait_option);
+
+ PRINTM(MINFO, "Trying to associate to %s and bssid " MACSTR "\n",
+ (char *)req_ssid.ssid, MAC2STR(ssid_bssid.bssid));
+
+ /* Zero SSID implies use BSSID to connect */
+ if (bssid)
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ else /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+ if (channel) {
+ ssid_bssid.channel_flags = channel->flags;
+ ssid_bssid.channel_flags |= CHAN_FLAGS_MAX;
+ PRINTM(MCMND, "channel flags=0x%x\n", channel->flags);
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT_TIMEOUT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Inform the IBSS information to kernel, otherwise
+ * kernel will give a panic after successful assoc */
+ if (mode == MLAN_BSS_MODE_IBSS) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_inform_ibss_bss(priv, channel,
+ beacon_interval)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (assoc_rsp) {
+ moal_memcpy_ext(priv->phandle, assoc_rsp, &ssid_bssid.assoc_rsp,
+ sizeof(mlan_ds_misc_assoc_rsp),
+ sizeof(mlan_ds_misc_assoc_rsp));
+ PRINTM(MCMND, "assoc_rsp ie len=%d\n",
+ assoc_rsp->assoc_resp_len);
+ }
+done:
+ if (ret) {
+ /* clear the encryption mode */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_set_auth(priv, MLAN_ENCRYPTION_MODE_NONE,
+ MFALSE, wait_option)) {
+ PRINTM(MERROR, "Could not clear encryption \n");
+ ret = -EFAULT;
+ }
+ /* clear IE */
+ ie_len = 0;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len,
+ wait_option)) {
+ PRINTM(MERROR, "Could not clear RSN IE\n");
+ ret = -EFAULT;
+ }
+ }
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to fill the tx/rx rate info
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void woal_cfg80211_fill_rate_info(moal_private *priv,
+ struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_rate *rate = NULL;
+ t_u16 Rates[12] = {0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c};
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ rate = (mlan_ds_rate *)req->pbuf;
+ rate->sub_command = MLAN_OID_GET_DATA_RATE;
+ req->req_id = MLAN_IOCTL_RATE;
+ req->action = MLAN_ACT_GET;
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (rate->param.data_rate.tx_rate_format != MLAN_RATE_FORMAT_LG) {
+ if (rate->param.data_rate.tx_rate_format ==
+ MLAN_RATE_FORMAT_HT) {
+ sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
+ if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->txrate.bw = RATE_INFO_BW_40;
+#else
+ sinfo->txrate.flags |=
+ RATE_INFO_FLAGS_40_MHZ_WIDTH;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ else
+ sinfo->txrate.bw = RATE_INFO_BW_20;
+#endif
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ else if (rate->param.data_rate.tx_rate_format ==
+ MLAN_RATE_FORMAT_VHT) {
+ sinfo->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ sinfo->txrate.nss = rate->param.data_rate.tx_nss + 1;
+ if (rate->param.data_rate.tx_ht_bw == MLAN_VHT_BW80)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->txrate.bw = RATE_INFO_BW_80;
+#else
+ sinfo->txrate.flags |=
+ RATE_INFO_FLAGS_80_MHZ_WIDTH;
+#endif
+ else if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->txrate.bw = RATE_INFO_BW_40;
+#else
+ sinfo->txrate.flags |=
+ RATE_INFO_FLAGS_40_MHZ_WIDTH;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ else
+ sinfo->txrate.bw = RATE_INFO_BW_20;
+#endif
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 18)
+ else if (rate->param.data_rate.tx_rate_format ==
+ MLAN_RATE_FORMAT_HE) {
+ sinfo->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
+ sinfo->txrate.nss = rate->param.data_rate.tx_nss + 1;
+ sinfo->txrate.mcs = rate->param.data_rate.tx_mcs_index;
+ sinfo->txrate.he_gi = rate->param.data_rate.tx_ht_gi;
+ if (rate->param.data_rate.tx_ht_bw == MLAN_VHT_BW80)
+ sinfo->txrate.bw = RATE_INFO_BW_80;
+ else if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
+ sinfo->txrate.bw = RATE_INFO_BW_40;
+ else
+ sinfo->txrate.bw = RATE_INFO_BW_20;
+ }
+#endif
+ if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI)
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ sinfo->txrate.mcs = rate->param.data_rate.tx_mcs_index;
+ } else {
+ /* Bit rate is in 500 kb/s units. Convert it to 100kb/s units */
+ sinfo->txrate.legacy =
+ Rates[rate->param.data_rate.tx_data_rate] * 5;
+ }
+ // Fill Rx rate
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ if (rate->param.data_rate.rx_rate_format != MLAN_RATE_FORMAT_LG) {
+ if (rate->param.data_rate.rx_rate_format ==
+ MLAN_RATE_FORMAT_HT) {
+ sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS;
+ if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
+ sinfo->rxrate.bw = RATE_INFO_BW_40;
+ else
+ sinfo->rxrate.bw = RATE_INFO_BW_20;
+ } else if (rate->param.data_rate.rx_rate_format ==
+ MLAN_RATE_FORMAT_VHT) {
+ sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ sinfo->rxrate.nss = rate->param.data_rate.rx_nss + 1;
+ if (rate->param.data_rate.rx_ht_bw == MLAN_VHT_BW80)
+ sinfo->rxrate.bw = RATE_INFO_BW_80;
+ else if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
+ sinfo->rxrate.bw = RATE_INFO_BW_40;
+ else
+ sinfo->rxrate.bw = RATE_INFO_BW_20;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 18)
+ else if (rate->param.data_rate.rx_rate_format ==
+ MLAN_RATE_FORMAT_HE) {
+ sinfo->rxrate.flags = RATE_INFO_FLAGS_HE_MCS;
+ sinfo->rxrate.nss = rate->param.data_rate.rx_nss + 1;
+ sinfo->rxrate.mcs = rate->param.data_rate.rx_mcs_index;
+ sinfo->rxrate.he_gi = rate->param.data_rate.rx_ht_gi;
+ if (rate->param.data_rate.rx_ht_bw == MLAN_VHT_BW80)
+ sinfo->rxrate.bw = RATE_INFO_BW_80;
+ else if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
+ sinfo->rxrate.bw = RATE_INFO_BW_40;
+ else
+ sinfo->rxrate.bw = RATE_INFO_BW_20;
+ }
+#endif
+ if (rate->param.data_rate.rx_ht_gi == MLAN_HT_SGI)
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ sinfo->rxrate.mcs = rate->param.data_rate.rx_mcs_index;
+ } else {
+ /* Bit rate is in 500 kb/s units. Convert it to 100kb/s units */
+ sinfo->rxrate.legacy =
+ Rates[rate->param.data_rate.rx_data_rate] * 5;
+ }
+#endif
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return;
+}
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
+ struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_signal signal;
+ mlan_ds_get_stats stats;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ mlan_bss_info bss_info;
+ t_u8 dtim_period = 0;
+#endif
+
+ ENTER();
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->filled = MBIT(NL80211_STA_INFO_RX_BYTES) |
+ MBIT(NL80211_STA_INFO_TX_BYTES) |
+ MBIT(NL80211_STA_INFO_RX_PACKETS) |
+ MBIT(NL80211_STA_INFO_TX_PACKETS) |
+ MBIT(NL80211_STA_INFO_SIGNAL) |
+ MBIT(NL80211_STA_INFO_TX_BITRATE) |
+ MBIT(NL80211_STA_INFO_RX_BITRATE);
+#else
+ sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
+ STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->filled |= MBIT(NL80211_STA_INFO_TX_FAILED);
+#else
+ sinfo->filled |= STATION_INFO_TX_FAILED;
+#endif
+#endif
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Get stats information from the firmware */
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ PRINTM(MERROR, "Error getting stats information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ sinfo->rx_bytes = priv->stats.rx_bytes;
+ sinfo->tx_bytes = priv->stats.tx_bytes;
+ sinfo->rx_packets = priv->stats.rx_packets;
+ sinfo->tx_packets = priv->stats.tx_packets;
+ sinfo->signal = signal.bcn_rssi_avg;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ sinfo->tx_failed = stats.failed;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ /* Update BSS information */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->filled |= MBIT(NL80211_STA_INFO_BSS_PARAM);
+#else
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
+#endif
+ sinfo->bss_param.flags = 0;
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (ret)
+ goto done;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+ sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
+ /* Get DTIM period */
+ ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
+ &dtim_period);
+ if (ret) {
+ PRINTM(MERROR, "Get DTIM period failed\n");
+ goto done;
+ }
+ sinfo->bss_param.dtim_period = dtim_period;
+#endif
+ woal_cfg80211_fill_rate_info(priv, sinfo);
+done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+/**
+ * @brief Set all radar channel's dfs_state
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return N/A
+ */
+void woal_update_radar_chans_dfs_state(struct wiphy *wiphy)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ int i;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ sband = wiphy->bands[band];
+ if (!sband)
+ continue;
+ for (i = 0; i < sband->n_channels; i++) {
+ if (sband->channels[i].flags & IEEE80211_CHAN_RADAR) {
+ if (moal_extflg_isset(handle, EXT_DFS_OFFLOAD))
+ sband->channels[i].dfs_state =
+ NL80211_DFS_AVAILABLE;
+ else
+ sband->channels[i].dfs_state =
+ NL80211_DFS_USABLE;
+ }
+ }
+ }
+ PRINTM(MCMND, "Set radar dfs_state: dfs_offload=%d\n",
+ moal_extflg_isset(handle, EXT_DFS_OFFLOAD));
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+
+/**
+ * @brief This function will be used by sort, to compare LHS & RHS
+ *
+ * @param lhs LHS value
+ * @param rhs RHS value
+ * @return 0
+ */
+static int compare(const void *lhs, const void *rhs)
+{
+ const chan_freq_power_t *lhs_cfp = (const chan_freq_power_t *)(lhs);
+ const chan_freq_power_t *rhs_cfp = (const chan_freq_power_t *)(rhs);
+
+ if (lhs_cfp->channel < rhs_cfp->channel)
+ return -1;
+ if (lhs_cfp->channel > rhs_cfp->channel)
+ return 1;
+
+ return 0;
+}
+/**
+ * @brief This function update channel region config
+ *
+ * @param buf Buffer containing channel region config
+ * @param num_chan Length of buffer
+ * @param regd ieee80211_regdomain to be updated
+ *
+ * @return N/A
+ */
+static struct ieee80211_regdomain *
+create_custom_regdomain(mlan_ds_custom_reg_domain *custom_reg)
+{
+ struct ieee80211_reg_rule *rule;
+ bool new_rule;
+ int idx, freq, prev_freq = 0;
+ t_u8 chan;
+ t_u16 num_chan = 0;
+ t_u32 bw, prev_bw = 0;
+ t_u16 chflags, prev_chflags = 0, valid_rules = 0;
+ struct ieee80211_regdomain *regd = NULL;
+ int regd_size;
+ const struct ieee80211_freq_range *freq_range = NULL;
+
+ num_chan = custom_reg->num_bg_chan;
+ num_chan += custom_reg->num_a_chan;
+
+ sort(&custom_reg->cfp_tbl[custom_reg->num_bg_chan],
+ custom_reg->num_a_chan, sizeof(chan_freq_power_t), &compare, NULL);
+
+ regd_size = sizeof(struct ieee80211_regdomain) +
+ num_chan * sizeof(struct ieee80211_reg_rule);
+
+ regd = kzalloc(regd_size, GFP_KERNEL);
+ if (!regd) {
+ return NULL;
+ }
+#define NXP_CHANNEL_TMP_NOHT40 MBIT(15)
+ /* preprocess 2.4G 40MHz support */
+ for (idx = 0; idx < num_chan; idx++) {
+ chan = custom_reg->cfp_tbl[idx].channel;
+ if (!chan) {
+ if (regd)
+ kfree(regd);
+ return NULL;
+ }
+
+ if (chan > 14)
+ continue;
+
+ chflags = custom_reg->cfp_tbl[idx].dynamic.flags;
+
+ if (chflags & NXP_CHANNEL_DISABLED)
+ continue;
+
+ /* duplicate a temp flag */
+ if (chflags & NXP_CHANNEL_NOHT40)
+ chflags |= NXP_CHANNEL_TMP_NOHT40;
+ }
+ for (idx = 0; idx < num_chan; idx++) {
+ chan = custom_reg->cfp_tbl[idx].channel;
+ if (!chan) {
+ if (regd)
+ kfree(regd);
+ return NULL;
+ }
+
+ if (chan > 14)
+ continue;
+
+ chflags = custom_reg->cfp_tbl[idx].dynamic.flags;
+
+ if (chflags & NXP_CHANNEL_DISABLED)
+ continue;
+
+ /* 40 MHz band of one center channel will spread to upper and
+ * lower 2 channels */
+ /* Mark HT40 flag for all channels of this 40 MHz band */
+ if (!(chflags & NXP_CHANNEL_TMP_NOHT40)) {
+ if (idx >= 2)
+ custom_reg->cfp_tbl[idx - 2].dynamic.flags &=
+ ~NXP_CHANNEL_NOHT40;
+ if (idx >= 1)
+ custom_reg->cfp_tbl[idx - 1].dynamic.flags &=
+ ~NXP_CHANNEL_NOHT40;
+ if (idx < (num_chan - 1))
+ custom_reg->cfp_tbl[idx + 1].dynamic.flags &=
+ ~NXP_CHANNEL_NOHT40;
+ if (idx < (num_chan - 2))
+ custom_reg->cfp_tbl[idx + 2].dynamic.flags &=
+ ~NXP_CHANNEL_NOHT40;
+ } else {
+ custom_reg->cfp_tbl[idx].dynamic.flags &=
+ ~NXP_CHANNEL_TMP_NOHT40;
+ }
+ }
+ for (idx = 0; idx < num_chan; idx++) {
+ enum ieee80211_band band;
+
+ chan = custom_reg->cfp_tbl[idx].channel;
+ if (!chan) {
+ if (regd)
+ kfree(regd);
+ return NULL;
+ }
+ chflags = custom_reg->cfp_tbl[idx].dynamic.flags;
+ band = (chan <= 14) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(chan, band);
+ PRINTM(MINFO, "chan=%d freq=%d chan_flag=0x%x\n", chan, freq,
+ chflags);
+ new_rule = false;
+
+ if (chflags & NXP_CHANNEL_DISABLED)
+ continue;
+
+ if (band == IEEE80211_BAND_5GHZ) {
+ if (!(chflags & NXP_CHANNEL_NOHT80))
+ bw = MHZ_TO_KHZ(80);
+ else if (!(chflags & NXP_CHANNEL_NOHT40))
+ bw = MHZ_TO_KHZ(40);
+ else
+ bw = MHZ_TO_KHZ(20);
+ } else {
+ if (!(chflags & NXP_CHANNEL_NOHT40))
+ bw = MHZ_TO_KHZ(40);
+ else
+ bw = MHZ_TO_KHZ(20);
+ }
+
+ if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
+ freq - prev_freq > 20) {
+ valid_rules++;
+ new_rule = true;
+ }
+
+ rule = &regd->reg_rules[valid_rules - 1];
+
+ rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
+
+ prev_chflags = chflags;
+ prev_freq = freq;
+ prev_bw = bw;
+
+ if (!new_rule)
+ continue;
+
+ rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
+ rule->power_rule.max_eirp = DBM_TO_MBM(19);
+ rule->flags = 0;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (chflags & NXP_CHANNEL_PASSIVE)
+ rule->flags |= NL80211_RRF_NO_IR;
+#endif
+ if (chflags & NXP_CHANNEL_DFS)
+ rule->flags |= NL80211_RRF_DFS;
+ if (chflags & NXP_CHANNEL_NO_OFDM)
+ rule->flags |= NL80211_RRF_NO_OFDM;
+ rule->freq_range.max_bandwidth_khz = bw;
+ }
+
+ regd->n_reg_rules = valid_rules;
+
+ if (custom_reg->region.country_code[0] == 'W' &&
+ custom_reg->region.country_code[1] == 'W') {
+ regd->alpha2[0] = '0';
+ regd->alpha2[1] = '0';
+ } else {
+ /* set alpha2 from FW. */
+ regd->alpha2[0] = custom_reg->region.country_code[0];
+ regd->alpha2[1] = custom_reg->region.country_code[1];
+ }
+ PRINTM(MCMND, "create_custom_regdomain: %c%c rules=%d\n",
+ regd->alpha2[0], regd->alpha2[1], valid_rules);
+ for (idx = 0; idx < regd->n_reg_rules; idx++) {
+ rule = &regd->reg_rules[idx];
+ freq_range = &rule->freq_range;
+ PRINTM(MCMND,
+ "flags=0x%x star_freq=%d end_freq=%d freq_diff=%d max_bandwidth=%d\n",
+ rule->flags, freq_range->start_freq_khz,
+ freq_range->end_freq_khz,
+ freq_range->end_freq_khz - freq_range->start_freq_khz,
+ freq_range->max_bandwidth_khz);
+ }
+ return regd;
+}
+
+/**
+ * @brief create custom channel regulatory config
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return 0-success, otherwise failure
+ */
+static int woal_update_custom_regdomain(moal_private *priv, struct wiphy *wiphy)
+{
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+
+ int ret = 0;
+ struct ieee80211_regdomain *regd = NULL;
+
+ ENTER();
+
+ if (!priv || !wiphy) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -EFAULT;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GET_CHAN_REGION_CFG;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+ memset(&misc->param.custom_reg_domain, 0,
+ sizeof(misc->param.custom_reg_domain));
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(country_code, 0, sizeof(country_code));
+ if (MTRUE ==
+ is_cfg80211_special_region_code(priv->phandle->country_code)) {
+ country_code[0] = 'W';
+ country_code[1] = 'W';
+ } else {
+ country_code[0] = priv->phandle->country_code[0];
+ country_code[1] = priv->phandle->country_code[1];
+ }
+ if (misc->param.custom_reg_domain.region.country_code[0] !=
+ country_code[0] ||
+ misc->param.custom_reg_domain.region.country_code[1] !=
+ country_code[1]) {
+ PRINTM(MERROR, "country code %c%c not match %c%c\n",
+ misc->param.custom_reg_domain.region.country_code[0],
+ misc->param.custom_reg_domain.region.country_code[1],
+ country_code[0], country_code[1]);
+ ret = -EFAULT;
+ goto done;
+ }
+ regd = create_custom_regdomain(&misc->param.custom_reg_domain);
+ if (regd) {
+ PRINTM(MMSG, "call regulatory_set_wiphy_regd %c%c",
+ misc->param.custom_reg_domain.region.country_code[0],
+ misc->param.custom_reg_domain.region.country_code[1]);
+ wiphy->regulatory_flags &=
+ ~(REGULATORY_STRICT_REG | REGULATORY_CUSTOM_REG);
+ wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
+ regulatory_set_wiphy_regd(wiphy, regd);
+ kfree(regd);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Request the driver to change regulatory domain
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param request A pointer to regulatory_request structure
+ *
+ * @return 0
+ */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+static void
+#else
+static int
+#endif
+woal_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ t_u8 region[COUNTRY_CODE_LEN];
+ enum ieee80211_band band;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+ int ret = 0;
+#endif
+ mlan_fw_info fw_info;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
+ LEAVE();
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+ return -EINVAL;
+#else
+ return;
+#endif
+ }
+
+ PRINTM(MCMND,
+ "cfg80211 regulatory domain callback "
+ "%c%c initiator=%d\n",
+ request->alpha2[0], request->alpha2[1], request->initiator);
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if (fw_info.force_reg) {
+ PRINTM(MINFO,
+ "Regulatory domain is enforced in the on-chip OTP\n");
+ LEAVE();
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+ return -EINVAL;
+#else
+ return;
+#endif
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(handle, EXT_DFS_OFFLOAD))
+ woal_update_radar_chans_dfs_state(wiphy);
+#endif
+ memset(region, 0, sizeof(region));
+ moal_memcpy_ext(priv->phandle, region, request->alpha2,
+ sizeof(request->alpha2), sizeof(region));
+ region[2] = ' ';
+ if ((handle->country_code[0] != request->alpha2[0]) ||
+ (handle->country_code[1] != request->alpha2[1])) {
+ if (moal_extflg_isset(handle, EXT_CNTRY_TXPWR)) {
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ handle->country_code[0] = request->alpha2[0];
+ handle->country_code[1] = request->alpha2[1];
+ handle->country_code[2] = ' ';
+ memset(country_code, 0, sizeof(country_code));
+ if (MTRUE == is_cfg80211_special_region_code(region)) {
+ country_code[0] = 'W';
+ country_code[1] = 'W';
+ } else {
+ country_code[0] = request->alpha2[0];
+ country_code[1] = request->alpha2[1];
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_country_power_table(priv,
+ country_code)) {
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+ return -EFAULT;
+#else
+ return;
+#endif
+ }
+ }
+ }
+ if (MTRUE != is_cfg80211_special_region_code(region)) {
+ if (!moal_extflg_isset(handle, EXT_CNTRY_TXPWR)) {
+ handle->country_code[0] = request->alpha2[0];
+ handle->country_code[1] = request->alpha2[1];
+ handle->country_code[2] = ' ';
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_region_code(priv, handle->country_code))
+ PRINTM(MERROR, "Set country code failed!\n");
+ }
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ PRINTM(MCMND, "Regulatory domain BY_DRIVER\n");
+ break;
+ case NL80211_REGDOM_SET_BY_CORE:
+ PRINTM(MCMND, "Regulatory domain BY_CORE\n");
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ PRINTM(MCMND, "Regulatory domain BY_USER\n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ if (fw_region && moal_extflg_isset(handle, EXT_CNTRY_TXPWR))
+ woal_update_custom_regdomain(priv, wiphy);
+#endif
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ PRINTM(MCMND, "Regulatory domain BY_COUNTRY_IE\n");
+ break;
+ }
+ if (priv->wdev && priv->wdev->wiphy &&
+ (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) &&
+ (MTRUE != is_cfg80211_special_region_code(region))) {
+ band = priv->phandle->band;
+ priv->phandle->band = IEEE80211_BAND_2GHZ;
+ woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
+ priv->phandle->band = IEEE80211_BAND_5GHZ;
+ woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
+ priv->phandle->band = band;
+ }
+
+ LEAVE();
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
+ return ret;
+#endif
+}
+
+#ifdef UAP_CFG80211
+/**
+ * @brief Swithces BSS role of interface
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT)
+ * @param bss_role bss role
+ *
+ * @return 0 --success, otherwise fail
+ */
+mlan_status woal_role_switch(moal_private *priv, t_u8 wait_option,
+ t_u8 bss_role)
+{
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_ROLE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->param.bss_role = bss_role;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set/get bandcfg
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action get or set action
+ * @param band_cfg A pointer to mlan_ds_band_cfg structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_setget_bandcfg(moal_private *priv, t_u8 action,
+ mlan_ds_band_cfg *band_cfg)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_radio_cfg *radio_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
+ radio_cfg->sub_command = MLAN_OID_BAND_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = action;
+
+ if (req->action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &radio_cfg->param.band_cfg,
+ band_cfg, sizeof(mlan_ds_band_cfg),
+ sizeof(radio_cfg->param.band_cfg));
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto error;
+ }
+ moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
+ sizeof(mlan_ds_band_cfg), sizeof(mlan_ds_band_cfg));
+error:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief request scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param scan_cfg A pointer to wlan_user_scan_cfg structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_uap_scan(moal_private *priv, wlan_user_scan_cfg *scan_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_handle *handle = priv->phandle;
+ moal_private *tmp_priv;
+ u8 role;
+ mlan_ds_band_cfg org_bandcfg;
+ mlan_ds_band_cfg bandcfg;
+ u8 band_change = MFALSE;
+ ENTER();
+ if (priv->bss_index > 0)
+ tmp_priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ else
+ tmp_priv = priv;
+ if (!tmp_priv) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ role = GET_BSS_ROLE(tmp_priv);
+ if (role == MLAN_BSS_ROLE_UAP)
+ woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT, MLAN_BSS_ROLE_STA);
+ if (tmp_priv != priv) {
+ woal_setget_bandcfg(priv, MLAN_ACT_GET, &bandcfg);
+ woal_setget_bandcfg(tmp_priv, MLAN_ACT_GET, &org_bandcfg);
+ if (bandcfg.config_bands != org_bandcfg.config_bands) {
+ woal_setget_bandcfg(tmp_priv, MLAN_ACT_SET, &bandcfg);
+ band_change = MTRUE;
+ }
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
+ goto done;
+ }
+#endif /* REASSOCIATION */
+ tmp_priv->report_scan_result = MTRUE;
+ ret = woal_request_userscan(tmp_priv, MOAL_IOCTL_WAIT, scan_cfg);
+ woal_sched_timeout(5);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+done:
+ if (role == MLAN_BSS_ROLE_UAP)
+ woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT, MLAN_BSS_ROLE_UAP);
+ if (band_change)
+ woal_setget_bandcfg(tmp_priv, MLAN_ACT_SET, &org_bandcfg);
+ LEAVE();
+ return ret;
+}
+#endif
+
+static int woal_find_wps_ie_in_probereq(const t_u8 *ie, int len)
+{
+ int left_len = len;
+ const t_u8 *pos = ie;
+ t_u8 ie_id, ie_len;
+ IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
+ const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
+
+ while (left_len >= 2) {
+ ie_id = *pos;
+ ie_len = *(pos + 1);
+ if ((ie_len + 2) > left_len)
+ break;
+ if (ie_id == VENDOR_SPECIFIC_221) {
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wps_oui[3])
+ return MTRUE;
+ }
+
+ pos += (ie_len + 2);
+ left_len -= (ie_len + 2);
+ }
+
+ return MFALSE;
+}
+
+/**
+ * @brief check if the scan result expired
+ *
+ * @param priv A pointer to moal_private
+ *
+ *
+ * @return MTRUE/MFALSE;
+ */
+t_u8 woal_is_scan_result_expired(moal_private *priv)
+{
+ mlan_scan_resp scan_resp;
+ wifi_timeval t;
+ ENTER();
+ // Don't block ACS scan
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return MTRUE;
+ }
+ // Don't block scan when non any interface active
+ if (!woal_is_any_interface_active(priv->phandle)) {
+ LEAVE();
+ return MTRUE;
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ // Do not skip p2p interface connect scan
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ LEAVE();
+ return MTRUE;
+ }
+#endif
+#endif
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ LEAVE();
+ return MTRUE;
+ }
+ woal_get_monotonic_time(&t);
+/** scan result expired value */
+#define SCAN_RESULT_EXPIRTED 1
+ if (t.time_sec > (scan_resp.age_in_secs + SCAN_RESULT_EXPIRTED)) {
+ LEAVE();
+ return MTRUE;
+ }
+ LEAVE();
+ return MFALSE;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+/**
+ * @brief Request the driver to do a scan. Always returning
+ * zero meaning that the scan request is given to driver,
+ * and will be valid until passed to cfg80211_scan_done().
+ * To inform scan results, call cfg80211_inform_bss().
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param request A pointer to cfg80211_scan_request structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_scan(struct wiphy *wiphy,
+ struct cfg80211_scan_request *request)
+#else
+/**
+ * @brief Request the driver to do a scan. Always returning
+ * zero meaning that the scan request is given to driver,
+ * and will be valid until passed to cfg80211_scan_done().
+ * To inform scan results, call cfg80211_inform_bss().
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param request A pointer to cfg80211_scan_request structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+#endif
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct net_device *dev = request->wdev->netdev;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ wlan_user_scan_cfg *scan_req = NULL;
+ mlan_bss_info bss_info;
+ mlan_scan_cfg scan_cfg;
+ struct ieee80211_channel *chan;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ t_u8 buf[ETH_ALEN];
+#endif
+ int ret = 0, i;
+ unsigned long flags;
+
+ ENTER();
+
+ PRINTM(MINFO, "Received scan request on %s\n", dev->name);
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ PRINTM(MCMND, "scan already in processing...\n");
+ LEAVE();
+ return -EAGAIN;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (priv->last_event & EVENT_BG_SCAN_REPORT) {
+ PRINTM(MCMND, "block scan while pending BGSCAN result\n");
+ priv->last_event = 0;
+ LEAVE();
+ return -EAGAIN;
+ }
+#endif
+#if defined(STA_CFG80211) || defined(UAP_CFG80211)
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->phandle->is_go_timer_set &&
+ priv->wdev->iftype != NL80211_IFTYPE_P2P_GO) {
+ PRINTM(MCMND, "block scan in go timer....\n");
+ LEAVE();
+ return -EAGAIN;
+ }
+#endif
+#endif
+#endif
+ if (priv->fake_scan_complete || !woal_is_scan_result_expired(priv)) {
+ PRINTM(MEVENT,
+ "scan result not expired or fake scan complete flag is on\n");
+ return -EAGAIN;
+ }
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ if (bss_info.scan_block) {
+ PRINTM(MEVENT, "Block scan in mlan module\n");
+ return -EAGAIN;
+ }
+ }
+ if (priv->phandle->scan_request &&
+ priv->phandle->scan_request != request) {
+ PRINTM(MCMND,
+ "different scan_request is coming before previous one is finished on %s...\n",
+ dev->name);
+ LEAVE();
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
+ priv->phandle->scan_request = request;
+ spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
+ if (is_zero_timeval(priv->phandle->scan_time_start)) {
+ woal_get_monotonic_time(&priv->phandle->scan_time_start);
+ PRINTM(MINFO, "%s : start_timeval=%d:%d \n", __func__,
+ priv->phandle->scan_time_start.time_sec,
+ priv->phandle->scan_time_start.time_usec);
+ }
+ scan_req = kmalloc(sizeof(wlan_user_scan_cfg), GFP_KERNEL);
+ memset(scan_req, 0x00, sizeof(wlan_user_scan_cfg));
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
+ if (!is_broadcast_ether_addr(request->bssid)) {
+ moal_memcpy_ext(priv->phandle, scan_req->specific_bssid,
+ request->bssid, ETH_ALEN,
+ sizeof(scan_req->specific_bssid));
+ PRINTM(MIOCTL, "scan: bssid=" MACSTR "\n",
+ MAC2STR(scan_req->specific_bssid));
+ }
+#endif
+
+ if (priv->phandle->scan_request->n_channels <= 38)
+ scan_req->ext_scan_type = EXT_SCAN_ENHANCE;
+
+ memset(&scan_cfg, 0, sizeof(mlan_scan_cfg));
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->phandle->miracast_mode)
+ scan_req->scan_chan_gap = priv->phandle->scan_chan_gap;
+ else {
+#endif
+ woal_get_scan_config(priv, &scan_cfg);
+ if (scan_cfg.scan_chan_gap)
+ scan_req->scan_chan_gap = scan_cfg.scan_chan_gap;
+ else if (woal_is_any_interface_active(priv->phandle))
+ scan_req->scan_chan_gap = priv->phandle->scan_chan_gap;
+ else
+ scan_req->scan_chan_gap = 0;
+#ifdef WIFI_DIRECT_SUPPORT
+ }
+#endif
+ /** indicate FW, gap is optional */
+ if (scan_req->scan_chan_gap && priv->phandle->pref_mac)
+ scan_req->scan_chan_gap |= GAP_FLAG_OPTIONAL;
+
+ for (i = 0; i < priv->phandle->scan_request->n_ssids; i++) {
+ moal_memcpy_ext(priv->phandle, scan_req->ssid_list[i].ssid,
+ priv->phandle->scan_request->ssids[i].ssid,
+ priv->phandle->scan_request->ssids[i].ssid_len,
+ sizeof(scan_req->ssid_list[i].ssid));
+ if (priv->phandle->scan_request->ssids[i].ssid_len)
+ scan_req->ssid_list[i].max_len = 0;
+ else
+ scan_req->ssid_list[i].max_len = 0xff;
+ PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req->ssid_list[i].ssid);
+ }
+#if defined(WIFI_DIRECT_SUPPORT)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ priv->phandle->scan_request->n_ssids) {
+ if (!memcmp(scan_req->ssid_list[0].ssid, "DIRECT-", 7))
+ scan_req->ssid_list[0].max_len = 0xfe;
+ }
+#endif
+#endif
+ for (i = 0; i < MIN(WLAN_USER_SCAN_CHAN_MAX,
+ priv->phandle->scan_request->n_channels);
+ i++) {
+ chan = priv->phandle->scan_request->channels[i];
+ scan_req->chan_list[i].chan_number = chan->hw_value;
+ scan_req->chan_list[i].radio_type = chan->band;
+ if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) ||
+ !priv->phandle->scan_request->n_ssids)
+ scan_req->chan_list[i].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE;
+ else if (chan->flags & IEEE80211_CHAN_RADAR)
+ scan_req->chan_list[i].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
+ else
+ scan_req->chan_list[i].scan_type =
+ MLAN_SCAN_TYPE_ACTIVE;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ scan_req->chan_list[i].scan_time =
+ priv->phandle->scan_request->duration;
+#else
+ scan_req->chan_list[i].scan_time = 0;
+#endif
+#if defined(WIFI_DIRECT_SUPPORT)
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ priv->phandle->scan_request->n_ssids) {
+ if (!memcmp(scan_req->ssid_list[0].ssid, "DIRECT-", 7))
+ scan_req->chan_list[i].scan_time =
+ MIN_SPECIFIC_SCAN_CHAN_TIME;
+ }
+#endif
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->phandle->miracast_mode)
+ scan_req->chan_list[i].scan_time =
+ priv->phandle->miracast_scan_time;
+ else if (woal_is_any_interface_active(priv->phandle)) {
+ if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ scan_req->chan_list[i].scan_time =
+ INIT_PASSIVE_SCAN_CHAN_TIME;
+ else
+ scan_req->chan_list[i].scan_time =
+ MIN_SPECIFIC_SCAN_CHAN_TIME;
+ }
+#endif
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
+ scan_req->chan_list[i].scan_time =
+ MIN_SPECIFIC_SCAN_CHAN_TIME;
+#endif
+ }
+ if (priv->phandle->scan_request->ie &&
+ priv->phandle->scan_request->ie_len) {
+ if (woal_find_wps_ie_in_probereq(
+ (t_u8 *)priv->phandle->scan_request->ie,
+ priv->phandle->scan_request->ie_len)) {
+ PRINTM(MIOCTL,
+ "Notify firmware only keep probe response\n");
+ scan_req->proberesp_only = MTRUE;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(
+ priv, NULL, 0, NULL, 0, NULL, 0,
+ (t_u8 *)priv->phandle->scan_request->ie,
+ priv->phandle->scan_request->ie_len,
+ MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Fail to set scan request IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /** Clear SCAN IE in Firmware */
+ if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ,
+ MOAL_IOCTL_WAIT);
+ }
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /** use sync scan for uap */
+ ret = woal_uap_scan(priv, scan_req);
+ if (!ret) {
+ kfree(scan_req);
+ LEAVE();
+ return ret;
+ } else {
+ PRINTM(MERROR, "Uap SCAN failure\n");
+ goto done;
+ }
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ PRINTM(MIOCTL, "NL80211_SCAN_FLAG_RANDOM_ADDR is set\n");
+ get_random_bytes(buf, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++) {
+ buf[i] &= ~request->mac_addr_mask[i];
+ buf[i] |= request->mac_addr[i] &
+ request->mac_addr_mask[i];
+ }
+ moal_memcpy_ext(priv->phandle, scan_req->random_mac, buf,
+ ETH_ALEN, sizeof(scan_req->random_mac));
+ } else
+#endif
+ moal_memcpy_ext(priv->phandle, scan_req->random_mac,
+ priv->random_mac, ETH_ALEN,
+ sizeof(scan_req->random_mac));
+
+ PRINTM(MCMND, "wlan:random_mac " MACSTR "\n",
+ MAC2STR(scan_req->random_mac));
+ if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, scan_req)) {
+ PRINTM(MERROR, "woal_do_scan fails!\n");
+ ret = -EAGAIN;
+ goto done;
+ }
+done:
+ if (ret) {
+ spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
+ woal_cfg80211_scan_done(request, MTRUE);
+ priv->phandle->scan_request = NULL;
+ priv->phandle->scan_priv = NULL;
+ spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
+ } else
+ PRINTM(MMSG, "wlan: %s START SCAN\n", dev->name);
+ kfree(scan_req);
+ LEAVE();
+ return ret;
+}
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+static void woal_cfg80211_abort_scan(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
+ ENTER();
+ PRINTM(MMSG, "wlan: ABORT SCAN start\n");
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return;
+}
+#endif
+/**
+ * @brief construct and send ft action request
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ie A pointer to ft ie
+ * @param le Value of ie len
+ * @param bssid A pointer to target ap bssid
+ * @
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_send_ft_action_requst(moal_private *priv, t_u8 *ie, t_u8 len,
+ t_u8 *bssid, t_u8 *target_ap)
+{
+ IEEE80211_MGMT *mgmt = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = NULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+ t_u16 packet_len = 0;
+ t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ int ret = 0;
+
+ ENTER();
+
+ /* pkt_type + tx_control */
+#define HEADER_SIZE 8
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4*/
+#define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
+ /* 14 = category + action + sta addr + target ap */
+#define FT_REQUEST_LEN 14
+ packet_len = (t_u16)len + MGMT_HEADER_LEN + FT_REQUEST_LEN;
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ /* Add pkt_type and tx_control */
+ moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
+ &pkt_type, sizeof(pkt_type), sizeof(pkt_type));
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ &tx_control, sizeof(tx_control), sizeof(tx_control));
+ /*Add packet len*/
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
+ &packet_len, sizeof(packet_len), sizeof(packet_len));
+
+ mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
+ HEADER_SIZE + sizeof(packet_len));
+ memset(mgmt, 0, MGMT_HEADER_LEN);
+ mgmt->frame_control =
+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
+ moal_memcpy_ext(priv->phandle, mgmt->da, bssid, ETH_ALEN,
+ sizeof(mgmt->da));
+ moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
+ sizeof(mgmt->sa));
+ moal_memcpy_ext(priv->phandle, mgmt->bssid, bssid, ETH_ALEN,
+ sizeof(mgmt->bssid));
+ moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
+ sizeof(mgmt->addr4));
+
+ mgmt->u.ft_req.category = 0x06; /**ft action code 0x6*/
+ mgmt->u.ft_req.action = 0x1; /**ft action request*/
+ moal_memcpy_ext(priv->phandle, mgmt->u.ft_req.sta_addr,
+ priv->current_addr, ETH_ALEN,
+ sizeof(mgmt->u.ft_req.sta_addr));
+ moal_memcpy_ext(priv->phandle, mgmt->u.ft_req.target_ap_addr, target_ap,
+ ETH_ALEN, sizeof(mgmt->u.ft_req.target_ap_addr));
+
+ if (ie && len)
+ moal_memcpy_ext(priv->phandle,
+ (t_u8 *)(&mgmt->u.ft_req.variable), ie, len,
+ len);
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->priority = 7;
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief construct and send ft auth request
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ie A pointer to ft ie
+ * @param le Value of ie len
+ * @param bssid A pointer to target ap bssid
+ * @
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_send_ft_auth_requst(moal_private *priv, t_u8 *ie, t_u8 len,
+ t_u8 *bssid)
+{
+ IEEE80211_MGMT *mgmt = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ pmlan_buffer pmbuf = NULL;
+ t_u32 pkt_type;
+ t_u32 tx_control;
+ t_u16 packet_len = 0;
+ t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ int ret = 0;
+
+ ENTER();
+ /* pkt_type + tx_control */
+#define HEADER_SIZE 8
+ /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4*/
+#define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
+ /* 6 = auth_alg + auth_transaction +auth_status*/
+#define AUTH_BODY_LEN 6
+ packet_len = (t_u16)len + MGMT_HEADER_LEN + AUTH_BODY_LEN;
+ pmbuf = woal_alloc_mlan_buffer(priv->phandle,
+ MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
+ packet_len + sizeof(packet_len));
+ if (!pmbuf) {
+ PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
+ pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
+ tx_control = 0;
+ /* Add pkt_type and tx_control */
+ moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
+ &pkt_type, sizeof(pkt_type), sizeof(pkt_type));
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
+ &tx_control, sizeof(tx_control), sizeof(tx_control));
+ /*Add packet len*/
+ moal_memcpy_ext(priv->phandle,
+ pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
+ &packet_len, sizeof(packet_len), sizeof(packet_len));
+
+ mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
+ HEADER_SIZE + sizeof(packet_len));
+ memset(mgmt, 0, MGMT_HEADER_LEN);
+ mgmt->frame_control =
+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+ moal_memcpy_ext(priv->phandle, mgmt->da, bssid, ETH_ALEN,
+ sizeof(mgmt->da));
+ moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
+ sizeof(mgmt->sa));
+ moal_memcpy_ext(priv->phandle, mgmt->bssid, bssid, ETH_ALEN,
+ sizeof(mgmt->bssid));
+ moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
+ sizeof(mgmt->addr4));
+
+ mgmt->u.auth.auth_alg = cpu_to_le16(WLAN_AUTH_FT);
+ mgmt->u.auth.auth_transaction = cpu_to_le16(1);
+ mgmt->u.auth.status_code = cpu_to_le16(0);
+ if (ie && len)
+ moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
+ ie, len, len);
+
+ pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
+ pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
+ pmbuf->bss_index = priv->bss_index;
+ pmbuf->priority = 7;
+
+ status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
+
+ switch (status) {
+ case MLAN_STATUS_PENDING:
+ atomic_inc(&priv->phandle->tx_pending);
+ queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
+ break;
+ case MLAN_STATUS_SUCCESS:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ break;
+ case MLAN_STATUS_FAILURE:
+ default:
+ woal_free_mlan_buffer(priv->phandle, pmbuf);
+ ret = -EFAULT;
+ break;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief connect the AP through ft over air.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param bssid A pointer to bssid
+ * @param chan struct ieee80211_channel
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_connect_ft_over_air(moal_private *priv, t_u8 *bssid,
+ struct ieee80211_channel *chan)
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ t_u8 status = 0;
+#endif
+
+ t_u8 wait_option = MOAL_IOCTL_WAIT;
+ int ret = 0;
+ long timeout = 0;
+
+ ENTER();
+
+ if (!bssid) {
+ PRINTM(MERROR,
+ "Invalid bssid, unable to connect AP to through FT\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /*enable auth register frame*/
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MTRUE);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+#define AUTH_TX_DEFAULT_WAIT_TIME 1200
+ woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE, &status,
+ chan, 0, AUTH_TX_DEFAULT_WAIT_TIME);
+#endif
+
+ /*construct auth request and send out*/
+ woal_send_ft_auth_requst(priv, priv->ft_ie, priv->ft_ie_len, bssid);
+ PRINTM(MMSG, "wlan: send out FT auth,wait for auth response\n");
+ /*wait until received auth response*/
+ priv->ft_wait_condition = MFALSE;
+ timeout = wait_event_timeout(priv->ft_wait_q, priv->ft_wait_condition,
+ 1 * HZ);
+ if (!timeout) {
+ /*connet fail */
+ if (!priv->ft_roaming_triggered_by_driver) {
+ woal_inform_bss_from_scan_result(priv, NULL,
+ wait_option);
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_SUCCESS,
+ GFP_KERNEL);
+ }
+ priv->ft_roaming_triggered_by_driver = MFALSE;
+ PRINTM(MMSG, "wlan: keep connected to bssid " MACSTR "\n",
+ MAC2STR(priv->cfg_bssid));
+ } else {
+ PRINTM(MMSG, "wlan: FT auth received \n");
+ moal_memcpy_ext(priv->phandle, priv->target_ap_bssid, bssid,
+ ETH_ALEN, sizeof(priv->target_ap_bssid));
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE, &status,
+ NULL, 0, 0);
+#endif
+
+ woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief connect the AP through ft over DS.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param bssid A pointer to bssid
+ * @param chan struct ieee80211_channel
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_connect_ft_over_ds(moal_private *priv, t_u8 *bssid,
+ struct ieee80211_channel *pchan)
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ t_u8 status = 0;
+#endif
+ t_u8 wait_option = MOAL_IOCTL_WAIT;
+ int ret = 0;
+ long timeout = 0;
+
+ ENTER();
+
+ if (priv->media_connected) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE,
+ &status, pchan, 0, 1200);
+#endif
+ /*construct ft action request and send out*/
+ woal_send_ft_action_requst(priv, priv->ft_ie, priv->ft_ie_len,
+ (t_u8 *)priv->cfg_bssid, bssid);
+ PRINTM(MMSG,
+ "wlan: send out FT request,wait for FT response\n");
+ /*wait until received auth response*/
+ priv->ft_wait_condition = MFALSE;
+ timeout = wait_event_timeout(priv->ft_wait_q,
+ priv->ft_wait_condition, 1 * HZ);
+ if (!timeout) {
+ /*go over air, as current AP may be unreachable */
+ PRINTM(MMSG, "wlan: go over air\n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ woal_cfg80211_remain_on_channel_cfg(
+ priv, wait_option, MTRUE, &status, NULL, 0, 0);
+#endif
+ woal_connect_ft_over_air(priv, bssid, pchan);
+ LEAVE();
+ return ret;
+ } else {
+ PRINTM(MMSG, "wlan: received FT response\n");
+ moal_memcpy_ext(priv->phandle, priv->target_ap_bssid,
+ bssid, ETH_ALEN,
+ sizeof(priv->target_ap_bssid));
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE,
+ &status, NULL, 0, 0);
+#endif
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief start FT Roaming.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ssid_bssid A pointer to mlan_ssid_bssid structure
+ *
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_start_ft_roaming(moal_private *priv,
+ mlan_ssid_bssid *ssid_bssid)
+{
+ struct ieee80211_channel chan;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MEVENT, "Try to start FT roaming......\n");
+ chan.band = (ssid_bssid->channel < 36) ? IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ;
+ chan.center_freq = ieee80211_channel_to_frequency(ssid_bssid->channel
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ ,
+ chan.band
+#endif
+ );
+
+ if (!(priv->last_event & EVENT_PRE_BCN_LOST) &&
+ (ssid_bssid->ft_cap & MBIT(0))) {
+ woal_connect_ft_over_ds(priv, (t_u8 *)&ssid_bssid->bssid,
+ &chan);
+ } else {
+ /*if pre beacon lost, it need to send auth request instead ft
+ * action request when ft over ds */
+ woal_connect_ft_over_air(priv, (t_u8 *)&ssid_bssid->bssid,
+ &chan);
+ }
+
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Request the driver to connect to the ESS with
+ * the specified parameters from kernel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param sme A pointer to cfg80211_connect_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+ mlan_bss_info bss_info;
+ unsigned long flags;
+ mlan_ds_misc_assoc_rsp *assoc_rsp = NULL;
+ IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
+ mlan_ssid_bssid ssid_bssid;
+ moal_handle *handle = priv->phandle;
+ int i;
+
+ ENTER();
+
+ PRINTM(MINFO, "Received association request on %s\n", dev->name);
+ priv->cfg_disconnect = MFALSE;
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return 0;
+ }
+#endif
+ if (priv->wdev->iftype != NL80211_IFTYPE_STATION
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+#endif /* KERNEL_VERSION */
+#endif /* WIFI_DIRECT_SUPPORT */
+ ) {
+ PRINTM(MERROR,
+ "Received infra assoc request when station not in infra mode\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ memset(&ssid_bssid, 0, sizeof(ssid_bssid));
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid.ssid, sme->ssid,
+ sme->ssid_len, sizeof(ssid_bssid.ssid.ssid));
+ ssid_bssid.ssid.ssid_len = sme->ssid_len;
+ if (sme->bssid)
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, sme->bssid,
+ ETH_ALEN, sizeof(ssid_bssid.bssid));
+ /* Not allowed to connect to the same AP which is already connected
+ with other interface */
+ for (i = 0; i < handle->priv_num; i++) {
+ if (handle->priv[i] != priv &&
+ MTRUE == woal_is_connected(handle->priv[i], &ssid_bssid)) {
+ PRINTM(MMSG,
+ "wlan: already connected with other interface, bssid " MACSTR
+ "\n",
+ MAC2STR(handle->priv[i]->cfg_bssid));
+ LEAVE();
+ return -EINVAL;
+ }
+ }
+
+ /** cancel pending scan */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
+ (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ /* if bsstype == wifi direct, and iftype == station or p2p
+ * client, that means wpa_supplicant wants to enable wifi direct
+ * functionality, so we should init p2p client.
+ *
+ * Note that due to kernel iftype check, ICS wpa_supplicant
+ * could not updaet iftype to init p2p client, so we have to
+ * done it here.
+ * */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_init_p2p_client(priv)) {
+ PRINTM(MERROR,
+ "Init p2p client for wpa_supplicant failed.\n");
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+ }
+ }
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ /* WAR for P2P connection with vendor TV */
+ woal_sched_timeout(200);
+ }
+#endif
+#endif
+ /*11r roaming triggered by supplicant */
+ if (priv->media_connected && priv->ft_ie_len &&
+ !(priv->ft_cap & MBIT(0))) {
+ /** get current bss info */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ /** get target bss info */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_essid(priv, &ssid_bssid, MOAL_IOCTL_WAIT)) {
+ ret = woal_cfg80211_connect_scan(priv, sme,
+ MOAL_IOCTL_WAIT);
+ if (!ret) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv,
+ MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR,
+ "can't find targe AP \n");
+ // LEAVE();
+ // return -EFAULT;
+ }
+ }
+ }
+ if (bss_info.mdid == ssid_bssid.ft_md &&
+ bss_info.ft_cap == ssid_bssid.ft_cap) {
+ ret = woal_start_ft_roaming(priv, &ssid_bssid);
+ LEAVE();
+ return 0;
+ }
+ }
+
+ priv->cfg_connect = MTRUE;
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ priv->assoc_status = 0;
+ assoc_rsp = kzalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_ATOMIC);
+ if (!assoc_rsp) {
+ PRINTM(MERROR, "Failed to allocate memory for assoc_rsp\n");
+ ret = -ENOMEM;
+ LEAVE();
+ return ret;
+ }
+ ret = woal_cfg80211_assoc(priv, (void *)sme, MOAL_IOCTL_WAIT,
+ assoc_rsp);
+
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+ if (!ret) {
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp->assoc_resp_buf;
+ priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_save_conn_params(priv, sme);
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ priv->channel = bss_info.bss_chan;
+ if (!ssid_bssid.ft_md) {
+ priv->ft_ie_len = 0;
+ priv->ft_pre_connect = MFALSE;
+ priv->ft_md = 0;
+ priv->ft_cap = 0;
+ }
+ }
+ spin_lock_irqsave(&priv->connect_lock, flags);
+ priv->cfg_connect = MFALSE;
+ if (!ret && priv->media_connected) {
+ PRINTM(MMSG,
+ "wlan: Connected to bssid " MACSTR " successfully\n",
+ MAC2STR(priv->cfg_bssid));
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ passoc_rsp->ie_buffer,
+ assoc_rsp->assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
+ } else {
+ PRINTM(MINFO, "wlan: Failed to connect to bssid " MACSTR "\n",
+ MAC2STR(priv->cfg_bssid));
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ spin_unlock_irqrestore(&priv->connect_lock, flags);
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
+ NULL, 0, woal_get_assoc_status(priv),
+ GFP_KERNEL);
+ }
+
+ kfree(assoc_rsp);
+ assoc_rsp = NULL;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function will print diconnect reason code according
+ * to IEEE 802.11 spec
+ *
+ * @param reason_code reason code for the deauth/disaccoc
+ * received from firmware
+ * @return N/A
+ */
+static void woal_print_disconnect_reason(t_u16 reason_code)
+{
+ ENTER();
+
+ switch (reason_code) {
+ case MLAN_REASON_UNSPECIFIED:
+ PRINTM(MMSG, "wlan: REASON: Unspecified reason\n");
+ break;
+ case MLAN_REASON_PREV_AUTH_NOT_VALID:
+ PRINTM(MMSG,
+ "wlan: REASON: Previous authentication no longer valid\n");
+ break;
+ case MLAN_REASON_DEAUTH_LEAVING:
+ PRINTM(MMSG,
+ "wlan: REASON: (Deauth) Sending STA is leaving (or has left) IBSS or ESS\n");
+ break;
+ case MLAN_REASON_DISASSOC_DUE_TO_INACTIVITY:
+ PRINTM(MMSG,
+ "wlan: REASON: Disassociated due to inactivity \n");
+ break;
+ case MLAN_REASON_DISASSOC_AP_BUSY:
+ PRINTM(MMSG,
+ "wlan: REASON: (Disassociated) AP unable to handle all connected STAs\n");
+ break;
+ case MLAN_REASON_CLASS2_FRAME_FROM_NOAUTH_STA:
+ PRINTM(MMSG,
+ "wlan: REASON: Class 2 frame was received from nonauthenticated STA\n");
+ break;
+ case MLAN_REASON_CLASS3_FRAME_FROM_NOASSOC_STA:
+ PRINTM(MMSG,
+ "wlan: REASON: Class 3 frame was received from nonassociated STA\n");
+ break;
+ case MLAN_REASON_DISASSOC_STA_HAS_LEFT:
+ PRINTM(MMSG,
+ "wlan: REASON: (Disassocated) Sending STA is leaving (or has left) BSS\n");
+ break;
+ case MLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
+ PRINTM(MMSG,
+ "wlan: REASON: STA requesting (re)assoc is not authenticated with responding STA\n");
+ break;
+ default:
+ break;
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Request the driver to disconnect
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param reason_code Reason code
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ t_u16 reason_code)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+ PRINTM(MMSG,
+ "wlan: Received disassociation request on %s, reason: %u\n",
+ dev->name, reason_code);
+ woal_print_disconnect_reason(reason_code);
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return 0;
+ }
+#endif
+ if (priv->phandle->driver_status) {
+ PRINTM(MERROR,
+ "Block woal_cfg80211_disconnect in abnormal driver state\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (priv->cfg_disconnect) {
+ PRINTM(MERROR, "Disassociation already in progress\n");
+ LEAVE();
+ return 0;
+ }
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MMSG, " Already disconnected\n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ if (priv->wdev->current_bss &&
+ (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ priv->cfg_disconnect = MTRUE;
+ cfg80211_disconnected(priv->netdev, 0, NULL, 0,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ true,
+#endif
+ GFP_KERNEL);
+ }
+#endif
+ LEAVE();
+ return 0;
+ }
+
+ priv->cfg_disconnect = MTRUE;
+ if (woal_disconnect(priv, MOAL_IOCTL_WAIT_TIMEOUT, priv->cfg_bssid,
+ reason_code) != MLAN_STATUS_SUCCESS) {
+ priv->cfg_disconnect = MFALSE;
+ LEAVE();
+ return -EFAULT;
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ if (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
+ cfg80211_disconnected(priv->netdev, 0, NULL, 0,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ true,
+#endif
+ GFP_KERNEL);
+#endif
+
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ if (priv->bss_type == MLAN_BSS_TYPE_STA)
+ woal_clear_conn_params(priv);
+ priv->channel = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function is deauthentication handler when host MLME
+ * enable.
+ * In this case driver will prepare and send Deauth Req.
+ *
+ * @param wiphy A pointer to wiphy.
+ *
+ * @param dev A pointer to net_device
+ *
+ * @param req A pointer to cfg80211_deauth_request
+ *
+ * @return 0 -- success, otherwise fail
+ */
+
+static int woal_cfg80211_deauthenticate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_deauth_request *req)
+{
+ int ret = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (priv->host_mlme) {
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ priv->auth_alg = 0xFFFF;
+ /*send deauth packet to notify disconnection to wpa_supplicant
+ */
+ woal_deauth_event(priv, req->reason_code);
+ }
+#endif
+
+ ret = woal_cfg80211_disconnect(wiphy, dev, req->reason_code);
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
+ if (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
+ cfg80211_disconnected(priv->netdev, 0, NULL, 0, GFP_KERNEL);
+#endif
+ return ret;
+}
+
+/**
+ * @brief This function is disassociation handler when host MLME
+ * enable.
+ * In this case driver will prepare and send Disassoc frame.
+ *
+ * @param wiphy A pointer to wiphy.
+ *
+ * @param dev A pointer to net_device
+ *
+ * @param req A pointer to cfg80211_disassoc_request
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_disassociate(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_disassoc_request *req)
+{
+ int ret = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ if (priv->host_mlme) {
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ priv->auth_alg = 0xFFFF;
+ /*send deauth packet to notify disconnection to wpa_supplicant
+ */
+ woal_deauth_event(priv, req->reason_code);
+ }
+#endif
+
+ ret = woal_cfg80211_disconnect(wiphy, dev, req->reason_code);
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
+ if (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
+ priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
+ cfg80211_disconnected(priv->netdev, 0, NULL, 0, GFP_KERNEL);
+#endif
+ return ret;
+}
+
+/**
+ * @brief Request the driver to get the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo);
+ }
+#endif
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param idx Station index
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_dump_station(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ t_u8 *mac, struct station_info *sinfo)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return woal_uap_cfg80211_dump_station(wiphy, dev, idx, mac,
+ sinfo);
+ }
+#endif
+
+ if (!priv->media_connected || idx != 0) {
+ PRINTM(MINFO,
+ "cfg80211: Media not connected or not for this station!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ moal_memcpy_ext(priv->phandle, mac, priv->cfg_bssid, ETH_ALEN,
+ ETH_ALEN);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_dump_station_info(priv, sinfo)) {
+ PRINTM(MERROR, "cfg80211: Failed to get station info\n");
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Convert driver band configuration to IEEE band type
+ *
+ * @param band Driver band configuration
+ *
+ * @return IEEE band type
+ */
+t_u8 woal_bandcfg_to_ieee_band(Band_Config_t bandcfg)
+{
+ t_u8 ret_radio_type = 0;
+
+ ENTER();
+
+ switch (bandcfg.chanBand) {
+ case BAND_5GHZ:
+ ret_radio_type = IEEE80211_BAND_5GHZ;
+ break;
+ case BAND_2GHZ:
+ default:
+ ret_radio_type = IEEE80211_BAND_2GHZ;
+ break;
+ }
+ LEAVE();
+ return ret_radio_type;
+}
+
+/**
+ * @brief Request the driver to dump survey info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param idx Station index
+ * @param survey A pointer to survey_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_dump_survey(struct wiphy *wiphy,
+ struct net_device *dev, int idx,
+ struct survey_info *survey)
+{
+ int ret = -ENOENT;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ enum ieee80211_band band;
+ ChanStatistics_t *pchan_stats = NULL;
+ mlan_scan_resp scan_resp;
+
+ ENTER();
+ PRINTM(MIOCTL, "dump_survey idx=%d\n", idx);
+
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ pchan_stats = (ChanStatistics_t *)scan_resp.pchan_stats;
+ if (idx > scan_resp.num_in_chan_stats || idx < 0) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (idx == scan_resp.num_in_chan_stats ||
+ !pchan_stats[idx].cca_scan_duration)
+ goto done;
+ ret = 0;
+ memset(survey, 0, sizeof(*survey));
+ band = woal_bandcfg_to_ieee_band(pchan_stats[idx].bandcfg);
+ survey->channel = ieee80211_get_channel(
+ wiphy, ieee80211_channel_to_frequency(pchan_stats[idx].chan_num
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ ,
+ band
+#endif
+ ));
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = pchan_stats[idx].noise;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
+ survey->time = pchan_stats[idx].cca_scan_duration;
+ survey->time_busy = pchan_stats[idx].cca_busy_duration;
+#else
+ survey->filled |=
+ SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+ survey->channel_time = pchan_stats[idx].cca_scan_duration;
+ survey->channel_time_busy = pchan_stats[idx].cca_busy_duration;
+#endif
+#endif
+done:
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+static int woal_cfg80211_get_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
+ chan_band_info channel;
+
+ memset(&channel, 0x00, sizeof(channel));
+
+#ifdef UAP_SUPPORT
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ if (priv->bss_started == MTRUE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_ap_channel(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &channel)) {
+ PRINTM(MERROR, "Fail to get ap channel \n");
+ return -EFAULT;
+ }
+ } else {
+ PRINTM(MIOCTL, "get_channel when AP is not started\n");
+ return -EFAULT;
+ }
+ } else
+#endif
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (priv->media_connected == MTRUE) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_sta_channel(priv, MOAL_IOCTL_WAIT,
+ &channel)) {
+ PRINTM(MERROR, "Fail to get sta channel \n");
+ return -EFAULT;
+ }
+ } else {
+ PRINTM(MIOCTL,
+ "get_channel when STA is not connected\n");
+ return -EFAULT;
+ }
+ } else {
+ PRINTM(MERROR, "BssRole not support %d.\n", GET_BSS_ROLE(priv));
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_FAILURE == woal_chandef_create(priv, chandef, &channel))
+ return -EFAULT;
+ else
+ return 0;
+}
+#endif
+
+/**
+ * @brief Request the driver to change the IEEE power save
+ * mdoe
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param enabled Enable or disable
+ * @param timeout Timeout value
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ int timeout)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+ if (moal_extflg_isset(priv->phandle, EXT_HW_TEST) ||
+ (priv->phandle->params.ps_mode == MLAN_INIT_PARA_DISABLED)) {
+ PRINTM(MIOCTL, "block set power hw_test=%d ps_mode=%d\n",
+ moal_extflg_isset(priv->phandle, EXT_HW_TEST),
+ priv->phandle->params.ps_mode);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (priv->phandle->driver_status) {
+ PRINTM(MERROR,
+ "Block woal_cfg80211_set_power_mgmt in abnormal driver state\n");
+ LEAVE();
+ return -EFAULT;
+ }
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
+ PRINTM(MIOCTL, "skip set power for p2p interface\n");
+ LEAVE();
+ return ret;
+ }
+#endif
+#endif
+ if (enabled)
+ disabled = 0;
+ else
+ disabled = 1;
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_SET,
+ &disabled, timeout,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+/**
+ * @brief Request the driver to get the transmit power info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param type TX power adjustment type
+ * @param dbm TX power in dbm
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_get_tx_power(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct wireless_dev *wdev,
+#endif
+ int *dbm)
+{
+ int ret = 0;
+ moal_private *priv = NULL;
+ mlan_power_cfg_t power_cfg;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+
+ ENTER();
+
+ if (!handle) {
+ PRINTM(MFATAL, "Unable to get handle\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+ *dbm = power_cfg.power_level;
+
+ LEAVE();
+ return ret;
+}
+/**
+ * @brief Request the driver to change the transmit power
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param type TX power adjustment type
+ * @param dbm TX power in dbm
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct wireless_dev *wdev,
+#endif
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ enum tx_power_setting type,
+#else
+ enum nl80211_tx_power_setting type,
+#endif
+ int dbm)
+{
+ int ret = 0;
+ moal_private *priv = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+
+ priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (type) {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = dbm;
+ } else
+ power_cfg.is_power_auto = 1;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg))
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
+/**
+ * CFG802.11 operation handler for connection quality monitoring.
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param rssi_thold rssi threshold
+ * @param rssi_hyst rssi hysteresis
+ */
+static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ ENTER();
+ priv->cqm_rssi_thold = rssi_thold;
+ priv->cqm_rssi_high_thold = rssi_thold;
+ priv->cqm_rssi_hyst = rssi_hyst;
+
+ PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n", (int)rssi_thold,
+ (int)rssi_hyst);
+ woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+/**
+ * @brief remain on channel config
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param cancel cancel remain on channel flag
+ * @param status A pointer to status, success, in process or reject
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type channel_type,
+ * @param duration Duration wait to receive frame
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_remain_on_channel_cfg(moal_private *priv, t_u8 wait_option,
+ t_u8 remove, t_u8 *status,
+ struct ieee80211_channel *chan,
+ enum mlan_channel_type channel_type,
+ t_u32 duration)
+{
+ mlan_ds_remain_chan chan_cfg;
+ int ret = 0;
+
+ ENTER();
+
+ if (!status || (!chan && !remove)) {
+ PRINTM(MERROR,
+ "Invalid parameter status=%p, chan=%p, remove=%d\n",
+ status, chan, remove);
+ LEAVE();
+ return -EFAULT;
+ }
+ memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan));
+ if (remove) {
+ chan_cfg.remove = MTRUE;
+ } else {
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->phandle->is_go_timer_set) {
+ PRINTM(MINFO,
+ "block remain on channel while go timer is on\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ chan_cfg.bandcfg.chanBand = BAND_2GHZ;
+ else if (chan->band == IEEE80211_BAND_5GHZ)
+ chan_cfg.bandcfg.chanBand = BAND_5GHZ;
+ switch (channel_type) {
+ case CHAN_HT40MINUS:
+ chan_cfg.bandcfg.chan2Offset = SEC_CHAN_BELOW;
+ chan_cfg.bandcfg.chanWidth = CHAN_BW_40MHZ;
+ break;
+ case CHAN_HT40PLUS:
+ chan_cfg.bandcfg.chan2Offset = SEC_CHAN_ABOVE;
+ chan_cfg.bandcfg.chanWidth = CHAN_BW_40MHZ;
+ break;
+ case CHAN_VHT80:
+ chan_cfg.bandcfg.chanWidth = CHAN_BW_80MHZ;
+ break;
+ case CHAN_NO_HT:
+ case CHAN_HT20:
+ default:
+ break;
+ }
+ chan_cfg.channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cfg.remain_period = duration;
+ PRINTM(MCMND,
+ "Remain on Channel: chan=%d, offset=%d width=%d\n",
+ chan_cfg.channel, chan_cfg.bandcfg.chan2Offset,
+ chan_cfg.bandcfg.chanWidth);
+ }
+ if (MLAN_STATUS_SUCCESS ==
+ woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg))
+ *status = chan_cfg.status;
+ else
+ ret = -EFAULT;
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+#else
+/**
+ * @brief tx mgmt frame
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to frame cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct net_device *dev, u64 cookie)
+#endif
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct net_device *dev = wdev->netdev;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+ t_u8 status = 1;
+ moal_private *remain_priv = NULL;
+
+ ENTER();
+
+ if (priv->phandle->remain_on_channel) {
+ remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (!remain_priv) {
+ PRINTM(MERROR,
+ "mgmt_tx_cancel_wait: Wrong remain_bss_index=%d\n",
+ priv->phandle->remain_bss_index);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(remain_priv,
+ MOAL_IOCTL_WAIT, MTRUE,
+ &status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "mgmt_tx_cancel_wait: Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie, &priv->phandle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+/**
+ * @brief Make chip remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type
+ * @param duration Duration for timer
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct ieee80211_channel *chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ enum nl80211_channel_type channel_type,
+#endif
+ unsigned int duration, u64 *cookie)
+#else
+/**
+ * @brief Make chip remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chan A pointer to ieee80211_channel structure
+ * @param channel_type Channel type
+ * @param duration Duration for timer
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int
+woal_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 *cookie)
+#endif
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct net_device *dev = wdev->netdev;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+ t_u8 status = 1;
+ moal_private *remain_priv = NULL;
+
+ ENTER();
+
+ if (!chan || !cookie) {
+ PRINTM(MERROR, "Invalid parameter for remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /** cancel previous remain on channel */
+ if (priv->phandle->remain_on_channel &&
+ ((priv->phandle->chan.center_freq != chan->center_freq))) {
+ remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (!remain_priv) {
+ PRINTM(MERROR,
+ "remain_on_channel: Wrong remain_bss_index=%d\n",
+ priv->phandle->remain_bss_index);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(remain_priv,
+ MOAL_IOCTL_WAIT, MTRUE,
+ &status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "remain_on_channel: Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->phandle->cookie = 0;
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MFALSE,
+ &status, chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ channel_type,
+#else
+ 0,
+#endif
+ (t_u32)duration)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (status) {
+ PRINTM(MMSG,
+ "%s: Set remain on Channel: channel=%d with status=%d\n",
+ dev->name,
+ ieee80211_frequency_to_channel(chan->center_freq),
+ status);
+ if (!priv->phandle->remain_on_channel) {
+ priv->phandle->is_remain_timer_set = MTRUE;
+ woal_mod_timer(&priv->phandle->remain_timer, duration);
+ }
+ }
+
+ /* remain on channel operation success */
+ /* we need update the value cookie */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ *cookie = (u64)random32() | 1;
+#else
+ *cookie = (u64)prandom_u32() | 1;
+#endif
+ priv->phandle->remain_on_channel = MTRUE;
+ priv->phandle->remain_bss_index = priv->bss_index;
+ priv->phandle->cookie = *cookie;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type = channel_type;
+#endif
+ moal_memcpy_ext(priv->phandle, &priv->phandle->chan, chan,
+ sizeof(struct ieee80211_channel),
+ sizeof(priv->phandle->chan));
+
+ if (status == 0)
+ PRINTM(MIOCTL,
+ "%s: Set remain on Channel: channel=%d cookie = %#llx\n",
+ dev->name,
+ ieee80211_frequency_to_channel(chan->center_freq),
+ priv->phandle->cookie);
+
+ cfg80211_ready_on_channel(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ dev,
+#else
+ priv->wdev,
+#endif
+ *cookie, chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ channel_type,
+#endif
+ duration, GFP_KERNEL);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+/**
+ * @brief Cancel remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev A pointer to wireless_dev structure
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+#else
+/**
+ * @brief Cancel remain on channel
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param cookie A pointer to timer cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie)
+#endif
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct net_device *dev = wdev->netdev;
+#endif
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ moal_private *remain_priv = NULL;
+ int ret = 0;
+ t_u8 status = 1;
+
+ ENTER();
+ PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
+ remain_priv = priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (!remain_priv) {
+ PRINTM(MERROR,
+ "cancel_remain_on_channel: Wrong remain_bss_index=%d\n",
+ priv->phandle->remain_bss_index);
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_cfg80211_remain_on_channel_cfg(remain_priv, MOAL_IOCTL_WAIT,
+ MTRUE, &status, NULL, 0, 0)) {
+ PRINTM(MERROR,
+ "cancel_remain_on_channel: Fail to cancel remain on channel\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ priv->phandle->remain_on_channel = MFALSE;
+ if (priv->phandle->cookie)
+ priv->phandle->cookie = 0;
+done:
+ LEAVE();
+ return ret;
+}
+#endif /* KERNEL_VERSION */
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+/**
+ * @brief start sched scan
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param request A pointer to struct cfg80211_sched_scan_request
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+ struct ieee80211_channel *chan = NULL;
+ int i = 0;
+ int ret = 0;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ struct cfg80211_ssid *ssid = NULL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ t_u8 buf[ETH_ALEN];
+#endif
+ ENTER();
+
+#ifdef UAP_CFG80211
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ LEAVE();
+ return -EFAULT;
+ }
+#endif
+
+ memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
+ if (!request) {
+ PRINTM(MERROR, "Invalid sched_scan req parameter\n");
+ LEAVE();
+ return -EINVAL;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
+ PRINTM(MIOCTL,
+ "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d ie_len=%d\n",
+ priv->netdev->name, request->n_ssids, request->n_match_sets,
+ request->n_channels, request->scan_plans[0].interval,
+ (int)request->ie_len);
+#else
+ PRINTM(MIOCTL,
+ "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d ie_len=%d\n",
+ priv->netdev->name, request->n_ssids, request->n_match_sets,
+ request->n_channels, request->interval, (int)request->ie_len);
+#endif
+ /** We have pending scan, start bgscan later */
+ if (priv->phandle->scan_pending_on_block)
+ priv->scan_cfg.start_later = MTRUE;
+ for (i = 0; i < request->n_match_sets; i++) {
+ ssid = &request->match_sets[i].ssid;
+ strncpy(priv->scan_cfg.ssid_list[i].ssid, ssid->ssid,
+ ssid->ssid_len);
+ priv->scan_cfg.ssid_list[i].max_len = 0;
+ PRINTM(MIOCTL, "sched scan: ssid=%s\n", ssid->ssid);
+ }
+ /** Add broadcast scan, when n_match_sets = 0 */
+ if (!request->n_match_sets)
+ priv->scan_cfg.ssid_list[0].max_len = 0xff;
+ for (i = 0; i < MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels); i++) {
+ chan = request->channels[i];
+ priv->scan_cfg.chan_list[i].chan_number = chan->hw_value;
+ priv->scan_cfg.chan_list[i].radio_type = chan->band;
+ if (chan->flags &
+ (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR))
+ priv->scan_cfg.chan_list[i].scan_type =
+ MLAN_SCAN_TYPE_PASSIVE;
+ else
+ priv->scan_cfg.chan_list[i].scan_type =
+ MLAN_SCAN_TYPE_ACTIVE;
+ priv->scan_cfg.chan_list[i].scan_time = 0;
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->phandle->miracast_mode)
+ priv->scan_cfg.chan_list[i].scan_time =
+ priv->phandle->miracast_scan_time;
+#endif
+ }
+ priv->scan_cfg.chan_per_scan =
+ MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels);
+
+ /** set scan request IES */
+ if (request->ie && request->ie_len) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_cfg80211_mgmt_frame_ie(
+ priv, NULL, 0, NULL, 0, NULL, 0,
+ (t_u8 *)request->ie, request->ie_len,
+ MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Fail to set sched scan IE\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ /** Clear SCAN IE in Firmware */
+ if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
+ woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
+ NULL, 0, NULL, 0,
+ MGMT_MASK_PROBE_REQ,
+ MOAL_IOCTL_WAIT);
+ }
+
+ /* Interval between scan cycles in milliseconds,supplicant set to 10
+ * second */
+ /* We want to use 30 second for per scan cycle */
+ priv->scan_cfg.scan_interval = MIN_BGSCAN_INTERVAL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
+ if (request->scan_plans[0].interval * 1000 > MIN_BGSCAN_INTERVAL)
+ priv->scan_cfg.scan_interval =
+ request->scan_plans[0].interval * 1000;
+ if (request->n_scan_plans >= 2) {
+ priv->scan_cfg.config_ees = MTRUE;
+ priv->scan_cfg.ees_mode =
+ MBIT(EES_MODE_HIGH) | MBIT(EES_MODE_MID);
+ priv->scan_cfg.high_period =
+ request->scan_plans[0].interval * 1000;
+ priv->scan_cfg.high_period_count =
+ request->scan_plans[0].iterations;
+ priv->scan_cfg.mid_period = request->scan_plans[1].interval;
+ if (request->scan_plans[1].iterations == 0)
+ priv->scan_cfg.mid_period_count = DEF_REPEAT_COUNT;
+ else
+ priv->scan_cfg.mid_period_count =
+ request->scan_plans[1].iterations;
+ if (request->n_scan_plans == 3) {
+ priv->scan_cfg.ees_mode |= MBIT(EES_MODE_LOW);
+ priv->scan_cfg.low_period =
+ request->scan_plans[2].interval;
+ priv->scan_cfg.low_period_count = DEF_REPEAT_COUNT;
+ }
+ }
+#else
+ if (request->interval > MIN_BGSCAN_INTERVAL)
+ priv->scan_cfg.scan_interval = request->interval;
+#endif
+ priv->scan_cfg.repeat_count = DEF_REPEAT_COUNT;
+ priv->scan_cfg.report_condition =
+ BG_SCAN_SSID_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE;
+ priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
+ priv->scan_cfg.action = BG_SCAN_ACT_SET;
+ priv->scan_cfg.enable = MTRUE;
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->phandle->miracast_mode)
+ priv->scan_cfg.scan_chan_gap = priv->phandle->scan_chan_gap;
+ else
+ priv->scan_cfg.scan_chan_gap = 0;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ PRINTM(MIOCTL, "NL80211_SCAN_FLAG_RANDOM_ADDR is set\n");
+ get_random_bytes(buf, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++) {
+ buf[i] &= ~request->mac_addr_mask[i];
+ buf[i] |= request->mac_addr[i] &
+ request->mac_addr_mask[i];
+ }
+ moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac, buf,
+ ETH_ALEN, sizeof(priv->scan_cfg.random_mac));
+ } else
+#endif
+ moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac,
+ priv->random_mac, ETH_ALEN,
+ sizeof(priv->scan_cfg.random_mac));
+
+ PRINTM(MCMND, "wlan:random_mac " MACSTR "\n",
+ MAC2STR(priv->scan_cfg.random_mac));
+ if (MLAN_STATUS_SUCCESS ==
+ woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg)) {
+ priv->sched_scanning = MTRUE;
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ priv->bg_scan_reqid = request->reqid;
+#endif
+ } else
+ ret = -EFAULT;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief stop sched scan
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ u64 reqid
+#endif
+)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ ENTER();
+ PRINTM(MIOCTL, "sched scan stop\n");
+ priv->sched_scanning = MFALSE;
+ woal_stop_bg_scan(priv, MOAL_NO_WAIT);
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ LEAVE();
+ return 0;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+/**
+ * @brief cfg80211_resume handler
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_resume(struct wiphy *wiphy)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
+ struct cfg80211_wowlan_wakeup wakeup_report;
+#endif
+ mlan_ds_hs_wakeup_reason wakeup_reason;
+ int i;
+
+ PRINTM(MCMND, "<--- Enter woal_cfg80211_resume --->\n");
+
+ if (!priv) {
+ PRINTM(MERROR, "woal_cfg80211_resume: priv is NULL\n");
+ goto done;
+ }
+
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (handle->priv[i]->last_event &
+ EVENT_BG_SCAN_REPORT) {
+ if (handle->priv[i]->sched_scanning) {
+ woal_inform_bss_from_scan_result(
+ handle->priv[i], NULL,
+ MOAL_IOCTL_WAIT);
+ cfg80211_sched_scan_results(
+ handle->priv[i]->wdev->wiphy
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ ,
+ 0
+#endif
+ );
+ woal_bgscan_stop_event(handle->priv[i]);
+ handle->priv[i]->last_event = 0;
+ PRINTM(MIOCTL,
+ "Report sched scan result in cfg80211 resume\n");
+ }
+ if (!moal_extflg_isset(handle, EXT_HW_TEST) &&
+ handle->priv[i]->roaming_enabled) {
+ handle->priv[i]->roaming_required =
+ MTRUE;
+#ifdef ANDROID_KERNEL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+ __pm_wakeup_event(
+ &handle->ws,
+ ROAMING_WAKE_LOCK_TIMEOUT);
+#else
+ wake_lock_timeout(
+ &handle->wake_lock,
+ msecs_to_jiffies(
+ ROAMING_WAKE_LOCK_TIMEOUT));
+#endif
+#endif
+ wake_up_interruptible(
+ &handle->reassoc_thread.wait_q);
+ }
+ }
+ }
+ }
+
+ woal_get_wakeup_reason(priv, &wakeup_reason);
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext))
+ woal_wake_reason_logger(priv, wakeup_reason);
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
+ memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup));
+ wakeup_report.pattern_idx = -1;
+
+ switch (wakeup_reason.hs_wakeup_reason) {
+ case NO_HSWAKEUP_REASON:
+ break;
+ case BCAST_DATA_MATCHED:
+ break;
+ case MCAST_DATA_MATCHED:
+ break;
+ case UCAST_DATA_MATCHED:
+ break;
+ case MASKTABLE_EVENT_MATCHED:
+ break;
+ case NON_MASKABLE_EVENT_MATCHED:
+ break;
+ case NON_MASKABLE_CONDITION_MATCHED:
+ if (wiphy->wowlan_config && wiphy->wowlan_config->disconnect)
+ wakeup_report.disconnect = true;
+ break;
+ case MAGIC_PATTERN_MATCHED:
+ if (wiphy->wowlan_config && wiphy->wowlan_config->magic_pkt)
+ wakeup_report.magic_pkt = true;
+ if (wiphy->wowlan_config && wiphy->wowlan_config->n_patterns)
+ wakeup_report.pattern_idx = 1;
+ break;
+ case CONTROL_FRAME_MATCHED:
+ break;
+ case MANAGEMENT_FRAME_MATCHED:
+ break;
+ case GTK_REKEY_FAILURE:
+ if (wiphy->wowlan_config &&
+ wiphy->wowlan_config->gtk_rekey_failure)
+ wakeup_report.gtk_rekey_failure = true;
+ break;
+ default:
+ break;
+ }
+
+ if ((wakeup_reason.hs_wakeup_reason > 0) &&
+ (wakeup_reason.hs_wakeup_reason <= 10)) {
+ cfg80211_report_wowlan_wakeup(priv->wdev, &wakeup_report,
+ GFP_KERNEL);
+ }
+#endif
+
+done:
+ handle->cfg80211_suspend = MFALSE;
+ PRINTM(MCMND, "<--- Leave woal_cfg80211_resume --->\n");
+ return 0;
+}
+
+/**
+ * @brief is_wowlan_pattern_supported
+ *
+ * @param priv A pointer to moal_private
+ * @param pat A pointer to wowlan pattern
+ * @param byte_seq A pointer to byte_seq
+ *
+ * @return 1 -- support, 0 -- not support
+ */
+static t_bool is_wowlan_pattern_supported(moal_private *priv,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ struct cfg80211_pkt_pattern *pat,
+#else
+ struct cfg80211_wowlan_trig_pkt_pattern
+ *pat,
+#endif
+ s8 *byte_seq)
+{
+ int j, k, valid_byte_cnt = 0;
+ t_bool dont_care_byte = MFALSE;
+
+ for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
+ for (k = 0; k < 8; k++) {
+ if (pat->mask[j] & 1 << k) {
+ moal_memcpy_ext(priv->phandle,
+ byte_seq + valid_byte_cnt,
+ &pat->pattern[j * 8 + k], 1, 1);
+ valid_byte_cnt++;
+ if (dont_care_byte)
+ return MFALSE;
+ } else {
+ if (valid_byte_cnt)
+ dont_care_byte = MTRUE;
+ }
+
+ if (valid_byte_cnt > MAX_NUM_BYTE_SEQ)
+ return MFALSE;
+ }
+ }
+
+ byte_seq[MAX_NUM_BYTE_SEQ] = valid_byte_cnt;
+
+ return MTRUE;
+}
+
+/**
+ * @brief cfg80211_suspend handler
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wow A pointer to cfg80211_wowlan
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ int i;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_misc_mef_flt_cfg mef_cfg;
+ mef_entry_t *mef_entry = NULL;
+ int filt_num = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ t_bool first_pat = MTRUE;
+#endif
+ t_u8 byte_seq[MAX_NUM_BYTE_SEQ + 1];
+ const t_u8 ipv4_mc_mac[] = {0x33, 0x33};
+ const t_u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
+ moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
+ mlan_ds_hs_cfg hscfg;
+
+ PRINTM(MCMND, "<--- Enter woal_cfg80211_suspend --->\n");
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
+ if (handle->scan_request) {
+ PRINTM(MIOCTL,
+ "Cancel pending scan in woal_cfg80211_suspend\n");
+ woal_cancel_scan(handle->priv[i],
+ MOAL_IOCTL_WAIT);
+ }
+ handle->priv[i]->last_event = 0;
+ }
+ }
+
+ handle->cfg80211_suspend = MTRUE;
+ if (!wow) {
+ PRINTM(MERROR, "None of the WOWLAN triggers enabled\n");
+ ret = 0;
+ goto done;
+ }
+
+ if (!priv || !priv->media_connected) {
+ PRINTM(MERROR,
+ "Can not configure WOWLAN in disconnected state\n");
+ ret = 0;
+ goto done;
+ }
+
+ PRINTM(MCMND, "wow->n_patterns=%d\n", wow->n_patterns);
+ PRINTM(MCMND, "wow->any=%d\n", wow->any);
+ PRINTM(MCMND, "wow->disconnect=%d\n", wow->disconnect);
+ PRINTM(MCMND, "wow->magic_pkt=%d\n", wow->magic_pkt);
+ PRINTM(MCMND, "wow->gtk_rekey_failure=%d\n", wow->gtk_rekey_failure);
+ PRINTM(MCMND, "wow->eap_identity_req=%d\n", wow->eap_identity_req);
+ PRINTM(MCMND, "wow->four_way_handshake=%d\n", wow->four_way_handshake);
+ PRINTM(MCMND, "wow->rfkill_release=%d\n", wow->rfkill_release);
+
+ if (!(wow->n_patterns) && !(wow->magic_pkt)) {
+ PRINTM(MCMND, "No pattern or magic packet configured\n");
+ ret = 0;
+ goto done;
+ }
+
+ memset(&mef_cfg, 0, sizeof(mef_cfg));
+ mef_cfg.mef_act_type = MEF_ACT_WOWLAN;
+ mef_entry = &mef_cfg.mef_entry;
+
+ mef_entry->mode = MEF_MODE_HOST_SLEEP;
+ mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
+
+ for (i = 0; i < wow->n_patterns; i++) {
+ memset(byte_seq, 0, sizeof(byte_seq));
+ if (!is_wowlan_pattern_supported(priv, &wow->patterns[i],
+ byte_seq)) {
+ PRINTM(MERROR, "Pattern not supported\n");
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ if (!wow->patterns[i].pkt_offset) {
+#endif
+ if (!(byte_seq[0] & 0x01) &&
+ (byte_seq[MAX_NUM_BYTE_SEQ] == 1)) {
+ mef_cfg.criteria |= CRITERIA_UNICAST;
+ continue;
+ } else if (is_broadcast_ether_addr(byte_seq)) {
+ mef_cfg.criteria |= CRITERIA_BROADCAST;
+ continue;
+ } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
+ (byte_seq[MAX_NUM_BYTE_SEQ] == 2)) ||
+ (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
+ (byte_seq[MAX_NUM_BYTE_SEQ] == 3))) {
+ mef_cfg.criteria |= CRITERIA_MULTICAST;
+ continue;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ }
+
+ mef_entry->filter_item[filt_num].fill_flag =
+ (FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
+ FILLING_OFFSET);
+ mef_entry->filter_item[filt_num].repeat = 1;
+ mef_entry->filter_item[filt_num].offset =
+ wow->patterns[i].pkt_offset;
+ moal_memcpy_ext(
+ priv->phandle,
+ mef_entry->filter_item[filt_num].byte_seq, byte_seq,
+ MAX_NUM_BYTE_SEQ,
+ sizeof(mef_entry->filter_item[filt_num].byte_seq));
+ mef_entry->filter_item[filt_num].num_byte_seq =
+ byte_seq[MAX_NUM_BYTE_SEQ];
+ mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
+
+ if (first_pat)
+ first_pat = MFALSE;
+ else
+ mef_entry->rpn[filt_num] = RPN_TYPE_OR;
+
+ filt_num++;
+#endif
+ }
+
+ if (wow->magic_pkt) {
+ mef_cfg.criteria |= CRITERIA_UNICAST | CRITERIA_BROADCAST |
+ CRITERIA_MULTICAST;
+ mef_entry->filter_item[filt_num].fill_flag =
+ (FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
+ FILLING_OFFSET);
+ mef_entry->filter_item[filt_num].repeat = 16;
+ moal_memcpy_ext(
+ priv->phandle,
+ mef_entry->filter_item[filt_num].byte_seq,
+ priv->current_addr, ETH_ALEN,
+ sizeof(mef_entry->filter_item[filt_num].byte_seq));
+ mef_entry->filter_item[filt_num].num_byte_seq = ETH_ALEN;
+ mef_entry->filter_item[filt_num].offset = 56;
+ mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
+ if (filt_num)
+ mef_entry->rpn[filt_num] = RPN_TYPE_OR;
+ filt_num++;
+ mef_entry->filter_item[filt_num].fill_flag =
+ (FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
+ FILLING_OFFSET);
+ mef_entry->filter_item[filt_num].repeat = 16;
+ moal_memcpy_ext(
+ priv->phandle,
+ mef_entry->filter_item[filt_num].byte_seq,
+ priv->current_addr, ETH_ALEN,
+ sizeof(mef_entry->filter_item[filt_num].byte_seq));
+ mef_entry->filter_item[filt_num].num_byte_seq = ETH_ALEN;
+ mef_entry->filter_item[filt_num].offset = 28;
+ mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
+ if (filt_num)
+ mef_entry->rpn[filt_num] = RPN_TYPE_OR;
+ filt_num++;
+ }
+
+ mef_entry->filter_num = filt_num;
+
+ if (!mef_cfg.criteria)
+ mef_cfg.criteria = CRITERIA_BROADCAST | CRITERIA_UNICAST |
+ CRITERIA_MULTICAST;
+
+ status = woal_set_get_wowlan_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &mef_cfg);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "woal_set_get_wowlan_config fail!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ status = woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
+ &hscfg);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Fail to get HS parameter in woal_cfg80211_suspend: 0x%x 0x%x 0x%x\n",
+ hscfg.conditions, hscfg.gap, hscfg.gpio);
+ ret = -EFAULT;
+ goto done;
+ }
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (wow->n_patterns || wow->magic_pkt)
+ hscfg.conditions = 0;
+ status = woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &hscfg);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Fail to set HS parameter in woal_cfg80211_suspend: 0x%x 0x%x 0x%x\n",
+ hscfg.conditions, hscfg.gap, hscfg.gpio);
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_cfg80211_suspend --->\n");
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static void woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+
+ device_set_wakeup_enable(handle->hotplug_device, enabled);
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+/**
+ * @brief change station info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to peer mac
+ * @param params station parameters
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_parameters *params)
+{
+ int ret = 0;
+
+ ENTER();
+
+ /**do nothing*/
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#ifdef UAP_SUPPORT
+/**
+ * @brief add station
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to peer mac
+ * @param params station parameters
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_add_station(struct wiphy *wiphy,
+ struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_parameters *params)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+#ifdef UAP_SUPPORT
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME) &&
+ (priv->bss_role == MLAN_BSS_ROLE_UAP)) {
+ ret = woal_cfg80211_uap_add_station(wiphy, dev, (u8 *)mac,
+ params);
+ LEAVE();
+ return ret;
+ }
+#endif
+#endif
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+/**
+ * @brief Update ft ie for Fast BSS Transition
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param ftie A pointer to cfg80211_update_ft_ies_params structure
+ *
+ * @return 0 success , other failure
+ */
+int woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_update_ft_ies_params *ftie)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ IEEEtypes_MobilityDomain_t *md_ie = NULL;
+ int ret = 0;
+ mlan_ds_misc_assoc_rsp assoc_rsp;
+ IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
+ mlan_bss_info bss_info;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ struct cfg80211_roam_info roam_info = {};
+#endif
+
+ ENTER();
+
+ if (!ftie) {
+ LEAVE();
+ return ret;
+ }
+#ifdef MLAN_64BIT
+ PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %lx \n", ftie->ie_len);
+#else
+ PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %x \n", ftie->ie_len);
+#endif
+ md_ie = (IEEEtypes_MobilityDomain_t *)woal_parse_ie_tlv(
+ ftie->ie, ftie->ie_len, MOBILITY_DOMAIN);
+ if (!md_ie) {
+ PRINTM(MERROR, "No Mobility domain IE\n");
+ LEAVE();
+ return ret;
+ }
+ priv->ft_cap = md_ie->ft_cap;
+ if (priv->ft_ie_len) {
+ priv->pre_ft_ie_len = priv->ft_ie_len;
+ moal_memcpy_ext(priv->phandle, priv->pre_ft_ie, priv->ft_ie,
+ priv->ft_ie_len, MAX_IE_SIZE);
+ }
+ memset(priv->ft_ie, 0, MAX_IE_SIZE);
+ moal_memcpy_ext(priv->phandle, priv->ft_ie, ftie->ie,
+ MIN(ftie->ie_len, MAX_IE_SIZE), sizeof(priv->ft_ie));
+ priv->ft_ie_len = ftie->ie_len;
+ priv->ft_md = ftie->md;
+
+ if (!priv->ft_pre_connect) {
+ LEAVE();
+ return ret;
+ }
+ /* check if is different AP */
+ if (!memcmp(&priv->target_ap_bssid, priv->cfg_bssid,
+ MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MMSG, "This is the same AP, no Fast bss transition\n");
+ priv->ft_pre_connect = MFALSE;
+ priv->ft_ie_len = 0;
+ LEAVE();
+ return 0;
+ }
+
+ /* start fast BSS transition to target AP */
+ priv->assoc_status = 0;
+ priv->sme_current.bssid = priv->conn_bssid;
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
+ &priv->target_ap_bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->conn_bssid));
+ memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
+ ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
+ MOAL_IOCTL_WAIT, &assoc_rsp);
+
+ if ((priv->ft_cap & MBIT(0)) || priv->ft_roaming_triggered_by_driver) {
+ if (!ret) {
+ woal_inform_bss_from_scan_result(priv, NULL,
+ MOAL_IOCTL_WAIT);
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)
+ assoc_rsp.assoc_resp_buf;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ roam_info.bssid = priv->cfg_bssid;
+ roam_info.req_ie = priv->sme_current.ie;
+ roam_info.req_ie_len = priv->sme_current.ie_len;
+ roam_info.resp_ie = passoc_rsp->ie_buffer;
+ roam_info.resp_ie_len = assoc_rsp.assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE;
+ cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid,
+ priv->sme_current.ie,
+ priv->sme_current.ie_len,
+ passoc_rsp->ie_buffer,
+ assoc_rsp.assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ GFP_KERNEL);
+#else
+ cfg80211_roamed(priv->netdev, priv->cfg_bssid,
+ priv->sme_current.ie,
+ priv->sme_current.ie_len,
+ passoc_rsp->ie_buffer,
+ assoc_rsp.assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ GFP_KERNEL);
+#endif
+#endif
+ PRINTM(MMSG,
+ "Fast BSS transition to bssid " MACSTR
+ " successfully\n",
+ MAC2STR(priv->cfg_bssid));
+ } else {
+ PRINTM(MMSG,
+ "Fast BSS transition failed, keep connect to " MACSTR
+ " \n",
+ MAC2STR(priv->cfg_bssid));
+ moal_memcpy_ext(priv->phandle,
+ (void *)priv->sme_current.bssid,
+ &priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->conn_bssid));
+ priv->ft_ie_len = priv->pre_ft_ie_len;
+ moal_memcpy_ext(priv->phandle, priv->ft_ie,
+ priv->pre_ft_ie, priv->pre_ft_ie_len,
+ MAX_IE_SIZE);
+ }
+ priv->ft_roaming_triggered_by_driver = MFALSE;
+
+ } else {
+ if (!ret) {
+ memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
+ woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_IOCTL_WAIT);
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)
+ assoc_rsp.assoc_resp_buf;
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
+ NULL, 0, passoc_rsp->ie_buffer,
+ assoc_rsp.assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ WLAN_STATUS_SUCCESS,
+ GFP_KERNEL);
+ PRINTM(MMSG,
+ "wlan: Fast Bss transition to bssid " MACSTR
+ " successfully\n",
+ MAC2STR(priv->cfg_bssid));
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ priv->channel = bss_info.bss_chan;
+ } else {
+ PRINTM(MMSG,
+ "wlan: Failed to connect to bssid " MACSTR "\n",
+ MAC2STR(priv->target_ap_bssid));
+ cfg80211_connect_result(priv->netdev,
+ priv->target_ap_bssid, NULL, 0,
+ NULL, 0,
+ woal_get_assoc_status(priv),
+ GFP_KERNEL);
+ moal_memcpy_ext(priv->phandle,
+ (void *)priv->sme_current.bssid,
+ &priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->conn_bssid));
+ memset(priv->target_ap_bssid, 0, ETH_ALEN);
+ priv->ft_ie_len = priv->pre_ft_ie_len;
+ moal_memcpy_ext(priv->phandle, priv->ft_ie,
+ priv->pre_ft_ie, priv->pre_ft_ie_len,
+ MAX_IE_SIZE);
+ // priv->ft_ie_len = 0;
+ }
+ }
+
+ priv->ft_pre_connect = MFALSE;
+ LEAVE();
+ return 0;
+}
+#endif
+
+/**
+ * @brief Save connect parameters for roaming
+ *
+ * @param priv A pointer to moal_private
+ * @param sme A pointer to cfg80211_connect_params structure
+ */
+void woal_save_conn_params(moal_private *priv,
+ struct cfg80211_connect_params *sme)
+{
+ ENTER();
+ woal_clear_conn_params(priv);
+ moal_memcpy_ext(priv->phandle, &priv->sme_current, sme,
+ sizeof(struct cfg80211_connect_params),
+ sizeof(priv->sme_current));
+ if (sme->channel) {
+ priv->sme_current.channel = &priv->conn_chan;
+ moal_memcpy_ext(priv->phandle, priv->sme_current.channel,
+ sme->channel, sizeof(struct ieee80211_channel),
+ sizeof(priv->conn_chan));
+ }
+ if (sme->bssid) {
+ priv->sme_current.bssid = priv->conn_bssid;
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
+ sme->bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->conn_bssid));
+ }
+ if (sme->ssid && sme->ssid_len) {
+ priv->sme_current.ssid = priv->conn_ssid;
+ memset(priv->conn_ssid, 0, MLAN_MAX_SSID_LENGTH);
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ssid,
+ sme->ssid, sme->ssid_len,
+ sizeof(priv->conn_ssid));
+ }
+ if (sme->ie && sme->ie_len) {
+ priv->sme_current.ie = kzalloc(sme->ie_len, GFP_KERNEL);
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie,
+ sme->ie, sme->ie_len, sme->ie_len);
+ }
+ if (sme->key && sme->key_len && (sme->key_len <= MAX_WEP_KEY_SIZE)) {
+ priv->sme_current.key = priv->conn_wep_key;
+ moal_memcpy_ext(priv->phandle, (t_u8 *)priv->sme_current.key,
+ sme->key, sme->key_len,
+ sizeof(priv->conn_wep_key));
+ }
+}
+
+/**
+ * @brief clear connect parameters for ing
+ *
+ * @param priv A pointer to moal_private
+ */
+void woal_clear_conn_params(moal_private *priv)
+{
+ ENTER();
+ if (priv->sme_current.ie_len)
+ kfree(priv->sme_current.ie);
+ memset(&priv->sme_current, 0, sizeof(struct cfg80211_connect_params));
+ priv->roaming_required = MFALSE;
+ LEAVE();
+}
+
+/**
+ * @brief Build new roaming connect ie for okc
+ *
+ * @param priv A pointer to moal_private
+ * @param entry A pointer to pmksa_entry
+ **/
+int woal_update_okc_roaming_ie(moal_private *priv, struct pmksa_entry *entry)
+{
+ struct cfg80211_connect_params *sme = &priv->sme_current;
+ int ret = MLAN_STATUS_SUCCESS;
+ const t_u8 *sme_pos, *sme_ptr;
+ t_u8 *okc_ie_pos;
+ t_u8 id, ie_len;
+ int left_len;
+
+ ENTER();
+
+ if (!sme->ie || !sme->ie_len) {
+ PRINTM(MERROR, "No connect ie saved in driver\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (!entry) {
+ PRINTM(MERROR, "No roaming ap pmkid\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (!priv->okc_roaming_ie) {
+ int okc_ie_len = sme->ie_len + sizeof(t_u16) + PMKID_LEN;
+
+ /** Alloc new buffer for okc roaming ie */
+ priv->okc_roaming_ie = kzalloc(okc_ie_len, GFP_KERNEL);
+ if (!priv->okc_roaming_ie) {
+ PRINTM(MERROR, "Fail to allocate assoc req ie\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+
+ /* Build OKC RSN IE with PMKID list
+ * Format of RSN IE: length(bytes) and container
+ * | 1| 1 | 2 | 4 | 2 |
+ * |id|len|version|group data cipher suite|pairwise cipher suite count|
+ * | 4 * m | 2 | 4 * n | 2 |
+ * |pairwise cipher suite list|AKM suite count|AKM suite list|RSN Cap |
+ * | 2 | 16 * s | 4 |
+ * |PMKIDCount|PMKID List|Group Management Cipher Suite|
+ */
+#define PAIRWISE_CIPHER_COUNT_OFFSET 8
+#define AKM_SUITE_COUNT_OFFSET(n) (10 + (n)*4)
+#define PMKID_COUNT_OFFSET(n) (14 + (n)*4)
+
+ sme_pos = sme->ie;
+ left_len = sme->ie_len;
+ okc_ie_pos = priv->okc_roaming_ie;
+ priv->okc_ie_len = 0;
+
+ while (left_len >= 2) {
+ id = *sme_pos;
+ ie_len = *(sme_pos + 1);
+ if ((ie_len + 2) > left_len) {
+ PRINTM(MERROR, "Invalid ie len %d\n", ie_len);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (id == RSN_IE) {
+ t_u16 pairwise_count, akm_count;
+ t_u8 *rsn_ie_len;
+ int rsn_offset;
+
+ pairwise_count =
+ *(t_u16 *)(sme_pos +
+ PAIRWISE_CIPHER_COUNT_OFFSET);
+ akm_count =
+ *(t_u16 *)(sme_pos + AKM_SUITE_COUNT_OFFSET(
+ pairwise_count));
+ rsn_offset =
+ PMKID_COUNT_OFFSET(pairwise_count + akm_count);
+ sme_ptr = (t_u8 *)(sme_pos + rsn_offset);
+
+ moal_memcpy_ext(priv->phandle, okc_ie_pos, sme_pos,
+ rsn_offset, rsn_offset);
+ rsn_ie_len = okc_ie_pos + 1;
+ okc_ie_pos += rsn_offset;
+ *(t_u16 *)okc_ie_pos = 1;
+ okc_ie_pos += sizeof(t_u16);
+ moal_memcpy_ext(priv->phandle, okc_ie_pos, entry->pmkid,
+ PMKID_LEN, PMKID_LEN);
+ okc_ie_pos += PMKID_LEN;
+ priv->okc_ie_len +=
+ rsn_offset + sizeof(t_u16) + PMKID_LEN;
+ *rsn_ie_len =
+ rsn_offset - 2 + sizeof(t_u16) + PMKID_LEN;
+
+ if ((ie_len + 2) > rsn_offset) {
+ /** Previous conn ie include pmkid list */
+ u16 pmkid_count = *(t_u16 *)sme_ptr;
+ rsn_offset += (sizeof(t_u16) +
+ PMKID_LEN * pmkid_count);
+ if ((ie_len + 2) > rsn_offset) {
+ sme_ptr += (sizeof(t_u16) +
+ PMKID_LEN * pmkid_count);
+ moal_memcpy_ext(
+ priv->phandle, okc_ie_pos,
+ sme_ptr,
+ (ie_len + 2 - rsn_offset),
+ (ie_len + 2 - rsn_offset));
+ okc_ie_pos += (ie_len + 2 - rsn_offset);
+ priv->okc_ie_len +=
+ (ie_len + 2 - rsn_offset);
+ *rsn_ie_len +=
+ (ie_len + 2 - rsn_offset);
+ }
+ }
+ } else {
+ moal_memcpy_ext(priv->phandle, okc_ie_pos, sme_pos,
+ ie_len + 2, ie_len + 2);
+ okc_ie_pos += ie_len + 2;
+ priv->okc_ie_len += ie_len + 2;
+ }
+
+ sme_pos += (ie_len + 2);
+ left_len -= (ie_len + 2);
+ }
+
+done:
+ if (ret != MLAN_STATUS_SUCCESS) {
+ if (priv->okc_roaming_ie) {
+ kfree(priv->okc_roaming_ie);
+ priv->okc_roaming_ie = NULL;
+ priv->okc_ie_len = 0;
+ }
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start roaming: driver handle roaming
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return N/A
+ */
+void woal_start_roaming(moal_private *priv)
+{
+ mlan_ds_get_signal signal;
+ mlan_ssid_bssid ssid_bssid;
+ char rssi_low[10];
+ int ret = 0;
+ mlan_ds_misc_assoc_rsp *assoc_rsp;
+ IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ struct cfg80211_roam_info roam_info = {};
+#endif
+
+ ENTER();
+ if (priv->ft_roaming_triggered_by_driver) {
+ PRINTM(MIOCTL, "FT roaming is in processing ...... \n");
+ LEAVE();
+ return;
+ }
+
+ if (priv->last_event & EVENT_BG_SCAN_REPORT) {
+ woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
+ PRINTM(MIOCTL, "Report bgscan result\n");
+ }
+ if (priv->media_connected == MFALSE || !priv->sme_current.ssid_len) {
+ PRINTM(MIOCTL, "Not connected, ignore roaming\n");
+ LEAVE();
+ return;
+ }
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
+ PRINTM(MERROR, "Error getting signal information\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+ ssid_bssid.ssid.ssid_len = priv->sme_current.ssid_len;
+ moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid,
+ priv->sme_current.ssid, priv->sme_current.ssid_len,
+ sizeof(ssid_bssid.ssid.ssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ PRINTM(MIOCTL, "Can not find better network\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ /* check if we found different AP */
+ if (!memcmp(&ssid_bssid.bssid, priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MIOCTL, "This is the same AP, no roaming\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "Find AP: bssid=" MACSTR ", signal=%d\n",
+ MAC2STR(ssid_bssid.bssid), ssid_bssid.rssi);
+ /* check signal */
+ if (!(priv->last_event & EVENT_PRE_BCN_LOST)) {
+ if ((abs(signal.bcn_rssi_avg) - abs(ssid_bssid.rssi)) <
+ DELTA_RSSI) {
+ PRINTM(MERROR, "New AP's signal is not good too.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ /**check if need start FT Roaming*/
+ if (priv->ft_ie_len && (priv->ft_md == ssid_bssid.ft_md) &&
+ (priv->ft_cap == ssid_bssid.ft_cap)) {
+ priv->ft_roaming_triggered_by_driver = MTRUE;
+ woal_start_ft_roaming(priv, &ssid_bssid);
+ goto done;
+ }
+ /* start roaming to new AP */
+ priv->sme_current.bssid = priv->conn_bssid;
+ moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
+ &ssid_bssid.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->conn_bssid));
+
+#ifdef STA_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
+ /** Check if current roaming support OKC offload roaming */
+ if (priv->sme_current.crypto.n_akm_suites &&
+ priv->sme_current.crypto.akm_suites[0] ==
+ WLAN_AKM_SUITE_8021X) {
+ struct pmksa_entry *entry = NULL;
+
+ /** Get OKC PMK Cache entry
+ * Firstly try to get pmksa from cfg80211
+ */
+ priv->wait_target_ap_pmkid = MTRUE;
+ cfg80211_pmksa_candidate_notify(priv->netdev, 0,
+ priv->sme_current.bssid,
+ MTRUE, GFP_ATOMIC);
+ if (wait_event_interruptible_timeout(
+ priv->okc_wait_q,
+ !priv->wait_target_ap_pmkid,
+ OKC_WAIT_TARGET_PMKSA_TIMEOUT)) {
+ PRINTM(MIOCTL, "OKC Roaming is ready\n");
+ entry = priv->target_ap_pmksa;
+ } else {
+ /** Try to get pmksa from pmksa list */
+ priv->wait_target_ap_pmkid = MFALSE;
+ entry = woal_get_pmksa_entry(
+ priv, priv->sme_current.bssid);
+ }
+ /** Build okc roaming ie */
+ woal_update_okc_roaming_ie(priv, entry);
+ priv->target_ap_pmksa = NULL;
+ }
+ }
+#endif
+#endif
+ assoc_rsp = kzalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_ATOMIC);
+ if (!assoc_rsp) {
+ PRINTM(MERROR, "Failed to allocate memory for assoc_rsp\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
+ MOAL_IOCTL_WAIT, assoc_rsp);
+ if (!ret) {
+ const t_u8 *ie;
+ int ie_len;
+
+ woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
+ passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp->assoc_resp_buf;
+
+ /** Update connect ie in roam event */
+ ie = priv->sme_current.ie;
+ ie_len = priv->sme_current.ie_len;
+#ifdef STA_CFG80211
+ if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
+ /** Check if current roaming support OKC offload roaming
+ */
+ if (priv->sme_current.crypto.n_akm_suites &&
+ priv->sme_current.crypto.akm_suites[0] ==
+ WLAN_AKM_SUITE_8021X) {
+ if (priv->okc_roaming_ie && priv->okc_ie_len) {
+ ie = priv->okc_roaming_ie;
+ ie_len = priv->okc_ie_len;
+ }
+ }
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ roam_info.bssid = priv->cfg_bssid;
+ roam_info.req_ie = ie;
+ roam_info.req_ie_len = ie_len;
+ roam_info.resp_ie = passoc_rsp->ie_buffer;
+ roam_info.resp_ie_len =
+ assoc_rsp->assoc_resp_len - ASSOC_RESP_FIXED_SIZE;
+ cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid, ie, ie_len,
+ passoc_rsp->ie_buffer,
+ assoc_rsp->assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ GFP_KERNEL);
+#else
+ cfg80211_roamed(priv->netdev, priv->cfg_bssid, ie, ie_len,
+ passoc_rsp->ie_buffer,
+ assoc_rsp->assoc_resp_len -
+ ASSOC_RESP_FIXED_SIZE,
+ GFP_KERNEL);
+#endif
+#endif
+ PRINTM(MMSG, "Roamed to bssid " MACSTR " successfully\n",
+ MAC2STR(priv->cfg_bssid));
+ } else {
+ PRINTM(MIOCTL, "Roaming to bssid " MACSTR " failed\n",
+ MAC2STR(ssid_bssid.bssid));
+ }
+ kfree(assoc_rsp);
+done:
+ /* config rssi low threshold again */
+ priv->last_event = 0;
+ priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
+ sprintf(rssi_low, "%d", priv->rssi_low);
+ woal_set_rssi_low_threshold(priv, rssi_low, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+#ifdef UAP_SUPPORT
+/**
+ * @brief add uap station
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to peer mac
+ * @param params station parameters
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ mlan_ioctl_req *req = NULL;
+ t_u32 req_len = 0;
+ mlan_ds_bss *bss = NULL;
+ t_u8 *pos;
+ t_u8 qosinfo;
+ MrvlIEtypes_Data_t *tlv;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ MrvlExtIEtypes_Data_t *ext_tlv;
+#endif
+ mlan_status status;
+ int ret = 0;
+
+ ENTER();
+
+ req_len = sizeof(mlan_ds_bss);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ if (params->ext_capab_len)
+ req_len += sizeof(MrvlIEtypesHeader_t) + params->ext_capab_len;
+#endif
+ if (params->supported_rates_len)
+ req_len += sizeof(MrvlIEtypesHeader_t) +
+ params->supported_rates_len;
+ if (params->uapsd_queues || params->max_sp)
+ req_len += sizeof(MrvlIEtypesHeader_t) + sizeof(qosinfo);
+ if (params->ht_capa)
+ req_len += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(struct ieee80211_ht_cap);
+ if (params->vht_capa)
+ req_len += sizeof(MrvlIEtypesHeader_t) +
+ sizeof(struct ieee80211_vht_cap);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (params->opmode_notif_used)
+ req_len += sizeof(MrvlIEtypesHeader_t) + sizeof(u8);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ if (params->he_capa_len)
+ req_len += sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
+#endif
+ req = woal_alloc_mlan_ioctl_req(req_len);
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_ADD_STATION;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ bss->param.sta_info.listen_interval = params->listen_interval;
+ bss->param.sta_info.aid = params->aid;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ bss->param.sta_info.cap_info = params->capability;
+#else
+ bss->param.sta_info.cap_info = 0;
+#endif
+ bss->param.sta_info.tlv_len = 0;
+ bss->param.sta_info.sta_flags = params->sta_flags_set;
+ moal_memcpy_ext(priv->phandle, bss->param.sta_info.peer_mac, mac,
+ MLAN_MAC_ADDR_LENGTH,
+ sizeof(bss->param.sta_info.peer_mac));
+ PRINTM(MMSG, "wlan: UAP/GO add peer station, address =" MACSTR "\n",
+ MAC2STR(mac));
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ PRINTM(MCMND,
+ "sta_flags=0x%x listen_interval=%d aid=%d cap_info=0x%x\n",
+ params->sta_flags_set, params->listen_interval, params->aid,
+ params->capability);
+#else
+ PRINTM(MCMND, "sta_flags=0x%x listen_interval=%d aid=%d\n",
+ params->sta_flags_set, params->listen_interval, params->aid);
+#endif
+ pos = &bss->param.sta_info.tlv[0];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ if (params->ext_capab_len) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = EXT_CAPABILITY;
+ tlv->header.len = params->ext_capab_len;
+ moal_memcpy_ext(priv->phandle, tlv->data, params->ext_capab,
+ tlv->header.len, tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+#endif
+ if (params->supported_rates_len) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = SUPPORTED_RATES;
+ tlv->header.len = params->supported_rates_len;
+ moal_memcpy_ext(priv->phandle, tlv->data,
+ params->supported_rates, tlv->header.len,
+ tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+ if (params->uapsd_queues || params->max_sp) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = QOS_INFO;
+ tlv->header.len = sizeof(qosinfo);
+ qosinfo = params->uapsd_queues | (params->max_sp << 5);
+ moal_memcpy_ext(priv->phandle, tlv->data, &qosinfo,
+ tlv->header.len, tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+ if (params->ht_capa) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = HT_CAPABILITY;
+ tlv->header.len = sizeof(struct ieee80211_ht_cap);
+ moal_memcpy_ext(priv->phandle, tlv->data, params->ht_capa,
+ tlv->header.len, tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+ if (params->vht_capa) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = VHT_CAPABILITY;
+ tlv->header.len = sizeof(struct ieee80211_vht_cap);
+ moal_memcpy_ext(priv->phandle, tlv->data, params->vht_capa,
+ tlv->header.len, tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (params->opmode_notif_used) {
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ tlv->header.type = OPER_MODE_NTF;
+ tlv->header.len = sizeof(u8);
+ moal_memcpy_ext(priv->phandle, tlv->data, &params->opmode_notif,
+ tlv->header.len, tlv->header.len);
+ pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ if (params->he_capa_len) {
+ ext_tlv = (MrvlExtIEtypes_Data_t *)pos;
+ ext_tlv->header.type = EXTENSION;
+ ext_tlv->header.len = params->he_capa_len + sizeof(u8);
+ ext_tlv->header.ext_id = HE_CAPABILITY;
+ moal_memcpy_ext(priv->phandle, ext_tlv->data,
+ (u8 *)params->he_capa, params->he_capa_len,
+ params->he_capa_len);
+ pos += sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
+ bss->param.sta_info.tlv_len +=
+ sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
+ tlv = (MrvlIEtypes_Data_t *)pos;
+ }
+#endif
+ DBG_HEXDUMP(MCMD_D, "sta tlv", &bss->param.sta_info.tlv[0],
+ bss->param.sta_info.tlv_len);
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function is probe client handle.
+ *
+ * @param wiphy A pointer to wiphy.
+ *
+ * @param dev A pointer to net_device
+ *
+ * @param peer A pointer to peer
+ *
+ * @param cookie A pointer to cookie
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_probe_client(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *peer,
+ u64 *cookie)
+{
+ return -1;
+}
+#endif
+
+/**
+ * @brief Sends deauth packet to kernel
+ *
+ * @param priv A pointer to moal_private struct
+ * @param sa A pointer to source address
+ * @param reason_code disconnect reason code
+ * @return N/A
+ */
+void woal_host_mlme_disconnect(moal_private *priv, u16 reason_code, u8 *sa)
+{
+ t_u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ t_u8 frame_buf[26];
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)frame_buf;
+ ENTER();
+
+ mgmt->frame_control = IEEE80211_STYPE_DEAUTH;
+ mgmt->duration = 0;
+ mgmt->seq_ctrl = 0;
+ mgmt->u.deauth.reason_code = reason_code;
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ moal_memcpy_ext(priv->phandle, mgmt->da, broadcast_addr,
+ ETH_ALEN, sizeof(mgmt->da));
+ moal_memcpy_ext(priv->phandle, mgmt->sa,
+ priv->sme_current.bssid, ETH_ALEN,
+ sizeof(mgmt->sa));
+ moal_memcpy_ext(priv->phandle, mgmt->bssid, priv->cfg_bssid,
+ ETH_ALEN, sizeof(mgmt->bssid));
+ priv->host_mlme = MFALSE;
+ priv->auth_flag = 0;
+ } else {
+ moal_memcpy_ext(priv->phandle, mgmt->da, priv->current_addr,
+ ETH_ALEN, sizeof(mgmt->da));
+ moal_memcpy_ext(priv->phandle, mgmt->sa, sa, ETH_ALEN,
+ sizeof(mgmt->sa));
+ moal_memcpy_ext(priv->phandle, mgmt->bssid, priv->current_addr,
+ ETH_ALEN, sizeof(mgmt->bssid));
+ PRINTM(MMSG,
+ "wlan: hostmlme notify deauth station " MACSTR "\n",
+ MAC2STR(sa));
+ }
+
+ if (GET_BSS_ROLE(priv) != MLAN_BSS_ROLE_UAP) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ mutex_lock(&priv->wdev->mtx);
+ cfg80211_rx_mlme_mgmt(priv->netdev, frame_buf, 26);
+ mutex_unlock(&priv->wdev->mtx);
+#else
+ cfg80211_send_deauth(priv->netdev, frame_buf, 26);
+#endif
+
+ } else {
+ int freq = ieee80211_channel_to_frequency(
+ priv->channel
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ ,
+ (priv->channel <= 14 ? IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ)
+#endif
+ );
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ cfg80211_rx_mgmt(
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ priv->wdev,
+#else
+ priv->netdev,
+#endif
+ freq, 0, frame_buf, 26
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ ,
+ 0
+#endif
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
+ ,
+ GFP_ATOMIC
+#endif
+ );
+#else
+ cfg80211_rx_mgmt(priv->netdev, freq, frame_buf, 26, GFP_ATOMIC);
+#endif
+ }
+
+ LEAVE();
+ return;
+}
+#endif
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct wireless_dev *wdev = NULL;
+ int psmode = 0;
+
+ ENTER();
+
+ wdev = (struct wireless_dev *)&priv->w_dev;
+ memset(wdev, 0, sizeof(struct wireless_dev));
+ wdev->wiphy = priv->phandle->wiphy;
+ if (!wdev->wiphy) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (bss_type == MLAN_BSS_TYPE_STA) {
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ priv->roaming_enabled = MFALSE;
+ priv->roaming_required = MFALSE;
+ }
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ wdev->iftype = NL80211_IFTYPE_STATION;
+#endif
+#endif
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+ /* Get IEEE power save mode */
+ if (MLAN_STATUS_SUCCESS == woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
+ &psmode, 0,
+ MOAL_IOCTL_WAIT)) {
+ /* Save the IEEE power save mode to wiphy, because after
+ * warmreset wiphy power save should be updated instead
+ * of using the last saved configuration */
+ if (psmode)
+ priv->wdev->ps = MTRUE;
+ else
+ priv->wdev->ps = MFALSE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Initialize the wiphy
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_cfg80211_init_wiphy(moal_private *priv, t_u8 wait_option)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int retry_count, rts_thr, frag_thr;
+ struct wiphy *wiphy = NULL;
+ mlan_ioctl_req *req = NULL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
+ mlan_ds_radio_cfg *radio = NULL;
+#endif
+ pmlan_ds_11n_cfg cfg_11n = NULL;
+ t_u32 hw_dev_cap;
+#ifdef UAP_SUPPORT
+ pmlan_uap_bss_param sys_cfg = NULL;
+#endif
+ int mcs_supp = 0;
+
+ ENTER();
+ wiphy = priv->phandle->wiphy;
+ /* Get 11n tx parameters from MLAN */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+ cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;
+
+ /* Get supported MCS sets */
+ memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
+ req->req_id = MLAN_IOCTL_11N_CFG;
+ req->action = MLAN_ACT_GET;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* Initialize parameters for 2GHz and 5GHz bands */
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ if (IS_CARD9098(priv->phandle->card_type) ||
+ IS_CARD9097(priv->phandle->card_type)) {
+ mcs_supp = priv->phandle->params.antcfg & 0xf;
+ if (mcs_supp != 3 && mcs_supp != 0)
+ cfg_11n->param.supported_mcs_set[1] = 0;
+ cfg_11n->param.supported_mcs_set[4] = 0;
+ }
+ woal_cfg80211_setup_ht_cap(
+ &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, hw_dev_cap,
+ cfg_11n->param.supported_mcs_set);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ woal_cfg80211_setup_he_cap(priv,
+ wiphy->bands[IEEE80211_BAND_2GHZ]);
+#endif
+ }
+ /* For 2.4G band only card, this shouldn't be set */
+ if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
+ if (IS_CARD9098(priv->phandle->card_type) ||
+ IS_CARD9097(priv->phandle->card_type)) {
+ mcs_supp = (priv->phandle->params.antcfg & 0xf00) >> 8;
+ if (mcs_supp != 3 && mcs_supp != 0)
+ cfg_11n->param.supported_mcs_set[1] = 0;
+ }
+ woal_cfg80211_setup_ht_cap(
+ &wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, hw_dev_cap,
+ cfg_11n->param.supported_mcs_set);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ woal_cfg80211_setup_vht_cap(
+ priv, &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ woal_cfg80211_setup_he_cap(priv,
+ wiphy->bands[IEEE80211_BAND_5GHZ]);
+#endif
+ }
+ kfree(req);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
+ /* Get antenna modes */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)req->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ req->req_id = MLAN_IOCTL_RADIO_CFG;
+ req->action = MLAN_ACT_GET;
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ /* Set available antennas to wiphy */
+ wiphy->available_antennas_tx = radio->param.ant_cfg.tx_antenna;
+ wiphy->available_antennas_rx = radio->param.ant_cfg.rx_antenna;
+#endif /* CFG80211_VERSION_CODE */
+
+ /* Set retry limit count to wiphy */
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_GET, wait_option,
+ &retry_count)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ }
+#ifdef UAP_SUPPORT
+ else {
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR,
+ "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = MLAN_STATUS_FAILURE;
+ kfree(sys_cfg);
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_GET, wait_option,
+ sys_cfg)) {
+ ret = MLAN_STATUS_FAILURE;
+ kfree(sys_cfg);
+ goto done;
+ }
+ retry_count = sys_cfg->retry_limit;
+ kfree(sys_cfg);
+ }
+#endif
+ wiphy->retry_long = (t_u8)retry_count;
+ wiphy->retry_short = (t_u8)retry_count;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ wiphy->mgmt_stypes = ieee80211_mgmt_stypes;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
+#endif /* KERNEL_VERSION */
+
+ /* Set RTS threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE)
+ rts_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->rts_threshold = (t_u32)rts_thr;
+
+ /* Set fragment threshold to wiphy */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE)
+ frag_thr = MLAN_FRAG_RTS_DISABLED;
+ wiphy->frag_threshold = (t_u32)frag_thr;
+
+done:
+ LEAVE();
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+/**
+ * @brief Update channel flag
+ *
+ * @param wiphy A pointer to wiphy structure
+ *
+ * @return N/A
+ */
+void woal_update_channel_flag(struct wiphy *wiphy, mlan_fw_info *fw_info)
+{
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ int i;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ sband = wiphy->bands[band];
+ if (!sband)
+ continue;
+ if (sband->band & IEEE80211_BAND_5GHZ &&
+ fw_info->prohibit_80mhz) {
+ for (i = 0; i < sband->n_channels; i++) {
+ sband->channels[i].flags |=
+ IEEE80211_CHAN_NO_80MHZ;
+ PRINTM(MCMND, "hw_value=%d channel flag %x\n",
+ sband->channels[i].hw_value,
+ sband->channels[i].flags);
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * This function registers the device with CFG802.11 subsystem.
+ *
+ * @param priv A pointer to moal_private
+ *
+ */
+mlan_status woal_register_cfg80211(moal_private *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ struct wiphy *wiphy;
+ void *wdev_priv = NULL;
+ mlan_fw_info fw_info;
+ char *country = NULL, *reg_alpha2 = NULL;
+ int index = 0;
+
+ ENTER();
+
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ reg_alpha2 = priv->phandle->params.reg_alpha2;
+ wiphy = wiphy_new(&woal_cfg80211_ops, sizeof(moal_handle *));
+ if (!wiphy) {
+ PRINTM(MERROR, "Could not allocate wiphy device\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wiphy;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
+ woal_cfg80211_ops.auth = woal_cfg80211_authenticate;
+ woal_cfg80211_ops.assoc = woal_cfg80211_associate;
+ woal_cfg80211_ops.disconnect = NULL;
+ woal_cfg80211_ops.connect = NULL;
+#ifdef UAP_SUPPORT
+ woal_cfg80211_ops.probe_client = woal_cfg80211_probe_client;
+#endif
+ }
+#endif
+#ifdef CONFIG_PM
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ if (fw_info.fw_supplicant_support)
+ wiphy->wowlan = &wowlan_support_with_gtk;
+ else
+ wiphy->wowlan = &wowlan_support;
+#else
+ wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT;
+ if (fw_info.fw_supplicant_support) {
+ wiphy->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+ }
+ wiphy->wowlan.n_patterns = MAX_NUM_FILTERS;
+ wiphy->wowlan.pattern_min_len = 1;
+ wiphy->wowlan.pattern_max_len = WOWLAN_MAX_PATTERN_LEN;
+ wiphy->wowlan.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN;
+#endif
+#endif
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ wiphy->coalesce = &coalesce_support;
+#endif
+ wiphy->max_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
+ wiphy->max_scan_ie_len = MAX_IE_SIZE;
+ wiphy->interface_modes = 0;
+ wiphy->interface_modes =
+ MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_AP);
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ wiphy->interface_modes |=
+ MBIT(NL80211_IFTYPE_P2P_GO) | MBIT(NL80211_IFTYPE_P2P_CLIENT);
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ woal_register_cfg80211_vendor_command(wiphy);
+#endif
+ /* Make this wiphy known to this driver only */
+ wiphy->privid = mrvl_wiphy_privid;
+
+ if (!fw_info.fw_bands)
+ fw_info.fw_bands = BAND_B | BAND_G;
+ if (fw_info.fw_bands & BAND_A) {
+ if (priv->phandle->second_mac)
+ wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &mac1_cfg80211_band_5ghz;
+ else
+
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ woal_update_channel_flag(wiphy, &fw_info);
+#endif
+ priv->phandle->band = IEEE80211_BAND_5GHZ;
+ }
+ /* Supported bands */
+ if (fw_info.fw_bands & (BAND_B | BAND_G | BAND_GN | BAND_GAC)) {
+ if (priv->phandle->second_mac)
+ wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &mac1_cfg80211_band_2ghz;
+ else
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
+ /* If 2.4G enable, it will overwrite default to 2.4G*/
+ priv->phandle->band = IEEE80211_BAND_2GHZ;
+ }
+
+ if (fw_info.fw_bands & BAND_A) {
+ /** reduce scan time from 110ms to 80ms */
+ woal_set_scan_time(priv, INIT_ACTIVE_SCAN_CHAN_TIME,
+ INIT_PASSIVE_SCAN_CHAN_TIME,
+ INIT_SPECIFIC_SCAN_CHAN_TIME);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ cfg80211_iface_comb_ap_sta.radar_detect_widths |=
+ MBIT(NL80211_CHAN_WIDTH_40);
+ if (fw_info.fw_bands & BAND_AAC)
+ cfg80211_iface_comb_ap_sta.radar_detect_widths |=
+ MBIT(NL80211_CHAN_WIDTH_80);
+#endif
+ } else
+ woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ SPECIFIC_SCAN_CHAN_TIME);
+
+ /* Initialize cipher suits */
+ wiphy->cipher_suites = cfg80211_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (!moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+#endif
+ wiphy->max_acl_mac_addrs = MAX_MAC_FILTER_NUM;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ if (fw_info.max_ap_assoc_sta) {
+ wiphy->max_ap_assoc_sta = fw_info.max_ap_assoc_sta;
+ PRINTM(MCMND, "Set wiphy max_ap_assoc_sta=%d\n",
+ wiphy->max_ap_assoc_sta);
+ }
+#endif
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ /* Initialize interface combinations */
+ wiphy->iface_combinations = &cfg80211_iface_comb_ap_sta;
+ wiphy->n_iface_combinations = 1;
+#endif
+
+ moal_memcpy_ext(priv->phandle, wiphy->perm_addr, priv->current_addr,
+ ETH_ALEN, sizeof(wiphy->perm_addr));
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ wiphy->flags = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
+ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ wiphy->flags |= WIPHY_FLAG_NETNS_OK;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ wiphy->flags |=
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX;
+ wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS;
+ else
+#endif
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+#endif
+#ifdef ANDROID_KERNEL
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (!moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+#endif
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#else
+ wiphy->max_sched_scan_reqs = 1;
+#endif
+ wiphy->max_sched_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
+ wiphy->max_sched_scan_ie_len = MAX_IE_SIZE;
+ wiphy->max_match_sets = MRVDRV_MAX_SSID_LIST_LENGTH;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
+ wiphy->max_sched_scan_plans = 3;
+ wiphy->max_sched_scan_plan_iterations = 100;
+#endif
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ wiphy->features |= NL80211_FEATURE_SAE;
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN;
+#endif
+
+ wiphy->reg_notifier = woal_cfg80211_reg_notifier;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ /* Indicate to cfg80211 that the driver can support
+ * CSA and ESCA,i.e., both types of channel switch
+ * Applications like hostapd 2.6 will append CSA IE
+ * and ECSA IE and expect the driver to advertise 2
+ * in max_num_csa_counters to successfully issue a
+ * channel switch
+ */
+ wiphy->max_num_csa_counters = MAX_CSA_COUNTERS_NUM;
+#endif
+ wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
+#endif
+ /* Set struct moal_handle pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wiphy);
+ *(unsigned long *)wdev_priv = (unsigned long)priv->phandle;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ set_wiphy_dev(wiphy, (struct device *)priv->phandle->hotplug_device);
+#endif
+ /* Set phy name*/
+ for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
+ if (m_handle[index] == priv->phandle) {
+ dev_set_name(&wiphy->dev, mwiphy_name, index);
+ break;
+ }
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_BEACON_HINTS)) {
+ /* REGULATORY_DISABLE_BEACON_HINTS: NO-IR flag won't be removed
+ * on chn where an AP is visible! */
+ wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
+ }
+ if (moal_extflg_isset(priv->phandle, EXT_COUNTRY_IE_IGNORE)) {
+ PRINTM(MIOCTL, "Don't follow countryIE provided by AP.\n");
+ wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
+ } else {
+ PRINTM(MIOCTL, "Follow countryIE provided by AP.\n");
+ }
+#endif
+
+ priv->phandle->country_code[0] = '0';
+ priv->phandle->country_code[1] = '0';
+ priv->phandle->country_code[2] = ' ';
+
+ if (reg_alpha2 && !strncmp(reg_alpha2, "99", strlen("99"))) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+ REGULATORY_DISABLE_BEACON_HINTS |
+ REGULATORY_COUNTRY_IE_IGNORE;
+#else
+ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+#endif
+ wiphy_apply_custom_regulatory(wiphy, &mrvl_regdom);
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ if (woal_request_extcap(priv, (t_u8 *)&priv->extended_capabilities,
+ sizeof(priv->extended_capabilities)) < 0)
+ PRINTM(MERROR,
+ "Failed to get driver extended capability, use default\n");
+ DBG_HEXDUMP(MCMD_D, "wiphy ext cap",
+ (t_u8 *)&priv->extended_capabilities,
+ sizeof(priv->extended_capabilities));
+ wiphy->extended_capabilities = (t_u8 *)&priv->extended_capabilities;
+ wiphy->extended_capabilities_mask =
+ (t_u8 *)&priv->extended_capabilities;
+ wiphy->extended_capabilities_len = sizeof(priv->extended_capabilities);
+#endif
+ if (wiphy_register(wiphy) < 0) {
+ PRINTM(MERROR, "Wiphy device registration failed!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto err_wiphy;
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ if (fw_info.force_reg ||
+ (fw_region && priv->phandle->params.txpwrlimit_cfg)) {
+ PRINTM(MCMND, "FW region_code=%d force_reg=%d\n",
+ fw_info.region_code, fw_info.force_reg);
+ country = region_code_2_string(fw_info.region_code);
+ if (country) {
+ moal_memcpy_ext(priv->phandle,
+ priv->phandle->country_code, country, 2,
+ 2);
+ woal_update_custom_regdomain(priv, wiphy);
+ }
+ }
+#endif
+ if ((!reg_alpha2 || strncmp(reg_alpha2, "99", strlen("99")))
+
+ ) {
+ /** we will try driver parameter first */
+ if (reg_alpha2 && woal_is_valid_alpha2(reg_alpha2)) {
+ PRINTM(MIOCTL, "Notify reg_alpha2 %c%c\n",
+ reg_alpha2[0], reg_alpha2[1]);
+ if (!moal_extflg_isset(priv->phandle,
+ EXT_DISABLE_REGD_BY_DRIVER))
+ regulatory_hint(wiphy, reg_alpha2);
+ } else {
+ country = region_code_2_string(fw_info.region_code);
+ if (country) {
+ if (fw_info.region_code != 0) {
+ PRINTM(MIOCTL,
+ "Notify hw region code=%d %c%c\n",
+ fw_info.region_code, country[0],
+ country[1]);
+ if (!moal_extflg_isset(
+ priv->phandle,
+ EXT_DISABLE_REGD_BY_DRIVER))
+ regulatory_hint(wiphy, country);
+ }
+ } else
+ PRINTM(MCMND,
+ "hw region code=%d not supported\n",
+ fw_info.region_code);
+ }
+ }
+ priv->phandle->wiphy = wiphy;
+ woal_cfg80211_init_wiphy(priv, MOAL_IOCTL_WAIT);
+
+ return ret;
+err_wiphy:
+ if (wiphy)
+ wiphy_free(wiphy);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.h
new file mode 100644
index 000000000000..8080a481ca74
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sta_cfg80211.h
@@ -0,0 +1,41 @@
+/** @file moal_sta_cfg80211.h
+ *
+ * @brief This file contains the STA CFG80211 specific defines.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MOAL_STA_CFG80211_H_
+#define _MOAL_STA_CFG80211_H_
+
+/** Convert RSSI signal strength from dBm to mBm (100*dBm) */
+#define RSSI_DBM_TO_MDM(x) ((x)*100)
+
+mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type);
+
+mlan_status woal_cfg80211_set_key(moal_private *priv, t_u8 is_enable_wep,
+ t_u32 cipher, const t_u8 *key, int key_len,
+ const t_u8 *seq, int seq_len, t_u8 key_index,
+ const t_u8 *addr, int disable,
+ t_u8 wait_option);
+
+mlan_status woal_cfg80211_set_wep_keys(moal_private *priv, const t_u8 *key,
+ int key_len, t_u8 index,
+ t_u8 wait_option);
+
+#endif /* _MOAL_STA_CFG80211_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.c
new file mode 100644
index 000000000000..34e66cf8321a
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.c
@@ -0,0 +1,4526 @@
+/** @file moal_uap.c
+ *
+ * @brief This file contains the major functions in UAP
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#ifdef SDIO
+#include "moal_sdio.h"
+#endif /* SDIO */
+#include "moal_eth_ioctl.h"
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief uap addba parameter handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_addba_param(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_param param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_addba_param() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n",
+ (int)param.action, (int)param.timeout, (int)param.txwinsize,
+ (int)param.rxwinsize, (int)param.txamsdu, (int)param.rxamsdu);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action)
+ /* Get addba param from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ else {
+ /* Set addba param in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg_11n->param.addba_param.timeout = param.timeout;
+ cfg_11n->param.addba_param.txwinsize = param.txwinsize;
+ cfg_11n->param.addba_param.rxwinsize = param.rxwinsize;
+ cfg_11n->param.addba_param.txamsdu = param.txamsdu;
+ cfg_11n->param.addba_param.rxamsdu = param.rxamsdu;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ param.timeout = cfg_11n->param.addba_param.timeout;
+ param.txwinsize = cfg_11n->param.addba_param.txwinsize;
+ param.rxwinsize = cfg_11n->param.addba_param.rxwinsize;
+ param.txamsdu = cfg_11n->param.addba_param.txamsdu;
+ param.rxamsdu = cfg_11n->param.addba_param.rxamsdu;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap aggr priority tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ aggr_prio_tbl param;
+ int ret = 0;
+ int i = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get aggr_prio_tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set aggr_prio_tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i];
+ }
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i];
+ param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap addba reject tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_reject_para param;
+ int ret = 0;
+ int i = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba_reject tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba_reject tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ cfg_11n->param.addba_reject[i] = param.addba_reject[i];
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++)
+ param.addba_reject[i] = cfg_11n->param.addba_reject[i];
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get_fw_info handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ fw_info fw;
+ mlan_fw_info fw_info;
+ int ret = 0;
+
+ ENTER();
+ memset(&fw, 0, sizeof(fw));
+ memset(&fw_info, 0, sizeof(fw_info));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fw.fw_release_number = fw_info.fw_ver;
+ fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support;
+ fw.fw_bands = fw_info.fw_bands;
+ fw.region_code = fw_info.region_code;
+ fw.hw_dot_11n_dev_cap = fw_info.hw_dot_11n_dev_cap;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure deep sleep
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ deep_sleep_para param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if (!param.action) {
+ /* Get deep_sleep status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set deep_sleep in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ if (param.deep_sleep == MTRUE) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = param.idle_time;
+ } else {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ }
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
+ param.deep_sleep = MTRUE;
+ else
+ param.deep_sleep = MFALSE;
+ param.idle_time = pm->param.auto_deep_sleep.idletime;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure band steering
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_band_steer(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *pm = NULL;
+ band_steer_para param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_band_steer() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "band_steer_para", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_band_steer_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_MISC_BAND_STEERING;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ pm->param.band_steer_cfg.action = param.action;
+ pm->param.band_steer_cfg.block_2g_prb_req = param.block_2g_prb_req;
+ pm->param.band_steer_cfg.state = param.state;
+ pm->param.band_steer_cfg.max_btm_req_allowed =
+ param.max_btm_req_allowed;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.action = pm->param.band_steer_cfg.action;
+ param.block_2g_prb_req = pm->param.band_steer_cfg.block_2g_prb_req;
+ param.state = pm->param.band_steer_cfg.state;
+ param.max_btm_req_allowed =
+ pm->param.band_steer_cfg.max_btm_req_allowed;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure beacon stuck detect mechanism
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_beacon_stuck(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *pm = NULL;
+ beacon_stuck_detect_para param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_beacon_stuck() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ DBG_HEXDUMP(MCMD_D, "beacon_stuck_detect_para", (t_u8 *)&param,
+ sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_beacon_stuck_param_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ pm = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_MISC_BEACON_STUCK;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ pm->param.beacon_stuck_cfg.action = param.action;
+ pm->param.beacon_stuck_cfg.beacon_stuck_detect_count =
+ param.beacon_stuck_detect_count;
+ pm->param.beacon_stuck_cfg.recovery_confirm_count =
+ param.recovery_confirm_count;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.action = pm->param.beacon_stuck_cfg.action;
+ param.beacon_stuck_detect_count =
+ pm->param.beacon_stuck_cfg.beacon_stuck_detect_count;
+ param.recovery_confirm_count =
+ pm->param.beacon_stuck_cfg.recovery_confirm_count;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief configure tx_pause settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ tx_data_pause_para param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *)&param,
+ sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!param.action) {
+ /* Get Tx data pause status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set Tx data pause in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.tx_datapause.tx_pause = param.txpause;
+ misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.txpause = misc->param.tx_datapause.tx_pause;
+ param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef SDIO
+/**
+ * @brief uap sdcmd52rw ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ sdcmd52_para param;
+ t_u8 func, data = 0;
+ int ret = 0, reg;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8)param.cmd52_params[0];
+ reg = (t_u32)param.cmd52_params[1];
+
+ if (!param.action) {
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ data = sdio_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ else
+ data = sdio_f0_readb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_readb: reading register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_read_ioreg: reading register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+ param.cmd52_params[2] = data;
+ } else {
+ data = (t_u8)param.cmd52_params[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
+ func, reg, data);
+#ifdef SDIO_MMC
+ sdio_claim_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(
+ ((struct sdio_mmc_card *)priv->phandle->card)
+ ->func,
+ data, reg, &ret);
+ sdio_release_host(
+ ((struct sdio_mmc_card *)priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR,
+ "sdio_writeb: writing register 0x%X failed\n",
+ reg);
+ goto done;
+ }
+#else
+ if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
+ 0) {
+ PRINTM(MERROR,
+ "sdio_write_ioreg: writing register 0x%X failed\n",
+ reg);
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#endif
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief configure snmp mib
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ snmp_mib_para param;
+ t_u8 value[MAX_SNMP_VALUE_SIZE];
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(value, 0, MAX_SNMP_VALUE_SIZE);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *)&param, sizeof(param));
+ if (param.action) {
+ if (copy_from_user(value, req->ifr_data + sizeof(param),
+ MIN(param.oid_val_len,
+ MAX_SNMP_VALUE_SIZE))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value,
+ MIN(param.oid_val_len, sizeof(t_u32)));
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
+ switch (param.oid) {
+ case OID_80211D_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
+ break;
+ case OID_80211H_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
+ break;
+ default:
+ PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __func__,
+ param.oid);
+ goto done;
+ }
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ snmp->param.oid_value = *(t_u32 *)value;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ if (copy_to_user(req->ifr_data + sizeof(param),
+ &snmp->param.oid_value,
+ MIN(param.oid_val_len, sizeof(t_u32)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure domain info
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_domain_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11d_cfg *cfg11d = NULL;
+ domain_info_para param;
+ t_u8 tlv[MAX_DOMAIN_TLV_LEN];
+ t_u16 tlv_data_len = 0;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(tlv, 0, MAX_DOMAIN_TLV_LEN);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *)&param, sizeof(param));
+ if (param.action) {
+ /* get tlv header */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param),
+ TLV_HEADER_LEN)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ tlv_data_len = ((t_u16 *)(tlv))[1];
+ if ((TLV_HEADER_LEN + tlv_data_len) > sizeof(tlv)) {
+ PRINTM(MERROR, "TLV buffer is overflowed");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* get full tlv */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param),
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv,
+ TLV_HEADER_LEN + tlv_data_len);
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11d = (mlan_ds_11d_cfg *)ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11D_CFG;
+ cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, cfg11d->param.domain_tlv, tlv,
+ TLV_HEADER_LEN + tlv_data_len,
+ sizeof(cfg11d->param.domain_tlv));
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ tlv_data_len = ((t_u16 *)(cfg11d->param.domain_tlv))[1];
+ if (copy_to_user(req->ifr_data + sizeof(param),
+ &cfg11d->param.domain_tlv,
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure dfs testing settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11h_cfg *cfg11h = NULL;
+ dfs_testing_para param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11h = (mlan_ds_11h_cfg *)ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
+ cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg11h->param.dfs_testing.usr_cac_period_msec =
+ param.usr_cac_period;
+ cfg11h->param.dfs_testing.usr_nop_period_sec =
+ param.usr_nop_period;
+ cfg11h->param.dfs_testing.usr_no_chan_change =
+ param.no_chan_change;
+ cfg11h->param.dfs_testing.usr_fixed_new_chan =
+ param.fixed_new_chan;
+ cfg11h->param.dfs_testing.usr_cac_restart = param.cac_restart;
+ priv->phandle->cac_restart = param.cac_restart;
+ priv->phandle->cac_period_jiffies =
+ param.usr_cac_period * HZ / 1000;
+ priv->user_cac_period_msec =
+ cfg11h->param.dfs_testing.usr_cac_period_msec;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!param.action) { /* GET */
+ param.usr_cac_period =
+ cfg11h->param.dfs_testing.usr_cac_period_msec;
+ param.usr_nop_period =
+ cfg11h->param.dfs_testing.usr_nop_period_sec;
+ param.no_chan_change =
+ cfg11h->param.dfs_testing.usr_no_chan_change;
+ param.fixed_new_chan =
+ cfg11h->param.dfs_testing.usr_fixed_new_chan;
+ param.cac_restart = cfg11h->param.dfs_testing.usr_cac_restart;
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+/**
+ * @brief uap channel NOP status check ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param data BSS control type
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_get_channel_nop_info(moal_private *priv, t_u8 wait_option,
+ mlan_ds_11h_chan_nop_info *ch_info)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_cfg *ds_11hcfg = NULL;
+
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!ch_info) {
+ PRINTM(MERROR, "Invalid chan_info\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_GET;
+
+ ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
+ ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_NOP_INFO;
+ moal_memcpy_ext(priv->phandle, &ds_11hcfg->param.ch_nop_info, ch_info,
+ sizeof(mlan_ds_11h_chan_nop_info),
+ sizeof(ds_11hcfg->param.ch_nop_info));
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, ch_info, &ds_11hcfg->param.ch_nop_info,
+ sizeof(mlan_ds_11h_chan_nop_info),
+ sizeof(mlan_ds_11h_chan_nop_info));
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+#endif
+
+/**
+ * @brief configure channel switch count
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_chan_switch_count_cfg(struct net_device *dev,
+ struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11h_cfg *cfg11h = NULL;
+ cscount_cfg_t param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "%s corrupt data\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "cscount_cfg_t", (t_u8 *)&param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11h = (mlan_ds_11h_cfg *)ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
+ cfg11h->sub_command = MLAN_OID_11H_CHAN_SWITCH_COUNT;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg11h->param.cs_count = param.cs_count;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!param.action) { /* GET */
+ param.cs_count = cfg11h->param.cs_count;
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Configure TX beamforming support
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ tx_bf_cfg_para_hdr param;
+ t_u16 action = 0;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(param));
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action)
+ /* Get BF configurations */
+ action = MLAN_ACT_GET;
+ else
+ /* Set BF configurations */
+ action = MLAN_ACT_SET;
+ if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *)&bf_cfg, sizeof(bf_cfg));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr), &bf_cfg,
+ sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get 11n configurations
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_ht_tx_cfg(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ds_11n_tx_cfg httx_cfg;
+ mlan_ioctl_req *ioctl_req = NULL;
+ ht_tx_cfg_para_hdr param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(ht_tx_cfg_para_hdr));
+ memset(&httx_cfg, 0, sizeof(mlan_ds_11n_tx_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_ht_tx_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(ht_tx_cfg_para_hdr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+ if (copy_from_user(&httx_cfg,
+ req->ifr_data + sizeof(ht_tx_cfg_para_hdr),
+ sizeof(mlan_ds_11n_tx_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) {
+ /* Get 11n tx parameters from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set HT Tx configurations */
+ cfg_11n->param.tx_cfg.httxcap = httx_cfg.httxcap;
+ PRINTM(MINFO, "SET: httxcap:0x%x\n", httx_cfg.httxcap);
+ /* Update 11n tx parameters in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ httx_cfg.httxcap = cfg_11n->param.tx_cfg.httxcap;
+ PRINTM(MINFO, "GET: httxcap:0x%x\n", httx_cfg.httxcap);
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(ht_tx_cfg_para_hdr), &httx_cfg,
+ sizeof(mlan_ds_11n_tx_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get Set/Get 11AC configurations
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_vht_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0, resbuf_len = 0;
+ mlan_ds_11ac_cfg *cfg_11ac = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11ac_vht_cfg *vhtcfg = NULL, vht_cfg;
+ t_u8 *respbuf = NULL;
+ vht_cfg_para_hdr param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+#define CMD_RESPBUF_LEN 2048
+ gfp_t flag;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(vht_cfg_para_hdr));
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ respbuf = kzalloc(CMD_RESPBUF_LEN, flag);
+ if (!respbuf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_ht_tx_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(vht_cfg_para_hdr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11ac = (mlan_ds_11ac_cfg *)ioctl_req->pbuf;
+ cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
+ ioctl_req->req_id = MLAN_IOCTL_11AC_CFG;
+ if (copy_from_user(&vht_cfg, req->ifr_data + sizeof(vht_cfg_para_hdr),
+ sizeof(mlan_ds_11ac_vht_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (vht_cfg.band == BAND_SELECT_BOTH) {
+ cfg_11ac->param.vht_cfg.band = (BAND_SELECT_BG | BAND_SELECT_A);
+ } else {
+ cfg_11ac->param.vht_cfg.band = vht_cfg.band;
+ }
+ if (!param.action) {
+ /* GET operation */
+ if (vht_cfg.band == BAND_SELECT_BOTH) {
+ /* if get both bands, get BG first */
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
+ }
+ PRINTM(MINFO, "GET: vhtcfg band: 0x%x\n",
+ cfg_11ac->param.vht_cfg.band);
+ if (priv->bss_role == MLAN_BSS_ROLE_UAP)
+ cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
+ else
+ cfg_11ac->param.vht_cfg.txrx = vht_cfg.txrx;
+ PRINTM(MINFO, "GET: vhtcfg txrx: 0x%x\n",
+ cfg_11ac->param.vht_cfg.txrx);
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Band */
+ if (vht_cfg.band == BAND_SELECT_BOTH)
+ cfg_11ac->param.vht_cfg.band =
+ (BAND_SELECT_BG | BAND_SELECT_A);
+ else
+ cfg_11ac->param.vht_cfg.band = vht_cfg.band;
+ PRINTM(MINFO, "SET: vhtcfg band: 0x%x\n",
+ cfg_11ac->param.vht_cfg.band);
+ /* Tx/Rx */
+ cfg_11ac->param.vht_cfg.txrx = vht_cfg.txrx;
+ PRINTM(MINFO, "SET: vhtcfg txrx: 0x%x\n",
+ cfg_11ac->param.vht_cfg.txrx);
+ /* BW cfg */
+ cfg_11ac->param.vht_cfg.bwcfg = vht_cfg.bwcfg;
+ PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
+ cfg_11ac->param.vht_cfg.bwcfg);
+
+ cfg_11ac->param.vht_cfg.vht_cap_info = vht_cfg.vht_cap_info;
+ PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
+ cfg_11ac->param.vht_cfg.vht_cap_info);
+ cfg_11ac->param.vht_cfg.vht_tx_mcs = vht_cfg.vht_tx_mcs;
+ cfg_11ac->param.vht_cfg.vht_rx_mcs = vht_cfg.vht_rx_mcs;
+ /* Update 11AC parameters in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* number of vhtcfg entries */
+ *respbuf = 1;
+ vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
+ moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
+ sizeof(mlan_ds_11ac_vht_cfg),
+ sizeof(mlan_ds_11ac_vht_cfg));
+ resbuf_len = 1 + sizeof(mlan_ds_11ac_vht_cfg);
+
+ if ((ioctl_req->action == MLAN_ACT_GET) &&
+ (vht_cfg.band == BAND_SELECT_BOTH)) {
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* number of vhtcfg entries */
+ *respbuf = 2;
+ vhtcfg++;
+ moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
+ sizeof(mlan_ds_11ac_vht_cfg),
+ sizeof(mlan_ds_11ac_vht_cfg));
+ resbuf_len += sizeof(mlan_ds_11ac_vht_cfg);
+ }
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ if (copy_to_user(req->ifr_data, respbuf, resbuf_len)) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ if (respbuf)
+ kfree(respbuf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap hs_cfg ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req,
+ BOOLEAN invoke_hostcmd)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ds_hs_cfg hscfg;
+ ds_hs_cfg hs_cfg;
+ mlan_bss_info bss_info;
+ t_u16 action;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ memset(&hs_cfg, 0, sizeof(ds_hs_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hs_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n",
+ hs_cfg.flags, hs_cfg.conditions, (int)hs_cfg.gpio, hs_cfg.gap);
+
+ /* HS config is blocked if HS is already activated */
+ if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) &&
+ (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL ||
+ invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (hs_cfg.flags & HS_CFG_FLAG_SET) {
+ action = MLAN_ACT_SET;
+ if (hs_cfg.flags != HS_CFG_FLAG_ALL) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT, &hscfg);
+ }
+ if (hs_cfg.flags & HS_CFG_FLAG_CONDITION)
+ hscfg.conditions = hs_cfg.conditions;
+ if (hs_cfg.flags & HS_CFG_FLAG_GPIO)
+ hscfg.gpio = hs_cfg.gpio;
+ if (hs_cfg.flags & HS_CFG_FLAG_GAP)
+ hscfg.gap = hs_cfg.gap;
+
+ if (invoke_hostcmd == MTRUE) {
+ /* Issue IOCTL to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action,
+ MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ action = MLAN_ACT_GET;
+ }
+
+ /* Issue IOCTL to invoke hostcmd */
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) {
+ hs_cfg.flags = HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO |
+ HS_CFG_FLAG_GAP;
+ hs_cfg.conditions = hscfg.conditions;
+ hs_cfg.gpio = hscfg.gpio;
+ hs_cfg.gap = hscfg.gap;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (req->ifr_data != NULL) {
+ ret = woal_uap_hs_cfg(dev, req, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap mgmt_frame_control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_mgmt_frame_control(struct net_device *dev,
+ struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ t_u16 action = 0;
+ mgmt_frame_ctrl param;
+ mlan_uap_bss_param *sys_config = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (param.action)
+ action = MLAN_ACT_SET;
+ else
+ action = MLAN_ACT_GET;
+ if (action == MLAN_ACT_SET) {
+ /* Initialize the invalid values so that the correct
+ values below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_config);
+ sys_config->mgmt_ie_passthru_mask = param.mask;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, action,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ param.mask = sys_config->mgmt_ie_passthru_mask;
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get tx rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0, i = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ tx_rate_cfg_t tx_rate_config;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&tx_rate_config, req->ifr_data,
+ sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *)mreq->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ mreq->req_id = MLAN_IOCTL_RATE;
+ if (!(tx_rate_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ if ((tx_rate_config.user_data_cnt <= 0) ||
+ (tx_rate_config.user_data_cnt > 4)) {
+ PRINTM(MERROR, "Invalid user_data_cnt\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mreq->action = MLAN_ACT_SET;
+ if (tx_rate_config.rate_format == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((tx_rate_config.rate_format < 0) ||
+ (tx_rate_config.rate < 0)) {
+ PRINTM(MERROR,
+ "Invalid format or rate selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* rate_format sanity check */
+ if ((tx_rate_config.rate_format >
+ MLAN_RATE_FORMAT_HE)) {
+ PRINTM(MERROR, "Invalid format selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ rate->param.rate_cfg.rate_format =
+ tx_rate_config.rate_format;
+
+ /* rate sanity check */
+ if (tx_rate_config.user_data_cnt >= 2) {
+ if (((tx_rate_config.rate_format ==
+ MLAN_RATE_FORMAT_LG) &&
+ (tx_rate_config.rate >
+ MLAN_RATE_INDEX_OFDM7)) ||
+ ((tx_rate_config.rate_format ==
+ MLAN_RATE_FORMAT_HT) &&
+ (tx_rate_config.rate != 32) &&
+ (tx_rate_config.rate > 15)) ||
+ ((tx_rate_config.rate_format ==
+ MLAN_RATE_FORMAT_VHT) &&
+ (tx_rate_config.rate >
+ MLAN_RATE_INDEX_MCS9)) ||
+ ((tx_rate_config.rate_format ==
+ MLAN_RATE_FORMAT_HE) &&
+ (tx_rate_config.rate >
+ MLAN_RATE_INDEX_MCS11))) {
+ PRINTM(MERROR,
+ "Invalid rate selection\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ rate->param.rate_cfg.rate = tx_rate_config.rate;
+ }
+
+ /* nss sanity check */
+ if ((tx_rate_config.rate_format == 2) ||
+ (tx_rate_config.rate_format == 3)) {
+ if ((tx_rate_config.nss < 1) ||
+ (tx_rate_config.nss > 2)) {
+ PRINTM(MERROR,
+ "Invalid nss selection %d\n",
+ tx_rate_config.nss);
+ ret = -EINVAL;
+ goto done;
+ }
+ rate->param.rate_cfg.nss = tx_rate_config.nss;
+ }
+ if (tx_rate_config.user_data_cnt <= 3)
+ rate->param.rate_cfg.rate_setting = 0xffff;
+ else
+ rate->param.rate_cfg.rate_setting =
+ tx_rate_config.rate_setting;
+ }
+ }
+
+ status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (tx_rate_config.action) {
+ priv->rate_index = tx_rate_config.action;
+ } else {
+ if (rate->param.rate_cfg.is_rate_auto)
+ tx_rate_config.rate_format = AUTO_RATE;
+ else {
+ /* fixed rate */
+ tx_rate_config.rate_format =
+ rate->param.rate_cfg.rate_format;
+ tx_rate_config.rate = rate->param.rate_cfg.rate;
+ if (rate->param.rate_cfg.rate_format ==
+ MLAN_RATE_FORMAT_VHT ||
+ rate->param.rate_cfg.rate_format ==
+ MLAN_RATE_FORMAT_HE)
+ tx_rate_config.nss = rate->param.rate_cfg.nss;
+ tx_rate_config.rate_setting =
+ rate->param.rate_cfg.rate_setting;
+ }
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ tx_rate_config.bitmap_rates[i] =
+ rate->param.rate_cfg.bitmap_rates[i];
+ }
+
+ if (copy_to_user(req->ifr_data, &tx_rate_config,
+ sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RF antenna mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ ant_cfg_t antenna_config;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&antenna_config, 0, sizeof(ant_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)mreq->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (!(antenna_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode;
+ radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode;
+ }
+
+ status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (mreq->action == MLAN_ACT_GET) {
+ antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna;
+ antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna;
+ if (copy_to_user(req->ifr_data, &antenna_config,
+ sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get HT stream configurations
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_htstream_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_11n_cfg *cfg = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ htstream_cfg_t htstream_cfg;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&htstream_cfg, 0, sizeof(htstream_cfg_t));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_htstream_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&htstream_cfg, req->ifr_data,
+ sizeof(htstream_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!htstream_cfg.action) {
+ /* Get operation */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Update HT stream parameter in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ /* Set HT Stream configuration */
+ cfg->param.stream_cfg = htstream_cfg.stream_cfg;
+ PRINTM(MINFO, "SET: htstream_cfg:0x%x\n",
+ cfg->param.stream_cfg);
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Copy to user */
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ PRINTM(MINFO, "GET: htstream_cfg:0x%x\n",
+ htstream_cfg.stream_cfg);
+ htstream_cfg.stream_cfg = cfg->param.stream_cfg;
+ if (copy_to_user(req->ifr_data, &htstream_cfg,
+ sizeof(htstream_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get DFS_REPEATER mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_dfs_repeater(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ dfs_repeater_mode param;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&param, 0, sizeof(dfs_repeater_mode));
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(dfs_repeater_mode))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)mreq->pbuf;
+ misc->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
+ mreq->req_id = MLAN_IOCTL_MISC_CFG;
+ mreq->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ param.mode = misc->param.dfs_repeater.mode;
+
+ if (copy_to_user(req->ifr_data, &param, sizeof(dfs_repeater_mode))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get skip CAC mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_skip_cac(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ skip_cac_para param;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "skip_cac() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&param, 0, sizeof(skip_cac_para));
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(skip_cac_para))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Currently default action is get */
+ if (param.action == 0) {
+ param.skip_cac = (t_u16)priv->skip_cac;
+ } else {
+ priv->skip_cac = param.skip_cac;
+ }
+
+ if (copy_to_user(req->ifr_data, &param, sizeof(skip_cac_para))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get DFS_REPEATER mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_cac_timer_status(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ cac_timer_status param;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&param, 0, sizeof(cac_timer_status));
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(cac_timer_status))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Currently default action is get */
+ param.mode = 0;
+
+ if (priv->phandle->cac_period == MTRUE) {
+ long cac_left_jiffies;
+
+ cac_left_jiffies =
+ MEAS_REPORT_TIME -
+ (jiffies - priv->phandle->meas_start_jiffies);
+
+ /* cac_left_jiffies would be negative if timer has already
+ * elapsed. positive if timer is still yet to lapsed
+ */
+ if (cac_left_jiffies > 0)
+ param.mode = (t_u32)cac_left_jiffies / HZ;
+ }
+
+ if (copy_to_user(req->ifr_data, &param, sizeof(cac_timer_status))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set/get uap operation control
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_operation_ctrl(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_uap_oper_ctrl uap_oper;
+ uap_oper_para_hdr param;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(uap_oper_para_hdr));
+ memset(&uap_oper, 0, sizeof(mlan_uap_oper_ctrl));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_operation_ctrl corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(uap_oper_para_hdr))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_OPER_CTRL;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (copy_from_user(&uap_oper, req->ifr_data + sizeof(uap_oper_para_hdr),
+ sizeof(mlan_uap_oper_ctrl))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) {
+ /* Get uap operation control parameters from FW */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set uap operation control configurations */
+ ioctl_req->action = MLAN_ACT_SET;
+ bss->param.ap_oper_ctrl.ctrl_value = uap_oper.ctrl_value;
+ if (uap_oper.ctrl_value == 2)
+ bss->param.ap_oper_ctrl.chan_opt = uap_oper.chan_opt;
+ if (uap_oper.chan_opt == 3) {
+ bss->param.ap_oper_ctrl.band_cfg = uap_oper.band_cfg;
+ bss->param.ap_oper_ctrl.channel = uap_oper.channel;
+ }
+ }
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(uap_oper_para_hdr),
+ &bss->param.ap_oper_ctrl,
+ sizeof(mlan_uap_oper_ctrl))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ t_u32 subcmd = 0;
+ ENTER();
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int)subcmd);
+ switch (subcmd) {
+ case UAP_ADDBA_PARA:
+ ret = woal_uap_addba_param(dev, req);
+ break;
+ case UAP_AGGR_PRIOTBL:
+ ret = woal_uap_aggr_priotbl(dev, req);
+ break;
+ case UAP_ADDBA_REJECT:
+ ret = woal_uap_addba_reject(dev, req);
+ break;
+ case UAP_FW_INFO:
+ ret = woal_uap_get_fw_info(dev, req);
+ break;
+ case UAP_DEEP_SLEEP:
+ ret = woal_uap_deep_sleep(dev, req);
+ break;
+ case UAP_TX_DATA_PAUSE:
+ ret = woal_uap_txdatapause(dev, req);
+ break;
+#ifdef SDIO
+ case UAP_SDCMD52_RW:
+ ret = woal_uap_sdcmd52_rw(dev, req);
+ break;
+#endif
+ case UAP_SNMP_MIB:
+ ret = woal_uap_snmp_mib(dev, req);
+ break;
+ case UAP_DFS_TESTING:
+ ret = woal_uap_dfs_testing(dev, req);
+ break;
+ case UAP_CHAN_SWITCH_COUNT_CFG:
+ ret = woal_uap_chan_switch_count_cfg(dev, req);
+ break;
+ case UAP_DOMAIN_INFO:
+ ret = woal_uap_domain_info(dev, req);
+ break;
+ case UAP_TX_BF_CFG:
+ ret = woal_uap_tx_bf_cfg(dev, req);
+ break;
+ case UAP_HT_TX_CFG:
+ ret = woal_uap_ht_tx_cfg(dev, req);
+ break;
+ case UAP_VHT_CFG:
+ ret = woal_uap_vht_cfg(dev, req);
+ break;
+ case UAP_HS_CFG:
+ ret = woal_uap_hs_cfg(dev, req, MTRUE);
+ break;
+ case UAP_HS_SET_PARA:
+ ret = woal_uap_hs_set_para(dev, req);
+ break;
+ case UAP_MGMT_FRAME_CONTROL:
+ ret = woal_uap_mgmt_frame_control(dev, req);
+ break;
+ case UAP_TX_RATE_CFG:
+ ret = woal_uap_tx_rate_cfg(dev, req);
+ break;
+ case UAP_ANTENNA_CFG:
+ ret = woal_uap_antenna_cfg(dev, req);
+ break;
+ case UAP_HT_STREAM_CFG:
+ ret = woal_uap_htstream_cfg(dev, req);
+ break;
+ case UAP_DFS_REPEATER_MODE:
+ ret = woal_uap_dfs_repeater(dev, req);
+ break;
+ case UAP_CAC_TIMER_STATUS:
+ ret = woal_uap_cac_timer_status(dev, req);
+ break;
+ case UAP_SKIP_CAC:
+ ret = woal_uap_skip_cac(dev, req);
+ break;
+ case UAP_OPERATION_CTRL:
+ ret = woal_uap_operation_ctrl(dev, req);
+ break;
+ case UAP_BAND_STEER:
+ ret = woal_uap_band_steer(dev, req);
+ break;
+ case UAP_BEACON_STUCK_DETECT:
+ ret = woal_uap_beacon_stuck(dev, req);
+ break;
+ default:
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap station deauth ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_deauth_param deauth_param;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&deauth_param, 0, sizeof(mlan_deauth_param));
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&deauth_param, req->ifr_data,
+ sizeof(mlan_deauth_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
+ MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
+ sizeof(mlan_deauth_param),
+ sizeof(bss->param.deauth_param));
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code,
+ sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ int data[2] = {0, 0};
+ mlan_bss_info bss_info;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_radio_ctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data[0]) {
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *)mreq->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ mreq->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = (t_u32)data[1];
+ status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+ if (status != MLAN_STATUS_PENDING)
+ kfree(mreq);
+ } else {
+ /* Get radio status */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ data[1] = bss_info.radio_on;
+ if (copy_to_user(req->ifr_data, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap bss control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0, data = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap report mic error ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_report_mic_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(mac_addr, 0, MLAN_MAC_ADDR_LENGTH);
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_report_mic_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(mac_addr, req->ifr_data, MLAN_MAC_ADDR_LENGTH)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ioctl report mic err station: " MACSTR "\n",
+ MAC2STR(mac_addr));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *)ioctl_req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_REPORT_MIC_ERR;
+ ioctl_req->req_id = MLAN_IOCTL_SEC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, sec->param.sta_mac, mac_addr,
+ MLAN_MAC_ADDR_LENGTH, sizeof(sec->param.sta_mac));
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap set key ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_set_key_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ encrypt_key key;
+ int ret = 0;
+ t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&key, 0, sizeof(encrypt_key));
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_set_key_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&key, req->ifr_data, sizeof(encrypt_key))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl report set key: " MACSTR " key_index=%d, key_len=%d \n",
+ MAC2STR(key.mac_addr), (int)key.key_index, (int)key.key_len);
+
+ if ((key.key_len > MLAN_MAX_KEY_LENGTH) || (key.key_index > 3)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *)ioctl_req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY,
+ ioctl_req->req_id = MLAN_IOCTL_SEC_CFG;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
+ key.mac_addr, MLAN_MAC_ADDR_LENGTH,
+ sizeof(sec->param.encrypt_key.mac_addr));
+ sec->param.encrypt_key.key_index = key.key_index;
+ sec->param.encrypt_key.key_len = key.key_len;
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.key_material,
+ key.key_material, key.key_len,
+ sizeof(sec->param.encrypt_key.key_material));
+ if (0 == memcmp(sec->param.encrypt_key.mac_addr, bcast_addr, ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get uap power mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action Action set or get
+ * @param ps_mgmt A pointer to mlan_ds_ps_mgmt structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+int woal_set_get_uap_power_mode(moal_private *priv, t_u32 action,
+ mlan_ds_ps_mgmt *ps_mgmt)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (!ps_mgmt) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+ ioctl_req->action = action;
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_mgmt, ps_mgmt,
+ sizeof(mlan_ds_ps_mgmt),
+ sizeof(pm_cfg->param.ps_mgmt));
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, ps_mgmt,
+ &pm_cfg->param.ps_mgmt,
+ sizeof(mlan_ds_ps_mgmt),
+ sizeof(mlan_ds_ps_mgmt));
+ }
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief uap power mode ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ds_ps_mgmt ps_mgmt;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->bss_type != MLAN_BSS_TYPE_UAP) {
+ PRINTM(MERROR, "Invlaid BSS_TYPE for UAP power mode command\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
+ "inact_to=%d min_awake=%d max_awake=%d\n",
+ ps_mgmt.flags, (int)ps_mgmt.ps_mode,
+ (int)ps_mgmt.sleep_param.ctrl_bitmap,
+ (int)ps_mgmt.sleep_param.min_sleep,
+ (int)ps_mgmt.sleep_param.max_sleep,
+ (int)ps_mgmt.inact_param.inactivity_to,
+ (int)ps_mgmt.inact_param.min_awake,
+ (int)ps_mgmt.inact_param.max_awake);
+
+ if (ps_mgmt.flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
+ PS_FLAG_INACT_SLEEP_PARAM)) {
+ PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n",
+ ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) {
+ PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n",
+ (int)ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+ if (ps_mgmt.flags) {
+ ioctl_req->action = MLAN_ACT_SET;
+ moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_mgmt, &ps_mgmt,
+ sizeof(mlan_ds_ps_mgmt),
+ sizeof(pm_cfg->param.ps_mgmt));
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code,
+ sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+ if (!ps_mgmt.flags) {
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &pm_cfg->param.ps_mgmt,
+ sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS config ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ int offset = 0;
+ t_u32 action = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get action */
+ if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ offset += sizeof(action);
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (action == 1)
+ ioctl_req->action = MLAN_ACT_SET;
+ else
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (ioctl_req->action == MLAN_ACT_SET) {
+ /* Get the BSS config from user */
+ if (copy_from_user(&bss->param.bss_config,
+ req->ifr_data + offset,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ offset = sizeof(action);
+
+ /* Copy to user : BSS config */
+ if (copy_to_user(req->ifr_data + offset, &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get station list handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_get_sta_list_ioctl(struct net_device *dev,
+ struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ /* Copy to user : sta_list */
+ if (copy_to_user(req->ifr_data, &info->param.sta_list,
+ ioctl_req->data_read_written)) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uAP set WAPI key ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_set_wapi_key_ioctl(moal_private *priv, wapi_msg *msg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ wapi_key_msg *key_msg = NULL;
+ t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (msg->msg_len != sizeof(wapi_key_msg)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ key_msg = (wapi_key_msg *)msg->msg;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH;
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
+ key_msg->mac_addr, ETH_ALEN,
+ sizeof(sec->param.encrypt_key.mac_addr));
+ sec->param.encrypt_key.key_index = key_msg->key_id;
+ if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.key_material,
+ key_msg->key, sec->param.encrypt_key.key_len,
+ sizeof(sec->param.encrypt_key.key_material));
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable wapi in firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+static mlan_status woal_enable_wapi(moal_private *priv, t_u8 enable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Get AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+
+ /* Change AP default setting */
+ req->action = MLAN_ACT_SET;
+ if (enable == MFALSE) {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_WAPI;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Set AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ if (enable)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief uAP set WAPI flag ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_set_wapi_flag_ioctl(moal_private *priv, wapi_msg *msg)
+{
+ t_u8 wapi_psk_ie[] = {0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14,
+ 0x72, 0x02, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x14, 0x72, 0x01, 0x00, 0x00};
+ t_u8 wapi_cert_ie[] = {0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14,
+ 0x72, 0x01, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x14, 0x72, 0x01, 0x00, 0x00};
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+ misc->param.gen_ie.len = sizeof(wapi_psk_ie);
+ if (msg->msg[0] & WAPI_MODE_PSK) {
+ moal_memcpy_ext(priv->phandle, misc->param.gen_ie.ie_data,
+ wapi_psk_ie, misc->param.gen_ie.len,
+ sizeof(misc->param.gen_ie.ie_data));
+ } else if (msg->msg[0] & WAPI_MODE_CERT) {
+ moal_memcpy_ext(priv->phandle, misc->param.gen_ie.ie_data,
+ wapi_cert_ie, misc->param.gen_ie.len,
+ sizeof(misc->param.gen_ie.ie_data));
+ } else if (msg->msg[0] == 0) {
+ /* disable WAPI in driver */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0))
+ ret = -EFAULT;
+ woal_enable_wapi(priv, MFALSE);
+ goto done;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_enable_wapi(priv, MTRUE);
+done:
+ if ((status != MLAN_STATUS_PENDING) && req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set wapi ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int woal_uap_set_wapi(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ wapi_msg msg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_set_wapi() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type,
+ msg.msg_len);
+ DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg,
+ MIN(msg.msg_len, sizeof(msg.msg)));
+
+ switch (msg.msg_type) {
+ case P80211_PACKET_WAPIFLAG:
+ ret = woal_uap_set_wapi_flag_ioctl(priv, &msg);
+ break;
+ case P80211_PACKET_SETKEY:
+ ret = woal_uap_set_wapi_key_ioctl(priv, &msg);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Initialize the members of mlan_uap_bss_param
+ * which are uploaded from firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_uap_get_bss_param(moal_private *priv,
+ mlan_uap_bss_param *sys_cfg,
+ t_u8 wait_option)
+{
+ mlan_ds_bss *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_bss *)req->pbuf;
+ info->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get bss info failed!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, sys_cfg, &info->param.bss_config,
+ sizeof(mlan_uap_bss_param), sizeof(mlan_uap_bss_param));
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set uap httxcfg
+ *
+ * @param priv A pointer to moal_private structure
+ * @param band_cfg Band cfg
+ * @param en Enabled/Disabled
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_set_uap_ht_tx_cfg(moal_private *priv, Band_Config_t bandcfg,
+ t_u16 ht_cap, t_u8 en)
+{
+ int ret = 0;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ /* Set HT Tx configurations */
+ if (bandcfg.chanBand == BAND_2GHZ) {
+ if (en)
+ cfg_11n->param.tx_cfg.httxcap = ht_cap;
+ else
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
+ } else if (bandcfg.chanBand == BAND_5GHZ) {
+ if (en)
+ cfg_11n->param.tx_cfg.httxcap = ht_cap;
+ else
+ cfg_11n->param.tx_cfg.httxcap = 0;
+ cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
+ }
+ PRINTM(MCMND, "SET: httxcap=0x%x band:0x%x\n",
+ cfg_11n->param.tx_cfg.httxcap, cfg_11n->param.tx_cfg.misc_cfg);
+ /* Update 11n tx parameters in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set 11n status based on the configured security mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_uap_set_11n_status(moal_private *priv,
+ mlan_uap_bss_param *sys_cfg, t_u8 action)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_fw_info fw_info;
+
+ ENTER();
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ if (action == MLAN_ACT_DISABLE) {
+ if ((sys_cfg->supported_mcs_set[0] == 0) &&
+ (sys_cfg->supported_mcs_set[4] == 0) &&
+ (sys_cfg->supported_mcs_set[1] == 0)) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0;
+ sys_cfg->supported_mcs_set[4] = 0;
+ sys_cfg->supported_mcs_set[1] = 0;
+ }
+ }
+
+ if (action == MLAN_ACT_ENABLE) {
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ sys_cfg->supported_mcs_set[0] = 0xFF;
+ if (sys_cfg->bandcfg.chan2Offset)
+ sys_cfg->supported_mcs_set[4] = 0x01;
+ else
+ sys_cfg->supported_mcs_set[4] = 0x0;
+ if (fw_info.usr_dev_mcs_support == HT_STREAM_MODE_2X2)
+ sys_cfg->supported_mcs_set[1] = 0xFF;
+ else
+ sys_cfg->supported_mcs_set[1] = 0;
+ }
+
+done:
+ LEAVE();
+ return status;
+}
+
+#define VHT_CAP_11AC_MASK 0x007fffff
+
+/**
+ * @brief enable/disable 11AC
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ * @param vht20_40 Enable VHT 20 MHz or 40 MHz band
+ * @param vhtcap_ie A pointer to vht capability IE
+ *
+ * @return 0--success, otherwise failure
+ */
+int woal_uap_set_11ac_status(moal_private *priv, t_u8 action, t_u8 vht20_40,
+ IEEEtypes_VHTCap_t *vhtcap_ie)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ac_cfg *cfg_11ac = NULL;
+ mlan_fw_info fw_info;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
+ cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
+ req->req_id = MLAN_IOCTL_11AC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
+ cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_TXRX;
+
+ /*
+ * p2p GO (negotiation or auto GO) cases, wpa_supplicant will download
+ * invalid vht capability with value 0 in beacon parameters, so for p2p
+ * GO case (vht_cap_info = 0), driver will use hardware 11ac vht
+ * capability value instead of up layer value.
+ */
+ if (vhtcap_ie && vhtcap_ie->vht_cap.vht_cap_info != 0) {
+ cfg_11ac->param.vht_cfg.vht_cap_info =
+ woal_le32_to_cpu(vhtcap_ie->vht_cap.vht_cap_info);
+ /** todo mcs configuration */
+ } else {
+ cfg_11ac->param.vht_cfg.vht_cap_info =
+ fw_info.usr_dot_11ac_dev_cap_a;
+ }
+ if (action == MLAN_ACT_DISABLE) {
+ cfg_11ac->param.vht_cfg.bwcfg = MFALSE;
+ cfg_11ac->param.vht_cfg.vht_cap_info &= ~VHT_CAP_11AC_MASK;
+ cfg_11ac->param.vht_cfg.vht_rx_mcs =
+ cfg_11ac->param.vht_cfg.vht_tx_mcs = 0xffff;
+ cfg_11ac->param.vht_cfg.skip_usr_11ac_mcs_cfg = MTRUE;
+ } else {
+ if (vht20_40)
+ cfg_11ac->param.vht_cfg.bwcfg = MFALSE;
+ else
+ cfg_11ac->param.vht_cfg.bwcfg = MTRUE;
+ cfg_11ac->param.vht_cfg.vht_cap_info &=
+ ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
+ cfg_11ac->param.vht_cfg.vht_tx_mcs =
+ fw_info.usr_dot_11ac_mcs_support >> 16;
+ cfg_11ac->param.vht_cfg.vht_rx_mcs =
+ fw_info.usr_dot_11ac_mcs_support & 0xffff;
+ cfg_11ac->param.vht_cfg.skip_usr_11ac_mcs_cfg = MTRUE;
+ }
+ PRINTM(MCMND,
+ "Uap:11ac=%d vht_cap_info=0x%x, vht_tx_mcs=0x%x, vht_rx_mcs=0x%x\n",
+ action, cfg_11ac->param.vht_cfg.vht_cap_info,
+ cfg_11ac->param.vht_cfg.vht_tx_mcs,
+ cfg_11ac->param.vht_cfg.vht_rx_mcs);
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set 11ax cfg
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param he_cfg a pointer to mlan_ds_11ax_he_cfg
+ *
+ * @return 0--success, otherwise failure
+ */
+int woal_11ax_cfg(moal_private *priv, t_u8 action, mlan_ds_11ax_he_cfg *he_cfg)
+{
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11ax_cfg *cfg_11ax = NULL;
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ cfg_11ax = (mlan_ds_11ax_cfg *)req->pbuf;
+ cfg_11ax->sub_command = MLAN_OID_11AX_HE_CFG;
+ req->req_id = MLAN_IOCTL_11AX_CFG;
+ req->action = action;
+ moal_memcpy_ext(priv->phandle, &cfg_11ax->param.he_cfg, he_cfg,
+ sizeof(mlan_ds_11ax_he_cfg),
+ sizeof(mlan_ds_11ax_he_cfg));
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, he_cfg, &cfg_11ax->param.he_cfg,
+ sizeof(mlan_ds_11ax_he_cfg),
+ sizeof(mlan_ds_11ax_he_cfg));
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief enable/disable 11AX
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ * @param band band config
+ * @param hecap_ie
+ *
+ * @return 0--success, otherwise failure
+ */
+int woal_uap_set_11ax_status(moal_private *priv, t_u8 action, t_u8 band,
+ IEEEtypes_HECap_t *hecap_ie)
+{
+ mlan_fw_info fw_info;
+ int ret = 0;
+ mlan_ds_11ax_he_cfg he_cfg;
+ ENTER();
+
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if ((band == BAND_5GHZ && !(fw_info.fw_bands & BAND_AAX)) ||
+ (band == BAND_2GHZ && !(fw_info.fw_bands & BAND_GAX))) {
+ PRINTM(MERROR, "fw doesn't support 11ax\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&he_cfg, 0, sizeof(he_cfg));
+ if (band == BAND_5GHZ)
+ he_cfg.band = MBIT(1);
+ else if (band == BAND_2GHZ)
+ he_cfg.band = MBIT(0);
+ else {
+ PRINTM(MERROR, "Invalid band!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (woal_11ax_cfg(priv, MLAN_ACT_GET, &he_cfg)) {
+ PRINTM(MERROR, "Fail to get 11ax cfg!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (hecap_ie) {
+ DBG_HEXDUMP(MCMD_D, "hecap_ie", (t_u8 *)hecap_ie,
+ hecap_ie->ieee_hdr.len +
+ sizeof(IEEEtypes_Header_t));
+ he_cfg.he_cap.id = hecap_ie->ieee_hdr.element_id;
+ he_cfg.he_cap.len = hecap_ie->ieee_hdr.len;
+ moal_memcpy_ext(priv->phandle, &he_cfg.he_cap.ext_id,
+ &hecap_ie->ext_id, he_cfg.he_cap.len,
+ he_cfg.he_cap.len);
+ }
+ if (action == MLAN_ACT_DISABLE) {
+ if (he_cfg.he_cap.len &&
+ (he_cfg.he_cap.ext_id == HE_CAPABILITY)) {
+ memset(he_cfg.he_cap.he_txrx_mcs_support, 0xff,
+ sizeof(he_cfg.he_cap.he_txrx_mcs_support));
+ } else {
+ PRINTM(MCMND, "11ax already disabled\n");
+ goto done;
+ }
+ }
+ DBG_HEXDUMP(MCMD_D, "HE_CFG ", (t_u8 *)&he_cfg, sizeof(he_cfg));
+ ret = woal_11ax_cfg(priv, MLAN_ACT_SET, &he_cfg);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Parse AP configuration from ASCII string
+ *
+ * @param priv A pointer to moal_private structure
+ * @param ap_cfg A pointer to mlan_uap_bss_param structure
+ * @param buf A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_ap_cfg_parse_data(moal_private *priv, mlan_uap_bss_param *ap_cfg,
+ char *buf)
+{
+ int ret = 0, atoi_ret;
+ int set_sec = 0, set_key = 0, set_chan = 0;
+ int set_preamble = 0, set_scb = 0, set_ssid = 0;
+ char *begin = buf, *value = NULL, *opt = NULL;
+
+ ENTER();
+
+ while (begin) {
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (opt && !strncmp(opt, "END", strlen("END"))) {
+ if (!ap_cfg->ssid.ssid_len) {
+ PRINTM(MERROR,
+ "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Parsing terminated by string END\n");
+ break;
+ }
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) {
+ if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) {
+ PRINTM(MERROR,
+ "ASCII_CMD: %s not matched with AP_CFG\n",
+ value);
+ ret = -EFAULT;
+ goto done;
+ }
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR,
+ "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "SSID", strlen("SSID"))) {
+ if (set_ssid) {
+ PRINTM(MWARN,
+ "Skipping SSID, found again!\n");
+ continue;
+ }
+ if (strlen(value) >= MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR,
+ "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->ssid.ssid_len = strlen(value);
+ strncpy((char *)ap_cfg->ssid.ssid, value,
+ MIN(MLAN_MAX_SSID_LENGTH - 1,
+ strlen(value)));
+ PRINTM(MINFO, "ssid=%s, len=%d\n",
+ ap_cfg->ssid.ssid,
+ (int)ap_cfg->ssid.ssid_len);
+ set_ssid = 1;
+ } else {
+ PRINTM(MERROR,
+ "AP_CFG: Invalid option %s, expect SSID\n",
+ opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (!strncmp(opt, "SEC", strlen("SEC"))) {
+ if (set_sec) {
+ PRINTM(MWARN, "Skipping SEC, found again!\n");
+ continue;
+ }
+ if (!strnicmp(value, "open", strlen("open"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else if (!strnicmp(value, "wpa2-psk",
+ strlen("wpa2-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA2;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 =
+ CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ } else if (!strnicmp(value, "wpa-psk",
+ strlen("wpa-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_TKIP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ } else if (!strnicmp(value, "wep128",
+ strlen("wep128"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_STATIC_WEP;
+ } else {
+ PRINTM(MERROR,
+ "AP_CFG: Invalid value=%s for %s\n",
+ value, opt);
+ ret = -EFAULT;
+ goto done;
+ }
+ set_sec = 1;
+ } else if (!strncmp(opt, "KEY", strlen("KEY"))) {
+ if (set_key) {
+ PRINTM(MWARN, "Skipping KEY, found again!\n");
+ continue;
+ }
+ if (set_sec &&
+ ap_cfg->protocol == PROTOCOL_STATIC_WEP) {
+ if (strlen(value) != MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR,
+ "Invalid WEP KEY length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->wep_cfg.key0.key_index = 0;
+ ap_cfg->wep_cfg.key0.is_default = 1;
+ ap_cfg->wep_cfg.key0.length = strlen(value);
+ moal_memcpy_ext(
+ priv->phandle, ap_cfg->wep_cfg.key0.key,
+ value, strlen(value),
+ sizeof(ap_cfg->wep_cfg.key0.key));
+ set_key = 1;
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2 &&
+ ap_cfg->protocol != PROTOCOL_WPA) {
+ PRINTM(MWARN,
+ "Warning! No KEY for open mode\n");
+ set_key = 1;
+ continue;
+ }
+ if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(value) > MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PSK/PMK length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->wpa_cfg.length = strlen(value);
+ moal_memcpy_ext(priv->phandle,
+ ap_cfg->wpa_cfg.passphrase, value,
+ strlen(value),
+ sizeof(ap_cfg->wpa_cfg.passphrase));
+ set_key = 1;
+ } else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) {
+ if (set_chan) {
+ PRINTM(MWARN,
+ "Skipping CHANNEL, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) {
+ PRINTM(MERROR,
+ "AP_CFG: Channel must be between 1 and %d"
+ "(both included)\n",
+ MLAN_MAX_CHANNEL);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->channel = atoi_ret;
+ set_chan = 1;
+ } else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) {
+ if (set_preamble) {
+ PRINTM(MWARN,
+ "Skipping PREAMBLE, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* This is a READ only value from FW, so we
+ * can not set this and pass it successfully */
+ set_preamble = 1;
+ } else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) {
+ if (set_scb) {
+ PRINTM(MWARN,
+ "Skipping MAX_SCB, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) {
+ PRINTM(MERROR,
+ "AP_CFG: MAX_SCB must be between 1 to %d "
+ "(both included)\n",
+ MAX_STA_COUNT);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->max_sta_count = (t_u16)atoi_ret;
+ set_scb = 1;
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set AP configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param data A pointer to user data
+ * @param len Length of buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_set_ap_cfg(moal_private *priv, t_u8 *data, int len)
+{
+ int ret = 0;
+ static char buf[MAX_BUF_LEN];
+ mlan_uap_bss_param *sys_config = NULL;
+ int restart = 0;
+
+ ENTER();
+
+#define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */
+ if ((len - 1) <= MIN_AP_CFG_CMD_LEN) {
+ PRINTM(MERROR, "Invalid length of command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(buf, 0, MAX_BUF_LEN);
+ moal_memcpy_ext(priv->phandle, buf, data, len, sizeof(buf) - 1);
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ woal_uap_get_bss_param(priv, sys_config, MOAL_IOCTL_WAIT);
+
+ /* Setting the default values */
+ sys_config->channel = 6;
+ sys_config->preamble_type = 0;
+
+ ret = woal_uap_ap_cfg_parse_data(priv, sys_config, buf);
+ if (ret)
+ goto done;
+
+ /* If BSS already started stop it first and restart
+ * after changing the setting */
+ if (priv->bss_started == MTRUE) {
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ if (ret)
+ goto done;
+ restart = 1;
+ }
+
+ /* If the security mode is configured as WEP or WPA-PSK,
+ * it will disable 11n automatically, and if configured as
+ * open(off) or wpa2-psk, it will automatically enable 11n */
+ if ((sys_config->protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config->protocol == PROTOCOL_WPA)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(priv, sys_config,
+ MLAN_ACT_DISABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(priv, sys_config,
+ MLAN_ACT_ENABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Start the BSS after successful configuration */
+ if (restart)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+
+done:
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get ap scan channel list
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param scan_channels A pointer to mlan_uap_scan_channels structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_get_ap_scan_channels(moal_private *priv, t_u16 action,
+ mlan_uap_scan_channels *scan_channels)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_SCAN_CHANNELS;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.ap_scan_channels,
+ scan_channels, sizeof(mlan_uap_scan_channels),
+ sizeof(bss->param.ap_scan_channels));
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, scan_channels,
+ &bss->param.ap_scan_channels,
+ sizeof(mlan_uap_scan_channels),
+ sizeof(mlan_uap_scan_channels));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get uap channel
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param wait_option wait option
+ * @param uap_channel A pointer to mlan_uap_channel structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_get_ap_channel(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ chan_band_info *uap_channel)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ moal_memcpy_ext(priv->phandle, &bss->param.ap_channel, uap_channel,
+ sizeof(chan_band_info), sizeof(bss->param.ap_channel));
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, uap_channel,
+ &bss->param.ap_channel, sizeof(chan_band_info),
+ sizeof(chan_band_info));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief start ACS scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_start_acs_scan(moal_private *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_ACS_SCAN;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ PRINTM(MIOCTL,
+ "ACS scan done: bandcfg:[chanBand=0x%x chanWidth=0x%x chan2Offset=0x%x scanMode=0x%x], channel=%d\n",
+ bss->param.ap_acs_scan.bandcfg.chanBand,
+ bss->param.ap_acs_scan.bandcfg.chanWidth,
+ bss->param.ap_acs_scan.bandcfg.chan2Offset,
+ bss->param.ap_acs_scan.bandcfg.scanMode,
+ bss->param.ap_acs_scan.chan);
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brie check if we need do ACS scan
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_do_acs_check(moal_private *priv)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_uap_bss_param *sys_config = NULL;
+ mlan_uap_scan_channels *scan_channels = NULL;
+ chan_band_info uap_channel;
+ ENTER();
+
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ PRINTM(MERROR, "Fail to get sys config data\n");
+ kfree(sys_config);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ if (!(sys_config->bandcfg.scanMode == SCAN_MODE_ACS)) {
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+ }
+ scan_channels = kzalloc(sizeof(mlan_uap_scan_channels), GFP_ATOMIC);
+ if (scan_channels == NULL) {
+ PRINTM(MERROR, "Fail to alloc scan channels buffer\n");
+ kfree(sys_config);
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+ scan_channels->remove_nop_channel = MTRUE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_ap_scan_channels(priv, MLAN_ACT_GET, scan_channels)) {
+ PRINTM(MERROR, "Fail to get scan channels\n");
+ goto done;
+ }
+
+ if (scan_channels->num_remvoed_channel && scan_channels->num_of_chan) {
+ scan_channels->remove_nop_channel = 0;
+ /** set back new channel list after remove nop channels */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_ap_scan_channels(priv, MLAN_ACT_SET,
+ scan_channels)) {
+ PRINTM(MERROR, "Fail to get scan channels\n");
+ goto done;
+ }
+ }
+ if (scan_channels->num_of_chan)
+ ret = woal_start_acs_scan(priv);
+ else
+ ret = MLAN_STATUS_FAILURE;
+ /** set to default channel 6 when 5G ACS is configured */
+ if ((ret != MLAN_STATUS_SUCCESS) &&
+ (sys_config->bandcfg.chanBand == BAND_5GHZ)) {
+ memset(&uap_channel, 0, sizeof(uap_channel));
+ uap_channel.bandcfg.chanBand = DEFAULT_UAP_BAND;
+ uap_channel.channel = DEFAULT_UAP_CHANNEL;
+ ret = woal_set_get_ap_channel(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT, &uap_channel);
+ }
+done:
+ kfree(scan_channels);
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS control ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param data BSS control type
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_bss_ctrl(moal_private *priv, t_u8 wait_option, int data)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data);
+ if ((data != UAP_BSS_START) && (data != UAP_BSS_STOP) &&
+ (data != UAP_BSS_RESET)) {
+ PRINTM(MERROR, "Invalid parameter: %d\n", data);
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ switch (data) {
+ case UAP_BSS_START:
+ if (priv->bss_started == MTRUE) {
+ PRINTM(MWARN, "Warning: BSS already started!\n");
+ /* goto done; */
+ } else if (!priv->uap_host_based
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ || moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)
+#endif
+ ) {
+ woal_do_acs_check(priv);
+ /* about to start bss: issue channel check */
+ status = woal_11h_channel_check_ioctl(priv,
+ MOAL_IOCTL_WAIT);
+ if (status) {
+ PRINTM(MMSG, "11h channel check fails\n");
+ status = MLAN_STATUS_FAILURE;
+ ret = -1;
+ goto done;
+ }
+ }
+ bss->sub_command = MLAN_OID_BSS_START;
+ if (priv->uap_host_based) {
+ bss->param.host_based |= UAP_FLAG_HOST_BASED;
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
+ bss->param.host_based |= UAP_FLAG_HOST_MLME;
+#endif
+#endif
+ }
+ break;
+ case UAP_BSS_STOP:
+ if (priv->bss_started == MFALSE) {
+ PRINTM(MWARN, "Warning: BSS already stopped!\n");
+ /* This is a situation where CAC it started and BSS
+ * start is dealyed and before CAC timer expires BSS
+ * stop is triggered.
+ *
+ * Do not skip sending the BSS_STOP command since there
+ * are many routines triggered on BSS_STOP command
+ * response.
+ */
+ woal_cancel_cac_block(priv);
+ }
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ break;
+ case UAP_BSS_RESET:
+ bss->sub_command = MLAN_OID_UAP_BSS_RESET;
+ woal_cancel_cac_block(priv);
+ break;
+ }
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_FAILURE) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (data == UAP_BSS_STOP || data == UAP_BSS_RESET) {
+ priv->bss_started = MFALSE;
+ woal_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ if (data == UAP_BSS_RESET)
+ woal_request_set_mac_address(priv, wait_option);
+ woal_flush_tcp_sess_queue(priv);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ * @return N/A
+ */
+void woal_uap_set_multicast_list(struct net_device *dev)
+{
+ ENTER();
+
+ LEAVE();
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+ ENTER();
+ switch (cmd) {
+ case WOAL_ANDROID_DEF_CMD:
+ /** android default ioctl ID is SIOCDEVPRIVATE + 1 */
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ case UAP_IOCTL_CMD:
+ ret = woal_uap_ioctl(dev, req);
+ break;
+ case UAP_POWER_MODE:
+ ret = woal_uap_power_mode_ioctl(dev, req);
+ break;
+ case UAP_BSS_CTRL:
+ ret = woal_uap_bss_ctrl_ioctl(dev, req);
+ break;
+ case UAP_WAPI_MSG:
+ ret = woal_uap_set_wapi(dev, req);
+ break;
+ case UAP_BSS_CONFIG:
+ ret = woal_uap_bss_cfg_ioctl(dev, req);
+ break;
+ case UAP_STA_DEAUTH:
+ ret = woal_uap_sta_deauth_ioctl(dev, req);
+ break;
+ case UAP_RADIO_CTL:
+ ret = woal_uap_radio_ctl(dev, req);
+ break;
+ case UAP_REPORT_MIC_ERR:
+ ret = woal_uap_report_mic_ioctl(dev, req);
+ break;
+ case UAP_SET_KEY:
+ ret = woal_uap_set_key_ioctl(dev, req);
+ break;
+ case UAPHOSTPKTINJECT:
+ ret = woal_send_host_packet(dev, req);
+ break;
+ case UAP_GET_STA_LIST:
+ ret = woal_uap_get_sta_list_ioctl(dev, req);
+ break;
+ case UAP_CUSTOM_IE:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case UAP_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ default:
+#ifdef UAP_WEXT
+ ret = woal_uap_do_priv_ioctl(dev, req, cmd);
+#else
+ ret = -EOPNOTSUPP;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+#ifdef CONFIG_PROC_FS
+/**
+ * @brief Get version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void woal_uap_get_version(moal_private *priv, char *version, int max_len)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return;
+ }
+
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "MOAL UAP VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ snprintf(version, max_len, priv->phandle->driver_version,
+ info->param.ver_ext.version_str);
+ }
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return;
+}
+#endif
+
+/**
+ * @brief Get uap statistics
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ustats A pointer to mlan_ds_uap_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
+ * success, otherwise fail
+ */
+mlan_status woal_uap_get_stats(moal_private *priv, t_u8 wait_option,
+ mlan_ds_uap_stats *ustats)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_get_info *)req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (ustats)
+ moal_memcpy_ext(priv->phandle, ustats,
+ &info->param.ustats,
+ sizeof(mlan_ds_uap_stats),
+ sizeof(mlan_ds_uap_stats));
+#ifdef UAP_WEXT
+ priv->w_stats.discard.fragment =
+ info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc =
+ info->param.ustats.ack_failure_count;
+#endif
+ }
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get system configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param ap_wmm_para A pointer to wmm_parameter_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_get_ap_wmm_para(moal_private *priv, t_u16 action,
+ wmm_parameter_t *ap_wmm_para)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_CFG_WMM_PARAM;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &bss->param.ap_wmm_para,
+ ap_wmm_para, sizeof(wmm_parameter_t),
+ sizeof(bss->param.ap_wmm_para));
+
+ ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (bss->param.ap_wmm_para.reserved != MLAN_STATUS_COMPLETE) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, ap_wmm_para,
+ &bss->param.ap_wmm_para,
+ sizeof(wmm_parameter_t),
+ sizeof(wmm_parameter_t));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get system configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param wait_option Wait option
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_set_get_sys_config(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ mlan_uap_bss_param *sys_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET)
+ moal_memcpy_ext(priv->phandle, &bss->param.bss_config, sys_cfg,
+ sizeof(mlan_uap_bss_param),
+ sizeof(bss->param.bss_config));
+
+ ret = woal_request_ioctl(priv, req, wait_option);
+ if (ret != MLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (action == MLAN_ACT_GET)
+ moal_memcpy_ext(priv->phandle, sys_cfg, &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param),
+ sizeof(mlan_uap_bss_param));
+
+done:
+ if (ret != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set invalid data for each member of mlan_uap_bss_param
+ * structure
+ *
+ * @param config A pointer to mlan_uap_bss_param structure
+ *
+ * @return N/A
+ */
+void woal_set_sys_config_invalid_data(mlan_uap_bss_param *config)
+{
+ ENTER();
+
+ memset(config, 0, sizeof(mlan_uap_bss_param));
+ config->bcast_ssid_ctl = 0x7F;
+ config->radio_ctl = 0x7F;
+ config->dtim_period = 0x7F;
+ config->beacon_period = 0x7FFF;
+ config->tx_data_rate = 0x7FFF;
+ config->mcbc_data_rate = 0x7FFF;
+ config->tx_power_level = 0x7F;
+ config->tx_antenna = 0x7F;
+ config->rx_antenna = 0x7F;
+ config->pkt_forward_ctl = 0x7F;
+ config->max_sta_count = 0x7FFF;
+ config->auth_mode = 0x7F;
+ config->sta_ageout_timer = 0x7FFFFFFF;
+ config->pairwise_update_timeout = 0x7FFFFFFF;
+ config->pwk_retries = 0x7FFFFFFF;
+ config->groupwise_update_timeout = 0x7FFFFFFF;
+ config->gwk_retries = 0x7FFFFFFF;
+ config->mgmt_ie_passthru_mask = 0x7FFFFFFF;
+ config->ps_sta_ageout_timer = 0x7FFFFFFF;
+ config->rts_threshold = 0x7FFF;
+ config->frag_threshold = 0x7FFF;
+ config->retry_limit = 0x7FFF;
+ config->filter.filter_mode = 0x7FFF;
+ config->filter.mac_count = 0x7FFF;
+ config->wpa_cfg.rsn_protection = 0x7F;
+ config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF;
+ config->enable_2040coex = 0x7F;
+ config->wmm_para.qos_info = 0x7F;
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.h
new file mode 100644
index 000000000000..b60dfefeed02
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap.h
@@ -0,0 +1,581 @@
+/** @file moal_uap.h
+ *
+ * @brief This file contains uap driver specific defines etc.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 02/02/2009: initial version
+********************************************************/
+
+#ifndef _MOAL_UAP_H
+#define _MOAL_UAP_H
+
+/** Maximum buffer length for WOAL_UAP_SET_GET_256_CHAR */
+#define MAX_BUF_LEN 256
+
+/** Private command ID to send ioctl */
+#define UAP_IOCTL_CMD (SIOCDEVPRIVATE + 2)
+/** Updating ADDBA variables */
+#define UAP_ADDBA_PARA 0
+/** Updating priority table for AMPDU/AMSDU */
+#define UAP_AGGR_PRIOTBL 1
+/** Updating addbareject table */
+
+#define UAP_ADDBA_REJECT 2
+/** Get FW INFO */
+#define UAP_FW_INFO 4
+/** Updating Deep sleep variables */
+#define UAP_DEEP_SLEEP 3
+/** Tx data pause subcommand */
+#define UAP_TX_DATA_PAUSE 5
+#ifdef SDIO
+/** sdcmd52 read write subcommand */
+#define UAP_SDCMD52_RW 6
+#endif
+/** snmp mib subcommand */
+#define UAP_SNMP_MIB 7
+/** domain info subcommand */
+#define UAP_DOMAIN_INFO 8
+/** TX beamforming configuration */
+#define UAP_TX_BF_CFG 9
+/** dfs testing subcommand */
+#define UAP_DFS_TESTING 10
+/** sub command ID to set/get Host Sleep configuration */
+#define UAP_HS_CFG 11
+/** sub command ID to set/get Host Sleep Parameters */
+#define UAP_HS_SET_PARA 12
+
+/** Management Frame Control Mask */
+#define UAP_MGMT_FRAME_CONTROL 13
+
+#define UAP_TX_RATE_CFG 14
+
+/** Subcommand ID to set/get antenna configuration */
+#define UAP_ANTENNA_CFG 15
+
+#define UAP_DFS_REPEATER_MODE 16
+
+#define UAP_CAC_TIMER_STATUS 17
+
+/** Skip CAC */
+#define UAP_SKIP_CAC 18
+
+#define UAP_HT_TX_CFG 19
+
+#define UAP_VHT_CFG 20
+
+#define UAP_HT_STREAM_CFG 21
+
+#define UAP_OPERATION_CTRL 22
+
+#define UAP_CHAN_SWITCH_COUNT_CFG 23
+#define UAP_BAND_STEER 24
+
+#define UAP_BEACON_STUCK_DETECT 25
+
+/** Private command ID to Power Mode */
+#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3)
+
+/** Private command id to start/stop/reset bss */
+#define UAP_BSS_CTRL (SIOCDEVPRIVATE + 4)
+/** BSS START */
+#define UAP_BSS_START 0
+/** BSS STOP */
+#define UAP_BSS_STOP 1
+/** BSS RESET */
+#define UAP_BSS_RESET 2
+
+/** wapi_msg */
+typedef struct _wapi_msg {
+ /** message type */
+ t_u16 msg_type;
+ /** message len */
+ t_u16 msg_len;
+ /** message */
+ t_u8 msg[96];
+} wapi_msg;
+
+/* wapi key msg */
+typedef struct _wapi_key_msg {
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+ /** pad */
+ t_u8 pad;
+ /** key id */
+ t_u8 key_id;
+ /** key */
+ t_u8 key[32];
+} wapi_key_msg;
+
+/** Private command ID to set wapi info */
+#define UAP_WAPI_MSG (SIOCDEVPRIVATE + 10)
+/** set wapi flag */
+#define P80211_PACKET_WAPIFLAG 0x0001
+/** set wapi key */
+#define P80211_PACKET_SETKEY 0x0003
+/** wapi mode psk */
+#define WAPI_MODE_PSK 0x04
+/** wapi mode certificate */
+#define WAPI_MODE_CERT 0x08
+
+typedef struct _tx_rate_cfg_t {
+ /** sub command */
+ int subcmd;
+ /** Action */
+ int action;
+ /** Rate format */
+ int rate_format;
+ /** Rate configured */
+ int rate;
+ /** nss */
+ int nss;
+ /** user_data_cnt */
+ int user_data_cnt;
+ /** Rate bitmap */
+ t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ /** Rate Setting */
+ t_u16 rate_setting;
+} tx_rate_cfg_t;
+
+/** ant_cfg structure */
+typedef struct _ant_cfg_t {
+ /** Subcommand */
+ int subcmd;
+ /** Action */
+ int action;
+ /** TX mode configured */
+ int tx_mode;
+ /** RX mode configured */
+ int rx_mode;
+} ant_cfg_t;
+
+/** htstream_cfg structure */
+typedef struct _htstream_cfg_t {
+ /** Subcommand */
+ int subcmd;
+ /** Action */
+ int action;
+ /** HT stream configuration */
+ t_u32 stream_cfg;
+} htstream_cfg_t;
+
+/* dfs repeater mode */
+typedef struct _dfs_repeater_mode {
+ /** subcmd */
+ t_u32 subcmd;
+ /** set/get */
+ t_u32 action;
+ /** mode */
+ t_u32 mode;
+} dfs_repeater_mode;
+
+/* */
+typedef struct _cac_timer_status {
+ /** subcmd */
+ t_u32 subcmd;
+ /** set/get */
+ t_u32 action;
+ /** mode */
+ t_u32 mode;
+} cac_timer_status;
+
+/** skip_cac parameters */
+typedef struct _skip_cac_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable deepsleep*/
+ t_u16 skip_cac;
+} skip_cac_para;
+
+/** radio control command */
+#define UAP_RADIO_CTL (SIOCDEVPRIVATE + 5)
+
+/** Private command ID to BSS config */
+#define UAP_BSS_CONFIG (SIOCDEVPRIVATE + 6)
+
+/** deauth station */
+#define UAP_STA_DEAUTH (SIOCDEVPRIVATE + 7)
+
+/** enable UAP report mic error */
+#define UAP_REPORT_MIC_ERR (SIOCDEVPRIVATE + 8)
+/** uap set key */
+#define UAP_SET_KEY (SIOCDEVPRIVATE + 9)
+/** encrypt key */
+typedef struct _encrypt_key {
+ /** Key index */
+ t_u32 key_index;
+ /** Key length */
+ t_u32 key_len;
+ /** Key */
+ t_u8 key_material[MLAN_MAX_KEY_LENGTH];
+ /** mac address */
+ t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
+} encrypt_key;
+
+/** pkt_header */
+typedef struct _pkt_header {
+ /** pkt_len */
+ u32 pkt_len;
+ /** pkt_type */
+ u32 TxPktType;
+ /** tx control */
+ u32 TxControl;
+} pkt_header;
+/** uap get station list */
+#define UAP_GET_STA_LIST (SIOCDEVPRIVATE + 11)
+/** Packet inject command ioctl number */
+#define UAPHOSTPKTINJECT WOAL_MGMT_FRAME_TX_IOCTL
+
+/** Private command ID to set/get custom IE buffer */
+#define UAP_CUSTOM_IE (SIOCDEVPRIVATE + 13)
+
+/** HS WAKE UP event id */
+#define UAP_EVENT_ID_HS_WAKEUP 0x80000001
+/** HS_ACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_ACTIVATED 0x80000002
+/** HS DEACTIVATED event id */
+#define UAP_EVENT_ID_DRV_HS_DEACTIVATED 0x80000003
+
+/** Host sleep flag set */
+#define HS_CFG_FLAG_GET 0
+/** Host sleep flag get */
+#define HS_CFG_FLAG_SET 1
+/** Host sleep flag for condition */
+#define HS_CFG_FLAG_CONDITION 2
+/** Host sleep flag for GPIO */
+#define HS_CFG_FLAG_GPIO 4
+/** Host sleep flag for Gap */
+#define HS_CFG_FLAG_GAP 8
+/** Host sleep flag for all */
+#define HS_CFG_FLAG_ALL 0x0f
+/** Host sleep mask to get condition */
+#define HS_CFG_CONDITION_MASK 0x0f
+
+/** ds_hs_cfg */
+typedef struct _ds_hs_cfg {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Bit0: 0 - Get, 1 Set
+ * Bit1: 1 - conditions is valid
+ * Bit2: 2 - gpio is valid
+ * Bit3: 3 - gap is valid
+ */
+ t_u32 flags;
+ /** Host sleep config condition */
+ /** Bit0: non-unicast data
+ * Bit1: unicast data
+ * Bit2: mac events
+ * Bit3: magic packet
+ */
+ t_u32 conditions;
+ /** GPIO */
+ t_u32 gpio;
+ /** Gap in milliseconds */
+ t_u32 gap;
+} ds_hs_cfg;
+
+/** Private command ID to get BSS type */
+#define UAP_GET_BSS_TYPE (SIOCDEVPRIVATE + 15)
+
+/** addba_param */
+typedef struct _addba_param {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** block ack timeout for ADDBA request */
+ t_u32 timeout;
+ /** Buffer size for ADDBA request */
+ t_u32 txwinsize;
+ /** Buffer size for ADDBA response */
+ t_u32 rxwinsize;
+ /** amsdu for ADDBA request */
+ t_u8 txamsdu;
+ /** amsdu for ADDBA response */
+ t_u8 rxamsdu;
+} addba_param;
+
+/** aggr_prio_tbl */
+typedef struct _aggr_prio_tbl {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** ampdu priority table */
+ t_u8 ampdu[MAX_NUM_TID];
+ /** amsdu priority table */
+ t_u8 amsdu[MAX_NUM_TID];
+} aggr_prio_tbl;
+
+/** addba_reject parameters */
+typedef struct _addba_reject_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** BA Reject paramters */
+ t_u8 addba_reject[MAX_NUM_TID];
+} addba_reject_para;
+
+/** fw_info */
+typedef struct _fw_info {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Get */
+ t_u32 action;
+ /** Firmware release number */
+ t_u32 fw_release_number;
+ /** Device support for MIMO abstraction of MCSs */
+ t_u8 hw_dev_mcs_support;
+ /** fw_bands*/
+ t_u8 fw_bands;
+ /** Region Code */
+ t_u16 region_code;
+ /** 802.11n device capabilities */
+ t_u32 hw_dot_11n_dev_cap;
+} fw_info;
+
+typedef struct _ht_tx_cfg_para_hdr {
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} ht_tx_cfg_para_hdr;
+
+typedef struct _tx_bf_cfg_para_hdr {
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} tx_bf_cfg_para_hdr;
+
+typedef struct _vht_cfg_para_hdr {
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} vht_cfg_para_hdr;
+
+typedef struct _uap_oper_para_hdr {
+ /** Sub command */
+ t_u32 subcmd;
+ /** Action: Set/Get */
+ t_u32 action;
+} uap_oper_para_hdr;
+
+#ifdef SDIO
+/** sdcmd52rw parameters */
+typedef struct _sdcmd52_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Write /Read */
+ t_u32 action;
+ /** Command 52 paramters */
+ t_u8 cmd52_params[3];
+} sdcmd52_para;
+#endif
+
+/** deep_sleep parameters */
+typedef struct _deep_sleep_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable deepsleep*/
+ t_u16 deep_sleep;
+ /** idle_time */
+ t_u16 idle_time;
+} deep_sleep_para;
+
+/** band_steering parameters */
+typedef struct _band_steer_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u8 action;
+ /** enable/disable band steering*/
+ t_u8 state;
+ /** Probe Response will be blocked to 2G channel for first
+ * block_2g_prb_req probe requests*/
+ t_u8 block_2g_prb_req;
+ /** When band steering is enabled, limit the btm request sent to STA at
+ * <max_btm_req_allowed>*/
+ t_u8 max_btm_req_allowed;
+
+} band_steer_para;
+
+/** beacon stuck detect mechanism parameters */
+typedef struct _beacon_stuck_detect_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u8 action;
+ /** No of beacon interval after which firmware will check if beacon Tx
+ * is going fine */
+ t_u8 beacon_stuck_detect_count;
+ /** Upon performing MAC reset, no of beacon interval after which
+ * firmware will check if recovery was successful */
+ t_u8 recovery_confirm_count;
+} beacon_stuck_detect_para;
+
+/** tx_data_pause parameters */
+typedef struct _tx_data_pause_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** enable/disable Tx data pause*/
+ t_u16 txpause;
+ /** Max number of TX buffer allowed for all PS client*/
+ t_u16 txbufcnt;
+} tx_data_pause_para;
+
+/** mgmt_frame_ctrl */
+typedef struct _mgmt_frame_ctrl {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** mask */
+ t_u32 mask;
+} mgmt_frame_ctrl;
+
+typedef struct _snmp_mib_para {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** oid to set/get */
+ t_u16 oid;
+ /** length of oid value */
+ t_u16 oid_val_len;
+ /** oid value to set/get */
+ t_u8 oid_value[];
+} snmp_mib_para;
+
+/** Max length for oid_value field */
+#define MAX_SNMP_VALUE_SIZE 128
+
+/** Oid for 802.11D enable/disable */
+#define OID_80211D_ENABLE 0x0009
+/** Oid for 802.11H enable/disable */
+#define OID_80211H_ENABLE 0x000a
+
+/** dfs_testing parameters */
+typedef struct _dfs_testing_param {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** user CAC period (msec) */
+ t_u32 usr_cac_period;
+ /** user NOP period (sec) */
+ t_u16 usr_nop_period;
+ /** don't change channel on radar */
+ t_u8 no_chan_change;
+ /** fixed channel to change to on radar */
+ t_u8 fixed_new_chan;
+ /** CAC restart */
+ t_u8 cac_restart;
+} dfs_testing_para;
+
+/** Channel switch count config */
+typedef struct _cscount_cfg_t {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** user channel switch count */
+ t_u8 cs_count;
+} cscount_cfg_t;
+
+/** domain_info parameters */
+typedef struct _domain_info_param {
+ /** subcmd */
+ t_u32 subcmd;
+ /** Set/Get */
+ t_u32 action;
+ /** domain_param TLV (incl. header) */
+ t_u8 tlv[];
+} domain_info_para;
+
+/** DOMAIN_INFO param sizes */
+#define TLV_HEADER_LEN (2 + 2)
+#define SUB_BAND_LEN 3
+#define MAX_SUB_BANDS 40
+
+/** MAX domain TLV length */
+#define MAX_DOMAIN_TLV_LEN \
+ (TLV_HEADER_LEN + COUNTRY_CODE_LEN + (SUB_BAND_LEN * MAX_SUB_BANDS))
+
+int woal_set_get_uap_power_mode(moal_private *priv, t_u32 action,
+ mlan_ds_ps_mgmt *ps_mgmt);
+void woal_uap_set_multicast_list(struct net_device *dev);
+int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+int woal_uap_bss_ctrl(moal_private *priv, t_u8 wait_option, int data);
+#ifdef UAP_CFG80211
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+int woal_uap_get_channel_nop_info(moal_private *priv, t_u8 wait_option,
+ pmlan_ds_11h_chan_nop_info ch_info);
+#endif
+#endif
+mlan_status woal_set_get_ap_channel(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ pchan_band_info uap_channel);
+#ifdef CONFIG_PROC_FS
+void woal_uap_get_version(moal_private *priv, char *version, int max_len);
+#endif
+mlan_status woal_uap_get_stats(moal_private *priv, t_u8 wait_option,
+ pmlan_ds_uap_stats ustats);
+#if defined(UAP_WEXT) || defined(UAP_CFG80211)
+extern struct iw_handler_def woal_uap_handler_def;
+struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev);
+/** IOCTL function for wireless private IOCTLs */
+int woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
+#endif
+/** Set invalid data for each member of mlan_uap_bss_param */
+void woal_set_sys_config_invalid_data(pmlan_uap_bss_param config);
+/** Set/Get system configuration parameters */
+mlan_status woal_set_get_sys_config(moal_private *priv, t_u16 action,
+ t_u8 wait_option,
+ mlan_uap_bss_param *sys_cfg);
+/** Set get AP wmm parameter */
+mlan_status woal_set_get_ap_wmm_para(moal_private *priv, t_u16 action,
+ wmm_parameter_t *ap_wmm_para);
+int woal_uap_set_ap_cfg(moal_private *priv, t_u8 *data, int len);
+int woal_uap_set_11ac_status(moal_private *priv, t_u8 action, t_u8 vht20_40,
+ IEEEtypes_VHTCap_t *vhtcap_ie);
+int woal_11ax_cfg(moal_private *priv, t_u8 action, mlan_ds_11ax_he_cfg *he_cfg);
+int woal_uap_set_11ax_status(moal_private *priv, t_u8 action, t_u8 band,
+ IEEEtypes_HECap_t *hecap_ie);
+int woal_set_uap_ht_tx_cfg(moal_private *priv, Band_Config_t bandcfg,
+ t_u16 ht_cap, t_u8 en);
+mlan_status woal_uap_set_11n_status(moal_private *priv,
+ mlan_uap_bss_param *sys_cfg, t_u8 action);
+#ifdef UAP_WEXT
+void woal_ioctl_get_uap_info_resp(moal_private *priv, pmlan_ds_get_info info);
+int woal_set_get_custom_ie(moal_private *priv, t_u16 mask, t_u8 *ie,
+ int ie_len);
+#endif /* UAP_WEXT */
+
+#endif /* _MOAL_UAP_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.c
new file mode 100644
index 000000000000..f065de43005b
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.c
@@ -0,0 +1,3259 @@
+/** @file moal_uap_cfg80211.c
+ *
+ * @brief This file contains the functions for uAP CFG80211.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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 "moal_cfg80211.h"
+#include "moal_uap_cfg80211.h"
+/** deauth reason code */
+#define REASON_CODE_DEAUTH_LEAVING 3
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief send deauth to station
+ *
+ * @param A pointer to moal_private
+ * @param mac A pointer to station mac address
+ * @param reason_code ieee deauth reason code
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_deauth_station(moal_private *priv, u8 *mac_addr,
+ u16 reason_code)
+{
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ moal_memcpy_ext(priv->phandle, bss->param.deauth_param.mac_addr,
+ mac_addr, MLAN_MAC_ADDR_LENGTH,
+ sizeof(bss->param.deauth_param.mac_addr));
+ bss->param.deauth_param.reason_code = reason_code;
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief send deauth to all station
+ *
+ * @param A pointer to moal_private
+ * @param mac A pointer to station mac address
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_deauth_all_station(moal_private *priv)
+{
+ int ret = -EFAULT;
+ int i = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return 0;
+ }
+ PRINTM(MIOCTL, "del all station\n");
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (!info->param.sta_list.sta_count)
+ goto done;
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ PRINTM(MIOCTL, "deauth station " MACSTR "\n",
+ MAC2STR(info->param.sta_list.info[i].mac_address));
+ ret = woal_deauth_station(
+ priv, info->param.sta_list.info[i].mac_address,
+ REASON_CODE_DEAUTH_LEAVING);
+ }
+ woal_sched_timeout(200);
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ return ret;
+}
+
+/**
+ * @brief Verify RSN IE
+ *
+ * @param rsn_ie Pointer RSN IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8 woal_check_rsn_ie(IEEEtypes_Rsn_t *rsn_ie,
+ mlan_uap_bss_param *sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = rsn_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Rsn_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 = 0;
+ sys_config->key_mgmt = 0;
+ /* check the group cipher */
+ switch (rsn_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(rsn_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (rsn_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |=
+ CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Rsn_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *)((u8 *)rsn_ie +
+ sizeof(IEEEtypes_Rsn_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left < (sizeof(wpa_suite_auth_key_mgmt_t) +
+ (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt |= KEY_MGMT_PSK;
+ break;
+ case RSN_AKM_PSK_SHA256:
+ sys_config->key_mgmt |= KEY_MGMT_PSK_SHA256;
+ break;
+ case RSN_AKM_SAE:
+ sys_config->key_mgmt |= KEY_MGMT_SAE;
+ break;
+ case RSN_AKM_OWE:
+ sys_config->key_mgmt |= KEY_MGMT_OWE;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Verify WPA IE
+ *
+ * @param wpa_ie Pointer WPA IE
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8 woal_check_wpa_ie(IEEEtypes_Wpa_t *wpa_ie,
+ mlan_uap_bss_param *sys_config)
+{
+ int left = 0;
+ int count = 0;
+ int i = 0;
+ wpa_suite_auth_key_mgmt_t *key_mgmt = NULL;
+ left = wpa_ie->len + 2;
+ if (left < sizeof(IEEEtypes_Wpa_t))
+ return MFALSE;
+ sys_config->wpa_cfg.group_cipher = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa = 0;
+ switch (wpa_ie->group_cipher.type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ count = le16_to_cpu(wpa_ie->pairwise_cipher.count);
+ for (i = 0; i < count; i++) {
+ switch (wpa_ie->pairwise_cipher.list[i].type) {
+ case WPA_CIPHER_TKIP:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ sys_config->wpa_cfg.pairwise_cipher_wpa |=
+ CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+ }
+ left -= sizeof(IEEEtypes_Wpa_t) + (count - 1) * sizeof(wpa_suite);
+ if (left < sizeof(wpa_suite_auth_key_mgmt_t))
+ return MFALSE;
+ key_mgmt =
+ (wpa_suite_auth_key_mgmt_t *)((u8 *)wpa_ie +
+ sizeof(IEEEtypes_Wpa_t) +
+ (count - 1) * sizeof(wpa_suite));
+ count = le16_to_cpu(key_mgmt->count);
+ if (left < (sizeof(wpa_suite_auth_key_mgmt_t) +
+ (count - 1) * sizeof(wpa_suite)))
+ return MFALSE;
+ for (i = 0; i < count; i++) {
+ switch (key_mgmt->list[i].type) {
+ case RSN_AKM_8021X:
+ sys_config->key_mgmt = KEY_MGMT_EAP;
+ break;
+ case RSN_AKM_PSK:
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ break;
+ }
+ }
+ return MTRUE;
+}
+
+/**
+ * @brief Find RSN/WPA IES
+ *
+ * @param ie Pointer IE buffer
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return MTRUE/MFALSE
+ */
+static t_u8 woal_find_wpa_ies(const t_u8 *ie, int len,
+ mlan_uap_bss_param *sys_config)
+{
+ int bytes_left = len;
+ const t_u8 *pcurrent_ptr = ie;
+ t_u16 total_ie_len;
+ t_u8 element_len;
+ t_u8 wpa2 = 0;
+ t_u8 wpa = 0;
+ t_u8 ret = MFALSE;
+ IEEEtypes_ElementId_e element_id;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ const t_u8 wpa_oui[4] = {0x00, 0x50, 0xf2, 0x01};
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR,
+ "InterpretIE: Error in processing IE, bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case RSN_IE:
+ wpa2 = woal_check_rsn_ie(
+ (IEEEtypes_Rsn_t *)pcurrent_ptr, sys_config);
+ break;
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ (pvendor_ie->vend_hdr.oui_type == wpa_oui[3])) {
+ wpa = woal_check_wpa_ie(
+ (IEEEtypes_Wpa_t *)pcurrent_ptr,
+ sys_config);
+ }
+ break;
+ default:
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+ if (wpa && wpa2) {
+ sys_config->protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa2) {
+ sys_config->protocol = PROTOCOL_WPA2;
+ ret = MTRUE;
+ } else if (wpa) {
+ sys_config->protocol = PROTOCOL_WPA;
+ ret = MTRUE;
+ }
+ return ret;
+}
+
+/**
+ * @brief Find and set WMM IES
+ *
+ * @param priv Pointer to moal_private
+ * @param ie Pointer IE buffer
+ * @param sys_config Pointer to mlan_uap_bss_param structure
+ *
+ * @return N/A
+ */
+static t_void woal_set_wmm_ies(moal_private *priv, const t_u8 *ie, int len,
+ mlan_uap_bss_param *sys_config)
+{
+ int bytes_left = len;
+ const t_u8 *pcurrent_ptr = ie;
+ t_u16 total_ie_len;
+ t_u8 element_len;
+ IEEEtypes_VendorSpecific_t *pvendor_ie;
+ IEEEtypes_ElementId_e element_id;
+ const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
+
+ while (bytes_left >= 2) {
+ element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
+ element_len = *((t_u8 *)pcurrent_ptr + 1);
+ total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
+ if (bytes_left < total_ie_len) {
+ PRINTM(MERROR,
+ "InterpretIE: Error in processing IE, bytes left < IE length\n");
+ bytes_left = 0;
+ continue;
+ }
+ switch (element_id) {
+ case VENDOR_SPECIFIC_221:
+ pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
+ if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(pvendor_ie->vend_hdr.oui)) &&
+ pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
+ if (total_ie_len ==
+ sizeof(IEEEtypes_WmmParameter_t)) {
+ /*
+ * Only accept and copy the WMM IE if
+ * it matches the size expected for the
+ * WMM Parameter IE.
+ */
+ moal_memcpy_ext(
+ priv->phandle,
+ &sys_config->wmm_para,
+ pcurrent_ptr +
+ sizeof(IEEEtypes_Header_t),
+ element_len,
+ sizeof(sys_config->wmm_para));
+ /** set uap_host_based_config to true */
+ sys_config->uap_host_based_config =
+ MTRUE;
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+ pcurrent_ptr += element_len + 2;
+ /* Need to account for IE ID and IE Len */
+ bytes_left -= (element_len + 2);
+ }
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+/**
+ * @brief initialize AP or GO bss config
+ * @param priv A pointer to moal private structure
+ * @param band BAND_2GHZ/BAND_5GHZ
+ * @param params A pointer to cfg80211_ap_settings structure
+ * @return 0 -- success, otherwise fail
+ */
+t_u8 woal_check_11ac_capability(moal_private *priv, t_u8 band,
+ struct cfg80211_ap_settings *params)
+#else
+/**
+ * @brief initialize AP or GO bss config
+ * @param band BAND_2GHZ/BAND_5GHZ
+ * @param priv A pointer to moal private structure
+ * @return 0 -- success, otherwise fail
+ */
+t_u8 woal_check_11ac_capability(moal_private *priv, t_u8 band)
+#endif
+{
+ mlan_fw_info fw_info;
+ t_u8 enable_11ac = MFALSE;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ const u8 *vht_ie = NULL;
+#endif
+ ENTER();
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if ((band == BAND_5GHZ) && !(fw_info.fw_bands & BAND_AAC)) {
+ PRINTM(MCMND, "FW don't support 5G AC");
+ LEAVE();
+ return enable_11ac;
+ }
+ if ((band == BAND_2GHZ) && !(fw_info.fw_bands & BAND_GAC)) {
+ PRINTM(MCMND, "FW don't support 2G AC");
+ LEAVE();
+ return enable_11ac;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
+ params->beacon.tail_len);
+ if (vht_ie)
+ enable_11ac = MTRUE;
+ else
+ enable_11ac = MFALSE;
+#else
+ enable_11ac = MTRUE;
+#endif
+ LEAVE();
+ return enable_11ac;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+/**
+ * @brief initialize AP or GO bss config
+ * @param priv A pointer to moal private structure
+ * @param band BAND_5G/BAND_2GHZ
+ * @param params A pointer to cfg80211_ap_settings structure
+ * @return 0 -- success, otherwise fail
+ */
+t_u8 woal_check_11ax_capability(moal_private *priv, t_u8 band,
+ struct cfg80211_ap_settings *params)
+{
+ mlan_fw_info fw_info;
+ t_u8 enable_11ax = MFALSE;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
+ mlan_ds_11ax_he_cfg he_cfg;
+ t_u8 he_txrx_mcs_support[4] = {0xff, 0xff, 0xff, 0xff};
+#endif
+ ENTER();
+ memset(&fw_info, 0, sizeof(mlan_fw_info));
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
+ if ((band == BAND_5GHZ) && !(fw_info.fw_bands & BAND_AAX)) {
+ PRINTM(MCMND, "FW don't support 5G AX\n");
+ LEAVE();
+ return enable_11ax;
+ }
+ if ((band == BAND_2GHZ) && !(fw_info.fw_bands & BAND_GAX)) {
+ PRINTM(MCMND, "FW don't support 2G AX");
+ LEAVE();
+ return enable_11ax;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ if (params->he_cap)
+ enable_11ax = MTRUE;
+ else
+ enable_11ax = MFALSE;
+#else
+ memset(&he_cfg, 0, sizeof(he_cfg));
+ if (band == BAND_5GHZ)
+ he_cfg.band = MBIT(1);
+ else if (band == BAND_2GHZ)
+ he_cfg.band = MBIT(0);
+ if (0 == woal_11ax_cfg(priv, MLAN_ACT_GET, &he_cfg)) {
+ if (he_cfg.he_cap.len &&
+ (he_cfg.he_cap.ext_id == HE_CAPABILITY)) {
+ if (memcmp(he_cfg.he_cap.he_txrx_mcs_support,
+ he_txrx_mcs_support,
+ sizeof(he_txrx_mcs_support)))
+ enable_11ax = MTRUE;
+ }
+ }
+#endif
+ PRINTM(MCMND, "enable_11ax=%d\n", enable_11ax);
+ LEAVE();
+ return enable_11ax;
+}
+#endif
+
+/**
+ * @brief get ht_cap from beacon ie
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ *
+ * @return ht_cap
+ */
+static t_u16 woal_get_htcap_info(const t_u8 *ie, int len)
+{
+ t_u16 ht_cap_info = 0;
+ IEEEtypes_HTCap_t *htcap_ie = NULL;
+ htcap_ie =
+ (IEEEtypes_HTCap_t *)woal_parse_ie_tlv(ie, len, HT_CAPABILITY);
+ if (htcap_ie) {
+ /* hostap has converted ht_cap_info to little endian, here
+ * conver to host endian */
+ ht_cap_info = woal_le16_to_cpu(htcap_ie->ht_cap.ht_cap_info);
+ PRINTM(MMSG, "Get ht_cap from beacon ies: 0x%x\n", ht_cap_info);
+ }
+ return ht_cap_info;
+}
+
+/**
+ * @brief get vht_cap from beacon ie
+ *
+ * @param ie Pointer to IEs
+ * @param len Total length of ie
+ *
+ * @return Pointer to vht_cap ie
+ */
+static IEEEtypes_VHTCap_t *woal_get_vhtcap_info(const t_u8 *ie, int len)
+{
+ IEEEtypes_VHTCap_t *vhtcap_ie = NULL;
+ vhtcap_ie = (IEEEtypes_VHTCap_t *)woal_parse_ie_tlv(ie, len,
+ VHT_CAPABILITY);
+ if (vhtcap_ie)
+ PRINTM(MMSG, "Get vht_cap from beacon ies: 0x%x\n",
+ vhtcap_ie->vht_cap.vht_cap_info);
+ return vhtcap_ie;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+/** Starting Frequency for 11A band */
+#define START_FREQ_11A_BAND 5000 /* in MHz */
+/**
+ * @brief convert cfg80211_chan_def to Band_Config
+ *
+ * @param bandcfg A pointer to (Band_Config_t structure
+ * @param chandef A pointer to cfg80211_chan_def structure
+ *
+ * @return N/A
+ */
+static void woal_convert_chan_to_bandconfig(Band_Config_t *bandcfg,
+ struct cfg80211_chan_def *chandef)
+{
+ ENTER();
+
+ if (chandef->chan->hw_value <= MAX_BG_CHANNEL)
+ bandcfg->chanBand = BAND_2GHZ;
+ else
+ bandcfg->chanBand = BAND_5GHZ;
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ bandcfg->chanWidth = CHAN_BW_20MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ bandcfg->chanWidth = CHAN_BW_40MHZ;
+ if (chandef->center_freq1 > chandef->chan->center_freq)
+ bandcfg->chan2Offset = SEC_CHAN_ABOVE;
+ else
+ bandcfg->chan2Offset = SEC_CHAN_BELOW;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ bandcfg->chan2Offset =
+ woal_get_second_channel_offset(chandef->chan->hw_value);
+ bandcfg->chanWidth = CHAN_BW_80MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ default:
+ break;
+ }
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Enable radar detect for DFS channel
+ *
+ * @param priv A pointer to moal private structure
+ * @param chandef A pointer to cfg80211_chan_def structure
+ * @return N/A
+ */
+static void woal_enable_dfs_support(moal_private *priv,
+ struct cfg80211_chan_def *chandef)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
+ mlan_ds_11h_cfg *p11h_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ ENTER();
+ if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) {
+ PRINTM(MIOCTL, "No radar channel\n");
+ LEAVE();
+ return;
+ }
+ PRINTM(MIOCTL, "start Radar detect, chan %d , Bw %d \n",
+ chandef->chan->hw_value, chandef->width);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (NULL == req) {
+ PRINTM(MIOCTL, "No Memory to allocate ioctl buffer\n");
+ LEAVE();
+ return;
+ }
+ p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
+ pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
+ pchan_rpt_req->startFreq = 5000;
+ pchan_rpt_req->chanNum = (t_u8)chandef->chan->hw_value;
+ woal_convert_chan_to_bandconfig(&pchan_rpt_req->bandcfg, chandef);
+ pchan_rpt_req->host_based = MTRUE;
+ pchan_rpt_req->millisec_dwell_time = 0;
+
+ p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+ /* Send Channel Check command and wait until the report is ready */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return;
+}
+#endif
+
+/**
+ * @brief Prase supported rates from beacon data, set bss cfg accordingly
+ *
+ * @param priv A pointer to moal_private
+ * @param bss_cfg A pointer to bss configuration structure
+ * @param head_ie A pointer to beacon head IE buffer
+ * @param head_len head IE buffer length
+ * @param tail_ie A pointer to beacon tail IE buffer
+ * @param tail_len tail IE buffer length *
+ * @return N/A
+ */
+static void woal_set_uap_rates(moal_private *priv, mlan_uap_bss_param *bss_cfg,
+ const t_u8 *head_ie, int head_len,
+ const t_u8 *tail_ie, int tail_len)
+{
+ pIEEEtypes_Header_t rate_ie;
+ pIEEEtypes_Header_t ext_rate_ie;
+ int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ const u8 *var_pos = head_ie + var_offset;
+ int len = head_len - var_offset;
+ int rate_len = 0;
+
+ rate_ie = (void *)woal_parse_ie_tlv(var_pos, len, WLAN_EID_SUPP_RATES);
+ if (rate_ie) {
+ memset(bss_cfg->rates, 0, sizeof(bss_cfg->rates));
+ moal_memcpy_ext(priv->phandle, bss_cfg->rates, rate_ie + 1,
+ rate_ie->len, sizeof(bss_cfg->rates));
+ rate_len = MIN(rate_ie->len, sizeof(bss_cfg->rates));
+ }
+ ext_rate_ie = (void *)woal_parse_ie_tlv(tail_ie, tail_len,
+ WLAN_EID_EXT_SUPP_RATES);
+ if (ext_rate_ie) {
+ moal_memcpy_ext(priv->phandle, &bss_cfg->rates[rate_len],
+ ext_rate_ie + 1, ext_rate_ie->len,
+ sizeof(bss_cfg->rates) - rate_len);
+ rate_len += MIN(ext_rate_ie->len,
+ (sizeof(bss_cfg->rates) - rate_len));
+ }
+ DBG_HEXDUMP(MCMD_D, "rates", bss_cfg->rates, sizeof(bss_cfg->rates));
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+/**
+ * @brief initialize AP or GO bss config
+ *
+ * @param priv A pointer to moal private structure
+ * @param params A pointer to cfg80211_ap_settings structure
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_beacon_config(moal_private *priv,
+ struct cfg80211_ap_settings *params)
+#else
+/**
+ * @brief initialize AP or GO bss config
+ *
+ * @param priv A pointer to moal private structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_cfg80211_beacon_config(moal_private *priv,
+ struct beacon_parameters *params)
+#endif
+{
+ struct wiphy *wiphy = NULL;
+ const t_u8 *ie = NULL;
+ int ret = 0, ie_len;
+ mlan_uap_bss_param *sys_config = NULL;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ int i = 0;
+#else
+ t_u8 wpa_ies;
+ const t_u8 *ssid_ie = NULL;
+ struct ieee80211_mgmt *head = NULL;
+ t_u16 capab_info = 0;
+#endif
+ t_u8 rates_bg[13] = {0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18,
+ 0x24, 0x30, 0x48, 0x60, 0x6c, 0x00};
+ t_u8 rates_a[9] = {0x8c, 0x12, 0x98, 0x24, 0xb0,
+ 0x48, 0x60, 0x6c, 0x00};
+#ifdef WIFI_DIRECT_SUPPORT
+ t_u8 rates_wfd[9] = {0x8c, 0x12, 0x18, 0x24, 0x30,
+ 0x48, 0x60, 0x6c, 0x00};
+#endif
+ t_u8 chan2Offset = SEC_CHAN_NONE;
+ t_u8 enable_11n = MTRUE;
+ t_u16 ht_cap = 0;
+ t_u8 enable_11ac = MFALSE;
+ t_u8 vht20_40 = MFALSE;
+ IEEEtypes_VHTCap_t *vhtcap_ie = NULL;
+ IEEEtypes_HECap_t *hecap_ie = NULL;
+ t_u8 enable_11ax = MFALSE;
+ t_u8 *wapi_ie = NULL;
+ int wapi_ie_len = 0;
+#ifdef WIFI_DIRECT_SUPPORT
+ int GoAgeoutTime = priv->phandle->params.GoAgeoutTime;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ mlan_ds_11h_chan_nop_info chan_nop_info;
+ Band_Config_t bandcfg;
+#endif
+ ENTER();
+
+ if (!params) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ ie = ((struct cfg80211_ap_settings *)params)->beacon.tail;
+ ie_len = ((struct cfg80211_ap_settings *)params)->beacon.tail_len;
+#else
+ ie = ((struct beacon_parameters *)params)->tail;
+ ie_len = ((struct beacon_parameters *)params)->tail_len;
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ wapi_ie = (t_u8 *)woal_parse_ie_tlv(params->beacon.tail,
+ params->beacon.tail_len, WAPI_IE);
+#else
+ wapi_ie = (t_u8 *)woal_parse_ie_tlv(params->tail, params->tail_len,
+ WAPI_IE);
+#endif
+ if (wapi_ie) {
+ wapi_ie_len = *(wapi_ie + 1) + 2;
+ if (MLAN_STATUS_FAILURE ==
+ woal_set_get_gen_ie(priv, MLAN_ACT_SET, wapi_ie,
+ &wapi_ie_len, MOAL_IOCTL_WAIT)) {
+ PRINTM(MERROR, "Failed to set wapi ie\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ wiphy = priv->phandle->wiphy;
+ if (priv->bss_type != MLAN_BSS_TYPE_UAP
+#ifdef WIFI_DIRECT_SUPPORT
+ && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT
+#endif
+ ) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (priv->phandle->params.uap_max_sta)
+ sys_config->max_sta_count = priv->phandle->params.uap_max_sta;
+
+ /* Setting the default values */
+ sys_config->channel = 6;
+ sys_config->preamble_type = 0;
+ sys_config->mgmt_ie_passthru_mask = priv->mgmt_subtype_mask;
+ moal_memcpy_ext(priv->phandle, sys_config->mac_addr, priv->current_addr,
+ ETH_ALEN, sizeof(sys_config->mac_addr));
+
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT && GoAgeoutTime) {
+ sys_config->sta_ageout_timer = GoAgeoutTime;
+ sys_config->ps_sta_ageout_timer = GoAgeoutTime;
+ }
+#endif
+ /* Set frag_threshold, rts_threshold, and retry limit */
+ sys_config->frag_threshold = wiphy->frag_threshold;
+ sys_config->rts_threshold = wiphy->rts_threshold;
+ sys_config->retry_limit = wiphy->retry_long;
+ if (sys_config->frag_threshold == (t_u16)MLAN_FRAG_RTS_DISABLED) {
+ sys_config->frag_threshold = MLAN_FRAG_MAX_VALUE;
+ }
+ if (sys_config->rts_threshold == (t_u16)MLAN_FRAG_RTS_DISABLED) {
+ sys_config->rts_threshold = MLAN_RTS_MAX_VALUE;
+ }
+
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ if (params->beacon_interval)
+ sys_config->beacon_period = params->beacon_interval;
+#else
+ if (params->interval)
+ sys_config->beacon_period = params->interval;
+#endif
+ if (params->dtim_period)
+ sys_config->dtim_period = params->dtim_period;
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ /** back up ap's channel */
+ moal_memcpy_ext(priv->phandle, &priv->chan, &params->chandef,
+ sizeof(struct cfg80211_chan_def), sizeof(priv->chan));
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->phandle->usr_nop_period_sec) {
+ PRINTM(MCMND, "Checking if AP's channel %d is under NOP\n",
+ priv->channel);
+ woal_convert_chan_to_bandconfig(&bandcfg, &params->chandef);
+ memset(&chan_nop_info, 0, sizeof(chan_nop_info));
+ chan_nop_info.curr_chan = priv->channel;
+ chan_nop_info.chan_width = bandcfg.chanWidth;
+ if (params->chandef.width >= NL80211_CHAN_WIDTH_20)
+ chan_nop_info.new_chan.is_11n_enabled = MTRUE;
+ chan_nop_info.new_chan.bandcfg = bandcfg;
+ woal_uap_get_channel_nop_info(priv, MOAL_IOCTL_WAIT,
+ &chan_nop_info);
+ if (chan_nop_info.chan_under_nop) {
+ PRINTM(MCMND,
+ "cfg80211: Channel %d is under NOP, New channel=%d\n",
+ priv->channel, chan_nop_info.new_chan.channel);
+ priv->chan_under_nop = chan_nop_info.chan_under_nop;
+ priv->channel = chan_nop_info.new_chan.channel;
+ woal_chandef_create(priv, &priv->chan,
+ &chan_nop_info.new_chan);
+ }
+ }
+#endif
+
+ if (priv->channel) {
+ memset(sys_config->rates, 0, sizeof(sys_config->rates));
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ switch (priv->chan.width) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+#endif
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ enable_11n = MFALSE;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ if (priv->chan.center_freq1 <
+ priv->chan.chan->center_freq)
+ chan2Offset = SEC_CHAN_BELOW;
+ else
+ chan2Offset = SEC_CHAN_ABOVE;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ chan2Offset =
+ woal_get_second_channel_offset(priv->channel);
+ break;
+ default:
+ PRINTM(MWARN, "Unknown channel width: %d\n",
+ priv->chan.width);
+ break;
+ }
+#else
+ switch (params->channel_type) {
+ case NL80211_CHAN_NO_HT:
+ enable_11n = MFALSE;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan2Offset = SEC_CHAN_ABOVE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan2Offset = SEC_CHAN_BELOW;
+ break;
+ default:
+ PRINTM(MWARN, "Unknown channel type: %d\n",
+ params->channel_type);
+ break;
+ }
+#endif
+#endif /* CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
+
+ sys_config->channel = priv->channel;
+ if (priv->channel <= MAX_BG_CHANNEL) {
+ sys_config->bandcfg.chanBand = BAND_2GHZ;
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ moal_memcpy_ext(priv->phandle,
+ sys_config->rates, rates_wfd,
+ sizeof(rates_wfd),
+ sizeof(sys_config->rates));
+ else
+#endif
+ moal_memcpy_ext(priv->phandle,
+ sys_config->rates, rates_bg,
+ sizeof(rates_bg),
+ sizeof(sys_config->rates));
+ } else {
+ sys_config->bandcfg.chanBand = BAND_5GHZ;
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ chan2Offset =
+ woal_get_second_channel_offset(priv->channel);
+#endif
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ /* Force enable 40MHZ on WFD interface */
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ chan2Offset = woal_get_second_channel_offset(
+ priv->channel);
+#endif
+#endif
+#ifdef WIFI_DIRECT_SUPPORT
+ if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
+ moal_memcpy_ext(priv->phandle,
+ sys_config->rates, rates_wfd,
+ sizeof(rates_wfd),
+ sizeof(sys_config->rates));
+ else
+#endif
+ moal_memcpy_ext(priv->phandle,
+ sys_config->rates, rates_a,
+ sizeof(rates_a),
+ sizeof(sys_config->rates));
+ }
+
+ /* Replaced with rate from userspace, if exist */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ woal_set_uap_rates(priv, sys_config, params->beacon.head,
+ params->beacon.head_len, params->beacon.tail,
+ params->beacon.tail_len);
+#else
+ woal_set_uap_rates(priv, sys_config, params->head,
+ params->head_len, params->tail,
+ params->tail_len);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ enable_11ac = woal_check_11ac_capability(
+ priv, sys_config->bandcfg.chanBand, params);
+ if (enable_11ac &&
+ ((priv->chan.width == NL80211_CHAN_WIDTH_20) ||
+ (priv->chan.width == NL80211_CHAN_WIDTH_40)))
+ vht20_40 = MTRUE;
+#else
+ enable_11ac = woal_check_11ac_capability(
+ priv, sys_config->bandcfg.chanBand);
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ enable_11ax = woal_check_11ax_capability(
+ priv, sys_config->bandcfg.chanBand, params);
+#endif
+
+ /* Disable GreenField by default */
+ sys_config->ht_cap_info = 0x10c;
+ if (enable_11n)
+ sys_config->ht_cap_info |= 0x20;
+ if (chan2Offset) {
+ sys_config->bandcfg.chan2Offset = chan2Offset;
+ sys_config->ht_cap_info |= 0x1042;
+ sys_config->ampdu_param = 3;
+ } else {
+ sys_config->bandcfg.chan2Offset = 0;
+ }
+ if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ ht_cap = woal_get_htcap_info(ie, ie_len);
+ if (ht_cap) {
+ if (sys_config->bandcfg.chanBand == BAND_2GHZ)
+ sys_config->ht_cap_info =
+ (ht_cap &
+ (wiphy->bands[IEEE80211_BAND_2GHZ]
+ ->ht_cap.cap &
+ 0x13ff)) |
+ 0x0c;
+ else
+ sys_config->ht_cap_info =
+ (ht_cap &
+ (wiphy->bands[IEEE80211_BAND_5GHZ]
+ ->ht_cap.cap &
+ 0x13ff)) |
+ 0x0c;
+ }
+ PRINTM(MCMND,
+ "11n=%d, ht_cap=0x%x, channel=%d, bandcfg:chanBand=0x%x chanWidth=0x%x chan2Offset=0x%x scanMode=0x%x\n",
+ enable_11n, sys_config->ht_cap_info,
+ priv->channel, sys_config->bandcfg.chanBand,
+ sys_config->bandcfg.chanWidth,
+ sys_config->bandcfg.chan2Offset,
+ sys_config->bandcfg.scanMode);
+ }
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+ if (!params->ssid || !params->ssid_len) {
+ ret = -EINVAL;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, sys_config->ssid.ssid, params->ssid,
+ MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len),
+ sizeof(sys_config->ssid.ssid));
+ sys_config->ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len);
+ /**
+ * hidden_ssid=0: broadcast SSID in beacons.
+ * hidden_ssid=1: send empty SSID (length=0) in beacon.
+ * hidden_ssid=2: clear SSID (ACSII 0), but keep the original length
+ */
+ if (!params->hidden_ssid)
+ sys_config->bcast_ssid_ctl = 1;
+ else if (params->hidden_ssid == 1)
+ sys_config->bcast_ssid_ctl = 0;
+ else if (params->hidden_ssid == 2)
+ sys_config->bcast_ssid_ctl = 2;
+ switch (params->auth_type) {
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ sys_config->auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ sys_config->auth_mode = MLAN_AUTH_MODE_AUTO;
+ break;
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ default:
+ sys_config->auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ }
+
+ sys_config->protocol = PROTOCOL_NO_SECURITY;
+ if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) &&
+ (params->crypto.wpa_versions & NL80211_WPA_VERSION_2))
+ sys_config->protocol = PROTOCOL_WPA | PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config->protocol = PROTOCOL_WPA2;
+ else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config->protocol = PROTOCOL_WPA;
+ if (params->crypto.n_akm_suites ||
+ (params->privacy && params->crypto.wpa_versions))
+ woal_find_wpa_ies(ie, ie_len, sys_config);
+ for (i = 0; i < params->crypto.n_akm_suites; i++) {
+ switch (params->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ sys_config->key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ sys_config->key_mgmt |= KEY_MGMT_PSK;
+ break;
+ }
+ }
+ sys_config->wpa_cfg.pairwise_cipher_wpa = 0;
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 = 0;
+ for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
+ switch (params->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config->wpa_cfg.pairwise_cipher_wpa |=
+ CIPHER_TKIP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |=
+ CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ sys_config->wpa_cfg.pairwise_cipher_wpa |=
+ CIPHER_AES_CCMP;
+ if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 |=
+ CIPHER_AES_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ sys_config->protocol = PROTOCOL_WAPI;
+ break;
+ }
+ }
+ switch (params->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config->protocol = PROTOCOL_STATIC_WEP;
+ sys_config->key_mgmt = KEY_MGMT_NONE;
+ sys_config->wpa_cfg.length = 0;
+ moal_memcpy_ext(priv->phandle,
+ &sys_config->wep_cfg.key0,
+ &priv->uap_wep_key[0], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key0));
+ moal_memcpy_ext(priv->phandle,
+ &sys_config->wep_cfg.key1,
+ &priv->uap_wep_key[1], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key1));
+ moal_memcpy_ext(priv->phandle,
+ &sys_config->wep_cfg.key2,
+ &priv->uap_wep_key[2], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key2));
+ moal_memcpy_ext(priv->phandle,
+ &sys_config->wep_cfg.key3,
+ &priv->uap_wep_key[3], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key3));
+ }
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ sys_config->protocol = PROTOCOL_WAPI;
+ break;
+ }
+#else
+/* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set ssid
+ * when GO (AP) starts up, so get it from beacon head parameter
+ * TODO: right now use hard code
+ * 24 -- ieee80211 header lenth, 12 -- fixed element length for beacon
+ */
+#define BEACON_IE_OFFSET 36
+ /* Find SSID in head
+ * SSID IE id: 0, right now use hard code
+ */
+ ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET,
+ params->head_len - BEACON_IE_OFFSET, 0);
+
+ if (!ssid_ie) {
+ PRINTM(MERROR, "No ssid IE found.\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (*(ssid_ie + 1) > 32) {
+ PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1));
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, sys_config->ssid.ssid, ssid_ie + 2,
+ *(ssid_ie + 1), sizeof(sys_config->ssid.ssid));
+ sys_config->ssid.ssid_len = *(ssid_ie + 1);
+ head = (struct ieee80211_mgmt *)params->head;
+
+ capab_info = le16_to_cpu(head->u.beacon.capab_info);
+ PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info);
+ sys_config->auth_mode = MLAN_AUTH_MODE_OPEN;
+ /** For ICS, we don't support OPEN mode */
+ if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ sys_config->protocol = PROTOCOL_STATIC_WEP;
+ sys_config->key_mgmt = KEY_MGMT_NONE;
+ sys_config->.wpa_cfg.length = 0;
+ moal_memcpy_ext(priv->phandle, &sys_config->wep_cfg.key0,
+ &priv->uap_wep_key[0], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key0));
+ moal_memcpy_ext(priv->phandle, &sys_config->wep_cfg.key1,
+ &priv->uap_wep_key[1], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key1));
+ moal_memcpy_ext(priv->phandle, &sys_config->wep_cfg.key2,
+ &priv->uap_wep_key[2], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key2));
+ moal_memcpy_ext(priv->phandle, &sys_config->wep_cfg.key3,
+ &priv->uap_wep_key[3], sizeof(wep_key),
+ sizeof(sys_config->wep_cfg.key3));
+ } else {
+ /** Get cipher and key_mgmt from RSN/WPA IE */
+ if (capab_info & WLAN_CAPABILITY_PRIVACY) {
+ wpa_ies = woal_find_wpa_ies(
+ params->tail, params->tail_len, sys_config);
+ if (wpa_ies == MFALSE) {
+ /* hard code setting to wpa2-psk */
+ sys_config->protocol = PROTOCOL_WPA2;
+ sys_config->key_mgmt = KEY_MGMT_PSK;
+ sys_config->wpa_cfg.pairwise_cipher_wpa2 =
+ CIPHER_AES_CCMP;
+ sys_config->wpa_cfg.group_cipher =
+ CIPHER_AES_CCMP;
+ }
+ }
+ }
+#endif
+
+ if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
+ /*find and set wmm ie*/
+ woal_set_wmm_ies(priv, ie, ie_len, sys_config);
+ }
+ /* If the security mode is configured as WEP or WPA-PSK,
+ * it will disable 11n automatically, and if configured as
+ * open(off) or wpa2-psk, it will automatically enable 11n */
+ if ((sys_config->protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config->protocol == PROTOCOL_WPA))
+ enable_11n = MFALSE;
+ if (!enable_11n) {
+ woal_set_uap_ht_tx_cfg(priv, sys_config->bandcfg, ht_cap,
+ MFALSE);
+ woal_uap_set_11n_status(priv, sys_config, MLAN_ACT_DISABLE);
+ } else {
+ woal_set_uap_ht_tx_cfg(priv, sys_config->bandcfg, ht_cap,
+ MTRUE);
+ woal_uap_set_11n_status(priv, sys_config, MLAN_ACT_ENABLE);
+ woal_set_get_tx_bf_cap(priv, MLAN_ACT_GET,
+ &sys_config->tx_bf_cap);
+ }
+ if (enable_11ac && enable_11n) {
+ vhtcap_ie = woal_get_vhtcap_info(ie, ie_len);
+ woal_uap_set_11ac_status(priv, MLAN_ACT_ENABLE, vht20_40,
+ vhtcap_ie);
+ } else {
+ woal_uap_set_11ac_status(priv, MLAN_ACT_DISABLE, vht20_40,
+ NULL);
+ }
+ if (enable_11ax && enable_11n) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ hecap_ie = (IEEEtypes_HECap_t *)woal_parse_ext_ie_tlv(
+ ie, ie_len, HE_CAPABILITY);
+#endif
+ woal_uap_set_11ax_status(priv, MLAN_ACT_ENABLE,
+ sys_config->bandcfg.chanBand,
+ hecap_ie);
+ } else
+ woal_uap_set_11ax_status(priv, MLAN_ACT_DISABLE,
+ sys_config->bandcfg.chanBand, NULL);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ if (params->inactivity_timeout) {
+ sys_config->sta_ageout_timer = params->inactivity_timeout * 10;
+ sys_config->ps_sta_ageout_timer =
+ params->inactivity_timeout * 10;
+ }
+ PRINTM(MIOCTL, "inactivity_timeout=%d\n", params->inactivity_timeout);
+ PRINTM(MIOCTL, "sta_ageout_timer=%d ps_sta_ageout_timer=%d\n",
+ sys_config->sta_ageout_timer, sys_config->ps_sta_ageout_timer);
+#endif
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ woal_enable_dfs_support(priv, &priv->chan);
+#endif
+done:
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+}
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+/**
+ * @brief Callback function for virtual interface
+ * setup
+ *
+ * @param dev A pointer to structure net_device
+ *
+ * @return N/A
+ */
+static void woal_virt_if_setup(struct net_device *dev)
+{
+ ENTER();
+ ether_setup(dev);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)
+ dev->needs_free_netdev = true;
+#else
+ dev->destructor = free_netdev;
+#endif
+ LEAVE();
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_index BSS index number
+ * @param name_assign_type Interface name assignment type
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *woal_alloc_virt_interface(moal_handle *handle, t_u8 bss_index,
+ unsigned char name_assign_type,
+ t_u8 bss_type, const char *name)
+#else
+/**
+ * @brief This function adds a new interface. It will
+ * allocate, initialize and register the device.
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param bss_index BSS index number
+ * @param bss_type BSS type
+ *
+ * @return A pointer to the new priv structure
+ */
+moal_private *woal_alloc_virt_interface(moal_handle *handle, t_u8 bss_index,
+ t_u8 bss_type,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+ const
+#endif
+ char *name)
+#endif
+{
+ struct net_device *dev = NULL;
+ moal_private *priv = NULL;
+ ENTER();
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+#ifndef MAX_WMM_QUEUE
+#define MAX_WMM_QUEUE 4
+#endif
+ /* Allocate an Ethernet device */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ dev = alloc_netdev_mq(sizeof(moal_private), name, name_assign_type,
+ woal_virt_if_setup, MAX_WMM_QUEUE);
+#else
+ dev = alloc_netdev_mq(sizeof(moal_private), name, NET_NAME_UNKNOWN,
+ woal_virt_if_setup, MAX_WMM_QUEUE);
+#endif
+#else
+ dev = alloc_netdev_mq(sizeof(moal_private), name, woal_virt_if_setup,
+ MAX_WMM_QUEUE);
+#endif
+#else
+ dev = alloc_netdev(sizeof(moal_private), name, woal_virt_if_setup);
+#endif
+ if (!dev) {
+ PRINTM(MFATAL, "Init virtual ethernet device failed\n");
+ goto error;
+ }
+ /* Allocate device name */
+ if ((dev_alloc_name(dev, name) < 0)) {
+ PRINTM(MERROR, "Could not allocate device name\n");
+ goto error;
+ }
+
+ priv = (moal_private *)netdev_priv(dev);
+ /* Save the priv to handle */
+ handle->priv[bss_index] = priv;
+
+ /* Use the same handle structure */
+ priv->phandle = handle;
+ priv->netdev = dev;
+ priv->bss_index = bss_index;
+ priv->bss_type = bss_type;
+ priv->bss_role = MLAN_BSS_ROLE_STA;
+
+ INIT_LIST_HEAD(&priv->tcp_sess_queue);
+ spin_lock_init(&priv->tcp_sess_lock);
+
+ INIT_LIST_HEAD(&priv->tx_stat_queue);
+ spin_lock_init(&priv->tx_stat_lock);
+ spin_lock_init(&priv->connect_lock);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ SET_MODULE_OWNER(dev);
+#endif
+
+ PRINTM(MCMND, "Alloc virtual interface%s\n", dev->name);
+
+ LEAVE();
+ return priv;
+error:
+ if (dev)
+ free_netdev(dev);
+ LEAVE();
+ return NULL;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param name_assign_type Interface name assignment type
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ * @param new_dev new net_device to return
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_add_virt_if(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params,
+ struct net_device **new_dev)
+#else
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ * @param new_dev new net_device to return
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_add_virt_if(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+ const
+#endif
+ char *name,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params,
+ struct net_device **new_dev)
+#endif
+{
+ int ret = 0;
+ struct net_device *ndev = NULL;
+ moal_private *priv = NULL, *new_priv = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ struct wireless_dev *wdev = NULL;
+ moal_private *vir_priv;
+ int i = 0;
+
+ ENTER();
+ ASSERT_RTNL();
+ priv = woal_get_vir_priv_bss_type(handle, MLAN_BSS_TYPE_WIFIDIRECT);
+ if (priv && priv->bss_role == MLAN_BSS_ROLE_UAP &&
+ priv->bss_started == MTRUE) {
+ if (handle->pref_mac)
+ handle = (moal_handle *)handle->pref_mac;
+ }
+ priv = (moal_private *)woal_get_priv_bss_type(handle,
+ MLAN_BSS_TYPE_WIFIDIRECT);
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is NULL\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ if (priv->phandle->drv_mode.intf_num == priv->phandle->priv_num) {
+ PRINTM(MERROR, "max virtual interface limit reached\n");
+ for (i = 0; i < priv->phandle->priv_num; i++) {
+ vir_priv = priv->phandle->priv[i];
+ if (vir_priv->bss_virtual) {
+ woal_cfg80211_del_virt_if(wiphy,
+ vir_priv->netdev);
+ break;
+ }
+ }
+ if (priv->phandle->drv_mode.intf_num ==
+ priv->phandle->priv_num) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ }
+ PRINTM(MMSG, "Add virtual interface %s\n", name);
+ if ((type != NL80211_IFTYPE_P2P_CLIENT) &&
+ (type != NL80211_IFTYPE_P2P_GO)) {
+ PRINTM(MERROR, "Invalid iftype: %d\n", type);
+ LEAVE();
+ return -EINVAL;
+ }
+
+ handle = priv->phandle;
+ /* Cancel previous scan req */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ new_priv = woal_alloc_virt_interface(handle, handle->priv_num,
+ name_assign_type,
+ MLAN_BSS_TYPE_WIFIDIRECT, name);
+#else
+ new_priv = woal_alloc_virt_interface(handle, handle->priv_num,
+ MLAN_BSS_TYPE_WIFIDIRECT, name);
+#endif
+ if (!new_priv) {
+ PRINTM(MERROR, "Add virtual interface fail.");
+ LEAVE();
+ return -EFAULT;
+ }
+ handle->priv_num++;
+
+ wdev = (struct wireless_dev *)&new_priv->w_dev;
+ memset(wdev, 0, sizeof(struct wireless_dev));
+ ndev = new_priv->netdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
+ ndev->ieee80211_ptr = wdev;
+ wdev->iftype = type;
+ wdev->wiphy = wiphy;
+ new_priv->wdev = wdev;
+ new_priv->bss_virtual = MTRUE;
+ new_priv->pa_netdev = priv->netdev;
+
+ woal_init_sta_dev(ndev, new_priv);
+
+ /* Initialize priv structure */
+ woal_init_priv(new_priv, MOAL_IOCTL_WAIT);
+ /** Init to GO/CLIENT mode */
+ if (type == NL80211_IFTYPE_P2P_CLIENT)
+ woal_cfg80211_init_p2p_client(new_priv);
+ else if (type == NL80211_IFTYPE_P2P_GO)
+ woal_cfg80211_init_p2p_go(new_priv);
+ ret = register_netdevice(ndev);
+ if (ret) {
+ handle->priv[new_priv->bss_index] = NULL;
+ handle->priv_num--;
+ if (ndev->reg_state == NETREG_REGISTERED) {
+ unregister_netdevice(ndev);
+ free_netdev(ndev);
+ ndev = NULL;
+ }
+ PRINTM(MFATAL, "register net_device failed, ret=%d\n", ret);
+ goto done;
+ }
+ netif_carrier_off(ndev);
+ woal_stop_queue(ndev);
+ if (new_dev)
+ *new_dev = ndev;
+#ifdef CONFIG_PROC_FS
+ woal_create_proc_entry(new_priv);
+ woal_debug_entry(new_priv);
+#endif /* CONFIG_PROC_FS */
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Notify mlan BSS will be removed.
+ *
+ * @param priv A pointer to moal_private structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
+ * otherwise fail
+ */
+mlan_status woal_bss_remove(moal_private *priv)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_REMOVE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief This function removes an virtual interface.
+ *
+ * @param wiphy A pointer to the wiphy structure
+ * @param dev A pointer to the net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_del_virt_if(struct wiphy *wiphy, struct net_device *dev)
+{
+ int ret = 0;
+ int i = 0;
+ moal_private *priv = NULL;
+ moal_private *vir_priv = NULL;
+ moal_private *remain_priv = NULL;
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ t_u8 find_bss = MFALSE;
+
+ for (i = 0; i < handle->priv_num; i++) {
+ vir_priv = handle->priv[i];
+ if (vir_priv) {
+ if (vir_priv->netdev == dev) {
+ find_bss = MTRUE;
+ PRINTM(MMSG,
+ "Del virtual interface %s, index=%d\n",
+ dev->name, i);
+ break;
+ }
+ }
+ }
+ if (!find_bss) {
+ /* Switch to the other MAC */
+ if (handle->pref_mac)
+ handle = (moal_handle *)handle->pref_mac;
+ for (i = 0; i < handle->priv_num; i++) {
+ vir_priv = handle->priv[i];
+ if (vir_priv) {
+ if (vir_priv->netdev == dev) {
+ find_bss = MTRUE;
+ PRINTM(MMSG,
+ "Del virtual interface %s, index=%d\n",
+ dev->name, i);
+ break;
+ }
+ }
+ }
+ }
+
+ priv = (moal_private *)woal_get_priv_bss_type(handle,
+ MLAN_BSS_TYPE_WIFIDIRECT);
+ if (!priv)
+ return ret;
+ if (vir_priv && vir_priv->netdev == dev) {
+ woal_stop_queue(dev);
+ netif_carrier_off(dev);
+ netif_device_detach(dev);
+ if (handle->is_remain_timer_set) {
+ woal_cancel_timer(&handle->remain_timer);
+ woal_remain_timer_func(handle);
+ }
+
+ /*** cancel pending scan */
+ woal_cancel_scan(vir_priv, MOAL_IOCTL_WAIT);
+
+ woal_flush_tx_stat_queue(vir_priv);
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ /* cancel previous remain on channel to avoid firmware hang */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ remain_priv =
+ priv->phandle
+ ->priv[priv->phandle->remain_bss_index];
+ if (remain_priv) {
+ if (woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_IOCTL_WAIT, MTRUE,
+ &channel_status, NULL, 0, 0))
+ PRINTM(MERROR,
+ "del_virt_if: Fail to cancel remain on channel\n");
+
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ }
+#endif
+
+ woal_clear_all_mgmt_ies(vir_priv, MOAL_IOCTL_WAIT);
+ woal_cfg80211_deinit_p2p(vir_priv);
+ woal_bss_remove(vir_priv);
+#ifdef CONFIG_PROC_FS
+ /* Remove proc debug */
+ woal_debug_remove(vir_priv);
+ woal_proc_remove(vir_priv);
+#endif /* CONFIG_PROC_FS */
+ /* Last reference is our one */
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+ PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+#else
+ PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev));
+#endif
+ PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name);
+ /* Clear the priv in handle */
+ vir_priv->phandle->priv[vir_priv->bss_index] = NULL;
+ priv->phandle->priv_num--;
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdevice(dev);
+ }
+ return ret;
+}
+#endif
+#endif
+
+#if defined(WIFI_DIRECT_SUPPORT)
+/**
+ * @brief This function removes an virtual interface.
+ *
+ * @param handle A pointer to the moal_handle structure
+ *
+ * @return N/A
+ */
+void woal_remove_virtual_interface(moal_handle *handle)
+{
+#ifdef WIFI_DIRECT_SUPPORT
+ moal_private *priv = NULL;
+ int vir_intf = 0;
+ int i = 0;
+#endif
+ ENTER();
+ rtnl_lock();
+#ifdef WIFI_DIRECT_SUPPORT
+ for (i = 0; i < handle->priv_num; i++) {
+ priv = handle->priv[i];
+ if (priv) {
+ if (priv->bss_virtual) {
+ PRINTM(MCMND, "Remove virtual interface %s\n",
+ priv->netdev->name);
+#ifdef CONFIG_PROC_FS
+ /* Remove proc debug */
+ woal_debug_remove(priv);
+ woal_proc_remove(priv);
+#endif /* CONFIG_PROC_FS */
+ netif_device_detach(priv->netdev);
+ if (priv->netdev->reg_state ==
+ NETREG_REGISTERED)
+ unregister_netdevice(priv->netdev);
+ handle->priv[i] = NULL;
+ vir_intf++;
+ }
+ }
+ }
+#endif
+ rtnl_unlock();
+#ifdef WIFI_DIRECT_SUPPORT
+ handle->priv_num -= vir_intf;
+#endif
+ LEAVE();
+}
+#endif
+
+/**
+ * @brief This function check if uap interface is ready
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ *
+ * @return MTRUE/MFALSE;
+ */
+static t_u8 woal_uap_interface_ready(struct wiphy *wiphy, char *name,
+ struct net_device **new_dev)
+{
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ moal_private *priv = NULL;
+ int i;
+
+ for (i = 0; i < handle->priv_num; i++) {
+ priv = handle->priv[i];
+ if (priv && (priv->bss_type == MLAN_BSS_TYPE_UAP) &&
+ !strcmp(priv->netdev->name, name)) {
+ priv->wdev->iftype = NL80211_IFTYPE_AP;
+ *new_dev = priv->netdev;
+ break;
+ }
+ }
+ if (priv && *new_dev)
+ return MTRUE;
+ else
+ return MFALSE;
+}
+
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 37)
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return A pointer to net_device -- success, otherwise null
+ */
+struct net_device *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params)
+#else
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, char *name,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+#endif
+#else
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return A pointer to wireless_dev -- success, otherwise null
+ */
+struct wireless_dev *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
+ const
+#endif
+ char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params)
+#else
+/**
+ * @brief Request the driver to add a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param name Virtual interface name
+ * @param name_assign_type Interface name assignment type
+ * @param type Virtual interface type
+ * @param flags Flags for the virtual interface
+ * @param params A pointer to vif_params structure
+ *
+ * @return A pointer to wireless_dev -- success, otherwise null
+ */
+struct wireless_dev *
+woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
+ enum nl80211_iftype type,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
+ u32 *flags,
+#endif
+ struct vif_params *params)
+#endif
+#endif
+{
+ struct net_device *ndev = NULL;
+ int ret = 0;
+#if defined(WIFI_DIRECT_SUPPORT)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ u32 *flags = &params->flags;
+#endif
+#endif
+
+ ENTER();
+ PRINTM(MIOCTL, "add virtual intf: %d name: %s\n", type, name);
+ switch (type) {
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ ret = woal_cfg80211_add_virt_if(wiphy, name, name_assign_type,
+ type, flags, params, &ndev);
+#else
+ ret = woal_cfg80211_add_virt_if(wiphy, name, type, flags,
+ params, &ndev);
+#endif
+ break;
+#endif
+#endif
+ case NL80211_IFTYPE_AP:
+ if (!woal_uap_interface_ready(wiphy, (char *)name, &ndev)) {
+ PRINTM(MMSG,
+ "Not support dynamically create %s UAP interface\n",
+ name);
+ ret = -EFAULT;
+ }
+ break;
+ default:
+ PRINTM(MWARN, "Not supported if type: %d\n", type);
+ ret = -EFAULT;
+ break;
+ }
+ LEAVE();
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 37)
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return ndev;
+#else
+ return ret;
+#endif
+#else
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return ndev->ieee80211_ptr;
+#endif
+}
+
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+/**
+ * @brief Request the driver to del a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev The pointer to net_device
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
+#else
+/**
+ * @brief Request the driver to del a virtual interface
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param wdev The pointer to wireless_dev
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+#endif
+{
+ int ret = 0;
+
+ moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
+ int i;
+ moal_private *vir_priv = NULL;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ struct net_device *dev = wdev->netdev;
+#endif
+ ENTER();
+
+ PRINTM(MIOCTL, "del virtual intf %s\n", dev->name);
+ ASSERT_RTNL();
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+ for (i = 0; i < handle->priv_num; i++) {
+ vir_priv = handle->priv[i];
+ if (vir_priv) {
+ if (vir_priv->netdev == dev) {
+ PRINTM(MMSG,
+ "Del virtual interface %s, index=%d\n",
+ dev->name, i);
+ break;
+ }
+ }
+ }
+ if (vir_priv && vir_priv->bss_type == MLAN_BSS_TYPE_UAP) {
+ woal_cfg80211_del_beacon(wiphy, dev);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+ vir_priv->wdev->beacon_interval = 0;
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ memset(&vir_priv->wdev->chandef, 0,
+ sizeof(vir_priv->wdev->chandef));
+#endif
+#endif
+ vir_priv->wdev->ssid_len = 0;
+ PRINTM(MMSG, "Skip del UAP virtual interface %s",
+ dev->name);
+ }
+ LEAVE();
+ return ret;
+ }
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
+ ret = woal_cfg80211_del_virt_if(wiphy, dev);
+#endif
+#endif
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+/**
+ * @brief initialize AP or GO parameters
+
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_ap_settings structure
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *params)
+#else
+/**
+ * @brief initialize AP or GO parameters
+
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params)
+#endif
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ t_u8 wait_option = MOAL_IOCTL_WAIT_TIMEOUT;
+
+ ENTER();
+
+ PRINTM(MMSG, "wlan: Starting AP\n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
+ /* cancel previous remain on channel to avoid firmware hang */
+ if (priv->phandle->remain_on_channel) {
+ t_u8 channel_status;
+ moal_private *remain_priv;
+ remain_priv =
+ priv->phandle->priv[priv->phandle->remain_bss_index];
+ if (remain_priv) {
+ PRINTM(MCMND,
+ "Cancel Remain on Channel before Starting AP\n");
+ if (woal_cfg80211_remain_on_channel_cfg(
+ remain_priv, MOAL_IOCTL_WAIT, MTRUE,
+ &channel_status, NULL, 0, 0))
+ PRINTM(MERROR,
+ "add beacon: Fail to cancel remain on channel\n");
+ if (priv->phandle->cookie) {
+ cfg80211_remain_on_channel_expired(
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ remain_priv->netdev,
+#else
+ remain_priv->wdev,
+#endif
+ priv->phandle->cookie,
+ &priv->phandle->chan,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
+ priv->phandle->channel_type,
+#endif
+ GFP_ATOMIC);
+ priv->phandle->cookie = 0;
+ }
+ priv->phandle->remain_on_channel = MFALSE;
+ }
+ }
+#endif
+
+#ifdef STA_CFG80211
+ /*** cancel pending scan */
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+#endif
+
+ if (!params) {
+ LEAVE();
+ return -EFAULT;
+ }
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ priv->channel = ieee80211_frequency_to_channel(
+ params->chandef.chan->center_freq);
+#else
+ priv->channel =
+ ieee80211_frequency_to_channel(params->channel->center_freq);
+#endif
+#endif
+ /* bss config */
+ if (MLAN_STATUS_SUCCESS != woal_cfg80211_beacon_config(priv, params)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* set mgmt frame ies */
+ ret = woal_cfg80211_mgmt_frame_ie(priv,
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
+ params->tail, params->tail_len, NULL,
+ 0, NULL, 0, NULL, 0, MGMT_MASK_BEACON
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ params->beacon.tail,
+ params->beacon.tail_len,
+ params->beacon.proberesp_ies,
+ params->beacon.proberesp_ies_len,
+ params->beacon.assocresp_ies,
+ params->beacon.assocresp_ies_len,
+#else
+ params->tail, params->tail_len,
+ params->proberesp_ies,
+ params->proberesp_ies_len,
+ params->assocresp_ies,
+ params->assocresp_ies_len,
+#endif
+ NULL, 0,
+ MGMT_MASK_BEACON |
+ MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP
+#endif
+ ,
+ MOAL_IOCTL_WAIT);
+ if (ret)
+ goto done;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) {
+ ret = woal_cfg80211_mgmt_frame_ie(
+ priv, params->beacon.beacon_ies,
+ params->beacon.beacon_ies_len, NULL, 0, NULL, 0, NULL,
+ 0, MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT);
+ if (ret) {
+ PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
+ goto done;
+ }
+ }
+#else
+ if (params->beacon_ies && params->beacon_ies_len) {
+ ret = woal_cfg80211_mgmt_frame_ie(priv, params->beacon_ies,
+ params->beacon_ies_len, NULL,
+ 0, NULL, 0, NULL, 0,
+ MGMT_MASK_BEACON_WPS_P2P,
+ MOAL_IOCTL_WAIT);
+ if (ret) {
+ PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
+ goto done;
+ }
+ }
+#endif
+#endif
+ priv->uap_host_based = MTRUE;
+
+ /* if the bss is stopped, then start it */
+ if (priv->bss_started == MFALSE) {
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ wait_option = MOAL_NO_WAIT;
+#endif
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, wait_option, UAP_BSS_START)) {
+ priv->uap_host_based = MFALSE;
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ PRINTM(MMSG, "wlan: AP started\n");
+done:
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+/**
+ * @brief set AP or GO parameter
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_beacon_data structure
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *params)
+#else
+/**
+ * @brief set AP or GO parameter
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to beacon_parameters structure
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *params)
+#endif
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "set beacon\n");
+ if (params != NULL) {
+#if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
+ if (params->tail && params->tail_len) {
+ ret = woal_cfg80211_mgmt_frame_ie(
+ priv, params->tail, params->tail_len, NULL, 0,
+ NULL, 0, NULL, 0, MGMT_MASK_BEACON,
+ MOAL_IOCTL_WAIT);
+ if (ret)
+ goto done;
+ }
+#else
+ t_u16 mask = 0;
+ if (params->tail && params->tail_len)
+ mask |= MGMT_MASK_BEACON;
+ if (params->proberesp_ies && params->proberesp_ies_len)
+ mask |= MGMT_MASK_PROBE_RESP;
+ if (params->assocresp_ies && params->assocresp_ies_len)
+ mask |= MGMT_MASK_ASSOC_RESP;
+ PRINTM(MIOCTL, "Set beacon: mask=0x%x\n", mask);
+ if (mask) {
+ ret = woal_cfg80211_mgmt_frame_ie(
+ priv, params->tail, params->tail_len,
+ params->proberesp_ies,
+ params->proberesp_ies_len,
+ params->assocresp_ies,
+ params->assocresp_ies_len, NULL, 0, mask,
+ MOAL_IOCTL_WAIT);
+ if (ret)
+ goto done;
+ }
+ if (params->beacon_ies && params->beacon_ies_len) {
+ ret = woal_cfg80211_mgmt_frame_ie(
+ priv, params->beacon_ies,
+ params->beacon_ies_len, NULL, 0, NULL, 0, NULL,
+ 0, MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT);
+ if (ret) {
+ PRINTM(MERROR,
+ "Failed to set beacon wps/p2p ie\n");
+ goto done;
+ }
+ }
+#endif
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief reset AP or GO parameters
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = 0;
+#ifdef STA_SUPPORT
+ moal_private *pmpriv = NULL;
+#endif
+
+ ENTER();
+
+ if (priv->phandle->driver_status) {
+ PRINTM(MERROR,
+ "Block woal_cfg80211_del_beacon in abnormal driver state\n");
+ LEAVE();
+ return ret;
+ }
+ priv->uap_host_based = MFALSE;
+ PRINTM(MMSG, "wlan: Stoping AP\n");
+#ifdef STA_SUPPORT
+ woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
+#endif
+ memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
+ woal_deauth_all_station(priv);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cancel_cac_block(priv);
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ memset(&priv->chan, 0, sizeof(struct cfg80211_chan_def));
+ if (priv->phandle->is_cac_timer_set &&
+ priv->bss_index == priv->phandle->cac_bss_index) {
+ woal_cancel_timer(&priv->phandle->cac_timer);
+ priv->phandle->is_cac_timer_set = MFALSE;
+ /* Make sure Chan Report is cancelled */
+ woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev, &priv->phandle->dfs_channel,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev, NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#endif
+ memset(&priv->phandle->dfs_channel, 0,
+ sizeof(struct cfg80211_chan_def));
+ priv->phandle->cac_bss_index = 0xff;
+ }
+ if (priv->csa_workqueue)
+ flush_workqueue(priv->csa_workqueue);
+#endif
+ /* if the bss is still running, then stop it */
+ if (priv->bss_started == MTRUE) {
+ if (MLAN_STATUS_FAILURE ==
+ woal_uap_bss_ctrl(priv, MOAL_NO_WAIT, UAP_BSS_STOP)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_FAILURE ==
+ woal_uap_bss_ctrl(priv, MOAL_NO_WAIT, UAP_BSS_RESET)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ /* Set WLAN MAC addresses */
+ if (MLAN_STATUS_FAILURE ==
+ woal_request_set_mac_address(priv, MOAL_NO_WAIT)) {
+ PRINTM(MERROR, "Set MAC address failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ woal_clear_all_mgmt_ies(priv, MOAL_NO_WAIT);
+#ifdef STA_SUPPORT
+ if (!woal_is_any_interface_active(priv->phandle)) {
+ pmpriv = woal_get_priv((moal_handle *)priv->phandle,
+ MLAN_BSS_ROLE_STA);
+ if (pmpriv)
+ woal_set_scan_time(pmpriv, ACTIVE_SCAN_CHAN_TIME,
+ PASSIVE_SCAN_CHAN_TIME,
+ SPECIFIC_SCAN_CHAN_TIME);
+ }
+#endif
+
+ priv->cipher = 0;
+ memset(priv->uap_wep_key, 0, sizeof(priv->uap_wep_key));
+ priv->channel = 0;
+ PRINTM(MMSG, "wlan: AP stopped\n");
+done:
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+/**
+ * @brief change BSS
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to bss_parameters structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
+ struct bss_parameters *params)
+{
+ int ret = 0;
+ t_u8 change = MFALSE;
+ mlan_uap_bss_param *sys_config = NULL;
+ u8 bss_started = MFALSE;
+ t_u8 pkt_forward_ctl;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+ PRINTM(MIOCTL, "isolate=%d\n", params->ap_isolate);
+
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ pkt_forward_ctl = sys_config->pkt_forward_ctl;
+ if (params->ap_isolate) {
+ /** disable packet forwarding */
+ sys_config->pkt_forward_ctl |= PKT_FWD_INTRA_BCAST;
+ sys_config->pkt_forward_ctl |= PKT_FWD_INTRA_UCAST;
+ } else {
+ sys_config->pkt_forward_ctl &= ~PKT_FWD_INTRA_BCAST;
+ sys_config->pkt_forward_ctl &= ~PKT_FWD_INTRA_UCAST;
+ }
+ if (pkt_forward_ctl != sys_config->pkt_forward_ctl) {
+ change = MTRUE;
+ PRINTM(MIOCTL, "ap_isolate=%xd\n", params->ap_isolate);
+ }
+ if (change) {
+ if (priv->bss_started == MTRUE) {
+ bss_started = MTRUE;
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ }
+ if (params->use_short_preamble == 1)
+ sys_config->preamble_type = 1;
+ else if (params->use_short_preamble == 0)
+ sys_config->preamble_type = 2;
+ else
+ sys_config->preamble_type = 0;
+ if (MLAN_STATUS_SUCCESS ==
+ woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ sys_config))
+ ret = 0;
+ if (bss_started)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT_TIMEOUT,
+ UAP_BSS_START);
+ }
+done:
+ kfree(sys_config);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+/**
+ * @brief del station
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param param A pointer tostation_del_parameters structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#else
+/**
+ * @brief del station
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac_addr A pointer to station mac address
+ *
+ * @return 0 -- success, otherwise fail
+ */
+#endif
+int woal_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ struct station_del_parameters *param)
+#else
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac_addr)
+#else
+ u8 *mac_addr)
+#endif
+#endif
+{
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ const u8 *mac_addr = NULL;
+#endif
+ u16 reason_code = REASON_CODE_DEAUTH_LEAVING;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ ENTER();
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+ if (priv->phandle->is_cac_timer_set &&
+ priv->bss_index == priv->phandle->cac_bss_index) {
+ woal_cancel_timer(&priv->phandle->cac_timer);
+ priv->phandle->is_cac_timer_set = MFALSE;
+ /* Make sure Chan Report is cancelled */
+ woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev, &priv->phandle->dfs_channel,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev, NL80211_RADAR_CAC_ABORTED,
+ GFP_KERNEL);
+#endif
+ memset(&priv->phandle->dfs_channel, 0,
+ sizeof(struct cfg80211_chan_def));
+ priv->phandle->cac_bss_index = 0xff;
+ }
+#endif
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
+ woal_cancel_cac_block(priv);
+#endif
+
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return 0;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
+ if (param) {
+ mac_addr = param->mac;
+ reason_code = param->reason_code;
+ }
+#endif
+ /** we will not send deauth to p2p interface, it might cause WPS failure
+ */
+ if (mac_addr) {
+ PRINTM(MMSG, "wlan: deauth station " MACSTR "\n",
+ MAC2STR(mac_addr));
+#ifdef WIFI_DIRECT_SUPPORT
+ if (!priv->phandle->is_go_timer_set)
+#endif
+ woal_deauth_station(priv, (u8 *)mac_addr, reason_code);
+ } else {
+ PRINTM(MIOCTL, "del all station\n");
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get station info
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param mac A pointer to station mac address
+ * @param stainfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+ const u8 *mac,
+#else
+ u8 *mac,
+#endif
+ struct station_info *stainfo)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = -EFAULT;
+ int i = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ mlan_ds_get_stats stats;
+
+ ENTER();
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ goto done;
+ for (i = 0; i < info->param.sta_list.sta_count; i++) {
+ if (!memcmp(info->param.sta_list.info[i].mac_address, mac,
+ ETH_ALEN)) {
+ PRINTM(MIOCTL, "Get station: " MACSTR " RSSI=%d\n",
+ MAC2STR(mac),
+ (int)info->param.sta_list.info[i].rssi);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ stainfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+ BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS) |
+ BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_SIGNAL);
+
+ stainfo->rx_bytes = priv->stats.rx_bytes;
+ stainfo->tx_bytes = priv->stats.tx_bytes;
+ stainfo->rx_packets = priv->stats.rx_packets;
+ stainfo->tx_packets = priv->stats.tx_packets;
+#else
+ stainfo->filled = STATION_INFO_INACTIVE_TIME |
+ STATION_INFO_SIGNAL;
+#endif
+ stainfo->inactive_time = 0;
+ stainfo->signal = info->param.sta_list.info[i].rssi;
+ ret = 0;
+ break;
+ }
+ }
+ memset(&stats, 0, sizeof(mlan_ds_get_stats));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
+ PRINTM(MERROR, "Error getting stats information\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ stainfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES) |
+ BIT(NL80211_STA_INFO_TX_FAILED) |
+ BIT(NL80211_STA_INFO_RX_DROP_MISC);
+ stainfo->tx_failed = stats.failed;
+ stainfo->tx_retries = stats.retry;
+ stainfo->rx_dropped_misc = stats.fcs_error;
+#endif
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request the driver to dump the station information
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param idx Station index
+ * @param mac MAC address of the station
+ * @param sinfo A pointer to station_info structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_uap_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, t_u8 *mac,
+ struct station_info *sinfo)
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ int ret = -EFAULT;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+ t_u32 sec = 0, usec = 0;
+ t_u64 cur_msec = 0;
+
+ ENTER();
+ if (priv->media_connected == MFALSE) {
+ PRINTM(MINFO, "cfg80211: Media not connected!\n");
+ LEAVE();
+ return -ENOENT;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *)ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ goto done;
+ if (idx >= info->param.sta_list.sta_count) {
+ ret = -EFAULT;
+ goto done;
+ }
+ ret = 0;
+ moal_memcpy_ext(priv->phandle, mac,
+ info->param.sta_list.info[idx].mac_address, ETH_ALEN,
+ ETH_ALEN);
+ PRINTM(MIOCTL, "Dump station: " MACSTR " RSSI=%d\n", MAC2STR(mac),
+ (int)info->param.sta_list.info[idx].rssi);
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+ BIT(NL80211_STA_INFO_SIGNAL);
+#else
+ sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_SIGNAL;
+#endif
+ if (info->param.sta_list.info[idx].stats.last_rx_in_msec) {
+ moal_get_system_time(priv->phandle, &sec, &usec);
+ cur_msec = (t_u64)sec * 1000 + (t_u64)usec / 1000;
+ sinfo->inactive_time = (t_u32)(
+ cur_msec -
+ info->param.sta_list.info[idx].stats.last_rx_in_msec);
+ PRINTM(MIOCTL,
+ "cur:%llu - [%d].last_rx:%llu = inactive_time:%d\n",
+ cur_msec, idx,
+ info->param.sta_list.info[idx].stats.last_rx_in_msec,
+ sinfo->inactive_time);
+ } else
+ sinfo->inactive_time = 0;
+ sinfo->signal = info->param.sta_list.info[idx].rssi;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+/**
+ * @brief set mac filter
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_acl_data structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_acl_data *params)
+{
+ int ret = -EFAULT;
+ mlan_uap_bss_param *sys_config = NULL;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ u8 bss_started = MFALSE;
+ ENTER();
+
+ PRINTM(MIOCTL, "Set mac acl, entries=%d, policy=%d\n",
+ params->n_acl_entries, params->acl_policy);
+ sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_config) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ sys_config)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&sys_config->filter, 0, sizeof(mac_filter));
+ if (params->n_acl_entries <= MAX_MAC_FILTER_NUM)
+ sys_config->filter.mac_count = params->n_acl_entries;
+ else
+ sys_config->filter.mac_count = MAX_MAC_FILTER_NUM;
+
+ if (params->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+ sys_config->filter.filter_mode = MAC_FILTER_MODE_ALLOW_MAC;
+ else if (params->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED)
+ sys_config->filter.filter_mode = MAC_FILTER_MODE_BLOCK_MAC;
+ moal_memcpy_ext(
+ priv->phandle, sys_config->filter.mac_list, params->mac_addrs,
+ sys_config->filter.mac_count * sizeof(mlan_802_11_mac_addr),
+ sizeof(sys_config->filter.mac_list));
+ if (priv->bss_started == MTRUE) {
+ bss_started = MTRUE;
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ }
+ if (MLAN_STATUS_SUCCESS == woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_config))
+ ret = 0;
+done:
+ kfree(sys_config);
+ if (bss_started)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT_TIMEOUT, UAP_BSS_START);
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
+/**
+ * @brief Set txq parameters
+
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to ieee80211_txq_params structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_set_txq_params(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_txq_params *params)
+{
+ int ret = 0;
+ u8 ac = 0;
+ wmm_parameter_t ap_wmm_para;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+
+ ENTER();
+
+ /* AC_BE: 0, AC_BK:1, AC_VI: 2, AC_VO:3 */
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ switch (params->ac) {
+ case NL80211_AC_VO:
+ ac = 3;
+ break;
+ case NL80211_AC_VI:
+ ac = 2;
+ break;
+ case NL80211_AC_BK:
+ ac = 1;
+ break;
+ case NL80211_AC_BE:
+ ac = 0;
+ break;
+ default:
+ break;
+ }
+#else
+ switch (params->queue) {
+ case NL80211_TXQ_Q_VO:
+ ac = 3;
+ break;
+ case NL80211_TXQ_Q_VI:
+ ac = 2;
+ break;
+ case NL80211_TXQ_Q_BK:
+ ac = 1;
+ break;
+ case NL80211_TXQ_Q_BE:
+ ac = 0;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ PRINTM(MMSG, "Set AC=%d, txop=%d cwmin=%d, cwmax=%d aifs=%d\n", ac,
+ params->txop, params->cwmin, params->cwmax, params->aifs);
+
+ memset(&ap_wmm_para, 0, sizeof(wmm_parameter_t));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_ap_wmm_para(priv, MLAN_ACT_GET, &ap_wmm_para)) {
+ PRINTM(MERROR, "wlan: We don't support AP WMM parameter\n");
+ LEAVE();
+ return ret;
+ }
+ ap_wmm_para.ac_params[ac].aci_aifsn.aifsn = params->aifs;
+ ap_wmm_para.ac_params[ac].ecw.ecw_max = ilog2(params->cwmax + 1);
+ ap_wmm_para.ac_params[ac].ecw.ecw_min = ilog2(params->cwmin + 1);
+ ap_wmm_para.ac_params[ac].tx_op_limit = params->txop;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_ap_wmm_para(priv, MLAN_ACT_SET, &ap_wmm_para)) {
+ PRINTM(MERROR, "wlan: Fail to set AP WMM parameter\n");
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+#endif
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
+/**
+ * @brief cac timer call back function.
+ *
+ * @param context a pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_cac_timer_func(void *context)
+{
+ moal_handle *handle = (moal_handle *)context;
+ moal_private *priv = handle->priv[handle->cac_bss_index];
+
+ PRINTM(MEVENT, "cac_timer fired.\n");
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+ cfg80211_cac_event(priv->netdev, &handle->dfs_channel,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+#else
+ cfg80211_cac_event(priv->netdev, NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+#endif
+ handle->is_cac_timer_set = MFALSE;
+ memset(&handle->dfs_channel, 0, sizeof(struct cfg80211_chan_def));
+ handle->cac_bss_index = 0xff;
+}
+
+/**
+ * @brief This function switch AP's channel
+ * 1. clear mgmt IEs 2. stop uAP
+ * 3. set beacon after 4. set new channel
+ * 5. start uAP 6. notify cfg80211
+ *
+ * @param priv a pointer to moal_private
+ * @param wait_option wait option
+ *
+ * @return N/A
+ */
+void woal_switch_uap_channel(moal_private *priv, t_u8 wait_option)
+{
+ chan_band_info uap_channel;
+ t_u8 chan2Offset = SEC_CHAN_NONE;
+ ENTER();
+ woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, wait_option, UAP_BSS_STOP)) {
+ PRINTM(MERROR, "%s: stop uap failed \n", __func__);
+ goto done;
+ }
+ if (woal_cfg80211_set_beacon(priv->wdev->wiphy, priv->netdev,
+ &priv->beacon_after)) {
+ PRINTM(MERROR, "%s: set mgmt ies failed \n", __func__);
+ goto done;
+ }
+
+ uap_channel.channel = ieee80211_frequency_to_channel(
+ priv->csa_chan.chan->center_freq);
+ switch (priv->csa_chan.width) {
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ uap_channel.bandcfg.chanWidth = CHAN_BW_20MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ uap_channel.bandcfg.chanWidth = CHAN_BW_20MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ if (priv->csa_chan.center_freq1 <
+ priv->csa_chan.chan->center_freq)
+ chan2Offset = SEC_CHAN_BELOW;
+ else
+ chan2Offset = SEC_CHAN_ABOVE;
+ uap_channel.bandcfg.chanWidth = CHAN_BW_40MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ uap_channel.bandcfg.chanWidth = CHAN_BW_80MHZ;
+ chan2Offset =
+ woal_get_second_channel_offset(uap_channel.channel);
+ break;
+ default:
+ PRINTM(MWARN, "Unknown channel width: %d\n",
+ priv->csa_chan.width);
+ break;
+ }
+ if (priv->csa_chan.chan->band == IEEE80211_BAND_2GHZ)
+ uap_channel.bandcfg.chanBand = BAND_2GHZ;
+ else if (priv->csa_chan.chan->band == IEEE80211_BAND_5GHZ)
+ uap_channel.bandcfg.chanBand = BAND_5GHZ;
+ uap_channel.bandcfg.chan2Offset = chan2Offset;
+ if (MLAN_STATUS_SUCCESS != woal_set_get_ap_channel(priv, MLAN_ACT_SET,
+ wait_option,
+ &uap_channel)) {
+ PRINTM(MERROR, "Fail to set ap channel \n");
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT_TIMEOUT, UAP_BSS_START)) {
+ PRINTM(MERROR, "%s: start uap failed \n", __func__);
+ goto done;
+ }
+ PRINTM(MMSG, "CSA: old chan %d => new chan %d \n", priv->channel,
+ uap_channel.channel);
+ priv->channel = uap_channel.channel;
+ moal_memcpy_ext(priv->phandle, &priv->chan, &priv->csa_chan,
+ sizeof(struct cfg80211_chan_def), sizeof(priv->chan));
+ cfg80211_ch_switch_notify(priv->netdev, &priv->chan);
+ if (priv->uap_tx_blocked) {
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ woal_start_queue(priv->netdev);
+ priv->uap_tx_blocked = MFALSE;
+ }
+done:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief csa work handler
+ *
+ * @param work a pointer to work_struct
+ *
+ * @return 0 -- success, otherwise fail
+ */
+void woal_csa_work_queue(struct work_struct *work)
+{
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ moal_private *priv = container_of(delayed_work, moal_private, csa_work);
+ ENTER();
+ if (priv->bss_started == MTRUE)
+ woal_switch_uap_channel(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+}
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+/**
+ * @brief start radar detection
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chandef A pointer to cfg80211_chan_def structure
+ * @param cac_time_ms A cac dwell time
+ * @return 0 -- success, otherwise fail
+ */
+
+int woal_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef,
+ u32 cac_time_ms)
+#else
+/**
+ * @brief start radar detection
+ *
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param chandef A pointer to cfg80211_chan_def structure
+ * @return 0 -- success, otherwise fail
+ */
+
+int woal_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef)
+#endif
+{
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ moal_handle *handle = priv->phandle;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
+ mlan_ds_11h_cfg *p11h_cfg = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ PRINTM(MIOCTL, "start Radar detect, chan %d , Bw %d , Time %d \n",
+ chandef->chan->hw_value, chandef->width, cac_time_ms);
+#else
+ PRINTM(MIOCTL, "start Radar detect, chan %d , Bw %d \n",
+ chandef->chan->hw_value, chandef->width);
+#endif
+
+ if (priv->bss_started == MTRUE) {
+ PRINTM(MERROR, "recv CAC request when bss already started \n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (priv->phandle->cac_period || handle->is_cac_timer_set) {
+ PRINTM(MERROR,
+ "Maybe other interface is doing CAC, please defer your oper\n");
+ ret = -EBUSY;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (NULL == req) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
+ pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
+ pchan_rpt_req->startFreq = START_FREQ_11A_BAND;
+ pchan_rpt_req->chanNum = (t_u8)chandef->chan->hw_value;
+ woal_convert_chan_to_bandconfig(&pchan_rpt_req->bandcfg, chandef);
+ pchan_rpt_req->host_based = MTRUE;
+
+#if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ pchan_rpt_req->millisec_dwell_time = cac_time_ms;
+#else
+ pchan_rpt_req->millisec_dwell_time = IEEE80211_DFS_MIN_CAC_TIME_MS;
+
+ if ((woal_is_etsi_country(priv->phandle->country_code) == MTRUE)) {
+ if (chandef->chan->hw_value == 120 ||
+ chandef->chan->hw_value == 124 ||
+ chandef->chan->hw_value == 128) {
+ pchan_rpt_req->millisec_dwell_time =
+ IEEE80211_DFS_MIN_CAC_TIME_MS * 10;
+ }
+ if (chandef->chan->hw_value == 116 &&
+ ((chandef->width == NL80211_CHAN_WIDTH_40) ||
+ (chandef->width == NL80211_CHAN_WIDTH_80))) {
+ pchan_rpt_req->millisec_dwell_time =
+ IEEE80211_DFS_MIN_CAC_TIME_MS * 10;
+ }
+ }
+#endif
+ if (priv->user_cac_period_msec) {
+ pchan_rpt_req->millisec_dwell_time = priv->user_cac_period_msec;
+ PRINTM(MCMD_D,
+ "cfg80211 dfstesting: User CAC Period=%d (msec) \n",
+ pchan_rpt_req->millisec_dwell_time);
+ }
+
+ p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
+ req->req_id = MLAN_IOCTL_11H_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Send Channel Check command and wait until the report is ready */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Fail to start radar detection\n");
+ ret = -EFAULT;
+ } else {
+ moal_memcpy_ext(priv->phandle, &handle->dfs_channel, chandef,
+ sizeof(struct cfg80211_chan_def),
+ sizeof(handle->dfs_channel));
+ handle->cac_bss_index = priv->bss_index;
+ handle->is_cac_timer_set = MTRUE;
+ /* avoid EVENT_CHANNEL_RAPORT_READY missing, add 1s gap */
+ woal_mod_timer(&handle->cac_timer,
+ pchan_rpt_req->millisec_dwell_time + 1000);
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief channel switch
+
+ * @param wiphy A pointer to wiphy structure
+ * @param dev A pointer to net_device structure
+ * @param params A pointer to cfg80211_csa_settings structure
+ *
+ * @return 0 -- success, otherwise fail
+ */
+int woal_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_csa_settings *params)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
+ t_u32 chsw_msec;
+ mlan_uap_bss_param *bss_cfg = NULL;
+
+ ENTER();
+
+ if (!params) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* TODO: support this case in next version */
+ if (params->radar_required) {
+ PRINTM(MMSG,
+ " hostapd handle this case by disable and re-enable interface\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ /* actually hostapd would always choose one diff channel*/
+ if (cfg80211_chandef_identical(&params->chandef, &priv->chan)) {
+ PRINTM(MMSG,
+ "csa channel is same with current channel, invaild\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ bss_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!bss_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (params->block_tx) {
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+ woal_stop_queue(dev);
+ priv->uap_tx_blocked = MTRUE;
+ }
+
+ woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
+ if (woal_cfg80211_set_beacon(wiphy, dev, &params->beacon_csa)) {
+ PRINTM(MERROR, "%s: setting csa mgmt ies failed\n", __func__);
+ goto done;
+ }
+
+ moal_memcpy_ext(priv->phandle, &priv->csa_chan, &params->chandef,
+ sizeof(struct cfg80211_chan_def),
+ sizeof(priv->csa_chan));
+ moal_memcpy_ext(priv->phandle, &priv->beacon_after,
+ &params->beacon_after,
+ sizeof(struct cfg80211_beacon_data),
+ sizeof(priv->beacon_after));
+
+ if (!priv->phandle->fw_ecsa_enable) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
+ bss_cfg)) {
+ PRINTM(MERROR, "%s: get uap config failed\n", __func__);
+ ret = -EFAULT;
+ goto done;
+ }
+ chsw_msec = params->count * bss_cfg->beacon_period;
+ queue_delayed_work(priv->csa_workqueue, &priv->csa_work,
+ msecs_to_jiffies(chsw_msec));
+ }
+done:
+ kfree(bss_cfg);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Register the device with cfg80211
+ *
+ * @param dev A pointer to net_device structure
+ * @param bss_type BSS type
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_register_uap_cfg80211(struct net_device *dev, t_u8 bss_type)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct wireless_dev *wdev = NULL;
+
+ ENTER();
+
+ wdev = (struct wireless_dev *)&priv->w_dev;
+ memset(wdev, 0, sizeof(struct wireless_dev));
+
+ wdev->wiphy = priv->phandle->wiphy;
+ if (!wdev->wiphy) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ if (bss_type == MLAN_BSS_TYPE_UAP)
+ wdev->iftype = NL80211_IFTYPE_AP;
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.h
new file mode 100644
index 000000000000..9f3c470825ca
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_cfg80211.h
@@ -0,0 +1,30 @@
+/** @file moal_uap_cfg80211.h
+ *
+ * @brief This file contains the uAP CFG80211 specific defines.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+#ifndef _MOAL_UAP_CFG80211_H_
+#define _MOAL_UAP_CFG80211_H_
+
+#include "moal_uap.h"
+
+mlan_status woal_register_uap_cfg80211(struct net_device *dev, t_u8 bss_type);
+
+#endif /* _MOAL_UAP_CFG80211_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.c
new file mode 100644
index 000000000000..02e3cc232b4d
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.c
@@ -0,0 +1,179 @@
+/** @file moal_uap_priv.c
+ *
+ * @brief This file contains standard ioctl functions
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+/**
+ * @brief ioctl function for wireless IOCTLs
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iwreq *wrq = (struct iwreq *)req;
+ int ret = 0;
+
+ ENTER();
+
+ switch (cmd) {
+ case WOAL_UAP_SETNONE_GETNONE:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_START:
+ break;
+ case WOAL_UAP_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
+ UAP_BSS_STOP);
+ break;
+ case WOAL_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
+ UAP_BSS_START);
+ break;
+ case WOAL_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
+ UAP_BSS_STOP);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case WOAL_UAP_SETONEINT_GETWORDCHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_VERSION:
+ ret = woal_get_driver_version(priv, req);
+ break;
+ case WOAL_UAP_VEREXT:
+ ret = woal_get_driver_verext(priv, req);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case WOAL_UAP_SET_GET_256_CHAR:
+ switch (wrq->u.data.flags) {
+ case WOAL_WL_FW_RELOAD:
+ break;
+ case WOAL_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ case WOAL_UAP_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WOAL_UAP_SET_GET_BSS_ROLE:
+ ret = woal_set_get_bss_role(priv, wrq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+#endif
+#endif
+ case WOAL_UAP_HOST_CMD:
+ ret = woal_host_command(priv, wrq);
+ break;
+ case WOAL_UAP_FROYO_START:
+ break;
+ case WOAL_UAP_FROYO_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_START:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ break;
+ case WOAL_UAP_FROYO_AP_BSS_STOP:
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+ break;
+ case WOAL_UAP_FROYO_WL_FW_RELOAD:
+ break;
+ case WOAL_UAP_FROYO_AP_SET_CFG:
+ ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer,
+ wrq->u.data.length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle get info resp
+ *
+ * @param priv Pointer to moal_private structure
+ * @param info Pointer to mlan_ds_get_info structure
+ *
+ * @return N/A
+ */
+void woal_ioctl_get_uap_info_resp(moal_private *priv, mlan_ds_get_info *info)
+{
+ ENTER();
+ switch (info->sub_command) {
+ case MLAN_OID_GET_STATS:
+ priv->w_stats.discard.fragment =
+ info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc =
+ info->param.ustats.ack_failure_count;
+ break;
+ default:
+ break;
+ }
+ LEAVE();
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.h
new file mode 100644
index 000000000000..d050bac0e6bc
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_priv.h
@@ -0,0 +1,128 @@
+/** @file moal_uap_priv.h
+ *
+ * @brief This file contains definition for extended private IOCTL call.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#ifndef _MOAL_UAP_PRIV_H_
+#define _MOAL_UAP_PRIV_H_
+
+/** Private command ID */
+#define WOAL_UAP_IOCTL 0x8BE0
+
+/** Private command to get/set 256 chars */
+#define WOAL_UAP_SET_GET_256_CHAR (WOAL_UAP_IOCTL + 1)
+/** Private command ID to FW reload */
+#define WOAL_WL_FW_RELOAD 1
+/** Private command ID to set AP configuration */
+#define WOAL_AP_SET_CFG 2
+
+/** Private command ID to set/get none */
+#define WOAL_UAP_SETNONE_GETNONE (WOAL_UAP_IOCTL + 2)
+/** Private command ID to start UAP */
+#define WOAL_UAP_START 1
+/** Private command ID to stop UAP */
+#define WOAL_UAP_STOP 2
+/** Private command ID to start AP BSS */
+#define WOAL_AP_BSS_START 3
+/** Private command ID to stop AP BSS */
+#define WOAL_AP_BSS_STOP 4
+
+/** Private command ID to set one int/get word char */
+#define WOAL_UAP_SETONEINT_GETWORDCHAR (WOAL_UAP_IOCTL + 3)
+/** Private command ID to get version */
+#define WOAL_UAP_VERSION 1
+/** Private command ID to get extended version */
+#define WOAL_UAP_VEREXT 2
+
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+/** Private command ID to set one int/get one int */
+#define WOAL_UAP_SETONEINT_GETONEINT (WOAL_UAP_IOCTL + 5)
+/** Private command ID for set/get BSS role */
+#define WOAL_UAP_SET_GET_BSS_ROLE 1
+#endif
+#endif
+
+/** Private command ID for hostcmd */
+#define WOAL_UAP_HOST_CMD (WOAL_UAP_IOCTL + 17)
+
+/** The following command IDs are for Froyo app */
+/** Private command ID to start AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_START (WOAL_UAP_IOCTL + 24)
+/** Private command ID to stop AP BSS */
+#define WOAL_UAP_FROYO_AP_BSS_STOP (WOAL_UAP_IOCTL + 26)
+/** Private command ID to set AP config */
+#define WOAL_UAP_FROYO_AP_SET_CFG (WOAL_UAP_IOCTL + 27)
+/** Private command ID to start driver */
+#define WOAL_UAP_FROYO_START (WOAL_UAP_IOCTL + 28)
+/** Private command ID to reload FW */
+#define WOAL_UAP_FROYO_WL_FW_RELOAD (WOAL_UAP_IOCTL + 29)
+/** Private command ID to stop driver */
+#define WOAL_UAP_FROYO_STOP (WOAL_UAP_IOCTL + 30)
+
+/**
+ * iwpriv ioctl handlers
+ */
+static const struct iw_priv_args woal_uap_priv_args[] = {
+ {WOAL_UAP_SETNONE_GETNONE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, ""},
+ {WOAL_UAP_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "start"},
+ {WOAL_UAP_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "stop"},
+ {WOAL_AP_BSS_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "bssstart"},
+ {WOAL_AP_BSS_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "bssstop"},
+ {WOAL_UAP_SETONEINT_GETWORDCHAR, IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_CHAR | 128, ""},
+ {WOAL_UAP_VERSION, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
+ "version"},
+ {WOAL_UAP_VEREXT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
+ "verext"},
+#ifdef WIFI_DIRECT_SUPPORT
+#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
+ {WOAL_UAP_SETONEINT_GETONEINT, IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1, ""},
+ {WOAL_UAP_SET_GET_BSS_ROLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
+ "bssrole"},
+#endif
+#endif
+ {WOAL_UAP_SET_GET_256_CHAR, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, ""},
+ {WOAL_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "fwreload"},
+ {WOAL_AP_SET_CFG, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
+ "apcfg"},
+ {WOAL_UAP_HOST_CMD, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_BYTE | 2047,
+ "hostcmd"},
+ {WOAL_UAP_FROYO_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "START"},
+ {WOAL_UAP_FROYO_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "STOP"},
+ {WOAL_UAP_FROYO_AP_BSS_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
+ "AP_BSS_START"},
+ {WOAL_UAP_FROYO_AP_BSS_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
+ "AP_BSS_STOP"},
+ {WOAL_UAP_FROYO_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, "WL_FW_RELOAD"},
+ {WOAL_UAP_FROYO_AP_SET_CFG, IW_PRIV_TYPE_CHAR | 256,
+ IW_PRIV_TYPE_CHAR | 256, "AP_SET_CFG"},
+};
+
+#endif /* _MOAL_UAP_PRIV_H_ */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_wext.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_wext.c
new file mode 100644
index 000000000000..51967247f796
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_uap_wext.c
@@ -0,0 +1,1865 @@
+/** @file moal_uap_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 08/06/2010: initial version
+************************************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_wext.h"
+#include "moal_uap_priv.h"
+
+/********************************************************
+ Global Variables
+********************************************************/
+typedef struct _chan_to_freq_t {
+ /** Channel */
+ t_u16 channel;
+ /** Frequency */
+ t_u32 freq;
+ /** Band */
+ t_u8 band;
+} chan_to_freq_t;
+
+const chan_to_freq_t chan_to_freq[] = {
+ {1, 2412, 0}, {2, 2417, 0}, {3, 2422, 0}, {4, 2427, 0},
+ {5, 2432, 0}, {6, 2437, 0}, {7, 2442, 0}, {8, 2447, 0},
+ {9, 2452, 0}, {10, 2457, 0}, {11, 2462, 0}, {12, 2467, 0},
+ {13, 2472, 0}, {14, 2484, 0}, {183, 4915, 1}, {184, 4920, 1},
+ {185, 4925, 1}, {187, 4935, 1}, {188, 4940, 1}, {189, 4945, 1},
+ {192, 4960, 1}, {196, 4980, 1}, {7, 5035, 1}, {8, 5040, 1},
+ {9, 5045, 1}, {11, 5055, 1}, {12, 5060, 1}, {16, 5080, 1},
+ {34, 5170, 1}, {36, 5180, 1}, {38, 5190, 1}, {40, 5200, 1},
+ {42, 5210, 1}, {44, 5220, 1}, {46, 5230, 1}, {48, 5240, 1},
+ {52, 5260, 1}, {56, 5280, 1}, {60, 5300, 1}, {64, 5320, 1},
+ {100, 5500, 1}, {104, 5520, 1}, {108, 5540, 1}, {112, 5560, 1},
+ {116, 5580, 1}, {120, 5600, 1}, {124, 5620, 1}, {128, 5640, 1},
+ {132, 5660, 1}, {136, 5680, 1}, {140, 5700, 1}, {144, 5720, 1},
+ {149, 5745, 1}, {153, 5765, 1}, {157, 5785, 1}, {161, 5805, 1},
+ {165, 5825, 1},
+};
+
+/** Convertion from frequency to channel */
+#define freq_to_chan(x) ((((x)-2412) / 5) + 1)
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Get frequency for channel in given band
+ *
+ * @param channel channel
+ * @param band band
+ *
+ * @return freq
+ */
+static int channel_to_frequency(t_u16 channel, t_u8 band)
+{
+ int i = 0;
+
+ ENTER();
+ for (i = 0; i < ARRAY_SIZE(chan_to_freq); i++) {
+ if (channel == chan_to_freq[i].channel &&
+ band == chan_to_freq[i].band) {
+ LEAVE();
+ return chan_to_freq[i].freq;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *cwrq = wrqu->name;
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct sockaddr *awrq = &wrqu->addr;
+ int ret = 0;
+
+ ENTER();
+
+ if (priv->bss_started)
+ moal_memcpy_ext(priv->phandle, awrq->sa_data,
+ priv->current_addr, MLAN_MAC_ADDR_LENGTH,
+ sizeof(awrq->sa_data));
+ else
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Change the AP BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct sockaddr *awrq = &wrqu->addr;
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: uAP bss : " MACSTR "\n",
+ MAC2STR((t_u8 *)awrq->sa_data));
+
+ /*
+ * Using this ioctl to start/stop the BSS, return if bss
+ * is already started/stopped.
+ */
+ if (memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ if (priv->bss_started == MFALSE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
+ UAP_BSS_START);
+ else
+ PRINTM(MINFO, "BSS is already started.\n");
+ } else {
+ /* zero_mac means bss_stop */
+ if (priv->bss_started == MTRUE)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
+ UAP_BSS_STOP);
+ else
+ PRINTM(MINFO, "BSS is already stopped.\n");
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set frequency/channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ int ret = 0, chan = 0, i = 0;
+
+ ENTER();
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ i = ap_cfg->num_of_chan;
+
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ /* If setting by frequency, convert to a channel */
+ if (fwrq->e == 1)
+ chan = freq_to_chan(fwrq->m / 100000);
+ else
+ chan = fwrq->m;
+ if (chan > 0 && chan < MLAN_MAX_CHANNEL)
+ sys_cfg->channel = chan;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+ for (i = 0; i < ap_cfg->num_of_chan; i++)
+ if (ap_cfg->chan_list[i].chan_number == chan)
+ break;
+ if (i == ap_cfg->num_of_chan) {
+ PRINTM(MERROR, "Channel %d is not supported\n", chan);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ kfree(sys_cfg);
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency and channel
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+ mlan_uap_bss_param *ap_cfg = NULL;
+ t_u8 band = 0;
+ int ret = 0;
+
+ ENTER();
+
+ ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!ap_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ kfree(ap_cfg);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ band = (ap_cfg->bandcfg.chanBand == BAND_5GHZ);
+ fwrq->m = (long)channel_to_frequency(ap_cfg->channel, band);
+ fwrq->i = (long)ap_cfg->channel;
+ fwrq->e = 6;
+
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_bss_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ t_u32 *uwrq = &wrqu->mode;
+ ENTER();
+
+ switch (*uwrq) {
+ case IW_MODE_AUTO:
+ case IW_MODE_MASTER:
+ PRINTM(MINFO, "This is correct mode in AP mode\n");
+ break;
+ default:
+ PRINTM(MERROR, "Invalid mode for AP\n");
+ ret = -EINVAL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_bss_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ t_u32 *uwrq = &wrqu->mode;
+ ENTER();
+
+ *uwrq = IW_MODE_MASTER;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
+ wep_key *pkey = NULL;
+ int key_index = 0;
+
+ ENTER();
+
+ /* Check index */
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", key_index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (ap_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
+ if (sys_cfg == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+ sys_cfg->wep_cfg.key0.key_index = 0;
+ sys_cfg->wep_cfg.key1.key_index = 1;
+ sys_cfg->wep_cfg.key2.key_index = 2;
+ sys_cfg->wep_cfg.key3.key_index = 3;
+
+ if (key_index >= 0 && key_index <= 3) {
+ if (key_index == 0)
+ pkey = &sys_cfg->wep_cfg.key0;
+ else if (key_index == 1)
+ pkey = &sys_cfg->wep_cfg.key1;
+ else if (key_index == 2)
+ pkey = &sys_cfg->wep_cfg.key2;
+ else if (key_index == 3)
+ pkey = &sys_cfg->wep_cfg.key3;
+ }
+
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n",
+ dwrq->length);
+ ret = -E2BIG;
+ goto done;
+ }
+ if (key_index < 0) {
+ /* Get current default key index */
+ if (ap_cfg->wep_cfg.key0.is_default)
+ pkey = &sys_cfg->wep_cfg.key0;
+ if (ap_cfg->wep_cfg.key1.is_default)
+ pkey = &sys_cfg->wep_cfg.key1;
+ if (ap_cfg->wep_cfg.key2.is_default)
+ pkey = &sys_cfg->wep_cfg.key2;
+ if (ap_cfg->wep_cfg.key3.is_default)
+ pkey = &sys_cfg->wep_cfg.key3;
+ else { /* Something wrong, select first key as default
+ */
+ PRINTM(MERROR,
+ "No default key set! Selecting first key.\n");
+ pkey = &sys_cfg->wep_cfg.key0;
+ }
+ }
+
+ sys_cfg->protocol = PROTOCOL_STATIC_WEP;
+ if (extra)
+ moal_memcpy_ext(priv->phandle, pkey->key, extra,
+ dwrq->length, sizeof(pkey->key));
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ pkey->length = MAX_WEP_KEY_SIZE;
+ else
+ pkey->length = MIN_WEP_KEY_SIZE;
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sys_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * Do we want to just set the transmit key index ?
+ */
+ if (key_index < 0) {
+ PRINTM(MINFO,
+ "*** iwconfig mlanX key on ***\n");
+ } else {
+ /* Get current key configuration at key_index */
+ if (key_index == 0)
+ moal_memcpy_ext(priv->phandle, pkey,
+ &ap_cfg->wep_cfg.key0,
+ sizeof(wep_key),
+ sizeof(wep_key));
+ if (key_index == 1)
+ moal_memcpy_ext(priv->phandle, pkey,
+ &ap_cfg->wep_cfg.key1,
+ sizeof(wep_key),
+ sizeof(wep_key));
+ if (key_index == 2)
+ moal_memcpy_ext(priv->phandle, pkey,
+ &ap_cfg->wep_cfg.key2,
+ sizeof(wep_key),
+ sizeof(wep_key));
+ if (key_index == 3)
+ moal_memcpy_ext(priv->phandle, pkey,
+ &ap_cfg->wep_cfg.key3,
+ sizeof(wep_key),
+ sizeof(wep_key));
+ /* Set current key index as default */
+ pkey->is_default = MTRUE;
+ }
+ }
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ kfree(sys_cfg);
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+ wep_key *pkey = NULL;
+ mlan_uap_bss_param *ap_cfg = NULL;
+ int ret = 0;
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!ap_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (ap_cfg->auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+
+ switch (ap_cfg->protocol) {
+ case PROTOCOL_NO_SECURITY:
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ break;
+ case PROTOCOL_STATIC_WEP:
+ if (ap_cfg->wep_cfg.key0.is_default)
+ pkey = &ap_cfg->wep_cfg.key0;
+ else if (ap_cfg->wep_cfg.key1.is_default)
+ pkey = &ap_cfg->wep_cfg.key1;
+ else if (ap_cfg->wep_cfg.key2.is_default)
+ pkey = &ap_cfg->wep_cfg.key2;
+ else if (ap_cfg->wep_cfg.key3.is_default)
+ pkey = &ap_cfg->wep_cfg.key3;
+ if (pkey) {
+ dwrq->flags |= (pkey->key_index + 1);
+ dwrq->length = pkey->length;
+ moal_memcpy_ext(priv->phandle, extra, pkey->key,
+ pkey->length, pkey->length);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ ret = -EFAULT;
+ }
+ break;
+ case PROTOCOL_WPA:
+ case PROTOCOL_WPA2:
+ case PROTOCOL_WPA2_MIXED:
+ moal_memcpy_ext(priv->phandle, extra,
+ ap_cfg->wpa_cfg.passphrase,
+ ap_cfg->wpa_cfg.length, ap_cfg->wpa_cfg.length);
+ dwrq->length = ap_cfg->wpa_cfg.length;
+ dwrq->flags |= 1;
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ default:
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ break;
+ }
+ dwrq->flags |= IW_ENCODE_NOKEY;
+
+done:
+ kfree(ap_cfg);
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ mlan_uap_bss_param *sys_cfg = NULL;
+ IEEEtypes_Header_t *tlv = NULL;
+ int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0;
+ int ret = 0;
+
+ ENTER();
+
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ tlv_buf_left = dwrq->length;
+ tlv = (IEEEtypes_Header_t *)extra;
+ while (tlv_buf_left >= tlv_hdr_len) {
+ if (tlv->element_id == WPA_IE) {
+ sys_cfg->protocol |= PROTOCOL_WPA;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_TKIP;
+ PRINTM(MINFO, "Set IE Cipher TKIP\n");
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher CCMP\n");
+ }
+ if (priv->pairwise_cipher ==
+ (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa =
+ CIPHER_TKIP | CIPHER_AES_CCMP;
+ PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n");
+ }
+ moal_memcpy_ext(priv->phandle,
+ priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *)tlv),
+ sizeof(IEEEtypes_Header_t) + tlv->len,
+ sizeof(priv->bcn_ie_buf) -
+ priv->bcn_ie_len);
+ priv->bcn_ie_len +=
+ sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (tlv->element_id == RSN_IE) {
+ sys_cfg->protocol |= PROTOCOL_WPA2;
+ if (priv->pairwise_cipher == CIPHER_TKIP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
+ CIPHER_TKIP;
+ }
+ if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
+ CIPHER_AES_CCMP;
+ }
+ if (priv->pairwise_cipher ==
+ (CIPHER_TKIP | CIPHER_AES_CCMP)) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ }
+ moal_memcpy_ext(priv->phandle,
+ priv->bcn_ie_buf + priv->bcn_ie_len,
+ ((t_u8 *)tlv),
+ sizeof(IEEEtypes_Header_t) + tlv->len,
+ sizeof(priv->bcn_ie_buf) -
+ priv->bcn_ie_len);
+ priv->bcn_ie_len +=
+ sizeof(IEEEtypes_Header_t) + tlv->len;
+ }
+ if (priv->group_cipher == CIPHER_TKIP)
+ sys_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ if (priv->group_cipher == CIPHER_AES_CCMP)
+ sys_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ tlv_buf_left -= (tlv_hdr_len + tlv->len);
+ tlv = (IEEEtypes_Header_t *)((t_u8 *)tlv + tlv_hdr_len +
+ tlv->len);
+ }
+ sys_cfg->key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg->key_mgmt & KEY_MGMT_PSK)
+ sys_cfg->key_mgmt_operation |= 0x01;
+ if (sys_cfg->key_mgmt & KEY_MGMT_EAP)
+ sys_cfg->key_mgmt_operation |= 0x03;
+
+ if (sys_cfg->protocol) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP configuration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->pairwise_cipher = 0;
+ priv->group_cipher = 0;
+
+ /* custom IE command to set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+#define UAP_RSN_MASK (BIT(8) | BIT(5) | BIT(1) | BIT(3))
+ woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error setting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ } else if (dwrq->length == 0) {
+ /* custom IE command to re-set priv->bcn_ie_buf */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf,
+ priv->bcn_ie_len)) {
+ PRINTM(MERROR, "Error resetting wpa-rsn IE\n");
+ ret = -EFAULT;
+ }
+ priv->bcn_ie_len = 0;
+ }
+
+done:
+ kfree(sys_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_uap_bss_param *sys_cfg = NULL;
+ wep_key *pwep_key = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 5) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ pkey_material = (t_u8 *)(ext + 1);
+ /* Disable Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sys_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else if (ext->alg == IW_ENCODE_ALG_WEP) {
+ sys_cfg->protocol = PROTOCOL_STATIC_WEP;
+ /* Set WEP key */
+ switch (key_index) {
+ case 0:
+ pwep_key = &sys_cfg->wep_cfg.key0;
+ break;
+ case 1:
+ pwep_key = &sys_cfg->wep_cfg.key1;
+ break;
+ case 2:
+ pwep_key = &sys_cfg->wep_cfg.key2;
+ break;
+ case 3:
+ pwep_key = &sys_cfg->wep_cfg.key3;
+ break;
+ }
+ if (pwep_key) {
+ pwep_key->key_index = key_index;
+ pwep_key->is_default = MTRUE;
+ pwep_key->length = ext->key_len;
+ moal_memcpy_ext(priv->phandle, pwep_key->key,
+ pkey_material, ext->key_len,
+ sizeof(pwep_key->key));
+ }
+ } else {
+ /* Set GTK/PTK key */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ sec->param.encrypt_key.key_len = ext->key_len;
+ sec->param.encrypt_key.key_index = key_index;
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.key_material,
+ pkey_material, ext->key_len,
+ sizeof(sec->param.encrypt_key.key_material));
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
+ ext->addr.sa_data, ETH_ALEN,
+ sizeof(sec->param.encrypt_key.mac_addr));
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn,
+ (t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ DBG_HEXDUMP(MCMD_D, "Uap Rx PN",
+ sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn,
+ (t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ DBG_HEXDUMP(MCMD_D, "Uap Tx PN",
+ sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
+ }
+ PRINTM(MIOCTL,
+ "set uap wpa key key_index=%d, key_len=%d key_flags=0x%x " MACSTR
+ "\n",
+ key_index, ext->key_len,
+ sec->param.encrypt_key.key_flags,
+ MAC2STR(sec->param.encrypt_key.mac_addr));
+ DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len);
+#define IW_ENCODE_ALG_AES_CMAC 5
+
+ if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
+ sec->param.encrypt_key.key_flags |=
+ KEY_FLAG_AES_MCAST_IGTK;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+ /* Cipher set will be done in set generic IE */
+ priv->pairwise_cipher = ext->alg;
+ priv->group_cipher = ext->alg;
+ goto done; /* No AP configuration */
+ }
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ kfree(sys_cfg);
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_set_mlme(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ds_bss *bss = NULL;
+ mlan_ds_get_info *pinfo = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sta_list *sta_list = NULL;
+ const t_u8 bc_addr[] = {0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF};
+ t_u8 sta_addr[ETH_ALEN];
+ int ret = 0, i;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ memset(sta_addr, 0, ETH_ALEN);
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+ moal_memcpy_ext(priv->phandle, sta_addr,
+ (t_u8 *)mlme->addr.sa_data, ETH_ALEN,
+ sizeof(sta_addr));
+ PRINTM(MIOCTL, "Deauth station: " MACSTR ", reason=%d\n",
+ MAC2STR(sta_addr), mlme->reason_code);
+
+ /* FIXME: For flushing all stations we need to use zero MAC,
+ * but right now the FW does not support this. So, manually
+ * delete each one individually.
+ */
+ /* If deauth all station, get the connected STA list first */
+ if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ PRINTM(MIOCTL, "Deauth all stations\n");
+ req = woal_alloc_mlan_ioctl_req(
+ sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pinfo = (mlan_ds_get_info *)req->pbuf;
+ pinfo->sub_command = MLAN_OID_UAP_STA_LIST;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ sta_list =
+ kmalloc(sizeof(mlan_ds_sta_list), GFP_KERNEL);
+ if (sta_list == NULL) {
+ PRINTM(MERROR, "Memory allocation failed!\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, sta_list,
+ &pinfo->param.sta_list,
+ sizeof(mlan_ds_sta_list),
+ sizeof(mlan_ds_sta_list));
+ kfree(req);
+ req = NULL;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (sta_list && !memcmp(bc_addr, sta_addr, ETH_ALEN)) {
+ for (i = 0; i < sta_list->sta_count; i++) {
+ moal_memcpy_ext(
+ priv->phandle,
+ bss->param.deauth_param.mac_addr,
+ sta_list->info[i].mac_address, ETH_ALEN,
+ sizeof(bss->param.deauth_param
+ .mac_addr));
+ bss->param.deauth_param.reason_code =
+ mlme->reason_code;
+
+ status = woal_request_ioctl(priv, req,
+ MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ moal_memcpy_ext(
+ priv->phandle, bss->param.deauth_param.mac_addr,
+ sta_addr, ETH_ALEN,
+ sizeof(bss->param.deauth_param.mac_addr));
+ bss->param.deauth_param.reason_code = mlme->reason_code;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ kfree(sta_list);
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_param *vwrq = &wrqu->param;
+ mlan_uap_bss_param *sys_cfg = NULL;
+
+ ENTER();
+
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value == IW_AUTH_CIPHER_TKIP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
+ priv->pairwise_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value == IW_AUTH_CIPHER_CCMP) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ priv->pairwise_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ } else if (vwrq->value ==
+ (IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) {
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
+ (CIPHER_TKIP | CIPHER_AES_CCMP);
+ priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP);
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n");
+ }
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ /* Rest are not supported now */
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ /* XXX Do not delete no-operation line */
+ ;
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP) {
+ sys_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ priv->group_cipher = CIPHER_TKIP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher TKIP\n");
+ } else if (vwrq->value & IW_AUTH_CIPHER_CCMP) {
+ sys_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ priv->group_cipher = CIPHER_AES_CCMP;
+ if (!priv->uap_key_mgmt)
+ priv->uap_key_mgmt = KEY_MGMT_PSK;
+ PRINTM(MINFO, "Set Auth Cipher CCMP\n");
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_VERSION:
+ switch (vwrq->value) {
+ case IW_AUTH_WPA_VERSION_DISABLED:
+ sys_cfg->protocol = PROTOCOL_NO_SECURITY;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA:
+ sys_cfg->protocol = PROTOCOL_WPA;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg->protocol = PROTOCOL_WPA2;
+ break;
+ case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2:
+ sys_cfg->protocol = PROTOCOL_WPA2_MIXED;
+ break;
+ default:
+ break;
+ }
+ priv->uap_protocol = sys_cfg->protocol;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ switch (vwrq->value) {
+ case IW_AUTH_KEY_MGMT_802_1X:
+ sys_cfg->key_mgmt |= KEY_MGMT_EAP;
+ priv->uap_key_mgmt |= KEY_MGMT_EAP;
+ break;
+ case IW_AUTH_KEY_MGMT_PSK:
+ sys_cfg->key_mgmt |= KEY_MGMT_PSK;
+ priv->uap_key_mgmt |= KEY_MGMT_PSK;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ kfree(sys_cfg);
+ LEAVE();
+ return -EOPNOTSUPP; /* No AP configuration */
+ }
+ if (!sys_cfg->key_mgmt)
+ sys_cfg->key_mgmt = priv->uap_key_mgmt;
+ if (sys_cfg->key_mgmt & KEY_MGMT_PSK)
+ sys_cfg->key_mgmt_operation |= 0x01;
+ if (sys_cfg->key_mgmt & KEY_MGMT_EAP)
+ sys_cfg->key_mgmt_operation |= 0x03;
+ if (!sys_cfg->protocol)
+ sys_cfg->protocol = priv->uap_protocol;
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ kfree(sys_cfg);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_param *vwrq = &wrqu->param;
+ mlan_uap_bss_param *ap_cfg = NULL;
+
+ ENTER();
+
+ ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!ap_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ kfree(ap_cfg);
+ LEAVE();
+ return -EFAULT;
+ }
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg->wpa_cfg.pairwise_cipher_wpa ==
+ CIPHER_AES_CCMP ||
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 ==
+ CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ if (ap_cfg->wpa_cfg.group_cipher == CIPHER_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (ap_cfg->wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (ap_cfg->auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (ap_cfg->auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (ap_cfg->protocol == PROTOCOL_WPA ||
+ ap_cfg->protocol == PROTOCOL_WPA2 ||
+ ap_cfg->protocol == PROTOCOL_WPA2_MIXED)
+ vwrq->value = 1;
+ else
+ vwrq->value = 0;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ if (ap_cfg->key_mgmt & KEY_MGMT_EAP)
+ vwrq->value |= IW_AUTH_KEY_MGMT_802_1X;
+ if (ap_cfg->key_mgmt & KEY_MGMT_PSK)
+ vwrq->value |= IW_AUTH_KEY_MGMT_PSK;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ kfree(ap_cfg);
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+ kfree(ap_cfg);
+ LEAVE();
+ return 0;
+}
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ mlan_uap_bss_param *ap_cfg = NULL;
+ struct iw_range *range = (struct iw_range *)extra;
+ t_u8 band = 0;
+ int i;
+
+ ENTER();
+
+ ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!ap_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ kfree(ap_cfg);
+ LEAVE();
+ return -EFAULT;
+ }
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ range->num_bitrates = MAX_DATA_RATES;
+ for (i = 0;
+ i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) && ap_cfg->rates[i];
+ i++) {
+ range->bitrate[i] = (ap_cfg->rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = MIN(ap_cfg->num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long)ap_cfg->chan_list[i].chan_number;
+ band = (ap_cfg->chan_list[i].bandcfg.chanBand == BAND_5GHZ);
+ range->freq[i].m =
+ (long)channel_to_frequency(
+ ap_cfg->chan_list[i].chan_number, band) *
+ 100000;
+ range->freq[i].e = 1;
+ }
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+#if (WIRELESS_EXT >= 18)
+ if (ap_cfg->protocol & PROTOCOL_WPA)
+ range->enc_capa |= IW_ENC_CAPA_WPA;
+ if (ap_cfg->protocol & PROTOCOL_WPA2)
+ range->enc_capa |= IW_ENC_CAPA_WPA2;
+ if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP ||
+ ap_cfg->wpa_cfg.group_cipher == CIPHER_TKIP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
+ if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP ||
+ ap_cfg->wpa_cfg.group_cipher == CIPHER_AES_CCMP)
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
+#endif
+ kfree(ap_cfg);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ mlan_uap_bss_param *sys_cfg = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto done;
+ }
+ sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!sys_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Initialize the invalid values so that the correct values
+ * below are downloaded to firmware */
+ woal_set_sys_config_invalid_data(sys_cfg);
+
+ /* Set the SSID */
+#if WIRELESS_EXT > 20
+ sys_cfg->ssid.ssid_len = dwrq->length;
+#else
+ sys_cfg->ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ moal_memcpy_ext(priv->phandle, sys_cfg->ssid.ssid, extra,
+ sys_cfg->ssid.ssid_len, sizeof(sys_cfg->ssid.ssid));
+ if (!sys_cfg->ssid.ssid_len || sys_cfg->ssid.ssid[0] < 0x20) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (sys_cfg->ssid.ssid_len > 0) ? (char *)sys_cfg->ssid.ssid :
+ "NULL");
+
+ /* Set AP configuration */
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
+ MOAL_IOCTL_WAIT,
+ sys_cfg)) {
+ PRINTM(MERROR, "Error setting AP confiruration\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ kfree(sys_cfg);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_uap_bss_param *ap_cfg = NULL;
+
+ ENTER();
+
+ ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
+ if (!ap_cfg) {
+ PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
+ return -EFAULT;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ ap_cfg)) {
+ PRINTM(MERROR, "Error getting AP confiruration\n");
+ kfree(ap_cfg);
+ LEAVE();
+ return -EFAULT;
+ }
+
+ if (priv->bss_started) {
+ dwrq->length = MIN(dwrq->length, ap_cfg->ssid.ssid_len);
+ moal_memcpy_ext(priv->phandle, extra, ap_cfg->ssid.ssid,
+ dwrq->length, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ dwrq->flags = 1;
+ kfree(ap_cfg);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler)woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler)woal_get_name, /* SIOCGIWNAME */
+ (iw_handler)NULL, /* SIOCSIWNWID */
+ (iw_handler)NULL, /* SIOCGIWNWID */
+ (iw_handler)woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler)woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler)woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler)woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler)NULL, /* SIOCSIWSENS */
+ (iw_handler)NULL, /* SIOCGIWSENS */
+ (iw_handler)NULL, /* SIOCSIWRANGE */
+ (iw_handler)woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler)woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler)NULL, /* SIOCGIWPRIV */
+ (iw_handler)NULL, /* SIOCSIWSTATS */
+ (iw_handler)NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+#ifdef CONFIG_WEXT_SPY
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+#endif
+#else /* WIRELESS_EXT > 15 */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler)woal_set_wap, /* SIOCSIWAP */
+ (iw_handler)woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler)woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler)NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, */ /* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler)NULL, /* SIOCSIWSCAN */
+ (iw_handler)NULL, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler)NULL, /* SIOCSIWSCAN */
+ (iw_handler)NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler)woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler)woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler)NULL, /* SIOCSIWNICKN */
+ (iw_handler)NULL, /* SIOCGIWNICKN */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* SIOCSIWRATE */
+ (iw_handler)NULL, /* SIOCGIWRATE */
+ (iw_handler)NULL, /* SIOCSIWRTS */
+ (iw_handler)NULL, /* SIOCGIWRTS */
+ (iw_handler)NULL, /* SIOCSIWFRAG */
+ (iw_handler)NULL, /* SIOCGIWFRAG */
+ (iw_handler)NULL, /* SIOCSIWTXPOW */
+ (iw_handler)NULL, /* SIOCGIWTXPOW */
+ (iw_handler)NULL, /* SIOCSIWRETRY */
+ (iw_handler)NULL, /* SIOCGIWRETRY */
+ (iw_handler)woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler)woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler)NULL, /* SIOCSIWPOWER */
+ (iw_handler)NULL, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler)woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler)woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler)woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler)woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler)woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+// clang-format off
+/** wlan_handler_def */
+struct iw_handler_def woal_uap_handler_def = {
+ num_standard: ARRAY_SIZE(woal_handler),
+ num_private : ARRAY_SIZE(woal_private_handler),
+ num_private_args : ARRAY_SIZE(woal_uap_priv_args),
+ standard : (iw_handler *)woal_handler,
+ private : (iw_handler *)woal_private_handler,
+ private_args : (struct iw_priv_args *)woal_uap_priv_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats : woal_get_uap_wireless_stats,
+#endif
+};
+// clang-format on
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u16 wait_option = MOAL_IOCTL_WAIT;
+
+ ENTER();
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (in_atomic() || !write_can_lock(&dev_base_lock))
+ wait_option = MOAL_NO_WAIT;
+#endif
+
+ priv->w_stats.qual.qual = 0;
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.discard.code = 0;
+ priv->w_stats.status = IW_MODE_MASTER;
+ woal_uap_get_stats(priv, wait_option, NULL);
+
+ LEAVE();
+ return &priv->w_stats;
+}
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c
new file mode 100644
index 000000000000..155003f086af
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.c
@@ -0,0 +1,2028 @@
+/** @file moal_usb.c
+ *
+ * @brief This file contains the interfaceing to USB bus
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_usb.h"
+extern struct semaphore AddRemoveCardSem;
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+/** Card-type detection frame response */
+typedef struct {
+ /** 32-bit ACK+WINNER field */
+ t_u32 ack_winner;
+ /** 32-bit Sequence number */
+ t_u32 seq;
+ /** 32-bit extend */
+ t_u32 extend;
+ /** 32-bit chip-revision code */
+ t_u32 chip_rev;
+ /** 32-bit strap setting */
+ t_u32 strap;
+} usb_ack_pkt;
+#endif
+
+/** NXP USB device */
+#define NXP_USB_DEVICE(vid, pid, name) \
+ USB_DEVICE(vid, pid), .driver_info = (t_ptr)name
+
+/** Name of the USB driver */
+const char usbdriver_name[] = "usbxxx";
+
+/** This structure contains the device signature */
+struct usb_device_id woal_usb_table[] = {
+/* Enter the device signature inside */
+#ifdef USB8897
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8997
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997V2_PID_1,
+ "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_3, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_4, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_5, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_6, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8978
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_1_BT,
+ "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
+ "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9098
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9097
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_1, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
+#endif
+ /* Terminating entry */
+ {},
+};
+
+/** This structure contains the device signature */
+struct usb_device_id woal_usb_table_skip_fwdnld[] = {
+/* Enter the device signature inside */
+#ifdef USB8897
+ {NXP_USB_DEVICE(USB8897_VID_1, USB8897_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8997
+ {NXP_USB_DEVICE(USB8997_VID_1, USB8997_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB8978
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2, "NXP WLAN USB Adapter")},
+ {NXP_USB_DEVICE(USB8978_VID_1, USB8978_PID_2_BT,
+ "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9098
+ {NXP_USB_DEVICE(USB9098_VID_1, USB9098_PID_2, "NXP WLAN USB Adapter")},
+#endif
+#ifdef USB9097
+ {NXP_USB_DEVICE(USB9097_VID_1, USB9097_PID_2, "NXP WLAN USB Adapter")},
+#endif
+ /* Terminating entry */
+ {},
+};
+
+static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size);
+static int woal_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id);
+static void woal_usb_disconnect(struct usb_interface *intf);
+static mlan_status woal_usb_write_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout);
+static mlan_status woal_usb_read_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout);
+#ifdef CONFIG_PM
+static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int woal_usb_resume(struct usb_interface *intf);
+#endif /* CONFIG_PM */
+
+/** woal_usb_driver */
+static struct usb_driver REFDATA woal_usb_driver = {
+ /* Driver name */
+ .name = usbdriver_name,
+
+ /* Probe function name */
+ .probe = woal_usb_probe,
+
+ /* Disconnect function name */
+ .disconnect = woal_usb_disconnect,
+
+ /* Device signature table */
+ .id_table = woal_usb_table,
+#ifdef CONFIG_PM
+ /* Suspend function name */
+ .suspend = woal_usb_suspend,
+
+ /* Resume function name */
+ .resume = woal_usb_resume,
+
+ /* Reset resume function name */
+ .reset_resume = woal_usb_resume,
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ /* Driver supports autosuspend */
+ .supports_autosuspend = 1,
+#endif
+#endif /* CONFIG_PM */
+};
+
+MODULE_DEVICE_TABLE(usb, woal_usb_table);
+MODULE_DEVICE_TABLE(usb, woal_usb_table_skip_fwdnld);
+
+/* moal interface ops */
+static moal_if_ops usb_ops;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+extern int skip_fwdnld;
+extern int max_tx_buf;
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+/**
+ * @brief This function receive packet of the data/cmd/event packet
+ * and pass to MLAN
+ *
+ * @param urb Pointer to struct urb
+ * @param regs Registers
+ *
+ * @return N/A
+ */
+static void woal_usb_receive(struct urb *urb, struct pt_regs *regs)
+#else
+/**
+ * @brief This function receive packet of the data/cmd/event packet
+ * and pass to MLAN
+ *
+ * @param urb Pointer to struct urb
+ *
+ * @return N/A
+ */
+static void woal_usb_receive(struct urb *urb)
+#endif
+{
+ urb_context *context = NULL;
+ moal_handle *handle = NULL;
+ mlan_buffer *pmbuf = NULL;
+ struct usb_card_rec *cardp = NULL;
+ int recv_length;
+ int size;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ if (!urb || !urb->context) {
+ PRINTM(MERROR, "URB or URB context is not valid in USB Rx\n");
+ LEAVE();
+ return;
+ }
+ context = (urb_context *)urb->context;
+ handle = context->handle;
+ pmbuf = context->pmbuf;
+ recv_length = urb->actual_length;
+
+ if (!handle || !handle->card || !pmbuf) {
+ PRINTM(MERROR,
+ "moal handle, card structure or mlan_buffer is not valid in USB Rx\n");
+ LEAVE();
+ return;
+ }
+ cardp = (struct usb_card_rec *)handle->card;
+ if (cardp->rx_cmd_ep == context->ep)
+ atomic_dec(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_dec(&cardp->rx_data_urb_pending);
+
+ if (recv_length) {
+ if (urb->status || (handle->surprise_removed == MTRUE)) {
+ if (handle->surprise_removed || handle->is_suspended) {
+ woal_free_mlan_buffer(handle, pmbuf);
+ context->pmbuf = NULL;
+ goto rx_exit;
+ } else {
+ PRINTM(MERROR,
+ "EP %d Rx URB status failure: %d\n",
+ context->ep, urb->status);
+ /* Do not free mlan_buffer in case of command ep
+ */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ goto setup_for_next;
+ }
+ }
+ pmbuf->data_len = recv_length;
+ pmbuf->flags |= MLAN_BUF_FLAG_RX_DEAGGR;
+ /* Send packet to MLAN */
+ atomic_inc(&handle->rx_pending);
+ status = mlan_recv(handle->pmlan_adapter, pmbuf, context->ep);
+ PRINTM(MINFO, "Receive length = 0x%x, status=%d\n", recv_length,
+ status);
+ if (status == MLAN_STATUS_PENDING) {
+ queue_work(handle->workqueue, &handle->main_work);
+ /* urb for data_ep is re-submitted now, unless we reach
+ * HIGH_RX_PENDING */
+ /* urb for cmd_ep will be re-submitted in callback
+ * moal_recv_complete */
+ if (cardp->rx_cmd_ep == context->ep)
+ goto rx_exit;
+ else if (atomic_read(&handle->rx_pending) >=
+ HIGH_RX_PENDING) {
+ context->pmbuf = NULL;
+ goto rx_exit;
+ }
+ } else {
+ atomic_dec(&handle->rx_pending);
+ if (status == MLAN_STATUS_FAILURE) {
+ PRINTM(MERROR,
+ "MLAN fail to process the receive data\n");
+ } else if ((status == MLAN_STATUS_SUCCESS) &&
+ (pmbuf->flags &
+ MLAN_BUF_FLAG_SLEEPCFM_RESP)) {
+ pmbuf->flags &= ~MLAN_BUF_FLAG_SLEEPCFM_RESP;
+ queue_work(handle->workqueue,
+ &handle->main_work);
+ }
+ /* Do not free mlan_buffer in case of command ep */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ }
+ } else if (urb->status) {
+ if (!((cardp->rx_data_ep == context->ep) &&
+ (cardp->resubmit_urbs == 1))) {
+ if (!handle->is_suspended) {
+ PRINTM(MMSG, "Card is removed: %d\n",
+ urb->status);
+ handle->surprise_removed = MTRUE;
+ }
+ }
+ woal_free_mlan_buffer(handle, pmbuf);
+ context->pmbuf = NULL;
+ goto rx_exit;
+ } else {
+ /* Do not free mlan_buffer in case of command ep */
+ if (cardp->rx_cmd_ep != context->ep)
+ woal_free_mlan_buffer(handle, pmbuf);
+ goto setup_for_next;
+ }
+
+setup_for_next:
+ if (cardp->rx_cmd_ep == context->ep) {
+ size = MLAN_RX_CMD_BUF_SIZE;
+ } else {
+ if (cardp->rx_deaggr_ctrl.enable) {
+ size = cardp->rx_deaggr_ctrl.aggr_max;
+ if (cardp->rx_deaggr_ctrl.aggr_mode ==
+ MLAN_USB_AGGR_MODE_NUM) {
+ size *= MAX(MLAN_USB_MAX_PKT_SIZE,
+ cardp->rx_deaggr_ctrl.aggr_align);
+ size = MAX(size, MLAN_RX_DATA_BUF_SIZE);
+ }
+ } else
+ size = MLAN_RX_DATA_BUF_SIZE;
+ }
+ woal_usb_submit_rx_urb(context, size);
+
+rx_exit:
+ LEAVE();
+ return;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+/**
+ * @brief Call back function to handle the status of the Tx data URB
+ *
+ * @param urb Pointer to urb structure
+ * @param regs Registers
+ *
+ * @return N/A
+ */
+static void woal_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
+#else
+/**
+ * @brief Call back function to handle the status of the Tx data URB
+ *
+ * @param urb Pointer to urb structure
+ *
+ * @return N/A
+ */
+static void woal_usb_tx_complete(struct urb *urb)
+#endif
+{
+ urb_context *context = NULL;
+ moal_handle *handle = NULL;
+ struct usb_card_rec *cardp = NULL;
+
+ ENTER();
+
+ if (!urb || !urb->context) {
+ PRINTM(MERROR,
+ "URB or URB context is not valid in USB Tx complete\n");
+ LEAVE();
+ return;
+ }
+ context = (urb_context *)urb->context;
+ handle = context->handle;
+
+ if (!handle || !handle->card || !context->pmbuf) {
+ PRINTM(MERROR,
+ "moal handle, card structure or mlan_buffer is not valid in USB Tx complete\n");
+ LEAVE();
+ return;
+ }
+ cardp = handle->card;
+
+ /* Handle the transmission complete validations */
+ if (urb->status) {
+ PRINTM(MERROR, "EP %d Tx URB status failure: %d\n", context->ep,
+ urb->status);
+ mlan_write_data_async_complete(handle->pmlan_adapter,
+ context->pmbuf, context->ep,
+ MLAN_STATUS_FAILURE);
+ } else {
+ mlan_write_data_async_complete(handle->pmlan_adapter,
+ context->pmbuf, context->ep,
+ MLAN_STATUS_SUCCESS);
+ }
+
+ /* Decrease pending URB counter */
+ if (context->ep == cardp->tx_cmd_ep)
+ atomic_dec(&cardp->tx_cmd_urb_pending);
+ else if (context->ep == cardp->tx_data_ep)
+ atomic_dec(&cardp->tx_data_urb_pending);
+
+ queue_work(handle->workqueue, &handle->main_work);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sets up the data to receive
+ *
+ * @param ctx Pointer to urb_context structure
+ * @param size Skb size
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_submit_rx_urb(urb_context *ctx, int size)
+{
+ moal_handle *handle = ctx->handle;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u8 *data = NULL;
+
+ ENTER();
+
+ if (handle->surprise_removed || handle->is_suspended) {
+ if ((cardp->rx_cmd_ep == ctx->ep) && ctx->pmbuf) {
+ woal_free_mlan_buffer(handle, ctx->pmbuf);
+ ctx->pmbuf = NULL;
+ }
+ PRINTM(MERROR,
+ "Card removed/suspended, EP %d Rx URB submit skipped\n",
+ ctx->ep);
+ goto rx_ret;
+ }
+
+ if (cardp->rx_cmd_ep != ctx->ep) {
+ ctx->pmbuf = woal_alloc_mlan_buffer(handle, size);
+ if (!ctx->pmbuf) {
+ PRINTM(MERROR,
+ "Fail to submit Rx URB due to no memory/skb\n");
+ goto rx_ret;
+ }
+ ctx->pmbuf->data_offset = MLAN_RX_HEADER_LEN;
+ data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
+ } else {
+ ctx->pmbuf->data_offset = 0;
+ data = ctx->pmbuf->pbuf + ctx->pmbuf->data_offset;
+ }
+
+ if (cardp->rx_cmd_ep == ctx->ep &&
+ cardp->rx_cmd_ep_type == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(ctx->urb, cardp->udev,
+ usb_rcvintpipe(cardp->udev, ctx->ep), data,
+ size - ctx->pmbuf->data_offset,
+ woal_usb_receive, (void *)ctx,
+ cardp->rx_cmd_interval);
+ else
+ usb_fill_bulk_urb(ctx->urb, cardp->udev,
+ usb_rcvbulkpipe(cardp->udev, ctx->ep), data,
+ size - ctx->pmbuf->data_offset,
+ woal_usb_receive, (void *)ctx);
+ if (cardp->rx_cmd_ep == ctx->ep)
+ atomic_inc(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_inc(&cardp->rx_data_urb_pending);
+ if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
+ /* Submit URB failure */
+ PRINTM(MERROR, "Submit EP %d Rx URB failed: %d\n", ctx->ep,
+ ret);
+ woal_free_mlan_buffer(handle, ctx->pmbuf);
+ if (cardp->rx_cmd_ep == ctx->ep)
+ atomic_dec(&cardp->rx_cmd_urb_pending);
+ else
+ atomic_dec(&cardp->rx_data_urb_pending);
+ ctx->pmbuf = NULL;
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ ret = MLAN_STATUS_SUCCESS;
+ }
+rx_ret:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+/**
+ * @brief Check chip revision
+ *
+ * @param handle A pointer to moal_handle structure
+ * @param usb_chip_rev A pointer to usb_chip_rev variable
+ * @param usb_strap A pointer to usb_strap
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_check_chip_revision(moal_handle *handle, t_u32 *usb_chip_rev,
+ t_u32 *usb_strap)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_buffer mbuf;
+ t_u8 *tx_buff = 0;
+ t_u8 *recv_buff = 0;
+ usb_ack_pkt ack_pkt;
+ t_u32 extend_ver;
+ t_u8 tx_size = CHIP_REV_TX_BUF_SIZE;
+ struct usb_card_rec *cardp = handle->card;
+
+ ENTER();
+
+ /* Allocate memory for transmit */
+ tx_buff = kzalloc(tx_size, GFP_ATOMIC | GFP_DMA);
+ if (tx_buff == NULL) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for chip revision check frame transmission\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ /* Allocate memory for receive */
+ recv_buff = kzalloc(CHIP_REV_RX_BUF_SIZE, GFP_ATOMIC | GFP_DMA);
+ if (recv_buff == NULL) {
+ PRINTM(MERROR,
+ "Could not allocate buffer for chip revision check frame response\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ /* The struct is initialised to all zero */
+ memset(&ack_pkt, 0, sizeof(usb_ack_pkt));
+
+ /* Send pseudo data to check winner status first */
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)tx_buff;
+ mbuf.data_len = tx_size;
+
+ /* Send the chip revision check frame */
+ ret = woal_usb_write_data_sync(handle, &mbuf, cardp->tx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Chip revision check frame dnld: write_data failed, ret %d\n",
+ ret);
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+
+ memset(&mbuf, 0, sizeof(mlan_buffer));
+ mbuf.pbuf = (t_u8 *)recv_buff;
+ mbuf.data_len = CHIP_REV_RX_BUF_SIZE;
+
+ /* Receive the chip revision check frame response */
+ ret = woal_usb_read_data_sync(handle, &mbuf, cardp->rx_cmd_ep,
+ MLAN_USB_BULK_MSG_TIMEOUT);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR,
+ "Chip revision check frame response: read_data failed, ret %d\n",
+ ret);
+ ret = MLAN_STATUS_FAILURE;
+ goto cleanup;
+ }
+ moal_memcpy_ext(handle, &ack_pkt, recv_buff, sizeof(usb_ack_pkt),
+ sizeof(ack_pkt));
+ ack_pkt.ack_winner = woal_le32_to_cpu(ack_pkt.ack_winner);
+ ack_pkt.seq = woal_le32_to_cpu(ack_pkt.seq);
+ ack_pkt.extend = woal_le32_to_cpu(ack_pkt.extend);
+ ack_pkt.chip_rev = woal_le32_to_cpu(ack_pkt.chip_rev);
+ ack_pkt.strap = woal_le32_to_cpu(ack_pkt.strap);
+
+ if ((ack_pkt.extend & 0xffff0000) == EXTEND_HDR) {
+ extend_ver = ack_pkt.extend & 0x0000ffff;
+ *usb_chip_rev = ack_pkt.chip_rev & 0x000000ff;
+ if (extend_ver >= EXTEND_V2) {
+ PRINTM(MINFO, "chip_rev=0x%x, strap=0x%x\n",
+ *usb_chip_rev, ack_pkt.strap);
+ *usb_strap = ack_pkt.strap & 0x7;
+ } else
+ PRINTM(MINFO, "chip_rev=0x%x\n", *usb_chip_rev);
+ }
+cleanup:
+ kfree(recv_buff);
+ kfree(tx_buff);
+
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief This function unlink urb
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return N/A
+ */
+static void woal_usb_unlink_urb(void *card_desc)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)card_desc;
+ int i;
+ ENTER();
+ if (cardp) {
+ /* Unlink Rx cmd URB */
+ if (atomic_read(&cardp->rx_cmd_urb_pending) &&
+ cardp->rx_cmd.urb) {
+ usb_kill_urb(cardp->rx_cmd.urb);
+ }
+ /* Unlink Rx data URBs */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb)
+ usb_kill_urb(
+ cardp->rx_data_list[i].urb);
+ }
+ }
+ /* Unlink Tx cmd URB */
+ if (atomic_read(&cardp->tx_cmd_urb_pending) &&
+ cardp->tx_cmd.urb) {
+ usb_kill_urb(cardp->tx_cmd.urb);
+ }
+ /* Unlink Tx data URBs */
+ if (atomic_read(&cardp->tx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_kill_urb(
+ cardp->tx_data_list[i].urb);
+ }
+ }
+ }
+ }
+ LEAVE();
+}
+
+/**
+ * @brief Free Tx/Rx urb, skb and Rx buffer
+ *
+ * @param cardp Pointer usb_card_rec
+ *
+ * @return N/A
+ */
+void woal_usb_free(struct usb_card_rec *cardp)
+{
+ int i;
+
+ ENTER();
+
+ woal_usb_unlink_urb(cardp);
+ /* Free Rx data URBs */
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_free_urb(cardp->rx_data_list[i].urb);
+ cardp->rx_data_list[i].urb = NULL;
+ }
+ }
+ /* Free Rx cmd URB */
+ if (cardp->rx_cmd.urb) {
+ usb_free_urb(cardp->rx_cmd.urb);
+ cardp->rx_cmd.urb = NULL;
+ }
+
+ /* Free Tx data URBs */
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_free_urb(cardp->tx_data_list[i].urb);
+ cardp->tx_data_list[i].urb = NULL;
+ }
+ }
+ /* Free Tx cmd URB */
+ if (cardp->tx_cmd.urb) {
+ usb_free_urb(cardp->tx_cmd.urb);
+ cardp->tx_cmd.urb = NULL;
+ }
+
+ LEAVE();
+ return;
+}
+
+static t_u16 woal_update_card_type(t_void *card)
+{
+ struct usb_card_rec *cardp_usb = (struct usb_card_rec *)card;
+ t_u16 card_type = 0;
+
+ /* Update card type */
+#ifdef USB8897
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8897_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8897_PID_2) {
+ card_type = CARD_TYPE_USB8897;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8897,
+ strlen(CARD_USB8897), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V15, strlen(V15),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB8997
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_2 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_3 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_4 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_5 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997_PID_6 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8997V2_PID_1) {
+ card_type = CARD_TYPE_USB8997;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8997,
+ strlen(CARD_USB8997), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB8978
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8978_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB8978_PID_2) {
+ card_type = CARD_TYPE_USB8978;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB8978,
+ strlen(CARD_USB8978), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V16, strlen(V16),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB9098
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9098_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9098_PID_2) {
+ card_type = CARD_TYPE_USB9098;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB9098,
+ strlen(CARD_USB9098), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+#ifdef USB9097
+ if (woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9097_PID_1 ||
+ woal_cpu_to_le16(cardp_usb->udev->descriptor.idProduct) ==
+ USB9097_PID_2) {
+ card_type = CARD_TYPE_USB9097;
+ moal_memcpy_ext(NULL, driver_version, CARD_USB9097,
+ strlen(CARD_USB9097), strlen(driver_version));
+ moal_memcpy_ext(NULL,
+ driver_version + strlen(INTF_CARDTYPE) +
+ strlen(KERN_VERSION),
+ V17, strlen(V17),
+ strlen(driver_version) - strlen(INTF_CARDTYPE) -
+ strlen(KERN_VERSION));
+ }
+#endif
+ return card_type;
+}
+
+/**
+ * @brief Sets the configuration values
+ *
+ * @param intf Pointer to usb_interface
+ * @param id Pointer to usb_device_id
+ *
+ * @return Address of variable usb_cardp, error code otherwise
+ */
+static int woal_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ struct usb_card_rec *usb_cardp = NULL;
+ t_u16 card_type = 0;
+
+ ENTER();
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ PRINTM(MMSG,
+ "USB probe: idVendor=%x idProduct=%x bInterfaceNumber=%d\n",
+ id->idVendor, id->idProduct, id->bInterfaceNumber);
+#endif
+
+ udev = interface_to_usbdev(intf);
+ usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+ if (!usb_cardp) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ /* Check probe is for our device */
+ for (i = 0; woal_usb_table[i].idVendor; i++) {
+ if (woal_cpu_to_le16(udev->descriptor.idVendor) ==
+ woal_usb_table[i].idVendor &&
+ woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ woal_usb_table[i].idProduct) {
+ PRINTM(MMSG, "VID/PID = %X/%X, Boot2 version = %X\n",
+ woal_cpu_to_le16(udev->descriptor.idVendor),
+ woal_cpu_to_le16(udev->descriptor.idProduct),
+ woal_cpu_to_le16(udev->descriptor.bcdDevice));
+ switch (woal_cpu_to_le16(udev->descriptor.idProduct)) {
+#ifdef USB8897
+ case USB8897_PID_1:
+#endif /* USB8897 */
+#ifdef USB8997
+ case USB8997_PID_1:
+ case USB8997V2_PID_1:
+#endif /* USB8997 */
+#ifdef USB8978
+ case USB8978_PID_1:
+ case USB8978_PID_1_BT:
+#endif /* USB8978 */
+#ifdef USB9098
+ case USB9098_PID_1:
+#endif /* USB9098 */
+#ifdef USB9097
+ case USB9097_PID_1:
+#endif /* USB9097 */
+ /* If skip FW is set, we must return error so
+ * the next driver can download the FW */
+ if (skip_fwdnld)
+ goto error;
+ else
+ usb_cardp->boot_state = USB_FW_DNLD;
+ break;
+#ifdef USB8897
+ case USB8897_PID_2:
+#endif /* USB8897 */
+#ifdef USB8997
+ case USB8997_PID_2:
+#endif /* USB8997 */
+#ifdef USB8978
+ case USB8978_PID_2:
+ case USB8978_PID_2_BT:
+#endif /* USB8978 */
+#ifdef USB9098
+ case USB9098_PID_2:
+#endif /* USB9098 */
+#ifdef USB9097
+ case USB9097_PID_2:
+#endif /* USB9097 */
+ usb_cardp->boot_state = USB_FW_READY;
+ break;
+ }
+ /*To do, get card type*/
+ /* if
+ (woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ USB8897_PID_2) usb_cardp->card_type =
+ CARD_TYPE_USB8897; else if
+ (woal_cpu_to_le16(udev->descriptor.idProduct) ==
+ USB8997_PID_2) usb_cardp->card_type =
+ CARD_TYPE_USB997;
+ */
+ break;
+ }
+ }
+
+ if (woal_usb_table[i].idVendor) {
+ usb_cardp->udev = udev;
+ iface_desc = intf->cur_altsetting;
+ usb_cardp->intf = intf;
+
+ PRINTM(MINFO,
+ "bcdUSB = 0x%X bDeviceClass = 0x%X"
+ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+ woal_cpu_to_le16(udev->descriptor.bcdUSB),
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+ udev->descriptor.bDeviceProtocol);
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if ((usb_endpoint_is_bulk_in(endpoint) ||
+ usb_endpoint_is_int_in(endpoint)) &&
+ (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)) {
+ usb_cardp->rx_cmd_ep_type =
+ usb_endpoint_type(endpoint);
+ usb_cardp->rx_cmd_interval =
+ endpoint->bInterval;
+ /* We found a bulk in command/event endpoint */
+ PRINTM(MCMND,
+ "Rx CMD/EVT: max packet size = %d, address = %d ep_type=%d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress,
+ usb_cardp->rx_cmd_ep_type);
+ usb_cardp->rx_cmd_ep =
+ (endpoint->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+
+ atomic_set(&usb_cardp->rx_cmd_urb_pending, 0);
+ if (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)
+ usb_cardp->second_mac = MTRUE;
+ }
+ if (usb_endpoint_is_bulk_in(endpoint) &&
+ (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_DATA_IF2)) {
+ /* We found a bulk in data endpoint */
+ PRINTM(MINFO,
+ "Bulk IN: max packet size = %d, address = %d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress);
+ usb_cardp->rx_data_ep =
+ (endpoint->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+ atomic_set(&usb_cardp->rx_data_urb_pending, 0);
+ }
+ if (usb_endpoint_is_bulk_out(endpoint) &&
+ (usb_endpoint_num(endpoint) == MLAN_USB_EP_DATA ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_DATA_IF2)) {
+ /* We found a bulk out data endpoint */
+ PRINTM(MCMND,
+ "Bulk OUT: max packet size = %d, address = %d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress);
+ usb_cardp->tx_data_ep =
+ endpoint->bEndpointAddress;
+ atomic_set(&usb_cardp->tx_data_urb_pending, 0);
+ usb_cardp->tx_data_maxpktsize =
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize);
+ }
+
+ if ((usb_endpoint_is_bulk_out(endpoint) ||
+ usb_endpoint_is_int_out(endpoint)) &&
+ (usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT ||
+ usb_endpoint_num(endpoint) ==
+ MLAN_USB_EP_CMD_EVENT_IF2)) {
+ usb_cardp->tx_cmd_ep_type =
+ usb_endpoint_type(endpoint);
+ usb_cardp->tx_cmd_interval =
+ endpoint->bInterval;
+ /* We found a bulk out command/event endpoint */
+ PRINTM(MCMND,
+ "Tx CMD: max packet size = %d, address = %d ep_type=%d\n",
+ woal_le16_to_cpu(
+ endpoint->wMaxPacketSize),
+ endpoint->bEndpointAddress,
+ usb_cardp->tx_cmd_ep_type);
+ usb_cardp->tx_cmd_ep =
+ endpoint->bEndpointAddress;
+ atomic_set(&usb_cardp->tx_cmd_urb_pending, 0);
+ usb_cardp->tx_cmd_maxpktsize = woal_le16_to_cpu(
+ endpoint->wMaxPacketSize);
+ }
+ }
+
+ if (usb_cardp->boot_state == USB_FW_DNLD) {
+ if (!usb_cardp->tx_cmd_ep || !usb_cardp->rx_cmd_ep)
+ goto error;
+ } else if (usb_cardp->boot_state == USB_FW_READY) {
+ if (!usb_cardp->tx_cmd_ep || !usb_cardp->tx_data_ep ||
+ !usb_cardp->rx_cmd_ep || !usb_cardp->rx_data_ep) {
+ PRINTM(MERROR,
+ "%s: invalid endpoint assignment\n",
+ __FUNCTION__);
+ goto error;
+ }
+ }
+
+ usb_cardp->tx_aggr_ctrl.enable = MFALSE;
+ usb_cardp->tx_aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ usb_cardp->tx_aggr_ctrl.aggr_align =
+ MAX(max_tx_buf, MLAN_USB_TX_AGGR_ALIGN);
+ usb_cardp->tx_aggr_ctrl.aggr_max = MLAN_USB_TX_MAX_AGGR_NUM;
+ usb_cardp->tx_aggr_ctrl.aggr_tmo =
+ MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000;
+ usb_cardp->rx_deaggr_ctrl.enable = MFALSE;
+ usb_cardp->rx_deaggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM;
+ usb_cardp->rx_deaggr_ctrl.aggr_align = MLAN_USB_RX_ALIGN_SIZE;
+ usb_cardp->rx_deaggr_ctrl.aggr_max = MLAN_USB_RX_MAX_AGGR_NUM;
+ usb_cardp->rx_deaggr_ctrl.aggr_tmo =
+ MLAN_USB_RX_DEAGGR_TIMEOUT_USEC;
+ usb_set_intfdata(intf, usb_cardp);
+
+ card_type = woal_update_card_type(usb_cardp);
+ if (!card_type) {
+ PRINTM(MERROR,
+ "usb probe: woal_update_card_type() failed\n");
+ goto error;
+ }
+
+ /* At this point wlan_add_card() will be called */
+ if (!(woal_add_card(usb_cardp, &usb_cardp->udev->dev, &usb_ops,
+ card_type))) {
+ PRINTM(MERROR, "%s: woal_add_card failed\n",
+ __FUNCTION__);
+ goto error;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ /* Note: From 2.6.34.2 onwards, remote wakeup is NOT enabled by
+ * default. So drivers wanting remote wakeup will have to enable
+ * this using -
+ * device_set_wakeup_enable(&udev->dev, 1);
+ * It has been observed that some cards having device attr =
+ * 0xa0 do not support remote wakeup. These cards come
+ * immediately out of the suspend when power/wakeup file is set
+ * to 'enabled'. To support all types of cards i.e. with/without
+ * remote wakeup, we are NOT setting the 'power/wakeup' file
+ * from here. Also in principle, we are not supposed to change
+ * the wakeup policy, which is purely a userspace decision.
+ */
+ /* if (udev->actconfig->desc.bmAttributes &
+ USB_CONFIG_ATT_WAKEUP) intf->needs_remote_wakeup = 1; */
+#endif
+ usb_get_dev(udev);
+ LEAVE();
+ return 0;
+ } else {
+ PRINTM(MINFO, "Discard the Probe request\n");
+ PRINTM(MINFO, "VID = 0x%X PID = 0x%X\n",
+ woal_cpu_to_le16(udev->descriptor.idVendor),
+ woal_cpu_to_le16(udev->descriptor.idProduct));
+ }
+error:
+ kfree(usb_cardp);
+ usb_cardp = NULL;
+ LEAVE();
+ return -ENXIO;
+}
+
+/**
+ * @brief Free resource and cleanup
+ *
+ * @param intf Pointer to usb_interface
+ *
+ * @return N/A
+ */
+static void woal_usb_disconnect(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *phandle = NULL;
+ ENTER();
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or phandle is not valid\n");
+ LEAVE();
+ return;
+ }
+ phandle = (moal_handle *)cardp->phandle;
+
+ /*
+ * Update Surprise removed to TRUE
+ * Free all the URB's allocated
+ */
+ phandle->surprise_removed = MTRUE;
+
+ /* Card is removed and we can call wlan_remove_card */
+ PRINTM(MINFO, "Call remove card\n");
+ woal_remove_card(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+ kfree(cardp);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief killall pending urbs
+ *
+ * @param handle Pointer to moal_handle
+ *
+ *
+ * @return N/A
+ */
+void woal_kill_urbs(moal_handle *handle)
+{
+ ENTER();
+ handle->is_suspended = MTRUE;
+ woal_usb_unlink_urb(handle->card);
+ LEAVE();
+}
+
+/**
+ * @brief resubmit urbs
+ *
+ * @param handle Pointer to moal_handle
+ *
+ *
+ * @return N/A
+ */
+void woal_resubmit_urbs(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = handle->card;
+
+ ENTER();
+ handle->is_suspended = MFALSE;
+
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf)
+ woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE);
+ }
+ LEAVE();
+}
+
+#ifdef CONFIG_PM
+/**
+ * @brief Handle suspend
+ *
+ * @param intf Pointer to usb_interface
+ * @param message Pointer to pm_message_t structure
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *handle = NULL;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "<--- Enter woal_usb_suspend --->\n");
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
+ ret = 0;
+ goto done;
+ }
+ handle = cardp->phandle;
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MWARN, "Device already suspended\n");
+ ret = 0;
+ goto done;
+ }
+#ifdef STA_SUPPORT
+ for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
+ if (handle->priv[i] &&
+ (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
+ woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
+ }
+#endif
+ /* Enable Host Sleep */
+ woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
+
+ /* Indicate device suspended */
+ /* The flag must be set here before the usb_kill_urb() calls.
+ * Reason: In the complete handlers, urb->status(= -ENOENT) and
+ * 'is_suspended' flag is used in combination to distinguish
+ * between a suspended state and a 'disconnect' one.
+ */
+ handle->is_suspended = MTRUE;
+ for (i = 0; i < handle->priv_num; i++)
+ netif_carrier_off(handle->priv[i]->netdev);
+
+ /* Unlink Rx cmd URB */
+ if (atomic_read(&cardp->rx_cmd_urb_pending) && cardp->rx_cmd.urb) {
+ usb_kill_urb(cardp->rx_cmd.urb);
+ }
+ /* Unlink Rx data URBs */
+ if (atomic_read(&cardp->rx_data_urb_pending)) {
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ if (cardp->rx_data_list[i].urb) {
+ usb_kill_urb(cardp->rx_data_list[i].urb);
+ usb_init_urb(cardp->rx_data_list[i].urb);
+ }
+ }
+ }
+
+ /* Unlink Tx data URBs */
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ if (cardp->tx_data_list[i].urb) {
+ usb_kill_urb(cardp->tx_data_list[i].urb);
+ }
+ }
+ /* Unlink Tx cmd URB */
+ if (cardp->tx_cmd.urb) {
+ usb_kill_urb(cardp->tx_cmd.urb);
+ }
+
+ handle->suspend_wait_q_woken = MTRUE;
+ wake_up_interruptible(&handle->suspend_wait_q);
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_usb_suspend --->\n");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Handle resume
+ *
+ * @param intf Pointer to usb_interface
+ *
+ * @return MLAN_STATUS_SUCCESS
+ */
+static int woal_usb_resume(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ moal_handle *handle = NULL;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MCMND, "<--- Enter woal_usb_resume --->\n");
+ if (!cardp || !cardp->phandle) {
+ PRINTM(MERROR, "Card or adapter structure is not valid\n");
+ ret = 0;
+ goto done;
+ }
+ handle = cardp->phandle;
+
+ if (handle->is_suspended == MFALSE) {
+ PRINTM(MWARN, "Device already resumed\n");
+ ret = 0;
+ goto done;
+ }
+
+ /* Indicate device resumed.
+ * The netdev queue will be resumed only after the urbs
+ * have been resubmitted */
+ handle->is_suspended = MFALSE;
+
+ if (!atomic_read(&cardp->rx_data_urb_pending)) {
+ /* Submit multiple Rx data URBs */
+ woal_usb_submit_rx_data_urbs(handle);
+ }
+ if (!atomic_read(&cardp->rx_cmd_urb_pending)) {
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf)
+ woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE);
+ }
+
+ for (i = 0; i < handle->priv_num; i++)
+ if (handle->priv[i]->media_connected == MTRUE)
+ netif_carrier_on(handle->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ if (handle->hs_activated)
+ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
+ MOAL_NO_WAIT);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Resume handler may be called due to remote wakeup,
+ force to exit suspend anyway */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ cardp->udev->autosuspend_disabled = 1;
+#else
+#ifdef CONFIG_PM_RUNTIME
+ cardp->udev->dev.power.runtime_auto = 0;
+#endif
+#endif /* < 2.6.35 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ cardp->udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+#ifdef CONFIG_PM_RUNTIME
+ atomic_inc(&(cardp->udev)->dev.power.usage_count);
+#endif
+#endif /* >= 2.6.34 */
+#endif /* >= 2.6.24 */
+
+done:
+ PRINTM(MCMND, "<--- Leave woal_usb_resume --->\n");
+ LEAVE();
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * @brief This function initialize the tx URBs
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_tx_init(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->tx_cmd.handle = handle;
+ cardp->tx_cmd.ep = cardp->tx_cmd_ep;
+ /* Allocate URB for command */
+ cardp->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->tx_cmd.urb) {
+ PRINTM(MERROR, "Tx command URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+
+ cardp->tx_data_ix = 0;
+ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) {
+ cardp->tx_data_list[i].handle = handle;
+ cardp->tx_data_list[i].ep = cardp->tx_data_ep;
+ /* Allocate URB for data */
+ cardp->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->tx_data_list[i].urb) {
+ PRINTM(MERROR, "Tx data URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+
+init_exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function submits the rx data URBs
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_submit_rx_data_urbs(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_FAILURE;
+ t_u32 buffer_len = MLAN_RX_DATA_BUF_SIZE;
+
+ ENTER();
+
+ if (cardp->rx_deaggr_ctrl.enable) {
+ buffer_len = cardp->rx_deaggr_ctrl.aggr_max;
+ if (cardp->rx_deaggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
+ buffer_len *= MAX(MLAN_USB_MAX_PKT_SIZE,
+ cardp->rx_deaggr_ctrl.aggr_align);
+ buffer_len = MAX(buffer_len, MLAN_RX_DATA_BUF_SIZE);
+ }
+ }
+
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ /* Submit Rx data URB */
+ if (!cardp->rx_data_list[i].pmbuf) {
+ if (woal_usb_submit_rx_urb(&cardp->rx_data_list[i],
+ buffer_len))
+ continue;
+ }
+ ret = MLAN_STATUS_SUCCESS;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function initialize the rx URBs and submit them
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_rx_init(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ int i;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->rx_cmd.handle = handle;
+ cardp->rx_cmd.ep = cardp->rx_cmd_ep;
+ /* Allocate URB for command/event */
+ cardp->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->rx_cmd.urb) {
+ PRINTM(MERROR, "Rx command URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+
+ cardp->rx_cmd.pmbuf =
+ woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE);
+ if (cardp->rx_cmd.pmbuf) {
+ /* Submit Rx command URB */
+ if (woal_usb_submit_rx_urb(&cardp->rx_cmd,
+ MLAN_RX_CMD_BUF_SIZE)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+ for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
+ cardp->rx_data_list[i].handle = handle;
+ cardp->rx_data_list[i].ep = cardp->rx_data_ep;
+ /* Allocate URB for data */
+ cardp->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!cardp->rx_data_list[i].urb) {
+ PRINTM(MERROR, "Rx data URB allocation failed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto init_exit;
+ }
+ }
+ ret = woal_usb_submit_rx_data_urbs(handle);
+ if (ret) {
+ PRINTM(MERROR, "Rx data URB submission failed\n");
+ goto init_exit;
+ }
+
+init_exit:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data blocks to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to send
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_write_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout)
+{
+ struct usb_card_rec *cardp = handle->card;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 ep = endpoint;
+ t_u32 length = pmbuf->data_len;
+ int actual_length;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ int bulk_out_maxpktsize = 512;
+
+ if (ep == cardp->tx_cmd_ep)
+ bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
+ else if (ep == cardp->tx_data_ep)
+ bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
+
+ if (length % bulk_out_maxpktsize == 0)
+ length++;
+
+ /* Send the data block */
+ ret = usb_bulk_msg(cardp->udev, usb_sndbulkpipe(cardp->udev, ep),
+ (t_u8 *)data, length, &actual_length, timeout);
+ if (ret) {
+ PRINTM(MERROR, "usb_blk_msg for send failed, ret %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+
+ pmbuf->data_len = actual_length;
+ DBG_HEXDUMP(MIF_D, "write sync", data, actual_length);
+
+ return ret;
+}
+
+/**
+ * @brief This function read data blocks to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to receive
+ * @param timeout Timeout value in milliseconds (if 0 the wait is forever)
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_read_data_sync(moal_handle *handle,
+ mlan_buffer *pmbuf, t_u32 endpoint,
+ t_u32 timeout)
+{
+ struct usb_card_rec *cardp = handle->card;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ t_u8 ep = endpoint;
+ t_u32 buf_len = pmbuf->data_len;
+ int actual_length;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+ /* Receive the data response */
+ ret = usb_bulk_msg(cardp->udev, usb_rcvbulkpipe(cardp->udev, ep), data,
+ buf_len, &actual_length, timeout);
+ if (ret) {
+ PRINTM(MERROR, "usb_bulk_msg failed: %d\n", ret);
+ ret = MLAN_STATUS_FAILURE;
+ }
+ pmbuf->data_len = actual_length;
+ DBG_HEXDUMP(MIF_D, "read sync", data, actual_length);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function downloads data/command packet to device
+ *
+ * @param handle Pointer to moal_handle structure
+ * @param pmbuf Pointer to mlan_buffer structure
+ * @param ep Endpoint to send
+ *
+ * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE or
+ * MLAN_STATUS_RESOURCE
+ */
+mlan_status woal_write_data_async(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u8 ep)
+{
+ struct usb_card_rec *cardp = handle->card;
+ urb_context *context = NULL;
+ t_u8 *data = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
+ struct urb *tx_urb = NULL;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ t_u32 data_len = pmbuf->data_len;
+ int bulk_out_maxpktsize = 512;
+
+ ENTER();
+
+ /* Check if device is removed */
+ if (handle->surprise_removed) {
+ PRINTM(MERROR, "Device removed\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto tx_ret;
+ }
+
+ if ((ep == cardp->tx_data_ep) &&
+ (atomic_read(&cardp->tx_data_urb_pending) >= MVUSB_TX_HIGH_WMARK)) {
+ ret = MLAN_STATUS_RESOURCE;
+ goto tx_ret;
+ }
+ PRINTM(MINFO, "woal_write_data_async: ep=%d\n", ep);
+
+ if (ep == cardp->tx_cmd_ep) {
+ context = &cardp->tx_cmd;
+ bulk_out_maxpktsize = cardp->tx_cmd_maxpktsize;
+ } else {
+ if (ep == cardp->tx_data_ep) {
+ bulk_out_maxpktsize = cardp->tx_data_maxpktsize;
+ if (cardp->tx_data_ix >= MVUSB_TX_HIGH_WMARK)
+ cardp->tx_data_ix = 0;
+ context = &cardp->tx_data_list[cardp->tx_data_ix++];
+ }
+ }
+
+ if (!context) {
+ PRINTM(MERROR, "Cannot allocate Tx urb_context\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto tx_ret;
+ }
+ context->handle = handle;
+ context->ep = ep;
+ context->pmbuf = pmbuf;
+
+ tx_urb = context->urb;
+
+ if (data_len % bulk_out_maxpktsize == 0)
+ data_len++;
+
+ /*
+ * Use USB API usb_fill_bulk_urb() to set the
+ * configuration information of the Tx bulk URB
+ * and initialize the Tx callback
+ */
+
+ if (ep == cardp->tx_cmd_ep &&
+ cardp->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) {
+ usb_fill_int_urb(tx_urb, cardp->udev,
+ usb_sndintpipe(cardp->udev, ep), data,
+ data_len, woal_usb_tx_complete,
+ (void *)context, cardp->tx_cmd_interval);
+ } else
+ usb_fill_bulk_urb(tx_urb, cardp->udev,
+ usb_sndbulkpipe(cardp->udev, ep), data,
+ data_len, woal_usb_tx_complete,
+ (void *)context);
+ /* We find on Ubuntu 12.10 this flag does not work */
+ // tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if (ep == cardp->tx_cmd_ep)
+ atomic_inc(&cardp->tx_cmd_urb_pending);
+ else if (ep == cardp->tx_data_ep)
+ atomic_inc(&cardp->tx_data_urb_pending);
+ if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
+ /* Submit URB failure */
+ PRINTM(MERROR, "Submit EP %d Tx URB failed: %d\n", ep, ret);
+ if (ep == cardp->tx_cmd_ep)
+ atomic_dec(&cardp->tx_cmd_urb_pending);
+ else {
+ if (ep == cardp->tx_data_ep) {
+ atomic_dec(&cardp->tx_data_urb_pending);
+ if (cardp->tx_data_ix)
+ cardp->tx_data_ix--;
+ else
+ cardp->tx_data_ix = MVUSB_TX_HIGH_WMARK;
+ }
+ }
+ ret = MLAN_STATUS_FAILURE;
+ } else {
+ if (ep == cardp->tx_data_ep &&
+ (atomic_read(&cardp->tx_data_urb_pending) ==
+ MVUSB_TX_HIGH_WMARK))
+ ret = MLAN_STATUS_PRESOURCE;
+ else
+ ret = MLAN_STATUS_SUCCESS;
+ }
+
+tx_ret:
+
+ if (!ret)
+ ret = MLAN_STATUS_PENDING;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function register usb device and initialize parameter
+ *
+ * @param handle Pointer to moal_handle structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+static mlan_status woal_usb_register_dev(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ cardp->phandle = handle;
+ LEAVE();
+ return ret;
+}
+
+static void woal_usb_unregister_dev(moal_handle *handle)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+ PRINTM(MMSG, "USB: unregister device\n");
+ woal_usb_free(cardp);
+ cardp->phandle = NULL;
+ return;
+}
+
+/**
+ * @brief This function registers driver.
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status woal_usb_bus_register(void)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ ENTER();
+
+ if (skip_fwdnld) {
+ woal_usb_driver.id_table = woal_usb_table_skip_fwdnld;
+ }
+ /*
+ * API registers the NXP USB driver
+ * to the USB system
+ */
+ if (usb_register(&woal_usb_driver)) {
+ PRINTM(MFATAL, "USB Driver Registration Failed \n");
+ ret = MLAN_STATUS_FAILURE;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function removes usb driver.
+ *
+ * @return N/A
+ */
+void woal_usb_bus_unregister(void)
+{
+ ENTER();
+ /* API unregisters the driver from USB subsystem */
+ usb_deregister(&woal_usb_driver);
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function check if this is second mac
+ *
+ * @param handle A pointer to moal_handle structure
+ * @return MTRUE/MFALSE
+ *
+ */
+static t_u8 woal_usb_is_second_mac(moal_handle *handle)
+{
+ return ((struct usb_card_rec *)(handle->card))->second_mac;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+/**
+ * @brief This function makes USB device to suspend.
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_enter_usb_suspend(moal_handle *handle)
+{
+ struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)(handle->card))->intf;
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ ENTER();
+
+ PRINTM(MIOCTL, "USB suspend ioctl (state %d)\n", udev->state);
+
+ if (handle->is_suspended == MTRUE) {
+ PRINTM(MERROR, "Device already suspended\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+ handle->suspend_wait_q_woken = MFALSE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Enter into USB suspend */
+ usb_lock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
+ udev->autosuspend_delay = 0; /* Autosuspend delay in jiffies */
+#else
+ pm_runtime_set_autosuspend_delay(&udev->dev, 0); /* Autosuspend delay in
+ jiffies */
+#endif /* < 2.6.38 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ udev->autosuspend_disabled = 0; /* /sys/bus/usb/devices/.../power/level
+ < auto */
+#endif /* < 2.6.34 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+ usb_unlock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 1;
+#else
+ atomic_set(&intf->pm_usage_cnt, 1);
+#endif /* < 2.6.32 */
+ usb_autopm_put_interface(intf);
+#else
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 1);
+ usb_enable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ /* Wait for suspend to complete */
+ wait_event_interruptible(handle->suspend_wait_q,
+ handle->suspend_wait_q_woken);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function makes USB device to resume.
+ *
+ * @param handle A pointer to moal_handle structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+int woal_exit_usb_suspend(moal_handle *handle)
+{
+ struct usb_device *udev = ((struct usb_card_rec *)(handle->card))->udev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ struct usb_interface *intf =
+ ((struct usb_card_rec *)(handle->card))->intf;
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ ENTER();
+
+ PRINTM(MIOCTL, "USB resume ioctl (state %d)\n", udev->state);
+
+ if (handle->is_suspended == MFALSE ||
+ udev->state != USB_STATE_SUSPENDED) {
+ PRINTM(MERROR, "Device already resumed\n");
+ LEAVE();
+ return -EFAULT;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ /* Exit from USB suspend */
+ usb_lock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+ udev->autosuspend_disabled = 1; /* /sys/bus/usb/devices/.../power/level
+ < on */
+#endif /* < 2.6.34 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
+ udev->autoresume_disabled = 0;
+#endif /* < 2.6.33 */
+ usb_unlock_device(udev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+ intf->pm_usage_cnt = 0;
+#else
+ atomic_set(&intf->pm_usage_cnt, 0);
+#endif /* < 2.6.32 */
+ usb_autopm_get_interface(intf);
+#else
+ usb_lock_device(udev);
+ atomic_set(&udev->dev.power.usage_count, 0);
+ usb_disable_autosuspend(udev);
+ usb_unlock_device(udev);
+#endif /* < 2.6.34 */
+#endif /* >= 2.6.24 */
+
+ LEAVE();
+ return 0;
+}
+#endif /* CONFIG_USB_SUSPEND */
+
+/**
+ * @brief This function will submit rx urb.
+ *
+ * @param handle Pointer to moal_handle
+ * @param ep Endpoint to re-submit urb
+ *
+ * @return N/A
+ */
+void woal_submit_rx_urb(moal_handle *handle, t_u8 ep)
+{
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+
+ ENTER();
+
+ if ((ep == cardp->rx_cmd_ep) &&
+ (!atomic_read(&cardp->rx_cmd_urb_pending))) {
+ woal_usb_submit_rx_urb(&cardp->rx_cmd, MLAN_RX_CMD_BUF_SIZE);
+ }
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function dump firmware memory to file
+ *
+ * @param phandle A pointer to moal_handle
+ *
+ * @return N/A
+ */
+void woal_usb_dump_fw_info(moal_handle *phandle)
+{
+ moal_private *priv = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *pcfg_misc = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ priv = woal_get_priv(phandle, MLAN_BSS_ROLE_ANY);
+ if (!priv) {
+ PRINTM(MERROR, "woal_dump_firmware_info get priv is NULL!\n");
+ goto done;
+ }
+ /* Allocate an IOCTL request buffer */
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ PRINTM(MERROR, "woal_dump_firmware_info alloc req fail!\n");
+ goto done;
+ }
+
+ /* Fill request buffer */
+ pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
+ pcfg_misc->sub_command = MLAN_OID_MISC_FW_DUMP_EVENT;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+done:
+ LEAVE();
+ return;
+}
+
+static mlan_status woal_usb_get_fw_name(moal_handle *handle)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+ t_u32 revision_id = 0;
+ t_u32 strap = 0;
+#endif
+ struct usb_card_rec *cardp = (struct usb_card_rec *)handle->card;
+#if defined(USB9098)
+ moal_handle *ref_handle = NULL;
+#endif
+
+ ENTER();
+ if (handle->params.fw_name)
+ goto done;
+ if (cardp->boot_state == USB_FW_READY)
+ goto done;
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+ ret = woal_check_chip_revision(handle, &revision_id, &strap);
+ if (ret != MLAN_STATUS_SUCCESS) {
+ PRINTM(MFATAL, "Chip revision check failure!\n");
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ PRINTM(MCMND, "revision=0x%x, strap=0x%x\n", revision_id, strap);
+#endif
+
+#ifdef USB8997
+ if (IS_USB8997(handle->card_type)) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART8997_DEFAULT_COMBO_FW_NAME);
+ else if (strap != 0)
+ strcpy(handle->card_info->fw_name,
+ USBUSB8997_DEFAULT_COMBO_FW_NAME);
+ }
+#endif
+
+#ifdef USB8978
+ if (IS_USB8978(handle->card_type)) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART8978_DEFAULT_COMBO_FW_NAME);
+ else if (strap != 0)
+ strcpy(handle->card_info->fw_name,
+ USBUSB8978_DEFAULT_COMBO_FW_NAME);
+ }
+#endif
+
+#ifdef USB9098
+ if (IS_USB9098(handle->card_type)) {
+ if (cardp->second_mac) {
+ ref_handle = (moal_handle *)handle->pref_mac;
+ if (ref_handle) {
+ strcpy(handle->card_info->fw_name,
+ ref_handle->card_info->fw_name);
+ strcpy(handle->card_info->fw_name_wlan,
+ ref_handle->card_info->fw_name_wlan);
+ }
+ goto done;
+ }
+ switch (revision_id) {
+ case USB9098_Z1Z2:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9098_DEFAULT_COMBO_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9098_DEFAULT_COMBO_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9098_DEFAULT_WLAN_FW_NAME);
+ break;
+ case USB9098_A0:
+ case USB9098_A1:
+ case USB9098_A2:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9098_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9098_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9098_WLAN_V1_FW_NAME);
+ break;
+ }
+ }
+#endif
+#ifdef USB9097
+ if (IS_USB9097(handle->card_type)) {
+ switch (revision_id) {
+ case USB9097_B0:
+ case USB9097_B1:
+ if (strap != 0) {
+ if (strap == CARD_TYPE_USB_UART)
+ strcpy(handle->card_info->fw_name,
+ USBUART9097_COMBO_V1_FW_NAME);
+ else
+ strcpy(handle->card_info->fw_name,
+ USBUSB9097_COMBO_V1_FW_NAME);
+ }
+ strcpy(handle->card_info->fw_name_wlan,
+ USB9097_WLAN_V1_FW_NAME);
+ break;
+ }
+ }
+#endif
+done:
+ PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
+ handle->card_info->fw_name_wlan);
+ LEAVE();
+ return ret;
+}
+
+static moal_if_ops usb_ops = {
+ .register_dev = woal_usb_register_dev,
+ .unregister_dev = woal_usb_unregister_dev,
+ .read_data_sync = woal_usb_read_data_sync,
+ .write_data_sync = woal_usb_write_data_sync,
+ .get_fw_name = woal_usb_get_fw_name,
+ .dump_fw_info = woal_usb_dump_fw_info,
+ .is_second_mac = woal_usb_is_second_mac,
+};
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.h
new file mode 100644
index 000000000000..7c95c28be29c
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_usb.h
@@ -0,0 +1,234 @@
+/** @file moal_usb.h
+ *
+ * @brief This file contains definitions for USB interface.
+ * driver.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+/*************************************************************
+Change Log:
+ 10/21/2008: initial version
+************************************************************/
+
+#ifndef _MOAL_USB_H
+#define _MOAL_USB_H
+
+#ifdef USB8997
+/** USB VID 1 */
+#define USB8997_VID_1 0x1286
+/** USB PID 1 */
+#define USB8997_PID_1 0x204D
+/** USB PID 2 */
+#define USB8997_PID_2 0x204E
+#define USB8997_PID_3 0x2047
+#define USB8997_PID_4 0x2048
+#define USB8997_PID_5 0x2050
+#define USB8997_PID_6 0x2051
+#define USB8997V2_PID_1 0x2052
+#endif /* USB8997 */
+
+#ifdef USB8978
+/** USB VID 1 */
+#define USB8978_VID_1 0x1286
+/** USB PID 1 */
+#define USB8978_PID_1 0x2062
+/** USB PID 2 */
+#define USB8978_PID_2 0x2063
+/* BT downloaded combo firmware; register for WLAN enumeration */
+#define USB8978_PID_1_BT 0x2064
+#define USB8978_PID_2_BT 0x2065
+#endif
+
+#ifdef USB8897
+/** USB VID 1 */
+#define USB8897_VID_1 0x1286
+/** USB PID 1 */
+#define USB8897_PID_1 0x2045
+/** USB PID 2 */
+#define USB8897_PID_2 0x2046
+#endif /* USB8897 */
+
+#ifdef USB9098
+/** USB VID 1 */
+#define USB9098_VID_1 0x1286
+/** USB PID 1 */
+#define USB9098_PID_1 0x2056
+/** USB PID 2 */
+#define USB9098_PID_2 0x2057
+#endif /* USB9098 */
+
+#ifdef USB9097
+/** USB VID 1 */
+#define USB9097_VID_1 0x1286
+/** USB PID 1 */
+#define USB9097_PID_1 0x2060
+/** USB PID 2 */
+#define USB9097_PID_2 0x2061
+#endif /* USB9097 */
+
+/** Boot state: FW download */
+#define USB_FW_DNLD 1
+/** Boot state: FW ready */
+#define USB_FW_READY 2
+
+/** High watermark for Tx data */
+#define MVUSB_TX_HIGH_WMARK 12
+
+/** Number of Rx data URB */
+#define MVUSB_RX_DATA_URB 6
+
+#if defined(USB8997) || defined(USB9098) || defined(USB9097) || defined(USB8978)
+/* Transmit buffer size for chip revision check */
+#define CHIP_REV_TX_BUF_SIZE 16
+/* Receive buffer size for chip revision check */
+#define CHIP_REV_RX_BUF_SIZE 2048
+
+/* Extensions */
+#define EXTEND_HDR (0xAB950000)
+#define EXTEND_V1 (0x00000001)
+#define EXTEND_V2 (0x00000002)
+
+#endif
+
+/** Default firmaware name */
+#ifdef USB8997
+#define USB8997_DEFAULT_COMBO_FW_NAME "nxp/usbusb8997_combo_v4.bin"
+#define USB8997_DEFAULT_WLAN_FW_NAME "nxp/usb8997_wlan_v4.bin"
+#define USBUART8997_DEFAULT_COMBO_FW_NAME "nxp/usbuart8997_combo_v4.bin"
+#define USBUSB8997_DEFAULT_COMBO_FW_NAME "nxp/usbusb8997_combo_v4.bin"
+
+#endif /* USB8997 */
+
+#ifdef USB8978
+#define USB8978_DEFAULT_COMBO_FW_NAME "nxp/usbusb8978_combo.bin"
+#define USB8978_DEFAULT_WLAN_FW_NAME "nxp/usb8978_wlan.bin"
+#define USBUART8978_DEFAULT_COMBO_FW_NAME "nxp/usbuart8978_combo.bin"
+#define USBUSB8978_DEFAULT_COMBO_FW_NAME "nxp/usbusb8978_combo.bin"
+#endif /* USB8978 */
+
+#ifdef USB8897
+#define USB8897_DEFAULT_COMBO_FW_NAME "nxp/usb8897_uapsta.bin"
+#define USB8897_DEFAULT_WLAN_FW_NAME "nxp/usb8897_wlan.bin"
+#endif /* USB8897 */
+
+#ifdef USB9098
+#define USB9098_Z1Z2 0x00
+#define USB9098_A0 0x01
+#define USB9098_A1 0x02
+#define USB9098_A2 0x03
+#define USB9098_DEFAULT_COMBO_FW_NAME "nxp/usbusb9098_combo.bin"
+#define USB9098_DEFAULT_WLAN_FW_NAME "nxp/usb9098_wlan.bin"
+#define USBUART9098_DEFAULT_COMBO_FW_NAME "nxp/usbuart9098_combo.bin"
+#define USBUSB9098_DEFAULT_COMBO_FW_NAME "nxp/usbusb9098_combo.bin"
+#define USB9098_WLAN_V1_FW_NAME "nxp/usb9098_wlan_v1.bin"
+#define USBUART9098_COMBO_V1_FW_NAME "nxp/usbuart9098_combo_v1.bin"
+#define USBUSB9098_COMBO_V1_FW_NAME "nxp/usbusb9098_combo_v1.bin"
+#endif /* USB9098 */
+
+#ifdef USB9097
+#define USB9097_B0 0x01
+#define USB9097_B1 0x02
+#define USB9097_DEFAULT_COMBO_FW_NAME "nxp/usbusb9097_combo_v1.bin"
+#define USB9097_DEFAULT_WLAN_FW_NAME "nxp/usb9097_wlan_v1.bin"
+#define USB9097_WLAN_V1_FW_NAME "nxp/usb9097_wlan_v1.bin"
+#define USBUART9097_COMBO_V1_FW_NAME "nxp/usbuart9097_combo_v1.bin"
+#define USBUSB9097_COMBO_V1_FW_NAME "nxp/usbusb9097_combo_v1.bin"
+#endif /* USB9097 */
+
+/** urb context */
+typedef struct _urb_context {
+ /** Pointer to moal_handle structure */
+ moal_handle *handle;
+ /** Pointer to mlan buffer */
+ mlan_buffer *pmbuf;
+ /** URB */
+ struct urb *urb;
+ /** EP */
+ t_u8 ep;
+} urb_context;
+
+/** USB card description structure*/
+struct usb_card_rec {
+ /** USB device */
+ struct usb_device *udev;
+ /** MOAL handle */
+ moal_handle *phandle;
+ /** USB interface */
+ struct usb_interface *intf;
+ /** Rx command endpoint type */
+ int rx_cmd_ep_type;
+ /** Rx command interval for INTR type */
+ t_u8 rx_cmd_interval;
+ /** Rx data endpoint address */
+ t_u8 rx_cmd_ep;
+ /** Rx cmd contxt */
+ urb_context rx_cmd;
+ /** Rx command URB pending count */
+ atomic_t rx_cmd_urb_pending;
+ /** Rx data context list */
+ urb_context rx_data_list[MVUSB_RX_DATA_URB];
+ /** Flag to indicate boot state */
+ t_u8 boot_state;
+ /** Rx data endpoint address */
+ t_u8 rx_data_ep;
+ /** Rx data URB pending count */
+ atomic_t rx_data_urb_pending;
+ /** Tx data endpoint address */
+ t_u8 tx_data_ep;
+ /** Tx command endpoint type */
+ int tx_cmd_ep_type;
+ /** Tx command interval for INTR type */
+ t_u8 tx_cmd_interval;
+ /** Tx command endpoint address */
+ t_u8 tx_cmd_ep;
+ /** Tx data URB pending count */
+ atomic_t tx_data_urb_pending;
+ /** Tx command URB pending count */
+ atomic_t tx_cmd_urb_pending;
+ /** Tx data endpoint max pkt size */
+ int tx_data_maxpktsize;
+ /** Tx cmd endpoint max pkt size */
+ int tx_cmd_maxpktsize;
+ /** Pre-allocated urb for command */
+ urb_context tx_cmd;
+ /** Index to point to next data urb to use */
+ int tx_data_ix;
+ /** Pre-allocated urb for data */
+ urb_context tx_data_list[MVUSB_TX_HIGH_WMARK];
+ usb_aggr_ctrl tx_aggr_ctrl;
+ usb_aggr_ctrl rx_deaggr_ctrl;
+ t_u8 resubmit_urbs;
+ /** USB card type */
+ t_u16 card_type;
+ t_u8 second_mac;
+};
+
+void woal_kill_urbs(moal_handle *handle);
+void woal_resubmit_urbs(moal_handle *handle);
+
+mlan_status woal_write_data_async(moal_handle *handle, mlan_buffer *pmbuf,
+ t_u8 ep);
+mlan_status woal_usb_submit_rx_data_urbs(moal_handle *handle);
+mlan_status woal_usb_rx_init(moal_handle *handle);
+mlan_status woal_usb_tx_init(moal_handle *handle);
+mlan_status woal_usb_aggr_init(moal_handle *handle);
+void woal_submit_rx_urb(moal_handle *handle, t_u8 ep);
+void woal_usb_bus_unregister(void);
+mlan_status woal_usb_bus_register(void);
+void woal_usb_free(struct usb_card_rec *cardp);
+#endif /*_MOAL_USB_H */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.c
new file mode 100644
index 000000000000..0072b18a0aea
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.c
@@ -0,0 +1,3175 @@
+/** @file moal_wext.c
+ *
+ * @brief This file contains wireless extension standard ioctl functions
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/************************************************************************
+Change log:
+ 10/21/2008: initial version
+************************************************************************/
+
+#include "moal_main.h"
+
+#ifdef STA_SUPPORT
+/** Approximate amount of data needed to pass a scan result back to iwlist */
+#define MAX_SCAN_CELL_SIZE \
+ (IW_EV_ADDR_LEN + MLAN_MAX_SSID_LENGTH + IW_EV_UINT_LEN + \
+ IW_EV_FREQ_LEN + IW_EV_QUAL_LEN + MLAN_MAX_SSID_LENGTH + \
+ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
+/** Macro for minimum size of scan buffer */
+#define MIN_ACCEPTED_GET_SCAN_BUF 8000
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+static t_s32 woal_ssid_cmp(mlan_802_11_ssid *ssid1, mlan_802_11_ssid *ssid2)
+{
+ ENTER();
+
+ if (!ssid1 || !ssid2) {
+ LEAVE();
+ return -1;
+ }
+ if (ssid1->ssid_len != ssid2->ssid_len) {
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/**
+ * @brief Sort Channels
+ *
+ * @param freq A pointer to iw_freq structure
+ * @param num Number of Channels
+ *
+ * @return N/A
+ */
+static inline void woal_sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/**
+ * @brief Convert RSSI to quality
+ *
+ * @param rssi RSSI in dBm
+ *
+ * @return Quality of the link (0-5)
+ */
+static t_u8 woal_rssi_to_quality(t_s16 rssi)
+{
+/** Macro for RSSI range */
+#define MOAL_RSSI_NO_SIGNAL -90
+#define MOAL_RSSI_VERY_LOW -80
+#define MOAL_RSSI_LOW -70
+#define MOAL_RSSI_GOOD -60
+#define MOAL_RSSI_VERY_GOOD -50
+#define MOAL_RSSI_INVALID 0
+ if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
+ return 0;
+ else if (rssi <= MOAL_RSSI_VERY_LOW)
+ return 1;
+ else if (rssi <= MOAL_RSSI_LOW)
+ return 2;
+ else if (rssi <= MOAL_RSSI_GOOD)
+ return 3;
+ else if (rssi <= MOAL_RSSI_VERY_GOOD)
+ return 4;
+ else
+ return 5;
+}
+
+/**
+ * @brief Set Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ ENTER();
+ /*
+ * Check the size of the string
+ */
+ if (dwrq->length > 16) {
+ LEAVE();
+ return -E2BIG;
+ }
+ memset(priv->nick_name, 0, sizeof(priv->nick_name));
+ moal_memcpy_ext(priv->phandle, priv->nick_name, extra, dwrq->length,
+ sizeof(priv->nick_name));
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get Adapter Node Name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ ENTER();
+ /*
+ * Get the Nick Name saved
+ */
+ strncpy(extra, (char *)priv->nick_name, 16);
+ extra[16] = '\0';
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Commit handler: called after a bunch of SET operations
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_config_commit(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *cwrq, char *extra)
+{
+ ENTER();
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get name
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param cwrq A pointer to char buffer
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_name(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *cwrq = wrqu->name;
+ ENTER();
+ strcpy(cwrq, "IEEE 802.11-DS");
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+ long f = fwrq->m / 100000;
+ bss->param.bss_chan.freq = f;
+ } else
+ bss->param.bss_chan.channel = fwrq->m;
+
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_change_adhoc_chan(priv, bss->param.bss_chan.channel,
+ MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get frequency
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param fwrq A pointer to iw_freq structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_freq(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_freq *fwrq = &wrqu->freq;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_CHANNEL;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fwrq->m = (long)bss->param.bss_chan.freq;
+ fwrq->i = (long)bss->param.bss_chan.channel;
+ fwrq->e = 6;
+ fwrq->flags = IW_FREQ_FIXED;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq Wireless mode to set
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_bss_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u32 *uwrq = &wrqu->mode;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *)req->pbuf;
+ bss->sub_command = MLAN_OID_BSS_MODE;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ switch (*uwrq) {
+ case IW_MODE_INFRA:
+ bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
+ break;
+ case IW_MODE_ADHOC:
+ bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
+ break;
+ case IW_MODE_AUTO:
+ bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ goto done;
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current BSSID
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to sockaddr structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct sockaddr *awrq = &wrqu->addr;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (bss_info.media_connected == MTRUE)
+ moal_memcpy_ext(priv->phandle, awrq->sa_data, &bss_info.bssid,
+ MLAN_MAC_ADDR_LENGTH, sizeof(awrq->sa_data));
+ else
+ memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
+ const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct sockaddr *awrq = &wrqu->addr;
+ mlan_ssid_bssid ssid_bssid;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
+ MAC2STR((t_u8 *)awrq->sa_data));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+#endif
+
+ /* zero_mac means disconnect */
+ if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE);
+ goto done;
+ }
+
+ /* Broadcast MAC means search for best network */
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+ if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
+ /* Check if we are already assoicated to the AP */
+ if (bss_info.media_connected == MTRUE) {
+ if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
+ ETH_ALEN, sizeof(ssid_bssid.bssid));
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ PRINTM(MERROR,
+ "ASSOC: WAP: MAC address not found in BSSID List\n");
+ ret = -ENETUNREACH;
+ goto done;
+ }
+ /* Zero SSID implies use BSSID to connect */
+ memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(priv->prev_ssid_bssid.ssid));
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->prev_ssid_bssid.bssid));
+#endif /* REASSOCIATION */
+
+done:
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get wlan mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param uwrq A pointer to t_u32 string
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_get_bss_mode(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u32 *uwrq = &wrqu->mode;
+ ENTER();
+ *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success
+ */
+static int woal_set_sens(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get sensitivity
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -1
+ */
+static int woal_get_sens(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = -1;
+
+ ENTER();
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+
+ ENTER();
+ if (vwrq->disabled) {
+ woal_set_radio(priv, 0);
+ goto done;
+ }
+ woal_set_radio(priv, 1);
+
+ if (!vwrq->fixed)
+ power_cfg.is_power_auto = 1;
+ else {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = vwrq->value;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx power
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_power_cfg_t power_cfg;
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = power_cfg.power_level;
+ if (power_cfg.is_power_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ if (bss_info.radio_on) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, disabled;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
+ PRINTM(MIOCTL, "block set power in hw_test mode\n");
+ LEAVE();
+ return ret;
+ }
+ disabled = vwrq->disabled;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, vwrq->flags,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get power management
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return MLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int woal_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, ps_mode = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
+ &ps_mode, 0,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+
+ if (ps_mode)
+ vwrq->disabled = 0;
+ else
+ vwrq->disabled = 1;
+
+ vwrq->value = 0;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, retry_val = vwrq->value;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /*
+ * The MAC has a 4-bit Total_Tx_Count register
+ * Total_Tx_Count = 1 + Tx_Retry_Count
+ */
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_retry(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Tx retry count
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int retry_val, ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_retry(priv, MLAN_ACT_GET,
+ MOAL_IOCTL_WAIT,
+ &retry_val)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Get Tx retry count */
+ vwrq->value = retry_val;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_encode(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ int index = 0;
+ t_u32 auth_mode = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ /* Check index */
+ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (index > 3) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ sec->param.encrypt_key.key_len = 0;
+ if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
+ if (dwrq->length > MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Key length (%d) out of range\n",
+ dwrq->length);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (index < 0)
+ sec->param.encrypt_key.key_index =
+ MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index;
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.key_material, extra,
+ dwrq->length,
+ sizeof(sec->param.encrypt_key.key_material));
+ /* Set the length */
+ if (dwrq->length > MIN_WEP_KEY_SIZE)
+ sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
+ else
+ sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
+ } else {
+ /*
+ * No key provided so it is either enable key,
+ * on or off
+ */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
+ sec->param.encrypt_key.key_disable = MTRUE;
+ } else {
+ /*
+ * iwconfig mlanX key [n]
+ * iwconfig mlanX key on
+ * iwconfig mlanX key open
+ * iwconfig mlanX key restricted
+ * Do we want to just set the transmit key index ?
+ */
+ if (index < 0) {
+ PRINTM(MINFO,
+ "*** iwconfig mlanX key on ***\n");
+ sec->param.encrypt_key.key_index =
+ MLAN_KEY_INDEX_DEFAULT;
+ } else
+ sec->param.encrypt_key.key_index = index;
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
+ switch (dwrq->flags & 0xf000) {
+ case IW_ENCODE_RESTRICTED:
+ /* iwconfig mlanX restricted key [1] */
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ PRINTM(MINFO, "Auth mode restricted!\n");
+ break;
+ case IW_ENCODE_OPEN:
+ /* iwconfig mlanX key [2] open */
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ PRINTM(MINFO, "Auth mode open!\n");
+ break;
+ case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
+ default:
+ /* iwconfig mlanX key [2] open restricted */
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ PRINTM(MINFO, "Auth mode auto!\n");
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ }
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_encode(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ mlan_ds_sec_cfg *sec = NULL;
+ mlan_ioctl_req *req = NULL;
+ t_u32 auth_mode;
+ int index = (dwrq->flags & IW_ENCODE_INDEX);
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (index < 0 || index > 4) {
+ PRINTM(MERROR, "Key index #%d out of range\n", index);
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ dwrq->flags = 0;
+ /*
+ * Check encryption mode
+ */
+ switch (auth_mode) {
+ case MLAN_AUTH_MODE_OPEN:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case MLAN_AUTH_MODE_SHARED:
+ case MLAN_AUTH_MODE_NETWORKEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+
+ case MLAN_AUTH_MODE_AUTO:
+ dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
+ break;
+
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_GET;
+
+ if (!index)
+ sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
+ else
+ sec->param.encrypt_key.key_index = index - 1;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(extra, 0, 16);
+ if (sec->param.encrypt_key.key_len) {
+ moal_memcpy_ext(priv->phandle, extra,
+ sec->param.encrypt_key.key_material,
+ sec->param.encrypt_key.key_len,
+ sec->param.encrypt_key.key_len);
+ dwrq->length = sec->param.encrypt_key.key_len;
+ dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if (sec->param.encrypt_key.key_disable)
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ else
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (vwrq->value == -1) {
+ rate_cfg.is_rate_auto = 1;
+ } else {
+ rate_cfg.is_rate_auto = 0;
+ rate_cfg.rate_type = MLAN_RATE_VALUE;
+ rate_cfg.rate = vwrq->value / 500000;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_SET, &rate_cfg)) {
+ ret = -EFAULT;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get data rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_rate_cfg_t rate_cfg;
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (rate_cfg.is_rate_auto)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+ vwrq->value = rate_cfg.rate * 500000;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ rthr = MLAN_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get RTS threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int rthr, ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = rthr;
+ vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE) ||
+ (vwrq->value > MLAN_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int fthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ fthr = MLAN_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Fragment threshold
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0, fthr;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ vwrq->value = fthr;
+ vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE) ||
+ (vwrq->value > MLAN_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+#if (WIRELESS_EXT >= 18)
+/**
+ * @brief Get IE
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ int copy_size = 0, ie_len;
+ t_u8 ie[MAX_IE_SIZE];
+
+ ENTER();
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie,
+ &ie_len,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ copy_size = MIN(ie_len, dwrq->length);
+ moal_memcpy_ext(priv->phandle, extra, ie, copy_size, copy_size);
+ dwrq->length = copy_size;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set IE
+ *
+ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
+ * for eventual passthrough to the firmware in an associate/join
+ * (and potentially start) command.
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ int ie_len = dwrq->length;
+ const t_u8 wps_oui[] = {0x00, 0x50, 0xf2, 0x04};
+ mlan_ds_wps_cfg *pwps = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ /* extra + 2 to skip element id and length */
+ if (!memcmp((t_u8 *)(extra + 2), wps_oui, sizeof(wps_oui))) {
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pwps = (mlan_ds_wps_cfg *)req->pbuf;
+ req->req_id = MLAN_IOCTL_WPS_CFG;
+ req->action = MLAN_ACT_SET;
+ pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
+ pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
+
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_gen_ie(priv, MLAN_ACT_SET,
+ (t_u8 *)extra, &ie_len,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ int key_index;
+ t_u8 *pkey_material = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key_index < 0 || key_index > 5) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (ext->key_len > (MLAN_MAX_KEY_LENGTH)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *)req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+ pkey_material = (t_u8 *)(ext + 1);
+ sec->param.encrypt_key.key_len = ext->key_len;
+ moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
+ (u8 *)ext->addr.sa_data, ETH_ALEN,
+ sizeof(sec->param.encrypt_key.mac_addr));
+ /* Disable and Remove Key */
+ if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
+ sec->param.encrypt_key.key_remove = MTRUE;
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
+ PRINTM(MIOCTL,
+ "Remove key key_index=%d, dwrq->flags=0x%x " MACSTR "\n",
+ key_index, dwrq->flags,
+ MAC2STR(sec->param.encrypt_key.mac_addr));
+ } else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+ /* Set WEP key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.key_material,
+ pkey_material, ext->key_len,
+ sizeof(sec->param.encrypt_key.key_material));
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ sec->param.encrypt_key.is_current_wep_key = MTRUE;
+ } else {
+ /* Set WPA key */
+ sec->param.encrypt_key.key_index = key_index;
+ sec->param.encrypt_key.key_flags = ext->ext_flags;
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn,
+ (t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn,
+ (t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
+ SEQ_MAX_SIZE);
+ }
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.key_material,
+ pkey_material, ext->key_len,
+ sizeof(sec->param.encrypt_key.key_material));
+ PRINTM(MIOCTL,
+ "set wpa key key_index=%d, key_len=%d key_flags=0x%x " MACSTR
+ "\n",
+ key_index, ext->key_len,
+ sec->param.encrypt_key.key_flags,
+ MAC2STR(sec->param.encrypt_key.mac_addr));
+ DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
+#define IW_ENCODE_ALG_AES_CMAC 5
+ if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
+ sec->param.encrypt_key.key_flags |=
+ KEY_FLAG_AES_MCAST_IGTK;
+#define IW_ENCODE_ALG_SMS4 0x20
+ /* Set WAPI key */
+ if (ext->alg == IW_ENCODE_ALG_SMS4) {
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ moal_memcpy_ext(priv->phandle,
+ sec->param.encrypt_key.pn,
+ (t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn));
+ moal_memcpy_ext(
+ priv->phandle,
+ &sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
+ (t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
+ sizeof(sec->param.encrypt_key.pn) -
+ SEQ_MAX_SIZE);
+ DBG_HEXDUMP(MCMD_D, "WAPI PN",
+ sec->param.encrypt_key.pn, PN_SIZE);
+ }
+ }
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS)
+ ret = -EFAULT;
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Extended version of encoding configuration
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int woal_get_encode_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+/**
+ * @brief Request MLME operation
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_set_mlme(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+
+ ENTER();
+ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_disconnect(priv, MOAL_IOCTL_WAIT,
+ (t_u8 *)mlme->addr.sa_data,
+ DEF_DEAUTH_REASON_CODE))
+ ret = -EFAULT;
+ }
+ LEAVE();
+ return ret;
+}
+
+/** @brief Set authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_auth(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_param *vwrq = &wrqu->param;
+ t_u32 auth_mode = 0;
+ t_u32 encrypt_mode = 0;
+ ENTER();
+
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (vwrq->value & IW_AUTH_CIPHER_NONE)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
+ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
+ else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
+ else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+ encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (vwrq->value) {
+ case IW_AUTH_ALG_SHARED_KEY:
+ PRINTM(MINFO, "Auth mode shared key!\n");
+ auth_mode = MLAN_AUTH_MODE_SHARED;
+ break;
+ case IW_AUTH_ALG_LEAP:
+ PRINTM(MINFO, "Auth mode LEAP!\n");
+ auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
+ break;
+ case IW_AUTH_ALG_OPEN_SYSTEM:
+ PRINTM(MINFO, "Auth mode open!\n");
+ auth_mode = MLAN_AUTH_MODE_OPEN;
+ break;
+ case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
+ default:
+ PRINTM(MINFO, "Auth mode auto!\n");
+ auth_mode = MLAN_AUTH_MODE_AUTO;
+ break;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+#define IW_AUTH_WAPI_ENABLED 0x20
+ case IW_AUTH_WAPI_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
+ ret = -EFAULT;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
+ priv->wpa_version = vwrq->value;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
+ priv->key_mgmt = vwrq->value;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+#if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+ case IW_AUTH_MFP:
+#endif
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get authentication mode parameters
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_auth(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_param *vwrq = &wrqu->param;
+ t_u32 encrypt_mode = 0;
+ t_u32 auth_mode;
+ t_u32 wpa_enable;
+ ENTER();
+ switch (vwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
+ ret = -EFAULT;
+ else {
+ if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
+ vwrq->value = IW_AUTH_CIPHER_NONE;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
+ vwrq->value = IW_AUTH_CIPHER_WEP40;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
+ vwrq->value = IW_AUTH_CIPHER_TKIP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
+ vwrq->value = IW_AUTH_CIPHER_CCMP;
+ else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
+ vwrq->value = IW_AUTH_CIPHER_WEP104;
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
+ ret = -EFAULT;
+ else {
+ if (auth_mode == MLAN_AUTH_MODE_SHARED)
+ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
+ vwrq->value = IW_AUTH_ALG_LEAP;
+ else
+ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
+ ret = -EFAULT;
+ else
+ vwrq->value = wpa_enable;
+ break;
+ case IW_AUTH_WPA_VERSION:
+ vwrq->value = priv->wpa_version;
+ break;
+ case IW_AUTH_KEY_MGMT:
+ vwrq->value = priv->key_mgmt;
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ default:
+ ret = -EOPNOTSUPP;
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set PMKSA Cache
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return -EOPNOTSUPP
+ */
+static int woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ ENTER();
+ LEAVE();
+ return -EOPNOTSUPP;
+}
+
+#endif /* WE >= 18 */
+
+/* Data rate listing
+ * MULTI_BANDS:
+ * abg a b b/g
+ * Infra G(12) A(8) B(4) G(12)
+ * Adhoc A+B(12) A(8) B(4) B(4)
+ * non-MULTI_BANDS:
+ b b/g
+ * Infra B(4) G(12)
+ * Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_get_range(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int i;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ struct iw_range *range = (struct iw_range *)extra;
+ moal_802_11_rates rates;
+ mlan_chan_list *pchan_list = NULL;
+ mlan_bss_info bss_info;
+ gfp_t flag;
+
+ ENTER();
+
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ pchan_list = kzalloc(sizeof(mlan_chan_list), flag);
+ if (!pchan_list) {
+ LEAVE();
+ return -ENOMEM;
+ }
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(&rates, 0, sizeof(rates));
+ woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
+ range->num_bitrates = rates.num_of_rates;
+
+ for (i = 0;
+ i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
+ i++) {
+ range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+
+ woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
+
+ range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
+
+ for (i = 0; i < range->num_frequency; i++) {
+ range->freq[i].i = (long)pchan_list->cf[i].channel;
+ range->freq[i].m = (long)pchan_list->cf[i].freq * 100000;
+ range->freq[i].e = 1;
+ }
+ kfree(pchan_list);
+
+ PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ woal_sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MLAN_RTS_MIN_VALUE;
+ range->max_rts = MLAN_RTS_MAX_VALUE;
+ range->min_frag = MLAN_FRAG_MIN_VALUE;
+ range->max_frag = MLAN_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+/** Minimum power period */
+#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
+/** Maximum power period */
+#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
+/** Minimum power timeout value */
+#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
+/** Maximim power timeout value */
+#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
+
+ /* Power Management duration & timeout */
+ range->min_pmp = IW_POWER_PERIOD_MIN;
+ range->max_pmp = IW_POWER_PERIOD_MAX;
+ range->min_pmt = IW_POWER_TIMEOUT_MIN;
+ range->max_pmt = IW_POWER_TIMEOUT_MAX;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = MLAN_TX_RETRY_MIN;
+ range->max_retry = MLAN_TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ /*
+ * need to put the right values here
+ */
+/** Maximum quality percentage */
+#define IW_MAX_QUAL_PERCENT 5
+/** Average quality percentage */
+#define IW_AVG_QUAL_PERCENT 3
+ range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+
+ range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+
+ range->sensitivity = 0;
+
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ range->txpower[0] = bss_info.min_power_level;
+ range->txpower[1] = bss_info.max_power_level;
+ range->num_txpower = 2;
+ range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+#if (WIRELESS_EXT >= 18)
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_CCMP | IW_ENC_CAPA_CIPHER_TKIP;
+#endif
+ LEAVE();
+ return 0;
+}
+
+#ifdef MEF_CFG_RX_FILTER
+/**
+ * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE: enable/disable
+ *
+ * @return 0 -- success, otherwise fail
+ */
+static int woal_set_rxfilter(moal_private *priv, BOOLEAN enable)
+{
+ int ret = 0;
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ds_misc_mef_cfg *mef_cfg = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *)req->pbuf;
+ mef_cfg = &misc->param.mef_cfg;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ misc->sub_command = MLAN_OID_MISC_MEF_CFG;
+ req->action = MLAN_ACT_SET;
+
+ mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+ if (status != MLAN_STATUS_PENDING)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Set priv command
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int woal_set_priv(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ char *buf = NULL;
+ int power_mode = 0;
+ int band = 0;
+ char *pband = NULL;
+ mlan_bss_info bss_info;
+ mlan_ds_get_signal signal;
+ mlan_rate_cfg_t rate;
+ char *pdata = NULL;
+ t_u8 country_code[COUNTRY_CODE_LEN];
+ int len = 0;
+ gfp_t flag;
+ ENTER();
+ if (!priv || !priv->phandle) {
+ PRINTM(MERROR, "priv or handle is NULL\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ buf = kzalloc(dwrq->length + 1, flag);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ buf[dwrq->length] = '\0';
+ PRINTM(MIOCTL, "SIOCSIWPRIV request = %s\n", buf);
+ if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
+ 0) {
+ if (dwrq->length > strlen("RSSILOW-THRESHOLD") + 1) {
+ pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_rssi_low_threshold(priv, pdata,
+ MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (bss_info.media_connected) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
+ &signal)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
+ signal.bcn_rssi_avg) +
+ 1;
+ } else {
+ len = sprintf(buf, "OK\n") + 1;
+ }
+ } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
+ len = sprintf(buf, "LinkSpeed %d\n",
+ (int)(rate.rate * 500000 / 1000000)) +
+ 1;
+ } else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
+ len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ priv->current_addr[0], priv->current_addr[1],
+ priv->current_addr[2], priv->current_addr[3],
+ priv->current_addr[4], priv->current_addr[5]) +
+ 1;
+ } else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_powermode(priv, &power_mode)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
+ } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
+ PRINTM(MIOCTL, "Set Active Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
+ PRINTM(MIOCTL, "Set Passive Scan\n");
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
+ if (dwrq->length > strlen("POWERMODE") + 1) {
+ pdata = buf + strlen("POWERMODE") + 1;
+ if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_powermode(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
+ memset(country_code, 0, sizeof(country_code));
+ if ((strlen(buf) - strlen("COUNTRY") - 1) > COUNTRY_CODE_LEN) {
+ ret = -EFAULT;
+ goto done;
+ }
+ moal_memcpy_ext(priv->phandle, country_code,
+ buf + strlen("COUNTRY") + 1,
+ COUNTRY_CODE_LEN - 1, sizeof(country_code) - 1);
+ PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_region_code(priv, country_code)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (memcmp(buf, WEXT_CSCAN_HEADER, strlen(WEXT_CSCAN_HEADER)) ==
+ 0) {
+ PRINTM(MIOCTL, "Set Combo Scan\n");
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_combo_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
+ if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "Band %d\n", band) + 1;
+ } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
+ pband = buf + strlen("SETBAND") + 1;
+ if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "START", strlen("START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) ==
+ 0) {
+ /* it will be done by GUI */
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-START",
+ strlen("BTCOEXSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
+ 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
+ 0) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_bg_scan(priv, buf, dwrq->length)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MTRUE;
+ priv->bg_scan_reported = MFALSE;
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
+ if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ priv->bg_scan_start = MFALSE;
+ priv->bg_scan_reported = MFALSE;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
+ 0) {
+#ifdef MEF_CFG_RX_FILTER
+ ret = woal_set_rxfilter(priv, MTRUE);
+ if (ret)
+ goto done;
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
+ 0) {
+#ifdef MEF_CFG_RX_FILTER
+ ret = woal_set_rxfilter(priv, MFALSE);
+ if (ret)
+ goto done;
+#endif
+ len = sprintf(buf, "OK\n") + 1;
+ } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
+ if (dwrq->length > strlen("RXFILTER-ADD") + 1) {
+ pdata = buf + strlen("RXFILTER-ADD") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_add_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
+ 0) {
+ if (dwrq->length > strlen("RXFILTER-REMOVE") + 1) {
+ pdata = buf + strlen("RXFILTER-REMOVE") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_remove_rxfilter(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
+ if (dwrq->length > strlen("QOSINFO") + 1) {
+ pdata = buf + strlen("QOSINFO") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
+ if (dwrq->length > strlen("SLEEPPD") + 1) {
+ pdata = buf + strlen("SLEEPPD") + 1;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_sleeppd(priv, pdata)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ len = sprintf(buf, "OK\n") + 1;
+ } else {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
+ dwrq->length = (t_u16)len;
+ if (copy_to_user(dwrq->pointer, buf, dwrq->length))
+ ret = -EFAULT;
+done:
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Request a scan
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param req_ssid A pointer to mlan_802_11_ssid structure
+ *
+ * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
+ */
+mlan_status woal_wext_request_scan(moal_private *priv, t_u8 wait_option,
+ mlan_802_11_ssid *req_ssid)
+{
+ wlan_user_scan_cfg scan_req;
+ mlan_scan_cfg scan_cfg;
+ ENTER();
+ if (!woal_is_any_interface_active(priv->phandle)) {
+ LEAVE();
+ return woal_request_scan(priv, wait_option, req_ssid);
+ }
+ memset(&scan_cfg, 0, sizeof(scan_cfg));
+ memset(&scan_req, 0, sizeof(scan_req));
+ if (req_ssid && req_ssid->ssid_len != 0) {
+ moal_memcpy_ext(priv->phandle, scan_req.ssid_list[0].ssid,
+ req_ssid->ssid, req_ssid->ssid_len,
+ MLAN_MAX_SSID_LENGTH);
+ scan_req.ssid_list[0].max_len = 0;
+ }
+ woal_get_scan_config(priv, &scan_cfg);
+ if (scan_cfg.scan_chan_gap)
+ scan_req.scan_chan_gap = scan_cfg.scan_chan_gap;
+ else
+ scan_req.scan_chan_gap = priv->phandle->scan_chan_gap;
+ /** indicate FW, gap is optional */
+ if (scan_req.scan_chan_gap && priv->phandle->pref_mac)
+ scan_req.scan_chan_gap |= GAP_FLAG_OPTIONAL;
+ LEAVE();
+ return woal_request_userscan(priv, wait_option, &scan_req);
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ moal_handle *handle = priv->phandle;
+#if WIRELESS_EXT >= 18
+ struct iw_scan_req *req;
+ struct iw_point *dwrq = (struct iw_point *)vwrq;
+#endif
+ mlan_802_11_ssid req_ssid;
+
+ ENTER();
+ if (handle->scan_pending_on_block == MTRUE) {
+ PRINTM(MINFO, "scan already in processing...\n");
+ LEAVE();
+ return ret;
+ }
+#ifdef REASSOCIATION
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+ priv->report_scan_result = MTRUE;
+
+ memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
+
+#if WIRELESS_EXT >= 18
+ if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+ (dwrq->length == sizeof(struct iw_scan_req))) {
+ req = (struct iw_scan_req *)extra;
+
+ if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
+ req_ssid.ssid_len = req->essid_len;
+ moal_memcpy_ext(priv->phandle, req_ssid.ssid,
+ (t_u8 *)req->essid, req->essid_len,
+ sizeof(req_ssid.ssid));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wext_request_scan(priv, MOAL_NO_WAIT,
+ &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+#endif
+ if (MLAN_STATUS_SUCCESS !=
+ woal_wext_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
+ ret = -EFAULT;
+ goto done;
+ }
+#if WIRELESS_EXT >= 18
+ }
+#endif
+
+ if (priv->phandle->surprise_removed) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+done:
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_set_essid(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ struct iw_point *dwrq = &wrqu->data;
+ mlan_802_11_ssid req_ssid;
+ mlan_ssid_bssid ssid_bssid;
+#ifdef REASSOCIATION
+ moal_handle *handle = priv->phandle;
+ mlan_bss_info bss_info;
+#endif
+ int ret = 0;
+ t_u32 mode = 0;
+
+ ENTER();
+
+#ifdef REASSOCIATION
+ /* Cancel re-association */
+ priv->reassoc_required = MFALSE;
+
+ if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
+ PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
+ LEAVE();
+ return -EBUSY;
+ }
+#endif /* REASSOCIATION */
+
+ /* Check the size of the string */
+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ ret = -E2BIG;
+ goto setessid_ret;
+ }
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
+ memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
+
+#if WIRELESS_EXT > 20
+ req_ssid.ssid_len = dwrq->length;
+#else
+ req_ssid.ssid_len = dwrq->length - 1;
+#endif
+
+ /*
+ * Check if we asked for `any' or 'particular'
+ */
+ if (!dwrq->flags) {
+#ifdef REASSOCIATION
+ if (!req_ssid.ssid_len) {
+ memset(&priv->prev_ssid_bssid.ssid, 0x00,
+ sizeof(mlan_802_11_ssid));
+ memset(&priv->prev_ssid_bssid.bssid, 0x00,
+ MLAN_MAC_ADDR_LENGTH);
+ goto setessid_ret;
+ }
+#endif
+ /* Do normal SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else {
+ /* Set the SSID */
+ moal_memcpy_ext(priv->phandle, req_ssid.ssid, extra,
+ MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH),
+ sizeof(req_ssid.ssid));
+ if (!req_ssid.ssid_len ||
+ (MFALSE == woal_ssid_valid(&req_ssid))) {
+ PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
+ ret = -EINVAL;
+ goto setessid_ret;
+ }
+
+ PRINTM(MINFO, "Requested new SSID = %s\n",
+ (char *)req_ssid.ssid);
+ moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid, &req_ssid,
+ sizeof(mlan_802_11_ssid),
+ sizeof(ssid_bssid.ssid));
+ if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
+ PRINTM(MIOCTL, "Already connect to the network\n");
+ goto setessid_ret;
+ }
+
+ if (dwrq->flags != 0xFFFF) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_essid(priv, &ssid_bssid,
+ MOAL_IOCTL_WAIT)) {
+ /* Do specific SSID scanning */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_scan(priv, MOAL_IOCTL_WAIT,
+ &req_ssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ }
+ }
+ }
+
+ mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
+ if (mode == IW_MODE_ADHOC)
+ /* disconnect before try to associate */
+ woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
+ DEF_DEAUTH_REASON_CODE);
+
+ if (mode != IW_MODE_ADHOC) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_11d_check_ap_channel(priv, MOAL_IOCTL_WAIT,
+ &ssid_bssid)) {
+ PRINTM(MERROR,
+ "The AP's channel is invalid for current region\n");
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ } else if (MLAN_STATUS_SUCCESS !=
+ woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
+ /* Adhoc start, Check the channel command */
+ woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
+
+#ifdef REASSOCIATION
+ if (priv->reassoc_on == MTRUE && req_ssid.ssid_len) {
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &req_ssid, sizeof(mlan_802_11_ssid),
+ sizeof(priv->prev_ssid_bssid.ssid));
+ memset(&priv->prev_ssid_bssid.bssid, 0x00,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+#endif /* REASSOCIATION */
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+
+#ifdef REASSOCIATION
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto setessid_ret;
+ }
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
+ &bss_info.ssid, sizeof(mlan_802_11_ssid),
+ sizeof(priv->prev_ssid_bssid.ssid));
+ moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
+ &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
+ sizeof(priv->prev_ssid_bssid.bssid));
+#endif /* REASSOCIATION */
+
+setessid_ret:
+ if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
+ woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
+#ifdef REASSOCIATION
+ MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
+#endif
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get current essid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ mlan_bss_info bss_info;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (bss_info.media_connected) {
+ dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
+ moal_memcpy_ext(priv->phandle, extra, bss_info.ssid.ssid,
+ dwrq->length, dwrq->length);
+ } else
+ dwrq->length = 0;
+
+ if (bss_info.scan_table_idx)
+ dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
+ else
+ dwrq->flags = 1;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0--success, otherwise fail
+ */
+static int woal_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ unsigned int i;
+ unsigned int j;
+ mlan_scan_resp scan_resp;
+ mlan_bss_info bss_info;
+ BSSDescriptor_t *scan_table;
+ mlan_ds_get_signal rssi;
+ t_u16 buf_size = 16 + 256 * 2;
+ char *buf = NULL;
+ char *ptr;
+#if WIRELESS_EXT >= 18
+ t_u8 *praw_data;
+#endif
+ int beacon_size;
+ t_u8 *pbeacon;
+ IEEEtypes_ElementId_e element_id;
+ t_u8 element_len;
+ gfp_t flag;
+
+ ENTER();
+
+ if (priv->phandle->scan_pending_on_block == MTRUE) {
+ LEAVE();
+ return -EAGAIN;
+ }
+ flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+ buf = kzalloc((buf_size), flag);
+ if (!buf) {
+ PRINTM(MERROR, "Cannot allocate buffer!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&bss_info, 0, sizeof(bss_info));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ memset(&scan_resp, 0, sizeof(scan_resp));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
+ if (dwrq->length)
+ end_buf = extra + dwrq->length;
+ if (priv->media_connected == MTRUE)
+ PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
+ PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
+ (int)scan_resp.num_in_scan_table);
+
+#if WIRELESS_EXT > 13
+ /* The old API using SIOCGIWAPLIST had a hard limit of
+ * IW_MAX_AP. The new API using SIOCGIWSCAN is only
+ * limited by buffer size WE-14 -> WE-16 the buffer is
+ * limited to IW_SCAN_MAX_DATA bytes which is 4096.
+ */
+ for (i = 0; i < MIN(scan_resp.num_in_scan_table, 64); i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ PRINTM(MINFO,
+ "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf,
+ (t_u32)MAX_SCAN_CELL_SIZE);
+ ret = -E2BIG;
+ break;
+ }
+ if (!scan_table[i].freq) {
+ PRINTM(MWARN, "Invalid channel number %d\n",
+ (int)scan_table[i].channel);
+ continue;
+ }
+ PRINTM(MINFO, "i=%d Ssid: %-32s\n", i,
+ scan_table[i].ssid.ssid);
+
+ /* check ssid is valid or not, ex. hidden ssid will be filter
+ * out */
+ if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE)
+ continue;
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ moal_memcpy_ext(priv->phandle, iwe.u.ap_addr.sa_data,
+ &scan_table[i].mac_address, ETH_ALEN,
+ sizeof(iwe.u.ap_addr.sa_data));
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
+ &iwe, iwe.len);
+
+ /* Add the ESSID */
+ iwe.u.data.length = scan_table[i].ssid.ssid_len;
+
+ if (iwe.u.data.length > 32)
+ iwe.u.data.length = 32;
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
+ (char *)scan_table[i].ssid.ssid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
+ iwe.u.mode = IW_MODE_ADHOC;
+ else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_AUTO;
+
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
+ &iwe, iwe.len);
+
+ /* Frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long)scan_table[i].freq;
+ iwe.u.freq.e = 6;
+ iwe.u.freq.flags = IW_FREQ_FIXED;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
+ &iwe, iwe.len);
+
+ memset(&iwe, 0, sizeof(iwe));
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
+ if (!bss_info.bcn_nf_last)
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ else
+ iwe.u.qual.noise = bss_info.bcn_nf_last;
+
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) &&
+ bss_info.adhoc_state == ADHOC_STARTED) {
+ memset(&rssi, 0, sizeof(mlan_ds_get_signal));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
+ &rssi)) {
+ ret = -EFAULT;
+ break;
+ }
+ iwe.u.qual.level = rssi.data_rssi_avg;
+ }
+ iwe.u.qual.qual =
+ woal_rssi_to_quality((t_s16)(iwe.u.qual.level - 0x100));
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
+ &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (scan_table[i].privacy)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
+ &iwe, NULL);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j])
+ break;
+
+ iwe.u.bitrate.value =
+ (scan_table[i].supported_rates[j] & 0x7f) *
+ 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val = IWE_STREAM_ADD_VALUE(info, current_ev,
+ current_val, end_buf,
+ &iwe, iwe.len);
+ }
+ if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
+ !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) &&
+ bss_info.adhoc_state == ADHOC_STARTED) {
+ iwe.u.bitrate.value = 22 * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_val = IWE_STREAM_ADD_VALUE(info, current_ev,
+ current_val, end_buf,
+ &iwe, iwe.len);
+ }
+
+ /* Check if an event is added */
+ if ((unsigned int)(current_val - current_ev) >= IW_EV_PARAM_LEN)
+ current_ev = current_val;
+
+ /* Beacon Interval */
+ memset(&iwe, 0, sizeof(iwe));
+ ptr = buf;
+ ptr += sprintf(ptr, "Beacon interval=%d",
+ scan_table[i].beacon_period);
+
+ iwe.u.data.length = strlen(buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
+ &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+
+ /* Parse and send the IEs */
+ pbeacon = scan_table[i].pbeacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+ if (pbeacon) {
+ pbeacon += sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+ beacon_size -= sizeof(scan_table[i].beacon_period) +
+ sizeof(scan_table[i].time_stamp) +
+ sizeof(scan_table[i].cap_info);
+
+ while ((unsigned int)beacon_size >=
+ sizeof(IEEEtypes_Header_t)) {
+ element_id = (IEEEtypes_ElementId_e)(
+ *(t_u8 *)pbeacon);
+ element_len = *((t_u8 *)pbeacon + 1);
+ if ((unsigned int)beacon_size <
+ (unsigned int)element_len +
+ sizeof(IEEEtypes_Header_t)) {
+ PRINTM(MERROR,
+ "Get scan: Error in processing IE, "
+ "bytes left < IE length\n");
+ break;
+ }
+
+ switch (element_id) {
+#if WIRELESS_EXT >= 18
+ case VENDOR_SPECIFIC_221:
+ case RSN_IE:
+ case WAPI_IE:
+ praw_data = (t_u8 *)pbeacon;
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ moal_memcpy_ext(
+ priv->phandle, buf, praw_data,
+ element_len +
+ sizeof(IEEEtypes_Header_t),
+ buf_size);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length =
+ element_len +
+ sizeof(IEEEtypes_Header_t);
+ iwe.len = IW_EV_POINT_LEN +
+ iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(
+ info, current_ev, end_buf, &iwe,
+ buf);
+ current_val = current_ev +
+ IW_EV_LCP_LEN +
+ strlen(buf);
+ break;
+#endif
+ default:
+ break;
+ }
+ pbeacon += element_len +
+ sizeof(IEEEtypes_Header_t);
+ beacon_size -= element_len +
+ sizeof(IEEEtypes_Header_t);
+ }
+ }
+
+#if WIRELESS_EXT > 14
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, buf_size);
+ ptr = buf;
+ ptr += sprintf(ptr, "band=");
+ memset(&iwe, 0, sizeof(iwe));
+ if (scan_table[i].bss_band == BAND_A)
+ ptr += sprintf(ptr, "a");
+ else
+ ptr += sprintf(ptr, "bg");
+ iwe.u.data.length = strlen(buf);
+ PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+ PRINTM(MINFO, "BUF: %s\n", buf);
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
+ &iwe, buf);
+ current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+#endif
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((unsigned int)(current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+#endif
+
+done:
+ kfree(buf);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * iwconfig settable callbacks
+ */
+static const iw_handler woal_handler[] = {
+ (iw_handler)woal_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler)woal_get_name, /* SIOCGIWNAME */
+ (iw_handler)NULL, /* SIOCSIWNWID */
+ (iw_handler)NULL, /* SIOCGIWNWID */
+ (iw_handler)woal_set_freq, /* SIOCSIWFREQ */
+ (iw_handler)woal_get_freq, /* SIOCGIWFREQ */
+ (iw_handler)woal_set_bss_mode, /* SIOCSIWMODE */
+ (iw_handler)woal_get_bss_mode, /* SIOCGIWMODE */
+ (iw_handler)woal_set_sens, /* SIOCSIWSENS */
+ (iw_handler)woal_get_sens, /* SIOCGIWSENS */
+ (iw_handler)NULL, /* SIOCSIWRANGE */
+ (iw_handler)woal_get_range, /* SIOCGIWRANGE */
+ (iw_handler)woal_set_priv, /* SIOCSIWPRIV */
+ (iw_handler)NULL, /* SIOCGIWPRIV */
+ (iw_handler)NULL, /* SIOCSIWSTATS */
+ (iw_handler)NULL, /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+#ifdef CONFIG_WEXT_SPY
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+#else
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+#endif
+#else /* WIRELESS_EXT > 15 */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+ (iw_handler)woal_set_wap, /* SIOCSIWAP */
+ (iw_handler)woal_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+ (iw_handler)woal_set_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler)NULL, /* -- hole -- */
+#endif
+ /* (iw_handler) wlan_get_aplist, */ /* SIOCGIWAPLIST */
+ NULL, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler)woal_set_scan, /* SIOCSIWSCAN */
+ (iw_handler)woal_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler)NULL, /* SIOCSIWSCAN */
+ (iw_handler)NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler)woal_set_essid, /* SIOCSIWESSID */
+ (iw_handler)woal_get_essid, /* SIOCGIWESSID */
+ (iw_handler)woal_set_nick, /* SIOCSIWNICKN */
+ (iw_handler)woal_get_nick, /* SIOCGIWNICKN */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)woal_set_rate, /* SIOCSIWRATE */
+ (iw_handler)woal_get_rate, /* SIOCGIWRATE */
+ (iw_handler)woal_set_rts, /* SIOCSIWRTS */
+ (iw_handler)woal_get_rts, /* SIOCGIWRTS */
+ (iw_handler)woal_set_frag, /* SIOCSIWFRAG */
+ (iw_handler)woal_get_frag, /* SIOCGIWFRAG */
+ (iw_handler)woal_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler)woal_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler)woal_set_retry, /* SIOCSIWRETRY */
+ (iw_handler)woal_get_retry, /* SIOCGIWRETRY */
+ (iw_handler)woal_set_encode, /* SIOCSIWENCODE */
+ (iw_handler)woal_get_encode, /* SIOCGIWENCODE */
+ (iw_handler)woal_set_power, /* SIOCSIWPOWER */
+ (iw_handler)woal_get_power, /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)NULL, /* -- hole -- */
+ (iw_handler)woal_set_gen_ie, /* SIOCSIWGENIE */
+ (iw_handler)woal_get_gen_ie, /* SIOCGIWGENIE */
+ (iw_handler)woal_set_auth, /* SIOCSIWAUTH */
+ (iw_handler)woal_get_auth, /* SIOCGIWAUTH */
+ (iw_handler)woal_set_encode_ext, /* SIOCSIWENCODEEXT */
+ (iw_handler)woal_get_encode_ext, /* SIOCGIWENCODEEXT */
+ (iw_handler)woal_set_pmksa, /* SIOCSIWPMKSA */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/**
+ * iwpriv settable callbacks
+ */
+static const iw_handler woal_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+#endif /* STA_SUPPORT */
+
+/********************************************************
+ Global Functions
+********************************************************/
+
+#if WIRELESS_EXT > 14
+
+/**
+ * @brief This function sends customized event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param str A pointer to event string
+ *
+ * @return N/A
+ */
+void woal_send_iwevcustom_event(moal_private *priv, char *str)
+{
+ union iwreq_data iwrq;
+ char buf[IW_CUSTOM_MAX];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.pointer = buf;
+ iwrq.data.length = strlen(buf) + 1;
+
+ /* Send Event to upper layer */
+ wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
+ PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
+
+ LEAVE();
+ return;
+}
+#endif
+
+#if WIRELESS_EXT >= 18
+/**
+ * @brief This function sends mic error event to application.
+ *
+ * @param priv A pointer to moal_private structure
+ * @param event MIC MERROR EVENT.
+ *
+ * @return N/A
+ */
+void woal_send_mic_error_event(moal_private *priv, t_u32 event)
+{
+ union iwreq_data iwrq;
+ struct iw_michaelmicfailure mic;
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(iwrq));
+ memset(&mic, 0, sizeof(mic));
+ if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
+ mic.flags = IW_MICFAILURE_PAIRWISE;
+ else
+ mic.flags = IW_MICFAILURE_GROUP;
+ iwrq.data.pointer = &mic;
+ iwrq.data.length = sizeof(mic);
+
+ wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
+ (char *)&mic);
+
+ LEAVE();
+ return;
+}
+#endif
+
+// clang-format off
+#ifdef STA_SUPPORT
+/** wlan_handler_def */
+struct iw_handler_def woal_handler_def = {
+ num_standard: ARRAY_SIZE(woal_handler),
+ num_private : ARRAY_SIZE(woal_private_handler),
+ num_private_args : ARRAY_SIZE(woal_private_args),
+ standard : (iw_handler *)woal_handler,
+ private : (iw_handler *)woal_private_handler,
+ private_args : (struct iw_priv_args *)woal_private_args,
+#if WIRELESS_EXT > 20
+ get_wireless_stats : woal_get_wireless_stats,
+#endif
+};
+// clang-format on
+
+/**
+ * @brief Get wireless statistics
+ *
+ * @param dev A pointer to net_device structure
+ *
+ * @return A pointer to iw_statistics buf
+ */
+struct iw_statistics *woal_get_wireless_stats(struct net_device *dev)
+{
+ moal_private *priv = (moal_private *)netdev_priv(dev);
+ t_u16 wait_option = MOAL_IOCTL_WAIT;
+
+ ENTER();
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ /*
+ * Since schedule() is not allowed from an atomic context
+ * such as when dev_base_lock for netdevices is acquired
+ * for reading/writing in kernel before this call, HostCmd
+ * is issued in non-blocking way in such contexts and
+ * blocking in other cases.
+ */
+ if (in_atomic() || !write_can_lock(&dev_base_lock))
+ wait_option = MOAL_NO_WAIT;
+#endif
+
+ priv->w_stats.status = woal_get_mode(priv, wait_option);
+ priv->w_stats.discard.retries = priv->stats.tx_errors;
+ priv->w_stats.qual.qual = 0;
+
+ /* Send RSSI command to get beacon RSSI/NF, valid only if associated */
+ if (priv->media_connected == MTRUE) {
+ if (MLAN_STATUS_SUCCESS ==
+ woal_get_signal_info(priv, wait_option, NULL))
+ priv->w_stats.qual.qual = woal_rssi_to_quality(
+ (t_s16)(priv->w_stats.qual.level - 0x100));
+ }
+#if WIRELESS_EXT > 18
+ priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
+#else
+ priv->w_stats.qual.updated |= 7;
+#endif
+ if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
+ priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+
+ PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
+ PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
+ PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
+ priv->w_stats.discard.code = 0;
+ if (MLAN_STATUS_SUCCESS != woal_get_stats_info(priv, wait_option, NULL))
+ PRINTM(MERROR, "Error getting stats information\n");
+
+ LEAVE();
+ return &priv->w_stats;
+}
+#endif /* STA_SUPPORT */
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.h b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.h
new file mode 100644
index 000000000000..f363f2f0a99d
--- /dev/null
+++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_wext.h
@@ -0,0 +1,58 @@
+/** @file moal_wext.h
+ *
+ * @brief This file contains definition for wireless extension IOCTL call.
+ *
+ *
+ * Copyright 2014-2020 NXP
+ *
+ * This software file (the File) is distributed by NXP
+ * under the terms of the GNU General Public License Version 2, June 1991
+ * (the License). You may use, redistribute and/or modify the File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or 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.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#ifndef _WOAL_WEXT_H_
+#define _WOAL_WEXT_H_
+
+/** NF value for default scan */
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) \
+ iwe_stream_add_event((i), (c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) \
+ iwe_stream_add_point((i), (c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) \
+ iwe_stream_add_value((i), (c), (v), (e), (w), (l))
+#else
+/** Add event */
+#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) \
+ iwe_stream_add_event((c), (e), (w), (l))
+/** Add point */
+#define IWE_STREAM_ADD_POINT(i, c, e, w, p) \
+ iwe_stream_add_point((c), (e), (w), (p))
+/** Add value */
+#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) \
+ iwe_stream_add_value((c), (v), (e), (w), (l))
+#endif
+
+extern struct iw_handler_def woal_handler_def;
+struct iw_statistics *woal_get_wireless_stats(struct net_device *dev);
+#endif /* _WOAL_WEXT_H_ */